Patches for Berkeley DB XML version 2.3.10
-
Certain runtime errors during query execution when using modules cause a double free.
diff -ru dbxml-2.3.10-original/xqilla/include/xqilla/context/ContextHelpers.hpp dbxml-2.3.10/xqilla/include/xqilla/context/ContextHelpers.hpp
--- dbxml-2.3.10-original/xqilla/include/xqilla/context/ContextHelpers.hpp 2006-11-01 16:37:11.000000000 +0000
+++ dbxml-2.3.10/xqilla/include/xqilla/context/ContextHelpers.hpp 2007-03-05 14:53:58.000000000 +0000
@@ -88,4 +88,24 @@
DynamicContext* context_;
};
+class XQILLA_API AutoDocumentCacheReset
+{
+public:
+ AutoDocumentCacheReset(DynamicContext* context)
+ : oldDC(const_cast(context->getDocumentCache())),
+ context_ (context)
+ {
+ }
+
+ ~AutoDocumentCacheReset()
+ {
+ context_->setDocumentCache(oldDC);
+ }
+
+ DocumentCache *oldDC;
+
+protected:
+ DynamicContext* context_;
+};
+
#endif
diff -ru dbxml-2.3.10-original/xqilla/src/functions/XQUserFunction.cpp dbxml-2.3.10/xqilla/src/functions/XQUserFunction.cpp
--- dbxml-2.3.10-original/xqilla/src/functions/XQUserFunction.cpp 2007-01-23 16:16:42.000000000 +0000
+++ dbxml-2.3.10/xqilla/src/functions/XQUserFunction.cpp 2007-03-05 14:58:18.000000000 +0000
@@ -29,6 +29,7 @@
#include
#include
#include
+#include
#include
#include
@@ -400,11 +401,11 @@
VariableStore* varStore=context->getVariableStore();
Scope *oldScope = varStore->getScopeState();
+ AutoDocumentCacheReset reset(context);
+
DocumentCache* docCache=_di->getFunctionDefinition()->getModuleDocumentCache();
- DocumentCache* origDocCache=NULL;
if(docCache!=NULL)
{
- origDocCache=const_cast(context->getDocumentCache());
context->setDocumentCache(docCache);
}
if(_toDo) {
@@ -462,9 +463,9 @@
}
// if we had to switch document cache, check that the returned types are known also in the original context; if not, upgrade them to the base type
- if(origDocCache!=NULL)
+ if(docCache!=NULL)
{
- if(item!=NULLRCP && !origDocCache->isTypeDefined(item->getTypeURI(), item->getTypeName()))
+ if(item!=NULLRCP && !reset.oldDC->isTypeDefined(item->getTypeURI(), item->getTypeName()))
{
if(item->isNode())
{
@@ -475,7 +476,7 @@
{
AnyAtomicType::Ptr atom=item;
const XMLCh* uri=atom->getTypeURI(), *name=atom->getTypeName();
- while(!origDocCache->isTypeDefined(uri, name))
+ while(!reset.oldDC->isTypeDefined(uri, name))
{
XERCES_CPP_NAMESPACE_QUALIFIER DatatypeValidator* pDV=docCache->getDatatypeValidator(uri, name);
assert(pDV!=NULL);
@@ -488,7 +489,6 @@
item=context->getItemFactory()->createDerivedFromAtomicType(uri, name, atom->asString(context), context);
}
}
- context->setDocumentCache(origDocCache);
}
return item;
}
-
Fixed a bug which incorrectly reported an error for fractional seconds when the seconds filed was "59".
diff -ru dbxml-2.3.10-original/xqilla/src/items/impl/ATDateTimeOrDerivedImpl.cpp dbxml-2.3.10/xqilla/src/items/impl/ATDateTimeOrDerivedImpl.cpp
--- dbxml-2.3.10-original/xqilla/src/items/impl/ATDateTimeOrDerivedImpl.cpp 2006-11-01 16:37:20.000000000 +0000
+++ dbxml-2.3.10/xqilla/src/items/impl/ATDateTimeOrDerivedImpl.cpp 2007-03-12 11:41:21.000000000 +0000
@@ -727,7 +727,7 @@
}
// check time format
- if(MM > 12 || YY == 0 || DD > DateUtils::maximumDayInMonthFor(YY, MM) || hh > 24 || mm > 59 || ss > 59 || zonehh > 24 || zonemm > 59 )
+ if(MM > 12 || YY == 0 || DD > DateUtils::maximumDayInMonthFor(YY, MM) || hh > 24 || mm > 59 || ss >= 60 || zonehh > 24 || zonemm > 59 )
{
wrongformat = true;
}
diff -ru dbxml-2.3.10-original/xqilla/src/items/impl/ATTimeOrDerivedImpl.cpp dbxml-2.3.10/xqilla/src/items/impl/ATTimeOrDerivedImpl.cpp
--- dbxml-2.3.10-original/xqilla/src/items/impl/ATTimeOrDerivedImpl.cpp 2006-11-01 16:37:21.000000000 +0000
+++ dbxml-2.3.10/xqilla/src/items/impl/ATTimeOrDerivedImpl.cpp 2007-03-12 11:41:32.000000000 +0000
@@ -474,7 +474,7 @@
}
}
- if ( hh > 24 || mm > 59 || ss > 59 || zonehh > 24 || zonemm > 59 )
+ if ( hh > 24 || mm > 59 || ss >= 60 || zonehh > 24 || zonemm > 59 )
wrongformat = true;
if(hh==24 && mm==0 && ss==0)
hh=0;
-
Fix a problem with XmlIndexLookup where a GT lookup that happens to start with the last entry in the index might return results when it should return none.
--- dbxml-2.3.10/dbxml/src/dbxml/Cursor.cpp 2006-10-30 12:45:52.000000000 -0500
+++ dbxml-2.3.10.patch/dbxml/src/dbxml/Cursor.cpp 2007-03-19 13:58:27.000000000 -0400
@@ -21,6 +21,16 @@
#define MINIMUM_BULK_GET_BUFFER 256 * 1024
+// determine if two keys refer to the same index, based
+// on initial structure bytes.
+static bool isSameIndex(const Dbt &k1, const Dbt &k2)
+{
+ const xmlbyte_t *p1 = (const xmlbyte_t*)k1.get_data();
+ const xmlbyte_t *p2 = (const xmlbyte_t*)k2.get_data();
+ return (Key::compareStructure(p1, p1 + k1.get_size(),
+ p2, p2 + k2.get_size()) == 0);
+}
+
// Cursor
Cursor::Cursor(DbWrapper &db, Transaction *txn,
CursorType type, u_int32_t flags)
@@ -252,10 +262,16 @@
// no throw for NOTFOUND and KEYEMPTY
err = cursor_.get(&key_, &data_, DB_SET);
if(err == 0) {
+ // save key structure for comparison below
+ DbtOut tmp(key_.get_data(), key_.get_size());
// Do the DB_NEXT_NODUP without the DB_MULTIPLE_KEY,
// otherwise the multiple get will get all of it's keys
// with the NODUP flag...
err = cursor_.get(&key_, &data_, DB_NEXT_NODUP);
+ if ((err == 0) && !isSameIndex(key_, tmp)) {
+ done_ = true;
+ return 0;
+ }
flags = DB_CURRENT;
} else if(err == DB_NOTFOUND) {
err = 0;
@@ -322,9 +338,7 @@
case DbWrapper::GTX:
case DbWrapper::GTE: {
// Check the Prefix and VIDs are the same.
- const xmlbyte_t *p1 = (const xmlbyte_t*)key_.get_data();
- const xmlbyte_t *p2 = (const xmlbyte_t*)tmpKey_.get_data();
- if(Key::compareStructure(p1, p1 + key_.get_size(), p2, p2 + tmpKey_.get_size()) != 0) {
+ if (!isSameIndex(key_, tmpKey_)) {
done_ = true;
ie.reset();
return 0;
@@ -621,9 +635,7 @@
case DbWrapper::LTX:
case DbWrapper::LTE: {
// Check the Prefix and VIDs are the same.
- const xmlbyte_t *p1 = (const xmlbyte_t*)key_.get_data();
- const xmlbyte_t *p2 = (const xmlbyte_t*)tmpKey_.get_data();
- if(Key::compareStructure(p1, p1 + key_.get_size(), p2, p2 + tmpKey_.get_size()) != 0) {
+ if (!isSameIndex(key_, tmpKey_)) {
done_ = true;
ie.reset();
return 0;
-
Improved query performance for queries consisting of a simple path and predicate.
diff -ru dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/CostBasedOptimizer.cpp dbxml-2.3.10/dbxml/src/dbxml/optimizer/CostBasedOptimizer.cpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/CostBasedOptimizer.cpp 2007-02-02 20:11:55.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/optimizer/CostBasedOptimizer.cpp 2007-03-21 20:30:20.000000000 +0000
@@ -352,7 +352,7 @@
}
DbXmlNav::Steps::reverse_iterator CostBasedOptimizer::findBestIndex(DbXmlNav::Steps::reverse_iterator start,
- DbXmlNav::Steps::reverse_iterator end)
+ DbXmlNav::Steps::reverse_iterator end, bool findJoin)
{
DbXmlNav::Steps::reverse_iterator found_it = end;
QueryPlan::Cost found_cost;
@@ -374,7 +374,7 @@
}
}
}
- } else if((*i)->getType() == (ASTNode::whichType)DbXmlASTNode::JOIN) {
+ } else if(findJoin && (*i)->getType() == (ASTNode::whichType)DbXmlASTNode::JOIN) {
LookupIndex *index = findLookupIndex(*i);
if(index != 0 && index->isSuitableForLookupIndex()) {
@@ -448,7 +448,7 @@
}
DbXmlNav::Steps &args = const_cast(nav->getSteps());
- DbXmlNav::Steps::reverse_iterator found_it = findBestIndex(args.rbegin(), args.rend());
+ DbXmlNav::Steps::reverse_iterator found_it = findBestIndex(args.rbegin(), args.rend(), /*findJoin*/false);
if(found_it != args.rend()) {
// Create a navigation for the forward steps,
@@ -568,7 +568,7 @@
args.push_back(const_cast(item->getArgument()));
}
- DbXmlNav::Steps::reverse_iterator found_it = findBestIndex(args.rbegin(), args.rend());
+ DbXmlNav::Steps::reverse_iterator found_it = findBestIndex(args.rbegin(), args.rend(), /*findJoin*/true);
if(found_it == args.rend()) {
found_it = findLastJoin(args.rbegin(), args.rend());
diff -ru dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/CostBasedOptimizer.hpp dbxml-2.3.10/dbxml/src/dbxml/optimizer/CostBasedOptimizer.hpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/CostBasedOptimizer.hpp 2006-10-30 17:45:59.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/optimizer/CostBasedOptimizer.hpp 2007-03-21 20:29:19.000000000 +0000
@@ -34,7 +34,7 @@
private:
void compressSteps(DbXmlNav *nav);
DbXmlNav::Steps::reverse_iterator findBestIndex(DbXmlNav::Steps::reverse_iterator start,
- DbXmlNav::Steps::reverse_iterator end);
+ DbXmlNav::Steps::reverse_iterator end, bool findJoin);
bool isASTNodeReversible(ASTNode *ast);
bool reverseASTNode(ASTNode *ast, Join::Type &axis, LookupIndex *index, DbXmlNav *&reverse);
-
Improved index utilisation for user defined functions that are called more than once in the query.
diff -ru dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/QueryPlanGenerator.cpp dbxml-2.3.10/dbxml/src/dbxml/optimizer/QueryPlanGenerator.cpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/QueryPlanGenerator.cpp 2007-01-17 20:13:07.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/optimizer/QueryPlanGenerator.cpp 2007-03-22 11:13:19.000000000 +0000
@@ -749,8 +749,8 @@
root = new (mm) ImpliedSchemaNode(ImpliedSchemaNode::ROOT, mm);
item->setImpliedSchema(root);
- storeInScopeVars(root);
}
+ storeInScopeVars(root);
result.join(root);
result.operation = new (&memMgr_) PathsQP(result.returnPaths, &memMgr_);
@@ -1073,7 +1073,7 @@
void QueryPlanGenerator::storeInScopeVars(ImpliedSchemaNode *root) {
// List the in scope vars
- VariableIDs vars;
+ VariableIDs &vars = inScopeVars_[root];
VarStore::MyScope* index = const_cast(varStore_.getCurrentScope());
while(index) {
std::vector< std::pair > tmp = index->getVars();
@@ -1086,8 +1086,6 @@
index = const_cast(varStore_.getGlobalScope());
else index = index->getNext();
}
-
- inScopeVars_[root] = vars;
}
class ArgHolder {
-
Certain predicates containing "or" and an unoptimizable sub-expression do not optimize correctly.
--- dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/QueryPlanGenerator.cpp 2007-04-18 10:05:24.000000000 +0100
+++ dbxml-2.3.10/dbxml/src/dbxml/optimizer/QueryPlanGenerator.cpp 2007-08-08 11:32:10.000000000 +0100
@@ -1566,11 +1572,12 @@
else if(name == Or::name) {
UnionQP *unionOp = new (&memMgr_) UnionQP(&memMgr_);
+ result.operation = unionOp;
for(VectorOfASTNodes::iterator i = args.begin(); i != args.end(); ++i) {
PathResult ret = generate(*i, ids);
unionOp->addArg(ret.operation);
+ if(ret.operation == 0) result.operation = 0;
}
- result.operation = unionOp;
}
// These operators use the presence of the node arguments, not their value
-
Fixes several problems with XmlModify, including a SEGV that can occur when removing a last child element that has leading text. [#15615]
diff -c dbxml-2.3.10-original/dbxml/src/dbxml/nodeStore/NsDom.cpp dbxml-2.3.10/dbxml/src/dbxml/nodeStore/NsDom.cpp
*** dbxml-2.3.10-original/dbxml/src/dbxml/nodeStore/NsDom.cpp Tue Jan 9 15:29:19 2007
--- dbxml-2.3.10/dbxml/src/dbxml/nodeStore/NsDom.cpp Mon Oct 22 13:44:51 2007
***************
*** 529,545 ****
if (prev)
prev->nsMakeTransient();
- // Move text, if present. Just copy; explicit
- // remove isn't required, as the node's going away
- NsNode *node = child->getNsNode();
- if (node->hasLeadingText()) {
- if (next) {
- _coalesceTextNodes(child, next, false);
- } else {
- _coalesceTextNodes(child, this, true);
- }
- }
-
if (next) {
next->setElemPrev(prev);
if (prev)
--- 529,534 ----
***************
*** 580,585 ****
--- 569,585 ----
getNsDocument()->addToModifications(
NodeModification::UPDATE, this);
+ // Move text, if present. Just copy; explicit
+ // remove isn't required, as the node's going away
+ NsNode *node = child->getNsNode();
+ if (node->hasLeadingText()) {
+ if (next) {
+ _coalesceTextNodes(child, next, false);
+ } else {
+ _coalesceTextNodes(child, this, true);
+ }
+ }
+
// Remove the child from the tree
child->_makeStandalone();
child->_parent = 0;
***************
*** 638,644 ****
int32_t index = -1; // -1 means append as last on list
bool isChild = false;
NsDomNav *prev = 0;
!
// if no next, operation is appending child text
if (!nextChild) {
modified = this;
--- 638,644 ----
int32_t index = -1; // -1 means append as last on list
bool isChild = false;
NsDomNav *prev = 0;
! NsDomNav *ttext = 0;
// if no next, operation is appending child text
if (!nextChild) {
modified = this;
***************
*** 662,667 ****
--- 662,678 ----
nsNodeElement);
modified = (NsDomElement*)nextChild;
index = modified->getNsNode()->getNumLeadingText();
+ NsNode *tnode = modified->getNsNode();
+ if (tnode->hasTextChild()) {
+ // existing text on target will move "right."
+ // get first text child for renumbering, later
+ NsDomNav *last = modified->getNsLastChild(true);
+ while (last && last->getNsNodeType() ==
+ nsNodeText) {
+ ttext = (NsDomText*)last;
+ last = last->getNsPrevSibling();
+ }
+ }
}
}
***************
*** 702,707 ****
--- 713,730 ----
((NsDomText*)next)->setIndex(newindex + 1);
next = next->getNsNextSibling();
}
+
+ // If modified == nextChild, we added leading text to
+ // an element; if it had child text, child text indexes
+ // must be renumbered
+ if (ttext) { // ttext set above
+ while (ttext &&
+ (ttext->getNsNodeType() == nsNodeText)) {
+ int32_t newindex = ((NsDomText*)ttext)->getIndex();
+ ((NsDomText*)ttext)->setIndex(newindex + 1);
+ ttext = ttext->getNsNextSibling();
+ }
+ }
getNsDocument()->addToModifications(NodeModification::UPDATE, modified);
return child;
***************
*** 976,982 ****
{
NsNode *tnode = target->getNsNode();
MemoryManager *mmgr = getMemoryManager();
!
// Cannot count on sibling links to the source.
// They have been eliminated in the caller.
// Instead use a counter. Previous sibling link
--- 999,1014 ----
{
NsNode *tnode = target->getNsNode();
MemoryManager *mmgr = getMemoryManager();
! NsDomNav *ttext = 0;
! if (tnode->hasTextChild()) {
! // existing child text on target will move "right."
! // get first text child for renumbering, later
! NsDomNav *last = target->getNsLastChild(true);
! while (last && last->getNsNodeType() == nsNodeText) {
! ttext = (NsDomText*)last;
! last = last->getNsPrevSibling();
! }
! }
// Cannot count on sibling links to the source.
// They have been eliminated in the caller.
// Instead use a counter. Previous sibling link
***************
*** 994,1001 ****
int32_t index = 0;
if (toChild) {
index = tnode->getFirstTextChildIndex();
! DBXML_ASSERT(index >= 0);
}
for (int i = 0; i < num; i++) {
DBXML_ASSERT(first->getNsNodeType() == nsNodeText);
if (nsTextType(first->getNsTextType()) == NS_PINST) {
--- 1026,1034 ----
int32_t index = 0;
if (toChild) {
index = tnode->getFirstTextChildIndex();
! if (index == -1) index = 0;
}
+
for (int i = 0; i < num; i++) {
DBXML_ASSERT(first->getNsNodeType() == nsNodeText);
if (nsTextType(first->getNsTextType()) == NS_PINST) {
***************
*** 1016,1028 ****
}
// caller has already rearranged sibling links correctly
// need to renumber indexes on any remaining text siblings
- // "first" is pointing to it, or it's pointing to the source node
tmp = first;
while (tmp && (tmp->getNsNodeType() == nsNodeText)) {
int32_t newindex = ((NsDomText*)tmp)->getIndex();
((NsDomText*)tmp)->setIndex(newindex + num);
tmp = tmp->getNsNextSibling();
}
}
//
--- 1049,1067 ----
}
// caller has already rearranged sibling links correctly
// need to renumber indexes on any remaining text siblings
tmp = first;
while (tmp && (tmp->getNsNodeType() == nsNodeText)) {
int32_t newindex = ((NsDomText*)tmp)->getIndex();
((NsDomText*)tmp)->setIndex(newindex + num);
tmp = tmp->getNsNextSibling();
}
+
+ // renumber child text nodes on target
+ while (ttext && (ttext->getNsNodeType() == nsNodeText)) {
+ int32_t newindex = ((NsDomText*)ttext)->getIndex();
+ ((NsDomText*)ttext)->setIndex(newindex + num);
+ ttext = ttext->getNsNextSibling();
+ }
}
//
***************
*** 1527,1534 ****
previous = newtext;
if (returnLast)
retval = newtext; // return last
! else if (i == startIndex)
retval = newtext;
}
return retval;
}
--- 1566,1580 ----
previous = newtext;
if (returnLast)
retval = newtext; // return last
! else if (i == startIndex) {
retval = newtext;
+ // first text child is first child only if
+ // no child elements
+ if (!_node->hasChildElem())
+ _firstChild = newtext;
+ }
+ // child text is *always* last child
+ _lastChild = newtext;
}
return retval;
}
diff -c dbxml-2.3.10-original/dbxml/src/dbxml/nodeStore/NsNode.cpp dbxml-2.3.10/dbxml/src/dbxml/nodeStore/NsNode.cpp
*** dbxml-2.3.10-original/dbxml/src/dbxml/nodeStore/NsNode.cpp Tue Jan 30 10:19:07 2007
--- dbxml-2.3.10/dbxml/src/dbxml/nodeStore/NsNode.cpp Mon Oct 22 12:18:49 2007
***************
*** 934,941 ****
NsNode::clearPrev(XER_NS MemoryManager *mmgr)
{
nd_header.nh_flags &= ~NS_HASPREV;
! if (!noNav()) {
! DBXML_ASSERT(nd_nav);
nd_nav->nn_prev.freeNid(mmgr);
memset(&nd_nav->nn_prev, 0, sizeof(NsNid));
}
--- 934,941 ----
NsNode::clearPrev(XER_NS MemoryManager *mmgr)
{
nd_header.nh_flags &= ~NS_HASPREV;
! if (!noNav() && nd_nav) {
! //DBXML_ASSERT(nd_nav);
nd_nav->nn_prev.freeNid(mmgr);
memset(&nd_nav->nn_prev, 0, sizeof(NsNid));
}
-
Bug in statistics calculation for substring indexes, that could result in a crash. [#15823]
diff -u dbxml-2.3.10-original/dbxml/src/dbxml/Statistics.cpp dbxml-2.3.10/dbxml/src/dbxml/Statistics.cpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/Statistics.cpp 2006-10-30 17:45:53.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/Statistics.cpp 2007-10-26 12:16:19.000000000 +0100
@@ -220,7 +220,6 @@
context.key().set_size(structureLength); // trim the value off
}
- StatsMapKey tmpKey(key.container);
KeyStatistics tmpStats;
KeyStatistics result;
@@ -242,9 +241,6 @@
else {
++found;
- // Cache the intermediate value (it might be useful)
- tmpKey.key.unmarshalStructure(context.key());
- tmpKey.key.getIndex().set(key.key.getSyntaxType(), Index::SYNTAX_MASK);
tmpStats.setThisFromDbt(context.data());
// Fix the unique keys value, if necessary
@@ -253,9 +249,6 @@
tmpStats.numUniqueKeys_ = 1;
}
- // Store the intermediate value
- putKeyStatistics(tmpKey, tmpStats);
-
// add the value it to the results
result.add(tmpStats);
-
Fixes a bad exception that might occur when inserting schema-invalid XML. [#15824]
*** dbxml-2.3.10-original/dbxml/src/dbxml/nodeStore/NsSAX2Reader.cpp Mon Oct 30 12:45:57 2006
--- dbxml-2.3.10/dbxml/src/dbxml/nodeStore/NsSAX2Reader.cpp Fri Oct 26 10:51:11 2007
***************
*** 1008,1016 ****
const XMLSSize_t colNum)
{
int len = NsUtil::nsStringLen(errorText);
! xmlbyte_t buf[500];
! xmlbyte_t *bufp = buf;
! len = NsUtil::nsToUTF8((MemoryManager*)0, &bufp,
errorText, len+1, 500);
std::ostringstream s;
--- 1008,1015 ----
const XMLSSize_t colNum)
{
int len = NsUtil::nsStringLen(errorText);
! xmlbyte_t *bufp = (xmlbyte_t *) fMemoryManager->allocate(500);
! len = NsUtil::nsToUTF8(fMemoryManager, &bufp,
errorText, len+1, 500);
std::ostringstream s;
***************
*** 1022,1028 ****
s << " Parse error in document ";
s << "at line, " << lineNum;
s << ", char " << colNum;
! s << ". Parser message: " << buf;
// log warnings as info, and errors as warning.
// Neither is fatal to the program, and may be
// what is expected.
--- 1021,1027 ----
s << " Parse error in document ";
s << "at line, " << lineNum;
s << ", char " << colNum;
! s << ". Parser message: " << bufp;
// log warnings as info, and errors as warning.
// Neither is fatal to the program, and may be
// what is expected.
Adds an index optimized case and diacritic insensitive version of the
fn:contains() function - dbxml:contains().
diff -ur dbxml-2.3.10-original/dbxml/src/dbxml/dataItem/DbXmlContains.cpp dbxml-2.3.10/dbxml/src/dbxml/dataItem/DbXmlContains.cpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/dataItem/DbXmlContains.cpp 2006-10-30 17:45:54.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/dataItem/DbXmlContains.cpp 2007-08-07 16:49:44.000000000 +0100
@@ -24,10 +24,11 @@
using namespace DbXml;
using namespace std;
-DbXmlContains::DbXmlContains(ASTNode *arg, XPath2MemoryManager* memMgr)
+DbXmlContains::DbXmlContains(ASTNode *arg, bool caseDiacriticInsensitive, XPath2MemoryManager* memMgr)
: DbXmlASTNode(DBXML_CONTAINS, memMgr),
joinType_(Join::SELF),
nodeTest_(0),
+ cdInsens_(caseDiacriticInsensitive),
arg_(arg)
{
staticTyping(0);
@@ -37,6 +38,7 @@
: DbXmlASTNode(DBXML_CONTAINS, memMgr),
joinType_(join),
nodeTest_(cnt->nodeTest_),
+ cdInsens_(cnt->cdInsens_),
arg_(cnt->arg_)
{
setQueryPlanHolder(cnt);
@@ -48,6 +50,7 @@
: DbXmlASTNode(DBXML_CONTAINS, memMgr),
joinType_(join),
nodeTest_(nodeTest),
+ cdInsens_(cnt->cdInsens_),
arg_(cnt->arg_)
{
setQueryPlanHolder(cnt);
@@ -193,7 +196,14 @@
if(container == 0 || *container == 0)
continue;
- if(XMLString::patternMatch(container, pattern) > -1)
+ if(contains_->isCaseAndDiacriticInsensitive()) {
+ XMLBuffer buf1, buf2;
+ Normalizer::caseFoldAndRemoveDiacritics(container, buf1);
+ Normalizer::caseFoldAndRemoveDiacritics(pattern, buf2);
+
+ if(XMLString::patternMatch(buf1.getRawBuffer(), buf2.getRawBuffer()) > -1)
+ return item;
+ } else if(XMLString::patternMatch(container, pattern) > -1)
return item;
}
@@ -221,3 +231,53 @@
{
_src.copy(comp->getStaticResolutionContext());
}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+const XMLCh DbXmlFunContainsCD::name[] = {
+ chLatin_c, chLatin_o, chLatin_n,
+ chLatin_t, chLatin_a, chLatin_i,
+ chLatin_n, chLatin_s, chNull
+};
+const unsigned int DbXmlFunContainsCD::minArgs = 2;
+const unsigned int DbXmlFunContainsCD::maxArgs = 2;
+
+DbXmlFunContainsCD::DbXmlFunContainsCD(const VectorOfASTNodes &args, XPath2MemoryManager *memMgr)
+ : DbXmlFunction(name, minArgs, maxArgs, "string?, string?", args, memMgr)
+{
+}
+
+ASTNode *DbXmlFunContainsCD::staticResolution(StaticContext *context)
+{
+ return resolveArguments(context);
+}
+
+ASTNode *DbXmlFunContainsCD::staticTyping(StaticContext *context)
+{
+ _src.clear();
+
+ _src.getStaticType().flags = StaticType::BOOLEAN_TYPE;
+ return calculateSRCForArguments(context);
+}
+
+Sequence DbXmlFunContainsCD::collapseTreeInternal(DynamicContext *context, int flags) const
+{
+ Item::Ptr item1 = getParamNumber(1,context)->next(context);
+ Item::Ptr item2 = getParamNumber(2,context)->next(context);
+
+ const XMLCh *str1 = item1.isNull() ? XMLUni::fgZeroLenString : item1->asString(context);
+ const XMLCh *str2 = item2.isNull() ? XMLUni::fgZeroLenString : item2->asString(context);
+
+ bool result;
+ if(str2 == 0 || *str2 == 0) result = true;
+ else if(str1 == 0 || *str1 == 0) result = false;
+ else {
+ XMLBuffer buf1, buf2;
+ Normalizer::caseFoldAndRemoveDiacritics(str1, buf1);
+ Normalizer::caseFoldAndRemoveDiacritics(str2, buf2);
+
+ result = XMLString::patternMatch(buf1.getRawBuffer(), buf2.getRawBuffer()) > -1;
+ }
+
+ return Sequence(context->getItemFactory()->createBoolean(result, context), context->getMemoryManager());
+}
diff -ur dbxml-2.3.10-original/dbxml/src/dbxml/dataItem/DbXmlContains.hpp dbxml-2.3.10/dbxml/src/dbxml/dataItem/DbXmlContains.hpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/dataItem/DbXmlContains.hpp 2006-11-21 18:49:43.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/dataItem/DbXmlContains.hpp 2007-08-07 16:49:00.000000000 +0100
@@ -13,6 +13,7 @@
#include "QueryPlanResultImpl.hpp"
#include "DbXmlASTNode.hpp"
#include "Join.hpp"
+#include "DbXmlFunction.hpp"
#include
#include
@@ -35,7 +36,7 @@
const DbXmlContains *contains_;
};
- DbXmlContains(ASTNode *arg, XPath2MemoryManager* memMgr);
+ DbXmlContains(ASTNode *arg, bool caseDiacriticInsensitive, XPath2MemoryManager* memMgr);
DbXmlContains(Join::Type join, const DbXmlContains *cnt, XPath2MemoryManager* memMgr);
DbXmlContains(Join::Type join, DbXmlNodeTest *nodeTest, const DbXmlContains *cnt,
XPath2MemoryManager* memMgr);
@@ -47,6 +48,8 @@
Join::Type getJoinType() const { return joinType_; }
const DbXmlNodeTest *getNodeTest() const { return nodeTest_; }
+ bool isCaseAndDiacriticInsensitive() const { return cdInsens_; }
+
const ASTNode *getArgument() const { return arg_; }
void setArgument(ASTNode *a) { arg_ = a; }
@@ -63,6 +66,7 @@
Join::Type joinType_;
DbXmlNodeTest *nodeTest_;
+ bool cdInsens_;
ASTNode *arg_;
};
@@ -77,6 +81,24 @@
QueryPlanHolder arg0qph_;
};
+class DbXmlFunContainsCD : public DbXmlFunction
+{
+public:
+ static const XMLCh name[];
+ static const unsigned int minArgs, maxArgs;
+
+ DbXmlFunContainsCD(const VectorOfASTNodes &args, XPath2MemoryManager* memMgr);
+
+ virtual ASTNode *staticResolution(StaticContext* context);
+ virtual ASTNode *staticTyping(StaticContext *context);
+ virtual Sequence collapseTreeInternal(DynamicContext* context, int flags=0) const;
+
+ QueryPlanHolder &getArg0QPH() { return arg0qph_; }
+
+private:
+ QueryPlanHolder arg0qph_;
+};
+
}
#endif
diff -ur dbxml-2.3.10-original/dbxml/src/dbxml/dataItem/DbXmlFunction.cpp dbxml-2.3.10/dbxml/src/dbxml/dataItem/DbXmlFunction.cpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/dataItem/DbXmlFunction.cpp 2006-10-30 17:45:55.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/dataItem/DbXmlFunction.cpp 2007-08-07 17:23:56.000000000 +0100
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
@@ -68,6 +69,13 @@
chNull
};
+DbXmlFunction::DbXmlFunction(const XMLCh* name, unsigned int argsFrom, unsigned int argsTo,
+ const char* paramDecl, const VectorOfASTNodes &args, XPath2MemoryManager* memMgr)
+ : XQFunction(name, argsFrom, argsTo, paramDecl, args, memMgr)
+{
+ _fURI = XMLChFunctionURI;
+}
+
void DbXmlFunction::getQNameArg(unsigned int argNum, const XMLCh *&uri, const XMLCh *&name, DynamicContext *context) const
{
// Convert the string to a qname, thus checking it's syntax
@@ -87,6 +95,10 @@
XQThrow(FunctionException,X("DbXmlFunction::getQNameArg"),
X("No namespace binding for prefix in argument to a DB XML extension function."));
}
+ catch(StaticErrorException &e) {
+ XQThrow(FunctionException,X("DbXmlFunction::getQNameArg"),
+ X("No namespace binding for prefix in argument to a DB XML extension function."));
+ }
}
bool DbXmlFunction::getConstantQNameArg(unsigned int argNum, const XMLCh *&uri, const XMLCh *&name, DynamicContext *context) const
diff -ur dbxml-2.3.10-original/dbxml/src/dbxml/dataItem/DbXmlFunction.hpp dbxml-2.3.10/dbxml/src/dbxml/dataItem/DbXmlFunction.hpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/dataItem/DbXmlFunction.hpp 2007-01-12 18:05:49.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/dataItem/DbXmlFunction.hpp 2007-08-07 17:24:09.000000000 +0100
@@ -27,8 +27,7 @@
protected:
DbXmlFunction(const XMLCh* name, unsigned int argsFrom, unsigned int argsTo,
- const char* paramDecl, const VectorOfASTNodes &args, XPath2MemoryManager* memMgr)
- : XQFunction(name, argsFrom, argsTo, paramDecl, args, memMgr) {}
+ const char* paramDecl, const VectorOfASTNodes &args, XPath2MemoryManager* memMgr);
};
template
diff -ur dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/ASTRewriteOptimizer.cpp dbxml-2.3.10/dbxml/src/dbxml/optimizer/ASTRewriteOptimizer.cpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/ASTRewriteOptimizer.cpp 2006-10-30 17:45:58.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/optimizer/ASTRewriteOptimizer.cpp 2007-08-07 17:19:56.000000000 +0100
@@ -643,7 +643,7 @@
return item;
}
-ASTNode *ASTRewriteOptimizer::createDbXmlContains(DbXmlFunContains *item)
+ASTNode *ASTRewriteOptimizer::createDbXmlContains(XQFunction *item, QueryPlanHolder *qph, bool caseDiacriticInsensitive)
{
VectorOfASTNodes &args = const_cast(item->getArguments());
@@ -663,9 +663,9 @@
nav->addStep(arg0);
}
- DbXmlContains *contains = new (mm) DbXmlContains(arg1, mm);
+ DbXmlContains *contains = new (mm) DbXmlContains(arg1, caseDiacriticInsensitive, mm);
contains->setLocationInfo(item);
- contains->setQueryPlanHolder(&item->getArg0QPH());
+ contains->setQueryPlanHolder(qph);
nav->addStep(contains);
nav->recalculateSRC();
@@ -695,7 +695,13 @@
if(uri == XQFunction::XMLChFunctionURI) {
if(name == FunctionContains::name) {
- return createDbXmlContains((DbXmlFunContains*)item);
+ return createDbXmlContains(item, &((DbXmlFunContains*)item)->getArg0QPH(), /*caseDiacriticInsensitive*/false);
+ }
+ }
+
+ else if(uri == DbXmlFunction::XMLChFunctionURI) {
+ if(name == DbXmlFunContainsCD::name) {
+ return createDbXmlContains(item, &((DbXmlFunContainsCD*)item)->getArg0QPH(), /*caseDiacriticInsensitive*/true);
}
}
diff -ur dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/ASTRewriteOptimizer.hpp dbxml-2.3.10/dbxml/src/dbxml/optimizer/ASTRewriteOptimizer.hpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/ASTRewriteOptimizer.hpp 2006-10-30 17:45:59.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/optimizer/ASTRewriteOptimizer.hpp 2007-08-07 16:55:40.000000000 +0100
@@ -51,7 +51,7 @@
private:
ASTNode *createDbXmlCompare(XQOperator *item, GeneralComp::ComparisonOperation op, bool generalComp,
QueryPlanHolder *arg0qph, QueryPlanHolder *arg1qph);
- ASTNode *createDbXmlContains(DbXmlFunContains *item);
+ ASTNode *createDbXmlContains(XQFunction *item, QueryPlanHolder *qph, bool caseDiacriticInsensitive);
ASTNode *createDbXmlIntersect(Intersect *item);
ASTNode *optimizeFLOWRToNav(VectorOfVariableBinding *bindings, XQFLWOR *item, bool quantified);
diff -ur dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/CostBasedOptimizer.cpp dbxml-2.3.10/dbxml/src/dbxml/optimizer/CostBasedOptimizer.cpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/CostBasedOptimizer.cpp 2007-04-18 10:05:23.000000000 +0100
+++ dbxml-2.3.10/dbxml/src/dbxml/optimizer/CostBasedOptimizer.cpp 2007-08-07 17:02:17.000000000 +0100
@@ -424,7 +424,7 @@
case ((ASTNode::whichType)DbXmlASTNode::DBXML_CONTAINS): {
DbXmlContains *oldCnt = (DbXmlContains*)item;
DbXmlContains *cnt = new (mm)
- DbXmlContains(const_cast(oldCnt->getArgument()), mm);
+ DbXmlContains(const_cast(oldCnt->getArgument()), oldCnt->isCaseAndDiacriticInsensitive(), mm);
cnt->setLocationInfo(oldCnt);
forward->addStep(cnt);
break;
diff -ur dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/QueryPlanGenerator.cpp dbxml-2.3.10/dbxml/src/dbxml/optimizer/QueryPlanGenerator.cpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/QueryPlanGenerator.cpp 2007-04-18 10:05:24.000000000 +0100
+++ dbxml-2.3.10/dbxml/src/dbxml/optimizer/QueryPlanGenerator.cpp 2007-08-07 17:03:28.000000000 +0100
@@ -1057,6 +1057,12 @@
generateLookup(fun, ImpliedSchemaNode::METADATA, fun->getChildURIName(),
fun->getParentURIName(), result);
}
+
+ else if(name == DbXmlFunContainsCD::name) {
+ DbXmlFunContainsCD *db = (DbXmlFunContainsCD*)item;
+ generateSubstring(ImpliedSchemaNode::SUBSTRING, args, result, ids,
+ &db->getArg0QPH());
+ }
}
else {
diff -ur dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/QueryPlanOptimizer.cpp dbxml-2.3.10/dbxml/src/dbxml/optimizer/QueryPlanOptimizer.cpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/optimizer/QueryPlanOptimizer.cpp 2006-10-30 17:45:59.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/optimizer/QueryPlanOptimizer.cpp 2007-08-07 17:13:30.000000000 +0100
@@ -37,6 +37,10 @@
} else if(funName == FunctionContains::name) {
((DbXmlFunContains*)item)->getArg0QPH().generateQueryPlan(mgr_, txn_, xpc_);
}
+ } else if(funUri == DbXmlFunction::XMLChFunctionURI) {
+ if(funName == DbXmlFunContainsCD::name) {
+ ((DbXmlFunContainsCD*)item)->getArg0QPH().generateQueryPlan(mgr_, txn_, xpc_);
+ }
}
return item;
diff -ur dbxml-2.3.10-original/dbxml/src/dbxml/QueryContext.cpp dbxml-2.3.10/dbxml/src/dbxml/QueryContext.cpp
--- dbxml-2.3.10-original/dbxml/src/dbxml/QueryContext.cpp 2007-01-12 18:05:49.000000000 +0000
+++ dbxml-2.3.10/dbxml/src/dbxml/QueryContext.cpp 2007-08-07 16:48:16.000000000 +0100
@@ -21,6 +21,7 @@
#include "dataItem/MetaDataFunction.hpp"
#include "dataItem/NodeHandleFunction.hpp"
#include "dataItem/LookupIndexFunction.hpp"
+#include "dataItem/DbXmlContains.hpp"
#include
@@ -358,6 +359,7 @@
context->addCustomFunction(new (memMgr) DbXmlFuncFactory(memMgr));
context->addCustomFunction(new (memMgr) DbXmlFuncFactory(memMgr));
context->addCustomFunction(new (memMgr) DbXmlFuncFactory(memMgr));
+ context->addCustomFunction(new (memMgr) DbXmlFuncFactory(memMgr));
}
DbXmlContext *QueryContext::createDynamicContext(Transaction *txn, const DynamicContext *staticContext)