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

com.bigdata.rdf.sparql.ast.TestStaticAnalysis Maven / Gradle / Ivy

There is a newer version: 2.1.4
Show newest version
/**

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.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;

import org.apache.log4j.Logger;
import org.openrdf.model.impl.LiteralImpl;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.query.MalformedQueryException;
import org.openrdf.query.algebra.StatementPattern.Scope;

import com.bigdata.bop.BOpUtility;
import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.IVariable;
import com.bigdata.bop.Var;
import com.bigdata.rdf.internal.IV;
import com.bigdata.rdf.internal.XSD;
import com.bigdata.rdf.sail.sparql.Bigdata2ASTSPARQLParser;
import com.bigdata.rdf.sparql.ast.eval.AST2BOpContext;
import com.bigdata.rdf.sparql.ast.eval.ASTSearchOptimizer;
import com.bigdata.rdf.sparql.ast.optimizers.ASTBottomUpOptimizer;
import com.bigdata.rdf.sparql.ast.optimizers.ASTSetValueExpressionsOptimizer;
import com.bigdata.rdf.sparql.ast.optimizers.ASTSubGroupJoinVarOptimizer;
import com.bigdata.rdf.sparql.ast.optimizers.ASTWildcardProjectionOptimizer;
import com.bigdata.rdf.sparql.ast.optimizers.IASTOptimizer;
import com.bigdata.rdf.sparql.ast.service.ServiceNode;
import com.bigdata.rdf.vocab.decls.FOAFVocabularyDecl;

/**
 * Test suite for methods supporting static analysis of the variables, including
 * whether a variable MUST be bound, MIGHT be bound, or is NOT bound. The static
 * analysis centers around {@link GraphPatternGroup}s. Methods are provided for
 * both the group itself, the group and its parent groups, and the group and its
 * child groups.
 * 

* Note: The static analysis depends on the AST as generated from the parse tree * or as rewritten by one or more {@link IASTOptimizer}s. Most tests do not run * the {@link IASTOptimizer}s because we want to analyze the AST as generated * from the parse tree rather than the AST as optimized by the suite of * optimizers. In many cases, actually running the suite of optimizers will * cause some structures to be pruned from the AST. This is especially true of * the unit tests for the static analysis of the TCK queries, many of which use * variables in filters when the variables are not bound in that scope or use a * "badly designed left join" pattern. * * TODO If we modify the methods which report on the must/may bindings to look * for null IVs, then we will need to add the URIs appearing in the query to the * database before we run the parser. * * @author Bryan Thompson * @version $Id$ */ public class TestStaticAnalysis extends AbstractASTEvaluationTestCase { private final static Logger log = Logger .getLogger(TestStaticAnalysis.class); /** * */ public TestStaticAnalysis() { } /** * @param arg0 */ public TestStaticAnalysis(String arg0) { super(arg0); } private static final Set> EMPTY_SET = Collections.emptySet(); /** * Unit test of static analysis for variables which must be bound by a * query. This involves checking the WHERE clause and the projection for the * query. * * @throws MalformedQueryException */ public void test_static_analysis01() throws MalformedQueryException { final String queryStr = "" + "PREFIX rdf: \n"+ "PREFIX rdfs: \n"+ "PREFIX foaf: \n"+ "select ?x where { ?x rdf:type foaf:Person }"; final QueryRoot queryRoot = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI).getOriginalAST(); final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> expected = new LinkedHashSet>(); expected.add(Var.var("x")); assertEquals(expected, sa.getDefinitelyProducedBindings(queryRoot)); assertEquals( expected, sa.getDefinitelyProducedBindings(queryRoot.getWhereClause(), new LinkedHashSet>(), true/* recursive */)); } /** * Unit test of static analysis for variables which must be bound by a * query. This involves checking the WHERE clause and the projection for the * query. In this case, a constant is projected out of the query in addition * to the bindings produced by the WHERE clause. * * @throws MalformedQueryException */ public void test_static_analysis02() throws MalformedQueryException { final String queryStr = "" + "PREFIX rdf: \n"+ "PREFIX rdfs: \n"+ "PREFIX foaf: \n"+ "select ?x (12 as ?y) where { ?x rdf:type foaf:Person }"; final QueryRoot queryRoot = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI).getOriginalAST(); final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> expectedProjected = new LinkedHashSet>(); expectedProjected.add(Var.var("x")); expectedProjected.add(Var.var("y")); assertEquals(expectedProjected, sa.getDefinitelyProducedBindings(queryRoot)); final Set> expectedWhereClause = new LinkedHashSet>(); expectedWhereClause.add(Var.var("x")); assertEquals( expectedWhereClause, sa.getDefinitelyProducedBindings(queryRoot.getWhereClause(), new LinkedHashSet>(), true/* recursive */)); } /** * Unit test of static analysis for variables with a named subquery. This * test verifies that we observe the variables projected by the subquery, * but not those which it uses internally. * * @throws MalformedQueryException */ public void test_static_analysis03() throws MalformedQueryException { final String queryStr = "" + "PREFIX rdf: \n"+ "PREFIX rdfs: \n"+ "PREFIX foaf: \n"+ "select ?x (12 as ?y)\n" + " with \n{" + " select ?x {\n" + " ?x rdf:type foaf:Person .\n" + " ?x rdfs:label ?y .\n" + " }\n" + " } as %namedSet1 \n"+ " where {\n" + " include %namedSet1\n" + "}"; final QueryRoot queryRoot = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI).getOriginalAST(); final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> expectedProjected = new LinkedHashSet>(); expectedProjected.add(Var.var("x")); expectedProjected.add(Var.var("y")); assertEquals(expectedProjected, sa.getDefinitelyProducedBindings(queryRoot)); final Set> expectedWhereClause = new LinkedHashSet>(); expectedWhereClause.add(Var.var("x")); assertEquals( expectedWhereClause, sa.getDefinitelyProducedBindings(queryRoot.getWhereClause(), new LinkedHashSet>(), true/* recursive */)); } /** * Unit test of static analysis for variables with a SPARQL 1.1 subquery. * This test verifies that we observe the variables projected by the * subquery, but not those which it uses internally. * * @throws MalformedQueryException */ public void test_static_analysis04() throws MalformedQueryException { final String queryStr = "" + "PREFIX rdf: \n"+ "PREFIX rdfs: \n"+ "PREFIX foaf: \n"+ "select ?x (12 as ?y)\n" + " where {\n" + " ?q foaf:knows ?p ." + " {\n" + " select ?x {\n" + " ?x rdf:type foaf:Person .\n" + " ?x rdfs:label ?z .\n" + " }\n" + " }\n" + "}"; final QueryRoot queryRoot = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI).getOriginalAST(); final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> expectedProjected = new LinkedHashSet>(); expectedProjected.add(Var.var("x")); expectedProjected.add(Var.var("y")); assertEquals(expectedProjected, sa.getDefinitelyProducedBindings(queryRoot)); final Set> expectedWhereClause = new LinkedHashSet>(); expectedWhereClause.add(Var.var("x")); expectedWhereClause.add(Var.var("p")); expectedWhereClause.add(Var.var("q")); assertEquals( expectedWhereClause, sa.getDefinitelyProducedBindings(queryRoot.getWhereClause(), new LinkedHashSet>(), true/* recursive */)); } /** * Unit test of static analysis for a SERVICE call. * * @see Wildcard projection * ignores variables inside a SERVICE call */ public void test_static_analysis05() throws MalformedQueryException { final String queryStr = "" + "PREFIX rdf: \n"+ "PREFIX rdfs: \n"+ "PREFIX foaf: \n"+ "select ?x (12 as ?y)\n" + " where {\n" + " service ?uri {\n" + " ?x rdf:type foaf:Person .\n" + " ?x rdfs:label ?z .\n" + " }\n" + "}"; final QueryRoot queryRoot = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI).getOriginalAST(); final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> expectedProjected = new LinkedHashSet>(); expectedProjected.add(Var.var("x")); expectedProjected.add(Var.var("y")); assertEquals(expectedProjected, sa.getDefinitelyProducedBindings(queryRoot)); // The spanned variables includes the SERVICE URI (if it is a variable). { final Set> expectedWhereClause = new LinkedHashSet>(); expectedWhereClause.add(Var.var("uri")); expectedWhereClause.add(Var.var("x")); expectedWhereClause.add(Var.var("z")); assertEquals(expectedWhereClause, sa.getSpannedVariables( queryRoot.getWhereClause(), new LinkedHashSet>())); } // The definitely bound variables does NOT include the SERVICE URI. When // that is a variable it needs to become bound through other means. { final Set> expectedWhereClause = new LinkedHashSet>(); expectedWhereClause.add(Var.var("x")); expectedWhereClause.add(Var.var("z")); assertEquals(expectedWhereClause, sa.getDefinitelyProducedBindings( queryRoot.getWhereClause(), new LinkedHashSet>(), true/* recursive */)); } } /** * Unit test for computing the join variables for a named subquery based on * the analysis of the bindings which MUST be produced by the subquery and * those which MUST be bound on entry into the group in which the subquery * solution set is included within the main query. *

