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
586 lines
19 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996 - 2000.
|
|
//
|
|
// File: strrest.cxx
|
|
//
|
|
// Contents: Builds a restriction object from a string
|
|
//
|
|
// History: 96/Jan/3 DwightKr Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <parser.hxx>
|
|
#include <pvarset.hxx>
|
|
#include <strsort.hxx>
|
|
#include <cierror.h>
|
|
|
|
extern CDbContentRestriction * TreeFromText(
|
|
WCHAR const * wcsRestriction,
|
|
IColumnMapper & ColumnMapper,
|
|
LCID lcid );
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetStringDbRestriction - public constructor
|
|
//
|
|
// Synopsis: Builds a CDbRestriction from the string passed
|
|
//
|
|
// Arguments: [wcsRestriction] - the string containing the restriction
|
|
// [ulDialect] - triplish dialect
|
|
// [pList] - property list describing the proptypes
|
|
// [lcid] - the locale of the query
|
|
//
|
|
// History: 96/Jan/03 DwightKr Created.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CDbRestriction * GetStringDbRestriction(
|
|
const WCHAR * wcsRestriction,
|
|
ULONG ulDialect,
|
|
IColumnMapper * pList,
|
|
LCID lcid )
|
|
{
|
|
Win4Assert( 0 != wcsRestriction );
|
|
Win4Assert( ISQLANG_V1 == ulDialect || ISQLANG_V2 == ulDialect );
|
|
|
|
XPtr<CDbRestriction> xRest;
|
|
|
|
if ( ISQLANG_V1 == ulDialect )
|
|
{
|
|
CQueryScanner scanner( wcsRestriction, TRUE, lcid );
|
|
|
|
CQueryParser query( scanner,
|
|
VECTOR_RANK_JACCARD,
|
|
lcid,
|
|
L"contents",
|
|
CONTENTS,
|
|
pList );
|
|
|
|
xRest.Set( query.ParseQueryPhrase() );
|
|
}
|
|
else
|
|
{
|
|
xRest.Set( TreeFromText( wcsRestriction, *pList, lcid ) );
|
|
}
|
|
|
|
return xRest.Acquire();
|
|
} //GetStringDbRestriction
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: FormDbQueryTree
|
|
//
|
|
// Synopsis: Builds a CDbCmdTreeNode from the restriction, sort
|
|
// specification, grouping specification and output columns.
|
|
//
|
|
// Arguments: [xDbRestriction] - the restriction
|
|
// [xDbSortNode] - the sort specification (optional)
|
|
// [xDbProjectList] - the output columns
|
|
// [xDbGroupNode] - the grouping specification (optional)
|
|
// [ulMaxRecords] - max records to return
|
|
// [ulFirstRows] - only sort and display the first ulFirstRows
|
|
// rows
|
|
//
|
|
// History: 1996/Jan/03 DwightKr Created.
|
|
// 2000/Jul/01 KitmanH Added ulFirstRows
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
CDbCmdTreeNode * FormDbQueryTree( XPtr<CDbCmdTreeNode> & xDbCmdTreeNode,
|
|
XPtr<CDbSortNode> & xDbSortNode,
|
|
XPtr<CDbProjectListAnchor> & xDbProjectList,
|
|
XPtr<CDbNestingNode> & xDbGroupNode,
|
|
ULONG ulMaxRecords,
|
|
ULONG ulFirstRows )
|
|
{
|
|
XPtr<CDbCmdTreeNode> xDbCmdTree = 0;
|
|
|
|
//
|
|
// First create a selection node and append the restriction tree to it
|
|
//
|
|
CDbSelectNode * pSelect = new CDbSelectNode();
|
|
if ( 0 == pSelect )
|
|
{
|
|
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
|
|
}
|
|
|
|
xDbCmdTree.Set( pSelect );
|
|
if ( !pSelect->IsValid() )
|
|
{
|
|
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
|
|
}
|
|
|
|
//
|
|
// Now make the restriction a child of the selection node.
|
|
//
|
|
|
|
pSelect->AddRestriction( xDbCmdTreeNode.GetPointer() );
|
|
xDbCmdTreeNode.Acquire();
|
|
|
|
//
|
|
// If there is a nesting node, add the project list and the selection
|
|
// node below the lowest nesting node. Otherwise, create a projection
|
|
// node and make the selection a child of the projection node.
|
|
//
|
|
if ( 0 != xDbGroupNode.GetPointer() )
|
|
{
|
|
CDbNestingNode * pBottomNestingNode = xDbGroupNode.GetPointer();
|
|
CDbCmdTreeNode * pTree = pBottomNestingNode;
|
|
|
|
while (pTree->GetFirstChild() != 0 &&
|
|
(pTree->GetFirstChild()->GetCommandType() == DBOP_nesting ||
|
|
pTree->GetFirstChild()->GetCommandType() == DBOP_sort))
|
|
{
|
|
pTree = pTree->GetFirstChild();
|
|
if (pTree->GetCommandType() == DBOP_nesting)
|
|
pBottomNestingNode = (CDbNestingNode *)pTree;
|
|
}
|
|
|
|
// Add the input projection list to the nesting node
|
|
if (! pBottomNestingNode->SetChildList( *xDbProjectList.GetPointer() ))
|
|
THROW( CException(E_INVALIDARG) );
|
|
|
|
//
|
|
// Make the selection a child of the lowest node.
|
|
//
|
|
if (pBottomNestingNode == pTree)
|
|
{
|
|
pBottomNestingNode->AddTable( xDbCmdTree.GetPointer() );
|
|
xDbCmdTree.Acquire();
|
|
}
|
|
else
|
|
{
|
|
Win4Assert( pTree->IsSortNode() );
|
|
((CDbSortNode *)pTree)->AddTable( xDbCmdTree.GetPointer() );
|
|
xDbCmdTree.Acquire();
|
|
}
|
|
|
|
xDbCmdTree.Set( xDbGroupNode.Acquire() );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Create the projection nodes
|
|
//
|
|
CDbProjectNode * pProject = new CDbProjectNode();
|
|
if ( 0 == pProject )
|
|
{
|
|
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
|
|
}
|
|
|
|
//
|
|
// Make the selection a child of the projection node.
|
|
//
|
|
pProject->AddTable( xDbCmdTree.GetPointer() );
|
|
xDbCmdTree.Acquire();
|
|
|
|
xDbCmdTree.Set( pProject );
|
|
|
|
//
|
|
// Next add the column list to the project node
|
|
//
|
|
|
|
pProject->AddList( xDbProjectList.GetPointer() );
|
|
xDbProjectList.Acquire();
|
|
|
|
//
|
|
// Next make the project node a child of the sort node
|
|
//
|
|
|
|
if ( !xDbSortNode.IsNull() && 0 != xDbSortNode->GetFirstChild() )
|
|
{
|
|
xDbSortNode->AddTable( xDbCmdTree.GetPointer() );
|
|
xDbCmdTree.Acquire();
|
|
|
|
xDbCmdTree.Set( xDbSortNode.Acquire() );
|
|
}
|
|
}
|
|
|
|
CDbTopNode *pTop = 0;
|
|
|
|
//
|
|
// If the user specified a max # of records to examine, then setup
|
|
// a node to reflect this.
|
|
//
|
|
if ( ulMaxRecords > 0 )
|
|
{
|
|
pTop = new CDbTopNode();
|
|
if ( pTop == 0 )
|
|
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
|
|
|
|
pTop->SetChild( xDbCmdTree.Acquire() );
|
|
pTop->SetValue(ulMaxRecords );
|
|
}
|
|
|
|
//
|
|
// Set FirstRows here
|
|
//
|
|
if ( ulFirstRows > 0 )
|
|
{
|
|
CDbFirstRowsNode *pFR = new CDbFirstRowsNode();
|
|
if ( pFR == 0 )
|
|
THROW( CException( STATUS_NO_MEMORY ) );
|
|
|
|
CDbCmdTreeNode *pChild = pTop ? pTop : xDbCmdTree.Acquire();
|
|
pFR->SetChild( pChild );
|
|
pFR->SetValue( ulFirstRows );
|
|
|
|
return pFR;
|
|
}
|
|
|
|
if ( 0 != pTop )
|
|
return pTop;
|
|
|
|
return xDbCmdTree.Acquire();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ParseStringColumns
|
|
//
|
|
// Synopsis: Parses the textual columns separated by commas into CDbColumns.
|
|
// Also, adds the columns to a set of named variables if the
|
|
// optional parameter pVariableSet is passed.
|
|
//
|
|
// Arguments: [wcsColumns] -- List of columns, separated by commas
|
|
// [pList] -- Column mapper.
|
|
// [lcid] -- locale
|
|
// [pVarSet] -- [optional] Variable Set.
|
|
// [pawcsColumns] -- [optional] Parsed columns
|
|
//
|
|
// History: 3-03-97 srikants Created
|
|
// 7-23-97 KyleP Return parsed columns
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CDbColumns * ParseStringColumns( WCHAR const * wcsColumns,
|
|
IColumnMapper * pList,
|
|
LCID lcid,
|
|
PVariableSet * pVarSet,
|
|
CDynArray<WCHAR> * pawcsColumns )
|
|
{
|
|
CDbColumns * pDbCols = new CDbColumns(0);
|
|
if ( 0 == pDbCols )
|
|
{
|
|
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
|
|
}
|
|
|
|
XPtr<CDbColumns> xDbCols( pDbCols );
|
|
|
|
CQueryScanner scan( wcsColumns, FALSE, lcid );
|
|
|
|
for ( XPtrST<WCHAR> wcsColumn( scan.AcqColumn() );
|
|
wcsColumn.GetPointer() != 0;
|
|
wcsColumn.Set( scan.AcqColumn() )
|
|
)
|
|
{
|
|
CDbColId *pDbColId = 0;
|
|
DBID *pdbid = 0;
|
|
_wcsupr( wcsColumn.GetPointer() );
|
|
|
|
if ( FAILED(pList->GetPropInfoFromName( wcsColumn.GetPointer(), &pdbid, 0, 0 )) )
|
|
{
|
|
//
|
|
// This column was not defined. Report an error.
|
|
//
|
|
qutilDebugOut(( DEB_IERROR, "Column name %ws not found\n", wcsColumn.GetPointer() ));
|
|
THROW( CException( QUERY_E_INVALID_OUTPUT_COLUMN ) );
|
|
}
|
|
|
|
pDbColId = (CDbColId *)pdbid;
|
|
|
|
unsigned colNum = pDbCols->Count();
|
|
for (unsigned i=0; i<colNum; i++)
|
|
{
|
|
if (pDbCols->Get(i) == *pDbColId)
|
|
break;
|
|
}
|
|
|
|
if (i != colNum)
|
|
{
|
|
//
|
|
// This column is a duplicate of another, possibly an alias.
|
|
//
|
|
qutilDebugOut(( DEB_IERROR, "Column name %ws is duplicated\n", wcsColumn.GetPointer() ));
|
|
THROW( CException( QUERY_E_DUPLICATE_OUTPUT_COLUMN ) );
|
|
}
|
|
pDbCols->Add( *pDbColId, colNum );
|
|
|
|
|
|
//
|
|
// Add the output column to the list of replaceable parameters if needed.
|
|
//
|
|
if ( pVarSet )
|
|
{
|
|
Win4Assert( 0 != pawcsColumns );
|
|
|
|
pVarSet->SetVariable( wcsColumn.GetPointer(), 0, 0);
|
|
pawcsColumns->Add( wcsColumn.GetPointer(), colNum );
|
|
wcsColumn.Acquire();
|
|
}
|
|
|
|
wcsColumn.Free();
|
|
scan.AcceptColumn(); // Remove the column name
|
|
|
|
//
|
|
// Skip over commas seperating output columns
|
|
//
|
|
if ( scan.LookAhead() == COMMA_TOKEN )
|
|
{
|
|
scan.Accept(); // Remove the ','
|
|
}
|
|
else if ( scan.LookAhead() != EOS_TOKEN )
|
|
{
|
|
THROW( CException( QPARSE_E_EXPECTING_COMMA ) );
|
|
}
|
|
}
|
|
|
|
qutilDebugOut(( DEB_ITRACE, "%d columns added to CDbColumns\n", pDbCols->Count() ));
|
|
|
|
//
|
|
// We must have exhausted the CiColumns line. If not, there was a syntax
|
|
// error we couldn't parse.
|
|
//
|
|
if ( scan.LookAhead() != EOS_TOKEN )
|
|
{
|
|
//
|
|
// Contains a syntax error. Report an error.
|
|
//
|
|
qutilDebugOut(( DEB_IWARN, "Syntax error in CiColumns= line\n" ));
|
|
THROW( CException( QUERY_E_INVALID_OUTPUT_COLUMN ) );
|
|
}
|
|
|
|
return xDbCols.Acquire();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: ParseColumnsWithFriendlyNames
|
|
//
|
|
// Synopsis: Parses the columns string and leaves the friendly names
|
|
// in the project list.
|
|
//
|
|
// Arguments: [wcsColumns] - Columns names
|
|
// [pList] - Property List
|
|
// [pVarSet] - (not used) Variable Set - Optional
|
|
//
|
|
// Returns: The project list anchor of the tree.
|
|
//
|
|
// History: 3-18-97 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CDbProjectListAnchor * ParseColumnsWithFriendlyNames(
|
|
WCHAR const * wcsColumns,
|
|
IColumnMapper * pList,
|
|
PVariableSet * pVarSet )
|
|
{
|
|
CDbColumns * pDbCols = new CDbColumns( 0 );
|
|
XPtr<CDbColumns> xDbCols( pDbCols );
|
|
|
|
XPtr<CDbProjectListAnchor> xDbColList( new CDbProjectListAnchor() );
|
|
|
|
if ( 0 == xDbCols.GetPointer() ||
|
|
0 == xDbColList.GetPointer() )
|
|
{
|
|
THROW( CException(E_OUTOFMEMORY) );
|
|
}
|
|
|
|
CQueryScanner scan( wcsColumns, FALSE );
|
|
|
|
for ( XPtrST<WCHAR> wcsColumn( scan.AcqColumn() );
|
|
wcsColumn.GetPointer() != 0;
|
|
wcsColumn.Set( scan.AcqColumn() )
|
|
)
|
|
{
|
|
CDbColId *pDbColId = 0;
|
|
DBID *pdbid = 0;
|
|
|
|
_wcsupr( wcsColumn.GetPointer() );
|
|
|
|
if ( FAILED(pList->GetPropInfoFromName( wcsColumn.GetPointer(), &pdbid, 0, 0 )) )
|
|
{
|
|
//
|
|
// This column was not defined. Report an error.
|
|
//
|
|
qutilDebugOut(( DEB_IERROR, "Column name %ws not found\n",
|
|
wcsColumn.GetPointer() ));
|
|
THROW( CException(QUERY_E_INVALID_OUTPUT_COLUMN) );
|
|
}
|
|
|
|
pDbColId = (CDbColId *)pdbid;
|
|
|
|
unsigned colNum = pDbCols->Count();
|
|
for (unsigned i=0; i<colNum; i++)
|
|
{
|
|
if (pDbCols->Get(i) == *pDbColId)
|
|
break;
|
|
}
|
|
|
|
if (i != colNum)
|
|
{
|
|
//
|
|
// This column is a duplicate of another, possibly an alias.
|
|
//
|
|
qutilDebugOut(( DEB_IERROR, "Column name %ws is duplicated\n",
|
|
wcsColumn.GetPointer() ));
|
|
THROW( CException(QUERY_E_DUPLICATE_OUTPUT_COLUMN) );
|
|
}
|
|
pDbCols->Add( *pDbColId, colNum );
|
|
if (! xDbColList->AppendListElement( *pDbColId,
|
|
wcsColumn.GetPointer() ))
|
|
THROW( CException(E_OUTOFMEMORY) );
|
|
|
|
delete wcsColumn.Acquire();
|
|
scan.AcceptColumn(); // Remove the column name
|
|
|
|
//
|
|
// Skip over commas seperating output columns
|
|
//
|
|
if ( scan.LookAhead() == COMMA_TOKEN )
|
|
{
|
|
scan.Accept(); // Remove the ','
|
|
}
|
|
else if ( scan.LookAhead() != EOS_TOKEN )
|
|
{
|
|
THROW( CException(QPARSE_E_EXPECTING_COMMA ) );
|
|
}
|
|
}
|
|
|
|
qutilDebugOut(( DEB_TRACE, "%d columns added to project list\n", pDbCols->Count() ));
|
|
|
|
//
|
|
// We must have exhausted the CiColumns line. If not, there was a syntax
|
|
// error we couldn't parse.
|
|
//
|
|
if ( scan.LookAhead() != EOS_TOKEN )
|
|
{
|
|
//
|
|
// Contains a syntax error. Report an error.
|
|
//
|
|
qutilDebugOut(( DEB_IERROR, "Syntax error in CiColumns= line\n" ));
|
|
THROW( CException(QUERY_E_INVALID_OUTPUT_COLUMN) );
|
|
}
|
|
|
|
return xDbColList.Acquire();
|
|
}
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CTextToTree::FormFullTree
|
|
//
|
|
// Synopsis: Creates a full tree from the parameters given to the
|
|
// construtor.
|
|
//
|
|
// History: 3-04-97 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DBCOMMANDTREE * CTextToTree::FormFullTree()
|
|
{
|
|
XPtr<CDbProjectListAnchor> xDbProjectList;
|
|
|
|
if ( _fKeepFriendlyNames )
|
|
{
|
|
//
|
|
// Get the Project List Anchor for the string columns retaining the
|
|
// friendly names.
|
|
//
|
|
xDbProjectList.Set(
|
|
ParseColumnsWithFriendlyNames( _wcsColumns,
|
|
_xPropList.GetPointer(),
|
|
_pVariableSet ) );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Convert the textual form of the columns into DBColumns.
|
|
//
|
|
XPtr<CDbColumns> xDbColumns;
|
|
CDbColumns * pDbColumns = _pDbColumns;
|
|
|
|
if ( 0 == pDbColumns )
|
|
{
|
|
xDbColumns.Set( ParseStringColumns( _wcsColumns,
|
|
_xPropList.GetPointer(),
|
|
_locale,
|
|
_pVariableSet ) );
|
|
pDbColumns = xDbColumns.GetPointer();
|
|
}
|
|
|
|
//
|
|
// Build the projection list from the column list.
|
|
//
|
|
xDbProjectList.Set( new CDbProjectListAnchor );
|
|
if ( 0 == xDbProjectList.GetPointer() )
|
|
{
|
|
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
|
|
}
|
|
|
|
for (unsigned i=0; i < pDbColumns->Count(); i++)
|
|
{
|
|
if (! xDbProjectList->AppendListElement( pDbColumns->Get(i) ))
|
|
{
|
|
THROW( CException(STATUS_INSUFFICIENT_RESOURCES) );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert the textual form of the sort columns into CDbSortNode.
|
|
//
|
|
XPtr<CDbSortNode> xDbSortNode;
|
|
if ( 0 != _wcsSort )
|
|
xDbSortNode.Set( GetStringDbSortNode( _wcsSort, _xPropList.GetPointer(), _locale ) );
|
|
|
|
XPtr<CDbNestingNode> xDbNestingNode;
|
|
if ( 0 != _wcsGroup )
|
|
{
|
|
CQueryScanner scanner( _wcsGroup, FALSE, _locale, TRUE );
|
|
CParseGrouping ParseGrouping( scanner, _xPropList.GetPointer(), _fKeepFriendlyNames );
|
|
ParseGrouping.Parse();
|
|
|
|
if ( 0 != _wcsSort )
|
|
ParseGrouping.AddSortList( xDbSortNode );
|
|
|
|
xDbNestingNode.Set( ParseGrouping.AcquireNode() );
|
|
}
|
|
|
|
qutilDebugOut(( DEB_TRACE, "ExecuteQuery:\n" ));
|
|
qutilDebugOut(( DEB_TRACE, "\tCiRestriction = '%ws'\n", _wcsRestriction ));
|
|
|
|
XPtr<CDbCmdTreeNode> xDbCmdTreeNode;
|
|
|
|
// Use a restriction if one was already passed in
|
|
if (0 != _pDbCmdTree)
|
|
{
|
|
Win4Assert(0 == _wcsRestriction);
|
|
xDbCmdTreeNode.Set((CDbCmdTreeNode *)CDbCmdTreeNode::CastFromStruct(_pDbCmdTree));
|
|
}
|
|
else
|
|
{
|
|
Win4Assert(_wcsRestriction);
|
|
|
|
xDbCmdTreeNode.Set( GetStringDbRestriction( _wcsRestriction,
|
|
_ulDialect,
|
|
_xPropList.GetPointer(),
|
|
_locale ) );
|
|
}
|
|
|
|
//
|
|
// Now form the query tree from the restriction, sort set, and
|
|
// projection list.
|
|
//
|
|
|
|
CDbCmdTreeNode *pDbCmdTree = FormDbQueryTree( xDbCmdTreeNode,
|
|
xDbSortNode,
|
|
xDbProjectList,
|
|
xDbNestingNode,
|
|
_maxRecs,
|
|
_cFirstRows );
|
|
|
|
return pDbCmdTree->CastToStruct();
|
|
} //FormFullTree
|
|
|