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.

586 lines
19 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000.
  5. //
  6. // File: strrest.cxx
  7. //
  8. // Contents: Builds a restriction object from a string
  9. //
  10. // History: 96/Jan/3 DwightKr Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <parser.hxx>
  16. #include <pvarset.hxx>
  17. #include <strsort.hxx>
  18. #include <cierror.h>
  19. extern CDbContentRestriction * TreeFromText(
  20. WCHAR const * wcsRestriction,
  21. IColumnMapper & ColumnMapper,
  22. LCID lcid );
  23. //+---------------------------------------------------------------------------
  24. //
  25. // Function: GetStringDbRestriction - public constructor
  26. //
  27. // Synopsis: Builds a CDbRestriction from the string passed
  28. //
  29. // Arguments: [wcsRestriction] - the string containing the restriction
  30. // [ulDialect] - triplish dialect
  31. // [pList] - property list describing the proptypes
  32. // [lcid] - the locale of the query
  33. //
  34. // History: 96/Jan/03 DwightKr Created.
  35. //
  36. //----------------------------------------------------------------------------
  37. CDbRestriction * GetStringDbRestriction(
  38. const WCHAR * wcsRestriction,
  39. ULONG ulDialect,
  40. IColumnMapper * pList,
  41. LCID lcid )
  42. {
  43. Win4Assert( 0 != wcsRestriction );
  44. Win4Assert( ISQLANG_V1 == ulDialect || ISQLANG_V2 == ulDialect );
  45. XPtr<CDbRestriction> xRest;
  46. if ( ISQLANG_V1 == ulDialect )
  47. {
  48. CQueryScanner scanner( wcsRestriction, TRUE, lcid );
  49. CQueryParser query( scanner,
  50. VECTOR_RANK_JACCARD,
  51. lcid,
  52. L"contents",
  53. CONTENTS,
  54. pList );
  55. xRest.Set( query.ParseQueryPhrase() );
  56. }
  57. else
  58. {
  59. xRest.Set( TreeFromText( wcsRestriction, *pList, lcid ) );
  60. }
  61. return xRest.Acquire();
  62. } //GetStringDbRestriction
  63. //+---------------------------------------------------------------------------
  64. //
  65. // Function: FormDbQueryTree
  66. //
  67. // Synopsis: Builds a CDbCmdTreeNode from the restriction, sort
  68. // specification, grouping specification and output columns.
  69. //
  70. // Arguments: [xDbRestriction] - the restriction
  71. // [xDbSortNode] - the sort specification (optional)
  72. // [xDbProjectList] - the output columns
  73. // [xDbGroupNode] - the grouping specification (optional)
  74. // [ulMaxRecords] - max records to return
  75. // [ulFirstRows] - only sort and display the first ulFirstRows
  76. // rows
  77. //
  78. // History: 1996/Jan/03 DwightKr Created.
  79. // 2000/Jul/01 KitmanH Added ulFirstRows
  80. //
  81. //----------------------------------------------------------------------------
  82. CDbCmdTreeNode * FormDbQueryTree( XPtr<CDbCmdTreeNode> & xDbCmdTreeNode,
  83. XPtr<CDbSortNode> & xDbSortNode,
  84. XPtr<CDbProjectListAnchor> & xDbProjectList,
  85. XPtr<CDbNestingNode> & xDbGroupNode,
  86. ULONG ulMaxRecords,
  87. ULONG ulFirstRows )
  88. {
  89. XPtr<CDbCmdTreeNode> xDbCmdTree = 0;
  90. //
  91. // First create a selection node and append the restriction tree to it
  92. //
  93. CDbSelectNode * pSelect = new CDbSelectNode();
  94. if ( 0 == pSelect )
  95. {
  96. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  97. }
  98. xDbCmdTree.Set( pSelect );
  99. if ( !pSelect->IsValid() )
  100. {
  101. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  102. }
  103. //
  104. // Now make the restriction a child of the selection node.
  105. //
  106. pSelect->AddRestriction( xDbCmdTreeNode.GetPointer() );
  107. xDbCmdTreeNode.Acquire();
  108. //
  109. // If there is a nesting node, add the project list and the selection
  110. // node below the lowest nesting node. Otherwise, create a projection
  111. // node and make the selection a child of the projection node.
  112. //
  113. if ( 0 != xDbGroupNode.GetPointer() )
  114. {
  115. CDbNestingNode * pBottomNestingNode = xDbGroupNode.GetPointer();
  116. CDbCmdTreeNode * pTree = pBottomNestingNode;
  117. while (pTree->GetFirstChild() != 0 &&
  118. (pTree->GetFirstChild()->GetCommandType() == DBOP_nesting ||
  119. pTree->GetFirstChild()->GetCommandType() == DBOP_sort))
  120. {
  121. pTree = pTree->GetFirstChild();
  122. if (pTree->GetCommandType() == DBOP_nesting)
  123. pBottomNestingNode = (CDbNestingNode *)pTree;
  124. }
  125. // Add the input projection list to the nesting node
  126. if (! pBottomNestingNode->SetChildList( *xDbProjectList.GetPointer() ))
  127. THROW( CException(E_INVALIDARG) );
  128. //
  129. // Make the selection a child of the lowest node.
  130. //
  131. if (pBottomNestingNode == pTree)
  132. {
  133. pBottomNestingNode->AddTable( xDbCmdTree.GetPointer() );
  134. xDbCmdTree.Acquire();
  135. }
  136. else
  137. {
  138. Win4Assert( pTree->IsSortNode() );
  139. ((CDbSortNode *)pTree)->AddTable( xDbCmdTree.GetPointer() );
  140. xDbCmdTree.Acquire();
  141. }
  142. xDbCmdTree.Set( xDbGroupNode.Acquire() );
  143. }
  144. else
  145. {
  146. //
  147. // Create the projection nodes
  148. //
  149. CDbProjectNode * pProject = new CDbProjectNode();
  150. if ( 0 == pProject )
  151. {
  152. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  153. }
  154. //
  155. // Make the selection a child of the projection node.
  156. //
  157. pProject->AddTable( xDbCmdTree.GetPointer() );
  158. xDbCmdTree.Acquire();
  159. xDbCmdTree.Set( pProject );
  160. //
  161. // Next add the column list to the project node
  162. //
  163. pProject->AddList( xDbProjectList.GetPointer() );
  164. xDbProjectList.Acquire();
  165. //
  166. // Next make the project node a child of the sort node
  167. //
  168. if ( !xDbSortNode.IsNull() && 0 != xDbSortNode->GetFirstChild() )
  169. {
  170. xDbSortNode->AddTable( xDbCmdTree.GetPointer() );
  171. xDbCmdTree.Acquire();
  172. xDbCmdTree.Set( xDbSortNode.Acquire() );
  173. }
  174. }
  175. CDbTopNode *pTop = 0;
  176. //
  177. // If the user specified a max # of records to examine, then setup
  178. // a node to reflect this.
  179. //
  180. if ( ulMaxRecords > 0 )
  181. {
  182. pTop = new CDbTopNode();
  183. if ( pTop == 0 )
  184. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  185. pTop->SetChild( xDbCmdTree.Acquire() );
  186. pTop->SetValue(ulMaxRecords );
  187. }
  188. //
  189. // Set FirstRows here
  190. //
  191. if ( ulFirstRows > 0 )
  192. {
  193. CDbFirstRowsNode *pFR = new CDbFirstRowsNode();
  194. if ( pFR == 0 )
  195. THROW( CException( STATUS_NO_MEMORY ) );
  196. CDbCmdTreeNode *pChild = pTop ? pTop : xDbCmdTree.Acquire();
  197. pFR->SetChild( pChild );
  198. pFR->SetValue( ulFirstRows );
  199. return pFR;
  200. }
  201. if ( 0 != pTop )
  202. return pTop;
  203. return xDbCmdTree.Acquire();
  204. }
  205. //+---------------------------------------------------------------------------
  206. //
  207. // Function: ParseStringColumns
  208. //
  209. // Synopsis: Parses the textual columns separated by commas into CDbColumns.
  210. // Also, adds the columns to a set of named variables if the
  211. // optional parameter pVariableSet is passed.
  212. //
  213. // Arguments: [wcsColumns] -- List of columns, separated by commas
  214. // [pList] -- Column mapper.
  215. // [lcid] -- locale
  216. // [pVarSet] -- [optional] Variable Set.
  217. // [pawcsColumns] -- [optional] Parsed columns
  218. //
  219. // History: 3-03-97 srikants Created
  220. // 7-23-97 KyleP Return parsed columns
  221. //
  222. //----------------------------------------------------------------------------
  223. CDbColumns * ParseStringColumns( WCHAR const * wcsColumns,
  224. IColumnMapper * pList,
  225. LCID lcid,
  226. PVariableSet * pVarSet,
  227. CDynArray<WCHAR> * pawcsColumns )
  228. {
  229. CDbColumns * pDbCols = new CDbColumns(0);
  230. if ( 0 == pDbCols )
  231. {
  232. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  233. }
  234. XPtr<CDbColumns> xDbCols( pDbCols );
  235. CQueryScanner scan( wcsColumns, FALSE, lcid );
  236. for ( XPtrST<WCHAR> wcsColumn( scan.AcqColumn() );
  237. wcsColumn.GetPointer() != 0;
  238. wcsColumn.Set( scan.AcqColumn() )
  239. )
  240. {
  241. CDbColId *pDbColId = 0;
  242. DBID *pdbid = 0;
  243. _wcsupr( wcsColumn.GetPointer() );
  244. if ( FAILED(pList->GetPropInfoFromName( wcsColumn.GetPointer(), &pdbid, 0, 0 )) )
  245. {
  246. //
  247. // This column was not defined. Report an error.
  248. //
  249. qutilDebugOut(( DEB_IERROR, "Column name %ws not found\n", wcsColumn.GetPointer() ));
  250. THROW( CException( QUERY_E_INVALID_OUTPUT_COLUMN ) );
  251. }
  252. pDbColId = (CDbColId *)pdbid;
  253. unsigned colNum = pDbCols->Count();
  254. for (unsigned i=0; i<colNum; i++)
  255. {
  256. if (pDbCols->Get(i) == *pDbColId)
  257. break;
  258. }
  259. if (i != colNum)
  260. {
  261. //
  262. // This column is a duplicate of another, possibly an alias.
  263. //
  264. qutilDebugOut(( DEB_IERROR, "Column name %ws is duplicated\n", wcsColumn.GetPointer() ));
  265. THROW( CException( QUERY_E_DUPLICATE_OUTPUT_COLUMN ) );
  266. }
  267. pDbCols->Add( *pDbColId, colNum );
  268. //
  269. // Add the output column to the list of replaceable parameters if needed.
  270. //
  271. if ( pVarSet )
  272. {
  273. Win4Assert( 0 != pawcsColumns );
  274. pVarSet->SetVariable( wcsColumn.GetPointer(), 0, 0);
  275. pawcsColumns->Add( wcsColumn.GetPointer(), colNum );
  276. wcsColumn.Acquire();
  277. }
  278. wcsColumn.Free();
  279. scan.AcceptColumn(); // Remove the column name
  280. //
  281. // Skip over commas seperating output columns
  282. //
  283. if ( scan.LookAhead() == COMMA_TOKEN )
  284. {
  285. scan.Accept(); // Remove the ','
  286. }
  287. else if ( scan.LookAhead() != EOS_TOKEN )
  288. {
  289. THROW( CException( QPARSE_E_EXPECTING_COMMA ) );
  290. }
  291. }
  292. qutilDebugOut(( DEB_ITRACE, "%d columns added to CDbColumns\n", pDbCols->Count() ));
  293. //
  294. // We must have exhausted the CiColumns line. If not, there was a syntax
  295. // error we couldn't parse.
  296. //
  297. if ( scan.LookAhead() != EOS_TOKEN )
  298. {
  299. //
  300. // Contains a syntax error. Report an error.
  301. //
  302. qutilDebugOut(( DEB_IWARN, "Syntax error in CiColumns= line\n" ));
  303. THROW( CException( QUERY_E_INVALID_OUTPUT_COLUMN ) );
  304. }
  305. return xDbCols.Acquire();
  306. }
  307. //+---------------------------------------------------------------------------
  308. //
  309. // Function: ParseColumnsWithFriendlyNames
  310. //
  311. // Synopsis: Parses the columns string and leaves the friendly names
  312. // in the project list.
  313. //
  314. // Arguments: [wcsColumns] - Columns names
  315. // [pList] - Property List
  316. // [pVarSet] - (not used) Variable Set - Optional
  317. //
  318. // Returns: The project list anchor of the tree.
  319. //
  320. // History: 3-18-97 srikants Created
  321. //
  322. //----------------------------------------------------------------------------
  323. CDbProjectListAnchor * ParseColumnsWithFriendlyNames(
  324. WCHAR const * wcsColumns,
  325. IColumnMapper * pList,
  326. PVariableSet * pVarSet )
  327. {
  328. CDbColumns * pDbCols = new CDbColumns( 0 );
  329. XPtr<CDbColumns> xDbCols( pDbCols );
  330. XPtr<CDbProjectListAnchor> xDbColList( new CDbProjectListAnchor() );
  331. if ( 0 == xDbCols.GetPointer() ||
  332. 0 == xDbColList.GetPointer() )
  333. {
  334. THROW( CException(E_OUTOFMEMORY) );
  335. }
  336. CQueryScanner scan( wcsColumns, FALSE );
  337. for ( XPtrST<WCHAR> wcsColumn( scan.AcqColumn() );
  338. wcsColumn.GetPointer() != 0;
  339. wcsColumn.Set( scan.AcqColumn() )
  340. )
  341. {
  342. CDbColId *pDbColId = 0;
  343. DBID *pdbid = 0;
  344. _wcsupr( wcsColumn.GetPointer() );
  345. if ( FAILED(pList->GetPropInfoFromName( wcsColumn.GetPointer(), &pdbid, 0, 0 )) )
  346. {
  347. //
  348. // This column was not defined. Report an error.
  349. //
  350. qutilDebugOut(( DEB_IERROR, "Column name %ws not found\n",
  351. wcsColumn.GetPointer() ));
  352. THROW( CException(QUERY_E_INVALID_OUTPUT_COLUMN) );
  353. }
  354. pDbColId = (CDbColId *)pdbid;
  355. unsigned colNum = pDbCols->Count();
  356. for (unsigned i=0; i<colNum; i++)
  357. {
  358. if (pDbCols->Get(i) == *pDbColId)
  359. break;
  360. }
  361. if (i != colNum)
  362. {
  363. //
  364. // This column is a duplicate of another, possibly an alias.
  365. //
  366. qutilDebugOut(( DEB_IERROR, "Column name %ws is duplicated\n",
  367. wcsColumn.GetPointer() ));
  368. THROW( CException(QUERY_E_DUPLICATE_OUTPUT_COLUMN) );
  369. }
  370. pDbCols->Add( *pDbColId, colNum );
  371. if (! xDbColList->AppendListElement( *pDbColId,
  372. wcsColumn.GetPointer() ))
  373. THROW( CException(E_OUTOFMEMORY) );
  374. delete wcsColumn.Acquire();
  375. scan.AcceptColumn(); // Remove the column name
  376. //
  377. // Skip over commas seperating output columns
  378. //
  379. if ( scan.LookAhead() == COMMA_TOKEN )
  380. {
  381. scan.Accept(); // Remove the ','
  382. }
  383. else if ( scan.LookAhead() != EOS_TOKEN )
  384. {
  385. THROW( CException(QPARSE_E_EXPECTING_COMMA ) );
  386. }
  387. }
  388. qutilDebugOut(( DEB_TRACE, "%d columns added to project list\n", pDbCols->Count() ));
  389. //
  390. // We must have exhausted the CiColumns line. If not, there was a syntax
  391. // error we couldn't parse.
  392. //
  393. if ( scan.LookAhead() != EOS_TOKEN )
  394. {
  395. //
  396. // Contains a syntax error. Report an error.
  397. //
  398. qutilDebugOut(( DEB_IERROR, "Syntax error in CiColumns= line\n" ));
  399. THROW( CException(QUERY_E_INVALID_OUTPUT_COLUMN) );
  400. }
  401. return xDbColList.Acquire();
  402. }
  403. //+---------------------------------------------------------------------------
  404. //
  405. // Member: CTextToTree::FormFullTree
  406. //
  407. // Synopsis: Creates a full tree from the parameters given to the
  408. // construtor.
  409. //
  410. // History: 3-04-97 srikants Created
  411. //
  412. //----------------------------------------------------------------------------
  413. DBCOMMANDTREE * CTextToTree::FormFullTree()
  414. {
  415. XPtr<CDbProjectListAnchor> xDbProjectList;
  416. if ( _fKeepFriendlyNames )
  417. {
  418. //
  419. // Get the Project List Anchor for the string columns retaining the
  420. // friendly names.
  421. //
  422. xDbProjectList.Set(
  423. ParseColumnsWithFriendlyNames( _wcsColumns,
  424. _xPropList.GetPointer(),
  425. _pVariableSet ) );
  426. }
  427. else
  428. {
  429. //
  430. // Convert the textual form of the columns into DBColumns.
  431. //
  432. XPtr<CDbColumns> xDbColumns;
  433. CDbColumns * pDbColumns = _pDbColumns;
  434. if ( 0 == pDbColumns )
  435. {
  436. xDbColumns.Set( ParseStringColumns( _wcsColumns,
  437. _xPropList.GetPointer(),
  438. _locale,
  439. _pVariableSet ) );
  440. pDbColumns = xDbColumns.GetPointer();
  441. }
  442. //
  443. // Build the projection list from the column list.
  444. //
  445. xDbProjectList.Set( new CDbProjectListAnchor );
  446. if ( 0 == xDbProjectList.GetPointer() )
  447. {
  448. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  449. }
  450. for (unsigned i=0; i < pDbColumns->Count(); i++)
  451. {
  452. if (! xDbProjectList->AppendListElement( pDbColumns->Get(i) ))
  453. {
  454. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  455. }
  456. }
  457. }
  458. //
  459. // Convert the textual form of the sort columns into CDbSortNode.
  460. //
  461. XPtr<CDbSortNode> xDbSortNode;
  462. if ( 0 != _wcsSort )
  463. xDbSortNode.Set( GetStringDbSortNode( _wcsSort, _xPropList.GetPointer(), _locale ) );
  464. XPtr<CDbNestingNode> xDbNestingNode;
  465. if ( 0 != _wcsGroup )
  466. {
  467. CQueryScanner scanner( _wcsGroup, FALSE, _locale, TRUE );
  468. CParseGrouping ParseGrouping( scanner, _xPropList.GetPointer(), _fKeepFriendlyNames );
  469. ParseGrouping.Parse();
  470. if ( 0 != _wcsSort )
  471. ParseGrouping.AddSortList( xDbSortNode );
  472. xDbNestingNode.Set( ParseGrouping.AcquireNode() );
  473. }
  474. qutilDebugOut(( DEB_TRACE, "ExecuteQuery:\n" ));
  475. qutilDebugOut(( DEB_TRACE, "\tCiRestriction = '%ws'\n", _wcsRestriction ));
  476. XPtr<CDbCmdTreeNode> xDbCmdTreeNode;
  477. // Use a restriction if one was already passed in
  478. if (0 != _pDbCmdTree)
  479. {
  480. Win4Assert(0 == _wcsRestriction);
  481. xDbCmdTreeNode.Set((CDbCmdTreeNode *)CDbCmdTreeNode::CastFromStruct(_pDbCmdTree));
  482. }
  483. else
  484. {
  485. Win4Assert(_wcsRestriction);
  486. xDbCmdTreeNode.Set( GetStringDbRestriction( _wcsRestriction,
  487. _ulDialect,
  488. _xPropList.GetPointer(),
  489. _locale ) );
  490. }
  491. //
  492. // Now form the query tree from the restriction, sort set, and
  493. // projection list.
  494. //
  495. CDbCmdTreeNode *pDbCmdTree = FormDbQueryTree( xDbCmdTreeNode,
  496. xDbSortNode,
  497. xDbProjectList,
  498. xDbNestingNode,
  499. _maxRecs,
  500. _cFirstRows );
  501. return pDbCmdTree->CastToStruct();
  502. } //FormFullTree