//***************************************************************************
//
//   (c) 1999-2001 by Microsoft Corp. All Rights Reserved.
//
//   eseitrtr.cpp
//
//   cvadai     19-Mar-99       Created as prototype for Quasar.
//
//***************************************************************************

#define _ESEIT_CPP_
#pragma warning( disable : 4786 ) // identifier was truncated to 'number' characters in the 
#pragma warning( disable : 4251 ) //  needs to have dll-interface to be used by clients of class

#include "precomp.h"

#include <std.h>
#include <smrtptr.h>
#include <repdrvr.h>
#include <eseitrtr.h>
#include <eseutils.h>
#include <eseobjs.h>
#include <reputils.h>
#include <wbemint.h>
#include <repcache.h>
#include <like.h>
#include <datepart.h>

typedef std::map <DWORD, DWORD> Properties;

//***************************************************************************
//
//  CWmiESEIterator::CWmiESEIterator
//
//***************************************************************************

CWmiESEIterator::CWmiESEIterator()
{
    m_pSession = NULL;
    m_uRefCount = 0;
    m_pConn = NULL;
    m_pToks = NULL;
    m_bFirst = TRUE;
    m_bEnum = FALSE;
    m_bWQL = FALSE;
    m_iStartPos = 0;
    m_iLastPos = 0;
    m_bClasses = FALSE;
}

//***************************************************************************
//
//  CWmiESEIterator::~CWmiESEIterator
//
//***************************************************************************
CWmiESEIterator::~CWmiESEIterator()
{
    Cancel(0);
    if (m_pSession)
        m_pSession->Release();

    delete m_pToks;
}

//***************************************************************************
//
//  CWmiESEIterator::QueryInterface
//
//***************************************************************************

