zorba-coders team mailing list archive
-
zorba-coders team
-
Mailing list archive
-
Message #26940
[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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" : "<a/>", "y" : "<b/>" }: 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" || " ",
+ for $j in (1 to 4)
+ return "Called with " || $expected-old-values[$j] || ": " || local:is-cached($expected-old-uuids[$j], $old-uuids) || " ",
+ for $k in (1 to 3)
+ return "Called with " || $expected-new-values[$k] || ": " || local:is-cached($expected-new-uuids[$k], $old-uuids) || " "
+)
=== 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" || " ",
+ for $j in (1 to 4)
+ return "Called with " || $expected-old-values[$j] || ": " || local:is-cached($expected-old-uuids[$j], $old-uuids) || " ",
+ for $k in (1 to 3)
+ return "Called with " || $expected-new-values[$k] || ": " || local:is-cached($expected-new-uuids[$k], $old-uuids) || " "
+)
=== 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" || " ",
+ for $j in (1 to 4)
+ return "Called with " || $expected-old-values[$j] || ": " || local:is-cached($expected-old-uuids[$j], $old-uuids) || " ",
+ for $k in (1 to 3)
+ return "Called with " || $expected-new-values[$k] || ": " || local:is-cached($expected-new-uuids[$k], $old-uuids) || " "
+)
=== 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" || " ",
+ for $j in (1 to 4)
+ return "Called with " || $expected-old-values[$j] || ": " || local:is-cached($expected-old-uuids[$j], $old-uuids) || " ",
+ for $k in (1 to 3)
+ return "Called with " || $expected-new-values[$k] || ": " || local:is-cached($expected-new-uuids[$k], $old-uuids) || " "
+)
=== 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