//+--------------------------------------------------------------------------- // // 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 #pragma hdrstop #include #include 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 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 xTable; unsigned int cSortProp = states.NumberOfSortProps(); if ( cSortProp > 0 ) { CDbSortNode * pSort = new CDbSortNode(); if ( 0 == pSort ) { THROW( CException( STATUS_NO_MEMORY ) ); } XPtr 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 xTable( pTable ); XPtr 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 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; jGetPropInfoFromName( 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 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 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 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 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 aMachines(cDirs); CDynArrayInPlace aCatalogs(cDirs); CDynArrayInPlace 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) ); }