Skip to content

Commit

Permalink
Merge pull request #5078 from evolvedbinary/feat/time-pragma
Browse files Browse the repository at this point in the history
New exist:time XQuery Pragma
  • Loading branch information
dizzzz authored Oct 6, 2023
2 parents b5b4b88 + 381294b commit ec356d0
Show file tree
Hide file tree
Showing 15 changed files with 753 additions and 313 deletions.
2 changes: 2 additions & 0 deletions exist-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,7 @@
<exclude>src/test/java/org/exist/xquery/functions/session/AttributeTest.java</exclude>
<exclude>src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java</exclude>
<exclude>src/main/java/org/exist/xquery/functions/util/Eval.java</exclude>
<exclude>src/main/java/org/exist/xquery/pragmas/TimePragma.java</exclude>
<exclude>src/test/java/org/exist/xquery/util/URIUtilsTest.java</exclude>
<exclude>src/main/java/org/exist/xquery/value/ArrayListValueSequence.java</exclude>
<exclude>src/test/java/org/exist/xquery/value/BifurcanMapTest.java</exclude>
Expand Down Expand Up @@ -918,6 +919,7 @@ The original license statement is also included below.]]></preamble>
<include>src/test/java/org/exist/xquery/functions/session/AttributeTest.java</include>
<include>src/test/java/org/exist/xquery/functions/xmldb/XMLDBAuthenticateTest.java</include>
<include>src/main/java/org/exist/xquery/functions/util/Eval.java</include>
<include>src/main/java/org/exist/xquery/pragmas/TimePragma.java</include>
<include>src/test/java/org/exist/xquery/util/URIUtilsTest.java</include>
<include>src/main/java/org/exist/xquery/value/ArrayListValueSequence.java</include>
<include>src/test/java/org/exist/xquery/value/BifurcanMapTest.java</include>
Expand Down
98 changes: 98 additions & 0 deletions exist-core/src/main/java/org/exist/xquery/AbstractPragma.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* eXist-db Open Source Native XML Database
* Copyright (C) 2001 The eXist-db Authors
*
* [email protected]
* 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.dom.QName;
import org.exist.xquery.util.ExpressionDumper;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Sequence;

import javax.annotation.Nullable;

