org.apache.jena.sdb.layout2.QueryCompiler2 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jena-sdb Show documentation
Show all versions of jena-sdb Show documentation
SDB is a persistence layer for use with Apache Jena that uses an SQL database to store triples/quads.
/*
* 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.sdb.layout2;
import org.apache.jena.sdb.compiler.OpSQL ;
import org.apache.jena.sdb.compiler.QueryCompilerMain ;
import org.apache.jena.sdb.compiler.SDB_QC ;
import org.apache.jena.sdb.core.SDBRequest ;
import org.apache.jena.sdb.core.ScopeEntry ;
import org.apache.jena.sdb.core.sqlexpr.S_Like ;
import org.apache.jena.sdb.core.sqlexpr.SqlColumn ;
import org.apache.jena.sdb.core.sqlnode.SqlNode ;
import org.apache.jena.sdb.core.sqlnode.SqlSelectBlock ;
import org.apache.jena.sdb.util.RegexUtils ;
import org.apache.jena.sparql.algebra.Op ;
import org.apache.jena.sparql.algebra.Transform ;
import org.apache.jena.sparql.algebra.TransformCopy ;
import org.apache.jena.sparql.algebra.Transformer ;
import org.apache.jena.sparql.algebra.op.OpFilter ;
import org.apache.jena.sparql.core.Var ;
import org.apache.jena.sparql.expr.E_Regex ;
import org.apache.jena.sparql.expr.Expr ;
import org.apache.jena.sparql.expr.ExprList ;
// Common processing for all layout2 forms.
public abstract class QueryCompiler2 extends QueryCompilerMain
{
public QueryCompiler2(SDBRequest request)
{
super(request) ;
}
@Override
protected Op postProcessSQL(Op op)
{
// Modifiers: the structure is:
// slice
// distinct/reduced
// project
// order
// having
// group
// [toList]
// Look for certain structures we can do especially well.
// (slice (filter regex (...)))
// (filter regex)
// Must be done filter changes then limit/offset changes.
// Looks for (filter ... (sql ...))
op = rewriteFilters(op, request) ;
// (slice (distinct ...)) done as two steps.
// (distinct ....
op = rewriteDistinct(op, request) ;
// Order
op = rewriteOrder(op, request);
// Look for (slice ...) or (slice (project ...))
op = rewriteLimitOffset(op, request) ;
return op ;
}
// See if theer are any filter operations we can move all or part of into SQL.
protected static Op rewriteFilters(Op op, SDBRequest request)
{
Transform t = new FilterOptimizer(request) ;
return Transformer.transform(t, op) ;
}
// Find variables that need to be returned.
private static class FilterOptimizer extends TransformCopy
{
private final SDBRequest request ;
public FilterOptimizer(SDBRequest request)
{ this.request = request ; }
@Override
public Op transform(OpFilter opFilter, Op op)
{
if ( ! SDB_QC.isOpSQL(op) )
return super.transform(opFilter, op) ;
SqlNode sqlNode = ((OpSQL)op).getSqlNode() ;
if ( ! sqlNode.isSelectBlock() )
return super.transform(opFilter, op) ;
SqlSelectBlock ssb = sqlNode.asSelectBlock() ;
ExprList exprs = opFilter.getExprs() ;
ExprList exprs2 = new ExprList() ;
for ( Object obj : exprs.getList() )
{
Expr expr = (Expr)obj ;
Expr expr2 = convert(expr, ssb, (OpSQL)op) ;
// Not all filter conversions are complete - only a partial constraint
// may have been added to the SQL meaning the expr must still be done
// in ARQ to get exact semantic but hopefully on much less data
if ( expr2 != null )
exprs2.add(expr2) ;
}
return OpFilter.filterBy(exprs2, op) ;
}
// return null for don't need an expr anymore.
private Expr convert(Expr expr, SqlSelectBlock ssb, OpSQL opSQL)
{
if ( ! ( expr instanceof E_Regex ) )
return expr ;
E_Regex regex = (E_Regex)expr ;
Expr exprPattern = regex.getArg(2) ;
Expr exprFlags = ( regex.getArg(3) == null ? null : regex.getArg(3) ) ;
boolean caseInsensitive = false ;
// Any flags?
if ( exprFlags != null )
{
// Expression for flags?
if ( ! exprFlags.isConstant() ) return expr ;
String flags = exprFlags.getConstant().asString() ;
if ( ! "i".equals(flags) ) return expr ;
caseInsensitive = true ;
}
// Check pattern - must be a constant string
if ( !exprPattern.isConstant() ) return expr ;
String pattern = exprPattern.getConstant().asString() ;
if ( pattern == null ) return expr ;
// See if it's LIKEable.
String patternLike = RegexUtils.regexToLike(pattern) ;
if ( patternLike == null )
return expr ;
// Check target
// BUG in old ARQ getRegexExpr() returns the wrong thing.
if ( ! regex.getArg(1).isVariable() ) return expr ;
Var v = regex.getArg(1).asVar() ;
// Scope check
if ( ! ssb.getNodeScope().hasColumnForVar(v) )
// Probably out of scope - or just not in the graph apttern.
return expr ;
// Find the column for this variable.
ScopeEntry sc = ssb.getNodeScope().findScopeForVar(v) ;
// Get the lexical column : this is layout2 specific.
SqlColumn col = new SqlColumn(sc.getColumn().getTable(), "lex") ;
S_Like sreg = new S_Like(col, patternLike, caseInsensitive) ;
ssb.getConditions().add(sreg) ;
// Completely replace the filter - so remove from OpFilter.
return null ;
}
}
}