[bugfix] External variable: supplied value overrides declared default#6475
Open
joewiz wants to merge 2 commits into
Open
[bugfix] External variable: supplied value overrides declared default#6475joewiz wants to merge 2 commits into
joewiz wants to merge 2 commits into
Conversation
A value supplied for an external variable by the external environment must take precedence over the variable's declared default (XQuery 3.1 §4.15 External Variables). eXist evaluated the default unconditionally for a `declare variable $x external := ...` declaration, so a value bound via XQueryContext.declareVariable (XMLDB declareVariable, util:eval external vars, REST/API callers, etc.) was ignored whenever the declaration carried a default. VariableDeclaration now carries an `external` flag (set by the tree parser for `declare variable ... external`). On eval, an external declaration with a default first checks whether a value was supplied (a non-null global value already bound before execution) and, if so, uses it instead of evaluating the default. Behavior is unchanged for non-external globals, for external variables without a default, and for defaulted externals with no supplied value. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Open
2 tasks
joewiz
added a commit
to joewiz/existdb-openapi
that referenced
this pull request
Jun 14, 2026
Adds a `variables` describe block to query.cy.js covering: scalar string binding; JSON number → xs:double; JSON array → array(*) (members via ?*); JSON object → map(*); a supplied name with no matching external declaration is ignored; and a missing required external returns an error. All use no-default externals, so the spec is independent of the eXist-core default-override fix (eXist-db/exist#6475). 37/37 green locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
line-o
reviewed
Jun 14, 2026
| final XQueryService service = server.getRoot().getService(XQueryService.class); | ||
| try { | ||
| service.query("declare variable $required external; $required"); | ||
| org.junit.Assert.fail("expected XPDY0002 for an unbound external variable with no default"); |
Member
Author
There was a problem hiding this comment.
[This response was co-authored with Claude Code. -Joe]
Done — switched to import static org.junit.Assert.fail; and the short fail(...). Thanks for the review!
Addresses @line-o's review on PR eXist-db#6475. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
joewiz
added a commit
to joewiz/existdb-openapi
that referenced
this pull request
Jun 14, 2026
Adds a `variables` describe block to query.cy.js covering: scalar string binding; JSON number → xs:double; JSON array → array(*) (members via ?*); JSON object → map(*); a supplied name with no matching external declaration is ignored; and a missing required external returns an error. All use no-default externals, so the spec is independent of the eXist-core default-override fix (eXist-db/exist#6475). 37/37 green locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[This PR was co-authored with Claude Code. -Joe]
What & why
A value supplied for an external variable by the external environment should take precedence over the variable's declared default value (XQuery 3.1 §4.15 External Variables: "If a value is supplied by the external environment for an external variable, that value is used; otherwise, if a default value is specified, the default is used.").
eXist evaluated the default unconditionally for a
declare variable $x external := …declaration, so a value bound before execution — viaXQueryContext.declareVariable(the XMLDBXQueryService.declareVariable,util:eval's external-variables argument, REST/API callers, etc.) — was silently ignored whenever the declaration carried a default. Only externals without a default honored a supplied value.How
VariableDeclarationwas constructed identically for a plain internal global (declare variable $x := …) and an external-with-default (declare variable $x external := …), soeval()couldn't tell them apart and always evaluated the initializer.XQueryTree.g) now marks the declaration as external via a newVariableDeclaration.setExternal(true).VariableDeclaration.eval(): for an external declaration with a default, it first checks whether a value was already supplied (a non-null global value bound before execution) and, if so, uses it (applying the declared sequence type) instead of evaluating the default.Behavior is unchanged for: non-external globals (always evaluate their initializer), external variables without a default, and defaulted externals with no supplied value.
Test plan
ExternalVariableDefaultOverrideTest(exist-core), 5 cases, all green locally:xs:integer21 → 42) overrides default; default used when not supplied; missing required external still raisesXPDY0002; a plain internal global with an initializer is unaffected.Motivation
Enables parameterized server-side queries (binding
$paramvalues at call time) over HTTP — e.g. an editor running a stored.xqagainst the database the waybasex -bname=valuedoes — without forcing query authors to drop default values from their external-variable declarations.