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.

641 lines
21 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 2000.
  5. //
  6. // File: DOQUERY.CXX
  7. //
  8. // Contents: Functions to make query nodes and trees, and to execute
  9. // queries.
  10. //
  11. // History: 02 Nov 94 alanw Created from main.cxx and screen.cxx.
  12. //
  13. //----------------------------------------------------------------------------
  14. #include <pch.cxx>
  15. #pragma hdrstop
  16. #include <doquery.hxx>
  17. #include <catstate.hxx>
  18. static const GUID guidBmk = DBBMKGUID;
  19. static const GUID psGuidStorage = PSGUID_STORAGE;
  20. static const GUID psGuidQuery = DBQUERYGUID;
  21. static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
  22. static const GUID guidRowset = DBPROPSET_ROWSET;
  23. static CDbColId psRank( psGuidQuery, DISPID_QUERY_RANK );
  24. static CDbColId psBookmark( guidBmk, PROPID_DBBMK_BOOKMARK );
  25. static CDbColId psPath( psGuidStorage, PID_STG_PATH );
  26. //+---------------------------------------------------------------------------
  27. //
  28. // Function: FormTableNode
  29. //
  30. // Synopsis: Forms a selection node and if needed a sort node
  31. //
  32. // Arguments: [rst] - Restriction tree describing the query
  33. // [states] - global state info
  34. // [plist] - friendly property name list
  35. //
  36. // Returns: A pointer to a commandtree node
  37. //
  38. // History: 9-4-95 SitaramR Created
  39. //
  40. //----------------------------------------------------------------------------
  41. CDbCmdTreeNode *FormTableNode(
  42. CDbCmdTreeNode & rst,
  43. CCatState & states,
  44. IColumnMapper * plist )
  45. {
  46. //
  47. // First create a selection node and append the restriction tree to it
  48. //
  49. XPtr<CDbSelectNode> xSelect( new CDbSelectNode() );
  50. if ( xSelect.IsNull() || !xSelect->IsValid() )
  51. THROW( CException( STATUS_NO_MEMORY ) );
  52. //
  53. // Clone the restriction and use it.
  54. //
  55. CDbCmdTreeNode * pExpr = rst.Clone();
  56. if ( 0 == pExpr )
  57. {
  58. THROW( CException( STATUS_NO_MEMORY ) );
  59. }
  60. //
  61. // Now make the restriction a child of the selection node.
  62. //
  63. xSelect->SetRestriction( pExpr );
  64. XPtr<CDbCmdTreeNode> xTable;
  65. unsigned int cSortProp = states.NumberOfSortProps();
  66. if ( cSortProp > 0 )
  67. {
  68. CDbSortNode * pSort = new CDbSortNode();
  69. if ( 0 == pSort )
  70. {
  71. THROW( CException( STATUS_NO_MEMORY ) );
  72. }
  73. XPtr<CDbCmdTreeNode> xSort( pSort );
  74. for( unsigned i = 0; i < cSortProp; i++ )
  75. {
  76. WCHAR const * wcsName;
  77. SORTDIR sd;
  78. states.GetSortProp( i,
  79. &wcsName,
  80. &sd );
  81. DBID *pdbid = 0;
  82. if( FAILED(plist->GetPropInfoFromName( wcsName,
  83. &pdbid,
  84. 0,
  85. 0 )) )
  86. THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_SORT ) );
  87. //
  88. // Add the sort column.
  89. //
  90. CDbColId *pprop = (CDbColId *)pdbid;
  91. if ( !pSort->AddSortColumn( *pprop,
  92. (sd == SORT_DOWN) ? TRUE : FALSE,
  93. states.GetLocale()))
  94. {
  95. THROW( CException( STATUS_NO_MEMORY ) );
  96. }
  97. }
  98. if ( pSort->AddTable( xSelect.GetPointer() ) )
  99. xSelect.Acquire();
  100. else
  101. {
  102. THROW( CException( STATUS_NO_MEMORY ) );
  103. }
  104. xTable.Set( xSort.Acquire() );
  105. }
  106. else
  107. xTable.Set( xSelect.Acquire() );
  108. return xTable.Acquire();
  109. }
  110. //+---------------------------------------------------------------------------
  111. //
  112. // Function: FormQueryTree
  113. //
  114. // Synopsis: Forms a query tree consisting of the projection nodes,
  115. // selection node, sort node(s) and the restriction tree.
  116. //
  117. // Arguments: [rst] - Restriction tree describing the query
  118. // [states] - global state info
  119. // [plist] - friendly property name list
  120. //
  121. // Returns: A pointer to the query tree. It is the responsibility of
  122. // the caller to later free it.
  123. //
  124. // History: 6-20-95 srikants Created
  125. //
  126. //----------------------------------------------------------------------------
  127. CDbCmdTreeNode * FormQueryTree( CDbCmdTreeNode & rst,
  128. CCatState & states,
  129. IColumnMapper * plist,
  130. BOOL fAddBmkCol,
  131. BOOL fAddRankForBrowse )
  132. {
  133. CDbCmdTreeNode *pTable = FormTableNode( rst, states, plist );
  134. XPtr<CDbCmdTreeNode> xTable( pTable );
  135. XPtr<CDbCmdTreeNode> xQuery;
  136. unsigned cCategories = states.NumberOfCategories();
  137. if ( cCategories > 0 )
  138. {
  139. //
  140. // First create nesting node for the base table
  141. //
  142. CDbNestingNode *pNestNodeBase = new CDbNestingNode;
  143. if ( pNestNodeBase == 0 )
  144. THROW ( CException( STATUS_NO_MEMORY ) );
  145. XPtr<CDbCmdTreeNode> xNestNodeBase( pNestNodeBase );
  146. BOOL fNeedPath = TRUE;
  147. BOOL fNeedRank = fAddRankForBrowse;
  148. //
  149. // Next add all the columns in the state.
  150. //
  151. CDbColId * pprop = 0;
  152. DBID *pdbid = 0;
  153. unsigned int cCol = states.NumberOfColumns();
  154. for ( unsigned int i = 0; i < cCol; i++ )
  155. {
  156. if( FAILED(plist->GetPropInfoFromName( states.GetColumn( i ),
  157. &pdbid,
  158. 0,
  159. 0 )) )
  160. THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_OUTPUT ) );
  161. pprop = (CDbColId *)pdbid;
  162. if ( *pprop == psPath )
  163. {
  164. fNeedPath = FALSE;
  165. }
  166. else if ( *pprop == psRank )
  167. {
  168. fNeedRank = FALSE;
  169. }
  170. if ( !pNestNodeBase->AddChildColumn( *pprop ) )
  171. {
  172. THROW( CException( STATUS_NO_MEMORY ) );
  173. }
  174. }
  175. if ( fNeedPath && !pNestNodeBase->AddChildColumn( psPath ) )
  176. {
  177. THROW( CException( STATUS_NO_MEMORY ) );
  178. }
  179. if ( fNeedRank && !pNestNodeBase->AddChildColumn( psRank ) )
  180. {
  181. THROW( CException( STATUS_NO_MEMORY ) );
  182. }
  183. //
  184. // Add categories to the output column
  185. //
  186. for ( i = 0; i < cCategories; i++ )
  187. {
  188. //
  189. // We need to ensure that we don't add categories that have already been
  190. // added above. The following test can be speeded up from O( i*j ) to O( i+j ),
  191. // but the the number of categories and the number of columns are usually very small.
  192. //
  193. BOOL fFound = FALSE;
  194. for ( unsigned j=0; j<states.NumberOfColumns(); j++ )
  195. {
  196. if ( _wcsicmp( states.GetCategory(i), states.GetColumn( j ) ) == 0 )
  197. {
  198. fFound = TRUE;
  199. break;
  200. }
  201. }
  202. if ( !fFound )
  203. {
  204. if( FAILED(plist->GetPropInfoFromName( states.GetCategory( i ),
  205. &pdbid,
  206. 0,
  207. 0 )) )
  208. THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_CATEGORIZATION ) );
  209. pprop = (CDbColId *)pdbid;
  210. if ( !pNestNodeBase->AddChildColumn( *pprop ) )
  211. THROW( CException( STATUS_NO_MEMORY ) );
  212. }
  213. }
  214. if ( pNestNodeBase->AddTable( xTable.GetPointer() ) )
  215. xTable.Acquire();
  216. else
  217. {
  218. THROW( CException( STATUS_NO_MEMORY ) );
  219. }
  220. if ( FAILED(plist->GetPropInfoFromName( states.GetCategory( cCategories - 1 ),
  221. &pdbid,
  222. 0,
  223. 0 )) )
  224. THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_OUTPUT ) );
  225. pprop = (CDbColId *)pdbid;
  226. if ( !pNestNodeBase->AddGroupingColumn( *pprop ) )
  227. THROW( CException( STATUS_NO_MEMORY ) );
  228. if ( !pNestNodeBase->AddParentColumn( *pprop ) )
  229. THROW( CException( STATUS_NO_MEMORY ) );
  230. if ( !pNestNodeBase->AddParentColumn( psBookmark ) )
  231. THROW( CException( STATUS_NO_MEMORY ) );
  232. //
  233. // Now create the nesting nodes for remaining categories, if any
  234. //
  235. XPtr<CDbCmdTreeNode> xCategChild( xNestNodeBase.Acquire() );
  236. for ( int j=cCategories-2; j>=0; j-- )
  237. {
  238. if ( FAILED(plist->GetPropInfoFromName( states.GetCategory( j ),
  239. &pdbid,
  240. 0,
  241. 0 )) )
  242. {
  243. THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_OUTPUT ) );
  244. }
  245. pprop = (CDbColId *)pdbid;
  246. CDbNestingNode *pCategParent = new CDbNestingNode;
  247. if ( pCategParent == 0 )
  248. THROW( CException( STATUS_NO_MEMORY ) );
  249. XPtr<CDbCmdTreeNode> xCategParent( pCategParent );
  250. if ( pCategParent->AddTable( xCategChild.GetPointer() ) )
  251. xCategChild.Acquire();
  252. else
  253. {
  254. THROW( CException( STATUS_NO_MEMORY ) );
  255. }
  256. if ( !pCategParent->AddGroupingColumn( *pprop ) )
  257. THROW( CException( STATUS_NO_MEMORY ) );
  258. if ( !pCategParent->AddParentColumn( *pprop ) )
  259. THROW( CException( STATUS_NO_MEMORY ) );
  260. if ( !pCategParent->AddParentColumn( psBookmark ) )
  261. THROW( CException( STATUS_NO_MEMORY ) );
  262. xCategChild.Set( xCategParent.Acquire() );
  263. }
  264. xQuery.Set( xCategChild.Acquire() );
  265. }
  266. else
  267. {
  268. //
  269. // Create the projection node
  270. //
  271. CDbProjectNode * pProject = new CDbProjectNode();
  272. if ( 0 == pProject )
  273. {
  274. THROW( CException( STATUS_NO_MEMORY ) );
  275. }
  276. XPtr<CDbCmdTreeNode> xProject( pProject );
  277. //
  278. // Add the selection/sort node
  279. //
  280. if ( pProject->AddTable( xTable.GetPointer() ) )
  281. xTable.Acquire();
  282. else
  283. {
  284. THROW( CException( STATUS_NO_MEMORY ) );
  285. }
  286. //
  287. // We query with two additional, but hidden, columns: path and rank,
  288. // because this information is needed by the browser (via Clipboard).
  289. // Care is taken in CRows::DisplayHeader and CRows::DisplayRows so that
  290. // the hidden columns are not displayed to the user
  291. //
  292. BOOL fNeedPath = TRUE;
  293. BOOL fNeedRank = fAddRankForBrowse;
  294. //
  295. // Next add all the columns in the state.
  296. //
  297. unsigned int cCol = states.NumberOfColumns();
  298. for ( unsigned int i = 0; i < cCol; i++ )
  299. {
  300. CDbColId * pprop = 0;
  301. DBID *pdbid = 0;
  302. if( FAILED(plist->GetPropInfoFromName( states.GetColumn( i ),
  303. &pdbid,
  304. 0,
  305. 0 )) )
  306. THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_OUTPUT ) );
  307. pprop = (CDbColId *)pdbid;
  308. if ( *pprop == psPath )
  309. {
  310. fNeedPath = FALSE;
  311. }
  312. else if ( *pprop == psRank )
  313. {
  314. fNeedRank = FALSE;
  315. }
  316. if ( !pProject->AddProjectColumn( *pprop ) )
  317. {
  318. THROW( CException( STATUS_NO_MEMORY ) );
  319. }
  320. }
  321. if ( fNeedPath && !pProject->AddProjectColumn( psPath ) )
  322. {
  323. THROW( CException( STATUS_NO_MEMORY ) );
  324. }
  325. if ( fNeedRank && !pProject->AddProjectColumn( psRank ) )
  326. {
  327. THROW( CException( STATUS_NO_MEMORY ) );
  328. }
  329. if (fAddBmkCol && !pProject->AddProjectColumn( psBookmark ) )
  330. {
  331. THROW( CException( STATUS_NO_MEMORY ) );
  332. }
  333. xQuery.Set( xProject.Acquire() );
  334. }
  335. CDbTopNode *pTop = 0;
  336. if ( states.IsMaxResultsSpecified() )
  337. {
  338. //
  339. // Use the top node to set a cap on the number of query results
  340. //
  341. pTop = new CDbTopNode();
  342. if ( pTop == 0 )
  343. THROW( CException( STATUS_NO_MEMORY ) );
  344. pTop->SetChild( xQuery.Acquire() );
  345. pTop->SetValue( states.GetMaxResults() );
  346. }
  347. //
  348. // Set FirstRows here
  349. //
  350. if ( states.IsFirstRowsSpecified() )
  351. {
  352. CDbFirstRowsNode *pFR = new CDbFirstRowsNode();
  353. if ( pFR == 0 )
  354. THROW( CException( STATUS_NO_MEMORY ) );
  355. CDbCmdTreeNode *pChild = pTop ? pTop : xQuery.Acquire();
  356. pFR->SetChild( pChild );
  357. pFR->SetValue( states.GetFirstRows() );
  358. return pFR;
  359. }
  360. if ( 0 != pTop )
  361. return pTop;
  362. return xQuery.Acquire();
  363. }
  364. //+---------------------------------------------------------------------------
  365. //
  366. // Function: SetScopePropertiesNoThrow
  367. //
  368. // Synopsis: Sets rowset properties pertaining to scope on command object.
  369. //
  370. // Arguments: [pCmd] -- Command object
  371. // [cDirs] -- Number of elements in following arrays
  372. // [apDirs] -- Array of scopes
  373. // [aulFlags] -- Array of flags (depths)
  374. // [apCats] -- Array of catalogs
  375. // [apMachines] -- Array of machines
  376. //
  377. // Notes: Either apDirs and aulFlags, or apCats and apMachines may be
  378. // NULL.
  379. //
  380. // History: 03-Mar-1997 KyleP Created
  381. // 14-May-1997 mohamedn use real BSTRs
  382. // 19-May-1997 KrishnaN Not throwing exceptions.
  383. //
  384. //----------------------------------------------------------------------------
  385. SCODE SetScopePropertiesNoThrow( ICommand * pCmd,
  386. unsigned cDirs,
  387. WCHAR const * const * apDirs,
  388. ULONG const * aulFlags,
  389. WCHAR const * const * apCats,
  390. WCHAR const * const * apMachines )
  391. {
  392. SCODE sc = S_OK;
  393. TRY
  394. {
  395. XInterface<ICommandProperties> xCmdProp;
  396. sc = pCmd->QueryInterface( IID_ICommandProperties, xCmdProp.GetQIPointer() );
  397. if ( FAILED( sc ) )
  398. return sc;
  399. //
  400. // It's expensive to convert all of these to BSTRs, but we have
  401. // to since our public API just takes regular strings.
  402. //
  403. CDynArrayInPlace<XBStr> aMachines(cDirs);
  404. CDynArrayInPlace<XBStr> aCatalogs(cDirs);
  405. CDynArrayInPlace<XBStr> aScopes(cDirs);
  406. unsigned i;
  407. //
  408. // init array of BSTRs of machines
  409. //
  410. if ( 0 != apMachines)
  411. {
  412. for ( i = 0; i < cDirs; i++ )
  413. {
  414. XBStr xBstr;
  415. xBstr.SetText( (WCHAR *)apMachines[i]);
  416. aMachines.Add(xBstr,i);
  417. xBstr.Acquire();
  418. }
  419. }
  420. //
  421. // init array of BSTRs of catalogs
  422. //
  423. if ( 0 != apCats)
  424. {
  425. for ( i = 0; i < cDirs; i++ )
  426. {
  427. XBStr xBstr;
  428. xBstr.SetText( (WCHAR *)apCats[i]);
  429. aCatalogs.Add(xBstr,i);
  430. xBstr.Acquire();
  431. }
  432. }
  433. //
  434. // init array of BSTRs of scopes
  435. //
  436. if ( 0 != apDirs)
  437. {
  438. for ( i = 0; i < cDirs; i++ )
  439. {
  440. XBStr xBstr;
  441. xBstr.SetText( (WCHAR *)apDirs[i]);
  442. aScopes.Add(xBstr,i);
  443. xBstr.Acquire();
  444. }
  445. }
  446. SAFEARRAY saScope = { 1, // Dimension
  447. FADF_AUTO | FADF_BSTR, // Flags: on stack, contains BSTRs
  448. sizeof(BSTR), // Size of an element
  449. 1, // Lock count. 1 for safety.
  450. (void *) aScopes.GetPointer(),// The data
  451. { cDirs, 0 } }; // Bounds (element count, low bound)
  452. SAFEARRAY saDepth = { 1, // Dimension
  453. FADF_AUTO, // Flags: on stack
  454. sizeof(LONG), // Size of an element
  455. 1, // Lock count. 1 for safety.
  456. (void *)aulFlags, // The data
  457. { cDirs, 0 } }; // Bounds (element count, low bound)
  458. SAFEARRAY saCatalog = { 1, // Dimension
  459. FADF_AUTO | FADF_BSTR, // Flags: on stack, contains BSTRs
  460. sizeof(BSTR), // Size of an element
  461. 1, // Lock count. 1 for safety.
  462. (void *) aCatalogs.GetPointer(), // The data
  463. { cDirs, 0 } }; // Bounds (element count, low bound)
  464. SAFEARRAY saMachine = { 1, // Dimension
  465. FADF_AUTO | FADF_BSTR, // Flags: on stack, contains BSTRs
  466. sizeof(BSTR), // Size of an element
  467. 1, // Lock count. 1 for safety.
  468. (void *) aMachines.GetPointer(), // The data
  469. { cDirs, 0 } }; // Bounds (element count, low bound)
  470. DBPROP aScopeProps[2] = {
  471. { DBPROP_CI_INCLUDE_SCOPES , 0, DBPROPSTATUS_OK, {0, DBKIND_GUID_PROPID, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (ULONG_PTR)&saScope } },
  472. { DBPROP_CI_DEPTHS , 0, DBPROPSTATUS_OK, {0, DBKIND_GUID_PROPID, 0}, { VT_I4 | VT_ARRAY, 0, 0, 0, (ULONG_PTR)&saDepth } } };
  473. DBPROP aCatalogProps[1] = {
  474. { DBPROP_CI_CATALOG_NAME , 0, DBPROPSTATUS_OK, {0, DBKIND_GUID_PROPID, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (ULONG_PTR)&saCatalog } } };
  475. DBPROP aMachineProps[1] = {
  476. { DBPROP_MACHINE , 0, DBPROPSTATUS_OK, {0, DBKIND_GUID_PROPID, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (ULONG_PTR)&saMachine } } };
  477. DBPROPSET aAllPropsets[3] = {
  478. { aScopeProps, 2, DBPROPSET_FSCIFRMWRK_EXT } ,
  479. { aCatalogProps, 1, DBPROPSET_FSCIFRMWRK_EXT } ,
  480. { aMachineProps, 1, DBPROPSET_CIFRMWRKCORE_EXT } };
  481. DBPROPSET * pPropsets = 0;
  482. ULONG cPropsets = 0;
  483. if ( 0 != apDirs )
  484. {
  485. pPropsets = &aAllPropsets[0];
  486. cPropsets = 1;
  487. }
  488. else
  489. {
  490. pPropsets = &aAllPropsets[1];
  491. }
  492. if ( 0 != apCats && 0 != apMachines )
  493. {
  494. cPropsets += 2;
  495. }
  496. sc = xCmdProp->SetProperties( cPropsets, pPropsets );
  497. }
  498. CATCH(CException, e)
  499. {
  500. sc = GetOleError(e);
  501. }
  502. END_CATCH
  503. return sc;
  504. }
  505. //+---------------------------------------------------------------------------
  506. //
  507. // Function: SetScopeProperties
  508. //
  509. // Synopsis: Sets rowset properties pertaining to scope on command object.
  510. //
  511. // Arguments: [pCmd] -- Command object
  512. // [cDirs] -- Number of elements in following arrays
  513. // [apDirs] -- Array of scopes
  514. // [aulFlags] -- Array of flags (depths)
  515. // [apCats] -- Array of catalogs
  516. // [apMachines] -- Array of machines
  517. //
  518. // History: 03-Mar-1997 KyleP Created
  519. //
  520. //----------------------------------------------------------------------------
  521. void SetScopeProperties( ICommand * pCmd,
  522. unsigned cDirs,
  523. WCHAR const * const * apDirs,
  524. ULONG const * aulFlags,
  525. WCHAR const * const * apCats,
  526. WCHAR const * const * apMachines )
  527. {
  528. SCODE sc = SetScopePropertiesNoThrow(pCmd, cDirs, apDirs,
  529. aulFlags, apCats, apMachines);
  530. if (FAILED(sc))
  531. THROW( CException(sc) );
  532. }