[mapguide-commits] r1130 - in trunk/MgDev: Common/MapGuideCommon/System Server/src/Core Server/src/Gws/GwsCommon Server/src/Gws/GwsQueryEngine Server/src/Gws/GwsQueryEngine/inc Server/src/Gws/GwsResource Server/src/Gws/Include Server/src/Services/Feature

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Thu Feb 22 19:41:59 EST 2007


Author: brucedechant
Date: 2007-02-22 19:41:58 -0500 (Thu, 22 Feb 2007)
New Revision: 1130

Added:
   trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsBatchSortedBlockJoinQueryResults.cpp
   trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsRightBatchSortedBlockJoinQueryResults.cpp
Modified:
   trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp
   trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h
   trunk/MgDev/Server/src/Core/serverconfig.ini
   trunk/MgDev/Server/src/Gws/GwsCommon/GwsResourceUtil.cpp
   trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsFeatureSourceQuery.cpp
   trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedFeatureQuery.cpp
   trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedJoinQuery.cpp
   trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsQueryEngine.vcproj
   trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsRightJoinQueryResults.cpp
   trunk/MgDev/Server/src/Gws/GwsQueryEngine/Makefile.am
   trunk/MgDev/Server/src/Gws/GwsQueryEngine/inc/GwsQuery.h
   trunk/MgDev/Server/src/Gws/GwsResource/GwsResource.h
   trunk/MgDev/Server/src/Gws/GwsResource/GwsResource.rc
   trunk/MgDev/Server/src/Gws/Include/GwsCommon.h
   trunk/MgDev/Server/src/Services/Feature/Makefile.am
   trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcproj
   trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.cpp
   trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.h
Log:
Add an optimized join query algorithm to the server that is significantly faster then the default brute force algorithm. This optimized algorithm is only used when the primary is unordered and the secondary is ordered.


Modified: trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.cpp	2007-02-23 00:41:58 UTC (rev 1130)
@@ -55,6 +55,9 @@
 #define MG_CONFIG_MIN_TIMER_INTERVAL                    1
 #define MG_CONFIG_MAX_TIMER_INTERVAL                    MG_CONFIG_MAX_INT32
 
+#define MG_CONFIG_MIN_JOIN_QUERY_BATCH_SIZE             1
+#define MG_CONFIG_MAX_JOIN_QUERY_BATCH_SIZE             1024
+
 ///////////////////////////////////////////////////////////////////////////////
 /// Length ranges of string properties
 ///
@@ -239,6 +242,8 @@
 const INT32  MgConfigProperties::DefaultFeatureServicePropertyDataConnectionTimeout         = 600;
 const STRING MgConfigProperties::FeatureServicePropertyDataConnectionTimerInterval          = L"DataConnectionTimerInterval";
 const INT32  MgConfigProperties::DefaultFeatureServicePropertyDataConnectionTimerInterval   = 60;
+const STRING MgConfigProperties::FeatureServicePropertyJoinQueryBatchSize                   = L"JoinQueryBatchSize";
+const INT32  MgConfigProperties::DefaultFeatureServicePropertyJoinQueryBatchSize            = 100;
 
 // ******************************************************************
 // Mapping Service Properties
@@ -507,6 +512,7 @@
     { MgConfigProperties::FeatureServicePropertyDataConnectionPoolSize              , MgPropertyType::Int32     , MG_CONFIG_MIN_CONNECTION_POOL_SIZE    , MG_CONFIG_MAX_CONNECTION_POOL_SIZE    , L""                                       },
     { MgConfigProperties::FeatureServicePropertyDataConnectionTimeout               , MgPropertyType::Int32     , MG_CONFIG_MIN_TIMEOUT                 , MG_CONFIG_MAX_TIMEOUT                 , L""                                       },
     { MgConfigProperties::FeatureServicePropertyDataConnectionTimerInterval         , MgPropertyType::Int32     , MG_CONFIG_MIN_TIMER_INTERVAL          , MG_CONFIG_MAX_TIMER_INTERVAL          , L""                                       },
+    { MgConfigProperties::FeatureServicePropertyJoinQueryBatchSize                  , MgPropertyType::Int32     , MG_CONFIG_MIN_JOIN_QUERY_BATCH_SIZE   , MG_CONFIG_MAX_JOIN_QUERY_BATCH_SIZE   , L""                                       },
     { L""                                                                           , 0                         , 0.0                                   , 0.0                                   , L""                                       }
 };
 

Modified: trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h
===================================================================
--- trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Common/MapGuideCommon/System/ConfigProperties.h	2007-02-23 00:41:58 UTC (rev 1130)
@@ -291,6 +291,10 @@
     static const STRING FeatureServicePropertyDataConnectionTimerInterval;      /// value("DataConnectionTimerInterval")
     static const INT32 DefaultFeatureServicePropertyDataConnectionTimerInterval;/// value(60)
 
+    /// Sets the batch size used by the join query algorithm
+    static const STRING FeatureServicePropertyJoinQueryBatchSize;                    /// value("JoinQueryBatchSize")
+    static const INT32 DefaultFeatureServicePropertyJoinQueryBatchSize;              /// value(100)
+
     /// MAPPING SERVICE PROPERTIES SECTION -------------------------------------------------------------------------------
 
     /// Mapping Service properties

Modified: trunk/MgDev/Server/src/Core/serverconfig.ini
===================================================================
--- trunk/MgDev/Server/src/Core/serverconfig.ini	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Core/serverconfig.ini	2007-02-23 00:41:58 UTC (rev 1130)
@@ -242,6 +242,8 @@
 # DataConnectionTimerInterval      Time interval in seconds for when the server
 #                                  checks for idle connections
 #                                       0 < Value <= 2147483647
+# JoinQueryBatchSize               Join query batch size
+#                                       1 < Value <= 1024
 # *****************************************************************************
 CacheSize                          = 100
 CacheTimeLimit                     = 86400
@@ -252,6 +254,7 @@
 DataConnectionPoolSize             = 20
 DataConnectionTimeout              = 600
 DataConnectionTimerInterval        = 60
+JoinQueryBatchSize                 = 100
 
 [MappingServiceProperties]
 # *****************************************************************************

Modified: trunk/MgDev/Server/src/Gws/GwsCommon/GwsResourceUtil.cpp
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsCommon/GwsResourceUtil.cpp	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/GwsCommon/GwsResourceUtil.cpp	2007-02-23 00:41:58 UTC (rev 1130)
@@ -270,6 +270,7 @@
     GET_STR (eGwsNoLayers, str);
     GET_STR (eGwsFeatureSourceIsReadOnly, str);
     GET_STR (eGwsFeatureClassHasNoIdentity, str);
+    GET_STR (eGwsFdoInvalidDataType, str);
     default:
         str = L"GWS message resource id is not defined.";
         break;