HRESULT STDMETHODCALLTYPE CWmiESEIterator::QueryInterface
        (REFIID riid,
        void __RPC_FAR *__RPC_FAR *ppvObject)
{
    *ppvObject = 0;

    if (IID_IUnknown==riid || IID_IWmiDbIterator==riid )
    {
        *ppvObject = (IWmiDbIterator *)this;
        AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}

//***************************************************************************
//
//  CWmiESEIterator::AddRef
//
//***************************************************************************

ULONG STDMETHODCALLTYPE CWmiESEIterator::AddRef()
{
    InterlockedIncrement((LONG *) &m_uRefCount);
    return m_uRefCount;
}

//***************************************************************************
//
//  CWmiESEIterator::Release
//
//***************************************************************************

ULONG STDMETHODCALLTYPE CWmiESEIterator::Release()
{
    ULONG uNewCount = InterlockedDecrement((LONG *) &m_uRefCount);
    if (0 != uNewCount)
        return uNewCount;
    delete this;
    return WBEM_S_NO_ERROR;
}
//***************************************************************************
//
//  CWmiESEIterator::Cancel
//
//***************************************************************************

HRESULT STDMETHODCALLTYPE CWmiESEIterator::Cancel( 
    /* [in] */ DWORD dwFlags) 
{
    HRESULT hr = WBEM_S_NO_ERROR;

    if (m_pConn)
    {
        if (m_pSession->m_pController)
            ((CWmiDbController *)m_pSession->m_pController)->ConnCache.ReleaseConnection(m_pConn, hr);        
        m_pConn = NULL;
    }       

    if (m_pSession)
        ((CWmiDbSession *)m_pSession)->UnlockDynasties();

    return hr;
}

//***************************************************************************
//
//  CWmiESEIterator::NextBatch
//
//***************************************************************************

HRESULT STDMETHODCALLTYPE CWmiESEIterator::NextBatch( 
    /* [in] */ DWORD dwNumRequested,
    /* [in] */ DWORD dwTimeOutSeconds,
    /* [in] */ DWORD dwFlags,
    /* [in] */ DWORD dwRequestedHandleType,
    /* [in] */ REFIID riid,
    /* [out] */ DWORD __RPC_FAR *pdwNumReturned,
    /* [iid_is][length_is][size_is][out] */ LPVOID __RPC_FAR *ppObjects)
{

    HRESULT hr = WBEM_S_NO_ERROR, hrRet = WBEM_S_NO_ERROR;
    bool bImmediate = !(dwRequestedHandleType & WMIDB_HANDLE_TYPE_SUBSCOPED);

    hr = TestDriverStatus();
    if (FAILED(hr))
        return hr;

    if (!dwNumRequested || !ppObjects)
        return WBEM_E_INVALID_PARAMETER;

    if (dwRequestedHandleType == WMIDB_HANDLE_TYPE_INVALID &&
        riid == IID_IWmiDbHandle)
        return WBEM_E_INVALID_PARAMETER;
   
    if (dwFlags & WMIDB_FLAG_LOOKAHEAD || 
        (riid != IID_IWmiDbHandle &&
         riid != IID_IWbemClassObject &&
         riid != IID__IWmiObject))
        /// UuidCompare(pIIDRequestedInterface, &IID_IWmiDbHandle, NULL) ||
        // UuidCompare(pIIDRequestedInterface, &IID_IWbemClassObject, NULL))
        return WBEM_E_NOT_SUPPORTED;

    // Read the current row, compare it against m_pToks
    // Continue until we run out of rows, or meet the requested number.

    LPWSTR lpKey = NULL;

    try
    {
        SQL_ID dObjectId = 0, dClassId = 0, dScopeId = 0;
        int iNumRetrieved = 0;

        hr = GetFirstMatch(dObjectId, dClassId, dScopeId, &lpKey);
        while (SUCCEEDED(hr) )
        {
            CDeleteMe <wchar_t> d (lpKey);

            hr = ((CWmiDbSession *)m_pSession)->VerifyObjectSecurity(NULL, dObjectId, dClassId, dScopeId, 0, WBEM_ENABLE);
            if (SUCCEEDED(hr))
            {
                if (FAILED(hr = TestDriverStatus()))
                    break;

                if (riid == IID_IWmiDbHandle)
                {                            
                    CWmiDbHandle *pTemp = new CWmiDbHandle;
                    if (pTemp)
                    {
                        ((CWmiDbSession *)m_pSession)->AddRef_Lock();
                        DWORD dwVersion = 0;
                        // Obtain a lock for this object
                        // =============================                      

                        hr = ((CWmiDbController *)m_pSession->m_pController)->LockCache.AddLock(bImmediate, dObjectId, dwRequestedHandleType, pTemp, 
                            dScopeId, dClassId, &((CWmiDbController *)m_pSession->m_pController)->SchemaCache, false,
                            0, 0, &dwVersion);
                        
                        if (FAILED(hr))
                        {
                            delete pTemp;
                            // If they failed to get a handle, what do we do?
                            // Ignore it and continue, I guess.
                            hrRet = WBEM_S_PARTIAL_RESULTS;
                            ppObjects[iNumRetrieved] = NULL;
                            
                        }
                        else
                        {
                            pTemp->m_pSession = m_pSession;
                            pTemp->AddRef();
                            ((CWmiDbController *)m_pSession->m_pController)->AddHandle();
                            pTemp->m_dwVersion = dwVersion;
                            pTemp->m_dwHandleType = dwRequestedHandleType;
                            pTemp->m_dClassId = dClassId;
                            pTemp->m_dObjectId = dObjectId;

                            if (pTemp->m_dClassId == MAPPEDNSCLASSID)
                                pTemp->m_bDefault = FALSE;
                            if (dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR)
                                pTemp->m_bSecDesc = TRUE;

                            pTemp->m_dScopeId = dScopeId;

                            ppObjects[iNumRetrieved] = pTemp;                                                        
                        }
                        iNumRetrieved++;
                    }
                    else
                        hr = WBEM_E_OUT_OF_MEMORY;
                }
                else if (riid == IID_IWbemClassObject ||
                            riid == IID__IWmiObject)
                {
                    IWbemClassObject *pTemp = NULL;
                    DWORD dwVer = 0;

                    if (m_dwOpenTable == OPENTABLE_CLASSMAP)
                    {
                        // If this is a class, we need to populate it on
                        // a different connection, so we don't lose our
                        // pointer into the db.

                        CSQLConnection *pConn = NULL;
                        if (((CWmiDbSession *)m_pSession)->m_pController)
                        {
                            hr = ((CWmiDbController *)((CWmiDbSession *)m_pSession)->m_pController)->ConnCache.GetConnection(&pConn, FALSE, FALSE);
                            if (SUCCEEDED(hr))
                            {
                                hr = ((CWmiDbSession *)m_pSession)->GetObjectData(pConn, dObjectId, dClassId, dScopeId,
                                    0, dwVer, &pTemp, TRUE, lpKey, dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR);
                                
                                if (((CWmiDbSession *)m_pSession)->m_pController)
                                    ((CWmiDbController *)((CWmiDbSession *)m_pSession)->m_pController)->ConnCache.ReleaseConnection(pConn, hr, FALSE);
                            }
                        }
                    }
                    else if (m_dwOpenTable == OPENTABLE_INDEXREF)
                    {
                        CSQLConnection *pConn = NULL;
                        if (((CWmiDbSession *)m_pSession)->m_pController)
                        {
                            hr = ((CWmiDbController *)((CWmiDbSession *)m_pSession)->m_pController)->ConnCache.GetConnection(&pConn, FALSE, FALSE);
                            if (SUCCEEDED(hr))
                            {
                                m_pSession->LoadClassInfo(pConn, dClassId, FALSE);

                                hr = ((CWmiDbSession *)m_pSession)->GetObjectData(pConn, dObjectId, dClassId, dScopeId,
                                    0, dwVer, &pTemp, TRUE, lpKey, dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR);

                                if (((CWmiDbSession *)m_pSession)->m_pController)
                                    ((CWmiDbController *)((CWmiDbSession *)m_pSession)->m_pController)->ConnCache.ReleaseConnection(pConn, hr, FALSE);
                            }
                        }
                    }
                    else
                    {
                        hr = ((CWmiDbSession *)m_pSession)->GetObjectData(m_pConn, dObjectId, dClassId, dScopeId,
                            0, dwVer, &pTemp, TRUE, lpKey, dwFlags & WBEM_FLAG_USE_SECURITY_DESCRIPTOR);

                    }

                    ppObjects[iNumRetrieved] = pTemp;
                    if (FAILED(hr))
                        hrRet = WBEM_S_PARTIAL_RESULTS;
                    else
                        iNumRetrieved++;

                }
            }
            else
                hrRet = WBEM_S_PARTIAL_RESULTS;

            hr = TestDriverStatus();
            if (SUCCEEDED(hr))
            {
                if (m_pSession && ((CWmiDbSession *)m_pSession)->m_pController)
                    ((CWmiDbController *)m_pSession->m_pController)->IncrementHitCount(false);
            }
            else
                break;

            if (iNumRetrieved == dwNumRequested)
                break;

            hr = GetNextMatch(dObjectId, dClassId, dScopeId, &lpKey);
        }

        if (pdwNumReturned)
            *pdwNumReturned = iNumRetrieved;

        // Null out m_pStatus if there are no more results!!!
        if ((hr == WBEM_S_NO_MORE_DATA || !iNumRetrieved) &&
            hr != WBEM_E_SHUTTING_DOWN)
        {
            hrRet = WBEM_S_NO_MORE_DATA;
            Cancel(0);
        }
    }
    catch (...)
    {
        hr = WBEM_E_CRITICAL_ERROR;
    }

    return hrRet;
}

//***************************************************************************
//
//  CWmiESEIterator::GetFirstMatch
//
//***************************************************************************

HRESULT CWmiESEIterator::GetFirstMatch(SQL_ID &dObjectId, SQL_ID &dClassId, SQL_ID &dScopeId,
                                       LPWSTR * lpKey)
{
    HRESULT hr = 0;

    // Loop through the table we have chosen to 
    // scan on, and see if any objects match.

    hr = GetNextMatch(dObjectId, dClassId, dScopeId, lpKey, m_bFirst);
    m_bFirst = FALSE;

    return hr;
}

//***************************************************************************
//
//  CWmiESEIterator::GetNextMatch
//
//***************************************************************************

HRESULT CWmiESEIterator::GetNextMatch(SQL_ID &dObjectId, SQL_ID &dClassId, 
                                      SQL_ID &dScopeId, LPWSTR * lpKey, BOOL bFirst)
{
    HRESULT hr = 0;

    OBJECTMAP oj;
    CLASSMAP cd;
    CONTAINEROBJ co;
    INDEXDATA id;
    REFERENCEPROPERTIES pm;
    DWORD dwType = 0;

    if (lpKey)
        *lpKey = NULL;

    switch(m_dwOpenTable)
    {
    case OPENTABLE_CLASSMAP:
        if (!bFirst)
            hr = GetNext_ClassMap(m_pConn, cd);
        else
            hr = GetClassMapData(m_pConn, ((CESEConnection *)m_pConn)->GetSessionID(), m_tableid, cd);

        while (SUCCEEDED(hr))
        {
            hr = TestDriverStatus();
            if (FAILED(hr))
                break;

            hr = GetFirst_ObjectMap(m_pConn, cd.dClassId, oj);
            
            if (oj.dObjectId != dObjectId && oj.iObjectState != 2)
            {
                if (ObjectMatches(oj.dObjectId, oj.dClassId, oj.dObjectScopeId))
                {
                    dObjectId = oj.dObjectId;
                    dClassId = oj.dClassId;
                    dScopeId = oj.dObjectScopeId;
                    if (lpKey)
                    {
                        if (oj.sObjectKey)
                        {
                            LPWSTR lpNew = new wchar_t[wcslen(oj.sObjectKey)+1];
                            if (lpNew)
                            {
                                wcscpy(lpNew, oj.sObjectKey);
                                *lpKey = lpNew;
                            }
                            else
                                hr = WBEM_E_OUT_OF_MEMORY;
                        }
                    }
                    
                    oj.Clear();
                    break;
                }
            }

            oj.Clear();
            hr = GetNext_ClassMap(m_pConn, cd);
        }
        cd.Clear();

        break;
    case OPENTABLE_OBJECTMAP:
        // If here, the query is too complex to evaluate
        // through indices.  Scan on each participating
        // class.

        if (!bFirst)
            hr = GetNext_ObjectMap(m_pConn, oj);
        else
        {
            hr = GetObjectMapData(m_pConn, ((CESEConnection *)m_pConn)->GetSessionID(), m_tableid, oj);
        }

        while (TRUE)
        {
            while (SUCCEEDED(hr) )
            {
                hr = TestDriverStatus();
                if (FAILED(hr))
                    break;

                if (m_bClasses)
                {
                    if (oj.dClassId != 1)
                    {
                        hr = GetNext_ObjectMap(m_pConn, oj);            
                        continue;
                    }
                }

                if (oj.dObjectId != dObjectId && oj.iObjectState != 2)
                {
                    if (ObjectMatches(oj.dObjectId, oj.dClassId, oj.dObjectScopeId))
                    {
                        dObjectId = oj.dObjectId;
                        dClassId = oj.dClassId;
                        dScopeId = oj.dObjectScopeId;
                        if (lpKey)
                        {
                            if (oj.sObjectKey)
                            {
                                LPWSTR lpNew = new wchar_t[wcslen(oj.sObjectKey)+1];
                                if (lpNew)
                                {
                                    wcscpy(lpNew, oj.sObjectKey);
                                    *lpKey = lpNew;
                                }
                                else
                                    hr = WBEM_E_OUT_OF_MEMORY;
                            }
                        }
                        oj.Clear();
                        break;
                    }
                }
                hr = GetNext_ObjectMap(m_pConn, oj);            
            }
        
            if (!m_bEnum && hr == WBEM_E_NOT_FOUND)
            {
                // See if there is other class criteria
                // We expect each derived class to be
                // listed as separate tokens.

                DWORD dwNumToks = m_pToks->GetNumTokens();
                BOOL bEnd = TRUE;

                for (int i = m_iLastPos+1; i < dwNumToks; i++)
                {
                    ESEToken *pTok = m_pToks->GetToken(i);
                    if (pTok->tokentype == ESE_EXPR_TYPE_EXPR)
                    {
                        ESEWQLToken *pTok2 = (ESEWQLToken *)pTok;
                        if (pTok2->Value.valuetype == ESE_VALUE_TYPE_SYSPROP)
                        {
                            if (pTok2->dClassId)
                            {
                                hr = GetFirst_ObjectMapByClass(m_pConn, pTok2->dClassId, oj);
                                if (SUCCEEDED(hr))
                                {
                                    m_iLastPos = i;
                                    bEnd = FALSE;                                    
                                    break;
                                }
                            }
                        }
                    }
                }

                if (bEnd)
                    break;
            }
            else
                break;
        }

        break;

    case OPENTABLE_INDEXNUMERIC:
    case OPENTABLE_INDEXSTRING:
    case OPENTABLE_INDEXREAL:
    case OPENTABLE_INDEXREF:

        // If here, we should have ANDed criteria
        // only, or an A AND (B OR C) construct.
        // That means we only have to scan once.

        if (m_dwOpenTable == OPENTABLE_INDEXNUMERIC)
            dwType = SQL_POS_INDEXNUMERIC;
        else if (m_dwOpenTable == OPENTABLE_INDEXSTRING)
            dwType = SQL_POS_INDEXSTRING;
        else if (m_dwOpenTable == OPENTABLE_INDEXREAL)
            dwType = SQL_POS_INDEXREAL;
        else if (m_dwOpenTable == OPENTABLE_INDEXREF)
            dwType = SQL_POS_INDEXREF;
        if (m_tableid)
        {
            if (!bFirst)
                hr = GetNext_IndexData(m_pConn, m_tableid, dwType, id);
            else
                hr = GetIndexData(m_pConn, ((CESEConnection *)m_pConn)->GetSessionID(), 
                            m_tableid, dwType, id);
            while (SUCCEEDED(hr))
            {
                hr = TestDriverStatus();
                if (FAILED(hr))
                    break;

                if (id.dObjectId != dObjectId)
                {
                    hr = GetFirst_ObjectMap(m_pConn, id.dObjectId, oj);
                    if ((oj.iObjectState != 2) && ObjectMatches(id.dObjectId, oj.dClassId, oj.dObjectScopeId, &id,
                        NULL, &dObjectId, &dClassId, &dScopeId))
                    {
                        oj.Clear();
                        break;
                    }
                    oj.Clear();
                }
                hr = GetNext_IndexData(m_pConn, m_tableid, dwType, id);
            }
        }
        else
            hr = WBEM_E_INVALID_QUERY;
        break;

    case OPENTABLE_CONTAINEROBJS:
        if (!bFirst)
            hr = GetNext_ContainerObjs(m_pConn, co);
        else
            hr = GetContainerObjsData(m_pConn, ((CESEConnection *)m_pConn)->GetSessionID(), m_tableid, co);
        while (SUCCEEDED(hr))
        {
            hr = TestDriverStatus();
            if (FAILED(hr))
                break;

            if (co.dContaineeId != dObjectId)
            {
                hr = GetFirst_ObjectMap(m_pConn, co.dContaineeId, oj);
                if ((oj.iObjectState != 2) && ObjectMatches(co.dContaineeId, oj.dClassId, oj.dObjectScopeId))
                {
                    dObjectId = oj.dObjectId;
                    dClassId = oj.dClassId;
                    dScopeId = oj.dObjectScopeId;
                    oj.Clear();
                    break;
                }                
                oj.Clear();
            }
            hr = GetNext_ContainerObjs(m_pConn, co);
        }
        break;
    case OPENTABLE_REFPROPS:
        if (!bFirst)
            hr = GetNext_ReferenceProperties(m_pConn, pm);
        else
            hr = GetReferencePropertiesData(m_pConn, ((CESEConnection *)m_pConn)->GetSessionID(), m_tableid, pm);
        while (SUCCEEDED(hr))
        {
            hr = TestDriverStatus();
            if (FAILED(hr))
                break;

            if (pm.dClassId != dObjectId)
            {
                hr = GetFirst_ObjectMap(m_pConn, pm.dClassId, oj);
                if (oj.iObjectState != 2 && ObjectMatches(oj.dObjectId, oj.dClassId, oj.dObjectScopeId, NULL,
                        &pm, &dObjectId, &dClassId, &dScopeId))
                {
                    oj.Clear();
                    break;
                }                
                oj.Clear();
            }
            hr = GetNext_ReferenceProperties(m_pConn, pm);
        }
        break;
    default:
        hr = WBEM_E_NOT_FOUND;
    }

    return hr;
}


//***************************************************************************
//
//  CWmiESEIterator::SysMatch
//
//***************************************************************************

BOOL CWmiESEIterator::SysMatch (SQL_ID dObjectId, SQL_ID dClassId, SQL_ID dScopeId, ESEToken *pToken)
{
    BOOL bRet = FALSE;
    HRESULT hr = WBEM_S_NO_ERROR;
    ESEWQLToken *pTok = (ESEWQLToken *)pToken;

    _bstr_t sName;

    hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetPropertyInfo
                (pTok->dPropertyId, &sName);
    if (SUCCEEDED(hr))
    {
        if (!_wcsicmp(sName, L"__Class"))
        {
            SQL_ID dClass = 0;
            hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetClassID
                (pTok->Value.sValue, dScopeId, dClass);
            if (SUCCEEDED(hr))
            {
                // Compare if class or instance.
                if (dClassId == 1)
                    bRet = (dClass == dObjectId);
                else
                    bRet = (dClass == dClassId);
            }
        }
        else if (!_wcsicmp(sName, L"__SuperClass"))
        {
            CLASSMAP cd;
            SQL_ID dParent = 1, dClass = 1;            
            if (wcslen(pTok->Value.sValue))
            {                    
                hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetClassID
                    (pTok->Value.sValue, dScopeId, dClass);
                if (FAILED(hr))
                {
                    if (m_dwOpenTable != OPENTABLE_CLASSMAP)
                    {
                        hr = GetFirst_ClassMapByName(m_pConn, pTok->Value.sValue, cd);
                        dClass = cd.dClassId;
                        cd.Clear();
                    }
                    else
                        hr = WBEM_E_NOT_FOUND; // If this was going to match, it would be in the cache...
                }
            }
            if (dClassId == 1)
                hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetParentId(
                    dObjectId, dParent);
            else
                hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetParentId(
                    dClassId, dParent);
    
            if (FAILED(hr))
            {                
                if (dClassId == 1)
                {
                    if (m_dwOpenTable == OPENTABLE_CLASSMAP)
                        hr = GetClassMapData(m_pConn, ((CESEConnection *)m_pConn)->GetSessionID(), m_tableid, cd);
                    else
                        hr = GetFirst_ClassMap(m_pConn, dObjectId, cd);
                }
                else
                    hr = GetFirst_ClassMap(m_pConn, dClassId, cd);

                dParent = cd.dSuperClassId;
                cd.Clear();

            }
            bRet = (SUCCEEDED(hr) && (dParent == dClass));
        }
        else if (!_wcsicmp(sName, L"__Derivation"))
        {
            SQL_ID dClass = 0;
            hr =  ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetClassID
                (pTok->Value.sValue, dScopeId, dClass);
            if (SUCCEEDED(hr))
            {
                if (dClassId == 1)
                {
                    if (dObjectId == dClass)
                        bRet = TRUE;
                    else
                        bRet = (BOOL)((CWmiDbController *)m_pSession->m_pController)->
                            SchemaCache.IsDerivedClass(dClass, dObjectId);
                }
                else
                {
                    if (dClass == dClassId)
                        bRet = TRUE;
                    else
                        bRet = (BOOL)((CWmiDbController *)m_pSession->m_pController)->
                            SchemaCache.IsDerivedClass(dClass, dClassId);                          
                }
            }
        }
        else if (!_wcsicmp(sName, L"__Dynasty"))
        {
            SQL_ID dClass = 0;
            hr =  ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetClassID
                (pTok->Value.sValue, dScopeId, dClass);
            if (SUCCEEDED(hr))
            {
                if (dClassId == 1)
                    bRet = (BOOL)((CWmiDbController *)m_pSession->m_pController)->
                            SchemaCache.IsDerivedClass(dClass, dObjectId);
                else
                    bRet = (BOOL)((CWmiDbController *)m_pSession->m_pController)->
                            SchemaCache.IsDerivedClass(dClass, dClassId);      
                if (bRet)
                {
                    SQL_ID dParent = 0;
                    hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetParentId(
                            dClass, dParent);
                    if (SUCCEEDED(hr) && dParent == 1)
                        bRet = TRUE;
                }
            }
        }
        else if (!_wcsicmp(sName, L"__Genus"))
        {
            if (pTok->Value.dValue == 1)
                bRet = (dClassId == 1);
            else
                bRet = (dClassId != 1);
        }
        else if (!_wcsicmp(sName, L"__Server"))
        {
            bRet = (!_wcsicmp(pTok->Value.sValue, m_pSession->m_sMachineName));
        }
        else if (!_wcsicmp(sName, L"__Namespace"))
        {
            bRet = (!_wcsnicmp(pTok->Value.sValue, m_pSession->m_sNamespacePath, wcslen(m_pSession->m_sNamespacePath)));
            if (bRet)
            {
                _bstr_t sName;
                hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetNamespaceName(dScopeId, &sName);
                if (SUCCEEDED(hr))
                {
                    WCHAR *pTemp2 = (LPWSTR)pTok->Value.sValue;
                    pTemp2 += (wcslen(m_pSession->m_sNamespacePath)+1);

                    bRet = (!_wcsicmp(sName, pTemp2));
                }
            }
        }
        else if (!_wcsicmp(sName, L"__Property_Count"))
        {
            Properties props;
            DWORD dwNumProps = 0;
            if (dClassId == 1)
            {                
                hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetPropertyList(dObjectId, props, &dwNumProps);
                if (SUCCEEDED(hr))
                {
                    bRet = (dwNumProps == pTok->Value.dValue);
                }
            }
            else
            {
                hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetPropertyList(dClassId, props, &dwNumProps);
                if (SUCCEEDED(hr))
                {
                    bRet = (dwNumProps == pTok->Value.dValue);
                }
            }

        }
        else if (!_wcsicmp(sName, L"__Path"))
        {
            bRet = TRUE; // post-filter, since we don't know our true path.
        }
        else if (!_wcsicmp(sName, L"__RelPath"))
        {
            OBJECTMAP oj;
            hr = GetObjectMapData(m_pConn, ((CESEConnection *)m_pConn)->GetSessionID(), m_tableid, oj);
            if (SUCCEEDED(hr))
            {
                WCHAR *pPtr = (LPWSTR)oj.sObjectPath;
                WCHAR *pLast = NULL;
                while (pPtr && *pPtr)
                {
                    if (*pPtr == L':')
                        pLast = pPtr;

                    pPtr++;
                }
                if (pLast)
                    pLast++;
                else
                    pLast = (LPWSTR)pTok->Value.sValue;

                if (pLast)
                    bRet = (!_wcsicmp(pTok->Value.sValue, pLast));
                else
                    bRet = FALSE;

            }
            oj.Clear();
        }
        else 
        {
            bRet = FALSE; // Others not supported.
        }
    }

    // We only support equal and not equal for system properties.

    if (SUCCEEDED(hr) && pTok->optype == WQL_TOK_NE)
        bRet = !bRet;

    return bRet;
}

//***************************************************************************
//
//  Match helper functions
//
//***************************************************************************

BOOL MatchNumeric (SQL_ID dLeft, SQL_ID dRight, DWORD dwOp, SQL_ID dThird=0)
{
    BOOL bRet = FALSE;
    switch(dwOp)
    {
        case WQL_TOK_BETWEEN:
            bRet = (dLeft >= dRight);
            if (bRet)
                bRet = (dRight >= dThird);
            break;
        case WQL_TOK_EQ:
            bRet = (dLeft == dRight);
            break;
        case WQL_TOK_GT:
            bRet = (dLeft > dRight);
            break;
        case WQL_TOK_GE:
            bRet = (dLeft >= dRight);
            break;
        case WQL_TOK_LT:
            bRet = (dLeft < dRight);
            break;
        case WQL_TOK_LE:
            bRet = (dLeft <= dRight);
            break;
        case WQL_TOK_NE:
            bRet = (dLeft != dRight);
            break;
    }

    return bRet;
}

BOOL MatchString (LPWSTR lpLeft, LPWSTR lpRight, DWORD dwOp, LPWSTR lpThird=0)
{
    BOOL bRet = FALSE;

    if (!lpLeft || !lpRight)
        return FALSE;

    switch(dwOp)
    {
        case WQL_TOK_BETWEEN:
            bRet = (_wcsicmp(lpRight, lpLeft) >= 0) ? TRUE: FALSE;
            if (bRet)
                bRet = (_wcsicmp(lpRight, lpThird) >= 0)? TRUE: FALSE;
            break;
        case WQL_TOK_LIKE:
            {
                CLike c (lpRight);
                bRet = c.Match(lpLeft);
            }
            break;
        case WQL_TOK_NOT_LIKE:
            {
                CLike c (lpRight);
                bRet = !(c.Match(lpLeft));
            }
            break;
        case WQL_TOK_EQ:
            bRet = (!_wcsicmp(lpLeft, lpRight));               
            break;
        case WQL_TOK_GT:
            bRet = (_wcsicmp(lpLeft, lpRight) > 0 ? TRUE: FALSE);
            break;
        case WQL_TOK_GE:
            bRet = (_wcsicmp(lpLeft, lpRight) >= 0 ? TRUE: FALSE);
            break;
        case WQL_TOK_LT:
            bRet = (_wcsicmp(lpLeft, lpRight) < 0 ? TRUE: FALSE);
            break;
        case WQL_TOK_LE:
            bRet = (_wcsicmp(lpLeft, lpRight) <= 0 ? TRUE: FALSE);
            break;
        case WQL_TOK_NE:
            bRet = (_wcsicmp(lpLeft, lpRight));
            break;
    }

    return bRet;
}

BOOL MatchDouble (double dLeft, double dRight, DWORD dwOp, double dThird=0)
{
    BOOL bRet = FALSE;
    switch(dwOp)
    {
        case WQL_TOK_BETWEEN:
            bRet = (dRight >= dLeft);
            if (bRet)
                bRet = (dLeft >= dThird);
            break;
        case WQL_TOK_EQ:
            bRet = (dLeft == dRight);
            break;
        case WQL_TOK_GT:
            bRet = (dLeft > dRight);
            break;
        case WQL_TOK_GE:
            bRet = (dLeft >= dRight);
            break;
        case WQL_TOK_LT:
            bRet = (dLeft < dRight);
            break;
        case WQL_TOK_LE:
            bRet = (dLeft <= dRight);
            break;
        case WQL_TOK_NE:
            bRet = (dLeft != dRight);
            break;
    }
    return bRet;
}

SQL_ID GetDatePart(DWORD dwFunc, LPWSTR lpValue)
{
    int dValue = 0;
    HRESULT hr = 0;
    CDatePart dp;

    dp.SetDate(lpValue);

    switch(dwFunc)
    {
    case ESE_FUNCTION_DATEPART_MONTH:
        hr = dp.GetPart(DATEPART_MONTH, &dValue);                           
        break;
    case ESE_FUNCTION_DATEPART_YEAR:
        hr = dp.GetPart(DATEPART_YEAR, &dValue);
        break;
    case ESE_FUNCTION_DATEPART_DAY:
        hr = dp.GetPart(DATEPART_DAY, &dValue);
        break;
    case ESE_FUNCTION_DATEPART_HOUR:
        hr = dp.GetPart(DATEPART_HOUR, &dValue);
        break;
    case ESE_FUNCTION_DATEPART_MINUTE:
        hr = dp.GetPart(DATEPART_MINUTE, &dValue);
        break;
    case ESE_FUNCTION_DATEPART_SECOND:
        hr = dp.GetPart(DATEPART_SECOND, &dValue);
        break;
    case ESE_FUNCTION_DATEPART_MILLISECOND:
        hr = dp.GetPart(DATEPART_MILLISECOND, &dValue);
        break;
    default:
        break;
    }

    if (FAILED(hr))
        dValue = -1;
    
    return dValue;
}

//***************************************************************************
//
//  CWmiESEIterator::PropMatch
//
//***************************************************************************

BOOL CWmiESEIterator::PropMatch(CLASSDATA cd, CLASSDATA cd2, ESEWQLToken *pToken)
{
    BOOL bRet = FALSE;

    SQL_ID dValue = 0, dCompValue = 0;

    if (pToken->Value.dwFunc ||
        pToken->CompValue.dwFunc)
    {
        if (cd.sPropertyStringValue)
            dValue = GetDatePart(pToken->Value.dwFunc, cd.sPropertyStringValue);
        if (cd2.sPropertyStringValue)
            dCompValue = GetDatePart(pToken->CompValue.dwFunc, cd2.sPropertyStringValue);
    }

    switch(pToken->Value.valuetype)
    {
        case ESE_VALUE_TYPE_SQL_ID:
            if (!dValue)
                dValue = cd.dPropertyNumericValue;
            if (!dCompValue)
                dCompValue = cd2.dPropertyNumericValue;

            bRet = MatchNumeric(dValue, dCompValue, 
                pToken->optype, 0);

            break;
        case ESE_VALUE_TYPE_STRING:                   
            bRet = MatchString(cd.sPropertyStringValue, cd2.sPropertyStringValue,
                    pToken->optype, 0);

            break;
        case ESE_VALUE_TYPE_REAL:
            bRet = MatchDouble(cd.rPropertyRealValue, cd2.rPropertyRealValue,
                pToken->optype, 0);

            break;
        default:
            bRet = FALSE;
            break;
    }

    return bRet;
}

//***************************************************************************
//
//  CWmiESEIterator::Match
//
//***************************************************************************

BOOL CWmiESEIterator::Match (CLASSDATA cd, ESEToken *pTok)
{
    BOOL bRet = FALSE;

    ESEWQLToken *pToken = (ESEWQLToken *)pTok;

    if (pToken->tokentype == ESE_EXPR_TYPE_EXPR)
    {
        if (pToken->optype == WQL_TOK_ISNULL) 
        {
            if (cd.iFlags & ESE_FLAG_NULL)
                bRet = TRUE;
        }
        else if (pToken->optype == WQL_TOK_NOT_NULL)
        {
            if (!(cd.iFlags & ESE_FLAG_NULL))
                bRet = TRUE;
        }
        else
        {
            SQL_ID dValue = 0, dCompValue = 0;

            if (pToken->Value.dwFunc ||
                pToken->CompValue.dwFunc)
            {
                if (cd.sPropertyStringValue)
                {
                    dValue = GetDatePart(pToken->Value.dwFunc, cd.sPropertyStringValue);
                    dCompValue = GetDatePart(pToken->CompValue.dwFunc, cd.sPropertyStringValue);
                }
                else
                    return FALSE;
            }

            switch(pToken->Value.valuetype)
            {
                case ESE_VALUE_TYPE_SQL_ID:
                    if (!dValue)
                        dValue = cd.dPropertyNumericValue;

                    bRet = MatchNumeric(dValue, pToken->Value.dValue, 
                        pToken->optype, dCompValue);

                    break;
                case ESE_VALUE_TYPE_STRING:                   
                    bRet = MatchString(cd.sPropertyStringValue, pToken->Value.sValue,
                            pToken->optype, pToken->CompValue.sValue);

                    break;
                case ESE_VALUE_TYPE_REAL:
                    bRet = MatchDouble(cd.rPropertyRealValue, pToken->Value.rValue,
                        pToken->optype, pToken->CompValue.rValue);

                    break;
                case ESE_VALUE_TYPE_REF:

                switch(pToken->optype)
                {
                    case WQL_TOK_ISA:
                        
                        bRet = cd.dRefClassId == pToken->Value.dValue;
                        if (!bRet)
                        {
                            bRet = (((CWmiDbSession *)m_pSession)->GetSchemaCache()->IsDerivedClass
                                (pToken->Value.dValue, cd.dRefClassId));
                        }

                        break;
                }
                    break;
                case ESE_VALUE_TYPE_SYSPROP:
                    bRet = TRUE; // we already evaluated this.
                    break;
            }
        }
    }

    return bRet;
}

//***************************************************************************
//
//  CWmiESEIterator::ObjectMatches
//
//***************************************************************************

BOOL CWmiESEIterator::ObjectMatches (SQL_ID dObjectId, SQL_ID dClassId, 
                                     SQL_ID dScopeId, INDEXDATA *pData,
                                     REFERENCEPROPERTIES *pPData,SQL_ID *pObjectId, 
                                     SQL_ID *pClassId,SQL_ID *pScopeId)
{
    SQL_ID d1 = dObjectId, d2 = dClassId, d3 = dScopeId;
    BOOL bRet = FALSE;
    if (m_pToks->GetNumTokens())
    {
        TEMPQLTYPE tok = ESE_TEMPQL_TYPE_NONE;

        if (m_bWQL)
            bRet = ObjectMatchesWQL(d1, d2, d3);
        else
        {
            if (dClassId == 1)
                bRet = ObjectMatchesClass(d1, d2, d3, pPData);
            else
                bRet = ObjectMatchesRef(d1, d2, d3, pData);
        }
        if (bRet)
        {
            if (pObjectId)
                *pObjectId = d1;
            if (pClassId)
                *pClassId = d2;
            if (pScopeId)
                *pScopeId = d3;
        }

    }
    else
        bRet = TRUE;
    return bRet;
}

//***************************************************************************
//
//  CWmiESEIterator::ObjectMatchesClass
//
//***************************************************************************

BOOL CWmiESEIterator::ObjectMatchesClass (SQL_ID &dObjectId, SQL_ID &dClassId, SQL_ID &dScopeId, REFERENCEPROPERTIES*pm)
{
    BOOL bRet = FALSE;

    // The class with this ID contains a reference to our target class.
    // * Does the scope match?
    // * Do the other properties match?
    // * What is the actual endpoint (assoc or ref?)
    // => Dealing with a class, we need to look at PropertyMap, as well as
    //    ClassData for qualifiers!

    // NOTE: This is expected to be post-filtered anyway, so we will only
    //  perform rudimentary matching.

    int iNumTokens = m_pToks->GetNumTokens();
    TEMPQLTYPE qltype = m_pToks->GetToken(0)->qltype;
    OBJECTMAP oj;
    HRESULT hr = 0;
    SQL_ID dTargetId;
    _bstr_t sName;
    BOOL bAssoc = FALSE;
    
    for (int i = m_iStartPos; i < iNumTokens; i++)
    {
        ESEToken *pTok = m_pToks->GetToken(i);
        if (!(pTok->qltype == ESE_TEMPQL_TYPE_REF ||
              pTok->qltype == ESE_TEMPQL_TYPE_ASSOC))
        {
            continue;
        }

        if (pTok->qltype == ESE_TEMPQL_TYPE_ASSOC)
            bAssoc = TRUE;

        qltype = pTok->qltype;
        bRet = FALSE;
        if (pTok->tokentype == ESE_EXPR_TYPE_EXPR)
        {
            ESETempQLToken *pTok2 = (ESETempQLToken *)pTok;
            switch (pTok2->token)
            {
            case TEMPQL_TOKEN_TARGETID:
                dTargetId = pTok2->dValue;
                if (pm->dRefClassId == dTargetId)
                    bRet = TRUE;
                break;

            case TEMPQL_TOKEN_RESULTCLASS:
                if (qltype == ESE_TEMPQL_TYPE_REF)
                {
                    // Is this class ID derived from the one
                    // in question?

                    if (dObjectId == pTok2->dValue)
                        bRet = TRUE;
                    else if (((CWmiDbSession *)m_pSession)->GetSchemaCache()->IsDerivedClass
                        (pTok2->dValue, dObjectId))
                        bRet = TRUE;      
                }
                else
                {
                    // We can't move the pointer
                    // on PropertyMap, or we will mess up our cursor.

                    bRet = TRUE; // postfilter
                }

                break;
            case TEMPQL_TOKEN_ROLE:
                // Is the current property ID named the token in question?
                {
                    _bstr_t sVal;
                    ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetPropertyInfo(pm->iPropertyId, &sVal);
                    
                    if (!_wcsicmp(sVal, pTok2->sValue))
                        bRet = TRUE;
                }
                break;
            case TEMPQL_TOKEN_RESULTROLE:

                // We can't move the pointer
                // on PropertyMap, or we will mess up our cursor.

                bRet = TRUE; // postfilter

                break;
            case TEMPQL_TOKEN_ASSOCQUALIFIER:
            case TEMPQL_TOKEN_REQQUALIFIER:
                if (qltype == ESE_TEMPQL_TYPE_REF ||
                    pTok2->token == TEMPQL_TOKEN_ASSOCQUALIFIER)
                {
                    // Does this association instance have this qualifier?
                    CLASSDATA cd;
                    hr = GetFirst_ClassData(m_pConn, dObjectId, cd);
                    while (SUCCEEDED(hr))
                    {
                        if (pTok2->dValue == cd.iPropertyId)
                        {
                            bRet = TRUE;
                            cd.Clear();
                            break;
                        }
                        hr = GetNext_ClassData(m_pConn, cd);
                    }
                }
                else
                {
                    // We can't move the pointer
                    // on PropertyMap, or we will mess up our cursor.

                    bRet = TRUE; // postfilter
                }
                break;
            case TEMPQL_TOKEN_ASSOCCLASS:                
                // Is this association instance derived from this class?
                if (dObjectId == pTok2->dValue)
                    bRet = TRUE;
                else if (((CWmiDbSession *)m_pSession)->GetSchemaCache()->IsDerivedClass
                            (pTok2->dValue, dObjectId))
                    bRet = TRUE;      
                break;
            default:
                break;
            }
        }

        if (!bRet)
            break;
    }


    // FIXME: If the return object is an association, 
    // we need to retrieve the other object.
    


    return bRet;
}
      
//***************************************************************************
//
//  CWmiESEIterator::ObjectMatchesWQL
//
//***************************************************************************
 
BOOL CWmiESEIterator::ObjectMatchesWQL (SQL_ID dObjectId, SQL_ID dClassId, SQL_ID dScopeId)
{
    BOOL bRet = FALSE;

    // Traverse the set of tokens to
    // see if this object matches.
    // Since we do *NOT* want to 
    // modify the position of the current
    // index, we will retrieve
    // the data from the ClassData table,
    // and see if it matches in toto.

    int i = 0;
    int iNumToks = m_pToks->GetNumTokens();

    int * results = new int [iNumToks];
    if (!results)
        return FALSE;

    CDeleteMe <int> d (results);

    for (i = m_iStartPos; i < iNumToks; i++)
    {
        ESEWQLToken *pTok = (ESEWQLToken *)m_pToks->GetToken(i);

        if (pTok->tokentype == ESE_EXPR_TYPE_EXPR &&
            pTok->optype != WQL_TOK_ISNULL &&
            pTok->Value.valuetype != ESE_VALUE_TYPE_SYSPROP)
            results[i] = 0;
        else 
            results[i] = -1;
    }

    int iNumSysToks = 0, iNumOther = 0;

    // Prematch on system criteria.

    BOOL bScopeMatch = FALSE, bClassMatch = FALSE;
    BOOL bScopeCrit = FALSE, bClassCrit = FALSE;
    
    for (i = m_iStartPos; i < iNumToks; i++)
    {
        ESEToken *pTok2 = m_pToks->GetToken(i);
        if (!pTok2->qltype && pTok2->tokentype == ESE_EXPR_TYPE_EXPR)
        {
            ESEWQLToken *pTok = (ESEWQLToken *)pTok2;
            if (pTok->Value.valuetype == ESE_VALUE_TYPE_SYSPROP)
            {
                // Make sure class and scope ID match
                // If there are multiple scopes and classes,
                // these are ORed together.

                if (!dScopeId && (dClassId == 1))
                    bScopeMatch = TRUE;

                if (pTok->dScopeId)
                {
                    bScopeCrit = TRUE;
                    if (dScopeId == pTok->dScopeId)
                        bScopeMatch = TRUE;
                }                        

                if (pTok->dClassId)
                {
                    bClassCrit = TRUE;
                    results[i] = TRUE;
                    if (dClassId == pTok->dClassId)
                        bClassMatch = TRUE;
                }
                iNumSysToks++;
            }
            else if (pTok->tokentype == ESE_EXPR_TYPE_EXPR)
                iNumOther++;
        }
    }

    if (!((bScopeMatch || !bScopeCrit) ))
        bRet = FALSE;
    else
    {
        if (iNumSysToks)
            bRet = TRUE;

        if (iNumOther)
        {
            BOOL bPropToProp = FALSE;
            CLASSDATA cd;
            HRESULT hr = 0;
            hr = GetFirst_ClassData(m_pConn, dObjectId, cd);
            while (SUCCEEDED(hr))
            {
                // See if this property matches any
                // line of criteria.

                for (i = m_iStartPos; i < iNumToks; i++)
                {
                    ESEToken *pTok2 = m_pToks->GetToken(i);
                    if (!pTok2->qltype && pTok2->tokentype == ESE_EXPR_TYPE_EXPR)
                    {
                        ESEWQLToken *pTok = (ESEWQLToken *)pTok2;
                        if (!pTok->bSysProp)
                        {                            
                            if (pTok->dPropertyId == cd.iPropertyId)
                            {
                                if (!pTok->dCompPropertyId)
                                {
                                    results[i] = Match(cd, pTok);
                                    cd.Clear();
                                }
                                else
                                    bPropToProp = TRUE;
                            }
                        }
                    }
                }

                hr = GetNext_ClassData(m_pConn, cd);
            }

            if (hr == WBEM_E_NOT_FOUND)
                hr = WBEM_S_NO_ERROR;

            if (SUCCEEDED(hr))
            {
                // Fishing around for specific property values 
                // is pretty expensive, so we do this last.
                // We could optimize this by caching each CLASSDATA
                // as we hit it the first time.

                if (bPropToProp)
                {
                    for (i = m_iStartPos; i < iNumToks; i++)
                    {
                        if (m_pToks->GetToken(i)->tokentype == ESE_EXPR_TYPE_EXPR)
                        {
                            ESEWQLToken *pTok = (ESEWQLToken *)m_pToks->GetToken(i);
                            if (pTok->dCompPropertyId)
                            {
                                CLASSDATA cd2;
                                hr = GetFirst_ClassData(m_pConn, dObjectId, cd, pTok->dPropertyId);
                                if (SUCCEEDED(hr))
                                {
                                    hr = GetFirst_ClassData(m_pConn, dObjectId, cd2, pTok->dCompPropertyId);
                                    if (SUCCEEDED(hr))
                                    {
                                        results[i] = PropMatch (cd, cd2, pTok);
                                        cd2.Clear();
                                    }
                                    else
                                        results[i] = FALSE;
                                    cd.Clear();
                                }
                                else
                                    results[i] = FALSE;
                            }
                        }
                    }
                    hr = WBEM_S_NO_ERROR;
                }
            }

            if (SUCCEEDED(hr))
            {
                // Check for System properties
                for (i = m_iStartPos; i < iNumToks; i++)
                {
                    if (m_pToks->GetToken(i)->tokentype == ESE_EXPR_TYPE_EXPR)
                    {
                        if (((ESEWQLToken *)m_pToks->GetToken(i))->bSysProp == TRUE)
                        {
                            results[i] = SysMatch(dObjectId, dClassId, dScopeId, m_pToks->GetToken(i));
                        }
                        // Post-filter ISA stuff.
                        if ((((ESEWQLToken *)m_pToks->GetToken(i))->optype) == WQL_TOK_ISA)
                            results[i] = TRUE;
                    }
                }
            }

            if (SUCCEEDED(hr))
            {
                // Go through the array and make sure
                // we have the results we expected.

                for (i = m_iStartPos; i < iNumToks; i++)
                {
                    ESEToken *pTok = m_pToks->GetToken(i);
                    switch(pTok->tokentype)
                    {
                    case ESE_EXPR_TYPE_AND:
                        if (results[i-1] && results[i-2])
                            bRet = TRUE;
                        else
                            bRet = FALSE;
                        results[i] = bRet;
                        break;
                    case ESE_EXPR_TYPE_OR:
                        if (results[i-1] || results[i-2])
                            bRet = TRUE;
                        else
                            bRet = FALSE;
                        results[i] = bRet;
                        break;

                    case ESE_EXPR_TYPE_NOT:
                        if (bRet)
                            bRet = FALSE;
                        else
                            bRet = TRUE;
                        results[i] = bRet;
                        break;                        
                    case ESE_EXPR_TYPE_EXPR:
                        bRet = results[i];
                        break;
                    }
                }
            }
        }
        else 
        {
            if (bClassCrit && !bClassMatch)
                bRet = FALSE;
        }

    }

    return bRet;
}

//***************************************************************************
//
//  CWmiESEIterator::ObjectMatchesRef
//
//***************************************************************************
 
BOOL CWmiESEIterator::ObjectMatchesRef (SQL_ID &dObjectId, SQL_ID &dClassId, 
                                        SQL_ID &dScopeId, INDEXDATA *pData)
{
    BOOL bRet = TRUE;
    int iNumTokens = m_pToks->GetNumTokens();
    TEMPQLTYPE qltype = m_pToks->GetToken(0)->qltype;
    OBJECTMAP oj;
    HRESULT hr = 0;
    SQL_ID dTargetId;
    _bstr_t sName;
    BOOL bAssoc = FALSE;

    for (int i = m_iStartPos; i < iNumTokens; i++)
    {
        ESEToken *pTok = m_pToks->GetToken(i);
        if (!(pTok->qltype == ESE_TEMPQL_TYPE_REF ||
              pTok->qltype == ESE_TEMPQL_TYPE_ASSOC))
        {

            continue;
        }

        if (pTok->qltype == ESE_TEMPQL_TYPE_ASSOC)
            bAssoc = TRUE;

        qltype = pTok->qltype;
        bRet = FALSE;
        if (pTok->tokentype == ESE_EXPR_TYPE_EXPR)
        {
            ESETempQLToken *pTok2 = (ESETempQLToken *)pTok;
            switch (pTok2->token)
            {
            case TEMPQL_TOKEN_TARGETID:
                dTargetId = pTok2->dValue;
                if (pData)
                {
                    if (pData->dValue == pTok2->dValue)
                        bRet = TRUE;
                }
                break;

            case TEMPQL_TOKEN_RESULTCLASS:
                if (qltype == ESE_TEMPQL_TYPE_REF)
                {
                    // Is this class ID derived from the one
                    // in question?

                    if (dClassId == pTok2->dValue)
                        bRet = TRUE;
                    else if (((CWmiDbSession *)m_pSession)->GetSchemaCache()->IsDerivedClass
                        (pTok2->dValue, dClassId))
                        bRet = TRUE;      
                }
                else
                {
                    // Check the other endpoint of the association
                    // Get the other endpoint from CLASSDATA

                    CLASSDATA cd;
                    hr = GetFirst_ClassData(m_pConn, dObjectId, cd);
                    while (SUCCEEDED(hr))
                    {
                        if (cd.dRefId!= dTargetId)
                        {
                            hr = GetFirst_ObjectMap(m_pConn, cd.dRefId, oj);
                            if (SUCCEEDED(hr))
                            {
                                if (oj.dClassId == pTok2->dValue)
                                    bRet = TRUE;
                                else if (((CWmiDbSession *)m_pSession)->GetSchemaCache()->IsDerivedClass
                                    (pTok2->dValue, oj.dClassId))
                                    bRet = TRUE; 
                                cd.Clear();
                                oj.Clear();
                                break;
                            }
                            oj.Clear();
                        }
                        hr = GetNext_ClassData(m_pConn, cd);
                    }
                }

                break;
            case TEMPQL_TOKEN_ROLE:
                // Is the current property ID named the token in question?
                if (pData)
                {
                    hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetPropertyInfo
                                (pData->iPropertyId, &sName);
                    if (SUCCEEDED(hr))
                    {
                        if (!_wcsicmp(sName, pTok2->sValue))
                            bRet = TRUE;
                    }
                }
                break;
            case TEMPQL_TOKEN_RESULTROLE:
                // Is the property ID of the endpoint named the token in question?
                {
                    CLASSDATA cd;
                    hr = GetFirst_ClassData(m_pConn, dObjectId, cd);
                    while (SUCCEEDED(hr))
                    {
                        if (cd.dRefId != dTargetId)
                        {
                            hr = ((CWmiDbSession *)m_pSession)->GetSchemaCache()->GetPropertyInfo
                                        (cd.iPropertyId, &sName);
                            if (SUCCEEDED(hr))
                            {
                                if (!_wcsicmp(sName, pTok2->sValue))
                                    bRet = TRUE;
                                cd.Clear();
                                break;
                            }
                        }
                        hr = GetNext_ClassData(m_pConn, cd);
                    }
                }
                break;
            case TEMPQL_TOKEN_ASSOCQUALIFIER:
            case TEMPQL_TOKEN_REQQUALIFIER:
                if (qltype == ESE_TEMPQL_TYPE_REF ||
                    pTok2->token == TEMPQL_TOKEN_ASSOCQUALIFIER)
                {
                    // Does this association instance have this qualifier?
                    CLASSDATA cd;
                    hr = GetFirst_ClassData(m_pConn, dObjectId, cd);
                    while (SUCCEEDED(hr))
                    {
                        if (pTok2->dValue == cd.iPropertyId)
                        {
                            bRet = TRUE;
                            cd.Clear();
                            break;
                        }
                        hr = GetNext_ClassData(m_pConn, cd);
                    }
                    if (!bRet)
                    {
                        hr = GetFirst_ClassData(m_pConn, dClassId, cd);
                        while (SUCCEEDED(hr))
                        {
                            if (pTok2->dValue == cd.iPropertyId)
                            {
                                bRet = TRUE;
                                cd.Clear();
                                break;
                            }
                            hr = GetNext_ClassData(m_pConn, cd);
                        }
                    }
                }
                else
                {
                    // Does the endpoint contain this qualifier?
                    CLASSDATA cd;
                    hr = GetFirst_ClassData (m_pConn, dObjectId, cd);
                    while (SUCCEEDED(hr))
                    {       
                        if (cd.dRefId != dTargetId)
                        {
                            CLASSDATA cd2;
                            hr = GetFirst_ClassData(m_pConn, cd.dRefId, cd2);
                            while (SUCCEEDED(hr))
                            {
                                if (pTok2->dValue == cd2.iPropertyId)
                                {
                                    bRet = TRUE;
                                    cd2.Clear();
                                    break;
                                }
                                hr = GetNext_ClassData(m_pConn, cd2);
                            }
                            if (!bRet)
                            {
                                hr = GetFirst_ClassData(m_pConn, cd.dRefClassId, cd2);
                                while (SUCCEEDED(hr))
                                {
                                    if (pTok2->dValue == cd2.iPropertyId)
                                    {
                                        bRet = TRUE;
                                        cd2.Clear();
                                        break;
                                    }
                                    hr = GetNext_ClassData(m_pConn, cd2);
                                }
                            }
                            cd.Clear();
                            break;
                        }
                        hr = GetNext_ClassData(m_pConn, cd);
                    }
                }

                break;
            case TEMPQL_TOKEN_ASSOCCLASS:                
                // Is this association instance derived from this class?
                if (dClassId == pTok2->dValue)
                    bRet = TRUE;
                else if (((CWmiDbSession *)m_pSession)->GetSchemaCache()->IsDerivedClass
                            (pTok2->dValue, dClassId))
                    bRet = TRUE;      
                break;
            default:
                break;
            }
        }

        if (!bRet)
            break;
    }

    if (bRet && bAssoc)
    {
        CLASSDATA cd;
        hr = GetFirst_ClassData (m_pConn, dObjectId, cd);
        while (SUCCEEDED(hr))
        {
            if (cd.dRefId != dTargetId)
            {
                hr = GetFirst_ObjectMap(m_pConn, cd.dRefId, oj);
                if (SUCCEEDED(hr))
                {
                    dObjectId = oj.dObjectId;
                    dClassId = oj.dClassId;
                    dScopeId = oj.dObjectScopeId;
                    oj.Clear();
                    break;
                }
                oj.Clear();
            }
            hr = GetNext_ClassData(m_pConn, cd);
        }
        cd.Clear();

    }

    return bRet;
}

//***************************************************************************
//
//  CWmiESEIterator::TestDriverStatus
//
//***************************************************************************
 
HRESULT CWmiESEIterator::TestDriverStatus ()
{
   HRESULT hr = WBEM_S_NO_ERROR;

   if (!m_pSession || 
       !(m_pSession->m_pController) || 
       ((CWmiDbController *)m_pSession->m_pController)->m_dwCurrentStatus == WBEM_E_SHUTTING_DOWN)
   {
        Cancel(0);
        hr = WBEM_E_SHUTTING_DOWN;
   }

    return hr;
}