[mapguide-commits] r8528 - in trunk/MgDev/Server/src: Services/Feature UnitTesting

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Tue Feb 3 03:41:32 PST 2015


Author: jng
Date: 2015-02-03 03:41:32 -0800 (Tue, 03 Feb 2015)
New Revision: 8528

Modified:
   trunk/MgDev/Server/src/Services/Feature/FeatureServiceCommand.cpp
   trunk/MgDev/Server/src/Services/Feature/FeatureServiceCommand.h
   trunk/MgDev/Server/src/Services/Feature/SelectCommand.cpp
   trunk/MgDev/Server/src/Services/Feature/SelectCommand.h
   trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.cpp
   trunk/MgDev/Server/src/UnitTesting/TestFeatureService.cpp
   trunk/MgDev/Server/src/UnitTesting/TestFeatureService.h
Log:
#2530: Add support for limited ordering support for SDF and SHP providers via the FdoIExtendedSelect command. The "limit" is that ordering can only be applied on a single property for these providers, otherwise the standard unsupported exception is thrown back as usual.

Modified: trunk/MgDev/Server/src/Services/Feature/FeatureServiceCommand.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/FeatureServiceCommand.cpp	2015-02-02 11:59:46 UTC (rev 8527)
+++ trunk/MgDev/Server/src/Services/Feature/FeatureServiceCommand.cpp	2015-02-03 11:41:32 UTC (rev 8528)
@@ -22,14 +22,14 @@
 #include "SelectCommand.h"
 #include "SelectAggregateCommand.h"
 
