[mapguide-commits] r4399 - in sandbox/rfc60/MgDev/Server/src: Common/Manager Core Gws/GwsQueryEngine Gws/GwsQueryEngine/inc Gws/Include Services/Feature Services/Mapping Services/Rendering Services/Resource UnitTesting

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Wed Dec 9 12:38:17 EST 2009


Author: uvlite
Date: 2009-12-09 12:38:17 -0500 (Wed, 09 Dec 2009)
New Revision: 4399

Modified:
   sandbox/rfc60/MgDev/Server/src/Common/Manager/FdoConnectionManager.cpp
   sandbox/rfc60/MgDev/Server/src/Common/Manager/FdoConnectionManager.h
   sandbox/rfc60/MgDev/Server/src/Core/Server.cpp
   sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/GwsExtendedFeatureDescription.cpp
   sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedFeatureQuery.cpp
   sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/inc/GwsQuery.h
   sandbox/rfc60/MgDev/Server/src/Gws/Include/GwsQueryEngine.h
   sandbox/rfc60/MgDev/Server/src/Services/Feature/ServerGwsFeatureReader.cpp
   sandbox/rfc60/MgDev/Server/src/Services/Feature/ServerGwsFeatureReader.h
   sandbox/rfc60/MgDev/Server/src/Services/Mapping/MappingUtil.cpp
   sandbox/rfc60/MgDev/Server/src/Services/Rendering/FeatureInfoRenderer.h
   sandbox/rfc60/MgDev/Server/src/Services/Resource/ResourceOperationFactory.cpp
   sandbox/rfc60/MgDev/Server/src/Services/Resource/ServerResourceService.cpp
   sandbox/rfc60/MgDev/Server/src/UnitTesting/TestPerformance.cpp
Log:
RFC60 merged trunk to sandbox 

Modified: sandbox/rfc60/MgDev/Server/src/Common/Manager/FdoConnectionManager.cpp
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Common/Manager/FdoConnectionManager.cpp	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Common/Manager/FdoConnectionManager.cpp	2009-12-09 17:38:17 UTC (rev 4399)
@@ -97,7 +97,8 @@
                                         INT32 nFdoConnectionPoolSize,
                                         INT32 nFdoConnectionTimeout,
                                         STRING excludedProviders,
-                                        STRING fdoConnectionPoolSizeCustom)
+                                        STRING fdoConnectionPoolSizeCustom,
+                                        STRING fdoConnectionUseLimit)
 {
     MG_FDOCONNECTION_MANAGER_TRY()
 
@@ -121,6 +122,8 @@
 
     m_fdoConnectionPoolSizeCustomCol = MgStringCollection::ParseCollection(fdoConnectionPoolSizeCustom, L",");
 
+    m_fdoConnectionUseLimitCol = MgStringCollection::ParseCollection(fdoConnectionUseLimit, L",");
+
     // Update the provider cache size collection
     if (m_fdoConnectionPoolSizeCustomCol.p)
     {
@@ -142,7 +145,7 @@
                 nCustomPoolSize = MgUtil::StringToInt32(value);
             }
 
-            ProviderInfo* providerInfo = new ProviderInfo(provider, nCustomPoolSize, (FdoThreadCapability)-1, (m_bFdoConnectionPoolEnabled & !IsExcludedProvider(provider)));
+            ProviderInfo* providerInfo = new ProviderInfo(provider, nCustomPoolSize, (FdoThreadCapability)-1, (m_bFdoConnectionPoolEnabled & !IsExcludedProvider(provider)), -1);
             if(providerInfo)
             {
                 m_ProviderInfoCollection.insert(ProviderInfoCacheEntry_Pair(provider, providerInfo));
@@ -150,6 +153,49 @@
         }
     }
 