Added: trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsBatchSortedBlockJoinQueryResults.cpp
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsBatchSortedBlockJoinQueryResults.cpp	                        (rev 0)
+++ trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsBatchSortedBlockJoinQueryResults.cpp	2007-02-23 00:41:58 UTC (rev 1130)
@@ -0,0 +1,1264 @@
+//
+//  Copyright (C) 2004-2007  Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+/////////////////////////////////////////////////////////////////////
+//
+// Includes
+//
+/////////////////////////////////////////////////////////////////////
+#include "stdafx.h"
+
+#include "GwsQueryEngineImp.h"
+#include "GwsBinaryFeatureWriter.h"
+
+// This setting limits the batch size used by the join algorithm
+#ifdef _DEBUG_BATCHSORT_JOIN
+int CGwsBatchSortedBlockJoinQueryResults::sm_nBatchSize = 5; // Default
+#else
+int CGwsBatchSortedBlockJoinQueryResults::sm_nBatchSize = 100; //Default
+#endif
+
+/////////////////////////////////////////////////////////////////////
+//
+// class CGwsBatchSortedBlockJoinQueryResults
+//
+/////////////////////////////////////////////////////////////////////
+CGwsBatchSortedBlockJoinQueryResults::CGwsBatchSortedBlockJoinQueryResults (
+)
+{
+    m_right = NULL;
+    m_primaryFeatureIterator = NULL;
+    m_pPrimaryCacheIterator = m_pPrimaryCache.begin();
+}
+
+CGwsBatchSortedBlockJoinQueryResults::~CGwsBatchSortedBlockJoinQueryResults (
+) throw()
+{
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    printf("CGwsBatchSortedBlockJoinQueryResults::~CGwsBatchSortedBlockJoinQueryResults()\n");
+    #endif
+
+    ClearIteratorCache();
+
+    for ( size_t i=0;i<m_propertyDescriptionCollection.size();i++ )
+    {
+        CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+        delete propDesc;
+    }
+
+    m_propertyDescriptionCollection.clear();
+
+    if (m_primaryFeatureIterator != NULL)
+    {
+        m_primaryFeatureIterator->Release ();
+        m_primaryFeatureIterator = NULL;
+    }
+}
+
+EGwsStatus CGwsBatchSortedBlockJoinQueryResults::InitializeReader (
+    IGWSQuery                       * query,
+    CGwsPreparedJoinQuery           * prepquery,
+    bool                            bScrollable
+)
+{
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    printf("CGwsBatchSortedBlockJoinQueryResults::InitializeReader() - Start\n");
+    #endif
+    EGwsStatus                  stat = eGwsOk;
+    CGwsPreparedQuery         * leftquery = prepquery->LeftQuery ();
+    CGwsPreparedQuery         * rightquery = prepquery->RightQuery ();
+    FdoPtr<FdoStringCollection> leftcols = prepquery->LeftProperties ();
+    FdoPtr<FdoStringCollection> rightcols = prepquery->RightProperties ();
+
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    FdoPtr<FdoFilter> lqFilter = leftquery->GetFilter();
+    FdoPtr<FdoFilter> rqFilter = rightquery->GetFilter();
+
+    FdoStringP lqFilterStr = lqFilter ? lqFilter->ToString() : NULL;
+    FdoStringP rqFilterStr = rqFilter ? rqFilter->ToString() : NULL;
+
+    printf("  Left  Query Filter: %S\n", lqFilterStr);
+    printf("  Right Query Filter: %S\n", rqFilterStr);
+    printf("  Left  Query Properties: %S\n", leftcols ? leftcols->ToString() : L"<null>");
+    printf("  Right Query Properties: %S\n", rightcols ? rightcols->ToString() : L"<null>");
+    #endif
+
+    stat = CGwsJoinQueryResults::InitializeReader (leftcols, query, leftquery, bScrollable);
+    if (IGWSException::IsError (stat)) {
+        PushStatus  (stat);
+        return stat;
+    }
+
+    IGWSFeatureIterator * primaryFeatureIterator = NULL;
+    stat = leftquery->Execute (& primaryFeatureIterator, bScrollable);
+    if (IGWSException::IsError (stat)) {
+        delete primaryFeatureIterator;
+    }
+    else
+    {
+        m_primaryFeatureIterator = primaryFeatureIterator;
+    }
+
+    m_prepquery = prepquery;
+
+    CGwsRightJoinQueryResults * results =
+            (CGwsRightJoinQueryResults *) rightquery->CreateFeatureIterator (eGwsRightBatchSortedBlockIterator);
+    stat = results->InitializeReader (query, rightquery, rightcols, bScrollable);
+
+    if (IGWSException::IsError (stat)) {
+        delete results;
+    } else {
+        m_right = results;
+        m_right->AddRef ();
+    }
+
+    // Get the feature description so that we can get the primary property names
+    FdoPtr<IGWSExtendedFeatureDescription> featDsc;
+    DescribeFeature (&featDsc);
+
+    m_propertyNames = featDsc->PropertyNames();
+
+    // Set the size of the property collection cache
+    m_propertyDescriptionCollection.resize(m_propertyNames->GetCount());
+    
+    for(int j=0;j<m_propertyNames->GetCount();j++)
+    {
+        FdoString* propertyName = m_propertyNames->GetString(j);
+        const CGwsPropertyDesc propertyDesc = GetPropertyDescriptor(propertyName);
+        CGwsPropertyDesc* pPropertyDesc = new CGwsPropertyDesc(propertyDesc);
+        if(pPropertyDesc)
+        {
+            m_propertyDescriptionCollection[j] = pPropertyDesc;
+        }
+    }
+
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    printf("CGwsBatchSortedBlockJoinQueryResults::InitializeReader() - End\n");
+    #endif
+    return stat;
+}
+
+bool CGwsBatchSortedBlockJoinQueryResults::ReadNext ()
+{
+
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    printf("CGwsBatchSortedBlockJoinQueryResults::ReadNext()\n");
+    #endif
+
+    if(m_pPrimaryCache.size() > 0)
+    {
+        m_pPrimaryCacheIterator++;
+    }
+
+    if(m_pPrimaryCacheIterator == m_pPrimaryCache.end())
+    {
+        m_bLeftJoinValuesSet = false;
+    }
+
+    // Read the left side
+    bool bRes = CGwsFeatureIterator::ReadNext ();
+
+    // Read the right side
+    bRes = SetupBatchRightSide(bRes);
+
+    return bRes;
+}
+
+IGWSFeatureIterator * CGwsBatchSortedBlockJoinQueryResults::GetJoinedFeatures (int iJoin)
+{
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    printf("  CGwsBatchSortedBlockJoinQueryResults::GetJoinedFeatures(%d)\n", iJoin);
+    #endif
+    // check join feature index
+    FdoPtr<IGWSExtendedFeatureDescription> fdsc;
+    DescribeFeature (& fdsc);
+    if (iJoin >= fdsc->GetCount ())
+        GWS_THROW (eGwsIndexOutOfBounds);
+
+    if (iJoin < m_prepquery->GetPathLength () - 1) {
+        if (m_prepquery->QueryType () == eGwsQueryLeftOuterJoin ||
+            m_prepquery->QueryType () == eGwsQueryEqualJoin)
+        {
+            CGwsJoinQueryResults * jqr = dynamic_cast<CGwsJoinQueryResults*> (m_reader.p);
+            assert (jqr);
+            return jqr->GetJoinedFeatures (iJoin);
+        }
+    }
+
+    return GetJoinedFeatures ();
+}
+
+IGWSFeatureIterator * CGwsBatchSortedBlockJoinQueryResults::GetJoinedFeatures ()
+{
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    printf("  CGwsBatchSortedBlockJoinQueryResults::GetJoinedFeatures()\n");
+    #endif
+
+    // Only update the ride side when needed
+    EGwsStatus stat = eGwsOk;
+    if(!m_bLeftJoinValuesSet)
+    {
+        GetJoinValues ();
+        assert (m_bLeftJoinValuesSet);
+        stat = m_right->SetRelatedValues (m_leftJoinVals);
+    }
+
+    if (IGWSException::IsError (stat)) {
+        CopyStatus (* m_right); // TODO: candidate for exception throwing
+        return NULL;
+    }
+    m_right->AddRef ();
+    return m_right;
+
+}
+
+bool CGwsBatchSortedBlockJoinQueryResults::SetupBatchRightSide(bool bRes) {
+
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    printf("  CGwsBatchSortedBlockJoinQueryResults::SetupBatchRightSide()\n");
+    #endif
+    if (m_prepquery->QueryType () == eGwsQueryLeftOuterJoin) {
+        return bRes;
+
+    } else {
+        while (bRes) {
+            FdoPtr<IGWSFeatureIterator> riter = GetJoinedFeatures ();
+
+            if (riter->ReadNext ()) {
+                break;
+            }
+            m_bLeftJoinValuesSet = false;
+            bRes = CGwsFeatureIterator::ReadNext ();
+        }
+    }
+    return bRes;
+}
+
+FdoDataValueCollection * CGwsBatchSortedBlockJoinQueryResults::GetJoinValues ()
+{
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    printf("  CGwsBatchSortedBlockJoinQueryResults::GetJoinValues()\n");
+    #endif
+    if (! m_bLeftJoinValuesSet)
+    {
+        // Clear the cache
+        ClearIteratorCache();
+
+        // Populate the primary iterator cache
+        for(int i=0;i<sm_nBatchSize;i++)
+        {
+            if(m_primaryFeatureIterator->ReadNext())
+            {
+                PrimaryCacheEntry* cacheEntry = new PrimaryCacheEntry();
+                if(cacheEntry)
+                {
+                    // Need to cache all primary properties as we walk the primary iterator
+                    cacheEntry->propertyCollection.resize(m_propertyNames->GetCount());
+
+                    for(int j=0;j<m_propertyNames->GetCount();j++)
+                    {
+                        PropertyCacheEntry* propertyCacheEntry = new PropertyCacheEntry();
+                        if(propertyCacheEntry)
+                        {
+                            FdoString* propertyName = m_propertyNames->GetString(j);
+                            #ifdef _DEBUG_BATCHSORT_JOIN
+                            printf("%S - ", propertyName);
+                            #endif
+
+                            CGwsPropertyDesc* propertyDesc = m_propertyDescriptionCollection[j];
+                            if(FdoPropertyType_GeometricProperty == propertyDesc->m_ptype)
+                            {
+                                // This is a geometry property
+                                FdoByteArray* geometry = m_primaryFeatureIterator->GetGeometry(propertyName);
+                                #ifdef _DEBUG_BATCHSORT_JOIN
+                                printf("<Geometry>\n");
+                                #endif
+
+                                propertyCacheEntry->geometry = geometry;
+                            }
+                            else
+                            {
+                                // This is a data property
+                                FdoDataValue* dataValue =  m_primaryFeatureIterator->GetDataValue(propertyName);
+                                #ifdef _DEBUG_BATCHSORT_JOIN
+                                FdoStringP value = dataValue->ToString();
+                                printf("%S\n", value);
+                                #endif
+
+                                // Is this the primary key?
+                                if(wcscmp(propertyName, m_leftcols->GetString(0)) == 0)
+                                {
+                                    dataValue->AddRef();
+                                    cacheEntry->primaryKey = dataValue;
+                                }
+
+                                propertyCacheEntry->dataValue = dataValue;
+                            }
+
+                            cacheEntry->propertyCollection[j] = propertyCacheEntry;
+                        }
+                    }
+
+                    // Add the iterator cache entry
+                    m_pPrimaryCache.push_back(cacheEntry);
+                }
+            }
+            else
+            {
+                // No more keys
+                break;
+            }
+        }
+
+        // Sort the cache if needed
+        if(m_pPrimaryCache.size() > 1)
+        {
+            QuickSort(m_pPrimaryCache, 0, (FdoInt32)(m_pPrimaryCache.size()-1));
+        }
+
+        // Set the 1st cache entry to read
+        m_pPrimaryCacheIterator = m_pPrimaryCache.begin();
+
+        FdoPtr<FdoDataValueCollection> dvcol = NULL;
+
+        for ( size_t i=0;i<m_pPrimaryCache.size();i++ )
+        {
+            FdoPtr<FdoDataValue> val = NULL;
+
+            PrimaryCacheEntry* cacheEntry = m_pPrimaryCache.at(i);
+            if(cacheEntry)
+            {
+                FdoPtr<FdoDataValue> primary = cacheEntry->primaryKey;
+                FdoDataType dtPrimary = primary->GetDataType();
+
+                // We need to match primary data type to secondary join data type
+                FdoDataType dtSecondary = dtPrimary;
+                if (m_right)
+                {
+                    FdoPtr<FdoStringCollection> joinColumns = m_right->GetJoinColumns();
+                    FdoString* propname = joinColumns->GetString (0);
+                    CGwsPropertyDesc propDesc = m_right->GetPropertyDescriptor(propname);
+                    dtSecondary = propDesc.m_dataprop;
+                }
+
+                switch (dtPrimary)
+                {
+                    case FdoDataType_Byte:
+                    case FdoDataType_Int16:
+                    case FdoDataType_Int32:
+                    case FdoDataType_Int64:
+                    case FdoDataType_Decimal:
+                    case FdoDataType_Single:
+                    case FdoDataType_Double:
+                        switch (dtSecondary)
+                        {
+                            case FdoDataType_Byte:
+                            case FdoDataType_Int16:
+                            case FdoDataType_Int32:
+                            case FdoDataType_Int64:
+                            case FdoDataType_Decimal:
+                            case FdoDataType_Single:
+                            case FdoDataType_Double:
+                                val = primary;
+                                break;
+
+                            case FdoDataType_String:
+                                // Convert primary to string
+                                {
+                                    FdoStringP strPrimVal = primary->ToString();
+                                    FdoPtr<FdoStringValue> strval = FdoStringValue::Create();
+                                    strval->SetString(strPrimVal);
+                                    val = strval;
+                                }
+                                break;
+                        }
+                        break;
+
+
+                    case FdoDataType_String:
+                        switch (dtSecondary)
+                        {
+                            case FdoDataType_String:
+                                val = primary;
+                                break;
+
+                            case FdoDataType_Byte:
+                            case FdoDataType_Int16:
+                            case FdoDataType_Int32:
+                            case FdoDataType_Int64:
+                            case FdoDataType_Decimal:
+                            case FdoDataType_Single:
+                            case FdoDataType_Double:
+                                // Convert primary string to number
+                                {
+                                    FdoStringP strPrimVal = primary->ToString();
+
+                                    // Remove the single quote from the string
+                                    FdoStringP quote = "'";           // NOXLATE
+                                    FdoStringP emptyString = "";      // NOXLATE
+                                    strPrimVal = strPrimVal.Replace(quote, emptyString);
+
+                                    if (strPrimVal.IsNumber())
+                                    {
+                                        FdoPtr<FdoDoubleValue> dval = FdoDoubleValue::Create();
+                                        dval->SetDouble(strPrimVal.ToDouble());
+                                        val = dval;
+                                    }
+                                }
+                                break;
+                        }
+                }
+
+                if(val)
+                {
+                    if (dvcol == NULL)
+                        dvcol = (CGwsDataValueCollection *) CGwsDataValueCollection::Create ();
+                    dvcol->Add (val);
+                }
+            }
+        }
+
+        m_leftJoinVals = dvcol;
+
+        #ifdef _DEBUG_BATCHSORT_JOIN
+        wchar_t* buffer = new wchar_t[255];
+        m_leftJoinVals.ToString(buffer, 255);
+        printf("  Join Values = %S\n", buffer);
+        delete [] buffer;
+        #endif
+
+        m_bLeftJoinValuesSet = true;
+    }
+    return NULL; // m_leftJoinVals;
+}
+
+FdoString * CGwsBatchSortedBlockJoinQueryResults::GetString (FdoString* propertyName)
+{
+    FdoString* result = NULL;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        if(propDesc->m_dataprop == FdoDataType_String)
+                        {
+                            FdoStringValue* value = (FdoStringValue*)(propertyCacheEntry->dataValue.p);
+                            if(value)
+                            {
+                                result = value->GetString();
+                            }
+                        }
+                        else
+                        {
+                            // Wrong data type
+                            // Exception!
+                            GWS_THROW (eGwsFdoInvalidDataType);
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+bool CGwsBatchSortedBlockJoinQueryResults::GetBoolean(FdoString* propertyName)
+{
+    bool result = false;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        if(propDesc->m_dataprop == FdoDataType_Boolean)
+                        {
+                            FdoBooleanValue* value = (FdoBooleanValue*)(propertyCacheEntry->dataValue.p);
+                            if(value)
+                            {
+                                result = value->GetBoolean();
+                            }
+                        }
+                        else
+                        {
+                            // Wrong data type
+                            // Exception!
+                            GWS_THROW (eGwsFdoInvalidDataType);
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+FdoByte CGwsBatchSortedBlockJoinQueryResults::GetByte(FdoString* propertyName)
+{
+    FdoByte result = 0;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        if(propDesc->m_dataprop == FdoDataType_Byte)
+                        {
+                            FdoByteValue* value = (FdoByteValue*)(propertyCacheEntry->dataValue.p);
+                            if(value)
+                            {
+                                result = value->GetByte();
+                            }
+                        }
+                        else
+                        {
+                            // Wrong data type
+                            // Exception!
+                            GWS_THROW (eGwsFdoInvalidDataType);
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+FdoDateTime CGwsBatchSortedBlockJoinQueryResults::GetDateTime(FdoString* propertyName)
+{
+    FdoDateTime result;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        if(propDesc->m_dataprop == FdoDataType_DateTime)
+                        {
+                            FdoDateTimeValue* value = (FdoDateTimeValue*)(propertyCacheEntry->dataValue.p);
+                            if(value)
+                            {
+                                result = value->GetDateTime();
+                            }
+                        }
+                        else
+                        {
+                            // Wrong data type
+                            // Exception!
+                            GWS_THROW (eGwsFdoInvalidDataType);
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+double CGwsBatchSortedBlockJoinQueryResults::GetDouble(FdoString* propertyName)
+{
+    double result = 0.0;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        if(propDesc->m_dataprop == FdoDataType_Double)
+                        {
+                            FdoDoubleValue* value = (FdoDoubleValue*)(propertyCacheEntry->dataValue.p);
+                            if(value)
+                            {
+                                result = value->GetDouble();
+                            }
+                        }
+                        else
+                        {
+                            // Wrong data type
+                            // Exception!
+                            GWS_THROW (eGwsFdoInvalidDataType);
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+FdoInt16 CGwsBatchSortedBlockJoinQueryResults::GetInt16(FdoString* propertyName)
+{
+    FdoInt16 result = 0;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        if(propDesc->m_dataprop == FdoDataType_Int16)
+                        {
+                            FdoInt16Value* value = (FdoInt16Value*)(propertyCacheEntry->dataValue.p);
+                            if(value)
+                            {
+                                result = value->GetInt16();
+                            }
+                        }
+                        else
+                        {
+                            // Wrong data type
+                            // Exception!
+                            GWS_THROW (eGwsFdoInvalidDataType);
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+FdoInt32 CGwsBatchSortedBlockJoinQueryResults::GetInt32(FdoString* propertyName)
+{
+    FdoInt32 result = 0;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        if(propDesc->m_dataprop == FdoDataType_Int32)
+                        {
+                            FdoInt32Value* value = (FdoInt32Value*)(propertyCacheEntry->dataValue.p);
+                            if(value)
+                            {
+                                result = value->GetInt32();
+                            }
+                        }
+                        else
+                        {
+                            // Wrong data type
+                            // Exception!
+                            GWS_THROW (eGwsFdoInvalidDataType);
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+FdoInt64 CGwsBatchSortedBlockJoinQueryResults::GetInt64(FdoString* propertyName)
+{
+    FdoInt64 result = 0;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        if(propDesc->m_dataprop == FdoDataType_Int64)
+                        {
+                            FdoInt64Value* value = (FdoInt64Value*)(propertyCacheEntry->dataValue.p);
+                            if(value)
+                            {
+                                result = value->GetInt64();
+                            }
+                        }
+                        else
+                        {
+                            // Wrong data type
+                            // Exception!
+                            GWS_THROW (eGwsFdoInvalidDataType);
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+float CGwsBatchSortedBlockJoinQueryResults::GetSingle(FdoString* propertyName)
+{
+    float result = 0.0;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        if(propDesc->m_dataprop == FdoDataType_Single)
+                        {
+                            FdoSingleValue* value = (FdoSingleValue*)(propertyCacheEntry->dataValue.p);
+                            if(value)
+                            {
+                                result = value->GetSingle();
+                            }
+                        }
+                        else
+                        {
+                            // Wrong data type
+                            // Exception!
+                            GWS_THROW (eGwsFdoInvalidDataType);
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+FdoLOBValue * CGwsBatchSortedBlockJoinQueryResults::GetLOB(FdoString* propertyName)
+{
+    FdoLOBValue* result = NULL;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        if(propDesc->m_dataprop == FdoDataType_CLOB)
+                        {
+                            FdoLOBValue* value = (FdoLOBValue*)(propertyCacheEntry->dataValue.p);
+                            if(value)
+                            {
+                                result = value;
+                            }
+                        }
+                        else
+                        {
+                            // Wrong data type
+                            // Exception!
+                            GWS_THROW (eGwsFdoInvalidDataType);
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+FdoIStreamReader* CGwsBatchSortedBlockJoinQueryResults::GetLOBStreamReader(const wchar_t* propertyName )
+{
+    // Not implemented
+    assert (false);
+    return NULL;
+}
+
+bool CGwsBatchSortedBlockJoinQueryResults::IsNull(FdoString* propertyName)
+{
+    bool result = false;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_DataProperty)
+                    {
+                        FdoDataValue* value = (FdoDataValue*)(propertyCacheEntry->dataValue.p);
+                        if(value)
+                        {
+                            result = value->IsNull();
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+FdoIRaster*  CGwsBatchSortedBlockJoinQueryResults::GetRaster(FdoString* propertyName)
+{
+    // Not implemented
+    assert (false);
+    return NULL;
+}
+FdoDataValue * CGwsBatchSortedBlockJoinQueryResults::GetPropertyValue (
+    const CGwsPropertyDesc & desc
+)
+{
+    if (desc.m_ptype != FdoPropertyType_DataProperty)
+        return NULL;
+
+    FdoDataValue* result = NULL;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(propDesc->m_dataprop == desc.m_dataprop)
+                {
+                    if(wcscmp(propDesc->m_name.c_str(), desc.m_name.c_str()) == 0)
+                    {
+                        FdoDataValue* value = (FdoDataValue*)(propertyCacheEntry->dataValue.p);
+                        if(value)
+                        {
+                            result = value;
+                        }
+
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+FdoDataValue * CGwsBatchSortedBlockJoinQueryResults::GetDataValue (FdoString* propertyName)
+{
+    const CGwsPropertyDesc & desc = GetPropertyDescriptor (propertyName);
+    if (desc.m_name.empty ())
+        return NULL;
+    return GetPropertyValue (desc);
+}
+
+FdoDataValueCollection * CGwsBatchSortedBlockJoinQueryResults::GetDataValues (
+    FdoStringCollection* propertyNames
+)
+{
+    CGwsDataValueCollection * vals = NULL;
+    for (int i = 0; i < propertyNames->GetCount (); i ++) {
+        FdoPtr<FdoDataValue> val = GetDataValue (propertyNames->GetString (i));
+        assert (val != NULL);
+        if (vals == NULL)
+            vals = (CGwsDataValueCollection *) CGwsDataValueCollection::Create ();
+        vals->Add (val);
+    }
+    return vals;
+}
+
+const FdoByte * CGwsBatchSortedBlockJoinQueryResults::GetGeometry(
+    FdoString * propertyName,
+    FdoInt32  * count
+)
+{
+    FdoByte * gvalue = NULL;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_GeometricProperty)
+                    {
+                        FdoByteArray* value = (FdoByteArray*)(propertyCacheEntry->geometry.p);
+                        if(value)
+                        {
+                            gvalue = value->GetData();
+
+                            if(count)
+                            {
+                                *count = value->GetCount();
+                            }
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    if (m_converter != NULL && ! m_bGeometryConverted && gvalue) {
+        EGwsStatus stat = m_converter->ConvertForward (gvalue, * count);
+        if (IGWSException::IsError (stat))
+            GWS_THROW (stat);
+        m_bGeometryConverted = true;
+    }
+    return gvalue;
+
+}
+
+FdoByteArray* CGwsBatchSortedBlockJoinQueryResults::GetGeometry(FdoString* propertyName)
+{
+    FdoByteArray * gvalue = NULL;
+
+    // Read from the cache
+    PrimaryCacheEntry* cacheEntry = *m_pPrimaryCacheIterator;
+    for(size_t i=0;i<cacheEntry->propertyCollection.size();i++)
+    {
+        PropertyCacheEntry* propertyCacheEntry = cacheEntry->propertyCollection.at(i);
+        if(propertyCacheEntry)
+        {
+            CGwsPropertyDesc* propDesc = m_propertyDescriptionCollection[i];
+            if(propDesc)
+            {
+                if(wcscmp(propDesc->m_name.c_str(), propertyName) == 0)
+                {
+                    if(propDesc->m_ptype == FdoPropertyType_GeometricProperty)
+                    {
+                        FdoByteArray* value = (FdoByteArray*)(propertyCacheEntry->geometry.p);
+                        if(value)
+                        {
+                            gvalue = value;
+                        }
+                    }
+                    else
+                    {
+                        // Invalid property type
+                        // Exception!
+                        GWS_THROW (eGwsFdoInvalidPropertyType);
+                    }
+
+                    break;
+                }
+            }
+        }
+    }
+
+    if (m_converter != NULL && ! m_bGeometryConverted && gvalue) {
+        EGwsStatus stat = m_converter->ConvertForward (gvalue);
+        if (IGWSException::IsError (stat))
+            GWS_THROW (stat);
+        m_bGeometryConverted = true;
+    }
+    return gvalue;
+}
+
+FdoByteArray * CGwsBatchSortedBlockJoinQueryResults::GetOriginalGeometry (FdoString* propertyName)
+{
+    return GetGeometry (propertyName);
+}
+
+FdoIFeatureReader* CGwsBatchSortedBlockJoinQueryResults::GetFeatureObject(FdoString* propertyName)
+{
+    // Not implemented
+    assert (false);
+    return NULL;
+}
+
+void CGwsBatchSortedBlockJoinQueryResults::ClearIteratorCache()
+{
+    for ( size_t i=0;i<m_pPrimaryCache.size();i++ )
+    {
+        PrimaryCacheEntry* primaryCacheEntry = m_pPrimaryCache.at(i);
+        if(primaryCacheEntry)
+        {
+            for(size_t j=0;j<primaryCacheEntry->propertyCollection.size();j++)
+            {
+                PropertyCacheEntry* propertyCacheEntry = primaryCacheEntry->propertyCollection.at(j);
+                if(propertyCacheEntry)
+                {
+                    delete propertyCacheEntry;
+                }
+            }
+
+            primaryCacheEntry->propertyCollection.clear();
+
+            delete primaryCacheEntry;
+        }
+    }
+
+    m_pPrimaryCache.clear();
+    m_pPrimaryCacheIterator = m_pPrimaryCache.begin();
+}
+
+void CGwsBatchSortedBlockJoinQueryResults::QuickSort(std::vector<PrimaryCacheEntry*>& cache, FdoInt32 left, FdoInt32 right)
+{
+    assert(left >= 0);
+    assert(right >= 0);
+
+    int i = left;
+    int j = right;
+    PrimaryCacheEntry* cacheEntry = cache[(left + right) / 2];
+
+    do {
+
+        while (QuickSortCompare(cache[i], cacheEntry))
+            i++;
+
+        while (QuickSortCompare(cacheEntry, cache[j]))
+            j--;
+
+        if (i <= j) {
+            if (i < j) {
+                PrimaryCacheEntry* tempCacheEntry = cache[i];
+                cache[i] = cache[j];
+                cache[j] = tempCacheEntry;
+            }
+
+            i++; j--;
+        }
+    } while (i <= j);
+
+    if (left < j)
+        QuickSort(cache, left, j);
+
+    if (i < right)
+        QuickSort(cache, i, right);
+}
+
+bool CGwsBatchSortedBlockJoinQueryResults::QuickSortCompare(PrimaryCacheEntry* compareA, PrimaryCacheEntry* compareB)
+{
+    bool bResult = false;
+
+    if((compareA != NULL) && (compareB != NULL))
+    {
+        FdoPtr<FdoDataValue> compareADataValue;
+        FdoPtr<FdoDataValue> compareBDataValue;
+
+        compareADataValue = compareA->primaryKey;
+        compareBDataValue = compareB->primaryKey;
+
+        FdoDataType dataType = compareADataValue->GetDataType();
+        switch (dataType)
+        {
+            case FdoDataType_Int32:
+                {
+                    FdoInt32 compareAValue = ((FdoInt32Value*)(compareADataValue.p))->GetInt32();
+                    FdoInt32 compareBValue = ((FdoInt32Value*)(compareBDataValue.p))->GetInt32();
+                    if(compareAValue < compareBValue)
+                    {
+                        bResult = true;
+                    }
+                }
+                break;
+            case FdoDataType_String:
+                    FdoStringP compareAValue = ((FdoStringValue*)(compareADataValue.p))->GetString();
+                    FdoStringP compareBValue = ((FdoStringValue*)(compareBDataValue.p))->GetString();
+                    if(wcscmp(compareAValue, compareBValue) < 0)
+                    {
+                        bResult = true;
+                    }
+                break;
+        }
+    }
+
+    return bResult;
+}


Property changes on: trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsBatchSortedBlockJoinQueryResults.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsFeatureSourceQuery.cpp
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsFeatureSourceQuery.cpp	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsFeatureSourceQuery.cpp	2007-02-23 00:41:58 UTC (rev 1130)
@@ -401,14 +401,18 @@
             if (rSupportsOrdering) {
                 // sort-merge
                 joinmethod = eGwsSortMerge;
-
             } else {
                 // nested loop join and sorted block
                 joinmethod = eGwsNestedLoopSortedBlock;
             }
         } else {
-            // nested loop join
-            joinmethod = eGwsNestedLoops;
+            if (rSupportsOrdering) {
+                joinmethod = eGwsBatchSortedBlock;
+            }
+            else {
+                // nested loop join
+                joinmethod = eGwsNestedLoops;
+            }
         }
 
         prepQuery = CreatePreparedJoinQuery (pFQuery->Type (),

Modified: trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedFeatureQuery.cpp
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedFeatureQuery.cpp	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedFeatureQuery.cpp	2007-02-23 00:41:58 UTC (rev 1130)
@@ -76,12 +76,16 @@
         return new CGwsNestedLoopsJoinQueryResults ();
     case eGwsNestedLoopSortedBlockIterator:
         return new CGwsNestedLoopSortedBlockJoinQueryResults ();
+    case eGwsBatchSortedBlockIterator:
+        return new CGwsBatchSortedBlockJoinQueryResults ();
     case eGwsRightSortMergeJoinIterator:
         return new CGwsRightSortedJoinQueryResults ();
     case eGwsRightNestedLoopsIterator:
         return new CGwsRightNestedLoopJoinQueryResults ();
     case eGwsRightNestedLoopSortedBlockIterator:
         return new CGwsRightNestedLoopSortedBlockJoinQueryResults ();
+    case eGwsRightBatchSortedBlockIterator:
+        return new CGwsRightBatchSortedBlockJoinQueryResults ();
     }
     return NULL;
 
@@ -357,8 +361,12 @@
     try {
         FdoPtr<FdoFilter> filter = ((FdoISelect *)m_pCommand.p)->GetFilter ();
         PrepareFilter (filter, m_bIsAxisAlignedRectangleFilter);
-        // do I need to set filter after converting it?
-
+        #ifdef _DEBUG
+        if(filter)
+        {
+            printf("Filter:%S\n\n", filter->ToString());
+        }
+        #endif
         //Code for executing an extended query - if it's requested (bScrollable)
         //AND if it's supported (m_bSdfExtendedQuerySupported)
         bool bGotScrollableIterator = false;

Modified: trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedJoinQuery.cpp
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedJoinQuery.cpp	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedJoinQuery.cpp	2007-02-23 00:41:58 UTC (rev 1130)
@@ -116,6 +116,8 @@
              reader = dynamic_cast<CGwsJoinQueryResults *> (CreateFeatureIterator (eGwsNestedLoopsIterator));
         } else if (m_joinmethod == eGwsNestedLoopSortedBlock) {
             reader = dynamic_cast<CGwsJoinQueryResults *> (CreateFeatureIterator (eGwsNestedLoopSortedBlockIterator));
+        } else if (m_joinmethod == eGwsBatchSortedBlock) {
+            reader = dynamic_cast<CGwsJoinQueryResults *> (CreateFeatureIterator (eGwsBatchSortedBlockIterator));
         }
 
         if (reader != NULL) {

Modified: trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsQueryEngine.vcproj
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsQueryEngine.vcproj	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsQueryEngine.vcproj	2007-02-23 00:41:58 UTC (rev 1130)
@@ -243,6 +243,10 @@
 			</File>
 		</Filter>
 		<File
+			RelativePath=".\GwsBatchSortedBlockJoinQueryResults.cpp"
+			>
+		</File>
+		<File
 			RelativePath=".\GwsBinaryFeature.cpp"
 			>
 		</File>
@@ -387,6 +391,10 @@
 			>
 		</File>
 		<File
+			RelativePath=".\GwsRightBatchSortedBlockJoinQueryResults.cpp"
+			>
+		</File>
+		<File
 			RelativePath=".\GwsRightJoinQueryResults.cpp"
 			>
 		</File>

Added: trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsRightBatchSortedBlockJoinQueryResults.cpp
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsRightBatchSortedBlockJoinQueryResults.cpp	                        (rev 0)
+++ trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsRightBatchSortedBlockJoinQueryResults.cpp	2007-02-23 00:41:58 UTC (rev 1130)
@@ -0,0 +1,163 @@
+//
+//  Copyright (C) 2004-2007  Autodesk, Inc.
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of version 2.1 of the GNU Lesser
+//  General Public License as published by the Free Software Foundation.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+
+/////////////////////////////////////////////////////////////////////
+//
+// Includes
+//
+/////////////////////////////////////////////////////////////////////
+#include "stdafx.h"
+
+#include "GwsQueryEngineImp.h"
+
+/////////////////////////////////////////////////////////////////////
+//
+// class CGwsRightBatchSortedBlockJoinQueryResults
+//
+/////////////////////////////////////////////////////////////////////
+CGwsRightBatchSortedBlockJoinQueryResults::CGwsRightBatchSortedBlockJoinQueryResults ()
+{
+    m_pos = eBeforeFirstRow;
+}
+
+CGwsRightBatchSortedBlockJoinQueryResults::~CGwsRightBatchSortedBlockJoinQueryResults () throw()
+{
+}
+
+EGwsStatus CGwsRightBatchSortedBlockJoinQueryResults::InitializeReader  (
+    IGWSQuery                  * query,
+    CGwsPreparedQuery          * prepquery,
+    FdoStringCollection        * joincols,
+    bool                       bScrollable
+)
+{
+    return CGwsRightNestedLoopJoinQueryResults::InitializeReader (query, prepquery, joincols, bScrollable);
+}
+
+bool CGwsRightBatchSortedBlockJoinQueryResults::ReadNext()
+{
+    if (m_usepool) {
+        // reading from the pool
+        if (m_poolpos + 1 < m_pool->GetCount ()) {
+            m_poolpos ++;
+            return true;
+        }
+        return false;
+    }
+
+    bool bRet = false;
+    if(m_pos == eBeforeFirstRow)
+    {
+        bRet = CGwsRightJoinQueryResults::ReadNext ();
+    }
+    else
+    {
+        // Next read will be for the next primary key so we don't want to advance the secondary
+        m_pos = eBeforeFirstRow;
+    }
+
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    printf("  CGwsRightBatchSortedBlockJoinQueryResults::ReadNext() - JoinColumns:%S\n", m_joincols->ToString());
+    #endif
+
+    if (bRet)
+    {
+        #ifdef _DEBUG_BATCHSORT_JOIN
+        printf("  CGwsRightBatchSortedBlockJoinQueryResults::ReadNext()\n");
+        #endif
+        m_pool->AddFeature (this);
+        m_pos = eOnJoinRow;
+    }
+    return bRet;
+}
+
+void CGwsRightBatchSortedBlockJoinQueryResults::Close ()
+{
+    CGwsRightNestedLoopJoinQueryResults::Close ();
+}
+
+EGwsStatus CGwsRightBatchSortedBlockJoinQueryResults::SetRelatedValues (
+    const GWSFeatureId & vals
+)
+{
+    #ifdef _DEBUG_BATCHSORT_JOIN
+    printf("  CGwsRightBatchSortedBlockJoinQueryResults::SetRelatedValues()\n");
+    #endif
+        if (m_joinkeys == vals) {
+            if (! m_neverusepooling) {
+                // this completes features pool
+                if (! m_bClosed) {
+                    while (ReadNext ())
+                        ;
+                    Close ();
+                }
+            }
+            m_usepool = true;
+            m_poolpos = -1;
+            return eGwsOk;
+        }
+        m_pool->Reset ();
+        m_usepool = false;
+        m_poolpos = -1;
+
+    // The code below is similar to the base class, but we want to use an IN clause in order to
+    // do a batch comparison instead of the typical = and LIKE operators.
+    EGwsStatus stat = eGwsOk;
+
+    try {
+        Close ();
+
+        FdoString* propname = m_joincols->GetString (0);
+        WSTR filter = propname;
+        filter += L" IN (";
+
+        FdoPtr<FdoFilter> pFilter = NULL;
+
+        for (int idx = 0; idx < vals.GetCount (); idx ++)
+        {
+            if(idx > 0)
+            {
+                filter += L",";
+            }
+
+            FdoPtr<FdoDataValue> val = vals.GetItem (idx);
+            FdoStringP valStr = val->ToString();
+            filter += valStr;
+        }
+
+        filter += L")";
+        pFilter = FdoFilter::Parse(filter.c_str());
+        m_prepquery->SetFilter (pFilter);
+
+        IGWSFeatureIterator * fiter = NULL;
+        stat = m_prepquery->Execute (& fiter);
+        if (IGWSException::IsError (stat)) {
+            PushStatus (stat);
+            return stat;
+        }
+        m_reader = dynamic_cast<FdoIFeatureReader*> (fiter);
+        m_bClosed = false;
+
+        stat = CGwsRightJoinQueryResults::SetRelatedValues (vals);
+
+    } catch (FdoException *e) {
+        PushFdoException (eGwsFailed, e);
+        e->Release();
+        stat = eGwsFailed;
+    }
+    return stat;
+}


Property changes on: trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsRightBatchSortedBlockJoinQueryResults.cpp
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsRightJoinQueryResults.cpp
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsRightJoinQueryResults.cpp	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/GwsQueryEngine/GwsRightJoinQueryResults.cpp	2007-02-23 00:41:58 UTC (rev 1130)
@@ -517,4 +517,9 @@
     return CGwsFeatureIterator::ToString (propertyName, buff, len);
 }
 
+FdoStringCollection* CGwsRightJoinQueryResults::GetJoinColumns()
+{
+    m_joincols.p->AddRef();
+    return m_joincols;
+}
 

Modified: trunk/MgDev/Server/src/Gws/GwsQueryEngine/Makefile.am
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsQueryEngine/Makefile.am	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/GwsQueryEngine/Makefile.am	2007-02-23 00:41:58 UTC (rev 1130)
@@ -5,6 +5,7 @@
 lib_LTLIBRARIES = libMgGwsQueryEngine.la
 
 libMgGwsQueryEngine_la_SOURCES = \
+  GwsBatchSortedBlockJoinQueryResults.cpp \
   GwsBinaryFeature.cpp \
   GwsBinaryFeatureReader.cpp \
   GwsBinaryFeatureWriter.cpp \
@@ -38,6 +39,7 @@
   GwsQueryFactories.cpp \
   GwsQueryUtils.cpp \
   GwsQueryXml.cpp \
+  GwsRightBatchSortedBlockJoinQueryResults.cpp \
   GwsRightJoinQueryResults.cpp \
   GwsRightNestedLoopJoinQueryResults.cpp \
   GwsRightNestedLoopSortedBlockJoinQueryResults.cpp \

Modified: trunk/MgDev/Server/src/Gws/GwsQueryEngine/inc/GwsQuery.h
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsQueryEngine/inc/GwsQuery.h	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/GwsQueryEngine/inc/GwsQuery.h	2007-02-23 00:41:58 UTC (rev 1130)
@@ -57,6 +57,12 @@
 } EGwsCacheFeatureStatus;
 
 
+typedef enum _EGwsCursorPosition {
+    eBeforeFirstRow,
+    eOnJoinRow,
+    eAfterJoinRow,
+    eAfterLastRow
+} EGwsCursorPosition;
 
 /////////////////////////////////////////////////////////////////////////////////
 //
@@ -71,6 +77,7 @@
     kGwsSortMergeResults = 1,
     kGwsNestedLoopSortBlockResults,
     kGwsNestedLoopResults,
+    kGwsBatchSortBlockResults,
     kGwsHashResults
 } EJoinResultsType;
 
@@ -79,6 +86,7 @@
     eGwsSortMerge = 1,
     eGwsNestedLoops,
     eGwsNestedLoopSortedBlock,
+    eGwsBatchSortedBlock,
     eGwsHash
 } EGwsJoinMethod;
 
@@ -88,9 +96,11 @@
     eGwsSortMergeJoinIterator,
     eGwsNestedLoopsIterator,
     eGwsNestedLoopSortedBlockIterator,
+    eGwsBatchSortedBlockIterator,
     eGwsRightSortMergeJoinIterator,
     eGwsRightNestedLoopsIterator,
-    eGwsRightNestedLoopSortedBlockIterator
+    eGwsRightNestedLoopSortedBlockIterator,
+    eGwsRightBatchSortedBlockIterator
 
 } EGwsFeatureIteratorType;
 
@@ -914,7 +924,7 @@
     GWS_QUERYENGINE_API
     virtual EJoinResultsType    Type () const = 0;
 
-    FdoDataValueCollection *    GetJoinValues ();
+    virtual FdoDataValueCollection *    GetJoinValues ();
 
     GWS_QUERYENGINE_API
     bool                        CacheReadNext ();
@@ -937,8 +947,8 @@
     bool                                    m_bLeftJoinValuesSet;
     bool                                    m_started;
     bool                                    m_forceOneToOne;
+    bool    SetupRightSide(bool leftResult);
 private:
-    bool    SetupRightSide(bool leftResult);
 };
 
 
@@ -1031,6 +1041,9 @@
     GWS_QUERYENGINE_API
     virtual void                ToString    (FdoString* propertyName, wchar_t * buff, int len);
 
+    GWS_QUERYENGINE_API
+    virtual FdoStringCollection* GetJoinColumns();
+
 protected:
     IGWSFeature *               GetPooledFeature ();
 
@@ -1138,9 +1151,126 @@
     }
 };
 
+typedef struct {
+    FdoPtr<FdoByteArray> geometry;
+    FdoPtr<FdoDataValue> dataValue;
+} PropertyCacheEntry;
 
+typedef std::vector< CGwsPropertyDesc* > PropertyDescriptionCollection;
+typedef std::vector< PropertyCacheEntry* > PropertyCollection;
+
+typedef struct {
+    PropertyCollection propertyCollection;
+    FdoPtr<FdoDataValue> primaryKey;
+} PrimaryCacheEntry;
+
 ///////////////////////////////////////////////////////////////////////////////
 //
+// class CGwsBatchSortedBlock
+// Left join results iterator. (Batch sorted block)
+//
+///////////////////////////////////////////////////////////////////////////////
+class CGwsBatchSortedBlockJoinQueryResults : public CGwsJoinQueryResults
+{
+friend class CGwsPreparedFeatureQuery;
+friend class CGwsPreparedLeftJoinQuery;
+friend class CGwsPreparedEqualJoinQuery;
+friend class CGwsPreparedJoinQuery;
+public:
+    GWS_QUERYENGINE_API     CGwsBatchSortedBlockJoinQueryResults  ();
+    GWS_QUERYENGINE_API
+    virtual                 ~CGwsBatchSortedBlockJoinQueryResults () throw();
+
+    GWS_QUERYENGINE_API
+    virtual EGwsStatus      InitializeReader (
+                                IGWSQuery                       * query,
+                                CGwsPreparedJoinQuery           * prepquery,
+                                bool                            bScrollable = false);
+    GWS_QUERYENGINE_API
+    virtual EJoinResultsType Type () const
+    {
+        return kGwsBatchSortBlockResults;
+    }
+
+    GWS_QUERYENGINE_API
+    virtual bool                ReadNext ();
+
+    GWS_QUERYENGINE_API
+    virtual IGWSFeatureIterator *  GetJoinedFeatures (int i);
+
+    // get right hand side joined features
+    IGWSFeatureIterator *       GetJoinedFeatures ();
+
+    virtual FdoDataValueCollection *    GetJoinValues ();
+
+    // Getters by the prperty name - this will come from the cache
+    GWS_QUERYENGINE_API
+    virtual bool            IsNull      (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoString   *   GetString   (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual bool            GetBoolean  (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoByte         GetByte     (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoDateTime     GetDateTime (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual double          GetDouble   (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoInt16        GetInt16    (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoInt32        GetInt32    (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoInt64        GetInt64    (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual float           GetSingle   (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoLOBValue*    GetLOB      (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoIStreamReader* GetLOBStreamReader(const wchar_t* propertyName );
+    GWS_QUERYENGINE_API
+    virtual FdoIRaster*     GetRaster   (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual const FdoByte * GetGeometry (FdoString* propertyName, FdoInt32 * count) ;
+    GWS_QUERYENGINE_API
+    virtual FdoByteArray*   GetGeometry (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoIFeatureReader* GetFeatureObject(FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoDataValue *  GetDataValue (FdoString* propertyName);
+    GWS_QUERYENGINE_API
+    virtual FdoDataValueCollection *
+        GetDataValues (FdoStringCollection* propertyNames);
+
+    // returns unconverted geometry. Coordinate system transaformations are not applied
+    GWS_QUERYENGINE_API
+    virtual FdoByteArray*   GetOriginalGeometry (FdoString* propertyName);
+
+    // get data property value
+    GWS_QUERYENGINE_API
+    virtual FdoDataValue *  GetPropertyValue (const CGwsPropertyDesc &);
+
+    GWS_QUERYENGINE_API
+    static int sm_nBatchSize;
+
+protected:
+    bool    SetupBatchRightSide(bool leftResult);
+    void    ClearIteratorCache();
+    void QuickSort(std::vector<PrimaryCacheEntry*>& cache, FdoInt32 left, FdoInt32 right);
+    bool QuickSortCompare(PrimaryCacheEntry* compareA, PrimaryCacheEntry* compareB);
+
+    IGWSFeatureIterator* m_primaryFeatureIterator;
+
+    FdoPtr<FdoStringCollection> m_propertyNames;
+    PropertyDescriptionCollection m_propertyDescriptionCollection;
+
+    // Primary iterator cache
+    std::vector<PrimaryCacheEntry*> m_pPrimaryCache;
+    std::vector<PrimaryCacheEntry*>::iterator m_pPrimaryCacheIterator;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
 // class CGwsRightSortedJoinQueryResults
 // ordered right side of the joined query results
 //
@@ -1171,14 +1301,6 @@
     virtual EGwsStatus          SetRelatedValues (const GWSFeatureId & vals);
 
 protected:
-    typedef enum _EGwsCursorPosition {
-        eBeforeFirstRow,
-        eOnJoinRow,
-        eAfterJoinRow,
-        eAfterLastRow
-    } EGwsCursorPosition;
-
-protected:
     EGwsCursorPosition      m_pos;
 };
 
@@ -1258,6 +1380,43 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 //
+// class CGwsRightBatchSortedBlockJoinQueryResults
+//
+// join batch sorted block right side
+//
+///////////////////////////////////////////////////////////////////////////////
+class CGwsRightBatchSortedBlockJoinQueryResults
+                    : public CGwsRightNestedLoopJoinQueryResults
+{
+friend class CGwsPreparedFeatureQuery;
+friend class CGwsPreparedLeftJoinQuery;
+friend class CGwsPreparedEqualJoinQuery;
+friend class CGwsPreparedJoinQuery;
+public:
+    GWS_QUERYENGINE_API         CGwsRightBatchSortedBlockJoinQueryResults ();
+    GWS_QUERYENGINE_API
+    virtual                     ~CGwsRightBatchSortedBlockJoinQueryResults () throw();
+
+
+    GWS_QUERYENGINE_API
+    virtual EGwsStatus          InitializeReader (
+                                    IGWSQuery                  * query,
+                                    CGwsPreparedQuery          * prepquery,
+                                    FdoStringCollection        * joincols,
+                                    bool                        bScrollable);
+
+    GWS_QUERYENGINE_API
+    virtual bool                ReadNext();
+    GWS_QUERYENGINE_API
+    virtual void                Close ();
+    GWS_QUERYENGINE_API
+    virtual EGwsStatus          SetRelatedValues (const GWSFeatureId & vals);
+protected:
+    EGwsCursorPosition      m_pos;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+//
 // class CGwsMultiSelectIterator
 // Wrapper, implemeting multiple selects during iteration
 // Must be able to wrap all iterator types

Modified: trunk/MgDev/Server/src/Gws/GwsResource/GwsResource.h
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsResource/GwsResource.h	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/GwsResource/GwsResource.h	2007-02-23 00:41:58 UTC (rev 1130)
@@ -211,6 +211,7 @@
 #define IDS_STRING_eGwsFeatureClassHasNoIdentity 1192
 #define IDS_PROGRESS_LAYEREXTENTS       1193
 #define IDS_PROGRESS_LAYER              1194
+#define IDS_STRING_eGwsFdoInvalidDataType 1195
 
 // Next default values for new objects
 // 

Modified: trunk/MgDev/Server/src/Gws/GwsResource/GwsResource.rc
===================================================================
--- trunk/MgDev/Server/src/Gws/GwsResource/GwsResource.rc	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/GwsResource/GwsResource.rc	2007-02-23 00:41:58 UTC (rev 1130)
@@ -435,6 +435,7 @@
     IDS_STRING_eGwsFeatureClassHasNoIdentity 
                             "Instance cannot be updated because the feature class doesn't have identity properties."
     IDS_PROGRESS_LAYEREXTENTS "Calculating layer extents..."
+    IDS_STRING_eGwsFdoInvalidDataType "Invalid data type."
 END
 
 #endif    // English (U.S.) resources

Modified: trunk/MgDev/Server/src/Gws/Include/GwsCommon.h
===================================================================
--- trunk/MgDev/Server/src/Gws/Include/GwsCommon.h	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Gws/Include/GwsCommon.h	2007-02-23 00:41:58 UTC (rev 1130)
@@ -223,6 +223,7 @@
     ,eGwsNoLayers
     ,eGwsFeatureSourceIsReadOnly
     ,eGwsFeatureClassHasNoIdentity
+    ,eGwsFdoInvalidDataType
 
 } EGwsStatus;
 

Modified: trunk/MgDev/Server/src/Services/Feature/Makefile.am
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/Makefile.am	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Services/Feature/Makefile.am	2007-02-23 00:41:58 UTC (rev 1130)
@@ -10,6 +10,7 @@
   -I../../../../Oem/dbxml-2.2.13/xerces-c-src/src \
   -I../../Gws/Include \
   -I../../Gws/GwsCommon/inc \
+  -I../../Gws/GwsQueryEngine/inc \
   -I../../../../Common/Security \
   -I../../../../Common/Foundation \
   -I../../../../Common/Geometry \

Modified: trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcproj
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcproj	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Services/Feature/ServerFeatureService.vcproj	2007-02-23 00:41:58 UTC (rev 1130)
@@ -41,7 +41,7 @@
 			<Tool
 				Name="VCCLCompilerTool"
 				Optimization="0"
-				AdditionalIncludeDirectories="..\..\..\..\Oem\ACE\ACE_wrappers;&quot;..\..\..\..\Oem\dbxml-2.2.13\xerces-c-src\src&quot;;..\..\..\..\Oem\FDO\inc;..\..\..\..\Common\CoordinateSystem;..\..\..\..\Common\Security;..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\..\..\Common\MdfParser;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\..\Common\ServerUtil;..\..\Gws\Include;..\..\Gws\GwsCommon\inc"
+				AdditionalIncludeDirectories="..\..\..\..\Oem\ACE\ACE_wrappers;&quot;..\..\..\..\Oem\dbxml-2.2.13\xerces-c-src\src&quot;;..\..\..\..\Oem\FDO\inc;..\..\..\..\Common\CoordinateSystem;..\..\..\..\Common\Security;..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\..\..\Common\MdfParser;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\..\Common\ServerUtil;..\..\Gws\Include;..\..\Gws\GwsCommon\inc;..\..\Gws\GwsQueryEngine\inc"
 				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MG_SERVER_FEATURE_EXPORTS"
 				MinimalRebuild="true"
 				ExceptionHandling="2"
@@ -123,7 +123,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalIncludeDirectories="..\..\..\..\Oem\ACE\ACE_wrappers;&quot;..\..\..\..\Oem\dbxml-2.2.13\xerces-c-src\src&quot;;..\..\..\..\Oem\FDO\inc;..\..\..\..\Common\CoordinateSystem;..\..\..\..\Common\Security;..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\..\..\Common\MdfParser;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\..\Common\ServerUtil;..\..\Gws\Include;..\..\Gws\GwsCommon\inc"
+				AdditionalIncludeDirectories="..\..\..\..\Oem\ACE\ACE_wrappers;&quot;..\..\..\..\Oem\dbxml-2.2.13\xerces-c-src\src&quot;;..\..\..\..\Oem\FDO\inc;..\..\..\..\Common\CoordinateSystem;..\..\..\..\Common\Security;..\..\..\..\Common\Foundation;..\..\..\..\Common\Geometry;..\..\..\..\Common\PlatformBase;..\..\..\..\Common\MapGuideCommon;..\..\..\..\Common\MdfModel;..\..\..\..\Common\MdfParser;..\..\Common;..\..\Common\Base;..\..\Common\Manager;..\..\Common\ServerUtil;..\..\Gws\Include;..\..\Gws\GwsCommon\inc;..\..\Gws\GwsQueryEngine\inc"
 				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MG_SERVER_FEATURE_EXPORTS"
 				ExceptionHandling="2"
 				RuntimeLibrary="2"

Modified: trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.cpp	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.cpp	2007-02-23 00:41:58 UTC (rev 1130)
@@ -16,6 +16,7 @@
 //
 
 #include "ServerFeatureServiceDefs.h"
+#include "MapGuideCommon.h"
 #include "Services/FeatureService.h"
 #include "ServerSelectFeatures.h"
 #include "ServerFeatureConnection.h"
@@ -30,6 +31,10 @@
 
 #include "ServerGwsFeatureReader.h"
 #include "GwsConnectionPool.h"
+#include "GwsCommonImp.h"
+#include "GwsMutableFeature.h"
+#include "GwsFdoCommand.h"
+#include "GwsQuery.h"
 
 
 MgServerSelectFeatures::MgServerSelectFeatures()
@@ -40,6 +45,19 @@
     m_customFunction = NULL;
     m_customPropertyName = L"";
     m_featureSource = NULL;
+
+    // Set a default join query batch size
+    m_nJoinQueryBatchSize = MgConfigProperties::DefaultFeatureServicePropertyJoinQueryBatchSize;
+
+    // Get the join batch size
+    MgConfiguration* config = MgConfiguration::GetInstance();
+    if(config)
+    {
+        config->GetIntValue(MgConfigProperties::FeatureServicePropertiesSection,
+                            MgConfigProperties::FeatureServicePropertyJoinQueryBatchSize,
+                            m_nJoinQueryBatchSize,
+                            MgConfigProperties::DefaultFeatureServicePropertyJoinQueryBatchSize);
+    }
 }
 
 MgServerSelectFeatures::~MgServerSelectFeatures()
@@ -380,7 +398,7 @@
         {
             FdoPtr<FdoIGeometry> geometry = geometryFactory->CreateGeometryFromFgf(byteArray);
             STRING geomText = geometry->GetText();
-            ACE_DEBUG((LM_ERROR, ACE_TEXT("SPATIAL FILTER: %W\n"), geomText.c_str()));
+            ACE_DEBUG((LM_ERROR, ACE_TEXT("SPATIAL FILTER:\n%W\n\n"), geomText.c_str()));
         }
         #endif
 
@@ -997,6 +1015,9 @@
             FdoPtr<IGWSFeatureIterator> iter;
             FdoPtr<IGWSFeatureIterator> iterCopy;
 
+            // Set batch size as it may be needed
+            CGwsBatchSortedBlockJoinQueryResults::sm_nBatchSize = m_nJoinQueryBatchSize;
+
             // Prepare and Execute Query
             query->Prepare();
             query->Execute(&iter, true);

Modified: trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.h
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.h	2007-02-22 23:22:12 UTC (rev 1129)
+++ trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.h	2007-02-23 00:41:58 UTC (rev 1130)
@@ -86,6 +86,9 @@
     MgResourceIdentifier* GetSecondaryResourceIdentifier(MgResourceIdentifier* primResId, CREFSTRING extensionName, CREFSTRING relationName);
 
     MdfModel::FeatureSource* GetFeatureSource(MgResourceIdentifier* resource);
+
+    // This setting limits the batch size used by the join query algorithm
+    INT32 m_nJoinQueryBatchSize;
 };
 
 #endif



More information about the mapguide-commits mailing list