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.

736 lines
24 KiB

  1. //-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995
  5. //
  6. // File: caccess.cxx
  7. //
  8. // Contents: Microsoft OleDB/OleDS Data Source Object for ADSI
  9. //
  10. // CImpIAccessor object implementing the IAccessor interface.
  11. //
  12. // History: 10-01-96 shanksh Created.
  13. //-------------------------------------------------------------------------
  14. #include "oleds.hxx"
  15. #pragma hdrstop
  16. //-------------------------------------------------------------------------
  17. // CImpIAccessor::CImpIAccessor
  18. //
  19. // CImpIAccessor constructor.
  20. //
  21. //-------------------------------------------------------------------------
  22. CImpIAccessor::CImpIAccessor (
  23. void *pParentObj, //@parm IN | Parent object pointer
  24. LPUNKNOWN pUnkOuter //@parm IN | Outer Unknown pointer
  25. )
  26. {
  27. // Initialize simple member vars
  28. _pUnkOuter = pUnkOuter;
  29. _pObj = pParentObj;
  30. _pextbuffer = NULL;
  31. _dwStatus = 0;
  32. _pIDC = NULL;
  33. ENLIST_TRACKING(CImpIAccessor);
  34. // This section is for serializing &CreateAccessor.
  35. InitializeCriticalSection(&_criticalsectionAccessor);
  36. return;
  37. }
  38. //-------------------------------------------------------------------------
  39. // CImpIAccessor::~CImpIAccessor
  40. //
  41. // @mfunc CImpIAccessor destructor.
  42. //
  43. // @rdesc NONE
  44. //-------------------------------------------------------------------------
  45. CImpIAccessor::~CImpIAccessor (
  46. void
  47. )
  48. {
  49. ULONG_PTR hAccessor, hAccessorLast;
  50. PADSACCESSOR pADsaccessor, pADsaccessorBadHandle;
  51. // Cleanup only if there's anything to clean.
  52. if( _pextbuffer ) {
  53. // Get a pointer to the special "BadHandle" accessor.
  54. _pextbuffer->GetItemOfExtBuffer(hAccessorBadHandle, &pADsaccessorBadHandle);
  55. // Get the number of available accessor handles.
  56. _pextbuffer->GetLastItemHandle(hAccessorLast);
  57. // Loop through the reminding accessor handles deleting those which
  58. // are referenced only by this object and refcount decrementing the
  59. // other ones
  60. for (hAccessor =1; hAccessor <=hAccessorLast; hAccessor++) {
  61. // Get a pointer to the next accessor.
  62. _pextbuffer->GetItemOfExtBuffer(hAccessor, &pADsaccessor);
  63. // For valid accessors just delete them.
  64. if( pADsaccessor != pADsaccessorBadHandle )
  65. DeleteADsAccessor(pADsaccessor);
  66. }
  67. // Now delete the buffer which holds accessor handles.
  68. delete _pextbuffer;
  69. }
  70. if( _pIMalloc )
  71. _pIMalloc->Release();
  72. if( _pIDC )
  73. _pIDC->Release();
  74. // Get rid of the critical section.
  75. DeleteCriticalSection(&_criticalsectionAccessor);
  76. return;
  77. }
  78. //-------------------------------------------------------------------------
  79. // CImpIAccessor::FInit
  80. //
  81. // @mfunc Initialize the Accessor implementation object.
  82. //
  83. // @rdesc Did the Initialization Succeed
  84. // @flag S_OK initialization succeeded,
  85. // @flag E_OUTOFMEMORY initialization failed because of
  86. // memory allocation problem,
  87. //-------------------------------------------------------------------------
  88. STDMETHODIMP
  89. CImpIAccessor::FInit (
  90. void
  91. )
  92. {
  93. HRESULT hr;
  94. PADSACCESSOR pADsaccessorBadHandle;
  95. // Prepare a special, "Bad Handle" accessor.
  96. pADsaccessorBadHandle = (PADSACCESSOR)((BYTE *)&_dwGetDataTypeBadHandle);
  97. _dwGetDataTypeBadHandle = ACCESSORTYPE_INERROR;
  98. // Create the ExtBuffer array to hold pointers to malloc'd accessors.
  99. _pextbuffer = (LPEXTBUFF) new CExtBuff;
  100. if (_pextbuffer == NULL ||
  101. !(_pextbuffer->FInit(
  102. sizeof(PADSACCESSOR),
  103. &pADsaccessorBadHandle
  104. ) ))
  105. RRETURN( E_OUTOFMEMORY );
  106. if( !_pIDC ) {
  107. hr = CoCreateInstance(
  108. CLSID_OLEDB_CONVERSIONLIBRARY,
  109. NULL,
  110. CLSCTX_INPROC_SERVER,
  111. IID_IDataConvert,
  112. (void **)&_pIDC
  113. );
  114. if ( FAILED(hr) ) {
  115. RRETURN (hr);
  116. }
  117. }
  118. hr = CoGetMalloc(MEMCTX_TASK, &_pIMalloc);
  119. RRETURN (hr);
  120. }
  121. //-------------------------------------------------------------------------
  122. // CImpIAccessor::AddRefAccessor
  123. //
  124. // @mfunc Adds a reference count to an existing accessor.
  125. //
  126. // @rdesc Did release of the accessor Succeed
  127. // @flag S_OK | accessor addrefed successfully,
  128. // @flag DB_E_BADACCESSORHANDLE | accessor could not be addrefed
  129. // because its handle was invalid.
  130. //-------------------------------------------------------------------------
  131. STDMETHODIMP CImpIAccessor::AddRefAccessor(
  132. HACCESSOR hAccessor, //@parm IN | handle of the accessor to release
  133. DBREFCOUNT *pcRefCounts //@parm OUT | count of references
  134. )
  135. {
  136. PADSACCESSOR pADsaccessor, pADsaccessorBadHandle;
  137. HRESULT hr;
  138. // Clear in case of error below.
  139. if( pcRefCounts )
  140. *pcRefCounts = 0;
  141. CAutoBlock cab( &(_criticalsectionAccessor) );
  142. // Get a pointer to the accessor.
  143. _pextbuffer->GetItemOfExtBuffer(hAccessor, &pADsaccessor);
  144. // Get a pointer to the special "BadHandle" accessor.
  145. _pextbuffer->GetItemOfExtBuffer(hAccessorBadHandle, &pADsaccessorBadHandle);
  146. // If the handle is valid
  147. if (pADsaccessor != pADsaccessorBadHandle) {
  148. if (pADsaccessor->cRef <= 0)
  149. BAIL_ON_FAILURE( hr = E_FAIL );
  150. pADsaccessor->cRef++;
  151. if (pcRefCounts)
  152. *pcRefCounts = pADsaccessor->cRef;
  153. RRETURN( S_OK );
  154. }
  155. // otherwise complain about a bad handle.
  156. else
  157. RRETURN( DB_E_BADACCESSORHANDLE );
  158. error:
  159. RRETURN( hr );
  160. }
  161. //-------------------------------------------------------------------------
  162. // CImpIAccessor::CreateAccessor
  163. //
  164. // @mfunc Creates an accessor, which is a set of bindings that can be used to
  165. // send data to or retrieve data from the data cache. The method performs
  166. // extensive validations on the input bindings which include verification of
  167. // the access type requested, column availability, data conversions involved,
  168. // etc.
  169. //
  170. // @rdesc Returns one of the following values:
  171. // S_OK | creation of the accessor succeeded,
  172. // E_INVALIDARG | creation of the accessor failed because
  173. // phAccessor was a NULL pointer,
  174. // E_OUTOFMEMORY | creation of the accessor failed because of
  175. // memory allocation problem,
  176. // DB_E_CANTCREATEACCESSOR | DBROWSETFLAGS_MULTIPLEACCESSOR flag was not
  177. // set and a row-fetching method has already
  178. // been called.
  179. // OTHER | other result codes returned by called functions.
  180. //-------------------------------------------------------------------------
  181. STDMETHODIMP CImpIAccessor::CreateAccessor(
  182. DBACCESSORFLAGS dwAccessorFlags,
  183. DBCOUNTITEM cBindings,
  184. const DBBINDING rgBindings[],
  185. DBLENGTH cbRowSize,
  186. HACCESSOR *phAccessor,
  187. DBBINDSTATUS rgStatus[]
  188. )
  189. {
  190. PADSACCESSOR pADsaccessor;
  191. ULONG_PTR hADsaccessor;
  192. HRESULT hr;
  193. ULONG dwGetDataType, dwSetDataType;
  194. DBCOUNTITEM ibind;
  195. BOOL fProviderOwned;
  196. DBBINDSTATUS bindstatus;
  197. ULONG wMask, wBaseType;
  198. if (phAccessor)
  199. *phAccessor = (HACCESSOR)0;
  200. // At the creation of the CAutoBlock object a critical section
  201. // is entered. Concurrent calls to CreateAccessor are entirely
  202. // legal but their interleaving cannot be allowed. The critical
  203. // section is left when this method terminate and the destructor
  204. // for CAutoBlock is called.
  205. CAutoBlock cab( &(_criticalsectionAccessor) );
  206. // phAccessor must never be NULL, non-zero bindings count implies a
  207. // non-NULL array of bindings.
  208. if( phAccessor == NULL || (cBindings && rgBindings == NULL) )
  209. RRETURN( E_INVALIDARG );
  210. // cBindings is 0 and was called on the Command.
  211. if( cBindings == 0 )
  212. RRETURN( DB_E_NULLACCESSORNOTSUPPORTED );
  213. // dwAccessorFlags cannot take any other values than those legal.
  214. if( dwAccessorFlags & (~DBACCESSOR_VALID_FLAGS) )
  215. RRETURN( DB_E_BADACCESSORFLAGS );
  216. // Compute internal types for use by methods using accessors,
  217. DetermineTypes(
  218. dwAccessorFlags,
  219. &dwGetDataType,
  220. &dwSetDataType
  221. );
  222. // and detect possible inconsistencies in AccessorFlags.
  223. if( dwGetDataType == GD_ACCESSORTYPE_INERROR ||
  224. dwSetDataType == SD_ACCESSORTYPE_INERROR )
  225. RRETURN( DB_E_BADACCESSORFLAGS );
  226. // fix conformance test failure. If BYREF accessors are not supported,
  227. // (indicated by DBPROP_BYREFACCESSORS being FALSE), we should return
  228. // the right error
  229. else if( (DB_E_BYREFACCESSORNOTSUPPORTED == dwGetDataType) ||
  230. (DB_E_BYREFACCESSORNOTSUPPORTED == dwSetDataType) )
  231. RRETURN( DB_E_BYREFACCESSORNOTSUPPORTED );
  232. // Initialize the status array to DBBINDSTATUS_OK.
  233. if( rgStatus )
  234. memset(rgStatus, 0x00, (size_t)(cBindings*sizeof(DBBINDSTATUS)));
  235. hr = S_OK;
  236. fProviderOwned = FALSE;
  237. // Perform validations that apply to all types of accessors.
  238. for (ibind=0; ibind < cBindings; ibind++) {
  239. bindstatus = DBBINDSTATUS_OK;
  240. if( rgBindings[ibind].dwMemOwner != DBMEMOWNER_PROVIDEROWNED &&
  241. rgBindings[ibind].dwMemOwner != DBMEMOWNER_CLIENTOWNED )
  242. bindstatus = DBBINDSTATUS_BADBINDINFO;
  243. // The part to be bound must specify one or more out of three values, and
  244. if( (rgBindings[ibind].dwPart &
  245. (DBPART_VALUE |DBPART_LENGTH |DBPART_STATUS)) == 0 ||
  246. // nothing else.
  247. (rgBindings[ibind].dwPart &
  248. ~(DBPART_VALUE |DBPART_LENGTH |DBPART_STATUS)) ||
  249. // Is it a good type to bind to?
  250. !IsGoodBindingType(rgBindings[ibind].wType) )
  251. bindstatus = DBBINDSTATUS_BADBINDINFO;
  252. // DBTYPE_BYREF, DBTYPE_VECTOR and DBTYPE_ARRAY cannot be combined.
  253. else if( (wMask = (rgBindings[ibind].wType & TYPE_MODIFIERS)) &&
  254. wMask != DBTYPE_BYREF &&
  255. wMask != DBTYPE_VECTOR &&
  256. wMask != DBTYPE_ARRAY )
  257. bindstatus = DBBINDSTATUS_BADBINDINFO;
  258. else if ((wBaseType = (rgBindings[ibind].wType & ~TYPE_MODIFIERS)) ==
  259. DBTYPE_EMPTY ||
  260. wBaseType == DBTYPE_NULL)
  261. bindstatus = DBBINDSTATUS_BADBINDINFO;
  262. // DBTYPE_ARRAY and DBTYPE_VECTOR are not supported types
  263. else if( (rgBindings[ibind].wType & DBTYPE_ARRAY) ||
  264. (rgBindings[ibind].wType & DBTYPE_VECTOR) )
  265. bindstatus = DBBINDSTATUS_UNSUPPORTEDCONVERSION;
  266. // dwFlags was DBBINDFLAG_HTML and the type was not a String
  267. else if ( rgBindings[ibind].dwFlags &&
  268. (rgBindings[ibind].dwFlags != DBBINDFLAG_HTML ||
  269. (wBaseType != DBTYPE_STR &&
  270. wBaseType != DBTYPE_WSTR &&
  271. wBaseType != DBTYPE_BSTR)) )
  272. {
  273. // Set Bind status to DBBINDSTATUS_BADBINDINFO
  274. bindstatus = DBBINDSTATUS_BADBINDINFO;
  275. }
  276. else if( rgBindings[ibind].wType == (DBTYPE_RESERVED | DBTYPE_BYREF) )
  277. bindstatus = DBBINDSTATUS_BADBINDINFO;
  278. else if( rgBindings[ibind].dwMemOwner == DBMEMOWNER_PROVIDEROWNED ) {
  279. if( (rgBindings[ibind].wType & TYPE_MODIFIERS) == 0
  280. && rgBindings[ibind].wType != DBTYPE_BSTR )
  281. bindstatus = DBBINDSTATUS_BADBINDINFO;
  282. else
  283. fProviderOwned = TRUE;
  284. }
  285. if( bindstatus != DBBINDSTATUS_OK )
  286. hr = DB_E_ERRORSOCCURRED;
  287. if( rgStatus )
  288. rgStatus[ibind] = bindstatus;
  289. }
  290. // Check for errors in the bindings
  291. BAIL_ON_FAILURE( hr );
  292. if( fProviderOwned &&
  293. (dwGetDataType == GD_ACCESSORTYPE_READ ||
  294. dwGetDataType == GD_ACCESSORTYPE_READ_OPTIMIZED) )
  295. dwGetDataType = GD_ACCESSORTYPE_READ_COLS_BYREF;
  296. // Allocate space for the accessor structure.
  297. pADsaccessor = (ADSACCESSOR *) new BYTE
  298. [(size_t)(sizeof(ADSACCESSOR) + (cBindings ? (cBindings-1) : 0)*
  299. sizeof(DBBINDING))];
  300. if( pADsaccessor == NULL )
  301. RRETURN( E_OUTOFMEMORY );
  302. if( cBindings )
  303. memcpy(
  304. &(pADsaccessor->rgBindings[0]),
  305. &rgBindings[0],
  306. (size_t)(cBindings*sizeof(DBBINDING))
  307. );
  308. pADsaccessor->cBindings = cBindings;
  309. // For accessors valid for writing fill out a list of columns
  310. // so that notifications about their changes can be properly issued.
  311. if( dwSetDataType == SD_ACCESSORTYPE_READWRITE && cBindings ) {
  312. pADsaccessor->rgcol = new DBORDINAL [ (size_t)cBindings ];
  313. if( pADsaccessor->rgcol == NULL ) {
  314. dwSetDataType = SD_ACCESSORTYPE_INERROR;
  315. }
  316. else
  317. for (ibind =0; ibind <cBindings; ibind++)
  318. (pADsaccessor->rgcol)[ibind] = rgBindings[ibind].iOrdinal;
  319. }
  320. else
  321. pADsaccessor->rgcol = NULL;
  322. // Allocate DBOBJECT structures supporting IUnknown types.
  323. for (ibind =0; ibind <cBindings; ibind++)
  324. pADsaccessor->rgBindings[ibind].pObject = NULL;
  325. // Set accessor flags now, so that possible accessor cleanup routine would
  326. // know about additional structures for IUnknown types support.
  327. pADsaccessor->dwFlags = dwAccessorFlags;
  328. // Insert the new accessor pointer into the extensible buffer in which
  329. // accessors are stored.
  330. if( FAILED(hr = _pextbuffer->InsertIntoExtBuffer(
  331. &pADsaccessor,
  332. hADsaccessor
  333. )) ) {
  334. DeleteADsAccessor(pADsaccessor);
  335. RRETURN (hr);
  336. }
  337. pADsaccessor->cRef = 1;
  338. // Fill out the new accessor structure with the binding info.
  339. //pADsaccessor->obRowData = obRowData;
  340. pADsaccessor->cbRowSize = cbRowSize;
  341. // Return the accessor index in the extensible buffer as the accessor
  342. // handle.
  343. *phAccessor = (HACCESSOR) hADsaccessor;
  344. // Now can safely leave.
  345. RRETURN( NOERROR );
  346. error:
  347. RRETURN( hr );
  348. }
  349. //-------------------------------------------------------------------------
  350. // CImpIAccessor::DetermineTypes
  351. //
  352. // @mfunc Determines internal accessor type classification for use by GetData,
  353. // SetData and parameter handling code. Each of these has a separate type indicator
  354. // variable and a separate set of defined types. This allows a very efficient
  355. // handling of different accessors by methods that utilize them.
  356. // Types are determined on the basis of AccessorFlags. Incorrect combinations of
  357. // flags result in assignment of INERROR types.
  358. //
  359. // @rdesc NONE
  360. //-------------------------------------------------------------------------
  361. STDMETHODIMP_(void)
  362. CImpIAccessor::DetermineTypes(
  363. DBACCESSORFLAGS dwAccessorFlags,
  364. ULONG *pdwGetDataType,
  365. ULONG *pdwSetDataType
  366. )
  367. {
  368. if( dwAccessorFlags & DBACCESSOR_PASSBYREF )
  369. {
  370. *pdwGetDataType = (ULONG) DB_E_BYREFACCESSORNOTSUPPORTED;
  371. *pdwSetDataType = (ULONG) DB_E_BYREFACCESSORNOTSUPPORTED;
  372. return;
  373. }
  374. else if( dwAccessorFlags & DBACCESSOR_PARAMETERDATA )
  375. {
  376. *pdwGetDataType = GD_ACCESSORTYPE_INERROR;
  377. *pdwSetDataType = GD_ACCESSORTYPE_INERROR;
  378. return;
  379. }
  380. // Determine types used in row data manipulations.
  381. if( dwAccessorFlags & DBACCESSOR_ROWDATA ) {
  382. // Determine accessor type from the point of
  383. // view of GetData.
  384. if( dwAccessorFlags & DBACCESSOR_OPTIMIZED )
  385. *pdwGetDataType = GD_ACCESSORTYPE_READ_OPTIMIZED;
  386. else
  387. *pdwGetDataType = GD_ACCESSORTYPE_READ;
  388. // Determine accessor type from the point of
  389. // view of SetData. PASSBYREF is disallowed.
  390. *pdwSetDataType = SD_ACCESSORTYPE_READWRITE;
  391. }
  392. else {
  393. *pdwGetDataType = GD_ACCESSORTYPE_INERROR;
  394. *pdwSetDataType = GD_ACCESSORTYPE_INERROR;
  395. }
  396. return;
  397. }
  398. //-------------------------------------------------------------------------
  399. // CImpIAccessor::GetBindings
  400. //
  401. // @mfunc Returns bindings of an accessor.
  402. //
  403. // @rdesc Returns one of the following values:
  404. // S_OK | getting bindings succeeded,
  405. // E_INVALIDARG | getting bindings failed because
  406. // pdwAccessorFlags or pcBindings or
  407. // prgBindings was a NULL pointer,
  408. // E_OUTOFMEMORY | getting bindings failed because memory
  409. // allocation for the bindings array failed,
  410. // OTHER | other result codes stored on the accessor
  411. // object and singifying invalid accessor handle.
  412. //-------------------------------------------------------------------------
  413. STDMETHODIMP CImpIAccessor::GetBindings
  414. (
  415. HACCESSOR hAccessor, // IN | accessor handle
  416. DBACCESSORFLAGS *pdwAccessorFlags, // OUT | stores accessor flags
  417. DBCOUNTITEM *pcBindings, // OUT | stores # of bindings
  418. DBBINDING **prgBindings // OUT | stores array of bindings
  419. )
  420. {
  421. PADSACCESSOR pADsaccessor;
  422. PADSACCESSOR pADsaccessorBadHandle;
  423. DBCOUNTITEM ibind;
  424. DBOBJECT *pObject;
  425. if( pcBindings )
  426. *pcBindings = 0;
  427. if( prgBindings )
  428. *prgBindings = NULL;
  429. if( pdwAccessorFlags )
  430. *pdwAccessorFlags = DBACCESSOR_INVALID;
  431. // Are arguments valid?
  432. if( pdwAccessorFlags == NULL || pcBindings == NULL || prgBindings == NULL )
  433. RRETURN( E_INVALIDARG );
  434. // Obtain pointer to the accessor to be used.
  435. _pextbuffer->GetItemOfExtBuffer(hAccessor, &pADsaccessor);
  436. // Get a pointer to the special "BadHandle" accessor.
  437. _pextbuffer->GetItemOfExtBuffer(hAccessorBadHandle, &pADsaccessorBadHandle);
  438. // Recognize bad accessor handles and return appropriate HRESULT.
  439. if( pADsaccessor == pADsaccessorBadHandle )
  440. return DB_E_BADACCESSORHANDLE;
  441. // If necessary allocate the array of binding structures.
  442. if( pADsaccessor->cBindings ) {
  443. *prgBindings = (DBBINDING *) _pIMalloc->Alloc((ULONG)(
  444. pADsaccessor->cBindings*sizeof(DBBINDING) ));
  445. if( *prgBindings == NULL )
  446. RRETURN ( E_OUTOFMEMORY );
  447. // Copy bindings.
  448. memcpy(
  449. *prgBindings,
  450. pADsaccessor->rgBindings,
  451. (size_t)(pADsaccessor->cBindings*sizeof(DBBINDING))
  452. );
  453. // Loop through bindings and allocate and copy DBOBJECT structs.
  454. for (ibind=0; ibind <pADsaccessor->cBindings; ibind++) {
  455. // If the accessor had failed bindings for SetData, we have
  456. // overloaded an unused structure member with status info, and
  457. // this needs to be cleaned now.
  458. (*prgBindings)[ibind].pTypeInfo = NULL;
  459. if( (*prgBindings)[ibind].pObject ) {
  460. pObject = (DBOBJECT *) _pIMalloc->Alloc( sizeof(DBOBJECT) );
  461. if( pObject ) {
  462. memcpy(
  463. pObject,
  464. (*prgBindings)[ibind].pObject,
  465. sizeof(DBOBJECT)
  466. );
  467. (*prgBindings)[ibind].pObject = pObject;
  468. }
  469. else {
  470. while (ibind--)
  471. if( (*prgBindings)[ibind].pObject )
  472. _pIMalloc->Free((*prgBindings)[ibind].pObject);
  473. _pIMalloc->Free( *prgBindings );
  474. *prgBindings = NULL;
  475. RRETURN( E_OUTOFMEMORY );
  476. }
  477. }
  478. }
  479. }
  480. // Return the count of bindings,
  481. *pcBindings = pADsaccessor->cBindings;
  482. // and accessor flags.
  483. *pdwAccessorFlags = (pADsaccessor->dwFlags & ~DBACCESSOR_REFERENCES_BLOB);
  484. return S_OK;
  485. }
  486. //-------------------------------------------------------------------------
  487. // CImpIAccessor::ReleaseAccessor
  488. //
  489. // @mfunc Releases accessor. If accessor handle is valid the corresponding accessor
  490. // is either freed (if no one else is using it) or its ref count is decremented.
  491. //
  492. // @rdesc Did release of the accessor Succeed
  493. // @flag S_OK | accessor released successfully,
  494. // @flag DB_E_BADACCESSORHANDLE | accessor could not be released because its
  495. // | handle was invalid.
  496. //-------------------------------------------------------------------------
  497. STDMETHODIMP CImpIAccessor::ReleaseAccessor
  498. (
  499. HACCESSOR hAccessor, //@parm IN | handle of the accessor to release
  500. DBREFCOUNT *pcRefCounts //@parm OUT | ref count of the released accessor
  501. )
  502. {
  503. PADSACCESSOR pADsaccessor, pADsaccessorBadHandle;
  504. if( pcRefCounts )
  505. *pcRefCounts = 0;
  506. CAutoBlock cab( &(_criticalsectionAccessor) );
  507. // Get a pointer to the accessor.
  508. _pextbuffer->GetItemOfExtBuffer(hAccessor, &pADsaccessor);
  509. // Get a pointer to the special "BadHandle" accessor.
  510. _pextbuffer->GetItemOfExtBuffer(hAccessorBadHandle, &pADsaccessorBadHandle);
  511. // If the handle is valid
  512. if( pADsaccessor != pADsaccessorBadHandle ) {
  513. ADsAssert(pADsaccessor->cRef > 0);
  514. // Delete if no one else is using it, otherwise
  515. if( pADsaccessor->cRef == 1 ) {
  516. // Delete the accessor structure itself, as well as allocations
  517. // hanging off this structure.
  518. DeleteADsAccessor(pADsaccessor);
  519. // Make sure this handle is marked as "Bad" for future.
  520. _pextbuffer->DeleteFromExtBuffer(hAccessor);
  521. }
  522. // decrement the refcount.
  523. else {
  524. pADsaccessor->cRef--;
  525. if( pcRefCounts )
  526. *pcRefCounts = pADsaccessor->cRef;
  527. }
  528. return NOERROR;
  529. }
  530. // otherwise complain about a bad handle.
  531. else
  532. RRETURN( DB_E_BADACCESSORHANDLE );
  533. }
  534. //-------------------------------------------------------------------------
  535. // CImpIAccessor::DeleteADsAccessor
  536. //
  537. // @mfunc Deletes structures hanging off the ADSACCESSOR and then deletes the
  538. // accessor structure itself.
  539. //
  540. // @rdesc NONE
  541. //-------------------------------------------------------------------------
  542. STDMETHODIMP_(void) CImpIAccessor::DeleteADsAccessor
  543. (
  544. PADSACCESSOR pADsaccessor //@parm IN | Kagera accessor ptr
  545. )
  546. {
  547. DBCOUNTITEM ibind;
  548. // Delete the list of affected columns.
  549. if( pADsaccessor->rgcol )
  550. delete [] pADsaccessor->rgcol;
  551. // If the accessor references BLOBS then DBOBJECT structures describing
  552. // objects dealing with BLOBS need to be deallocated.
  553. for (ibind =0; ibind <pADsaccessor->cBindings; ibind++)
  554. if( pADsaccessor->rgBindings[ibind].pObject )
  555. delete pADsaccessor->rgBindings[ibind].pObject;
  556. delete [] pADsaccessor;
  557. }
  558. STDMETHODIMP
  559. CImpIAccessor::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  560. {
  561. // Is the pointer bad?
  562. if( ppv == NULL )
  563. RRETURN( E_INVALIDARG );
  564. // Place NULL in *ppv in case of failure
  565. *ppv = NULL;
  566. if( IsEqualIID(iid, IID_IUnknown) ) {
  567. *ppv = (IAccessor FAR *) this;
  568. }
  569. else if( IsEqualIID(iid, IID_IAccessor) ) {
  570. *ppv = (IAccessor FAR *) this;
  571. }
  572. else {
  573. RRETURN( E_NOINTERFACE );
  574. }
  575. AddRef();
  576. return S_OK;
  577. }
  578. //---------------------------------------------------------------------------
  579. // CreateBadAccessor
  580. //
  581. // Inserts a bad accessor into the array of accessors (indexed by accessor
  582. // handles). This is required so that inheritance of accessors from commands
  583. // works correctly. If there are any 'holes' in the command's array of
  584. // accessors, then a rowset created from the command should also inherit these
  585. // 'holes' i,e, the array of accessor handles should not be compacted to
  586. // eliminate these holes. This is done using this function.
  587. //
  588. //---------------------------------------------------------------------------
  589. HRESULT
  590. CImpIAccessor::CreateBadAccessor(void)
  591. {
  592. PADSACCESSOR pADsaccessorBadHandle;
  593. ULONG_PTR hADsaccessor;
  594. HRESULT hr;
  595. // Get a pointer to the special "BadHandle" accessor.
  596. _pextbuffer->GetItemOfExtBuffer(hAccessorBadHandle, &pADsaccessorBadHandle);
  597. // ignore the returned accessor handle
  598. hr = _pextbuffer->InsertIntoExtBuffer(
  599. &pADsaccessorBadHandle, hADsaccessor);
  600. RRETURN( hr );
  601. }
  602. //---------------------------------------------------------------------------