+    // Update the provider cache size collection
+    if (m_fdoConnectionUseLimitCol.p)
+    {
+        for(INT32 i=0;i<m_fdoConnectionUseLimitCol->GetCount();i++)
+        {
+            STRING providerUseLimit =  m_fdoConnectionUseLimitCol->GetItem(i);
+
+            STRING provider = providerUseLimit;
+            INT32 useLimit = -1;   // No limit
+
+            // Parse the format: provider:useLimit
+            // Example: OSGeo.SDF:1000
+
+            size_t position = providerUseLimit.find(L":", 0); // NOXLATE
+            if(position != string::npos)
+            {
+                provider = providerUseLimit.substr(0, position);
+                STRING value = providerUseLimit.substr(position+1, providerUseLimit.size());
+                useLimit = MgUtil::StringToInt32(value);
+            }
+
+            ProviderInfoCollection::iterator iterProviderInfoCollection = m_ProviderInfoCollection.find(provider);
+            if(m_ProviderInfoCollection.end() != iterProviderInfoCollection)
+            {
+                ProviderInfo* providerInfo = iterProviderInfoCollection->second;
+                if(providerInfo)
+                {
+                    // Update the use limit
+                    providerInfo->SetUseLimit(useLimit);
+                }
+            }
+            else
+            {
+                // Not found so add it
+                ProviderInfo* providerInfo = new ProviderInfo(provider, nFdoConnectionPoolSize, (FdoThreadCapability)-1, (m_bFdoConnectionPoolEnabled & !IsExcludedProvider(provider)), useLimit);
+                if(providerInfo)
+                {
+                    m_ProviderInfoCollection.insert(ProviderInfoCacheEntry_Pair(provider, providerInfo));
+                }
+            }
+        }
+    }
+
 #ifdef _DEBUG
     ShowProviderInfoCache();
 #endif
