package net.sf.jsqlparser.util.deparser;
import java.util.Iterator;
import java.util.List;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.AllColumns;
import net.sf.jsqlparser.statement.select.AllTableColumns;
import net.sf.jsqlparser.statement.select.FromItem;
import net.sf.jsqlparser.statement.select.FromItemVisitor;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.Limit;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.OrderByVisitor;
import net.sf.jsqlparser.statement.select.PlainSelect;
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.SelectVisitor;
import net.sf.jsqlparser.statement.select.SubJoin;
import net.sf.jsqlparser.statement.select.SubSelect;
import net.sf.jsqlparser.statement.select.Top;
import net.sf.jsqlparser.statement.select.Union;
/**
* A class to de-parse (that is, tranform from JSqlParser hierarchy into a string)
* a {@link net.sf.jsqlparser.statement.select.Select}
*/
public class SelectDeParser implements SelectVisitor, OrderByVisitor, SelectItemVisitor, FromItemVisitor {
protected StringBuffer buffer;
protected ExpressionVisitor expressionVisitor;
public SelectDeParser() {
}
/**
* @param expressionVisitor a {@link ExpressionVisitor} to de-parse expressions. It has to share the same<br>
* StringBuffer (buffer parameter) as this object in order to work
* @param buffer the buffer that will be filled with the select
*/
public SelectDeParser(ExpressionVisitor expressionVisitor, StringBuffer buffer) {
this.buffer = buffer;
this.expressionVisitor = expressionVisitor;
}
public void visit(PlainSelect plainSelect) {
buffer.append("SELECT ");
Top top = plainSelect.getTop();
if (top != null)
top.toString();
if (plainSelect.getDistinct() != null) {
buffer.append("DISTINCT ");
if (plainSelect.getDistinct().getOnSelectItems() != null) {
buffer.append("ON (");
for (Iterator iter = plainSelect.getDistinct().getOnSelectItems().iterator(); iter.hasNext();) {
SelectItem selectItem = (SelectItem) iter.next();
selectItem.accept(this);
if (iter.hasNext()) {
buffer.append(", ");
}
}
buffer.append(") ");
}
}
for (Iterator iter = plainSelect.getSelectItems().iterator(); iter.hasNext();) {
SelectItem selectItem = (SelectItem) iter.next();
selectItem.accept(this);
if (iter.hasNext()) {
buffer.append(", ");
}
}
buffer.append(" ");
if (plainSelect.getFromItem() != null) {
buffer.append("FROM ");
plainSelect.getFromItem().accept(this);
}
if (plainSelect.getJoins() != null) {
for (Iterator iter = plainSelect.getJoins().iterator(); iter.hasNext();) {
Join join = (Join) iter.next();
deparseJoin(join);
}
}
if (plainSelect.getWhere() != null) {
buffer.append(" WHERE ");
plainSelect.getWhere().accept(expressionVisitor);
}
if (plainSelect.getGroupByColumnReferences() != null) {
buffer.append(" GROUP BY ");
for (Iterator iter = plainSelect.getGroupByColumnReferences().iterator(); iter.hasNext();) {
Expression columnReference = (Expression) iter.next();
columnReference.accept(expressionVisitor);
if (iter.hasNext()) {
buffer.append(", ");
}
}
}
if (plainSelect.getHaving() != null) {
buffer.append(" HAVING ");
plainSelect.getHaving().accept(expressionVisitor);
}
if (plainSelect.getOrderByElements() != null) {
deparseOrderBy(plainSelect.getOrderByElements());
}
if (plainSelect.getLimit() != null) {
deparseLimit(plainSelect.getLimit());
}
}
public void visit(Union union) {
for (Iterator iter = union.getPlainSelects().iterator(); iter.hasNext();) {
buffer.append("(");
PlainSelect plainSelect = (PlainSelect) iter.next();
plainSelect.accept(this);
buffer.append(")");
if (iter.hasNext()) {
buffer.append(" UNION ");
}
}
if (union.getOrderByElements() != null) {
deparseOrderBy(union.getOrderByElements());
}
if (union.getLimit() != null) {
deparseLimit(union.getLimit());
}
}
public void visit(OrderByElement orderBy) {
orderBy.getExpression().accept(expressionVisitor);
if (orderBy.isAsc())
buffer.append(" ASC");
else
buffer.append(" DESC");
}
public void visit(Column column) {
buffer.append(column.getWholeColumnName());
}
public void visit(AllColumns allColumns) {
buffer.append("*");
}
public void visit(AllTableColumns allTableColumns) {
buffer.append(allTableColumns.getTable().getWholeTableName() + ".*");
}
public void visit(SelectExpressionItem selectExpressionItem) {
selectExpressionItem.getExpression().accept(expressionVisitor);
if (selectExpressionItem.getAlias() != null) {
buffer.append(" AS " + selectExpressionItem.getAlias());
}
}
public void visit(SubSelect subSelect) {
buffer.append("(");
subSelect.getSelectBody().accept(this);
buffer.append(")");
}
public void visit(Table tableName) {
buffer.append(tableName.getWholeTableName());
String alias = tableName.getAlias();
if (alias != null && !alias.equals("")) {
buffer.append(" AS " + alias);
}
}
public void deparseOrderBy(List orderByElements) {
buffer.append(" ORDER BY ");
for (Iterator iter = orderByElements.iterator(); iter.hasNext();) {
OrderByElement orderByElement = (OrderByElement) iter.next();
orderByElement.accept(this);
if (iter.hasNext()) {
buffer.append(", ");
}
}
}
public void deparseLimit(Limit limit) {
// LIMIT n OFFSET skip
buffer.append(" LIMIT ");
if (limit.isRowCountJdbcParameter()) {
buffer.append("?");
} else if (limit.getRowCount() != 0) {
buffer.append(limit.getRowCount());
} else {
/*
from mysql docs:
For compatibility with PostgreSQL, MySQL also supports the LIMIT row_count OFFSET offset syntax.
To retrieve all rows from a certain offset up to the end of the result set, you can use some large number
for the second parameter.
*/
buffer.append("18446744073709551615");
}
if (limit.isOffsetJdbcParameter()) {
buffer.append(" OFFSET ?");
} else if (limit.getOffset() != 0) {
buffer.append(" OFFSET " + limit.getOffset());
}
}
public StringBuffer getBuffer() {
return buffer;
}
public void setBuffer(StringBuffer buffer) {
this.buffer = buffer;
}
public ExpressionVisitor getExpressionVisitor() {
return expressionVisitor;
}
public void setExpressionVisitor(ExpressionVisitor visitor) {
expressionVisitor = visitor;
}
public void visit(SubJoin subjoin) {
buffer.append("(");
subjoin.getLeft().accept(this);
buffer.append(" ");
deparseJoin(subjoin.getJoin());
buffer.append(")");
}
public void deparseJoin(Join join) {
if (join.isSimple())
buffer.append(", ");
else
{
if (join.isRight())
buffer.append("RIGHT ");
else if (join.isNatural())
buffer.append("NATURAL ");
else if (join.isFull())
buffer.append("FULL ");
else if (join.isLeft())
buffer.append("LEFT ");
if (join.isOuter())
buffer.append("OUTER ");
else if (join.isInner())
buffer.append("INNER ");
buffer.append("JOIN ");
}
FromItem fromItem = join.getRightItem();
fromItem.accept(this);
if (join.getOnExpression() != null) {
buffer.append(" ON ");
join.getOnExpression().accept(expressionVisitor);
}
if (join.getUsingColumns() != null) {
buffer.append(" USING ( ");
for (Iterator iterator = join.getUsingColumns().iterator(); iterator.hasNext();) {
Column column = (Column) iterator.next();
buffer.append(column.getWholeColumnName());
if (iterator.hasNext()) {
buffer.append(" ,");
}
}
buffer.append(")");
}
}
}