* Note: The join should be on ?x in this example. * * FIXME Write more unit tests for * {@link StaticAnalysis#getJoinVars(SubqueryRoot, Set)} and friends. */ public void test_static_analysis_join_vars() throws MalformedQueryException { final String queryStr = "" + "PREFIX rdf: \n"+ "PREFIX rdfs: \n"+ "PREFIX foaf: \n"+ "select ?x ?o \n"+ " with {"+ " select ?x where { ?x rdf:type foaf:Person }\n"+ " } AS %namedSet1 \n"+ "where { \n" + " ?x rdfs:label ?o \n" + " INCLUDE %namedSet1 \n"+ "}"; final QueryRoot queryRoot = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI).getOriginalAST(); final StaticAnalysis sa = new StaticAnalysis(queryRoot); // variables which must be bound in the top-level query's projection. { final Set> expectedProjected = new LinkedHashSet>(); expectedProjected.add(Var.var("x")); expectedProjected.add(Var.var("o")); assertEquals(expectedProjected, sa.getDefinitelyProducedBindings(queryRoot)); } // variables which must be bound in the named subquery's projection. { final Set> expectedProjected = new LinkedHashSet>(); expectedProjected.add(Var.var("x")); final NamedSubqueryRoot namedSubquery = (NamedSubqueryRoot) queryRoot .getNamedSubqueries().get(0); assertEquals(expectedProjected, sa.getDefinitelyProducedBindings(namedSubquery)); } // variables which must be bound in the main query's where clause. { final Set> expectedWhereClause = new LinkedHashSet>(); expectedWhereClause.add(Var.var("x")); expectedWhereClause.add(Var.var("o")); assertEquals(expectedWhereClause, sa.getDefinitelyProducedBindings( queryRoot.getWhereClause(), new LinkedHashSet>(), true/* recursive */)); } // the join variables as reported by static analysis. { final Set> expectedJoinVars = new LinkedHashSet>(); expectedJoinVars.add(Var.var("x")); final NamedSubqueryRoot namedSubquery = (NamedSubqueryRoot) queryRoot .getNamedSubqueries().get(0); final NamedSubqueryInclude anInclude = BOpUtility.visitAll( queryRoot, NamedSubqueryInclude.class).next(); final Set> vars = sa.getJoinVars(namedSubquery, anInclude, new LinkedHashSet>()); assertEquals(expectedJoinVars, vars); } } /** * Static analysis of TCK query: * *

     * PREFIX : 
     * 
     * SELECT ?v { :x :p ?v . FILTER(?v = 1)
     * 
* * This query does not present a problem since ?v is in scope * when the filter is evaluated. */ public void test_static_analysis_filter_nested_1() throws MalformedQueryException { final String queryStr = "" + // "PREFIX : \n" + // "SELECT ?v \n" +// "{ :x :p ?v . FILTER(?v = 1) }"; final QueryRoot queryRoot = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI).getOriginalAST(); final StaticAnalysis sa = new StaticAnalysis(queryRoot); @SuppressWarnings("unchecked") final GraphPatternGroup whereClause = queryRoot .getWhereClause(); final Set> expected = asSet(new String[]{"v"}); // Test "must" bound bindings for the query. assertEquals(expected, sa.getDefinitelyProducedBindings(queryRoot)); // Test "must" bound bindings for the where clause. assertEquals(expected, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); // Test "maybe" bound bindings for the where clause. assertEquals(expected, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); // Test "incoming" bindings for the where clause. assertEquals(EMPTY_SET, sa.getDefinitelyIncomingBindings(whereClause, new LinkedHashSet>())); } /** * Static analysis of TCK query: * *
     * PREFIX :  
     * 
     * SELECT ?v
     * { :x :p ?v . { FILTER(?v = 1) } }
     * 
* * ?v is not bound in the FILTER because it is evaluated with * bottom up semantics and therefore the bindings from the parent group are * not visible. */ public void test_static_analysis_filter_nested_2() throws MalformedQueryException { final String queryStr = "" + // "PREFIX : \n" + // "SELECT ?v \n" +// "{ :x :p ?v . { FILTER(?v = 1) } }"; final ASTContainer astContainer = new Bigdata2ASTSPARQLParser().parseQuery2( queryStr, baseURI); final AST2BOpContext context = new AST2BOpContext(astContainer, store); QueryRoot queryRoot = astContainer.getOriginalAST(); // Set the IValueExpressions on the AST. queryRoot = (QueryRoot) new ASTSetValueExpressionsOptimizer().optimize( context, new QueryNodeWithBindingSet(queryRoot, null)).getQueryNode(); if (log.isInfoEnabled()) log.info("\nqueryStr=\n" + queryStr + "\nAST:\n" + BOpUtility.toString(queryRoot)); final StaticAnalysis sa = new StaticAnalysis(queryRoot); // Test "must" bound bindings for the query. assertEquals(asSet(new String[] { "v" }), sa.getDefinitelyProducedBindings(queryRoot)); // WHERE clause { @SuppressWarnings("unchecked") final GraphPatternGroup whereClause = queryRoot .getWhereClause(); final Set> expected = asSet(new String[] { "v" }); // Test "incoming" bindings for the where clause. assertEquals(EMPTY_SET, sa.getDefinitelyIncomingBindings(whereClause, new LinkedHashSet>())); // Test "must" bound bindings for the where clause. assertEquals(expected, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); // Test "maybe" bound bindings for the where clause. assertEquals(expected, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } // FILTER's group clause. { final JoinGroupNode filterClause = (JoinGroupNode) queryRoot .getWhereClause().get(1); // Test "incoming" bindings. assertEquals(asSet(new String[] { "v" }), sa.getDefinitelyIncomingBindings( filterClause, new LinkedHashSet>())); // Test "must" bound bindings. assertEquals( EMPTY_SET, sa.getDefinitelyProducedBindings(filterClause, new LinkedHashSet>(), true/* recursive */)); // Test "maybe" bound bindings. assertEquals(EMPTY_SET, sa.getMaybeProducedBindings(filterClause, new LinkedHashSet>(), true/* recursive */)); // The FILTER node itself. final FilterNode filter = BOpUtility.visitAll(queryRoot, FilterNode.class).next(); assertEquals(Collections.singletonList(filter), sa.getPreFilters(filterClause)); assertEquals(Collections.emptyList(), sa.getJoinFilters(filterClause)); assertEquals(Collections.emptyList(), sa.getPostFilters(filterClause)); assertEquals(Collections.emptyList(), sa.getPruneFilters(filterClause)); } } /** * Static analysis of TCK query: * *
     * PREFIX :    
     * 
     * SELECT *
     * { 
     *     :x :p ?v . 
     *     { :x :q ?w 
     *       OPTIONAL {  :x :p ?v2 FILTER(?v = 1) }
     *     }
     * }
     * 
* * ?v is bound in the outer join group. *

* ?w is bound in the child join group regardless of whether * the embedded optional succeeds. *

* ?v is not bound in the FILTER because it is evaluated with * bottom up semantics and therefore the bindings from the outer parent * group are not visible. *

* For reference, the AST for that SPARQL query is: * *

     * PREFIX : 
     * QueryType: SELECT
     * SELECT * 
     *   JoinGroupNode {
     *     StatementPatternNode(ConstantNode(TermId(0U)[http://example/x]), ConstantNode(TermId(0U)[http://example/p]), VarNode(v), DEFAULT_CONTEXTS)
     *     JoinGroupNode {
     *       StatementPatternNode(ConstantNode(TermId(0U)[http://example/x]), ConstantNode(TermId(0U)[http://example/q]), VarNode(w), DEFAULT_CONTEXTS)
     *       JoinGroupNode [optional] {
     *         StatementPatternNode(ConstantNode(TermId(0U)[http://example/x]), ConstantNode(TermId(0U)[http://example/p]), VarNode(v2), DEFAULT_CONTEXTS)
     *         FILTER( com.bigdata.rdf.sparql.ast.FunctionNode(VarNode(v),ConstantNode(XSDInteger(1)))[ com.bigdata.rdf.sparql.ast.FunctionNode.functionURI=http://www.w3.org/2005/xpath-functions#equal-to] )
     *       }
     *     }
     *   }
     * 
* * This can be reduced to a filter which does not bind anything. Since the * FILTER can not succeed, it should logically be replaced by failing the * group(s) within which it appears. This needs to be done recursively up to * the parent, stopping at the first parent group which is optional. If all * parents up to the WHERE clause are eliminated, then the WHERE clause * itself can not succeed and the query should be replaced by a * "DropSolutionsBOp". The DropSolutionsOp can be substituted in directly * for a group which can not succeed and then we can work the pruning of the * parents as an efficiency. *

* Note: An AST optimizer needs to recognize and transform this query by * lifting out * *

     *  :x :q ?w OPTIONAL {  :x :p ?v2 FILTER(?v = 1) }
     * 
* * into a named subquery. Since the named subquery runs without any incoming * bindings, the result will be as if we had used bottom up evaluation. * * @see ASTBottomUpOptimizer */ public void test_static_analysis_filter_scope_1() throws MalformedQueryException { final String queryStr = "" + // "PREFIX : \n" + // "SELECT * \n" + // "{ \n" + // " :x :p ?v . \n" + // " { :x :q ?w \n" + // " OPTIONAL { :x :p ?v2 FILTER(?v = 1) } \n" + // " } \n" + // "}"// ; final ASTContainer astContainer = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI); final AST2BOpContext context = new AST2BOpContext(astContainer, store); QueryRoot queryRoot = astContainer.getOriginalAST(); // Set the IValueExpressions on the AST. queryRoot = (QueryRoot) new ASTSetValueExpressionsOptimizer().optimize( context, new QueryNodeWithBindingSet(queryRoot, null)).getQueryNode(); // Rewrite the wild card in the projection. queryRoot = (QueryRoot) new ASTWildcardProjectionOptimizer().optimize( context, new QueryNodeWithBindingSet(queryRoot, null)).getQueryNode(); if (log.isInfoEnabled()) log.info("\nqueryStr=\n" + queryStr + "\nAST:\n" + BOpUtility.toString(queryRoot)); final StaticAnalysis sa = new StaticAnalysis(queryRoot); // Test "must" bound bindings for the query. assertEquals(asSet(new String[] { "v", "w" }), sa.getDefinitelyProducedBindings(queryRoot)); // Outer group clause { :x :p ?v . } { final GraphPatternGroup group = (JoinGroupNode) queryRoot .getWhereClause(); // Test "incoming" bindings. assertEquals(EMPTY_SET, sa.getDefinitelyIncomingBindings(group, new LinkedHashSet>())); // Test "must" bound bindings. assertEquals( asSet(new String[] { "v" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "must" bound bindings (recursive). assertEquals( asSet(new String[] { "v", "w" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); // Test "maybe" bound bindings. assertEquals( asSet(new String[] { "v" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "maybe" bound bindings (recursive). assertEquals( asSet(new String[] { "v", "w", "v2" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); } // Nested group clause { :x :q ?w } { final GraphPatternGroup group = (JoinGroupNode) queryRoot .getWhereClause().get(1); // Test "incoming" bindings. assertEquals( asSet(new String[] { "v" }), sa.getDefinitelyIncomingBindings(group,new LinkedHashSet>())); // Test "must" bound bindings. assertEquals( asSet(new String[] { "w" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "must" bound bindings (recursive). assertEquals( asSet(new String[] { "w" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); // Test "maybe" bound bindings. assertEquals( asSet(new String[] { "w" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "maybe" bound bindings (recursive). assertEquals( asSet(new String[] { "w", "v2" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); } // Optional group clause { :x :p ?v2 FILTER(?v = 1) } { final JoinGroupNode group = (JoinGroupNode) queryRoot .getWhereClause().get(1).get(1); sa.getDefinitelyIncomingBindings(group,new LinkedHashSet>()); // Test "incoming" bindings. assertEquals( asSet(new String[] { "v", "w" }), sa.getDefinitelyIncomingBindings(group,new LinkedHashSet>())); // Test "must" bound bindings. assertEquals( asSet(new String[] { "v2" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "must" bound bindings (recursive). assertEquals( asSet(new String[] { "v2" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); // Test "maybe" bound bindings. assertEquals( asSet(new String[] { "v2" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "maybe" bound bindings (recursive). assertEquals( asSet(new String[] { "v2" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); // The FILTER node itself. final FilterNode filter = BOpUtility.visitAll(queryRoot, FilterNode.class).next(); assertEquals(Collections.singletonList(filter), sa.getPreFilters(group)); assertEquals(Collections.emptyList(), sa.getJoinFilters(group)); assertEquals(Collections.emptyList(), sa.getPostFilters(group)); assertEquals(Collections.emptyList(), sa.getPruneFilters(group)); } } /** * Join-scope - 1 (aka var-scope-join-1). * *
     * PREFIX : 
     * 
     * SELECT *
     * { 
     *   ?X  :name "paul"
     *   {?Y :name "george" . OPTIONAL { ?X :email ?Z } }
     * }
     * 
*

* Note: For this query, the bindings of ?X in the outer group * are not visible when the inner groups are evaluated. Because of this, * ?X in the optional clause binds for values which differ from * the values bound on ?X in the outer group. This means that * the solutions from the middle group with bindings for ?Y and * ?X fail to join with the solutions in the outer group. Note * that there is no email address for "paul" for the data set used to run * this query. If there were, then the query would have a result. *

* These group expressions need to be evaluated independently because they * are not sharing a binding for ?X until we join them together * on ?X. *

* In order for us to run this query correctly we need to run * *

     * {?Y :name "george" . OPTIONAL { ?X :email ?Z } }
     * 
* * BEFORE * *
     * ?X  :name "paul"
     * 
* * This can be most easily achieved by lifting the former out into a named * subquery. * * @see ASTBottomUpOptimizer */ public void test_static_analysis_join_scope_1() throws MalformedQueryException { final String queryStr = "" + // "PREFIX : \n" + // "SELECT * \n" + // "{ \n" + // " ?X :name \"paul\" . \n" + // " {?Y :name \"george\" . OPTIONAL { ?X :email ?Z } } \n" + // "}"// ; final ASTContainer astContainer = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI); final AST2BOpContext context = new AST2BOpContext(astContainer, store); QueryRoot queryRoot = astContainer.getOriginalAST(); // Rewrite the wild card in the projection. queryRoot = (QueryRoot) new ASTWildcardProjectionOptimizer().optimize( context, new QueryNodeWithBindingSet(queryRoot, null)).getQueryNode(); if (log.isInfoEnabled()) log.info("\nqueryStr=\n" + queryStr + "\nAST:\n" + BOpUtility.toString(queryRoot)); final StaticAnalysis sa = new StaticAnalysis(queryRoot); // Test "must" bound bindings for the query. assertEquals(asSet(new String[] { "X", "Y" }), sa.getDefinitelyProducedBindings(queryRoot)); // Outer group clause { ?X :name "paul" } { final GraphPatternGroup group = (JoinGroupNode) queryRoot .getWhereClause(); // Test "incoming" bindings. assertEquals( EMPTY_SET, sa.getDefinitelyIncomingBindings(group,new LinkedHashSet>())); // Test "must" bound bindings. assertEquals( asSet(new String[] { "X" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "must" bound bindings (recursive). assertEquals( asSet(new String[] { "X", "Y" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); // Test "maybe" bound bindings. assertEquals( asSet(new String[] { "X" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "maybe" bound bindings (recursive). assertEquals( asSet(new String[] { "X", "Y", "Z" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); } // Nested group clause { ?Y :name "george" } { final GraphPatternGroup group = (JoinGroupNode) queryRoot .getWhereClause().get(1); // Test "incoming" bindings. assertEquals( asSet(new String[] { "X" }), sa.getDefinitelyIncomingBindings(group,new LinkedHashSet>())); // Test "must" bound bindings. assertEquals( asSet(new String[] { "Y" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "must" bound bindings (recursive). assertEquals( asSet(new String[] { "Y" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); // Test "maybe" bound bindings. assertEquals( asSet(new String[] { "Y" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "maybe" bound bindings (recursive). assertEquals( asSet(new String[] { "Y", "X", "Z" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); } // Optional group clause OPTIONAL { ?X :email ?Z } { final JoinGroupNode group = (JoinGroupNode) queryRoot .getWhereClause().get(1).get(1); // Test "incoming" bindings. assertEquals( asSet(new String[] { "X", "Y" }), sa.getDefinitelyIncomingBindings(group,new LinkedHashSet>())); // Test "must" bound bindings. assertEquals( asSet(new String[] { "X", "Z" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "must" bound bindings (recursive). assertEquals( asSet(new String[] { "X", "Z" }), sa.getDefinitelyProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); // Test "maybe" bound bindings. assertEquals( asSet(new String[] { "X", "Z" }), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), false/* recursive */)); // Test "maybe" bound bindings (recursive). assertEquals( asSet(new String[] { "X", "Z"}), sa.getMaybeProducedBindings(group, new LinkedHashSet>(), true/* recursive */)); } } /** * Unit test for analysis of a {@link ServiceNode}. The analysis of a * {@link ServiceNode} is just the analysis of the graph pattern reported by * {@link ServiceNode#getGraphPattern()}. * *
     * PREFIX bd: 
     * SELECT ?subj ?score 
     * WHERE {
     *   ?lit bd:search "mike" .
     *   ?lit bd:relevance ?score .
     *   ?subj ?p ?lit .
     * }
     * 
* * Note: The "be:search", "bd:relevance" and ?subj ?p ?lit * statement patterns below will be transformed into a {@link ServiceNode}. * Since there is nothing else in the main query's WHERE clause, the * {@link ServiceNode} is not lifted out into a named subquery. */ public void test_static_analysis_serviceCall() throws MalformedQueryException { final String queryStr = "" + // "PREFIX bd: \n" + // "SELECT ?subj ?score\n" + // "WHERE {\n" + // " ?lit bd:search \"mike\" .\n" + // " ?lit bd:relevance ?score .\n" + // " ?subj ?p ?lit .\n" + // "}"; final ASTContainer astContainer = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI); final AST2BOpContext context = new AST2BOpContext(astContainer, store); QueryRoot queryRoot = astContainer.getOriginalAST(); // rewrite the search predicates as an AST ServiceNode. queryRoot = (QueryRoot) new ASTSearchOptimizer().optimize( context, new QueryNodeWithBindingSet(queryRoot, null)).getQueryNode(); if (log.isInfoEnabled()) log.info("\nqueryStr=\n" + queryStr + "\nAST:\n" + BOpUtility.toString(queryRoot)); final StaticAnalysis sa = new StaticAnalysis(queryRoot); { // variables which must be bound in the top-level query's // projection. { final Set> expectedProjected = new LinkedHashSet>(); expectedProjected.add(Var.var("subj")); expectedProjected.add(Var.var("score")); assertEquals(expectedProjected, sa.getDefinitelyProducedBindings(queryRoot)); } // variables which must be bound in the main query's where clause. { final Set> expected = new LinkedHashSet>(); expected.add(Var.var("subj")); expected.add(Var.var("score")); expected.add(Var.var("p")); expected.add(Var.var("lit")); assertEquals(expected, sa.getDefinitelyProducedBindings( queryRoot.getWhereClause(), new LinkedHashSet>(), true/* recursive */)); } // variables which may be bound in the main query's where clause. { final Set> expected = new LinkedHashSet>(); expected.add(Var.var("subj")); expected.add(Var.var("score")); expected.add(Var.var("p")); expected.add(Var.var("lit")); assertEquals(expected, sa.getMaybeProducedBindings( queryRoot.getWhereClause(), new LinkedHashSet>(), true/* recursive */)); } } } /** * Test suite for predicting the join variables for a SERVICE call. * *
     * SELECT ?s ?o1 ?o2
     * {
     *   SERVICE  {
     *   ?s ?p ?o1 . }
     *   OPTIONAL {
     *     SERVICE  {
     *     ?s ?p2 ?o2 }
     *   }
     * }
     * 
*/ public void test_static_analysis_serviceCall2() throws MalformedQueryException { final String queryStr = "SELECT ?s ?o1 ?o2\n"// + "{\n"// + " SERVICE {\n"// + " ?s ?p ?o1 . }\n"// + " OPTIONAL {\n"// + " SERVICE {\n"// + " ?s ?p2 ?o2 }\n"// + " }\n"// + "}"; final ASTContainer astContainer = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI); final AST2BOpContext context = new AST2BOpContext(astContainer, store); QueryRoot queryRoot = astContainer.getOriginalAST(); // Assign join variables to join groups. queryRoot = (QueryRoot) new ASTSubGroupJoinVarOptimizer().optimize( context, new QueryNodeWithBindingSet(queryRoot, null)).getQueryNode(); if (log.isInfoEnabled()) log.info("\nqueryStr=\n" + queryStr + "\nAST:\n" + BOpUtility.toString(queryRoot)); final StaticAnalysis sa = new StaticAnalysis(queryRoot); /** * Locate the various pieces of the AST. * *
         * 
         * QueryType: SELECT
         * SELECT VarNode(s) VarNode(o1) VarNode(o2)
         *   JoinGroupNode {
         *     SERVICE  {
         *       JoinGroupNode {
         *         StatementPatternNode(VarNode(s), VarNode(p), VarNode(o1), DEFAULT_CONTEXTS)
         *       }
         *     }
         *     JoinGroupNode [optional] {
         *       SERVICE  {
         *         JoinGroupNode {
         *           StatementPatternNode(VarNode(s), VarNode(p2), VarNode(o2), DEFAULT_CONTEXTS)
         *         }
         *       }
         *     }
         *   }
         * 
*/ final GraphPatternGroup whereClause = queryRoot.getWhereClause(); final ServiceNode endpoint1; final JoinGroupNode optionalGroup; final ServiceNode endpoint2; { endpoint1 = (ServiceNode) whereClause.get(0); assertEquals(endpoint1.getServiceRef().getValue(), new URIImpl( "http://localhost:18080/openrdf/repositories/endpoint1")); optionalGroup = (JoinGroupNode) whereClause.get(1); assertTrue(optionalGroup.isOptional()); endpoint2 = (ServiceNode) optionalGroup.get(0); assertEquals(endpoint2.getServiceRef().getValue(), new URIImpl( "http://localhost:18080/openrdf/repositories/endpoint2")); // final Iterator itr = BOpUtility.visitAll( // whereClause, ServiceNode.class); // // endpoint1 = itr.next(); // // assertEquals(endpoint1.getServiceRef().getValue(), new URIImpl( // "http://localhost:18080/openrdf/repositories/endpoint1")); // // endpoint2 = itr.next(); // // assertEquals(endpoint2.getServiceRef().getValue(), new URIImpl( // "http://localhost:18080/openrdf/repositories/endpoint2")); // // assertFalse(itr.hasNext()); } { // variables which must be bound in the top-level query's // projection. { final Set> expectedProjected = new LinkedHashSet>(); expectedProjected.add(Var.var("s")); expectedProjected.add(Var.var("o1")); assertEquals(expectedProjected, sa.getDefinitelyProducedBindings(queryRoot)); } // variables which must be bound in the main query's where clause. { final Set> expected = new LinkedHashSet>(); expected.add(Var.var("s")); expected.add(Var.var("p")); expected.add(Var.var("o1")); assertEquals(expected, sa.getDefinitelyProducedBindings( queryRoot.getWhereClause(), new LinkedHashSet>(), true/* recursive */)); } // variables which may be bound in the main query's where clause. { final Set> expected = new LinkedHashSet>(); expected.add(Var.var("s")); expected.add(Var.var("p")); expected.add(Var.var("o1")); expected.add(Var.var("p2")); expected.add(Var.var("o2")); assertEquals(expected, sa.getMaybeProducedBindings( queryRoot.getWhereClause(), new LinkedHashSet>(), true/* recursive */)); } } // variables which must be bound by endpoint1. { final Set> expected = new LinkedHashSet>(); expected.add(Var.var("s")); expected.add(Var.var("p")); expected.add(Var.var("o1")); assertEquals(expected, sa.getDefinitelyProducedBindings(endpoint1, new LinkedHashSet>(), true/* recursive */)); } // variables which must be bound by endpoint2. { final Set> expected = new LinkedHashSet>(); expected.add(Var.var("s")); expected.add(Var.var("p2")); expected.add(Var.var("o2")); assertEquals(expected, sa.getDefinitelyProducedBindings(endpoint2, new LinkedHashSet>(), true/* recursive */)); } // ServiceCallJoin variables for endpoint1 { final Set> expected = new LinkedHashSet>(); assertEquals(expected, sa.getJoinVars(endpoint1, new LinkedHashSet>())); } // ServiceCallJoin variables for endpoint2 { final Set> expected = new LinkedHashSet>(); expected.add(Var.var("s")); assertEquals(expected, sa.getJoinVars(endpoint2, new LinkedHashSet>())); } // Join with the OPTIONAL group. { final Set> expected = new LinkedHashSet>(); expected.add(Var.var("s")); final Set> actual = new HashSet>(); for (IVariable v : optionalGroup.getJoinVars()) { actual.add(v); } assertEquals(expected, actual); } } /** * Unit test(s) for the correct identification of pre-, join-, post-, and * prune- filters. */ public void test_static_analysis_filters() throws MalformedQueryException { final String queryStr = ""+// "PREFIX : \n" +// "PREFIX rdf: \n"+// "PREFIX rdfs: \n"+// "PREFIX foaf: \n"+// "SELECT ?a ?b \n" +// " WHERE {\n" +// " ?a rdf:type foaf:Person . \n" +// " ?a foaf:knows ?b .\n"+// " { \n"+// " ?a :age ?ageA .\n"+// " ?b :age ?ageB .\n"+// " FILTER ( ?a != ?b ) .\n"+// pre-filter (can be lifted) " FILTER ( ?ageA > ?ageB) .\n"+// join-filter " FILTER ( ?x < 100 ) .\n"+// prune-filter (can be pruned) " }\n"+// " FILTER ( ?ageA > 20 ) .\n"+//post-filter (depends on subgroup) " "+// "}"; final ASTContainer astContainer = new Bigdata2ASTSPARQLParser() .parseQuery2(queryStr, baseURI); final AST2BOpContext context = new AST2BOpContext(astContainer, store); QueryRoot queryRoot = astContainer.getOriginalAST(); // Set the IValueExpressions on the AST. queryRoot = (QueryRoot) new ASTSetValueExpressionsOptimizer().optimize( context, new QueryNodeWithBindingSet(queryRoot, null)).getQueryNode(); if (log.isInfoEnabled()) log.info("\nqueryStr=\n" + queryStr + "\nAST:\n" + BOpUtility.toString(queryRoot)); final StaticAnalysis sa = new StaticAnalysis(queryRoot); /* * Locate the outer join group and the inner join group. */ final JoinGroupNode outerGroup; final JoinGroupNode innerGroup; { final Iterator itr = BOpUtility.visitAll( queryRoot.getWhereClause(), JoinGroupNode.class); outerGroup = itr.next(); innerGroup = itr.next(); } /* * Locate the different filters in the query. */ final FilterNode ageA_GT_ageB; final FilterNode a_NE_b; final FilterNode x_LT_10; final FilterNode ageA_GT_20; // Filters in the outer group. { FilterNode tmp = null; for(IGroupMemberNode child : outerGroup) { if(child instanceof FilterNode) { tmp = (FilterNode)child; break; } } ageA_GT_20 = tmp; } assertNotNull(ageA_GT_20); // Filters in the inner group. // " FILTER ( ?ageA > ?ageB) .\n"+// join-filter // " FILTER ( ?a != ?b ) .\n"+// pre-filter // " FILTER ( ?x < 100 ) .\n"+// prune-filter { FilterNode GT = null; FilterNode NE = null; FilterNode LT = null; for (IGroupMemberNode child : innerGroup) { if (child instanceof FilterNode) { final FilterNode tmp = (FilterNode) child; final FunctionNode expr = (FunctionNode) tmp .getValueExpressionNode(); if (expr.getFunctionURI().equals(FunctionRegistry.GT)) { GT = tmp; } else if (expr.getFunctionURI() .equals(FunctionRegistry.NE)) { NE = tmp; } else if (expr.getFunctionURI() .equals(FunctionRegistry.LT)) { LT = tmp; } else throw new AssertionError(); } } ageA_GT_ageB = GT; a_NE_b = NE; x_LT_10 = LT; } assertNotNull(ageA_GT_ageB); assertNotNull(a_NE_b); assertNotNull(x_LT_10); /* * Now verify the static analysis of the filters. */ // " FILTER ( ?ageA > ?ageB) .\n"+// join-filter // " FILTER ( ?a != ?b ) .\n"+// pre-filter // " FILTER ( ?x < 100 ) .\n"+// prune-filter // " }\n"+// // " FILTER ( ?ageA > 20 ) .\n"+//post-filter // Inner group. assertEquals("pre-filters", Collections.singletonList(a_NE_b), sa.getPreFilters(innerGroup)); assertEquals("join-filters", Collections.singletonList(ageA_GT_ageB), sa.getJoinFilters(innerGroup)); assertEquals("post-filters", Collections.singletonList(x_LT_10), sa.getPostFilters(innerGroup)); assertEquals("prune-filters", Collections.singletonList(x_LT_10), sa.getPruneFilters(innerGroup)); assertEquals("definitely-and-filters", asSet(new String[] { "a", "b", "ageA", "ageB", "x" }), sa.getDefinitelyProducedBindingsAndFilterVariables(innerGroup, new LinkedHashSet>())); // Outer group. assertEquals("pre-filters", Collections.emptyList(), sa.getPreFilters(outerGroup)); assertEquals("join-filters", Collections.emptyList(), sa.getJoinFilters(outerGroup)); assertEquals("post-filters", Collections.singletonList(ageA_GT_20), sa.getPostFilters(outerGroup)); assertEquals("prune-filters", Collections.emptyList(), sa.getPruneFilters(outerGroup)); assertEquals("definitely-and-filters", asSet(new String[] { "a", "b", "ageA" }), sa.getDefinitelyProducedBindingsAndFilterVariables(outerGroup, new LinkedHashSet>())); } /** * Unit test focused on required and optional {@link StatementPatternNode} * s. */ public void test_static_analysis_getMaybeProducedBindings() { final IV p = makeIV(new URIImpl("http://example/p")); final IV q = makeIV(new URIImpl("http://example/q")); // The source AST. final QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause; final StatementPatternNode sp1, sp2; { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("n")); whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); sp1 = new StatementPatternNode(new VarNode("a"), new ConstantNode(p), new VarNode("n")); whereClause.addChild(sp1); sp2 = new StatementPatternNode(new VarNode("a"), new ConstantNode(q), new VarNode("m")); whereClause.addChild(sp2); sp2.setOptional(true); } final StaticAnalysis sa = new StaticAnalysis(queryRoot); // Where clause. { assertEquals(Collections.emptySet(), sa.getDefinitelyIncomingBindings(whereClause, new LinkedHashSet>())); final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); expectedVars.add(Var.var("m")); assertEquals(expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } // sp1 { assertEquals(Collections.emptySet(), sa.getDefinitelyIncomingBindings(sp1, new LinkedHashSet>())); final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals(expectedVars, sa.getDefinitelyProducedBindings(sp1, new LinkedHashSet>(), true/* recursive */)); assertEquals(expectedVars, sa.getMaybeProducedBindings(sp1, new LinkedHashSet>(), true/* recursive */)); } // sp2 { { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals(expectedVars, sa.getDefinitelyIncomingBindings( sp2, new LinkedHashSet>())); } { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("m")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(sp2, new LinkedHashSet>(), true/* recursive */)); assertEquals( expectedVars, sa.getMaybeProducedBindings(sp2, new LinkedHashSet>(), true/* recursive */)); } } } /** * Unit test of static analysis methods as they pertain to a MINUS group. * Unlike OPTIONAL, the variables in the left and right hand side of a MINUS * operator are not visible to one another. This has implications for (a) * MINUS operators where the right hand side does not share any variables * (such cases should be pruned); and (b) FILTERS in the right hand side * will fail in they assume visibility of variables in the left hand side. * *
     * PREFIX : 
     * SELECT ?a ?n 
     * WHERE {
     *     ?a :p ?n
     *     MINUS {
     *         ?a :q ?n .
     *     }
     * }
     * 
*/ public void test_static_analysis_minus_sharedVariables() { final IV p = makeIV(new URIImpl("http://example/p")); final IV q = makeIV(new URIImpl("http://example/q")); // The source AST. final QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, minusGroup; { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("n")); whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause.addChild(new StatementPatternNode(new VarNode("a"), new ConstantNode(p), new VarNode("n"))); minusGroup = new JoinGroupNode(); whereClause.addChild(minusGroup); minusGroup.setMinus(true); minusGroup.addChild(new StatementPatternNode(new VarNode("a"), new ConstantNode(q), new VarNode("n"))); } final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); /* * First, the QueryRoot. */ { assertEquals(expectedVars, sa.getDefinitelyProducedBindings(queryRoot)); assertEquals(expectedVars, sa.getMaybeProducedBindings(queryRoot)); } /* * Now the whereClause. */ { assertEquals(Collections.emptySet(), sa.getDefinitelyIncomingBindings(whereClause, new LinkedHashSet>())); assertEquals(Collections.emptySet(), sa.getMaybeIncomingBindings(whereClause, new LinkedHashSet>())); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); assertEquals(expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } /* * Finally, the MINUS group. */ { assertEquals(expectedVars, sa.getDefinitelyIncomingBindings( minusGroup, new LinkedHashSet>())); assertEquals(expectedVars, sa.getMaybeIncomingBindings( minusGroup, new LinkedHashSet>())); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(minusGroup, new LinkedHashSet>(), true/* recursive */)); assertEquals(expectedVars, sa.getMaybeProducedBindings(minusGroup, new LinkedHashSet>(), true/* recursive */)); } } /** * Variant test for a MINUS operator without shared variables. * *
     * PREFIX : 
     * SELECT ?s ?p ?o
     * WHERE {
     *     ?s ?p ?o
     *     MINUS {
     *         ?x ?y ?z .
     *     }
     * }
     * 
*/ public void test_static_analysis_minus_nothingShared() { // The source AST. final QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, minusGroup; { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("s")); projection.addProjectionVar(new VarNode("p")); projection.addProjectionVar(new VarNode("o")); whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause.addChild(new StatementPatternNode(new VarNode("s"), new VarNode("p"), new VarNode("o"))); minusGroup = new JoinGroupNode(); whereClause.addChild(minusGroup); minusGroup.setMinus(true); minusGroup.addChild(new StatementPatternNode(new VarNode("x"), new VarNode("y"), new VarNode("z"))); } final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("s")); expectedVars.add(Var.var("p")); expectedVars.add(Var.var("o")); final Set> otherVars = new LinkedHashSet>(); otherVars.add(Var.var("x")); otherVars.add(Var.var("y")); otherVars.add(Var.var("z")); /* * First, the QueryRoot. */ { assertEquals(expectedVars, sa.getDefinitelyProducedBindings(queryRoot)); assertEquals(expectedVars, sa.getMaybeProducedBindings(queryRoot)); } /* * Now the whereClause. */ { assertEquals(Collections.emptySet(), sa.getDefinitelyIncomingBindings(whereClause, new LinkedHashSet>())); assertEquals(Collections.emptySet(), sa.getMaybeIncomingBindings(whereClause, new LinkedHashSet>())); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); assertEquals(expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } /* * Finally, the MINUS group. */ { assertEquals(expectedVars, sa.getDefinitelyIncomingBindings( minusGroup, new LinkedHashSet>())); assertEquals(expectedVars, sa.getMaybeIncomingBindings( minusGroup, new LinkedHashSet>())); assertEquals( otherVars, sa.getDefinitelyProducedBindings(minusGroup, new LinkedHashSet>(), true/* recursive */)); assertEquals(otherVars, sa.getMaybeProducedBindings(minusGroup, new LinkedHashSet>(), true/* recursive */)); } } /** * Variant test for query mixing MINUS and OPTIONAL groups. * *
     * PREFIX : 
     * SELECT ?a ?n ?b
     * WHERE {
     *     ?a :p ?n
     *     OPTIONAL {
     *        ?b :p 3.0
     *     }
     *     MINUS {
     *         ?a :q ?n .
     *         OPTIONAL {
     *            ?c :q 3.0
     *         }
     *     }
     * }
     * 
*/ public void test_static_analysis_minus_and_optional() { final IV p = makeIV(new URIImpl("http://example/p")); final IV q = makeIV(new URIImpl("http://example/q")); final IV three = makeIV(new LiteralImpl("3.0", XSD.DECIMAL)); // The source AST. final QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, optGroup1, minusGroup, optGroup2; { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("n")); projection.addProjectionVar(new VarNode("b")); whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause.addChild(new StatementPatternNode(new VarNode("a"), new ConstantNode(p), new VarNode("n"))); optGroup1 = new JoinGroupNode(true/*optional*/); whereClause.addChild(optGroup1); optGroup1.addChild(new StatementPatternNode(new VarNode("b"), new ConstantNode(p), new ConstantNode(three))); minusGroup = new JoinGroupNode(); whereClause.addChild(minusGroup); minusGroup.setMinus(true); minusGroup.addChild(new StatementPatternNode(new VarNode("a"), new ConstantNode(q), new VarNode("n"))); optGroup2 = new JoinGroupNode(true/*optional*/); minusGroup.addChild(optGroup2); optGroup2.addChild(new StatementPatternNode(new VarNode("c"), new ConstantNode(q), new ConstantNode(three))); } final StaticAnalysis sa = new StaticAnalysis(queryRoot); /* * First, the QueryRoot. */ { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals(expectedVars, sa.getDefinitelyProducedBindings(queryRoot)); expectedVars.add(Var.var("b")); assertEquals(expectedVars, sa.getMaybeProducedBindings(queryRoot)); } /* * Now the whereClause. */ { assertEquals(Collections.emptySet(), sa.getDefinitelyIncomingBindings(whereClause, new LinkedHashSet>())); assertEquals(Collections.emptySet(), sa.getMaybeIncomingBindings(whereClause, new LinkedHashSet>())); final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); expectedVars.add(Var.var("b")); assertEquals(expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } /* * Optional group1. */ { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals(expectedVars, sa.getDefinitelyIncomingBindings(optGroup1, new LinkedHashSet>())); assertEquals(expectedVars, sa.getMaybeIncomingBindings(optGroup1, new LinkedHashSet>())); expectedVars.clear(); expectedVars.add(Var.var("b")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(optGroup1, new LinkedHashSet>(), true/* recursive */)); assertEquals(expectedVars, sa.getMaybeProducedBindings(optGroup1, new LinkedHashSet>(), true/* recursive */)); } /* * The MINUS group. */ { { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals(expectedVars, sa.getDefinitelyIncomingBindings( minusGroup, new LinkedHashSet>())); expectedVars.add(Var.var("b")); assertEquals(expectedVars, sa.getMaybeIncomingBindings( minusGroup, new LinkedHashSet>())); } { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(minusGroup, new LinkedHashSet>(), true/* recursive */)); expectedVars.add(Var.var("c")); assertEquals( expectedVars, sa.getMaybeProducedBindings(minusGroup, new LinkedHashSet>(), true/* recursive */)); } } /* * Optional group 2. */ { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals(expectedVars, sa.getDefinitelyIncomingBindings(optGroup2, new LinkedHashSet>())); expectedVars.add(Var.var("b")); assertEquals(expectedVars, sa.getMaybeIncomingBindings(optGroup2, new LinkedHashSet>())); expectedVars.clear(); expectedVars.add(Var.var("c")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(optGroup2, new LinkedHashSet>(), true/* recursive */)); assertEquals(expectedVars, sa.getMaybeProducedBindings(optGroup2, new LinkedHashSet>(), true/* recursive */)); } } /** * Variant test for query mixing normal child join groups and OPTIONAL * join groups. * *
     * PREFIX : 
     * SELECT ?a ?n ?b ?c
     * WHERE {
     *     ?a :p ?n
     *     {
     *         ?a :q ?n .
     *         OPTIONAL {
     *            ?c :q 3.0
     *         }
     *     }
     *     OPTIONAL {
     *         ?b :p 3.0
     *     }
     * }
     * 
*/ public void test_static_analysis_subGroups_and_optional() { final IV p = makeIV(new URIImpl("http://example/p")); final IV q = makeIV(new URIImpl("http://example/q")); final IV three = makeIV(new LiteralImpl("3.0", XSD.DECIMAL)); // The source AST. final QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, optGroup1, childGroup, optGroup2; { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("n")); projection.addProjectionVar(new VarNode("b")); projection.addProjectionVar(new VarNode("c")); whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause.addChild(new StatementPatternNode(new VarNode("a"), new ConstantNode(p), new VarNode("n"))); { childGroup = new JoinGroupNode(); whereClause.addChild(childGroup); childGroup.addChild(new StatementPatternNode(new VarNode("a"), new ConstantNode(q), new VarNode("n"))); optGroup2 = new JoinGroupNode(true/* optional */); childGroup.addChild(optGroup2); optGroup2.addChild(new StatementPatternNode(new VarNode("c"), new ConstantNode(q), new ConstantNode(three))); } { optGroup1 = new JoinGroupNode(true/* optional */); whereClause.addChild(optGroup1); optGroup1.addChild(new StatementPatternNode(new VarNode("b"), new ConstantNode(p), new ConstantNode(three))); } } final StaticAnalysis sa = new StaticAnalysis(queryRoot); /* * First, the QueryRoot. */ { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals(expectedVars, sa.getDefinitelyProducedBindings(queryRoot)); expectedVars.add(Var.var("b")); expectedVars.add(Var.var("c")); assertEquals(expectedVars, sa.getMaybeProducedBindings(queryRoot)); } /* * Now the whereClause. */ { assertEquals(Collections.emptySet(), sa.getDefinitelyIncomingBindings(whereClause, new LinkedHashSet>())); assertEquals(Collections.emptySet(), sa.getMaybeIncomingBindings(whereClause, new LinkedHashSet>())); final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); expectedVars.add(Var.var("b")); expectedVars.add(Var.var("c")); assertEquals(expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } /* * The child join group. */ { { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals(expectedVars, sa.getDefinitelyIncomingBindings( childGroup, new LinkedHashSet>())); assertEquals(expectedVars, sa.getMaybeIncomingBindings( childGroup, new LinkedHashSet>())); } { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(childGroup, new LinkedHashSet>(), true/* recursive */)); expectedVars.add(Var.var("c")); assertEquals( expectedVars, sa.getMaybeProducedBindings(childGroup, new LinkedHashSet>(), true/* recursive */)); } /* * Optional group 2 (embedded in the child join group). */ { { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals(expectedVars, sa.getDefinitelyIncomingBindings(optGroup2, new LinkedHashSet>())); assertEquals(expectedVars, sa.getMaybeIncomingBindings( optGroup2, new LinkedHashSet>())); } { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("c")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(optGroup2, new LinkedHashSet>(), true/* recursive */)); assertEquals( expectedVars, sa.getMaybeProducedBindings(optGroup2, new LinkedHashSet>(), true/* recursive */)); } } } /* * Optional group1. */ { { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("n")); assertEquals(expectedVars, sa.getDefinitelyIncomingBindings( optGroup1, new LinkedHashSet>())); expectedVars.add(Var.var("c")); assertEquals(expectedVars, sa.getMaybeIncomingBindings( optGroup1, new LinkedHashSet>())); } { final Set> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("b")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(optGroup1, new LinkedHashSet>(), true/* recursive */)); assertEquals( expectedVars, sa.getMaybeProducedBindings(optGroup1, new LinkedHashSet>(), true/* recursive */)); } } } /** * Unit test for * {@link StaticAnalysis#getProjectedVars(IGroupMemberNode, GraphPatternGroup, QueryBase, Set, Set)} * . This unit test is a based on * bigdata-perf/CI/govtrack/queries/query10.rq *

* Given: * *

     * SELECT ?var1 ?var6 ?var4 ?var10
     *  WHERE {
     *         ?var1 a 
     *         OPTIONAL {
     *                 ?var1  ?var6
     *         }.
     *         OPTIONAL {
     *                 ?var12  ?var1.
     *                 ?var12  ?var4
     *         }.
     *         OPTIONAL {
     *                 ?var1  ?var13.
     *                 ?var13  ?var10
     *         }
     * }
     * 
* * This test verifies that the correct projection is computed for each of * the sub-groups in the query. Those projections are as follows: * *
     *         SELECT ?var1 ?var6
     *         WHERE {
     *                 ?var1 a 
     *                 OPTIONAL {
     *                      ?var1  ?var6
     *                 }.
     *         }
     * 
* *
     *         SELECT ?var1 ?var4
     *         WHERE {
     *            INCLUDE %_set1
     *            OPTIONAL {
     *                 ?var12  ?var1.
     *                 ?var12  ?var4
     *            }.
     *         }
     * 
* *
     *      SELECT ?var1 ?var10
     *      WHERE {
     *         INCLUDE %_set1
     *         OPTIONAL {
     *                 ?var1  ?var13.
     *                 ?var13  ?var10
     *         }
     *     }
     * 
* * @see https://sourceforge.net/apps/trac/bigdata/ticket/397 */ public void test_static_analysis_getProjectedVars() { @SuppressWarnings("rawtypes") final IV a = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV polititian = makeIV(new URIImpl("http://www.rdfabout.com/rdf/schema/politico/Politician")); @SuppressWarnings("rawtypes") final IV name = makeIV(new URIImpl("http://www.rdfabout.com/rdf/schema/usgovt/name")); @SuppressWarnings("rawtypes") final IV sponsor = makeIV(new URIImpl("http://www.rdfabout.com/rdf/schema/usgovt/sponsor")); @SuppressWarnings("rawtypes") final IV title = makeIV(new URIImpl("http://www.rdfabout.com/rdf/schema/usgovt/title")); @SuppressWarnings("rawtypes") final IV N = makeIV(new URIImpl("http://www.w3.org/2001/vcard-rdf/3.0#N")); @SuppressWarnings("rawtypes") final IV family = makeIV(new URIImpl("http://www.w3.org/2001/vcard-rdf/3.0#Family")); // The source AST. final QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, optionalGroup1, optionalGroup2, optionalGroup3; { // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("var1")); projection.addProjectionVar(new VarNode("var6")); projection.addProjectionVar(new VarNode("var4")); projection.addProjectionVar(new VarNode("var10")); } whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); // ?_var1 a whereClause.addChild(new StatementPatternNode(new VarNode("var1"), new ConstantNode(a), new ConstantNode(polititian), null/* c */, Scope.DEFAULT_CONTEXTS)); // ?_var1 ?_var6 { optionalGroup1 = new JoinGroupNode(true/* optional */); whereClause.addChild(optionalGroup1); optionalGroup1.addChild(new StatementPatternNode( new VarNode("var1"), new ConstantNode(name), new VarNode("var6"), null/* c */, Scope.DEFAULT_CONTEXTS)); } { optionalGroup2 = new JoinGroupNode(true/* optional */); whereClause.addChild(optionalGroup2); // ?_var12 ?_var1. optionalGroup2.addChild(new StatementPatternNode(new VarNode( "var12"), new ConstantNode(sponsor), new VarNode( "var1"), null/* c */, Scope.DEFAULT_CONTEXTS)); // ?_var12 ?_var4 optionalGroup2.addChild(new StatementPatternNode(new VarNode( "var12"), new ConstantNode(title), new VarNode( "var4"), null/* c */, Scope.DEFAULT_CONTEXTS)); } { optionalGroup3 = new JoinGroupNode(true/* optional */); whereClause.addChild(optionalGroup3); // ?_var1 ?_var13. optionalGroup3.addChild(new StatementPatternNode(new VarNode( "var1"), new ConstantNode(N), new VarNode( "var13"), null/* c */, Scope.DEFAULT_CONTEXTS)); // ?_var13 ?_var10 optionalGroup3.addChild(new StatementPatternNode(new VarNode( "var13"), new ConstantNode(family), new VarNode( "var10"), null/* c */, Scope.DEFAULT_CONTEXTS)); } } final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> exogenousVars = new LinkedHashSet>(); // Optional group 1. if(true){ final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("var1")); expectedVars.add(Var.var("var6")); assertEquals(expectedVars, sa.getProjectedVars(optionalGroup1, optionalGroup1, queryRoot, exogenousVars, new LinkedHashSet>()// projectedVars )); } // Optional group 2. { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("var1")); expectedVars.add(Var.var("var4")); assertEquals(expectedVars, sa.getProjectedVars(optionalGroup2, optionalGroup2, queryRoot, exogenousVars, new LinkedHashSet>()// projectedVars )); } // Optional group 3. { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("var1")); expectedVars.add(Var.var("var10")); assertEquals(expectedVars, sa.getProjectedVars(optionalGroup3, optionalGroup3, queryRoot, exogenousVars, new LinkedHashSet>()// projectedVars )); } } /** * Unit test for static analysis of the MUST and MIGHT bound variables for a * subquery. * *
     * SELECT (?a as ?b) {
     *    ?a rdf:type foaf:Person
     * }
     * 
* * Should report that ?b must be bound * * @see https://sourceforge.net/apps/trac/bigdata/ticket/430 * * TODO Extend this test to cover the case where b is an * exogenously bound variable. This does not change the MUST/MIGHT * analysis of the query. */ public void test_static_analysis_projection_01() { @SuppressWarnings("rawtypes") final IV rdfType = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV foafPerson = makeIV(FOAFVocabularyDecl.Person); // The source AST. final QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause; { // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionExpression(new AssignmentNode( new VarNode("b"), new VarNode("a"))); } whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause.addChild(new StatementPatternNode(new VarNode("a"), new ConstantNode(rdfType), new ConstantNode(foafPerson))); } final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> exogenousVars = new LinkedHashSet>(); // QueryRoot { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("b")); assertEquals(expectedVars, sa.getDefinitelyProducedBindings(queryRoot)); assertEquals(expectedVars, sa.getMaybeProducedBindings(queryRoot)); } // whereClause { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); assertEquals( expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } } /** * Variant with optional group binding ?a (so ?b * is MIGHT be bound). * *
     * SELECT (?a as ?b) {
     *    OPTIONAL {
     *      ?a rdf:type foaf:Person
     *    }
     * }
     * 
* * Should report that ?b might be bound * * TODO Extend this test to also cover the case where b is an * exogenously bound variable. In that case, it MUST be bound. * * TODO Extend this test to also cover the case where a is an * exogenously bound variable. Since a is not projected, it's * bound value SHOULD NOT be visible inside of the query (variables with * exogenous variables must obey the same scoping rules as variables which * only become bound during query evaluation). * * @see https://sourceforge.net/apps/trac/bigdata/ticket/430 */ public void test_static_analysis_projection_02() { @SuppressWarnings("rawtypes") final IV rdfType = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV foafPerson = makeIV(FOAFVocabularyDecl.Person); // The source AST. final QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, optionalGroup; { // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionExpression(new AssignmentNode( new VarNode("b"), new VarNode("a"))); } whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); optionalGroup = new JoinGroupNode(true/*optional*/); whereClause.addChild(optionalGroup); optionalGroup.addChild(new StatementPatternNode(new VarNode("a"), new ConstantNode(rdfType), new ConstantNode(foafPerson))); } final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> exogenousVars = new LinkedHashSet>(); // QueryRoot { final LinkedHashSet> expectedVars = new LinkedHashSet>(); assertEquals(expectedVars, sa.getDefinitelyProducedBindings(queryRoot)); expectedVars.add(Var.var("b")); assertEquals(expectedVars, sa.getMaybeProducedBindings(queryRoot)); } // whereClause { final LinkedHashSet> expectedVars = new LinkedHashSet>(); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); expectedVars.add(Var.var("a")); assertEquals( expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } // optionalGroup { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(optionalGroup, new LinkedHashSet>(), true/* recursive */)); assertEquals( expectedVars, sa.getMaybeProducedBindings(optionalGroup, new LinkedHashSet>(), true/* recursive */)); } } /** * Unit test where the SELECT expression includes the bind of a constant * onto a variable. */ public void test_static_analysis_projection_03() { // @SuppressWarnings("rawtypes") // final IV rdfType = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV foafPerson = makeIV(FOAFVocabularyDecl.Person); // The source AST. final QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause; { // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionExpression(new AssignmentNode( new VarNode("b"), new ConstantNode(foafPerson))); } whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); } final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> exogenousVars = new LinkedHashSet>(); // QueryRoot { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("b")); assertEquals(expectedVars, sa.getDefinitelyProducedBindings(queryRoot)); assertEquals(expectedVars, sa.getMaybeProducedBindings(queryRoot)); } // whereClause { final LinkedHashSet> expectedVars = new LinkedHashSet>(); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); assertEquals( expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } } /** * Unit test for static analysis of the MUST and MIGHT bound variables for a * query involving a select expression which could result in an error. Note * that this query is NOT an aggregation query so the error will fail the * solution. * *
     * SELECT ?a ?b (?a/?b as ?c) {
     *    ?x rdf:type foaf:Person .
     *    ?x :age ?a .
     *    ?x :grade ?b .
     * }
     * 
* * In this query, it is presumed that ?b is the number of years * of school and will be ZERO in the data for people who have not yet begun * formal schooling. Hence, the select expression can evaluate to an error * (divide by zero). However, since this is NOT an aggregation query, the * error will cause the solution to be dropped. Hence, ?c is * definitely bound for this query. * * @see https://sourceforge.net/apps/trac/bigdata/ticket/430 * * TODO Extend this test to cover the case where b is an * exogenously bound variable. This does not change the MUST/MIGHT * analysis of the query. */ public void test_static_analysis_projection_04() { @SuppressWarnings("rawtypes") final IV rdfType = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV foafPerson = makeIV(FOAFVocabularyDecl.Person); @SuppressWarnings("rawtypes") final IV age = makeIV(new URIImpl("http://example.org/age")); @SuppressWarnings("rawtypes") final IV grade = makeIV(new URIImpl("http://example.org/grade")); // The source AST. QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause; { // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("b")); projection.addProjectionExpression(new AssignmentNode( new VarNode("c"), FunctionNode.binary( FunctionRegistry.DIVIDE, new VarNode("a"), new VarNode("b")))); } // WHERE clause. { whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause .addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(rdfType), new ConstantNode( foafPerson))); whereClause.addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(age), new VarNode("a"))); whereClause.addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(grade), new VarNode("b"))); } } /* * Note: Since it involves function nodes, we need to generate the value * expressions in order to run this test. */ { final IBindingSet[] bindingSets = new IBindingSet[] {}; final ASTContainer astContainer = new ASTContainer(queryRoot); final AST2BOpContext context = new AST2BOpContext(astContainer, store); queryRoot = (QueryRoot) new ASTSetValueExpressionsOptimizer() .optimize(context, new QueryNodeWithBindingSet(queryRoot, bindingSets)) .getQueryNode(); } final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> exogenousVars = new LinkedHashSet>(); // QueryRoot { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("b")); expectedVars.add(Var.var("c")); assertEquals(expectedVars, sa.getDefinitelyProducedBindings(queryRoot)); assertEquals(expectedVars, sa.getMaybeProducedBindings(queryRoot)); } // whereClause { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("x")); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("b")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); assertEquals( expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } } /** * Unit test for static analysis of the MUST and MIGHT bound variables for a * query involving a select expression which depends on a variable which is * not definitely bound. * *
     * SELECT ?a ?b (?a + ?b as ?c) {
     *    ?x rdf:type foaf:Person .
     *    ?x :age ?a .
     *    OPTIONAL {
     *       ?x :grade ?b .
     *    }
     * }
     * 
* * @see https://sourceforge.net/apps/trac/bigdata/ticket/430 * * TODO Extend this test to cover the case where b is an * exogenously bound variable. This does not change the MUST/MIGHT * analysis of the query. */ public void test_static_analysis_projection_05() { @SuppressWarnings("rawtypes") final IV rdfType = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV foafPerson = makeIV(FOAFVocabularyDecl.Person); @SuppressWarnings("rawtypes") final IV age = makeIV(new URIImpl("http://example.org/age")); @SuppressWarnings("rawtypes") final IV grade = makeIV(new URIImpl("http://example.org/grade")); // The source AST. QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, optionalGroup; { // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("b")); projection.addProjectionExpression(new AssignmentNode( new VarNode("c"), FunctionNode.binary( FunctionRegistry.DIVIDE, new VarNode("a"), new VarNode("b")))); } // WHERE clause. { whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause .addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(rdfType), new ConstantNode( foafPerson))); whereClause.addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(age), new VarNode("a"))); optionalGroup = new JoinGroupNode(true/* optional */); whereClause.addChild(optionalGroup); optionalGroup.addChild(new StatementPatternNode( new VarNode("x"), new ConstantNode(grade), new VarNode( "b"))); } } /* * Note: Since it involves function nodes, we need to generate the value * expressions in order to run this test. */ { final IBindingSet[] bindingSets = new IBindingSet[] {}; final ASTContainer astContainer = new ASTContainer(queryRoot); final AST2BOpContext context = new AST2BOpContext(astContainer, store); queryRoot = (QueryRoot) new ASTSetValueExpressionsOptimizer() .optimize(context, new QueryNodeWithBindingSet(queryRoot, bindingSets)) .getQueryNode(); } final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> exogenousVars = new LinkedHashSet>(); // QueryRoot { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); assertEquals(expectedVars, sa.getDefinitelyProducedBindings(queryRoot)); expectedVars.add(Var.var("b")); expectedVars.add(Var.var("c")); assertEquals(expectedVars, sa.getMaybeProducedBindings(queryRoot)); } // whereClause { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("x")); expectedVars.add(Var.var("a")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); expectedVars.add(Var.var("b")); assertEquals( expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } // optionalGroup { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("x")); expectedVars.add(Var.var("b")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(optionalGroup, new LinkedHashSet>(), true/* recursive */)); assertEquals( expectedVars, sa.getMaybeProducedBindings(optionalGroup, new LinkedHashSet>(), true/* recursive */)); } } /** * Unit test for static analysis of the MUST and MIGHT bound variables for a * subquery involving aggregation and a select expression ("The result of an * Aggregate which returns an error, is an error, but the SELECT expression * result of projecting an error is unbound"). * *
     * SELECT ?a ?b (?a/?b as ?c) {
     *    ?x rdf:type foaf:Person .
     *    ?x :age ?a .
     *    ?x :grade ?b .
     * }
     * GROUP BY ?b
     * 
* * In this query, it is presumed that ?b is the number of years * of school and will be ZERO in the data for people who have not yet begun * formal schooling. Hence, the select expression can evaluate to an error * (divide by zero). *

* Since this is an aggregation query, the solution will still be reported * with an unbound value for ?c. This illustrates the general * principle that we can not assume that a select expression based on * definitely bound variables will itself be definitely bound. * * @see https://sourceforge.net/apps/trac/bigdata/ticket/430 * * TODO Extend this test to cover the case where b is an * exogenously bound variable. Does this change the MUST/MIGHT analysis * of the query? */ public void test_static_analysis_projection_06() { @SuppressWarnings("rawtypes") final IV rdfType = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV foafPerson = makeIV(FOAFVocabularyDecl.Person); @SuppressWarnings("rawtypes") final IV age = makeIV(new URIImpl("http://example.org/age")); @SuppressWarnings("rawtypes") final IV grade = makeIV(new URIImpl("http://example.org/grade")); // The source AST. QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause; { // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("b")); projection.addProjectionExpression(new AssignmentNode( new VarNode("c"), FunctionNode.binary( FunctionRegistry.DIVIDE, new VarNode("a"), new VarNode("b")))); } // WHERE clause. { whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause .addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(rdfType), new ConstantNode( foafPerson))); whereClause.addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(age), new VarNode("a"))); whereClause.addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(grade), new VarNode("b"))); } // GROUP BY { final GroupByNode groupBy = new GroupByNode(); queryRoot.setGroupBy(groupBy); groupBy.addGroupByVar(new VarNode("b")); } } /* * Note: Since it involves function nodes, we need to generate the value * expressions in order to run this test. */ { final IBindingSet[] bindingSets = new IBindingSet[] {}; final ASTContainer astContainer = new ASTContainer(queryRoot); final AST2BOpContext context = new AST2BOpContext(astContainer, store); queryRoot = (QueryRoot) new ASTSetValueExpressionsOptimizer() .optimize(context, new QueryNodeWithBindingSet(queryRoot, bindingSets)) .getQueryNode(); } final StaticAnalysis sa = new StaticAnalysis(queryRoot); final Set> exogenousVars = new LinkedHashSet>(); // QueryRoot { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("b")); assertEquals(expectedVars, sa.getDefinitelyProducedBindings(queryRoot)); expectedVars.add(Var.var("c")); assertEquals(expectedVars, sa.getMaybeProducedBindings(queryRoot)); } // whereClause { final LinkedHashSet> expectedVars = new LinkedHashSet>(); expectedVars.add(Var.var("x")); expectedVars.add(Var.var("a")); expectedVars.add(Var.var("b")); assertEquals( expectedVars, sa.getDefinitelyProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); assertEquals( expectedVars, sa.getMaybeProducedBindings(whereClause, new LinkedHashSet>(), true/* recursive */)); } } /** * Unit test for locating a reference go a {@link GraphPatternGroup} which * appears as an annotation of another node. This covers {@link UnionNode} * and {@link JoinGroupNode} when appearing as children of a * {@link QueryRoot}'s whereClause. * *

     * SELECT ?a ?b {
     *    ?x rdf:type foaf:Person .
     *    {
     *       ?x :age ?a
     *    } UNION {
     *       ?x :grade ?b
     *    }
     * }
     * 
*/ public void test_findParent_01() { @SuppressWarnings("rawtypes") final IV rdfType = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV foafPerson = makeIV(FOAFVocabularyDecl.Person); @SuppressWarnings("rawtypes") final IV age = makeIV(new URIImpl("http://example.org/age")); @SuppressWarnings("rawtypes") final IV grade = makeIV(new URIImpl("http://example.org/grade")); // The source AST. QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, joinGroup1, joinGroup2; final UnionNode unionNode; { // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("b")); } // WHERE clause. { whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause .addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(rdfType), new ConstantNode( foafPerson))); unionNode = new UnionNode(); whereClause.addChild(unionNode); joinGroup1 = new JoinGroupNode(); unionNode.addChild(joinGroup1); joinGroup1.addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(age), new VarNode("a"))); joinGroup2 = new JoinGroupNode(); unionNode.addChild(joinGroup2); joinGroup2.addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(grade), new VarNode("b"))); } } final StaticAnalysis sa = new StaticAnalysis(queryRoot); assertTrue(unionNode == sa.findParent(joinGroup1)); assertTrue(unionNode == sa.findParent(joinGroup2)); assertTrue(whereClause == sa.findParent(unionNode)); assertTrue(queryRoot == sa.findParent(whereClause)); } /** * This verifies the ability to locate the parent of a graph group in a * {@link SubqueryRoot}. * *
     * SELECT ?a ?b {
     *    ?x rdf:type foaf:Person .
     *    {
     *       SELECT ?x ?a ?b {
     *         ?x :age ?a
     *         ?x :grade ?b
     *       }
     *    }
     * }
     * 
*/ public void test_findParent_02() { @SuppressWarnings("rawtypes") final IV rdfType = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV foafPerson = makeIV(FOAFVocabularyDecl.Person); @SuppressWarnings("rawtypes") final IV age = makeIV(new URIImpl("http://example.org/age")); @SuppressWarnings("rawtypes") final IV grade = makeIV(new URIImpl("http://example.org/grade")); // The source AST. QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, subqueryWhereClause; final SubqueryRoot subqueryRoot; { // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("b")); } // WHERE clause. { whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause .addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(rdfType), new ConstantNode( foafPerson))); subqueryRoot = new SubqueryRoot(QueryType.SELECT); whereClause.addChild(subqueryRoot); subqueryWhereClause = new JoinGroupNode(); subqueryRoot.setWhereClause(subqueryWhereClause); subqueryWhereClause.addChild(new StatementPatternNode( new VarNode("x"), new ConstantNode(age), new VarNode( "a"))); subqueryWhereClause.addChild(new StatementPatternNode( new VarNode("x"), new ConstantNode(grade), new VarNode( "b"))); } } final StaticAnalysis sa = new StaticAnalysis(queryRoot); assertTrue(subqueryRoot == sa.findParent(subqueryWhereClause)); assertTrue(whereClause == subqueryRoot.getParent()); } /** * This verifies the ability to locate the parent of a graph group in a * {@link NamedSubqueryRoot}. * *
     * SELECT ?a ?b {
     *    WITH {
     *       SELECT ?x ?a ?b {
     *         ?x :age ?a
     *         ?x :grade ?b
     *       }
     *    } as %set1
     *    ?x rdf:type foaf:Person .
     *    INCLUDE %set1 .
     * }
     * 
*/ public void test_findParent_03() { @SuppressWarnings("rawtypes") final IV rdfType = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV foafPerson = makeIV(FOAFVocabularyDecl.Person); @SuppressWarnings("rawtypes") final IV age = makeIV(new URIImpl("http://example.org/age")); @SuppressWarnings("rawtypes") final IV grade = makeIV(new URIImpl("http://example.org/grade")); // The source AST. QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, subqueryWhereClause; final NamedSubqueryRoot subqueryRoot; final NamedSubqueryInclude include; final String namedSet = "set1"; { // Named subquery. { subqueryRoot = new NamedSubqueryRoot(QueryType.SELECT, namedSet); subqueryWhereClause = new JoinGroupNode(); subqueryRoot.setWhereClause(subqueryWhereClause); subqueryWhereClause.addChild(new StatementPatternNode( new VarNode("x"), new ConstantNode(age), new VarNode( "a"))); subqueryWhereClause.addChild(new StatementPatternNode( new VarNode("x"), new ConstantNode(grade), new VarNode( "b"))); queryRoot.getNamedSubqueriesNotNull().add(subqueryRoot); } // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("b")); } // WHERE clause. { whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause .addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(rdfType), new ConstantNode( foafPerson))); whereClause.addChild(include = new NamedSubqueryInclude( namedSet)); } } final StaticAnalysis sa = new StaticAnalysis(queryRoot); assertTrue(subqueryRoot == sa.findParent(subqueryWhereClause)); assertTrue(whereClause == include.getParent()); } /** * Unit test for locating a reference go a {@link GraphPatternGroup} which * appears as an annotation of another node. This covers {@link UnionNode} * and {@link JoinGroupNode} when appearing as children of a * {@link QueryRoot}'s whereClause. * *
     * SELECT ?a ?b {
     *    ?x rdf:type foaf:Person .
     *    SERVICE {
     *       ?x :age ?a
     *    }
     *    FILTER {
     *       EXISTS {?x :grade ?b}
     *    }
     * }
     * 
*/ public void test_findParent_04() { @SuppressWarnings("rawtypes") final IV rdfType = makeIV(RDF.TYPE); @SuppressWarnings("rawtypes") final IV foafPerson = makeIV(FOAFVocabularyDecl.Person); @SuppressWarnings("rawtypes") final IV age = makeIV(new URIImpl("http://example.org/age")); @SuppressWarnings("rawtypes") final IV grade = makeIV(new URIImpl("http://example.org/grade")); @SuppressWarnings("rawtypes") final IV serviceUri = makeIV(new URIImpl("http://example.org/service")); // The source AST. QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); final JoinGroupNode whereClause, serviceGroup, existsGroup; final ServiceNode serviceNode; final FilterNode filterNode; { // Top-level projection { final ProjectionNode projection = new ProjectionNode(); queryRoot.setProjection(projection); projection.addProjectionVar(new VarNode("a")); projection.addProjectionVar(new VarNode("b")); } // WHERE clause. { whereClause = new JoinGroupNode(); queryRoot.setWhereClause(whereClause); whereClause .addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(rdfType), new ConstantNode( foafPerson))); serviceGroup = new JoinGroupNode(); serviceGroup.addChild(new StatementPatternNode( new VarNode("x"), new ConstantNode(age), new VarNode( "a"))); serviceNode = new ServiceNode(new ConstantNode(serviceUri), serviceGroup); whereClause.addChild(serviceNode); existsGroup = new JoinGroupNode(); existsGroup.addChild(new StatementPatternNode(new VarNode("x"), new ConstantNode(grade), new VarNode("b"))); filterNode = new FilterNode(new ExistsNode(new VarNode( "anon-var-1"), existsGroup)); whereClause.addChild(filterNode); } } final StaticAnalysis sa = new StaticAnalysis(queryRoot); assertTrue(serviceNode == sa.findParent(serviceGroup)); assertTrue(filterNode == sa.findParent(existsGroup)); assertTrue(queryRoot == sa.findParent(whereClause)); } // /** // * Unit test for whether or not a variable is "in-scope" in some part of the // * AST. // * // *
//     * PREFIX :    
//     * SELECT ?v
//     * { 
//     *     :x :p ?v . 
//     *     FILTER(?v = 1) .
//     * }
//     * 
// * // * The variable ?v is in scope in the outer group and the // * filter. // * // * @see http://www.w3.org/TR/sparql11-query/#variableScope // */ // public void test_static_analysis_inScope_01() { // // @SuppressWarnings("rawtypes") // final IV x = makeIV(new URIImpl("http://example.org/x")); // @SuppressWarnings("rawtypes") // final IV p = makeIV(new URIImpl("http://example.org/p")); // @SuppressWarnings("rawtypes") // final IV one = makeIV(new LiteralImpl("1", XSD.INTEGER)); // // // The source AST. // QueryRoot queryRoot = new QueryRoot(QueryType.SELECT); // final JoinGroupNode whereClause; // final FilterNode filterNode; // { // // // Top-level projection // { // final ProjectionNode projection = new ProjectionNode(); // queryRoot.setProjection(projection); // // projection.addProjectionVar(new VarNode("v")); // } // // // WHERE clause. // { // whereClause = new JoinGroupNode(); // queryRoot.setWhereClause(whereClause); // // whereClause.addChild(new StatementPatternNode(new ConstantNode( // x), new ConstantNode(p), new VarNode("v"))); // // filterNode = new FilterNode(FunctionNode.binary( // FunctionRegistry.EQ, new VarNode("v"), // new ConstantNode(one))); // whereClause.addChild(filterNode); // // } // // } // // final StaticAnalysis sa = new StaticAnalysis(queryRoot); // // { // // final Set> expected = new LinkedHashSet>(); // // expected.add(Var.var("v")); // // assertEquals(expected, sa.getInScopeVariables(filterNode, // new LinkedHashSet>())); // // } // // } // // /** // * ?v is also in scope when it appears in an OPTIONAL group // * // *
//     * PREFIX :    
//     * SELECT ?v
//     * { 
//     *     :x :p ?v .
//     *     OPTIONAL { 
//     *        FILTER(?v = 1) .
//     *     }
//     * }
//     * 
// */ // public void test_static_analysis_inScope_02() { // // } // // /** // * This test examines a DAWG/TCK query based on a badly formed left join // * pattern: // * // *
//     * PREFIX :    
//     * SELECT ?v ?w ?v2
//     * { 
//     *     :x :p ?v . 
//     *     { :x :q ?w 
//     *       OPTIONAL {  :x :p ?v2 FILTER(?v = 1) }
//     *     }
//     * }
//     * 
// * // * The variable ?v is in scope in the outer group, but it is // * not in scope in the filter. // * // * TODO What about when the optional group has ?v in the BPG? // * // * TODO What about when the optional group has ?v and the parent group // * also has ?v? // * // * TODO Examples with more variables. // */ // public void test_static_analysis_inScope_03() { // // fail("write tests"); // // } // // /** // * // * TODO The test suite should cover all of the bottom-up examples so we can // * work out what the right behavior of this method is in each case. It // * should also cover the EXISTS graph pattern, SERVICE graph pattern, and // * subquery graph patterns as those are not linked in the standard // * parent-child hierarchy (or write a separate test suite for finding those // * things, maybe for BOpUtility). // */ // public void test_static_analysis_inScope_xxx() { // // fail("write tests"); // // } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy