Matthias Brantner has proposed merging 
lp:~matthias-brantner/zorba/external_func_param into lp:zorba.

Requested reviews:
  Markos Zaharioudakis (markos-za)

For more details, see:
https://code.launchpad.net/~matthias-brantner/zorba/external_func_param/+merge/77410

Added ExternalFunctionParameter abstract class. Instances of this class canbe 
registered in the DynamicContext and, for example, retrieved in  external 
functions. This allows the user to do caching between successive calls to 
external functions. The ExternalFunctionParameter class defines a pure virtual 
function destroy" which is invoked by Zorba if the according DynamicContext is 
destroyed. In this function, the user can do cleanup of ressources. A common 
implementation is to destroy the object itself (e.g. delete this).

A test is contained in test/unit/external_function.cpp
-- 
https://code.launchpad.net/~matthias-brantner/zorba/external_func_param/+merge/77410
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'ChangeLog'
--- ChangeLog	2011-09-28 06:57:59 +0000
+++ ChangeLog	2011-09-28 21:52:34 +0000
@@ -30,11 +30,15 @@
   * Fixed bug # (Should not destroy the parent of a node that is being detached 
     before the detach is done). 
   * Fixed bug #3408181 (available-collection() returns undeclared collections)
+<<<<<<< TREE
   * Fixed bug #859465 (Fatal error if a PUL contains two deactivate IC primitives)
   * Fixed bug #859467 (Fatal error if a PUL contains two activate Foreign Key primitives)
   * Fixed bug #859468 (Fatal error if a PUL contains two activate Simple IC primitives)
   * Fixed bug #859522 (Fatal error if a PUL contains two delete document primitives)
   * Fixed bug #859968 (Using put on an attribute produces an invalid XDM instance and may cause segmentation faults)
+=======
+  * Added ExternalFunctionParameter class to be registered in the DynamicContext
+>>>>>>> MERGE-SOURCE
   * Fixed bug #855314 (should not fold a constant expr that returns an error item)
 	
 version 2.0.1

=== modified file 'include/zorba/api_shared_types.h'
--- include/zorba/api_shared_types.h	2011-08-25 15:54:19 +0000
+++ include/zorba/api_shared_types.h	2011-09-28 21:52:34 +0000
@@ -34,6 +34,7 @@
   class ItemFactory;
   class Iterator;
   class StatelessExternalFunction;
+  class ExternalFunctionParameter;
   class ExternalModule;
   class TypeIdentifier;
   class ItemSequence;

=== modified file 'include/zorba/dynamic_context.h'
--- include/zorba/dynamic_context.h	2011-09-21 14:49:55 +0000
+++ include/zorba/dynamic_context.h	2011-09-28 21:52:34 +0000
@@ -24,6 +24,7 @@
 #include <zorba/api_shared_types.h>
 #include <zorba/static_context_consts.h>
 #include <zorba/xmldatamanager.h>