@@ -432,9 +478,10 @@
                     if(pFdoConnectionCacheEntry)
                     {
                         INT32 time = now.sec() - pFdoConnectionCacheEntry->lastUsed.sec();
-                        if((time > m_nFdoConnectionTimeout) || (!pFdoConnectionCacheEntry->bValid))
+                        INT32 useLimit = providerInfo->GetUseLimit();
+                        if((time > m_nFdoConnectionTimeout) || (!pFdoConnectionCacheEntry->bValid) || (useLimit != -1 && pFdoConnectionCacheEntry->nUseTotal >= useLimit))
                         {
-                            // Connection has expired or is no longer valid so close it and remove it
+                            // Connection has expired or is no longer valid or has reached the use limit so close it and remove it
                             if (pFdoConnectionCacheEntry->pFdoConnection)
                             {
                                 // Is it in use?
@@ -604,6 +651,9 @@
                             if(pFdoConnectionCacheEntry->ltName == ltName)
                             {
                                 // We have a long transaction name match
+                                INT32 useLimit = providerInfo->GetUseLimit();
+                                if (useLimit == -1 || pFdoConnectionCacheEntry->nUseTotal <= useLimit)
+                                {
                                 if((!pFdoConnectionCacheEntry->bInUse) || 
                                    (providerInfo->GetThreadModel() == FdoThreadCapability_PerCommandThreaded) ||
                                    (providerInfo->GetThreadModel() == FdoThreadCapability_MultiThreaded))
@@ -612,6 +662,7 @@
                                     pFdoConnectionCacheEntry->lastUsed = ACE_OS::gettimeofday();
                                     pFdoConnectionCacheEntry->bInUse = true;
                                     pFdoConnectionCacheEntry->nUseCount++;  // Only used by PerCommandThreaded/MultiThreaded
+                                        pFdoConnectionCacheEntry->nUseTotal++;
 
                                     // Check to see if the key is blank which indicates a blank connection string was cached
                                     if(0 < key.size())
@@ -631,6 +682,7 @@
                             }
                         }
                     }
+                    }
 
                     // Next match
                     iter++;
@@ -1093,6 +1145,7 @@
             pFdoConnectionCacheEntry->bValid = true;
             pFdoConnectionCacheEntry->bInUse = true;
             pFdoConnectionCacheEntry->nUseCount = 1;
+            pFdoConnectionCacheEntry->nUseTotal = 1;
 
             #ifdef _DEBUG_FDOCONNECTION_MANAGER
             ACE_DEBUG ((LM_DEBUG, ACE_TEXT("CacheFdoConnection:\nConnection: %@\nProvider = %W\nKey = %W\nVersion(LT) = %W\n\n"), (void*)pFdoConnection, provider.c_str(), key.c_str(), ltName.empty() ? L"(empty)" : ltName.c_str()));
@@ -1255,7 +1308,7 @@
     else
     {
         // Provider information has not been cached yet so a connection will be available.
-        providerInfo = new ProviderInfo(provider, m_nFdoConnectionPoolSize, (FdoThreadCapability)-1, (m_bFdoConnectionPoolEnabled & !IsExcludedProvider(provider)));
+        providerInfo = new ProviderInfo(provider, m_nFdoConnectionPoolSize, (FdoThreadCapability)-1, (m_bFdoConnectionPoolEnabled & !IsExcludedProvider(provider)), -1);
         if(providerInfo)
         {
             m_ProviderInfoCollection.insert(ProviderInfoCacheEntry_Pair(provider, providerInfo));
@@ -1459,7 +1512,7 @@
     if(NULL == providerInfo)
     {
         // Create new entry
-        providerInfo = new ProviderInfo(provider, m_nFdoConnectionPoolSize, (FdoThreadCapability)-1, (m_bFdoConnectionPoolEnabled & !IsExcludedProvider(provider)));
+        providerInfo = new ProviderInfo(provider, m_nFdoConnectionPoolSize, (FdoThreadCapability)-1, (m_bFdoConnectionPoolEnabled & !IsExcludedProvider(provider)), -1);
         if(providerInfo)
         {
             m_ProviderInfoCollection.insert(ProviderInfoCacheEntry_Pair(provider, providerInfo));

Modified: sandbox/rfc60/MgDev/Server/src/Common/Manager/FdoConnectionManager.h
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Common/Manager/FdoConnectionManager.h	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Common/Manager/FdoConnectionManager.h	2009-12-09 17:38:17 UTC (rev 4399)
@@ -42,6 +42,7 @@
     bool bValid;
     bool bInUse;
     INT32 nUseCount;    // Used by PerCommandThreaded/MultiThreaded providers
+    INT32 nUseTotal;    // Total number of times this connection has been used
 } FdoConnectionCacheEntry;
 
 // FDO Connection Cache
@@ -55,12 +56,14 @@
     ProviderInfo(STRING provider,
                  INT32 poolSize,
                  FdoThreadCapability threadModel,
-                 bool bKeepCached)
+                 bool bKeepCached,
+                 INT32 useLimit)
     {
         m_provider = provider;
         m_poolSize = poolSize;
         m_threadModel = threadModel;
         m_bKeepCached = bKeepCached;
+        m_useLimit = useLimit;
 
         m_currentConnections = 0;
     }
@@ -154,6 +157,18 @@
 
     STRING GetProviderName()                        { return m_provider; }
 
+    INT32 GetUseLimit()
+    {
+        ACE_MT(ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex, -1));
+        return m_useLimit;
+    }
+
+    void SetUseLimit(INT32 useLimit)
+    {
+        ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sm_mutex));
+        m_useLimit = useLimit;
+    }
+
 private:
     // The name of the provider
     STRING m_provider;
@@ -173,6 +188,9 @@
     // The flag indicating if the FDO connections for this provider should be cached
     bool m_bKeepCached;
 
+    // The # of times this FDO connections can be used before it is released
+    INT32 m_useLimit;
+
     static ACE_Recursive_Thread_Mutex sm_mutex;
 };
 
@@ -197,7 +215,8 @@
                     INT32 nFdoConnectionPoolSize,
                     INT32 nFdoConnectionTimeout,
                     STRING excludedProviders,
-                    STRING fdoConnectionPoolSizeCustom);
+                    STRING fdoConnectionPoolSizeCustom,
+                    STRING fdoConnectionUseLimit);
 
     static void Terminate();
     void ClearCache();
