← Back to team overview

zorba-coders team mailing list archive

[Merge] lp:~zorba-coders/zorba/feature-caching-annotations into lp:zorba

 

Federico Cavalieri has proposed merging lp:~zorba-coders/zorba/feature-caching-annotations into lp:zorba with lp:~zorba-coders/zorba/feature-caching as a prerequisite.

Commit message:
Implemented function annotation to exclude an argument from the cache key.
Implemented function annotation to use deep equality on an argument for caching purposes.
Fixed bug in deep-equal that causes an assertion failure when comparing objects with nested function items.

Requested reviews:
  Federico Cavalieri (fcavalieri)
  Matthias Brantner (matthias-brantner)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/feature-caching-annotations/+merge/216293

Implemented function annotation to exclude an argument from the cache key.
Implemented function annotation to use deep equality on an argument for caching purposes.
Fixed bug in deep-equal that causes an assertion failure when comparing objects with nested function items.
-- 
https://code.launchpad.net/~zorba-coders/zorba/feature-caching-annotations/+merge/216293
Your team Zorba Coders is subscribed to branch lp:~zorba-coders/zorba/feature-caching.
=== modified file 'modules/util-tests/util-tests.xq'
--- modules/util-tests/util-tests.xq	2014-04-17 12:21:32 +0000
+++ modules/util-tests/util-tests.xq	2014-04-17 12:21:32 +0000
@@ -181,6 +181,60 @@
 declare %an:strictlydeterministic function tests:test-05-sd($x as xs:boolean, $y) as item()* external;
 
 (:~
+ : Equivalent to:
+ : declare %an:cache %an:exclude-from-cache-key(2) function local:test-06-cache($x as xs:integer, $y as xs:integer) as xs:integer
+ : {
+ :   $x + $y
+ : };
+ :
+ : @param $x as described above
+ : @param $y as described above
+ : @return as described above
+ :)
+declare %an:cache %an:exclude-from-cache-key(2) function tests:test-06-cache($x as xs:integer, $y as xs:integer) as xs:integer external;
+
+(:~
+ : Equivalent to:
+ : declare %an:strictlydeterministic %an:exclude-from-cache-key(2) function local:test-06-sd($x as xs:integer, $y as xs:integer) as xs:integer
+ : {
+ :   $x + $y
+ : };
+ :
+ : @param $x as described above
+ : @param $y as described above
+ : @return as described above
+ :)
+declare %an:strictlydeterministic %an:exclude-from-cache-key(2) function tests:test-06-sd($x as xs:integer, $y as xs:integer) as xs:integer external;
+
+(:~
+ : Equivalent to:
+ : declare %an:strictlydeterministic %an:compare-with-deep-equal(2) function local:test-07-cache($x as item()*, $y as item()*)
+ : {
+ :   serialize({"x" : $x, "y" : $y}),
+ :   tests:uuid()
+ : };
+ :
+ : @param $x as described above
+ : @param $y as described above
+ : @return as described above
+ :)
+declare %an:cache %an:compare-with-deep-equal(2) function tests:test-07-cache($x as item()*, $y as item()*) external;
+
+(:~
+ : Equivalent to:
+ : declare %an:strictlydeterministic %an:compare-with-deep-equal(2) function local:test-07-sd($x as item()*, $y as item()*)
+ : {
+ :   serialize({"x" : $x, "y" : $y}),
+ :   tests:uuid()
+ : };
+ :
+ : @param $x as described above
+ : @param $y as described above
+ : @return as described above
+ :)
+declare %an:strictlydeterministic %an:compare-with-deep-equal(2) function tests:test-07-sd($x as item()*, $y as item()*) external;
+
+(:~
  : Returns a non seekable streamable string
  :
  : @return a non seekable streamable string

=== modified file 'modules/util-tests/util-tests.xq.src/util-tests.cpp'
--- modules/util-tests/util-tests.xq.src/util-tests.cpp	2014-04-17 12:21:32 +0000
+++ modules/util-tests/util-tests.xq.src/util-tests.cpp	2014-04-17 12:21:32 +0000
@@ -301,6 +301,59 @@
 }
 
 zorba::ItemSequence_t
+UtilTestsModule::test06(const Arguments_t& aArgs,
+    const zorba::StaticContext* aSctx,
+    const zorba::DynamicContext* aDctx) const
+{
+  zorba::ItemFactory* lFactory = zorba::Zorba::getInstance(0)->getItemFactory();
+  zorba::Item lX = getOneItemArgument(aArgs, 0);
+  zorba::Item lY = getOneItemArgument(aArgs, 1);
+  zorba::Item lRet = lFactory->createInteger(atoi(lX.getStringValue().str().c_str()) + atoi(lY.getStringValue().str().c_str()));
+
+  return zorba::ItemSequence_t(
+    new zorba::SingletonItemSequence(
+      lRet
+    )
+  );
+}
+
+zorba::ItemSequence_t
+UtilTestsModule::test07(const Arguments_t& aArgs,
+    const zorba::StaticContext* aSctx,
+    const zorba::DynamicContext* aDctx) const
+{
+  zorba::ItemFactory* lFactory = zorba::Zorba::getInstance(0)->getItemFactory();
+  std::ostringstream os;
+  Zorba_SerializerOptions_t lOptions;
+  lOptions.omit_xml_declaration = ZORBA_OMIT_XML_DECLARATION_YES;
+  Serializer_t lSerializer = Serializer::createSerializer(lOptions);
+
+  std::vector<zorba::Item> lResult;
+  std::vector<std::pair<Item, Item> > lPairs;
+  lPairs.push_back(std::pair<Item, Item>(lFactory->createString("x"), getOneItemArgument(aArgs, 0)));
+  lPairs.push_back(std::pair<Item, Item>(lFactory->createString("y"), getOneItemArgument(aArgs, 1)));
+  Item lObj = lFactory->createJSONObject(lPairs);
+  std::stringstream lSerializedObj;
+  zorba::SingletonItemSequence lSeq(lObj);
+  lSerializer->serialize(lSeq.getIterator(), lSerializedObj);
+  lResult.push_back(lFactory->createString(lSerializedObj.str()));
+
+
+  uuid u;
+  uuid::create(&u);
+  std::ostringstream oss;
+  oss << "urn:uuid:" << u;
+  zorba::Item lRandomItem = lFactory->createString(oss.str());
+  lResult.push_back(lRandomItem);
+
+  return zorba::ItemSequence_t(
+    new zorba::VectorItemSequence(
+      lResult
+    )
+  );
+}
+
+zorba::ItemSequence_t
 UUIDFunction::evaluate(
     const Arguments_t& aArgs,
     const zorba::StaticContext*,
@@ -349,6 +402,14 @@
        lFunc = new Test05CacheFunction(this);
     else if (aLocalname.compare("test-05-sd") == 0)
        lFunc = new Test05SDFunction(this);
+    else if (aLocalname.compare("test-06-cache") == 0)
+       lFunc = new Test06CacheFunction(this);
+    else if (aLocalname.compare("test-06-sd") == 0)
+       lFunc = new Test06SDFunction(this);
+    else if (aLocalname.compare("test-07-cache") == 0)
+       lFunc = new Test07CacheFunction(this);
+    else if (aLocalname.compare("test-07-sd") == 0)
+       lFunc = new Test07SDFunction(this);
     else if (aLocalname.compare("non-seeakable-streamable-string") == 0)
       lFunc = new NonSeeakableStreamableStringFunction(this);
     else if (aLocalname.compare("uuid") == 0)

=== modified file 'modules/util-tests/util-tests.xq.src/util-tests.h'
--- modules/util-tests/util-tests.xq.src/util-tests.h	2014-04-17 12:21:32 +0000
+++ modules/util-tests/util-tests.xq.src/util-tests.h	2014-04-17 12:21:32 +0000
@@ -77,6 +77,16 @@
           const zorba::StaticContext* aSctx,
           const zorba::DynamicContext* aDctx) const;
 
+  zorba::ItemSequence_t
+  test06(const Arguments_t& aArgs,
+          const zorba::StaticContext* aSctx,
+          const zorba::DynamicContext* aDctx) const;
+
+  zorba::ItemSequence_t
+  test07(const Arguments_t& aArgs,
+          const zorba::StaticContext* aSctx,
+          const zorba::DynamicContext* aDctx) const;
+
   static zorba::Item
   getOneItemArgument(const Arguments_t& aArgs, int aIndex);
 };
@@ -322,6 +332,94 @@
 
 /******************************************************************************
  *****************************************************************************/
+class Test06CacheFunction : public TestFunction
+{
+public:
+  Test06CacheFunction(const UtilTestsModule* aModule) :
+    TestFunction(aModule) {};
+
+  virtual ~Test06CacheFunction() {}
+
+  virtual zorba::String
+  getLocalName() const { return "test-06-cache"; }
+
+  zorba::ItemSequence_t
+  evaluate(const Arguments_t& aArgs,
+      const zorba::StaticContext* aSctx,
+      const zorba::DynamicContext* aDctx) const
+  {
+    return theModule->test06(aArgs, aSctx, aDctx);
+  }
+};
+
+/******************************************************************************
+ *****************************************************************************/
+class Test06SDFunction : public TestFunction
+{
+public:
+  Test06SDFunction(const UtilTestsModule* aModule) :
+    TestFunction(aModule) {};
+
+  virtual ~Test06SDFunction() {}
+
+  virtual zorba::String
+  getLocalName() const { return "test-06-sd"; }
+
+  zorba::ItemSequence_t
+  evaluate(const Arguments_t& aArgs,
+      const zorba::StaticContext* aSctx,
+      const zorba::DynamicContext* aDctx) const
+  {
+    return theModule->test06(aArgs, aSctx, aDctx);
+  }
+};
+
+/******************************************************************************
+ *****************************************************************************/
+class Test07CacheFunction : public TestFunction
+{
+public:
+  Test07CacheFunction(const UtilTestsModule* aModule) :
+    TestFunction(aModule) {};
+
+  virtual ~Test07CacheFunction() {}
+
+  virtual zorba::String
+  getLocalName() const { return "test-07-cache"; }
+
+  zorba::ItemSequence_t
+  evaluate(const Arguments_t& aArgs,
+      const zorba::StaticContext* aSctx,
+      const zorba::DynamicContext* aDctx) const
+  {
+    return theModule->test07(aArgs, aSctx, aDctx);
+  }
+};
+
+/******************************************************************************
+ *****************************************************************************/
+class Test07SDFunction : public TestFunction
+{
+public:
+  Test07SDFunction(const UtilTestsModule* aModule) :
+    TestFunction(aModule) {};
+
+  virtual ~Test07SDFunction() {}
+
+  virtual zorba::String
+  getLocalName() const { return "test-07-sd"; }
+
+  zorba::ItemSequence_t
+  evaluate(const Arguments_t& aArgs,
+      const zorba::StaticContext* aSctx,
+      const zorba::DynamicContext* aDctx) const
+  {
+    return theModule->test07(aArgs, aSctx, aDctx);
+  }
+};
+
+/******************************************************************************
+ *****************************************************************************/
 class NonSeeakableStreamableStringFunction : public TestFunction
 {
 public:

=== modified file 'src/annotations/annotations.cpp'
--- src/annotations/annotations.cpp	2014-04-17 12:21:32 +0000
+++ src/annotations/annotations.cpp	2014-04-17 12:21:32 +0000
@@ -44,7 +44,10 @@
 AnnotationInternal::theAnnotName2IdMap(0, NULL, 64, false);
 
 std::vector<AnnotationInternal::RuleBitSet>
-AnnotationInternal::theRuleSet;
+AnnotationInternal::theConflictRuleSet;
+
+std::vector<AnnotationInternal::AnnotationRequirement>
+AnnotationInternal::theRequiredRuleSet;
 
 
 /*******************************************************************************
@@ -85,6 +88,12 @@
   ZANN(nondeterministic, nondeterministic);
 
   //
+  // Zorba annotations - caching behaviour
+  //
+  ZANN(exclude-from-cache-key, exclude_from_cache_key);
+  ZANN(compare-with-deep-equal, compare_with_deep_equal);
+
+  //
   // Zorba annotations - xquery scripting
   //
   ZANN(assignable, assignable);
@@ -135,70 +144,82 @@
 
 #undef ZANN
 
-  // create a set of rules to detect conflicts between annotations
 #define ZANN(a) \
   ( 1 << static_cast<uint64_t>(AnnotationInternal::a) )
 
-  theRuleSet.push_back(
+  // create a set of rules to detect conflicts between annotations
+  theConflictRuleSet.push_back(
        ZANN(zann_unique) |
        ZANN(zann_nonunique));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_value_equality) |
       ZANN(zann_general_equality) |
       ZANN(zann_value_range) |
       ZANN(zann_general_range));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_automatic) |
       ZANN(zann_manual));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_mutable) |
       ZANN(zann_queue) |
       ZANN(zann_append_only) |
       ZANN(zann_const));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_ordered) |
       ZANN(zann_unordered));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_assignable) |
       ZANN(zann_nonassignable));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_strictlydeterministic) |
       ZANN(zann_deterministic) |
       ZANN(zann_nondeterministic));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_strictlydeterministic) |
       ZANN(zann_cache));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_sequential) |
       ZANN(zann_nonsequential));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(fn_private) |
       ZANN(fn_public));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_unordered) |
       ZANN(zann_queue));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_unordered) |
       ZANN(zann_append_only));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_queue) |
       ZANN(zann_append_only));
 
-  theRuleSet.push_back(
+  theConflictRuleSet.push_back(
       ZANN(zann_read_only_nodes) |
       ZANN(zann_mutable_nodes));
+
+  // create a set of rules to detect missing requirements between annotations
+  theRequiredRuleSet.push_back(AnnotationRequirement(
+      zann_exclude_from_cache_key,
+      ZANN(zann_cache) | ZANN(zann_strictlydeterministic)
+    ));
+
+  theRequiredRuleSet.push_back(AnnotationRequirement(
+      zann_compare_with_deep_equal,
+      ZANN(zann_cache) | ZANN(zann_strictlydeterministic)
+    ));
+
 #undef ZANN
 }
 
@@ -405,13 +426,22 @@
 /*******************************************************************************
   Called from translator to detect duplicates and conflicting declarations
 ********************************************************************************/
-void AnnotationList::checkConflictingDeclarations(
+void AnnotationList::checkDeclarations(
     DeclarationKind declKind,
     const QueryLoc& loc) const
 {
   // make sure we don't have more annotations then max 64 bit
   assert(AnnotationInternal::zann_end < 64);
 
+  RuleBitSet lDeclaredAnnotations = checkDuplicateDeclarations(declKind, loc);
+  checkConflictingDeclarations(lDeclaredAnnotations, declKind, loc);
+  checkRequiredDeclarations(lDeclaredAnnotations, declKind, loc);
+}
+
+AnnotationList::RuleBitSet AnnotationList::checkDuplicateDeclarations(
+    DeclarationKind declKind,
+    const QueryLoc& loc) const
+{
   RuleBitSet lCurrAnn;
 
   // mark and detect duplicates
@@ -436,19 +466,25 @@
         ERROR_PARAMS(ZED(XQST0106_Duplicate), qname->getStringValue()));
       }
     }
-
     lCurrAnn.set(id);
   }
+  return lCurrAnn;
+}
 
