Patches for Berkeley DB XML version 2.3.10

  1. Certain runtime errors during query execution when using modules cause a double free.
  2. Apply the following patch to the dbxml-2.3.10 release.  
    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;
     }
    
    

  3. Fixed a bug which incorrectly reported an error for fractional seconds when the seconds filed was "59".
  4. Apply the following patch to the dbxml-2.3.10 release.  
    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;
    

  5. 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.
  6. Apply the following patch to the dbxml-2.3.10 release.  
    --- 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;
    

  7. Improved query performance for queries consisting of a simple path and predicate.
  8. Apply the following patch to the dbxml-2.3.10 release.  
    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);
    

  9. Improved index utilisation for user defined functions that are called more than once in the query.
  10. Apply the following patch to the dbxml-2.3.10 release.  
    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 {
    
    

  11. Certain predicates containing "or" and an unoptimizable sub-expression do not optimize correctly.
  12. Apply the following patch to the dbxml-2.3.10 release.  
    --- 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
    

  13. Fixes several problems with XmlModify, including a SEGV that can occur when removing a last child element that has leading text. [#15615]
  14. Apply the following patch to the dbxml-2.3.10 release.  
    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));
      	}
    

  15. Bug in statistics calculation for substring indexes, that could result in a crash. [#15823]
  16. Apply the following patch to the dbxml-2.3.10 release.  
    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);
     
    

  17. Fixes a bad exception that might occur when inserting schema-invalid XML. [#15824]
  18. Apply the following patch to the dbxml-2.3.10 release.  
    *** 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().
  • Apply the following patch to the dbxml-2.3.10 release.  
    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)