Skip to content

Commit

Permalink
apacheGH-2218: Implement LATERAL as per SEP-0006/SEP-0007
Browse files Browse the repository at this point in the history
  • Loading branch information
afs committed Feb 8, 2024
1 parent fededc7 commit 5d97dec
Show file tree
Hide file tree
Showing 16 changed files with 565 additions and 125 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Triple;
import org.apache.jena.sparql.algebra.Op;
import org.apache.jena.sparql.algebra.Transform;
import org.apache.jena.sparql.algebra.TransformCopy;
import org.apache.jena.sparql.algebra.Transformer;
import org.apache.jena.sparql.algebra.op.*;
import org.apache.jena.sparql.engine.binding.Binding;
import org.apache.jena.sparql.engine.binding.BindingFactory;
import org.apache.jena.sparql.engine.iterator.QueryIterLateral;
import org.apache.jena.sparql.expr.Expr;
import org.apache.jena.sparql.expr.ExprList;
import org.apache.jena.sparql.pfunction.PropFuncArg;
Expand All @@ -40,12 +43,42 @@
* Substitution in SPARQL algebra.
* <p>
* See also {@link QueryTransformOps} and {@link UpdateTransformOps} which operate on SPARQL syntax.
* <p>
* {@link #inject} provides the substitution, while leaving a variable present, used by LATERAL.
*/
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 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).
* <p>
* <pre>
* (bgp
* (?s :p 123)
* (?s :q ?a)
* )
* </pre>
* with binding {@code ?s = :x } becomes
* <pre>
* (assign (?s :x)
* (bgp
* (:x :p 123)
* (:x :q ?a)
* ))
* </pre>
*/
public static Op inject(Op opInput, Binding binding) {
Set<Var> injectVars = binding.varsMentioned();
Transform transform = new QueryIterLateral.TransformInject(injectVars, binding::get);
Op opOutput = Transformer.transform(transform, opInput);
return opOutput;
}

public static Op substitute(Op op, Binding binding) {
// Want to avoid cost if the binding is empty
// but the empty test is not zero-cost on non-empty things.

if ( isNotNeeded(binding) )
return op;
return Transformer.transform(new OpSubstituteWorker(binding), op);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ public class VarExprList {
private List<Var> vars;
private LinkedHashMap<Var, Expr> exprs; // Preserve order.

public VarExprList(List<Var> vars) {
this.vars = new ArrayList<>(vars);
this.exprs = new LinkedHashMap<>();
}
// public VarExprList(List<Var> vars) {
// this.vars = new ArrayList<>(vars);
// this.exprs = new LinkedHashMap<>();
// }

public VarExprList(VarExprList other) {
this.vars = new ArrayList<>(other.vars);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.apache.jena.sparql.engine.binding;

import java.util.Iterator;
import java.util.Set;
import java.util.function.BiConsumer;

import org.apache.jena.graph.Node;
Expand Down Expand Up @@ -56,6 +57,9 @@ public static BindingBuilder builder(Binding parent) {
/** Iterate over all variables of this binding. */
public Iterator<Var> vars();

/** Iterate over all variables of this binding. */
public Set<Var> varsMentioned();

/** Operate on each entry. */
public void forEach(BiConsumer<Var, Node> action);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
package org.apache.jena.sparql.engine.binding;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.BiConsumer;

import org.apache.jena.atlas.iterator.IteratorConcat;
Expand All @@ -45,14 +47,20 @@ protected BindingBase(Binding _parent) {
// public Binding getParent() { return parent; }

@Override
final public Iterator<Var> vars()
{
final public Iterator<Var> vars() {
Iterator<Var> iter = vars1();
if ( parent != null )
iter = IteratorConcat.concat(parent.vars(), iter);
return iter;
}

@Override
final public Set<Var> varsMentioned() {
Set<Var> result = new LinkedHashSet<>();
vars().forEachRemaining(result::add);
return result;
}

/** Operate on each entry. */
@Override
public void forEach(BiConsumer<Var, Node> action) {
Expand Down
Loading

0 comments on commit 5d97dec

Please sign in to comment.