/** Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com 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 */ package com.bigdata.rdf.sparql.ast; import java.util.Map; import com.bigdata.bop.BOp; import com.bigdata.rdf.sparql.ast.optimizers.ASTNamedSubqueryOptimizer; /** * A subquery with a named solution set which can be referenced from other parts * of the query. * * @see NamedSubqueryInclude */ public class NamedSubqueryRoot extends SubqueryBase implements INamedSolutionSet { /** * */ private static final long serialVersionUID = 1L; public interface Annotations extends INamedSolutionSet.Annotations { /** * The {@link String}[] of the named solution sets on which this named * subquery has a dependency. This is computed by the * {@link ASTNamedSubqueryOptimizer}. */ String DEPENDS_ON = "dependsOn"; /** * A {@link VarNode}[] specifying the join variables that will be used * when the named result set is join with the query. The join variables * MUST be bound for a solution to join. * <p> * Note: This can be different for each context in the query in which a * given named result set is included. When there are different join * variables for different INCLUDEs, then we need to build a hash index * for each set of join variable context that will be consumed within * the query. * <p> * Note: If no join variables are specified, then the join will consider * the N x M cross product, filtering for solutions which join. This is * very expensive. Whenever possible you should identify one or more * variables which must be bound for the join and specify those as the * join variables. */ String JOIN_VARS = "joinVars"; /** * The set of variables which are known to have been materialized once * this named subquery is evaluated. This is set when the * {@link NamedSubqueryRoot} is evaluated and then referenced by the * {@link NamedSubqueryInclude}. */ String DONE_SET = "doneSet"; } /** * Deep copy constructor. */ public NamedSubqueryRoot(final NamedSubqueryRoot queryBase) { super(queryBase); } /** * Shallow copy constructor. */ public NamedSubqueryRoot(final BOp[] args, final Map<String, Object> anns) { super(args, anns); } /** * * @param queryType * @param name * The name of the subquery result set. */ public NamedSubqueryRoot(final QueryType queryType, final String name) { super(queryType); setName(name); } @Override public String getName() { return (String) getProperty(Annotations.NAMED_SET); } @Override public void setName(final String name) { if (name == null) throw new IllegalArgumentException(); setProperty(Annotations.NAMED_SET, name); } /** * The join variables to be used when the named result set is included into * the query. */ public VarNode[] getJoinVars() { return (VarNode[]) getProperty(Annotations.JOIN_VARS); } /** * Set the join variables. * * @param joinVars * The join variables. */ public void setJoinVars(final VarNode[] joinVars) { setProperty(Annotations.JOIN_VARS, joinVars); } /** * Return the set of named solution sets on which this named subquery * depends. * <p> * Note: This is currently set by the {@link ASTNamedSubqueryOptimizer}. * However, it could also be computed dynamically by scanning for * {@link NamedSubqueryInclude}s within the WHERE clause of the named * subquery. * * @see Annotations#DEPENDS_ON */ public final String[] getDependsOn() { return (String[]) getRequiredProperty(Annotations.DEPENDS_ON); } public final void setDependsOn(final String[] dependsOn) { setProperty(Annotations.DEPENDS_ON, dependsOn); } @Override public String toString(int indent) { final StringBuilder sb = new StringBuilder(); sb.append("\n"); sb.append(indent(indent)); sb.append("WITH {"); sb.append(super.toString(indent+1)); sb.append("\n"); sb.append(indent(indent)); sb.append("} AS ").append(getName()); final VarNode[] joinVars = getJoinVars(); if (joinVars != null) { sb.append(" JOIN ON ("); boolean first = true; for (VarNode var : joinVars) { if (!first) sb.append(","); sb.append(var); first = false; } sb.append(")"); } final String[] dependsOn = (String[]) getProperty(Annotations.DEPENDS_ON); if(dependsOn != null) { sb.append(" DEPENDS ON ("); boolean first = true; for (String s : dependsOn) { if (!first) sb.append(","); sb.append(s); first = false; } sb.append(")"); } return sb.toString(); } }