blob: eaccd32ae2c3b55039a3a3bb7016f985472cf4d7 [file] [log] [blame]
/*
* 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.core;
import java.util.ArrayList;
import java.util.List;
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.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.expr.Expr;
import org.apache.jena.sparql.expr.ExprList;
import org.apache.jena.sparql.pfunction.PropFuncArg;
public class Substitute {
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);
}
public static Op substitute(Op op, Var var, Node node) {
Binding b = BindingFactory.binding(var, node);
return substitute(op, b);
}
public static BasicPattern substitute(BasicPattern bgp, Binding binding) {
if ( isNotNeeded(binding) )
return bgp;
BasicPattern bgp2 = new BasicPattern();
for ( Triple triple : bgp ) {
Triple t = substitute(triple, binding);
bgp2.add(t);
}
return bgp2;
}
public static Triple substitute(Triple triple, Binding binding) {
if ( isNotNeeded(binding) )
return triple;
Node s = triple.getSubject();
Node p = triple.getPredicate();
Node o = triple.getObject();
Node s1 = substitute(s, binding);
Node p1 = substitute(p, binding);
Node o1 = substitute(o, binding);
Triple t = triple;
if ( s1 != s || p1 != p || o1 != o )
t = new Triple(s1, p1, o1);
return t;
}
public static TriplePath substitute(TriplePath triplePath, Binding binding) {
if ( triplePath.isTriple() )
return new TriplePath(Substitute.substitute(triplePath.asTriple(), binding));
Node s = triplePath.getSubject();
Node o = triplePath.getObject();
Node s1 = substitute(s, binding);
Node o1 = substitute(o, binding);
TriplePath tp = triplePath;
if ( s1 != s || o1 != o )
tp = new TriplePath(s1, triplePath.getPath(), o1);
return tp;
}
public static Quad substitute(Quad quad, Binding binding) {
if ( isNotNeeded(binding) )
return quad;
Node g = quad.getGraph();
Node s = quad.getSubject();
Node p = quad.getPredicate();
Node o = quad.getObject();
Node g1 = substitute(g, binding);
Node s1 = substitute(s, binding);
Node p1 = substitute(p, binding);
Node o1 = substitute(o, binding);
Quad q = quad;
if ( s1 != s || p1 != p || o1 != o || g1 != g )
q = new Quad(g1, s1, p1, o1);
return q;
}
public static Node substitute(Node n, Binding b) {
return Var.lookup(b, n);
}
public static PropFuncArg substitute(PropFuncArg propFuncArg, Binding binding) {
if ( isNotNeeded(binding) )
return propFuncArg;
if ( propFuncArg.isNode() ) {
Node n = propFuncArg.getArg();
if ( !Var.isVar(n) )
// Not a Var, no substitute needed.
return propFuncArg;
return new PropFuncArg(substitute(propFuncArg.getArg(), binding));
}
List<Node> newArgList = new ArrayList<>();
for ( Node n : propFuncArg.getArgList() )
newArgList.add(substitute(n, binding));
return new PropFuncArg(newArgList);
}
public static Expr substitute(Expr expr, Binding binding) {
if ( isNotNeeded(binding) )
return expr;
return expr.copySubstitute(binding);
}
public static ExprList substitute(ExprList exprList, Binding binding) {
if ( isNotNeeded(binding) )
return exprList;
return exprList.copySubstitute(binding);
}
private static boolean isNotNeeded(Binding b) {
return b == null || b.isEmpty();
}
// ----
private static class OpSubstituteWorker extends TransformCopy {
private Binding binding;
public OpSubstituteWorker(Binding binding) {
super(TransformCopy.COPY_ALWAYS);
this.binding = binding;
}
@Override
public Op transform(OpBGP opBGP) {
BasicPattern bgp = opBGP.getPattern();
bgp = substitute(bgp, binding);
return new OpBGP(bgp);
}
@Override
public Op transform(OpQuadPattern quadPattern) {
Node gNode = quadPattern.getGraphNode();
Node g = substitute(gNode, binding);
BasicPattern triples = new BasicPattern();
for ( Triple triple : quadPattern.getBasicPattern() ) {
Node s = substitute(triple.getSubject(), binding);
Node p = substitute(triple.getPredicate(), binding);
Node o = substitute(triple.getObject(), binding);
Triple t = new Triple(s, p, o);
triples.add(t);
}
// Pure quading.
// for ( Iterator iter = quadPattern.getQuads().iterator() ;
// iter.hasNext() ; )
// {
// Quad quad = (Quad)iter.next() ;
// if ( ! quad.getGraph().equals(gNode) )
// throw new ARQInternalErrorException("Internal error: quads block
// is not uniform over the graph node") ;
// Node s = substitute(quad.getSubject(), binding) ;
// Node p = substitute(quad.getPredicate(), binding) ;
// Node o = substitute(quad.getObject(), binding) ;
// Triple t = new Triple(s, p, o) ;
// triples.add(t) ;
// }
return new OpQuadPattern(g, triples);
}
@Override
public Op transform(OpPath opPath) {
return new OpPath(substitute(opPath.getTriplePath(), binding));
}
@Override
public Op transform(OpPropFunc opPropFunc, Op subOp) {
PropFuncArg sArgs = opPropFunc.getSubjectArgs();
PropFuncArg oArgs = opPropFunc.getObjectArgs();
PropFuncArg sArgs2 = substitute(sArgs, binding);
PropFuncArg oArgs2 = substitute(oArgs, binding);
if ( sArgs2 == sArgs && oArgs2 == oArgs && opPropFunc.getSubOp() == subOp )
return super.transform(opPropFunc, subOp);
return new OpPropFunc(opPropFunc.getProperty(), sArgs2, oArgs2, subOp);
}
@Override
public Op transform(OpFilter filter, Op op) {
ExprList exprs = filter.getExprs().copySubstitute(binding);
if ( exprs == filter.getExprs() )
return filter;
return OpFilter.filterBy(exprs, op);
}
@Override
public Op transform(OpAssign opAssign, Op subOp) {
VarExprList varExprList2 = transformVarExprList(opAssign.getVarExprList());
if ( varExprList2.isEmpty() )
return subOp;
return OpAssign.assign(subOp, varExprList2);
}
@Override
public Op transform(OpExtend opExtend, Op subOp) {
VarExprList varExprList2 = transformVarExprList(opExtend.getVarExprList());
if ( varExprList2.isEmpty() )
return subOp;
return OpExtend.create(subOp, varExprList2);
}
private VarExprList transformVarExprList(VarExprList varExprList) {
VarExprList varExprList2 = new VarExprList();
for ( Var v : varExprList.getVars() ) {
// if ( binding.contains(v))
// // Already bound. No need to do anything because the
// // logical assignment will test value.
// continue ;
Expr expr = varExprList.getExpr(v);
expr = expr.copySubstitute(binding);
varExprList2.add(v, expr);
}
return varExprList2;
}
// The expression?
// public Op transform(OpLeftJoin opLeftJoin, Op left, Op right) {
// return xform(opLeftJoin, left, right) ; }
@Override
public Op transform(OpGraph op, Op sub) {
Node n = substitute(op.getNode(), binding);
return new OpGraph(n, sub);
}
@Override
public Op transform(OpService op, Op sub) {
Node n = substitute(op.getService(), binding);
return new OpService(n, sub, op.getSilent());
}
}
}