Skip to content

Commit cfcae5e

Browse files
committed
[bugfix] If the value for an external variable is sent to the XML:DB API but the XQuery does not declare such an external variable, then raise an error.
1 parent e2e0512 commit cfcae5e

File tree

4 files changed

+67
-11
lines changed

4 files changed

+67
-11
lines changed

exist-core/src/main/java/org/exist/xmldb/LocalXPathQueryService.java

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.apache.logging.log4j.Logger;
5050
import org.exist.EXistException;
5151
import org.exist.debuggee.Debuggee;
52+
import org.exist.dom.QName;
5253
import org.exist.security.PermissionDeniedException;
5354
import org.exist.security.Subject;
5455
import org.exist.source.DBSource;
@@ -63,6 +64,13 @@
6364
import org.exist.storage.txn.Txn;
6465
import org.exist.util.LockException;
6566
import org.exist.xmldb.function.LocalXmldbFunction;
67+
import org.exist.xquery.CompiledXQuery;
68+
import org.exist.xquery.ExternalModule;
69+
import org.exist.xquery.Variable;
70+
import org.exist.xquery.VariableDeclaration;
71+
import org.exist.xquery.XPathException;
72+
import org.exist.xquery.XQuery;
73+
import org.exist.xquery.XQueryContext;
6674
import org.exist.xquery.value.AnyURIValue;
6775
import org.exist.xquery.value.BinaryValue;
6876
import org.exist.xquery.value.Sequence;
@@ -82,10 +90,6 @@
8290
import org.exist.dom.persistent.NodeSet;
8391
import org.exist.security.Permission;
8492
import com.evolvedbinary.j8fu.Either;
85-
import org.exist.xquery.CompiledXQuery;
86-
import org.exist.xquery.XPathException;
87-
import org.exist.xquery.XQuery;
88-
import org.exist.xquery.XQueryContext;
8993

9094
import javax.annotation.Nullable;
9195

@@ -424,7 +428,20 @@ protected void declareVariables(final XQueryContext context) throws XPathExcepti
424428

425429
// declare static variables
426430
for (final Map.Entry<String, Object> entry : variableDecls.entrySet()) {
427-
context.declareVariable(entry.getKey(), true, entry.getValue());
431+
final String varNameStr = entry.getKey();
432+
433+
final QName varName;
434+
try {
435+
varName = QName.parse(context, varNameStr);
436+
} catch (final QName.IllegalQNameException e) {
437+
throw new XPathException(org.exist.xquery.ErrorCodes.W3CErrorCode.XPST0081, "Error declaring variable, invalid qname: " + varNameStr + ". " + e.getMessage(), e);
438+
}
439+
440+
if (!context.isExternalVariableDeclared(varName)) {
441+
throw new XPathException(org.exist.xquery.ErrorCodes.W3CErrorCode.XPDY0002, "External variable " + varName + " is not declared in the XQuery");
442+
}
443+
444+
context.declareVariable(varName, true, entry.getValue());
428445
}
429446
}
430447

