|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 2000.
//
// File: strgroup.cxx
//
// Contents: Builds a nesting node object from a GroupBy string
//
// History: 10 Apr 1997 AlanW Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <strsort.hxx>
static GUID guidBmk = DBBMKGUID; static CDbColId psBookmark( guidBmk, PROPID_DBBMK_BOOKMARK );
//+---------------------------------------------------------------------------
//
// Function: GetStringDbGroupNode - public
//
// Synopsis: Builds a CDbNestingNode from the string passed
//
// Arguments: [pwszGroup] - the string containing the grouping specification
// [pList] - the property list describing the column names
//
// Notes: CPListException is used instead of CParserException so the
// error class will be IDQError, not RESError in idq.dll.
//
// History: 10 Apr 1997 AlanW Created.
//
//----------------------------------------------------------------------------
CDbNestingNode * GetStringDbGroupNode( const WCHAR * pwszGroup, IColumnMapper * pList ) { Win4Assert( 0 != pwszGroup ); CQueryScanner scanner( pwszGroup, FALSE, GetUserDefaultLCID(), TRUE );
CParseGrouping ParseObj( scanner, pList, FALSE ); ParseObj.Parse();
return ParseObj.AcquireNode(); }
//+---------------------------------------------------------------------------
//
// Method: CParseGrouping::Parse, public
//
// Synopsis: Parse a GroupBy string, construct the nesting node
//
// Arguments: -NONE- uses previously set member variables
//
// Notes: CPListException is used instead of CParserException so the
// error class will be IDQError, not RESError in idq.dll.
//
// History: 10 Apr 1997 AlanW Created.
//
//----------------------------------------------------------------------------
void CParseGrouping::Parse( ) { while (_Scanner.LookAhead() != EOS_TOKEN) { XPtr<CDbNestingNode> xNode( ParseGrouping() ); if (_Scanner.LookAhead() == COMMA_TOKEN) { _Scanner.Accept(); } else if (_Scanner.LookAhead() != EOS_TOKEN) { THROW( CPListException(QPARSE_E_EXPECTING_COMMA, 0) ); }
if (0 == _cNestings) { Win4Assert( _xNode.GetPointer() == 0 ); _xNode.Set( xNode.Acquire() ); } else { CDbNestingNode * pNode = _xNode.GetPointer(); for (unsigned i=1; i < _cNestings; i++) { Win4Assert( pNode->GetCommandType() == DBOP_nesting ); pNode = (CDbNestingNode *)pNode->GetFirstChild(); } Win4Assert( pNode != 0 && pNode->GetFirstChild()->GetCommandType() == DBOP_project_list_anchor ); pNode->AddTable( xNode.Acquire() ); } _cNestings++; } if (_fNeedSortNode) AddSortList( _xSortNode ); }
//+---------------------------------------------------------------------------
//
// Method: CParseGrouping::ParseGrouping, private
//
// Synopsis: Parse an individual grouping specification
//
// Arguments: -NONE- uses previously set member variables
//
// Notes: The scanner is advanced past the parsed grouping spec.
//
// History: 10 Apr 1997 AlanW Created.
//
//----------------------------------------------------------------------------
CDbNestingNode * CParseGrouping::ParseGrouping( ) { CDbNestingNode * pDbNestingNode = new CDbNestingNode(); if ( 0 == pDbNestingNode ) { THROW( CException(STATUS_INSUFFICIENT_RESOURCES) ); }
XPtr<CDbNestingNode> xDbNestingNode(pDbNestingNode);
//
// Parse any leading grouping type specification.
//
ULONG ulCatType = eUnique; // Assume unique value categories
if ( _Scanner.LookAhead() == W_OPEN_TOKEN ) ulCatType = ParseGroupingType();
// NOTE: only the unique categorization is implemented.
if (ulCatType != eUnique) THROW( CPListException(QPARSE_E_INVALID_GROUPING, 0) );
if ( 0 == _xSortNode.GetPointer() ) { CDbSortNode * pDbSortNode = new CDbSortNode(); if ( 0 == pDbSortNode ) { THROW( CException(STATUS_INSUFFICIENT_RESOURCES) ); }
_xSortNode.Set(pDbSortNode); }
BOOL fFirstGroupingColumn = TRUE; for ( XPtrST<WCHAR> pwszColumnName( _Scanner.AcqColumn() ); pwszColumnName.GetPointer() != 0; pwszColumnName.Set( _Scanner.AcqColumn() ) ) { _Scanner.AcceptColumn(); // Remove the column name
//
// Parse for the [a] or [d] parameters.
//
unsigned order = QUERY_SORTASCEND; // Assume ascending sort order
if ( _Scanner.LookAhead() == W_OPEN_TOKEN ) { _Scanner.Accept(); // Remove the '['
WCHAR wchOrder = _Scanner.GetCommandChar();
if ( wchOrder == L'a' ) { order = QUERY_SORTASCEND; } else if ( wchOrder == L'd' ) { order = QUERY_SORTDESCEND; _fNeedSortNode = TRUE; } else { // Report an error
THROW( CPListException(QPARSE_E_INVALID_SORT_ORDER, 0) ); }
WCHAR wchNext = _Scanner.GetCommandChar(); if (wchNext != 0 && !iswspace(wchNext)) // some alphabetic character followed the '[a' or '[d'.
THROW( CPListException(QPARSE_E_INVALID_SORT_ORDER, 0) );
_Scanner.AcceptCommand(); // Remove the command character
if ( _Scanner.LookAhead() != W_CLOSE_TOKEN ) { // Report an error
THROW( CPListException(QPARSE_E_EXPECTING_BRACE, 0) ); }
_Scanner.Accept(); // Remove the ']' character
}
//
// Add the new grouping column to the nesting node
//
CDbColId *pDbColId = 0; DBID *pdbid = 0; if ( FAILED(_xPropList->GetPropInfoFromName( pwszColumnName.GetPointer(), &pdbid, 0, 0 )) ) { //
// Column name not found.
//
THROW( CPListException(QPARSE_E_NO_SUCH_SORT_PROPERTY, 0) ); } pDbColId = (CDbColId *)pdbid;
if ( fFirstGroupingColumn ) { fFirstGroupingColumn = FALSE; if ( !pDbNestingNode->AddParentColumn(psBookmark) ) { // Report a failure.
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) ); } }
if ( !pDbNestingNode->AddParentColumn(*pDbColId) ) { // Report a failure.
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) ); }
BOOL fFail = _fKeepFriendlyNames ? !pDbNestingNode->AddGroupingColumn(*pDbColId, pwszColumnName.GetPointer()) : !pDbNestingNode->AddGroupingColumn(*pDbColId);
if (fFail) { // Report a failure.
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) ); }
//
// Add the column to the sort node in case we will need it.
//
CDbSortKey sortKey( *pDbColId, order == QUERY_SORTDESCEND );
if ( !_xSortNode->AddSortColumn(sortKey) ) { // Report a failure.
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) ); }
pwszColumnName.Free();
//
// Skip over +'s seperating grouping columns
//
if ( _Scanner.LookAhead() == PLUS_TOKEN ) { // We don't support this syntax (or document it)
//_Scanner.Accept(); // Remove the '+'
THROW( CPListException(QPARSE_E_INVALID_GROUPING, 0) ); }
//
// Find a new grouping specification if a comma is found
if ( _Scanner.LookAhead() == COMMA_TOKEN ) { break; } }
return xDbNestingNode.Acquire(); }
//+---------------------------------------------------------------------------
//
// Method: CParseGrouping::ParseGroupingType, private
//
// Synopsis: Parses and returns the grouping type.
//
// Arguments: -NONE-
//
// Returns: ECategoryType - grouping type found if valid
//
// Notes: Upon return, the scanner is advanced past the grouping type.
// Throws CPListException in case of syntax errors
//
// History: 10 Apr 1997 AlanW Created.
//
//----------------------------------------------------------------------------
CParseGrouping::ECategoryType CParseGrouping::ParseGroupingType( ) { Win4Assert( _Scanner.LookAhead() == W_OPEN_TOKEN ); _Scanner.Accept(); // Remove the '['
XPtrST<WCHAR> pwszCategoryName( _Scanner.AcqWord() ); ECategoryType CatType = eInvalidCategory;
if ( pwszCategoryName.IsNull() ) THROW( CPListException(QPARSE_E_INVALID_GROUPING, 0) );
if ( _wcsicmp( pwszCategoryName.GetPointer(), L"unique" ) == 0 ) { CatType = eUnique; } else if ( _wcsicmp( pwszCategoryName.GetPointer(), L"quantile" ) == 0 ) { CatType = eBuckets; } else if ( _wcsicmp( pwszCategoryName.GetPointer(), L"cluster" ) == 0 ) { CatType = eCluster; } else if ( _wcsicmp( pwszCategoryName.GetPointer(), L"range" ) == 0 ) { CatType = eRange; } else if ( _wcsicmp( pwszCategoryName.GetPointer(), L"time" ) == 0 ) { CatType = eTime; } else if ( _wcsicmp( pwszCategoryName.GetPointer(), L"alpha" ) == 0 ) { CatType = eAlpha; } else { // Report an error
THROW( CPListException(QPARSE_E_INVALID_GROUPING, 0) ); } _Scanner.AcceptWord(); // Remove the grouping type name
if ( _Scanner.LookAhead() != W_CLOSE_TOKEN ) { // Report an error
THROW( CPListException(QPARSE_E_EXPECTING_BRACE, 0) ); } _Scanner.Accept(); // Remove the ']' character
return CatType; }
//+---------------------------------------------------------------------------
//
// Method: CParseGrouping::AddSortList, private
//
// Synopsis: Add sort columns.
//
// Arguments: [SortNode] - a smart pointer to the sort node to be added
//
// Notes: A sort list is added below the lowermost nesting node.
// If there already is a sort node there, the sort columns are
// appended to the list.
//
// History: 21 Apr 1997 AlanW Created.
//
//----------------------------------------------------------------------------
void CParseGrouping::AddSortList( XPtr<CDbSortNode> & SortNode ) { Win4Assert( _cNestings > 0 );
CDbNestingNode * pNode = _xNode.GetPointer(); for (unsigned i=1; i < _cNestings; i++) { Win4Assert( pNode->GetCommandType() == DBOP_nesting ); pNode = (CDbNestingNode *)pNode->GetFirstChild(); }
Win4Assert( pNode != 0 && (pNode->GetFirstChild()->GetCommandType() == DBOP_project_list_anchor || pNode->GetFirstChild()->GetCommandType() == DBOP_sort ));
if (pNode->GetFirstChild()->GetCommandType() == DBOP_project_list_anchor) { // No sort node yet. Add a node.
if (_xSortNode.GetPointer()) { pNode->AddTable( _xSortNode.Acquire() ); if ( 0 == SortNode.GetPointer() ) { //
// If called with _xSortNode, the Acquire above cleared the
// smart pointer. We're done.
//
return; } } else { pNode->AddTable( SortNode.Acquire() ); return; } }
Win4Assert(pNode->GetFirstChild()->GetCommandType() == DBOP_sort); Win4Assert(pNode->GetFirstChild()->GetFirstChild()->GetCommandType() == DBOP_sort_list_anchor); Win4Assert(0 == _xSortNode.GetPointer());
// The sort list elements from SortNode will be carved off and appended
// to the list in pSLA.
CDbSortListAnchor * pSLA = (CDbSortListAnchor *)pNode->GetFirstChild()->GetFirstChild();
Win4Assert(SortNode.GetPointer() != 0); Win4Assert(SortNode->GetCommandType() == DBOP_sort); Win4Assert(SortNode->GetFirstChild()->GetCommandType() == DBOP_sort_list_anchor); XPtr<CDbSortListElement> xSLE ( (CDbSortListElement *) SortNode->GetFirstChild()->AcquireChildren() );
if (xSLE.GetPointer()) { pSLA->AppendList( xSLE.GetPointer() ); xSLE.Acquire(); } }
|