#include "../config/pathan_config.h" /* * Copyright (c) 2001, DecisionSoft Limited All rights reserved. * Please see LICENSE.TXT for more information. */ #include #include #include "../utils/NumUtils.hpp" #include #include #include #include "../exceptions/XPath2TypeCastException.hpp" #include #include #include #include #include #include #include #include #include #include #include DataItemImpl::DataItemImpl(XPath2MemoryManager* memMgr) : _predList(PathanAllocator(memMgr)), _memMgr(memMgr) { // Nothing to do } DataItemImpl::~DataItemImpl(void) { //no-op } void DataItemImpl::addPredicates(const VectorOfDataItems &steps) { _predList.insert(_predList.end(),steps.begin(),steps.end()); } const VectorOfDataItems& DataItemImpl::getPredicates(void) const { return _predList; } /** Returns true if this DataItem has no predicates, and is an instance of DataItemSequence or DataItemLiteral */ bool DataItemImpl::isConstant() const { return (_type == DataItem::SEQUENCE || _type == DataItem::LITERAL) && _predList.empty(); } /** Returns true if this DataItem has no predicates, and is an instance of DataItemSequence or DataItemLiteral. If the literal value of this DataItem is a single DateOrTimeType, then hasTimezone() on it must return true, otherwise this method will return false. */ bool DataItemImpl::isConstantAndHasTimezone(StaticContext *context) const { if(isConstant()) { Sequence s(collapseTree(context->createDynamicContext())); if(s.getLength() == 1) { const Item* item = s.first(); if(item->isAtomicValue() && ((const AnyAtomicType *)item)->isDateOrTimeTypeValue() && !((const DateOrTimeType *)item)->hasTimezone()) { return false; } } return true; } else { return false; } } DataItem::whichType DataItemImpl::getType(void) const { return _type; } void DataItemImpl::setType(DataItem::whichType t) { _type = t; } const Numeric *DataItemImpl::getConstantNumericPredicate(const DataItem *predicate, StaticContext *context) const { if(predicate->isConstant()) { Sequence predTest(predicate->collapseTree(context->createDynamicContext())); if(predTest.getLength() == 1) { const Item *item = predTest.first(); if(item->isAtomicValue()) { const AnyAtomicType* atom1 = (const AnyAtomicType*)item; if(atom1->isNumericValue()) { return (const Numeric *)atom1; } } } } return 0; } void DataItemImpl::checkPredicates(Sequence &s, DynamicContext *context) const { if(_predList.size() == 0 || s.isEmpty()) return; for(VectorOfDataItems::const_iterator it = _predList.begin(); it != _predList.end(); ++it) { // quick check: if the predicate is just a literal number, return the Nth item in the sequence s = checkPredicate(s, *it, context); } } Sequence DataItemImpl::checkPredicate(const Sequence &s, const DataItem *predicate, DynamicContext *context) const { if(s.isEmpty()) return s; // quick check: if the predicate is just a literal number, return the Nth item in the sequence const Numeric *numeric = getConstantNumericPredicate(predicate, context); if(numeric != 0) { const ATDecimalOrDerived* index = (const ATDecimalOrDerived*)numeric->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, context); const Numeric* one = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), 1, context); const Numeric* length = DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), (long)s.getLength(), context); if(index->lessThan(one, context) || index->greaterThan(length, context)) { return Sequence(context->getMemoryManager()); } else { // indexes are zero based, in sequences index = (const ATDecimalOrDerived*)index->subtract(one, context); return Sequence(s.item(index), context->getMemoryManager()); } } unsigned int oldContextSize = context->getContextSize(); unsigned int oldContextPosition = context->getContextPosition(); const Item* oldCurrentItem = context->getContextItem(); Sequence output(s.getLength(), context->getMemoryManager()); context->setContextSize(s.getLength()); int c = 1; Sequence::const_iterator end = s.end(); for(Sequence::const_iterator i = s.begin(); i != end; ++i, ++c) { context->setContextPosition(c); context->setContextItem(*i); if(checkPredicate(predicate, context)) { output.addItem(*i); } } context->setContextSize(oldContextSize); context->setContextPosition(oldContextPosition); context->setContextItem(oldCurrentItem); return output; } Sequence DataItemImpl::collapseTree(DynamicContext* context, int flags) const { if(_predList.empty()) return collapseTreeInternal(context, flags); // if we have predicates, don't let the flags limit the result set or rearrange it Sequence s = collapseTreeInternal(context); checkPredicates(s, context); return s; } bool DataItemImpl::checkPredicate(const DataItem* predicate, DynamicContext* context) const { Sequence predTest(predicate->collapseTree(context,DataItem::UNORDERED|DataItem::RETURN_TWO)); // 3.2.2 ... // The predicate truth value is derived by applying the following rules, in order: // 1) If the value of the predicate expression is an atomic value of a numeric type, the predicate truth // value is true if and only if the value of the predicate expression is equal to the context position. if(predTest.getLength()==1 && predTest.first()->isAtomicValue()) { const AnyAtomicType* atom1 = (const AnyAtomicType*)predTest.first(); if(atom1->isNumericValue()) { const Numeric* num = (const Numeric*)atom1; return num->equals(DatatypeFactory::POD2AT::createInteger(context->getMemoryManager(), (long)context->getContextPosition(), context), context); } } // 2) Otherwise, the predicate truth value is the effective boolean value of the predicate expression return predTest.getEffectiveBooleanValue(context); } /** Calls staticResolution on the DataItem, then if isConstant() is true for it, and constantFold is true, returns the result of the constantFold() method, otherwise returns the result of the resolvePredicates() method. */ DataItem *DataItemImpl::resolveDataItem(DataItem *&di, StaticContext *context, StaticResolutionContext *src, bool cf) { di = di->staticResolution(context, src); if(di->isConstant() && cf) { return constantFold(context, src); } else { return resolvePredicates(context, src); } } /** Calls staticResolution on the DataItems, then if isConstant() is true for all of them, and constantFold is true, returns the result of the constantFold() method, otherwise returns the result of the resolvePredicates() method. */ DataItem *DataItemImpl::resolveDataItems(VectorOfDataItems &dis, StaticContext *context, StaticResolutionContext *src, bool cf) { bool allConstant = true; for(VectorOfDataItems::iterator i = dis.begin(); i != dis.end(); ++i) { *i = (*i)->staticResolution(context, src); if(!(*i)->isConstant()) { allConstant = false; } } if(allConstant && cf) { return constantFold(context, src); } else { return resolvePredicates(context, src); } } /** Calls staticResolution on the DataItems, then if isConstantAndHasTimezone() is true for all of them, and constantFold is true, returns the result of the constantFold() method, otherwise returns the result of the resolvePredicates() method. */ DataItem *DataItemImpl::resolveDataItemsForDateOrTime(VectorOfDataItems &dis, StaticContext *context, StaticResolutionContext *src, bool cf) { bool allConstant = true; for(VectorOfDataItems::iterator i = dis.begin(); i != dis.end(); ++i) { *i = (*i)->staticResolution(context, src); if(!(*i)->isConstantAndHasTimezone(context)) { allConstant = false; if((*i)->isConstant()) { src->implicitTimezoneUsed(true); } } } if(allConstant && cf) { return constantFold(context, src); } else { return resolvePredicates(context, src); } } /** Calls staticResolution on the predicates of this DataItem, constant folding if possible */ DataItem *DataItemImpl::resolvePredicates(StaticContext *context, StaticResolutionContext *src) { VectorOfDataItems newPreds(PathanAllocator(context->getMemoryManager())); DataItemImpl *result = resolvePredicate(_predList.rbegin(), newPreds, context, src); result->_predList = newPreds; return result; } /** Calls staticResolution on the predicates of this DataItem, constant folding if possible */ DataItemImpl *DataItemImpl::resolvePredicate(VectorOfDataItems::reverse_iterator it, VectorOfDataItems &newPreds, StaticContext *context, StaticResolutionContext *src) { if(it == _predList.rend()) { return this; } else { DataItemImpl *newDI = resolvePredicate(it + 1, newPreds, context, src); // A predicate before us has short circuited the predicate resolving, // so we'll just pass back it's result. if(newDI != this) { return newDI; } StaticResolutionContext newSrc(context->getMemoryManager()); DataItem *pred = (*it)->staticResolution(context, &newSrc); if(!newSrc.isUsed() && getConstantNumericPredicate(pred, context) == 0) { // It's not a numeric constant DynamicContext *dContext = context->createDynamicContext(); if(pred->collapseTree(dContext).getEffectiveBooleanValue(dContext)) { // We have a true predicate, so don't add it to the new predicate list return this; } else { // We have a false predicate, which is constant folded to an empty sequence, // short circuiting the subsequent predicate resolutions newPreds.clear(); return new (getMemoryManager()) DataItemSequence(getMemoryManager()); } } else { // It's not constant, or it's numeric, so add it to the new predicate list, and return newPreds.push_back(pred); // Remove context item usage newSrc.contextItemUsed(false); newSrc.contextPositionUsed(false); newSrc.contextSizeUsed(false); src->add(&newSrc); return this; } } } /** Performs constant folding on this DataItem, transfering any predicates to the returned DataItem */ DataItem *DataItemImpl::constantFold(StaticContext *context, StaticResolutionContext *src) const { DynamicContext *dContext = context->createDynamicContext(); DataItem* newBlock = new (getMemoryManager()) DataItemSequence(collapseTreeInternal(dContext), getMemoryManager()); newBlock->addPredicates(_predList); return newBlock->staticResolution(context, src); } XPath2MemoryManager* DataItemImpl::getMemoryManager(void) const { return _memMgr; }