+void AnnotationList::checkConflictingDeclarations(
+    RuleBitSet currAnn,
+    DeclarationKind declKind,
+    const QueryLoc& loc) const
+{
   // check rules
-  std::vector<RuleBitSet>::const_iterator ite = AnnotationInternal::theRuleSet.begin();
-  std::vector<RuleBitSet>::const_iterator end = AnnotationInternal::theRuleSet.end();
+  std::vector<RuleBitSet>::const_iterator ite = AnnotationInternal::theConflictRuleSet.begin();
+  std::vector<RuleBitSet>::const_iterator end = AnnotationInternal::theConflictRuleSet.end();
 
   for (; ite != end; ++ite)
   {
     const RuleBitSet& lCurrSet = *ite;
 
-    if ((lCurrAnn & lCurrSet).count() > 1)
+    if ((currAnn & lCurrSet).count() > 1)
     {
       // build error string to return set of conflicting annotations
       std::ostringstream lProblems;
@@ -478,6 +514,52 @@
   }
 }
 
+void AnnotationList::checkRequiredDeclarations(
+    RuleBitSet declaredAnn,
+    DeclarationKind declKind,
+    const QueryLoc& loc) const
+{
+  // check rules
+  std::vector<AnnotationRequirement>::const_iterator ite = AnnotationInternal::theRequiredRuleSet.begin();
+  std::vector<AnnotationRequirement>::const_iterator end = AnnotationInternal::theRequiredRuleSet.end();
+
+  for (; ite != end; ++ite)
+  {
+    const AnnotationId& lCurrAnn = ite->first;
+    const RuleBitSet& lCurrSet = ite->second;
+
+    if (declaredAnn.test(lCurrAnn) && (declaredAnn & lCurrSet).count() == 0)
+    {
+      // build error string to return set of required annotations
+      std::ostringstream lProblems;
+      for (csize i = 0, j = 0; i < AnnotationInternal::zann_end; ++i)
+      {
+        if (lCurrSet.test(i))
+        {
+          AnnotationId id = static_cast<AnnotationId>(i);
+          lProblems << AnnotationInternal::lookup(id)->getStringValue()
+                    << ((j == lCurrSet.count() - 1) ? "" : ", ");
+          ++j;
+        }
+      }
+
+      if (declKind == var_decl)
+      {
+        RAISE_ERROR(err::XQST0116, loc,
+        ERROR_PARAMS(ZED(XQST0116_Requirement),
+            AnnotationInternal::lookup(lCurrAnn)->getStringValue(),
+            lProblems.str()));
+      }
+      else
+      {
+        RAISE_ERROR(err::XQST0106, loc,
+        ERROR_PARAMS(ZED(XQST0106_Requirement),
+            AnnotationInternal::lookup(lCurrAnn)->getStringValue(),
+            lProblems.str()));
+      }
+    }
+  }
+}
 
 } /* namespace zorba */
 /* vim:set et sw=2 ts=2: */

=== modified file 'src/annotations/annotations.h'
--- src/annotations/annotations.h	2014-04-17 12:21:32 +0000
+++ src/annotations/annotations.h	2014-04-17 12:21:32 +0000
@@ -60,6 +60,8 @@
     fn_public = 0,
     fn_private,
     zann_strictlydeterministic,
+    zann_exclude_from_cache_key,
+    zann_compare_with_deep_equal,
     zann_deterministic,
     zann_nondeterministic,
     zann_assignable,
@@ -94,13 +96,20 @@
 
 protected:
   typedef std::bitset<static_cast<int>(zann_end) + 1> RuleBitSet;
+  typedef std::pair<AnnotationId, RuleBitSet> AnnotationRequirement;
 
 protected:
-  static std::vector<store::Item_t>      theAnnotId2NameMap;
-
-  static ItemHandleHashMap<AnnotationId> theAnnotName2IdMap;
-
-  static std::vector<RuleBitSet>         theRuleSet;
+  static std::vector<store::Item_t>             theAnnotId2NameMap;
+  static ItemHandleHashMap<AnnotationId>        theAnnotName2IdMap;
+
+  //A conflict is present if for a rule (bitset) 2 or more annotations
+  //are declared
+  static std::vector<RuleBitSet>                theConflictRuleSet;
+
+  //A conflict is present if for a rule (pair of annotation and bitset)
+  //the annotation is present and none of the annotations in the bitset
+  //are declared
+  static std::vector<AnnotationRequirement>     theRequiredRuleSet;
 
 protected:
   AnnotationId                   theId;
@@ -159,11 +168,10 @@
 
 public:
   typedef AnnotationInternal::RuleBitSet RuleBitSet;
-
+  typedef AnnotationInternal::AnnotationRequirement AnnotationRequirement;
   typedef AnnotationInternal::AnnotationId AnnotationId;
 
   typedef std::vector<AnnotationInternal*> Annotations;
-
   typedef Annotations::size_type size_type;
 
 protected:
@@ -191,7 +199,12 @@
       const store::Item_t& qname,
       const std::vector<const_expr*>& literals);
 
-  void checkConflictingDeclarations(DeclarationKind k, const QueryLoc& loc) const;
+  void checkDeclarations(DeclarationKind k, const QueryLoc& loc) const;
+
+private:
+  RuleBitSet checkDuplicateDeclarations(DeclarationKind k, const QueryLoc& loc) const;
+  void checkConflictingDeclarations(RuleBitSet bs, DeclarationKind k, const QueryLoc& loc) const;
+  void checkRequiredDeclarations(RuleBitSet bs, DeclarationKind k, const QueryLoc& loc) const;
 };
 
 

=== modified file 'src/compiler/codegen/plan_visitor.cpp'
--- src/compiler/codegen/plan_visitor.cpp	2014-04-17 12:21:32 +0000
+++ src/compiler/codegen/plan_visitor.cpp	2014-04-17 12:21:32 +0000
@@ -2523,15 +2523,15 @@
     }
     else if (func->isUdf())
     {
-      // need to computeResultCaching here for iterprint to work
+      // need to computeCacheSettings here for iterprint to work
       user_function* udf = static_cast<user_function*>(func);
-      udf->computeResultCaching(theCCB->theXQueryDiagnostics);
+      udf->computeCacheSettings(theCCB->theXQueryDiagnostics);
     }
     else if (func->isExternal())
     {
-      // need to computeResultCaching here for iterprint to work
+      // need to computeCacheSettings here for iterprint to work
       external_function* extf = static_cast<external_function*>(func);
-      extf->computeResultCaching(theCCB->theXQueryDiagnostics);
+      extf->computeCacheSettings(theCCB->theXQueryDiagnostics);
     }
   }
   else

=== modified file 'src/compiler/translator/translator.cpp'
--- src/compiler/translator/translator.cpp	2014-04-17 12:21:32 +0000
+++ src/compiler/translator/translator.cpp	2014-04-17 12:21:32 +0000
@@ -1740,6 +1740,7 @@
   // Create the inline udf obj.
   std::unique_ptr<user_function> inlineUDF( 
   new user_function(loc,
+                    theRootSctx,
                     signature(function_item_expr::create_inline_fname(loc),
                               funcType->get_param_types(),
                               returnType),
@@ -3962,7 +3963,7 @@
         if (theAnnotations.get())
         {
           theAnnotations->
-          checkConflictingDeclarations(AnnotationList::var_decl, loc);
+          checkDeclarations(AnnotationList::var_decl, loc);
 
           if (ZANN_CONTAINS(fn_private))
           {
@@ -4025,7 +4026,7 @@
       annotations->accept(*this);
 
       theAnnotations->
-      checkConflictingDeclarations(AnnotationList::func_decl, loc);
+      checkDeclarations(AnnotationList::func_decl, loc);
     }
 
     const QueryLoc& loc = func_decl->get_location();
@@ -4211,7 +4212,7 @@
     {
       // It's a UDF (non-external) function declaration. Create a user_function
       // obj with no body for now.
-      func = new user_function(loc, sig, NULL, scriptKind, theCCB);
+      func = new user_function(loc, theRootSctx, sig, NULL, scriptKind, theCCB);
     }
 
     func->setAnnotations(theAnnotations.get());
@@ -5105,7 +5106,7 @@
   }
 
   theAnnotations->
-  checkConflictingDeclarations(AnnotationList::collection_decl, loc);
+  checkDeclarations(AnnotationList::collection_decl, loc);
 
   // compute (redundant) enum values and assign
   // default annotations if no annotation for a group
@@ -5261,7 +5262,7 @@
   if (theAnnotations.get())
   {
     theAnnotations->
-    checkConflictingDeclarations(AnnotationList::index_decl, loc);
+    checkDeclarations(AnnotationList::index_decl, loc);
 
     if (ZANN_CONTAINS(zann_general_equality) ||
         ZANN_CONTAINS(zann_general_range))
@@ -6627,7 +6628,7 @@
   if (theAnnotations.get())
   {
     theAnnotations->
-    checkConflictingDeclarations(AnnotationList::var_decl, loc);
+    checkDeclarations(AnnotationList::var_decl, loc);
 
     if (ZANN_CONTAINS(zann_assignable))
     {
@@ -12721,6 +12722,7 @@
     expr* body = CREATE(cast)(theRootSctx, theUDF, loc, argVar, type, false);
 
     udf.reset(new user_function(loc,
+                                theRootSctx,
                                 signature(qnameItem, theRTM.ITEM_TYPE_QUESTION, type),
                                 body,
                                 SIMPLE_EXPR,
@@ -12755,6 +12757,7 @@
       FunctionConsts::FunctionKind fkind = func->getKind();
 
       udf.reset(new user_function(loc,
+                                  theRootSctx,
                                   func->getSignature(),
                                   NULL, // no body for now
                                   func->getScriptingKind(),
@@ -13133,6 +13136,7 @@
   // Create the udf obj.
   std::unique_ptr<user_function> udf( 
   new user_function(loc,
+                    theRootSctx,
                     signature(function_item_expr::create_inline_fname(loc),
                               paramTypes,
                               returnType),

=== modified file 'src/diagnostics/diagnostic_en.xml'
--- src/diagnostics/diagnostic_en.xml	2014-04-17 12:21:32 +0000
+++ src/diagnostics/diagnostic_en.xml	2014-04-17 12:21:32 +0000
@@ -914,6 +914,10 @@
       <entry key="Conflicting">
         <value>$2: conflicting annotations in declaration</value>
       </entry>
+      
+      <entry key="Requirement">
+        <value>$2: annotation requires one of the following annotations: $3</value>
+      </entry>
     </diagnostic>
 
     <diagnostic code="XQST0111">
@@ -955,6 +959,10 @@
       <entry key="Conflicting">
         <value>$2: conflicting annotations in declaration</value>
       </entry>
+      
+      <entry key="Requirement">
+        <value>$2: annotation requires one of the following annotations: $3</value>
+      </entry>
     </diagnostic>
 
     <diagnostic code="XQST0120">
@@ -2436,7 +2444,26 @@
     <diagnostic code="ZXQP0061" name="DISABLE_HTTP_OPTION_IN_QUERY">
       <value>"$1": this option cannot be specified in a query, it must be set via C++ API or command-line parameter</value>
     </diagnostic>
-
+    
+    <diagnostic code="ZXQP0062" name="MISSING_ANNOTATION_LITERALS">
+      <value>"$1": annotation requires at least one literal</value>
+    </diagnostic>
+    
+    <diagnostic code="ZXQP0063" name="INVALID_ANNOTATION_LITERAL_TYPE">
+      <value>"$1": is not a valid annotation literal for annotation "$2", literal has type $3, whereas the allowed types are: $4</value>
+    </diagnostic>
+    
+    <diagnostic code="ZXQP0064" name="INVALID_ARGUMENT_INDEX">
+      <value>"$1": is not a valid argument index for function "$2", valid indexes are in the range [1-$3]</value>
+    </diagnostic>
+    
+    <diagnostic code="ZXQP0065" name="INVALID_ANNOTATION">
+      <value>"$1": is not a valid annotation for function "$2", $3</value>
+      <entry key="NO_ARGUMENTS">
+        <value>function has no arguments</value>
+      </entry>
+    </diagnostic>
+      
     <diagnostic code="ZXQP8401" name="THESAURUS_VERSION_MISMATCH"
       if="!defined(ZORBA_NO_FULL_TEXT)">
       <comment>

=== modified file 'src/functions/cacheable_function.cpp'
--- src/functions/cacheable_function.cpp	2014-04-17 12:21:32 +0000
+++ src/functions/cacheable_function.cpp	2014-04-17 12:21:32 +0000
@@ -22,6 +22,7 @@
 
 #include "diagnostics/xquery_warning.h"
 #include "diagnostics/assert.h"
+#include "diagnostics/util_macros.h"
 
 #include "types/typeops.h"
 
@@ -38,6 +39,19 @@
 
 /*******************************************************************************
 ********************************************************************************/
+FunctionCache::FunctionCache(
+    static_context* aSctx,
+    boost::dynamic_bitset<>& aExcludeFromCacheKey,
+    boost::dynamic_bitset<>& aCompareWithDeepEqual,
+    bool aAcrossSnapshots):
+      FunctionCacheBaseMap(aSctx, aExcludeFromCacheKey, aCompareWithDeepEqual),
+      theAcrossSnapshots(aAcrossSnapshots),
+      theSnapshotID(0)
+{
+}
+
+/*******************************************************************************
+********************************************************************************/
 bool FunctionCache::ensureCacheValidity(PlanState& aPlanState)
 {
   if (!theAcrossSnapshots)
@@ -53,7 +67,6 @@
   return true;
 }
 
-
 /*******************************************************************************
 ********************************************************************************/
 FunctionCache::iterator FunctionCache::find(const store::Item_t& item, PlanState& aPlanState)
@@ -97,11 +110,10 @@
       function(aSig, aKind, aIsBuiltin),
       theLoc(aLoc),
       theTypeManager(aTypeManager),
-      theCacheResults(false),
+      theHasCache(false),
       theCacheAcrossSnapshots(false),
-      theCacheComputed(false),
-      theIsCacheAutomatic(false)
-
+      theIsCacheAutomatic(false),
+      theAreCacheSettingsComputed(false)
 {
 
 }
@@ -127,15 +139,15 @@
 ********************************************************************************/
 FunctionCache* cacheable_function::getCache()
 {
-  return &theCache;
+  return theCache.get();
 }
 
 
 /*******************************************************************************
 ********************************************************************************/
-bool cacheable_function::cacheResults() const
+bool cacheable_function::hasCache() const
 {
-  return theCacheResults;
+  return theHasCache;
 }
 
 /*******************************************************************************
@@ -156,11 +168,14 @@
 
 /*******************************************************************************
 ********************************************************************************/
-void cacheable_function::computeResultCaching(XQueryDiagnostics* aDiag)
+void cacheable_function::computeCacheSettings(XQueryDiagnostics* aDiag)
 {
-  if (theCacheComputed)
+  if (theAreCacheSettingsComputed)
     return;
 
+  theExcludeFromCacheKey = boost::dynamic_bitset<>(theSignature.paramCount());
+  theCompareWithDeepEqual = boost::dynamic_bitset<>(theSignature.paramCount());
+
   if (!theTypeManager)
     theTypeManager = getTypeManager();
 
@@ -169,16 +184,20 @@
   if (!theAnnotationList)
     useDefaultCachingSettings();
   else if (theAnnotationList->contains(AnnotationInternal::zann_cache))
-    useZorbaCache(aDiag);
+    useLegacyCache(aDiag);
   else if (theAnnotationList->contains(AnnotationInternal::zann_strictlydeterministic))
     useStrictlyDeterministicCache(aDiag);
   else if (theAnnotationList->contains(AnnotationInternal::zann_deterministic))
-    theCacheResults = false;
+    theHasCache = false;
   else
     useDefaultCachingSettings();
 
-  theCacheComputed = true;
-  theCache.setAcrossSnapshots(theCacheAcrossSnapshots);
+  theAreCacheSettingsComputed = true;
+  theCache.reset(new FunctionCache(
+      theModuleSctx,
+      theExcludeFromCacheKey,
+      theCompareWithDeepEqual,
+      theCacheAcrossSnapshots));
 }
 
 
@@ -188,17 +207,17 @@
 {
   if (isVariadic() || isUpdating() || isSequential() || !isDeterministic())
   {
-    theCacheResults = false;
+    theHasCache = false;
   }
   else
   {
     if (!haveAtomicArgumentsAndReturnType())
     {
-      theCacheResults = false;
+      theHasCache = false;
     }
     else
     {
-      theCacheResults = true;
+      theHasCache = true;
       theIsCacheAutomatic = true;
       theCacheAcrossSnapshots = false;
     }
@@ -260,7 +279,7 @@
 
 /*******************************************************************************
 ********************************************************************************/
-void cacheable_function::useZorbaCache(XQueryDiagnostics* aDiag)
+void cacheable_function::useLegacyCache(XQueryDiagnostics* aDiag)
 {
   if (isUpdating() || isVariadic())
   {
@@ -271,9 +290,10 @@
         WARN_PARAMS(getName()->getStringValue(), isUpdating() ? ZED(ZWST0005_UPDATING) : ZED(ZWST0005_VARIADIC)),
         WARN_LOC(theLoc)));
     }
-    theCacheResults = false;
+    theHasCache = false;
     return;
   }
+
   if (isSequential() || !isDeterministic())
   {
     if (aDiag)
@@ -284,7 +304,9 @@
         WARN_LOC(theLoc)));
     }
   }
-  theCacheResults = true;
+
+  parseCachingAnnotations(aDiag);
+  theHasCache = true;
   theIsCacheAutomatic = false;
   theCacheAcrossSnapshots = true;
 }
@@ -305,25 +327,137 @@
             (isSequential() ? ZED(ZWST0005_SEQUENTIAL) : ZED(ZWST0005_VARIADIC))),
         WARN_LOC(theLoc)));
     }
-    theCacheResults = false;
+    theHasCache = false;
   }
   else
   {
-    theCacheResults = true;
+    parseCachingAnnotations(aDiag);
+    theHasCache = true;
     theIsCacheAutomatic = false;
     theCacheAcrossSnapshots = false;
   }
 }
 
+/*******************************************************************************
+********************************************************************************/
 bool cacheable_function::disableAutomaticCaching()
 {
   if (theIsCacheAutomatic)
   {
-    theCacheResults = false;
-    theCache.clear();
+    theHasCache = false;
+    theCache->clear();
     return true;
   }
   return false;
 }
 
+/*******************************************************************************
+********************************************************************************/
+void cacheable_function::parseCachingAnnotations(XQueryDiagnostics* aDiag)
+{
+  parseCachingAnnotation(
+      theAnnotationList->get(AnnotationInternal::zann_compare_with_deep_equal),
+      theCompareWithDeepEqual,
+      aDiag);
+  parseCachingAnnotation(
+      theAnnotationList->get(AnnotationInternal::zann_exclude_from_cache_key),
+      theExcludeFromCacheKey,
+      aDiag);
+}
+
+/*******************************************************************************
+********************************************************************************/
+void cacheable_function::parseCachingAnnotation(AnnotationInternal* aAnnotation,
+    boost::dynamic_bitset<>& aBitset,
+    XQueryDiagnostics* aDiag)
+{
+  if (!aAnnotation)
+    return;
+
+  aBitset = boost::dynamic_bitset<>(theSignature.paramCount());
+  csize lNum = aAnnotation->getNumLiterals();
+  if (lNum)
+  {
+    for (csize i=0; i<lNum; ++i)
+    {
+      zorba::store::Item* lLiteral = aAnnotation->getLiteral(i);
+      if (lLiteral->getTypeCode() != store::XS_INTEGER)
+      {
+        RAISE_ERROR(zerr::ZXQP0063_INVALID_ANNOTATION_LITERAL_TYPE, theLoc,
+          ERROR_PARAMS(
+            lLiteral->getStringValue(),
+            lLiteral->getType()->getLocalName(),
+            AnnotationInternal::lookup(aAnnotation->getId())->getStringValue(),
+            "integer"));
+      }
+      else
+      {
+        int lIndex = atoi(lLiteral->getStringValue().c_str());
+        if (lIndex <1 || lIndex>(int)theSignature.paramCount())
+        {
+          std::string lFunctionName = "anonymous";
+          if (theSignature.getName())
+            lFunctionName = theSignature.getName()->getStringValue().str();
+
+          if (theSignature.paramCount())
+          {
+            RAISE_ERROR(zerr::ZXQP0064_INVALID_ARGUMENT_INDEX, theLoc,
+              ERROR_PARAMS(
+                lLiteral->getStringValue(),
+                lFunctionName,
+                theSignature.paramCount()));
+          }
+          else
+          {
+            RAISE_ERROR(zerr::ZXQP0065_INVALID_ANNOTATION, theLoc,
+              ERROR_PARAMS(
+                lLiteral->getStringValue(),
+                lFunctionName,
+                ZED(ZXQP0065_NO_ARGUMENTS)));
+          }
+        }
+        else
+        {
+          aBitset[lIndex-1] = 1;
+        }
+      }
+    }
+  }
+  else
+  {
+    RAISE_ERROR(zerr::ZXQP0062_MISSING_ANNOTATION_LITERALS, theLoc,
+      ERROR_PARAMS(AnnotationInternal::lookup(aAnnotation->getId())->getStringValue()));
+  }
+}
+
+/*******************************************************************************
+********************************************************************************/
+void cacheable_function::saveDynamicBitset(const boost::dynamic_bitset<>& aBitset, ::zorba::serialization::Archiver& ar)
+{
+  size_t lSize = aBitset.size();
+  ar & lSize;
+  bool lValue;
+  for (boost::dynamic_bitset<>::size_type i = 0; i<lSize; ++i)
+  {
+    lValue = (bool)aBitset[i];
+    ar & lValue;
+  }
+}
+
+/*******************************************************************************
+********************************************************************************/
+void cacheable_function::loadDynamicBitset(boost::dynamic_bitset<>& aBitset, ::zorba::serialization::Archiver& ar)
+{
+  size_t lSize = 0;
+  ar & lSize;
+  aBitset.resize(lSize);
+  bool lValue;
+  for (boost::dynamic_bitset<>::size_type i = 0; i<lSize; ++i)
+  {
+    ar & lValue;
+    aBitset[i] = lValue;
+  }
+}
+
+
 }

