Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1351 lines
44 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 2000.
  5. //
  6. // File: colinfo.cxx
  7. //
  8. // Contents: Column information for rowsets
  9. //
  10. // Classes: CColumnsInfo
  11. //
  12. // Notes: Designed as an aggregated class of an IRowset or an
  13. // IQuery implementation.
  14. //
  15. // History: 04 Feb 1995 AlanW Created
  16. //
  17. //--------------------------------------------------------------------------
  18. #include "pch.cxx"
  19. #pragma hdrstop
  20. #include <colinfo.hxx>
  21. #include <query.hxx>
  22. #include <tblvarnt.hxx>
  23. #include "tblrowal.hxx"
  24. #include "tabledbg.hxx"
  25. // Always bind as DBTYPE_VARIANT, so we can use provider-owned memory
  26. #define ALWAYS_USE_VARIANT_BINDING
  27. ULONG CColumnsInfo::_nUnique = 0;
  28. const static GUID guidBmk = DBBMKGUID;
  29. //+-------------------------------------------------------------------------
  30. //
  31. // Method: CColumnsInfo::QueryInterface, public
  32. //
  33. // Synopsis: Invokes QueryInterface on controlling unknown object
  34. //
  35. // Arguments: [riid] -- interface ID
  36. // [ppvObject] -- returned interface pointer
  37. //
  38. // Returns: SCODE
  39. //
  40. // History: 04 Feb 1995 AlanW Created
  41. //
  42. //--------------------------------------------------------------------------
  43. STDMETHODIMP CColumnsInfo::QueryInterface(
  44. REFIID riid,
  45. void **ppvObject)
  46. {
  47. return _rUnknown.QueryInterface(riid,ppvObject);
  48. } //QueryInterface
  49. //+-------------------------------------------------------------------------
  50. //
  51. // Method: CColumnsInfo::AddRef, public
  52. //
  53. // Synopsis: Invokes AddRef on controlling unknown object
  54. //
  55. // Returns: ULONG
  56. //
  57. // History: 04 Feb 1995 AlanW Created
  58. //
  59. //--------------------------------------------------------------------------
  60. STDMETHODIMP_(ULONG) CColumnsInfo::AddRef()
  61. {
  62. return _rUnknown.AddRef();
  63. } //AddRef
  64. //+-------------------------------------------------------------------------
  65. //
  66. // Method: CColumnsInfo::Release, public
  67. //
  68. // Synopsis: Invokes Release on controlling unknown object
  69. //
  70. // Returns: ULONG
  71. //
  72. // History: 04 Feb 1995 AlanW Created
  73. //
  74. //--------------------------------------------------------------------------
  75. STDMETHODIMP_(ULONG) CColumnsInfo::Release()
  76. {
  77. return _rUnknown.Release();
  78. } //Release
  79. //+---------------------------------------------------------------------------
  80. //
  81. // Member: CColumnsInfo::CColumnsInfo, public
  82. //
  83. // Synopsis: Creates a column information class
  84. //
  85. // Arguments: [cols] -- a reference to the output column set, pidmapped
  86. // [pidmap] -- property IDs and names for the columns
  87. // [ErrorObject] -- a reference to enclosing object's error obj.
  88. // [rUnknown] -- a reference to the controlling IUnknown
  89. // [fSequential] -- TRUE if the query is sequential
  90. //
  91. // Notes:
  92. //
  93. // History: 04 Feb 1995 AlanW Created
  94. //
  95. //----------------------------------------------------------------------------
  96. CColumnsInfo::CColumnsInfo(
  97. CColumnSet const & cols,
  98. CPidMapperWithNames const & pidmap,
  99. CCIOleDBError & ErrorObject,
  100. IUnknown & rUnknown,
  101. BOOL fSequential ) :
  102. _idUnique(0),
  103. _rUnknown(rUnknown),
  104. _fSequential(fSequential),
  105. _fChaptered(FALSE),
  106. _cbRowWidth(0),
  107. _cColumns( cols.Count() ),
  108. _cBoundColumns(0),
  109. _iColRowId(pidInvalid),
  110. _pColumns(0),
  111. _pidmap( cols.Count()+1 ),
  112. _ErrorObject( ErrorObject ),
  113. _fNotPrepared(FALSE)
  114. {
  115. _SetColumns(cols, pidmap, fSequential);
  116. }
  117. //+---------------------------------------------------------------------------
  118. //
  119. // Member: CColumnsInfo::CColumnsInfo, public
  120. //
  121. // Synopsis: Creates an empty column information class
  122. //
  123. // Arguments: [rUnknown] -- a reference to the controlling IUnknown
  124. // [ErrorObject] -- a reference to enclosing object's error obj.
  125. //
  126. // Notes: Used in the command object where column information may
  127. // change, depending upon the command.
  128. //
  129. // History: 11 Aug 1997 AlanW Created
  130. //
  131. //----------------------------------------------------------------------------
  132. CColumnsInfo::CColumnsInfo(
  133. IUnknown & rUnknown,
  134. CCIOleDBError & ErrorObject,
  135. BOOL fNotPrepared) :
  136. _idUnique(_GetNewId()),
  137. _rUnknown(rUnknown),
  138. _fSequential(FALSE),
  139. _fChaptered(FALSE),
  140. _cbRowWidth(0),
  141. _cColumns( 0 ),
  142. _cBoundColumns(0),
  143. _iColRowId(pidInvalid),
  144. _pColumns(0),
  145. _pidmap( 0 ),
  146. _ErrorObject( ErrorObject ),
  147. _fNotPrepared(fNotPrepared)
  148. {
  149. }
  150. //+---------------------------------------------------------------------------
  151. //
  152. // Member: CColumnsInfo::~CColumnsInfo, public
  153. //
  154. // Synopsis: Destroys a column information class
  155. //
  156. // Notes:
  157. //
  158. // History: 12 Feb 1995 AlanW Created
  159. //
  160. //----------------------------------------------------------------------------
  161. CColumnsInfo::~CColumnsInfo( )
  162. {
  163. delete _pColumns;
  164. }
  165. //+---------------------------------------------------------------------------
  166. //
  167. // Member: CColumnsInfo::InitColumns, public
  168. //
  169. // Synopsis: Initializes or reinitializes columns.
  170. //
  171. // Arguments: [cols] -- a reference to the output column set, pidmapped
  172. // [pidmap] -- property IDs and names for the columns
  173. // [fSequential] -- TRUE if the query is sequential
  174. //
  175. // Notes:
  176. //
  177. // History: 11 Aug 1997 AlanW Created
  178. //
  179. //----------------------------------------------------------------------------
  180. void CColumnsInfo::InitColumns (
  181. CColumnSet const & cols,
  182. CPidMapperWithNames const & pidmap,
  183. BOOL fSequential )
  184. {
  185. _pidmap.Clear();
  186. _cColumns = cols.Count();
  187. _fSequential = fSequential;
  188. _SetColumns(cols, pidmap, fSequential);
  189. _fChaptered = FALSE;
  190. _fNotPrepared = FALSE;
  191. }
  192. //+---------------------------------------------------------------------------
  193. //
  194. // Member: CColumnsInfo::InitColumns, public
  195. //
  196. // Synopsis: Reinitializes columns to be null.
  197. //
  198. // Arguments: [fNotPrepared] - TRUE if GetColumnInfo and MapColumnIDs should
  199. // return DB_E_NOTPREPARED for a command object
  200. //
  201. // Notes:
  202. //
  203. // History: 11 Aug 1997 AlanW Created
  204. //
  205. //----------------------------------------------------------------------------
  206. void CColumnsInfo::InitColumns ( BOOL fNotPrepared )
  207. {
  208. _pidmap.Clear();
  209. _cColumns = 0;
  210. _fSequential = FALSE;
  211. _fChaptered = FALSE;
  212. _fNotPrepared = fNotPrepared;
  213. }
  214. //+---------------------------------------------------------------------------
  215. //
  216. // Member: CColumnsInfo::_SetColumns, private
  217. //
  218. // Synopsis: Initializes or reinitializes columns.
  219. //
  220. // Arguments: [cols] -- a reference to the output column set, pidmapped
  221. // [pidmap] -- property IDs and names for the columns
  222. // [fSequential] -- TRUE if the query is sequential
  223. //
  224. // Notes:
  225. //
  226. // History: 11 Aug 1997 AlanW Created
  227. //
  228. //----------------------------------------------------------------------------
  229. void CColumnsInfo::_SetColumns (
  230. CColumnSet const & cols,
  231. CPidMapperWithNames const & pidmap,
  232. BOOL fSequential )
  233. {
  234. Win4Assert( 0 == _pColumns && 0 == _cbRowWidth );
  235. _idUnique = _GetNewId();
  236. //
  237. // We want the PidMapper to give back 1-based column numbers;
  238. // add either a null propspec or the bookmark column as its first element.
  239. //
  240. if (fSequential)
  241. {
  242. CFullPropSpec nullCol;
  243. _pidmap.NameToPid( nullCol );
  244. }
  245. else
  246. {
  247. CFullPropSpec bmkCol( guidBmk, PROPID_DBBMK_BOOKMARK );
  248. _pidmap.NameToPid( bmkCol );
  249. }
  250. for (unsigned i = 0; i < _cColumns; i++)
  251. {
  252. PROPID pidTmp = cols.Get(i);
  253. const CFullPropSpec & ColId = *pidmap.Get(pidTmp);
  254. if (ColId.IsPropertyPropid() &&
  255. ColId.GetPropSet() == guidBmk)
  256. {
  257. Win4Assert( !fSequential );
  258. if (ColId.GetPropertyPropid() == PROPID_DBBMK_BOOKMARK)
  259. {
  260. if (0 != pidmap.GetFriendlyName(pidTmp))
  261. {
  262. _pidmap.SetFriendlyName( 0, pidmap.GetFriendlyName(pidTmp) );
  263. }
  264. continue;
  265. }
  266. else if (ColId.GetPropertyPropid() == PROPID_DBBMK_CHAPTER)
  267. {
  268. _fChaptered = TRUE;
  269. }
  270. }
  271. PROPID pidNew = _pidmap.NameToPid( ColId );
  272. if (0 != pidmap.GetFriendlyName(pidTmp))
  273. {
  274. _pidmap.SetFriendlyName( pidNew, pidmap.GetFriendlyName(pidTmp) );
  275. }
  276. }
  277. // In case of duplicate columns, _cColumns needs to be adjusted.
  278. Win4Assert( _pidmap.Count() > 1 );
  279. _cColumns = _pidmap.Count() - 1;
  280. }
  281. //+---------------------------------------------------------------------------
  282. //
  283. // Member: CColumnsInfo::MapColumnID, private
  284. //
  285. // Synopsis: Map a column identifier to its column number in the
  286. // cursor.
  287. //
  288. // Arguments: [pColumnId] - A pointer to the column identifier.
  289. //
  290. // Returns: The column number (1-based). Returns DB_INVALIDCOLUMN
  291. // on error.
  292. //
  293. // History: 04 Feb 1995 AlanW Created
  294. //
  295. //----------------------------------------------------------------------------
  296. ULONG CColumnsInfo::MapColumnID(
  297. const DBID * pColumnId
  298. ) {
  299. PROPID pid = pidInvalid;
  300. if (pColumnId->eKind == DBKIND_PGUID_PROPID ||
  301. pColumnId->eKind == DBKIND_PGUID_NAME)
  302. {
  303. DBID dbcolMapped = *pColumnId;
  304. dbcolMapped.uGuid.guid = *pColumnId->uGuid.pguid;
  305. if (pColumnId->eKind == DBKIND_PGUID_PROPID)
  306. dbcolMapped.eKind = DBKIND_GUID_PROPID;
  307. else
  308. dbcolMapped.eKind = DBKIND_GUID_NAME;
  309. pid = _pidmap.NameToPid(dbcolMapped);
  310. }
  311. else
  312. {
  313. pid = _pidmap.NameToPid(*pColumnId);
  314. }
  315. tbDebugOut(( DEB_ITRACE, "pid: 0x%x, _cColumns: %d\n",
  316. pid, _cColumns ));
  317. if (pid == pidInvalid || pid > _cColumns || (pid == 0 && _fSequential) )
  318. return (ULONG) DB_INVALIDCOLUMN;
  319. return pid;
  320. }
  321. //+---------------------------------------------------------------------------
  322. //
  323. // Member: CColumnsInfo::MapColumnIDs, public
  324. //
  325. // Synopsis: Map a column identifier to its column number in the
  326. // rowset.
  327. //
  328. // Arguments: [cColumnIDs] -- # of elements in the arrays
  329. // [rgColumnIDs] -- A pointer to the column identifiers
  330. // [rgColumns] -- an array in which to return the column numbers.
  331. //
  332. // Returns: SCODE - DB_S_ERRORSOCCURRED, an element of rgColumnIDs was
  333. // invalid
  334. //
  335. // Notes: Column numbers are 1-based.
  336. //
  337. //----------------------------------------------------------------------------
  338. STDMETHODIMP CColumnsInfo::MapColumnIDs(
  339. DBORDINAL cColumnIDs,
  340. const DBID rgColumnIDs[],
  341. DBORDINAL rgColumns[])
  342. {
  343. _ErrorObject.ClearErrorInfo();
  344. SCODE sc = S_OK;
  345. if ((0 != cColumnIDs && 0 == rgColumnIDs) ||
  346. 0 == rgColumns)
  347. return _ErrorObject.PostHResult(E_INVALIDARG, IID_IColumnsInfo);
  348. if ( 0 == cColumnIDs )
  349. return S_OK;
  350. if ( _fNotPrepared )
  351. return _ErrorObject.PostHResult(DB_E_NOTPREPARED, IID_IColumnsInfo);
  352. if ( 0 == _cColumns )
  353. return _ErrorObject.PostHResult(DB_E_NOCOMMAND, IID_IColumnsInfo);
  354. unsigned cBadMapping = 0;
  355. TRY
  356. {
  357. for (ULONG i = 0; i < cColumnIDs; i++)
  358. {
  359. ULONG ulColID = MapColumnID( &rgColumnIDs[i] );
  360. rgColumns[i] = ulColID;
  361. if (ulColID == DB_INVALIDCOLUMN)
  362. cBadMapping++;
  363. }
  364. }
  365. CATCH( CException, e )
  366. {
  367. _ErrorObject.PostHResult(e.GetErrorCode(), IID_IColumnsInfo);
  368. sc = GetOleError(e);
  369. }
  370. END_CATCH;
  371. if (SUCCEEDED(sc) && cBadMapping)
  372. sc = (cBadMapping == cColumnIDs) ? DB_E_ERRORSOCCURRED :
  373. DB_S_ERRORSOCCURRED;
  374. return sc;
  375. } //MapColumnIDs
  376. //+---------------------------------------------------------------------------
  377. //
  378. // Member: CColumnsInfo::GetColumnInfo, public
  379. //
  380. // Synopsis: Return information about the columns in the rowset.
  381. //
  382. // Arguments: [pcColumns] - A pointer to where the number of columns
  383. // will be returned.
  384. // [prgInfo] - A pointer to where a pointer to an array of
  385. // DBCOLUMNINFO structures describing the columns
  386. // will be returned. This must be freed by the
  387. // caller.
  388. // [ppStringsBuffer] - A pointer to where extra data for strings
  389. // will be returned. This must be freed by the
  390. // caller if non-null.
  391. //
  392. // Returns: SCODE
  393. //
  394. // Notes: Some columns are standard columns available for all file
  395. // stores. For these columns, full information about data
  396. // type and sizes can be returned. For any other columns,
  397. // we can only say that it has a variant type.
  398. //
  399. // History: 07 Nov 1994 AlanW Created
  400. // 04 Feb 1995 AlanW Moved to CColumnsInfo and rewritten
  401. //
  402. //----------------------------------------------------------------------------
  403. STDMETHODIMP CColumnsInfo::GetColumnInfo(
  404. DBORDINAL * pcColumns,
  405. DBCOLUMNINFO * * prgInfo,
  406. WCHAR * * ppStringsBuffer)
  407. {
  408. _ErrorObject.ClearErrorInfo();
  409. SCODE scResult = S_OK;
  410. //
  411. // Initialize arguments before returning errors
  412. //
  413. if ( pcColumns)
  414. *pcColumns = 0;
  415. if ( prgInfo )
  416. *prgInfo = 0;
  417. if (ppStringsBuffer )
  418. *ppStringsBuffer = 0;
  419. if (0 == pcColumns ||
  420. 0 == prgInfo ||
  421. 0 == ppStringsBuffer)
  422. return _ErrorObject.PostHResult(E_INVALIDARG, IID_IColumnsInfo);
  423. if ( _fNotPrepared )
  424. return _ErrorObject.PostHResult(DB_E_NOTPREPARED, IID_IColumnsInfo);
  425. if ( 0 == _cColumns )
  426. return _ErrorObject.PostHResult(DB_E_NOCOMMAND, IID_IColumnsInfo);
  427. TRY
  428. {
  429. unsigned iFirstCol = _fSequential ? 1 : 0;
  430. unsigned cColumns = GetColumnCount() + 1 - iFirstCol;
  431. //
  432. // The total size required for the output array depends upon
  433. // the size of variable data discovered in the column information.
  434. // Although we could reallocate the memory we'll be writing into,
  435. // we'll just run through the loop twice, once to compute the
  436. // needed space, and the second time to copy the data out after
  437. // doing our allocation.
  438. //
  439. ULONG cchNames = 0;
  440. for (unsigned iCol = iFirstCol; iCol <= GetColumnCount(); iCol++)
  441. {
  442. const CFullPropSpec & ColId = *_pidmap.Get(iCol);
  443. if (ColId.IsPropertyName())
  444. {
  445. cchNames += wcslen(ColId.GetPropertyName()) + 1;
  446. }
  447. WCHAR const * pwszColName = _pidmap.GetFriendlyName(iCol);
  448. if (0 == pwszColName)
  449. pwszColName = _FindColumnInfo(ColId).pwszName;
  450. if (pwszColName)
  451. {
  452. cchNames += wcslen(pwszColName) + 1;
  453. }
  454. }
  455. XArrayOLE<DBCOLUMNINFO> ColumnInfo( cColumns );
  456. XArrayOLE<WCHAR> StringBuf( cchNames );
  457. DBCOLUMNINFO *pColInfo = ColumnInfo.GetPointer();
  458. WCHAR * pwcNames = StringBuf.GetPointer();
  459. for (iCol = iFirstCol; iCol <= GetColumnCount(); iCol++, pColInfo++)
  460. {
  461. const CFullPropSpec & ColId = *_pidmap.Get(iCol);
  462. const DBCOLUMNINFO & rColumnInfo = _FindColumnInfo( ColId );
  463. //
  464. // Copy the prototype column information, then update
  465. // specific fields in the column info:
  466. // column number
  467. // column ID
  468. // copies of strings
  469. //
  470. *pColInfo = rColumnInfo;
  471. pColInfo->iOrdinal = iCol;
  472. pColInfo->columnid.uGuid.guid = ColId.GetPropSet();
  473. if (ColId.IsPropertyName())
  474. {
  475. pColInfo->columnid.eKind = DBKIND_GUID_NAME;
  476. ULONG cch = wcslen(ColId.GetPropertyName()) + 1;
  477. RtlCopyMemory(pwcNames, ColId.GetPropertyName(),
  478. cch * sizeof (WCHAR));
  479. pColInfo->columnid.uName.pwszName = pwcNames;
  480. pwcNames += cch;
  481. }
  482. else
  483. {
  484. Win4Assert(ColId.IsPropertyPropid());
  485. pColInfo->columnid.eKind = DBKIND_GUID_PROPID;
  486. pColInfo->columnid.uName.ulPropid = ColId.GetPropertyPropid();
  487. }
  488. WCHAR const * pwszColName = _pidmap.GetFriendlyName(iCol);
  489. if (0 == pwszColName)
  490. pwszColName = _FindColumnInfo(ColId).pwszName;
  491. if (pwszColName)
  492. {
  493. ULONG cch = wcslen(pwszColName) + 1;
  494. RtlCopyMemory(pwcNames, pwszColName, cch * sizeof (WCHAR));
  495. pColInfo->pwszName = pwcNames;
  496. pwcNames += cch;
  497. }
  498. }
  499. Win4Assert( (unsigned)(pColInfo - ColumnInfo.GetPointer()) == cColumns );
  500. *prgInfo = ColumnInfo.Acquire();
  501. if (cchNames > 0)
  502. *ppStringsBuffer = StringBuf.Acquire();
  503. *pcColumns = cColumns;
  504. }
  505. CATCH( CException, e )
  506. {
  507. scResult = e.GetErrorCode();
  508. _ErrorObject.PostHResult(scResult, IID_IColumnsInfo);
  509. if (scResult != E_OUTOFMEMORY)
  510. scResult = E_FAIL;
  511. }
  512. END_CATCH;
  513. return scResult;
  514. }
  515. //+---------------------------------------------------------------------------
  516. //
  517. // Member: CColumnsInfo::SetColumnBindings, public
  518. //
  519. // Synopsis: Set current column bindings on the cursor. Save in
  520. // member variables. Workid is always added to the
  521. // bindings for movable rowsets for use with bookmarks
  522. // and hRows. Space for a USHORT reserved for row buffer
  523. // refcounting is always allocated.
  524. //
  525. // Arguments: [rpQuery] - a reference to the PQuery for the query
  526. // [hCursor] - a reference to the hCursor to have column
  527. // bindings set on.
  528. // [obRowRefcount] - on return, offset into the row buffer
  529. // where a USHORT reference count can be stored.
  530. // [obRowId] - on return, offset into the row buffer where
  531. // the row identifier is stored. Not valid for
  532. // sequential rowsets.
  533. //
  534. // Returns: Nothing. Throws on errors.
  535. //
  536. // Notes: Initializes the private members _cbRowWidth and _pColumns.
  537. //
  538. // History: 04 Feb 1995 AlanW Created
  539. //
  540. //----------------------------------------------------------------------------
  541. void CColumnsInfo::SetColumnBindings(
  542. PQuery & rpQuery,
  543. ULONG hCursor,
  544. ULONG &obRowRefcount,
  545. ULONG &obRowId,
  546. ULONG &obChaptRefcount,
  547. ULONG &obChaptId
  548. ) {
  549. CTableRowAlloc RowMap( 0 );
  550. USHORT maxAlignment = sizeof (USHORT);
  551. obRowRefcount = RowMap.AllocOffset( sizeof (USHORT),
  552. sizeof (USHORT),
  553. TRUE );
  554. if (_fChaptered)
  555. obChaptRefcount = RowMap.AllocOffset( sizeof (USHORT),
  556. sizeof (USHORT),
  557. TRUE );
  558. else
  559. obChaptRefcount = 0xFFFFFFFF;
  560. obRowId = 0xFFFFFFFF;
  561. obChaptId = 0xFFFFFFFF;
  562. BOOL fAddedWorkId = FALSE;
  563. BOOL fMayDefer = FALSE;
  564. // +1 In case WorkID or Path is added for rowid
  565. XPtr<CTableColumnSet> XColumns( new CTableColumnSet( GetColumnCount() + 1 ));
  566. unsigned cBoundColumns = 0;
  567. tbDebugOut(( DEB_ITRACE, "original column count: %d\n", GetColumnCount() ));
  568. for (unsigned iCol = 1; iCol <= GetColumnCount(); iCol++)
  569. {
  570. const CFullPropSpec & ColId = *_pidmap.Get( iCol );
  571. const DBCOLUMNINFO & rColumnInfo = _FindColumnInfo( ColId );
  572. tbDebugOut(( DEB_ITRACE, "colinfo::set, top of loop, cBoundColumns: %d\n",
  573. cBoundColumns ));
  574. tbDebugOut(( DEB_ITRACE, "adding '%ws'\n", rColumnInfo.pwszName ));
  575. //
  576. // If this is bookmark column, it will be mapped to the row ID
  577. // column. It's only valid for locatable rowsets.
  578. //
  579. if ( (rColumnInfo.dwFlags & DBCOLUMNFLAGS_ISBOOKMARK) &&
  580. ColId.IsPropertyPropid() &&
  581. ColId.GetPropertyPropid() == PROPID_DBBMK_BOOKMARK)
  582. {
  583. tbDebugOut(( DEB_ITRACE, "skipping bookmark column\n" ));
  584. Win4Assert(! _fSequential );
  585. if (_fSequential)
  586. THROW(CException(E_FAIL));
  587. continue;
  588. }
  589. // the self columns is resolved in the accessor -- no binding needed
  590. if ( ( ColId.IsPropertyPropid() ) &&
  591. ( ColId.GetPropertyPropid() == PROPID_DBSELF_SELF ) &&
  592. ( ColId.GetPropSet() == DBCOL_SELFCOLUMNS ) )
  593. {
  594. continue;
  595. }
  596. //
  597. // Create the new column. Note that its PropID is the
  598. // 1-based column ID.
  599. //
  600. XPtr<CTableColumn> TableCol(new CTableColumn( iCol ));
  601. #ifndef ALWAYS_USE_VARIANT_BINDING
  602. VARTYPE vt = rColumnInfo.wType;
  603. switch (vt)
  604. {
  605. case DBTYPE_VARIANT:
  606. {
  607. #endif // ndef ALWAYS_USE_VARIANT_BINDING
  608. fMayDefer = TRUE;
  609. TableCol->SetValueField( DBTYPE_VARIANT,
  610. RowMap.AllocOffset( sizeof (PROPVARIANT),
  611. sizeof (LONGLONG),
  612. TRUE ),
  613. sizeof (PROPVARIANT));
  614. // The status column is interesting for all columns
  615. TableCol->SetStatusField( RowMap.AllocOffset( sizeof (BYTE),
  616. sizeof (BYTE),
  617. TRUE ),
  618. sizeof (BYTE));
  619. // Length is interesting, especially when the value is deferred
  620. TableCol->SetLengthField( RowMap.AllocOffset( sizeof (ULONG),
  621. sizeof (ULONG),
  622. TRUE ),
  623. sizeof (ULONG));
  624. USHORT cbData, cbAlignment, rgfFlags;
  625. CTableVariant::VartypeInfo(DBTYPE_VARIANT, cbData, cbAlignment, rgfFlags);
  626. if ( cbAlignment > maxAlignment)
  627. maxAlignment = cbAlignment;
  628. #ifndef ALWAYS_USE_VARIANT_BINDING
  629. break;
  630. }
  631. case DBTYPE_DATE:
  632. case DBTYPE_WSTR:
  633. case DBTYPE_STR:
  634. //
  635. // Adjust DBTYPEs from the column info into ones that are
  636. // better for binding.
  637. //
  638. if (vt == DBTYPE_DATE)
  639. vt = VT_FILETIME;
  640. else if (vt == DBTYPE_WSTR)
  641. vt = VT_LPWSTR;
  642. else if (vt == DBTYPE_STR)
  643. vt = VT_LPSTR;
  644. // NOTE: fall through
  645. default:
  646. USHORT cbData, cbAlignment, rgfFlags;
  647. CTableVariant::VartypeInfo(vt, cbData, cbAlignment, rgfFlags);
  648. if (rgfFlags & CTableVariant::MultiSize)
  649. cbData = (USHORT) rColumnInfo.ulColumnSize;
  650. Win4Assert(cbData != 0 || vt == VT_EMPTY);
  651. if (cbData == 0 && vt != VT_EMPTY)
  652. {
  653. tbDebugOut(( DEB_WARN,
  654. "CColumnInfo::SetColumnBindings - Unknown variant type %4x\n",
  655. vt));
  656. }
  657. if (cbAlignment)
  658. {
  659. if (cbAlignment > maxAlignment)
  660. {
  661. maxAlignment = cbAlignment;
  662. }
  663. }
  664. else
  665. {
  666. cbAlignment = 1;
  667. }
  668. if (cbData != 0)
  669. {
  670. TableCol->SetValueField( vt,
  671. RowMap.AllocOffset( cbData,
  672. cbAlignment,
  673. TRUE ),
  674. cbData);
  675. Win4Assert( 0 == ( (TableCol->GetValueOffset()) % cbAlignment ) );
  676. //
  677. // The status column is interesting for almost all columns,
  678. // even inline columns, since a summary catalog might have
  679. // VT_EMPTY data for these columns (eg storage props).
  680. //
  681. TableCol->SetStatusField( RowMap.AllocOffset( sizeof (BYTE),
  682. sizeof (BYTE),
  683. TRUE ),
  684. sizeof (BYTE));
  685. }
  686. }
  687. #endif // ndef ALWAYS_USE_VARIANT_BINDING
  688. //
  689. // If this is the row ID column, save its offset in the row.
  690. //
  691. if (rColumnInfo.dwFlags & DBCOLUMNFLAGS_ISROWID)
  692. {
  693. #ifdef ALWAYS_USE_VARIANT_BINDING
  694. Win4Assert(TableCol->GetStoredType() == VT_VARIANT &&
  695. TableCol->IsValueStored() &&
  696. TableCol->GetValueSize() == sizeof (PROPVARIANT));
  697. PROPVARIANT prop;
  698. obRowId = TableCol->GetValueOffset() +
  699. (DWORD)((BYTE *) &prop.lVal - (BYTE *)&prop);
  700. #else // ndef ALWAYS_USE_VARIANT_BINDING
  701. Win4Assert(TableCol->GetStoredType() == VT_I4 &&
  702. TableCol->IsValueStored() &&
  703. TableCol->GetValueSize() == sizeof (ULONG));
  704. obRowId = TableCol->GetValueOffset();
  705. #endif // ndef ALWAYS_USE_VARIANT_BINDING
  706. _iColRowId = iCol;
  707. fAddedWorkId = TRUE;
  708. }
  709. //
  710. // If this is the chapter column, save its offset in the row.
  711. //
  712. if (rColumnInfo.dwFlags & DBCOLUMNFLAGS_ISCHAPTER)
  713. {
  714. Win4Assert( _fChaptered );
  715. #ifdef ALWAYS_USE_VARIANT_BINDING
  716. Win4Assert(TableCol->GetStoredType() == VT_VARIANT &&
  717. TableCol->IsValueStored() &&
  718. TableCol->GetValueSize() == sizeof (PROPVARIANT));
  719. PROPVARIANT prop;
  720. obChaptId = TableCol->GetValueOffset() +
  721. (DWORD)((BYTE *) &prop.lVal - (BYTE *)&prop);
  722. #else // ndef ALWAYS_USE_VARIANT_BINDING
  723. Win4Assert(TableCol->GetStoredType() == VT_I4 &&
  724. TableCol->IsValueStored() &&
  725. TableCol->GetValueSize() == sizeof (ULONG));
  726. obChaptId = TableCol->GetValueOffset();
  727. #endif // ndef ALWAYS_USE_VARIANT_BINDING
  728. }
  729. XColumns->Add(TableCol.GetPointer(), cBoundColumns++);
  730. TableCol.Acquire();
  731. }
  732. tbDebugOut(( DEB_ITRACE, "colinfo::set, after loop, cBoundColumns: %d\n",
  733. cBoundColumns ));
  734. // Need to add workid for non-sequential queries so that bookmarks
  735. // work, and either workid or path so that deferred values work.
  736. if ( ( ( !_fSequential ) ||
  737. ( fMayDefer && rpQuery.CanDoWorkIdToPath() ) ) &&
  738. ( !fAddedWorkId ) )
  739. {
  740. tbDebugOut(( DEB_ITRACE, "colinfo::set, adding WID column\n" ));
  741. //
  742. // Need to add the row ID column to the bindings, so that bookmarks
  743. // work, and deferred values can be loaded.
  744. //
  745. const DBCOLUMNINFO & rColumnInfo = _GetRowIdColumnInfo( );
  746. unsigned iCol = _pidmap.NameToPid( rColumnInfo.columnid );
  747. XPtr<CTableColumn> TableCol(new CTableColumn( iCol ));
  748. _iColRowId = iCol;
  749. Win4Assert (VT_I4 == rColumnInfo.wType);
  750. if (sizeof (ULONG) > maxAlignment)
  751. maxAlignment = sizeof (ULONG);
  752. TableCol->SetValueField( VT_I4,
  753. RowMap.AllocOffset( sizeof (ULONG),
  754. sizeof (ULONG),
  755. TRUE ),
  756. sizeof (ULONG));
  757. obRowId = TableCol->GetValueOffset();
  758. TableCol->SetStatusField( RowMap.AllocOffset( sizeof (BYTE),
  759. sizeof (BYTE),
  760. TRUE ),
  761. sizeof (BYTE));
  762. XColumns->Add(TableCol.GetPointer(), cBoundColumns++);
  763. TableCol.Acquire();
  764. }
  765. ULONG rem = RowMap.GetRowWidth() % maxAlignment;
  766. if ( 0 == rem )
  767. _cbRowWidth = RowMap.GetRowWidth();
  768. else
  769. _cbRowWidth = RowMap.GetRowWidth() + maxAlignment - rem;
  770. rpQuery.SetBindings( hCursor,
  771. _cbRowWidth,
  772. XColumns.GetReference(),
  773. _pidmap );
  774. tbDebugOut(( DEB_ITRACE, "colinfo::set, old # cols %d, new # cols %d\n",
  775. _cColumns, cBoundColumns ));
  776. _cBoundColumns = cBoundColumns;
  777. _pColumns = XColumns.Acquire();
  778. }
  779. //+---------------------------------------------------------------------------
  780. //
  781. // Member: CColumnsInfo::Get1ColumnInfo, public
  782. //
  783. // Synopsis: Return information about a single column in the rowset.
  784. //
  785. // Arguments: [iColumn] - the column number whose column info is to be
  786. // returned.
  787. //
  788. // Returns: DBCOLUMNINFO & - a pointer to column info for the column
  789. //
  790. // Notes:
  791. //
  792. // History: 29 Mar 1995 AlanW Created
  793. //
  794. //----------------------------------------------------------------------------
  795. const DBCOLUMNINFO & CColumnsInfo::Get1ColumnInfo(
  796. ULONG iColumn
  797. ) /*const*/
  798. {
  799. const CFullPropSpec & ColId = *_pidmap.Get(iColumn);
  800. return _FindColumnInfo( ColId );
  801. }
  802. #ifdef INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
  803. STDMETHODIMP CRowset::GetColumnsRowset(
  804. ULONG cSelections,
  805. DBID rgColumnSelection[],
  806. IRowset ** ppColCursor
  807. ) /*const*/ {
  808. _ErrorObject.ClearErrorInfo();
  809. return _ErrorObject.PostHResult(E_NOTIMPL, IID_IColumnsRowset);
  810. }
  811. STDMETHODIMP CRowset::GetAvailableColumns(
  812. ULONG * pcSelections,
  813. DBID ** rgColumnSelection
  814. ) /*const*/ {
  815. _ErrorObject.ClearErrorInfo();
  816. return _ErrorObject.PostHResult(E_NOTIMPL, IID_IColumnsRowset);
  817. }
  818. #endif // INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
  819. ////////////////////////////////////////////////////////////
  820. //
  821. // Data declarations for _FindColumnInfo
  822. //
  823. // Notes: These arrays of structures are prototype column info.
  824. // structures returned by _FindColumnInfo.
  825. //
  826. ////////////////////////////////////////////////////////////
  827. static const DBCOLUMNINFO aStoragePropDescs[] = {
  828. { L"FileDirectoryName", 0, 0,
  829. DBCOLUMNFLAGS_ISNULLABLE, MAX_PATH, // storage props are never deferred
  830. DBTYPE_WSTR, 0xff, 0xff,
  831. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_DIRECTORY ) }
  832. },
  833. { L"ClassID", 0, 0,
  834. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (GUID),
  835. DBTYPE_GUID, 0xff, 0xff,
  836. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_CLASSID ) }
  837. },
  838. { L"FileStorageType", 0, 0,
  839. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (ULONG),
  840. DBTYPE_UI4, 0xff, 0xff,
  841. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_STORAGETYPE ) }
  842. },
  843. { L"FileIndex", 0, 0,
  844. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
  845. DBTYPE_I8, 0xff, 0xff,
  846. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_FILEINDEX ) }
  847. },
  848. { L"FileUSN", 0, 0,
  849. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
  850. DBTYPE_I8, 0xff, 0xff,
  851. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_LASTCHANGEUSN ) }
  852. },
  853. { L"FileName", 0, 0,
  854. DBCOLUMNFLAGS_ISNULLABLE, MAX_PATH, // storage props are never deferred
  855. DBTYPE_WSTR, 0xff, 0xff,
  856. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_NAME ) }
  857. },
  858. { L"FilePathName", 0, 0,
  859. DBCOLUMNFLAGS_ISNULLABLE, MAX_PATH, // storage props are never deferred
  860. DBTYPE_WSTR, 0xff, 0xff,
  861. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_PATH ) }
  862. },
  863. { L"FileSize", 0, 0,
  864. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
  865. DBTYPE_I8, 0xff, 0xff,
  866. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_SIZE ) }
  867. },
  868. { L"FileAttributes", 0, 0,
  869. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (ULONG),
  870. DBTYPE_UI4, 0xff, 0xff,
  871. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_ATTRIBUTES ) }
  872. },
  873. // NOTE: file times are typed as DBTYPE_DATE, but are bound to the
  874. // table as VT_FILETIME.
  875. { L"FileWriteTime", 0, 0,
  876. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
  877. DBTYPE_DATE, 0xff, 0xff,
  878. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_WRITETIME ) }
  879. },
  880. { L"FileCreateTime", 0, 0,
  881. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
  882. DBTYPE_DATE, 0xff, 0xff,
  883. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_CREATETIME ) }
  884. },
  885. { L"FileAccessTime", 0, 0,
  886. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONGLONG),
  887. DBTYPE_DATE, 0xff, 0xff,
  888. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_ACCESSTIME ) }
  889. },
  890. { L"FileShortName", 0, 0,
  891. DBCOLUMNFLAGS_ISNULLABLE, 13, // storage props are never deferred
  892. DBTYPE_WSTR, 0xff, 0xff,
  893. { PSGUID_STORAGE, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PID_STG_SHORTNAME ) }
  894. },
  895. };
  896. const ULONG cStoragePropDescs =
  897. sizeof aStoragePropDescs /
  898. sizeof aStoragePropDescs[0];
  899. //
  900. // Standard query properties.
  901. // Does not include pidAll or pidContent, those are used only in restrictions.
  902. //
  903. static const DBCOLUMNINFO aQueryPropDescs[] = {
  904. { L"QueryRankvector", 0, 0,
  905. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof(PROPVARIANT),
  906. DBTYPE_VARIANT, 0xff, 0xff,
  907. { DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_RANKVECTOR ) }
  908. },
  909. { L"QueryRank", 0, 0,
  910. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
  911. DBTYPE_I4, 0xff, 0xff,
  912. { DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_RANK ) }
  913. },
  914. { L"QueryHitCount", 0, 0,
  915. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
  916. DBTYPE_I4, 0xff, 0xff,
  917. { DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_HITCOUNT ) }
  918. },
  919. { L"WorkID", 0, 0,
  920. DBCOLUMNFLAGS_ISFIXEDLENGTH|DBCOLUMNFLAGS_ISROWID, sizeof (LONG),
  921. DBTYPE_I4, 0xff, 0xff,
  922. { DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_WORKID ) }
  923. },
  924. { L"QueryUnfiltered", 0, 0,
  925. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof(BOOL),
  926. DBTYPE_BOOL, 0xff, 0xff,
  927. { DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_UNFILTERED ) }
  928. },
  929. { L"QueryVirtualPath", 0, 0,
  930. DBCOLUMNFLAGS_ISNULLABLE, MAX_PATH,
  931. DBTYPE_WSTR, 0xff, 0xff,
  932. { DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_VIRTUALPATH ) }
  933. },
  934. #if defined( DISPID_QUERY_NLIRRANK )
  935. { L"NLIRRank", 0, 0,
  936. DBCOLUMNFLAGS_ISNULLABLE|DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
  937. DBTYPE_I4, 0xff, 0xff,
  938. { DBQUERYGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( DISPID_QUERY_NLIRRANK ) }
  939. },
  940. #endif // defined( DISPID_QUERY_NLIRRANK )
  941. };
  942. const ULONG cQueryPropDescs =
  943. sizeof aQueryPropDescs /
  944. sizeof aQueryPropDescs[0];
  945. static DBCOLUMNINFO const aBmkPropDescs[] = {
  946. { L"Bookmark", 0, 0,
  947. DBCOLUMNFLAGS_ISBOOKMARK|DBCOLUMNFLAGS_ISFIXEDLENGTH,
  948. sizeof (CI_TBL_BMK),
  949. DBTYPE_BYTES, 0xff, 0xff,
  950. { DBBMKGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PROPID_DBBMK_BOOKMARK ) }
  951. },
  952. { L"Chapter", 0, 0,
  953. DBCOLUMNFLAGS_ISCHAPTER|DBCOLUMNFLAGS_ISBOOKMARK|DBCOLUMNFLAGS_ISFIXEDLENGTH,
  954. sizeof (CI_TBL_CHAPT),
  955. DBTYPE_BYTES, 0xff, 0xff,
  956. { DBBMKGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PROPID_DBBMK_CHAPTER ) }
  957. },
  958. };
  959. const ULONG cBmkPropDescs =
  960. sizeof aBmkPropDescs /
  961. sizeof aBmkPropDescs[0];
  962. // CLEANCODE: ole-db spec bug #1271 - const GUID init. less than useful
  963. #ifndef DBSELFGUID
  964. #define DBSELFGUID {0xc8b52231,0x5cf3,0x11ce,{0xad,0xe5,0x00,0xaa,0x00,0x44,0x77,0x3d}}
  965. #endif // ndef DBSELFGUID
  966. static DBCOLUMNINFO const aSelfPropDescs[] = {
  967. { L"Self", 0, 0,
  968. DBCOLUMNFLAGS_ISFIXEDLENGTH,
  969. sizeof( int ),
  970. DBTYPE_I4, 0xff, 0xff,
  971. { DBSELFGUID, DBKIND_GUID_PROPID, (LPWSTR) UIntToPtr( PROPID_DBSELF_SELF ) }
  972. },
  973. };
  974. const ULONG cSelfPropDescs =
  975. sizeof aSelfPropDescs /
  976. sizeof aSelfPropDescs[0];
  977. #ifdef INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
  978. static const DBCOLUMNINFO aColInfoPropDescs[] = {
  979. { L"ColumnId", 0, 0,
  980. DBCOLUMNFLAGS_ISFIXEDLENGTH, 3 * sizeof(PROPVARIANT),
  981. DBTYPE_VARIANT|DBTYPE_VECTOR, 0xff, 0xff,
  982. { DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)1 }
  983. },
  984. { L"ColumnName", 0, 0,
  985. 0, 20,
  986. DBTYPE_WSTR, 0xff, 0xff,
  987. { DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)2 }
  988. },
  989. { L"ColumnNumber", 0, 0,
  990. DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
  991. DBTYPE_I4, 0xff, 0xff,
  992. { DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)3 }
  993. },
  994. { L"ColumnType", 0, 0,
  995. DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof(USHORT),
  996. DBTYPE_I2, 0xff, 0xff,
  997. { DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)4 }
  998. },
  999. { L"ColumnLength", 0, 0,
  1000. DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
  1001. DBTYPE_I4, 0xff, 0xff,
  1002. { DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)5 }
  1003. },
  1004. { L"ColumnPrecision", 0, 0,
  1005. DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
  1006. DBTYPE_I4, 0xff, 0xff,
  1007. { DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)6 }
  1008. },
  1009. { L"ColumnScale", 0, 0,
  1010. DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
  1011. DBTYPE_I4, 0xff, 0xff,
  1012. { DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)7 }
  1013. },
  1014. { L"ColumnFlags", 0, 0,
  1015. DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (LONG),
  1016. DBTYPE_I4, 0xff, 0xff,
  1017. { DBCIDGUID, DBKIND_GUID_PROPID, (LPWSTR)8 }
  1018. },
  1019. };
  1020. const ULONG cColInfoPropDescs =
  1021. sizeof aColInfoPropDescs /
  1022. sizeof aColInfoPropDescs[0];
  1023. #endif // INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
  1024. //
  1025. // Array of column descriptions per known propset
  1026. // Each referenced array must have the same Guid for each element in
  1027. // the array.
  1028. //
  1029. const CColumnsInfo::SPropSetInfo CColumnsInfo::aPropSets [ ] = {
  1030. #define IPROPSET_STORAGE 0 // Storage property set index
  1031. { cStoragePropDescs, aStoragePropDescs },
  1032. { cQueryPropDescs, aQueryPropDescs },
  1033. { cBmkPropDescs, aBmkPropDescs },
  1034. { cSelfPropDescs, aSelfPropDescs },
  1035. #ifdef INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
  1036. { cColInfoPropDescs, aColInfoPropDescs },
  1037. #endif // INCLUDE_COLUMNS_ROWSET_IMPLEMENTATION
  1038. };
  1039. const ULONG CColumnsInfo::cPropSets =
  1040. sizeof CColumnsInfo::aPropSets /
  1041. sizeof CColumnsInfo::aPropSets[0];
  1042. DBCOLUMNINFO const DefaultColumnInfo = {
  1043. 0, 0, 0,
  1044. DBCOLUMNFLAGS_ISNULLABLE | DBCOLUMNFLAGS_MAYDEFER | DBCOLUMNFLAGS_ISFIXEDLENGTH, sizeof (PROPVARIANT),
  1045. DBTYPE_VARIANT, 0xff, 0xff,
  1046. { {0,0,0,{0,0,0,0,0,0,0,0}}, DBKIND_GUID_PROPID, (LPWSTR)0 }
  1047. };
  1048. //+---------------------------------------------------------------------------
  1049. //
  1050. // Member: CColumnsInfo::_FindColumnInfo, static
  1051. //
  1052. // Synopsis: Return information about a particular column ID.
  1053. //
  1054. // Arguments: [ColId] - Column ID to be looked up.
  1055. //
  1056. // Returns: DBCOLUMNINFO - the column information for the row looked up.
  1057. //
  1058. // Notes: Some columns are standard columns available for all file
  1059. // stores. For these columns, full information about data
  1060. // type and sizes can be returned. For any other columns,
  1061. // a generic column information structure is returned.
  1062. //
  1063. // History: 10 Feb 1995 AlanW Created
  1064. //
  1065. //----------------------------------------------------------------------------
  1066. DBCOLUMNINFO const & CColumnsInfo::_FindColumnInfo(
  1067. const CFullPropSpec & ColId
  1068. ) {
  1069. DBCOLUMNINFO const * pColInfo = &DefaultColumnInfo;
  1070. //
  1071. // All custom information we return has propids, not prop names.
  1072. // Valid property IDs start at 2
  1073. //
  1074. if (ColId.IsPropertyPropid())
  1075. {
  1076. for (unsigned iPropSet = 0; iPropSet < cPropSets; iPropSet++)
  1077. {
  1078. if (ColId.GetPropSet() ==
  1079. aPropSets[iPropSet].aPropDescs[0].columnid.uGuid.guid)
  1080. {
  1081. //
  1082. // Found the guid for the propset, now try to find the
  1083. // propid.
  1084. //
  1085. ULONG ulPropId = ColId.GetPropertyPropid();
  1086. Win4Assert( ulPropId != PID_CODEPAGE &&
  1087. ulPropId != PID_DICTIONARY);
  1088. for (unsigned iDesc = 0;
  1089. iDesc < aPropSets[iPropSet].cProps;
  1090. iDesc++)
  1091. {
  1092. if (ulPropId ==
  1093. aPropSets[iPropSet].aPropDescs[iDesc].columnid.uName.ulPropid)
  1094. {
  1095. pColInfo = &aPropSets[iPropSet].aPropDescs[iDesc];
  1096. break;
  1097. }
  1098. }
  1099. break;
  1100. }
  1101. }
  1102. }
  1103. return *pColInfo;
  1104. }
  1105. //+---------------------------------------------------------------------------
  1106. //
  1107. // Member: CColumnsInfo::_GetRowIdColumnInfo, static
  1108. //
  1109. // Synopsis: Return information about the row ID column
  1110. //
  1111. // Arguments: - None -
  1112. //
  1113. // Returns: DBCOLUMNINFO - the column information for the row looked up.
  1114. //
  1115. // Notes: It is assumed that there is only one row ID column in the
  1116. // standard column info. This may need to change for chaptered
  1117. // rowsets.
  1118. //
  1119. // History: 15 Mar 1995 AlanW Created
  1120. //
  1121. //----------------------------------------------------------------------------
  1122. DBCOLUMNINFO const & CColumnsInfo::_GetRowIdColumnInfo(
  1123. ) {
  1124. DBCOLUMNINFO const * pColInfo = 0;
  1125. for (unsigned iPropSet = 0;
  1126. iPropSet < cPropSets && pColInfo == 0;
  1127. iPropSet++)
  1128. {
  1129. for (unsigned iDesc = 0;
  1130. iDesc < aPropSets[iPropSet].cProps;
  1131. iDesc++)
  1132. {
  1133. if ( aPropSets[iPropSet].aPropDescs[iDesc].dwFlags &
  1134. DBCOLUMNFLAGS_ISROWID)
  1135. {
  1136. pColInfo = &aPropSets[iPropSet].aPropDescs[iDesc];
  1137. break;
  1138. }
  1139. }
  1140. }
  1141. Win4Assert(pColInfo != 0);
  1142. return *pColInfo;
  1143. }