@@ -258,6 +277,7 @@
     INT32 m_nFdoConnectionTimeout;
     Ptr<MgStringCollection> m_excludedProviders;
     Ptr<MgStringCollection> m_fdoConnectionPoolSizeCustomCol;
+    Ptr<MgStringCollection> m_fdoConnectionUseLimitCol;
 };
 
 #endif

Modified: sandbox/rfc60/MgDev/Server/src/Core/Server.cpp
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Core/Server.cpp	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Core/Server.cpp	2009-12-09 17:38:17 UTC (rev 4399)
@@ -890,11 +890,13 @@
             INT32 nDataConnectionPoolSize = MgConfigProperties::DefaultFeatureServicePropertyDataConnectionPoolSize;
             STRING dataConnectionPoolExcludedProviders = MgConfigProperties::DefaultFeatureServicePropertyDataConnectionPoolExcludedProviders;
             STRING dataConnectionPoolSizeCustom = MgConfigProperties::DefaultFeatureServicePropertyDataConnectionPoolSizeCustom;
+            STRING dataConnectionUseLimit = MgConfigProperties::DefaultFeatureServicePropertyDataConnectionUseLimit;
 
             pConfiguration->GetBoolValue(MgConfigProperties::FeatureServicePropertiesSection, MgConfigProperties::FeatureServicePropertyDataConnectionPoolEnabled, bDataConnectionPoolEnabled, MgConfigProperties::DefaultFeatureServicePropertyDataConnectionPoolEnabled);
             pConfiguration->GetIntValue(MgConfigProperties::FeatureServicePropertiesSection, MgConfigProperties::FeatureServicePropertyDataConnectionPoolSize, nDataConnectionPoolSize, MgConfigProperties::DefaultFeatureServicePropertyDataConnectionPoolSize);
             pConfiguration->GetStringValue(MgConfigProperties::FeatureServicePropertiesSection, MgConfigProperties::FeatureServicePropertyDataConnectionPoolExcludedProviders, dataConnectionPoolExcludedProviders, MgConfigProperties::DefaultFeatureServicePropertyDataConnectionPoolExcludedProviders);
             pConfiguration->GetStringValue(MgConfigProperties::FeatureServicePropertiesSection, MgConfigProperties::FeatureServicePropertyDataConnectionPoolSizeCustom, dataConnectionPoolSizeCustom, MgConfigProperties::DefaultFeatureServicePropertyDataConnectionPoolSizeCustom);
+            pConfiguration->GetStringValue(MgConfigProperties::FeatureServicePropertiesSection, MgConfigProperties::FeatureServicePropertyDataConnectionUseLimit, dataConnectionUseLimit, MgConfigProperties::DefaultFeatureServicePropertyDataConnectionUseLimit);
 
             // Add additional font mappings to the FontManager
             ACE_DEBUG((LM_DEBUG, ACE_TEXT("(%t) MgServer::open() - Adding Font Manager Mappings.\n")));
@@ -983,7 +985,7 @@
             ACE_DEBUG ((LM_DEBUG, ACE_TEXT("(%t) MgServer::open() - Initializing FDO Connection Manager.\n")));
             MgEventTimer& dataConnectionTimer = m_eventTimerManager.GetEventTimer(MgEventTimer::DataConnectionTimeout);
             MgFdoConnectionManager* pFdoConnectionManager = MgFdoConnectionManager::GetInstance();
-            pFdoConnectionManager->Initialize(bDataConnectionPoolEnabled, nDataConnectionPoolSize, dataConnectionTimer.GetEventTimeout(), dataConnectionPoolExcludedProviders, dataConnectionPoolSizeCustom);
+            pFdoConnectionManager->Initialize(bDataConnectionPoolEnabled, nDataConnectionPoolSize, dataConnectionTimer.GetEventTimeout(), dataConnectionPoolExcludedProviders, dataConnectionPoolSizeCustom, dataConnectionUseLimit);
 
             // On startup, perform the service registration for the Site server.
             // Note that this event will be perfomed by a timer for the Support server.

