#include "../config/pathan_config.h" /* * Copyright (c) 2001, DecisionSoft Limited All rights reserved. * Please see LICENSE.TXT for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include const XMLCh FunctionDistinctValues::name[] = { XERCES_CPP_NAMESPACE_QUALIFIER chLatin_d, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_i, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_s, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_t, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_i, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_n, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_c, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_t, XERCES_CPP_NAMESPACE_QUALIFIER chDash, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_v, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_a, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_l, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_u, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_e, XERCES_CPP_NAMESPACE_QUALIFIER chLatin_s, XERCES_CPP_NAMESPACE_QUALIFIER chNull }; /** * fn:distinct-values($arg as xdt:anyAtomicType*) as xdt:anyAtomicType* * fn:distinct-values($arg as xdt:anyAtomicType*, $collation as xs:string) as xdt:anyAtomicType* **/ FunctionDistinctValues::FunctionDistinctValues(const VectorOfDataItems &args, XPath2MemoryManager* memMgr) : ConstantFoldingFunction(name,1, 2, "anyAtomicType*, string", args, memMgr) { } bool FunctionDistinctValues::isNumericType(const XMLCh* typeURI, const XMLCh* typeName, const DynamicContext* context) const { return (context->isTypeOrDerivedFromType(typeURI,typeName, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA,XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL) || context->isTypeOrDerivedFromType(typeURI,typeName, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA,XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_FLOAT) || context->isTypeOrDerivedFromType(typeURI,typeName, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA,XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DOUBLE)); } Sequence FunctionDistinctValues::validateSequence(Sequence sequence, DynamicContext* context) const { if(sequence.isEmpty()) return sequence; Sequence::iterator i = sequence.begin(); Sequence firstStep(context->getMemoryManager()); // convert untypedAtomic into strings, strip all but one NaN, replace -0.0 with +0.0 bool bSeenNaN=false; for (; i != sequence.end(); ++i) { const AnyAtomicType* atom = (const AnyAtomicType*)*i; const XMLCh* atomTypeURI = atom->getTypeURI(); const XMLCh* atomTypeName = atom->getTypeName(); if (XPath2Utils::equals(atomTypeName, ATUntypedAtomic::fgDT_UNTYPEDATOMIC) && XPath2Utils::equals(atomTypeURI, FunctionConstructor::XMLChXPath2DatatypesURI )) { firstStep.addItem(atom->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_STRING, context)); } else if(atom->getPrimitiveTypeIndex()==AnyAtomicType::DOUBLE && ((const ATDoubleOrDerived*)atom)->isZero() && ((const ATDoubleOrDerived*)atom)->isNegative()) firstStep.addItem(DatatypeFactory::POD2AT::createDouble(context->getMemoryManager(), 0.0, context)); else if(atom->getPrimitiveTypeIndex()==AnyAtomicType::FLOAT && ((const ATFloatOrDerived*)atom)->isZero() && ((const ATFloatOrDerived*)atom)->isNegative()) firstStep.addItem(DatatypeFactory::POD2AT::createFloat(context->getMemoryManager(), 0.0, context)); else if(atom->getPrimitiveTypeIndex()==AnyAtomicType::DOUBLE && ((const ATDoubleOrDerived*)atom)->isNaN()) { if(!bSeenNaN) { firstStep.addItem(atom); bSeenNaN=true; } } else if(atom->getPrimitiveTypeIndex()==AnyAtomicType::FLOAT && ((const ATFloatOrDerived*)atom)->isNaN()) { if(!bSeenNaN) { firstStep.addItem(atom); bSeenNaN=true; } } else firstStep.addItem(atom); } // check that sequence contains items of a single type or one if its subtypes. // if there are different numeric types, promote them all to a single common type. const XMLCh* sequenceTypeURI = FunctionConstructor::XMLChXPath2DatatypesURI; const XMLCh* sequenceTypeName = ATUntypedAtomic::fgDT_UNTYPEDATOMIC; i = firstStep.begin(); for (; i != firstStep.end(); ++i) { const AnyAtomicType* atom = (const AnyAtomicType*)*i; const XMLCh* atomTypeURI = atom->getTypeURI(); const XMLCh* atomTypeName = atom->getTypeName(); if (! ( XPath2Utils::equals(sequenceTypeName, atomTypeName) && XPath2Utils::equals(sequenceTypeURI, atomTypeURI) ) ) { // if the sequenceType and atomType are not equal we must determine what to do if (XPath2Utils::equals(sequenceTypeName, ATUntypedAtomic::fgDT_UNTYPEDATOMIC) && XPath2Utils::equals(sequenceTypeURI, FunctionConstructor::XMLChXPath2DatatypesURI )) { // if the sequenceType is untypedAtomic then we are the first, so set the sequenceType to the atomType if (isNumericType(atomTypeURI, atomTypeName, context)) { sequenceTypeURI = atom->getPrimitiveTypeURI(); if(context->isTypeOrDerivedFromType(atomTypeURI, atomTypeName, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER)) { sequenceTypeName = XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER; } else { sequenceTypeName = atom->getPrimitiveTypeName(); } } else { sequenceTypeURI = atomTypeURI; sequenceTypeName = atomTypeName; } } else if (context->isTypeOrDerivedFromType(sequenceTypeURI, sequenceTypeName, atomTypeURI, atomTypeName)) { // if the sequenceType is derived from the atomType then we have a sequence of the atomType sequenceTypeURI = atomTypeURI; sequenceTypeName = atomTypeName; } else if (context->isTypeOrDerivedFromType(atomTypeURI, atomTypeName, sequenceTypeURI, sequenceTypeName)) { // if the atomType is derived from the sequenceType let it pass to get dealt with by the SequenceType class } else if (isNumericType(sequenceTypeURI, sequenceTypeName, context) && isNumericType(atomTypeURI, atomTypeName, context)) { // if we are dealing with numerics determine which common type to promote to if (XPath2Utils::equals(sequenceTypeName, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DOUBLE)) { // sequenceType is double, so do nothing since double is king } else if (XPath2Utils::equals(sequenceTypeName, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_FLOAT)) { // sequenceType is float, so if atomType is double then so is sequenceType if (XPath2Utils::equals(atom->getPrimitiveTypeName(), XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DOUBLE)) sequenceTypeName = atom->getPrimitiveTypeName(); } else if (context->isTypeOrDerivedFromType(sequenceTypeURI, sequenceTypeName, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DECIMAL)) { if (!context->isTypeOrDerivedFromType(atomTypeURI, atomTypeName, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER)) { sequenceTypeName = atom->getPrimitiveTypeName(); } } else { // we should never actually get here DSLthrow(IllegalArgumentException, X("FunctionDistinctValues::validateSequence"), X("Invalid argument to aggregate function")); } } else { // we have incompatible types DSLthrow(IllegalArgumentException, X("FunctionDistinctValues::validateSequence"), X("Invalid argument to aggregate function")); } } } SequenceType sequenceType(sequenceTypeURI, sequenceTypeName, SequenceType::STAR); Sequence castedSequence(context->getMemoryManager()); try { castedSequence = sequenceType.castAsFunction(firstStep, context); } catch (XPath2ErrorException &e) { DSLthrow(IllegalArgumentException, X("FunctionDistinctValues::validateSequence"), X("Invalid argument to aggregate function")); } return castedSequence; } Sequence FunctionDistinctValues::collapseTreeInternal(DynamicContext* context, int flags) const { Sequence arg(context->getMemoryManager()); try { arg = validateSequence(getParamNumber(1,context,DataItem::UNORDERED), context); } catch (IllegalArgumentException &e) { DSLthrow(IllegalArgumentException, X("FunctionDistinctValues::collapseTreeInternal"), X("Invalid argument to fn:distinct-values() function")); } if(arg.isEmpty()) return Sequence(context->getMemoryManager()); Collation* collation=NULL; if(getNumArgs()>1) { Sequence collArg = getParamNumber(2,context); const XMLCh* collName = ((const ATStringOrDerived*)collArg.first())->asString(context); try { DatatypeFactory::STR2AT::createAnyURI(context->getMemoryManager(), collName, context); } catch(XPath2ErrorException &e) { DSLthrow(FunctionException, X("FunctionDistinctValues::collapseTreeInternal"), X("Invalid collationURI")); } collation=context->getCollation(collName); if(collation==NULL) DSLthrow(FunctionException,X("FunctionDistinctValues::collapseTreeInternal"),X("Collation object is not available")); } else collation=context->getDefaultCollation(); if(collation==NULL) collation=context->getCollation(CodepointCollation::getCodepointCollationName()); Sequence resultSeq = Sequence(context->getMemoryManager()); Sequence::iterator it=arg.begin(); for(;it!=arg.end();it++) { bool bFound=false; Sequence::iterator it2=resultSeq.begin(); for(;it2!=resultSeq.end();it2++) { if(((const AnyAtomicType*)*it)->getPrimitiveTypeIndex() == AnyAtomicType::STRING) { if(collation->compare((*it2)->asString(context),(*it)->asString(context))==0) bFound = true; } else { try { if(Equals::equals(*it2,*it,context)) bFound=true; } catch (IllegalArgumentException &e) { DSLthrow(IllegalArgumentException, X("FunctionDistinctValues::collapseTreeInternal"), X("Type does not have equality defined")); } catch (XPath2ErrorException &e) { DSLthrow(IllegalArgumentException, X("FunctionDistinctValues::collapseTreeInternal"), X("Type does not have equality defined")); } } if(bFound) break; } if(!bFound) resultSeq.addItem((*it)); } return resultSeq; }