Skip to content

Commit

Permalink
apacheGH-2896: Inject values into (table unit)
Browse files Browse the repository at this point in the history
  • Loading branch information
afs committed Dec 30, 2024
1 parent d131057 commit e3d1f38
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

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 ;
Expand All @@ -34,25 +33,24 @@

/** 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 ;
}

Expand All @@ -61,15 +59,15 @@ public void closeTable() {}

@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 ;
}

Expand All @@ -85,6 +83,6 @@ public boolean isEmpty() {

@Override
public String toString() {
return "Table1(" + var + "," + NodeFmtLib.displayStr(value) + ")" ;
return "Table1(" + row + ")" ;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
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).
Expand All @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -27,8 +28,11 @@
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;
Expand Down Expand Up @@ -74,14 +78,14 @@ public static class TransformInject extends TransformCopy {
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
Expand Down Expand Up @@ -215,6 +219,7 @@ public Op transform(OpDatasetNames opDatasetNames) {
// Basic Graph Pattern Matching
// Property Path Patterns
// evaluation of algebra form Graph(var,P) involving a variable (from the syntax GRAPH ?variable {&hellip;})
// and also nested (table unit) inside (extend)

@Override
public Op transform(OpPath opPath) {
Expand Down Expand Up @@ -270,6 +275,36 @@ public Op transform(OpTriple opTriple) {
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
@Suite.SuiteClasses( {
TestExecEnvironment.class
, TestQueryExecDataset.class
, TestQueryExecution.class
} )

public class TS_ExecSPARQL {

}
Original file line number Diff line number Diff line change
@@ -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());
}
}
27 changes: 14 additions & 13 deletions jena-cmds/src/main/java/arq/cmdline/ModEngine.java
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -75,7 +76,7 @@ public void processArgs(CmdArgModule cmdLine)
}
}

List<String> unEngineDecls = cmdLine.getValues(unEngineDecl) ;
List<String> unEngineDecls = cmdLine.getValues(unEngineDecl);
for ( String engineName : unEngineDecls ) {
switch (engineName.toLowerCase()) {
case "reference", "ref" -> QueryEngineRef.unregister();
Expand Down
37 changes: 18 additions & 19 deletions jena-cmds/src/main/java/arq/query.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -163,6 +162,7 @@ protected void exec()
String avgStr = modTime.timeStr(avg) ;
System.err.println("Total time: "+modTime.timeStr(totalTime)+" sec for repeat count of "+repeatCount+ " : average: "+avgStr) ;
}
modEngine.resetRegistrations();
}

@Override
Expand Down Expand Up @@ -211,8 +211,7 @@ protected Dataset dealWithNoDataset(Query query) {
}

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() ) {
Expand Down

0 comments on commit e3d1f38

Please sign in to comment.