Modified: sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/GwsExtendedFeatureDescription.cpp
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/GwsExtendedFeatureDescription.cpp	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/GwsExtendedFeatureDescription.cpp	2009-12-09 17:38:17 UTC (rev 4399)
@@ -52,6 +52,7 @@
     m_joinName = other.m_joinName;
     m_joinDelimiter = other.m_joinDelimiter;
     m_forceOneToOne = other.m_forceOneToOne;
+    m_leftOuterJoin = other.m_leftOuterJoin;
     CGwsQueryResultDescriptors & src = (CGwsQueryResultDescriptors &) other;
     for (int i = 0; i < src.GetCount (); i ++) {
         FdoPtr<IGWSExtendedFeatureDescription> fdsc = src.GetItem (i);
@@ -66,7 +67,8 @@
     const FdoString        * joinName,
     const FdoString        * joinDelimiter,
     bool                     forceOneToOne,
-    FdoIdentifierCollection    * propnames
+    FdoIdentifierCollection    * propnames,
+    bool                     leftOuterJoin
 )
 {
     m_classDef = classDef;
@@ -78,6 +80,7 @@
     if(NULL != joinDelimiter)
         m_joinDelimiter = joinDelimiter;
     m_forceOneToOne = forceOneToOne;
+    m_leftOuterJoin = leftOuterJoin;
     m_propertynames = FdoStringCollection::Create ();
     appendPropertyNames (propnames, classDef, m_propertynames, m_propdsc);
     if( propnames != NULL )

Modified: sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedFeatureQuery.cpp
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedFeatureQuery.cpp	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/GwsPreparedFeatureQuery.cpp	2009-12-09 17:38:17 UTC (rev 4399)
@@ -169,7 +169,7 @@
             m_resultDescriptor->Release();
         }
         if(jqd)
-            m_resultDescriptor = new CGwsQueryResultDescriptors (m_classDef, m_classname, jqd->JoinName(), jqd->JoinDelimiter(), jqd->ForceOneToOne(), sellist);
+            m_resultDescriptor = new CGwsQueryResultDescriptors (m_classDef, m_classname, jqd->JoinName(), jqd->JoinDelimiter(), jqd->ForceOneToOne(), sellist, qDef->Type() == eGwsQueryLeftOuterJoin);
         else
             m_resultDescriptor = new CGwsQueryResultDescriptors (m_classDef, m_classname, NULL, NULL, true, sellist);
         m_resultDescriptor->AddRef ();
@@ -251,6 +251,7 @@
 
     } catch (FdoException * fdoEx) {
         PushFdoException (eGwsFdoProviderError, fdoEx);
+        fdoEx->Release ();
         stat = eGwsFdoProviderError;
     }
 

Modified: sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/inc/GwsQuery.h
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/inc/GwsQuery.h	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Gws/GwsQueryEngine/inc/GwsQuery.h	2009-12-09 17:38:17 UTC (rev 4399)
@@ -180,7 +180,8 @@
                                             const FdoString        * joinName,
                                             const FdoString        * joinDelimiter,
                                             bool                     forceOneToOne,
-                                            FdoIdentifierCollection    * propnames);
+                                            FdoIdentifierCollection    * propnames,
+                                            bool                   leftOuterJoin = false);
     GWS_QUERYENGINE_API             CGwsQueryResultDescriptors (const CGwsQueryResultDescriptors & other);
     GWS_QUERYENGINE_API
     virtual                         ~CGwsQueryResultDescriptors () throw();
@@ -229,6 +230,7 @@
     void                             SetCSName (const GWSCoordinateSystem & csname);
 
     virtual bool                    ForceOneToOneJoin() { return m_forceOneToOne; }