=== modified file 'src/functions/cacheable_function.h'
--- src/functions/cacheable_function.h	2014-04-17 12:21:32 +0000
+++ src/functions/cacheable_function.h	2014-04-17 12:21:32 +0000
@@ -18,26 +18,25 @@
 #define ZORBA_CACHEABLE_FUNCTION
 
 #include "functions/function.h"
-#include "zorbautils/hashmap_itemh_strict.h"
+#include "zorbautils/hashmap_itemh_cache.h"
 #include "store/api/item_handle.h"
+#include <boost/dynamic_bitset.hpp>
 
 namespace zorba
 {
 class expr;
 
-typedef typename zorba::ItemHandleStrictHashMap< std::vector<store::Item_t> > FunctionCacheBaseMap;
+typedef typename zorba::ItemHandleCacheHashMap< std::vector<store::Item_t> > FunctionCacheBaseMap;
 
 class FunctionCache : public FunctionCacheBaseMap
 {
-
 public:
   typedef typename FunctionCacheBaseMap::iterator iterator;
 
-  FunctionCache() :
-    theAcrossSnapshots(false),
-    theSnapshotID(0) {}
-
-  void setAcrossSnapshots(bool aAcrossSnapshots) {theAcrossSnapshots = aAcrossSnapshots;}
+  FunctionCache(static_context* aSctx,
+      boost::dynamic_bitset<>& aExcludeFromCacheKey,
+      boost::dynamic_bitset<>& aCompareWithDeepEqual,
+      bool aAcrossSnapshots);
 
   FunctionCache::iterator find(const store::Item_t& aKey, PlanState& aPlanState);
 
@@ -51,7 +50,6 @@
 public:
   bool theAcrossSnapshots;
   uint64_t theSnapshotID;
-
 };
 
 
@@ -62,17 +60,17 @@
   If an invocation uses the same arg values as a previous invocation, the cached
   result is simply returned without re-evaluating the udf.
 
-  theCacheResults:
+  theHasCache:
   ----------------
   Tells whether caching should be done for this udf or not.
 
   theCacheComputed:
   -----------------
-  Tells whether theCacheResults has been computed already or not.
-  theCacheResults is computed by the computeResultCaching() method, which is
+  Tells whether theHasCache has been computed already or not.
+  theHasCache is computed by the computeCacheSettings() method, which is
   invoked during codegen every time a udf call is encountered. The same udf may
-  be invoked multiple times, but the computation of theCacheResults needs to
-  be done only once. So, during the 1st invcocation of computeResultCaching(),
+  be invoked multiple times, but the computation of theHasCache needs to
+  be done only once. So, during the 1st invcocation of computeCacheSettings(),
   theCacheComputed is set to true, and subsequent invocations are noops.
 ********************************************************************************/
 class cacheable_function : public function
@@ -80,11 +78,17 @@
 protected:
   QueryLoc theLoc;
   TypeManager* theTypeManager;
-  FunctionCache theCache;
-  bool theCacheResults;
+  std::auto_ptr<FunctionCache> theCache;
+
+  //
+  // Cache settings
+  //
+  bool theHasCache;
   bool theCacheAcrossSnapshots;
-  bool theCacheComputed;
   bool theIsCacheAutomatic;
+  bool theAreCacheSettingsComputed;
+  boost::dynamic_bitset<> theExcludeFromCacheKey;
+  boost::dynamic_bitset<> theCompareWithDeepEqual;
 
 public:
   SERIALIZABLE_CLASS(cacheable_function)
@@ -100,17 +104,27 @@
       const QueryLoc& aLoc,
       TypeManager* aTypeManager);
   FunctionCache* getCache();
-  bool cacheResults() const;
+  bool hasCache() const;
   bool cacheAcrossSnapshots() const;
 
-  virtual void computeResultCaching(XQueryDiagnostics* aDiag);
+  virtual void computeCacheSettings(XQueryDiagnostics* aDiag);
+  virtual bool disableAutomaticCaching();
+
+protected:
   virtual void useDefaultCachingSettings();
+  virtual void useLegacyCache(XQueryDiagnostics* aDiag);
+  virtual void useStrictlyDeterministicCache(XQueryDiagnostics* aDiag);
+  void saveDynamicBitset(const boost::dynamic_bitset<>& aBitset, ::zorba::serialization::Archiver& ar);
+  void loadDynamicBitset(boost::dynamic_bitset<>& aBitset, ::zorba::serialization::Archiver& ar);
+
+private:
   virtual bool haveAtomicArgumentsAndReturnType() const;
   virtual bool isAtomicSequence(const xqtref_t& aType) const;
   virtual bool haveAllArgumentOneCardinality() const;
-  virtual void useZorbaCache(XQueryDiagnostics* aDiag);
-  virtual void useStrictlyDeterministicCache(XQueryDiagnostics* aDiag);
-  virtual bool disableAutomaticCaching();
+  virtual void parseCachingAnnotations(XQueryDiagnostics* aDiag);
+  virtual void parseCachingAnnotation(AnnotationInternal* aAnnotation,
+      boost::dynamic_bitset<>& aBitSet,
+      XQueryDiagnostics* aDiag);
 
   virtual TypeManager* getTypeManager();
 };

=== modified file 'src/functions/external_function.cpp'
--- src/functions/external_function.cpp	2014-04-17 12:21:32 +0000
+++ src/functions/external_function.cpp	2014-04-17 12:21:32 +0000
@@ -68,7 +68,7 @@
   zstring lLocalName;
   if (ar.is_serializing_out()) 
   {
-    computeResultCaching(NULL);
+    computeCacheSettings(NULL);
     ZORBA_ASSERT(theImpl);
     lLocalName = Unmarshaller::getInternalString(theImpl->getLocalName());
   }
@@ -93,19 +93,36 @@
     if (theImpl == NULL)
     {
       RAISE_ERROR(zerr::ZXQP0008_FUNCTION_IMPL_NOT_FOUND, theLoc,
-      ERROR_PARAMS(BUILD_STRING( '{', theNamespace, '}', lLocalName)));
+        ERROR_PARAMS(BUILD_STRING( '{', theNamespace, '}', lLocalName)));
     }
   }
 
   ar & theLoc;
-  ar & theCacheResults;
+  ar & theHasCache;
   ar & theCacheAcrossSnapshots;
-  ar & theCacheComputed;
+
+  if (ar.is_serializing_out())
+  {
+    saveDynamicBitset(theExcludeFromCacheKey, ar);
+    saveDynamicBitset(theCompareWithDeepEqual, ar);
+  }
+  else
+  {
+    loadDynamicBitset(theExcludeFromCacheKey, ar);
+    loadDynamicBitset(theCompareWithDeepEqual, ar);
+  }
+
+  ar & theAreCacheSettingsComputed;
   ar & theIsCacheAutomatic;
 
   if (!ar.is_serializing_out())
-    theCache.setAcrossSnapshots(theCacheAcrossSnapshots);
-
+  {
+    theCache.reset(new FunctionCache(
+      theModuleSctx,
+      theExcludeFromCacheKey,
+      theCompareWithDeepEqual,
+      theCacheAcrossSnapshots));
+  }
 }
 
 

=== modified file 'src/functions/udf.cpp'
--- src/functions/udf.cpp	2014-04-17 12:21:32 +0000
+++ src/functions/udf.cpp	2014-04-17 12:21:32 +0000
@@ -54,6 +54,7 @@
 ********************************************************************************/
 user_function::user_function(
     const QueryLoc& loc,
+    static_context* sctx,
     const signature& sig,
     expr* expr_body,
     unsigned short scriptingKind,
@@ -68,6 +69,7 @@
   theIsOptimized(false),
   thePlanStateSize(0)
 {
+  theModuleSctx = sctx;
   setFlag(FunctionConsts::isUDF);
   setPrivate(false);
 }
@@ -106,7 +108,7 @@
     getPlan(planStateSize, 1);
     ZORBA_ASSERT(thePlan != NULL);
 
-    computeResultCaching(theCCB->theXQueryDiagnostics);
+    computeCacheSettings(theCCB->theXQueryDiagnostics);
 
     if (theCCB->theHasEval)
     {
@@ -175,13 +177,29 @@
   ar & theArgVarsRefs;
 
   ar & theLoc;
-  ar & theCacheResults;
+  ar & theHasCache;
   ar & theCacheAcrossSnapshots;
-  ar & theCacheComputed;
+  if (ar.is_serializing_out())
+  {
+    saveDynamicBitset(theExcludeFromCacheKey, ar);
+    saveDynamicBitset(theCompareWithDeepEqual, ar);
+  }
+  else
+  {
+    loadDynamicBitset(theExcludeFromCacheKey, ar);
+    loadDynamicBitset(theCompareWithDeepEqual, ar);
+  }
+  ar & theAreCacheSettingsComputed;
   ar & theIsCacheAutomatic;
 
   if (!ar.is_serializing_out())
-    theCache.setAcrossSnapshots(theCacheAcrossSnapshots);
+  {
+    theCache.reset(new FunctionCache(
+      theModuleSctx,
+      theExcludeFromCacheKey,
+      theCompareWithDeepEqual,
+      theCacheAcrossSnapshots));
+  }
 }
 
 
@@ -586,7 +604,7 @@
 void user_function::useDefaultCachingSettings()
 {
   if (isOptimized() && !isRecursive())
-    theCacheResults = false;
+    theHasCache = false;
   else
     cacheable_function::useDefaultCachingSettings();
 }

=== modified file 'src/functions/udf.h'
--- src/functions/udf.h	2014-04-17 12:21:32 +0000
+++ src/functions/udf.h	2014-04-17 12:21:32 +0000
@@ -119,6 +119,7 @@
 public:
   user_function(
       const QueryLoc& loc,
+      static_context* sctx,
       const signature& sig,
       expr* expr_body,
       unsigned short scriptingKind,

=== modified file 'src/runtime/CMakeLists.txt'
--- src/runtime/CMakeLists.txt	2014-02-25 00:14:59 +0000
+++ src/runtime/CMakeLists.txt	2014-04-17 12:21:32 +0000
@@ -136,6 +136,7 @@
   numerics/format_integer.cpp
   numerics/format_number.cpp
   sequences/SequencesImpl.cpp
+  sequences/deep_equality.cpp
   visitors/iterprinter.cpp
   update/update.cpp
   util/item_iterator.cpp

=== modified file 'src/runtime/booleans/BooleanImpl.cpp'
--- src/runtime/booleans/BooleanImpl.cpp	2014-02-12 02:25:45 +0000
+++ src/runtime/booleans/BooleanImpl.cpp	2014-04-17 12:21:32 +0000
@@ -533,11 +533,11 @@
     {
     case CompareConsts::VALUE_EQUAL:
     {
-      return valueEqual(loc, aItem0, aItem1, typemgr, timezone, aCollation);
+      return valueEqual(loc, aItem0, aItem1, typemgr, timezone, aCollation, true);
     }
     case CompareConsts::VALUE_NOT_EQUAL:
     {
-      return ! valueEqual(loc, aItem0, aItem1, typemgr, timezone, aCollation);
+      return ! valueEqual(loc, aItem0, aItem1, typemgr, timezone, aCollation, true);
     }
     case CompareConsts::VALUE_GREATER:
     {
@@ -592,11 +592,14 @@
     store::Item_t& aItem1,
     const TypeManager* typemgr,
     long timezone,
-    XQPCollator* aCollation)
+    XQPCollator* aCollation,
+    bool raiseError)
 {
   store::Item_t castItem0, castItem1;
-  valueCasting(loc, typemgr, aItem0, aItem1, castItem0, castItem1);
-  return equal(loc, castItem0, castItem1, typemgr, timezone, aCollation);
+  if (valueCasting(loc, typemgr, aItem0, aItem1, castItem0, castItem1, raiseError))
+    return equal(loc, castItem0, castItem1, typemgr, timezone, aCollation, raiseError);
+  else
+    return false;
 }
 
 
@@ -612,7 +615,7 @@
     XQPCollator* aCollation)
 {
   store::Item_t castItem0, castItem1;
-  valueCasting(loc, typemgr, aItem0, aItem1, castItem0, castItem1);
+  valueCasting(loc, typemgr, aItem0, aItem1, castItem0, castItem1, true);
   return compare(loc, castItem0, castItem1, typemgr, timezone, aCollation);
 }
 
@@ -620,13 +623,14 @@
 /*******************************************************************************
 
 ********************************************************************************/
-void CompareIterator::valueCasting(
+bool CompareIterator::valueCasting(
     const QueryLoc& loc,
     const TypeManager* tm,
     store::Item_t& item0,
     store::Item_t& item1,
     store::Item_t& castItem0,
-    store::Item_t& castItem1)
+    store::Item_t& castItem1,
+    bool raiseError)
 {
   store::SchemaTypeCode type0 = item0->getTypeCode();
   store::SchemaTypeCode type1 = item1->getTypeCode();
@@ -641,7 +645,8 @@
     }
     else
     {
-      GenericCast::castToBuiltinAtomic(castItem0, item0, store::XS_STRING, NULL, loc);
+      if (!GenericCast::castToBuiltinAtomic(castItem0, item0, store::XS_STRING, NULL, loc, raiseError))
+        return false;
 
       if (!GenericCast::promote(castItem1, item1, store::XS_STRING, NULL, tm, loc))
         castItem1.transfer(item1);
@@ -652,7 +657,8 @@
     if (!GenericCast::promote(castItem0, item0, store::XS_STRING, NULL, tm, loc))
       castItem0.transfer(item0);
 
-    GenericCast::castToBuiltinAtomic(castItem1, item1, store::XS_STRING, NULL, loc);
+    if (!GenericCast::castToBuiltinAtomic(castItem1, item1, store::XS_STRING, NULL, loc, raiseError))
+      return false;
   }
   else
   {
@@ -662,6 +668,7 @@
     if (!GenericCast::promote(castItem1, item1, type0, NULL, tm, loc))
       castItem1.transfer(item1);
   }
+  return true;
 }
 
 