+#include <zorba/external_function_parameter.h>
 
 
 namespace zorba {
@@ -209,11 +210,12 @@
   virtual Item
   getDefaultCollection() const = 0;
 
-  /** \brief Add a name-value pair the this context.
+  /** \brief Add a name-value pair to this context.
    *         The value can be accessed in the evaluate method
    *         of external functions (see ContextualExternalFunction).
    *
-   * @param aName the name of the parameter to add
+   * @param aName the name of the parameter to add. If an entry with
+   *   the same name already exists, the existing entry is replaced.
    * @param aValue the value that can be accessed in the evaluate method.
    * @return returns true if an entry with the same name did not already exist,
    *         false otherwise.
@@ -228,12 +230,39 @@
    *
    * @param aName the name of the parameter to retrieve
    * @param aValue the value matching the given name if true is returned.
-   * @return returns true if an entry with the given name was found,
+   * @return true if an entry with the given name was found,
    *         false otherwise.
    */
   virtual bool
   getExternalFunctionParam ( const String& aName, void*& aValue ) const = 0;
 
+  /** \brief Add a name-value pair to this context.
+   *         The value can be accessed in the evaluate method
+   *         of external functions (see ContextualExternalFunction).
+   *
+   * @param aName the name of the parameter to add. If an entry with
+   *   the same name already exists, the existing entry is replaced.
+   * @param aParam the parameter to add
+   * @return true if an entry with the same name did not exist already,
+   *  false otherwise.
+   */
+  virtual bool
+  addExternalFunctionParameter ( const String& aName, ExternalFunctionParameter* aParam ) = 0;
+
+  /** \brief Get the value of a pair that was registered using
+   *         the addExternalFunctionParam method. This can
+   *         be used in the evaluate method
+   *         of external functions (see ContextualExternalFunction).
+   *
+   * @param aName the name of the parameter to retrieve
+   * @return the ExternalFunctionParameter* that was added using
+   *   addExternalFunctionParameter, or 0 if no entry with the given
+   *   name was found.
+   */
+  virtual ExternalFunctionParameter*
+  getExternalFunctionParameter ( const String& aName ) const = 0;
+  
+
 protected:
   /** \brief Destructor
    */

=== added file 'include/zorba/external_function_parameter.h'
--- include/zorba/external_function_parameter.h	1970-01-01 00:00:00 +0000
+++ include/zorba/external_function_parameter.h	2011-09-28 21:52:34 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ZORBA_EXTERNAL_FUNCTION_PARAM_API_H
+#define ZORBA_EXTERNAL_FUNCTION_PARAM_API_H
+
+namespace zorba {
+
+/**
+ * Instances of subclasses of this abstract class may
+ * be used as parameters to the DynamicContext::addExternalFunctionParameter
+ * function. This is useful in the implementation of
+ * external modules/functions in order to store information
+ * between several invocations of the same function.
+ *
+ * The destroy method is called by Zorba at the end
+ * of the execution of an XQuery program, when the corresponding
+ * DynamicContext is destroyed.
+ *
+ */
+class ExternalFunctionParameter
+{
+public:
+  /**
+   * This function is invoked by Zorba when the DynamicContext
+   * that contains the instance is destroyed. This allows
+   * the user to release resources. In the simplest case,
+   * an implementation might simply call "delete this" to
+   * destroy the object.
+   */
+  virtual void destroy() throw() = 0;
+
+  /**
+   * Virtual destructor with an empty implementation
+   */
+  virtual ~ExternalFunctionParameter() {}
+};
+
+}
+
+#endif

=== modified file 'src/api/dynamiccontextimpl.cpp'
--- src/api/dynamiccontextimpl.cpp	2011-09-06 14:05:29 +0000
+++ src/api/dynamiccontextimpl.cpp	2011-09-28 21:52:34 +0000
@@ -575,5 +575,38 @@
   return false;
 }
 
+
+/****************************************************************************//**
+
+********************************************************************************/
+bool
+DynamicContextImpl::addExternalFunctionParameter (
+    const String& aName,
+    ExternalFunctionParameter* aValue )
+{
+  ZORBA_DCTX_TRY
+  {
+    std::string lName = aName.c_str();
+    return theCtx->addExternalFunctionParameter(lName, aValue);
+  }
+  ZORBA_DCTX_CATCH
+  return false;
+}
+
+/****************************************************************************//**
+
+********************************************************************************/
+ExternalFunctionParameter*
+DynamicContextImpl::getExternalFunctionParameter ( const String& aName ) const
+{
+  ZORBA_DCTX_TRY
+  {
+    std::string lName = aName.c_str();
+    return theCtx->getExternalFunctionParameter(lName);
+  }
+  ZORBA_DCTX_CATCH
+  return 0;
+}
+
 } // namespace zorba
 /* vim:set et sw=2 ts=2: */

=== modified file 'src/api/dynamiccontextimpl.h'
--- src/api/dynamiccontextimpl.h	2011-09-06 14:05:29 +0000
+++ src/api/dynamiccontextimpl.h	2011-09-28 21:52:34 +0000
@@ -136,6 +136,12 @@
   virtual bool
   getExternalFunctionParam(const String& aName, void*&) const;
 
+  virtual bool
+  addExternalFunctionParameter ( const String& aName, ExternalFunctionParameter* aParam );
+
+  virtual ExternalFunctionParameter*
+  getExternalFunctionParameter ( const String& aName ) const;
+
 protected:
   void checkNoIterators() const;
 

=== modified file 'src/context/dynamic_context.cpp'
--- src/context/dynamic_context.cpp	2011-09-06 14:05:29 +0000
+++ src/context/dynamic_context.cpp	2011-09-28 21:52:34 +0000
@@ -50,6 +50,7 @@
 
 #include "diagnostics/assert.h"
 #include "diagnostics/util_macros.h"
+#include <zorba/external_function_parameter.h>
 
 using namespace std;
 
@@ -143,6 +144,15 @@
 ********************************************************************************/
 dynamic_context::~dynamic_context()
 {
+  for (uint32_t i = 0; i < keymap.size(); ++i)
+  {
+    dctx_value_t lValue = keymap.getentryVal(i);
+    if (lValue.type == dctx_value_t::ext_func_param_typed && lValue.func_param)
+    {
+      static_cast<ExternalFunctionParameter*>(lValue.func_param)->destroy();
+    }
+  }
+
   if (theAvailableIndices)
     delete theAvailableIndices;
 }
