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.

2566 lines
79 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: crowset.cxx
  7. //
  8. // Contents: IRowset implementation for ADSI OLEDB provider
  9. //
  10. //--------------------------------------------------------------------------
  11. #include "oleds.hxx"
  12. //-----------------------------------------------------------------------------
  13. // Note on nomenclature
  14. //
  15. // Index - index within the rowset cache.
  16. // 0 <= (Index <= m_cNumRowsCached - 1)
  17. //
  18. // Row - index within the entire rowset (not just the cache).
  19. // 0 <= Row <= #rows in rowset - 1
  20. //
  21. // Bookmark - a unique value associated with each row. Currently, this is the
  22. // same as the row value.
  23. //
  24. // Row handle - handle to a row in the rowset cache that is returned to the
  25. // user. This value has to be unique across all rows currently in the cache
  26. // (rows that the user has a reference on). Although we could use the index
  27. // as this unique value, we will use the row (+1, since 0 == DB_NULL_HROW and
  28. // hence row 0 cannot have a handle of 0). Using the row has the advantage
  29. // that we will be able to detect stale row handles passed in by the user in
  30. // most cases. This would be more difficult with the index as the index can
  31. // be reused.
  32. //
  33. // The rowset cache contains a fixed number of rows, specified by the
  34. // DBPROP_MAXOPENROWS property (if this property is set to 0, the rowset may
  35. // contain as many rows as possble). A row remains in the cache as long as the
  36. // consumer has a reference to the row. A row is removed from the cache when
  37. // its reference count goes to 0, as a result of a call to ReleaseRows. If the
  38. // cache becomes full, subsequent calls to fetch more rows in to the cache will
  39. // return DB_S_ROWLIMITEXCEEDED. The rows in the cache need not be contiguous.
  40. // For example, the consumer might fetch rows 1,2,3 and then call ReleaseRows
  41. // only on 2. In this case, 1 and 3 would still be in the cache. Each row in
  42. // the cache contains its "row" value. Currently, this value is also used as
  43. // the bookmark to the row.
  44. //-----------------------------------------------------------------------------
  45. //-----------------------------------------------------------------------------
  46. // CreateRowset
  47. //
  48. // Creates and initializes a rowset object. Called by a command or session
  49. // object. The rows are brought in only on demand.
  50. //
  51. //-----------------------------------------------------------------------------
  52. HRESULT
  53. CRowset::CreateRowset(
  54. CRowProvider *pIRowProvider, // The Row provider
  55. IUnknown *pParentObj, // parent object, a command or a session
  56. CSessionObject *pCSession, // Session Object
  57. CCommandObject *pCCommand, // Command Object
  58. ULONG cPropertySets, // # property sets in rowset property group
  59. DBPROPSET rgPropertySets[],// properties in rowset property group
  60. ULONG cAccessors, // accessor count
  61. HACCESSOR rgAccessors[], // accessors on command object
  62. BOOL fadsPathPresent, // Is ADsPath present in query
  63. BOOL fAllAttrs, // Return all attrs from row object?
  64. REFIID riid, // Interface desired
  65. IUnknown **ppIRowset // pointer to desired interface
  66. )
  67. {
  68. HRESULT hr;
  69. CRowset *pCRowset = NULL;
  70. BOOL fGotWarning = FALSE, fRowObjRequested;
  71. DBCOUNTITEM cRowsObtained;
  72. HROW *phRow = NULL;
  73. if( ppIRowset != NULL)
  74. *ppIRowset = NULL;
  75. pCRowset = new CRowset();
  76. if( NULL == pCRowset )
  77. BAIL_ON_FAILURE( hr = E_OUTOFMEMORY );
  78. hr = pCRowset->FInit(
  79. pIRowProvider,
  80. pParentObj,
  81. pCSession,
  82. pCCommand,
  83. cPropertySets,
  84. rgPropertySets,
  85. cAccessors,
  86. rgAccessors,
  87. fadsPathPresent,
  88. fAllAttrs
  89. );
  90. BAIL_ON_FAILURE(hr);
  91. if( hr != S_OK )
  92. fGotWarning = TRUE;
  93. if( ppIRowset != NULL )
  94. {
  95. #if (!defined(BUILD_FOR_NT40))
  96. // If the client requested IRow, create a rowset and get a row object
  97. // off the rowset. Once we make the provider read/write, we should add
  98. // IRowChange and IRowSchmaChange here in addition to IRow. If the
  99. // client set the DBPROP_IRow property, then we always create a row
  100. // object by default.
  101. hr = pCRowset->IsRowObjRequested(&fRowObjRequested);
  102. BAIL_ON_FAILURE( hr );
  103. if( IsEqualIID(riid, IID_IRow) || (fRowObjRequested) )
  104. {
  105. hr = pCRowset->GetNextRows(NULL, 0, 1, &cRowsObtained, &phRow);
  106. BAIL_ON_FAILURE(hr);
  107. if( DB_S_ENDOFROWSET == hr )
  108. BAIL_ON_FAILURE( hr = DB_E_NOTFOUND );
  109. if( hr != S_OK )
  110. BAIL_ON_FAILURE( E_FAIL );
  111. ADsAssert( (1 == cRowsObtained ) && (phRow != NULL) &&
  112. (*phRow != DB_NULL_HROW) );
  113. // Bump up reference count of rowset. This is to avoid the
  114. // destruction of the rowset if the call below fails. Artificially
  115. // incrementing the reference count by one will ensure that any
  116. // call to Release() on the rowset (say, from the destructor of
  117. // the row object) will not end up in the rowset object being
  118. // deleted.
  119. pCRowset->m_cRef++;
  120. hr = pCRowset->m_pCRowsetInfo->GetRowFromHROW(
  121. NULL,
  122. *phRow,
  123. riid,
  124. ppIRowset,
  125. FALSE, // this is not a tear-off
  126. pCRowset->m_fAllAttrs
  127. );
  128. // Restore reference count
  129. pCRowset->m_cRef--;
  130. BAIL_ON_FAILURE(hr);
  131. // Release the row handle since the row object now has a reference
  132. // to it. The reference count of the rowset is at 1 now since the
  133. // row object stored off a pointer to the rowset. The rowset will
  134. // be freed when the row is released.
  135. hr = pCRowset->ReleaseRows(1, phRow, NULL, NULL, NULL);
  136. BAIL_ON_FAILURE(hr);
  137. // we won't bother returning DB_S_NOTSINGLETON if there are more
  138. // rows in the rowset since the spec doesn't require it.
  139. }
  140. else
  141. #endif
  142. {
  143. hr = pCRowset->QueryInterface(riid, (void **)ppIRowset);
  144. BAIL_ON_FAILURE(hr);
  145. }
  146. }
  147. else // OpenRowset may pass in NULL as ppIRowset
  148. delete pCRowset;
  149. if( fGotWarning )
  150. RRETURN( DB_S_ERRORSOCCURRED );
  151. else
  152. RRETURN( S_OK );
  153. error:
  154. if( pCRowset )
  155. delete pCRowset;
  156. RRETURN(hr);
  157. }
  158. //-----------------------------------------------------------------------------
  159. // IsRowObjRequested
  160. //
  161. // From the properties specified by the client, check if DBPROP_IRow is set
  162. //
  163. //-----------------------------------------------------------------------------
  164. HRESULT
  165. CRowset::IsRowObjRequested(BOOL *pfRowObjRequested)
  166. {
  167. #if (!defined(BUILD_FOR_NT40))
  168. DBPROPIDSET rgPropertyIDSets;
  169. DBPROPID dbPropId;
  170. ULONG cPropSets;
  171. DBPROPSET *prgPropertySets;
  172. VARIANT *pVariant;
  173. HRESULT hr;
  174. int i, j;
  175. if( NULL == pfRowObjRequested )
  176. BAIL_ON_FAILURE( hr = E_INVALIDARG );
  177. dbPropId = DBPROP_IRow;
  178. cPropSets = 0;
  179. prgPropertySets = NULL;
  180. rgPropertyIDSets.cPropertyIDs = 1;
  181. rgPropertyIDSets.rgPropertyIDs = &dbPropId;
  182. rgPropertyIDSets.guidPropertySet = DBPROPSET_ROWSET;
  183. hr = m_pCUtilProp->GetProperties(1,
  184. &rgPropertyIDSets,
  185. &cPropSets,
  186. &prgPropertySets,
  187. PROPSET_COMMAND
  188. );
  189. BAIL_ON_FAILURE( hr );
  190. ADsAssert( (1 == cPropSets) && (prgPropertySets != NULL) );
  191. ADsAssert( (1 == prgPropertySets->cProperties) &&
  192. (prgPropertySets->rgProperties != NULL) );
  193. pVariant = &(prgPropertySets->rgProperties[0].vValue);
  194. *pfRowObjRequested = V_BOOL( pVariant );
  195. // Free memory allocated by GetProperties
  196. for (i = 0; i < cPropSets; i++)
  197. {
  198. for (j = 0; j < prgPropertySets[i].cProperties; j++)
  199. {
  200. DBPROP *pProp = &(prgPropertySets[i].rgProperties[j]);
  201. ADsAssert(pProp);
  202. // We should free the DBID in pProp, but we know that
  203. // GetProperties always returns DB_NULLID and FreeDBID doesn't
  204. // handle DB_NULLID. So, DBID is not freed here.
  205. VariantClear(&pProp->vValue);
  206. }
  207. CoTaskMemFree(prgPropertySets[i].rgProperties);
  208. }
  209. CoTaskMemFree(prgPropertySets);
  210. RRETURN( S_OK );
  211. error:
  212. RRETURN( hr );
  213. #else
  214. RRETURN(E_FAIL);
  215. #endif
  216. }
  217. //-----------------------------------------------------------------------------
  218. // CRowset
  219. //
  220. // Constructor initializes all fields to NULL
  221. //
  222. //-----------------------------------------------------------------------------
  223. CRowset::CRowset(void)
  224. {
  225. m_pCRowsetInfo = NULL;
  226. m_pCAccessor = NULL;
  227. m_pCRowProvider = NULL;
  228. m_pCUtilProp = NULL;
  229. m_pIDataConvert = NULL;
  230. m_pIColumnsInfo = NULL;
  231. m_pIRowProvider = NULL;
  232. m_pIMalloc = NULL;
  233. m_lLastFetchRow = RESET_ROW;
  234. m_cRowBytes = 0;
  235. m_cCol = 0;
  236. m_pColData = NULL;
  237. m_fCritSectionInitialized = FALSE;
  238. m_fEndOfRowset = FALSE;
  239. m_fadsPathPresent = TRUE;
  240. m_fAllAttrs = FALSE;
  241. m_cNumRowsCached = 0;
  242. m_LastFetchDir = FORWARD;
  243. m_pRowsPtr = NULL;
  244. m_dwRowCacheSize = 0;
  245. m_lCurrentRow = 0;
  246. m_cRef = 0;
  247. }
  248. //-----------------------------------------------------------------------------
  249. // ~Crowset
  250. //
  251. // Destructor releases all resources
  252. //
  253. //-----------------------------------------------------------------------------
  254. CRowset::~CRowset(void)
  255. {
  256. if( m_pRowsPtr )
  257. {
  258. int iRow;
  259. for(iRow = 0; iRow < m_cNumRowsCached; iRow++)
  260. {
  261. ADsAssert(m_pRowsPtr[iRow] != NULL);
  262. FreeRow(m_pRowsPtr[iRow]);
  263. }
  264. FreeADsMem(m_pRowsPtr);
  265. }
  266. if( m_pCRowsetInfo )
  267. delete m_pCRowsetInfo;
  268. if( m_pCAccessor )
  269. delete m_pCAccessor;
  270. if( m_pCUtilProp )
  271. delete m_pCUtilProp;
  272. // Shouldn't delete m_pCRowProvider since we didn't allocate it
  273. if( m_pIDataConvert )
  274. m_pIDataConvert->Release();
  275. if( m_pIColumnsInfo )
  276. m_pIColumnsInfo->Release();
  277. if( m_pIMalloc )
  278. m_pIMalloc->Release();
  279. // Shouldn't release m_pIRowProvider since we didn't AddRef it
  280. if( m_pColData )
  281. FreeADsMem(m_pColData);
  282. if( m_fCritSectionInitialized )
  283. DeleteCriticalSection(&m_RowsetCritSection);
  284. }
  285. //-----------------------------------------------------------------------------
  286. // FInit
  287. //
  288. // Initializes rowset object
  289. //
  290. //-----------------------------------------------------------------------------
  291. STDMETHODIMP
  292. CRowset::FInit(
  293. CRowProvider *pIRowProvider, // The Row provider
  294. IUnknown *pParentObj, // parent object, a command or a session
  295. CSessionObject *pCSession, // Session Object
  296. CCommandObject *pCCommand, // Command Object
  297. ULONG cPropertySets, // # property sets in rowset property group
  298. DBPROPSET rgPropertySets[],// properties in rowset property group
  299. ULONG cAccessors, // accessor count
  300. HACCESSOR rgAccessors[], // accessors on command object
  301. BOOL fadsPathPresent, // Is ADsPath present in query
  302. BOOL fAllAttrs // Return all attrs from row object?
  303. )
  304. {
  305. HRESULT hr;
  306. BOOL fGotWarning = FALSE;
  307. //
  308. // InitializeCriticalSection can throw exceptions under low memory conditions,
  309. // so catch the exception and handle it nicely.
  310. //
  311. try
  312. {
  313. InitializeCriticalSection(&m_RowsetCritSection);
  314. m_fCritSectionInitialized = TRUE;
  315. }
  316. catch(...)
  317. {
  318. BAIL_ON_FAILURE(hr = E_FAIL);
  319. }
  320. m_pCRowsetInfo = new CRowsetInfo(NULL, pParentObj, pCSession, pCCommand,
  321. pIRowProvider);
  322. if( NULL == m_pCRowsetInfo )
  323. BAIL_ON_FAILURE( hr = E_OUTOFMEMORY );
  324. hr = m_pCRowsetInfo->FInit( (IUnknown *) ((IAccessor *)this) );
  325. BAIL_ON_FAILURE(hr);
  326. m_pCAccessor = new CImpIAccessor(this, NULL);
  327. if( NULL == m_pCAccessor )
  328. BAIL_ON_FAILURE( hr = E_OUTOFMEMORY );
  329. hr = m_pCAccessor->FInit();
  330. BAIL_ON_FAILURE(hr);
  331. m_pCRowProvider = pIRowProvider;
  332. m_pCUtilProp = new CUtilProp();
  333. if( NULL == m_pCUtilProp )
  334. BAIL_ON_FAILURE( hr = E_OUTOFMEMORY );
  335. hr = m_pCUtilProp->FInit(NULL);
  336. BAIL_ON_FAILURE(hr);
  337. // Set the properties. Use PROPSET_COMMAND as we only want to set
  338. // properties in the rowset property group. Any other properties
  339. // should return error.
  340. hr = m_pCUtilProp->SetProperties(cPropertySets,
  341. rgPropertySets,
  342. PROPSET_COMMAND
  343. );
  344. // On session object, we need to check DBPROPOPTIONS to really decide if
  345. // there was a serious error. See comment before SetSearchPrefs in
  346. // csession.cxx
  347. if( pCSession &&
  348. ((DB_E_ERRORSOCCURRED == hr) || (DB_S_ERRORSOCCURRED == hr)) )
  349. {
  350. ULONG i, j;
  351. for(i = 0; i < cPropertySets; i++)
  352. for(j = 0; j < rgPropertySets[i].cProperties; j++)
  353. if( rgPropertySets[i].rgProperties[j].dwStatus !=
  354. DBPROPSTATUS_OK )
  355. if( rgPropertySets[i].rgProperties[j].dwOptions !=
  356. DBPROPOPTIONS_OPTIONAL )
  357. {
  358. BAIL_ON_FAILURE( hr = DB_E_ERRORSOCCURRED );
  359. }
  360. else
  361. fGotWarning = TRUE;
  362. // if we get here, then there was all required properties were set
  363. // successfully. However, hr could still be DB_ERRORSOCCURRED if all
  364. // properties were optional and all of them could not be set. This
  365. // condition is not an error for OpenRowset as noted in the comment
  366. // in csession.cxx. Hence reset hr to S_OK.
  367. hr = S_OK;
  368. }
  369. BAIL_ON_FAILURE(hr);
  370. if( hr != S_OK ) // warning needs to be returned to user
  371. fGotWarning = TRUE;
  372. // Get the maximum number of rows the rowset cache should support
  373. hr = GetMaxCacheSize();
  374. BAIL_ON_FAILURE(hr);
  375. // Get IDataConvert interface for later use by IRowset->GetData
  376. hr = CoCreateInstance(
  377. CLSID_OLEDB_CONVERSIONLIBRARY,
  378. NULL,
  379. CLSCTX_INPROC_SERVER,
  380. IID_IDataConvert,
  381. (void **)&m_pIDataConvert
  382. );
  383. BAIL_ON_FAILURE(hr);
  384. // Get IColumnsInfo interface pointer from row provider
  385. hr = pIRowProvider->QueryInterface(
  386. IID_IColumnsInfo,
  387. (void **)&m_pIColumnsInfo
  388. );
  389. BAIL_ON_FAILURE(hr);
  390. // No need to AddRef below since row provider is contained in CRowsetInfo
  391. // and CRowsetInfo's lifetime is within CRowset.
  392. m_pIRowProvider = pIRowProvider;
  393. // Copy inherited accessors from the command object
  394. hr = CopyAccessors(cAccessors, pCCommand, rgAccessors);
  395. BAIL_ON_FAILURE(hr);
  396. hr = CoGetMalloc(MEMCTX_TASK, &m_pIMalloc);
  397. BAIL_ON_FAILURE(hr);
  398. // get the column offsets from the row provider
  399. hr = GetColOffsets();
  400. BAIL_ON_FAILURE(hr);
  401. m_fadsPathPresent = fadsPathPresent;
  402. m_fAllAttrs = fAllAttrs;
  403. if( fGotWarning )
  404. RRETURN( DB_S_ERRORSOCCURRED );
  405. else
  406. RRETURN( S_OK );
  407. error:
  408. if( m_pCRowsetInfo != NULL )
  409. delete m_pCRowsetInfo; // Releases pParentObj, pCCommand, pCSession and
  410. // pIRowProvider
  411. if( m_pCAccessor != NULL )
  412. delete m_pCAccessor;
  413. if( m_pCUtilProp != NULL )
  414. delete m_pCUtilProp;
  415. if( m_pIDataConvert != NULL )
  416. m_pIDataConvert->Release();
  417. if( m_pIColumnsInfo != NULL )
  418. m_pIColumnsInfo->Release();
  419. if( m_pIMalloc )
  420. m_pIMalloc->Release();
  421. if( m_fCritSectionInitialized )
  422. DeleteCriticalSection(&m_RowsetCritSection);
  423. m_pCRowsetInfo = NULL;
  424. m_pCAccessor = NULL;
  425. m_pCRowProvider = NULL;
  426. m_pCUtilProp = NULL;
  427. m_pIDataConvert = NULL;
  428. m_pIColumnsInfo = NULL;
  429. m_pIRowProvider = NULL;
  430. m_pIMalloc = NULL;
  431. m_fCritSectionInitialized = FALSE;
  432. RRETURN( hr );
  433. }
  434. //-----------------------------------------------------------------------------
  435. // GetMaxCacheSize
  436. //
  437. // From the properties specified by the client, get the maximum number of rows
  438. // that the rowset cache should support.
  439. //
  440. //-----------------------------------------------------------------------------
  441. HRESULT
  442. CRowset::GetMaxCacheSize(void)
  443. {
  444. DBPROPIDSET rgPropertyIDSets;
  445. DBPROPID dbPropId;
  446. ULONG cPropSets;
  447. DBPROPSET *prgPropertySets;
  448. VARIANT *pVariant;
  449. HRESULT hr;
  450. ULONG i, j;
  451. dbPropId = DBPROP_MAXOPENROWS;
  452. cPropSets = 0;
  453. prgPropertySets = NULL;
  454. rgPropertyIDSets.cPropertyIDs = 1;
  455. rgPropertyIDSets.rgPropertyIDs = &dbPropId;
  456. rgPropertyIDSets.guidPropertySet = DBPROPSET_ROWSET;
  457. hr = m_pCUtilProp->GetProperties(1,
  458. &rgPropertyIDSets,
  459. &cPropSets,
  460. &prgPropertySets,
  461. PROPSET_COMMAND
  462. );
  463. BAIL_ON_FAILURE( hr );
  464. ADsAssert( (1 == cPropSets) && (prgPropertySets != NULL) );
  465. ADsAssert( (1 == prgPropertySets->cProperties) &&
  466. (prgPropertySets->rgProperties != NULL) );
  467. pVariant = &(prgPropertySets->rgProperties[0].vValue);
  468. m_dwMaxCacheSize = V_I4( pVariant );
  469. // Free memory allocated by GetProperties
  470. for (i = 0; i < cPropSets; i++)
  471. {
  472. for (j = 0; j < prgPropertySets[i].cProperties; j++)
  473. {
  474. DBPROP *pProp = &(prgPropertySets[i].rgProperties[j]);
  475. ADsAssert(pProp);
  476. // We should free the DBID in pProp, but we know that
  477. // GetProperties always returns DB_NULLID and FreeDBID doesn't
  478. // handle DB_NULLID. So, DBID is not freed here.
  479. VariantClear(&pProp->vValue);
  480. }
  481. CoTaskMemFree(prgPropertySets[i].rgProperties);
  482. }
  483. CoTaskMemFree(prgPropertySets);
  484. RRETURN( S_OK );
  485. error:
  486. RRETURN( hr );
  487. }
  488. //-----------------------------------------------------------------------------
  489. // CopyAccessors
  490. //
  491. // Copies inherited accessors from the command object to the rowset object. If
  492. // the rowset is being created by a session object, nothing has to be done.
  493. //
  494. //-----------------------------------------------------------------------------
  495. HRESULT
  496. CRowset::CopyAccessors(
  497. ULONG cAccessors, // accessor count
  498. CCommandObject *pCCommand, // Command Object
  499. HACCESSOR rgAccessors[] // accessors on command object
  500. )
  501. {
  502. HRESULT hr = S_OK;
  503. IAccessor *pIAccessorCommand = NULL; // Command's IAccessor
  504. IAccessor *pIAccessorRowset = NULL; // Rowset's IAccessor
  505. // Bump up reference count so that call to Release at the end of this
  506. // function doesn't delete rowset object.
  507. CAutoBlock cab(&m_RowsetCritSection);
  508. ++m_cRef;
  509. if( (cAccessors > 0) && (pCCommand != NULL) )
  510. {
  511. hr = pCCommand->QueryInterface(
  512. IID_IAccessor,
  513. (void **)&pIAccessorCommand
  514. );
  515. BAIL_ON_FAILURE(hr);
  516. hr = this->QueryInterface(
  517. IID_IAccessor,
  518. (void **)&pIAccessorRowset
  519. );
  520. BAIL_ON_FAILURE(hr);
  521. hr = CpAccessors2Rowset(
  522. pIAccessorCommand,
  523. pIAccessorRowset,
  524. cAccessors,
  525. rgAccessors,
  526. m_pCAccessor);
  527. BAIL_ON_FAILURE(hr);
  528. }
  529. error:
  530. if( pIAccessorCommand )
  531. pIAccessorCommand->Release();
  532. if( pIAccessorRowset )
  533. pIAccessorRowset->Release();
  534. --m_cRef;
  535. RRETURN( hr );
  536. }
  537. //-----------------------------------------------------------------------------
  538. // GetColOffsets
  539. //
  540. // Decides the offets of the columns in thr row buffer based on the column
  541. // info from the row provider
  542. //
  543. //-----------------------------------------------------------------------------
  544. HRESULT
  545. CRowset::GetColOffsets(void)
  546. {
  547. HRESULT hr;
  548. DBCOLUMNINFO *pColInfo = NULL;
  549. OLECHAR *pColNames = NULL;
  550. DWORD dwOffset, i;
  551. hr = m_pIColumnsInfo->GetColumnInfo(&m_cCol, &pColInfo, &pColNames);
  552. BAIL_ON_FAILURE( hr );
  553. // we don't need the column names
  554. m_pIMalloc->Free(pColNames);
  555. m_pColData = (COLDATA *) AllocADsMem(sizeof(COLDATA) * m_cCol);
  556. if( NULL == m_pColData )
  557. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  558. // Account for fields such as the row reference count that occur
  559. // before all columns in the row buffer
  560. dwOffset = sizeof(ROWBUFFER);
  561. for(i = 0; i < m_cCol; i++)
  562. {
  563. dwOffset = ColumnAlign(dwOffset);
  564. m_pColData[i].dwColOffset = dwOffset;
  565. // Account for the length and status fields of OLEDB data
  566. dwOffset += FIELD_OFFSET(OLEDBDATA, OledbValue);
  567. // Row provider returns all variable-length data types as BYREF
  568. if( pColInfo[i].wType & DBTYPE_BYREF )
  569. dwOffset += sizeof(char *);
  570. else
  571. dwOffset += (DWORD)pColInfo[i].ulColumnSize;
  572. m_pColData[i].wType = pColInfo[i].wType;
  573. }
  574. m_cRowBytes = dwOffset;
  575. m_pIMalloc->Free(pColInfo);
  576. RRETURN( S_OK );
  577. error:
  578. if( pColInfo != NULL )
  579. m_pIMalloc->Free(pColInfo);
  580. if( m_pColData != NULL )
  581. {
  582. FreeADsMem(m_pColData);
  583. m_pColData = NULL;
  584. }
  585. m_cCol = m_cRowBytes = 0;
  586. RRETURN( hr );
  587. }
  588. //-----------------------------------------------------------------------------
  589. // GetNextRows
  590. //
  591. // Gets rows using the row provider into the rowset's cache. Handles for these
  592. // rows are returned to the caller. The caller then retrieves the rows using
  593. // GetData.
  594. //
  595. //-----------------------------------------------------------------------------
  596. STDMETHODIMP
  597. CRowset::GetNextRows(
  598. HCHAPTER hChapter, // ignored since this is not a chaptered rowset
  599. DBROWOFFSET lRowsOffset,
  600. DBROWCOUNT cRows,
  601. DBCOUNTITEM *pcRowsObtained,
  602. HROW **prghRows
  603. )
  604. {
  605. HRESULT hr;
  606. RBOOKMARK StartRowBmk; // bookmark of first row to fetch
  607. ULONG cbBookmark = ADSI_BMK_SIZE; // size in bytes of the bookmark
  608. if( (NULL == pcRowsObtained) || (NULL == prghRows) )
  609. {
  610. if( pcRowsObtained != NULL )
  611. *pcRowsObtained = 0;
  612. RRETURN( E_INVALIDARG );
  613. }
  614. *pcRowsObtained = 0;
  615. if( 0 == cRows )
  616. RRETURN( S_OK );
  617. CAutoBlock cab(&m_RowsetCritSection);
  618. if( RESET_ROW == m_lLastFetchRow )
  619. // this is the first fetch OR RestartPosition was called prior to this
  620. {
  621. if( (lRowsOffset > 0) || ((0 == lRowsOffset) && (cRows > 0)) )
  622. {
  623. StartRowBmk = DBBMK_FIRST;
  624. cbBookmark = STD_BMK_SIZE;
  625. }
  626. else if( (lRowsOffset < 0) || ((0 == lRowsOffset) && (cRows < 0)) )
  627. {
  628. // can't set StartRowBmk to DBBMK_LAST as we want to set it one
  629. // beyond the end of the rowset
  630. // Seek to end of rowset
  631. hr = SeekToEnd();
  632. if( FAILED(hr) )
  633. RRETURN( hr );
  634. // m_lCurrentRow is now 2 off the last row of the rowset
  635. StartRowBmk = RowToBmk(m_lCurrentRow - 1);
  636. }
  637. if( cRows < 0 )
  638. // the first row we want to fetch is one before that specified by
  639. // the combination of StartRowBmk and lRowsOffset
  640. lRowsOffset--;
  641. }
  642. else // we have fetched rows before OR RestartPosition was not called
  643. {
  644. // except in the 3rd case below, it is possible that StartRowBmk
  645. // will end up pointing to a row that is outside the rowset
  646. if( (FORWARD == m_LastFetchDir) && (cRows > 0) )
  647. StartRowBmk = RowToBmk(m_lLastFetchRow + 1);
  648. else if( (BACKWARD == m_LastFetchDir) && (cRows < 0) )
  649. StartRowBmk = RowToBmk(m_lLastFetchRow - 1);
  650. else // first row returned will be same as last row returned previously
  651. StartRowBmk = RowToBmk(m_lLastFetchRow);
  652. }
  653. hr = GetRowsAt(NULL, hChapter, cbBookmark, (BYTE *) &StartRowBmk,
  654. lRowsOffset, cRows, pcRowsObtained, prghRows);
  655. if( SUCCEEDED(hr) )
  656. {
  657. // If we return DB_S_ENDOFROWSET because lRowsOffset indicated a
  658. // position outside the rowset, then we do not modify m_lLastFetchRow.
  659. // Only if we walked off either end of the rowset AND fetched at least
  660. // a row is m_lLastFetchRow updated. If no rows are returned due to
  661. // lack of space in the rowset cache, we do not modify m_lLastFetchRow.
  662. if( *pcRowsObtained )
  663. {
  664. m_LastFetchDir = (cRows > 0) ? FORWARD:BACKWARD;
  665. m_lLastFetchRow = HROWToRow( (*prghRows)[*pcRowsObtained - 1] );
  666. }
  667. }
  668. RRETURN( hr );
  669. }
  670. //-----------------------------------------------------------------------------
  671. // GetRowsAt
  672. //
  673. // Fetches rows starting from a given offset from a bookmark. Handles for
  674. // rows fetched are returned to the caller. The caller may send in an invalid
  675. // bookmark i.e, a bookmark that was not returned by a previous invocation of
  676. // GetData. Although, this is an error, the spec does not require the provider
  677. // to detect this condition. So, the user can send in a random bookmark and the
  678. // provider will return the correct row if there is a row that corresponds to
  679. // the bookmark and DB_S_ENDOFROWSET otherwise. We make use of this fact when
  680. // GetNextRows calls GetRowsAt. The bookmark passed in by GetNextRows may be
  681. // for a row that is not yet in the provider's cache.
  682. //
  683. //-----------------------------------------------------------------------------
  684. STDMETHODIMP
  685. CRowset::GetRowsAt(
  686. HWATCHREGION hReserved, // Reserved for future use. Ignored.
  687. HCHAPTER hChapter, // ignored as this is not a chaptered rowset
  688. DBBKMARK cbBookmark,
  689. const BYTE *pBookmark,
  690. DBROWOFFSET lRowsOffset,
  691. DBROWCOUNT cRows,
  692. DBCOUNTITEM *pcRowsObtained,
  693. HROW **prghRows
  694. )
  695. {
  696. LONG lStartRow, // first row returned
  697. lBmkRow, // row corresponding to bookmark
  698. lNextRow,
  699. lRowIndex;
  700. int iStep;
  701. HROW *phRow;
  702. ROWBUFFER *pRowBuffer;
  703. HRESULT hr;
  704. BOOL fMemAllocated = FALSE;
  705. DBCOUNTITEM iRow;
  706. ULONG_PTR ulRowsOffset;
  707. if( (0 == cbBookmark) || (NULL == pBookmark) ||
  708. (NULL == pcRowsObtained) || (NULL == prghRows) )
  709. {
  710. if( pcRowsObtained != NULL )
  711. *pcRowsObtained = 0;
  712. RRETURN( E_INVALIDARG );
  713. }
  714. *pcRowsObtained = 0;
  715. if( (cbBookmark != STD_BMK_SIZE) && (cbBookmark != ADSI_BMK_SIZE) )
  716. RRETURN( DB_E_BADBOOKMARK );
  717. if( 0 == cRows )
  718. RRETURN( S_OK ); // don't have to check for any errors
  719. CAutoBlock cab(&m_RowsetCritSection);
  720. // rowset can't have more than 2^32 rows. So, if offset points to beyond
  721. // that return eof.
  722. ulRowsOffset = (lRowsOffset > 0) ? lRowsOffset : -lRowsOffset;
  723. if( ulRowsOffset & 0xffffffff00000000 )
  724. RRETURN( DB_S_ENDOFROWSET );
  725. // Get first row to fetch
  726. hr = BmkToRow(cbBookmark, pBookmark, &lBmkRow);
  727. if( FAILED(hr) )
  728. RRETURN( hr );
  729. lStartRow = lBmkRow + lRowsOffset;
  730. if( lStartRow < FIRST_ROW )
  731. RRETURN( DB_S_ENDOFROWSET );
  732. lNextRow = lStartRow;
  733. if( NULL == *prghRows ) // provider has to allocate memory for handles
  734. {
  735. ULONG_PTR cNumHandles, cRowsAbs;
  736. // not sure if there is an abs64
  737. if(cRows < 0)
  738. cRowsAbs = -cRows;
  739. else
  740. cRowsAbs = cRows;
  741. // Guard against user requesting too many rows - maximum we can
  742. // return is the size of the rowset cache
  743. if( m_dwMaxCacheSize > 0 ) // user specified some max value
  744. cNumHandles = Min(cRowsAbs, (ULONG_PTR) m_dwMaxCacheSize);
  745. else
  746. cNumHandles = cRowsAbs;
  747. if( 0 == (cNumHandles * sizeof(HROW)) ) // numeric overflow
  748. *prghRows = NULL;
  749. else
  750. *prghRows = (HROW *) m_pIMalloc->Alloc(cNumHandles * sizeof(HROW));
  751. if( NULL == *prghRows )
  752. RRETURN( E_OUTOFMEMORY );
  753. fMemAllocated = TRUE;
  754. }
  755. iStep = (cRows > 0) ? 1 : -1;
  756. phRow = *prghRows;
  757. // fetch rows
  758. while( cRows )
  759. {
  760. hr = SeekToRow(lNextRow);
  761. BAIL_ON_FAILURE(hr);
  762. if( DB_S_ENDOFROWSET == hr )
  763. // we reached the end of the rowset OR we have reached the end of
  764. // whatever portion of the results set that ADSI has cached (depends
  765. // on the ADSIPROP_CACHE_RESULTS property)
  766. {
  767. if( (0 == *pcRowsObtained) && fMemAllocated )
  768. {
  769. m_pIMalloc->Free(*prghRows);
  770. *prghRows = NULL;
  771. }
  772. RRETURN( DB_S_ENDOFROWSET );
  773. }
  774. // Bring in the row that we just seeked to
  775. hr = BringInRow();
  776. BAIL_ON_FAILURE(hr);
  777. if( (DB_S_ROWLIMITEXCEEDED == hr) || (DB_S_ENDOFROWSET == hr) )
  778. // no more space in rowset cache OR end of rowset. We will hit end
  779. // of rowset only if m_lCurrentRow was one/two beyond the end of the
  780. // rowset when SeekToRow was called above AND lNextRow == m_lCurrentRow
  781. // (in which case, SeekToRow would just return without doing anything).
  782. {
  783. if( (0 == *pcRowsObtained) && fMemAllocated )
  784. {
  785. m_pIMalloc->Free(*prghRows);
  786. *prghRows = NULL;
  787. }
  788. RRETURN( hr );
  789. }
  790. // Get the index of the row within the rowset cache
  791. *phRow = RowToHROW(lNextRow);
  792. lRowIndex = HROWToIndex(*phRow);
  793. // Increment reference count of row
  794. pRowBuffer = m_pRowsPtr[lRowIndex];
  795. ADsAssert(pRowBuffer != NULL);
  796. IncrRefCount(pRowBuffer);
  797. phRow++;
  798. (*pcRowsObtained)++;
  799. lNextRow += iStep;
  800. cRows += (-iStep);
  801. } // while (cRows)
  802. RRETURN( S_OK );
  803. error:
  804. // release any rows that were brought into the cache
  805. phRow = *prghRows;
  806. for(iRow = 0; iRow < *pcRowsObtained; iRow++)
  807. {
  808. ULONG ulRefCount;
  809. ReleaseRows(1, phRow, NULL, &ulRefCount, NULL); //ignore ret value
  810. phRow++;
  811. }
  812. if( fMemAllocated )
  813. {
  814. m_pIMalloc->Free(*prghRows);
  815. *prghRows = NULL;
  816. }
  817. *pcRowsObtained = 0;
  818. RRETURN(hr);
  819. }
  820. //-----------------------------------------------------------------------------
  821. // BmkToRow
  822. //
  823. // Converts a bookmark to a row within the rowset.
  824. //
  825. //-----------------------------------------------------------------------------
  826. HRESULT
  827. CRowset::BmkToRow(
  828. ULONG cbBookmark, // number of bytes in the bookmark
  829. const BYTE *pBookmark, // pointer to bookmark
  830. LONG *plRow
  831. )
  832. {
  833. HRESULT hr;
  834. ADsAssert( plRow != NULL );
  835. if( STD_BMK_SIZE == cbBookmark )
  836. {
  837. // If pBookmark is a pointer passed in from GetNextRows, then it is
  838. // actually a LONG *. Accessing *pBookmark to get the LSByte of the
  839. // bookmark below assumes LITTLE ENDIAN format.
  840. if( DBBMK_FIRST == *pBookmark )
  841. *plRow = FIRST_ROW;
  842. else if( DBBMK_LAST == *pBookmark )
  843. {
  844. CAutoBlock cab(&m_RowsetCritSection); // protect access to m_ fields
  845. // Seek to end of rowset
  846. hr = SeekToEnd();
  847. if( FAILED(hr) )
  848. RRETURN( hr );
  849. // should have reached end of rowset
  850. ADsAssert( DB_S_ENDOFROWSET == hr );
  851. // Seeking to end of rowset sets current row to MAX + 2, if there
  852. // is at least one row in the result. If the result is empty, we
  853. // will return -1 in *plRow below, but that's OK as -1 implies
  854. // DB_S_ENDOFROWSET in GetRowsAt()
  855. *plRow = m_lCurrentRow - 2;
  856. }
  857. else
  858. RRETURN( DB_E_BADBOOKMARK );
  859. }
  860. else if( ADSI_BMK_SIZE == cbBookmark )
  861. *plRow = *((LONG *) pBookmark);
  862. else // should never get in here
  863. ADsAssert( FALSE );
  864. RRETURN( S_OK );
  865. }
  866. //-----------------------------------------------------------------------------
  867. // SeekToRow
  868. //
  869. // Positions the IDirectorySearch cursor such that the next call to GetNextRow
  870. // will fetch the row lTargetRow. If we hit the end of the rowset before
  871. // seeking to lTargetRow, returns DB_S_ENDOFROWSET.
  872. //
  873. //-----------------------------------------------------------------------------
  874. HRESULT
  875. CRowset::SeekToRow(LONG lTargetRow)
  876. {
  877. HRESULT hr;
  878. CAutoBlock cab(&m_RowsetCritSection);
  879. if( lTargetRow == m_lCurrentRow ) // already at the right row
  880. RRETURN( S_OK );
  881. if( lTargetRow < m_lCurrentRow )
  882. {
  883. while( lTargetRow != m_lCurrentRow )
  884. {
  885. hr = m_pCRowProvider->SeekToPreviousRow();
  886. BAIL_ON_FAILURE(hr);
  887. // m_fEndOfRowset is set to TRUE only if we hit the end of the
  888. // rowset while moving forward
  889. m_fEndOfRowset = FALSE;
  890. if( m_lCurrentRow > 0 )
  891. m_lCurrentRow--;
  892. if( S_ADS_NOMORE_ROWS == hr )
  893. if( m_lCurrentRow != lTargetRow )
  894. RRETURN( DB_S_ENDOFROWSET );
  895. }
  896. }
  897. else
  898. {
  899. while( lTargetRow != m_lCurrentRow )
  900. {
  901. hr = m_pCRowProvider->SeekToNextRow();
  902. BAIL_ON_FAILURE(hr);
  903. m_lCurrentRow++;
  904. if( S_ADS_NOMORE_ROWS == hr )
  905. {
  906. // if we were already at the end of the rowset, then reset
  907. // m_lCurrentRow to its original value
  908. if( m_fEndOfRowset)
  909. m_lCurrentRow--;
  910. else
  911. m_fEndOfRowset = TRUE;
  912. RRETURN( DB_S_ENDOFROWSET );
  913. }
  914. }
  915. m_fEndOfRowset = FALSE;
  916. }
  917. RRETURN( S_OK );
  918. error:
  919. RRETURN( hr );
  920. }
  921. //-----------------------------------------------------------------------------
  922. // SeekToEnd
  923. //
  924. // Moves the IDirectorySearch cursor forward till it hits the end of the
  925. // rowset.
  926. //
  927. //-----------------------------------------------------------------------------
  928. HRESULT
  929. CRowset::SeekToEnd(void)
  930. {
  931. HRESULT hr = S_OK;
  932. CAutoBlock cab(&m_RowsetCritSection);
  933. while(1) // till we reach end of rowset
  934. {
  935. hr = m_pCRowProvider->SeekToNextRow();
  936. BAIL_ON_FAILURE(hr);
  937. m_lCurrentRow++;
  938. if( S_ADS_NOMORE_ROWS == hr )
  939. {
  940. // if we were already at the end of the rowset, then reset
  941. // m_lCurrentRow to its original value
  942. if( m_fEndOfRowset)
  943. m_lCurrentRow--;
  944. else
  945. m_fEndOfRowset = TRUE;
  946. RRETURN( DB_S_ENDOFROWSET );
  947. }
  948. }
  949. error:
  950. RRETURN( hr );
  951. }
  952. //-----------------------------------------------------------------------------
  953. // BringInRow
  954. //
  955. // Brings in the row that we seeked to last. Only one row is brought in.
  956. //
  957. //-----------------------------------------------------------------------------
  958. HRESULT
  959. CRowset::BringInRow(void)
  960. {
  961. HRESULT hr;
  962. ROWBUFFER *pRowBuffer = NULL;
  963. DWORD cColErrors; // #columns in a row that had an error when retrieved
  964. int iCol, iRow;
  965. HROW hRow;
  966. LONG lIndex;
  967. DBSTATUS *pdbStatus;
  968. CAutoBlock cab(&m_RowsetCritSection);
  969. // check if the row is already in the cache
  970. hRow = RowToHROW(m_lCurrentRow);
  971. lIndex = HROWToIndex(hRow);
  972. if(lIndex != -1)
  973. // row is already in cache
  974. {
  975. pRowBuffer = m_pRowsPtr[lIndex];
  976. ADsAssert(pRowBuffer != NULL);
  977. if( pRowBuffer->cColErrors )
  978. RRETURN( DB_S_ERRORSOCCURRED );
  979. else
  980. RRETURN( S_OK );
  981. }
  982. // check if we have room in the cache
  983. if( (m_dwMaxCacheSize > 0) && ((DWORD)m_cNumRowsCached == m_dwMaxCacheSize) )
  984. RRETURN( DB_S_ROWLIMITEXCEEDED );
  985. // Allocate more space in the cache, if we have run out
  986. if( (DWORD)m_cNumRowsCached == m_dwRowCacheSize ) // no more space for rows
  987. {
  988. DWORD dwTmpSize;
  989. ROWBUFFER **pTmpRowsPtr;
  990. dwTmpSize = (0 == m_dwRowCacheSize) ? 1 : (m_dwRowCacheSize*2);
  991. // make sure we don't overflow the cache
  992. if( (m_dwMaxCacheSize > 0) && (dwTmpSize > m_dwMaxCacheSize) )
  993. dwTmpSize = m_dwMaxCacheSize;
  994. pTmpRowsPtr = (ROWBUFFER **) ReallocADsMem(m_pRowsPtr,
  995. m_dwRowCacheSize*sizeof(ROWBUFFER *),
  996. dwTmpSize*sizeof(ROWBUFFER *));
  997. if( NULL == pTmpRowsPtr )
  998. BAIL_ON_FAILURE( hr = E_OUTOFMEMORY );
  999. m_dwRowCacheSize = dwTmpSize;
  1000. m_pRowsPtr = pTmpRowsPtr;
  1001. }
  1002. // Allocate memory for a new row
  1003. pRowBuffer = (ROWBUFFER *) AllocADsMem(m_cRowBytes);
  1004. if( NULL == pRowBuffer )
  1005. BAIL_ON_FAILURE( hr = E_OUTOFMEMORY );
  1006. // initialize row to 0 (reference count initialized to 0 here)
  1007. memset((char *) pRowBuffer, 0, m_cRowBytes);
  1008. pRowBuffer->lRow = m_lCurrentRow;
  1009. // use row provider to get the next row
  1010. hr = m_pIRowProvider->NextRow();
  1011. BAIL_ON_FAILURE(hr);
  1012. m_lCurrentRow++;
  1013. if( DB_S_ENDOFROWSET == hr )
  1014. {
  1015. if( m_fEndOfRowset )
  1016. m_lCurrentRow--;
  1017. else
  1018. m_fEndOfRowset = TRUE;
  1019. FreeADsMem(pRowBuffer);
  1020. RRETURN( DB_S_ENDOFROWSET );
  1021. }
  1022. else
  1023. m_fEndOfRowset = FALSE;
  1024. cColErrors = 0;
  1025. for(iCol = 1; (DBORDINAL)iCol < m_cCol; iCol++)
  1026. {
  1027. hr = m_pIRowProvider->GetColumn(
  1028. iCol,
  1029. (DBSTATUS *) ( m_pColData[iCol].dwColOffset +
  1030. FIELD_OFFSET(OLEDBDATA, dbStatus) + (char *)pRowBuffer ),
  1031. (ULONG *) ( m_pColData[iCol].dwColOffset +
  1032. FIELD_OFFSET(OLEDBDATA, dwLength) + (char *)pRowBuffer ),
  1033. (BYTE *) ( m_pColData[iCol].dwColOffset +
  1034. FIELD_OFFSET(OLEDBDATA, OledbValue) + (char *)pRowBuffer )
  1035. );
  1036. if( FAILED(hr) )
  1037. cColErrors++;
  1038. // store the ADS_SEARCH_COLUMN if the DS returned any data. Even if
  1039. // GetColumn fails, this has to be done to ensure that the
  1040. // ADS_SEARCH_COLUMN structure is freed later.
  1041. pdbStatus = (DBSTATUS *) ( m_pColData[iCol].dwColOffset +
  1042. FIELD_OFFSET(OLEDBDATA, dbStatus) + (char *)pRowBuffer );
  1043. if( *pdbStatus != DBSTATUS_S_ISNULL )
  1044. memcpy((void *) ((char *)pRowBuffer + m_pColData[iCol].dwColOffset
  1045. + FIELD_OFFSET(OLEDBDATA, adsSearchCol)),
  1046. (void *) (&(m_pCRowProvider->_pdbSearchCol[iCol].adsColumn)),
  1047. sizeof(ADS_SEARCH_COLUMN) );
  1048. }
  1049. // Copy over the ADsPath search column, if required
  1050. if( FALSE == m_fadsPathPresent )
  1051. memcpy( (void *) (&(pRowBuffer->adsSearchCol)),
  1052. (void *) (&(m_pCRowProvider->_pdbSearchCol[iCol].adsColumn)),
  1053. sizeof(ADS_SEARCH_COLUMN) );
  1054. if( cColErrors == (m_cCol - 1) ) // all columns were in error
  1055. {
  1056. // any failure after this point should do this
  1057. FreeRow(pRowBuffer);
  1058. pRowBuffer = NULL; // so that we don't try to free again later
  1059. BAIL_ON_FAILURE( hr = DB_E_ERRORSOCCURRED );
  1060. }
  1061. // fill in the bookmark column
  1062. *( (DBSTATUS *) (m_pColData[0].dwColOffset +
  1063. FIELD_OFFSET(OLEDBDATA, dbStatus)+(char *)pRowBuffer) ) = DBSTATUS_S_OK;
  1064. *( (ULONG *) (m_pColData[0].dwColOffset +
  1065. FIELD_OFFSET(OLEDBDATA, dwLength)+(char *)pRowBuffer) ) = ADSI_BMK_SIZE;
  1066. // bookmark value is same as row
  1067. *( (ULONG *) (m_pColData[0].dwColOffset +
  1068. FIELD_OFFSET(OLEDBDATA, OledbValue)+(char *)pRowBuffer) ) =
  1069. m_lCurrentRow - 1;
  1070. // Store pointer to new row
  1071. m_pRowsPtr[m_cNumRowsCached] = pRowBuffer;
  1072. m_cNumRowsCached++;
  1073. if( cColErrors )
  1074. {
  1075. pRowBuffer->cColErrors = cColErrors;
  1076. RRETURN( DB_S_ERRORSOCCURRED );
  1077. }
  1078. RRETURN( S_OK );
  1079. error:
  1080. if( pRowBuffer )
  1081. FreeADsMem(pRowBuffer);
  1082. RRETURN( hr );
  1083. }
  1084. //----------------------------------------------------------------------------- // GetData
  1085. //
  1086. // Returns the data from the rowset cache in the format requested by the
  1087. // client. This routine performs deferred accessor validation i.e, checks that
  1088. // could not be done when the accessor was created due to lack of info. about
  1089. // the rowset.
  1090. //
  1091. //-----------------------------------------------------------------------------
  1092. STDMETHODIMP
  1093. CRowset::GetData(
  1094. HROW hRow,
  1095. HACCESSOR hAccessor,
  1096. void *pData
  1097. )
  1098. {
  1099. HRESULT hr;
  1100. LONG lRowIndex;
  1101. DBACCESSORFLAGS dwAccessorFlags;
  1102. DBCOUNTITEM cBindings = 0, cErrors = 0;
  1103. DBBINDING *prgBindings = NULL;
  1104. ROWBUFFER *pRowBuffer;
  1105. int iBind;
  1106. ULONG ulCol;
  1107. ULONG *pulProvLength;
  1108. DBLENGTH *pulConsLength;
  1109. DBSTATUS *pdbConsStatus, *pdbProvStatus;
  1110. void *pConsValue, *pProvValue;
  1111. OLEDBDATA *pProvOledbData;
  1112. if( NULL == pData ) // we don't supprt NULL accessor. So, this is an error
  1113. RRETURN( E_INVALIDARG );
  1114. CAutoBlock cab(&m_RowsetCritSection);
  1115. lRowIndex = HROWToIndex(hRow);
  1116. if( (lRowIndex < FIRST_ROW) || (lRowIndex >= m_cNumRowsCached) )
  1117. RRETURN( DB_E_BADROWHANDLE );
  1118. // Get pointer to the specified row
  1119. pRowBuffer = m_pRowsPtr[lRowIndex];
  1120. ADsAssert( pRowBuffer != NULL );
  1121. if( RefCount(pRowBuffer) <= 0 )
  1122. RRETURN( DB_E_BADROWHANDLE );
  1123. ADsAssert( m_pCAccessor );
  1124. hr = m_pCAccessor->GetBindings( // this call validates hAccessor
  1125. hAccessor,
  1126. &dwAccessorFlags,
  1127. &cBindings,
  1128. &prgBindings
  1129. );
  1130. if( FAILED(hr) )
  1131. RRETURN( hr );
  1132. ADsAssert( cBindings ); // NULL accessor is disallowed
  1133. for(iBind = 0; (DBCOUNTITEM)iBind < cBindings; iBind++)
  1134. {
  1135. // Free pObject in the binding, if any
  1136. if( prgBindings[iBind].pObject )
  1137. m_pIMalloc->Free(prgBindings[iBind].pObject);
  1138. // these types are disallowed
  1139. ADsAssert( !((prgBindings[iBind].wType & DBTYPE_VECTOR) ||
  1140. (prgBindings[iBind].wType & DBTYPE_ARRAY)) );
  1141. // Get pointers to consumer's OLEDB data using the bindings
  1142. if( prgBindings[iBind].dwPart & DBPART_STATUS )
  1143. pdbConsStatus = (DBSTATUS *) ( (char *)pData +
  1144. prgBindings[iBind].obStatus );
  1145. else
  1146. pdbConsStatus = NULL;
  1147. if( prgBindings[iBind].dwPart & DBPART_LENGTH )
  1148. pulConsLength = (DBLENGTH *) ( (char *)pData +
  1149. prgBindings[iBind].obLength );
  1150. else
  1151. pulConsLength = NULL;
  1152. if( prgBindings[iBind].dwPart & DBPART_VALUE )
  1153. pConsValue = (void *) ( (char *)pData +
  1154. prgBindings[iBind].obValue );
  1155. else
  1156. pConsValue = NULL;
  1157. // Check if accessor points to a valid column
  1158. ulCol = prgBindings[iBind].iOrdinal;
  1159. if( ulCol >= m_cCol )
  1160. {
  1161. if( pdbConsStatus )
  1162. *pdbConsStatus = DBSTATUS_E_BADACCESSOR;
  1163. cErrors++;
  1164. continue;
  1165. }
  1166. // Get pointers to providers OLEDB data from the row buffer cache
  1167. pProvOledbData = (OLEDBDATA *) ((char *)pRowBuffer +
  1168. m_pColData[ulCol].dwColOffset);
  1169. pdbProvStatus = &(pProvOledbData->dbStatus);
  1170. pulProvLength = &(pProvOledbData->dwLength);
  1171. pProvValue = &(pProvOledbData->OledbValue);
  1172. if( DBMEMOWNER_PROVIDEROWNED == prgBindings[iBind].dwMemOwner )
  1173. {
  1174. if( pdbConsStatus )
  1175. *pdbConsStatus = *pdbProvStatus;
  1176. if( pulConsLength )
  1177. *pulConsLength = *pulProvLength;
  1178. if( prgBindings[iBind].wType & DBTYPE_BYREF )
  1179. {
  1180. // If a binding specifies provider owned memory, and specifies
  1181. // type X | BYREF, and the provider's copy is not X or
  1182. // X | BYREF, return error
  1183. if( (prgBindings[iBind].wType & (~DBTYPE_BYREF)) !=
  1184. (m_pColData[ulCol].wType & (~DBTYPE_BYREF)) )
  1185. {
  1186. if( pdbConsStatus )
  1187. *pdbConsStatus = DBSTATUS_E_BADACCESSOR;
  1188. cErrors++;
  1189. continue;
  1190. }
  1191. if( m_pColData[ulCol].wType & DBTYPE_BYREF )
  1192. // provider's type exactly matches consumer's type
  1193. {
  1194. if( pConsValue )
  1195. *(void **) pConsValue = *(void **) pProvValue;
  1196. }
  1197. else
  1198. // provider actually has the data, not a pointer to the data
  1199. {
  1200. if( pConsValue )
  1201. *(void **) pConsValue = pProvValue;
  1202. }
  1203. }
  1204. else if( DBTYPE_BSTR == prgBindings[iBind].wType )
  1205. {
  1206. if( DBTYPE_BSTR != m_pColData[ulCol].wType )
  1207. {
  1208. if( pdbConsStatus )
  1209. *pdbConsStatus = DBSTATUS_E_BADACCESSOR;
  1210. cErrors++;
  1211. continue;
  1212. }
  1213. if( pConsValue )
  1214. *(void **) pConsValue = *(void **) pProvValue;
  1215. }
  1216. else // we should never get here
  1217. ADsAssert( FALSE );
  1218. }
  1219. else // binding specified client-owned memory
  1220. {
  1221. // workaround for bug in IDataConvert. Variant to Variant
  1222. // conversions may not always work (depending on the type in the
  1223. // variant). So, handle that case separately.
  1224. DBTYPE dbSrcType, dbDstType;
  1225. dbSrcType = m_pColData[ulCol].wType & (~DBTYPE_BYREF);
  1226. dbDstType = prgBindings[iBind].wType & (~DBTYPE_BYREF);
  1227. if( (DBTYPE_VARIANT == dbSrcType) &&
  1228. (DBTYPE_VARIANT == dbDstType) )
  1229. {
  1230. PVARIANT pSrcVariant, pDstVariant = NULL;
  1231. if( (*pdbProvStatus != DBSTATUS_S_OK) &&
  1232. (*pdbProvStatus != DBSTATUS_S_ISNULL) )
  1233. // provider wasn't able to get value from DS. Return bad
  1234. // status to consumer
  1235. {
  1236. if( pdbConsStatus )
  1237. *pdbConsStatus = *pdbProvStatus;
  1238. if( pulConsLength )
  1239. *pulConsLength = 0;
  1240. // value will not be set
  1241. cErrors++;
  1242. continue; // to next binding
  1243. }
  1244. if( m_pColData[ulCol].wType & DBTYPE_BYREF )
  1245. pSrcVariant = *(PVARIANT *)pProvValue;
  1246. else
  1247. pSrcVariant = (PVARIANT)pProvValue;
  1248. if( (prgBindings[iBind].wType & DBTYPE_BYREF) && pConsValue )
  1249. {
  1250. pDstVariant = (PVARIANT)m_pIMalloc->Alloc(sizeof(VARIANT));
  1251. if( NULL == pDstVariant )
  1252. hr = E_OUTOFMEMORY;
  1253. }
  1254. else
  1255. pDstVariant = (PVARIANT)pConsValue;
  1256. if( pdbConsStatus )
  1257. *pdbConsStatus = *pdbProvStatus;
  1258. if( pulConsLength )
  1259. *pulConsLength = *pulProvLength;
  1260. if( pDstVariant )
  1261. {
  1262. VariantInit(pDstVariant);
  1263. if( DBSTATUS_S_ISNULL == *pdbProvStatus )
  1264. // provider couldn't get this column from DS (probably
  1265. // because there was no attribute with this name)
  1266. {
  1267. if( prgBindings[iBind].wType & DBTYPE_BYREF )
  1268. // don't allocate anything if returning NULL status
  1269. m_pIMalloc->Free(pDstVariant);
  1270. else
  1271. V_VT(pDstVariant) = VT_EMPTY;
  1272. hr = S_OK;
  1273. }
  1274. else
  1275. {
  1276. hr = VariantCopy(pDstVariant, pSrcVariant);
  1277. if( SUCCEEDED(hr) )
  1278. {
  1279. if( pConsValue &&
  1280. (prgBindings[iBind].wType & DBTYPE_BYREF) )
  1281. *(void **) pConsValue = pDstVariant;
  1282. }
  1283. else if( prgBindings[iBind].wType & DBTYPE_BYREF )
  1284. m_pIMalloc->Free(pDstVariant);
  1285. } // else
  1286. } // if( pDstvariant)
  1287. } // if( DBTYPE_VARIANT == ...)
  1288. else
  1289. {
  1290. DBLENGTH dbTmpLen = 0;
  1291. hr = m_pIDataConvert->DataConvert(
  1292. m_pColData[ulCol].wType,
  1293. prgBindings[iBind].wType,
  1294. *pulProvLength,
  1295. &dbTmpLen,
  1296. pProvValue,
  1297. pConsValue,
  1298. prgBindings[iBind].cbMaxLen,
  1299. *pdbProvStatus,
  1300. pdbConsStatus,
  1301. prgBindings[iBind].bPrecision,
  1302. prgBindings[iBind].bScale,
  1303. DBDATACONVERT_DEFAULT
  1304. );
  1305. if( pulConsLength )
  1306. *pulConsLength = dbTmpLen;
  1307. // if the binding specified DBTYPE_VARIANT | DBTYPE_BYREF, then
  1308. // IDataConvert does not allocate a VT_NULL variant. Instead it
  1309. // returns nothing in pConsValue. If it is not BYREF, then
  1310. // return VT_EMPTY instead of VT_NULL.
  1311. if( SUCCEEDED(hr) && (DBSTATUS_S_ISNULL == *pdbProvStatus) &&
  1312. (prgBindings[iBind].wType == DBTYPE_VARIANT) &&
  1313. pConsValue )
  1314. {
  1315. PVARIANT pVariant;
  1316. pVariant = (PVARIANT)pConsValue;
  1317. V_VT(pVariant) = VT_EMPTY;
  1318. }
  1319. }
  1320. if( FAILED(hr) )
  1321. {
  1322. if( pdbConsStatus )
  1323. *pdbConsStatus = DBSTATUS_E_CANTCONVERTVALUE;
  1324. cErrors++;
  1325. continue;
  1326. }
  1327. } // client-owned memory
  1328. }
  1329. m_pIMalloc->Free(prgBindings);
  1330. if( cErrors )
  1331. if( cErrors != cBindings ) // not all columns had error
  1332. RRETURN( DB_S_ERRORSOCCURRED );
  1333. else
  1334. RRETURN( DB_E_ERRORSOCCURRED );
  1335. else
  1336. RRETURN( S_OK );
  1337. }
  1338. //-----------------------------------------------------------------------------
  1339. // AddRefRows
  1340. //
  1341. // Increments reference count of specified rows
  1342. //
  1343. //-----------------------------------------------------------------------------
  1344. STDMETHODIMP
  1345. CRowset::AddRefRows(
  1346. DBCOUNTITEM cRows,
  1347. const HROW rghRows[],
  1348. ULONG rgRefCounts[],
  1349. DBROWSTATUS rgRowStatus[]
  1350. )
  1351. {
  1352. int iRow;
  1353. LONG lRowIndex;
  1354. ROWBUFFER *pRowBuffer;
  1355. DBCOUNTITEM cErrors = 0;
  1356. if( (NULL == rghRows) && (cRows != 0) )
  1357. RRETURN( E_INVALIDARG );
  1358. CAutoBlock cab(&m_RowsetCritSection);
  1359. for(iRow = 0; (DBCOUNTITEM)iRow < cRows; iRow++)
  1360. {
  1361. lRowIndex = HROWToIndex(rghRows[iRow]);
  1362. if( (lRowIndex < 0) || (lRowIndex >= m_cNumRowsCached) )
  1363. {
  1364. if( rgRowStatus )
  1365. rgRowStatus[iRow] = DBROWSTATUS_E_INVALID;
  1366. if( rgRefCounts )
  1367. rgRefCounts[iRow] = 0;
  1368. cErrors++;
  1369. continue;
  1370. }
  1371. // Get pointer to the specified row
  1372. pRowBuffer = m_pRowsPtr[lRowIndex];
  1373. ADsAssert( pRowBuffer != NULL );
  1374. if( RefCount(pRowBuffer) <= 0 )
  1375. {
  1376. if( rgRowStatus )
  1377. rgRowStatus[iRow] = DBROWSTATUS_E_INVALID;
  1378. if( rgRefCounts )
  1379. rgRefCounts[iRow] = 0;
  1380. cErrors++;
  1381. continue;
  1382. }
  1383. IncrRefCount(pRowBuffer);
  1384. if( rgRefCounts )
  1385. rgRefCounts[iRow] = RefCount(pRowBuffer);
  1386. if( rgRowStatus )
  1387. rgRowStatus[iRow] = DBROWSTATUS_S_OK;
  1388. }
  1389. if( cErrors )
  1390. if( cErrors == cRows )
  1391. RRETURN( DB_E_ERRORSOCCURRED );
  1392. else
  1393. RRETURN( DB_S_ERRORSOCCURRED );
  1394. RRETURN( S_OK );
  1395. }
  1396. //----------------------------------------------------------------------------
  1397. // ReleaseRows
  1398. //
  1399. // Decrements reference count of specified rows. The rows are not freed even
  1400. // if the reference count goes down to 0.
  1401. //
  1402. //----------------------------------------------------------------------------
  1403. STDMETHODIMP
  1404. CRowset::ReleaseRows(
  1405. DBCOUNTITEM cRows,
  1406. const HROW rghRows[],
  1407. DBROWOPTIONS rgRowOptions[], // ignored
  1408. ULONG rgRefCounts[],
  1409. DBROWSTATUS rgRowStatus[]
  1410. )
  1411. {
  1412. int iRow;
  1413. LONG lRowIndex;
  1414. ROWBUFFER *pRowBuffer;
  1415. DBCOUNTITEM cErrors = 0;
  1416. if( (NULL == rghRows) && (cRows != 0) )
  1417. RRETURN( E_INVALIDARG );
  1418. CAutoBlock cab(&m_RowsetCritSection);
  1419. for(iRow = 0; (DBCOUNTITEM)iRow < cRows; iRow++)
  1420. {
  1421. lRowIndex = HROWToIndex(rghRows[iRow]);
  1422. if( (lRowIndex < 0) || (lRowIndex >= m_cNumRowsCached) )
  1423. {
  1424. if( rgRowStatus )
  1425. rgRowStatus[iRow] = DBROWSTATUS_E_INVALID;
  1426. if( rgRefCounts )
  1427. rgRefCounts[iRow] = 0;
  1428. cErrors++;
  1429. continue;
  1430. }
  1431. // Get pointer to the specified row
  1432. pRowBuffer = m_pRowsPtr[lRowIndex];
  1433. ADsAssert( pRowBuffer != NULL );
  1434. if( RefCount(pRowBuffer) <= 0 )
  1435. {
  1436. if( rgRowStatus )
  1437. rgRowStatus[iRow] = DBROWSTATUS_E_INVALID;
  1438. if( rgRefCounts )
  1439. rgRefCounts[iRow] = 0;
  1440. cErrors++;
  1441. continue;
  1442. }
  1443. DecrRefCount(pRowBuffer);
  1444. if( rgRefCounts )
  1445. rgRefCounts[iRow] = RefCount(pRowBuffer);
  1446. if( rgRowStatus )
  1447. rgRowStatus[iRow] = DBROWSTATUS_S_OK;
  1448. // Free the row's memory
  1449. if( 0 == RefCount(pRowBuffer) )
  1450. {
  1451. int i;
  1452. FreeRow(pRowBuffer);
  1453. m_cNumRowsCached--;
  1454. // compact the cache
  1455. for(i = lRowIndex; i < m_cNumRowsCached; i++)
  1456. m_pRowsPtr[i] = m_pRowsPtr[i+1];
  1457. }
  1458. }
  1459. if( cErrors )
  1460. if( cErrors == cRows )
  1461. RRETURN( DB_E_ERRORSOCCURRED );
  1462. else
  1463. RRETURN( DB_S_ERRORSOCCURRED );
  1464. RRETURN( S_OK );
  1465. }
  1466. //----------------------------------------------------------------------------
  1467. // RestartPosition
  1468. //
  1469. // Repositions the next fetch poition to the initial position
  1470. //
  1471. //----------------------------------------------------------------------------
  1472. STDMETHODIMP
  1473. CRowset::RestartPosition(
  1474. HCHAPTER hChapter // ignored
  1475. )
  1476. {
  1477. CAutoBlock cab(&m_RowsetCritSection);
  1478. m_lLastFetchRow = RESET_ROW;
  1479. RRETURN( S_OK );
  1480. }
  1481. //----------------------------------------------------------------------------
  1482. // FreeRow
  1483. //
  1484. // Frees the memory used by a row in the rowset cache. Also frees the ADsColumn
  1485. // structures contained within the row.
  1486. //
  1487. //----------------------------------------------------------------------------
  1488. void
  1489. CRowset::FreeRow(
  1490. ROWBUFFER *pRowBuffer
  1491. )
  1492. {
  1493. int iCol;
  1494. ADS_SEARCH_COLUMN *pADsCol;
  1495. DBSTATUS *pdbStatus;
  1496. PVARIANT pVariant;
  1497. CAutoBlock cab(&m_RowsetCritSection);
  1498. // start with column 1. Bookmark column is ignored.
  1499. for(iCol = 1; (DBORDINAL)iCol < m_cCol; iCol++)
  1500. {
  1501. pADsCol = (ADS_SEARCH_COLUMN *) ((char *)pRowBuffer +
  1502. m_pColData[iCol].dwColOffset +
  1503. FIELD_OFFSET(OLEDBDATA, adsSearchCol));
  1504. pdbStatus = (DBSTATUS *) ( m_pColData[iCol].dwColOffset +
  1505. FIELD_OFFSET(OLEDBDATA, dbStatus) +
  1506. (char *)pRowBuffer );
  1507. if( *pdbStatus != DBSTATUS_S_ISNULL )
  1508. {
  1509. if( (DBSTATUS_S_OK == *pdbStatus) &&
  1510. ((m_pColData[iCol].wType & (~DBTYPE_BYREF)) == DBTYPE_VARIANT) )
  1511. // variant (or variant array) needs to be freed
  1512. {
  1513. pVariant = *(PVARIANT *) ( (m_pColData[iCol].dwColOffset +
  1514. FIELD_OFFSET(OLEDBDATA, OledbValue) +
  1515. (char *)pRowBuffer) );
  1516. if( V_VT(pVariant) & VT_ARRAY )
  1517. SafeArrayDestroy(V_ARRAY(pVariant));
  1518. else
  1519. VariantClear(pVariant);
  1520. FreeADsMem(pVariant);
  1521. }
  1522. // ignore error return
  1523. m_pCRowProvider->_pDSSearch->FreeColumn(pADsCol);
  1524. }
  1525. }
  1526. if( FALSE == m_fadsPathPresent )
  1527. // ignore error return
  1528. m_pCRowProvider->_pDSSearch->FreeColumn(&(pRowBuffer->adsSearchCol));
  1529. FreeADsMem(pRowBuffer);
  1530. return;
  1531. }
  1532. //-----------------------------------------------------------------------------
  1533. // GetADsPathFromHROW
  1534. //
  1535. // Gets the ADsPath corresponding to a HROW. This function is called by
  1536. // GetURLFromHROW, only if m_fadsPathPresent is FALSE.
  1537. //
  1538. //-----------------------------------------------------------------------------
  1539. HRESULT
  1540. CRowset::GetADsPathFromHROW(
  1541. HROW hRow,
  1542. ADS_CASE_IGNORE_STRING *padsPath
  1543. )
  1544. {
  1545. LONG lRowIndex;
  1546. ROWBUFFER *pRowBuffer;
  1547. ADsAssert(FALSE == m_fadsPathPresent);
  1548. CAutoBlock cab(&m_RowsetCritSection);
  1549. lRowIndex = HROWToIndex(hRow);
  1550. if( (lRowIndex < 0) || (lRowIndex >= m_cNumRowsCached) )
  1551. RRETURN(E_HANDLE);
  1552. // Get pointer to the specified row
  1553. pRowBuffer = m_pRowsPtr[lRowIndex];
  1554. ADsAssert( pRowBuffer != NULL );
  1555. if( RefCount(pRowBuffer) <= 0 )
  1556. RRETURN(E_HANDLE);
  1557. if( NULL == padsPath )
  1558. RRETURN(E_INVALIDARG);
  1559. *padsPath =
  1560. pRowBuffer->adsSearchCol.pADsValues[0].CaseIgnoreString;
  1561. RRETURN( S_OK );
  1562. }
  1563. //-----------------------------------------------------------------------------
  1564. // IUnknown methods
  1565. //-----------------------------------------------------------------------------
  1566. STDMETHODIMP
  1567. CRowset::QueryInterface(
  1568. THIS_ REFIID riid,
  1569. LPVOID FAR* ppvObj
  1570. )
  1571. {
  1572. if( NULL == ppvObj )
  1573. RRETURN( E_INVALIDARG );
  1574. *ppvObj = NULL;
  1575. if( IsEqualIID(riid, IID_IUnknown) )
  1576. *ppvObj = (IUnknown FAR *) ((IAccessor *) this);
  1577. else if( IsEqualIID(riid, IID_IAccessor) )
  1578. *ppvObj = (IAccessor FAR *) this;
  1579. else if( IsEqualIID(riid, IID_IColumnsInfo) )
  1580. *ppvObj = (IColumnsInfo FAR *) this;
  1581. else if( IsEqualIID(riid, IID_IConvertType) )
  1582. *ppvObj = (IConvertType FAR *) this;
  1583. #if (!defined(BUILD_FOR_NT40))
  1584. else if( IsEqualIID(riid, IID_IGetRow) )
  1585. *ppvObj = (IGetRow FAR *) this;
  1586. #endif
  1587. else if( IsEqualIID(riid, IID_IRowset) )
  1588. *ppvObj = (IRowset FAR *) this;
  1589. else if( IsEqualIID(riid, IID_IRowsetIdentity) )
  1590. *ppvObj = (IRowsetIdentity FAR *) this;
  1591. else if( IsEqualIID(riid, IID_IRowsetInfo) )
  1592. *ppvObj = (IRowsetInfo FAR *) this;
  1593. else if( IsEqualIID(riid, IID_IRowsetLocate) )
  1594. *ppvObj = (IRowsetLocate FAR *) this;
  1595. else if( IsEqualIID(riid, IID_IRowsetScroll) )
  1596. *ppvObj = (IRowsetScroll FAR *) this;
  1597. else
  1598. RRETURN( E_NOINTERFACE );
  1599. AddRef();
  1600. RRETURN( S_OK );
  1601. }
  1602. //-----------------------------------------------------------------------------
  1603. // AddRef
  1604. //
  1605. // Increments reference count of this object
  1606. //
  1607. //-----------------------------------------------------------------------------
  1608. STDMETHODIMP_(ULONG)
  1609. CRowset::AddRef(
  1610. void
  1611. )
  1612. {
  1613. CAutoBlock cab(&m_RowsetCritSection);
  1614. ADsAssert(((LONG)m_cRef) >= 0);
  1615. return ++m_cRef;
  1616. }
  1617. //-----------------------------------------------------------------------------
  1618. // Release
  1619. //
  1620. // Decrements reference count of this object
  1621. //
  1622. //-----------------------------------------------------------------------------
  1623. STDMETHODIMP_(ULONG)
  1624. CRowset::Release(
  1625. void
  1626. )
  1627. {
  1628. CAutoBlock cab(&m_RowsetCritSection);
  1629. ADsAssert(m_cRef > 0);
  1630. m_cRef--;
  1631. if( 0 == m_cRef )
  1632. {
  1633. cab.UnBlock();
  1634. delete this;
  1635. return 0;
  1636. }
  1637. return m_cRef;
  1638. }
  1639. //-----------------------------------------------------------------------------
  1640. // IAccessor methods
  1641. //-----------------------------------------------------------------------------
  1642. STDMETHODIMP
  1643. CRowset::AddRefAccessor(
  1644. HACCESSOR hAccessor,
  1645. DBREFCOUNT *pcRefCount
  1646. )
  1647. {
  1648. ADsAssert(m_pCAccessor);
  1649. RRETURN( m_pCAccessor->AddRefAccessor(hAccessor, pcRefCount) );
  1650. }
  1651. STDMETHODIMP
  1652. CRowset::CreateAccessor(
  1653. DBACCESSORFLAGS dwAccessorFlags,
  1654. DBCOUNTITEM cBindings,
  1655. const DBBINDING rgBindings[],
  1656. DBLENGTH cbRowSize,
  1657. HACCESSOR * phAccessor,
  1658. DBBINDSTATUS rgStatus[]
  1659. )
  1660. {
  1661. ADsAssert(m_pCAccessor);
  1662. RRETURN(m_pCAccessor->CreateAccessor(
  1663. dwAccessorFlags,
  1664. cBindings,
  1665. rgBindings,
  1666. cbRowSize,
  1667. phAccessor,
  1668. rgStatus)
  1669. );
  1670. }
  1671. STDMETHODIMP
  1672. CRowset::ReleaseAccessor(
  1673. HACCESSOR hAccessor,
  1674. DBREFCOUNT *pcRefCount
  1675. )
  1676. {
  1677. ADsAssert(m_pCAccessor);
  1678. RRETURN( m_pCAccessor->ReleaseAccessor(
  1679. hAccessor,
  1680. pcRefCount)
  1681. );
  1682. }
  1683. STDMETHODIMP
  1684. CRowset::GetBindings(
  1685. HACCESSOR hAccessor,
  1686. DBACCESSORFLAGS * pdwAccessorFlags,
  1687. DBCOUNTITEM * pcBindings,
  1688. DBBINDING ** prgBindings
  1689. )
  1690. {
  1691. ADsAssert(m_pCAccessor);
  1692. RRETURN( m_pCAccessor->GetBindings(
  1693. hAccessor,
  1694. pdwAccessorFlags,
  1695. pcBindings,
  1696. prgBindings)
  1697. );
  1698. }
  1699. //-----------------------------------------------------------------------------
  1700. // IColumnsInfo methods
  1701. //-----------------------------------------------------------------------------
  1702. STDMETHODIMP
  1703. CRowset::GetColumnInfo(
  1704. DBORDINAL *pcColumns,
  1705. DBCOLUMNINFO **pprgInfo,
  1706. WCHAR ** ppStringBuffer
  1707. )
  1708. {
  1709. ADsAssert(m_pIColumnsInfo);
  1710. RRETURN( m_pIColumnsInfo->GetColumnInfo(
  1711. pcColumns,
  1712. pprgInfo,
  1713. ppStringBuffer)
  1714. );
  1715. }
  1716. STDMETHODIMP
  1717. CRowset::MapColumnIDs(
  1718. DBORDINAL cColumnIDs,
  1719. const DBID rgColumnIDs[],
  1720. DBORDINAL rgColumns[]
  1721. )
  1722. {
  1723. ADsAssert(m_pIColumnsInfo);
  1724. RRETURN( m_pIColumnsInfo->MapColumnIDs(
  1725. cColumnIDs,
  1726. rgColumnIDs,
  1727. rgColumns)
  1728. );
  1729. }
  1730. //-----------------------------------------------------------------------------
  1731. // IConvertType methods (mandatory for IRowset)
  1732. //-----------------------------------------------------------------------------
  1733. STDMETHODIMP
  1734. CRowset::CanConvert(
  1735. DBTYPE wFromType,
  1736. DBTYPE wToType,
  1737. DBCONVERTFLAGS dwConvertFlags
  1738. )
  1739. {
  1740. HRESULT hr;
  1741. if( dwConvertFlags & DBCONVERTFLAGS_PARAMETER ) // not allowed on rowset
  1742. RRETURN( DB_E_BADCONVERTFLAG );
  1743. if( (dwConvertFlags & (~(DBCONVERTFLAGS_ISLONG |
  1744. DBCONVERTFLAGS_ISFIXEDLENGTH |
  1745. DBCONVERTFLAGS_FROMVARIANT))) !=
  1746. DBCONVERTFLAGS_COLUMN )
  1747. RRETURN( DB_E_BADCONVERTFLAG );
  1748. if( dwConvertFlags & DBCONVERTFLAGS_ISLONG )
  1749. {
  1750. DBTYPE wType;
  1751. wType = wFromType & (~(DBTYPE_BYREF | DBTYPE_ARRAY | DBTYPE_VECTOR));
  1752. // wType has to be variable-length DBTYPE
  1753. if( (wType != DBTYPE_STR) && (wType != DBTYPE_WSTR) &&
  1754. (wType != DBTYPE_BYTES) && (wType != DBTYPE_VARNUMERIC) )
  1755. RRETURN( DB_E_BADCONVERTFLAG );
  1756. }
  1757. // CreateAccessor returns error for ARRAY and VECTOR types. So we cannot
  1758. // convert to these types.
  1759. if( (wToType & DBTYPE_ARRAY) || (wToType & DBTYPE_VECTOR) )
  1760. RRETURN( S_FALSE );
  1761. if( dwConvertFlags & DBCONVERTFLAGS_FROMVARIANT )
  1762. {
  1763. DBTYPE dbTmpType, wVtType;
  1764. wVtType = wFromType & VT_TYPEMASK;
  1765. // Take out all of the Valid VT_TYPES (36 is VT_RECORD in VC 6)
  1766. if( (wVtType > VT_DECIMAL && wVtType < VT_I1) ||
  1767. ((wVtType > VT_LPWSTR && wVtType < VT_FILETIME) && wVtType !=36) ||
  1768. (wVtType > VT_CLSID) )
  1769. RRETURN( DB_E_BADTYPE );
  1770. dbTmpType = wToType & (~DBTYPE_BYREF);
  1771. if( DBTYPE_VARIANT == dbTmpType )
  1772. // GetData will do the right thing, so return TRUE.
  1773. RRETURN( S_OK );
  1774. }
  1775. // GetData handles VARIANT to VARIANT conversions, so special check here
  1776. if( (DBTYPE_VARIANT == (wFromType & (~DBTYPE_BYREF))) &&
  1777. (DBTYPE_VARIANT == (wToType & (~DBTYPE_BYREF))) )
  1778. RRETURN( S_OK );
  1779. ADsAssert( m_pIDataConvert != NULL );
  1780. hr = m_pIDataConvert->CanConvert(wFromType, wToType);
  1781. RRETURN( (E_INVALIDARG == hr)? S_FALSE : hr );
  1782. }
  1783. //-----------------------------------------------------------------------------
  1784. // IGetRow methods
  1785. //-----------------------------------------------------------------------------
  1786. STDMETHODIMP
  1787. CRowset::GetRowFromHROW(
  1788. IUnknown *pUnkOuter,
  1789. HROW hRow,
  1790. REFIID riid,
  1791. IUnknown **ppUnk
  1792. )
  1793. {
  1794. ADsAssert(m_pCRowsetInfo);
  1795. RRETURN( m_pCRowsetInfo->GetRowFromHROW(
  1796. pUnkOuter,
  1797. hRow,
  1798. riid,
  1799. ppUnk,
  1800. TRUE, // this ia tear-off row
  1801. m_fAllAttrs)
  1802. );
  1803. }
  1804. STDMETHODIMP
  1805. CRowset::GetURLFromHROW(
  1806. HROW hRow,
  1807. LPOLESTR *ppwszURL
  1808. )
  1809. {
  1810. ADsAssert(m_pCRowsetInfo);
  1811. RRETURN( m_pCRowsetInfo->GetURLFromHROW(hRow, ppwszURL) );
  1812. }
  1813. //-----------------------------------------------------------------------------
  1814. // IRowsetIdentity methods
  1815. //-----------------------------------------------------------------------------
  1816. STDMETHODIMP
  1817. CRowset::IsSameRow(
  1818. HROW hRow1,
  1819. HROW hRow2
  1820. )
  1821. {
  1822. LONG lIndex1, lIndex2;
  1823. ROWBUFFER *pRowBuffer1, *pRowBuffer2;
  1824. lIndex1 = HROWToIndex(hRow1);
  1825. lIndex2 = HROWToIndex(hRow2);
  1826. if( (lIndex1 < 0) || (lIndex1 >= m_cNumRowsCached) ||
  1827. (lIndex2 < 0) || (lIndex2 >= m_cNumRowsCached) )
  1828. RRETURN( DB_E_BADROWHANDLE );
  1829. // Get pointer to the specified row
  1830. pRowBuffer1 = m_pRowsPtr[lIndex1];
  1831. pRowBuffer2 = m_pRowsPtr[lIndex2];
  1832. ADsAssert( (pRowBuffer1 != NULL) && (pRowBuffer2 != NULL) );
  1833. if( (RefCount(pRowBuffer1) <= 0) || (RefCount(pRowBuffer2) <= 0) )
  1834. RRETURN( DB_E_BADROWHANDLE );
  1835. if( lIndex1 == lIndex2 )
  1836. RRETURN( S_OK );
  1837. else
  1838. RRETURN( S_FALSE );
  1839. }
  1840. //-----------------------------------------------------------------------------
  1841. // IRowsetInfo methods
  1842. //-----------------------------------------------------------------------------
  1843. STDMETHODIMP
  1844. CRowset::GetProperties(
  1845. const ULONG cPropertyIDSets,
  1846. const DBPROPIDSET rgPropertyIDSets[],
  1847. ULONG *pcPropertySets,
  1848. DBPROPSET **pprgPropertySets
  1849. )
  1850. {
  1851. ADsAssert( m_pCUtilProp );
  1852. // Check arguments for error
  1853. HRESULT hr = m_pCUtilProp->GetPropertiesArgChk(
  1854. cPropertyIDSets,
  1855. rgPropertyIDSets,
  1856. pcPropertySets,
  1857. pprgPropertySets,
  1858. PROPSET_COMMAND);
  1859. if( FAILED(hr) )
  1860. RRETURN( hr );
  1861. RRETURN( m_pCUtilProp->GetProperties(
  1862. cPropertyIDSets,
  1863. rgPropertyIDSets,
  1864. pcPropertySets,
  1865. pprgPropertySets,
  1866. PROPSET_COMMAND) );
  1867. }
  1868. STDMETHODIMP
  1869. CRowset::GetReferencedRowset(
  1870. DBORDINAL iOrdinal,
  1871. REFIID riid,
  1872. IUnknown **ppReferencedRowset
  1873. )
  1874. {
  1875. ADsAssert(m_pCRowsetInfo);
  1876. RRETURN( m_pCRowsetInfo->GetReferencedRowset(
  1877. iOrdinal,
  1878. riid,
  1879. ppReferencedRowset)
  1880. );
  1881. }
  1882. STDMETHODIMP
  1883. CRowset::GetSpecification(
  1884. REFIID riid,
  1885. IUnknown **ppSpecification
  1886. )
  1887. {
  1888. ADsAssert(m_pCRowsetInfo);
  1889. RRETURN( m_pCRowsetInfo->GetSpecification(
  1890. riid,
  1891. ppSpecification)
  1892. );
  1893. }
  1894. //----------------------------------------------------------------------------- // IRowsetLocate methods
  1895. //-----------------------------------------------------------------------------
  1896. STDMETHODIMP
  1897. CRowset::Compare(
  1898. HCHAPTER hChapter,
  1899. DBBKMARK cbBookmark1,
  1900. const BYTE *pBookmark1,
  1901. DBBKMARK cbBookmark2,
  1902. const BYTE *pBookmark2,
  1903. DBCOMPARE *pComparison
  1904. )
  1905. {
  1906. if( (0 == cbBookmark1) || (0 == cbBookmark2) || (NULL == pComparison) ||
  1907. (NULL == pBookmark1) || (NULL == pBookmark2) )
  1908. RRETURN( E_INVALIDARG );
  1909. if( STD_BMK_SIZE == cbBookmark1 )
  1910. {
  1911. if( (*pBookmark1 != DBBMK_FIRST) && (*pBookmark1 != DBBMK_LAST) )
  1912. RRETURN( DB_E_BADBOOKMARK );
  1913. }
  1914. else
  1915. if( ADSI_BMK_SIZE != cbBookmark1 )
  1916. RRETURN( DB_E_BADBOOKMARK );
  1917. if( STD_BMK_SIZE == cbBookmark2 )
  1918. {
  1919. if( (*pBookmark2 != DBBMK_FIRST) && (*pBookmark2 != DBBMK_LAST) )
  1920. RRETURN( DB_E_BADBOOKMARK );
  1921. }
  1922. else
  1923. if( ADSI_BMK_SIZE != cbBookmark2 )
  1924. RRETURN( DB_E_BADBOOKMARK );
  1925. if( (STD_BMK_SIZE == cbBookmark1) || (STD_BMK_SIZE == cbBookmark2) )
  1926. // standard bookmarks can only be compared for equality (not for <, >)
  1927. {
  1928. if( cbBookmark1 != cbBookmark2 )
  1929. *pComparison = DBCOMPARE_NE;
  1930. else if( *pBookmark1 == *pBookmark2 )
  1931. *pComparison = DBCOMPARE_EQ;
  1932. else
  1933. *pComparison = DBCOMPARE_NE;
  1934. }
  1935. else
  1936. {
  1937. if( (*((RBOOKMARK *)pBookmark1)) < (*((RBOOKMARK *)pBookmark2)) )
  1938. *pComparison = DBCOMPARE_LT;
  1939. else if( (*((RBOOKMARK *)pBookmark1)) > (*((RBOOKMARK *)pBookmark2)) )
  1940. *pComparison = DBCOMPARE_GT;
  1941. else
  1942. *pComparison = DBCOMPARE_EQ;
  1943. }
  1944. RRETURN( S_OK );
  1945. }
  1946. STDMETHODIMP
  1947. CRowset::Hash(
  1948. HCHAPTER hChapter,
  1949. DBBKMARK cBookmarks,
  1950. const DBBKMARK rgcbBookmarks[],
  1951. const BYTE *rgpBookmarks[],
  1952. DBHASHVALUE rgHashedValues[],
  1953. DBROWSTATUS rgBookmarkStatus[]
  1954. )
  1955. {
  1956. int i;
  1957. HRESULT hr;
  1958. DBBKMARK cErrors = 0;
  1959. if( (NULL == rgHashedValues) || ((cBookmarks != 0) &&
  1960. ((NULL == rgpBookmarks) || (NULL == rgcbBookmarks))) )
  1961. RRETURN( E_INVALIDARG );
  1962. if( 0 == cBookmarks )
  1963. RRETURN( S_OK );
  1964. for(i = 0; (DBBKMARK)i < cBookmarks; i++)
  1965. {
  1966. if( (rgcbBookmarks[i] != ADSI_BMK_SIZE) || (NULL == rgpBookmarks[i]) )
  1967. {
  1968. cErrors++;
  1969. if( rgBookmarkStatus )
  1970. rgBookmarkStatus[i] = DBROWSTATUS_E_INVALID;
  1971. }
  1972. else
  1973. {
  1974. LONG lRow;
  1975. hr = BmkToRow(rgcbBookmarks[i], rgpBookmarks[i], &lRow);
  1976. if( FAILED(hr) )
  1977. {
  1978. cErrors++;
  1979. if( rgBookmarkStatus )
  1980. rgBookmarkStatus[i] = DBROWSTATUS_E_INVALID;
  1981. continue;
  1982. }
  1983. rgHashedValues[i] = (DWORD) lRow;
  1984. if( rgBookmarkStatus )
  1985. rgBookmarkStatus[i] = DBROWSTATUS_S_OK;
  1986. }
  1987. }
  1988. if( cErrors )
  1989. {
  1990. if( cErrors == cBookmarks )
  1991. RRETURN( DB_E_ERRORSOCCURRED );
  1992. else
  1993. RRETURN( DB_S_ERRORSOCCURRED );
  1994. }
  1995. else
  1996. RRETURN( S_OK );
  1997. }
  1998. STDMETHODIMP
  1999. CRowset::GetRowsByBookmark(
  2000. HCHAPTER hChapter,
  2001. DBCOUNTITEM cRows,
  2002. const DBBKMARK rgcbBookmarks[],
  2003. const BYTE *rgpBookmarks[],
  2004. HROW rghRows[],
  2005. DBROWSTATUS rgRowStatus[]
  2006. )
  2007. {
  2008. int i;
  2009. HRESULT hr;
  2010. DBCOUNTITEM cRowsObtained = 0, cErrors = 0;
  2011. if( (NULL == rghRows) || (NULL == rgcbBookmarks) || (NULL== rgpBookmarks) )
  2012. RRETURN( E_INVALIDARG );
  2013. if( 0 == cRows )
  2014. RRETURN( S_OK );
  2015. for(i = 0; (DBCOUNTITEM)i < cRows; i++)
  2016. {
  2017. if( (rgcbBookmarks[i] != ADSI_BMK_SIZE) || (NULL == rgpBookmarks[i]) )
  2018. {
  2019. cErrors++;
  2020. if( rgRowStatus )
  2021. rgRowStatus[i] = DBROWSTATUS_E_INVALID;
  2022. rghRows[i] = DB_NULL_HROW;
  2023. }
  2024. else
  2025. {
  2026. HROW *phRow;
  2027. phRow = &rghRows[i];
  2028. hr = GetRowsAt(NULL, hChapter, rgcbBookmarks[i],
  2029. (BYTE *) rgpBookmarks[i], 0, 1, &cRowsObtained,
  2030. &phRow
  2031. );
  2032. if( 1 == cRowsObtained )
  2033. {
  2034. if( rgRowStatus )
  2035. rgRowStatus[i] = DBROWSTATUS_S_OK;
  2036. }
  2037. else
  2038. {
  2039. cErrors++;
  2040. rghRows[i] = DB_NULL_HROW;
  2041. if( rgRowStatus )
  2042. {
  2043. if( DB_S_ROWLIMITEXCEEDED == hr )
  2044. rgRowStatus[i] = DBROWSTATUS_E_LIMITREACHED;
  2045. else if ( E_OUTOFMEMORY == hr )
  2046. rgRowStatus[i] = DBROWSTATUS_E_OUTOFMEMORY;
  2047. else
  2048. rgRowStatus[i] = DBROWSTATUS_E_INVALID;
  2049. }
  2050. } // else
  2051. } // else
  2052. } // for
  2053. if( cErrors )
  2054. {
  2055. if( cErrors == cRows )
  2056. RRETURN( DB_E_ERRORSOCCURRED );
  2057. else
  2058. RRETURN( DB_S_ERRORSOCCURRED );
  2059. }
  2060. else
  2061. RRETURN( S_OK );
  2062. }
  2063. //----------------------------------------------------------------------------
  2064. // IRowsetScroll methods
  2065. //----------------------------------------------------------------------------
  2066. STDMETHODIMP
  2067. CRowset::GetApproximatePosition(
  2068. HCHAPTER hChapter,
  2069. DBBKMARK cbBookmark,
  2070. const BYTE *pBookmark,
  2071. DBCOUNTITEM *pulPosition,
  2072. DBCOUNTITEM *pcRows
  2073. )
  2074. {
  2075. LONG cRows = 0;
  2076. HRESULT hr;
  2077. if( (cbBookmark != 0) && ( NULL == pBookmark) )
  2078. RRETURN( E_INVALIDARG );
  2079. CAutoBlock cab(&m_RowsetCritSection);
  2080. if( pcRows )
  2081. // get the total number of rows in the rowset
  2082. {
  2083. hr = SeekToEnd();
  2084. if( FAILED(hr) )
  2085. RRETURN( E_FAIL );
  2086. cRows = m_lCurrentRow - 1;
  2087. }
  2088. if( 0 == cbBookmark )
  2089. {
  2090. if( pcRows )
  2091. *pcRows = cRows;
  2092. RRETURN( S_OK );
  2093. }
  2094. else if( (cbBookmark != ADSI_BMK_SIZE) && (cbBookmark != STD_BMK_SIZE) )
  2095. RRETURN( DB_E_BADBOOKMARK );
  2096. else
  2097. {
  2098. LONG lRow;
  2099. hr = BmkToRow(cbBookmark, pBookmark, &lRow);
  2100. if( FAILED(hr) )
  2101. {
  2102. if( DB_E_BADBOOKMARK == hr )
  2103. RRETURN( DB_E_BADBOOKMARK );
  2104. else
  2105. RRETURN( E_FAIL );
  2106. }
  2107. if( pulPosition )
  2108. {
  2109. *pulPosition = lRow + 1; // this number is 1-based
  2110. if( pcRows && (*pulPosition > (DBCOUNTITEM)cRows) ) // bookmark was bad
  2111. *pulPosition = cRows; // make sure *pulPosition <= *pcRows
  2112. }
  2113. if( pcRows )
  2114. *pcRows = cRows;
  2115. }
  2116. RRETURN( S_OK );
  2117. }
  2118. STDMETHODIMP
  2119. CRowset::GetRowsAtRatio(
  2120. HWATCHREGION hReserved1,
  2121. HCHAPTER hChapter,
  2122. DBCOUNTITEM ulNumerator,
  2123. DBCOUNTITEM ulDenominator,
  2124. DBROWCOUNT cRows,
  2125. DBCOUNTITEM *pcRowsObtained,
  2126. HROW **prghRows
  2127. )
  2128. {
  2129. HRESULT hr;
  2130. LONG lStartRow, cTotalRows;
  2131. RBOOKMARK StartRowBmk;
  2132. if( (NULL == pcRowsObtained) || (NULL == prghRows) )
  2133. {
  2134. if( pcRowsObtained != NULL )
  2135. *pcRowsObtained = 0;
  2136. RRETURN( E_INVALIDARG );
  2137. }
  2138. *pcRowsObtained = 0;
  2139. if( (ulNumerator > ulDenominator) || (0 == ulDenominator) )
  2140. RRETURN( DB_E_BADRATIO );
  2141. if( ((ulNumerator == ulDenominator) && (cRows > 0)) ||
  2142. ((0 == ulNumerator) && (cRows < 0)) )
  2143. RRETURN( DB_S_ENDOFROWSET );
  2144. if( 0 == cRows )
  2145. RRETURN( S_OK );
  2146. CAutoBlock cab(&m_RowsetCritSection);
  2147. // get total number of rows
  2148. hr = SeekToEnd();
  2149. if( FAILED(hr) )
  2150. RRETURN( E_FAIL );
  2151. cTotalRows = m_lCurrentRow - 1;
  2152. // Make sure ratio of 1 sets lStartRow to cTotalRows -1 (last row)
  2153. lStartRow = (long)((((double) ulNumerator)/ulDenominator) *
  2154. (cTotalRows - 1));
  2155. StartRowBmk = RowToBmk(lStartRow);
  2156. hr = GetRowsAt(NULL, hChapter, ADSI_BMK_SIZE, (BYTE *) &StartRowBmk,
  2157. 0, cRows, pcRowsObtained, prghRows);
  2158. RRETURN( hr );
  2159. }
  2160. //----------------------------------------------------------------------------