com.bigdata.rdf.sail.sparql.TriplePatternExprBuilder Maven / Gradle / Ivy
/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
[email protected]
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Aug 27, 2011
*/
package com.bigdata.rdf.sail.sparql;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.openrdf.model.Literal;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.vocabulary.RDF;
import com.bigdata.bop.BOp;
import com.bigdata.bop.BOpUtility;
import com.bigdata.rdf.internal.impl.bnode.SidIV;
import com.bigdata.rdf.model.BigdataBNode;
import com.bigdata.rdf.model.BigdataStatement;
import com.bigdata.rdf.model.BigdataValue;
import com.bigdata.rdf.sail.sparql.ast.ASTBind;
import com.bigdata.rdf.sail.sparql.ast.ASTBlankNodePropertyList;
import com.bigdata.rdf.sail.sparql.ast.ASTCollection;
import com.bigdata.rdf.sail.sparql.ast.ASTConstruct;
import com.bigdata.rdf.sail.sparql.ast.ASTObjectList;
import com.bigdata.rdf.sail.sparql.ast.ASTPathAlternative;
import com.bigdata.rdf.sail.sparql.ast.ASTPathElt;
import com.bigdata.rdf.sail.sparql.ast.ASTPathMod;
import com.bigdata.rdf.sail.sparql.ast.ASTPathOneInPropertySet;
import com.bigdata.rdf.sail.sparql.ast.ASTPathSequence;
import com.bigdata.rdf.sail.sparql.ast.ASTPropertyList;
import com.bigdata.rdf.sail.sparql.ast.ASTPropertyListPath;
import com.bigdata.rdf.sail.sparql.ast.ASTTRefPattern;
import com.bigdata.rdf.sail.sparql.ast.ASTVar;
import com.bigdata.rdf.sail.sparql.ast.Node;
import com.bigdata.rdf.sail.sparql.ast.VisitorException;
import com.bigdata.rdf.sparql.ast.ConstantNode;
import com.bigdata.rdf.sparql.ast.PathNode;
import com.bigdata.rdf.sparql.ast.PathNode.PathAlternative;
import com.bigdata.rdf.sparql.ast.PathNode.PathElt;
import com.bigdata.rdf.sparql.ast.PathNode.PathMod;
import com.bigdata.rdf.sparql.ast.PathNode.PathNegatedPropertySet;
import com.bigdata.rdf.sparql.ast.PathNode.PathOneInPropertySet;
import com.bigdata.rdf.sparql.ast.PathNode.PathSequence;
import com.bigdata.rdf.sparql.ast.StatementPatternNode;
import com.bigdata.rdf.sparql.ast.TermNode;
import com.bigdata.rdf.sparql.ast.VarNode;
import com.bigdata.rdf.sparql.ast.optimizers.ASTPropertyPathOptimizer;
/**
* Class handles triple patterns and property paths.
*
* @author Bryan Thompson
* @version $Id$
* @openrdf
*/
public class TriplePatternExprBuilder extends ValueExprBuilder {
private static final transient Logger log = Logger.getLogger(TriplePatternExprBuilder.class);
/**
* @param context
*/
public TriplePatternExprBuilder(final BigdataASTContext context) {
super(context);
}
@Override
final public Object visit(final ASTPropertyList propListNode, final Object data)
throws VisitorException {
final TermNode subject = (TermNode) data;
final TermNode predicate = (TermNode) propListNode.getVerb().jjtAccept(
this, null);
@SuppressWarnings("unchecked")
final List objectList = (List) propListNode
.getObjectList().jjtAccept(this, null);
for (TermNode object : objectList) {
graphPattern.addSP(subject, predicate, object);
}
final ASTPropertyList nextPropList = propListNode.getNextPropertyList();
if (nextPropList != null) {
nextPropList.jjtAccept(this, subject);
}
return null;
}
@Override
final public Object visit(final ASTPropertyListPath propListNode,
final Object data) throws VisitorException {
final TermNode subject = (TermNode) data;
final BOp verb = (BOp) propListNode.getVerb().jjtAccept(
this, data);
@SuppressWarnings("unchecked")
final List objectList = (List) propListNode
.getObjectList().jjtAccept(this, null);
if (verb instanceof TermNode) {
final TermNode predicate = (TermNode) verb;
for (TermNode object : objectList) {
graphPattern.addSP(subject, predicate, object);
}
} else {
final PathAlternative pathAlt = (PathAlternative) verb;
/*
* Even simple triple patterns are going through the property path
* code logic. Easier to just recognize those here, although
* we could just as easily do it in the optimizer. But this would
* break a lot of the test cases.
*/
if (ASTPropertyPathOptimizer.isSimpleIRI(pathAlt)) {
final ConstantNode predicate =
ASTPropertyPathOptimizer.getSimpleIRI(pathAlt);
for (TermNode object : objectList) {
graphPattern.addSP(subject, predicate, object);
}
} else {
if (log.isDebugEnabled())
log.debug(BOpUtility.toString(pathAlt));
final PathNode path = new PathNode(pathAlt);
for (TermNode object : objectList) {
graphPattern.addPP(subject, path, object);
}
}
}
// if (verbPath instanceof VarNode) {
//
// @SuppressWarnings("unchecked")
// final List objectList = (List) propListNode
// .getObjectList().jjtAccept(this, null);
//
// for (TermNode object : objectList) {
//
// graphPattern.addSP(subject, verbPath, object);
//
// }
//
// } else {
//
// /*
// * PROPERTY PATHS
// *
// * Note: This code path is a single IRI (degenerative case) or a
// * more complex path. This is handled by the aspect of the visitor
// * which deals with property paths, even in the case where the
// * triple pattern is as simple as (var const var).
// *
// * FIXME This code block should be empty when we incorporate support
// * for property paths from the Sesame visitor methods. It currently
// * duplicates the code block above and provides handling for the
// * case when the predicate is a constant.
// *
// * Just need to make this block empty and let the visitor do the work.
// */
//
//// @SuppressWarnings("unchecked")
//// final List objectList = (List) propListNode
//// .getObjectList().jjtAccept(this, null);
////
//// for (TermNode object : objectList) {
////
//// graphPattern.addSP(subject, verbPath, object);
////
//// }
//
// }
final ASTPropertyListPath nextPropList = propListNode
.getNextPropertyList();
if (nextPropList != null) {
nextPropList.jjtAccept(this, subject);
}
return null;
}
@Override
public PathAlternative visit(final ASTPathAlternative pathAltNode, Object data)
throws VisitorException {
final int numChildren = pathAltNode.jjtGetNumChildren();
final PathSequence[] args = new PathSequence[numChildren];
for (int i = 0; i < numChildren; i++) {
args[i] = (PathSequence) pathAltNode.jjtGetChild(i).jjtAccept(this, data);
}
return new PathAlternative(args);
}
@Override
public PathSequence visit(ASTPathSequence pathSeqNode, Object data)
throws VisitorException {
final int numChildren = pathSeqNode.jjtGetNumChildren();
final PathElt[] args = new PathElt[numChildren];
for (int i = 0; i < numChildren; i++) {
args[i] = (PathElt) pathSeqNode.jjtGetChild(i).jjtAccept(this, data);
}
return new PathSequence(args);
}
@Override
public Object visit(ASTPathElt pathEltNode, Object data)
throws VisitorException {
final BOp arg;
if (pathEltNode.isNegatedPropertySet()) {
final int numChildren = pathEltNode.jjtGetNumChildren();
final PathOneInPropertySet[] args = new PathOneInPropertySet[numChildren];
for (int i = 0; i < numChildren; i++) {
args[i] = (PathOneInPropertySet) pathEltNode.jjtGetChild(i).jjtAccept(this, data);
}
arg = new PathNegatedPropertySet(args);
} else {
// handle the iri and nested path cases
arg = (BOp) pathEltNode.jjtGetChild(0).jjtAccept(this, data);
}
final boolean inverse = pathEltNode.isInverse();
final PathMod mod = toPathMod(pathEltNode.getPathMod());
return new PathElt(arg, inverse, mod);
}
private PathMod toPathMod(ASTPathMod pathModNode) {
if (pathModNode == null)
return null;
final long lower = pathModNode.getLowerBound();
final long upper = pathModNode.getUpperBound();
if (upper == 1) {
return PathMod.ZERO_OR_ONE;
} else if (lower == 1) {
return PathMod.ONE_OR_MORE;
} else {
return PathMod.ZERO_OR_MORE;
}
}
@Override
public Object visit(final ASTPathOneInPropertySet node, Object data)
throws VisitorException {
final ConstantNode arg = (ConstantNode) node.jjtGetChild(0).jjtAccept(this, data);
final boolean inverse = node.isInverse();
return new PathOneInPropertySet(arg, inverse);
}
@Override
final public List visit(final ASTObjectList node, final Object data)
throws VisitorException {
final int childCount = node.jjtGetNumChildren();
final List result = new ArrayList(childCount);
for (int i = 0; i < childCount; i++) {
result.add((TermNode) node.jjtGetChild(i).jjtAccept(this, null));
}
return result;
}
@Override
final public VarNode visit(final ASTBlankNodePropertyList node, final Object data)
throws VisitorException {
final VarNode bnodeVar = context.createAnonVar(node.getVarName());
super.visit(node, bnodeVar);
return bnodeVar;
}
/**
* Handle the RDF Collection syntax.
*/
@Override
public VarNode visit(final ASTCollection node, final Object data)
throws VisitorException {
final String listVarName = node.getVarName();
final VarNode rootListVar = context.createAnonVar(listVarName);
TermNode listVar = rootListVar;
final int childCount = node.jjtGetNumChildren();
for (int i = 0; i < childCount; i++) {
final TermNode childValue = (TermNode) node.jjtGetChild(i)
.jjtAccept(this, null);
graphPattern.addSP(listVar, context.createConstVar(RDF.FIRST),
childValue);
TermNode nextListVar;
if (i == childCount - 1) {
nextListVar = context.createConstVar(RDF.NIL);
} else {
nextListVar = context.createAnonVar(listVarName + "-" + (i + 1));
}
graphPattern.addSP(listVar, context.createConstVar(RDF.REST),
nextListVar);
listVar = nextListVar;
}
return rootListVar;
}
//
// FIXME Property paths (Implement).
//
// @Override
// public Object visit(ASTPathAlternative pathAltNode, Object data)
// throws VisitorException
// {
//
// int altCount = pathAltNode.jjtGetNumChildren();
//
// if (altCount > 1) {
// GraphPattern parentGP = graphPattern;
// Union union = new Union();
// Union currentUnion = union;
// for (int i = 0; i < altCount - 1; i++) {
// graphPattern = new GraphPattern(parentGP);
// pathAltNode.jjtGetChild(i).jjtAccept(this, data);
// TupleExpr arg = graphPattern.buildTupleExpr();
// currentUnion.setLeftArg(arg);
// if (i == altCount - 2) { // second-to-last item
// graphPattern = new GraphPattern(parentGP);
// pathAltNode.jjtGetChild(i + 1).jjtAccept(this, data);
// arg = graphPattern.buildTupleExpr();
// currentUnion.setRightArg(arg);
// }
// else {
// Union newUnion = new Union();
// currentUnion.setRightArg(newUnion);
// currentUnion = newUnion;
// }
// }
//
// parentGP.addRequiredTE(union);
// graphPattern = parentGP;
// }
// else {
// pathAltNode.jjtGetChild(0).jjtAccept(this, data);
// }
//
// return null;
// }
//
// @Override
// public PathOneInPropertySet visit(ASTPathOneInPropertySet node, Object data)
// throws VisitorException
// {
//
// PropertySetElem result = new PropertySetElem();
// result.setInverse(node.isInverse());
// ValueConstant predicate = (ValueConstant)node.jjtGetChild(0).jjtAccept(this, data);
// result.setPredicate(predicate);
//
// return result;
// }
//
// private ASTObjectList getObjectList(Node node) {
// if (node == null) {
// return null;
// }
// if (node instanceof ASTPropertyListPath) {
// return ((ASTPropertyListPath)node).getObjectList();
// }
// else {
// return getObjectList(node.jjtGetParent());
// }
// }
//
// private boolean checkInverse(Node node) {
// if (node instanceof ASTPathElt) {
// return ((ASTPathElt)node).isInverse();
// }
// else {
// Node parent = node.jjtGetParent();
// if (parent != null) {
// return checkInverse(parent);
// }
// else {
// return false;
// }
// }
// }
//
// @Override
// public Object visit(ASTPathSequence pathSeqNode, Object data)
// throws VisitorException
// {
//
// ValueExpr subject = (ValueExpr)data;
// Var subjVar = valueExpr2Var(subject);
//
// // check if we should invert subject and object.
// boolean invertSequence = checkInverse(pathSeqNode);
//
// @SuppressWarnings("unchecked")
// List objectList = (List)getObjectList(pathSeqNode).jjtAccept(this, null);
//
// List pathElements = pathSeqNode.getPathElements();
//
// int pathLength = pathElements.size();
//
// GraphPattern pathSequencePattern = new GraphPattern(graphPattern);
//
// Scope scope = pathSequencePattern.getStatementPatternScope();
// Var contextVar = pathSequencePattern.getContextVar();
//
// Var startVar = subjVar;
//
// for (int i = 0; i < pathLength; i++) {
// ASTPathElt pathElement = pathElements.get(i);
//
// ASTPathMod pathMod = pathElement.getPathMod();
//
// long lowerBound = Long.MIN_VALUE;
// long upperBound = Long.MIN_VALUE;
//
// if (pathMod != null) {
// lowerBound = pathMod.getLowerBound();
// upperBound = pathMod.getUpperBound();
//
// if (upperBound == Long.MIN_VALUE) {
// upperBound = lowerBound;
// }
// else if (lowerBound == Long.MIN_VALUE) {
// lowerBound = upperBound;
// }
// }
//
// if (pathElement.isNegatedPropertySet()) {
//
// // create a temporary negated property set object and set the
// // correct subject and object vars to continue
// // the path sequence.
//
// NegatedPropertySet nps = new NegatedPropertySet();
// nps.setScope(scope);
// nps.setSubjectVar(startVar);
// nps.setContextVar(contextVar);
//
// for (Node child : pathElement.jjtGetChildren()) {
// nps.addPropertySetElem((PropertySetElem)child.jjtAccept(this, data));
// }
//
// if (i == pathLength - 1) {
// nps.setObjectList(objectList);
// }
// else {
// // not last element in path.
// Var nextVar = createAnonVar(startVar.getName() + "-property-set-" + i);
//
// List nextVarList = new ArrayList();
// nextVarList.add(nextVar);
// nps.setObjectList(nextVarList);
//
// startVar = nextVar;
// }
//
// // convert the NegatedPropertySet to a proper TupleExpr
// pathSequencePattern.addRequiredTE(createTupleExprForNegatedPropertySet(nps, i));
//
// }
// else if (pathElement.isNestedPath()) {
// GraphPattern parentGP = graphPattern;
//
// graphPattern = new GraphPattern(parentGP);
//
// if (i == pathLength - 1) {
// // last element in the path
// pathElement.jjtGetChild(0).jjtAccept(this, startVar);
//
// TupleExpr te = graphPattern.buildTupleExpr();
//
// for (ValueExpr object : objectList) {
// Var objVar = valueExpr2Var(object);
// te = handlePathModifiers(scope, startVar, te, objVar, contextVar, lowerBound, upperBound);
// pathSequencePattern.addRequiredTE(te);
// }
// }
// else {
// // not the last element in the path, introduce an anonymous var
// // to connect.
// Var nextVar = createAnonVar(subjVar.getName() + "-nested-" + i);
//
// pathElement.jjtGetChild(0).jjtAccept(this, startVar);
//
// TupleExpr te = graphPattern.buildTupleExpr();
//
// // replace all object list occurrences with the intermediate var.
//
// te = replaceVarOccurrence(te, objectList, nextVar);
// te = handlePathModifiers(scope, startVar, te, nextVar, contextVar, lowerBound, upperBound);
// pathSequencePattern.addRequiredTE(te);
//
// startVar = nextVar;
// }
//
// graphPattern = parentGP;
// }
// else {
//
// ValueExpr pred = (ValueExpr)pathElement.jjtAccept(this, data);
// Var predVar = valueExpr2Var(pred);
//
// TupleExpr te;
//
// if (i == pathLength - 1) {
// // last element in the path, connect to list of defined objects
// for (ValueExpr object : objectList) {
// Var objVar = valueExpr2Var(object);
// Var endVar = objVar;
//
// if (invertSequence) {
// endVar = subjVar;
// }
//
// if (pathElement.isInverse()) {
// te = new StatementPattern(scope, endVar, predVar, startVar, contextVar);
// te = handlePathModifiers(scope, endVar, te, startVar, contextVar, lowerBound, upperBound);
// }
// else {
// te = new StatementPattern(scope, startVar, predVar, endVar, contextVar);
// te = handlePathModifiers(scope, startVar, te, endVar, contextVar, lowerBound, upperBound);
//
// }
//
// pathSequencePattern.addRequiredTE(te);
// }
// }
// else {
// // not the last element in the path, introduce an anonymous var
// // to connect.
// Var nextVar = createAnonVar(predVar.getName() + "-" + i);
//
// if (invertSequence && startVar.equals(subjVar)) { // first
// // element in
// // inverted
// // sequence
// for (ValueExpr object : objectList) {
// Var objVar = valueExpr2Var(object);
// startVar = objVar;
//
// if (pathElement.isInverse()) {
// Var temp = startVar;
// startVar = nextVar;
// nextVar = temp;
// }
//
// te = new StatementPattern(scope, startVar, predVar, nextVar, contextVar);
// te = handlePathModifiers(scope, startVar, te, nextVar, contextVar, lowerBound,
// upperBound);
//
// pathSequencePattern.addRequiredTE(te);
// }
// }
// else {
//
// if (pathElement.isInverse()) {
// startVar = nextVar;
// nextVar = subjVar;
// }
//
// te = new StatementPattern(scope, startVar, predVar, nextVar, contextVar);
// te = handlePathModifiers(scope, startVar, te, nextVar, contextVar, lowerBound, upperBound);
//
// pathSequencePattern.addRequiredTE(te);
// }
//
// // set the subject for the next element in the path.
// startVar = (pathElement.isInverse() ? startVar : nextVar);
// }
// }
// }
//
// // add the created path sequence to the graph pattern.
// for (TupleExpr te : pathSequencePattern.getRequiredTEs()) {
// graphPattern.addRequiredTE(te);
// }
//
// return null;
// }
//
// private TupleExpr createTupleExprForNegatedPropertySet(NegatedPropertySet nps, int index) {
// Var subjVar = nps.getSubjectVar();
//
// Var predVar = createAnonVar("nps-" + subjVar.getName() + "-" + index);
// // Var predVarInverse = createAnonVar("nps-inverse-" + subjVar.getName() +
// // "-" + index);
//
// ValueExpr filterCondition = null;
// ValueExpr filterConditionInverse = null;
//
// // build (inverted) filter conditions for each negated path element.
// for (PropertySetElem elem : nps.getPropertySetElems()) {
// ValueConstant predicate = elem.getPredicate();
//
// if (elem.isInverse()) {
// Compare compare = new Compare(predVar, predicate, CompareOp.NE);
// if (filterConditionInverse == null) {
// filterConditionInverse = compare;
// }
// else {
// filterConditionInverse = new And(compare, filterConditionInverse);
// }
// }
// else {
// Compare compare = new Compare(predVar, predicate, CompareOp.NE);
// if (filterCondition == null) {
// filterCondition = compare;
// }
// else {
// filterCondition = new And(compare, filterCondition);
// }
// }
// }
//
// TupleExpr patternMatch = null;
//
// // build a regular statement pattern (or a join of several patterns if the
// // object list has more than
// // one item)
// if (filterCondition != null) {
// for (ValueExpr objVar : nps.getObjectList()) {
// if (patternMatch == null) {
// patternMatch = new StatementPattern(nps.getScope(), subjVar, predVar, (Var)objVar,
// nps.getContextVar());
// }
// else {
// patternMatch = new Join(new StatementPattern(nps.getScope(), subjVar, predVar, (Var)objVar,
// nps.getContextVar()), patternMatch);
// }
// }
// }
//
// TupleExpr patternMatchInverse = null;
//
// // build a inverse statement pattern (or a join of several patterns if the
// // object list has more than
// // one item):
// if (filterConditionInverse != null) {
// for (ValueExpr objVar : nps.getObjectList()) {
// if (patternMatchInverse == null) {
// patternMatchInverse = new StatementPattern(nps.getScope(), (Var)objVar, predVar, subjVar,
// nps.getContextVar());
// }
// else {
// patternMatchInverse = new Join(new StatementPattern(nps.getScope(), (Var)objVar, predVar,
// subjVar, nps.getContextVar()), patternMatchInverse);
// }
// }
// }
//
// TupleExpr completeMatch = null;
//
// if (patternMatch != null) {
// completeMatch = new Filter(patternMatch, filterCondition);
// }
//
// if (patternMatchInverse != null) {
// if (completeMatch == null) {
// completeMatch = new Filter(patternMatchInverse, filterConditionInverse);
// }
// else {
// completeMatch = new Union(new Filter(patternMatchInverse, filterConditionInverse), completeMatch);
// }
// }
//
// return completeMatch;
// }
//
// private TupleExpr replaceVarOccurrence(TupleExpr te, List objectList, Var replacementVar)
// throws VisitorException
// {
// for (ValueExpr objExpr : objectList) {
// Var objVar = valueExpr2Var(objExpr);
// VarReplacer replacer = new VarReplacer(objVar, replacementVar);
// te.visit(replacer);
// }
// return te;
// }
//
// private TupleExpr handlePathModifiers(Scope scope, Var subjVar, TupleExpr te, Var endVar, Var contextVar,
// long lowerBound, long upperBound)
// throws VisitorException
// {
//
// TupleExpr result = te;
//
// if (lowerBound >= 0L) {
//
// if (lowerBound < upperBound) {
//
// if (upperBound < Long.MAX_VALUE) {
// // upperbound is fixed-length
//
// // create set of unions for all path lengths between lower
// // and upper bound.
// Union union = new Union();
// Union currentUnion = union;
//
// for (long length = lowerBound; length < upperBound; length++) {
//
// TupleExpr path = createPath(scope, subjVar, te, endVar, contextVar, length);
//
// currentUnion.setLeftArg(path);
// if (length == upperBound - 1) {
// path = createPath(scope, subjVar, te, endVar, contextVar, length + 1);
// currentUnion.setRightArg(path);
// }
// else {
// Union nextUnion = new Union();
// currentUnion.setRightArg(nextUnion);
// currentUnion = nextUnion;
// }
// }
//
// result = union;
// }
// else {
// // upperbound is abitrary-length
//
// result = new ArbitraryLengthPath(scope, subjVar, te, endVar, contextVar, lowerBound);
// }
// }
// else {
// // create single path of fixed length.
// TupleExpr path = createPath(scope, subjVar, te, endVar, contextVar, lowerBound);
// result = path;
// }
// }
//
// return result;
// }
//
// private TupleExpr createPath(Scope scope, Var subjVar, TupleExpr pathExpression, Var endVar,
// Var contextVar, long length)
// throws VisitorException
// {
// if (pathExpression instanceof StatementPattern) {
// Var predVar = ((StatementPattern)pathExpression).getPredicateVar();
//
// if (length == 0L) {
// return new ZeroLengthPath(scope, subjVar, endVar, contextVar);
// }
// else {
// GraphPattern gp = new GraphPattern();
// gp.setContextVar(contextVar);
// gp.setStatementPatternScope(scope);
//
// Var nextVar = null;
//
// for (long i = 0L; i < length; i++) {
// if (i < length - 1) {
// nextVar = createAnonVar(predVar.getName() + "-path-" + length + "-" + i);
// }
// else {
// nextVar = endVar;
// }
// gp.addRequiredSP(subjVar, predVar, nextVar);
// subjVar = nextVar;
// }
// return gp.buildTupleExpr();
// }
// }
// else {
// if (length == 0L) {
// return new ZeroLengthPath(scope, subjVar, endVar, contextVar);
// }
// else {
// GraphPattern gp = new GraphPattern();
// gp.setContextVar(contextVar);
// gp.setStatementPatternScope(scope);
//
// Var nextVar = null;
// for (long i = 0L; i < length; i++) {
// if (i < length - 1L) {
// nextVar = createAnonVar(subjVar.getName() + "-expression-path-" + length + "-" + i);
// }
// else {
// nextVar = endVar;
// }
//
// // create a clone of the path expression.
// TupleExpr clone = pathExpression.clone();
//
// VarReplacer replacer = new VarReplacer(endVar, nextVar);
// clone.visit(replacer);
//
// gp.addRequiredTE(clone);
//
// subjVar = nextVar;
// }
// return gp.buildTupleExpr();
// }
// }
// }
//
// protected class VarCollector extends QueryModelVisitorBase {
//
// private final Set collectedVars = new HashSet();
//
// @Override
// public void meet(Var var) {
// collectedVars.add(var);
// }
//
// /**
// * @return Returns the collectedVars.
// */
// public Set getCollectedVars() {
// return collectedVars;
// }
//
// }
//
// private class VarReplacer extends QueryModelVisitorBase {
//
// private Var toBeReplaced;
//
// private Var replacement;
//
// public VarReplacer(Var toBeReplaced, Var replacement) {
// this.toBeReplaced = toBeReplaced;
// this.replacement = replacement;
// }
//
// @Override
// public void meet(Var var) {
// if (toBeReplaced.equals(var)) {
// QueryModelNode parent = var.getParentNode();
// parent.replaceChildNode(var, replacement);
// replacement.setParentNode(parent);
// }
// }
// }
//
// private class SubSelectAlphaConvertor extends QueryModelVisitorBase {
//
// private Var toBeReplaced;
//
// private Var replacement;
//
// private Projection projection;
//
// public SubSelectAlphaConvertor(Projection projection, Var toBeReplaced, Var replacement) {
// this.projection = projection;
// this.toBeReplaced = toBeReplaced;
// this.replacement = replacement;
// }
//
// public void meet(Projection projection)
// throws VisitorException
// {
// if (projection.getBindingNames().contains(toBeReplaced.getName())) {
// super.meet(projection);
// }
// }
//
// public void meet(ProjectionElem elem)
// throws VisitorException
// {
// if (elem.getSourceName().equals(toBeReplaced.getName())) {
// elem.setSourceName(replacement.getName());
// elem.setTargetName(replacement.getName());
// }
// super.meet(elem);
// }
//
// public void meet(ExtensionElem elem)
// throws VisitorException
// {
// if (elem.getName().equals(toBeReplaced.getName())) {
// elem.setName(replacement.getName());
// }
// super.meet(elem);
// }
//
// @Override
// public void meet(Group group)
// throws VisitorException
// {
// super.meet(group);
//
// String name = toBeReplaced.getName();
//
// Set groupBindings = group.getGroupBindingNames();
// Set newGroupBindings = new HashSet(groupBindings);
//
// if (groupBindings.contains(name)) {
// newGroupBindings.remove(name);
// newGroupBindings.add(replacement.getName());
//
// group.setGroupBindingNames(newGroupBindings);
// }
// }
//
// @Override
// public void meet(StatementPattern sp)
// throws VisitorException
// {
// if (toBeReplaced.equals(sp.getContextVar())) {
// if (projection.getProjectionContext() != null
// && projection.getProjectionContext().equals(sp.getContextVar()))
// {
// Var newSpContextVar = createAnonVar(sp.getContextVar().getName()
// + UUID.randomUUID().toString());
// sp.setContextVar(newSpContextVar);
// }
// }
// super.meet(sp);
// }
//
// @Override
// public void meet(Var var) {
// if (toBeReplaced.equals(var)) {
// QueryModelNode parent = var.getParentNode();
//
// parent.replaceChildNode(var, replacement);
// replacement.setParentNode(parent);
// }
// }
// }
/*
* Reification done right.
*
* @see https://sourceforge.net/apps/trac/bigdata/ticket/526 (Reification
* done right)
*/
/**
* This is invoked in two different contexts. One for a bare triple
* reference pattern:
*
*
* <> d e
*
*
* and the other for a BIND() of a triple reference pattern onto a statement
* identifier variable:
*
*
* BIND(<> as ?sidVar)
*
*
* In both cases we translate the triple reference pattern into a new
* {@link StatementPatternNode}. We reach back to the parent to decide which
* of the two invocation contexts applies and either generate a new SID
* variable or use the one from the BIND(). Then we set the SID variable on
* the {@link StatementPatternNode} and add it to the current graph pattern
* group.
*
*
* If either the subject or object position in the triple reference pattern
* is a triple reference pattern, then it will have been turned into a
* {@link StatementPatternNode} by recursion through this method and we
* replace it with the SID variable which was assigned to that
* {@link StatementPatternNode}.
*
* @return The SID variable. This allows the existing code paths to
* handle nested triple reference patterns without change.
*/
public TermNode visit(final ASTTRefPattern node,
final Object data) throws VisitorException {
/*
* Accept and convert.
*/
final TermNode s = (TermNode) node.jjtGetChild(0).jjtAccept(this, data);
final TermNode p = (TermNode) node.jjtGetChild(1).jjtAccept(this, data);
final TermNode o = (TermNode) node.jjtGetChild(2).jjtAccept(this, data);
/*
* Check constraints.
*/
Resource cs = null;
URI cp = null;
Value co = null;
if(s instanceof ConstantNode) {
final BigdataValue v = ((ConstantNode)s).getValue();
if (v instanceof Literal) {
throw new VisitorException(
"Subject in triple reference pattern may not be literal.");
} else {
cs = (Resource) v;
}
} else {
if (((VarNode) s).isAnonymous()) {
/*
* Blank nodes have already been translated into variables.
*
* TODO We could run into trouble here if there anonymous
* variables are introduced for anything other than a blank node
* (and there are). We need to explicitly mark anonymous
* variables which correspond to blank nodes in the original
* query and then test for isBlankNode() here.
*/
throw new VisitorException(
"Subject in triple reference pattern may not be blank node.");
}
}
if (p instanceof ConstantNode) {
final BigdataValue v = ((ConstantNode) p).getValue();
if (!(v instanceof URI)) {
throw new VisitorException(
"Predicate in triple reference pattern must be IRI.");
} else {
cp = (URI) v;
}
}
if (o instanceof ConstantNode) {
final BigdataValue v = ((ConstantNode) o).getValue();
// See https://jira.blazegraph.com/browse/BLZG-1229
// To support SPARQL* syntax in CONSTRUCT clauses with nested TRef values,
// BNode should be allowed as an object value of the nesting node
// if (v instanceof BNode) {
//
// throw new VisitorException(
// "Object in triple reference pattern may not be blank node.");
//
// }
co = v;
} else {
if (((VarNode) o).isAnonymous()) {
/*
* Blank nodes have already been translated into variables.
*/
throw new VisitorException(
"Object in triple reference pattern may not be blank node.");
}
}
/*
* Note: The caller will associate the SID variable with this
* StatementPatternNode if it appears in a BIND(<<...>> AS ?sid)
* construction. That will overwrite the variable which we assign here.
*
* @see GroupGraphPatternBuilder#visit(ASTBind,Object)
*/
final StatementPatternNode sp = new StatementPatternNode(s, p, o,
graphPattern.getContext(),
graphPattern.getStatementPatternScope());
final Node parent = node.jjtGetParent();
final VarNode sidVar;
if(parent instanceof ASTBind) {
final ASTBind bind = (ASTBind) parent;
final Node aliasNode = bind.jjtGetChild(1);
final String alias = ((ASTVar) aliasNode).getName();
// Use the specified variable.
sidVar = new VarNode(alias);
// sidVar.setSID(true);
} else {
// Create a new variable.
sidVar = context.createSidVar();
}
// Set the SID variable on the SP.
sp.setSid(sidVar);
if (isInConstructClause(parent)) {
// @see https://jira.blazegraph.com/browse/BLZG-1229
// in construct clause we should keep TRef as is
if (cs == null || cp == null || co == null) {
throw new VisitorException(
"Invalid TRef: (" + cs + "," + cp + "," + co + ")");
}
BigdataStatement stmt = context.valueFactory.createStatement(cs, cp, co);
BigdataBNode val = context.valueFactory.createBNode(stmt);
SidIV iv = new SidIV(stmt);
val.setIV(iv);
iv.setValue(val);
return new ConstantNode(iv);
}
// add to the current join group.
graphPattern.addSP(sp);
// log.error("node:=" + node + " => " + sp);
// Return the SID variable.
return sidVar;
}
/**
* @param x the node to be tested
* @return true if provide node is ASTConstruct or has ASTConstruct in any of transitive parents.
*/
private boolean isInConstructClause(Node x) {
if (x == null) {
return false;
} else if (x instanceof ASTConstruct) {
return true;
} else {
return isInConstructClause(x.jjtGetParent());
}
}
}