All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.bigdata.rdf.sparql.ast.JoinGroupNode 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
*/
package com.bigdata.rdf.sparql.ast;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;

import com.bigdata.bop.BOp;
import com.bigdata.bop.IVariable;
import com.bigdata.rdf.internal.constraints.InBOp;
import com.bigdata.rdf.sparql.ast.hints.OptimizerQueryHint;
import com.bigdata.rdf.sparql.ast.optimizers.ASTStaticJoinOptimizer;
import com.bigdata.rdf.sparql.ast.service.ServiceNode;

/**
 * An optional or non-optional collection of query nodes that run together in
 * a group.
 */
public class JoinGroupNode extends GraphPatternGroup {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    interface Annotations extends GroupNodeBase.Annotations {

        /**
         * The graph variable or constant iff this {@link JoinGroupNode} models
         * a GraphPatternGroup. When not present, your have to read up the
         * parent chain to locate the dominating graph context.
         */
        String CONTEXT = "context";
        
        /**
         * A property that may be set by a query hint. When set, the value is a
         * {@link QueryOptimizerEnum}.
         * 
         * @see QueryHints#OPTIMIZER
         * @see OptimizerQueryHint
         */
        String OPTIMIZER = QueryHints.OPTIMIZER;

        /**
         * An optional boolean that indicates whether this {@link JoinGroupNode}
         * is the subgroup of an {@link ArbitraryLengthPathNode}. The default of
         * this annotation is {@value #DEFAULT_IS_SUBGROUP_OF_ALP_NODE} (see:
         * {@link #DEFAULT_IS_SUBGROUP_OF_ALP_NODE}).
         */
        String IS_SUBGROUP_OF_ALP_NODE = "isSubgroupOfArbitraryLengthPathNode";
        
        boolean DEFAULT_IS_SUBGROUP_OF_ALP_NODE = false;
        
    }
    
