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.

2216 lines
76 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 2000.
  5. //
  6. // File: hraccess.cxx
  7. //
  8. // Contents: OLE DB HRow accessor helper class
  9. //
  10. // Classes: CAccessor
  11. // CRowDataAccessor
  12. // CRowDataAccessorByRef
  13. //
  14. // History: 21 Nov 94 dlee Created from AlanW's tblwindo code
  15. //
  16. //--------------------------------------------------------------------------
  17. #include <pch.cxx>
  18. #pragma hdrstop
  19. #include <rowset.hxx>
  20. #include <query.hxx>
  21. #include "tabledbg.hxx"
  22. //+-------------------------------------------------------------------------
  23. //
  24. // Member: CAccessorBag::Destroy, private
  25. //
  26. // Synopsis: Removes an accessor from the bag and deletes it
  27. //
  28. // History: 12 Jan 1995 dlee Created
  29. //
  30. //--------------------------------------------------------------------------
  31. void CAccessorBag::Destroy(
  32. CAccessorBase * pAccessor )
  33. {
  34. pAccessor->SetInvalid();
  35. Remove(pAccessor);
  36. TRY
  37. {
  38. while (pAccessor->GetRefcount() > 0)
  39. pAccessor->Release(); // this can throw - we'll toss away error
  40. }
  41. CATCH( CException, e )
  42. {
  43. SCODE sc = GetOleError(e);
  44. tbDebugOut(( DEB_ERROR, "CAccessorBase::Release threw 0x%x\n", sc ));
  45. }
  46. END_CATCH;
  47. if (0 == pAccessor->GetInheritorCount() )
  48. delete pAccessor;
  49. } //Destroy
  50. //+-------------------------------------------------------------------------
  51. //
  52. // Member: CAccessorBag::~CAccessorBag, private
  53. //
  54. // Synopsis: Removes accessors the user forgot to free
  55. //
  56. // History: 16 Jan 1997 dlee Created
  57. //
  58. //--------------------------------------------------------------------------
  59. CAccessorBag::~CAccessorBag()
  60. {
  61. CAccessorBase *p;
  62. while ( p = First() )
  63. {
  64. tbDebugOut(( DEB_ITRACE,
  65. "App bug: Deleting an accessor that wasn't freed\n" ));
  66. Destroy( p );
  67. }
  68. } //~CAccessorBag
  69. //+-------------------------------------------------------------------------
  70. //
  71. // Member: CAccessorBag::Release, public
  72. //
  73. // Synopsis: Dereference an accessor; delete it if refcount goes to 0
  74. //
  75. // History: 18 Sep 1996 Alanw Created
  76. //
  77. //--------------------------------------------------------------------------
  78. void CAccessorBag::Release(HACCESSOR hAccessor, ULONG * pcRef)
  79. {
  80. CAccessorBase *pAccessor = Convert(hAccessor); // will throw if accessor invalid
  81. // caught by ReleaseAccessor
  82. if (0 == pAccessor->Release())
  83. {
  84. Destroy(pAccessor);
  85. if (pcRef)
  86. *pcRef = 0;
  87. }
  88. else
  89. {
  90. if (pcRef)
  91. *pcRef = pAccessor->GetRefcount();
  92. }
  93. } //Release
  94. //+-------------------------------------------------------------------------
  95. //
  96. // Member: CAccessorBag::AddRef, public
  97. //
  98. // Synopsis: Adds a reference to an accessor
  99. //
  100. // History: 18 Sep 1996 Alanw Created
  101. //
  102. //--------------------------------------------------------------------------
  103. void CAccessorBag::AddRef(HACCESSOR hAccessor, ULONG * pcRef)
  104. {
  105. CAccessorBase *pAccessor = Convert(hAccessor);
  106. ULONG cRef = pAccessor->AddRef();
  107. if (pcRef)
  108. *pcRef = cRef;
  109. } //AddRef
  110. // This pool has no private data -- it just calls the OLE allocator, so
  111. // it can be static.
  112. CAccessorAllocator CAccessor::_Pool;
  113. //+-------------------------------------------------------------------------
  114. //
  115. // Function: isVariableLength
  116. //
  117. // Synopsis: TRUE if the type is one of the odd oledb types that can
  118. // have variable length inline data
  119. //
  120. // Arguments: [type] -- oledb data type
  121. //
  122. // History: 6 Feb 95 dlee created
  123. //
  124. //--------------------------------------------------------------------------
  125. static BOOL isVariableLength( DWORD type )
  126. {
  127. type &= VT_TYPEMASK;
  128. return type == DBTYPE_STR ||
  129. type == DBTYPE_BYTES ||
  130. type == DBTYPE_WSTR;
  131. } //isVariableLength
  132. //+-------------------------------------------------------------------------
  133. //
  134. // Function: isValidByRef
  135. //
  136. // Synopsis: TRUE if the type is one of the odd oledb types that can
  137. // be combined with DBTYPE_BYREF
  138. //
  139. // Arguments: [type] -- oledb data type
  140. //
  141. // History: 9 Aug 95 dlee created
  142. //
  143. //--------------------------------------------------------------------------
  144. static BOOL isValidByRef( DWORD type )
  145. {
  146. type &= ~DBTYPE_BYREF;
  147. return type == DBTYPE_STR ||
  148. type == DBTYPE_WSTR ||
  149. type == DBTYPE_BYTES ||
  150. type == DBTYPE_GUID ||
  151. type == VT_CF ||
  152. type == DBTYPE_VARIANT;
  153. } //isValidByref
  154. //+-------------------------------------------------------------------------
  155. //
  156. // Function: isEquivalentType
  157. //
  158. // Synopsis: TRUE if the types are interchangable between OLE-DB and
  159. // PROPVARIANT. Unfortunately, several of the types are
  160. // equivalent but have different representations.
  161. //
  162. // Arguments: [vtDst] -- OLE-DB destination type
  163. // [vtSrc] -- PROPVARIANT source type
  164. //
  165. // History: 9 Aug 95 dlee created
  166. //
  167. //--------------------------------------------------------------------------
  168. static BOOL isEquivalentType( VARTYPE vtDst, VARTYPE vtSrc )
  169. {
  170. return ( ( vtDst == vtSrc ) ||
  171. ( ( ( DBTYPE_WSTR | DBTYPE_BYREF ) == vtDst ) &&
  172. ( VT_LPWSTR == vtSrc ) ) ||
  173. ( ( ( DBTYPE_STR | DBTYPE_BYREF ) == vtDst ) &&
  174. ( VT_LPSTR == vtSrc ) ) ||
  175. ( ( ( DBTYPE_WSTR | DBTYPE_BYREF | DBTYPE_VECTOR ) == vtDst ) &&
  176. ( ( VT_LPWSTR | VT_VECTOR ) == vtSrc ) ) ||
  177. ( ( ( DBTYPE_STR | DBTYPE_BYREF | DBTYPE_VECTOR ) == vtDst ) &&
  178. ( ( VT_LPSTR | VT_VECTOR ) == vtSrc ) ) ||
  179. ( ( ( DBTYPE_GUID | DBTYPE_BYREF ) == vtDst ) &&
  180. ( VT_CLSID == vtSrc ) ) ||
  181. ( ( ( VT_CF | DBTYPE_BYREF ) == vtDst ) &&
  182. ( VT_CF == vtSrc ) ) );
  183. } //isEquivalentType
  184. //+-------------------------------------------------------------------------
  185. //
  186. // Function: NullOrCantConvert, inline
  187. //
  188. // Synopsis: Returns DBSTATUS_S_ISNULL if [type] is one of the types which
  189. // represent null data, DBSTATUS_E_CANTCONVERTVALUE otherwise.
  190. //
  191. // Arguments: [type] -- variant data type
  192. //
  193. // History: 24 Feb 98 AlanW created
  194. //
  195. //--------------------------------------------------------------------------
  196. inline DBSTATUS NullOrCantConvert( VARTYPE type )
  197. {
  198. if ( type == VT_EMPTY || type == VT_NULL )
  199. return DBSTATUS_S_ISNULL;
  200. else
  201. return DBSTATUS_E_CANTCONVERTVALUE;
  202. } //NullOrCantConvert
  203. //+---------------------------------------------------------------------------
  204. //
  205. // Function: ConvertBackslashToSlash, inline
  206. //
  207. // Synopsis: Converts '\' characters to '/' in a string inplace.
  208. //
  209. // Arguments: [pwszPath] -- string to be converted
  210. //
  211. // History: 24 Feb 98 AlanW Added header
  212. //
  213. //----------------------------------------------------------------------------
  214. inline void ConvertBackslashToSlash( LPWSTR pwszPath )
  215. {
  216. Win4Assert( 0 != pwszPath );
  217. while ( 0 != *pwszPath )
  218. {
  219. if ( L'\\' == *pwszPath )
  220. {
  221. *pwszPath = L'/';
  222. }
  223. pwszPath++;
  224. }
  225. } //ConvertBackslashToSlash
  226. // DBGP - a debug parameter, only available on checked builds
  227. #ifndef DBGP
  228. #if DBG == 1
  229. #define DBGP(a) , a
  230. #else
  231. #define DBGP(a)
  232. #endif // DBG
  233. #endif // ndef DBGP
  234. //+-------------------------------------------------------------------------
  235. //
  236. // Member: CAccessor::_BindingFailed, private
  237. //
  238. // Synopsis: Stores a binding status for an individual binding error.
  239. // The caller should continue processing with the next binding.
  240. //
  241. // Arguments: [BindStat] -- what when wrong?
  242. // [iBinding] -- which binding was bad?
  243. // [pBindStatus] -- where to indicate bad binding
  244. //
  245. // History: 6 Feb 95 dlee created
  246. //
  247. //--------------------------------------------------------------------------
  248. void CAccessor::_BindingFailed(
  249. DBBINDSTATUS BindStat,
  250. DBORDINAL iBinding,
  251. DBBINDSTATUS* pBindStatus
  252. DBGP(char* pszExplanation)
  253. )
  254. {
  255. tbDebugOut(( DEB_TRACE,
  256. "CAccessor: construction failed, bindstatus=%x, binding %d\n",
  257. BindStat, iBinding ));
  258. #if DBG == 1
  259. if (pszExplanation)
  260. {
  261. tbDebugOut(( DEB_TRACE|DEB_NOCOMPNAME, "\t%s\n", pszExplanation ));
  262. }
  263. #endif // DBG
  264. if (pBindStatus != 0)
  265. {
  266. pBindStatus[iBinding] = BindStat;
  267. }
  268. _scStatus = DB_E_ERRORSOCCURRED;
  269. } //_BindingFailed
  270. //+-------------------------------------------------------------------------
  271. //
  272. // Member: CAccessor::_ConstructorFailed, private
  273. //
  274. // Synopsis: Indicate an error with parameters other than an individual
  275. // binding. Throw an exception for the error.
  276. //
  277. // Arguments: [scFailure] -- what when wrong?
  278. //
  279. // History: 16 Sep 1996 AlanW created
  280. //
  281. //--------------------------------------------------------------------------
  282. void CAccessor::_ConstructorFailed(
  283. SCODE scFailure
  284. DBGP(char* pszExplanation)
  285. )
  286. {
  287. tbDebugOut(( DEB_TRACE,
  288. "CAccessor: construction failed, sc=%x\n",
  289. scFailure ));
  290. #if DBG == 1
  291. if (pszExplanation)
  292. {
  293. tbDebugOut(( DEB_TRACE|DEB_NOCOMPNAME, "\t%s\n", pszExplanation ));
  294. }
  295. #endif // DBG
  296. _scStatus = scFailure;
  297. QUIETTHROW(CException(scFailure));
  298. } //_ConstructorFailed
  299. static const GUID s_guidStorage = PSGUID_STORAGE;
  300. static const GUID s_guidQuery = DBQUERYGUID;
  301. const DBORDINAL colInvalid = -1;
  302. //+---------------------------------------------------------------------------
  303. //
  304. // Member: CAccessor::_Initialize
  305. //
  306. // Synopsis: Initializes the object without verifying the coercions.
  307. //
  308. // Arguments: [dwAccessorFlags] - accessor flags, read/write, etc.
  309. // [cBindings] - count of bindings
  310. // [rgBindings] - array of binding structures
  311. // [pBindStat] - on return, pointer to first binding in error
  312. //
  313. // History: 21 Nov 94 dlee created
  314. // 11-07-95 srikants Moved from constructor
  315. //
  316. // Notes:
  317. //
  318. //----------------------------------------------------------------------------
  319. void CAccessor::_Initialize(
  320. DBACCESSORFLAGS dwAccessorFlags,
  321. DBORDINAL cBindings,
  322. const DBBINDING * rgBindings,
  323. DBBINDSTATUS * pBindStat)
  324. {
  325. // Invalid accessor flag?
  326. if ( dwAccessorFlags & ~ ( DBACCESSOR_PASSBYREF |
  327. DBACCESSOR_ROWDATA |
  328. DBACCESSOR_PARAMETERDATA |
  329. DBACCESSOR_OPTIMIZED) )
  330. _ConstructorFailed(DB_E_BADACCESSORFLAGS
  331. DBGP("bad dwAccessorFlags bits"));
  332. if ( (dwAccessorFlags & ( DBACCESSOR_ROWDATA | DBACCESSOR_PARAMETERDATA ) )
  333. == 0)
  334. _ConstructorFailed(DB_E_BADACCESSORFLAGS
  335. DBGP("bad dwAccessorFlags type"));
  336. if ( dwAccessorFlags & DBACCESSOR_PARAMETERDATA )
  337. _ConstructorFailed(DB_E_BADACCESSORFLAGS
  338. DBGP("parameter accessors are not supported"));
  339. // byref accessors are not supported
  340. if ( dwAccessorFlags & ( DBACCESSOR_PASSBYREF) )
  341. _ConstructorFailed(DB_E_BYREFACCESSORNOTSUPPORTED
  342. DBGP("byref accessors are not supported"));
  343. // null accessors are not supported
  344. if ( 0 == _cBindings )
  345. _ConstructorFailed(DB_E_NULLACCESSORNOTSUPPORTED
  346. DBGP("null accessors are not supported"));
  347. // verify each binding is ok and save it
  348. for (DBORDINAL iBinding = 0; iBinding < _cBindings; iBinding++)
  349. {
  350. CDataBinding DataBinding (rgBindings[iBinding]);
  351. DBPART cp = DataBinding.Binding().dwPart;
  352. DBTYPE wType = DataBinding.Binding().wType;
  353. if (0 != pBindStat)
  354. pBindStat[iBinding] = DBBINDSTATUS_OK;
  355. // check for invalid bits in the column parts
  356. if (cp &
  357. ~(DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS))
  358. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  359. DBGP("bad dwPart bits"));
  360. // at least one of value, length or status flags must be on
  361. if (0 == (cp & (DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS)))
  362. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  363. DBGP("zero dwPart"));
  364. // we don't support abstract data types
  365. if (0 != DataBinding.Binding().pTypeInfo)
  366. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  367. DBGP("bad pTypeInfo"));
  368. if (0 != DataBinding.Binding().pBindExt)
  369. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  370. DBGP("bad pBindExt"));
  371. if (0 != (DataBinding.Binding().dwFlags & DBBINDFLAG_HTML))
  372. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  373. DBGP("no HTML binding support"));
  374. else if (0 != DataBinding.Binding().dwFlags)
  375. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  376. DBGP("bad dwFlags"));
  377. //
  378. // Verify size and alignment of output buffer. Set cbWidth in local
  379. // copy of binding to handle length of fixed-width types correctly.
  380. //
  381. if ( 0 != ( wType & DBTYPE_BYREF ) )
  382. {
  383. if ( ! isValidByRef( wType ) )
  384. _BindingFailed( DBBINDSTATUS_BADBINDINFO,
  385. iBinding,
  386. pBindStat
  387. DBGP("byref on non-byref type") );
  388. // byref data: client's cbMaxLen is noise
  389. DataBinding.SetMaxLen(sizeof LPWSTR);
  390. }
  391. else if ( 0 != ( wType & DBTYPE_VECTOR ) )
  392. {
  393. USHORT cbWidth = sizeof ( DBVECTOR );
  394. USHORT cbAlign = sizeof ( DBVECTOR );
  395. #if CIDBG==1
  396. tbDebugOut(( DEB_ACCESSOR,
  397. "type %d, obValue %d, alignment needed: %d\n",
  398. (int) wType,
  399. (int) DataBinding.Binding().obValue,
  400. (int) cbAlign ));
  401. //Win4Assert( (0 == (DBPART_VALUE & cp)) ||
  402. // ( (0 != cbAlign) &&
  403. // (0 == (DataBinding.Binding().obValue % cbAlign)) ) );
  404. if ( (DBPART_VALUE & cp) &&
  405. (0 != (DataBinding.Binding().obValue % cbAlign)) )
  406. {
  407. tbDebugOut(( DEB_ERROR,
  408. "bad value alignment for DBVECTOR, obValue %d, alignment needed: %d\n",
  409. (int) DataBinding.Binding().obValue,
  410. (int) cbAlign ));
  411. }
  412. #endif // CIDBG==1
  413. // Fixed-length data types needn't have their width set, per
  414. // the Nile spec. So we set it to the default for the type.
  415. DataBinding.SetMaxLen( cbWidth );
  416. }
  417. else if ( 0 != ( wType & VT_ARRAY ) )
  418. {
  419. DataBinding.SetMaxLen( sizeof( SAFEARRAY * ) );
  420. }
  421. else
  422. {
  423. USHORT cbWidth,cbAlign,gfFlags;
  424. CTableVariant::VartypeInfo( wType,
  425. cbWidth,
  426. cbAlign,
  427. gfFlags );
  428. #if CIDBG==1
  429. tbDebugOut(( DEB_ACCESSOR,
  430. "type %d, obValue %d, alignment needed: %d\n",
  431. (int) wType,
  432. (int) DataBinding.Binding().obValue,
  433. (int) cbAlign ));
  434. //Win4Assert( (0 == (DBPART_VALUE & cp)) ||
  435. // ( (0 != cbAlign) &&
  436. // (0 == (DataBinding.Binding().obValue % cbAlign)) ) );
  437. if ( (DBPART_VALUE & cp) &&
  438. (0 != (DataBinding.Binding().obValue % cbAlign)) )
  439. {
  440. tbDebugOut(( DEB_ERROR,
  441. "bad value alignment for type %d, obValue %d, alignment needed: %d\n",
  442. (int) wType,
  443. (int) DataBinding.Binding().obValue,
  444. (int) cbAlign ));
  445. }
  446. #endif // CIDBG==1
  447. // Fixed-length data types needn't have their width set, per
  448. // the Nile spec. So we set it to the default for the type.
  449. if (! isVariableLength( wType ) )
  450. DataBinding.SetMaxLen( cbWidth );
  451. }
  452. if (DataBinding.Binding().dwMemOwner & ~(DBMEMOWNER_PROVIDEROWNED))
  453. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  454. DBGP("bad dwMemOwner bits"));
  455. if (DBTYPE_EMPTY == (wType & VT_TYPEMASK) ||
  456. DBTYPE_NULL == (wType & VT_TYPEMASK) ||
  457. 0 != (wType & VT_RESERVED))
  458. {
  459. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  460. DBGP("bad wType"));
  461. }
  462. if ((wType & ~VT_TYPEMASK) != 0 &&
  463. (wType & ~VT_TYPEMASK) != DBTYPE_ARRAY &&
  464. (wType & ~VT_TYPEMASK) != DBTYPE_VECTOR &&
  465. (wType & ~VT_TYPEMASK) != DBTYPE_BYREF )
  466. {
  467. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  468. DBGP("bad wType modifier combination"));
  469. }
  470. // SPECDEVIATION - this is bogus; DBTYPE_VARIANT must be supported!
  471. if ((DataBinding.Binding().dwMemOwner & DBMEMOWNER_PROVIDEROWNED) &&
  472. (wType != DBTYPE_BSTR) &&
  473. !(wType & (DBTYPE_BYREF | DBTYPE_VECTOR | DBTYPE_ARRAY )))
  474. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  475. DBGP("bad provider-owned mem type"));
  476. if ( (DataBinding.Binding().dwMemOwner & DBMEMOWNER_PROVIDEROWNED) &&
  477. (wType == (DBTYPE_BYREF|DBTYPE_VARIANT)) &&
  478. ! _fExtendedTypes )
  479. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStat
  480. DBGP("provider-owned mem without extended types"));
  481. _aBindings[ iBinding] = DataBinding;
  482. if ( DataBinding.Binding().pObject )
  483. {
  484. _aBindings[iBinding].Binding().pObject = new DBOBJECT;
  485. RtlCopyMemory( _aBindings[(unsigned)iBinding].Binding().pObject,
  486. DataBinding.Binding().pObject,
  487. sizeof( DBOBJECT ) );
  488. }
  489. }
  490. // Verify that none of the output offsets and lengths overlap with
  491. // any others. This must be run after the above loop so cbMaxLength
  492. // fields are properly initialized.
  493. if (_scStatus == S_OK)
  494. _ValidateOffsets( pBindStat );
  495. } //_Initialize
  496. //+---------------------------------------------------------------------------
  497. //
  498. // Member: CAccessor::Validate
  499. //
  500. // Synopsis: Validates the coercions with respect to the ColumnsInfo.
  501. //
  502. // Arguments: [rColumnsInfo] - The column info. for the rowset
  503. // [pBindStat] - Binding status array (optional)
  504. //
  505. // History: 21 Nov 94 dlee created
  506. // 11-08-95 srikants Created
  507. // 01-15-98 VikasMan Removed call to checkcoercion here
  508. // Checking done only in GetData now
  509. //
  510. //----------------------------------------------------------------------------
  511. void CAccessor::Validate(
  512. CColumnsInfo & rColumnsInfo,
  513. DBBINDSTATUS * pBindStatus )
  514. {
  515. _pColumnsInfo = &rColumnsInfo;
  516. Win4Assert( 0 != _pColumnsInfo );
  517. for (DBORDINAL iBinding = 0; iBinding < _cBindings; iBinding++)
  518. {
  519. CDataBinding & DataBinding = _aBindings[iBinding];
  520. DBTYPE wType = (DBTYPE) DataBinding.Binding().wType;
  521. //
  522. // Make sure the column id is valid. Remember, column numbers are
  523. // 1-based. Map columnid 0 to the row ID column for the bookmark.
  524. //
  525. DBORDINAL iColumnId = DataBinding.Binding().iOrdinal;
  526. if ( ! _pColumnsInfo->IsValidColumnId( (ULONG) iColumnId ) )
  527. {
  528. _BindingFailed(DBBINDSTATUS_BADORDINAL, iBinding, pBindStatus
  529. DBGP("invalid iOrdinal"));
  530. continue;
  531. }
  532. const DBCOLUMNINFO & rColInfo =
  533. _pColumnsInfo->Get1ColumnInfo( (ULONG) iColumnId );
  534. if ( DBTYPE_HCHAPTER == wType &&
  535. !(rColInfo.dwFlags & DBCOLUMNFLAGS_ISCHAPTER) )
  536. {
  537. _BindingFailed(DBBINDSTATUS_UNSUPPORTEDCONVERSION, iBinding, pBindStatus
  538. DBGP("Chapter type binding to non-chapter column"));
  539. continue;
  540. }
  541. //
  542. // The only IUNKNOWN binding we currently support is for the
  543. // DBCOL_SELFCOLUMNS guid, with propid PROPID_DBSELF_SELF.
  544. // We don't yet support binding to a particular column, just
  545. // to the row (file) as a whole, and only if the client is FSCI.
  546. //
  547. if ( DBTYPE_IUNKNOWN == wType )
  548. {
  549. // Map self to the rowid column
  550. if ( ( DBCOL_SELFCOLUMNS == rColInfo.columnid.uGuid.guid ) &&
  551. ( PROPID_DBSELF_SELF == rColInfo.columnid.uName.ulPropid ) )
  552. DataBinding.SetDataColumn( _pColumnsInfo->GetRowIdColumn() );
  553. else
  554. _BindingFailed(DBBINDSTATUS_BADBINDINFO,iBinding,pBindStatus
  555. DBGP("bad IUNKNOWN binding"));
  556. }
  557. // If it's the path column, save the column # for possible use later
  558. // when doing deferred or self loads
  559. if ( rColInfo.columnid.uGuid.guid == s_guidStorage &&
  560. rColInfo.columnid.uName.ulPropid == PID_STG_PATH )
  561. _iPathColumn = DataBinding.GetDataColumn();
  562. // If it's the vpath column, save the column # for later use. We
  563. // need to translate '\' to '/' in the vpath column.
  564. if ( rColInfo.columnid.uGuid.guid == s_guidQuery &&
  565. rColInfo.columnid.uName.ulPropid == DISPID_QUERY_VIRTUALPATH )
  566. _iVpathBinding = iBinding;
  567. // If it's a bookmark column, map it to the corresponding row ID
  568. // column for retrieval.
  569. if ( (rColInfo.dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) &&
  570. ! ( rColInfo.dwFlags & DBCOLUMNFLAGS_ISCHAPTER ) )
  571. DataBinding.SetDataColumn( _pColumnsInfo->GetRowIdColumn() );
  572. // If it's a chapter column, mark it to Addref the chapter on retrieval
  573. if ( (rColInfo.dwFlags & DBCOLUMNFLAGS_ISCHAPTER) &&
  574. (DBPART_VALUE & DataBinding.Binding().dwPart) )
  575. DataBinding.SetChapter( TRUE );
  576. }
  577. // look for pathname -- it may be in the rowbuffer columns, but not
  578. // in the accessor's bindings.
  579. if ( colInvalid == _iPathColumn )
  580. {
  581. for ( ULONG x = 0; x < rColumnsInfo.GetHiddenColumnCount(); x++ )
  582. {
  583. CFullPropSpec const &spec = *rColumnsInfo.GetPropSpec( x+1 );
  584. tbDebugOut(( DEB_ACCESSOR,
  585. "spec 0x%x IsPropid %d, propid 0x%x, pathpropid: 0x%x\n",
  586. &spec,
  587. spec.IsPropertyPropid(),
  588. spec.GetPropertyPropid(),
  589. PID_STG_PATH ));
  590. if ( spec.IsPropertyPropid() &&
  591. PID_STG_PATH == spec.GetPropertyPropid() &&
  592. s_guidStorage == spec.GetPropSet() )
  593. {
  594. _iPathColumn = x+1;
  595. break;
  596. }
  597. }
  598. }
  599. _idColInfo = _pColumnsInfo->GetId();
  600. } //Validate
  601. //+-------------------------------------------------------------------------
  602. //
  603. // Member: CAccessor::CAccessor, public
  604. //
  605. // Synopsis: Constructs an accessor object
  606. //
  607. // Arguments: [dwAccessorFlags] -- accessor flags
  608. // [cBindings] -- # of bindings specified
  609. // [rgBindings] -- array of bindings
  610. // [pBindStat] -- returns index of bad binding (if any)
  611. // [fExtTypes] -- TRUE if extended variants are supported
  612. // [pColumns] -- column info for early checking of column
  613. // coercions
  614. // [type] -- type of accessor
  615. // [pCreator] --
  616. //
  617. // History: 21 Nov 94 dlee created
  618. //
  619. //--------------------------------------------------------------------------
  620. CAccessor::CAccessor(
  621. DBACCESSORFLAGS dwAccessorFlags,
  622. DBCOUNTITEM cBindings,
  623. const DBBINDING * rgBindings,
  624. DBBINDSTATUS * pBindStat,
  625. BOOL fExtTypes,
  626. CColumnsInfo * pColumns,
  627. EAccessorType type,
  628. void * pCreator
  629. ) :
  630. CAccessorBase(pCreator, type),
  631. _dwAccessorFlags(dwAccessorFlags),
  632. _scStatus(S_OK),
  633. _aBindings( (unsigned) cBindings),
  634. _cBindings(cBindings),
  635. _idColInfo(0),
  636. _pColumnsInfo(0),
  637. _iPathColumn( colInvalid ),
  638. _iVpathBinding( colInvalid ),
  639. _fExtendedTypes( fExtTypes )
  640. {
  641. _Initialize( dwAccessorFlags, cBindings, rgBindings, pBindStat );
  642. if ( 0 != pColumns && _scStatus == S_OK )
  643. Validate( *pColumns, pBindStat );
  644. if (_scStatus != S_OK)
  645. QUIETTHROW(CException(_scStatus));
  646. } //CAccessor
  647. //+-------------------------------------------------------------------------
  648. //
  649. // Member: CAccessor::~CAccessor, public
  650. //
  651. // Synopsis: Destructs an accessor object
  652. //
  653. // History: 19 Apr 2000 dlee added header
  654. //
  655. //--------------------------------------------------------------------------
  656. CAccessor::~CAccessor()
  657. {
  658. // Delete DBOBJECTs
  659. for ( unsigned iBinding = 0; iBinding < _cBindings; iBinding++ )
  660. {
  661. if ( 0 != _aBindings[iBinding].Binding().pObject )
  662. delete _aBindings[iBinding].Binding().pObject;
  663. // These are for future use according to OLE-DB 2.0 and should be NULL
  664. Win4Assert( 0 == _aBindings[iBinding].Binding().pTypeInfo &&
  665. 0 == _aBindings[iBinding].Binding().pBindExt );
  666. }
  667. CAccessorBase * pParent = GetParent();
  668. if ( 0 != pParent )
  669. {
  670. if ( 0 == pParent->DecInheritors() && 0 == pParent->GetRefcount() )
  671. delete pParent;
  672. }
  673. } //~CAccessor
  674. //+-------------------------------------------------------------------------
  675. //
  676. // Member: CAccessor::_ValidateOffsets, private
  677. //
  678. // Synopsis: Checks a binding for overlapping output fields
  679. //
  680. // Arguments: [pBindStat] -- where to indicate bad binding
  681. //
  682. // History: 18 May 1995 dlee Created
  683. //
  684. //--------------------------------------------------------------------------
  685. void CAccessor::_ValidateOffsets( DBBINDSTATUS * pBindStatus )
  686. {
  687. for ( DBORDINAL iBinding = 0; iBinding < _cBindings; iBinding++ )
  688. {
  689. CDataBinding & DataBinding = _aBindings[ iBinding];
  690. COffsetLengthPair aPairs[3];
  691. ULONG cPairs = 0;
  692. DataBinding.CollectOutputPairs( aPairs, cPairs );
  693. // Check for overlap with data/length/status in this binding
  694. for ( DBORDINAL i = 0; i < cPairs; i++ )
  695. {
  696. for ( DBORDINAL j = i + 1; j < cPairs; j++)
  697. {
  698. if ( aPairs[i].isInConflict( aPairs[j] ) )
  699. {
  700. _BindingFailed( DBBINDSTATUS_BADBINDINFO,
  701. iBinding,
  702. pBindStatus
  703. DBGP("intra-binding field overlap") );
  704. continue;
  705. }
  706. }
  707. }
  708. // Check for overlap with other bindings
  709. for ( i = iBinding + 1; i < _cBindings; i++ )
  710. {
  711. CDataBinding &binding = _aBindings[i];
  712. COffsetLengthPair aTestPairs[3];
  713. ULONG cTestPairs = 0;
  714. binding.CollectOutputPairs( aTestPairs, cTestPairs );
  715. for (ULONG iPair = 0; iPair < cPairs; iPair++)
  716. {
  717. for (ULONG iTestPair = 0; iTestPair < cTestPairs; iTestPair++)
  718. {
  719. if ( aPairs[iPair].isInConflict( aTestPairs[iTestPair] ) )
  720. {
  721. _BindingFailed( DBBINDSTATUS_BADBINDINFO,
  722. i,
  723. pBindStatus
  724. DBGP("inter-binding field overlap") );
  725. continue;
  726. }
  727. }
  728. }
  729. }
  730. }
  731. } //_ValidateOffsets
  732. //+---------------------------------------------------------------------------
  733. //
  734. // Member: CAccessor::CanConvertType, static public
  735. //
  736. // Synopsis: Indicate whether a type conversion is valid.
  737. //
  738. // Arguments: [wFromType] -- source type
  739. // [wToType] -- destination type
  740. // [fExTypes] -- TRUE if extended types allowed
  741. // [xDataConvert] -- OLEDB IDataConvert interface pointer
  742. //
  743. // Returns: TRUE if the conversion is available, FALSE otherwise.
  744. // Throws E_FAIL or E_INVALIDARG on errors.
  745. //
  746. // History: 20 Nov 96 AlanW Created
  747. // 14 Jan 98 VikasMan Add xDataConvert parameter
  748. //
  749. //----------------------------------------------------------------------------
  750. BOOL CAccessor::CanConvertType(
  751. DBTYPE wFromType,
  752. DBTYPE wToType,
  753. BOOL fExTypes,
  754. XInterface<IDataConvert>& xDataConvert)
  755. {
  756. USHORT cbData, cbAlignFrom, rgfFlagsFrom;
  757. CTableVariant::VartypeInfo(wFromType, cbData, cbAlignFrom, rgfFlagsFrom);
  758. USHORT cbAlignTo, rgfFlagsTo;
  759. CTableVariant::VartypeInfo(wToType, cbData, cbAlignTo, rgfFlagsTo);
  760. if (0 == cbAlignFrom || 0 == cbAlignTo)
  761. QUIETTHROW(CException(E_INVALIDARG)); // bad type
  762. if ( ((wToType & ~VT_TYPEMASK) != 0 &&
  763. (wToType & ~VT_TYPEMASK) != DBTYPE_ARRAY &&
  764. (wToType & ~VT_TYPEMASK) != DBTYPE_VECTOR &&
  765. (wToType & ~VT_TYPEMASK) != DBTYPE_BYREF ) ||
  766. 0 != (wToType & VT_RESERVED) )
  767. {
  768. tbDebugOut(( DEB_IERROR, "CanConvertType: conversion to invalid type"));
  769. QUIETTHROW(CException(E_INVALIDARG));
  770. }
  771. if ( ((wFromType & ~VT_TYPEMASK) != 0 &&
  772. (wFromType & ~VT_TYPEMASK) != DBTYPE_ARRAY &&
  773. (wFromType & ~VT_TYPEMASK) != DBTYPE_VECTOR &&
  774. (wFromType & ~VT_TYPEMASK) != DBTYPE_BYREF ) ||
  775. 0 != (wFromType & VT_RESERVED) )
  776. {
  777. tbDebugOut(( DEB_IERROR, "CanConvertType: conversion from invalid type"));
  778. QUIETTHROW(CException(E_INVALIDARG));
  779. }
  780. //
  781. // check for conversions _Initialize() does not allow
  782. //
  783. // check if byref request for "short" type
  784. if ( (wToType & DBTYPE_BYREF) && !isValidByRef(wToType) )
  785. {
  786. tbDebugOut(( DEB_IERROR, "CanConvertType: conversion to byref type for short type"));
  787. return FALSE;
  788. }
  789. if ( DBTYPE_EMPTY == (wToType & VT_TYPEMASK) ||
  790. DBTYPE_NULL == (wToType & VT_TYPEMASK) )
  791. {
  792. tbDebugOut(( DEB_IERROR, "CanConvertType: conversion to empty or null type"));
  793. return FALSE;
  794. }
  795. //
  796. // check extended type conversions
  797. //
  798. // NEWFEATURE: - vector ==> array conversion?
  799. if ((wToType & DBTYPE_ARRAY) && (wToType != wFromType))
  800. {
  801. tbDebugOut(( DEB_IERROR, "CanConvertType: conversion to array"));
  802. return FALSE;
  803. }
  804. if ((wToType & DBTYPE_VECTOR) &&
  805. !(isEquivalentType(wToType,wFromType) || wFromType == VT_VARIANT))
  806. {
  807. tbDebugOut(( DEB_IERROR, "CanConvertType: conversion to vector"));
  808. return FALSE;
  809. }
  810. //
  811. // VARIANT conversions depend upon whether extended types are supported
  812. //
  813. if (wToType == DBTYPE_VARIANT)
  814. {
  815. if (fExTypes)
  816. return TRUE;
  817. if ( (wFromType & ~(DBTYPE_BYREF)) == DBTYPE_GUID)
  818. return FALSE;
  819. return TRUE;
  820. }
  821. //
  822. // Anything can coerce into DBTYPE_BYTES
  823. //
  824. if (wToType == DBTYPE_BYTES)
  825. return TRUE;
  826. // now use OLEDB to check if conversion is possible
  827. return COLEDBVariant::CanConvertType( wFromType, wToType, xDataConvert );
  828. } //CanConvertType
  829. //+-------------------------------------------------------------------------
  830. //
  831. // Member: CAccessor::GetBindings, public
  832. //
  833. // Synopsis: Fetches a copy of the bindings used by the accessor
  834. //
  835. // Arguments: [pAccessorFlags] -- accessor flags
  836. // [pcBindings] -- # of bindings returned
  837. // [ppBindings] -- array of bindings returned. the user
  838. // must IMalloc::Free this memory.
  839. //
  840. // Returns: SCODE - S_OK. Return value required by base class
  841. // CAccessorBase
  842. //
  843. // History: 21 Nov 94 dlee created
  844. // 05 May 97 emilyb switched first 2 params from
  845. // references to pointers so that
  846. // this can be a virtual member of
  847. // CAccessorBase. (CDistributedAccessor
  848. // cannot use references).
  849. //
  850. //--------------------------------------------------------------------------
  851. SCODE CAccessor::GetBindings(
  852. DBACCESSORFLAGS * pAccessorFlags,
  853. DBCOUNTITEM * pcBindings,
  854. DBBINDING ** ppBindings)
  855. {
  856. // in case of an error later, init the count to a good state
  857. *pcBindings = 0;
  858. // verify this pointer is good
  859. *ppBindings = 0;
  860. // allocate room for the bindings and copy them
  861. *ppBindings = (DBBINDING *) _Pool.Allocate( (ULONG) _cBindings * sizeof DBBINDING );
  862. *pAccessorFlags = _dwAccessorFlags;
  863. *pcBindings = _cBindings;
  864. for ( DBORDINAL i = 0; i < _cBindings; i++ )
  865. {
  866. (*ppBindings)[i] = _aBindings[ i].Binding();
  867. if ( _aBindings[i].Binding().pObject )
  868. {
  869. (*ppBindings)[i].pObject = (DBOBJECT*) _Pool.Allocate( sizeof( DBOBJECT ) );
  870. RtlCopyMemory( (*ppBindings)[i].pObject,
  871. _aBindings[i].Binding().pObject,
  872. sizeof( DBOBJECT ) );
  873. }
  874. // These are for future use according to OLE-DB 2.0 and should be NULL
  875. Win4Assert( 0 == _aBindings[i].Binding().pTypeInfo &&
  876. 0 == _aBindings[i].Binding().pBindExt );
  877. }
  878. return S_OK;
  879. } //GetBindings
  880. //+-------------------------------------------------------------------------
  881. //
  882. // Member: CRowDataAccessor::_LoadPath, private
  883. //
  884. // Synopsis: Loads the path of the object represented by the row
  885. //
  886. // Arguments: [rSrcSet] -- set of source columns
  887. // [pbSrc] -- source row buffer
  888. // [funnyPath] -- where to put the path
  889. //
  890. // History: 30 May 95 dlee created
  891. //
  892. //--------------------------------------------------------------------------
  893. void CRowDataAccessor::_LoadPath(
  894. CTableColumnSet & rSrcSet,
  895. BYTE * pbSrc,
  896. CFunnyPath & funnyPath )
  897. {
  898. // either path or workid must be available -- it's added by ColInfo
  899. // when the query is created.
  900. if ( colInvalid != _iPathColumn )
  901. {
  902. // pathname happened to be one of the columns -- this is faster than
  903. // doing a wid translation
  904. CTableColumn *pPathCol = rSrcSet.Find( (ULONG) _iPathColumn );
  905. WCHAR *pwc = 0;
  906. if (pPathCol->GetStoredType() == VT_LPWSTR)
  907. {
  908. pwc = * ( (WCHAR **) (pbSrc + pPathCol->GetValueOffset()) );
  909. }
  910. else
  911. {
  912. Win4Assert(pPathCol->GetStoredType() == VT_VARIANT);
  913. CTableVariant & varnt = * ( (CTableVariant *) (pbSrc + pPathCol->GetValueOffset()) );
  914. if (varnt.vt == VT_LPWSTR)
  915. pwc = varnt.pwszVal;
  916. }
  917. if (pwc)
  918. {
  919. funnyPath.SetPath( pwc );
  920. }
  921. }
  922. else
  923. {
  924. // translate the wid for the row into a pathname
  925. Win4Assert( colInvalid != _pColumnsInfo->GetRowIdColumn() );
  926. _pQuery->WorkIdToPath( _RowWid( rSrcSet, pbSrc ), funnyPath );
  927. }
  928. } //_LoadPath
  929. //+-------------------------------------------------------------------------
  930. //
  931. // Member: CRowDataAccessor::_BindToObject, private
  932. //
  933. // Synopsis: Binds to an object and returns an interface pointer
  934. //
  935. // Arguments: [pbDst] -- destination row buffer
  936. // [rDstBinding] -- binding for the destination
  937. // [pbSrc] -- source row buffer
  938. // [rSrcColumn] -- source column description
  939. // [rSrcSet] -- set of source columns
  940. //
  941. // Returns: DBSTATUS -- status of the column copy
  942. //
  943. // History: 10 Apr 95 dlee created
  944. //
  945. //--------------------------------------------------------------------------
  946. DBSTATUS CRowDataAccessor::_BindToObject(
  947. BYTE * pbDst,
  948. CDataBinding & rDstBinding,
  949. BYTE * pbSrc,
  950. CTableColumn & rSrcColumn,
  951. CTableColumnSet & rSrcSet)
  952. {
  953. //
  954. // CLEANCODE: This is all wrong. StgOpenStorage doesn't belong in
  955. // framework code! Though fixing this would be hard -- we'd have to
  956. // remote the object binding from the server process. And we only
  957. // try this for the path column -- if it doesn't exist this code won't
  958. // be executed.
  959. //
  960. DBSTATUS DstStatus = 0;
  961. // get the pathname for ole to open the storage
  962. CFunnyPath funnyPath;
  963. _LoadPath( rSrcSet, pbSrc, funnyPath );
  964. // bind to the file and return interface pointer requested
  965. if ( 0 != funnyPath.GetActualLength() )
  966. {
  967. // WORKAROUND: StgOpenStorage AVs for paths > MAX_PATH currently
  968. // So till it is fixed, make sure we do not pass a path > MAX_PATH
  969. if ( funnyPath.GetLength() < MAX_PATH )
  970. {
  971. XInterface<IStorage> xStorage;
  972. SCODE sc = StgOpenStorage( funnyPath.GetPath(),
  973. 0,
  974. rDstBinding.Binding().pObject->dwFlags,
  975. 0, 0,
  976. xStorage.GetPPointer() );
  977. if ( SUCCEEDED( sc ) )
  978. sc = xStorage->QueryInterface( rDstBinding.Binding().pObject->iid,
  979. (void **) pbDst );
  980. if ( FAILED( sc ) )
  981. DstStatus = DBSTATUS_E_CANTCREATE;
  982. }
  983. else
  984. {
  985. ciDebugOut(( DEB_WARN, "Not calling StgOpenStorage in CRowDataAccessor::_BindToObject for paths > MAX_PATH: \n(%ws)\n",
  986. funnyPath.GetPath() ));
  987. DstStatus = DBSTATUS_E_CANTCREATE;
  988. }
  989. }
  990. else
  991. DstStatus = DBSTATUS_S_ISNULL;
  992. return DstStatus;
  993. } //_BindToObject
  994. //+-------------------------------------------------------------------------
  995. //
  996. // Member: CRowDataAccessor::_LoadDeferred, private
  997. //
  998. // Synopsis: Loads a non-storage property value. Only called if the
  999. // value is large, hence not already loaded.
  1000. //
  1001. // Arguments: [rSrcVar] -- where the value is written
  1002. // [pbSrc] -- pointer to the row data (to get the wid)
  1003. // [iColumn] -- column being copied
  1004. // [rSrcSet] -- set of source columns
  1005. //
  1006. // Returns: DBSTATUS -- status of the load
  1007. //
  1008. // History: 1 Jun 95 dlee created
  1009. //
  1010. //--------------------------------------------------------------------------
  1011. DBSTATUS CRowDataAccessor::_LoadDeferred(
  1012. CTableVariant & rSrcVar,
  1013. BYTE * pbSrc,
  1014. DBORDINAL iColumn,
  1015. CTableColumnSet & rSrcSet)
  1016. {
  1017. // If the property set storage has not yet been opened for this object,
  1018. // load it now.
  1019. tbDebugOut(( DEB_ACCESSOR, "loading deferred value\n" ));
  1020. rSrcVar.vt = VT_EMPTY; // just in case we can't load anything
  1021. CFullPropSpec const *ps = _pColumnsInfo->GetPropSpec( (ULONG)
  1022. _aBindings[iColumn].GetDataColumn() );
  1023. //
  1024. // Try loading from the property cache/docfile if the workid column is
  1025. // available.
  1026. //
  1027. DBORDINAL rowIdCol = _pColumnsInfo->GetRowIdColumn();
  1028. if ( ( colInvalid == rowIdCol ) ||
  1029. ( !_pQuery->FetchDeferredValue( _RowWid( rSrcSet, pbSrc ), *ps, rSrcVar ) ) )
  1030. {
  1031. return DBSTATUS_S_ISNULL;
  1032. }
  1033. tbDebugOut(( DEB_ACCESSOR, "successfully loaded deferred value\n" ));
  1034. return DBSTATUS_S_OK;
  1035. } //_LoadDeferred
  1036. //+-------------------------------------------------------------------------
  1037. //
  1038. // Member: CRowDataAccessor::_ComplexCopy, private
  1039. //
  1040. // Synopsis: Do a complex copy of the value to the client's buffer
  1041. //
  1042. // Arguments: [rDstBinding] -- binding for the destination
  1043. // [pbSrc] -- source row buffer
  1044. // [rSrcColumn] -- source column description
  1045. // [iColumn] -- column being copied
  1046. // [vtSrc] -- type of the source
  1047. // [cbDstLength] -- on exit, size of destination data
  1048. // [pbSrcData] -- pointer to source data
  1049. // [vtDst] -- type of the destination value
  1050. // [pbDstData] -- where to write the value
  1051. // [rSrcSet] -- set of source columns
  1052. // [rRowBuffer] -- row buffer
  1053. // [hrow] -- hrow being retrieved
  1054. // [xDataConvert] -- smart pointer to IDataConvert interface.
  1055. // this is to be passed along and used finally
  1056. // in COLEDBVariant::CopyOrCoerce
  1057. //
  1058. // Returns: DBSTATUS -- status of the column copy
  1059. //
  1060. // History: 01 Jun 1995 dlee created
  1061. // 09 Jan 1998 vikasman added xDataConvert parameter
  1062. //
  1063. //--------------------------------------------------------------------------
  1064. DBSTATUS CRowDataAccessor::_ComplexCopy(
  1065. CDataBinding & rDstBinding,
  1066. BYTE * pbSrc,
  1067. CTableColumn & rSrcColumn,
  1068. DBORDINAL iColumn,
  1069. VARTYPE vtSrc,
  1070. DBLENGTH & cbDstLength,
  1071. BYTE * pbSrcData,
  1072. VARTYPE vtDst,
  1073. BYTE * pbDstData,
  1074. CTableColumnSet & rSrcSet,
  1075. CRowBuffer & rRowBuffer,
  1076. HROW hrow,
  1077. XInterface<IDataConvert>& xDataConvert)
  1078. {
  1079. DBSTATUS DstStatus = DBSTATUS_S_OK;
  1080. // Convert to a COLEDBVariant, then copy it using the OLEDBConvert
  1081. // method. This allows coercions and variant to nonvariant, etc.
  1082. // conversions to occur.
  1083. COLEDBVariant SrcVar;
  1084. BOOL fDoCopy = TRUE;
  1085. BOOL fFreeDeferredSrc = FALSE;
  1086. if ( VT_VARIANT == vtSrc )
  1087. {
  1088. Win4Assert(rSrcColumn.GetValueSize() == sizeof PROPVARIANT);
  1089. if ( ( rSrcColumn.IsDeferred( pbSrc ) ) )
  1090. {
  1091. DstStatus = _LoadDeferred( SrcVar,
  1092. pbSrc,
  1093. iColumn,
  1094. rSrcSet );
  1095. if ( DBStatusOK ( DstStatus ) )
  1096. {
  1097. // Attempt to store the data without using OLEDBConvert
  1098. if ( (VT_VARIANT == vtDst && _fExtendedTypes) ||
  1099. DBTYPE_PROPVARIANT == vtDst )
  1100. {
  1101. fDoCopy = FALSE;
  1102. * (PROPVARIANT *) pbDstData = SrcVar;
  1103. cbDstLength = sizeof (PROPVARIANT);
  1104. }
  1105. else if ( (VT_VARIANT|DBTYPE_BYREF) == vtDst ||
  1106. (DBTYPE_PROPVARIANT|DBTYPE_BYREF) == vtDst )
  1107. {
  1108. fDoCopy = FALSE;
  1109. // Slam the variant into the src data row buffer, then
  1110. // hand out a pointer to that variant.
  1111. // We need a home for the variant portion, and that
  1112. // place should do fine.
  1113. // The value portion of the variant will still be
  1114. // owned by the row buffer as a normal deferred value.
  1115. * (PROPVARIANT *) pbSrcData = SrcVar;
  1116. * (PROPVARIANT **) pbDstData = (PROPVARIANT *) pbSrcData;
  1117. cbDstLength = sizeof (PROPVARIANT);
  1118. }
  1119. else if ( isEquivalentType( vtDst, SrcVar.vt ) &&
  1120. SrcVar.VariantPointerInFirstWord() )
  1121. {
  1122. // Grab the pointer value out of the variant; any ptr will do
  1123. fDoCopy = FALSE;
  1124. * ( (LPWSTR *) pbDstData ) = SrcVar.pwszVal;
  1125. if ( SrcVar.vt & VT_ARRAY )
  1126. {
  1127. cbDstLength = sizeof (SAFEARRAY *);
  1128. }
  1129. else
  1130. {
  1131. switch (SrcVar.vt )
  1132. {
  1133. case VT_LPWSTR:
  1134. cbDstLength = wcslen(SrcVar.pwszVal) * sizeof (WCHAR);
  1135. break;
  1136. case VT_LPSTR:
  1137. cbDstLength = strlen(SrcVar.pszVal) * sizeof (char);
  1138. break;
  1139. case VT_BSTR:
  1140. cbDstLength = sizeof (BSTR);
  1141. break;
  1142. case VT_CLSID:
  1143. cbDstLength = sizeof (GUID);
  1144. break;
  1145. case VT_CF:
  1146. cbDstLength = sizeof (CLIPDATA);
  1147. break;
  1148. default:
  1149. tbDebugOut(( DEB_ERROR, "SrcVar.vt = 0x%x\n", SrcVar.vt ));
  1150. Win4Assert( SrcVar.vt != VT_EMPTY &&
  1151. !"unexpected variant type!" );
  1152. }
  1153. }
  1154. }
  1155. else if ( SrcVar.vt == vtDst )
  1156. {
  1157. Win4Assert( vtDst & DBTYPE_VECTOR );
  1158. Win4Assert( vtDst != VT_VARIANT );
  1159. fDoCopy = FALSE;
  1160. * (CAL *) pbDstData = SrcVar.cal;
  1161. cbDstLength = 0; // vectors defined to be 0 len
  1162. }
  1163. else
  1164. fFreeDeferredSrc = TRUE;
  1165. }
  1166. else
  1167. fDoCopy = FALSE;
  1168. }
  1169. else
  1170. {
  1171. RtlCopyMemory( &SrcVar, pbSrcData, sizeof SrcVar );
  1172. }
  1173. }
  1174. else
  1175. SrcVar.Init( vtSrc, pbSrcData, rSrcColumn.GetValueSize() );
  1176. if ( fDoCopy )
  1177. {
  1178. DstStatus = SrcVar.OLEDBConvert( pbDstData,
  1179. rDstBinding.GetMaxLen(),
  1180. vtDst,
  1181. _Pool,
  1182. cbDstLength,
  1183. xDataConvert,
  1184. _fExtendedTypes,
  1185. ((DBBINDING&)rDstBinding).bPrecision,
  1186. ((DBBINDING&)rDstBinding).bScale );
  1187. // Free the deferred value that was in a format that couldn't be
  1188. // used directly (and had to be converted).
  1189. if ( fFreeDeferredSrc )
  1190. {
  1191. PropVariantClear( &SrcVar );
  1192. }
  1193. }
  1194. // If accessor is byref and we had to allocate memory to return a
  1195. // deferred value, we have to tell the row buffer to let go of
  1196. // the memory when the HROW is released.
  1197. if ( ( DBSTATUS_S_OK == DstStatus ) &&
  1198. ( rSrcColumn.IsDeferred( pbSrc ) ) &&
  1199. ( rDstBinding.Binding().dwMemOwner == DBMEMOWNER_PROVIDEROWNED ) &&
  1200. ( ( vtDst & (DBTYPE_BYREF | DBTYPE_ARRAY | DBTYPE_VECTOR) ) ||
  1201. ( vtDst == VT_LPWSTR ) ||
  1202. ( vtDst == VT_LPSTR ) ||
  1203. ( vtDst == DBTYPE_BSTR ) ) )
  1204. {
  1205. PROPVARIANT var;
  1206. var.vt = vtDst;
  1207. if ( ( DBTYPE_VARIANT | DBTYPE_BYREF ) == vtDst ||
  1208. ( DBTYPE_PROPVARIANT | DBTYPE_BYREF ) == vtDst )
  1209. var = ** (PROPVARIANT **) pbDstData;
  1210. else if ( vtDst & DBTYPE_VECTOR )
  1211. RtlCopyMemory( &var.calpwstr,
  1212. pbDstData,
  1213. sizeof DBVECTOR );
  1214. else
  1215. var.pwszVal = * (WCHAR **) pbDstData;
  1216. tbDebugOut(( DEB_ITRACE, "save away type %x, val %x\n",
  1217. (int) vtDst,
  1218. ( vtDst & DBTYPE_VECTOR ) ?
  1219. (WCHAR *) var.calpwstr.pElems :
  1220. var.pwszVal ) );
  1221. CDeferredValue value( hrow, var );
  1222. rRowBuffer.AddDeferredValue( value );
  1223. rRowBuffer.SetByrefData( pbSrc );
  1224. }
  1225. return DstStatus;
  1226. } //_ComplexCopy
  1227. //+-------------------------------------------------------------------------
  1228. //
  1229. // Member: CRowDataAccessor::_ByRefCopy, private
  1230. //
  1231. // Synopsis: Copy a ByRef value. This hands out a live pointer into the
  1232. // row buffer's storage that the client can read from but not
  1233. // write to or try to free.
  1234. //
  1235. // Arguments: [rDstBinding] -- binding for the destination
  1236. // [pbSrc] -- source row buffer
  1237. // [rSrcColumn] -- source column description
  1238. // [vtSrc] -- type of the source
  1239. // [rSrcVar] -- variant to fill as a copy of the source
  1240. // data in variant form if the source data
  1241. // is not already a variant (and thus has
  1242. // a length column in the row buffer)
  1243. // [pbSrcData] -- pointer to source data
  1244. // [vtDst] -- type of the destination value
  1245. // [pbDstData] -- where to write the value
  1246. //
  1247. // Returns: DBSTATUS -- status of the column copy
  1248. //
  1249. // Notes: Coercions are not supported. This makes sense -- if you
  1250. // want slow coercions you shouldn't be binding byref in the
  1251. // first place.
  1252. //
  1253. // History: 25 Jul 95 dlee created
  1254. //
  1255. //--------------------------------------------------------------------------
  1256. DBSTATUS CRowDataAccessor::_ByRefCopy(
  1257. CDataBinding & rDstBinding,
  1258. BYTE * pbSrc,
  1259. CTableColumn & rSrcColumn,
  1260. VARTYPE vtSrc,
  1261. CTableVariant & rSrcVar,
  1262. BYTE * pbSrcData,
  1263. VARTYPE vtDst,
  1264. BYTE * pbDstData )
  1265. {
  1266. DBSTATUS DstStatus = DBSTATUS_S_OK;
  1267. RtlZeroMemory( &rSrcVar, sizeof CTableVariant );
  1268. if ( VT_EMPTY == vtSrc )
  1269. return DBSTATUS_S_ISNULL;
  1270. if ( rDstBinding.Binding().wType & DBTYPE_VECTOR )
  1271. {
  1272. if ( DBTYPE_VARIANT == vtSrc )
  1273. {
  1274. CTableVariant & varnt = * ( (CTableVariant *) pbSrcData );
  1275. tbDebugOut(( DEB_ACCESSOR, "byref copy, vtDst 0x%x varnt.vt 0x%x\n",
  1276. vtDst, varnt.vt ));
  1277. if ( isEquivalentType( vtDst, varnt.vt ) )
  1278. RtlCopyMemory( pbDstData, &(varnt.caub), sizeof DBVECTOR );
  1279. else
  1280. DstStatus = NullOrCantConvert( varnt.vt );
  1281. }
  1282. else if ( isEquivalentType( vtDst, vtSrc ) )
  1283. {
  1284. RtlCopyMemory( pbDstData, pbSrcData, sizeof DBVECTOR );
  1285. // Make a variant in case length is bound for this column
  1286. rSrcVar.vt = vtSrc;
  1287. RtlCopyMemory( &(rSrcVar.caub), pbSrcData, sizeof DBVECTOR );
  1288. }
  1289. else
  1290. {
  1291. DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
  1292. }
  1293. }
  1294. else if ( rDstBinding.Binding().wType & DBTYPE_ARRAY )
  1295. {
  1296. if ( DBTYPE_VARIANT == vtSrc )
  1297. {
  1298. CTableVariant & varnt = * ( (CTableVariant *) pbSrcData );
  1299. tbDebugOut(( DEB_ACCESSOR, "byref copy, vtDst 0x%x varnt.vt 0x%x\n",
  1300. vtDst, varnt.vt ));
  1301. if ( isEquivalentType( vtDst, varnt.vt ) )
  1302. RtlCopyMemory( pbDstData, &(varnt.parray), sizeof (SAFEARRAY *) );
  1303. else
  1304. DstStatus = NullOrCantConvert( varnt.vt );
  1305. }
  1306. else if ( isEquivalentType( vtDst, vtSrc ) )
  1307. {
  1308. RtlCopyMemory( pbDstData, pbSrcData, sizeof (SAFEARRAY *) );
  1309. // Make a variant in case length is bound for this column
  1310. rSrcVar.vt = vtSrc;
  1311. RtlCopyMemory( &(rSrcVar.parray), pbSrcData, sizeof (SAFEARRAY *) );
  1312. }
  1313. else
  1314. {
  1315. DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
  1316. }
  1317. }
  1318. else
  1319. {
  1320. Win4Assert( (rDstBinding.Binding().wType & DBTYPE_BYREF) ||
  1321. (rDstBinding.Binding().wType == DBTYPE_BSTR) );
  1322. if ( DBTYPE_VARIANT == vtSrc )
  1323. {
  1324. CTableVariant & varnt = * ( (CTableVariant *) pbSrcData );
  1325. tbDebugOut(( DEB_ACCESSOR, "byref non-vector copy, vtDst 0x%x, varnt.vt 0x%x\n",
  1326. vtDst, varnt.vt ));
  1327. if ((rDstBinding.Binding().wType & ~DBTYPE_BYREF) == DBTYPE_VARIANT)
  1328. {
  1329. // Just return a pointer to the stored variant
  1330. * (VARIANT **) pbDstData = (VARIANT *) pbSrcData;
  1331. }
  1332. else if ( ( varnt.VariantPointerInFirstWord() ) &&
  1333. ( isEquivalentType( vtDst, varnt.vt ) ) )
  1334. {
  1335. // Grab the pointer value out of the variant; any ptr will do
  1336. * ( (LPWSTR *) pbDstData ) = varnt.pwszVal;
  1337. // Make a variant in case length is bound for this column
  1338. rSrcVar.vt = varnt.vt;
  1339. rSrcVar.pwszVal = varnt.pwszVal;
  1340. }
  1341. else
  1342. {
  1343. * ( (LPWSTR *) pbDstData ) = 0;
  1344. DstStatus = NullOrCantConvert( varnt.vt );
  1345. }
  1346. }
  1347. else
  1348. {
  1349. // The constructor verified everything is fine -- copy the ptr
  1350. * (void **) pbDstData = * (void **) pbSrcData;
  1351. // Make a variant in case length is bound for this column
  1352. rSrcVar.vt = vtSrc;
  1353. rSrcVar.pwszVal = * (WCHAR **) pbSrcData;
  1354. }
  1355. }
  1356. if ( rSrcColumn.IsNull( pbSrc ) )
  1357. {
  1358. tbDebugOut(( DEB_ITRACE, "byref column status IsNull\n" ));
  1359. DstStatus = DBSTATUS_S_ISNULL;
  1360. }
  1361. return DstStatus;
  1362. } //_ByRefCopy
  1363. //+-------------------------------------------------------------------------
  1364. //
  1365. // Member: CRowDataAccessor::_CopyColumn, private
  1366. //
  1367. // Synopsis: Return a set of row data to the caller
  1368. //
  1369. // Arguments: [pbDst] -- destination row buffer
  1370. // [rDstBinding] -- binding for the destination
  1371. // [pbSrc] -- source row buffer
  1372. // [rSrcColumn] -- source column description
  1373. // [rSrcSet] -- set of source columns
  1374. // [iColumn] -- column being copied
  1375. // [rRowBuffer] -- row buffer
  1376. // [hrow] -- hrow being retrieved
  1377. // [xDataConvert] -- smart pointer to IDataConvert interface.
  1378. // this is to be passed along and used finally
  1379. // in COLEDBVariant::CopyOrCoerce
  1380. //
  1381. // Returns: DBSTATUS -- status of the column copy
  1382. //
  1383. // History: 21 Nov 1994 dlee created
  1384. // 09 Jan 1998 vikasman added xDataConvert parameter
  1385. //
  1386. //--------------------------------------------------------------------------
  1387. DBSTATUS CRowDataAccessor::_CopyColumn(
  1388. BYTE * pbDst,
  1389. CDataBinding & rDstBinding,
  1390. BYTE * pbSrc,
  1391. CTableColumn & rSrcColumn,
  1392. CTableColumnSet & rSrcSet,
  1393. DBORDINAL iColumn,
  1394. CRowBuffer & rRowBuffer,
  1395. HROW hrow,
  1396. XInterface<IDataConvert>& xDataConvert)
  1397. {
  1398. DBSTATUS DstStatus = DBSTATUS_S_OK;
  1399. DBLENGTH cbDstLength = 0;
  1400. CTableVariant varLen;
  1401. BOOL fVariantValid = FALSE;
  1402. BOOL fLengthValid = FALSE;
  1403. BOOL fStatusValid = FALSE;
  1404. // pull out the data types for clarity below
  1405. VARTYPE vtDst = (VARTYPE) rDstBinding.Binding().wType;
  1406. VARTYPE vtSrc = rSrcColumn.GetStoredType();
  1407. if (DBPART_VALUE & rDstBinding.Binding().dwPart)
  1408. {
  1409. // the row buffer promises NOT to set the byref bit for these.
  1410. // we'll break elsewhere if this is not true.
  1411. Win4Assert(vtSrc != ( VT_LPWSTR | VT_BYREF ) );
  1412. Win4Assert(vtSrc != ( VT_LPSTR | VT_BYREF ) );
  1413. BYTE *pbSrcData = pbSrc + rSrcColumn.GetValueOffset();
  1414. BYTE *pbDstData = pbDst + rDstBinding.Binding().obValue;
  1415. tbDebugOut(( DEB_ACCESSOR, "copying column %d, vtsrc 0x%x, vtdst 0x%x\n",
  1416. iColumn, vtSrc, vtDst ));
  1417. // vpath can be null if not an IIS root
  1418. if ( ( iColumn == _iVpathBinding ) &&
  1419. ( !rSrcColumn.IsNull( pbSrc ) ) )
  1420. {
  1421. Win4Assert(VT_VARIANT == vtSrc ||
  1422. VT_LPWSTR == vtSrc ||
  1423. VT_BSTR == vtSrc);
  1424. LPWSTR pwszPath = (LPWSTR) pbSrcData;
  1425. if (VT_VARIANT == vtSrc)
  1426. pwszPath = ((PROPVARIANT *)pbSrcData)->pwszVal;
  1427. if (pwszPath)
  1428. ConvertBackslashToSlash(pwszPath);
  1429. }
  1430. if ( DBTYPE_IUNKNOWN == vtDst )
  1431. {
  1432. DstStatus = _BindToObject( pbDstData,
  1433. rDstBinding,
  1434. pbSrc,
  1435. rSrcColumn,
  1436. rSrcSet );
  1437. }
  1438. else
  1439. {
  1440. // Transfer a data value
  1441. USHORT cbData, cbAlignment, rgfFlags;
  1442. CTableVariant::VartypeInfo(vtSrc, cbData, cbAlignment, rgfFlags);
  1443. if ( rSrcColumn.IsNull( pbSrc ) && (vtDst & DBTYPE_BYREF) == 0 )
  1444. {
  1445. tbDebugOut(( DEB_ITRACE,
  1446. "column %d status IsNull -> VT_EMPTY\n",
  1447. iColumn ));
  1448. RtlZeroMemory( pbDstData, rDstBinding.GetMaxLen() );
  1449. DstStatus = DBSTATUS_S_ISNULL;
  1450. }
  1451. else if ( ( vtDst == vtSrc ) &&
  1452. ( vtDst != VT_VARIANT ) &&
  1453. ( 0 == (rgfFlags & CTableVariant::ByRef ) ) &&
  1454. ( 0 != (rgfFlags & CTableVariant::StoreDirect ) ) )
  1455. {
  1456. // Data column equivalent and not indirect, so just copy it.
  1457. // Storage props (except filename/path) will do this.
  1458. cbDstLength = rSrcColumn.GetValueSize();
  1459. fLengthValid = TRUE;
  1460. RtlCopyMemory( pbDstData, pbSrcData, cbDstLength );
  1461. }
  1462. else if ( ( rDstBinding.Binding().dwMemOwner ==
  1463. DBMEMOWNER_PROVIDEROWNED ) &&
  1464. ( ! rSrcColumn.IsDeferred( pbSrc ) ) &&
  1465. ( ( vtDst & DBTYPE_BYREF ) ||
  1466. ( vtDst & DBTYPE_VECTOR ) ||
  1467. ( vtDst & VT_ARRAY ) ||
  1468. ( vtDst == DBTYPE_BSTR ) ) )
  1469. {
  1470. // Efficiently bound filename/path, etc. will do this
  1471. DstStatus = _ByRefCopy( rDstBinding,
  1472. pbSrc,
  1473. rSrcColumn,
  1474. vtSrc,
  1475. varLen,
  1476. pbSrcData,
  1477. vtDst,
  1478. pbDstData );
  1479. if ( DBSTATUS_S_OK == DstStatus )
  1480. rRowBuffer.SetByrefData( pbSrc );
  1481. fVariantValid = TRUE;
  1482. }
  1483. else if (vtDst == DBTYPE_BYTES &&
  1484. rDstBinding.GetMaxLen() > 1 &&
  1485. CTableVariant::TableIsStoredInline( rgfFlags, vtSrc ))
  1486. {
  1487. // Special case for small fixed-length fields
  1488. DBLENGTH cbCopy = rSrcColumn.GetValueSize();
  1489. if (rDstBinding.GetMaxLen() < cbCopy)
  1490. {
  1491. cbCopy = rDstBinding.GetMaxLen();
  1492. DstStatus = DBSTATUS_S_TRUNCATED;
  1493. }
  1494. RtlCopyMemory(pbDstData, pbSrcData, cbCopy);
  1495. cbDstLength = cbCopy;
  1496. fLengthValid = TRUE;
  1497. }
  1498. else if (vtDst == DBTYPE_BYTES &&
  1499. rDstBinding.GetMaxLen() > 1 &&
  1500. vtSrc == VT_VARIANT)
  1501. {
  1502. // Special case for small fixed-length fields from a variant
  1503. CTableVariant * pVarnt = (CTableVariant *)pbSrcData;
  1504. pVarnt->VartypeInfo(pVarnt->vt, cbData, cbAlignment, rgfFlags);
  1505. if (rgfFlags & CTableVariant::SimpleType)
  1506. {
  1507. DBLENGTH cbCopy = cbData;
  1508. if (rDstBinding.GetMaxLen() < cbCopy)
  1509. {
  1510. cbCopy = rDstBinding.GetMaxLen();
  1511. DstStatus = DBSTATUS_S_TRUNCATED;
  1512. }
  1513. RtlCopyMemory(pbDstData, &(pVarnt->lVal), cbCopy);
  1514. cbDstLength = cbCopy;
  1515. fLengthValid = TRUE;
  1516. }
  1517. else
  1518. {
  1519. DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
  1520. }
  1521. }
  1522. else
  1523. {
  1524. // Copying to/from a variant or a coercion is required.
  1525. DstStatus = _ComplexCopy( rDstBinding,
  1526. pbSrc,
  1527. rSrcColumn,
  1528. iColumn,
  1529. vtSrc,
  1530. cbDstLength,
  1531. pbSrcData,
  1532. vtDst,
  1533. pbDstData,
  1534. rSrcSet,
  1535. rRowBuffer,
  1536. hrow,
  1537. xDataConvert);
  1538. fLengthValid = TRUE;
  1539. }
  1540. }
  1541. // indicate status has been validated
  1542. fStatusValid = TRUE;
  1543. // bump the chapter reference count if we successfully transferred
  1544. // a chapter value
  1545. if ( DBSTATUS_S_OK == DstStatus && rDstBinding.IsChapter() )
  1546. rRowBuffer.ReferenceChapter( pbSrc );
  1547. }
  1548. // fill-in the length if the client asked for it
  1549. if (DBPART_LENGTH & rDstBinding.Binding().dwPart)
  1550. {
  1551. DBLENGTH *pcbDst = (DBLENGTH *) (pbDst + rDstBinding.Binding().obLength);
  1552. if ( ( DBSTATUS_S_ISNULL == DstStatus ) ||
  1553. ( DBSTATUS_E_CANTCONVERTVALUE == DstStatus ) ||
  1554. ( 0 != ( vtDst & DBTYPE_VECTOR ) ) ) // ole-db spec says so
  1555. {
  1556. *pcbDst = 0;
  1557. }
  1558. else if ( fLengthValid )
  1559. {
  1560. *pcbDst = cbDstLength;
  1561. }
  1562. else if (! isVariableLength( vtDst ) )
  1563. {
  1564. if ( vtDst & VT_BYREF )
  1565. {
  1566. USHORT cbWidth, cbAlign, fFlags;
  1567. CTableVariant::VartypeInfo( vtDst & ~VT_BYREF, cbWidth, cbAlign, fFlags );
  1568. *pcbDst = cbWidth;
  1569. }
  1570. else
  1571. {
  1572. *pcbDst = rDstBinding.GetMaxLen();
  1573. }
  1574. }
  1575. else
  1576. {
  1577. DBLENGTH cbLen = 0;
  1578. if (fVariantValid)
  1579. {
  1580. Win4Assert ( varLen.vt != VT_EMPTY );
  1581. cbLen = varLen.VarDataSize();
  1582. }
  1583. else
  1584. {
  1585. //
  1586. // DBBINDING doesn't want DBPART_VALUE
  1587. //
  1588. SCODE sc = S_OK;
  1589. ULONG cbDstBufNeeded = 0;
  1590. DBTYPE dbtypeSrc;
  1591. COLEDBVariant SrcVar;
  1592. BYTE *pbSrcData = pbSrc + rSrcColumn.GetValueOffset();
  1593. RtlCopyMemory( &SrcVar, pbSrcData, sizeof SrcVar );
  1594. SrcVar.GetDstLength( xDataConvert,
  1595. rDstBinding.Binding().wType,
  1596. cbLen );
  1597. }
  1598. // WSTR and STR lengths shouldn't include the terminating NULL
  1599. if ( (vtDst & VT_TYPEMASK) == DBTYPE_WSTR ||
  1600. vtDst == VT_LPWSTR )
  1601. cbLen -= sizeof (WCHAR);
  1602. else if ( (vtDst & VT_TYPEMASK) == DBTYPE_STR ||
  1603. vtDst == VT_LPSTR )
  1604. cbLen -= sizeof (char);
  1605. else if (vtDst == DBTYPE_BSTR)
  1606. cbLen = sizeof (BSTR);
  1607. *pcbDst = cbLen;
  1608. }
  1609. }
  1610. if (! fStatusValid)
  1611. {
  1612. if ( rSrcColumn.IsStatusStored() &&
  1613. rSrcColumn.GetStatus( pbSrc ) == CTableColumn::StoreStatusNull )
  1614. DstStatus = DBSTATUS_S_ISNULL;
  1615. }
  1616. if (DBPART_STATUS & rDstBinding.Binding().dwPart)
  1617. {
  1618. * (DBSTATUS *) (pbDst + rDstBinding.Binding().obStatus) = DstStatus;
  1619. }
  1620. return DstStatus;
  1621. } //_CopyColumn
  1622. //+-------------------------------------------------------------------------
  1623. //
  1624. // Member: CRowDataAccessor::GetData, public
  1625. //
  1626. // Synopsis: Copies data into the buffer as specified when the accessor
  1627. // was created
  1628. //
  1629. // Arguments: [hRow] -- row whose data is copied
  1630. // [pData] -- where data is written
  1631. // [rBufferSet] -- object useful for transforming an HROW
  1632. // into a buffer and a column layout
  1633. // [rQuery] -- query to use for this getdata
  1634. // [colInfo] -- info about the columns
  1635. // [xDataConvert] -- smart pointer to IDataConvert interface.
  1636. // this is to be passed along and used finally
  1637. // in COLEDBVariant::CopyOrCoerce
  1638. //
  1639. // History: 21 Nov 1994 dlee created
  1640. // 09 Jan 1998 vikasman added xDataConvert parameter
  1641. //
  1642. //--------------------------------------------------------------------------
  1643. void CRowDataAccessor::GetData(
  1644. HROW hRow,
  1645. void * pData,
  1646. CRowBufferSet & rBufferSet,
  1647. PQuery & rQuery,
  1648. CColumnsInfo & colInfo,
  1649. XInterface<IDataConvert>& xDataConvert)
  1650. {
  1651. if ( _idColInfo != colInfo.GetId() )
  1652. {
  1653. // We have a different columnsInfo with which we must validate.
  1654. Validate( colInfo, 0 );
  1655. }
  1656. _pQuery = &rQuery; // query to be used for this data retrieval
  1657. // first find the source data buffer and its layout
  1658. CLock lock( rBufferSet.GetBufferLock() );
  1659. CTableColumnSet *pRowBufColSet;
  1660. BYTE *pbSrc;
  1661. CRowBuffer &rRowBuffer = rBufferSet.Lookup( hRow,
  1662. &pRowBufColSet,
  1663. (void **) &pbSrc );
  1664. // now copy the data from the internal buffer to the user's buffer
  1665. ULONG cCopied = 0;
  1666. // We need to determine whether all the conversions failed or
  1667. // all of them succeeded or some failed/some passed
  1668. ULONG cSuccess = 0;
  1669. TRY
  1670. {
  1671. for ( cCopied = 0; cCopied < _cBindings; cCopied++ )
  1672. {
  1673. CTableColumn *pSrcCol = rRowBuffer.Find( (ULONG)
  1674. _aBindings[cCopied].GetDataColumn() );
  1675. if ( 0 == pSrcCol )
  1676. {
  1677. // Somehow, the row buffer doesn't have a column that's in
  1678. // the accessor. This is an internal error.
  1679. Win4Assert(!"CRowDataAccessor::GetData couldn't find column binding");
  1680. }
  1681. DBSTATUS DstStatus = _CopyColumn( (BYTE *) pData,
  1682. _aBindings[cCopied],
  1683. pbSrc,
  1684. *pSrcCol,
  1685. *pRowBufColSet,
  1686. cCopied,
  1687. rRowBuffer,
  1688. hRow,
  1689. xDataConvert);
  1690. tbDebugOut(( DEB_ITRACE, "GetData column %d, status 0x%x\n",
  1691. cCopied, DstStatus ));
  1692. // see if we have a coercion error. any other column status will
  1693. // not result in a special return code from GetData -- it's just
  1694. // reflected in the column status field (if the user asks for it)
  1695. if ( DBStatusOK( DstStatus ) )
  1696. {
  1697. // Success
  1698. cSuccess++;
  1699. }
  1700. }
  1701. }
  1702. CATCH( CException, e )
  1703. {
  1704. // fatal error -- free the data allocated so far for return to the
  1705. // client, then rethrow the error condition
  1706. for ( ULONG i = 0; i < cCopied; i++ )
  1707. if ( _aBindings[i].Binding().dwMemOwner != DBMEMOWNER_PROVIDEROWNED )
  1708. CTableVariant::Free( (BYTE *) pData + _aBindings[i].Binding().obValue,
  1709. (VARTYPE) _aBindings[i].Binding().wType,
  1710. _Pool );
  1711. RETHROW();
  1712. }
  1713. END_CATCH;
  1714. if ( cSuccess == _cBindings ) // takes care of _cBindings == 0 case
  1715. {
  1716. // AllSuccess
  1717. ; // do nothing
  1718. }
  1719. else if ( cSuccess == 0 )
  1720. {
  1721. // AllFail
  1722. QUIETTHROW( CException( DB_E_ERRORSOCCURRED ) );
  1723. }
  1724. else
  1725. {
  1726. // SomeSuccess/SomeFail
  1727. QUIETTHROW( CException( DB_S_ERRORSOCCURRED ) );
  1728. }
  1729. } //GetData
  1730. //+-------------------------------------------------------------------------
  1731. //
  1732. // Member: CRowDataAccessorByRef::GetData, public
  1733. //
  1734. // Synopsis: Copies data into the buffer as specified when the accessor
  1735. // was created. For provider-owned memory with variant byref
  1736. // binding.
  1737. //
  1738. // Arguments: [hRow] -- row whose data is copied
  1739. // [pData] -- where data is written
  1740. // [rBufferSet] -- object useful for transforming an HROW
  1741. // into a buffer and a column layout
  1742. // [rQuery] -- query to use for this getdata
  1743. // [colInfo] -- info about the columns
  1744. // [xDataConvert] -- smart pointer to IDataConvert interface.
  1745. // this is to be passed along and used finally
  1746. // in COLEDBVariant::CopyOrCoerce
  1747. //
  1748. // History: 09 Apr 1996 dlee created
  1749. // 09 Jan 1998 vikasman added xDataConvert parameter
  1750. //
  1751. //--------------------------------------------------------------------------
  1752. void CRowDataAccessorByRef::GetData(
  1753. HROW hRow,
  1754. void * pData,
  1755. CRowBufferSet & rBufferSet,
  1756. PQuery & rQuery,
  1757. CColumnsInfo & colInfo,
  1758. XInterface<IDataConvert> & xDataConvert)
  1759. {
  1760. // we validated the column info on construction
  1761. Win4Assert ( _idColInfo == colInfo.GetId() );
  1762. // first find the source data buffer and its layout
  1763. CLock lock( rBufferSet.GetBufferLock() );
  1764. CTableColumnSet *pRowBufColSet;
  1765. BYTE *pbSrc;
  1766. CRowBuffer &rRowBuffer = rBufferSet.Lookup( hRow,
  1767. &pRowBufColSet,
  1768. (void **) &pbSrc );
  1769. // now copy the data from the internal buffer to the user's buffer
  1770. for ( unsigned iCol = 0; iCol < _cBindings; iCol++ )
  1771. {
  1772. CDataBinding & dstDataBinding = _aBindings[ iCol ];
  1773. CTableColumn & rSrcCol = * rRowBuffer.Find( (ULONG)
  1774. dstDataBinding.GetDataColumn() );
  1775. Win4Assert( 0 != &rSrcCol &&
  1776. "CRowDataAccessorByRef::GetData couldn't find column binding");
  1777. BYTE *pbSrcData = pbSrc + rSrcCol.GetValueOffset();
  1778. DBBINDING & DstBinding = dstDataBinding.Binding();
  1779. Win4Assert( (DBTYPE_VARIANT|DBTYPE_BYREF) == DstBinding.wType ||
  1780. (DBTYPE_PROPVARIANT|DBTYPE_BYREF) == DstBinding.wType );
  1781. Win4Assert( DBPART_VALUE == DstBinding.dwPart );
  1782. Win4Assert( VT_VARIANT == rSrcCol.GetStoredType() );
  1783. PROPVARIANT **ppDstVar = (PROPVARIANT **) ( ( (BYTE*) pData ) +
  1784. DstBinding.obValue );
  1785. if ( !rSrcCol.IsDeferred( pbSrc ) )
  1786. {
  1787. // Convert '\' to '/' if this is the vpath.
  1788. // Vpath can be null if the file is not in an indexed IIS vroot.
  1789. if ( ( iCol == _iVpathBinding ) &&
  1790. ( !rSrcCol.IsNull( pbSrc ) ) )
  1791. {
  1792. Win4Assert( VT_LPWSTR == ((PROPVARIANT *)pbSrcData)->vt ||
  1793. VT_BSTR == ((PROPVARIANT *)pbSrcData)->vt );
  1794. LPWSTR pwszPath = ((PROPVARIANT *)pbSrcData)->pwszVal;
  1795. if (pwszPath)
  1796. ConvertBackslashToSlash(pwszPath);
  1797. }
  1798. *ppDstVar = (PROPVARIANT *) pbSrcData;
  1799. #if CIDBG==1
  1800. if ( rSrcCol.IsNull( pbSrc ) )
  1801. {
  1802. Win4Assert( VT_EMPTY == (*ppDstVar)->vt );
  1803. }
  1804. #endif // CIDBG==1
  1805. }
  1806. else
  1807. {
  1808. // deferred copies can go through this slow code path
  1809. _pQuery = &rQuery; // query to be used for this data retrieval
  1810. DBLENGTH cbDstLen;
  1811. _ComplexCopy( _aBindings[iCol],
  1812. pbSrc,
  1813. rSrcCol,
  1814. iCol,
  1815. rSrcCol.GetStoredType(),
  1816. cbDstLen,
  1817. pbSrcData,
  1818. DBTYPE_PROPVARIANT | DBTYPE_BYREF,
  1819. (BYTE *) ppDstVar,
  1820. *pRowBufColSet,
  1821. rRowBuffer,
  1822. hRow,
  1823. xDataConvert);
  1824. }
  1825. // bump the chapter reference count if we transferred
  1826. // a chapter value
  1827. if ( dstDataBinding.IsChapter() )
  1828. rRowBuffer.ReferenceChapter( pbSrc );
  1829. }
  1830. rRowBuffer.SetByrefData( pbSrc );
  1831. } //GetData
  1832. //+-------------------------------------------------------------------------
  1833. //
  1834. // Function: CreateAnAccessor
  1835. //
  1836. // Synopsis: Creates an accessor object deriving from CAccessor that is
  1837. // best-suited to handling the binding flags.
  1838. //
  1839. // Arguments: [dwAccessorFlags] -- read/write access requested
  1840. // [cBindings] -- # of bindings in rgBindings
  1841. // [rgBindings] -- array of bindings
  1842. // [rgBindStatus] -- array of binding statuses
  1843. // [fExtTypes] -- TRUE if extended variants are supported
  1844. // [pColumns] -- column info, may be 0
  1845. //
  1846. // History: 9 Apr 96 dlee created
  1847. //
  1848. //--------------------------------------------------------------------------
  1849. CAccessor * CreateAnAccessor(
  1850. DBACCESSORFLAGS dwAccessorFlags,
  1851. DBCOUNTITEM cBindings,
  1852. const DBBINDING * rgBindings,
  1853. DBBINDSTATUS * rgBindStatus,
  1854. BOOL fExtTypes,
  1855. void * pCreator,
  1856. CColumnsInfo * pColumns )
  1857. {
  1858. BOOL fByRefCandidate = TRUE;
  1859. // CRowDataAccessorByRef candidates must:
  1860. // - have a non-0 pColumns
  1861. // - allow extended variant types (PROPVARIANT)
  1862. // - only bind to VALUE, not STATUS or LENGTH
  1863. // - only bind as DBTYPE_PROPVARIANT or DBTYPE_VARIANT byref
  1864. // - only bind with DBMEMOWNER_PROVIDEROWNED
  1865. //
  1866. // Accessors that don't meet these criteria go through the slower
  1867. // CRowDataAccessor.
  1868. if ( ( 0 == pColumns ) ||
  1869. ( dwAccessorFlags != DBACCESSOR_ROWDATA ) ||
  1870. ! fExtTypes )
  1871. fByRefCandidate = FALSE;
  1872. for ( DBORDINAL iBinding = 0;
  1873. fByRefCandidate && iBinding < cBindings;
  1874. iBinding++ )
  1875. {
  1876. DBBINDING const & b = rgBindings[ iBinding ];
  1877. if ( b.dwPart != DBPART_VALUE ||
  1878. b.dwMemOwner != DBMEMOWNER_PROVIDEROWNED ||
  1879. (( b.wType != (DBTYPE_PROPVARIANT|DBTYPE_BYREF) ) &&
  1880. (! fExtTypes ||
  1881. b.wType != (DBTYPE_VARIANT|DBTYPE_BYREF) ) ) )
  1882. fByRefCandidate = FALSE;
  1883. }
  1884. tbDebugOut(( DEB_ITRACE, "accessor can be byref: %d\n", fByRefCandidate ));
  1885. if ( fByRefCandidate )
  1886. return new CRowDataAccessorByRef( dwAccessorFlags,
  1887. cBindings,
  1888. rgBindings,
  1889. rgBindStatus,
  1890. TRUE,
  1891. pCreator,
  1892. pColumns );
  1893. return new CRowDataAccessor( dwAccessorFlags,
  1894. cBindings,
  1895. rgBindings,
  1896. rgBindStatus,
  1897. fExtTypes,
  1898. pCreator,
  1899. pColumns );
  1900. } //CreateAnAccessor