//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1996-2000. // // File: monarch.cxx // // Contents: Public interfaces to Index Server // // History: 24 Jan 1997 Alanw Created // //---------------------------------------------------------------------------- #include "pch.cxx" #pragma hdrstop #include #include #include #include //+--------------------------------------------------------------------------- // // Function: AddToPropertyList, private // // Synopsis: Adds an array of properties to a property list // // Arguments: [PropertyList] -- destination for the props // [cProperties] -- # of properties to add // [pProperties] -- source of props // [lcid] -- Locale (used for uppercasing) // // History: 21 Jul 1997 dlee Created // //---------------------------------------------------------------------------- void AddToPropertyList( CLocalGlobalPropertyList & PropertyList, ULONG cProperties, CIPROPERTYDEF * pProperties, LCID lcid ) { if ( ( 0 != cProperties ) && ( 0 == pProperties ) ) THROW( CException( E_INVALIDARG ) ); XGrowable xTemp; for ( unsigned i = 0; i < cProperties; i++ ) { // // Uppercase the friendly name. Done at this level of code to // optimize other property lookup paths. // int cc = wcslen( pProperties[i].wcsFriendlyName ) + 1; xTemp.SetSize( cc + cc/2 ); int ccOut = LCMapString( lcid, LCMAP_UPPERCASE, pProperties[i].wcsFriendlyName, cc, xTemp.Get(), xTemp.Count() ); Win4Assert( 0 != ccOut ); Win4Assert( 0 == xTemp[ccOut-1] ); if ( 0 == ccOut ) THROW( CException() ); XPtr xEntry; // // Did the string change? // if ( ccOut == cc && RtlEqualMemory( pProperties[i].wcsFriendlyName, xTemp.Get(), cc*sizeof(WCHAR) ) ) { xEntry.Set( new CPropEntry( pProperties[i].wcsFriendlyName, 0, (DBTYPE) pProperties[i].dbType, pProperties[i].dbCol ) ); } else { XPtrST xFName( new WCHAR[ccOut] ); RtlCopyMemory( xFName.GetPointer(), xTemp.Get(), ccOut * sizeof(WCHAR) ); xEntry.Set( new CPropEntry( xFName, (DBTYPE) pProperties[i].dbType, pProperties[i].dbCol ) ); } // // Add new property to list. // PropertyList.AddEntry( xEntry.GetPointer(), 0 ); xEntry.Acquire(); } } //AddToPropertyList //+--------------------------------------------------------------------------- // // Function: CITextToSelectTree, public // // Synopsis: Converts a Tripoli query string into a DBCOMMANDTREE // // Arguments: [pwszRestriction] - input query string // [ppTree] - output command tree // [cProperties] - number of extension properties // [pProperties] - pointer to extension property array // // History: 29 Oct 1996 Alanw Created // //---------------------------------------------------------------------------- SCODE CITextToSelectTree( WCHAR const * pwszRestriction, DBCOMMANDTREE * * ppTree, ULONG cProperties, CIPROPERTYDEF * pProperties, LCID LocaleID ) { return CITextToSelectTreeEx( pwszRestriction, ISQLANG_V1, ppTree, cProperties, pProperties, LocaleID ); } //CITextToSelectTree //+--------------------------------------------------------------------------- // // Function: CITextToFullTree // // Synopsis: Forms a DBCOMMANDTREE from the given restriction, output // columns and sort columns. // // Arguments: [pwszRestriction] - Input query string in "Triplish" // [pwszColumns] - List of comma separated output columns. // [pwszSortColumns] - sort specification, may be NULL // [pwszGrouping] - grouping specification, may be NULL // [ppTree] - [out] The DBCOMMANDTREE representing the // query. // [cProperties] - [in] Number of properties in pProperties // [pProperties] - [in] List of custom properties // [LocaleID] - [in] The locale for query parsing // // Returns: S_OK if successful; Error code otherwise // // History: 3-03-97 srikants Created // //---------------------------------------------------------------------------- SCODE CITextToFullTree( WCHAR const * pwszRestriction, WCHAR const * pwszColumns, WCHAR const * pwszSortColumns, WCHAR const * pwszGrouping, DBCOMMANDTREE * * ppTree, ULONG cProperties, CIPROPERTYDEF * pProperties, LCID LocaleID ) { return CITextToFullTreeEx( pwszRestriction, ISQLANG_V1, pwszColumns, pwszSortColumns, pwszGrouping, ppTree, cProperties, pProperties, LocaleID ); } //CITextToFullTree //+--------------------------------------------------------------------------- // // Function: CITextToSelectTreeEx, public // // Synopsis: Converts a Tripoli query string into a DBCOMMANDTREE // // Arguments: [pwszRestriction] - input query string // [ulDialect] - dialect of triplish // [ppTree] - output command tree // [cProperties] - number of extension properties // [pProperties] - pointer to extension property array // // History: 29 Oct 1996 Alanw Created // //---------------------------------------------------------------------------- SCODE CITextToSelectTreeEx( WCHAR const * pwszRestriction, ULONG ulDialect, DBCOMMANDTREE * * ppTree, ULONG cProperties, CIPROPERTYDEF * pProperties, LCID LocaleID ) { if ( 0 == pwszRestriction || 0 == *pwszRestriction || 0 == ppTree ) return E_INVALIDARG; if ( ISQLANG_V1 != ulDialect && ISQLANG_V2 != ulDialect ) return E_INVALIDARG; SCODE sc = S_OK; CTranslateSystemExceptions translate; TRY { LCID lcid = LocaleID; if (lcid == -1) lcid = GetSystemDefaultLCID(); XInterface xPropertyList(new CLocalGlobalPropertyList(lcid)); AddToPropertyList( xPropertyList.GetReference(), cProperties, pProperties, LocaleID ); // // Setup the variables needed to execute this query; including: // // CiRestriction // CiMaxRecordsInResultSet // CiSort // // ixssoDebugOut(( DEB_TRACE, "ExecuteQuery:\n" )); // ixssoDebugOut(( DEB_TRACE, "\tCiRestriction = '%ws'\n", pwszRestriction )); *ppTree = GetStringDbRestriction( pwszRestriction, ulDialect, xPropertyList.GetPointer(), lcid )->CastToStruct(); } CATCH ( CException, e ) { sc = GetScodeError( e ); } END_CATCH; return sc; } //CITextToSelectTreeEx //+--------------------------------------------------------------------------- // // Function: CITextToFullTreeEx // // Synopsis: Forms a DBCOMMANDTREE from the given restriction, output // columns and sort columns. // // Arguments: [pwszRestriction] - Input query string in "Triplish" // [ulDialect] - Dialect of Triplish // [pwszColumns] - List of comma separated output columns. // [pwszSortColumns] - sort specification, may be NULL // [pwszGrouping] - grouping specification, may be NULL // [ppTree] - [out] The DBCOMMANDTREE representing the // query. // [cProperties] - [in] Number of properties in pProperties // [pProperties] - [in] List of custom properties // [LocaleID] - [in] The locale for query parsing // // Returns: S_OK if successful; Error code otherwise // // History: 3-03-97 srikants Created // //---------------------------------------------------------------------------- SCODE CITextToFullTreeEx( WCHAR const * pwszRestriction, ULONG ulDialect, WCHAR const * pwszColumns, WCHAR const * pwszSortColumns, WCHAR const * pwszGrouping, DBCOMMANDTREE * * ppTree, ULONG cProperties, CIPROPERTYDEF * pProperties, LCID LocaleID ) { if ( 0 == ppTree || 0 == pwszRestriction || 0 == *pwszRestriction || 0 == pwszColumns || 0 == *pwszColumns ) return E_INVALIDARG; if ( ISQLANG_V1 != ulDialect && ISQLANG_V2 != ulDialect ) return E_INVALIDARG; SCODE sc = S_OK; CTranslateSystemExceptions translate; TRY { LCID lcid = LocaleID; if (lcid == -1) lcid = GetSystemDefaultLCID(); XInterface xPropertyList(new CLocalGlobalPropertyList(lcid)); AddToPropertyList( xPropertyList.GetReference(), cProperties, pProperties, LocaleID ); CTextToTree textToTree( pwszRestriction, ulDialect, pwszColumns, xPropertyList.GetPointer(), lcid, pwszSortColumns, pwszGrouping ); *ppTree = textToTree.FormFullTree(); } CATCH ( CException, e ) { sc = GetScodeError( e ); } END_CATCH; return sc; } //CITextToFullTreeEx //+--------------------------------------------------------------------------- // // Function: CIBuildQueryNode // // Synopsis: Build a simple restriction node. // // Arguments: [wcsProperty] - Target property // [dwOperator] - Enumerated operator // [pvarPropertyValue] - property value // [ppTree] - [out] The DBCOMMANDTREE representing the // simple restriction. // [cProperties] - # of props in the pProperties array // [pProperties] - Array of properties // [LocaleId] - Locale to use. // // Returns: S_OK if successful; Error code otherwise // // History: July 22 1997 KrishnaN Created // //---------------------------------------------------------------------------- SCODE CIBuildQueryNode(WCHAR const *wcsProperty, DBCOMMANDOP dbOperator, PROPVARIANT const *pvarPropertyValue, DBCOMMANDTREE ** ppTree, ULONG cProperties, CIPROPERTYDEF const * pProperties, // Can be 0. LCID LocaleID) { if (0 == pvarPropertyValue || 0 == ppTree || (cProperties > 0 && 0 == pProperties)) return E_INVALIDARG; XInterface xPropertyList; SCODE sc = S_OK; *ppTree = 0; CTranslateSystemExceptions translate; TRY { xPropertyList.Set( new CLocalGlobalPropertyList( LocaleID ) ); // // No need to add to prop list if this is dbop_content. // CITextToSelectTree does that. // if (pProperties && dbOperator != DBOP_content) { AddToPropertyList( xPropertyList.GetReference(), cProperties, (CIPROPERTYDEF *)pProperties, LocaleID ); } DBID *pdbid = 0; CDbColId *pcdbCol = 0; DBTYPE ptype; // dbop_content prop info is taken care in citexttoselecttree call if (dbOperator != DBOP_content) { if( FAILED(xPropertyList->GetPropInfoFromName( wcsProperty, &pdbid, &ptype, 0 )) ) THROW( CParserException( QPARSE_E_NO_SUCH_PROPERTY ) ); } pcdbCol = (CDbColId *)pdbid; switch (dbOperator) { // // The caller passes a chunk of text. Pass it // to the parser and have it build a restriction // for us. // case DBOP_content: { if (pvarPropertyValue->vt != VT_LPWSTR && pvarPropertyValue->vt != (DBTYPE_WSTR|DBTYPE_BYREF)) THROW( CException( E_INVALIDARG ) ); sc = CITextToSelectTree(pvarPropertyValue->pwszVal, ppTree, cProperties, (CIPROPERTYDEF *)pProperties, LocaleID ); break; } // // The caller passes a chunk of text which should be // interpreted as free text. Build a natlang restriction. // case DBOP_content_freetext: { if (pvarPropertyValue->vt != VT_LPWSTR && pvarPropertyValue->vt != (DBTYPE_WSTR|DBTYPE_BYREF)) THROW( CException( E_INVALIDARG ) ); XPtr xNatLangRst( new CDbNatLangRestriction( pvarPropertyValue->pwszVal, *pcdbCol, LocaleID ) ); if ( xNatLangRst.IsNull() || !xNatLangRst->IsValid() ) THROW( CException( E_OUTOFMEMORY ) ); *ppTree = xNatLangRst->CastToStruct(); xNatLangRst.Acquire(); break; } // // Regular expressions and property value queries // case DBOP_like: case DBOP_equal: case DBOP_not_equal: case DBOP_less: case DBOP_less_equal: case DBOP_greater: case DBOP_greater_equal: case DBOP_allbits: case DBOP_anybits: case DBOP_equal_all: case DBOP_not_equal_all: case DBOP_greater_all: case DBOP_greater_equal_all: case DBOP_less_all: case DBOP_less_equal_all: case DBOP_allbits_all: case DBOP_anybits_all: case DBOP_equal_any: case DBOP_not_equal_any: case DBOP_greater_any: case DBOP_greater_equal_any: case DBOP_less_any: case DBOP_less_equal_any: case DBOP_allbits_any: case DBOP_anybits_any: { XPtr xPrpRst( new CDbPropertyRestriction (dbOperator, *(pcdbCol->CastToStruct()), *(CStorageVariant const *)(void *)pvarPropertyValue) ); if ( xPrpRst.IsNull() || !xPrpRst->IsValid() ) THROW( CException( E_OUTOFMEMORY ) ); *ppTree = xPrpRst->CastToStruct(); xPrpRst.Acquire(); break; } default: sc = E_INVALIDARG; break; } } CATCH(CException, e) { sc = GetScodeError( e ); Win4Assert(0 == *ppTree); } END_CATCH return sc; } //CIBuildQueryNode //+--------------------------------------------------------------------------- // // Function: CIBuildQueryTree // // Synopsis: Build a restriction tree from an existing tree (could be empty) // and a newly added node/tree. // // Arguments: [pExistingTree] - Ptr to existing command tree // [dwBoolOp] - Enumerated boolean operator // [cSiblings] - Number of trees to combine at the same level. // [ppSibsToCombine]- Array of sibling tree to combine. // [ppTree] - [out] The DBCOMMANDTREE representing the // combined restriction. // // Returns: S_OK if successful; Error code otherwise // // History: July 22 1997 KrishnaN Created // //---------------------------------------------------------------------------- SCODE CIBuildQueryTree(DBCOMMANDTREE const *pExistingTree, DBCOMMANDOP dbBoolOp, ULONG cSiblings, DBCOMMANDTREE const * const *ppSibsToCombine, DBCOMMANDTREE ** ppTree) { if (0 == cSiblings || 0 == ppTree || 0 == ppSibsToCombine || 0 == *ppSibsToCombine) return E_INVALIDARG; // AND and OR should have at least two operands if ((dbBoolOp == DBOP_and || dbBoolOp == DBOP_or) && 0 == pExistingTree && cSiblings < 2) return E_INVALIDARG; // NOT should have only one operand if (dbBoolOp == DBOP_not && (pExistingTree || cSiblings > 1)) return E_INVALIDARG; *ppTree = 0; SCODE sc = S_OK; CTranslateSystemExceptions translate; TRY { switch(dbBoolOp) { case DBOP_and: case DBOP_or: { CDbBooleanNodeRestriction *pAndOrCombiner = new CDbBooleanNodeRestriction( dbBoolOp ); if (0 == pAndOrCombiner) THROW( CException( E_OUTOFMEMORY ) ); if (pExistingTree) pAndOrCombiner->AppendChild((CDbRestriction *)CDbCmdTreeNode::CastFromStruct(pExistingTree)); for (ULONG i = 0; i < cSiblings; i++) pAndOrCombiner->AppendChild((CDbRestriction *)CDbCmdTreeNode::CastFromStruct(ppSibsToCombine[i])); *ppTree = pAndOrCombiner->CastToStruct(); break; } case DBOP_not: { CDbNotRestriction *pNotCombiner = new CDbNotRestriction((CDbRestriction *) CDbCmdTreeNode::CastFromStruct(ppSibsToCombine[0])); if (0 == pNotCombiner) THROW( CException( E_OUTOFMEMORY ) ); *ppTree = pNotCombiner->CastToStruct(); break; } default: sc = E_INVALIDARG; break; } } CATCH(CException, e) { sc = GetScodeError( e ); Win4Assert(0 == *ppTree); } END_CATCH return sc; } //CIBuildQueryTree //+--------------------------------------------------------------------------- // // Function: CIRestrictionToFullTree // // Synopsis: Forms a DBCOMMANDTREE from the given restriction, output // columns and sort columns. // // Arguments: [pTree] - Input query tree // [pwszColumns] - List of comma separated output columns. // [pwszSortColumns] - sort specification, may be NULL // [pwszGrouping] - grouping specification, may be NULL // [ppTree] - [out] The DBCOMMANDTREE representing the // query. // [cProperties] - [in] Number of properties in pProperties // [pProperties] - [in] List of custom properties // [LocaleID] - [in] The locale for query parsing // // Returns: S_OK if successful; Error code otherwise // // History: 3-03-97 srikants Created // //---------------------------------------------------------------------------- SCODE CIRestrictionToFullTree( DBCOMMANDTREE const *pTree, WCHAR const * pwszColumns, WCHAR const * pwszSortColumns, WCHAR const * pwszGrouping, DBCOMMANDTREE * * ppTree, ULONG cProperties, CIPROPERTYDEF * pProperties, LCID LocaleID ) { if ( 0 == ppTree || 0 == pTree || 0 == pwszColumns || 0 == *pwszColumns ) return E_INVALIDARG; SCODE sc = S_OK; CTranslateSystemExceptions translate; TRY { LCID lcid = LocaleID; if (lcid == -1) lcid = GetSystemDefaultLCID(); XInterface xPropertyList(new CLocalGlobalPropertyList(LocaleID)); AddToPropertyList( xPropertyList.GetReference(), cProperties, pProperties, LocaleID ); CTextToTree RestrictionToTree( pTree, pwszColumns, xPropertyList.GetPointer(), lcid, pwszSortColumns, pwszGrouping ); *ppTree = RestrictionToTree.FormFullTree(); } CATCH ( CException, e ) { sc = GetScodeError( e ); } END_CATCH; return sc; } //CIRestrictionToFullTree //+--------------------------------------------------------------------------- // // Function: CIMakeICommand // // Synopsis: Creates an ICommand // // Arguments: [ppCommand] -- where the ICommand is returned // [cScope] -- # of items in below arrays // [aDepths] -- array of depths // [awcsScope] -- array of scopes // [awcsCat] -- array of catalogs // [awcsMachine] -- array of machines // // Returns: S_OK if successful; Error code otherwise // // History: 6-11-97 dlee Fixed and added header // //---------------------------------------------------------------------------- SCODE CIMakeICommand( ICommand ** ppCommand, ULONG cScope, DWORD const * aDepths, WCHAR const * const * awcsScope, WCHAR const * const * awcsCat, WCHAR const * const * awcsMachine ) { if ( 0 == ppCommand || 0 == aDepths || 0 == awcsScope || 0 == awcsCat || 0 == awcsMachine || 0 == cScope ) return E_INVALIDARG; *ppCommand = 0; SCODE sc = S_OK; CTranslateSystemExceptions translate; TRY { // First get an ICommand object as an IUnknown XInterface xUnk; sc = MakeICommand( xUnk.GetIUPointer(), 0, 0, 0 ); if ( FAILED( sc ) ) THROW( CException( sc ) ); // QI to ICommand XInterface xCommand; sc = xUnk->QueryInterface( IID_ICommand, xCommand.GetQIPointer() ); if ( FAILED( sc ) ) THROW( CException( sc ) ); // SetScopeProperties throws SetScopeProperties( xCommand.GetPointer(), cScope, awcsScope, aDepths, awcsCat, awcsMachine ); *ppCommand = xCommand.Acquire(); } CATCH ( CException, e ) { sc = GetScodeError( e ); } END_CATCH; return sc; } //CIMakeICommand //+--------------------------------------------------------------------------- // // Function: CICreateCommand // // Synopsis: Creates an ICommand // // Arguments: [ppResult] -- where the resulting interface is returned // [pUnkOuter] -- outer unknown // [riid] -- iid of interface to return. Must be // IID_IUnknown unless pUnkOuter == 0 // [pwcsCatalog] -- catalog // [pwcsMachine] -- machine // // Returns: S_OK if successful; Error code otherwise // // History: 6-11-97 dlee Fixed and added header // //---------------------------------------------------------------------------- SCODE CICreateCommand( IUnknown ** ppResult, IUnknown * pUnkOuter, REFIID riid, WCHAR const * pwcsCatalog, WCHAR const * pwcsMachine ) { if ( 0 != pUnkOuter && IID_IUnknown != riid ) return CLASS_E_NOAGGREGATION; if ( 0 == ppResult || 0 == pwcsCatalog || 0 == pwcsMachine ) return E_INVALIDARG; // try to AV *ppResult = 0; SCODE sc = S_OK; CTranslateSystemExceptions translate; TRY { // // First get an ICommand object as an IUnknown // XInterface xUnk; sc = MakeICommand( xUnk.GetIUPointer(), 0, 0, pUnkOuter ); if ( FAILED( sc ) ) THROW( CException( sc ) ); // // QI to the interface requested // if ( IID_IUnknown != riid ) { IUnknown *pUnk; sc = xUnk->QueryInterface( riid, (void **) & pUnk ); if ( FAILED( sc ) ) THROW( CException( sc ) ); xUnk.Free(); xUnk.Set( pUnk ); } // // Set the scope, catalogs, and machines // { // SetScopeProperties throws DWORD dwFlags = QUERY_DEEP; WCHAR const * pwcScope = L"\\"; // // cheezy hack cast, since I can't QI for the ICommand yet // if the outer unknown is specified. Assume MakeICommand // returns an ICommand under the IUnknown. // SetScopeProperties( (ICommand *) xUnk.GetPointer(), 1, &pwcScope, &dwFlags, &pwcsCatalog, &pwcsMachine ); } *ppResult = xUnk.Acquire(); } CATCH ( CException, e ) { // // This is Index Server's function, not OLE-DB's, so don't mask // errors as E_FAIL with GetOleError // sc = GetScodeError( e ); } END_CATCH; return sc; } //CICreateCommand //+--------------------------------------------------------------------------- // // Class: CIPropertyList // // Synopsis: allow access to the default property list used by CITextTo*Tree // // History: 08-Aug-97 alanw Created // //---------------------------------------------------------------------------- class CIPropertyList : public ICiPropertyList { public: CIPropertyList() : _cRef( 1 ) { _xproplist.Set( new CLocalGlobalPropertyList() ); } ~CIPropertyList() { } virtual ULONG STDMETHODCALLTYPE AddRef( ) { return InterlockedIncrement(&_cRef); } virtual ULONG STDMETHODCALLTYPE Release( ) { ULONG uTmp = InterlockedDecrement(&_cRef); if (uTmp == 0) { delete this; return 0; } return uTmp; } virtual BOOL GetPropInfo( WCHAR const * wcsPropName, DBID ** ppPropid, DBTYPE * pPropType, unsigned int * puWidth ) { return (S_OK == _xproplist->GetPropInfoFromName( wcsPropName, ppPropid, pPropType, puWidth )); } virtual BOOL GetPropInfo( DBID const & prop, WCHAR const ** pwcsName, DBTYPE * pPropType, unsigned int * puWidth ) { return (S_OK == _xproplist->GetPropInfoFromId( &prop, (WCHAR **)pwcsName, pPropType, puWidth )); } virtual BOOL EnumPropInfo( ULONG const & iEntry, WCHAR const ** pwcsName, DBID ** ppProp, DBTYPE * pPropType, unsigned int * puWidth ) { return FALSE; // Not implemented because no one needs it. } private: XInterface _xproplist; LONG _cRef; }; //+--------------------------------------------------------------------------- // // Function: CIGetGlobalPropertyList, public // // Synopsis: Gets a reference to the property list used by CITextToSelectTree // // Arguments: [ppPropList] -- where the ICiPropertyList is returned // // Returns: S_OK if successful; Error code otherwise // // History: 08-Aug-97 alanw Created // //---------------------------------------------------------------------------- SCODE CIGetGlobalPropertyList( ICiPropertyList ** ppPropList ) { if ( 0 == ppPropList ) return E_INVALIDARG; *ppPropList = 0; SCODE sc = S_OK; CTranslateSystemExceptions translate; TRY { XPtr xProplist( new CIPropertyList() ); *ppPropList = xProplist.Acquire(); } CATCH ( CException, e ) { sc = GetScodeError( e ); } END_CATCH; return sc; } //CIGetGlobalPropertyList