@@ -584,11 +594,61 @@
       return false;
   }
 
-  ZORBA_ASSERT(val.type == dynamic_context::dctx_value_t::ext_func_param);
-  aValue = val.func_param;
-  return true;
-}
-
+  if (val.type == dynamic_context::dctx_value_t::ext_func_param)
+  {
+    aValue = val.func_param;
+    return true;
+  }
+  else
+  {
+    // could also be of type ext_func_param_typed
+    return false;
+  }
+}
+
+
+/*******************************************************************************
+
+********************************************************************************/
+bool dynamic_context::addExternalFunctionParameter(
+   const std::string& aName,
+   ExternalFunctionParameter* aValue)
+{
+  dctx_value_t val;
+  val.type = dynamic_context::dctx_value_t::ext_func_param_typed;
+  val.func_param = aValue;
+
+  ExternalFunctionParameter* lValue = getExternalFunctionParameter(aName);
+  if (lValue)
+  {
+    // destroy the object if it's already contained in the map
+    lValue->destroy();
+  }
+  return keymap.put ( aName, val);
+}
+
+
+/*******************************************************************************
+
+********************************************************************************/
+ExternalFunctionParameter*
+dynamic_context::getExternalFunctionParameter(const std::string& aName) const
+{
+  dctx_value_t val;
+  val.type = dynamic_context::dctx_value_t::no_val;
+  val.func_param = 0;
+
+  if ( !keymap.get(aName, val) ) {
+    if (theParent)
+      return theParent->getExternalFunctionParameter(aName);
+    else
+      return 0;
+  }
+
+  ExternalFunctionParameter* lRes
+    = static_cast<ExternalFunctionParameter*>(val.func_param);
+  return lRes;
+}
 
 /*
 std::vector<zstring>* dynamic_context::get_all_keymap_keys() const

=== modified file 'src/context/dynamic_context.h'
--- src/context/dynamic_context.h	2011-08-08 13:51:27 +0000
+++ src/context/dynamic_context.h	2011-09-28 21:52:34 +0000
@@ -57,7 +57,8 @@
     typedef enum
     {
       no_val,
-      ext_func_param // params that can be used by ext. functions
+      ext_func_param, // params that can be used by ext. functions
+      ext_func_param_typed 
     } val_type_t;
 
     val_type_t  type;
@@ -194,6 +195,13 @@
 
   bool getExternalFunctionParam(const std::string& aName, void*& aValue) const;
 
+  bool addExternalFunctionParameter(
+     const std::string& aName,
+     ExternalFunctionParameter* aValue);
+
+  ExternalFunctionParameter* getExternalFunctionParameter(
+      const std::string& aName) const;
+
   //std::vector<zstring>* get_all_keymap_keys() const;
 
 protected:

=== modified file 'test/unit/external_function.cpp'
--- test/unit/external_function.cpp	2011-06-14 17:26:33 +0000
+++ test/unit/external_function.cpp	2011-09-28 21:52:34 +0000
@@ -32,6 +32,20 @@
 using namespace zorba;
 
 bool lCalled = false;
+bool lGotParam = false;
+bool lDestroyedParam = false;
+
+class MyExternalFunctionParameter : public ExternalFunctionParameter
+{
+  public:
+    virtual void
+    destroy() throw()
+    {
+      lDestroyedParam = true;
+      delete this;
+    }
+};
+
 
 class MySimpleExternalFunction : public ContextualExternalFunction
 {
@@ -46,6 +60,14 @@
         const DynamicContext* dctx) const 
   {
     lCalled = true; // must not be reached because query is only compiled and not executed
+    ExternalFunctionParameter* lParam = 0;
+    if ( (lParam = dctx->getExternalFunctionParameter("myparam")) )
+    {
+      if (dynamic_cast<MyExternalFunctionParameter*>(lParam))
+      {
+        lGotParam = true;
+      }
+    }
     return ItemSequence_t(new EmptySequence());
   }
 };
@@ -97,12 +119,9 @@
     }
 };
 
-int
-external_function(int argc, char* argv[]) 
+bool
+external_function_test_1(Zorba* aZorba)
 {
-  void* lStore = zorba::StoreManager::getStore();
-  Zorba* lZorba = Zorba::getInstance(lStore);
-
   try {
     // test the sausalito use case
     // serialize a query and afterwards execute it
@@ -114,15 +133,15 @@
       MyExternalModule lMod;
 
       {
-        StaticContext_t lSctx = lZorba->createStaticContext();
+        StaticContext_t lSctx = aZorba->createStaticContext();
         lSctx->registerModule(&lMod);
 
-        XQuery_t lQuery = lZorba->compileQuery(lIn, lSctx);
+        XQuery_t lQuery = aZorba->compileQuery(lIn, lSctx);
         lQuery->saveExecutionPlan(lOut, ZORBA_USE_BINARY_ARCHIVE, SAVE_UNUSED_FUNCTIONS);
 
         zorba::DynamicContext* lDynContext = lQuery->getDynamicContext();
         lDynContext->setVariable("local:foo",
-                                 lZorba->getItemFactory()->createString("foo")); 
+                                 aZorba->getItemFactory()->createString("foo")); 
         // make sure constant folding doesn't happen, i.e. the function is not evaluated
         if (lCalled) {
           return 1;
@@ -143,14 +162,14 @@
         // this tests if, when loaded, the functions of the static context
         // that have not yet been compiled, can be compiled properly
         std::istringstream lIn(lOut.str());
-        XQuery_t lQuery = lZorba->createQuery();
+        XQuery_t lQuery = aZorba->createQuery();
         lQuery->loadExecutionPlan(lIn, &lCallback);
 
         // set the parameter for evaluating a different dynamic function then
         // in the test above
         zorba::DynamicContext* lDynContext = lQuery->getDynamicContext();
         lDynContext->setVariable("local:foo",
-                                 lZorba->getItemFactory()->createString("foo2")); 
+                                 aZorba->getItemFactory()->createString("foo2")); 
 
         // evaluate the query
         std::cout << lQuery << std::endl;
@@ -158,9 +177,82 @@
     }
   } catch (XQueryException& qe) {
     std::cerr << qe << std::endl;
+    return false;
+  } catch (ZorbaException& e) {
+    std::cerr << e << std::endl;
+    return false;
+  }
+  return true;
+}
+
+bool
+external_function_test_2(Zorba* aZorba)
+{
+  try {
+    std::ifstream lIn("ext_main.xq");
+    assert(lIn.good());
+    std::ostringstream lOut;
+    MyExternalModule lMod;
+
+    StaticContext_t lSctx = aZorba->createStaticContext();
+    lSctx->registerModule(&lMod);
+    {
+      XQuery_t lQuery = aZorba->compileQuery(lIn, lSctx);
+
+      zorba::DynamicContext* lDynContext = lQuery->getDynamicContext();
+
+      // must be released in MyExternalFunctionParameter::destroy
+      MyExternalFunctionParameter* lParam1 = new MyExternalFunctionParameter();
+      MyExternalFunctionParameter* lParam2 = new MyExternalFunctionParameter();
+
+      lDynContext->addExternalFunctionParameter("myparam", lParam1);
+      lDynContext->addExternalFunctionParameter("myparam", lParam2);
+
+      // make sure that destroy is invoked if the first parameter is overwritten
+      if (!lDestroyedParam)
+      {
+        return false;
+      }
+      else
+      {
+        lDestroyedParam = false;
+      }
+
+
+      lDynContext->setVariable("local:foo",
+                               aZorba->getItemFactory()->createString("foo")); 
+
+      std::cout << lQuery << std::endl;
+    }
+
+    // destroy is called if the XQuery object is destroyed
+    return lGotParam && lDestroyedParam;
+
+  } catch (XQueryException& qe) {
+    std::cerr << qe << std::endl;
+    return false;
+  } catch (ZorbaException& e) {
+    std::cerr << e << std::endl;
+    return false;
+  }
+  return true;
+}
+
+int
+external_function(int argc, char* argv[]) 
+{
+  void* lStore = zorba::StoreManager::getStore();
+  Zorba* lZorba = Zorba::getInstance(lStore);
+
+  std::cout << "executing external_function_test_1" << std::endl;
+  if (!external_function_test_1(lZorba))
+  {
     return 1;
-  } catch (ZorbaException& e) {
-    std::cerr << e << std::endl;
+  }
+
+  std::cout << "executing external_function_test_2" << std::endl;
+  if (!external_function_test_2(lZorba))
+  {
     return 2;
   }
 

-- 
Mailing list: https://launchpad.net/~zorba-coders
Post to     : zorba-coders@lists.launchpad.net
Unsubscribe : https://launchpad.net/~zorba-coders
More help   : https://help.launchpad.net/ListHelp

Reply via email to