-MgFeatureServiceCommand* MgFeatureServiceCommand::CreateCommand(MgResourceIdentifier* resource, FdoCommandType commandType)
+MgFeatureServiceCommand* MgFeatureServiceCommand::CreateCommand(MgResourceIdentifier* resource, FdoCommandType commandType, MgFeatureQueryOptions* options)
 {
     Ptr<MgFeatureServiceCommand> command;
     switch(commandType)
     {
         case FdoCommandType_Select:
         {
-            command = new MgSelectCommand(resource);
+            command = new MgSelectCommand(resource, options);
             break;
         }
         case FdoCommandType_SelectAggregates:

Modified: trunk/MgDev/Server/src/Services/Feature/FeatureServiceCommand.h
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/FeatureServiceCommand.h	2015-02-02 11:59:46 UTC (rev 8527)
+++ trunk/MgDev/Server/src/Services/Feature/FeatureServiceCommand.h	2015-02-03 11:41:32 UTC (rev 8528)
@@ -21,7 +21,7 @@
 class MgFeatureServiceCommand : public MgDisposable
 {
 public:
-    static MgFeatureServiceCommand* CreateCommand(MgResourceIdentifier* resource, FdoCommandType commandType);
+    static MgFeatureServiceCommand* CreateCommand(MgResourceIdentifier* resource, FdoCommandType commandType, MgFeatureQueryOptions* options);
 
     virtual FdoIdentifierCollection* GetPropertyNames() = 0;
 
@@ -35,6 +35,9 @@
     virtual void SetOrderingOption( FdoOrderingOption  option ) = 0;
     virtual FdoOrderingOption GetOrderingOption( ) = 0;
 
+    virtual bool IsExtended() { return false;  }
+    virtual void SetExtendedOrderingOption(FdoString* orderBy, FdoOrderingOption option) { }
+
     virtual FdoIdentifierCollection* GetGrouping() = 0;
     virtual void SetGroupingFilter( FdoFilter* filter ) = 0;
     virtual FdoFilter* GetGroupingFilter( ) = 0;

Modified: trunk/MgDev/Server/src/Services/Feature/SelectCommand.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/SelectCommand.cpp	2015-02-02 11:59:46 UTC (rev 8527)
+++ trunk/MgDev/Server/src/Services/Feature/SelectCommand.cpp	2015-02-03 11:41:32 UTC (rev 8528)
@@ -30,7 +30,7 @@
 // The maximum size of the subfilter for a selection query.  Tune this value for optimal selection perfomance.
 #define MG_MAX_SUBFILTER_SIZE  250
 
-MgSelectCommand::MgSelectCommand(MgResourceIdentifier* resource)
+MgSelectCommand::MgSelectCommand(MgResourceIdentifier* resource, MgFeatureQueryOptions* options)
 {
     CHECKARGUMENTNULL((MgResourceIdentifier*)resource, L"MgSelectCommand.MgSelectCommand");
 
@@ -44,9 +44,40 @@
     {
         throw new MgConnectionFailedException(L"MgSelectCommand.MgSelectCommand", __LINE__, __WFILE__, NULL, L"", NULL);
     }
+
+    FdoPtr<FdoIConnection> fdoConn = m_connection->GetConnection();
+
+    // For SDF/SHP providers, they do not support ordering. But, they can support ordering through the FdoIExtendedSelect
+    // command, provided that only a single property is being ordered on. So if it is the case that normal ordering is
+    // not supported, we should try for extended select if the conditions are met.
+    bool bTryExtendedSelect = false;
+    if (NULL != options)
+    {
+        Ptr<MgStringCollection> orderProps = options->GetOrderingProperties();
+        if (NULL != orderProps.p)
+        {
+            FdoPtr<FdoICommandCapabilities> cmdCaps = fdoConn->GetCommandCapabilities();
+            if (!cmdCaps->SupportsSelectOrdering())
+            {
+                FdoInt32 cmdCount;
+                FdoInt32* cmds = cmdCaps->GetCommands(cmdCount);
+                for (FdoInt32 i = 0; i < cmdCount; i++)
+                {
+                    if (FdoCommandType_ExtendedSelect == cmds[i] && orderProps->GetCount() == 1)
+                    {
+                        bTryExtendedSelect = true;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
     // Create FdoISelect command
-    FdoPtr<FdoIConnection> fdoConn = m_connection->GetConnection();
-    m_command = (FdoISelect*)fdoConn->CreateCommand(FdoCommandType_Select);
+    if (bTryExtendedSelect)
+        m_command = (FdoIExtendedSelect*)fdoConn->CreateCommand(FdoCommandType_ExtendedSelect);
+    else
+        m_command = (FdoISelect*)fdoConn->CreateCommand(FdoCommandType_Select);
     CHECKNULL((FdoISelect*)m_command, L"MgSelectCommand.MgSelectCommand");
 }
 
@@ -106,6 +137,27 @@
     m_command->SetOrderingOption(option);
 }
 
+bool MgSelectCommand::IsExtended()
+{
+    CHECKNULL((FdoISelect*)m_command, L"MgSelectCommand.SetExtendedOrderingOption");
+    FdoIExtendedSelect* extSelect = dynamic_cast<FdoIExtendedSelect*>(m_command.p);
+    if (NULL != extSelect)
+    {
+        return true;
+    }
+    return false;
+}
+
+void MgSelectCommand::SetExtendedOrderingOption(FdoString* orderBy, FdoOrderingOption option)
+{
+    CHECKNULL((FdoISelect*)m_command, L"MgSelectCommand.SetExtendedOrderingOption");
+    FdoIExtendedSelect* extSelect = dynamic_cast<FdoIExtendedSelect*>(m_command.p);
+    if (NULL != extSelect)
+    {
+        extSelect->SetOrderingOption(orderBy, option);
+    }
+}
+
 FdoOrderingOption MgSelectCommand::GetOrderingOption()
 {
     CHECKNULL((FdoISelect*)m_command, L"MgSelectCommand.GetOrderingOption");
@@ -165,27 +217,37 @@
 {
     FdoPtr<FdoIFeatureReader> reader;
 
-    // Break up the filter into smaller chunks
-    FdoPtr<MgFdoFilterCollection> subFilters = this->GetSubFilters();
-
     CHECKNULL((FdoISelect*)m_command, L"MgSelectCommand.Execute");
-
-    // Execute queries using the smaller filters and collect the results of the queries into a reader collection.
-    FdoPtr<MgFdoReaderCollection> frc = MgFdoReaderCollection::Create();
-
-    for (FdoInt32 filterIndex = 0; filterIndex < subFilters->GetCount(); filterIndex++)
+    FdoIExtendedSelect* extSelect = dynamic_cast<FdoIExtendedSelect*>(m_command.p);
+    if (NULL != extSelect)
     {
-        FdoPtr<FdoFilter> filter = subFilters->GetItem(filterIndex);
-        m_command->SetFilter(filter);
-        reader = m_command->Execute();
+        FdoPtr<FdoIScrollableFeatureReader> scReader = extSelect->ExecuteScrollable();
+        CHECKNULL((FdoIScrollableFeatureReader*)scReader, L"MgSelectCommand.Execute");
 
-        frc->Add(reader);
+        return new MgServerFeatureReader(m_connection, scReader);
     }
+    else
+    {
+        // Break up the filter into smaller chunks
+        FdoPtr<MgFdoFilterCollection> subFilters = this->GetSubFilters();
 
-    FdoPtr<MgFdoFeatureReader> featureReader = new MgFdoFeatureReader(frc);
-    CHECKNULL((FdoIFeatureReader*)featureReader, L"MgSelectCommand.Execute");
+        // Execute queries using the smaller filters and collect the results of the queries into a reader collection.
+        FdoPtr<MgFdoReaderCollection> frc = MgFdoReaderCollection::Create();
 
-    return new MgServerFeatureReader(m_connection, featureReader);
+        for (FdoInt32 filterIndex = 0; filterIndex < subFilters->GetCount(); filterIndex++)
+        {
+            FdoPtr<FdoFilter> filter = subFilters->GetItem(filterIndex);
+            m_command->SetFilter(filter);
+            reader = m_command->Execute();
+
+            frc->Add(reader);
+        }
+
+        FdoPtr<MgFdoFeatureReader> featureReader = new MgFdoFeatureReader(frc);
+        CHECKNULL((FdoIFeatureReader*)featureReader, L"MgSelectCommand.Execute");
+
+        return new MgServerFeatureReader(m_connection, featureReader);
+    }
 }
 
 bool MgSelectCommand::IsSupportedFunction(FdoFunction* fdoFunc)

Modified: trunk/MgDev/Server/src/Services/Feature/SelectCommand.h
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/SelectCommand.h	2015-02-02 11:59:46 UTC (rev 8527)
+++ trunk/MgDev/Server/src/Services/Feature/SelectCommand.h	2015-02-03 11:41:32 UTC (rev 8528)
@@ -27,7 +27,7 @@
     DECLARE_CLASSNAME(MgServerSqlProcessor)
 
 public:
-    MgSelectCommand(MgResourceIdentifier* resource);
+    MgSelectCommand(MgResourceIdentifier* resource, MgFeatureQueryOptions* options);
     virtual ~MgSelectCommand();
 
     virtual FdoIdentifierCollection* GetPropertyNames();
@@ -42,6 +42,9 @@
     virtual void SetOrderingOption( FdoOrderingOption  option );
     virtual FdoOrderingOption GetOrderingOption( );
 
+    virtual bool IsExtended();
+    virtual void SetExtendedOrderingOption(FdoString* orderBy, FdoOrderingOption option);
+
     virtual FdoIdentifierCollection* GetGrouping();
     virtual void SetGroupingFilter( FdoFilter* filter );
     virtual FdoFilter* GetGroupingFilter( );

Modified: trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.cpp
===================================================================
--- trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.cpp	2015-02-02 11:59:46 UTC (rev 8527)
+++ trunk/MgDev/Server/src/Services/Feature/ServerSelectFeatures.cpp	2015-02-03 11:41:32 UTC (rev 8528)
@@ -132,7 +132,7 @@
 #ifdef DEBUG_FDO_JOIN
             ACE_DEBUG((LM_INFO, ACE_TEXT("\n(%t) Feature Source (%W) supports FDO join optimization"), fsIdStr.c_str()));
 #endif
-            m_command = MgFeatureServiceCommand::CreateCommand(resource, FdoCommandType_Select);
+            m_command = MgFeatureServiceCommand::CreateCommand(resource, FdoCommandType_Select, m_options);
             mgReader = SelectFdoJoin(resource, className, false);
         }
         else 
@@ -162,7 +162,7 @@
 #endif
         // Perform the same select query as above, but route this through the FDO expression engine
         // Slow maybe, but anything is faster than going via the GWS query engine.
-        m_command = MgFeatureServiceCommand::CreateCommand(resource, FdoCommandType_Select);
+        m_command = MgFeatureServiceCommand::CreateCommand(resource, FdoCommandType_Select, m_options);
         mgReader = SelectFdoJoin(resource, className, true);
     }
     else
@@ -605,8 +605,17 @@
     if (cnt <= 0)
         return; // Nothing to do
 
+    bool bSupportsOrdering = m_command->SupportsSelectOrdering();
+    bool bExtended = m_command->IsExtended();
+    // Not supported? We can still support if it supports extended select. This may look like a bit of hack
+    // but the known implementations of FdoIExtendedSelect (SDF/SHP) will honor the ordering option if used
+    if (!bSupportsOrdering)
+    {
+        bSupportsOrdering = (cnt == 1) && bExtended;
+    }
+
     // Ordering options are supplied but provider does not support it
-    if (!m_command->SupportsSelectOrdering())
+    if (!bSupportsOrdering)
     {
         STRING message = MgServerFeatureUtil::GetMessage(L"MgOrderingOptionNotSupported");
 
@@ -615,23 +624,44 @@
         throw new MgFeatureServiceException(L"MgServerSelectFeatures.ApplyOrderingOptions", __LINE__, __WFILE__, &arguments, L"", NULL);
     }
 
-    FdoPtr<FdoIdentifierCollection> fic = m_command->GetOrdering();
-    CHECKNULL((FdoIdentifierCollection*)fic, L"MgServerSelectFeatures.ApplyOrderingOptions");
+    if ((cnt == 1) && bExtended)
+    {
+        // Order option Asc or Desc (default is Asc)
+        FdoOrderingOption option = MgServerFeatureUtil::GetFdoOrderingOption(m_options->GetOrderOption());
+        STRING propertyName = properties->GetItem(0);
 
-    // Order option Asc or Desc (default is Asc)
-    FdoOrderingOption option = MgServerFeatureUtil::GetFdoOrderingOption(m_options->GetOrderOption());
-    m_command->SetOrderingOption(option);
+        FdoPtr<FdoIdentifierCollection> fic = m_command->GetOrdering();
+        CHECKNULL((FdoIdentifierCollection*)fic, L"MgServerSelectFeatures.ApplyOrderingOptions");
 
-    for (INT32 i=0; i < cnt; i++)
+        // Order option Asc or Desc (default is Asc)
+        //
+        // With extended select, we still have to make sure the base ordering option is set
+        m_command->SetOrderingOption(option);
+        FdoPtr<FdoIdentifier> ident = FdoIdentifier::Create((FdoString*)propertyName.c_str());
+        fic->Add(ident);
+
+        m_command->SetExtendedOrderingOption((FdoString*)propertyName.c_str(), option);
+    }
+    else
     {
-        STRING propertyName = properties->GetItem(i);
+        FdoPtr<FdoIdentifierCollection> fic = m_command->GetOrdering();
+        CHECKNULL((FdoIdentifierCollection*)fic, L"MgServerSelectFeatures.ApplyOrderingOptions");
 
-        if (!propertyName.empty())
+        // Order option Asc or Desc (default is Asc)
+        FdoOrderingOption option = MgServerFeatureUtil::GetFdoOrderingOption(m_options->GetOrderOption());
+        m_command->SetOrderingOption(option);
+
+        for (INT32 i = 0; i < cnt; i++)
         {
-            FdoPtr<FdoIdentifier> fdoIden = FdoIdentifier::Create((FdoString*)propertyName.c_str());
-            CHECKNULL((FdoIdentifier*)fdoIden, L"MgServerSelectFeatures.ApplyOrderingOptions");
+            STRING propertyName = properties->GetItem(i);
 
-            fic->Add(fdoIden);
+            if (!propertyName.empty())
+            {
+                FdoPtr<FdoIdentifier> fdoIden = FdoIdentifier::Create((FdoString*)propertyName.c_str());
+                CHECKNULL((FdoIdentifier*)fdoIden, L"MgServerSelectFeatures.ApplyOrderingOptions");
+
+                fic->Add(fdoIden);
+            }
         }
     }
 }
@@ -780,11 +810,11 @@
 {
     if (!isSelectAggregate)
     {
-        m_command = MgFeatureServiceCommand::CreateCommand(resource, FdoCommandType_Select);
+        m_command = MgFeatureServiceCommand::CreateCommand(resource, FdoCommandType_Select, m_options);
     }
     else
     {
-        m_command = MgFeatureServiceCommand::CreateCommand(resource, FdoCommandType_SelectAggregates);
+        m_command = MgFeatureServiceCommand::CreateCommand(resource, FdoCommandType_SelectAggregates, m_options);
     }
     CHECKNULL((MgFeatureServiceCommand*)m_command, L"MgServerSelectFeatures.CreateCommand");
 }

Modified: trunk/MgDev/Server/src/UnitTesting/TestFeatureService.cpp
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestFeatureService.cpp	2015-02-02 11:59:46 UTC (rev 8527)
+++ trunk/MgDev/Server/src/UnitTesting/TestFeatureService.cpp	2015-02-03 11:41:32 UTC (rev 8528)
@@ -1374,7 +1374,86 @@
     }
 }
 
+///----------------------------------------------------------------------------
+/// Test Case Description:
+///
+/// This test case exercises selecting features against a SDF feature source
+/// with ordering (not supported in capabilities, but allowed through extended
+/// select but only on a single property)
+///----------------------------------------------------------------------------
+void TestFeatureService::TestCase_SelectFeaturesSdfWithOrdering()
+{
+    try
+    {
+        MgServiceManager* serviceManager = MgServiceManager::GetInstance();
+        if (serviceManager == 0)
+        {
+            throw new MgNullReferenceException(L"TestFeatureService.TestCase_SelectFeatures", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
 
+        Ptr<MgFeatureService> pService = dynamic_cast<MgFeatureService*>(serviceManager->RequestService(MgServiceType::FeatureService));
+        if (pService == 0)
+        {
+            throw new MgServiceNotAvailableException(L"TestFeatureService.TestCase_SelectFeatures", __LINE__, __WFILE__, NULL, L"", NULL);
+        }
+
+        Ptr<MgResourceIdentifier> resource = new MgResourceIdentifier(L"Library://UnitTests/Data/Sheboygan_VotingDistricts.FeatureSource");
+        STRING className = L"VotingDistricts";
+
+        Ptr<MgFeatureQueryOptions> options = new MgFeatureQueryOptions();
+        Ptr<MgStringCollection> orderProps = new MgStringCollection();
+        orderProps->Add(L"ID");
+        orderProps->Add(L"NAME");
+        options->SetOrderingFilter(orderProps, MgOrderingOption::Descending);
+
+        //Invalid conditions for ordered select
+        CPPUNIT_ASSERT_THROW_MG(pService->SelectFeatures(resource, className, options), MgFeatureServiceException*);
+        
+        orderProps->Clear();
+        orderProps->Add(L"ID");
+        options->SetOrderingFilter(orderProps, MgOrderingOption::Ascending);
+
+        STRING str;
+        //Now valid
+        Ptr<MgFeatureReader> reader = pService->SelectFeatures(resource, className, options);
+        while (reader->ReadNext())
+        {
+            str += reader->GetString(L"ID");
+        }
+        reader->Close();
+        CPPUNIT_ASSERT(str == L"12334456678");
+
+        orderProps->Clear();
+        orderProps->Add(L"ID");
+        options->SetOrderingFilter(orderProps, MgOrderingOption::Descending);
+
+        str.clear();
+        //Now valid
+        reader = pService->SelectFeatures(resource, className, options);
+        while (reader->ReadNext())
+        {
+            str += reader->GetString(L"ID");
+        }
+        reader->Close();
+        CPPUNIT_ASSERT(str == L"87665443321");
+    }
+    catch (MgException* e)
+    {
+        STRING message = e->GetDetails(TEST_LOCALE);
+        SAFE_RELEASE(e);
+        CPPUNIT_FAIL(MG_WCHAR_TO_CHAR(message.c_str()));
+    }
+    catch (FdoException* e)
+    {
+        FDO_SAFE_RELEASE(e);
+        CPPUNIT_FAIL("FdoException occurred");
+    }
+    catch (...)
+    {
+        throw;
+    }
+}
+
 ///----------------------------------------------------------------------------
 /// Test Case Description:
 ///

Modified: trunk/MgDev/Server/src/UnitTesting/TestFeatureService.h
===================================================================
--- trunk/MgDev/Server/src/UnitTesting/TestFeatureService.h	2015-02-02 11:59:46 UTC (rev 8527)
+++ trunk/MgDev/Server/src/UnitTesting/TestFeatureService.h	2015-02-03 11:41:32 UTC (rev 8528)
@@ -39,6 +39,7 @@
     CPPUNIT_TEST(TestCase_ApplySchema);
     CPPUNIT_TEST(TestCase_SelectFeatures);
     CPPUNIT_TEST(TestCase_SelectFeaturesWithXform);
+    CPPUNIT_TEST(TestCase_SelectFeaturesSdfWithOrdering);
     CPPUNIT_TEST(TestCase_SelectAggregate);
     CPPUNIT_TEST(TestCase_UpdateFeaturesInsert);
     CPPUNIT_TEST(TestCase_UpdateFeaturesPartialFailure);
@@ -93,6 +94,7 @@
     void TestCase_ApplySchema();
     void TestCase_SelectFeatures();
     void TestCase_SelectFeaturesWithXform();
+    void TestCase_SelectFeaturesSdfWithOrdering();
     void TestCase_SelectAggregate();
     void TestCase_UpdateFeaturesInsert();
     void TestCase_UpdateFeaturesPartialFailure();



More information about the mapguide-commits mailing list