/*
* 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.core.sqlexpr;
import org.apache.jena.atlas.io.IndentedWriter ;
import org.apache.jena.sdb.sql.SQLUtils ;
import org.apache.jena.sdb.util.RegexUtils ;
public class SqlExprGenerateSQL implements SqlExprVisitor
{
/* Precedence (from MySQL)
* :=
||, OR, XOR
&&, AND
NOT
BETWEEN, CASE, WHEN, THEN, ELSE
=, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN
|
&
<<, >>
-, +
*, /, DIV, %, MOD
^
- (unary minus), ~ (unary bit inversion)
!
BINARY, COLLATE
*/
/* Decreasing : PostgreSQL
Operator/Element Associativity Description
. left table/column name separator
:: left PostgreSQL-style typecast
[ ] left array element selection
- right unary minus
^ left exponentiation
* / % left multiplication, division, modulo
+ - left addition, subtraction
IS IS TRUE, IS FALSE, IS UNKNOWN, IS NULL
ISNULL test for null
NOTNULL test for not null
(any other) left all other native and user-defined operators
IN set membership
BETWEEN range containment
OVERLAPS time interval overlap
LIKE ILIKE SIMILAR string pattern matching
< > less than, greater than
= right equality, assignment
NOT right logical negation
AND left logical conjunction
OR left logical disjunction
*/
private IndentedWriter out ;
SqlExprGenerateSQL(IndentedWriter out)
{ this.out = out ; }
@Override
public void visit(SqlColumn column) { out.print(column.asString()) ; }
@Override
public void visit(SqlConstant constant) { out.print(constant.asSqlString()) ; }
@Override
public void visit(SqlFunction1 expr)
{
out.print(expr.getFuncSymbol()) ;
out.print("(") ;
expr.getExpr().visit(this) ;
out.print(")") ;
}
@Override
public void visit(SqlExpr1 expr)
{
printExpr(expr.getExpr()) ;
out.print(" ") ;
out.print(expr.getExprSymbol()) ;
}
@Override
public void visit(SqlExpr2 expr)
{
printExpr(expr.getLeft()) ;
out.print(" ") ;
out.print(expr.getOpSymbol()) ;
out.print(" ") ;
printExpr(expr.getRight()) ;
}
@Override
public void visit(S_Like pattern)
{
if ( pattern.isCaseInsensitive() )
{
out.print("lower(") ;
pattern.getExpr().visit(this) ;
out.print(") LIKE ") ;
out.print(SQLUtils.quoteStr(pattern.getPattern().toLowerCase())) ;
}
else
{
pattern.getExpr().visit(this) ;
out.print(" LIKE ") ;
out.print(SQLUtils.quoteStr(pattern.getPattern())) ;
}
return ;
}
public String RegexOperator = "REGEXP" ;
@Override
public void visit(S_Regex regex)
{
// TODO Make per-store dependent for syntax and case sensitiveity reasons.
// including "binary" for MySQL
regex.getExpr().visit(this) ;
String pattern = regex.getPattern() ;
String patternLike = RegexUtils.regexToLike(pattern) ;
if ( patternLike != null )
{
out.print(" LIKE ") ;
out.print(SQLUtils.quoteStr(patternLike)) ;
return ;
}
// MySQL :: LIKE // LIKE BINARY
out.print(" ") ; out.print(RegexOperator) ; out.print(" ") ;
if ( regex.getFlags() != null && ! regex.getFlags().equals("i") )
out.print("BINARY ") ;
out.print(SQLUtils.quoteStr(regex.getPattern())) ;
}
private void printExpr(SqlExpr expr)
{
boolean atomic = expr.isColumn() || expr.isConstant() ;
if ( ! atomic )
out.print("( ") ;
expr.visit(this) ;
if ( ! atomic )
out.print(" )") ;
}
}