This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new b7352cb5bd GH-2896: Inject values into (table unit)
b7352cb5bd is described below
commit b7352cb5bd71e7076eb7cf62fce2b6b333297ce6
Author: Andy Seaborne <[email protected]>
AuthorDate: Wed Dec 18 16:19:44 2024 +0000
GH-2896: Inject values into (table unit)
---
.../apache/jena/sparql/algebra/table/Table1.java | 28 ++++++------
.../org/apache/jena/sparql/core/Substitute.java | 4 +-
.../sparql/engine/iterator/QueryIterLateral.java | 43 +++++++++++++++++--
.../org/apache/jena/sparql/exec/TS_ExecSPARQL.java | 3 +-
.../jena/sparql/exec/TestQueryExecution.java | 50 ++++++++++++++++++++++
jena-cmds/src/main/java/arq/cmdline/ModEngine.java | 27 ++++++------
jena-cmds/src/main/java/arq/query.java | 37 ++++++++--------
7 files changed, 138 insertions(+), 54 deletions(-)
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/table/Table1.java
b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/table/Table1.java
index a7cc31ea1a..1f21ad409b 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/algebra/table/Table1.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/algebra/table/Table1.java
@@ -24,7 +24,6 @@ import java.util.List ;
import org.apache.jena.atlas.iterator.Iter ;
import org.apache.jena.graph.Node ;
-import org.apache.jena.riot.out.NodeFmtLib ;
import org.apache.jena.sparql.core.Var ;
import org.apache.jena.sparql.engine.ExecutionContext ;
import org.apache.jena.sparql.engine.QueryIterator ;
@@ -34,25 +33,24 @@ import
org.apache.jena.sparql.engine.iterator.QueryIterSingleton ;
/** A table of one row of one binding */
public class Table1 extends TableBase {
- private Var var ;
- private Node value ;
+ private final Binding row;
public Table1(Var var, Node value) {
- this.var = var ;
- this.value = value ;
+ this.row = BindingFactory.binding(var, value);
+ }
+
+ public Table1(Binding row) {
+ this.row = row;
}
@Override
public Iterator<Binding> rows() {
- Binding b = BindingFactory.binding(var, value) ;
- return Iter.singletonIterator(b) ;
+ return Iter.singletonIterator(row) ;
}
@Override
public QueryIterator iterator(ExecutionContext execCxt) {
- // Root binding?
- Binding binding = BindingFactory.binding(var, value) ;
- QueryIterator qIter = QueryIterSingleton.create(null, var, value,
execCxt) ;
+ QueryIterator qIter = QueryIterSingleton.create(row, execCxt) ;
return qIter ;
}
@@ -61,15 +59,15 @@ public class Table1 extends TableBase {
@Override
public List<Var> getVars() {
- List<Var> x = new ArrayList<>() ;
- x.add(var) ;
- return x ;
+ List<Var> x = new ArrayList<>();
+ row.forEach((v,n)->x.add(v));
+ return x;
}
@Override
public List<String> getVarNames() {
List<String> x = new ArrayList<>() ;
- x.add(var.getVarName()) ;
+ row.forEach((v,n)->x.add(v.getName()));
return x ;
}
@@ -85,6 +83,6 @@ public class Table1 extends TableBase {
@Override
public String toString() {
- return "Table1(" + var + "," + NodeFmtLib.displayStr(value) + ")" ;
+ return "Table1(" + row + ")" ;
}
}
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/core/Substitute.java
b/jena-arq/src/main/java/org/apache/jena/sparql/core/Substitute.java
index 19cbadc296..e741351417 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/core/Substitute.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/core/Substitute.java
@@ -49,7 +49,7 @@ import
org.apache.jena.sparql.syntax.syntaxtransform.UpdateTransformOps;
public class Substitute {
/**
* Inject takes an {@link Op} to transform using a {Binding binding}. The
- * transformation assumes the Ope structure is legal for the operation. The
+ * transformation assumes the Op structure is legal for the operation. The
* transformation is to wrap each place a variable is used (BGP, GRAPH,
Path and
* some equivalent operations) with a {@code BIND} to restrict the
vartibale to a specific value
* while still retaining the variable (e.g for FILETERs).
@@ -71,7 +71,7 @@ public class Substitute {
*/
public static Op inject(Op opInput, Binding binding) {
Set<Var> injectVars = binding.varsMentioned();
- Transform transform = new QueryIterLateral.TransformInject(injectVars,
binding::get);
+ Transform transform = new QueryIterLateral.TransformInject(injectVars,
binding);
Op opOutput = Transformer.transform(transform, opInput);
return opOutput;
}
diff --git
a/jena-arq/src/main/java/org/apache/jena/sparql/engine/iterator/QueryIterLateral.java
b/jena-arq/src/main/java/org/apache/jena/sparql/engine/iterator/QueryIterLateral.java
index 1162c6cb80..9ce2ce85a1 100644
---
a/jena-arq/src/main/java/org/apache/jena/sparql/engine/iterator/QueryIterLateral.java
+++
b/jena-arq/src/main/java/org/apache/jena/sparql/engine/iterator/QueryIterLateral.java
@@ -18,6 +18,7 @@
package org.apache.jena.sparql.engine.iterator;
+import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -27,8 +28,11 @@ import org.apache.jena.atlas.lib.SetUtils;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.Triple;
import org.apache.jena.sparql.algebra.Op;
+import org.apache.jena.sparql.algebra.Table;
import org.apache.jena.sparql.algebra.TransformCopy;
import org.apache.jena.sparql.algebra.op.*;
+import org.apache.jena.sparql.algebra.table.Table1;
+import org.apache.jena.sparql.algebra.table.TableN;
import org.apache.jena.sparql.core.*;
import org.apache.jena.sparql.engine.ExecutionContext;
import org.apache.jena.sparql.engine.QueryIterator;
@@ -74,14 +78,14 @@ public class QueryIterLateral extends QueryIterRepeatApply {
private final Set<Var> injectVars;
private final Set<Node> varsAsNodes;
private final Function<Var, Node> replacement;
+ private final Binding binding;
private static final boolean substitute = true;
- // Replacement becomes binding.??
- // Or "op call injection"!!
- public TransformInject(Set<Var> injectVars, Function<Var, Node>
replacement) {
+ public TransformInject(Set<Var> injectVars, Binding binding) {
this.injectVars = injectVars;
this.varsAsNodes = Set.copyOf(injectVars);
- this.replacement = replacement;
+ this.replacement = binding::get;
+ this.binding = binding;
}
@Override
@@ -215,6 +219,7 @@ public class QueryIterLateral extends QueryIterRepeatApply {
// Basic Graph Pattern Matching
// Property Path Patterns
// evaluation of algebra form Graph(var,P) involving a variable
(from the syntax GRAPH ?variable {…})
+ // and also nested (table unit) inside (extend)
@Override
public Op transform(OpPath opPath) {
@@ -270,6 +275,36 @@ public class QueryIterLateral extends QueryIterRepeatApply
{
return opExec;
}
+ private OpTable tableUnitTransformed = null;
+
+ @Override
+ public Op transform(OpTable opTable) {
+ // Unit table.
+ if ( opTable.isJoinIdentity() ) {
+ if ( tableUnitTransformed == null ) {
+ Table table2 = new Table1(binding);
+ // Multiple assignment does not matter!
+ tableUnitTransformed = OpTable.create(table2);
+ }
+ return tableUnitTransformed;
+ }
+
+ // By the assignment restriction, the binding only needs to be
added to each row of the table.
+ Table table = opTable.getTable();
+ // Table vars.
+ List<Var> vars = new ArrayList<>(table.getVars());
+ binding.vars().forEachRemaining(vars::add);
+ TableN table2 = new TableN(vars);
+ BindingBuilder builder = BindingFactory.builder();
+ table.iterator(null).forEachRemaining(row->{
+ builder.reset();
+ builder.addAll(row);
+ builder.addAll(binding);
+ table2.addBinding(builder.build());
+ });
+ return OpTable.create(table2);
+ }
+
private Triple applyReplacement(Triple triple, Function<Var, Node>
replacement) {
Node s2 = applyReplacement(triple.getSubject(), replacement);
Node p2 = applyReplacement(triple.getPredicate(), replacement);
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/exec/TS_ExecSPARQL.java
b/jena-arq/src/test/java/org/apache/jena/sparql/exec/TS_ExecSPARQL.java
index 6ae60d2e42..6a1739a19a 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/exec/TS_ExecSPARQL.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/exec/TS_ExecSPARQL.java
@@ -25,8 +25,9 @@ import org.junit.runners.Suite;
@Suite.SuiteClasses( {
TestExecEnvironment.class
, TestQueryExecDataset.class
+ , TestQueryExecution.class
} )
-
+
public class TS_ExecSPARQL {
}
diff --git
a/jena-arq/src/test/java/org/apache/jena/sparql/exec/TestQueryExecution.java
b/jena-arq/src/test/java/org/apache/jena/sparql/exec/TestQueryExecution.java
new file mode 100644
index 0000000000..258a3a003f
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/exec/TestQueryExecution.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jena.sparql.exec;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.Test;
+
+import org.apache.jena.graph.Node;
+import org.apache.jena.sparql.core.DatasetGraph;
+import org.apache.jena.sparql.core.DatasetGraphFactory;
+import org.apache.jena.sparql.engine.binding.Binding;
+
+/** Miscellaneous tests, e.g. from reports. */
+public class TestQueryExecution {
+ @Test public void lateral_with_join() {
+ // GH-2896 LATERAL
+ String qsReport = """
+ SELECT * {
+ BIND( 'x' AS ?xIn )
+ LATERAL {
+ VALUES ?x { 1 }
+ { SELECT ?xIn ?xOut { BIND(?xIn AS ?xOut) } }
+ }
+ }
+ """;
+ DatasetGraph dsg = DatasetGraphFactory.empty();
+ RowSet rowSet = QueryExec.dataset(dsg).query(qsReport).select();
+ Binding row = rowSet.next();
+ row.contains("xOut");
+ Node x = row.get("xOut");
+ assertEquals("x", x.getLiteralLexicalForm());
+ }
+}
diff --git a/jena-cmds/src/main/java/arq/cmdline/ModEngine.java
b/jena-cmds/src/main/java/arq/cmdline/ModEngine.java
index c278ef2f45..bb6b4b6028 100644
--- a/jena-cmds/src/main/java/arq/cmdline/ModEngine.java
+++ b/jena-cmds/src/main/java/arq/cmdline/ModEngine.java
@@ -44,24 +44,25 @@ public class ModEngine extends ModBase
private boolean timing = false ;
@Override
- public void registerWith(CmdGeneral cmdLine)
- {
- cmdLine.getUsage().startCategory("Query Engine") ;
- cmdLine.add(engineDecl, "--engine=EngineName", "Register another
engine factory[ref]") ;
- cmdLine.add(unEngineDecl, "--unengine=EngineName", "Unregister an
engine factory") ;
+ public void registerWith(CmdGeneral cmdLine) {
+ cmdLine.getUsage().startCategory("Query Engine");
+ cmdLine.add(engineDecl, "--engine=EngineName", "Register another
engine factory[ref]");
+ cmdLine.add(unEngineDecl, "--unengine=EngineName", "Unregister an
engine factory");
}
- public void checkCommandLine(CmdGeneral cmdLine)
- {}
+ public void resetRegistrations() {
+ QueryEngineRef.unregister();
+ QueryEngineRefQuad.unregister();
+ QueryEngineMainQuad.unregister();
+ }
@Override
- public void processArgs(CmdArgModule cmdLine)
- {
+ public void processArgs(CmdArgModule cmdLine) {
- List<String> engineDecls = cmdLine.getValues(engineDecl) ;
+ List<String> engineDecls = cmdLine.getValues(engineDecl);
-// if ( x.size() > 0 )
-// QueryEngineRegistry.get().factories().clear() ;
+ // if ( x.size() > 0 )
+ // QueryEngineRegistry.get().factories().clear() ;
for ( String engineName : engineDecls ) {
switch (engineName.toLowerCase()) {
@@ -75,7 +76,7 @@ public class ModEngine extends ModBase
}
}
- List<String> unEngineDecls = cmdLine.getValues(unEngineDecl) ;
+ List<String> unEngineDecls = cmdLine.getValues(unEngineDecl);
for ( String engineName : unEngineDecls ) {
switch (engineName.toLowerCase()) {
case "reference", "ref" -> QueryEngineRef.unregister();
diff --git a/jena-cmds/src/main/java/arq/query.java
b/jena-cmds/src/main/java/arq/query.java
index e3e7a6c75e..f08f250f52 100644
--- a/jena-cmds/src/main/java/arq/query.java
+++ b/jena-cmds/src/main/java/arq/query.java
@@ -61,28 +61,27 @@ public class query extends CmdARQ
protected ModResultsOut modResults = new ModResultsOut() ;
protected ModEngine modEngine = new ModEngine() ;
- public static void main (String... argv)
- {
- new query(argv).mainRun() ;
+ public static void main(String...argv) {
+ new query(argv).mainRun();
}
- public query(String[] argv)
- {
- super(argv) ;
- modQuery = new ModQueryIn(getDefaultSyntax()) ;
- modDataset = setModDataset() ;
+ public query(String[] argv) {
+ super(argv);
+ modQuery = new ModQueryIn(getDefaultSyntax());
+ modDataset = setModDataset();
modVersion.addClass(null, Jena.class);
- super.addModule(modQuery) ;
- super.addModule(modResults) ;
- super.addModule(modDataset) ;
- super.addModule(modEngine) ;
- super.addModule(modTime) ;
+ super.addModule(modQuery);
+ super.addModule(modResults);
+ super.addModule(modDataset);
+ super.addModule(modEngine);
+ super.addModule(modTime);
- super.getUsage().startCategory("Control") ;
- super.add(argExplain, "--explain", "Explain and log query execution")
;
- super.add(argRepeat, "--repeat=N or N,M", "Do N times or N warmup
and then M times (use for timing to overcome start up costs of Java)");
- super.add(argOptimize, "--optimize=", "Turn the query optimizer on or
off (default: on)") ;
+ super.getUsage().startCategory("Control");
+ super.add(argExplain, "--explain", "Explain and log query execution");
+ super.add(argRepeat, "--repeat=N or N,M",
+ "Do N times or N warmup and then M times (use for timing to
overcome start up costs of Java)");
+ super.add(argOptimize, "--optimize=", "Turn the query optimizer on or
off (default: on)");
}
/** Default syntax used when the syntax can not be determined from the
command name or file extension
@@ -163,6 +162,7 @@ public class query extends CmdARQ
String avgStr = modTime.timeStr(avg) ;
System.err.println("Total time: "+modTime.timeStr(totalTime)+" sec
for repeat count of "+repeatCount+ " : average: "+avgStr) ;
}
+ modEngine.resetRegistrations();
}
@Override
@@ -211,8 +211,7 @@ public class query extends CmdARQ
}
protected long totalTime = 0 ;
- protected void queryExec(boolean timed, ResultsFormat fmt, PrintStream
resultsDest)
- {
+ protected void queryExec(boolean timed, ResultsFormat fmt, PrintStream
resultsDest) {
try {
Query query = getQuery() ;
if ( isVerbose() ) {