/** 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 4, 2011 */ package com.bigdata.rdf.sparql.ast.eval; import org.openrdf.model.Value; import com.bigdata.BigdataStatics; import com.bigdata.bop.BOpUtility; import com.bigdata.rdf.sparql.ast.NamedSubqueryRoot; import com.bigdata.rdf.sparql.ast.QueryHints; import com.bigdata.rdf.sparql.ast.optimizers.ASTComplexOptionalOptimizer; import com.bigdata.rdf.sparql.ast.optimizers.ASTSparql11SubqueryOptimizer; import com.bigdata.rdf.sparql.ast.optimizers.TestASTSparql11SubqueryOptimizer; /** * Data driven test suite. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public class TestSubQuery extends AbstractDataDrivenSPARQLTestCase { /** * */ public TestSubQuery() { } /** * @param name */ public TestSubQuery(final String name) { super(name); } /** * <pre> * PREFIX : <http://example.org/> * SELECT * * WHERE { * ?s :p ?o . * { * SELECT ?s { ?s a :ty } ORDER BY ?s LIMIT 3 * } * } * </pre> * * mroycsi wrote: Based on sparql bottom up evaluation, the subquery will * return s1,s2,s3 as the solutions for ?s. Joined with the ?s :p ?o, you * should only get the statements where ?s is s1,s2,s3. * <p> * I haven't debugged bigdata so I don't know exactly what it is doing, but * it seems that currently with the bigdata evaluation, for each solution * produced from ?s :p ?o, the subquery is run, and it seems that the ?s * binding in the subquery is getting constrained by the ?s from the inbound * solution, so results of the subquery are not always s1,s2,s3, depending * on the inbound solution. * <p> * thompsonbry wrote: Normally bottom up evaluation only differs when you * are missing a shared variable such that the bindings for variables having * the same name are actually not correlated. * <P> * This is a bit of an odd case with an interaction between the order/limit * and the as-bound evaluation which leads to the "wrong" result. We * probably do not want to always do bottom up evaluation for a subquery * (e.g., by lifting it into a named subquery). Are you suggesting that * there is this special case which needs to be recognized where the * subquery MUST be evaluated first because the order by/limit combination * means that the results of the outer query joined with the inner query * could be different in this case? * <p> * mroycsi wrote: This is [a] pattern that is well known and commonly used * with sparql 1.1 subqueries. It is definitely a case where the subquery * needs to be evaluated first due to the limit clause. The order clause * probably doesn't matter if there isn't a limit since all the results are * just joined, so order doesn't matter till the solution gets to the order * by operations. * <p> * thompsonbry wrote: Ok. ORDER BY by itself does not matter and neither * does LIMIT by itself. But if you have both it matters and we need to run * the subquery first. * <p> * Note: This is handled by {@link ASTSparql11SubqueryOptimizer}. * * @see TestASTSparql11SubqueryOptimizer#test_subSelectWithLimitAndOrderBy() */ public void test_sparql_subquery_limiting_resource_pattern() throws Exception { new TestHelper("subquery-lpr").runTest(); } /** * Unit test of a SPARQL 1.1 subquery with a SLICE on the subquery. */ public void test_sparql_subquery_slice_01() throws Exception { new TestHelper("subquery-slice-01").runTest(); } /** * Simple Sub-Select unit test * * <pre> * PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> * PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> * PREFIX foaf: <http://xmlns.com/foaf/0.1/> * SELECT ?x ?o * WHERE { * ?x rdfs:label ?o . * { * SELECT ?x WHERE {?x rdf:type foaf:Person} * } * } * </pre> */ public void test_sparql_subselect() throws Exception { new TestHelper("sparql-subselect").runTest(); } /** * A unit test from the Sesame 2.5 TCK. * * <pre> * SELECT * { SELECT * { ?s ?p ?o } } * </pre> */ public void test_sparql11_subquery_02() throws Exception { new TestHelper( "sparql11-subquery-02", // testURI, "sparql11-subquery-02.rq",// queryFileURL "sparql11-subquery-02.ttl",// dataFileURL "sparql11-subquery-02.srx"// resultFileURL ).runTest(); } /** * A unit test from the Sesame 2.5 TCK. * * <pre> * SELECT (count(*) as ?count) * WHERE { * { SELECT ?s ?p ?o WHERE { ?s ?p ?o } } * } * </pre> */ public void test_sparql11_count_subquery_01() throws Exception { new TestHelper( "sparql11-count-subquery-01", // testURI, "sparql11-count-subquery-01.rq",// queryFileURL "sparql11-count-subquery-01.ttl",// dataFileURL "sparql11-count-subquery-01.srx"// resultFileURL ).runTest(); } /** * Test that only projected variables are included in subquery results. * * <pre> * PREFIX : <http://example.org/> * SELECT ?s ?x * WHERE { * { * SELECT ?s ?x { ?s :p ?x } * } * { * SELECT ?s ?fake1 ?fake2 { ?x :q ?s . LET (?fake1 := 1) . LET (?fake2 := 2) . } * } * } * </pre> */ public void test_sparql11_subquery_scope() throws Exception { new TestHelper("sparql11-subquery-scope").runTest(); } /** * In this test variant, the FILTER winds up attached to a * {@link NamedSubqueryRoot} (there are no shared variables projected out of * the sub-select) and does not require RDF {@link Value} materialization. * <p> * Note: The sub-select explicitly annotated using * {@link QueryHints#RUN_ONCE} to ensure that it gets lifted out as a * {@link NamedSubqueryRoot}, but this query does not have any shared * variables so the sub-select would be lifted out anyway. * * <pre> * select distinct ?s * where * { * ?s ?p ?o. * { * SELECT ?ps WHERE * { * hint:SubQuery hint:runOnce true. * ?ps a <http://www.example.org/schema/Person> . * } * limit 1 * } * filter (?s = ?ps) * } * </pre> * * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/796" * >Filter assigned to sub-query by query generator is dropped from * evaluation</a> */ public void test_sparql11_subquery_filter_01() throws Exception { final TestHelper h = new TestHelper( "sparql11-subselect-filter-01", // testURI, "sparql11-subselect-filter-01.rq",// queryFileURL "sparql11-subselect-filter-01.nt",// dataFileURL "sparql11-subselect-filter-01.srx"// resultFileURL ); // Run test. h.runTest(); // Make sure that this query used a NamedSubqueryRoot. assertTrue(BOpUtility.visitAll(h.getASTContainer().getOptimizedAST(), NamedSubqueryRoot.class).hasNext()); } /** * Variant where the FILTER requires RDF Value materialization and the * sub-select is lifted out as a named subquery. * * <pre> * select distinct ?s * where * { * ?s ?p ?o. * { * SELECT ?ps WHERE * { * ?ps a <http://www.example.org/schema/Person> . * } * limit 1 * } * filter (str(?s) = str(?ps)) * } * </pre> * * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/796" * >Filter assigned to sub-query by query generator is dropped from * evaluation</a> */ public void test_sparql11_subquery_filter_01b() throws Exception { final TestHelper h = new TestHelper( "sparql11-subselect-filter-01b", // testURI, "sparql11-subselect-filter-01b.rq",// queryFileURL "sparql11-subselect-filter-01.nt",// dataFileURL "sparql11-subselect-filter-01.srx"// resultFileURL ); // Run test. h.runTest(); // Make sure that this query used a NamedSubqueryRoot. assertTrue(BOpUtility.visitAll(h.getASTContainer().getOptimizedAST(), NamedSubqueryRoot.class).hasNext()); } /** * This ticket is for a bug when the {@link ASTComplexOptionalOptimizer} * runs. If that optimizer is disabled, then the query is fine. There are * two versions for this method. One in which one of the OPTIONALs is turned * into a required join. In this case, the problem is not demonstrated since * the {@link ASTComplexOptionalOptimizer} does not run. In the other case, * the join group is OPTIONAL rather than required and the problem is * demonstrated. * * <pre> * select ?name * { * { * select ?p * { * ?p a <http://www.example.org/schema/Person> . * optional{?p <http://www.example.org/schema/age> ?age.} * } * LIMIT 1 * } * * {?p <http://www.example.org/schema/name> ?name.} * * #OPTIONAL * { ?post a <http://www.example.org/schema/Post> . * ?post <http://www.example.org/schema/postedBy> ?p. * ?post <http://www.example.org/schema/content> ?postContent. * } * OPTIONAL{ * ?comment a <http://www.example.org/schema/Comment> . * ?comment <http://www.example.org/schema/parentPost> ?post. * ?cperson a <http://www.example.org/schema/Person> . * ?comment <http://www.example.org/schema/postedBy> ?cperson . * } * } * </pre> * * @see <a href="https://sourceforge.net/apps/trac/bigdata/ticket/801" > * Adding OPTIONAL removes solutions</a> */ public void test_ticket_801a_complex_optionals() throws Exception { final TestHelper h = new TestHelper( "test_ticket_801a_complex_optionals", // testURI, "test_ticket_801a_complex_optionals.rq",// queryFileURL "test_ticket_801_complex_optionals.nt",// dataFileURL "test_ticket_801_complex_optionals.srx"// resultFileURL ); // Run test. h.runTest(); } /** * In this variant, one of the child join groups is OPTIONAL rather than * required. This shows the problem reported in the ticket where adding an * OPTIONAL join group reduces the number of solutions. * * <pre> * select ?name * { * { * select ?p * { * ?p a <http://www.example.org/schema/Person> . * optional{?p <http://www.example.org/schema/age> ?age.} * } * LIMIT 1 * } * * {?p <http://www.example.org/schema/name> ?name.} * * OPTIONAL * { ?post a <http://www.example.org/schema/Post> . * ?post <http://www.example.org/schema/postedBy> ?p. * ?post <http://www.example.org/schema/content> ?postContent. * } * OPTIONAL{ * ?comment a <http://www.example.org/schema/Comment> . * ?comment <http://www.example.org/schema/parentPost> ?post. * ?cperson a <http://www.example.org/schema/Person> . * ?comment <http://www.example.org/schema/postedBy> ?cperson . * } * } * </pre> */ public void test_ticket_801b_complex_optionals() throws Exception { final TestHelper h = new TestHelper( "test_ticket_801b_complex_optionals", // testURI, "test_ticket_801b_complex_optionals.rq",// queryFileURL "test_ticket_801_complex_optionals.nt",// dataFileURL "test_ticket_801_complex_optionals.srx"// resultFileURL ); // Run test. h.runTest(); } }