/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.translator.simpledb;
import static org.teiid.language.SQLConstants.Reserved.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.teiid.language.*;
import org.teiid.language.Comparison.Operator;
import org.teiid.language.SQLConstants.Tokens;
import org.teiid.language.visitor.CollectorVisitor;
import org.teiid.language.visitor.SQLStringVisitor;
import org.teiid.metadata.Column;
import org.teiid.translator.TranslatorException;
public class SimpleDBSQLVisitor extends SQLStringVisitor {
private List<String> projectedColumns = new ArrayList<String>();
private ArrayList<TranslatorException> exceptions = new ArrayList<TranslatorException>();
private Column previousColumn;
private boolean skipCompare;
public void checkExceptions() throws TranslatorException {
if (!this.exceptions.isEmpty()) {
throw this.exceptions.get(0);
}
}
@Override
public void visit(Select obj) {
buffer.append(SELECT).append(Tokens.SPACE);
List<DerivedColumn> allowedColumns = new ArrayList<DerivedColumn>();
boolean otherCols = false;
for(int i = 0; i < obj.getDerivedColumns().size(); i++) {
DerivedColumn dc = obj.getDerivedColumns().get(i);
if (!(dc.getExpression() instanceof ColumnReference)) {
otherCols = true;
break;
}
ColumnReference column = (ColumnReference)dc.getExpression();
if (!SimpleDBMetadataProcessor.isItemName(column.getMetadataObject())) {
otherCols = true;
break;
}
}
boolean addedItemName = false;
for(int i = 0; i < obj.getDerivedColumns().size(); i++) {
DerivedColumn dc = obj.getDerivedColumns().get(i);
if (dc.getExpression() instanceof ColumnReference) {
ColumnReference column = (ColumnReference)dc.getExpression();
if (SimpleDBMetadataProcessor.isItemName(column.getMetadataObject())) {
if (!addedItemName && !otherCols) {
allowedColumns.add(dc);
addedItemName = true;
}
}
else {
allowedColumns.add(dc);
}
projectedColumns.add(SimpleDBMetadataProcessor.getName(column.getMetadataObject()));
} else if (dc.getExpression() instanceof AggregateFunction) {
allowedColumns.add(dc);
projectedColumns.add("Count"); //$NON-NLS-1$
}
else {
this.exceptions.add(new TranslatorException(SimpleDBPlugin.Event.TEIID24004, SimpleDBPlugin.Util.gs(SimpleDBPlugin.Event.TEIID24004, dc)));
}
}
append(allowedColumns);
if (obj.getFrom() != null && !obj.getFrom().isEmpty()) {
buffer.append(Tokens.SPACE).append(FROM).append(Tokens.SPACE);
append(obj.getFrom());
}
if (obj.getWhere() != null) {
buffer.append(Tokens.SPACE)
.append(WHERE)
.append(Tokens.SPACE);
append(obj.getWhere());
}
if (obj.getOrderBy() != null) {
validateOrderBy(obj);
buffer.append(Tokens.SPACE);
append(obj.getOrderBy());
}
}
// SORT is only supported when a criteria is available
private void validateOrderBy(Select obj) {
Collection<ColumnReference> whereColumns = CollectorVisitor.collectElements(obj.getWhere());
for (SortSpecification sort:obj.getOrderBy().getSortSpecifications()) {
boolean matched = false;
for (ColumnReference where:whereColumns) {
ColumnReference col = (ColumnReference)sort.getExpression();
if (col.getName().equals(where.getName())) {
matched = true;
}
}
if (!matched) {
this.exceptions.add(new TranslatorException(SimpleDBPlugin.Event.TEIID24005, SimpleDBPlugin.Util.gs(SimpleDBPlugin.Event.TEIID24005)));
break;
}
}
}
@Override
public void visit(Comparison obj) {
append(obj.getLeftExpression());
if (!this.skipCompare) {
buffer.append(Tokens.SPACE);
if (obj.getOperator().equals(Operator.NE)) {
buffer.append("!="); //$NON-NLS-1$
}
else {
buffer.append(obj.getOperator());
}
buffer.append(Tokens.SPACE);
append(obj.getRightExpression());
}
this.skipCompare = false;
}
@Override
public void visit(Array array) {
List<Expression> exprs = array.getExpressions();
append(exprs.get(0));
for (int i = 1; i < exprs.size(); i++) {
buffer.append(Tokens.SPACE).append(AndOr.Operator.OR).append(Tokens.SPACE);
buffer.append(SQLStringVisitor.getRecordName(this.previousColumn));
buffer.append(Tokens.SPACE).append(Tokens.EQ).append(Tokens.SPACE);
append(exprs.get(i));
}
}
@Override
public void visit(Literal obj) {
if (obj.getValue() == null) {
buffer.append(NULL);
} else {
String val = obj.getValue().toString();
buffer.append(Tokens.QUOTE)
.append(escapeString(val, Tokens.QUOTE))
.append(Tokens.QUOTE);
}
}
@Override
public void visit(Function obj) {
String name = obj.getName();
List<Expression> args = obj.getParameters();
if(name.equalsIgnoreCase(SimpleDBExecutionFactory.INTERSECTION) || name.equalsIgnoreCase(SimpleDBExecutionFactory.SIMPLEDB+"."+SimpleDBExecutionFactory.INTERSECTION)) { //$NON-NLS-1$
append(args.get(0));
buffer.append(Tokens.SPACE).append(Tokens.EQ).append(Tokens.SPACE);
for (int i = 1; i < args.size(); i++) {
append(args.get(i));
if (i < args.size()-1) {
buffer.append(Tokens.SPACE).append(SimpleDBExecutionFactory.INTERSECTION).append(Tokens.SPACE);
buffer.append(SQLStringVisitor.getRecordName(this.previousColumn));
buffer.append(Tokens.SPACE).append(Tokens.EQ).append(Tokens.SPACE);
}
}
this.skipCompare = true;
}
else {
super.visit(obj);
}
}
@Override
public void visit(ColumnReference obj) {
buffer.append(SQLStringVisitor.getRecordName(obj.getMetadataObject()));
this.previousColumn = obj.getMetadataObject();
}
public List<String> getProjectedColumns() {
return this.projectedColumns;
}
public static String getSQLString(LanguageObject obj) {
SimpleDBSQLVisitor visitor = new SimpleDBSQLVisitor();
visitor.append(obj);
return visitor.toString();
}
}