/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jena.sparql.engine.ref; import java.util.ArrayList ; import java.util.Iterator ; import java.util.List ; import org.apache.jena.atlas.lib.InternalErrorException ; import org.apache.jena.graph.Graph ; import org.apache.jena.graph.Node ; import org.apache.jena.query.ARQ ; import org.apache.jena.sparql.ARQInternalErrorException ; import org.apache.jena.sparql.algebra.Op ; import org.apache.jena.sparql.algebra.Table ; import org.apache.jena.sparql.algebra.TableFactory ; import org.apache.jena.sparql.algebra.op.OpDatasetNames ; import org.apache.jena.sparql.algebra.op.OpGraph ; import org.apache.jena.sparql.algebra.op.OpQuadPattern ; import org.apache.jena.sparql.algebra.table.TableEmpty ; import org.apache.jena.sparql.algebra.table.TableUnit ; import org.apache.jena.sparql.core.BasicPattern ; import org.apache.jena.sparql.core.DatasetGraph ; import org.apache.jena.sparql.core.Var ; import org.apache.jena.sparql.engine.ExecutionContext ; import org.apache.jena.sparql.engine.QueryIterator ; import org.apache.jena.sparql.engine.binding.Binding ; import org.apache.jena.sparql.engine.binding.BindingFactory ; import org.apache.jena.sparql.engine.binding.BindingRoot ; import org.apache.jena.sparql.engine.iterator.QueryIterConcat ; import org.apache.jena.sparql.engine.iterator.QueryIterDistinguishedVars ; import org.apache.jena.sparql.engine.iterator.QueryIterPlainWrapper ; import org.apache.jena.sparql.engine.iterator.QueryIterRoot ; import org.apache.jena.sparql.engine.main.StageBuilder ; import org.apache.jena.sparql.engine.main.StageGenerator ; // Spit out a few of the longer ops. public class Eval { public static Table eval(Evaluator evaluator, Op op) { EvaluatorDispatch ev = new EvaluatorDispatch(evaluator) ; op.visit(ev) ; Table table = ev.getResult() ; return table ; } static Table evalDS(OpDatasetNames opDSN, Evaluator evaluator) { Node graphNode = opDSN.getGraphNode() ; if ( graphNode.isURI() ) { if ( evaluator.getExecContext().getDataset().containsGraph(graphNode) ) { return new TableUnit() ; } else // WRONG { return new TableEmpty() ; } } if ( ! Var.isVar(graphNode) ) throw new ARQInternalErrorException("OpDatasetNames: Not a URI or variable: "+graphNode) ; DatasetGraph dsg = evaluator.getExecContext().getDataset() ; Iterator<Node> iter = dsg.listGraphNodes() ; List<Binding> list = new ArrayList<>((int)dsg.size()) ; for ( ; iter.hasNext(); ) { Node gn = iter.next(); Binding b = BindingFactory.binding(Var.alloc(graphNode), gn) ; list.add(b) ; } QueryIterator qIter = new QueryIterPlainWrapper(list.iterator(), evaluator.getExecContext()) ; return TableFactory.create(qIter) ; } static Table evalGraph(OpGraph opGraph, Evaluator evaluator) { ExecutionContext execCxt = evaluator.getExecContext() ; if ( ! Var.isVar(opGraph.getNode()) ) { DatasetGraph dsg = execCxt.getDataset() ; Node graphNode = opGraph.getNode() ; if ( ! dsg.containsGraph(graphNode) ) return new TableEmpty() ; Graph graph = execCxt.getDataset().getGraph(opGraph.getNode()) ; if ( graph == null ) // But contains was true?!! throw new InternalErrorException("Graph was present, now it's not") ; ExecutionContext execCxt2 = new ExecutionContext(execCxt, graph) ; Evaluator e2 = EvaluatorFactory.create(execCxt2) ; return eval(e2, opGraph.getSubOp()) ; } // Graph node is a variable. Var gVar = Var.alloc(opGraph.getNode()) ; Table current = null ; for ( Iterator<Node> iter = execCxt.getDataset().listGraphNodes() ; iter.hasNext() ; ) { Node gn = iter.next(); Graph graph = execCxt.getDataset().getGraph(gn) ; ExecutionContext execCxt2 = new ExecutionContext(execCxt, graph) ; Evaluator e2 = EvaluatorFactory.create(execCxt2) ; Table tableVarURI = TableFactory.create(gVar, gn) ; // Evaluate the pattern, join with this graph node possibility. // XXX If Var.ANON then no-opt. Table patternTable = eval(e2, opGraph.getSubOp()) ; Table stepResult = evaluator.join(patternTable, tableVarURI) ; if ( current == null ) current = stepResult ; else current = evaluator.union(current, stepResult) ; } if ( current == null ) // Nothing to loop over return new TableEmpty() ; return current ; } static Table evalQuadPattern(OpQuadPattern opQuad, Evaluator evaluator) { if ( opQuad.isEmpty() ) return TableFactory.createUnit() ; ExecutionContext cxt = evaluator.getExecContext() ; DatasetGraph ds = cxt.getDataset() ; BasicPattern pattern = opQuad.getBasicPattern() ; if ( ! opQuad.getGraphNode().isVariable() ) { if ( ! opQuad.getGraphNode().isURI() ) { throw new ARQInternalErrorException("Not a URI or variable: "+opQuad.getGraphNode()) ;} Graph g = null ; if ( opQuad.isDefaultGraph() ) g = ds.getDefaultGraph() ; else g = ds.getGraph(opQuad.getGraphNode()) ; if ( g == null ) return new TableEmpty() ; ExecutionContext cxt2 = new ExecutionContext(cxt, g) ; QueryIterator qIter = executeBGP(pattern, QueryIterRoot.create(cxt2), cxt2) ; return TableFactory.create(qIter) ; } else { // Variable. Var gVar = Var.alloc(opQuad.getGraphNode()) ; // Or just just devolve to OpGraph and get OpUnion chain of OpJoin QueryIterConcat concat = new QueryIterConcat(cxt) ; for ( Iterator<Node> graphNodes = cxt.getDataset().listGraphNodes() ; graphNodes.hasNext(); ) { Node gn = graphNodes.next() ; //Op tableVarURI = TableFactory.create(gn.getName(), Node.createURI(uri)) ; Graph g = cxt.getDataset().getGraph(gn) ; Binding b = BindingFactory.binding(BindingRoot.create(), gVar, gn) ; ExecutionContext cxt2 = new ExecutionContext(cxt, g) ; // Eval the pattern, eval the variable, join. // Pattern may be non-linear in the variable - do a pure execution. Table t1 = TableFactory.create(gVar, gn) ; QueryIterator qIter = executeBGP(pattern, QueryIterRoot.create(cxt2), cxt2) ; Table t2 = TableFactory.create(qIter) ; Table t3 = evaluator.join(t1, t2) ; concat.add(t3.iterator(cxt2)) ; } return TableFactory.create(concat) ; } } private static QueryIterator executeBGP(BasicPattern pattern, QueryIterator input, ExecutionContext execCxt) { if (pattern.isEmpty()) return input ; boolean hideBNodeVars = execCxt.getContext().isTrue(ARQ.hideNonDistiguishedVariables) ; StageGenerator gen = StageBuilder.executeInline ; QueryIterator qIter = gen.execute(pattern, input, execCxt) ; // Remove non-distinguished variables here. // Project out only named variables. if (hideBNodeVars) qIter = new QueryIterDistinguishedVars(qIter, execCxt) ; return qIter ; } // This is for an arbitrary quad collection. // Downside is that each quad is solved separtely, not in a BGP. // This breaks property functions with list arguments // and extension to entailment regimes which as DL. // public Table evalAny(Evaluator evaluator) // { // if ( getQuads().size() == 0 ) // return TableFactory.createUnit().eval(evaluator) ; // // ExecutionContext cxt = evaluator.getExecContext() ; // DatasetGraph ds = cxt.getDataset() ; // //Table working = TableFactory.createUnit().eval(evaluator) ; // Table working = null ; // for ( Iterator iter = quads.iterator() ; iter.hasNext() ; ) // { // Quad quad = (Quad)iter.next() ; // Table nextTable = oneStep(quad, cxt) ; // if ( working != null ) // working = evaluator.join(working, nextTable) ; // else // working = nextTable ; // } // return working ; // } // // private Table oneStep(Quad quad, ExecutionContext cxt) // { // Node gn = quad.getGraph() ; // DatasetGraph ds = cxt.getDataset() ; // if ( ! gn.isVariable() ) // { // if ( ! gn.isURI() ) // throw new ARQInternalErrorException("Not a URI or variable: "+gn) ; // // Graph g = gn.equals(AlgebraCompilerQuad.defaultGraph) ? // ds.getDefaultGraph() : // ds.getNamedGraph(gn.getURI()) ; // // if ( g == null ) // return new TableEmpty() ; // // ExecutionContext cxt2 = new ExecutionContext(cxt, g) ; // // A BGP of one triple ensure property functions are processed. // // QueryIterator qIter = new QueryIterTriplePattern(OpBGP.makeRoot(cxt2), quad.getTriple(), cxt2) ; // // return TableFactory.create(qIter) ; // // // Alt : gather adjacent quads with the same graph node. // // Then blank node projection can be done. // // // Create a BGP of one to sort property functions out. // // ** Projecting blank nodes must be off. // ElementBasicGraphPattern bgp = new ElementBasicGraphPattern() ; // bgp.addTriple(quad.getTriple()) ; // PlanElement planElt = PlanBasicGraphPattern.make(cxt.getContext(), bgp) ; // return TableFactory. // create(planElt.build(Algebra.makeRoot(cxt2), cxt2)) ; // } // else // { // // Or just just devolve to OpGraph and get OpUnion chain of OpJoin // QueryIterConcat concat = new QueryIterConcat(cxt) ; // for ( Iterator graphURIs = cxt.getDataset().listNames() ; graphURIs.hasNext(); ) // { // String uri = (String)graphURIs.next() ; // //Op tableVarURI = TableFactory.create(gn.getName(), Node.createURI(uri)) ; // // Graph g = cxt.getDataset().getNamedGraph(uri) ; // Binding b = new Binding1(BindingRoot.create(), gn.getName(), Node.createURI(uri)) ; // QueryIterator qIter1 = new QueryIterSingleton(b, cxt) ; // ExecutionContext cxt2 = new ExecutionContext(cxt, g) ; // QueryIterator qIter = new QueryIterTriplePattern(qIter1, quad.getTriple(), cxt2) ; // concat.add(qIter) ; // } // return TableFactory.create(concat) ; // } // // } }