    /**
     * Constructor required for {@link com.bigdata.bop.BOpUtility#deepCopy(FilterNode)}.
     * 

* Note: There is a nasty potential for a conflict here. This constructor is part * of the deep copy semantics. The JoinGroupNode(IGroupMemberNode child) * This means that the following code DOES NOT create a nested structure of a JoinGroupNode in a JoinGroupNode. *

     * new JoinGroupNode(new JoinGroupNode); // COPY CONSTRUCTOR PATTERN.
     * 
* Instead you MUST do this incrementally *
     * final JoinGroupNode parent = new JoinGroupNode();
     * parent.addChild(new JoinGroupNode());
     * 
* and if you need to add things to the child, then the pattern becomes: *
     * final JoinGroupNode parent = new JoinGroupNode();
     * final JoinGroupNode child1 = new JoinGroupNode()
     * parent.addChild(child1);
     * child1.addChild(...);
     * 
*/ public JoinGroupNode(final JoinGroupNode op) { super(op); } /** * Required shallow copy constructor. */ public JoinGroupNode(final BOp[] args, final Map anns) { super(args, anns); } /** * Construct a non-optional join group. */ public JoinGroupNode() { super(); } /** * Construct a non-optional join group having the specified child as its * initial member. */ public JoinGroupNode(final IGroupMemberNode child) { super(); addChild(child); } public JoinGroupNode(final boolean optional) { super(); setOptional(optional); } /** * Construct a possibly optional group having the specified child as its * initial member. * * @param optional * true iff the group is optional. * @param child * The initial child. */ public JoinGroupNode(final boolean optional, final IGroupMemberNode child) { super(); setOptional(optional); addChild(child); } /** * Construct a GRAPH group having the specified child as its initial member. * * @param context * The variable or constant for the GRAPH group. * @param child * The initial child. */ public JoinGroupNode(final TermNode context, final IGroupMemberNode child) { super(); setContext(context); addChild(child); } /** * Set the context for a GroupGraphPattern. * * @param context * The context (may be null). */ public void setContext(final TermNode context) { setProperty(Annotations.CONTEXT, context); } /** * {@inheritDoc} *

* Overridden to return the context associated with this * {@link JoinGroupNode} if it is defined and otherwise read up the parent * chain. */ @Override public TermNode getContext() { final TermNode context = (TermNode) getProperty(Annotations.CONTEXT); if (context != null) return context; // Note: the base class will test the parent. return super.getContext(); } @Override final public boolean isOptional() { return getProperty(Annotations.OPTIONAL, Annotations.DEFAULT_OPTIONAL); } final public void setOptional(final boolean optional) { setProperty(Annotations.OPTIONAL, optional); } @Override final public boolean isMinus() { return getProperty(Annotations.MINUS, Annotations.DEFAULT_MINUS); } public void setMinus(final boolean minus) { setProperty(Annotations.MINUS, minus); } /** * Returns the property {@link Annotations#IS_SUBGROUP_OF_ALP_NODE} of this * {@link JoinGroupNode}. */ final public boolean isSubgroupOfALPNode() { return getProperty(Annotations.IS_SUBGROUP_OF_ALP_NODE, Annotations.DEFAULT_IS_SUBGROUP_OF_ALP_NODE); } final public void setSubgroupOfALPNode( final boolean isSubgroup ) { setProperty(Annotations.IS_SUBGROUP_OF_ALP_NODE, isSubgroup); } /** * Return the {@link QueryOptimizerEnum} that is in effect for this * {@link JoinGroupNode}. This will be the value specified through * {@link QueryHints#OPTIMIZER} and otherwise the default value given by * {@link QueryHints#DEFAULT_OPTIMIZER}. * * @return The effective query optimizer for this join group. */ final public QueryOptimizerEnum getQueryOptimizer() { return getProperty(Annotations.OPTIMIZER, QueryHints.DEFAULT_OPTIMIZER); } /** * Return only the statement pattern child nodes in this group. */ public List getStatementPatterns() { return getChildren(StatementPatternNode.class); } /** * Return the #of statement patterns. */ public int getStatementPatternCount() { int n = 0; for (IQueryNode node : this) { if (node instanceof StatementPatternNode) { n++; } } return n; } /** * Return the #of required statement patterns (does not include those * flagged as OPTIONAL). */ public int getRequiredStatementPatternCount() { int n = 0; for (IQueryNode node : this) { if (node instanceof StatementPatternNode) { if(!((StatementPatternNode)node).isOptional()) { n++; } } } return n; } /** * Return only the {@link ServiceNode} child nodes in this group. */ public List getServiceNodes() { return getChildren(ServiceNode.class); } /** * Return only the {@link NamedSubqueryInclude} child nodes in this group. */ public List getNamedSubqueryIncludes() { return getChildren(NamedSubqueryInclude.class); } /** * Return any LET x:= expr or (expr AS ?x) nodes * in this group (these are modeled in exactly the same way by the * AST {@link AssignmentNode}). *

* Note: {@link AssignmentNode}s MUST NOT be reordered. They MUST be * evaluated left-to-right in the order given in the original query. */ public List getAssignments(){ return getChildren(AssignmentNode.class); } /** * Return only the filter child nodes in this group. */ public List getAllFiltersInGroup() { return getChildren(FilterNode.class); } /** * Return the set of IN filters for this group. * * FIXME We need to move away from the DataSetJoin class and replace it with * an IPredicate to which we have attached an inline access path. That * transformation needs to happen in a rewrite rule, which means that we * will wind up removing the IN filter and replacing it with an AST node for * that inline AP (something conceptually similar to a statement pattern but * for a column projection of the variable for the IN expression). That way * we do not have to magically "subtract" the known "IN" filters out of the * join- and post- filters. * * @see https://sourceforge.net/apps/trac/bigdata/ticket/233 (Replace * DataSetJoin with an "inline" access path.) */ public List getInFilters() { final List filters = new LinkedList(); for (IQueryNode node : this) { if (!(node instanceof FilterNode)) continue; /* * FIXME The "data set join" hack can be enabled by making this * [true]. I have it disabled for the moment since I am in the * middle of changing all of this static analysis stuff. * * Note: You will also have to modify the join- and post- filter * methods in the StaticAnalysis class for this to work. They need * to subtract out the IN filters if they have already been applied. */ if (false) { final FilterNode filter = (FilterNode) node; if (filter.getValueExpression() instanceof InBOp) { if (((InBOp) filter.getValueExpression()) .getValueExpression() instanceof IVariable) { filters.add(filter); } } } } return filters; } public List getReorderableChildren() { final List nodes = getChildren(IReorderableNode.class); final Iterator it = nodes.iterator(); while (it.hasNext()) { final IReorderableNode node = it.next(); if (ASTStaticJoinOptimizer.log.isDebugEnabled()) { ASTStaticJoinOptimizer.log.debug(node); ASTStaticJoinOptimizer.log.debug(node.isReorderable()); } if (!node.isReorderable()) { it.remove(); } } return nodes; } /* * Note: I took this out and put a simpler version of toString(indent) into * the base class. The multiple passes over the AST when rendering it into * a String were hiding order differences within the group node which were * making it difficult to identify test failures. The filters also make it * likely that we were failing to show some children of the AST because they * did not match any of the tested interfaces. * * BBT 8/30/2011 */ // public String toString(final int indent) { // .... // } @Override public Set> getRequiredBound(StaticAnalysis sa) { final Set> requiredBound = new HashSet>(); for (IGroupMemberNode child : getChildren()) { requiredBound.addAll(child.getRequiredBound(sa)); } return requiredBound; } @Override public Set> getDesiredBound(StaticAnalysis sa) { final Set> desiredBound = new HashSet>(); for (IGroupMemberNode child : getChildren()) { desiredBound.addAll(child.getDesiredBound(sa)); } return desiredBound; } }