windows-nt/Source/XPSP1/NT/inetsrv/query/qutil/querylib/doquery.cxx
2020-09-26 16:20:57 +08:00

642 lines
20 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 2000.
//
// File: DOQUERY.CXX
//
// Contents: Functions to make query nodes and trees, and to execute
// queries.
//
// History: 02 Nov 94 alanw Created from main.cxx and screen.cxx.
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <doquery.hxx>
#include <catstate.hxx>
static const GUID guidBmk = DBBMKGUID;
static const GUID psGuidStorage = PSGUID_STORAGE;
static const GUID psGuidQuery = DBQUERYGUID;
static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
static const GUID guidRowset = DBPROPSET_ROWSET;
static CDbColId psRank( psGuidQuery, DISPID_QUERY_RANK );
static CDbColId psBookmark( guidBmk, PROPID_DBBMK_BOOKMARK );
static CDbColId psPath( psGuidStorage, PID_STG_PATH );
//+---------------------------------------------------------------------------
//
// Function: FormTableNode
//
// Synopsis: Forms a selection node and if needed a sort node
//
// Arguments: [rst] - Restriction tree describing the query
// [states] - global state info
// [plist] - friendly property name list
//
// Returns: A pointer to a commandtree node
//
// History: 9-4-95 SitaramR Created
//
//----------------------------------------------------------------------------
CDbCmdTreeNode *FormTableNode(
CDbCmdTreeNode & rst,
CCatState & states,
IColumnMapper * plist )
{
//
// First create a selection node and append the restriction tree to it
//
XPtr<CDbSelectNode> xSelect( new CDbSelectNode() );
if ( xSelect.IsNull() || !xSelect->IsValid() )
THROW( CException( STATUS_NO_MEMORY ) );
//
// Clone the restriction and use it.
//
CDbCmdTreeNode * pExpr = rst.Clone();
if ( 0 == pExpr )
{
THROW( CException( STATUS_NO_MEMORY ) );
}
//
// Now make the restriction a child of the selection node.
//
xSelect->SetRestriction( pExpr );
XPtr<CDbCmdTreeNode> xTable;
unsigned int cSortProp = states.NumberOfSortProps();
if ( cSortProp > 0 )
{
CDbSortNode * pSort = new CDbSortNode();
if ( 0 == pSort )
{
THROW( CException( STATUS_NO_MEMORY ) );
}
XPtr<CDbCmdTreeNode> xSort( pSort );
for( unsigned i = 0; i < cSortProp; i++ )
{
WCHAR const * wcsName;
SORTDIR sd;
states.GetSortProp( i,
&wcsName,
&sd );
DBID *pdbid = 0;
if( FAILED(plist->GetPropInfoFromName( wcsName,
&pdbid,
0,
0 )) )
THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_SORT ) );
//
// Add the sort column.
//
CDbColId *pprop = (CDbColId *)pdbid;
if ( !pSort->AddSortColumn( *pprop,
(sd == SORT_DOWN) ? TRUE : FALSE,
states.GetLocale()))
{
THROW( CException( STATUS_NO_MEMORY ) );
}
}
if ( pSort->AddTable( xSelect.GetPointer() ) )
xSelect.Acquire();
else
{
THROW( CException( STATUS_NO_MEMORY ) );
}
xTable.Set( xSort.Acquire() );
}
else
xTable.Set( xSelect.Acquire() );
return xTable.Acquire();
}
//+---------------------------------------------------------------------------
//
// Function: FormQueryTree
//
// Synopsis: Forms a query tree consisting of the projection nodes,
// selection node, sort node(s) and the restriction tree.
//
// Arguments: [rst] - Restriction tree describing the query
// [states] - global state info
// [plist] - friendly property name list
//
// Returns: A pointer to the query tree. It is the responsibility of
// the caller to later free it.
//
// History: 6-20-95 srikants Created
//
//----------------------------------------------------------------------------
CDbCmdTreeNode * FormQueryTree( CDbCmdTreeNode & rst,
CCatState & states,
IColumnMapper * plist,
BOOL fAddBmkCol,
BOOL fAddRankForBrowse )
{
CDbCmdTreeNode *pTable = FormTableNode( rst, states, plist );
XPtr<CDbCmdTreeNode> xTable( pTable );
XPtr<CDbCmdTreeNode> xQuery;
unsigned cCategories = states.NumberOfCategories();
if ( cCategories > 0 )
{
//
// First create nesting node for the base table
//
CDbNestingNode *pNestNodeBase = new CDbNestingNode;
if ( pNestNodeBase == 0 )
THROW ( CException( STATUS_NO_MEMORY ) );
XPtr<CDbCmdTreeNode> xNestNodeBase( pNestNodeBase );
BOOL fNeedPath = TRUE;
BOOL fNeedRank = fAddRankForBrowse;
//
// Next add all the columns in the state.
//
CDbColId * pprop = 0;
DBID *pdbid = 0;
unsigned int cCol = states.NumberOfColumns();
for ( unsigned int i = 0; i < cCol; i++ )
{
if( FAILED(plist->GetPropInfoFromName( states.GetColumn( i ),
&pdbid,
0,
0 )) )
THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_OUTPUT ) );
pprop = (CDbColId *)pdbid;
if ( *pprop == psPath )
{
fNeedPath = FALSE;
}
else if ( *pprop == psRank )
{
fNeedRank = FALSE;
}
if ( !pNestNodeBase->AddChildColumn( *pprop ) )
{
THROW( CException( STATUS_NO_MEMORY ) );
}
}
if ( fNeedPath && !pNestNodeBase->AddChildColumn( psPath ) )
{
THROW( CException( STATUS_NO_MEMORY ) );
}
if ( fNeedRank && !pNestNodeBase->AddChildColumn( psRank ) )
{
THROW( CException( STATUS_NO_MEMORY ) );
}
//
// Add categories to the output column
//
for ( i = 0; i < cCategories; i++ )
{
//
// We need to ensure that we don't add categories that have already been
// added above. The following test can be speeded up from O( i*j ) to O( i+j ),
// but the the number of categories and the number of columns are usually very small.
//
BOOL fFound = FALSE;
for ( unsigned j=0; j<states.NumberOfColumns(); j++ )
{
if ( _wcsicmp( states.GetCategory(i), states.GetColumn( j ) ) == 0 )
{
fFound = TRUE;
break;
}
}
if ( !fFound )
{
if( FAILED(plist->GetPropInfoFromName( states.GetCategory( i ),
&pdbid,
0,
0 )) )
THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_CATEGORIZATION ) );
pprop = (CDbColId *)pdbid;
if ( !pNestNodeBase->AddChildColumn( *pprop ) )
THROW( CException( STATUS_NO_MEMORY ) );
}
}
if ( pNestNodeBase->AddTable( xTable.GetPointer() ) )
xTable.Acquire();
else
{
THROW( CException( STATUS_NO_MEMORY ) );
}
if ( FAILED(plist->GetPropInfoFromName( states.GetCategory( cCategories - 1 ),
&pdbid,
0,
0 )) )
THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_OUTPUT ) );
pprop = (CDbColId *)pdbid;
if ( !pNestNodeBase->AddGroupingColumn( *pprop ) )
THROW( CException( STATUS_NO_MEMORY ) );
if ( !pNestNodeBase->AddParentColumn( *pprop ) )
THROW( CException( STATUS_NO_MEMORY ) );
if ( !pNestNodeBase->AddParentColumn( psBookmark ) )
THROW( CException( STATUS_NO_MEMORY ) );
//
// Now create the nesting nodes for remaining categories, if any
//
XPtr<CDbCmdTreeNode> xCategChild( xNestNodeBase.Acquire() );
for ( int j=cCategories-2; j>=0; j-- )
{
if ( FAILED(plist->GetPropInfoFromName( states.GetCategory( j ),
&pdbid,
0,
0 )) )
{
THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_OUTPUT ) );
}
pprop = (CDbColId *)pdbid;
CDbNestingNode *pCategParent = new CDbNestingNode;
if ( pCategParent == 0 )
THROW( CException( STATUS_NO_MEMORY ) );
XPtr<CDbCmdTreeNode> xCategParent( pCategParent );
if ( pCategParent->AddTable( xCategChild.GetPointer() ) )
xCategChild.Acquire();
else
{
THROW( CException( STATUS_NO_MEMORY ) );
}
if ( !pCategParent->AddGroupingColumn( *pprop ) )
THROW( CException( STATUS_NO_MEMORY ) );
if ( !pCategParent->AddParentColumn( *pprop ) )
THROW( CException( STATUS_NO_MEMORY ) );
if ( !pCategParent->AddParentColumn( psBookmark ) )
THROW( CException( STATUS_NO_MEMORY ) );
xCategChild.Set( xCategParent.Acquire() );
}
xQuery.Set( xCategChild.Acquire() );
}
else
{
//
// Create the projection node
//
CDbProjectNode * pProject = new CDbProjectNode();
if ( 0 == pProject )
{
THROW( CException( STATUS_NO_MEMORY ) );
}
XPtr<CDbCmdTreeNode> xProject( pProject );
//
// Add the selection/sort node
//
if ( pProject->AddTable( xTable.GetPointer() ) )
xTable.Acquire();
else
{
THROW( CException( STATUS_NO_MEMORY ) );
}
//
// We query with two additional, but hidden, columns: path and rank,
// because this information is needed by the browser (via Clipboard).
// Care is taken in CRows::DisplayHeader and CRows::DisplayRows so that
// the hidden columns are not displayed to the user
//
BOOL fNeedPath = TRUE;
BOOL fNeedRank = fAddRankForBrowse;
//
// Next add all the columns in the state.
//
unsigned int cCol = states.NumberOfColumns();
for ( unsigned int i = 0; i < cCol; i++ )
{
CDbColId * pprop = 0;
DBID *pdbid = 0;
if( FAILED(plist->GetPropInfoFromName( states.GetColumn( i ),
&pdbid,
0,
0 )) )
THROW( CQueryException( QUERY_UNKNOWN_PROPERTY_FOR_OUTPUT ) );
pprop = (CDbColId *)pdbid;
if ( *pprop == psPath )
{
fNeedPath = FALSE;
}
else if ( *pprop == psRank )
{
fNeedRank = FALSE;
}
if ( !pProject->AddProjectColumn( *pprop ) )
{
THROW( CException( STATUS_NO_MEMORY ) );
}
}
if ( fNeedPath && !pProject->AddProjectColumn( psPath ) )
{
THROW( CException( STATUS_NO_MEMORY ) );
}
if ( fNeedRank && !pProject->AddProjectColumn( psRank ) )
{
THROW( CException( STATUS_NO_MEMORY ) );
}
if (fAddBmkCol && !pProject->AddProjectColumn( psBookmark ) )
{
THROW( CException( STATUS_NO_MEMORY ) );
}
xQuery.Set( xProject.Acquire() );
}
CDbTopNode *pTop = 0;
if ( states.IsMaxResultsSpecified() )
{
//
// Use the top node to set a cap on the number of query results
//
pTop = new CDbTopNode();
if ( pTop == 0 )
THROW( CException( STATUS_NO_MEMORY ) );
pTop->SetChild( xQuery.Acquire() );
pTop->SetValue( states.GetMaxResults() );
}
//
// Set FirstRows here
//
if ( states.IsFirstRowsSpecified() )
{
CDbFirstRowsNode *pFR = new CDbFirstRowsNode();
if ( pFR == 0 )
THROW( CException( STATUS_NO_MEMORY ) );
CDbCmdTreeNode *pChild = pTop ? pTop : xQuery.Acquire();
pFR->SetChild( pChild );
pFR->SetValue( states.GetFirstRows() );
return pFR;
}
if ( 0 != pTop )
return pTop;
return xQuery.Acquire();
}
//+---------------------------------------------------------------------------
//
// Function: SetScopePropertiesNoThrow
//
// Synopsis: Sets rowset properties pertaining to scope on command object.
//
// Arguments: [pCmd] -- Command object
// [cDirs] -- Number of elements in following arrays
// [apDirs] -- Array of scopes
// [aulFlags] -- Array of flags (depths)
// [apCats] -- Array of catalogs
// [apMachines] -- Array of machines
//
// Notes: Either apDirs and aulFlags, or apCats and apMachines may be
// NULL.
//
// History: 03-Mar-1997 KyleP Created
// 14-May-1997 mohamedn use real BSTRs
// 19-May-1997 KrishnaN Not throwing exceptions.
//
//----------------------------------------------------------------------------
SCODE SetScopePropertiesNoThrow( ICommand * pCmd,
unsigned cDirs,
WCHAR const * const * apDirs,
ULONG const * aulFlags,
WCHAR const * const * apCats,
WCHAR const * const * apMachines )
{
SCODE sc = S_OK;
TRY
{
XInterface<ICommandProperties> xCmdProp;
sc = pCmd->QueryInterface( IID_ICommandProperties, xCmdProp.GetQIPointer() );
if ( FAILED( sc ) )
return sc;
//
// It's expensive to convert all of these to BSTRs, but we have
// to since our public API just takes regular strings.
//
CDynArrayInPlace<XBStr> aMachines(cDirs);
CDynArrayInPlace<XBStr> aCatalogs(cDirs);
CDynArrayInPlace<XBStr> aScopes(cDirs);
unsigned i;
//
// init array of BSTRs of machines
//
if ( 0 != apMachines)
{
for ( i = 0; i < cDirs; i++ )
{
XBStr xBstr;
xBstr.SetText( (WCHAR *)apMachines[i]);
aMachines.Add(xBstr,i);
xBstr.Acquire();
}
}
//
// init array of BSTRs of catalogs
//
if ( 0 != apCats)
{
for ( i = 0; i < cDirs; i++ )
{
XBStr xBstr;
xBstr.SetText( (WCHAR *)apCats[i]);
aCatalogs.Add(xBstr,i);
xBstr.Acquire();
}
}
//
// init array of BSTRs of scopes
//
if ( 0 != apDirs)
{
for ( i = 0; i < cDirs; i++ )
{
XBStr xBstr;
xBstr.SetText( (WCHAR *)apDirs[i]);
aScopes.Add(xBstr,i);
xBstr.Acquire();
}
}
SAFEARRAY saScope = { 1, // Dimension
FADF_AUTO | FADF_BSTR, // Flags: on stack, contains BSTRs
sizeof(BSTR), // Size of an element
1, // Lock count. 1 for safety.
(void *) aScopes.GetPointer(),// The data
{ cDirs, 0 } }; // Bounds (element count, low bound)
SAFEARRAY saDepth = { 1, // Dimension
FADF_AUTO, // Flags: on stack
sizeof(LONG), // Size of an element
1, // Lock count. 1 for safety.
(void *)aulFlags, // The data
{ cDirs, 0 } }; // Bounds (element count, low bound)
SAFEARRAY saCatalog = { 1, // Dimension
FADF_AUTO | FADF_BSTR, // Flags: on stack, contains BSTRs
sizeof(BSTR), // Size of an element
1, // Lock count. 1 for safety.
(void *) aCatalogs.GetPointer(), // The data
{ cDirs, 0 } }; // Bounds (element count, low bound)
SAFEARRAY saMachine = { 1, // Dimension
FADF_AUTO | FADF_BSTR, // Flags: on stack, contains BSTRs
sizeof(BSTR), // Size of an element
1, // Lock count. 1 for safety.
(void *) aMachines.GetPointer(), // The data
{ cDirs, 0 } }; // Bounds (element count, low bound)
DBPROP aScopeProps[2] = {
{ DBPROP_CI_INCLUDE_SCOPES , 0, DBPROPSTATUS_OK, {0, DBKIND_GUID_PROPID, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (ULONG_PTR)&saScope } },
{ DBPROP_CI_DEPTHS , 0, DBPROPSTATUS_OK, {0, DBKIND_GUID_PROPID, 0}, { VT_I4 | VT_ARRAY, 0, 0, 0, (ULONG_PTR)&saDepth } } };
DBPROP aCatalogProps[1] = {
{ DBPROP_CI_CATALOG_NAME , 0, DBPROPSTATUS_OK, {0, DBKIND_GUID_PROPID, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (ULONG_PTR)&saCatalog } } };
DBPROP aMachineProps[1] = {
{ DBPROP_MACHINE , 0, DBPROPSTATUS_OK, {0, DBKIND_GUID_PROPID, 0}, { VT_BSTR | VT_ARRAY, 0, 0, 0, (ULONG_PTR)&saMachine } } };
DBPROPSET aAllPropsets[3] = {
{ aScopeProps, 2, DBPROPSET_FSCIFRMWRK_EXT } ,
{ aCatalogProps, 1, DBPROPSET_FSCIFRMWRK_EXT } ,
{ aMachineProps, 1, DBPROPSET_CIFRMWRKCORE_EXT } };
DBPROPSET * pPropsets = 0;
ULONG cPropsets = 0;
if ( 0 != apDirs )
{
pPropsets = &aAllPropsets[0];
cPropsets = 1;
}
else
{
pPropsets = &aAllPropsets[1];
}
if ( 0 != apCats && 0 != apMachines )
{
cPropsets += 2;
}
sc = xCmdProp->SetProperties( cPropsets, pPropsets );
}
CATCH(CException, e)
{
sc = GetOleError(e);
}
END_CATCH
return sc;
}
//+---------------------------------------------------------------------------
//
// Function: SetScopeProperties
//
// Synopsis: Sets rowset properties pertaining to scope on command object.
//
// Arguments: [pCmd] -- Command object
// [cDirs] -- Number of elements in following arrays
// [apDirs] -- Array of scopes
// [aulFlags] -- Array of flags (depths)
// [apCats] -- Array of catalogs
// [apMachines] -- Array of machines
//
// History: 03-Mar-1997 KyleP Created
//
//----------------------------------------------------------------------------
void SetScopeProperties( ICommand * pCmd,
unsigned cDirs,
WCHAR const * const * apDirs,
ULONG const * aulFlags,
WCHAR const * const * apCats,
WCHAR const * const * apMachines )
{
SCODE sc = SetScopePropertiesNoThrow(pCmd, cDirs, apDirs,
aulFlags, apCats, apMachines);
if (FAILED(sc))
THROW( CException(sc) );
}