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.

420 lines
13 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997 - 2000.
  5. //
  6. // File: strgroup.cxx
  7. //
  8. // Contents: Builds a nesting node object from a GroupBy string
  9. //
  10. // History: 10 Apr 1997 AlanW Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <strsort.hxx>
  16. static GUID guidBmk = DBBMKGUID;
  17. static CDbColId psBookmark( guidBmk, PROPID_DBBMK_BOOKMARK );
  18. //+---------------------------------------------------------------------------
  19. //
  20. // Function: GetStringDbGroupNode - public
  21. //
  22. // Synopsis: Builds a CDbNestingNode from the string passed
  23. //
  24. // Arguments: [pwszGroup] - the string containing the grouping specification
  25. // [pList] - the property list describing the column names
  26. //
  27. // Notes: CPListException is used instead of CParserException so the
  28. // error class will be IDQError, not RESError in idq.dll.
  29. //
  30. // History: 10 Apr 1997 AlanW Created.
  31. //
  32. //----------------------------------------------------------------------------
  33. CDbNestingNode * GetStringDbGroupNode( const WCHAR * pwszGroup,
  34. IColumnMapper * pList )
  35. {
  36. Win4Assert( 0 != pwszGroup );
  37. CQueryScanner scanner( pwszGroup, FALSE, GetUserDefaultLCID(), TRUE );
  38. CParseGrouping ParseObj( scanner, pList, FALSE );
  39. ParseObj.Parse();
  40. return ParseObj.AcquireNode();
  41. }
  42. //+---------------------------------------------------------------------------
  43. //
  44. // Method: CParseGrouping::Parse, public
  45. //
  46. // Synopsis: Parse a GroupBy string, construct the nesting node
  47. //
  48. // Arguments: -NONE- uses previously set member variables
  49. //
  50. // Notes: CPListException is used instead of CParserException so the
  51. // error class will be IDQError, not RESError in idq.dll.
  52. //
  53. // History: 10 Apr 1997 AlanW Created.
  54. //
  55. //----------------------------------------------------------------------------
  56. void CParseGrouping::Parse( )
  57. {
  58. while (_Scanner.LookAhead() != EOS_TOKEN)
  59. {
  60. XPtr<CDbNestingNode> xNode( ParseGrouping() );
  61. if (_Scanner.LookAhead() == COMMA_TOKEN)
  62. {
  63. _Scanner.Accept();
  64. }
  65. else if (_Scanner.LookAhead() != EOS_TOKEN)
  66. {
  67. THROW( CPListException(QPARSE_E_EXPECTING_COMMA, 0) );
  68. }
  69. if (0 == _cNestings)
  70. {
  71. Win4Assert( _xNode.GetPointer() == 0 );
  72. _xNode.Set( xNode.Acquire() );
  73. }
  74. else
  75. {
  76. CDbNestingNode * pNode = _xNode.GetPointer();
  77. for (unsigned i=1; i < _cNestings; i++)
  78. {
  79. Win4Assert( pNode->GetCommandType() == DBOP_nesting );
  80. pNode = (CDbNestingNode *)pNode->GetFirstChild();
  81. }
  82. Win4Assert( pNode != 0 && pNode->GetFirstChild()->GetCommandType() == DBOP_project_list_anchor );
  83. pNode->AddTable( xNode.Acquire() );
  84. }
  85. _cNestings++;
  86. }
  87. if (_fNeedSortNode)
  88. AddSortList( _xSortNode );
  89. }
  90. //+---------------------------------------------------------------------------
  91. //
  92. // Method: CParseGrouping::ParseGrouping, private
  93. //
  94. // Synopsis: Parse an individual grouping specification
  95. //
  96. // Arguments: -NONE- uses previously set member variables
  97. //
  98. // Notes: The scanner is advanced past the parsed grouping spec.
  99. //
  100. // History: 10 Apr 1997 AlanW Created.
  101. //
  102. //----------------------------------------------------------------------------
  103. CDbNestingNode * CParseGrouping::ParseGrouping( )
  104. {
  105. CDbNestingNode * pDbNestingNode = new CDbNestingNode();
  106. if ( 0 == pDbNestingNode )
  107. {
  108. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  109. }
  110. XPtr<CDbNestingNode> xDbNestingNode(pDbNestingNode);
  111. //
  112. // Parse any leading grouping type specification.
  113. //
  114. ULONG ulCatType = eUnique; // Assume unique value categories
  115. if ( _Scanner.LookAhead() == W_OPEN_TOKEN )
  116. ulCatType = ParseGroupingType();
  117. // NOTE: only the unique categorization is implemented.
  118. if (ulCatType != eUnique)
  119. THROW( CPListException(QPARSE_E_INVALID_GROUPING, 0) );
  120. if ( 0 == _xSortNode.GetPointer() )
  121. {
  122. CDbSortNode * pDbSortNode = new CDbSortNode();
  123. if ( 0 == pDbSortNode )
  124. {
  125. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  126. }
  127. _xSortNode.Set(pDbSortNode);
  128. }
  129. BOOL fFirstGroupingColumn = TRUE;
  130. for ( XPtrST<WCHAR> pwszColumnName( _Scanner.AcqColumn() );
  131. pwszColumnName.GetPointer() != 0;
  132. pwszColumnName.Set( _Scanner.AcqColumn() )
  133. )
  134. {
  135. _Scanner.AcceptColumn(); // Remove the column name
  136. //
  137. // Parse for the [a] or [d] parameters.
  138. //
  139. unsigned order = QUERY_SORTASCEND; // Assume ascending sort order
  140. if ( _Scanner.LookAhead() == W_OPEN_TOKEN )
  141. {
  142. _Scanner.Accept(); // Remove the '['
  143. WCHAR wchOrder = _Scanner.GetCommandChar();
  144. if ( wchOrder == L'a' )
  145. {
  146. order = QUERY_SORTASCEND;
  147. }
  148. else if ( wchOrder == L'd' )
  149. {
  150. order = QUERY_SORTDESCEND;
  151. _fNeedSortNode = TRUE;
  152. }
  153. else
  154. {
  155. // Report an error
  156. THROW( CPListException(QPARSE_E_INVALID_SORT_ORDER, 0) );
  157. }
  158. WCHAR wchNext = _Scanner.GetCommandChar();
  159. if (wchNext != 0 && !iswspace(wchNext))
  160. // some alphabetic character followed the '[a' or '[d'.
  161. THROW( CPListException(QPARSE_E_INVALID_SORT_ORDER, 0) );
  162. _Scanner.AcceptCommand(); // Remove the command character
  163. if ( _Scanner.LookAhead() != W_CLOSE_TOKEN )
  164. {
  165. // Report an error
  166. THROW( CPListException(QPARSE_E_EXPECTING_BRACE, 0) );
  167. }
  168. _Scanner.Accept(); // Remove the ']' character
  169. }
  170. //
  171. // Add the new grouping column to the nesting node
  172. //
  173. CDbColId *pDbColId = 0;
  174. DBID *pdbid = 0;
  175. if ( FAILED(_xPropList->GetPropInfoFromName( pwszColumnName.GetPointer(), &pdbid, 0, 0 )) )
  176. {
  177. //
  178. // Column name not found.
  179. //
  180. THROW( CPListException(QPARSE_E_NO_SUCH_SORT_PROPERTY, 0) );
  181. }
  182. pDbColId = (CDbColId *)pdbid;
  183. if ( fFirstGroupingColumn )
  184. {
  185. fFirstGroupingColumn = FALSE;
  186. if ( !pDbNestingNode->AddParentColumn(psBookmark) )
  187. {
  188. // Report a failure.
  189. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  190. }
  191. }
  192. if ( !pDbNestingNode->AddParentColumn(*pDbColId) )
  193. {
  194. // Report a failure.
  195. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  196. }
  197. BOOL fFail = _fKeepFriendlyNames ?
  198. !pDbNestingNode->AddGroupingColumn(*pDbColId, pwszColumnName.GetPointer()) :
  199. !pDbNestingNode->AddGroupingColumn(*pDbColId);
  200. if (fFail)
  201. {
  202. // Report a failure.
  203. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  204. }
  205. //
  206. // Add the column to the sort node in case we will need it.
  207. //
  208. CDbSortKey sortKey( *pDbColId, order == QUERY_SORTDESCEND );
  209. if ( !_xSortNode->AddSortColumn(sortKey) )
  210. {
  211. // Report a failure.
  212. THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
  213. }
  214. pwszColumnName.Free();
  215. //
  216. // Skip over +'s seperating grouping columns
  217. //
  218. if ( _Scanner.LookAhead() == PLUS_TOKEN )
  219. {
  220. // We don't support this syntax (or document it)
  221. //_Scanner.Accept(); // Remove the '+'
  222. THROW( CPListException(QPARSE_E_INVALID_GROUPING, 0) );
  223. }
  224. //
  225. // Find a new grouping specification if a comma is found
  226. if ( _Scanner.LookAhead() == COMMA_TOKEN )
  227. {
  228. break;
  229. }
  230. }
  231. return xDbNestingNode.Acquire();
  232. }
  233. //+---------------------------------------------------------------------------
  234. //
  235. // Method: CParseGrouping::ParseGroupingType, private
  236. //
  237. // Synopsis: Parses and returns the grouping type.
  238. //
  239. // Arguments: -NONE-
  240. //
  241. // Returns: ECategoryType - grouping type found if valid
  242. //
  243. // Notes: Upon return, the scanner is advanced past the grouping type.
  244. // Throws CPListException in case of syntax errors
  245. //
  246. // History: 10 Apr 1997 AlanW Created.
  247. //
  248. //----------------------------------------------------------------------------
  249. CParseGrouping::ECategoryType CParseGrouping::ParseGroupingType( )
  250. {
  251. Win4Assert( _Scanner.LookAhead() == W_OPEN_TOKEN );
  252. _Scanner.Accept(); // Remove the '['
  253. XPtrST<WCHAR> pwszCategoryName( _Scanner.AcqWord() );
  254. ECategoryType CatType = eInvalidCategory;
  255. if ( pwszCategoryName.IsNull() )
  256. THROW( CPListException(QPARSE_E_INVALID_GROUPING, 0) );
  257. if ( _wcsicmp( pwszCategoryName.GetPointer(), L"unique" ) == 0 )
  258. {
  259. CatType = eUnique;
  260. }
  261. else if ( _wcsicmp( pwszCategoryName.GetPointer(), L"quantile" ) == 0 )
  262. {
  263. CatType = eBuckets;
  264. }
  265. else if ( _wcsicmp( pwszCategoryName.GetPointer(), L"cluster" ) == 0 )
  266. {
  267. CatType = eCluster;
  268. }
  269. else if ( _wcsicmp( pwszCategoryName.GetPointer(), L"range" ) == 0 )
  270. {
  271. CatType = eRange;
  272. }
  273. else if ( _wcsicmp( pwszCategoryName.GetPointer(), L"time" ) == 0 )
  274. {
  275. CatType = eTime;
  276. }
  277. else if ( _wcsicmp( pwszCategoryName.GetPointer(), L"alpha" ) == 0 )
  278. {
  279. CatType = eAlpha;
  280. }
  281. else
  282. {
  283. // Report an error
  284. THROW( CPListException(QPARSE_E_INVALID_GROUPING, 0) );
  285. }
  286. _Scanner.AcceptWord(); // Remove the grouping type name
  287. if ( _Scanner.LookAhead() != W_CLOSE_TOKEN )
  288. {
  289. // Report an error
  290. THROW( CPListException(QPARSE_E_EXPECTING_BRACE, 0) );
  291. }
  292. _Scanner.Accept(); // Remove the ']' character
  293. return CatType;
  294. }
  295. //+---------------------------------------------------------------------------
  296. //
  297. // Method: CParseGrouping::AddSortList, private
  298. //
  299. // Synopsis: Add sort columns.
  300. //
  301. // Arguments: [SortNode] - a smart pointer to the sort node to be added
  302. //
  303. // Notes: A sort list is added below the lowermost nesting node.
  304. // If there already is a sort node there, the sort columns are
  305. // appended to the list.
  306. //
  307. // History: 21 Apr 1997 AlanW Created.
  308. //
  309. //----------------------------------------------------------------------------
  310. void CParseGrouping::AddSortList( XPtr<CDbSortNode> & SortNode )
  311. {
  312. Win4Assert( _cNestings > 0 );
  313. CDbNestingNode * pNode = _xNode.GetPointer();
  314. for (unsigned i=1; i < _cNestings; i++)
  315. {
  316. Win4Assert( pNode->GetCommandType() == DBOP_nesting );
  317. pNode = (CDbNestingNode *)pNode->GetFirstChild();
  318. }
  319. Win4Assert( pNode != 0 &&
  320. (pNode->GetFirstChild()->GetCommandType() == DBOP_project_list_anchor ||
  321. pNode->GetFirstChild()->GetCommandType() == DBOP_sort ));
  322. if (pNode->GetFirstChild()->GetCommandType() == DBOP_project_list_anchor)
  323. {
  324. // No sort node yet. Add a node.
  325. if (_xSortNode.GetPointer())
  326. {
  327. pNode->AddTable( _xSortNode.Acquire() );
  328. if ( 0 == SortNode.GetPointer() )
  329. {
  330. //
  331. // If called with _xSortNode, the Acquire above cleared the
  332. // smart pointer. We're done.
  333. //
  334. return;
  335. }
  336. }
  337. else
  338. {
  339. pNode->AddTable( SortNode.Acquire() );
  340. return;
  341. }
  342. }
  343. Win4Assert(pNode->GetFirstChild()->GetCommandType() == DBOP_sort);
  344. Win4Assert(pNode->GetFirstChild()->GetFirstChild()->GetCommandType() == DBOP_sort_list_anchor);
  345. Win4Assert(0 == _xSortNode.GetPointer());
  346. // The sort list elements from SortNode will be carved off and appended
  347. // to the list in pSLA.
  348. CDbSortListAnchor * pSLA = (CDbSortListAnchor *)pNode->GetFirstChild()->GetFirstChild();
  349. Win4Assert(SortNode.GetPointer() != 0);
  350. Win4Assert(SortNode->GetCommandType() == DBOP_sort);
  351. Win4Assert(SortNode->GetFirstChild()->GetCommandType() == DBOP_sort_list_anchor);
  352. XPtr<CDbSortListElement> xSLE ( (CDbSortListElement *) SortNode->GetFirstChild()->AcquireChildren() );
  353. if (xSLE.GetPointer())
  354. {
  355. pSLA->AppendList( xSLE.GetPointer() );
  356. xSLE.Acquire();
  357. }
  358. }