+    virtual bool                    LeftOuterJoin() { return m_leftOuterJoin; };
 
 protected:
      void                           appendPropertyNames (
@@ -255,6 +257,7 @@
     WSTR                                m_joinName;
     WSTR                                m_joinDelimiter;
     bool                                m_forceOneToOne;
+    bool                                m_leftOuterJoin;
 
     // joined properties
     std::vector<IGWSExtendedFeatureDescription*>

Modified: sandbox/rfc60/MgDev/Server/src/Gws/Include/GwsQueryEngine.h
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Gws/Include/GwsQueryEngine.h	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Gws/Include/GwsQueryEngine.h	2009-12-09 17:38:17 UTC (rev 4399)
@@ -413,6 +413,12 @@
     /// </summary>
     /// <returns>Returns the force one to one flag.</returns>
     virtual bool ForceOneToOneJoin() = 0;
+
+    /// </summary>
+    /// Returns whether the join is a left outer join.
+    /// </summary>
+    /// <returns>Returns whether the join is a left outer join.</returns>
+    virtual bool LeftOuterJoin() = 0;
 };
 
 

Modified: sandbox/rfc60/MgDev/Server/src/Services/Feature/ServerGwsFeatureReader.cpp
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Services/Feature/ServerGwsFeatureReader.cpp	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Services/Feature/ServerGwsFeatureReader.cpp	2009-12-09 17:38:17 UTC (rev 4399)
@@ -219,13 +219,25 @@
                             {
                                 // Since key values in this Pair do not need to be unqiue, we will use it to store the delimiter string that is defined
                                 // for the extended properties that originate from this secondary feature source
-                                m_secondaryGwsFeatureIteratorMap.insert(GwsFeatureIteratorPair(attributeNameDelimiter, secondaryIter));
+                                m_secondaryGwsFeatureIteratorMap.insert(GwsFeatureIteratorPair(attributeNameDelimiter, GwsRightSideIterator(secondaryIter,true)));
                             }
                             else
                             {
+                                FdoPtr<IGWSExtendedFeatureDescription> pDesc = m_primaryExtendedFeatureDescription->GetItem(i);
+                                if(pDesc->LeftOuterJoin())
+                                {
+                                    // Fix ticket #1162
+                                    // If we are processing left-outer joins, we don't skip the left side feature even though
+                                    // there is no right side feature exists.
+                                    m_secondaryGwsFeatureIteratorMap.insert(GwsFeatureIteratorPair(attributeNameDelimiter, GwsRightSideIterator(secondaryIter,false)));
+                                    retVal = true;
+                                }
+                                else
+                                {
                                 m_bAdvancePrimaryIterator = true;
                             }
                         }
+                        }
                         else
                         {
                             m_bAdvancePrimaryIterator = true;
@@ -264,7 +276,7 @@
                 if (m_secondaryGwsFeatureIteratorMap.size() > 0)
                 {
                     iter = m_secondaryGwsFeatureIteratorMap.begin();
-                    secondaryFeatureIter = iter->second;
+                    secondaryFeatureIter = iter->second.Iterator();
                     retVal = secondaryFeatureIter->ReadNext();
                 }
 
@@ -277,7 +289,7 @@
                     if (m_secondaryGwsFeatureIteratorMap.size() > 0)
                     {
                         iter = m_secondaryGwsFeatureIteratorMap.begin();
-                        secondaryFeatureIter = iter->second;
+                        secondaryFeatureIter = iter->second.Iterator();
                         retVal = secondaryFeatureIter->ReadNext();
                     }
                 }
@@ -324,13 +336,25 @@
                                     {
                                         // Since key values in this Pair do not need to be unqiue, we will use it to store the delimiter string that is defined
                                         // for the extended properties that originate from this secondary feature source
-                                        m_secondaryGwsFeatureIteratorMap.insert(GwsFeatureIteratorPair(attributeNameDelimiter, featureIter2));
+                                        m_secondaryGwsFeatureIteratorMap.insert(GwsFeatureIteratorPair(attributeNameDelimiter, GwsRightSideIterator(featureIter2,true)));
                                     }
                                     else
                                     {
+                                        FdoPtr<IGWSExtendedFeatureDescription> pDesc = m_primaryExtendedFeatureDescription->GetItem(i);
+                                        if(pDesc->LeftOuterJoin())
+                                        {
+                                            // Fix ticket #1162
+                                            // If we are processing left-outer joins, we don't skip the left side feature even though
+                                            // there is no right side feature exists.
+                                            m_secondaryGwsFeatureIteratorMap.insert(GwsFeatureIteratorPair(attributeNameDelimiter, GwsRightSideIterator(featureIter2,false)));
+                                            retVal = true;
+                                        }
+                                        else
+                                        {
                                         m_bAdvancePrimaryIterator = true;
                                     }
                                 }