@@ -760,7 +767,7 @@
 {
   store::Item_t castItem0, castItem1;
   generalCasting(loc, typemgr, aItem0, aItem1, castItem0, castItem1);
-  return equal(loc, castItem0, castItem1, typemgr, timezone, aCollation);
+  return equal(loc, castItem0, castItem1, typemgr, timezone, aCollation, true);
 }
 
 
@@ -882,7 +889,8 @@
     const store::Item_t& item1,
     const TypeManager* tm,
     long timezone,
-    XQPCollator* collation)
+    XQPCollator* collation,
+    bool raiseError)
 {
   store::SchemaTypeCode type0 = item0->getTypeCode();
   store::SchemaTypeCode type1 = item1->getTypeCode();
@@ -928,7 +936,7 @@
     {
       return item1->equals(item0);
     }
-    else
+    else if (raiseError)
     {
       xqtref_t type0 = tm->create_value_type(item0.getp());
       xqtref_t type1 = tm->create_value_type(item1.getp());
@@ -936,6 +944,8 @@
       RAISE_ERROR(err::XPTY0004, loc,
       ERROR_PARAMS(ZED(BadType_23o), *type0, ZED(NoCompareWithType_4), *type1));
     }
+    else
+      return false;
   }
 }
 
@@ -1261,7 +1271,8 @@
                                                        lItem1,
                                                        theTypeManager,
                                                        theTimezone,
-                                                       theCollation);
+                                                       theCollation,
+                                                       true);
         }
         catch (ZorbaException const& e)
         {

=== modified file 'src/runtime/booleans/BooleanImpl.h'
--- src/runtime/booleans/BooleanImpl.h	2014-02-12 02:25:45 +0000
+++ src/runtime/booleans/BooleanImpl.h	2014-04-17 12:21:32 +0000
@@ -188,7 +188,8 @@
       store::Item_t& aItem1,
       const TypeManager* typemgr,
       long timezone,
-      XQPCollator* aCollation);
+      XQPCollator* aCollation,
+      bool raiseError);
 
   static long valueCompare(
       const QueryLoc& loc,
@@ -229,7 +230,8 @@
       const store::Item_t& aItem1,
       const TypeManager* typemgr,
       long timezone,
-      XQPCollator* aCollation);
+      XQPCollator* aCollation,
+      bool raiseError);
 
   static long compare(
       const QueryLoc& loc,
@@ -240,13 +242,14 @@
       XQPCollator* aCollation);
 
 private:
-  static void valueCasting(
+  static bool valueCasting(
       const QueryLoc& loc,
       const TypeManager* typemgr,
       store::Item_t& aItem0,
       store::Item_t& aItem1,
       store::Item_t& castItem0,
-      store::Item_t& castItem1);
+      store::Item_t& castItem1,
+      bool raiseError);
 
   static void generalCasting(
       const QueryLoc& loc,

=== modified file 'src/runtime/core/fncall_iterator.cpp'
--- src/runtime/core/fncall_iterator.cpp	2014-04-17 12:21:32 +0000
+++ src/runtime/core/fncall_iterator.cpp	2014-04-17 12:21:32 +0000
@@ -254,7 +254,7 @@
 ********************************************************************************/
 bool UDFunctionCallIterator::isCached() const
 {
-  return theUDF->cacheResults();
+  return theUDF->hasCache();
 }
 
 /*******************************************************************************
@@ -271,7 +271,7 @@
     PlanState& aPlanState,
     UDFunctionCallIteratorState* aState)
 {
-  if (!aState->theCache && theUDF->cacheResults())
+  if (!aState->theCache && theUDF->hasCache())
   {
     aState->theCache = theUDF->getCache();
     csize numArgs = theChildren.size();
@@ -452,7 +452,7 @@
 {
   try
   {
-    if (theUDF->cacheResults())
+    if (theUDF->hasCache())
       return nextImplCache(aResult, aPlanState);
     else
       return nextImplNoCache(aResult, aPlanState);
@@ -1304,7 +1304,7 @@
 ********************************************************************************/
 bool ExtFunctionCallIterator::isCached() const
 {
-  return theFunctionDef->cacheResults();
+  return theFunctionDef->hasCache();
 }
 
 

=== modified file 'src/runtime/core/gflwor/common.cpp'
--- src/runtime/core/gflwor/common.cpp	2013-02-07 17:24:36 +0000
+++ src/runtime/core/gflwor/common.cpp	2014-04-17 12:21:32 +0000
@@ -251,7 +251,8 @@
                                            tmp2,
                                            theTypeManager,
                                            theTimezone,
-                                           (*iter3).theCollator))
+                                           (*iter3).theCollator,
+                                           true))
           {
             return false;                                 
           }

=== modified file 'src/runtime/seq/seq_util.h'
--- src/runtime/seq/seq_util.h	2013-10-01 23:33:19 +0000
+++ src/runtime/seq/seq_util.h	2014-04-17 12:21:32 +0000
@@ -43,7 +43,7 @@
 
   bool operator()( store::Item *i, store::Item *j ) const {
     store::Item_t it( i ), jt( j );
-    return CompareIterator::valueEqual( loc_, it, jt, tm_, tz_, coll_ );
+    return CompareIterator::valueEqual( loc_, it, jt, tm_, tz_, coll_, true );
   }
 
 private:

