|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995 - 2000.
//
// File: Parstree.cxx
//
// Contents: Converts OLE-DB command tree into CColumns, CSort, CRestriction
// and CCategorization.
//
// Classes: CParseCommandTree
//
// History: 31 May 95 AlanW Created
//
//--------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <coldesc.hxx>
#include <pidmap.hxx>
#include <parstree.hxx>
static GUID guidBmk = DBBMKGUID; const CFullPropSpec colChapter( guidBmk, PROPID_DBBMK_CHAPTER ); const CFullPropSpec colBookmark( guidBmk, PROPID_DBBMK_BOOKMARK );
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::~CParseCommandTree, public
//
// Synopsis: Destructor of CParseCommandTree
//
//----------------------------------------------------------------------------
CParseCommandTree::~CParseCommandTree( void ) { if (_prst) delete _prst; }
//--------------------------------------------------------------------------
//
// Command tree syntax accepted:
//
// QueryTree :
// Table |
// ContentTable |
// SetUnion |
// Categorization |
// Projection |
// OrderedQueryTree |
// Restriction |
// TopNode QueryTree
// Categorization :
// nesting OrderedQueryTree GroupingList ParentList ChildList coldef
// ContentTable :
// <empty> |
// scope_list_anchor scope_list_element |
// ScopeList scope_list_element
// GroupingList : ProjectList
// ParentList : ProjectList
// ChildList : ProjectList
// Projection :
// ProjectOperator QueryTree ProjectList
// ProjectOperator :
// project | project_order_preserving
// ProjectList :
// project_list_anchor project_list_element |
// ProjectList project_list_element
// OrderedQueryTree :
// sort QueryTree SortList
// ScopeList :
// scope_list_anchor scope_list_element |
// ScopeList scope_list_element
// SetUnion:
// ContentTable ContentTable |
// SetUnion ContentTable
// SortList :
// sort_list_anchor sort_list_element |
// SortList sort_list_element
// Restriction :
// select QueryTree ExprTree |
// select_order_preserving QueryTree ExprTree
// Table :
// scalar_identifier( Table )
// ExprTree :
// not ExprTree |
// and ExprList |
// or ExprList |
// content_proximity ContentExprList
// vector_or ContentExprList
// ExprTerm
// ExprList :
// ExprTree ExprTree |
// ExprList ExprTree
// ExprTerm :
// ContentExpr |
// ValueExpr |
// LikeExpr
// ValueExpr :
// ValueOperator scalar_identifier(ColId) scalar_constant
// ValueOperator :
// equal | not_equal | less | less_equal | greater | greater_equal |
// equal_any | not_equal_any | less_any | less_equal_any |
// greater_any | greater_equal_any |
// equal_all | not_equal_all | less_all | less_equal_all |
// greater_all | greater_equal_all | any_bits | all_bits
// LikeExpr :
// like(OfsRegexp) scalar_identifier(ColId) scalar_constant
// ContentExprTree :
// not ContentExprTree |
// and ContentExprList |
// or ContentExprList |
// content_proximity ContentExprList
// ContentExpr
// ContentExprList :
// ContentExprTree ContentExprTree |
// ContentExprList ContentExprTree
// ContentExpr :
// content PhraseList |
// freetext_content PhraseList
//
//+---------------------------------------------------------------------------
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseTree, public
//
// Synopsis: Parse a CDbCmdTreeNode into projection, sort, restriction
// and categorizations.
//
// Arguments: [pTree] -- CDbCmdTreeNode node at root of tree to be parsed
//
// Returns: nothing. Throws if error in tree.
//
// History: 31 May 95 AlanW Created
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseTree( CDbCmdTreeNode * pTree ) { CheckRecursionLimit(); if (pTree == 0) { vqDebugOut(( DEB_WARN, "ParseTree - null tree\n")); THROW( CException( E_INVALIDARG )); }
switch (pTree->GetCommandType()) { case DBOP_project: case DBOP_project_order_preserving: ParseProjection( pTree ); break;
case DBOP_sort: ParseSort( pTree ); break;
case DBOP_select: // case DBOP_select_order_preserving:
ParseRestriction( pTree ); break;
case DBOP_nesting: ParseCategorization( pTree ); break;
case DBOP_table_name: if ( _wcsicmp( ((CDbTableId *)pTree)->GetTableName(), DBTABLEID_NAME )) SetError( pTree ); break;
case DBOP_top: ParseTopNode( pTree ); break;
case DBOP_firstrows: ParseFirstRowsNode( pTree ); break;
case DBOP_content_table: ParseScope( pTree ); break;
case DBOP_set_union: ParseMultiScopes( pTree ); break;
default: vqDebugOut(( DEB_WARN, "ParseTree - unexpected operator %d\n", pTree->GetCommandType() )); SetError( pTree ); break; } return; }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseScope, public
//
// Synopsis: Parse a CDbCmdTreeNode scope operator
//
// Arguments: [pTree] -- CDbCmdTreeNode scope specification node
//
// History: 09-15-98 danleg Created
//
// Notes: Here is a variation of a tree with scope nodes. This routine
// gets a tree rooted either at a content_table node if a single
// scope is specified, or a set_union node if there are multiple
// scopes.
//
// proj
// _________________/
// /
// select ___________________ LA-proj
// _____________/ ____/
// / /
// set_union ________ content LE_proj ____ LE_proj
// ____/ ____/ ___/ __/
// / / / /
// / column_name column_name column_name
// /
// set_union ________________ content_table
// __/ __/
// / /
// / ...
// content_table ____ content_table
// ___/ ___/
// / /
// LA_scp LA_scp
// __/ __/
// / /
// LE_scp ... LE_scp ___ LE_scp ___ ...
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseScope( CDbCmdTreeNode * pTree ) { CheckRecursionLimit(); Win4Assert( DBOP_content_table == pTree->GetCommandType() );
if ( 0 != pTree->GetFirstChild() ) { //
// qualified scope
//
ParseScopeListElements( pTree ); } else { //
// unqualified scope
//
_cScopes++;
_xaMachines.SetSize( _cScopes ); _xaScopes.SetSize( _cScopes ); _xaFlags.SetSize( _cScopes ); _xaCatalogs.SetSize( _cScopes );
CDbContentTable * pCntntTbl = (CDbContentTable *) (pTree->CastToStruct())->value.pdbcntnttblValue;
_xaMachines[_cScopes-1] = pCntntTbl->GetMachine(); _xaCatalogs[_cScopes-1] = pCntntTbl->GetCatalog(); _xaFlags[_cScopes-1] = QUERY_DEEP | QUERY_PHYSICAL_PATH; _xaScopes[_cScopes-1] = L"\\"; }
if ( 0 != pTree->GetNextSibling() && DBOP_content_table == pTree->GetNextSibling()->GetCommandType() ) ParseTree( pTree->GetNextSibling() ); }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseScopeListElements, public
//
// Synopsis:
//
// Arguments: [pcntntTbl] -- node consisting of catalog/machine name info
// [pTree] -- CDbCmdTreeNode scope specification node
//
// History: 01-24-99 danleg Created
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseScopeListElements( CDbCmdTreeNode * pTree ) { CheckRecursionLimit(); if ( 0 == pTree->GetFirstChild() ) { SetError( pTree ); } if ( DBOP_scope_list_anchor != pTree->GetFirstChild()->GetCommandType() ) { SetError( pTree->GetFirstChild() ); } CheckOperatorArity( pTree->GetFirstChild(), -1 );
CDbContentTable * pCntntTbl = (CDbContentTable *) (pTree->CastToStruct())->value.pdbcntnttblValue; CDbCmdTreeNode * pLE_SCP = pTree->GetFirstChild()->GetFirstChild();
for ( ; pLE_SCP; pLE_SCP = pLE_SCP->GetNextSibling() ) { if ( DBOP_scope_list_element != pLE_SCP->GetCommandType() || 0 != pLE_SCP->GetFirstChild() ) { SetError( pLE_SCP ); } VerifyValueType( pLE_SCP, DBVALUEKIND_CONTENTSCOPE );
CDbContentScope * pCntntScp = (CDbContentScope *) (pLE_SCP->CastToStruct())->value.pdbcntntscpValue;
_cScopes++;
_xaMachines.SetSize( _cScopes ); _xaScopes.SetSize( _cScopes ); _xaFlags.SetSize( _cScopes ); _xaCatalogs.SetSize( _cScopes );
_xaMachines[_cScopes-1] = pCntntTbl->GetMachine(); _xaCatalogs[_cScopes-1] = pCntntTbl->GetCatalog();
//
// DBPROP_CI_SCOPE_FLAGS
//
if ( pCntntScp->GetType() & SCOPE_TYPE_WINPATH ) _xaFlags[_cScopes-1] = QUERY_PHYSICAL_PATH; else if ( pCntntScp->GetType() & SCOPE_TYPE_VPATH ) _xaFlags[_cScopes-1] = QUERY_VIRTUAL_PATH; else { // unknown flag
SetError( pLE_SCP ); }
if ( pCntntScp->GetFlags() & SCOPE_FLAG_DEEP ) _xaFlags[_cScopes-1] |= QUERY_DEEP; else _xaFlags[_cScopes-1] |= QUERY_SHALLOW;
//
// DBPROP_CI_INCLUDE_SCOPES
//
_xaScopes[_cScopes-1] = pCntntScp->GetValue(); } }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseMultiScopes, public
//
// Synopsis:
//
// Arguments: [pcntntTbl] -- node consisting of catalog/machine name info
// [pTree] -- CDbCmdTreeNode scope specification node
//
// History: 01-24-99 danleg Created
//
// Notes: Two possibilities:
//
// set_union ___ content
// ______________/
// /
// content_table ___ content_table ___ ... ___ content_table
//
//
// -- or --
//
// set_union ___ content
// ___________/
// /
// set_union _____________________________ set_union
// _____/ ______/
// / /
// content_table ___ content_table content_table ___ content_table
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseMultiScopes( CDbCmdTreeNode * pTree ) { CheckRecursionLimit(); Win4Assert( DBOP_set_union == pTree->GetCommandType() );
Win4Assert( 0 != pTree->GetFirstChild() && 0 != pTree->GetNextSibling() ); if ( DBOP_content_table == pTree->GetCommandType() ) { CDbCmdTreeNode * pCntntTbl = pTree->GetFirstChild();
for ( ; pCntntTbl; pCntntTbl = pCntntTbl->GetNextSibling() ) { if ( DBOP_content_table != pCntntTbl->GetCommandType() ) SetError( pCntntTbl );
ParseScope( pCntntTbl ); } } else { Win4Assert( DBOP_set_union == pTree->GetCommandType() );
if ( DBOP_content_table != pTree->GetFirstChild()->GetCommandType() && DBOP_set_union != pTree->GetFirstChild()->GetCommandType() ) SetError( pTree );
ParseTree( pTree->GetFirstChild() );
//
// Note that the DBOP_content branch gets parsed by ParseRestriction
//
if ( DBOP_content_table == pTree->GetNextSibling()->GetCommandType() || DBOP_set_union == pTree->GetNextSibling()->GetCommandType() ) ParseTree( pTree->GetNextSibling() ); } }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseProjection, public
//
// Synopsis: Parse a CDbCmdTreeNode project operator
//
// Arguments: [pTree] -- CDbCmdTreeNode node at root of tree to be parsed
//
// History: 31 May 95 AlanW Created
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseProjection( CDbCmdTreeNode * pTree ) { CheckRecursionLimit(); CheckOperatorArity( pTree, 2 );
CDbCmdTreeNode * pChild = pTree->GetFirstChild();
//
// Parse the projection list first, so a projection higher in the
// tree takes precedence. A projection is not permitted in a tree
// that also contains a nesting node.
//
// Should a higher level projection take precedence?
// We currently return an error.
//
if (_categ.Count() == 0 && _cols.Count() == 0) ParseProjectList ( pChild->GetNextSibling(), _cols ); else SetError( pTree );
ParseTree( pChild ); }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseProjectList, public
//
// Synopsis: Parse a CDbCmdTreeNode project list
//
// Arguments: [pTree] -- CDbCmdTreeNode node for project list head
// [Cols] -- CColumnSet in which columns are collected
//
// History: 31 May 95 AlanW Created
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseProjectList( CDbCmdTreeNode *pTree, CColumnSet& Cols ) { CheckRecursionLimit();
if (pTree->GetCommandType() != DBOP_project_list_anchor || pTree->GetFirstChild() == 0) { SetError( pTree ); }
CFullPropSpec Col;
CDbProjectListElement* pList = (CDbProjectListElement *) pTree->GetFirstChild(); for ( ; pList; pList = (CDbProjectListElement *)pList->GetNextSibling()) { if ( pList->GetCommandType() != DBOP_project_list_element || pList->GetFirstChild() == 0 ) { SetError( pList ); }
CDbCmdTreeNode * pColumn = pList->GetFirstChild(); if ( !pColumn->IsColumnName() ) { SetError( pColumn ); }
// Add element to projection list
PROPID pid = GetColumnPropSpec(pColumn, Col); Cols.Add( pid, Cols.Count() );
if ( 0 != pList->GetName() ) _pidmap.SetFriendlyName( pid, pList->GetName() ); } }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseSort, public
//
// Synopsis: Parse a CDbCmdTreeNode sort node
//
// Arguments: [pTree] -- CDbCmdTreeNode node for sort list head
//
// Notes: Sort nodes are added to the CSortSet in private data
//
// History: 31 May 95 AlanW Created
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseSort( CDbCmdTreeNode * pTree ) { CheckRecursionLimit(); CheckOperatorArity( pTree, 2 ); CDbCmdTreeNode * pChild = pTree->GetFirstChild();
//
// Parse the sort list first, so a sort higher in the
// tree is primary.
//
ParseSortList ( pChild->GetNextSibling() ); ParseTree( pChild ); }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseSortList, public
//
// Synopsis: Parse a CDbCmdTreeNode sort list
//
// Arguments: [pTree] -- CDbCmdTreeNode node for sort list head
//
// Notes: Sort nodes are added to the CSortSet in private data
//
// History: 31 May 95 AlanW Created
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseSortList( CDbCmdTreeNode * pTree ) { CheckRecursionLimit(); if (pTree->GetCommandType() != DBOP_sort_list_anchor || pTree->GetFirstChild() == 0) { SetError( pTree ); }
CDbSortListAnchor *pSortAnchor = (CDbSortListAnchor *) pTree;
unsigned i = 0; for (CDbCmdTreeNode * pSortList = pSortAnchor->GetFirstChild(); pSortList; pSortList = pSortList->GetNextSibling(), i++) { if (pSortList->GetCommandType() != DBOP_sort_list_element) { SetError( pSortList ); } VerifyValueType( pSortList, DBVALUEKIND_SORTINFO ); CheckOperatorArity( pSortList, 1 );
CDbSortListElement* pSLE = (CDbSortListElement *) pSortList; CFullPropSpec Col; PROPID pid = GetColumnPropSpec(pSLE->GetFirstChild(), Col);
DWORD dwOrder = pSLE->GetDirection() ? QUERY_SORTDESCEND : QUERY_SORTASCEND; LCID locale = pSLE->GetLocale();
if ( _categ.Count() != 0 && i < _sort.Count() ) { //
// Check that the sort specification matches any set as a result of
// the categorization (but which may differ in sort direction and
// locale).
//
SSortKey & sortkey = _sort.Get(i); if (sortkey.pidColumn != pid) { SetError(pSLE); }
if (sortkey.dwOrder != dwOrder) sortkey.dwOrder = dwOrder;
if (sortkey.locale != locale) sortkey.locale = locale; } else { // Add element to the sort list
SSortKey sortkey(pid, dwOrder, locale); _sort.Add( sortkey, _sort.Count() ); } } }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseRestriction, public
//
// Synopsis: Parse a CDbCmdTreeNode select node
//
// Arguments: [pTree] -- CDbCmdTreeNode node for select tree
//
// History: 31 May 95 AlanW Created
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseRestriction( CDbCmdTreeNode *pTree ) { CheckRecursionLimit(); //
// Only one selection can exist in the tree; there must be exactly
// two operands: the selection expression and a table identifier.
// For use with AddPostProcessing, another select should be
// allowed higher in the tree, with the restrictions anded
// together.
//
if (_prst != 0 ) SetError( pTree ); CheckOperatorArity( pTree, 2 ); VerifyValueType( pTree, DBVALUEKIND_EMPTY );
CDbCmdTreeNode * pTable = pTree->GetFirstChild(); CDbCmdTreeNode * pExpr = pTable->GetNextSibling();
_prst = ParseExpression( pExpr );
ParseTree( pTable ); }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseCategorization, public
//
// Synopsis: Parse a CDbCmdTreeNode nesting node
//
// Arguments: [pTree] -- CDbCmdTreeNode node for nesting tree
//
// History: 31 Jul 1995 AlanW Created
//
// Notes: Syntax accepted:
//
// Categorization :
// nesting OrderedQueryTree GroupingList
// ParentList ChildList coldef
// GroupingList : ProjectList
// ParentList : ProjectList
// ChildList : ProjectList
//
// The GroupingList may be a list of columns on which
// to do a unique value categorization, or a defined-by-guid
// function that specifies one of the other categorizations.
// The ParentList may only specify columns in the GroupingList,
// columns in upper level groupings, or certain aggregations
// on those columns.
// The ChildList forms the projectlist for the base table.
// The coldef node for the nesting column can give only the
// special column id for the chapter column.
//
// Only the unique value categorization is implemented at present.
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseCategorization( CDbCmdTreeNode *pTree ) { CheckRecursionLimit(); CheckOperatorArity( pTree, 5 ); VerifyValueType( pTree, DBVALUEKIND_EMPTY );
//
// We can't sort or project the output of a categorized table. We can,
// however permit a sort as a side-effect of an existing
// nesting node for a unique value categorization.
//
if (_categ.Count() == 0 && (_sort.Count() > 0 || _cols.Count() > 0)) SetError( pTree, E_INVALIDARG );
Win4Assert(_sort.Count() == _categ.Count());
CDbCmdTreeNode * pTable = pTree->GetFirstChild(); CDbCmdTreeNode * pGroupingList = pTable->GetNextSibling(); CDbCmdTreeNode * pParentList = pGroupingList->GetNextSibling(); CDbCmdTreeNode * pChildList = pParentList->GetNextSibling(); CDbCmdTreeNode * pNestingColumn = pChildList->GetNextSibling();
CheckOperatorArity( pGroupingList, 1 ); // one grouping col. now
// CheckOperatorArity( pParentList, -1 );
// CheckOperatorArity( pChildList, -1 );
CheckOperatorArity( pNestingColumn, 0 );
//
// For now, the only supported categorization is a unique
// value categorization. For this, the grouping list is
// just a projection list that gives the unique columns.
//
CColumnSet colGroup; ParseProjectList( pGroupingList, colGroup );
for (unsigned i = 0; i < colGroup.Count(); i++) { SSortKey sortkey(colGroup.Get(i), QUERY_SORTASCEND); _sort.Add( sortkey, _sort.Count() ); }
//
// For now, the parent list can only mention columns also
// in the grouping list (which are now in the sort list).
// In addition, the bookmark and chapter columns will be
// available in the parent table.
// We should also one day allow some aggregations.
//
CColumnSet colParent; if (pParentList->GetFirstChild() != 0) { ParseProjectList( pParentList, colParent ); if (colParent.Count() > _sort.Count() + 2) { SetError( pParentList, E_INVALIDARG ); } }
//
// Check that the columns are valid
//
pParentList = pParentList->GetFirstChild(); BOOL fChapterFound = FALSE; for (i = 0; i < colParent.Count(); i++) { CFullPropSpec const * pCol = _pidmap.PidToName(colParent.Get(i));
if (*pCol == colChapter) { fChapterFound = TRUE; } else if (*pCol == colBookmark) { // Bookmark is permitted in any parent column list
; } else { BOOL fFound = FALSE; for (unsigned j = 0; j < _sort.Count(); j++) if ( colParent.Get(i) == _sort.Get(j).pidColumn ) { fFound = TRUE; break; }
if (!fFound) SetError(pParentList, E_INVALIDARG); }
pParentList = pParentList->GetNextSibling(); } if (! fChapterFound) colParent.Add( _pidmap.NameToPid(colChapter), colParent.Count());
//
// Columns in the child list replace any existing project list
// (which can only have been set by a higher-level nesting node).
//
if (_cols.Count()) { vqDebugOut(( DEB_WARN, "CParseCommandTree - " "child list in multi-nested command tree ignored\n" )); _cols.Clear(); }
if ( 0 != pChildList->GetFirstChild() ) ParseProjectList( pChildList, _cols );
XPtr<CCategSpec> pCatParam = new CUniqueCategSpec( ); XPtr<CCategorizationSpec> pCat = new CCategorizationSpec( pCatParam.GetPointer(), colParent.Count() ); pCatParam.Acquire(); for (i = 0; i < colParent.Count(); i++) { pCat->SetColumn( colParent.Get(i), i ); }
_categ.Add( pCat.GetPointer(), _categ.Count() ); pCat.Acquire();
//
// Now parse the rest of the tree, and check that _cols was set
// either here or by a lower level nesting node.
//
ParseTree( pTable ); if ( 0 == _cols.Count() ) { Win4Assert( 0 == pChildList->GetFirstChild() ); SetError( pChildList ); } }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseTopNode, public
//
// Synopsis: Parse a CDbTopNode operator
//
// Arguments: [pTree] -- CDbTopNode node at root of tree to be parsed
//
// History: 21 Feb 96 AlanW Created
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseTopNode( CDbCmdTreeNode *pTree ) { CheckRecursionLimit(); CheckOperatorArity( pTree, 1 );
ULONG cMaxResults = ((CDbTopNode *)pTree)->GetValue(); if ( cMaxResults == 0 ) { //
// A query with zero results is uninteresting
//
SetError( pTree ); }
//
// If a top node has already been encountered, then set the
// limit on results to the minimum of the two Top values
//
if ( _cMaxResults == 0 ) { _cMaxResults = cMaxResults; } else { if ( cMaxResults < _cMaxResults ) _cMaxResults = cMaxResults; }
CDbCmdTreeNode *pChild = pTree->GetFirstChild();
ParseTree( pChild ); }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::ParseFirstRowsNode, public
//
// Synopsis: Parse a CDbFirstRowsNode operator
//
// Arguments: [pTree] -- CDbFirstRowsNode node at root of tree to be parsed
//
// History: 19-Jun-2000 KitmanH Created
//
//----------------------------------------------------------------------------
void CParseCommandTree::ParseFirstRowsNode( CDbCmdTreeNode *pTree ) { CheckRecursionLimit(); CheckOperatorArity( pTree, 1 );
ULONG cFirstRows = ((CDbFirstRowsNode *)pTree)->GetValue(); if ( cFirstRows == 0 ) { //
// A query with zero results is uninteresting
//
SetError( pTree ); }
//
// If a top node has already been encountered, then set the
// limit on results to the minimum of the two Top values
//
if ( _cFirstRows == 0 ) { _cFirstRows = cFirstRows; } else { if ( cFirstRows < _cFirstRows ) _cFirstRows = cFirstRows; }
CDbCmdTreeNode *pChild = pTree->GetFirstChild();
ParseTree( pChild ); }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::SetError, private
//
// Synopsis: Mark an error in a command tree node.
//
// Arguments: [pNode] -- CDbCmdTreeNode node to check
// [scError] -- optional error code.
//
// Returns: doesn't. Throws the error set in the node.
//
// History: 31 May 95 AlanW Created
//
//----------------------------------------------------------------------------
void CParseCommandTree::SetError( CDbCmdTreeNode* pNode, SCODE scError) { vqDebugOut(( DEB_ERROR, "SetError - node %x error %x\n", pNode, scError )); pNode->SetError( scError ); if ( ! SUCCEEDED( _scError )) { _scError = scError; _pErrorNode = pNode; }
THROW( CException( DB_E_ERRORSINCOMMAND )); }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::CheckOperatorArity, private
//
// Synopsis: Verify that a tree node has the correct number of
// operands.
//
// Arguments: [pNode] -- CDbCmdTreeNode node to check
// [cOperands] -- number of operands expected. If
// cOperands is negative, at least -cOperands
// must be present. Otherwise, exactly cOperands
// must be present.
//
// Returns: unsigned - the number of operands found
//
// History: 31 May 95 AlanW Created
//
//----------------------------------------------------------------------------
unsigned CParseCommandTree::CheckOperatorArity( CDbCmdTreeNode* pNode, int cOperands) { int cOps = 0;
for (CDbCmdTreeNode* pChild = pNode->GetFirstChild(); pChild; pChild = pChild->GetNextSibling(), cOps++) { if (cOperands >= 0 && cOps > cOperands) pChild->SetError( E_UNEXPECTED ); }
if (cOperands < 0) { //
// -(cOperands) or more operands are permitted
//
if (cOps < -(cOperands)) SetError(pNode, E_INVALIDARG); } else { if (cOps != cOperands) SetError(pNode, E_INVALIDARG); } return (unsigned) cOps; }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::GetColumnPropSpec, private
//
// Synopsis: Return a column identifier from a tree node argument
//
// Arguments: [pNode] -- CDbCmdTreeNode node to check
// [eKind] -- expected value kind
//
// Returns: PROPID from the pidmapper
//
// History: 12 Jun 95 AlanW Created
//
//----------------------------------------------------------------------------
PROPID CParseCommandTree::GetColumnPropSpec( CDbCmdTreeNode* pNode, CFullPropSpec& Col) { if (pNode->GetValueType() != DBVALUEKIND_ID) SetError(pNode, E_INVALIDARG);
CDbColumnNode * pColumnNode = (CDbColumnNode *)pNode;
if (pColumnNode->IsPropertyPropid()) { // pids 0 and 1 are reserved
if ( ( PID_CODEPAGE == pColumnNode->GetPropertyPropid() ) || ( PID_DICTIONARY == pColumnNode->GetPropertyPropid() ) ) SetError(pNode, E_INVALIDARG);
Col.SetProperty( pColumnNode->GetPropertyPropid() ); } else /* (pColumnNode->IsPropertyName()) */ { Col.SetProperty( pColumnNode->GetPropertyName() ); } Col.SetPropSet( pColumnNode->GetPropSet() );
return _pidmap.NameToPid( Col ); }
//+---------------------------------------------------------------------------
//
// Method: CParseCommandTree::GetValue, private
//
// Synopsis: Return a scalar constant from a tree node argument
//
// Arguments: [pNode] -- CDbCmdTreeNode node to check
//
// Returns: CStorageVariant& - reference to value of variant in node
//
// History: 12 Jun 95 AlanW Created
//
//----------------------------------------------------------------------------
BOOL CParseCommandTree::GetValue ( CDbCmdTreeNode* pNode, CStorageVariant & val ) { ((CDbScalarValue *)pNode)->Value( val ); return TRUE; }
|