/*
* #!
* Ontopia Engine
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* Licensed 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 net.ontopia.persistence.query.sql;
import net.ontopia.utils.OntopiaRuntimeException;
/**
* INTERNAL: Class used to build SQL queries from JDO queries.
*/
public abstract class AbstractSQLOptimizer {
protected void analyzeExpressions(SQLExpressionIF[] exprs) {
// Loop over SQL expressions and analyze them individually
for (int i=0; i < exprs.length; i++) {
analyzeExpression(exprs[i]);
}
}
protected void analyzeExpression(SQLExpressionIF sqlexpr) {
if (sqlexpr == null) return;
switch (sqlexpr.getType()) {
case SQLExpressionIF.AND:
analyzeAnd((SQLAnd)sqlexpr);
break;
case SQLExpressionIF.EQUALS:
analyzeEquals((SQLEquals)sqlexpr);
break;
case SQLExpressionIF.EXISTS:
analyzeExists((SQLExists)sqlexpr);
break;
case SQLExpressionIF.FALSE:
analyzeFalse((SQLFalse)sqlexpr);
break;
case SQLExpressionIF.IN:
analyzeIn((SQLIn)sqlexpr);
break;
case SQLExpressionIF.IS_NULL:
analyzeIsNull((SQLIsNull)sqlexpr);
break;
case SQLExpressionIF.JOIN:
analyzeJoin((SQLJoin)sqlexpr);
break;
case SQLExpressionIF.LIKE:
analyzeLike((SQLLike)sqlexpr);
break;
case SQLExpressionIF.NOT:
analyzeNot((SQLNot)sqlexpr);
break;
case SQLExpressionIF.NOT_EQUALS:
analyzeNotEquals((SQLNotEquals)sqlexpr);
break;
case SQLExpressionIF.OR:
analyzeOr((SQLOr)sqlexpr);
break;
case SQLExpressionIF.SET_OPERATION:
analyzeSetOperation((SQLSetOperation)sqlexpr);
break;
case SQLExpressionIF.VERBATIM:
analyzeVerbatimExpression((SQLVerbatimExpression)sqlexpr);
break;
case SQLExpressionIF.VALUE_EXPRESSION:
analyzeValueExpression((SQLValueExpression)sqlexpr);
break;
default:
throw new OntopiaRuntimeException("Invalid SQLExpressionIF: '" + sqlexpr + "'");
}
}
protected void analyzeAnd(SQLAnd expr) {
analyzeExpressions(expr.getExpressions());
}
protected void analyzeEquals(SQLEquals expr) {
analyzeValue(expr.getLeft());
analyzeValue(expr.getRight());
}
protected void analyzeExists(SQLExists expr) {
analyzeExpression(expr.getExpression());
}
protected void analyzeFalse(SQLFalse expr) {
}
protected void analyzeIn(SQLIn expr) {
analyzeValue(expr.getLeft());
analyzeValue(expr.getRight());
}
protected void analyzeIsNull(SQLIsNull expr) {
analyzeValue(expr.getValue());
}
protected void analyzeJoin(SQLJoin expr) {
analyzeValue(expr.getLeft());
analyzeValue(expr.getRight());
}
protected void analyzeLike(SQLLike expr) {
analyzeValue(expr.getLeft());
analyzeValue(expr.getRight());
}
protected void analyzeNot(SQLNot expr) {
analyzeExpression(expr.getExpression());
}
protected void analyzeNotEquals(SQLNotEquals expr) {
analyzeValue(expr.getLeft());
analyzeValue(expr.getRight());
}
protected void analyzeOr(SQLOr expr) {
analyzeExpressions(expr.getExpressions());
}
protected void analyzeSetOperation(SQLSetOperation expr) {
// TODO: Analyze individual queries
}
protected void analyzeVerbatimExpression(SQLVerbatimExpression expr) {
}
protected void analyzeValueExpression(SQLValueExpression expr) {
analyzeValue(expr.getValue());
}
protected void analyzeValues(SQLValueIF[] values) {
// Loop over SQL values and analyze them individually
for (int i=0; i < values.length; i++) {
analyzeValue(values[i]);
}
}
protected void analyzeValue(SQLValueIF sqlvalue) {
if (sqlvalue == null) return;
switch (sqlvalue.getType()) {
case SQLValueIF.COLUMNS:
analyzeColumns((SQLColumns)sqlvalue);
break;
case SQLValueIF.NULL:
analyzeNull((SQLNull)sqlvalue);
break;
case SQLValueIF.PARAMETER:
analyzeParameter((SQLParameter)sqlvalue);
break;
case SQLValueIF.PRIMITIVE:
analyzePrimitive((SQLPrimitive)sqlvalue);
break;
case SQLValueIF.TUPLE:
analyzeTuple((SQLTuple)sqlvalue);
break;
case SQLValueIF.VERBATIM:
analyzeVerbatim((SQLVerbatim)sqlvalue);
break;
case SQLValueIF.FUNCTION:
analyzeFunction((SQLFunction)sqlvalue);
break;
default:
throw new OntopiaRuntimeException("Invalid SQLValueIF: '" + sqlvalue + "'");
}
}
protected void analyzeColumns(SQLColumns value) {
}
protected void analyzeNull(SQLNull value) {
}
protected void analyzeParameter(SQLParameter value) {
}
protected void analyzePrimitive(SQLPrimitive value) {
}
protected void analyzeTuple(SQLTuple value) {
analyzeValues(value.getValues());
}
protected void analyzeVerbatim(SQLVerbatim value) {
}
protected void analyzeFunction(SQLFunction value) {
analyzeValues(value.getArguments());
}
protected int optimizeExpression(SQLExpressionIF sqlexpr) {
switch (sqlexpr.getType()) {
case SQLExpressionIF.AND:
return optimizeAnd((SQLAnd)sqlexpr);
case SQLExpressionIF.EQUALS:
return optimizeEquals((SQLEquals)sqlexpr);
case SQLExpressionIF.EXISTS:
return optimizeExists((SQLExists)sqlexpr);
case SQLExpressionIF.FALSE:
return optimizeFalse((SQLFalse)sqlexpr);
case SQLExpressionIF.IN:
return optimizeIn((SQLIn)sqlexpr);
case SQLExpressionIF.IS_NULL:
return optimizeIsNull((SQLIsNull)sqlexpr);
case SQLExpressionIF.JOIN:
return optimizeJoin((SQLJoin)sqlexpr);
case SQLExpressionIF.LIKE:
return optimizeLike((SQLLike)sqlexpr);
case SQLExpressionIF.NOT:
return optimizeNot((SQLNot)sqlexpr);
case SQLExpressionIF.NOT_EQUALS:
return optimizeNotEquals((SQLNotEquals)sqlexpr);
case SQLExpressionIF.OR:
return optimizeOr((SQLOr)sqlexpr);
case SQLExpressionIF.SET_OPERATION:
return optimizeSetOperation((SQLSetOperation)sqlexpr);
case SQLExpressionIF.VERBATIM:
return optimizeVerbatimExpression((SQLVerbatimExpression)sqlexpr);
case SQLExpressionIF.VALUE_EXPRESSION:
return optimizeValueExpression((SQLValueExpression)sqlexpr);
default:
throw new OntopiaRuntimeException("Invalid SQLExpressionIF: '" + sqlexpr + "'");
}
}
protected int optimizeAnd(SQLAnd expr) {
int totcount = 0;
int truecount = 0;
// NOTE: is true if all subexpressions are true
SQLExpressionIF[] exprs = expr.getExpressions();
for (int i=0; i < exprs.length; i++) {
if (exprs[i] == null) continue;
totcount++;
int result = optimizeExpression(exprs[i]);
// Remove removable expression
if (result == 1) {
exprs[i] = null;
truecount++;
}
else if (result == -1)
return -1;
}
// If all subexpressions are true so is the whole expression,
// otherwise it is non-optimizable.
if (totcount == truecount)
return 1;
else
return 0;
}
protected int optimizeEquals(SQLEquals expr) {
return 0;
}
protected int optimizeExists(SQLExists expr) {
return optimizeExpression(expr.getExpression());
}
protected int optimizeFalse(SQLFalse expr) {
return 0;
}
protected int optimizeIn(SQLIn expr) {
//! optimizeValue(expr.getLeft());
//! optimizeValue(expr.getRight());
return 0;
}
protected int optimizeIsNull(SQLIsNull expr) {
//! optimizeValue(expr.getValue());
return 0;
}
protected int optimizeJoin(SQLJoin expr) {
// ISSUE: Same optimization as for SQLEqual?
//! optimizeValue(expr.getLeft());
//! optimizeValue(expr.getRight());
return 0;
}
protected int optimizeLike(SQLLike expr) {
//! optimizeValue(expr.getLeft());
//! optimizeValue(expr.getRight());
return 0;
}
protected int optimizeNot(SQLNot expr) {
return optimizeExpression(expr.getExpression());
}
protected int optimizeNotEquals(SQLNotEquals expr) {
return 0;
}
protected int optimizeOr(SQLOr expr) {
int totcount = 0;
int falsecount = 0;
// NOTE: is true if any of the subexpressions are true
SQLExpressionIF[] exprs = expr.getExpressions();
for (int i=0; i < exprs.length; i++) {
if (exprs[i] == null) continue;
totcount++;
int result = optimizeExpression(exprs[i]);
// Remove removable expression
if (result == 1)
return 1;
else if (result == -1) {
exprs[i] = null;
falsecount++;
}
}
// If all subexpressions are false so is the whole expression,
// otherwise it is non-optimizable.
if (totcount == falsecount)
return 1;
else
return 0;
}
protected int optimizeSetOperation(SQLSetOperation expr) {
// TODO: Optimize individual queries
return 0;
}
protected int optimizeVerbatimExpression(SQLVerbatimExpression expr) {
return 0;
}
protected int optimizeValueExpression(SQLValueExpression expr) {
return 0;
}
//! protected int optimizeValues(SQLValueIF[] values) {
//! // Loop over SQL values and optimize them individually
//! for (int i=0; i < values.length; i++) {
//! optimizeValue(values[i]);
//! }
//! }
//!
//! protected int optimizeValue(SQLValueIF sqlvalue) {
//! switch (sqlvalue.getType()) {
//! case SQLValueIF.COLUMNS:
//! return optimizeColumns((SQLColumns)sqlvalue);
//! case SQLValueIF.NULL:
//! return optimizeNull((SQLNull)sqlvalue);
//! case SQLValueIF.PARAMETER:
//! return optimizeParameter((SQLParameter)sqlvalue);
//! case SQLValueIF.PRIMITIVE:
//! return optimizePrimitive((SQLPrimitive)sqlvalue);
//! case SQLValueIF.TUPLE:
//! return optimizeTuple((SQLTuple)sqlvalue);
//! case SQLValueIF.VERBATIM:
//! return optimizeVerbatim((SQLVerbatim)sqlvalue);
//! case SQLValueIF.FUNCTION:
//! return optimizeFunction((SQLFunction)sqlvalue);
//! default:
//! throw new OntopiaRuntimeException("Invalid SQLValueIF: '" + sqlvalue + "'");
//! }
//! }
//!
//! protected int optimizeColumns(SQLColumns value) {
//! }
//!
//! protected int optimizeNull(SQLNull value) {
//! }
//!
//! protected int optimizeParameter(SQLParameter value) {
//! }
//!
//! protected int optimizePrimitive(SQLPrimitive value) {
//! }
//!
//! protected int optimizeTuple(SQLTuple value) {
//! }
//!
//! protected int optimizeVerbatim(SQLVerbatim value) {
//! SQLTable[] tables = value.getTables();
//! for (int i=0; i < tables.length; i++) {
//! addTable(tables[i]);
//! }
//! }
//!
//! protected int optimizeFunction(SQLFunction value) {
//! ...
//! }
}