=== added file 'src/runtime/sequences/deep_equality.cpp'
--- src/runtime/sequences/deep_equality.cpp	1970-01-01 00:00:00 +0000
+++ src/runtime/sequences/deep_equality.cpp	2014-04-17 12:21:32 +0000
@@ -0,0 +1,788 @@
+/*
+ * 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.
+ */
+#include "stdafx.h"
+
+#include <string>
+#include <fstream>
+#include <vector>
+#include <algorithm>
+#include <sstream>
+
+#include "deep_equality.h"
+#include "diagnostics/xquery_diagnostics.h"
+#include "diagnostics/util_macros.h"
+
+#include "zorbatypes/decimal.h"
+#include "zorbatypes/URI.h"
+#include "zorbamisc/ns_consts.h"
+#include "zorbautils/fatal.h"
+
+// For timing
+#include <zorba/util/time.h>
+
+#include <zorba/util/transcode_stream.h>
+
+#include <util/fs_util.h>
+#include <util/uri_util.h>
+
+#include <compiler/api/compilercb.h>
+
+#include <runtime/sequences/sequences.h>
+#include <runtime/core/arithmetic_impl.h>
+#include <runtime/util/iterator_impl.h>
+#include <runtime/visitors/planiter_visitor.h>
+#include <runtime/util/doc_uri_heuristics.h>
+
+#include <system/globalenv.h>
+
+#include <types/casting.h>
+#include <types/typeops.h>
+#include <types/typeimpl.h>
+
+#include <store/api/store.h>
+#include <store/api/iterator.h>
+#include <store/api/item_factory.h>
+#include "store/api/temp_seq.h"
+#include <store/api/pul.h>
+
+#include <context/static_context.h>
+
+#include "zorbautils/hashset_node_itemh.h"
+#include "zorbautils/hashset_atomic_itemh.h"
+namespace zorba
+{
+namespace equality
+{
+
+bool deepEqualChildren(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Iterator_t& it1,
+    const store::Iterator_t& it2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError)
+{
+  store::Item_t child1, child2;
+  bool c1Valid, c2Valid;
+
+  it1->open();
+  it2->open();
+
+  while (1)
+  {
+    while ((c1Valid = it1->next(child1)) &&
+           (child1->getNodeKind() == store::StoreConsts::piNode ||
+            child1->getNodeKind() == store::StoreConsts::commentNode))
+      ;
+
+    while ((c2Valid = it2->next(child2)) &&
+            (child2->getNodeKind() == store::StoreConsts::piNode ||
+             child2->getNodeKind() == store::StoreConsts::commentNode))
+      ;
+
+    if (!c1Valid && !c2Valid)
+      return true;
+    else if (!c1Valid || !c2Valid)
+      return false;
+    else if (!deepEqual(loc, sctx, child1, child2, collator, timezone, raiseError))
+      return false;
+  }
+
+  return true;
+}
+
+
+bool deepEqualAttributes(
+  const QueryLoc& loc,
+  static_context* sctx,
+  const store::Iterator_t& it1,
+  const store::Iterator_t& it2,
+  XQPCollator* collator,
+  int timezone,
+  bool raiseError)
+{
+  store::Item_t child1, child2;
+  int c1count = 0, c2count = 0;
+
+  it1->open();
+  it2->open();
+
+  while (it1->next(child1))
+  {
+    c1count++;
+
+    it2->reset();
+
+    bool found = false;
+    while (it2->next(child2))
+    {
+      if (deepEqual(loc, sctx, child1, child2, collator, timezone, raiseError))
+      {
+        found = true;
+        break;
+      }
+    }
+
+    if (!found)
+      return false;
+  }
+
+  it2->reset();
+  while (it2->next(child2))
+    c2count++;
+
+  if (c1count != c2count)
+    return false;
+
+  return true;
+}
+
+
+bool deepEqualNodes(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item1,
+    const store::Item* item2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError)
+{
+  if (item1->getNodeKind() != item2->getNodeKind())
+    return false;
+
+  switch (item1->getNodeKind())
+  {
+  case store::StoreConsts::documentNode:
+  {
+    return deepEqualChildren(loc,
+                             sctx,
+                             item1->getChildren(),
+                             item2->getChildren(),
+                             collator,
+                             timezone,
+                             raiseError);
+    break;
+  }
+  case store::StoreConsts::elementNode:
+  {
+    if (! item1->getNodeName()->equals(item2->getNodeName()))
+      return false;
+
+    if (!deepEqualAttributes(loc,
+                             sctx,
+                             item1->getAttributes(),
+                             item2->getAttributes(),
+                             collator,
+                             timezone,
+                             raiseError))
+      return false;
+
+    if (item1->haveSimpleContent())
+    {
+      if (!item2->haveSimpleContent())
+        return false;
+
+      store::Item_t value1, value2;
+      store::Iterator_t ite1, ite2;
+      item1->getTypedValue(value1, ite1);
+      item2->getTypedValue(value2, ite2);
+
+      if (ite1 == NULL && ite2 == NULL)
+      {
+        return deepEqual(loc, sctx, value1, value2, collator, timezone, raiseError);
+      }
+      else if (ite1 != NULL && ite2 != NULL)
+      {
+        ite1->open();
+        ite2->open();
+
+        while (1)
+        {
+          bool c1Valid = ite1->next(value1);
+          bool c2Valid = ite2->next(value2);
+
+          if (!c1Valid && !c2Valid)
+            return true;
+          else if (!c1Valid || !c2Valid)
+            return false;
+          else if (!deepEqual(loc, sctx, value1, value2, collator, timezone, raiseError))
+            return false;
+        }
+      }
+      else
+      {
+        return false;
+      }
+    }
+    else if (item2->haveSimpleContent())
+    {
+      return false;
+    }
+    else
+    {
+      store::Item* typename1 = item1->getType();
+      store::Item* typename2 = item2->getType();
+
+      if (typename1->equals(typename2))
+      {
+        return deepEqualChildren(loc,
+                                 sctx,
+                                 item1->getChildren(),
+                                 item2->getChildren(),
+                                 collator,
+                                 timezone,
+                                 raiseError);
+      }
+      else
+      {
+        TypeManager* tm = sctx->get_typemanager();
+
+        xqtref_t type1 =
+        tm->create_named_type(typename1, SequenceType::QUANT_ONE, loc, raiseError);
+
+        xqtref_t type2 =
+        tm->create_named_type(typename2, SequenceType::QUANT_ONE, loc, raiseError);
+
+        ZORBA_ASSERT(type1->isComplex() && type2->isComplex());
+
+        if (type1->contentKind() != type2->contentKind())
+          return false;
+
+        return deepEqualChildren(loc,
+                                 sctx,
+                                 item1->getChildren(),
+                                 item2->getChildren(),
+                                 collator,
+                                 timezone,
+                                 raiseError);
+      }
+    }
+    break;
+  }
+  case store::StoreConsts::attributeNode:
+  {
+    if (! item1->getNodeName()->equals(item2->getNodeName()))
+      return false;
+
+    store::Item_t value1, value2;
+    store::Iterator_t ite1, ite2;
+    item1->getTypedValue(value1, ite1);
+    item2->getTypedValue(value2, ite2);
+
+    if (ite1 == NULL && ite2 == NULL)
+    {
+      return deepEqual(loc, sctx, value1, value2, collator, timezone, raiseError);
+    }
+    else if (ite1 != NULL && ite2 != NULL)
+    {
+      ite1->open();
+      ite2->open();
+
+      while (1)
+      {
+        bool c1Valid = ite1->next(value1);
+        bool c2Valid = ite2->next(value2);
+
+        if (!c1Valid && !c2Valid)
+          return true;
+        else if (!c1Valid || !c2Valid)
+          return false;
+        else if (!deepEqual(loc, sctx, value1, value2, collator, timezone, raiseError))
+          return false;
+      }
+    }
+    else
+    {
+      return false;
+    }
+
+    break;
+  }
+  case store::StoreConsts::textNode:
+  case store::StoreConsts::commentNode:
+  {
+    return (0 == utf8::compare(item1->getStringValue(),
+                               item2->getStringValue(),
+                               collator));
+  }
+
+  case store::StoreConsts::piNode:
+  {
+    if (utf8::compare(item1->getNodeName()->getStringValue(),
+                      item2->getNodeName()->getStringValue(),
+                      collator))
+      return false;
+
+    return (0 == utf8::compare(item1->getStringValue(),
+                               item2->getStringValue(),
+                               collator));
+  }
+
+  case store::StoreConsts::namespaceNode:
+  {
+    if (utf8::compare(item1->getNamespacePrefix(),
+                      item2->getNamespacePrefix(),
+                      collator))
+      return false;
+
+    return (0 == utf8::compare(item1->getStringValue(),
+                               item2->getStringValue(),
+                               collator));
+  }
+  default:
+    ZORBA_ASSERT(false);
+  }
+
+  return true;
+}
+
+
+bool deepEqualObjects(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item1,
+    const store::Item* item2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError)
+{
+  assert(item1->isObject());
+  assert(item2->isObject());
+
+  if (item1->getNumObjectPairs() != item2->getNumObjectPairs())
+    return false;
+
+  store::Iterator_t lKeys = item1->getObjectKeys();
+  lKeys->open();
+
+  store::Item_t lKey, lValue1, lValue2;
+
+  while (lKeys->next(lKey))
+  {
+    lValue2 = item2->getObjectValue(lKey);
+
+    if (lValue2 == NULL)
+      return false;
+
+    lValue1 = item1->getObjectValue(lKey);
+
+    if (!deepEqual(loc, sctx, lValue1, lValue2, collator, timezone, raiseError))
+      return false;
+  }
+
+  return true;
+}
+
+
+bool deepEqualArrays(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item1,
+    const store::Item* item2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError)
+{
+  assert(item1->isArray());
+  assert(item2->isArray());
+
+  if (item1->getArraySize() != item2->getArraySize())
+    return false;
+
+  store::Iterator_t lValues1 = item1->getArrayValues();
+  store::Iterator_t lValues2 = item2->getArrayValues();
+  lValues1->open();
+  lValues2->open();
+
+  store::Item_t lValue1, lValue2;
+
+  while (lValues1->next(lValue1) && lValues2->next(lValue2))
+  {
+    if (!deepEqual(loc, sctx, lValue1, lValue2, collator, timezone, raiseError))
+      return false;
+  }
+
+  return true;
+}
+
+
+bool deepEqual(
+    const QueryLoc& loc,
+    static_context* sctx,
+    store::Item_t& item1,
+    store::Item_t& item2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError)
+{
+  if (item1->isFunction() || item2->isFunction())
+  {
+    if (raiseError)
+    {
+      RAISE_ERROR(err::FOTY0015, loc,
+        ERROR_PARAMS((item1->isFunction() ? item1 : item2)->getFunctionName()->getStringValue()));
+    }
+    else
+      return false;
+  }
+
+  if (item1->getKind() != item2->getKind())
+    return false;
+
+  switch (item1->getKind())
+  {
+  case store::Item::ATOMIC:
+  {
+    assert(item2->isAtomic());
+
+    store::SchemaTypeCode type1 = item1->getTypeCode();
+    store::SchemaTypeCode type2 = item2->getTypeCode();
+
+    // check if both items are NaN
+    if (((type1 == store::XS_FLOAT && item1->getFloatValue().isNaN()) ||
+         (type1 == store::XS_DOUBLE && item1->getDoubleValue().isNaN()))
+        &&
+        ((type2 == store::XS_FLOAT && item2->getFloatValue().isNaN()) ||
+         (type2 == store::XS_DOUBLE && item2->getDoubleValue().isNaN())))
+    {
+      return true;
+    }
+
+    if (raiseError)
+    {
+      try
+      {
+        TypeManager* tm = sctx->get_typemanager();
+        return CompareIterator::valueEqual(loc, item1, item2, tm, timezone, collator, raiseError);
+       }
+       catch (ZorbaException const& e)
+       {
+        if (e.diagnostic() == err::XPTY0004)
+          return false;
+        throw;
+       }
+    }
+    else
+    {
+      TypeManager* tm = sctx->get_typemanager();
+      return CompareIterator::valueEqual(loc, item1, item2, tm, timezone, collator, raiseError);
+    }
+
+    break;
+  }
+  case store::Item::NODE:
+  {
+    return deepEqualNodes(loc, sctx, item1, item2, collator, timezone, raiseError);
+  }
+  case store::Item::OBJECT:
+  {
+    return deepEqualObjects(loc, sctx, item1, item2, collator, timezone, raiseError);
+  }
+  case store::Item::ARRAY:
+  {
+    return deepEqualArrays(loc, sctx, item1, item2, collator, timezone, raiseError);
+  }
+  default:
+  {
+    ZORBA_ASSERT(false);  // should never reach here
+  }
+  }
+
+  return false;
+}
+
+uint32_t deHashChildren(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Iterator_t& it,
+    XQPCollator* collator,
+    int timezone)
+{
+  uint32_t lHash = FNV_32_INIT;
+  uint32_t lInnerHash;
+  store::Item_t child;
+  it->open();
+
+  while (it->next(child))
+  {
+    if (child->getNodeKind() == store::StoreConsts::piNode
+        ||
+        child->getNodeKind() == store::StoreConsts::commentNode)
+      continue;
+
+    lInnerHash = deHash(loc, sctx, child, collator, timezone);
+    lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+  }
+
+  return lHash;
+}
+
+
+uint32_t deHashAttributes(
+  const QueryLoc& loc,
+  static_context* sctx,
+  const store::Iterator_t& it,
+  XQPCollator* collator,
+  int timezone)
+{
+  uint32_t lHash = FNV_32_INIT;
+  std::vector<uint32_t> lInnerHashes;
+  store::Item_t attr;
+
+  it->open();
+  while (it->next(attr))
+  {
+    lInnerHashes.push_back(deHash(loc, sctx, attr, collator, timezone));
+  }
+
+  std::sort(lInnerHashes.begin(), lInnerHashes.end());
+  for(std::vector<uint32_t>::iterator it = lInnerHashes.begin(); it != lInnerHashes.end(); ++it)
+  {
+    lHash = hashfun::h32(&(*it), sizeof(*it), lHash);
+  }
+
+  return lHash;
+}
+
+
+uint32_t deHashNode(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item,
+    XQPCollator* collator,
+    int timezone)
+{
+  uint32_t lHash = FNV_32_INIT;
+  uint32_t lInnerHash;
+
+  store::NodeKind lNodeKind = item->getNodeKind();
+  lHash = hashfun::h32(&lNodeKind, sizeof(lNodeKind), lHash);
+
+  switch (item->getNodeKind())
+  {
+    case store::StoreConsts::documentNode:
+    {
+      lInnerHash = equality::deHashChildren(loc, sctx, item->getChildren(), collator, timezone);
+      return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+    }
+    case store::StoreConsts::elementNode:
+    {
+      lInnerHash = item->getNodeName()->hash();
+      lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      lInnerHash = deHashAttributes(loc, sctx, item->getAttributes(), collator, timezone);
+      lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      bool lHaveSimpleContent = item->haveSimpleContent();
+      lHash = hashfun::h32(&lHaveSimpleContent, sizeof(lHaveSimpleContent), lHash);
+
+      if (lHaveSimpleContent)
+      {
+        store::Item_t value;
+        store::Iterator_t ite;
+        item->getTypedValue(value, ite);
+        if (value)
+        {
+          lInnerHash = deHash(loc, sctx, value, collator, timezone);
+          lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+        }
+        else if (ite)
+        {
+          ite->open();
+          while (ite->next(value))
+          {
+            lInnerHash = deHash(loc, sctx, value, collator, timezone);
+            lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+          }
+        }
+        return lHash;
+      }
+      else
+      {
+        lInnerHash = deHashChildren(loc, sctx, item->getChildren(), collator, timezone);
+        return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      }
+    }
+    case store::StoreConsts::attributeNode:
+    {
+      lInnerHash = item->getNodeName()->hash();
+      lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      store::Item_t value;
+      store::Iterator_t ite;
+      item->getTypedValue(value, ite);
+      if (value)
+      {
+        lInnerHash = deHash(loc, sctx, value, collator, timezone);
+        lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      }
+      else if (ite)
+      {
+        ite->open();
+        while (ite->next(value))
+        {
+          lInnerHash = deHash(loc, sctx, value, collator, timezone);
+          lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+        }
+      }
+      return lHash;
+    }
+    case store::StoreConsts::textNode:
+    case store::StoreConsts::commentNode:
+    {
+      zstring lStringValue = item->getStringValue();
+      return hashfun::h32(&lStringValue, sizeof(lStringValue), lHash);
+    }
+    case store::StoreConsts::piNode:
+    {
+      lInnerHash = item->getNodeName()->hash();
+      lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      zstring lStringValue = item->getStringValue();
+      return hashfun::h32(&lStringValue, sizeof(lStringValue), lHash);
+    }
+
+    case store::StoreConsts::namespaceNode:
+    {
+      zstring lNamespacePrefix = item->getNamespacePrefix();
+      lHash = hashfun::h32(&lNamespacePrefix, sizeof(lNamespacePrefix), lHash);
+      zstring lStringValue = item->getStringValue();
+      return hashfun::h32(&lStringValue, sizeof(lStringValue), lHash);
+    }
+    default:
+    {
+      /*
+       * The type of the item is one of:
+       * PUL, FUNCTION, ERROR_
+       */
+      return FNV_32_INIT;
+    }
+  }
+
+  return true;
+}
+
+struct ObjectKeyPred
+{
+    bool operator()(store::Item_t const& a, store::Item_t const& b) const
+    {
+        return a->getString() < b->getString();
+    }
+};
+
+uint32_t deHashObject(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item,
+    XQPCollator* collator,
+    int timezone)
+{
+  uint32_t lHash = FNV_32_INIT;
+  uint32_t lInnerHash;
+  std::vector<store::Item_t> lKeysVec;
+  store::Iterator_t lKeys = item->getObjectKeys();
+  store::Item_t lKey;
+  lKeys->open();
+
+  while (lKeys->next(lKey))
+  {
+    lKeysVec.push_back(lKey);
+  }
+
+  std::sort(lKeysVec.begin(), lKeysVec.end(), ObjectKeyPred());
+  for(std::vector<store::Item_t>::iterator it = lKeysVec.begin(); it != lKeysVec.end(); ++it)
+  {
+    lInnerHash = deHash(loc, sctx, *it, collator, timezone);
+    lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+  }
+
+  return lHash;
+}
+
+
+uint32_t deHashArray(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item,
+    XQPCollator* collator,
+    int timezone)
+{
+  uint32_t lHash = FNV_32_INIT;
+  uint32_t lInnerHash;
+
+  store::Iterator_t lValues = item->getArrayValues();
+  store::Item_t lValue;
+  lValues->open();
+
+  while (lValues->next(lValue))
+  {
+    lInnerHash = deHash(loc, sctx, lValue, collator, timezone);
+    lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+  }
+
+  return lHash;
+}
+
+
+uint32_t deHash(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item,
+    XQPCollator* collator,
+    int timezone)
+{
+  store::Item::ItemKind lKind = item->getKind();
+  uint32_t lHash = hashfun::h32(&lKind, sizeof(store::Item::ItemKind), FNV_32_INIT);
+  uint32_t lInnerHash;
+
+  switch (item->getKind())
+  {
+    case store::Item::ATOMIC:
+    {
+      store::SchemaTypeCode type = item->getTypeCode();
+      lHash = hashfun::h32(&type, sizeof(type), lHash);
+      lInnerHash = item->hash(timezone, collator);
+      return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+    }
+    case store::Item::NODE:
+    {
+      lInnerHash = deHashNode(loc, sctx, item, collator, timezone);
+      return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+    }
+    case store::Item::OBJECT:
+    {
+      lInnerHash = deHashObject(loc, sctx, item, collator, timezone);
+      return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+    }
+    case store::Item::ARRAY:
+    {
+      lInnerHash = deHashArray(loc, sctx, item, collator, timezone);
+      return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+    }
+    default:
+    {
+      /*
+       * The type of the item is one of:
+       * PUL, FUNCTION, ERROR_
+       */
+      return FNV_32_INIT;
+    }
+  }
+
+  return false;
+}
+
+
+
+}
+}

=== added file 'src/runtime/sequences/deep_equality.h'
--- src/runtime/sequences/deep_equality.h	1970-01-01 00:00:00 +0000
+++ src/runtime/sequences/deep_equality.h	2014-04-17 12:21:32 +0000
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2006-2014 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_DEEP_EQUALITY_H
+#define ZORBA_DEEP_EQUALITY_H
+
+#include "common/shared_types.h"
+#include "store/api/iterator.h"
+
+namespace zorba
+{
+
+namespace equality
+{
+
+bool deepEqual(
+    const QueryLoc& loc,
+    static_context* sctx,
+    store::Item_t& item1,
+    store::Item_t& item2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError);
+
+bool deepEqualChildren(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Iterator_t& it1,
+    const store::Iterator_t& it2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError);
+
+bool deepEqualAttributes(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Iterator_t& it1,
+    const store::Iterator_t& it2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError);
+
+bool deepEqualNodes(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item1,
+    const store::Item* item2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError);
+
+bool deepEqualObjects(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item1,
+    const store::Item* item2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError);
+
+bool deepEqualArrays(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item1,
+    const store::Item* item2,
+    XQPCollator* collator,
+    int timezone,
+    bool raiseError);
+
+uint32_t deHash(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item,
+    XQPCollator* collator,
+    int timezone);
+
+uint32_t deHashChildren(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Iterator_t& it,
+    XQPCollator* collator,
+    int timezone);
+
+uint32_t deHashAttributes(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Iterator_t& it,
+    XQPCollator* collator,
+    int timezone);
+
+uint32_t deHashNode(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item,
+    XQPCollator* collator,
+    int timezone);
+
+uint32_t deHashObject(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item,
+    XQPCollator* collator,
+    int timezone);
+
+uint32_t deHashArray(
+    const QueryLoc& loc,
+    static_context* sctx,
+    const store::Item* item,
+    XQPCollator* collator,
+    int timezone);
+
+}
+}
+#endif

=== modified file 'src/runtime/sequences/sequences_impl.cpp'
--- src/runtime/sequences/sequences_impl.cpp	2013-10-10 03:54:10 +0000
+++ src/runtime/sequences/sequences_impl.cpp	2014-04-17 12:21:32 +0000
@@ -20,6 +20,7 @@
 #include <vector>
 #include <sstream>
 
+#include "deep_equality.h"
 #include "diagnostics/xquery_diagnostics.h"
 #include "diagnostics/util_macros.h"
 
@@ -157,7 +158,7 @@
 
   if (!consumeNext(state->theSearchItem, theChildren[1].getp(), planState))
   {
-		RAISE_ERROR(err::FORG0006, loc, ERROR_PARAMS(ZED(EmptySeqNoSearchItem)));
+    RAISE_ERROR(err::FORG0006, loc, ERROR_PARAMS(ZED(EmptySeqNoSearchItem)));
   }
 
   if (theChildren.size() == 3)
@@ -191,7 +192,8 @@
                                             searchItem,
                                             tm,
                                             timezone,
-                                            state->theCollator);
+                                            state->theCollator,
+                                            true);
       }
     }
     catch (ZorbaException const& e)
@@ -384,11 +386,11 @@
 
   if (!consumeNext(lPositionItem, theChildren[1].getp(), planState))
   {
-		throw XQUERY_EXCEPTION(
-			err::FORG0006,
-			ERROR_PARAMS( ZED( EmptySeqNoFnRemoveArg ) ),
-			ERROR_LOC( loc )
-		);
+    throw XQUERY_EXCEPTION(
+      err::FORG0006,
+      ERROR_PARAMS( ZED( EmptySeqNoFnRemoveArg ) ),
+      ERROR_LOC( loc )
+    );
   }
   state->thePosition = lPositionItem->getIntegerValue();
 
@@ -729,12 +731,12 @@
       {
         if (!lNextItem->equals(result))
         {
-					throw XQUERY_EXCEPTION( err::FORG0003, ERROR_LOC( loc ) );
+          throw XQUERY_EXCEPTION( err::FORG0003, ERROR_LOC( loc ) );
         }
       }
       else
       {
-				throw XQUERY_EXCEPTION( err::FORG0003, ERROR_LOC( loc ) );
+        throw XQUERY_EXCEPTION( err::FORG0003, ERROR_LOC( loc ) );
       }
     }
 