exist-core/src/main/java/org/exist/xmlrpc/RpcConnection.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -265,30 +265,43 @@ private String createId(final XmldbURI collUri) throws EXistException, Permissio
265265
protected QueryResult doQuery(final DBBroker broker, final CompiledXQuery compiled,
266266
final NodeSet contextSet, final Map<String, Object> parameters) throws XPathException, EXistException, PermissionDeniedException {
267267
final XQuery xquery = broker.getBrokerPool().getXQueryService();
268-
269-
checkPragmas(compiled.getContext(), parameters);
268+
final XQueryContext context = compiled.getContext();
269+
checkPragmas(context, parameters);
270270
LockedDocumentMap lockedDocuments = null;
271271
try {
272272
// declare static variables
273273
final Map<String, Object> variableDecls = (Map<String, Object>) parameters.get(RpcAPI.VARIABLES);
274274
if (variableDecls != null) {
275275
for (final Map.Entry<String, Object> entry : variableDecls.entrySet()) {
276+
final String varNameStr = entry.getKey();
277+
278+
final QName varName;
279+
try {
280+
varName = QName.parse(context, varNameStr);
281+
} catch (final QName.IllegalQNameException e) {
282+
throw new XPathException(org.exist.xquery.ErrorCodes.W3CErrorCode.XPST0081, "Error declaring variable, invalid qname: " + varNameStr + ". " + e.getMessage(), e);
283+
}
284+
285+
if (!context.isExternalVariableDeclared(varName)) {
286+
throw new XPathException(org.exist.xquery.ErrorCodes.W3CErrorCode.XPDY0002, "External variable " + varName + " is not declared in the XQuery");
287+
}
288+
276289
if (LOG.isDebugEnabled()) {
277-
LOG.debug("declaring {} = {}", entry.getKey(), entry.getValue());
290+
LOG.debug("declaring {} = {}", varName, entry.getValue());
278291
}
279-
compiled.getContext().declareVariable(entry.getKey(), true, entry.getValue());
292+
context.declareVariable(varName, true, entry.getValue());
280293
}
281294
}
282295

283296
final long start = System.currentTimeMillis();
284297
lockedDocuments = beginProtected(broker, parameters);
285298
if (lockedDocuments != null) {
286-
compiled.getContext().setProtectedDocs(lockedDocuments);
299+
context.setProtectedDocs(lockedDocuments);
287300
}
288301
final Properties outputProperties = new Properties();
289302
final Sequence result = xquery.execute(broker, compiled, contextSet, outputProperties);
290303
// pass last modified date to the HTTP response
291-
HTTPUtils.addLastModifiedHeader(result, compiled.getContext());
304+
HTTPUtils.addLastModifiedHeader(result, context);
292305
LOG.info("query took {}ms.", System.currentTimeMillis() - start);
293306
return new QueryResult(result, outputProperties);
294307
} catch (final XPathException e) {

exist-core/src/test/java/org/exist/xmldb/XMLDBExternalVariableTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,31 @@ private String getBaseUri() {
115115
return baseUri.replace(PORT_PLACEHOLDER, Integer.toString(existWebServer.getPort()));
116116
}
117117

118+
@Test
119+
public void queryPostWithExternalVariableNotSupplied() throws XMLDBException {
120+
try (final Collection dbCollection = DatabaseManager.getCollection(getBaseUri() + "/db", TestUtils.ADMIN_DB_USER, TestUtils.ADMIN_DB_PWD)) {
121+
final XQueryService xqueryService = dbCollection.getService(XQueryService.class);
122+
123+
xqueryService.declareVariable("local:my-variable", "hello");
124+
xqueryService.declareVariable("local:other-variable", "goodbye");
125+
126+
final CompiledExpression compiled = xqueryService.compile("declare variable $local:my-variable as xs:string* external;\n$local:my-variable");
127+
128+
try {
129+
xqueryService.execute(compiled);
130+
fail("Expected XMLDBException with cause XPathException: XPDY0002 External variable local:other-variable is not declared in the XQuery");
131+
} catch (final XMLDBException e) {
132+
final Throwable cause = e.getCause();
133+
assertTrue(cause instanceof XPathException);
134+
}
135+
}
136+
}
137+
138+
@Test
139+
public void queryPostWithExternalVariableUndeclared() throws XMLDBException {
140+
queryPostWithExternalVariable(ErrorCodes.W3CErrorCode.XPDY0002, "xs:string*", (ExternalVariableValueRep[]) null);
141+
}
142+
118143
@Test
119144
public void queryPostWithExternalVariableUntypedNotSupplied() throws XMLDBException {
120145
queryPostWithExternalVariable(ErrorCodes.W3CErrorCode.XPDY0002, null, (ExternalVariableValueRep[]) null);

exist-core/src/test/java/org/exist/xquery/XPathQueryTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1899,6 +1899,7 @@ public void staticVariables() throws XMLDBException {
18991899
assertEquals(1, result.getSize());
19001900
result = service2.query("declare variable $name as xs:string external; $name");
19011901
assertEquals(1, result.getSize());
1902+
service2.clearVariables();
19021903
result = service2.query( doc, "//item[stock = 43]");
19031904
assertEquals(1, result.getSize());
19041905
result = service2.query(doc, "//item");

0 commit comments

Comments
 (0)