|
|
//+---------------------------------------------------------------------------
//
// 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) ); }
|