/** 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 Mar 2, 2012 */ package com.bigdata.rdf.sail.sparql; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Properties; import java.util.Set; import org.openrdf.model.vocabulary.DC; import org.openrdf.query.MalformedQueryException; import org.openrdf.query.algebra.StatementPattern.Scope; import org.openrdf.query.impl.DatasetImpl; import com.bigdata.rdf.internal.IV; import com.bigdata.rdf.model.BigdataStatement; import com.bigdata.rdf.model.BigdataURI; import com.bigdata.rdf.model.BigdataValue; import com.bigdata.rdf.model.StatementEnum; import com.bigdata.rdf.rio.StatementBuffer; import com.bigdata.rdf.sail.sparql.ast.ParseException; import com.bigdata.rdf.sail.sparql.ast.TokenMgrError; import com.bigdata.rdf.sparql.AbstractBigdataExprBuilderTestCase; import com.bigdata.rdf.sparql.ast.ConstantNode; import com.bigdata.rdf.sparql.ast.DatasetNode; import com.bigdata.rdf.sparql.ast.JoinGroupNode; import com.bigdata.rdf.sparql.ast.ProjectionNode; import com.bigdata.rdf.sparql.ast.QueryRoot; import com.bigdata.rdf.sparql.ast.QueryType; import com.bigdata.rdf.sparql.ast.StatementPatternNode; import com.bigdata.rdf.sparql.ast.VarNode; import com.bigdata.rdf.store.AbstractTripleStore; import com.bigdata.rdf.store.BD; import com.bigdata.rdf.vocab.decls.FOAFVocabularyDecl; /** * Test suite for the <code>VIRTUAL GRAPHS</code> SPARQL extension. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public class TestVirtualGraphs extends AbstractBigdataExprBuilderTestCase { public TestVirtualGraphs() { } public TestVirtualGraphs(String name) { super(name); } /** * Overridden to setup a quads mode instance. */ @Override protected Properties getProperties() { final Properties properties = new Properties(super.getProperties()); properties.setProperty(AbstractTripleStore.Options.QUADS_MODE, "true"); return properties; } /** * <pre> * PREFIX foaf: <http://xmlns.com/foaf/0.1/> * PREFIX dc: <http://purl.org/dc/elements/1.1/> * SELECT ?who ?g ?mbox * FROM <http://example.org/dft.ttl> * FROM NAMED VIRTUAL GRAPH :vg * WHERE * { * ?g dc:publisher ?who . * GRAPH ?g { ?x foaf:mbox ?mbox } * } * </pre> * * Where the membership in the KB for :vg is * * <pre> * <http://example.org/alice> * <http://example.org/bob> * </pre> * * Note: This should be turned into exactly the same AST as the * {@link #test_from_and_from_named()} test. The virtual graph definition is * expanded with the same effect as the original FROM NAMED clauses. * * @throws ParseException * @throws TokenMgrError * @throws MalformedQueryException */ public void test_virtualGraphs_01() throws MalformedQueryException, TokenMgrError, ParseException { final String sparql = "" + // "PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n" + // "PREFIX dc: <http://purl.org/dc/elements/1.1/>\n" + // "SELECT ?who ?g ?mbox\n" + // "FROM <http://example.org/dft.ttl>\n" + // "FROM NAMED VIRTUAL GRAPH <http://example.org/vg>\n" + // // "FROM NAMED <http://example.org/alice>\n" + // // "FROM NAMED <http://example.org/bob>\n" + // "WHERE {\n" + // " ?g dc:publisher ?who .\n" + // " GRAPH ?g { ?x foaf:mbox ?mbox } \n" + // "}"// ; /* * Setup the virtual graph associations in the data. */ final BigdataURI virtualGraph = valueFactory.asValue(BD.VIRTUAL_GRAPH); final BigdataURI vg = valueFactory .createURI("http://example.org/vg"); final BigdataURI context = valueFactory .createURI("http://www.bigdata.com/context"); final BigdataURI uri1 = valueFactory .createURI("http://example.org/dft.ttl"); final BigdataURI alice = valueFactory .createURI("http://example.org/alice"); final BigdataURI bob = valueFactory.createURI("http://example.org/bob"); /* * Most URIs wind up declared when we insert the statements, but not * [uri1]. Also, none of them wind up with the IVCache set unless we do * that explicitly. */ { final BigdataValue[] values = new BigdataValue[] { virtualGraph, vg, context, uri1, alice, bob }; tripleStore.getLexiconRelation().addTerms(values, values.length, false/* readOnly */); // // Cache the Value on the IV. // for(BigdataValue v : values) { // v.getIV().setValue(v); // } } // Insert the statements. { final StatementBuffer<BigdataStatement> sb = new StatementBuffer<BigdataStatement>( tripleStore, 10/* capacity */); sb.add(valueFactory.createStatement(vg, virtualGraph, alice, context, StatementEnum.Explicit)); sb.add(valueFactory.createStatement(vg, virtualGraph, bob, context, StatementEnum.Explicit)); sb.flush(); } final QueryRoot expected = new QueryRoot(QueryType.SELECT); { { final Map<String, String> prefixDecls = new LinkedHashMap<String, String>(PrefixDeclProcessor.defaultDecls); prefixDecls.put("foaf", FOAFVocabularyDecl.NAMESPACE); prefixDecls.put("dc", DC.NAMESPACE); expected.setPrefixDecls(prefixDecls); } { final ProjectionNode projection = new ProjectionNode(); expected.setProjection(projection); projection.addProjectionVar(new VarNode("who")); projection.addProjectionVar(new VarNode("g")); projection.addProjectionVar(new VarNode("mbox")); } { final DatasetImpl dataset = new DatasetImpl(); dataset.addDefaultGraph(uri1); dataset.addNamedGraph(alice); dataset.addNamedGraph(bob); final DatasetNode datasetNode = new DatasetNode(dataset, false/* update */); expected.setDataset(datasetNode); } { final JoinGroupNode whereClause = new JoinGroupNode(); expected.setWhereClause(whereClause); whereClause.addChild(new StatementPatternNode(new VarNode("g"), new ConstantNode(makeIV(valueFactory.createURI(DC.PUBLISHER .toString()))), new VarNode("who"), null/* c */, Scope.DEFAULT_CONTEXTS)); final JoinGroupNode group = new JoinGroupNode(); whereClause.addChild(group); group.setContext(new VarNode("g")); group.addChild(new StatementPatternNode( new VarNode("x"), new ConstantNode(makeIV(valueFactory .createURI(FOAFVocabularyDecl.mbox.toString()))), new VarNode("mbox"), new VarNode("g"), Scope.NAMED_CONTEXTS)); } } final QueryRoot actual = parse(sparql, baseURI); assertSameAST(sparql, expected, actual); } /** * <pre> * PREFIX foaf: <http://xmlns.com/foaf/0.1/> * PREFIX dc: <http://purl.org/dc/elements/1.1/> * SELECT ?who ?g ?mbox * FROM <http://example.org/dft.ttl> * FROM VIRTUAL GRAPH :vg * WHERE * { * ?g dc:publisher ?who . * GRAPH ?g { ?x foaf:mbox ?mbox } * } * </pre> * * Where the membership in the KB for :vg is * * <pre> * <http://example.org/alice> * <http://example.org/bob> * </pre> * * Note: This is similar to the above test, but verifies that the virtual * graph declaration is expanded into the default graph membership for the * dataset. This test also verifies that the FROM and FROM VIRTUAL GRAPH * clauses may be combined freely. * * @throws ParseException * @throws TokenMgrError * @throws MalformedQueryException */ public void test_virtualGraphs_02() throws MalformedQueryException, TokenMgrError, ParseException { final String sparql = "" + // "PREFIX foaf: <http://xmlns.com/foaf/0.1/>\n" + // "PREFIX dc: <http://purl.org/dc/elements/1.1/>\n" + // "SELECT ?who ?g ?mbox\n" + // "FROM <http://example.org/dft.ttl>\n" + // "FROM VIRTUAL GRAPH <http://example.org/vg>\n" + // "WHERE {\n" + // " ?g dc:publisher ?who .\n" + // " GRAPH ?g { ?x foaf:mbox ?mbox } \n" + // "}"// ; /* * Setup the virtual graph associations in the data. */ final BigdataURI virtualGraph = valueFactory.asValue(BD.VIRTUAL_GRAPH); final BigdataURI vg = valueFactory .createURI("http://example.org/vg"); final BigdataURI context = valueFactory .createURI("http://www.bigdata.com/context"); final BigdataURI uri1 = valueFactory .createURI("http://example.org/dft.ttl"); final BigdataURI alice = valueFactory .createURI("http://example.org/alice"); final BigdataURI bob = valueFactory.createURI("http://example.org/bob"); /* * Most URIs wind up declared when we insert the statements, but not * [uri1]. Also, none of them wind up with the IVCache set unless we do * that explicitly. */ { final BigdataValue[] values = new BigdataValue[] { virtualGraph, vg, context, uri1, alice, bob }; tripleStore.getLexiconRelation().addTerms(values, values.length, false/* readOnly */); // // Cache the Value on the IV. // for(BigdataValue v : values) { // v.getIV().setValue(v); // } } // Insert the statements. { final StatementBuffer<BigdataStatement> sb = new StatementBuffer<BigdataStatement>( tripleStore, 10/* capacity */); sb.add(valueFactory.createStatement(vg, virtualGraph, alice, context, StatementEnum.Explicit)); sb.add(valueFactory.createStatement(vg, virtualGraph, bob, context, StatementEnum.Explicit)); sb.flush(); } final QueryRoot expected = new QueryRoot(QueryType.SELECT); { { final Map<String, String> prefixDecls = new LinkedHashMap<String, String>(PrefixDeclProcessor.defaultDecls); prefixDecls.put("foaf", FOAFVocabularyDecl.NAMESPACE); prefixDecls.put("dc", DC.NAMESPACE); expected.setPrefixDecls(prefixDecls); } { final ProjectionNode projection = new ProjectionNode(); expected.setProjection(projection); projection.addProjectionVar(new VarNode("who")); projection.addProjectionVar(new VarNode("g")); projection.addProjectionVar(new VarNode("mbox")); } { /* * Note: There is some sensitivity to the distinction between an * empty named graph collection or an empty default graph * collection and a [null] reference. I am not yet convinced * that the code is laid out correctly here, in the * DataSetDeclProcessor, or in the DatasetNode class. * * Note: The IVCache on alice and bob must be cleared since the * Value is not resolved when we resolve the virtual graph IV to * the IVs of the virtual graph membership. */ // final BigdataURI alice2 = valueFactory.createURI(alice // .stringValue()); // alice2.setIV(alice.getIV().clone(true/* clearCache */)); // final BigdataURI bob2 = valueFactory.createURI(bob // .stringValue()); // bob2.setIV(bob.getIV().clone(true/* clearCache */)); @SuppressWarnings("rawtypes") final Set<IV> defaultGraphs = new LinkedHashSet<IV>(); defaultGraphs.add(uri1.getIV()); defaultGraphs.add(alice.getIV().clone(true/*clearCache*/)); defaultGraphs.add(bob.getIV().clone(true/*clearCache*/)); final DatasetNode datasetNode = new DatasetNode(defaultGraphs, null/* namedGraphs */, false/* update */); expected.setDataset(datasetNode); } { final JoinGroupNode whereClause = new JoinGroupNode(); expected.setWhereClause(whereClause); whereClause.addChild(new StatementPatternNode(new VarNode("g"), new ConstantNode(makeIV(valueFactory.createURI(DC.PUBLISHER .toString()))), new VarNode("who"), null/* c */, Scope.DEFAULT_CONTEXTS)); final JoinGroupNode group = new JoinGroupNode(); whereClause.addChild(group); group.setContext(new VarNode("g")); group.addChild(new StatementPatternNode( new VarNode("x"), new ConstantNode(makeIV(valueFactory .createURI(FOAFVocabularyDecl.mbox.toString()))), new VarNode("mbox"), new VarNode("g"), Scope.NAMED_CONTEXTS)); } } final QueryRoot actual = parse(sparql, baseURI); assertSameAST(sparql, expected, actual); } }