Skip to content

Commit b794672

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 1090114 commit b794672

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;
@@ -84,10 +92,6 @@
8492
import org.exist.dom.persistent.NodeSet;
8593
import org.exist.security.Permission;
8694
import com.evolvedbinary.j8fu.Either;
87-
import org.exist.xquery.CompiledXQuery;
88-
import org.exist.xquery.XPathException;
89-
import org.exist.xquery.XQuery;
90-
import org.exist.xquery.XQueryContext;
9195

9296
import javax.annotation.Nullable;
9397

@@ -421,7 +425,20 @@ protected void declareVariables(final XQueryContext context) throws XPathExcepti
421425

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

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 = (XQueryService) dbCollection.getService("XQueryService", "1.0");
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
@@ -1903,6 +1903,7 @@ public void staticVariables() throws XMLDBException {
19031903
assertEquals(1, result.getSize());
19041904
result = service2.query("declare variable $name as xs:string external; $name");
19051905
assertEquals(1, result.getSize());
1906+
service2.clearVariables();
19061907
result = service2.query( doc, "//item[stock = 43]");
19071908
assertEquals(1, result.getSize());
19081909
result = service2.query(doc, "//item");

0 commit comments

Comments
 (0)