blob: 3c62e8b72e3239efa2a314f53485b4f4055b85e6 [file] [log] [blame]
/*
* 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.algebra;
import java.util.ArrayDeque ;
import java.util.Deque ;
import org.apache.jena.graph.Node ;
import org.apache.jena.sparql.ARQInternalErrorException ;
import org.apache.jena.sparql.algebra.op.OpBGP ;
import org.apache.jena.sparql.algebra.op.OpDistinct ;
import org.apache.jena.sparql.algebra.op.OpGraph ;
import org.apache.jena.sparql.algebra.op.OpQuadPattern ;
import org.apache.jena.sparql.core.Quad ;
import org.apache.jena.sparql.core.Var ;
/** Convert query in algebra form so that the default graph of the query is the union of named graphs */
public class TransformUnionQuery extends TransformCopy
{
public static Op transform(Op op)
{
TransformUnionQuery t = new TransformUnionQuery() ;
Op op2 = Transformer.transform(t, op, new Pusher(t.currentGraph), new Popper(t.currentGraph)) ;
return op2 ;
}
// ** SEE AlgebraQuad : Pusher and Popper :share.
Deque<Node> currentGraph = new ArrayDeque<>() ;
public TransformUnionQuery()
{
currentGraph.push(Quad.defaultGraphNodeGenerated) ;
}
@Override
public Op transform(OpQuadPattern quadPattern)
{
if ( quadPattern.isDefaultGraph() || quadPattern.isUnionGraph() )
{
OpBGP opBGP = new OpBGP(quadPattern.getBasicPattern()) ;
return union(opBGP) ;
}
// Leave alone.
// if ( quadPattern.isExplicitDefaultGraph() ) {}
return super.transform(quadPattern) ;
}
@Override
public Op transform(OpBGP opBGP)
{
Node current = currentGraph.peek();
if ( current == Quad.defaultGraphNodeGenerated || current == Quad.unionGraph )
return union(opBGP) ;
// // Turn into a quad pattern.
// // Not perfect - see AlgebraQuad
// return new OpQuadPattern(currentGraph.peek(), opBGP.getPattern()) ;
// BGP over a named graph.
// Leave as-is.
return super.transform(opBGP) ;
}
private Op union(OpBGP opBGP)
{
// By using the unbinding Var.ANON, the distinct works.
// Else, we get duplicates from projection out of the graph var.
Var v = Var.ANON ; //varAlloc.allocVar() ;
Op op = new OpGraph(v, opBGP) ;
op = OpDistinct.create(op) ;
return op ;
}
@Override
public Op transform(OpGraph opGraph, Op x)
{
// Remove any Quad.unionGraph - OpBGPs will be rewritten.
return super.transform(opGraph, x) ;
}
static class Pusher extends OpVisitorBase
{
private Deque<Node> stack ;
Pusher(Deque<Node> stack) { this.stack = stack ; }
@Override
public void visit(OpGraph opGraph)
{
stack.push(opGraph.getNode()) ;
}
}
static class Popper extends OpVisitorBase
{
private Deque<Node> stack ;
Popper(Deque<Node> stack) { this.stack = stack ; }
@Override
public void visit(OpGraph opGraph)
{
Node n = stack.pop() ;
if ( ! opGraph.getNode().equals(n))
throw new ARQInternalErrorException() ;
}
}
}