Source code of Windows XP (NT5)
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.

2171 lines
68 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 2000.
  5. //
  6. // File: Distrib.cxx
  7. //
  8. // Contents: Top level distribution API
  9. //
  10. // Classes: CDistributedRowset
  11. //
  12. // History: 23-Feb-95 KyleP Created
  13. // 14-JAN-97 KrishnaN Undefined CI_INETSRV and related changes
  14. // 29-Mar-2000 KLam Fixed Bookmarks
  15. //
  16. // Notes: Some of the distributed versions of the Ole DB interfaces simply
  17. // call into the regular implementations. In such cases, we'll avoid
  18. // posting oledb errors because the underlying call had already done
  19. // that.
  20. //
  21. // NTRAID#DB-NTBUG9-84041-2000/07/31-dlee Distributed queries don't supported hierarcical rowsets
  22. //
  23. //----------------------------------------------------------------------------
  24. #include <pch.cxx>
  25. #pragma hdrstop
  26. #include "distrib.hxx"
  27. #include "disacc.hxx"
  28. #include "seqser.hxx"
  29. #include "seqsort.hxx"
  30. #include "scrlsort.hxx"
  31. //
  32. // IUnknown methods.
  33. //
  34. //+-------------------------------------------------------------------------
  35. //
  36. // Method: CDistributedRowset::RealQueryInterface
  37. //
  38. // Synopsis: Rebind to other interface
  39. //
  40. // Arguments: [riid] -- IID of new interface
  41. // [ppiuk] -- New interface * returned here
  42. //
  43. // Returns: S_OK if bind succeeded, E_NOINTERFACE if bind failed
  44. //
  45. // History: 10-Apr-1995 KyleP Created
  46. //
  47. // Notes: ref count is incremented inside QueryInterface
  48. //
  49. //--------------------------------------------------------------------------
  50. SCODE CDistributedRowset::RealQueryInterface( REFIID riid, VOID **ppiuk )
  51. {
  52. SCODE sc = S_OK;
  53. *ppiuk = 0;
  54. // note -- IID_IUnknown covered in QueryInterface
  55. if ( riid == IID_IRowset )
  56. {
  57. *ppiuk = (void *)((IRowset *)this);
  58. }
  59. else if (IID_ISupportErrorInfo == riid)
  60. {
  61. *ppiuk = (void *) ((IUnknown *) (ISupportErrorInfo *) &_DBErrorObj);
  62. }
  63. else if ( riid == IID_IRowsetInfo )
  64. {
  65. *ppiuk = (void *)((IRowsetInfo *)this);
  66. }
  67. else if ( riid == IID_IAccessor )
  68. {
  69. *ppiuk = (void *)((IAccessor *)this);
  70. }
  71. else if ( riid == IID_IColumnsInfo )
  72. {
  73. *ppiuk = (void *)((IColumnsInfo *)this);
  74. }
  75. else if ( riid == IID_IRowsetIdentity )
  76. {
  77. *ppiuk = (void *)((IRowsetIdentity *)this);
  78. }
  79. else if ( riid == IID_IConvertType )
  80. {
  81. *ppiuk = (void *)((IConvertType *)this);
  82. }
  83. else if ( riid == IID_IRowsetQueryStatus )
  84. {
  85. *ppiuk = (void *)((IRowsetQueryStatus *)this);
  86. }
  87. else if ( riid == IID_IConnectionPointContainer )
  88. {
  89. sc = _SetupConnectionPointContainer( this, ppiuk );
  90. }
  91. else
  92. {
  93. sc = E_NOINTERFACE;
  94. }
  95. return sc;
  96. }
  97. //
  98. // IRowset methods
  99. //
  100. //+---------------------------------------------------------------------------
  101. //
  102. // Member: CDistributedRowset::CreateAccessor, public
  103. //
  104. // Synopsis: Creates accessor
  105. //
  106. // Arguments: [dwAccessorFlags] -- Read/Write/ReadWrite
  107. // [cBindings] -- # Columns (bindings)
  108. // [rgBindings] -- Bindings
  109. // [cbRowWidth] -- row width (for IReadData)
  110. // [phAccessor] -- Accessor returned here
  111. // [rgStatus ] -- Set to index of failed binding
  112. //
  113. // History: 28-Mar-95 KyleP Created.
  114. // 22-Apr-97 EmilyB Changed to use accessorbag _aAccessors
  115. //
  116. // Notes: Need to have Ole DB error handling here because the error from the
  117. // underlying call is translated.
  118. //
  119. //----------------------------------------------------------------------------
  120. STDMETHODIMP CDistributedRowset::CreateAccessor( DBACCESSORFLAGS dwAccessorFlags,
  121. DBCOUNTITEM cBindings,
  122. const DBBINDING rgBindings[],
  123. DBLENGTH cbRowWidth,
  124. HACCESSOR * phAccessor,
  125. DBBINDSTATUS * rgStatus )
  126. {
  127. _DBErrorObj.ClearErrorInfo();
  128. if (0 == phAccessor || (0 != cBindings && 0 == rgBindings))
  129. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IAccessor);
  130. if ( 0 == cBindings )
  131. return _DBErrorObj.PostHResult(DB_E_NULLACCESSORNOTSUPPORTED, IID_IAccessor);
  132. SCODE sc = S_OK;
  133. LONG iFirstValidBookmark = -1;
  134. unsigned iBinding;
  135. XArray<DBBINDSTATUS> xStatusCopy;
  136. TRY
  137. {
  138. BOOL fCreateCopy = FALSE;
  139. BOOL fHasBookmark = FALSE;
  140. ULONG iMinColOrdinal = 1,
  141. iMaxColOrdinal = _cColumns;
  142. if ( -1 != _iColumnBookmark )
  143. {
  144. iMinColOrdinal--;
  145. iMaxColOrdinal--;
  146. }
  147. if ( rgStatus )
  148. {
  149. Win4Assert( 0 == DBSTATUS_S_OK );
  150. RtlZeroMemory( rgStatus, sizeof( rgStatus[0] ) * cBindings );
  151. }
  152. //
  153. // Create a copy of bindings iff it has bookmark column or
  154. // if it has invalid column, so that we can then mess around
  155. // with them ;-)
  156. //
  157. for ( iBinding = 0; iBinding < cBindings; iBinding++ )
  158. {
  159. fHasBookmark = ( _iColumnBookmark == rgBindings[iBinding].iOrdinal );
  160. if ( fHasBookmark ||
  161. rgBindings[iBinding].iOrdinal > iMaxColOrdinal ||
  162. rgBindings[iBinding].iOrdinal < iMinColOrdinal )
  163. {
  164. fCreateCopy = TRUE;
  165. break;
  166. }
  167. }
  168. const DBBINDING * pActualBindings = rgBindings;
  169. DBCOUNTITEM cActualBindings = cBindings;
  170. XArray<DBBINDING> xBindingCopy;
  171. if ( fCreateCopy )
  172. {
  173. unsigned iBindingCopy = 0;
  174. xBindingCopy.Init( (unsigned) cBindings );
  175. for ( iBinding = 0; iBinding < cBindings; iBinding++ )
  176. {
  177. // check for a valid bookmark
  178. if ( _iColumnBookmark == rgBindings[iBinding].iOrdinal &&
  179. DBTYPE_BYTES == ( rgBindings[iBinding].wType & ~DBTYPE_BYREF ) &&
  180. DBMEMOWNER_CLIENTOWNED == rgBindings[iBinding].dwMemOwner )
  181. {
  182. if ( -1 == iFirstValidBookmark )
  183. {
  184. iFirstValidBookmark = iBinding;
  185. }
  186. continue;
  187. }
  188. xBindingCopy[iBindingCopy] = rgBindings[iBinding];
  189. if ( rgBindings[iBinding].iOrdinal > iMaxColOrdinal ||
  190. rgBindings[iBinding].iOrdinal < iMinColOrdinal ||
  191. _iColumnBookmark == rgBindings[iBinding].iOrdinal )
  192. {
  193. // Invalid column -> set it to DB_INVALIDCOLUMN so
  194. // that we an appropriate error is returned
  195. xBindingCopy[iBindingCopy].iOrdinal = DB_INVALIDCOLUMN;
  196. }
  197. iBindingCopy++;
  198. }
  199. pActualBindings = xBindingCopy.GetPointer();
  200. cActualBindings = iBindingCopy;
  201. }
  202. if ( -1 != iFirstValidBookmark )
  203. {
  204. if ( rgStatus )
  205. {
  206. xStatusCopy.Init( (unsigned) cActualBindings );
  207. }
  208. // Create the bookmark accessors if needed
  209. if ( _xDistBmkAcc.IsNull() )
  210. {
  211. _xDistBmkAcc.Set( new CDistributedBookmarkAccessor(
  212. _aChild,
  213. _cChild,
  214. dwAccessorFlags,
  215. rgStatus ? &rgStatus[iFirstValidBookmark] : NULL,
  216. _iColumnBookmark,
  217. _cbBookmark ) );
  218. }
  219. Win4Assert( _xDistBmkAcc.GetPointer() );
  220. }
  221. *phAccessor = (HACCESSOR)new
  222. CDistributedAccessor( _aChild,
  223. _cChild,
  224. dwAccessorFlags,
  225. cActualBindings,
  226. pActualBindings,
  227. cbRowWidth,
  228. -1 != iFirstValidBookmark ?
  229. xStatusCopy.GetPointer() :
  230. rgStatus,
  231. (IUnknown *) (IRowset *) this,
  232. rgBindings,
  233. cBindings );
  234. CLock lock( _mutex );
  235. _aAccessors.Add( (CAccessorBase *)*phAccessor );
  236. if ( -1 != iFirstValidBookmark )
  237. {
  238. if ( rgStatus )
  239. {
  240. unsigned iBindingCopy = 0;
  241. for( iBinding = 0; iBinding < cBindings; iBinding++ )
  242. {
  243. if ( _iColumnBookmark != rgBindings[iBinding].iOrdinal )
  244. {
  245. rgStatus[iBinding] = xStatusCopy[iBindingCopy++];
  246. }
  247. }
  248. }
  249. ((CDistributedAccessor *)*phAccessor)->SetupBookmarkAccessor(
  250. _xDistBmkAcc.GetPointer(),
  251. rgStatus,
  252. _iColumnBookmark,
  253. _cbBookmark );
  254. }
  255. }
  256. CATCH( CException, e )
  257. {
  258. if ( -1 != iFirstValidBookmark )
  259. {
  260. if ( rgStatus )
  261. {
  262. unsigned iBindingCopy = 0;
  263. for( iBinding = 0; iBinding < cBindings; iBinding++ )
  264. {
  265. if ( _iColumnBookmark != rgBindings[iBinding].iOrdinal )
  266. {
  267. rgStatus[iBinding] = xStatusCopy[iBindingCopy++];
  268. }
  269. }
  270. }
  271. }
  272. sc = e.GetErrorCode();
  273. vqDebugOut(( DEB_ERROR, "CDistributedRowset::CreateAccessor caught exception 0x%x\n", sc ));
  274. }
  275. END_CATCH
  276. if (FAILED(sc))
  277. _DBErrorObj.PostHResult(sc, IID_IAccessor);
  278. return( sc );
  279. }
  280. //+---------------------------------------------------------------------------
  281. //
  282. // Member: CDistributedRowset::GetBindings, public
  283. //
  284. // Synopsis: Creates accessor
  285. //
  286. // Arguments: [hAccessor] -- Handle to Accessor
  287. // [pdwAccessorFlags] -- Type of binding returned here (read/write)
  288. // [pcBindings] -- Count of bindings in [prgBindings] retuned
  289. // here.
  290. // [prgBindings] -- Bindings returned here.
  291. //
  292. // History: 03-Apr-95 KyleP Created.
  293. // 22-Apr-97 EmilyB Changed to use accessorbag _aAccessors
  294. //
  295. // Notes: Need to have Ole DB error handling here because the error from the
  296. // underlying call is translated.
  297. //
  298. //----------------------------------------------------------------------------
  299. STDMETHODIMP CDistributedRowset::GetBindings( HACCESSOR hAccessor,
  300. DBACCESSORFLAGS * pdwAccessorFlags,
  301. DBCOUNTITEM * pcBindings,
  302. DBBINDING * prgBindings[])
  303. {
  304. _DBErrorObj.ClearErrorInfo();
  305. SCODE sc;
  306. TRY
  307. {
  308. CLock lock( _mutex );
  309. CDistributedAccessor * pAcc = (CDistributedAccessor *)_aAccessors.Convert(hAccessor);
  310. sc = pAcc->GetBindings( pdwAccessorFlags, pcBindings, prgBindings );
  311. }
  312. CATCH( CException, e )
  313. {
  314. vqDebugOut((DEB_ERROR, "CDistributedRowset: GetBindings caught exception 0x%x\n",
  315. e.GetErrorCode()) );
  316. // The reason we have an exception here is 'cos pAcc is invalid
  317. sc = DB_E_BADACCESSORHANDLE;
  318. }
  319. END_CATCH
  320. if (FAILED(sc))
  321. _DBErrorObj.PostHResult(sc, IID_IAccessor);
  322. return sc;
  323. }
  324. //+---------------------------------------------------------------------------
  325. //
  326. // Member: CDistributedRowset::GetData, public
  327. //
  328. // Synopsis: Fetch data for a row.
  329. //
  330. // Arguments: [hRow] -- Handle to row
  331. // [hAccessor] -- Accessor to use for fetch.
  332. // [pData] -- Data goes here.
  333. //
  334. // History: 03-Apr-95 KyleP Created.
  335. //
  336. // Notes: Need to have Ole DB error handling here because an exception could
  337. // happen.
  338. //
  339. //----------------------------------------------------------------------------
  340. STDMETHODIMP CDistributedRowset::GetData( HROW hRow,
  341. HACCESSOR hAccessor,
  342. void * pData )
  343. {
  344. _DBErrorObj.ClearErrorInfo();
  345. SCODE sc = S_OK;
  346. TRY
  347. {
  348. HROW hrowChild;
  349. int iChild = _RowManager.GetChildAndHROW( hRow, hrowChild );
  350. CLock lock( _mutex );
  351. CDistributedAccessor * pAcc = (CDistributedAccessor *)_aAccessors.Convert(hAccessor);
  352. sc = pAcc->GetData( iChild, hrowChild, pData );
  353. }
  354. CATCH( CException, e )
  355. {
  356. sc = e.GetErrorCode();
  357. vqDebugOut(( DEB_ERROR, "CDistributedRowset::GetData caught exception 0x%x\n", sc ));
  358. }
  359. END_CATCH
  360. if (FAILED(sc))
  361. _DBErrorObj.PostHResult(sc, IID_IRowset);
  362. return sc;
  363. }
  364. //+---------------------------------------------------------------------------
  365. //
  366. // Member: CDistributedRowset::GetReferencedRowset, public
  367. //
  368. // Synopsis: Traverse 'link' to associated rowset.
  369. //
  370. // Arguments: [iColumn] -- Column of 'link'.
  371. // [ppReferencedRowset] -- Link target goes here.
  372. //
  373. // History: 03-Apr-95 KyleP Created.
  374. //
  375. //----------------------------------------------------------------------------
  376. STDMETHODIMP CDistributedRowset::GetReferencedRowset( DBORDINAL iColumn,
  377. REFIID riid,
  378. IUnknown ** ppReferencedRowset )
  379. {
  380. _DBErrorObj.ClearErrorInfo();
  381. // NTRAID#DB-NTBUG9-84041-2000/07/31-dlee Distributed queries don't supported hierarcical rowsets
  382. // This can only be implemented when the distributed rowset gains
  383. // support for hierarchical rowsets.
  384. //
  385. Win4Assert( !"CDistributedRowset::GetReferencedRowset not yet implemented" );
  386. return _DBErrorObj.PostHResult(E_NOTIMPL, IID_IRowsetInfo);
  387. }
  388. //+---------------------------------------------------------------------------
  389. //
  390. // Member: CDistributedRowset::GetProperties, public
  391. //
  392. // Synopsis: Return information about the capabilities of the rowset
  393. //
  394. // Arguments: [cProperties] - number of desired properties or 0
  395. // [rgProperties] - array of desired properties or NULL
  396. // [pcProperties] - number of properties returned
  397. // [prgProperties] - array of returned properties
  398. //
  399. // Returns: SCODE
  400. //
  401. // History: 20 Nov 1995 AlanW Created.
  402. //
  403. // Notes: Need to have Ole DB error handling here because the underlying
  404. // call doesn't provide that.
  405. //
  406. //----------------------------------------------------------------------------
  407. STDMETHODIMP CDistributedRowset::GetProperties(
  408. const ULONG cProperties,
  409. const DBPROPIDSET rgPropertyIDSets[],
  410. ULONG * pcProperties,
  411. DBPROPSET ** prgProperties)
  412. {
  413. _DBErrorObj.ClearErrorInfo();
  414. // inner layer doesn't validate params...
  415. if ( (0 != cProperties && 0 == rgPropertyIDSets) ||
  416. 0 == pcProperties ||
  417. 0 == prgProperties )
  418. {
  419. vqDebugOut((DEB_IERROR, "CDistributedRowset::GetProperties: Invalid Argument(s)\n"));
  420. if (pcProperties)
  421. *pcProperties = 0;
  422. if (prgProperties)
  423. *prgProperties = 0;
  424. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowsetInfo);
  425. }
  426. SCODE scResult = S_OK;
  427. *pcProperties = 0;
  428. *prgProperties = 0;
  429. TRY
  430. {
  431. //
  432. // Update ROWSETQUERYSTATUS property
  433. //
  434. DWORD dwStatus;
  435. scResult = GetStatus( & dwStatus );
  436. if ( FAILED( scResult ) )
  437. THROW( CException( scResult ) );
  438. _Props.SetValLong( CMRowsetProps::eid_DBPROPSET_MSIDXS_ROWSET_EXT,
  439. CMRowsetProps::eid_MSIDXSPROPVAL_ROWSETQUERYSTATUS,
  440. dwStatus );
  441. scResult = _Props.GetProperties( cProperties,
  442. rgPropertyIDSets,
  443. pcProperties,
  444. prgProperties );
  445. }
  446. CATCH( CException, e )
  447. {
  448. scResult = GetOleError(e);
  449. vqDebugOut(( DEB_ERROR, "CDistributedRowset::GetProperties -- caught 0x%x\n", scResult ));
  450. }
  451. END_CATCH;
  452. if (FAILED(scResult))
  453. _DBErrorObj.PostHResult(scResult, IID_IRowsetInfo);
  454. return scResult;
  455. }
  456. //+---------------------------------------------------------------------------
  457. //
  458. // Member: CDistributedRowset::GetSpecification, public
  459. //
  460. // Synopsis: Fetch query object corresponding to rowset.
  461. //
  462. // Arguments: [riid] -- Bind spec to this interface.
  463. // [ppSpecification] -- Spec returned here.
  464. //
  465. // History: 03-Apr-95 KyleP Created.
  466. //
  467. //----------------------------------------------------------------------------
  468. STDMETHODIMP CDistributedRowset::GetSpecification( REFIID riid,
  469. IUnknown ** ppSpecification )
  470. {
  471. _DBErrorObj.ClearErrorInfo();
  472. //
  473. // NTRAID#DB-NTBUG9-84043-2000/07/31-dlee Distributed rowset doesn't implement GetSpecification()
  474. //
  475. // This is now implemented by the base rowset. We need to pass it on
  476. // through in a distributed fasion.
  477. //
  478. Win4Assert( !"CDistributedRowset::GetSpecification not yet implemented" );
  479. return _DBErrorObj.PostHResult(E_NOTIMPL, IID_IAccessor);
  480. }
  481. //+---------------------------------------------------------------------------
  482. //
  483. // Member: CDistributedRowset::MapColumnIDs, public
  484. //
  485. // Synopsis: Maps DBID to column ordinal.
  486. //
  487. // Arguments: [cColumnIDs] -- Count of elements in [rgColumnIDs]
  488. // [rgColumnIDs] -- DBID to be mapped.
  489. // [rgColumns] -- Output column ordinals.
  490. //
  491. // History: 03-Apr-95 KyleP Created.
  492. //
  493. // Notes: No need to have Ole DB error handling here because the underlying
  494. // call provides that.
  495. //
  496. //----------------------------------------------------------------------------
  497. STDMETHODIMP CDistributedRowset::MapColumnIDs( DBORDINAL cColumnIDs,
  498. DBID const rgColumnIDs[],
  499. DBORDINAL rgColumns[] )
  500. {
  501. _DBErrorObj.ClearErrorInfo();
  502. IColumnsInfo * pci = 0;
  503. SCODE sc = _aChild[0]->QueryInterface( IID_IColumnsInfo, (void **) &pci );
  504. if ( SUCCEEDED(sc) )
  505. {
  506. sc = pci->MapColumnIDs( cColumnIDs, rgColumnIDs, rgColumns );
  507. pci->Release();
  508. }
  509. ULONG iMaxColOrdinal = _cColumns;
  510. if ( -1 != _iColumnBookmark )
  511. {
  512. iMaxColOrdinal--;
  513. }
  514. //
  515. // Be sure none of the potentially added columns was returned.
  516. //
  517. unsigned cErrors = 0;
  518. if ( SUCCEEDED(sc) )
  519. {
  520. for (unsigned i=0; i<cColumnIDs; i++)
  521. {
  522. if (DB_INVALIDCOLUMN == rgColumns[i])
  523. {
  524. cErrors++;
  525. }
  526. else if ( rgColumns[i] > iMaxColOrdinal )
  527. {
  528. rgColumns[i] = DB_INVALIDCOLUMN;
  529. cErrors++;
  530. }
  531. }
  532. sc = cErrors == 0 ? S_OK :
  533. (cErrors != cColumnIDs) ? DB_S_ERRORSOCCURRED :
  534. DB_E_ERRORSOCCURRED;
  535. }
  536. if (FAILED(sc))
  537. _DBErrorObj.PostHResult(sc, IID_IColumnsInfo);
  538. return sc;
  539. }
  540. //+---------------------------------------------------------------------------
  541. //
  542. // Member: CDistributedRowset::ReleaseAccessor, public
  543. //
  544. // Synopsis: Releases accessor(s)
  545. //
  546. // Arguments: [hAccessor] -- Handle of accessor,
  547. // [pcRefCount] -- Ptr to ref count.
  548. //
  549. // History: 28-Mar-95 KyleP Created.
  550. // 22-Apr-97 EmilyB Changed to use accessorbag _aAccessors
  551. //
  552. // Notes: Need to have Ole DB error handling here because the underlying call
  553. // doesn't provide that.
  554. //
  555. //----------------------------------------------------------------------------
  556. STDMETHODIMP CDistributedRowset::ReleaseAccessor( HACCESSOR hAccessor,
  557. ULONG * pcRefCount)
  558. {
  559. _DBErrorObj.ClearErrorInfo();
  560. SCODE sc = S_OK;
  561. TRY
  562. {
  563. CLock lock( _mutex );
  564. _aAccessors.Release(hAccessor, pcRefCount);
  565. }
  566. CATCH(CException, e)
  567. {
  568. vqDebugOut((DEB_ERROR, "CDistributedRowset::ReleaseAccessor caught exception 0x%x\n",
  569. e.GetErrorCode()) );
  570. // The reason we have an exception here is 'cos the accessor is invalid
  571. sc = DB_E_BADACCESSORHANDLE;
  572. }
  573. END_CATCH
  574. if (FAILED(sc))
  575. _DBErrorObj.PostHResult(sc, IID_IAccessor);
  576. return sc;
  577. }
  578. //+---------------------------------------------------------------------------
  579. //
  580. // Member: CDistributedRowset::AddRefAccessor, public
  581. //
  582. // Synopsis: AddRef accessor(s)
  583. //
  584. // Arguments: [hAccessor] -- Handle of accessor,
  585. // [pcRefCount] -- Ptr to ref count.
  586. //
  587. // History: 16-Jan-97 KrishnaN Created.
  588. // 22-Apr-97 EmilyB Changed to use accessorbag
  589. // _aAccessors
  590. // Notes: Need to have Ole DB error handling here because the underlying call
  591. // doesn't provide that.
  592. //
  593. //----------------------------------------------------------------------------
  594. STDMETHODIMP CDistributedRowset::AddRefAccessor( HACCESSOR hAccessor,
  595. ULONG * pcRefCount)
  596. {
  597. _DBErrorObj.ClearErrorInfo();
  598. SCODE sc = S_OK;
  599. TRY
  600. {
  601. CLock lock( _mutex );
  602. _aAccessors.AddRef(hAccessor, pcRefCount);
  603. }
  604. CATCH(CException, e)
  605. {
  606. vqDebugOut((DEB_ERROR, "CDistributedRowset::AddRefAccessor caught exception 0x%x\n",
  607. e.GetErrorCode()) );
  608. // The reason we have an exception here is 'cos the accessor is invalid.
  609. sc = DB_E_BADACCESSORHANDLE;
  610. }
  611. END_CATCH;
  612. if (FAILED(sc))
  613. _DBErrorObj.PostHResult(sc, IID_IAccessor);
  614. return sc;
  615. }
  616. //+---------------------------------------------------------------------------
  617. //
  618. // Member: CDistributedRowset::ReleaseChapter, public
  619. //
  620. // Synopsis: Release chapter.
  621. //
  622. // Arguments: [hChapter] -- Chapter
  623. //
  624. // History: 03-Apr-95 KyleP Created.
  625. //
  626. //----------------------------------------------------------------------------
  627. STDMETHODIMP CDistributedRowset::ReleaseChapter( HCHAPTER hChapter )
  628. {
  629. _DBErrorObj.ClearErrorInfo();
  630. // NTRAID#DB-NTBUG9-84041-2000/07/31-dlee Distributed queries don't supported hierarcical rowsets
  631. // Currently there is no support for chapters.
  632. Win4Assert( !"CDistributedRowset::ReleaseChapter not yet implemented" );
  633. return _DBErrorObj.PostHResult(E_NOTIMPL, IID_IRowset);
  634. }
  635. //+---------------------------------------------------------------------------
  636. //
  637. // Member: CDistributedRowset::RestartPosition, public
  638. //
  639. // Synopsis: Reset cursor for GetNextRows
  640. //
  641. // Arguments: [hChapter] -- Chapter
  642. //
  643. // History: 16 Jun 95 AlanW Created.
  644. //
  645. // Notes: NO need to have Ole DB error handling here because the underlying
  646. // call provides that.
  647. //
  648. //----------------------------------------------------------------------------
  649. STDMETHODIMP CDistributedRowset::RestartPosition( HCHAPTER hChapter )
  650. {
  651. SCODE sc = S_OK;
  652. BOOL fNotified = FALSE;
  653. TRY
  654. {
  655. _iCurrentRow = 0;
  656. if ( !_xChildNotify.IsNull() )
  657. {
  658. sc = _xChildNotify->OnRowsetChange( DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  659. DBEVENTPHASE_OKTODO,
  660. FALSE );
  661. if ( S_FALSE == sc )
  662. THROW(CException(DB_E_CANCELED));
  663. fNotified = TRUE;
  664. }
  665. for ( unsigned i = 0; i < _cChild; i++ )
  666. {
  667. sc = _aChild[i]->RestartPosition( hChapter);
  668. if ( FAILED(sc) )
  669. {
  670. vqDebugOut(( DEB_ERROR, "IRowset::RestartPosition returned 0x%x\n", sc ));
  671. break;
  672. }
  673. }
  674. if ( fNotified )
  675. {
  676. _xChildNotify->OnRowsetChange( DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  677. DBEVENTPHASE_DIDEVENT,
  678. TRUE );
  679. }
  680. }
  681. CATCH( CException, e )
  682. {
  683. sc = e.GetErrorCode();
  684. }
  685. END_CATCH
  686. if ( fNotified && FAILED(sc) )
  687. {
  688. _xChildNotify->OnRowsetChange( DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  689. DBEVENTPHASE_FAILEDTODO,
  690. TRUE );
  691. }
  692. return sc;
  693. }
  694. //+---------------------------------------------------------------------------
  695. //
  696. // Member: CDistributedRowset::AddRefRows, public
  697. //
  698. // Synopsis: Incs ref. count on row(s)
  699. //
  700. // Arguments: [cRows] -- Number of HROWs in rghRows.
  701. // [rghRows] -- Rows to be refcounted.
  702. // [pcRefCounted] -- Count of rows *successfully* refcounted.
  703. // [rgRefCounts] -- Remaining refcounts on HROWs.
  704. //
  705. // History: 10-Apr-95 KyleP Created.
  706. //
  707. // Notes: Need to have Ole DB error handling here because the underlying
  708. // errors are being translated.
  709. //
  710. //----------------------------------------------------------------------------
  711. STDMETHODIMP CDistributedRowset::AddRefRows( DBCOUNTITEM cRows,
  712. const HROW rghRows[],
  713. DBREFCOUNT rgRefCounts[],
  714. DBROWSTATUS rgRowStatus[] )
  715. {
  716. _DBErrorObj.ClearErrorInfo();
  717. SCODE sc = S_OK;
  718. ULONG cRefCounted, cSuccessfullyRefCounted;
  719. if (cRows > 0 && 0 == rghRows)
  720. {
  721. vqDebugOut((DEB_IERROR, "CDistributedRowset::AddRefRows: Invalid Argument(s)\n"));
  722. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IRowset);
  723. }
  724. TRY
  725. {
  726. for ( cRefCounted = cSuccessfullyRefCounted = 0; cRefCounted < cRows; cRefCounted++ )
  727. {
  728. HROW hrowChild;
  729. int iChild = _RowManager.GetChildAndHROW( rghRows[cRefCounted], hrowChild );
  730. sc = _aChild[iChild]->AddRefRows( 1,
  731. &hrowChild,
  732. 0,
  733. (0 == rgRefCounts) ? 0 : &rgRefCounts[cRefCounted] );
  734. if ( FAILED(sc) )
  735. {
  736. vqDebugOut(( DEB_ERROR, "IRowset::AddRefRows returned 0x%x\n", sc ));
  737. continue;
  738. }
  739. _RowManager.AddRef( rghRows[cRefCounted] );
  740. cSuccessfullyRefCounted++;
  741. }
  742. if ( 0 != rgRefCounts )
  743. rgRefCounts[0] = cRefCounted;
  744. }
  745. CATCH( CException, e )
  746. {
  747. sc = e.GetErrorCode();
  748. vqDebugOut(( DEB_ERROR, "CDistributedRowset::AddRefRows -- caught 0x%x\n", sc ));
  749. }
  750. END_CATCH
  751. // if we see an error other than DB_E_ERRORSOCCURRED, pass it straight through
  752. if (FAILED(sc) && sc != DB_E_ERRORSOCCURRED)
  753. return _DBErrorObj.PostHResult(sc, IID_IRowset);
  754. if (cSuccessfullyRefCounted == cRefCounted)
  755. return S_OK;
  756. if (cSuccessfullyRefCounted > 0)
  757. sc = DB_S_ERRORSOCCURRED;
  758. else
  759. sc = DB_E_ERRORSOCCURRED;
  760. return _DBErrorObj.PostHResult(sc, IID_IRowset);
  761. }
  762. //+---------------------------------------------------------------------------
  763. //
  764. // Member: CDistributedRowset::ReleaseRows, public
  765. //
  766. // Synopsis: Releases row(s)
  767. //
  768. // Arguments: [cRows] -- Number of HROWs in rghRows.
  769. // [rghRows] -- Rows to be released.
  770. // [rgRowOptions]-- row options
  771. // [rgRefCounts] -- Remaining refcounts on HROWs.
  772. // [rgRowStatus] -- Status values.
  773. //
  774. // History: 10-Apr-95 KyleP Created.
  775. // 30-Jan-97 KrishnaN Modified to conform with 1.0 spec
  776. //
  777. // Notes: Need to have Ole DB error handling here because the underlying
  778. // errors are being translated.
  779. //
  780. //----------------------------------------------------------------------------
  781. STDMETHODIMP CDistributedRowset::ReleaseRows( DBCOUNTITEM cRows,
  782. const HROW rghRows[],
  783. DBROWOPTIONS rgRowOptions[],
  784. DBREFCOUNT rgRefCounts[],
  785. DBROWSTATUS rgRowStatus[])
  786. {
  787. _DBErrorObj.ClearErrorInfo();
  788. SCODE sc = S_OK;
  789. ULONG cReleased, cSuccessfullyReleased;
  790. DBROWSTATUS rowStatus;
  791. TRY
  792. {
  793. BOOL fNotify = FALSE;
  794. ULONG * pRefCounts = rgRefCounts;
  795. DBROWSTATUS * pRowStatus = rgRowStatus;
  796. XArray<ULONG> xrgRefCounts;
  797. XArray<DBROWSTATUS> xrgRowStatus;
  798. if ( !_xChildNotify.IsNull() )
  799. {
  800. fNotify = TRUE;
  801. if ( 0 == pRefCounts )
  802. {
  803. xrgRefCounts.Init( (unsigned) cRows );
  804. pRefCounts = xrgRefCounts.GetPointer();
  805. }
  806. if ( 0 == pRowStatus )
  807. {
  808. xrgRowStatus.Init( (unsigned) cRows );
  809. pRowStatus = xrgRowStatus.GetPointer();
  810. }
  811. }
  812. for ( cReleased = cSuccessfullyReleased = 0; cReleased < cRows; cReleased++ )
  813. {
  814. HROW hrowChild;
  815. Win4Assert( DB_NULL_HROW != rghRows[cReleased] );
  816. if ( DB_NULL_HROW != rghRows[cReleased] )
  817. {
  818. int iChild = _RowManager.GetChildAndHROW( rghRows[cReleased], hrowChild );
  819. sc = _aChild[iChild]->ReleaseRows( 1,
  820. &hrowChild,
  821. (0 == rgRowOptions) ? 0 : &rgRowOptions[cReleased],
  822. (0 == rgRefCounts) ? 0 : &rgRefCounts[cReleased],
  823. &rowStatus
  824. );
  825. }
  826. // At this time, there is no need to translate the error returned by the child.
  827. if (rgRowStatus)
  828. rgRowStatus[cReleased] = rowStatus;
  829. if ( FAILED(sc) )
  830. {
  831. vqDebugOut(( DEB_ERROR, "IRowset::ReleaseRows returned 0x%x\n", sc ));
  832. continue;
  833. }
  834. if ( DB_NULL_HROW != rghRows[cReleased] )
  835. _RowManager.Release( rghRows[cReleased] );
  836. cSuccessfullyReleased++;
  837. }
  838. if ( fNotify )
  839. {
  840. ULONG cRowsToNotify = 0;
  841. for (ULONG i=0; i<cRows; i++)
  842. if ( 0 == pRefCounts[i] && DBROWSTATUS_S_OK == pRowStatus[i] )
  843. cRowsToNotify++;
  844. if (cRowsToNotify)
  845. {
  846. XGrowable<HROW,20> xrghRows(cRowsToNotify);
  847. for (cRowsToNotify=0, i=0; i<cRows; i++)
  848. if ( 0 == pRefCounts[i] && DBROWSTATUS_S_OK == pRowStatus[i] )
  849. {
  850. xrghRows[cRowsToNotify] = rghRows[i];
  851. cRowsToNotify++;
  852. }
  853. _xChildNotify->OnRowChange( cRowsToNotify,
  854. xrghRows.Get(),
  855. DBREASON_ROW_RELEASE,
  856. DBEVENTPHASE_DIDEVENT,
  857. TRUE);
  858. }
  859. }
  860. }
  861. CATCH( CException, e )
  862. {
  863. sc = e.GetErrorCode();
  864. vqDebugOut(( DEB_ERROR, "CDistributedRowset::ReleaseRows -- caught 0x%x\n", sc ));
  865. }
  866. END_CATCH
  867. // if we see an error other than DB_E_ERRORSOCCURRED, pass it straight through
  868. if (FAILED(sc) && sc != DB_E_ERRORSOCCURRED)
  869. return _DBErrorObj.PostHResult(sc, IID_IRowset);
  870. if (cSuccessfullyReleased == cReleased)
  871. return S_OK;
  872. else if (cSuccessfullyReleased > 0)
  873. sc = DB_S_ERRORSOCCURRED;
  874. else
  875. sc = DB_E_ERRORSOCCURRED;
  876. return _DBErrorObj.PostHResult(sc, IID_IRowset);
  877. }
  878. //
  879. // IColumnsInfo methods
  880. //
  881. //+---------------------------------------------------------------------------
  882. //
  883. // Function: IsEqual, private
  884. //
  885. // Arguments: [col1] -- First DBID
  886. // [col2] -- Second DBID
  887. //
  888. // Returns: TRUE if col1 == col2
  889. //
  890. // History: 03-Apr-95 KyleP Created.
  891. //
  892. //----------------------------------------------------------------------------
  893. BOOL IsEqual( DBID const & col1, DBID const & col2 )
  894. {
  895. if ( col1.eKind != col2.eKind )
  896. return( FALSE );
  897. switch ( col1.eKind )
  898. {
  899. case DBKIND_GUID_PROPID:
  900. return ( col1.uGuid.guid == col2.uGuid.guid &&
  901. col1.uName.ulPropid == col2.uName.ulPropid );
  902. case DBKIND_GUID_NAME:
  903. return( col1.uGuid.guid == col2.uGuid.guid &&
  904. _wcsicmp( col1.uName.pwszName, col2.uName.pwszName ) == 0);
  905. case DBKIND_NAME:
  906. return( _wcsicmp( col1.uName.pwszName, col2.uName.pwszName ) == 0 );
  907. case DBKIND_PGUID_PROPID:
  908. return ( *col1.uGuid.pguid == *col2.uGuid.pguid &&
  909. col1.uName.ulPropid == col2.uName.ulPropid );
  910. case DBKIND_PGUID_NAME:
  911. return( *col1.uGuid.pguid == *col2.uGuid.pguid &&
  912. _wcsicmp( col1.uName.pwszName, col2.uName.pwszName ) == 0 );
  913. default:
  914. Win4Assert( !"Unknown eKind" );
  915. return( FALSE );
  916. }
  917. Win4Assert( !"How did we get here?" );
  918. return( TRUE );
  919. }
  920. //+---------------------------------------------------------------------------
  921. //
  922. // Member: CDistributedRowset::_GetFullColumnInfo, protected
  923. //
  924. // Synopsis: Returns basic info about columns in table.
  925. //
  926. // Arguments: [pcColumns] -- Count returned here.
  927. // [ppColInfo] -- Array of column descriptors returned here.
  928. // [ppwchInfo] -- Pointer to storage for all string values.
  929. //
  930. // History: 02-Mar-95 KyleP Created.
  931. // 24-Jan-97 KrishnaN Modified to conform to 1.0 spec
  932. //
  933. // Notes: Since each child cursor was given the same initial query,
  934. // we know all the columnid and column ordinals must be the
  935. // same. Other fields will vary, and will need to be set
  936. // to the most relaxed value from any child cursor.
  937. //
  938. // Need to have Ole DB error handling here because the underlying
  939. // errors are being translated.
  940. //
  941. // This implementation returns all the columns including the columns
  942. // that we added for sorting. The client will always call
  943. // GetColumnInfo, which trims out these extra columns
  944. //
  945. //----------------------------------------------------------------------------
  946. STDMETHODIMP CDistributedRowset::_GetFullColumnInfo( DBORDINAL * pcColumns,
  947. DBCOLUMNINFO ** ppColInfo,
  948. WCHAR ** ppwchInfo)
  949. {
  950. _DBErrorObj.ClearErrorInfo();
  951. if (0 == pcColumns || 0 == ppColInfo || 0 == ppwchInfo)
  952. {
  953. vqDebugOut((DEB_IERROR, "CDistributedRowset::GetColumnInfo: Invalid Argument(s)\n"));
  954. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IColumnsInfo);
  955. }
  956. SCODE sc = S_OK;
  957. //
  958. // Get rid of cached copy, if any.
  959. //
  960. if ( 0 != _aColInfo )
  961. {
  962. *pcColumns = _cColInfo;
  963. *ppColInfo = _aColInfo;
  964. *ppwchInfo = _awchInfo;
  965. _aColInfo = 0;
  966. _awchInfo = 0;
  967. }
  968. else
  969. {
  970. *ppColInfo = 0;
  971. *ppwchInfo = 0;
  972. *pcColumns = 0;
  973. TRY
  974. {
  975. //
  976. // Fetch from first child. We'll use this allocation for return, and
  977. // modify fields as needed.
  978. //
  979. IColumnsInfo * pci = 0;
  980. sc = _aChild[0]->QueryInterface( IID_IColumnsInfo, (void **) &pci );
  981. if ( FAILED(sc) )
  982. {
  983. vqDebugOut(( DEB_ERROR, "CDistributedRowset: QI to IColumnsInfo returned 0x%x\n", sc ));
  984. THROW( CException(sc) );
  985. }
  986. XInterface<IColumnsInfo> pColInfo(pci);
  987. DBCOLUMNINFO * paColTemp;
  988. WCHAR * pwchTemp;
  989. sc = pColInfo->GetColumnInfo( pcColumns, &paColTemp, &pwchTemp );
  990. XCoMem<DBCOLUMNINFO> pBaseline(paColTemp);
  991. XCoMem<WCHAR> pBaseStr(pwchTemp);
  992. if ( FAILED(sc) )
  993. {
  994. vqDebugOut(( DEB_ERROR, "IColumnsInfo::GetColumnInfo returned 0x%x\n", sc ));
  995. THROW( CException(sc) );
  996. }
  997. //
  998. // Now go through remaining cursors and adjust values. The same
  999. // columns must be in the same ordinal positions, but some values
  1000. // (ex: cbMaxLength) may differ between providers.
  1001. //
  1002. // Any string data is just taken from the first returned value.
  1003. //
  1004. for ( unsigned i = 1; i < _cChild; i++ )
  1005. {
  1006. sc = _aChild[i]->QueryInterface( IID_IColumnsInfo, (void **) &pci );
  1007. if ( FAILED(sc) )
  1008. {
  1009. vqDebugOut(( DEB_ERROR, "CDistributedRowset: QI to IColumnsInfo returned 0x%x\n", sc ));
  1010. THROW( CException(sc) );
  1011. }
  1012. XInterface<IColumnsInfo> pColInfo(pci);
  1013. DBCOLUMNINFO * pTempCols = 0;
  1014. WCHAR * pwchTemp2 = 0;
  1015. DBORDINAL cCols;
  1016. sc = pColInfo->GetColumnInfo( &cCols, &pTempCols, &pwchTemp2 );
  1017. if ( FAILED(sc) )
  1018. {
  1019. vqDebugOut(( DEB_ERROR, "IColumnsInfo::GetColumnInfo returned 0x%x\n", sc ));
  1020. THROW( CException(sc) );
  1021. }
  1022. XCoMem<DBCOLUMNINFO> pCols( pTempCols );
  1023. XCoMem<WCHAR> pStr( pwchTemp2 );
  1024. if ( cCols != *pcColumns )
  1025. {
  1026. Win4Assert( cCols == *pcColumns );
  1027. THROW( CException( E_FAIL ) );
  1028. }
  1029. //
  1030. // Review all columns.
  1031. //
  1032. for ( unsigned j = 0; j < cCols; j++ )
  1033. {
  1034. //
  1035. // DBID has to match.
  1036. //
  1037. if ( !IsEqual( pBaseline[j].columnid, pCols[j].columnid ) )
  1038. {
  1039. Win4Assert( !"Mismatched columns" );
  1040. THROW( CException( E_FAIL ) );
  1041. }
  1042. //
  1043. // pwszName should be returned if all names are the same.
  1044. //
  1045. if ( 0 != pBaseline[j].pwszName && 0 != pCols[j].pwszName &&
  1046. wcscmp( pBaseline[j].pwszName, pCols[j].pwszName ) != 0 )
  1047. pBaseline[j].pwszName = 0;
  1048. //
  1049. // iOrdinal must match.
  1050. //
  1051. if ( pBaseline[j].iOrdinal != pCols[j].iOrdinal )
  1052. {
  1053. Win4Assert( !"Mismatched columns" );
  1054. THROW( CException( E_FAIL ) );
  1055. }
  1056. //
  1057. // If dwType doesn't match, we go to DBTYPE_VARIANT
  1058. //
  1059. if ( pBaseline[j].wType != pCols[j].wType )
  1060. pBaseline[j].wType = DBTYPE_VARIANT;
  1061. //
  1062. // Take the maximum cbMaxLength, except for bookmark where we sum
  1063. // the lengths.
  1064. //
  1065. Win4Assert( 0 == (pBaseline[j].dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) ||
  1066. ( pBaseline[j].ulColumnSize == pCols[j].ulColumnSize &&
  1067. pBaseline[j].dwFlags & DBCOLUMNFLAGS_ISFIXEDLENGTH ) );
  1068. if ( pBaseline[j].dwFlags & DBCOLUMNFLAGS_ISBOOKMARK && i == (_cChild - 1) )
  1069. {
  1070. //
  1071. // Last pass through, add room for child id and give room
  1072. // to store ulColumnSize for *each* child.
  1073. //
  1074. pBaseline[j].ulColumnSize *= _cChild;
  1075. pBaseline[j].ulColumnSize += sizeof(ULONG);
  1076. }
  1077. else
  1078. if ( pBaseline[j].ulColumnSize < pCols[j].ulColumnSize )
  1079. pBaseline[j].ulColumnSize = pCols[j].ulColumnSize;
  1080. if ( pBaseline[j].wType == DBTYPE_NUMERIC )
  1081. {
  1082. //
  1083. // Precision and scale have to match?
  1084. //
  1085. if ( pBaseline[j].bPrecision != pCols[j].bPrecision ||
  1086. pBaseline[j].bScale != pCols[j].bScale )
  1087. {
  1088. Win4Assert( !"Mismatched columns" );
  1089. THROW( CException( E_FAIL ) );
  1090. }
  1091. }
  1092. //
  1093. // All the conditions in dwFlags are positive (e.g. IsXXX), so the
  1094. // final flag is the bitwise and of all children.
  1095. //
  1096. #if CIDBG == 1
  1097. if ( pBaseline[j].dwFlags != pCols[j].dwFlags )
  1098. {
  1099. vqDebugOut(( DEB_WARN,
  1100. "GetColumnInfo: Mismatched dwFlags 0x%x, 0x%x\n",
  1101. pBaseline[j].dwFlags, pCols[j].dwFlags ));
  1102. }
  1103. #endif // CIDBG == 1
  1104. pBaseline[j].dwFlags &= pCols[j].dwFlags;
  1105. } // for each column
  1106. } // for each cursor
  1107. *ppColInfo = pBaseline.Acquire(); // Allow memory to pass back to client.
  1108. *ppwchInfo = pBaseStr.Acquire();
  1109. }
  1110. CATCH( CException, e )
  1111. {
  1112. sc = e.GetErrorCode();
  1113. if ( sc != E_INVALIDARG && sc != E_OUTOFMEMORY )
  1114. {
  1115. vqDebugOut(( DEB_ERROR, "CDistributedRowset::GetColumnInfo: bogus error code 0x%x\n", sc ));
  1116. sc = E_FAIL;
  1117. }
  1118. }
  1119. END_CATCH
  1120. }
  1121. if (FAILED(sc))
  1122. _DBErrorObj.PostHResult(sc, IID_IColumnsInfo);
  1123. return( sc );
  1124. }
  1125. //+---------------------------------------------------------------------------
  1126. //
  1127. // Member: CDistributedRowset::GetColumnInfo, public
  1128. //
  1129. // Synopsis: Returns basic info about columns in table.
  1130. //
  1131. // Arguments: [pcColumns] -- Count returned here.
  1132. // [ppColInfo] -- Array of column descriptors returned here.
  1133. // [ppwchInfo] -- Pointer to storage for all string values.
  1134. //
  1135. // History: 27-Sep-98 VikasMan Created
  1136. //
  1137. // Notes: Calls _GetFullColumnInfo and then trims out the extra columns
  1138. // that we added for sorting
  1139. //
  1140. //----------------------------------------------------------------------------
  1141. STDMETHODIMP CDistributedRowset::GetColumnInfo( DBORDINAL * pcColumns,
  1142. DBCOLUMNINFO ** ppColInfo,
  1143. WCHAR ** ppwchInfo)
  1144. {
  1145. SCODE sc = _GetFullColumnInfo( pcColumns, ppColInfo, ppwchInfo );
  1146. if ( SUCCEEDED( sc ) && pcColumns && *pcColumns )
  1147. {
  1148. if ( *pcColumns < _cColumns )
  1149. return E_INVALIDARG;
  1150. Win4Assert( *pcColumns >= _cColumns );
  1151. *pcColumns = _cColumns;
  1152. }
  1153. return( sc );
  1154. }
  1155. //
  1156. // IRowsetIdentity methods
  1157. //
  1158. //+---------------------------------------------------------------------------
  1159. //
  1160. // Member: CDistributedRowset::IsSameRow, public
  1161. //
  1162. // Arguments: [hThisRow] -- First row.
  1163. // [hThatRow] -- Second row.
  1164. //
  1165. // Returns: S_OK if the rows are the same, else S_FALSE.
  1166. //
  1167. // History: 02-Mar-95 KyleP Created.
  1168. //
  1169. // Notes: Assumes child rowset(s) support DBROWSETFLAGS_TRUEIDENTITY.
  1170. //
  1171. // Notes: Need to have Ole DB error handling here because the underlying
  1172. // errors are being translated.
  1173. //----------------------------------------------------------------------------
  1174. STDMETHODIMP CDistributedRowset::IsSameRow( HROW hThisRow, HROW hThatRow )
  1175. {
  1176. _DBErrorObj.ClearErrorInfo();
  1177. SCODE sc = S_OK;
  1178. TRY
  1179. {
  1180. HROW hrowChild1, hrowChild2;
  1181. int iChild1 = _RowManager.GetChildAndHROW( hThisRow, hrowChild1 );
  1182. int iChild2 = _RowManager.GetChildAndHROW( hThatRow, hrowChild2 );
  1183. if ( iChild1 == iChild2 && hrowChild1 == hrowChild2 )
  1184. sc = S_OK;
  1185. else
  1186. sc = S_FALSE;
  1187. }
  1188. CATCH( CException, e )
  1189. {
  1190. sc = e.GetErrorCode();
  1191. vqDebugOut(( DEB_ERROR, "Exception 0x%x caught in CDistributedRowset::IsSameRow\n", sc ));
  1192. }
  1193. END_CATCH
  1194. if (FAILED(sc))
  1195. _DBErrorObj.PostHResult(sc, IID_IRowsetIdentity);
  1196. return sc;
  1197. }
  1198. //+---------------------------------------------------------------------------
  1199. //
  1200. // Member: CDistributedRowset::CDistributedRowset, public
  1201. //
  1202. // Synopsis: Initialize distributed rowset.
  1203. //
  1204. // Arguments: [pUnkOuter] -- outer unknown
  1205. // [ppMyUnk] -- OUT: on return, filled with pointer to my
  1206. // non-delegating IUnknown
  1207. // [aChild] -- Array of child rowsets.
  1208. // [cChild] -- Count of [aChild].
  1209. // [Props] -- Rowset properties
  1210. // [cColumns] -- Number of original columns
  1211. // [aAccessors] -- Bag of accessors which rowsets need to inherit
  1212. //
  1213. // History: 03-Apr-95 KyleP Created.
  1214. //
  1215. // Notes: Ownership of aChild is transferred.
  1216. //
  1217. //----------------------------------------------------------------------------
  1218. CDistributedRowset::CDistributedRowset(
  1219. IUnknown * pUnkOuter,
  1220. IUnknown ** ppMyUnk,
  1221. IRowset ** aChild,
  1222. unsigned cChild,
  1223. CMRowsetProps const & Props,
  1224. unsigned cColumns,
  1225. CAccessorBag & aAccessors,
  1226. CCIOleDBError & DBErrorObj)
  1227. :
  1228. #pragma warning(disable : 4355) // 'this' in a constructor
  1229. _aAccessors( (IUnknown *) (IRowset *)this ),
  1230. _impIUnknown(this),
  1231. #pragma warning(default : 4355) // 'this' in a constructor
  1232. _aChild( aChild ),
  1233. _cChild( cChild ),
  1234. _cColumns( cColumns ),
  1235. _aColInfo( 0 ),
  1236. _awchInfo( 0 ),
  1237. _iColumnBookmark( -1 ),
  1238. _cbBookmark( 0 ),
  1239. _Props( Props ),
  1240. _DBErrorObj( DBErrorObj ),
  1241. _cMaxResults( _Props.GetMaxResults() ),
  1242. _cFirstRows( _Props.GetFirstRows() ),
  1243. _iCurrentRow( 0 )
  1244. {
  1245. // NTRAID#DB-NTBUG9-84049-2000/07/31-dlee Distributed queries need to support MaxResults for scrollable sorted rowsets
  1246. Win4Assert( _cChild > 0 );
  1247. if (pUnkOuter)
  1248. _pControllingUnknown = pUnkOuter;
  1249. else
  1250. _pControllingUnknown = (IUnknown * )&_impIUnknown;
  1251. //
  1252. // We need to get column info once in order to figure out which column (if any)
  1253. // is the bookmark column. We'll cache the column info in _aColInfo just in
  1254. // case the client also needs it.
  1255. //
  1256. SCODE sc = _GetFullColumnInfo( &_cColInfo, &_aColInfo, &_awchInfo );
  1257. if ( FAILED(sc) )
  1258. {
  1259. vqDebugOut(( DEB_ERROR,
  1260. "CDistributedRowset: Error 0x%x fetching column info\n", sc ));
  1261. THROW( CException( sc ) );
  1262. }
  1263. for ( unsigned i = 0; i < _cColInfo; i++ )
  1264. {
  1265. if ( _aColInfo[i].dwFlags & DBCOLUMNFLAGS_ISBOOKMARK )
  1266. {
  1267. _iColumnBookmark = _aColInfo[i].iOrdinal;
  1268. _cbBookmark = _aColInfo[i].ulColumnSize;
  1269. break;
  1270. }
  1271. }
  1272. //
  1273. // GetBindings for each accessor in bag, and use them to create accessor
  1274. // in IRowset
  1275. //
  1276. // only CAccessors can be used by commands
  1277. CAccessorBase * pAccBase = (CAccessorBase *)aAccessors.First();
  1278. while ( 0 != pAccBase )
  1279. {
  1280. DBCOUNTITEM cBindings;
  1281. DBBINDING * rgBindings;
  1282. DBACCESSORFLAGS dwAccessorFlags;
  1283. SCODE sc = pAccBase->GetBindings(&dwAccessorFlags, &cBindings, &rgBindings);
  1284. if (FAILED(sc))
  1285. THROW(CException(sc));
  1286. HACCESSOR hAccessor;
  1287. sc = CreateAccessor(dwAccessorFlags, cBindings, rgBindings, 0, &hAccessor, 0);
  1288. CoTaskMemFree(rgBindings); //cleanup from GetBindings
  1289. if (FAILED(sc))
  1290. THROW(CException(sc));
  1291. //
  1292. // inherited accessors are accessed through same hAccessor as original.
  1293. // Set parent of newly created accessor so that we can link the 2 copies.
  1294. // Client never knows the direct HACESSOR for the inherited accessor.
  1295. // All accessor methods check bag for an accessor with a match on
  1296. // the parent or the creator.
  1297. //
  1298. ((CAccessorBase *)hAccessor)->SetParent(pAccBase);
  1299. //
  1300. // Increment inheritor count for parent accessor
  1301. //
  1302. pAccBase->IncInheritors();
  1303. pAccBase = (CDistributedAccessor *)aAccessors.Next();
  1304. }
  1305. #if CIDBG == 1
  1306. for ( i++; i < _cColInfo; i++ )
  1307. {
  1308. Win4Assert( 0 == (_aColInfo[i].dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) );
  1309. }
  1310. #endif
  1311. *ppMyUnk = ((IUnknown *)&_impIUnknown);
  1312. (*ppMyUnk)->AddRef();
  1313. }
  1314. //+---------------------------------------------------------------------------
  1315. //
  1316. // Member: CDistributedRowset::~CDistributedRowset, public
  1317. //
  1318. // Synopsis: Destructor
  1319. //
  1320. // History: 03-Apr-95 KyleP Created.
  1321. //
  1322. //----------------------------------------------------------------------------
  1323. CDistributedRowset::~CDistributedRowset()
  1324. {
  1325. unsigned ii;
  1326. if ( !_xChildNotify.IsNull() )
  1327. {
  1328. _xChildNotify->OnRowsetChange( DBREASON_ROWSET_RELEASE,
  1329. DBEVENTPHASE_DIDEVENT,
  1330. TRUE);
  1331. }
  1332. for ( ii = _xArrChildAsynchCP.Count(); ii > 0; ii-- )
  1333. {
  1334. if ( _xArrChildAsynchCP[ii-1].GetPointer() )
  1335. {
  1336. _xArrChildAsynchCP[ii-1]->Unadvise( _xArrAsynchAdvise[ii-1] );
  1337. }
  1338. }
  1339. for ( ii = _xArrChildWatchCP.Count(); ii > 0; ii-- )
  1340. {
  1341. if ( _xArrChildWatchCP[ii-1].GetPointer() )
  1342. {
  1343. _xArrChildWatchCP[ii-1]->Unadvise( _xArrWatchAdvise[ii-1] );
  1344. }
  1345. }
  1346. _xServerCPC.Free();
  1347. if ( 0 != _aColInfo )
  1348. CoTaskMemFree( _aColInfo );
  1349. if ( 0 != _awchInfo )
  1350. CoTaskMemFree( _awchInfo );
  1351. for ( unsigned i = 0; i < _cChild; i++ )
  1352. {
  1353. if ( 0 != _aChild[i] )
  1354. _aChild[i]->Release();
  1355. }
  1356. delete [] _aChild;
  1357. }
  1358. //+---------------------------------------------------------------------------
  1359. //
  1360. // Member: CDistributedRowset::CanConvertType, public
  1361. //
  1362. // Synopsis: Gives info. on the availability of type conversions.
  1363. //
  1364. // History: 29-Jan-97 KrishnaN Created.
  1365. //
  1366. //----------------------------------------------------------------------------
  1367. STDMETHODIMP CDistributedRowset::CanConvert( DBTYPE wFromType,
  1368. DBTYPE wToType,
  1369. DBCONVERTFLAGS dwConvertFlags)
  1370. {
  1371. _DBErrorObj.ClearErrorInfo();
  1372. SCODE sc;
  1373. for (unsigned iChild = 0; iChild < _cChild; iChild++)
  1374. {
  1375. IConvertType* pIConvertType = 0;
  1376. sc = _aChild[iChild]->QueryInterface( IID_IConvertType, (void **) &pIConvertType );
  1377. if (SUCCEEDED( sc ))
  1378. {
  1379. sc = pIConvertType->CanConvert(wFromType, wToType, dwConvertFlags);
  1380. pIConvertType->Release();
  1381. }
  1382. if (sc != S_OK)
  1383. return _DBErrorObj.PostHResult(sc, IID_IConvertType);
  1384. }
  1385. return S_OK;
  1386. }
  1387. //
  1388. // Helper function used by GetStatus and GetStatusEx
  1389. //
  1390. inline void ParseQueryFillStatus( DWORD dwQueryFillStatus,
  1391. DWORD & dwError,
  1392. DWORD & dwBusy,
  1393. DWORD & dwRefresh,
  1394. DWORD & dwDone )
  1395. {
  1396. if ( STAT_ERROR == dwQueryFillStatus )
  1397. {
  1398. dwError = 1;
  1399. dwDone = 0;
  1400. }
  1401. else if ( STAT_BUSY == dwQueryFillStatus )
  1402. {
  1403. dwBusy = 1;
  1404. dwDone = 0;
  1405. }
  1406. else if ( STAT_REFRESH == dwQueryFillStatus )
  1407. {
  1408. dwRefresh = 1;
  1409. dwDone = 0;
  1410. }
  1411. else if ( STAT_DONE == dwQueryFillStatus )
  1412. {
  1413. dwDone &= 1;
  1414. }
  1415. }
  1416. //
  1417. // Helper function used by GetStatus and GetStatusEx
  1418. //
  1419. inline void SetQueryFillStatus( DWORD & dwStatus,
  1420. DWORD dwError,
  1421. DWORD dwBusy,
  1422. DWORD dwRefresh,
  1423. DWORD dwDone )
  1424. {
  1425. if ( dwError )
  1426. {
  1427. dwStatus |= STAT_ERROR;
  1428. }
  1429. else if ( dwBusy )
  1430. {
  1431. dwStatus |= STAT_BUSY;
  1432. }
  1433. else if ( dwRefresh )
  1434. {
  1435. dwStatus |= STAT_REFRESH;
  1436. }
  1437. else if ( dwDone )
  1438. {
  1439. dwStatus |= STAT_DONE;
  1440. }
  1441. }
  1442. //+---------------------------------------------------------------------------
  1443. //
  1444. // Member: CDistributedRowset::GetStatus, public
  1445. //
  1446. // Synopsis: Return query status
  1447. //
  1448. // Arguments: [pdwStatus] -- pointer to where query status is returned
  1449. //
  1450. // Returns: SCODE error code
  1451. //
  1452. //----------------------------------------------------------------------------
  1453. STDMETHODIMP CDistributedRowset::GetStatus( DWORD * pdwStatus )
  1454. {
  1455. _DBErrorObj.ClearErrorInfo();
  1456. SCODE scResult = S_OK;
  1457. if ( pdwStatus )
  1458. {
  1459. *pdwStatus = 0;
  1460. DWORD dwBusy = 0;
  1461. DWORD dwError = 0;
  1462. DWORD dwRefresh = 0;
  1463. DWORD dwDone = 1;
  1464. XInterface<IRowsetQueryStatus> xIRowsetQueryStatus;
  1465. for (unsigned iChild = 0; iChild < _cChild; iChild++)
  1466. {
  1467. scResult = _aChild[iChild]->QueryInterface( IID_IRowsetQueryStatus,
  1468. xIRowsetQueryStatus.GetQIPointer() );
  1469. DWORD dwChildStatus;
  1470. if ( SUCCEEDED( scResult ) )
  1471. scResult = xIRowsetQueryStatus->GetStatus( &dwChildStatus );
  1472. xIRowsetQueryStatus.Free();
  1473. if (scResult != S_OK)
  1474. return scResult;
  1475. // OR the query reliability status
  1476. *pdwStatus |= QUERY_RELIABILITY_STATUS(dwChildStatus);
  1477. ParseQueryFillStatus( QUERY_FILL_STATUS( dwChildStatus ),
  1478. dwError, dwBusy, dwRefresh, dwDone );
  1479. }
  1480. // Now set the QUERY_FILL_STATUS. If we have at in the following order:
  1481. // ERROR > BUSY > REFRESH > DONE
  1482. SetQueryFillStatus( *pdwStatus, dwError, dwBusy, dwRefresh, dwDone );
  1483. }
  1484. return scResult;
  1485. }
  1486. //+---------------------------------------------------------------------------
  1487. //
  1488. // Member: CDistributedRowset::GetStatusEx, public
  1489. //
  1490. // Synopsis: Return query status
  1491. //
  1492. // Arguments: [pdwStatus] - returns query status
  1493. // [pcFilteredDocuments] - # of documents filtered
  1494. // [pcDocumentsToFilter] - # of docsuments yet to filter
  1495. // [pdwRatioFinishedDenominator] - ratio finished denominator
  1496. // [pdwRatioFinishedNumerator] - ratio finished numerator
  1497. // [cbBmk] - # of bytes in pBmk
  1498. // [pBmk] - bookmark for piRowBmk
  1499. // [piRowBmk] - returns index of bookmark in table
  1500. // [pcRowsTotal] - current # of rows in table
  1501. //
  1502. // Returns: SCODE error code
  1503. //
  1504. //----------------------------------------------------------------------------
  1505. STDMETHODIMP CDistributedRowset::GetStatusEx(
  1506. DWORD * pdwStatus,
  1507. DWORD * pcFilteredDocuments,
  1508. DWORD * pcDocumentsToFilter,
  1509. DBCOUNTITEM * pdwRatioFinishedDenominator,
  1510. DBCOUNTITEM * pdwRatioFinishedNumerator,
  1511. DBBKMARK cbBmk,
  1512. const BYTE * pBmk,
  1513. DBCOUNTITEM * piRowBmk,
  1514. DBCOUNTITEM * pcRowsTotal )
  1515. {
  1516. _DBErrorObj.ClearErrorInfo();
  1517. SCODE scResult = S_OK;
  1518. if ( pdwStatus )
  1519. *pdwStatus = 0;
  1520. if ( pcFilteredDocuments )
  1521. *pcFilteredDocuments = 0;
  1522. *pcDocumentsToFilter = 0;
  1523. if ( pdwRatioFinishedDenominator )
  1524. *pdwRatioFinishedDenominator = 0;
  1525. if ( pdwRatioFinishedNumerator )
  1526. *pdwRatioFinishedNumerator = 0;
  1527. if ( piRowBmk )
  1528. *piRowBmk = 0;
  1529. if ( pcRowsTotal )
  1530. *pcRowsTotal = 0;
  1531. DWORD dwBusy = 0;
  1532. DWORD dwError = 0;
  1533. DWORD dwRefresh = 0;
  1534. DWORD dwDone = 1;
  1535. ULONG iBmkCursor = 0;
  1536. BYTE const * pChildBmk = NULL;
  1537. // Parse bookmark
  1538. if ( cbBmk != 0 )
  1539. {
  1540. iBmkCursor = *( (ULONG*)pBmk );
  1541. pChildBmk = pBmk + sizeof( ULONG ) + ( iBmkCursor * sizeof( ULONG ) );
  1542. cbBmk = sizeof( ULONG );
  1543. }
  1544. double dRatio = 0;
  1545. XInterface<IRowsetQueryStatus> xIRowsetQueryStatus;
  1546. for (unsigned iChild = 0; iChild < _cChild; iChild++)
  1547. {
  1548. scResult = _aChild[iChild]->QueryInterface( IID_IRowsetQueryStatus,
  1549. xIRowsetQueryStatus.GetQIPointer() );
  1550. DWORD dwChildStatus;
  1551. DWORD cFilteredDocuments;
  1552. DWORD cDocumentsToFilter;
  1553. DBCOUNTITEM dwRatioFinishedDenominator;
  1554. DBCOUNTITEM dwRatioFinishedNumerator;
  1555. DBCOUNTITEM iRowBmk;
  1556. DBCOUNTITEM cRowsTotal;
  1557. if ( SUCCEEDED( scResult ) )
  1558. {
  1559. scResult = xIRowsetQueryStatus->GetStatusEx( &dwChildStatus,
  1560. &cFilteredDocuments,
  1561. &cDocumentsToFilter,
  1562. &dwRatioFinishedDenominator,
  1563. &dwRatioFinishedNumerator,
  1564. ( cbBmk > 0 && iBmkCursor == iChild ) ?
  1565. cbBmk : 0,
  1566. ( cbBmk > 0 && iBmkCursor == iChild ) ?
  1567. pChildBmk : 0,
  1568. &iRowBmk,
  1569. &cRowsTotal );
  1570. }
  1571. xIRowsetQueryStatus.Free();
  1572. if (scResult != S_OK)
  1573. {
  1574. return scResult;
  1575. }
  1576. // OR the query reliability status
  1577. if ( pdwStatus )
  1578. {
  1579. *pdwStatus |= QUERY_RELIABILITY_STATUS(dwChildStatus);
  1580. }
  1581. ParseQueryFillStatus( QUERY_FILL_STATUS( dwChildStatus ),
  1582. dwError, dwBusy, dwRefresh, dwDone );
  1583. if ( pcFilteredDocuments )
  1584. *pcFilteredDocuments += cFilteredDocuments;
  1585. if ( pcDocumentsToFilter )
  1586. *pcDocumentsToFilter += cDocumentsToFilter;
  1587. if ( dwRatioFinishedDenominator )
  1588. {
  1589. dRatio += ( (double)dwRatioFinishedNumerator / (double)dwRatioFinishedDenominator );
  1590. }
  1591. if ( pcRowsTotal )
  1592. *pcRowsTotal += cRowsTotal;
  1593. }
  1594. DWORD dwNum = 0;
  1595. DWORD dwDen = 0;
  1596. if ( dRatio )
  1597. {
  1598. Win4Assert( _cChild );
  1599. dRatio /= _cChild;
  1600. dwDen = 1;
  1601. while ( dRatio < 1.0 )
  1602. {
  1603. dRatio *= 10;
  1604. dwDen *= 10;
  1605. }
  1606. dwNum = (DWORD)dRatio;
  1607. }
  1608. if ( pdwRatioFinishedDenominator )
  1609. *pdwRatioFinishedDenominator = dwNum;
  1610. if ( pdwRatioFinishedNumerator )
  1611. *pdwRatioFinishedNumerator = dwDen;
  1612. // Now set the QUERY_FILL_STATUS. If we have at in the following order:
  1613. // ERROR > BUSY > REFRESH > DONE
  1614. if ( pdwStatus )
  1615. SetQueryFillStatus( *pdwStatus, dwError, dwBusy, dwRefresh, dwDone );
  1616. return scResult;
  1617. }
  1618. //+---------------------------------------------------------------------------
  1619. //
  1620. // Member: CDistributedRowset::_SetupChildNotifications, private
  1621. //
  1622. // Synopsis: Set up connection points to receive notifications from the
  1623. // child rowsets
  1624. //
  1625. // Arguments: fAsynchOnly - TRUE if Asynch only,
  1626. // FLASE if Asynch and Watchable
  1627. //
  1628. // Returns: void
  1629. //
  1630. // History: 03 Sep 1998 VikasMan Created
  1631. //
  1632. //----------------------------------------------------------------------------
  1633. void CDistributedRowset::_SetupChildNotifications( BOOL fAsynchOnly )
  1634. {
  1635. SCODE sc;
  1636. XInterface<IConnectionPointContainer> xChildCPC;
  1637. // various arrays for the child rowsets
  1638. _xArrAsynchAdvise.Init( _cChild );
  1639. _xArrChildAsynchCP.Init( _cChild );
  1640. if ( !fAsynchOnly )
  1641. {
  1642. _xArrWatchAdvise.Init( _cChild );
  1643. _xArrChildWatchCP.Init( _cChild );
  1644. }
  1645. _xArrChildRowsetWatchRegion.Init( _cChild );
  1646. for (unsigned iChild = 0; iChild < _cChild; iChild++)
  1647. {
  1648. sc = _aChild[iChild]->QueryInterface( IID_IConnectionPointContainer,
  1649. xChildCPC.GetQIPointer() );
  1650. if ( SUCCEEDED( sc ) )
  1651. {
  1652. sc = xChildCPC->FindConnectionPoint( IID_IDBAsynchNotify,
  1653. (IConnectionPoint**)_xArrChildAsynchCP[iChild].GetQIPointer() );
  1654. if (SUCCEEDED(sc))
  1655. {
  1656. sc = _xArrChildAsynchCP[iChild]->Advise( (IUnknown *)(void*)(_xChildNotify.GetPointer()),
  1657. &_xArrAsynchAdvise[iChild] );
  1658. }
  1659. if ( !fAsynchOnly )
  1660. {
  1661. sc = xChildCPC->FindConnectionPoint( IID_IRowsetWatchNotify,
  1662. (IConnectionPoint**)_xArrChildWatchCP[iChild].GetQIPointer() );
  1663. if (SUCCEEDED(sc))
  1664. {
  1665. sc = _xArrChildWatchCP[iChild]->Advise( (IUnknown *)(void*)(_xChildNotify.GetPointer()),
  1666. &_xArrWatchAdvise[iChild] );
  1667. }
  1668. }
  1669. xChildCPC.Free();
  1670. _aChild[iChild]->QueryInterface( IID_IRowsetWatchRegion,
  1671. _xArrChildRowsetWatchRegion[iChild].GetQIPointer() );
  1672. }
  1673. }
  1674. }
  1675. //+---------------------------------------------------------------------------
  1676. //
  1677. // Member: CDistributedRowset::_SetupConnectionPointContainer, private
  1678. //
  1679. // Synopsis: Setups the connection point conatiner and other notification stuff
  1680. // for the distributed rowset. Handles both asynchronous ( for
  1681. // scrollable sorted rowset ) and synchronous ( for sequential rowset )
  1682. // cases.
  1683. //
  1684. // Arguments: pRowset - Rowset for which notifications are to be handled
  1685. // ppiuk - IConnectionPointContainer interface is returned here
  1686. //
  1687. // Returns: SCODE
  1688. //
  1689. // History: 22 Sep 1998 VikasMan Created
  1690. //
  1691. //----------------------------------------------------------------------------
  1692. SCODE CDistributedRowset::_SetupConnectionPointContainer( IRowset * pRowset, VOID * * ppiuk )
  1693. {
  1694. SCODE sc = S_OK;
  1695. BOOL fWatchable = (_Props.GetPropertyFlags() & eWatchable) != 0;
  1696. BOOL fAsynchronous = (_Props.GetPropertyFlags() & eAsynchronous) != 0;
  1697. if ( _xServerCPC.IsNull() )
  1698. {
  1699. TRY
  1700. {
  1701. _xServerCPC.Set( new CConnectionPointContainer(
  1702. fAsynchronous ? 3 : 1,
  1703. * ((IUnknown *) pRowset),
  1704. _DBErrorObj ) );
  1705. // Create an instance of CDistributedRowsetWatchNotify which acts as
  1706. // sink for the child rowsets and connection point for this rowset's clients
  1707. _xChildNotify.Set( new CDistributedRowsetWatchNotify( pRowset, _cChild ) );
  1708. if ( fWatchable || fAsynchronous )
  1709. {
  1710. // set up to recieve notifications from all child rowsets
  1711. _SetupChildNotifications( !fWatchable );
  1712. }
  1713. _xChildNotify->AddConnectionPoints( _xServerCPC.GetPointer(),
  1714. fAsynchronous,
  1715. fWatchable );
  1716. }
  1717. CATCH( CException, e )
  1718. {
  1719. sc = GetOleError( e );
  1720. }
  1721. END_CATCH;
  1722. }
  1723. if ( S_OK == sc )
  1724. {
  1725. Win4Assert( _xServerCPC.GetPointer() );
  1726. *ppiuk = (void *) (IConnectionPointContainer *)
  1727. _xServerCPC.GetPointer();
  1728. }
  1729. return sc;
  1730. }
  1731. //+---------------------------------------------------------------------------
  1732. //
  1733. // Member: CDistributedRowset::GetNextRows, public
  1734. //
  1735. // Synopsis: Calls _GetNextRows(which is overridden by derived classes)
  1736. // and handles notifications
  1737. //
  1738. // Arguments: [hChapter] -- Chapter
  1739. // [cRowsToSkip] -- Skip this many rows before beginning.
  1740. // [cRows] -- Try to fetch this many rows.
  1741. // [pcRowsObtained] -- Actually fetched this many.
  1742. // [pphRows] -- Store HROWs here. Allocate memory if
  1743. // [pphRows] is zero.
  1744. //
  1745. // History: 22-Sep-98 VikasMan Created.
  1746. //
  1747. //----------------------------------------------------------------------------
  1748. SCODE CDistributedRowset::GetNextRows( HCHAPTER hChapter,
  1749. DBROWOFFSET cRowsToSkip,
  1750. DBROWCOUNT cRows,
  1751. DBCOUNTITEM * pcRowsObtained,
  1752. HROW * * pphRows )
  1753. {
  1754. SCODE scResult = S_OK;
  1755. BOOL fNotified = FALSE;
  1756. TRY
  1757. {
  1758. Win4Assert( pcRowsObtained );
  1759. *pcRowsObtained = 0;
  1760. DBROWCOUNT cRowLimit = _cFirstRows > 0 ? _cFirstRows : _cMaxResults;
  1761. // check for max rows
  1762. if ( cRowLimit )
  1763. {
  1764. if ( _iCurrentRow + cRowsToSkip > cRowLimit )
  1765. {
  1766. return DB_S_ROWLIMITEXCEEDED;
  1767. }
  1768. if ( _iCurrentRow + cRowsToSkip + cRows > cRowLimit )
  1769. {
  1770. cRows = cRowLimit - (_iCurrentRow + cRowsToSkip);
  1771. if ( 0 == cRows )
  1772. {
  1773. return DB_S_ROWLIMITEXCEEDED;
  1774. }
  1775. }
  1776. }
  1777. if ( !_xChildNotify.IsNull() )
  1778. {
  1779. scResult = _xChildNotify->OnRowsetChange( DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  1780. DBEVENTPHASE_OKTODO,
  1781. FALSE);
  1782. if ( S_FALSE == scResult )
  1783. THROW(CException(DB_E_CANCELED));
  1784. fNotified = TRUE;
  1785. }
  1786. scResult = _GetNextRows( hChapter,
  1787. cRowsToSkip,
  1788. cRows,
  1789. pcRowsObtained,
  1790. pphRows );
  1791. if ( SUCCEEDED( scResult ) && *pcRowsObtained )
  1792. {
  1793. _iCurrentRow += *pcRowsObtained;
  1794. }
  1795. if ( fNotified )
  1796. {
  1797. if ( SUCCEEDED(scResult) )
  1798. {
  1799. if ( *pcRowsObtained != 0 )
  1800. {
  1801. _xChildNotify->OnRowChange( *pcRowsObtained,
  1802. *pphRows,
  1803. DBREASON_ROW_ACTIVATE,
  1804. DBEVENTPHASE_DIDEVENT,
  1805. TRUE);
  1806. }
  1807. _xChildNotify->OnRowsetChange( DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  1808. DBEVENTPHASE_DIDEVENT,
  1809. TRUE);
  1810. }
  1811. }
  1812. }
  1813. CATCH( CException, e )
  1814. {
  1815. scResult = GetOleError(e);
  1816. }
  1817. END_CATCH;
  1818. if ( fNotified && FAILED(scResult) )
  1819. {
  1820. _xChildNotify->OnRowsetChange( DBREASON_ROWSET_FETCHPOSITIONCHANGE,
  1821. DBEVENTPHASE_FAILEDTODO,
  1822. TRUE);
  1823. }
  1824. return scResult;
  1825. }