#336 Type inference for avg() and sum() is wrong

v8.3
closed
Michael Kay
5
2012-10-08
2005-03-22
Michael Kay
No

The static type inferencing for the avg() and sum()
functions is incorrect. If the argument to the function
has a static type that is a node type, the inferencing
concludes wrongly that the result will be the same node
type. If the function is used in a context where (say)
a string is expected, this can lead to spurious type
errors (either at compile time or at run-time) when the
function actually delivers a number.

Source fix:

(a) in net.sf.saxon.functions.Aggregate, in the switch
statement of the getItemType() method,

(a1) immediately after "case SUM:" replace the line reading

ItemType base = argument[0].getItemType();

by

ItemType base =
Atomizer.getAtomizedItemType(argument[0], false);

(a2) immediately after "case AVG:" replace the line reading

ItemType base = argument[0].getItemType();

by

ItemType base =
Atomizer.getAtomizedItemType(argument[0], false);

(b) in net.sf.saxon.expr.Atomize, add the method (based
on the existing code in the getItemType() method)

public static ItemType

getAtomizedItemType(Expression operand, boolean
alwaysUntyped) {
ItemType in = operand.getItemType();
if (in instanceof AtomicType) {
return in;
}
if (in instanceof NodeTest) {

        if (in instanceof NoNodeTest) {
            return in;
        }
        // Some node-kinds always have a typed

value that's a string
int kinds = ((NodeTest)in).getNodeKindMask();
if ((kinds | STRING_KINDS) == STRING_KINDS) {
return Type.STRING_TYPE;
}
// Some node-kinds are always untyped
atomic; some are untypedAtomic provided that the
configuration
// is untyped
if (alwaysUntyped) {
if ((kinds | UNTYPED_IF_UNTYPED_KINDS)
== UNTYPED_IF_UNTYPED_KINDS) {
return Type.UNTYPED_ATOMIC_TYPE;
}
} else {
if ((kinds | UNTYPED_KINDS) ==
UNTYPED_KINDS) {
return Type.UNTYPED_ATOMIC_TYPE;
}
}

        SchemaType schemaType =

((NodeTest)in).getContentType();
if (schemaType instanceof SimpleType) {
return
((SimpleType)schemaType).getCommonAtomicType();
} else if
(((ComplexType)schemaType).isSimpleContent()) {
return
((ComplexType)schemaType).getSimpleContentType().getCommonAtomicType();
} else {
// if a complex type with complex
content can be atomized at all, it will return
untypedAtomic values
return Type.UNTYPED_ATOMIC_TYPE;
}
}
return Type.ANY_ATOMIC_TYPE;
}

Discussion