/**
* Base class for implementing an XQuery Pragma expression.
*
* @author <a href="mailto:[email protected]">Adam Retter</a>
*/
public abstract class AbstractPragma implements Pragma {
private final QName name;
private @Nullable final String contents;
private @Nullable final Expression expression;

public AbstractPragma(@Nullable final Expression expression, final QName name, @Nullable final String contents) {
this.expression = expression;
this.name = name;
this.contents = contents;
}

@Override
public QName getName() {
return name;
}

public @Nullable Expression getExpression() {
return expression;
}

@Override
public void analyze(final AnalyzeContextInfo contextInfo) throws XPathException {
// no-op by default
}

@Override
public void before(final XQueryContext context, @Nullable final Expression expression, final Sequence contextSequence) throws XPathException {
// no-op by default
}

@Override
public Sequence eval(final Sequence contextSequence, final Item contextItem) throws XPathException {
// no-op by default
return null;
}

@Override
public void after(final XQueryContext context, @Nullable final Expression expression) throws XPathException {
// no-op by default
}

protected @Nullable String getContents() {
return contents;
}

@Override
public void dump(final ExpressionDumper dumper) {
dumper.display("(# " + getName().getStringValue());
if (getContents() != null) {
dumper.display(' ').display(getContents());
}
}

@Override
public void resetState(final boolean postOptimization) {
//no-op by default
}

@Override
public String toString() {
return "(# " + name + ' ' + contents + "#)";
}
}
56 changes: 27 additions & 29 deletions exist-core/src/main/java/org/exist/xquery/ExtensionExpression.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,24 +33,23 @@
* Implements an XQuery extension expression. An extension expression starts with
* a list of pragmas, followed by an expression enclosed in curly braces. For evaluation
* details check {{@link #eval(Sequence, Item)}.
*
* @author wolf
*
* @author wolf
*/
public class ExtensionExpression extends AbstractExpression {

private Expression innerExpression;
private List<Pragma> pragmas = new ArrayList<>(3);
private final List<Pragma> pragmas = new ArrayList<>(3);

public ExtensionExpression(XQueryContext context) {
public ExtensionExpression(final XQueryContext context) {
super(context);
}

public void setExpression(Expression inner) {
public void setExpression(final Expression inner) {
this.innerExpression = inner;
}

public void addPragma(Pragma pragma) {
public void addPragma(final Pragma pragma) {
pragmas.add(pragma);
}

Expand All @@ -62,19 +61,20 @@ public void addPragma(Pragma pragma) {
* will be thrown. If all pragmas return null, we call eval on the original expression and return
* that.
*/
public Sequence eval(Sequence contextSequence, Item contextItem)
throws XPathException {
@Override
public Sequence eval(final Sequence contextSequence, final Item contextItem) throws XPathException {
callBefore(contextSequence);
Sequence result = null;
for (final Pragma pragma : pragmas) {
Sequence temp = pragma.eval(contextSequence, contextItem);
final Sequence temp = pragma.eval(contextSequence, contextItem);
if (temp != null) {
result = temp;
break;
}
}
if (result == null)
{result = innerExpression.eval(contextSequence, contextItem);}
if (result == null) {
result = innerExpression.eval(contextSequence, contextItem);
}
callAfter();
return result;
}
Expand All @@ -85,7 +85,7 @@ private void callAfter() throws XPathException {
}
}

private void callBefore(Sequence contextSequence) throws XPathException {
private void callBefore(final Sequence contextSequence) throws XPathException {
for (final Pragma pragma : pragmas) {
pragma.before(context, innerExpression, contextSequence);
}
Expand All @@ -95,31 +95,27 @@ public int returnsType() {
return innerExpression.returnsType();
}

public void analyze(AnalyzeContextInfo contextInfo) throws XPathException {
public void analyze(final AnalyzeContextInfo contextInfo) throws XPathException {
final AnalyzeContextInfo newContext = new AnalyzeContextInfo(contextInfo);
for (final Pragma pragma : pragmas) {
pragma.analyze(newContext);
}
innerExpression.analyze(newContext);
}

public void dump(ExpressionDumper dumper) {
public void dump(final ExpressionDumper dumper) {
for (final Pragma pragma : pragmas) {
dumper.display("(# " + pragma.getQName().getStringValue(), line);
if (pragma.getContents() != null)
{dumper.display(' ').display(pragma.getContents());}
dumper.display("#)").nl();
pragma.dump(dumper);
dumper.nl();
}
dumper.display('{');
dumper.startIndent();
innerExpression.dump(dumper);
dumper.endIndent();
dumper.nl().display('}').nl();
dumper.nl().display("}", line).nl();
}

/* (non-Javadoc)
* @see org.exist.xquery.AbstractExpression#getDependencies()
*/
@Override
public int getDependencies() {
return innerExpression.getDependencies();
}
Expand All @@ -129,31 +125,33 @@ public Cardinality getCardinality() {
return innerExpression.getCardinality();
}

public void setContextDocSet(DocumentSet contextSet) {
@Override
public void setContextDocSet(final DocumentSet contextSet) {
super.setContextDocSet(contextSet);
innerExpression.setContextDocSet(contextSet);
}

public void setPrimaryAxis(int axis) {
@Override
public void setPrimaryAxis(final int axis) {
innerExpression.setPrimaryAxis(axis);
}

@Override
public int getPrimaryAxis() {
return innerExpression.getPrimaryAxis();
}

/* (non-Javadoc)
* @see org.exist.xquery.AbstractExpression#resetState()
*/
public void resetState(boolean postOptimization) {
@Override
public void resetState(final boolean postOptimization) {
super.resetState(postOptimization);
innerExpression.resetState(postOptimization);
for (final Pragma pragma : pragmas) {
pragma.resetState(postOptimization);
}
}

public void accept(ExpressionVisitor visitor) {
@Override
public void accept(final ExpressionVisitor visitor) {
visitor.visit(innerExpression);
}
}
3 changes: 0 additions & 3 deletions exist-core/src/main/java/org/exist/xquery/Optimizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,12 @@
*/
package org.exist.xquery;

import org.exist.dom.QName;
import org.exist.storage.DBBroker;
import org.exist.xquery.functions.array.ArrayConstructor;
import org.exist.xquery.pragmas.Optimize;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.xquery.util.ExpressionDumper;
import org.exist.xquery.value.AtomicValue;
import org.exist.xquery.value.Type;

import javax.annotation.Nullable;
import java.util.*;
Expand Down
6 changes: 4 additions & 2 deletions exist-core/src/main/java/org/exist/xquery/Option.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.exist.Namespaces;
import org.exist.dom.QName;

import javax.annotation.Nullable;

/**
* Represents an XQuery option declared via "declare option".
*
Expand Down Expand Up @@ -89,9 +91,9 @@ public static String[] tokenize(final String contents) {
return items;
}

public static String[] parseKeyValuePair(final String s) {
public static @Nullable String[] parseKeyValuePair(final String s) {
final Matcher matcher = pattern.matcher(s);
if(matcher.matches()) {
if (matcher.matches()) {
String value = matcher.group(2);
if(value.charAt(0) == '\'' || value.charAt(0) == '"') {
value = value.substring(1, value.length() - 1);
Expand Down
60 changes: 15 additions & 45 deletions exist-core/src/main/java/org/exist/xquery/Pragma.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,60 +22,30 @@
package org.exist.xquery;

import org.exist.dom.QName;
import org.exist.xquery.util.ExpressionDumper;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Sequence;

import javax.annotation.Nullable;

public abstract class Pragma {

private QName qname;
private @Nullable String contents;
private Expression expression;

public Pragma(final QName qname, final @Nullable String contents) throws XPathException {
this(null, qname, contents);
}

public Pragma(final Expression expression, final QName qname, @Nullable final String contents) throws XPathException {
this.expression = expression;
this.qname = qname;
this.contents = contents;
}
/**
* Interface for implementing an XQuery Pragma expression.
*
* @author <a href="mailto:[email protected]">Adam Retter</a>
*/
public interface Pragma {

public Expression getExpression() {
return expression;
}
QName getName();

public void analyze(final AnalyzeContextInfo contextInfo) throws XPathException {
}
void analyze(AnalyzeContextInfo contextInfo) throws XPathException;

public Sequence eval(final Sequence contextSequence, @Nullable final Item contextItem)
throws XPathException {
return null;
}

public abstract void before(final XQueryContext context, final Sequence contextSequence) throws XPathException;

public abstract void before(final XQueryContext context, final Expression expression, final Sequence contextSequence) throws XPathException;

public abstract void after(final XQueryContext context) throws XPathException;

public abstract void after(final XQueryContext context, final Expression expression) throws XPathException;
void before(XQueryContext context, @Nullable Expression expression, Sequence contextSequence) throws XPathException;

protected String getContents() {
return contents;
}
Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException;

protected QName getQName() {
return qname;
}
void after(XQueryContext context, @Nullable Expression expression) throws XPathException;

public void resetState(final boolean postOptimization) {
}
void dump(final ExpressionDumper dumper);

@Override
public String toString() {
return "(# " + qname + (contents == null ? "" : ' ' + contents) + " #)";
}
}
void resetState(boolean postOptimization);
}
3 changes: 2 additions & 1 deletion exist-core/src/main/java/org/exist/xquery/XQueryContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -2984,6 +2984,7 @@ public Pragma getPragma(final String name, final String contents) throws XPathEx
} catch (final QName.IllegalQNameException e) {
throw new XPathException(rootExpression, ErrorCodes.XPST0081, "No namespace defined for prefix " + name);
}

final String ns = qname.getNamespaceURI();
if (ns.isEmpty()) {
throw new XPathException(rootExpression, ErrorCodes.XPST0081,
Expand All @@ -2999,7 +3000,7 @@ public Pragma getPragma(final String name, final String contents) throws XPathEx

return switch(qname.getLocalPart()) {
case Optimize.OPTIMIZE_PRAGMA_LOCAL_NAME -> new Optimize(rootExpression, this, qname, sanitizedContents, true);
case TimerPragma.TIMER_PRAGMA_LOCAL_NAME -> new TimerPragma(rootExpression, qname, sanitizedContents);
case TimePragma.TIME_PRAGMA_LOCAL_NAME, TimePragma.DEPRECATED_TIMER_PRAGMA_LOCAL_NAME -> new TimePragma(rootExpression, qname, sanitizedContents);
case ProfilePragma.PROFILING_PRAGMA_LOCAL_NAME -> new ProfilePragma(rootExpression, qname, sanitizedContents);
case ForceIndexUse.FORCE_INDEX_USE_PRAGMA_LOCAL_NAME -> new ForceIndexUse(rootExpression, qname, sanitizedContents);
case NoIndexPragma.NO_INDEX_PRAGMA_LOCAL_NAME -> new NoIndexPragma(rootExpression, qname, sanitizedContents);
Expand Down
Loading

0 comments on commit ec356d0

Please sign in to comment.