+                                }
                                 else
                                 {
                                     m_bAdvancePrimaryIterator = true;
@@ -1232,7 +1256,7 @@
              iter != m_secondaryGwsFeatureIteratorMap.end();
              iter++)
         {
-            IGWSFeatureIterator* pSecondaryFeatureIter = iter->second;
+            IGWSFeatureIterator* pSecondaryFeatureIter = iter->second.Iterator();
             if (pSecondaryFeatureIter)
             {
                 pSecondaryFeatureIter->Close();
@@ -1418,7 +1442,7 @@
              iter != m_secondaryGwsFeatureIteratorMap.end();
              iter++)
         {
-            secondaryFeatureIter = iter->second;
+            secondaryFeatureIter = iter->second.Iterator();
             CHECKNULL(secondaryFeatureIter, L"MgServerGwsFeatureReader.DeterminePropertyFeatureSource");
 
             FdoPtr<IGWSExtendedFeatureDescription> secondaryDesc;
@@ -1443,7 +1467,7 @@
 
                 if ( wcscmp(featureSource, relationName.c_str()) == 0 )
                 {
-                    *gwsFeatureIter = secondaryFeatureIter;
+                    *gwsFeatureIter = iter->second.HasData() ? secondaryFeatureIter : NULL;
                     className = (wchar_t*)fclassName;
                     iter = m_secondaryGwsFeatureIteratorMap.end();
                     iter--;
@@ -1746,7 +1770,7 @@
 
                         if (featureIter->ReadNext())
                         {
-                            m_secondaryGwsFeatureIteratorMap.insert(GwsFeatureIteratorPair(attributeNameDelimiter, featureIter));
+                            m_secondaryGwsFeatureIteratorMap.insert(GwsFeatureIteratorPair(attributeNameDelimiter, GwsRightSideIterator(featureIter,false)));
                             secFdoClassDefinition = featureIter->GetClassDefinition();
                         }
                         else

Modified: sandbox/rfc60/MgDev/Server/src/Services/Feature/ServerGwsFeatureReader.h
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Services/Feature/ServerGwsFeatureReader.h	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Services/Feature/ServerGwsFeatureReader.h	2009-12-09 17:38:17 UTC (rev 4399)
@@ -22,9 +22,28 @@
 #include "ServerFeatureServiceDefs.h"
 #include "GwsQueryEngine.h"
 
-typedef std::multimap<STRING, IGWSFeatureIterator*> GwsFeatureIteratorMap;
-typedef std::pair<STRING, IGWSFeatureIterator*> GwsFeatureIteratorPair;
+class GwsRightSideIterator
+{
+public:
+    GwsRightSideIterator(IGWSFeatureIterator* iter, bool b):m_iterator(iter), m_bHasData(b){}
 
+    IGWSFeatureIterator * Iterator(){return m_iterator;};
+    bool HasData(){return m_bHasData;}
+
+private:
+    IGWSFeatureIterator* m_iterator;
+
+    // Fix ticket #1162
+    // When we are processing left-outer joins, this field is needed because we need the iterator
+    // to describe the right-side result. In the meanwhile, we need a flag to indicate that this
+    // iterator does not contains data, and we will return all null value for the right side
+    // features
+    bool                m_bHasData;
+};
+
+typedef std::multimap<STRING, GwsRightSideIterator> GwsFeatureIteratorMap;
+typedef std::pair<STRING, GwsRightSideIterator> GwsFeatureIteratorPair;
+
 class MgJoinFeatureReader;
 class FdoExpressionEngine;
 class FdoFilter;

Modified: sandbox/rfc60/MgDev/Server/src/Services/Mapping/MappingUtil.cpp
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Services/Mapping/MappingUtil.cpp	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Services/Mapping/MappingUtil.cpp	2009-12-09 17:38:17 UTC (rev 4399)
@@ -719,12 +719,14 @@
                     int height = (int)(extent.height() * pixelsPerMapUnit + 0.5);
 
                     //perform the raster query
+                    FdoPtr<FdoIFeatureReader> fdoReader;
                     {
                         ACE_MT(ACE_GUARD(ACE_Recursive_Thread_Mutex, ace_mon, sg_fdoRfpMutex));
                         rsReader = ExecuteRasterQuery(svcFeature, extent, gl, overrideFilter.c_str(), dstCs, layerCs, width, height);
+                        fdoReader = (NULL == rsReader) ? NULL : rsReader->GetInternalReader();
                     }
 
-                    if (NULL != rsReader)
+                    if (NULL != fdoReader.p)
                     {
                         //stylize grid layer
                         dr->StartLayer(&layerInfo, &fcinfo);

Modified: sandbox/rfc60/MgDev/Server/src/Services/Rendering/FeatureInfoRenderer.h
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Services/Rendering/FeatureInfoRenderer.h	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Services/Rendering/FeatureInfoRenderer.h	2009-12-09 17:38:17 UTC (rev 4399)
@@ -123,12 +123,12 @@
 
     virtual RS_Bounds& GetBounds();
 
-    virtual bool SupportsZ();
-
     virtual bool RequiresClipping();
 
     virtual bool RequiresLabelClipping();
 
+    virtual bool SupportsZ();
+
     virtual bool RequiresCompositeLineStyleSeparation();
 
     ///////////////////////////////////

Modified: sandbox/rfc60/MgDev/Server/src/Services/Resource/ResourceOperationFactory.cpp
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Services/Resource/ResourceOperationFactory.cpp	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Services/Resource/ResourceOperationFactory.cpp	2009-12-09 17:38:17 UTC (rev 4399)
@@ -283,7 +283,7 @@
     case MgResourceService::opIdGetResourceContents:
         switch (VERSION_NO_PHASE(operationVersion))
         {
-        case VERSION_SUPPORTED(1,0):
+        case VERSION_SUPPORTED(2,2):
             handler.reset(new MgOpGetResourceContents());
             break;
         default:

Modified: sandbox/rfc60/MgDev/Server/src/Services/Resource/ServerResourceService.cpp
===================================================================
--- sandbox/rfc60/MgDev/Server/src/Services/Resource/ServerResourceService.cpp	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/Services/Resource/ServerResourceService.cpp	2009-12-09 17:38:17 UTC (rev 4399)
@@ -2182,8 +2182,6 @@
 {
     MG_RESOURCE_SERVICE_TRY()
 
-    MG_LOG_TRACE_ENTRY(L"MgServerResourceService::CheckPermission()");
-
     if (NULL == resource)
     {
         throw new MgNullArgumentException(

Modified: sandbox/rfc60/MgDev/Server/src/UnitTesting/TestPerformance.cpp
===================================================================
--- sandbox/rfc60/MgDev/Server/src/UnitTesting/TestPerformance.cpp	2009-12-09 15:08:49 UTC (rev 4398)
+++ sandbox/rfc60/MgDev/Server/src/UnitTesting/TestPerformance.cpp	2009-12-09 17:38:17 UTC (rev 4399)
@@ -219,7 +219,7 @@
     catch(FdoException* e)
     {
         FDO_SAFE_RELEASE(e);
-        CPPUNIT_FAIL("FdoException occured");
+        CPPUNIT_FAIL("FdoException occurred");
     }
     catch(...)
     {
@@ -569,7 +569,7 @@
     catch(FdoException* e)
     {
         FDO_SAFE_RELEASE(e);
-        CPPUNIT_FAIL("FdoException occured");
+        CPPUNIT_FAIL("FdoException occurred");
     }
     catch(...)
     {



More information about the mapguide-commits mailing list