@@ -755,7 +757,7 @@
 
   if (!consumeNext(result, theChildren[0].getp(), planState))
   {
-		throw XQUERY_EXCEPTION( err::FORG0004, ERROR_LOC( loc ) );
+    throw XQUERY_EXCEPTION( err::FORG0004, ERROR_LOC( loc ) );
   }
   do
   {
@@ -801,7 +803,7 @@
   else
   {
     if (theRaiseError)
-			throw XQUERY_EXCEPTION( err::FORG0005, ERROR_LOC( loc ) );
+      throw XQUERY_EXCEPTION( err::FORG0005, ERROR_LOC( loc ) );
     else
       GENV_ITEMFACTORY->createBoolean(result, false);
   }
@@ -813,433 +815,13 @@
 
 /////////////////////////////////////////////////////////////////////////////////
 //                                                                             //
-//  15.3 Deepe Equal, Union, Intersection, and Except                          //
+//  15.3 Deep Equal, Union, Intersection, and Except                          //
 //                                                                             //
 /////////////////////////////////////////////////////////////////////////////////
 
 /*******************************************************************************
   15.3.1 fn:deep-equal
 ********************************************************************************/
-
-static bool DeepEqual(
-    const QueryLoc& loc,
-    static_context* sctx,
-    store::Item_t& item1,
-    store::Item_t& item2,
-    XQPCollator* collator,
-    int timezone);
-
-
-static bool DeepEqualChildren(
-    const QueryLoc& loc,
-    static_context* sctx,
-    const store::Iterator_t& it1,
-    const store::Iterator_t& it2,
-    XQPCollator* collator,
-    int timezone)
-{
-  store::Item_t child1, child2;
-  bool c1Valid, c2Valid;
-
-  it1->open();
-  it2->open();
-
-  while (1)
-  {
-    while ((c1Valid = it1->next(child1)) &&
-           (child1->getNodeKind() == store::StoreConsts::piNode ||
-            child1->getNodeKind() == store::StoreConsts::commentNode))
-      ;
-
-    while ((c2Valid = it2->next(child2)) &&
-            (child2->getNodeKind() == store::StoreConsts::piNode ||
-             child2->getNodeKind() == store::StoreConsts::commentNode))
-      ;
-
-    if (!c1Valid && !c2Valid)
-      return true;
-    else if (!c1Valid || !c2Valid)
-      return false;
-    else if (!DeepEqual(loc, sctx, child1, child2, collator, timezone))
-      return false;
-  }
-
-  return true;
-}
-
-
-static bool DeepEqualAttributes(
-  const QueryLoc& loc,
-  static_context* sctx,
-  const store::Iterator_t& it1,
-  const store::Iterator_t& it2,
-  XQPCollator* collator,
-  int timezone)
-{
-  store::Item_t child1, child2;
-  int c1count = 0, c2count = 0;
-
-  it1->open();
-  it2->open();
-
-  while (it1->next(child1))
-  {
-    c1count++;
-
-    it2->reset();
-
-    bool found = false;
-    while (it2->next(child2))
-    {
-      if (DeepEqual(loc, sctx, child1, child2, collator, timezone))
-      {
-        found = true;
-        break;
-      }
-    }
-
-    if (!found)
-      return false;
-  }
-
-  it2->reset();
-  while (it2->next(child2))
-    c2count++;
-
-  if (c1count != c2count)
-    return false;
-
-  return true;
-}
-
-
-static bool DeepEqualNodes(
-    const QueryLoc& loc,
-    static_context* sctx,
-    const store::Item_t& item1,
-    const store::Item_t& item2,
-    XQPCollator* collator,
-    int timezone)
-{
-  if (item1->getNodeKind() != item2->getNodeKind())
-    return false;
-
-  switch (item1->getNodeKind())
-  {
-  case store::StoreConsts::documentNode:
-  {
-    return DeepEqualChildren(loc,
-                             sctx,
-                             item1->getChildren(),
-                             item2->getChildren(),
-                             collator,
-                             timezone);
-    break;
-  }
-  case store::StoreConsts::elementNode:
-  {
-    if (! item1->getNodeName()->equals(item2->getNodeName()))
-      return false;
-
-    if (!DeepEqualAttributes(loc,
-                             sctx,
-                             item1->getAttributes(),
-                             item2->getAttributes(),
-                             collator,
-                             timezone))
-      return false;
-
-    if (item1->haveSimpleContent())
-    {
-      if (!item2->haveSimpleContent())
-        return false;
-
-      store::Item_t value1, value2;
-      store::Iterator_t ite1, ite2;
-      item1->getTypedValue(value1, ite1);
-      item2->getTypedValue(value2, ite2);
-
-      if (ite1 == NULL && ite2 == NULL)
-      {
-        return DeepEqual(loc, sctx, value1, value2, collator, timezone);
-      }
-      else if (ite1 != NULL && ite2 != NULL)
-      {
-        ite1->open();
-        ite2->open();
-        
-        while (1)
-        {
-          bool c1Valid = ite1->next(value1);
-          bool c2Valid = ite2->next(value2);
-          
-          if (!c1Valid && !c2Valid)
-            return true;
-          else if (!c1Valid || !c2Valid)
-            return false;
-          else if (!DeepEqual(loc, sctx, value1, value2, collator, timezone))
-            return false;
-        }
-      }
-      else
-      {
-        return false;
-      }
-    }
-    else if (item2->haveSimpleContent())
-    {
-      return false;
-    }
-    else
-    {
-      store::Item* typename1 = item1->getType();
-      store::Item* typename2 = item2->getType();
-
-      if (typename1->equals(typename2))
-      {
-        return DeepEqualChildren(loc,
-                                 sctx,
-                                 item1->getChildren(),
-                                 item2->getChildren(),
-                                 collator,
-                                 timezone);
-      }
-      else
-      {
-        TypeManager* tm = sctx->get_typemanager();
-
-        xqtref_t type1 = 
-        tm->create_named_type(typename1, SequenceType::QUANT_ONE, loc, true);
-
-        xqtref_t type2 = 
-        tm->create_named_type(typename2, SequenceType::QUANT_ONE, loc, true);
-
-        ZORBA_ASSERT(type1->isComplex() && type2->isComplex());
-
-        if (type1->contentKind() != type2->contentKind())
-          return false;
-
-        return DeepEqualChildren(loc,
-                                 sctx,
-                                 item1->getChildren(),
-                                 item2->getChildren(),
-                                 collator,
-                                 timezone);
-      }
-    }
-  }
-  case store::StoreConsts::attributeNode:
-  {
-    if (! item1->getNodeName()->equals(item2->getNodeName()))
-      return false;
-
-    store::Item_t value1, value2;
-    store::Iterator_t ite1, ite2;
-    item1->getTypedValue(value1, ite1);
-    item2->getTypedValue(value2, ite2);
-
-    if (ite1 == NULL && ite2 == NULL)
-    {
-      return DeepEqual(loc, sctx, value1, value2, collator, timezone);
-    }
-    else if (ite1 != NULL && ite2 != NULL)
-    {
-      ite1->open();
-      ite2->open();
-
-      while (1)
-      {
-        bool c1Valid = ite1->next(value1);
-        bool c2Valid = ite2->next(value2);
-        
-        if (!c1Valid && !c2Valid)
-          return true;
-        else if (!c1Valid || !c2Valid)
-          return false;
-        else if (!DeepEqual(loc, sctx, value1, value2, collator, timezone))
-          return false;
-      }
-    }
-    else
-    {
-      return false;
-    }
-
-    break;
-  }
-  case store::StoreConsts::textNode:
-  case store::StoreConsts::commentNode:
-  {
-    return (0 == utf8::compare(item1->getStringValue(),
-                               item2->getStringValue(),
-                               collator));
-  }
-
-  case store::StoreConsts::piNode:
-  {
-    if (utf8::compare(item1->getNodeName()->getStringValue(),
-                      item2->getNodeName()->getStringValue(),
-                      collator))
-      return false;
-
-    return (0 == utf8::compare(item1->getStringValue(),
-                               item2->getStringValue(),
-                               collator));
-  }
-
-  case store::StoreConsts::namespaceNode:
-  {
-    if (utf8::compare(item1->getNamespacePrefix(),
-                      item2->getNamespacePrefix(),
-                      collator))
-      return false;
-    
-    return (0 == utf8::compare(item1->getStringValue(),
-                               item2->getStringValue(),
-                               collator));
-  }
-  default:
-    ZORBA_ASSERT(false);
-  }
-
-  return true;
-}
-
-
-static bool DeepEqualObjects(
-    const QueryLoc& loc,
-    static_context* sctx,
-    const store::Item_t& item1,
-    const store::Item_t& item2,
-    XQPCollator* collator,
-    int timezone)
-{
-  assert(item1->isObject());
-  assert(item2->isObject());
-
-  if (item1->getNumObjectPairs() != item2->getNumObjectPairs())
-    return false;
-
-  store::Iterator_t lKeys = item1->getObjectKeys();
-  lKeys->open();
-
-  store::Item_t lKey, lValue1, lValue2;
-
-  while (lKeys->next(lKey))
-  {
-    lValue2 = item2->getObjectValue(lKey);
-
-    if (lValue2 == NULL)
-      return false;
-
-    lValue1 = item1->getObjectValue(lKey);
-
-    if (!DeepEqual(loc, sctx, lValue1, lValue2, collator, timezone))
-      return false;
-  }
-
-  return true;
-}
-
-
-static bool DeepEqualArrays(
-    const QueryLoc& loc,
-    static_context* sctx,
-    const store::Item_t& item1,
-    const store::Item_t& item2,
-    XQPCollator* collator,
-    int timezone)
-{
-  assert(item1->isArray());
-  assert(item2->isArray());
-
-  if (item1->getArraySize() != item2->getArraySize())
-    return false;
-
-  store::Iterator_t lValues1 = item1->getArrayValues();
-  store::Iterator_t lValues2 = item2->getArrayValues();
-  lValues1->open();
-  lValues2->open();
-
-  store::Item_t lValue1, lValue2;
-
-  while (lValues1->next(lValue1) && lValues2->next(lValue2))
-  {
-    if (!DeepEqual(loc, sctx, lValue1, lValue2, collator, timezone))
-      return false;
-  }
-
-  return true;
-}
-
-
-static bool DeepEqual(
-    const QueryLoc& loc,
-    static_context* sctx,
-    store::Item_t& item1,
-    store::Item_t& item2,
-    XQPCollator* collator,
-    int timezone)
-{
-  if (item1->getKind() != item2->getKind())
-    return false;
-
-  switch (item1->getKind())
-  {
-  case store::Item::ATOMIC:
-  {
-    assert(item2->isAtomic());
-
-    store::SchemaTypeCode type1 = item1->getTypeCode();
-    store::SchemaTypeCode type2 = item2->getTypeCode();
-
-    // check if bot items are NaN
-    if (((type1 == store::XS_FLOAT && item1->getFloatValue().isNaN()) ||
-         (type1 == store::XS_DOUBLE && item1->getDoubleValue().isNaN()))
-        &&
-        ((type2 == store::XS_FLOAT && item2->getFloatValue().isNaN()) ||
-         (type2 == store::XS_DOUBLE && item2->getDoubleValue().isNaN())))
-    {
-      return true;
-    }
-
-    try
-    {
-      TypeManager* tm = sctx->get_typemanager();
-
-      return CompareIterator::valueEqual(loc, item1, item2, tm, timezone, collator);
-    }
-    catch (ZorbaException const& e)
-    {
-      if (e.diagnostic() == err::XPTY0004)
-        return false;
-      throw;
-    }
-
-    break;
-  }
-  case store::Item::NODE:
-  {
-    return DeepEqualNodes(loc, sctx, item1, item2, collator, timezone);
-  }
-  case store::Item::OBJECT:
-  {
-    return DeepEqualObjects(loc, sctx, item1, item2, collator, timezone);
-  }
-  case store::Item::ARRAY:
-  {
-    return DeepEqualArrays(loc, sctx, item1, item2, collator, timezone);
-  }
-  default:
-  {
-    ZORBA_ASSERT(false);  // should never reach here
-  }
-  }
-
-  return false;
-}
-
-
 bool FnDeepEqualIterator::nextImpl(
     store::Item_t& result,
     PlanState& planState) const
@@ -1279,11 +861,11 @@
 
     if (arg1->isFunction() || arg2->isFunction())
     {
-			RAISE_ERROR(err::FOTY0015, loc,
+      RAISE_ERROR(err::FOTY0015, loc,
       ERROR_PARAMS((arg1->isFunction() ? arg1 : arg2)->getFunctionName()->getStringValue()));
     }
 
-    equal = equal && DeepEqual(loc, theSctx, arg1, arg2, collator, timezone);
+    equal = equal && equality::deepEqual(loc, theSctx, arg1, arg2, collator, timezone, true);
   }
 
   STACK_PUSH(GENV_ITEMFACTORY->createBoolean(result, equal), state);
@@ -1453,7 +1035,7 @@
       {
         xqtref_t type = tm->create_value_type(lRunningItem);
         RAISE_ERROR(err::FORG0006, loc,
-				ERROR_PARAMS(ZED(BadArgTypeForFn_2o34o),
+                     ERROR_PARAMS(ZED(BadArgTypeForFn_2o34o),
                      *type,
                      "fn:avg",
                      ZED(ExpectedType_5),
@@ -1524,8 +1106,8 @@
     else
     {
       xqtref_t type = tm->create_value_type(lRunningItem);
-			RAISE_ERROR(err::FORG0006, loc,
-			ERROR_PARAMS(ZED(BadArgTypeForFn_2o34o),
+      RAISE_ERROR(err::FORG0006, loc,
+                   ERROR_PARAMS(ZED(BadArgTypeForFn_2o34o),
                    *type,
                    "fn:avg",
                    ZED(ExpectedNumericOrDurationType)));
@@ -1597,7 +1179,7 @@
     {
       xqtref_t type = tm->create_value_type(result);
       RAISE_ERROR(err::FORG0006, loc,
-			ERROR_PARAMS(ZED(BadArgTypeForFn_2o34o), *type, "fn:sum"));
+        ERROR_PARAMS(ZED(BadArgTypeForFn_2o34o), *type, "fn:sum"));
     }
 
     while (consumeNext(lRunningItem, theChildren[0].getp(), planState))
@@ -1641,8 +1223,8 @@
       {
         xqtref_t type1 = tm->create_value_type(result);
         xqtref_t type2 = tm->create_value_type(lRunningItem);
-				RAISE_ERROR(err::FORG0006, loc,
-				ERROR_PARAMS(ZED( SumImpossibleWithTypes_23 ), *type1, *type2));
+        RAISE_ERROR(err::FORG0006, loc,
+          ERROR_PARAMS(ZED( SumImpossibleWithTypes_23 ), *type1, *type2));
       }
     }
 

=== added file 'src/zorbautils/hashmap_itemh_cache.h'
--- src/zorbautils/hashmap_itemh_cache.h	1970-01-01 00:00:00 +0000
+++ src/zorbautils/hashmap_itemh_cache.h	2014-04-17 12:21:32 +0000
@@ -0,0 +1,474 @@
+/*
+ * 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 HASHMAP_ITEMH_CACHE_H
+#define HASHMAP_ITEMH_CACHE_H
+
+#include "context/static_context.h"
+#include "runtime/sequences/deep_equality.h"
+#include "zorbautils/hashfun.h"
+#include "zorbautils/hashmap.h"
+
+#include "store/api/item.h"
+#include "store/naive/item_vector.h"
+
+#include "system/globalenv.h"
+
+#include <boost/dynamic_bitset.hpp>
+
+namespace zorba 
+{ 
+
+class ItemHandleCacheHashMapCmp
+{
+protected:
+  zorba::QueryLoc theEmptyLoc;
+  long theTimeZone;
+  XQPCollator* theCollator;
+  static_context* theSctx;
+  boost::dynamic_bitset<> theExcludeFromCacheKey;
+  boost::dynamic_bitset<> theCompareWithDeepEqual;
+
+public:
+  ItemHandleCacheHashMapCmp(
+      static_context* aSctx,
+      boost::dynamic_bitset<>& aExcludeFromCacheKey,
+      boost::dynamic_bitset<>& aCompareWithDeepEqual)
+    :
+    theTimeZone(0),
+    theCollator(NULL),
+    theSctx(aSctx),
+    theExcludeFromCacheKey(aExcludeFromCacheKey),
+    theCompareWithDeepEqual(aCompareWithDeepEqual)
+  {
+    /*if (theSctx->get_local_typemanager() == NULL)
+      theSctx->set_typemanager(new TypeManagerImpl(&GENV_TYPESYSTEM));*/
+  }
+
+  ItemHandleCacheHashMapCmp(
+      static_context* aSctx,
+      boost::dynamic_bitset<>& aExcludeFromCacheKey,
+      boost::dynamic_bitset<>& aCompareWithDeepEqual,
+      long aTimezone,
+      XQPCollator* aCollator)
+    :
+    theTimeZone(aTimezone),
+    theCollator(aCollator),
+    theSctx(aSctx),
+    theExcludeFromCacheKey(aExcludeFromCacheKey),
+    theCompareWithDeepEqual(aCompareWithDeepEqual)
+  {
+    /*if (theSctx->get_local_typemanager() == NULL)
+      theSctx->set_typemanager(new TypeManagerImpl(&GENV_TYPESYSTEM));*/
+  }
+
+  bool id_equal(const store::Item* t1, const store::Item* t2) const
+  {
+    if (t1 == NULL && t2 ==NULL)
+      return true;
+
+    if (t1 == NULL || t2 ==NULL)
+      return false;
+
+    store::Item::ItemKind lKind1 = t1->getKind();
+    store::Item::ItemKind lKind2 = t2->getKind();
+    if (lKind1 != lKind2)
+      return false;
+
+    const simplestore::ItemVector* lVector1;
+    const simplestore::ItemVector* lVector2;
+    switch (lKind1)
+    {
+      case store::Item::NODE:
+      case store::Item::OBJECT:
+      case store::Item::ARRAY:
+      {
+        return t1 == t2;
+      }
+      case store::Item::ATOMIC:
+      {
+        if (t1->getTypeCode() != t2->getTypeCode())
+          return false;
+        return t1->equals(t2, theTimeZone, theCollator);
+      }
+      case store::Item::LIST:
+      {
+        lVector1 = static_cast<const simplestore::ItemVector*>(t1);
+        lVector2 = static_cast<const simplestore::ItemVector*>(t2);
+
+        if (lVector1->size() != lVector2->size())
+          return false;
+
+        for (unsigned int i=0; i<lVector1->size(); ++i)
+        {
+          if (!id_equal(lVector1->getItem(i), lVector2->getItem(i)))
+            return false;
+        }
+        return true;
+      }
+      default:
+      {
+        /*
+         * The type of the item is one of:
+         * PUL, FUNCTION, ERROR_
+         */
+        return false;
+      }
+    }
+  }
+
+  bool deep_equal(const store::Item* t1, const store::Item* t2) const
+  {
+    if (t1 == NULL && t2 == NULL)
+      return true;
+
+    if (t1 == NULL || t2 ==NULL)
+      return false;
+
+    store::Item::ItemKind lKind1 = t1->getKind();
+    store::Item::ItemKind lKind2 = t2->getKind();
+    if (lKind1 != lKind2)
+      return false;
+
+    const simplestore::ItemVector* lVector1;
+    const simplestore::ItemVector* lVector2;
+    switch (lKind1)
+    {
+      case store::Item::NODE:
+      {
+        return equality::deepEqualNodes(theEmptyLoc, theSctx, t1, t2, theCollator, theTimeZone, false);
+      }
+      case store::Item::OBJECT:
+      {
+        return equality::deepEqualObjects(theEmptyLoc, theSctx, t1, t2, theCollator, theTimeZone, false);
+      }
+      case store::Item::ARRAY:
+      {
+        return equality::deepEqualArrays(theEmptyLoc, theSctx, t1, t2, theCollator, theTimeZone, false);
+      }
+      case store::Item::ATOMIC:
+      {
+        if (t1->getTypeCode() != t2->getTypeCode())
+          return false;
+        return t1->equals(t2, theTimeZone, theCollator);
+      }
+      case store::Item::LIST:
+      {
+        lVector1 = static_cast<const simplestore::ItemVector*>(t1);
+        lVector2 = static_cast<const simplestore::ItemVector*>(t2);
+
+        if (lVector1->size() != lVector2->size())
+          return false;
+
+        for (unsigned int i=0; i<lVector1->size(); ++i)
+        {
+          if (!deep_equal(lVector1->getItem(i), lVector2->getItem(i)))
+            return false;
+        }
+        return true;
+      }
+      default:
+      {
+        /*
+         * The type of the item is one of:
+         * PUL, FUNCTION, ERROR_
+         */
+        return false;
+      }
+    }
+  }
+
+  bool equal(const store::Item* t1, const store::Item* t2) const
+  {
+    const simplestore::ItemVector* lVector1 =
+        static_cast<const simplestore::ItemVector*>(t1);
+    const simplestore::ItemVector* lVector2 =
+        static_cast<const simplestore::ItemVector*>(t2);
+
+    for (unsigned int i=0; i<lVector1->size(); ++i)
+    {
+      if (!theExcludeFromCacheKey[i])
+      {
+        if (theCompareWithDeepEqual[i])
+        {
+          if (!deep_equal(lVector1->getItem(i), lVector2->getItem(i)))
+            return false;
+        }
+        else
+        {
+          if (!id_equal(lVector1->getItem(i), lVector2->getItem(i)))
+            return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  uint32_t id_hash(const store::Item* t) const
+  {
+    if (t == NULL)
+      return FNV_32_INIT;
+
+    store::SchemaTypeCode lTypeCode;
+    uint32_t lInnerHash;
+    const simplestore::ItemVector* lVector;
+    store::Item::ItemKind lKind = t->getKind();
+    uint32_t lHash = hashfun::h32(&lKind, sizeof(store::Item::ItemKind), FNV_32_INIT);
+    switch (lKind)
+    {
+      case store::Item::NODE:
+      case store::Item::OBJECT:
+      case store::Item::ARRAY:
+      {
+        return hashfun::h32((void*)(&t), sizeof(t), lHash);
+      }
+      case store::Item::ATOMIC:
+      {
+        lTypeCode = t->getTypeCode();
+        lHash = hashfun::h32(&lTypeCode, sizeof(lTypeCode), lHash);
+        lInnerHash = t->hash(theTimeZone, theCollator);
+        return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      }
+      case store::Item::LIST:
+      {
+        lVector = static_cast<const simplestore::ItemVector*>(t);
+        for (unsigned int i=0; i<lVector->size(); ++i)
+        {
+          lInnerHash = id_hash(lVector->getItem(i));
+          lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+        }
+        return lHash;
+      }
+      default:
+      {
+        /*
+         * The type of the item is one of:
+         * PUL, FUNCTION, ERROR_
+         */
+        return FNV_32_INIT;
+      }
+    }
+  }
+
+  uint32_t deep_hash(const store::Item* t) const
+  {
+    if (t == NULL)
+      return FNV_32_INIT;
+
+    store::SchemaTypeCode lTypeCode;
+    uint32_t lInnerHash;
+    const simplestore::ItemVector* lVector;
+    store::Item::ItemKind lKind = t->getKind();
+    uint32_t lHash = hashfun::h32(&lKind, sizeof(store::Item::ItemKind), FNV_32_INIT);
+    switch (lKind)
+    {
+      case store::Item::NODE:
+      {
+        lInnerHash = equality::deHashNode(theEmptyLoc, theSctx, t, theCollator, theTimeZone);
+        return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      }
+      case store::Item::OBJECT:
+      {
+        lInnerHash = equality::deHashObject(theEmptyLoc, theSctx, t, theCollator, theTimeZone);
+        return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      }
+      case store::Item::ARRAY:
+      {
+        lInnerHash = equality::deHashArray(theEmptyLoc, theSctx, t, theCollator, theTimeZone);
+        return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      }
+      case store::Item::ATOMIC:
+      {
+        lTypeCode = t->getTypeCode();
+        lHash = hashfun::h32(&lTypeCode, sizeof(lTypeCode), lHash);
+        lInnerHash = t->hash(theTimeZone, theCollator);
+        return hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+      }
+      case store::Item::LIST:
+      {
+        lVector = static_cast<const simplestore::ItemVector*>(t);
+        for (unsigned int i=0; i<lVector->size(); ++i)
+        {
+          lInnerHash = equality::deHash(theEmptyLoc, theSctx, lVector->getItem(i), theCollator, theTimeZone);
+          lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+        }
+        return lHash;
+      }
+      default:
+      {
+        /*
+         * The type of the item is one of:
+         * PUL, FUNCTION, ERROR_
+         */
+        return FNV_32_INIT;
+      }
+    }
+  }
+
+  uint32_t hash(const store::Item* t) const
+  {
+    const simplestore::ItemVector* lVector =
+      static_cast<const simplestore::ItemVector*>(t);
+    uint32_t lHash = FNV_32_INIT;
+    uint32_t lInnerHash;
+
+    for (unsigned int i=0; i<lVector->size(); ++i)
+    {
+      if (!theExcludeFromCacheKey[i])
+      {
+        if (theCompareWithDeepEqual[i])
+          lInnerHash = deep_hash(lVector->getItem(i));
+        else
+          lInnerHash = id_hash(lVector->getItem(i));
+      }
+      lHash = hashfun::h32(&lInnerHash, sizeof(lInnerHash), lHash);
+    }
+    return lHash;
+  }
+
+
+  long get_timezone() const { return theTimeZone; }
+
+  const XQPCollator* get_collator() const { return theCollator; }
+};
+
+
+/*******************************************************************************
+  A hash-based map mapping item handles to data items of type V. Equality is
+  based on pointer equality for Nodes, Arrays and Objects and on the
+  store::Item::equals() method for atomic. PULs, Function Items, and Error_s are
+  not supported and are always considered different.
+
+  NOTE: Although the map uses raw item pointers instead of rchandles, reference
+        counting is still done, but done manually (see insert, clear and erase
+        methods)
+ ********************************************************************************/
+template <class V>
+class ItemHandleCacheHashMap
+{
+public:
+  typedef typename HashMap<store::Item*, V, ItemHandleCacheHashMapCmp>::iterator iterator;
+
+private:
+  HashMap<store::Item*, V, ItemHandleCacheHashMapCmp> theMap;
+
+public:
+  ItemHandleCacheHashMap(
+      static_context* aSctx,
+      boost::dynamic_bitset<>& aExcludeFromCacheKey,
+      boost::dynamic_bitset<>& aCompareWithDeepEqual)
+:
+  theMap(
+    ItemHandleCacheHashMapCmp(aSctx, aExcludeFromCacheKey, aCompareWithDeepEqual),
+    8,
+    false)
+{
+}
+
+  ItemHandleCacheHashMap(
+      static_context* aSctx,
+      boost::dynamic_bitset<>& aExcludeFromCacheKey,
+      boost::dynamic_bitset<>& aCompareWithDeepEqual,
+      ulong aSize,
+      bool aSync)
+  :
+    theMap(
+      ItemHandleCacheHashMapCmp(aSctx, aExcludeFromCacheKey, aCompareWithDeepEqual),
+      aSize,
+      aSync)
+  {
+  }
+
+  ItemHandleCacheHashMap(
+      static_context* aSctx,
+      boost::dynamic_bitset<>& aExcludeFromCacheKey,
+      boost::dynamic_bitset<>& aCompareWithDeepEqual,
+      long aTimezone,
+      XQPCollator* aCollation,
+      ulong aSize,
+      bool aSync)
+  :
+    theMap(
+      ItemHandleCacheHashMapCmp(aSctx, aExcludeFromCacheKey, aCompareWithDeepEqual, aTimezone, aCollation),
+      aSize,
+      aSync)
+  {
+  }
+
+  ~ItemHandleCacheHashMap()
+  {
+    clear();
+  }
+
+  void clear()
+  {
+    SYNC_CODE(AutoMutex lock(theMap.get_mutex());)
+
+    iterator ite = this->begin();
+    iterator end = this->end();
+
+    for (; ite != end; ++ite)
+    {
+      (*ite).first->removeReference();
+    }
+
+    theMap.clearNoSync();
+  }
+
+  iterator begin() const { return theMap.begin(); }
+
+  iterator end() const { return theMap.end(); }
+
+  iterator find(const store::Item_t& item)
+  {
+    return theMap.find(item.getp());
+  }
+
+  bool insert(const store::Item_t& item, V& value)
+  {
+    bool inserted = theMap.insert(item.getp(), value);
+
+    if (inserted)
+      item->addReference();
+
+    return inserted;
+  }
+
+  bool erase(const store::Item_t& key)
+  {
+    bool found = theMap.erase(key.getp());
+
+    if (found)
+      key->removeReference();
+
+    return found;
+  }
+
+  csize size() const
+  {
+    return theMap.size();
+  }
+
+  bool empty() const
+  {
+    return theMap.size() == 0;
+  }
+
+};
+
+}
+
+#endif

=== modified file 'src/zorbautils/hashset_atomic_itemh.h'
--- src/zorbautils/hashset_atomic_itemh.h	2013-09-25 03:41:10 +0000
+++ src/zorbautils/hashset_atomic_itemh.h	2014-04-17 12:21:32 +0000
@@ -81,7 +81,8 @@
                                            t2,
                                            theCompareParam->theTypeManager,
                                            theCompareParam->theTimezone,
-                                           theCompareParam->theCollator);
+                                           theCompareParam->theCollator,
+                                           true);
       }
       catch(ZorbaException const& e)
       {

=== added file 'test/rbkt/ExpQueryResults/zorba/caching/deep-equal-ext-cache-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/caching/deep-equal-ext-cache-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/caching/deep-equal-ext-cache-01.xml.res	2014-04-17 12:21:32 +0000
@@ -0,0 +1,11 @@
+Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: NOT CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: NOT CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: NOT CACHED
+ Called with { "x" : 1, "y" : 2 }: NOT CACHED
+ Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: CACHED
+ Called with { "x" : 1, "y" : 2 }: CACHED
+ Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: NOT CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: NOT CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: NOT CACHED

=== added file 'test/rbkt/ExpQueryResults/zorba/caching/deep-equal-ext-sd-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/caching/deep-equal-ext-sd-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/caching/deep-equal-ext-sd-01.xml.res	2014-04-17 12:21:32 +0000
@@ -0,0 +1,11 @@
+Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: NOT CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: NOT CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: NOT CACHED
+ Called with { "x" : 1, "y" : 2 }: NOT CACHED
+ Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: CACHED
+ Called with { "x" : 1, "y" : 2 }: CACHED
+ Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: NOT CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: NOT CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: NOT CACHED

=== added file 'test/rbkt/ExpQueryResults/zorba/caching/deep-equal-udf-cache-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/caching/deep-equal-udf-cache-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/caching/deep-equal-udf-cache-01.xml.res	2014-04-17 12:21:32 +0000
@@ -0,0 +1,11 @@
+Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: NOT CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: NOT CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: NOT CACHED
+ Called with { "x" : 1, "y" : 2 }: NOT CACHED
+ Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: CACHED
+ Called with { "x" : 1, "y" : 2 }: CACHED
+ Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: NOT CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: NOT CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: NOT CACHED

=== added file 'test/rbkt/ExpQueryResults/zorba/caching/deep-equal-udf-sd-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/caching/deep-equal-udf-sd-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/caching/deep-equal-udf-sd-01.xml.res	2014-04-17 12:21:32 +0000
@@ -0,0 +1,11 @@
+Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: NOT CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: NOT CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: NOT CACHED
+ Called with { "x" : 1, "y" : 2 }: NOT CACHED
+ Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: CACHED
+ Called with { "x" : 1, "y" : 2 }: CACHED
+ Called with { "x" : "&lt;a/&gt;", "y" : "&lt;b/&gt;" }: NOT CACHED
+ Called with { "x" : { "a" : 1 }, "y" : { "b" : 2 } }: NOT CACHED
+ Called with { "x" : [ 1 ], "y" : [ 2 ] }: NOT CACHED

=== added file 'test/rbkt/ExpQueryResults/zorba/caching/ignore-argument-ext-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/caching/ignore-argument-ext-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/caching/ignore-argument-ext-01.xml.res	2014-04-17 12:21:32 +0000
@@ -0,0 +1,1 @@
+{ "cache" : [ 2, 2, 2, 3, 3, 3 ], "sd" : [ 2, 2, 2, 3, 3, 3 ] }
\ No newline at end of file

=== added file 'test/rbkt/ExpQueryResults/zorba/caching/ignore-argument-udf-01.xml.res'
--- test/rbkt/ExpQueryResults/zorba/caching/ignore-argument-udf-01.xml.res	1970-01-01 00:00:00 +0000
+++ test/rbkt/ExpQueryResults/zorba/caching/ignore-argument-udf-01.xml.res	2014-04-17 12:21:32 +0000
@@ -0,0 +1,1 @@
+{ "cache" : [ 2, 2, 2, 3, 3, 3 ], "sd" : [ 2, 2, 2, 3, 3, 3 ] }
\ No newline at end of file

=== modified file 'test/rbkt/Queries/zorba/caching/annotations-compatibility.xq'
--- test/rbkt/Queries/zorba/caching/annotations-compatibility.xq	2014-04-17 12:21:32 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-compatibility.xq	2014-04-17 12:21:32 +0000
@@ -23,4 +23,8 @@
 {
 };
 
+declare %an:strictlydeterministic %an:exclude-from-cache-key(1) function local:foo-arg($x as xs:integer)
+{
+};
+
 1
\ No newline at end of file

=== added file 'test/rbkt/Queries/zorba/caching/annotations-literals-01.spec'
--- test/rbkt/Queries/zorba/caching/annotations-literals-01.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-literals-01.spec	2014-04-17 12:21:32 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/errors:ZXQP0062

=== added file 'test/rbkt/Queries/zorba/caching/annotations-literals-01.xq'
--- test/rbkt/Queries/zorba/caching/annotations-literals-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-literals-01.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,8 @@
+declare namespace an = "http://zorba.io/annotations";;
+
+declare %an:strictlydeterministic %an:exclude-from-cache-key function local:foo($x as xs:integer)
+{
+  1
+};
+
+local:foo(1)
\ No newline at end of file

=== added file 'test/rbkt/Queries/zorba/caching/annotations-literals-02.spec'
--- test/rbkt/Queries/zorba/caching/annotations-literals-02.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-literals-02.spec	2014-04-17 12:21:32 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/errors:ZXQP0063

=== added file 'test/rbkt/Queries/zorba/caching/annotations-literals-02.xq'
--- test/rbkt/Queries/zorba/caching/annotations-literals-02.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-literals-02.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,8 @@
+declare namespace an = "http://zorba.io/annotations";;
+
+declare %an:strictlydeterministic %an:exclude-from-cache-key(1,"a") function local:foo($x as xs:integer)
+{
+  1
+};
+
+local:foo(1)
\ No newline at end of file

=== added file 'test/rbkt/Queries/zorba/caching/annotations-literals-03.spec'
--- test/rbkt/Queries/zorba/caching/annotations-literals-03.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-literals-03.spec	2014-04-17 12:21:32 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/errors:ZXQP0064

=== added file 'test/rbkt/Queries/zorba/caching/annotations-literals-03.xq'
--- test/rbkt/Queries/zorba/caching/annotations-literals-03.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-literals-03.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,8 @@
+declare namespace an = "http://zorba.io/annotations";;
+
+declare %an:strictlydeterministic %an:exclude-from-cache-key(1, 2) function local:foo($x as xs:integer)
+{
+  1
+};
+
+local:foo(1)
\ No newline at end of file

=== added file 'test/rbkt/Queries/zorba/caching/annotations-literals-04.spec'
--- test/rbkt/Queries/zorba/caching/annotations-literals-04.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-literals-04.spec	2014-04-17 12:21:32 +0000
@@ -0,0 +1,1 @@
+Error: http://zorba.io/errors:ZXQP0065

=== added file 'test/rbkt/Queries/zorba/caching/annotations-literals-04.xq'
--- test/rbkt/Queries/zorba/caching/annotations-literals-04.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-literals-04.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,8 @@
+declare namespace an = "http://zorba.io/annotations";;
+
+declare %an:strictlydeterministic %an:exclude-from-cache-key(1) function local:foo()
+{
+  1
+};
+
+local:foo()
\ No newline at end of file

=== added file 'test/rbkt/Queries/zorba/caching/annotations-requirements-01.spec'
--- test/rbkt/Queries/zorba/caching/annotations-requirements-01.spec	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-requirements-01.spec	2014-04-17 12:21:32 +0000
@@ -0,0 +1,1 @@
+Error: http://www.w3.org/2005/xqt-errors:XQST0106

=== added file 'test/rbkt/Queries/zorba/caching/annotations-requirements-01.xq'
--- test/rbkt/Queries/zorba/caching/annotations-requirements-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/annotations-requirements-01.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,7 @@
+declare namespace an = "http://zorba.io/annotations";;
+
+declare %an:exclude-from-cache-key(1) function local:foo($x as xs:integer)
+{
+};
+
+1
\ No newline at end of file

=== added file 'test/rbkt/Queries/zorba/caching/deep-equal-ext-cache-01.xq'
--- test/rbkt/Queries/zorba/caching/deep-equal-ext-cache-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/deep-equal-ext-cache-01.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,53 @@
+import module namespace debug = "http://zorba.io/modules/util-tests";;
+declare namespace an = "http://zorba.io/annotations";;
+
+declare function local:is-cached($uuids, $old-uuids)
+{
+  if ($uuids = $old-uuids)
+  then "CACHED"
+  else "NOT CACHED"
+};
+
+variable $node := <a/>;
+variable $object := {"a": 1};
+variable $array := [1]; 
+
+let $old :=
+( 
+  debug:test-07-cache($node, <b/>),
+  debug:test-07-cache($object, {"b": 2}),
+  debug:test-07-cache($array, [2]),
+  debug:test-07-cache(1, 2)
+)
+
+let $old-values := (for $i in (1 to 4) return $old[$i * 2 - 1])
+let $old-uuids := (for $i in (1 to 4) return $old[$i * 2]) 
+
+let $equal := 
+(
+  debug:test-07-cache($node, <b/>),
+  debug:test-07-cache($object, {"b": 2}),
+  debug:test-07-cache($array, [2]),
+  debug:test-07-cache(1, 2)
+)
+
+let $expected-old-values := (for $i in (1 to 4) return $equal[$i * 2 -1])
+let $expected-old-uuids := (for $i in (1 to 4) return $equal[$i * 2])
+
+let $re-evaluated := 
+(
+  debug:test-07-cache(<a/>, <b/>),
+  debug:test-07-cache({"a":1}, {"b": 2}),
+  debug:test-07-cache([1], [2])
+)
+let $expected-new-values := (for $i in (1 to 3) return $re-evaluated[$i * 2 - 1])
+let $expected-new-uuids := (for $i in (1 to 3) return $re-evaluated[$i * 2])
+return
+(
+  for $i in (1 to 4)
+  return "Called with " || $old-values[$i] || ": NOT CACHED" || "&#10;",
+  for $j in (1 to 4)
+  return "Called with " || $expected-old-values[$j] || ": " || local:is-cached($expected-old-uuids[$j], $old-uuids) || "&#10;",
+  for $k in (1 to 3)
+  return "Called with " || $expected-new-values[$k] || ": " || local:is-cached($expected-new-uuids[$k], $old-uuids) || "&#10;"
+)

=== added file 'test/rbkt/Queries/zorba/caching/deep-equal-ext-sd-01.xq'
--- test/rbkt/Queries/zorba/caching/deep-equal-ext-sd-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/deep-equal-ext-sd-01.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,53 @@
+import module namespace debug = "http://zorba.io/modules/util-tests";;
+declare namespace an = "http://zorba.io/annotations";;
+
+declare function local:is-cached($uuids, $old-uuids)
+{
+  if ($uuids = $old-uuids)
+  then "CACHED"
+  else "NOT CACHED"
+};
+
+variable $node := <a/>;
+variable $object := {"a": 1};
+variable $array := [1];
+
+let $old :=
+( 
+  debug:test-07-cache($node, <b/>),
+  debug:test-07-cache($object, {"b": 2}),
+  debug:test-07-cache($array, [2]),
+  debug:test-07-cache(1, 2)
+)
+
+let $old-values := (for $i in (1 to 4) return $old[$i * 2 - 1])
+let $old-uuids := (for $i in (1 to 4) return $old[$i * 2]) 
+
+let $equal := 
+(
+  debug:test-07-cache($node, <b/>),
+  debug:test-07-cache($object, {"b": 2}),
+  debug:test-07-cache($array, [2]),
+  debug:test-07-cache(1, 2)
+)
+
+let $expected-old-values := (for $i in (1 to 4) return $equal[$i * 2 -1])
+let $expected-old-uuids := (for $i in (1 to 4) return $equal[$i * 2])
+
+let $re-evaluated := 
+(
+  debug:test-07-cache(<a/>, <b/>),
+  debug:test-07-cache({"a":1}, {"b": 2}),
+  debug:test-07-cache([1], [2])
+)
+let $expected-new-values := (for $i in (1 to 3) return $re-evaluated[$i * 2 - 1])
+let $expected-new-uuids := (for $i in (1 to 3) return $re-evaluated[$i * 2])
+return
+(
+  for $i in (1 to 4)
+  return "Called with " || $old-values[$i] || ": NOT CACHED" || "&#10;",
+  for $j in (1 to 4)
+  return "Called with " || $expected-old-values[$j] || ": " || local:is-cached($expected-old-uuids[$j], $old-uuids) || "&#10;",
+  for $k in (1 to 3)
+  return "Called with " || $expected-new-values[$k] || ": " || local:is-cached($expected-new-uuids[$k], $old-uuids) || "&#10;"
+)

=== added file 'test/rbkt/Queries/zorba/caching/deep-equal-udf-cache-01.xq'
--- test/rbkt/Queries/zorba/caching/deep-equal-udf-cache-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/deep-equal-udf-cache-01.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,59 @@
+import module namespace debug = "http://zorba.io/modules/util-tests";;
+declare namespace an = "http://zorba.io/annotations";;
+
+declare %an:cache %an:compare-with-deep-equal(2) function local:test-07-cache($x as item(), $y as item())
+{
+  serialize({"x" : $x, "y" : $y}),
+  debug:uuid()
+};
+
+declare function local:is-cached($uuids, $old-uuids)
+{
+  if ($uuids = $old-uuids)
+  then "CACHED"
+  else "NOT CACHED"
+};
+
+variable $node := <a/>;
+variable $object := {"a": 1};
+variable $array := [1]; 
+
+let $old :=
+( 
+  local:test-07-cache($node, <b/>),
+  local:test-07-cache($object, {"b": 2}),
+  local:test-07-cache($array, [2]),
+  local:test-07-cache(1, 2)
+)
+
+let $old-values := (for $i in (1 to 4) return $old[$i * 2 - 1])
+let $old-uuids := (for $i in (1 to 4) return $old[$i * 2]) 
+
+let $equal := 
+(
+  local:test-07-cache($node, <b/>),
+  local:test-07-cache($object, {"b": 2}),
+  local:test-07-cache($array, [2]),
+  local:test-07-cache(1, 2)
+)
+
+let $expected-old-values := (for $i in (1 to 4) return $equal[$i * 2 -1])
+let $expected-old-uuids := (for $i in (1 to 4) return $equal[$i * 2])
+
+let $re-evaluated := 
+(
+  local:test-07-cache(<a/>, <b/>),
+  local:test-07-cache({"a":1}, {"b": 2}),
+  local:test-07-cache([1], [2])
+)
+let $expected-new-values := (for $i in (1 to 3) return $re-evaluated[$i * 2 - 1])
+let $expected-new-uuids := (for $i in (1 to 3) return $re-evaluated[$i * 2])
+return
+(
+  for $i in (1 to 4)
+  return "Called with " || $old-values[$i] || ": NOT CACHED" || "&#10;",
+  for $j in (1 to 4)
+  return "Called with " || $expected-old-values[$j] || ": " || local:is-cached($expected-old-uuids[$j], $old-uuids) || "&#10;",
+  for $k in (1 to 3)
+  return "Called with " || $expected-new-values[$k] || ": " || local:is-cached($expected-new-uuids[$k], $old-uuids) || "&#10;"
+)

=== added file 'test/rbkt/Queries/zorba/caching/deep-equal-udf-sd-01.xq'
--- test/rbkt/Queries/zorba/caching/deep-equal-udf-sd-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/deep-equal-udf-sd-01.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,59 @@
+import module namespace debug = "http://zorba.io/modules/util-tests";;
+declare namespace an = "http://zorba.io/annotations";;
+
+declare %an:strictlydeterministic %an:compare-with-deep-equal(2) function local:test-07-cache($x as item(), $y as item())
+{
+  serialize({"x" : $x, "y" : $y}),
+  debug:uuid()
+};
+
+declare function local:is-cached($uuids, $old-uuids)
+{
+  if ($uuids = $old-uuids)
+  then "CACHED"
+  else "NOT CACHED"
+};
+
+variable $node := <a/>;
+variable $object := {"a": 1};
+variable $array := [1];
+
+let $old :=
+( 
+  local:test-07-cache($node, <b/>),
+  local:test-07-cache($object, {"b": 2}),
+  local:test-07-cache($array, [2]),
+  local:test-07-cache(1, 2)
+)
+
+let $old-values := (for $i in (1 to 4) return $old[$i * 2 - 1])
+let $old-uuids := (for $i in (1 to 4) return $old[$i * 2]) 
+
+let $equal := 
+(
+  local:test-07-cache($node, <b/>),
+  local:test-07-cache($object, {"b": 2}),
+  local:test-07-cache($array, [2]),
+  local:test-07-cache(1, 2)
+)
+
+let $expected-old-values := (for $i in (1 to 4) return $equal[$i * 2 -1])
+let $expected-old-uuids := (for $i in (1 to 4) return $equal[$i * 2])
+
+let $re-evaluated := 
+(
+  local:test-07-cache(<a/>, <b/>),
+  local:test-07-cache({"a":1}, {"b": 2}),
+  local:test-07-cache([1], [2])
+)
+let $expected-new-values := (for $i in (1 to 3) return $re-evaluated[$i * 2 - 1])
+let $expected-new-uuids := (for $i in (1 to 3) return $re-evaluated[$i * 2])
+return
+(
+  for $i in (1 to 4)
+  return "Called with " || $old-values[$i] || ": NOT CACHED" || "&#10;",
+  for $j in (1 to 4)
+  return "Called with " || $expected-old-values[$j] || ": " || local:is-cached($expected-old-uuids[$j], $old-uuids) || "&#10;",
+  for $k in (1 to 3)
+  return "Called with " || $expected-new-values[$k] || ": " || local:is-cached($expected-new-uuids[$k], $old-uuids) || "&#10;"
+)

=== added file 'test/rbkt/Queries/zorba/caching/ignore-argument-ext-01.xq'
--- test/rbkt/Queries/zorba/caching/ignore-argument-ext-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/ignore-argument-ext-01.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,22 @@
+import module namespace debug = "http://zorba.io/modules/util-tests";;
+
+{
+  "cache":
+  [
+    debug:test-06-cache(1,1),
+    debug:test-06-cache(1,2),
+    debug:test-06-cache(1,3),
+    debug:test-06-cache(2,1),
+    debug:test-06-cache(2,2),
+    debug:test-06-cache(2,3)
+  ],
+  "sd":
+  [
+    debug:test-06-cache(1,1),
+    debug:test-06-cache(1,2),
+    debug:test-06-cache(1,3),
+    debug:test-06-cache(2,1),
+    debug:test-06-cache(2,2),
+    debug:test-06-cache(2,3)
+  ]
+}
\ No newline at end of file

=== added file 'test/rbkt/Queries/zorba/caching/ignore-argument-udf-01.xq'
--- test/rbkt/Queries/zorba/caching/ignore-argument-udf-01.xq	1970-01-01 00:00:00 +0000
+++ test/rbkt/Queries/zorba/caching/ignore-argument-udf-01.xq	2014-04-17 12:21:32 +0000
@@ -0,0 +1,32 @@
+declare namespace an = "http://zorba.io/annotations";;
+
+declare %an:cache %an:exclude-from-cache-key(2) function local:test-06-cache($x as xs:integer, $y as xs:integer) as xs:integer
+{
+  $x + $y
+};
+
+declare %an:strictlydeterministic %an:exclude-from-cache-key(2) function local:test-06-sd($x as xs:integer, $y as xs:integer) as xs:integer
+{
+  $x + $y
+};
+
+{
+  "cache":
+  [
+    local:test-06-cache(1,1),
+    local:test-06-cache(1,2),
+    local:test-06-cache(1,3),
+    local:test-06-cache(2,1),
+    local:test-06-cache(2,2),
+    local:test-06-cache(2,3)
+  ],
+  "sd":
+  [
+    local:test-06-cache(1,1),
+    local:test-06-cache(1,2),
+    local:test-06-cache(1,3),
+    local:test-06-cache(2,1),
+    local:test-06-cache(2,2),
+    local:test-06-cache(2,3)
+  ]
+}
\ No newline at end of file


References