/** 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 */ /* * Created on Sep 15, 2011 */ package com.bigdata.rdf.sparql.ast.optimizers; import com.bigdata.bop.BOpContextBase; import com.bigdata.bop.BOpUtility; import com.bigdata.bop.IBindingSet; import com.bigdata.rdf.sparql.ast.AssignmentNode; import com.bigdata.rdf.sparql.ast.ConstantNode; import com.bigdata.rdf.sparql.ast.FilterNode; import com.bigdata.rdf.sparql.ast.FunctionNode; import com.bigdata.rdf.sparql.ast.GlobalAnnotations; import com.bigdata.rdf.sparql.ast.HavingNode; import com.bigdata.rdf.sparql.ast.IQueryNode; import com.bigdata.rdf.sparql.ast.IValueExpressionNode; import com.bigdata.rdf.sparql.ast.IValueExpressionNodeContainer; import com.bigdata.rdf.sparql.ast.OrderByExpr; import com.bigdata.rdf.sparql.ast.QueryNodeWithBindingSet; import com.bigdata.rdf.sparql.ast.QueryRoot; import com.bigdata.rdf.sparql.ast.RangeNode; import com.bigdata.rdf.sparql.ast.StatementPatternNode; import com.bigdata.rdf.sparql.ast.VarNode; import com.bigdata.rdf.sparql.ast.eval.AST2BOpContext; import com.bigdata.rdf.sparql.ast.eval.AST2BOpUtility; import cutthecrap.utils.striterators.Filter; import cutthecrap.utils.striterators.IStriterator; import cutthecrap.utils.striterators.Striterator; /** * Visit all the value expression nodes and convert them into value expressions * using {@link AST2BOpUtility#toVE(String, IValueExpressionNode)}. If a value * expression can be evaluated to a constant, then it is replaced by that * constant. * <p> * Note: <code>toVE()</code> is a NOP for {@link VarNode}s and * {@link ConstantNode}s. In fact, in only acts on the value expression of an * {@link AssignmentNode} and {@link FunctionNode}s. * <p> * Note: This has to be done carefully to avoid a side-effect during traversal. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id: ASTSetValueExpressionsOptimizer.java 5193 2011-09-15 14:18:56Z * thompsonbry $ */ public class ASTSetValueExpressionsOptimizer implements IASTOptimizer { /** * */ public ASTSetValueExpressionsOptimizer() { } @Override public QueryNodeWithBindingSet optimize( final AST2BOpContext context, final QueryNodeWithBindingSet input) { final IQueryNode queryNode = input.getQueryNode(); final IBindingSet[] bindingSets = input.getBindingSets(); final QueryRoot query = (QueryRoot) queryNode; final GlobalAnnotations globals = new GlobalAnnotations( context.getLexiconNamespace(), context.getTimestamp() ); // final String lex = context.db.getLexiconRelation().getNamespace(); // convert1(lex, query); // Works around a concurrent modification. convert2(context.context, globals, query); // Should be faster. return new QueryNodeWithBindingSet(query, bindingSets); } // /** // * Original version caches to avoid side-effects and visits all VENs both // * explicitly and recursively through toVE(). // */ // private void convert1(final String lex, final QueryRoot query) { // // final Iterator<IValueExpressionNode> it = BOpUtility.visitAll(query, // IValueExpressionNode.class); // // final ArrayList<IValueExpressionNode> allNodes = new ArrayList<IValueExpressionNode>(); // // while (it.hasNext()) { // // allNodes.add(it.next()); // // } // // for (IValueExpressionNode ven : allNodes) { // // /* // * Convert and cache the value expression on the node as a // * side-effect. // */ // // AST2BOpUtility.toVE(lex, ven); // // } // // } /** * "Optimized" version visits only the nodes in the AST which can have VENs * and then invokes toVE() only for each top-level VEN. This works out to be * just {@link AssignmentNode}s, {@link FilterNode}s, and * {@link OrderByExpr}s. All of those are marked by the * {@link IValueExpressionNodeContainer} interface. * * @param lex * @param query */ private void convert2(final BOpContextBase context, final GlobalAnnotations globals, final QueryRoot query) { /* * Visit nodes that require modification. */ final IStriterator it = new Striterator( BOpUtility.preOrderIteratorWithAnnotations(query)) .addFilter(new Filter() { private static final long serialVersionUID = 1L; @Override public boolean isValid(Object obj) { // if (obj instanceof AssignmentNode) // return true; // if (obj instanceof FilterNode) // return true; // if (obj instanceof OrderByExpr) // return true; if (obj instanceof IValueExpressionNodeContainer) return true; if (obj instanceof HavingNode) return true; if (obj instanceof StatementPatternNode) return true; return false; } }); // final Iterator<IValueExpressionNodeContainer> it = BOpUtility.visitAll( // query, IValueExpressionNodeContainer.class); while (it.hasNext()) { /* * Convert and cache the value expression on the node as a * side-effect. * * PROJECT's BIND()s (ALL projections, anywhere in the query * including subqueries and named subqueries). * * BIND() in GROUP BY, HAVING. * * FILTER()/BIND() in groups (ALL groups, anywhere in the query, including * EXISTS and SERVICE). * * HAVING : its children are top-level IValueExpressionNodes. */ final Object op = it.next(); if (op instanceof IValueExpressionNodeContainer) { // AssignmentNode, FilterNode, OrderByExpr AST2BOpUtility.toVE(context, globals, ((IValueExpressionNodeContainer) op).getValueExpressionNode()); } else if (op instanceof HavingNode) { final HavingNode havingNode = (HavingNode)op; for(IValueExpressionNode node : havingNode) { AST2BOpUtility.toVE(context, globals, node); } } else if (op instanceof StatementPatternNode) { final StatementPatternNode sp = (StatementPatternNode) op; final RangeNode range = sp.getRange(); if (range != null) { if (range.from() != null) AST2BOpUtility.toVE(context, globals, range.from()); if (range.to() != null) AST2BOpUtility.toVE(context, globals, range.to()); } } // if(op instanceof AssignmentNode) { // // AssignmentNode bind = (AssignmentNode) op; // // AST2BOpUtility.toVE(lex, bind.getValueExpressionNode()); // // } else if(op instanceof FilterNode) { // // final FilterNode filter = (FilterNode) op; // // AST2BOpUtility.toVE(lex, // filter.getValueExpressionNode()); // // } else if(op instanceof OrderByExpr) { // // final OrderByExpr orderBy = (OrderByExpr) op; // // AST2BOpUtility.toVE(lex, // orderBy.getValueExpressionNode()); // // } else { // // throw new AssertionError(op.toString()); // // } } } }