Fix XQuery 3.1 casting and numeric comparison compliance#6165
Fix XQuery 3.1 casting and numeric comparison compliance#6165joewiz wants to merge 8 commits intoeXist-db:developfrom
Conversation
Per XPath F&O 3.1 Section 19, casting between types that have no valid conversion path (e.g., xs:time to xs:date, xs:anyURI to xs:hexBinary) should raise XPTY0004, not FORG0001. FORG0001 is reserved for when the cast IS allowed but the specific value is invalid. Add Type.isCastable() implementing the XQuery 3.1 casting table to pre-validate cast operations before attempting them. CastExpression now checks castability first and raises XPTY0004 for impossible casts. CastableExpression returns false immediately for impossible casts. Fixes ~580 XQTS 3.1 test failures in prod-CastExpr and related sets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
fn:min and fn:max threw FORG0006 when given mixed numeric types (e.g., xs:integer and xs:double) because getCommonSuperType() returned ANY_ATOMIC_TYPE for cross-numeric-family types. Per XQuery 3.1, mixed numeric types should be promoted to a common type before comparison. Add a check: if both types are members of the xs:numeric union, allow the comparison to proceed to the existing numeric promotion code. Fixes ~60 XQTS 3.1 test failures in fn-min and fn-max. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When casting xs:double NaN, INF, or -INF to xs:integer or xs:decimal, eXist incorrectly raised FORG0001. Per XPath F&O 3.1 Section 4.1.16, FOCA0002 should be raised when the cast value is outside the target type's value space (NaN and infinities have no integer/decimal representation). Fixes ~44 XQTS 3.1 test failures in prod-CastExpr. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
xs:boolean cast to integer subtypes like xs:nonPositiveInteger or xs:negativeInteger hit the default case and threw an incorrect error. Now routes through IntegerValue conversion which properly validates the value against the subtype's range (e.g., true=1 is invalid for xs:nonPositiveInteger, producing the correct FORG0001). Also fixes the default error code from XPTY0004 to FORG0001 for BooleanValue, since any cast that reaches convertTo() has already passed the casting table validation. Fixes ~5 XQTS 3.1 test failures in prod-CastExpr. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
|
||
| public DecimalValue toDecimalValue() throws XPathException { | ||
| if (isNaN() || isInfinite()) { | ||
| throw conversionError(Type.DECIMAL); |
There was a problem hiding this comment.
Why no longer using the existing conversionError()method?
|
|
||
| public IntegerValue toIntegerSubType(final int subType) throws XPathException { | ||
| if (isNaN() || isInfinite()) { | ||
| throw conversionError(subType); |
There was a problem hiding this comment.
Why no longer using the existing conversionError()method?
|
|
||
| public IntegerValue toIntegerValue() throws XPathException { | ||
| if (isNaN() || isInfinite()) { | ||
| throw conversionError(Type.INTEGER); |
There was a problem hiding this comment.
Why no longer using the existing conversionError()method?
|
|
||
| public DecimalValue toDecimalValue() throws XPathException { | ||
| if (isNaN() || isInfinite()) { | ||
| throw conversionError(Type.DECIMAL); |
There was a problem hiding this comment.
why was the method call conversionError() removed and code duplication introduced? we could pass in an additional error code for the other usages instead in order to reduce code duplication.
|
|
||
| public IntegerValue toIntegerValue() throws XPathException { | ||
| if (isNaN() || isInfinite()) { | ||
| throw conversionError(Type.INTEGER); |
|
|
||
| public IntegerValue toIntegerSubType(final int subType) throws XPathException { | ||
| if (isNaN() || isInfinite()) { | ||
| throw conversionError(subType); |
| * | ||
| * @return true if the cast may succeed (for some values), false if the cast can never succeed | ||
| */ | ||
| public static boolean isCastable(final int sourceType, final int targetType) { |
There was a problem hiding this comment.
Please address the the NPath complexity of 8960, current threshold is 200.
DoubleValue: reuse conversionError() with an error code parameter instead of inlining XPathException construction in toDecimalValue(), toIntegerValue(), and toIntegerSubType(). Type.isCastable(): extract primitive casting table lookup into isPrimitiveCastable() and factor repeated type-group checks into isNumericTarget(), isDateTimeTarget(), isGregorianTarget(), and isStringOrUntypedAtomic() helpers. Reduces NPath complexity from 8960 to below the 200 threshold. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
[This response was co-authored with Claude Code. -Joe] Thanks for the review, @reinhapa! Addressed both points in f92f3e6:
|
StringValue.checkType() threw XPathException without an ErrorCodes
constant for xs:language, xs:Name, xs:NCName, xs:ID, xs:IDREF,
xs:ENTITY, and xs:NMTOKEN validation failures. The runner reported
these as exerr:ERROR instead of FORG0001.
Base64BinaryValueType.verifyString() had the error code as a string
in the message ("FORG0001: Invalid base64 data") instead of using
ErrorCodes.FORG0001 as the structured error code parameter.
Fixes ~58 XQTS HEAD test failures in prod-CastExpr and
misc-CombinedErrorCodes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two issues prevented fn:json-doc from working with relative URIs: 1. Relative URIs (no scheme) were unconditionally prefixed with the eXist database URI prefix, bypassing filesystem resolution. Now resolves relative URIs against the static base URI first, matching the behavior expected by the XQTS test suite. 2. JSON parse errors (JsonParseException) were caught by the generic IOException handler and reported as FOUT1170 (source not found) instead of FOJS0001 (JSON syntax error). Now catches JsonParseException separately. Fixes ~295 XQTS HEAD test failures in misc-JsonTestSuite (0% to 93%) and improves fn-json-doc results. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Several IETF date parsing issues: - Day and month names were case-sensitive (rejected "SAT", "aug"). Now uses case-insensitive matching. - Hours required exactly 2 digits but the IETF grammar allows 1-2 (digit digit?). Changed parseInt minimum from 2 to 1. - Whitespace between time and timezone was mandatory but should be optional per the grammar. - Seconds detection relied on whitespace check instead of colon check, failing when timezone immediately followed time. - 24:00:00 was rejected; now normalized to 00:00:00 of the next day. - Timezone is now optional (grammar: (S? timezone)?). Fixes ~8 XQTS HEAD test failures in fn-parse-ietf-date. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
[This response was co-authored with Claude Code. -Joe] The |
|
[This comment was co-authored with Claude Code. -Joe] Closing — superseded by #6207 (v2/xq31-compliance-fixes). This work has been consolidated into a clean v2/ branch as part of the eXist-db 7.0 PR reorganization. The new PR includes all commits from this PR plus additional related work, with reviewer feedback incorporated where applicable. See the reviewer guide for the full context. |
Summary
Push XQuery 3.1 XQTS compliance (HEAD test suite) from 85.3% to 88.8% (+652 tests) by fixing error codes, URI resolution, and parser edge cases.
Casting & type fixes
Type.isCastable): Pre-validates cast operations. Impossible casts now correctly raise XPTY0004 instead of FORG0001. Fixes ~580 tests.fn:json-doc URI resolution
fn:parse-ietf-date improvements
XQTS HEAD Results
Note: test totals vary between runs due to BrokerPool shutdown timeouts.
Test plan
🤖 Generated with Claude Code