/*
* Copyright (c) 2013-2015 Josef Hardi <josef.hardi@gmail.com>
*
* 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 com.obidea.semantika.database.sql.parser;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.List;
import com.obidea.semantika.database.sql.base.ISqlExpression;
import com.obidea.semantika.database.sql.base.SqlSelectItem;
import com.obidea.semantika.exception.SemantikaRuntimeException;
import com.obidea.semantika.mapping.base.sql.SqlColumn;
import com.obidea.semantika.mapping.base.sql.SqlMappingFactory;
import com.obidea.semantika.mapping.base.sql.SqlTable;
import com.obidea.semantika.util.Serializer;
import net.sf.jsqlparser.expression.Alias;
import net.sf.jsqlparser.expression.AllComparisonExpression;
import net.sf.jsqlparser.expression.AnalyticExpression;
import net.sf.jsqlparser.expression.AnyComparisonExpression;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.CaseExpression;
import net.sf.jsqlparser.expression.CastExpression;
import net.sf.jsqlparser.expression.DateValue;
import net.sf.jsqlparser.expression.DoubleValue;
import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.expression.ExtractExpression;
import net.sf.jsqlparser.expression.IntervalExpression;
import net.sf.jsqlparser.expression.JdbcNamedParameter;
import net.sf.jsqlparser.expression.JdbcParameter;
import net.sf.jsqlparser.expression.LongValue;
import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.OracleHierarchicalExpression;
import net.sf.jsqlparser.expression.Parenthesis;
import net.sf.jsqlparser.expression.SignedExpression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.TimeValue;
import net.sf.jsqlparser.expression.TimestampValue;
import net.sf.jsqlparser.expression.WhenClause;
import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseOr;
import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor;
import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
import net.sf.jsqlparser.expression.operators.arithmetic.Division;
import net.sf.jsqlparser.expression.operators.arithmetic.Modulo;
import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.Between;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExistsExpression;
import net.sf.jsqlparser.expression.operators.relational.GreaterThan;
import net.sf.jsqlparser.expression.operators.relational.GreaterThanEquals;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.IsNullExpression;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.Matches;
import net.sf.jsqlparser.expression.operators.relational.MinorThan;
import net.sf.jsqlparser.expression.operators.relational.MinorThanEquals;
import net.sf.jsqlparser.expression.operators.relational.NotEqualsTo;
import net.sf.jsqlparser.expression.operators.relational.RegExpMatchOperator;
import net.sf.jsqlparser.statement.select.AllColumns;
import net.sf.jsqlparser.statement.select.AllTableColumns;
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
import net.sf.jsqlparser.statement.select.SelectItem;
import net.sf.jsqlparser.statement.select.SelectItemVisitor;
import net.sf.jsqlparser.statement.select.SubSelect;
/* package */class SelectItemHandler implements SelectItemVisitor, ExpressionVisitor
{
private ISqlExpression mExpression = null;
private SelectItemList mSelectItems;
private FromTablesList mFromTables;
private int mOpenParenthesisCount = 0;
private static SqlMappingFactory sSqlFactory = SqlMappingFactory.getInstance();
public SelectItemHandler(SelectStatementHandler handler)
{
mSelectItems = handler.getSelectItems();
mFromTables = handler.getFromTablesList();
}
public void parse(List<SelectItem> selectItems)
{
for (SelectItem selectItem : selectItems) {
selectItem.accept(this);
}
}
@Override
public void visit(AllColumns allColumns)
{
for (SqlTable table : mFromTables) {
for (SqlColumn column : table.getColumns()) {
mSelectItems.add(new SqlSelectItem(column));
}
}
}
@Override
public void visit(AllTableColumns allTableColumns)
{
try {
String tableName = allTableColumns.getTable().getFullyQualifiedName();
for (SqlColumn column : mFromTables.getColumns(tableName)) {
mSelectItems.add(new SqlSelectItem(column));
}
}
catch (SqlParserException e) {
throw new SemantikaRuntimeException(e);
}
}
@Override
public void visit(SelectExpressionItem selectExpressionItem)
{
selectExpressionItem.getExpression().accept(this);
ISqlExpression expression = getExpression();
SqlSelectItem selectItem = new SqlSelectItem(expression);
Alias alias = selectExpressionItem.getAlias();
if (alias != null) {
String aliasName = removeQuotesIfAny(alias.getName());
selectItem.setAliasName(aliasName);
}
mSelectItems.add(selectItem);
}
@Override
public void visit(net.sf.jsqlparser.schema.Column tableColumn)
{
try {
String tableName = removeQuotesIfAny(tableColumn.getTable().getFullyQualifiedName());
String columnName = removeQuotesIfAny(tableColumn.getColumnName());
mExpression = mFromTables.getColumn(tableName, columnName);
}
catch (SqlParserException e) {
throw new SemantikaRuntimeException(e);
}
}
private static String removeQuotesIfAny(String value)
{
return value.replaceAll("^\"|\"$", "").replaceAll("^`|`$", ""); //$NON-NLS-1$ //$NON-NLS-2$
}
@Override
public void visit(Parenthesis parenthesis)
{
increaseOpenParenthesisCount();
parenthesis.getExpression().accept(this);
}
@Override
public void visit(NullValue nullValue)
{
throw new UnsupportedSqlExpressionException("NULL"); //$NON-NLS-1$
}
@Override
public void visit(net.sf.jsqlparser.expression.Function function)
{
throw new UnsupportedSqlExpressionException("CALL FUNCTION"); //$NON-NLS-1$
}
@Override
public void visit(JdbcParameter jdbcParameter)
{
throw new UnsupportedSqlExpressionException("PREPARED STATEMENT"); //$NON-NLS-1$
}
@Override
public void visit(DoubleValue doubleValue)
{
double value = doubleValue.getValue();
mExpression = sSqlFactory.createNumericValueExpression(value);
}
@Override
public void visit(LongValue longValue)
{
long value = longValue.getValue();
mExpression = sSqlFactory.createNumericValueExpression(value);
}
@Override
public void visit(DateValue dateValue)
{
Date value = dateValue.getValue();
mExpression = sSqlFactory.createDateTimeValueExpression(value);
}
@Override
public void visit(TimeValue timeValue)
{
Time value = timeValue.getValue();
mExpression = sSqlFactory.createDateTimeValueExpression(value);
}
@Override
public void visit(TimestampValue timestampValue)
{
Timestamp value = timestampValue.getValue();
mExpression = sSqlFactory.createDateTimeValueExpression(value);
}
@Override
public void visit(StringValue stringValue)
{
String value = stringValue.getValue();
mExpression = sSqlFactory.createStringValueExpression(value);
}
@Override
public void visit(Addition addition)
{
mExpression = visitBinaryExpression(addition);
if (mOpenParenthesisCount != 0) {
decreaseOpenParenthesisCount();
}
}
@Override
public void visit(Subtraction subtraction)
{
mExpression = visitBinaryExpression(subtraction);
if (mOpenParenthesisCount != 0) {
decreaseOpenParenthesisCount();
}
}
@Override
public void visit(Multiplication multiplication)
{
mExpression = visitBinaryExpression(multiplication);
if (mOpenParenthesisCount != 0) {
decreaseOpenParenthesisCount();
}
}
@Override
public void visit(Division division)
{
mExpression = visitBinaryExpression(division);
if (mOpenParenthesisCount != 0) {
decreaseOpenParenthesisCount();
}
}
@Override
public void visit(AndExpression andExpression)
{
throw new UnsupportedSqlExpressionException("AND"); //$NON-NLS-1$
}
@Override
public void visit(OrExpression orExpression)
{
throw new UnsupportedSqlExpressionException("OR"); //$NON-NLS-1$
}
@Override
public void visit(Between between)
{
throw new UnsupportedSqlExpressionException("BETWEEN"); //$NON-NLS-1$
}
@Override
public void visit(EqualsTo equalsTo)
{
throw new UnsupportedSqlExpressionException("EQUALS"); //$NON-NLS-1$
}
@Override
public void visit(GreaterThan greaterThan)
{
throw new UnsupportedSqlExpressionException("GREATER THAN"); //$NON-NLS-1$
}
@Override
public void visit(GreaterThanEquals greaterThanEquals)
{
throw new UnsupportedSqlExpressionException("GREATER THAN EQUALS"); //$NON-NLS-1$
}
@Override
public void visit(InExpression inExpression)
{
throw new UnsupportedSqlExpressionException("IN"); //$NON-NLS-1$
}
@Override
public void visit(IsNullExpression isNullExpression)
{
throw new UnsupportedSqlExpressionException("IS NULL"); //$NON-NLS-1$
}
@Override
public void visit(LikeExpression likeExpression)
{
throw new UnsupportedSqlExpressionException("LIKE"); //$NON-NLS-1$
}
@Override
public void visit(MinorThan minorThan)
{
throw new UnsupportedSqlExpressionException("LESS THAN"); //$NON-NLS-1$
}
@Override
public void visit(MinorThanEquals minorThanEquals)
{
throw new UnsupportedSqlExpressionException("LESS THAN EQUALS"); //$NON-NLS-1$
}
@Override
public void visit(NotEqualsTo notEqualsTo)
{
throw new UnsupportedSqlExpressionException("NOT EQUALS"); //$NON-NLS-1$
}
@Override
public void visit(SubSelect subSelect)
{
throw new UnsupportedSqlExpressionException("NESTED SELECT"); //$NON-NLS-1$
}
@Override
public void visit(CaseExpression caseExpression)
{
throw new UnsupportedSqlExpressionException("CASE"); //$NON-NLS-1$
}
@Override
public void visit(WhenClause whenClause)
{
throw new UnsupportedSqlExpressionException("WHEN"); //$NON-NLS-1$
}
@Override
public void visit(ExistsExpression existsExpression)
{
throw new UnsupportedSqlExpressionException("EXISTS"); //$NON-NLS-1$
}
@Override
public void visit(AllComparisonExpression allComparisonExpression)
{
throw new UnsupportedSqlExpressionException("NESTED SELECT"); //$NON-NLS-1$
}
@Override
public void visit(AnyComparisonExpression anyComparisonExpression)
{
throw new UnsupportedSqlExpressionException("NESTED SELECT"); //$NON-NLS-1$
}
@Override
public void visit(Concat concat)
{
mExpression = visitBinaryExpression(concat);
if (mOpenParenthesisCount != 0) {
decreaseOpenParenthesisCount();
}
}
@Override
public void visit(Matches matches)
{
throw new UnsupportedSqlExpressionException("MATCHES"); //$NON-NLS-1$
}
@Override
public void visit(BitwiseAnd bitwiseAnd)
{
throw new UnsupportedSqlExpressionException("BITWISE AND"); //$NON-NLS-1$
}
@Override
public void visit(BitwiseOr bitwiseOr)
{
throw new UnsupportedSqlExpressionException("BITWISE OR"); //$NON-NLS-1$
}
@Override
public void visit(BitwiseXor bitwiseXor)
{
throw new UnsupportedSqlExpressionException("BITWISE XOR"); //$NON-NLS-1$
}
@Override
public void visit(SignedExpression signed)
{
throw new UnsupportedSqlExpressionException("SIGNED"); //$NON-NLS-1$
}
@Override
public void visit(JdbcNamedParameter parameter)
{
throw new UnsupportedSqlExpressionException("JDBC NAMED PARAMETER"); //$NON-NLS-1$
}
@Override
public void visit(CastExpression cast)
{
throw new UnsupportedSqlExpressionException("CAST"); //$NON-NLS-1$
}
@Override
public void visit(Modulo module)
{
throw new UnsupportedSqlExpressionException("MODULO"); //$NON-NLS-1$
}
@Override
public void visit(AnalyticExpression analytic)
{
throw new UnsupportedSqlExpressionException("ANALYTIC"); //$NON-NLS-1$
}
@Override
public void visit(ExtractExpression extract)
{
throw new UnsupportedSqlExpressionException("EXTRACT"); //$NON-NLS-1$
}
@Override
public void visit(IntervalExpression interval)
{
throw new UnsupportedSqlExpressionException("INTERVAL"); //$NON-NLS-1$
}
@Override
public void visit(OracleHierarchicalExpression oracleHierarchical)
{
throw new UnsupportedSqlExpressionException("ORACLE HIERARCHICAL"); //$NON-NLS-1$
}
@Override
public void visit(RegExpMatchOperator regExpMatch)
{
throw new UnsupportedSqlExpressionException("REGEXP MATCH"); //$NON-NLS-1$
}
protected ISqlExpression visitBinaryExpression(BinaryExpression binaryExpression)
{
binaryExpression.getLeftExpression().accept(this);
ISqlExpression leftParameter = getExpression();
binaryExpression.getRightExpression().accept(this);
ISqlExpression rightParameter = getExpression();
if (binaryExpression instanceof Addition) {
return sSqlFactory.createAdditionExpression(leftParameter, rightParameter);
}
else if (binaryExpression instanceof Subtraction) {
return sSqlFactory.createSubstractExpression(leftParameter, rightParameter);
}
else if (binaryExpression instanceof Multiplication) {
return sSqlFactory.createMultiplyExpression(leftParameter, rightParameter);
}
else if (binaryExpression instanceof Division) {
return sSqlFactory.createDivideExpression(leftParameter, rightParameter);
}
else if (binaryExpression instanceof Concat) {
return sSqlFactory.createConcatExpression(leftParameter, rightParameter);
}
throw new UnsupportedSqlExpressionException(binaryExpression.toString());
}
private ISqlExpression getExpression()
{
return (ISqlExpression) Serializer.copy(mExpression);
}
private void increaseOpenParenthesisCount()
{
mOpenParenthesisCount++;
}
private void decreaseOpenParenthesisCount()
{
mOpenParenthesisCount--;
}
}