Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions exist-core/src/main/java/org/exist/xquery/RootNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,20 @@ public RootNode(XQueryContext context) {
super(context, Constants.SELF_AXIS);
}

@Override
public int getDependencies() {
// Declare CONTEXT_ITEM so the optimizer does not hoist predicates
// containing only / out of their iteration context. The default
// (CONTEXT_SET) is not enough on its own — the predicate optimizer
// looks at CONTEXT_ITEM to decide whether a sub-expression can be
// evaluated once outside the iteration. Without this override an
// expression like fn:count(.[5 * /]) is evaluated with no context
// item, falls through to getStaticallyKnownDocuments(), and returns
// arbitrary content from the static-context default (which under
// admin includes /db/system).
return Dependency.CONTEXT_ITEM | Dependency.CONTEXT_SET;
}

public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (context.getProfiler().isEnabled()) {
context.getProfiler().start(this);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* eXist-db Open Source Native XML Database
* Copyright (C) 2001 The eXist-db Authors
*
* info@exist-db.org
* http://www.exist-db.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.exist.xquery;

import org.exist.test.ExistXmldbEmbeddedServer;
import org.junit.ClassRule;
import org.junit.Test;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;

import static org.junit.Assert.assertEquals;

/**
* Regression test for RootNode dependency declaration.
*
* <p>{@link RootNode} represents the lone-slash root-step ({@code /}). Without
* declaring {@link Dependency#CONTEXT_ITEM} the optimizer's predicate hoister
* treats expressions containing only {@code /} as context-independent and
* evaluates them once outside the iteration context. With no context item to
* resolve against, {@code RootNode.eval} falls through to the static-context
* default (all statically known documents) and returns whatever the broker is
* allowed to see — including {@code /db/system/security} content for admin
* users.</p>
*
* <p>These XPath cases come from W3C qt3tests {@code prod-PathExpr/PathExpr-1},
* {@code -2}, {@code -15} (Nicolae Brinza, 2009): "Leading lone slash syntax
* constraints". Per the spec, with the bid element as context item, {@code /}
* resolves to its document node; arithmetic produces a single numeric value;
* the positional predicate has no match; count is zero.</p>
*/
public class RootNodeContextItemDependencyTest {

@ClassRule
public static final ExistXmldbEmbeddedServer existEmbeddedServer =
new ExistXmldbEmbeddedServer(false, true, true);

/**
* {@code 5 * /} inside a positional predicate. With proper context flow,
* {@code /} resolves to the bid element's owner document (single item),
* {@code 5 * <bid>23</bid>} atomizes to {@code 5 * 23 = 115}, and the
* positional predicate {@code [115]} matches nothing.
*/
@Test
public void loneSlashInArithmeticPredicate_multiplyOnRight() throws XMLDBException {

Check notice on line 63 in exist-core/src/test/java/org/exist/xquery/RootNodeContextItemDependencyTest.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

exist-core/src/test/java/org/exist/xquery/RootNodeContextItemDependencyTest.java#L63

The JUnit 4 test method name 'loneSlashInArithmeticPredicate_multiplyOnRight' doesn't match '[a-z][a-zA-Z0-9]*'
Comment thread
line-o marked this conversation as resolved.
Outdated
final ResourceSet result = existEmbeddedServer.executeQuery(
"let $ctx := document { <bid>23</bid> }/bid return fn:count($ctx[5 * /])");
assertEquals(1, result.getSize());
assertEquals("0", result.getResource(0).getContent());
}

/**
* Mirror of the above with the operands swapped — {@code (/) * 5}.
*/
@Test
public void loneSlashInArithmeticPredicate_multiplyOnLeft() throws XMLDBException {

Check notice on line 74 in exist-core/src/test/java/org/exist/xquery/RootNodeContextItemDependencyTest.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

exist-core/src/test/java/org/exist/xquery/RootNodeContextItemDependencyTest.java#L74

The JUnit 4 test method name 'loneSlashInArithmeticPredicate_multiplyOnLeft' doesn't match '[a-z][a-zA-Z0-9]*'
Comment thread
line-o marked this conversation as resolved.
Outdated
final ResourceSet result = existEmbeddedServer.executeQuery(
"let $ctx := document { <bid>23</bid> }/bid return fn:count($ctx[(/) * 5])");
assertEquals(1, result.getSize());
assertEquals("0", result.getResource(0).getContent());
}

/**
* Without the dependency fix, {@code /} in a hoisted predicate falls
* through to the static-context default — for an admin-level broker
* (the default in this test setup), that historically included
* {@code /db/system/security/exist/accounts/admin.xml}. Confirm the
* single-item document-node return path, not the multi-doc fallback,
* is the one that runs.
*/
@Test
public void loneSlashInPredicate_resolvesToSingleOwnerDocument() throws XMLDBException {

Check notice on line 90 in exist-core/src/test/java/org/exist/xquery/RootNodeContextItemDependencyTest.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

exist-core/src/test/java/org/exist/xquery/RootNodeContextItemDependencyTest.java#L90

The JUnit 4 test method name 'loneSlashInPredicate_resolvesToSingleOwnerDocument' doesn't match '[a-z][a-zA-Z0-9]*'
Comment thread
line-o marked this conversation as resolved.
Outdated
final ResourceSet result = existEmbeddedServer.executeQuery(
"let $ctx := document { <bid>23</bid> }/bid " +
"return fn:count($ctx[fn:count(/) eq 1])");
assertEquals(1, result.getSize());
assertEquals("1", result.getResource(0).getContent());
}
}
Loading