Package org.apache.ws.jaxme.sqls.impl

Source Code of org.apache.ws.jaxme.sqls.impl.SQLGeneratorImpl$SelectStatementMetaData

/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2003 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment: 
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The name "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package org.apache.ws.jaxme.sqls.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.ws.jaxme.sqls.BinaryColumn;
import org.apache.ws.jaxme.sqls.BooleanConstraint;
import org.apache.ws.jaxme.sqls.Column;
import org.apache.ws.jaxme.sqls.ColumnReference;
import org.apache.ws.jaxme.sqls.CombinedConstraint;
import org.apache.ws.jaxme.sqls.Constraint;
import org.apache.ws.jaxme.sqls.DeleteStatement;
import org.apache.ws.jaxme.sqls.ForeignKey;
import org.apache.ws.jaxme.sqls.Function;
import org.apache.ws.jaxme.sqls.Index;
import org.apache.ws.jaxme.sqls.Parts;
import org.apache.ws.jaxme.sqls.RawSQLCode;
import org.apache.ws.jaxme.sqls.SQLGenerator;
import org.apache.ws.jaxme.sqls.InsertStatement;
import org.apache.ws.jaxme.sqls.JoinReference;
import org.apache.ws.jaxme.sqls.Schema;
import org.apache.ws.jaxme.sqls.SelectStatement;
import org.apache.ws.jaxme.sqls.SelectTableReference;
import org.apache.ws.jaxme.sqls.SetStatement;
import org.apache.ws.jaxme.sqls.Statement;
import org.apache.ws.jaxme.sqls.StringColumn;
import org.apache.ws.jaxme.sqls.Table;
import org.apache.ws.jaxme.sqls.TableReference;
import org.apache.ws.jaxme.sqls.UpdateStatement;
import org.apache.ws.jaxme.sqls.Value;


/** <p>Default implementation of an SQL generator.</p>
*
* @author <a href="mailto:joe@ispsoft.de">Jochen Wiedmann</a>
*/
public class SQLGeneratorImpl implements SQLGenerator {
  private String statementTerminator, lineTerminator;

  public String getStatementTerminator() {
    return statementTerminator;
  }

  public void setStatementTerminator(String pStatementTerminator) {
    statementTerminator = pStatementTerminator;
  }

  public String getLineTerminator() {
    return lineTerminator;
  }

  public void setLineTerminator(String pLineTerminator) {
    lineTerminator = pLineTerminator;
  }

  protected String newStatement(String pStatement) {
    String s = getStatementTerminator();
    return s == null ? pStatement : pStatement + s;
  }

  public Collection getCreate(Schema pSchema) {
    if (pSchema.getName() == null) {
       // Default schema cannot be created
       return Collections.EMPTY_LIST;
    }
    List result = new ArrayList();
    result.add(newStatement("CREATE SCHEMA " + pSchema.getName()));
    return result;
  }

  public Collection getDrop(Schema pSchema) {
     if (pSchema.getName() == null) {
        // Default schema cannot be dropped
        return Collections.EMPTY_LIST;
     }
    List result = new ArrayList();
    result.add(newStatement("DROP SCHEMA " + pSchema.getName()));
    return result;
  }

  protected String getIndent() { return "  "; }

  protected String getTypeName(Column.Type pType) {
    if (pType.equals(Column.Type.BIGINT)) {
      return "BIGINT";
    } else if (pType.equals(Column.Type.BINARY)) {
      return "BINARY";
    } else if (pType.equals(Column.Type.BIT)) {
      return "BIT";
    } else if (pType.equals(Column.Type.CHAR)) {
      return "CHAR";
    } else if (pType.equals(Column.Type.DATE)) {
      return "DATE";
    } else if (pType.equals(Column.Type.DOUBLE)) {
      return "DOUBLE";
    } else if (pType.equals(Column.Type.FLOAT)) {
      return "FLOAT";
    } else if (pType.equals(Column.Type.INTEGER)) {
      return "INT";
    } else if (pType.equals(Column.Type.SMALLINT)) {
      return "SMALLINT";
    } else if (pType.equals(Column.Type.TIME)) {
      return "TIME";
    } else if (pType.equals(Column.Type.TIMESTAMP)) {
      return "TIMESTAMP";
    } else if (pType.equals(Column.Type.TINYINT)) {
      return "TINYINT";
    } else if (pType.equals(Column.Type.VARBINARY)) {
      return "VARBINARY";
    } else if (pType.equals(Column.Type.VARCHAR)) {
      return "VARCHAR";
    } else if (pType.equals(Column.Type.CLOB)) {
      return "CLOB";
    } else if (pType.equals(Column.Type.BLOB)) {
      return "BLOB";
    } else if (pType.equals(Column.Type.OTHER)) {
      return "BLOB";
    } else {
      throw new IllegalStateException("Unknown column type: " + pType);
    }
  }

  protected String getCreate(Column pColumn) {
    StringBuffer sb = new StringBuffer();
    sb.append(pColumn.getName()).append(" ");
    Column.Type type = pColumn.getType();
    Long length = null;
    if (type.equals(Column.Type.BINARY)
        ||  type.equals(Column.Type.VARBINARY)
        ||  type.equals(Column.Type.BLOB)
        ||  type.equals(Column.Type.OTHER)) {
      length = ((BinaryColumn) pColumn).getLength();
      if (length == null) {
        throw new IllegalStateException("The length of column " + pColumn.getQName() + " is not set.");
      }
    } else if (type.equals(Column.Type.CHAR)
                ||  type.equals(Column.Type.VARCHAR)
                ||  type.equals(Column.Type.CLOB)) {
      length = ((StringColumn) pColumn).getLength();
      if (length == null) {
        throw new IllegalStateException("The length of column " + pColumn.getQName() + " is not set.");
      }
    }
    sb.append(getTypeName(type));
    if (length != null) {
      sb.append("(").append(length).append(")");
    }
    if (!pColumn.isNullable()) {
      sb.append(" NOT NULL");
    }
    return sb.toString();
  }

  /** <p>Returns whether the primary key requires special handling
   * (in which case {@link #isPrimaryKeyPartOfCreateTable()} and
   * {@link #createPrimaryKeyAsPartOfCreateTable(Table)} are used)
   * or nor (in which case {@link #isUniqueIndexPartOfCreateTable()}
   * and {@link #createIndexAsPartOfCreateTable(Index)} apply).</p>
   */
  protected boolean isPrimaryKeyUniqueIndex() { return false; }

  /** <p>Returns whether a <code>CREATE TABLE</code> statement may contain
   * a <code>PRIMARY KEY</code> clause.</p>
   */
  protected boolean isPrimaryKeyPartOfCreateTable() { return false; }

  /** <p>Returns whether a <code>CREATE TABLE</code> statement may contain
   * a <code>UNIQUE</code> clause.</p>
   */
  protected boolean isUniqueIndexPartOfCreateTable() { return false; }

  /** <p>Returns whether a <code>CREATE TABLE</code> statement may contain
   * an <code>INDEX</code> clause.</p>
   */
  protected boolean isNonUniqueIndexPartOfCreateTable() { return false; }

  /** <p>Returns whether a <code>CREATE TABLE</code> statement may contain
   * a <code>FOREIGN KEY</code> clause.</p>
   */
  protected boolean isForeignKeyPartOfCreateTable() { return false; }

  protected String createPrimaryKeyAsPartOfCreateTable(Table pTable) {
    Index index = pTable.getPrimaryKey();
    if (index == null) {
      return null;
    }
    StringBuffer sb = new StringBuffer();
    sb.append("PRIMARY KEY").append(" (");
    boolean first = true;
    for (Iterator iter = index.getColumns();  iter.hasNext()) {
      if (first) {
        first = false;
      } else {
        sb.append(", ");
      }
      sb.append(((Column) iter.next()).getName().getName());
    }
    sb.append(")");
    return sb.toString();
  }

  protected String createIndexAsPartOfCreateTable(Index pIndex) {
    StringBuffer sb = new StringBuffer();
    sb.append(pIndex.isUnique() ? "UNIQUE" : "KEY").append(" (");
    boolean first = true;
    for (Iterator iter = pIndex.getColumns();  iter.hasNext()) {
      if (first) {
        first = false;
      } else {
        sb.append(", ");
      }
      sb.append(((Column) iter.next()).getName().getName());
    }
    sb.append(")");
    return sb.toString();
  }

  protected String createForeignKeyAsPartOfCreateTable(ForeignKey pKey) {
    StringBuffer sb = new StringBuffer();
    sb.append("FOREIGN KEY (");
    boolean first = true;
    Iterator iter = pKey.getColumnLinks();
    if (!iter.hasNext()) {
      throw new IllegalStateException("Foreign key on " +
                                       pKey.getTable().getQName() +
                                       " referencing " +
                                       pKey.getReferencedTable().getQName() +
                                       " doesn't have any columns.");
    }
    while (iter.hasNext()) {
      ForeignKey.ColumnLink link = (ForeignKey.ColumnLink) iter.next();
      if (first) {
        first = false;
      } else {
        sb.append(", ");
      }
      sb.append(link.getLocalColumn().getName().getName());
    }
    sb.append(") REFERENCES ");
    sb.append(pKey.getReferencedTable().getQName());
    sb.append(" (");
    first = true;
    iter = pKey.getColumnLinks();
    while (iter.hasNext()) {
      ForeignKey.ColumnLink link = (ForeignKey.ColumnLink) iter.next();
      if (first) {
        first = false;
      } else {
        sb.append(", ");
      }
      sb.append(link.getReferencedColumn().getName().getName());
    }
    sb.append(")");

    ForeignKey.Mode deleteMode = pKey.getOnDelete();
    if (deleteMode != null) {
      if (ForeignKey.Mode.CASCADE.equals(deleteMode)) {
        sb.append(" ON DELETE CASCADE");
      } else if (ForeignKey.Mode.REJECT.equals(deleteMode)) {
        sb.append(" ON DELETE RESTRICT");
      } else if (ForeignKey.Mode.SETNULL.equals(deleteMode)) {
        sb.append(" ON DELETE SET NULL");
      } else {
        throw new IllegalStateException("Unknown foreign key mode for ON  DELETE: " + deleteMode);
      }
    }
    ForeignKey.Mode updateMode = pKey.getOnUpdate();
    if (updateMode != null) {
      if (ForeignKey.Mode.CASCADE.equals(updateMode)) {
       sb.append(" ON UPDATE CASCADE");
      } else if (ForeignKey.Mode.REJECT.equals(updateMode)) {
         sb.append(" ON UPDATE RESTRICT");
      } else {
         throw new IllegalStateException("Unknown foreign key mode for ON UPDATE: " + updateMode);
      }
    }

    return sb.toString();
  }

  protected String getCreateTableHeader(Table pTable) {
    return "CREATE TABLE " + pTable.getQName();
  }

  public Collection getCreate(Table pTable) {
    String lf = getLineTerminator() == null ? "" : getLineTerminator();
    String indent = lf == null ? "" : getIndent();
    StringBuffer sb = new StringBuffer();
    sb.append(getCreateTableHeader(pTable)).append(" (");
    String s = lf + indent;
    for (Iterator iter = pTable.getColumns();  iter.hasNext()) {
      sb.append(s).append(getCreate((Column) iter.next()));
      s = "," + lf + indent;
    }

    for (Iterator iter = pTable.getIndexes();  iter.hasNext()) {
      Index index = (Index) iter.next();
      String st;
      if (index.isPrimaryKey()  &&  !isPrimaryKeyUniqueIndex()) {
        if (!isPrimaryKeyPartOfCreateTable()) {
          continue;
        }
        st = createPrimaryKeyAsPartOfCreateTable(pTable);
      } else if (index.isUnique()) {
        if (!isUniqueIndexPartOfCreateTable()) {
          continue;
        }
        st = createIndexAsPartOfCreateTable(index);
      } else {
        if (!isNonUniqueIndexPartOfCreateTable()) {
          continue;
        }
        st = createIndexAsPartOfCreateTable(index);
      }
      if (st != null) {
        sb.append(s).append(st);
      }
    }
    if (isForeignKeyPartOfCreateTable()) {
      for (Iterator iter = pTable.getForeignKeys();  iter.hasNext()) {
        ForeignKey key = (ForeignKey) iter.next();
        String st = createForeignKeyAsPartOfCreateTable(key);
        if (st != null) {
          sb.append(s).append(st);
        }
      }
    }
    sb.append(lf).append(")").append(lf);
    List result = new ArrayList();
    result.add(newStatement(sb.toString()));
    return result;
  }

  public Collection getDrop(Table pTable) {
    List result = new ArrayList();
    result.add(newStatement("DROP TABLE " + pTable.getQName()));
    return result;
  }

   public String getInsertQuery(InsertStatement pQuery) {
      StringBuffer result = new StringBuffer();
      result.append("INSERT INTO ");
      result.append(getTableAlias(pQuery.getTableReference()));
      boolean first = true;
      for (Iterator iter = pQuery.getSetValues();  iter.hasNext()) {
         if (first) {
            result.append(" (");
            first = false;
         } else {
            result.append(", ");
         }
         SetStatement.SetValue setValue = (SetStatement.SetValue) iter.next();
         result.append(getColumnAlias(null, setValue.getColumnReference()));
      }
      if (!first) {
         result.append(")");
      }
      result.append(" VALUES (");
      first = true;
      for (Iterator iter = pQuery.getSetValues();  iter.hasNext()) {
        if (first) {
          first = false;
        } else {
          result.append(", ");
        }
        SetStatement.SetValue setValue = (SetStatement.SetValue) iter.next();
        result.append(getValue(setValue.getValue()));
      }
      result.append(")");
    return newStatement(result.toString());
  }

  protected String getValue(Value pValue) {
    Value.Type type = pValue.getType();
    Object o = pValue.getValue();
    if (Value.Type.BOOLEAN.equals(type)) {
      return o == null ? "null" : (((Boolean) o).booleanValue() ? "TRUE" : "FALSE");
    } else if (Value.Type.BYTE.equals(type)   ||
               Value.Type.SHORT.equals(type||
               Value.Type.INT.equals(type)    ||
               Value.Type.LONG.equals(type)   ||
               Value.Type.FLOAT.equals(type||
               Value.Type.DOUBLE.equals(type)) {
      return o == null ? "null" : o.toString();
    } else if (Value.Type.DATE.equals(type||
               Value.Type.DATETIME.equals(type||
               Value.Type.TIME.equals(type)) {
      throw new IllegalStateException("Date/time handling not yet implemented.");
    } else if (Value.Type.DATE.equals(type)) {
      throw new IllegalStateException("Date handling not yet implemented.");
    } else if (Value.Type.PLACEHOLDER.equals(type)) {
      return "?";
    } else if (Value.Type.STRING.equals(type)) {
      return o == null ? "null" : getEscapedString(o.toString());
    } else if (Value.Type.NULL.equals(type)) {
      return "null";
    } else {
      throw new IllegalStateException("Unknown value type: " + type);     
    }
  }

  protected String getUpdateQuery(UpdateStatement pQuery) {
    StringBuffer sb = new StringBuffer();
    sb.append("UPDATE ");
    sb.append(getTableAlias(pQuery.getTableReference()));
    sb.append(" SET ");
    boolean first = true;
    for (Iterator iter = pQuery.getSetValues();  iter.hasNext()) {
      UpdateStatement.SetValue setValue = (UpdateStatement.SetValue) iter.next();
      if (first) {
        first = false;
      } else {
        sb.append(", ");
      }
      sb.append(getColumnAlias(null, setValue.getColumnReference()));
      sb.append("=");
      sb.append(getValue(setValue.getValue()));
    }
    String s = getWhereClause(null, pQuery.getWhere());
    if (s != null) {
      sb.append(" WHERE ").append(s);
    }
    return newStatement(sb.toString());
  }

  protected String getDeleteQuery(DeleteStatement pQuery) {
    StringBuffer result = new StringBuffer("DELETE FROM ");
    result.append(getTableAlias(pQuery.getTableReference()));
    String s = getWhereClause(null, pQuery.getWhere());
    if (s != null) {
      result.append(" WHERE ");
      result.append(s);
    }
    return result.toString();
  }

  protected boolean isQualifiedColumn(SelectStatementMetaData pData, ColumnReference pColumn) {
    if (pData == null) {
      return false;
    }
    Integer num = (Integer) pData.getColumnNames().get(pColumn.getColumn().getName().toString().toUpperCase());
    if (num == null) {
      throw new IllegalStateException("Column not in map of column counts.");
    }
    return num.intValue() > 1;
  }

   protected String getColumnAlias(SelectStatementMetaData pData, ColumnReference pColumn) {
     Column col = pColumn.getColumn();
     String s = col.getName().toString();
     if (col.isVirtual()) {
       VirtualColumn virtCol = (VirtualColumn) col;
       return virtCol.getValue() + " AS " + s;
     } else {
       if (isQualifiedColumn(pData, pColumn)) {
         TableReference tableReference = pColumn.getTableReference();
         if (tableReference.getAlias() != null) {
           s = tableReference.getAlias().getName() + "." + s;
         } else {
           s = tableReference.getTable().getName() + "." + s;
         }
       }

       if (pColumn.getAlias() != null) {
         s = s + " AS " + pColumn.getAlias().getName();
       }
     }
     return s;
   }

  protected String getColumnAlias(SelectStatementMetaData pData, ColumnReference[] pColumn) {
    StringBuffer sb = new StringBuffer("(");
    for (int i = 0;  i < pColumn.length;  i++) {
      if (i > 0) sb.append(", ");
      sb.append(getColumnAlias(pData, pColumn[i]));
    }
    sb.append(")");
    return sb.toString();
  }

  protected boolean isTableAliasUsingAs() { return true; }

  protected String getTableAlias(TableReference pTable) {
    Schema.Name schemaName = pTable.getTable().getSchema().getName();
    String tableName = pTable.getTable().getName().getName();
    if (schemaName != null) {
      tableName = schemaName.getName() + "." + tableName;
    }
    Table.Name alias = pTable.getAlias();
    if (alias != null) {
      if (isTableAliasUsingAs()) {
        tableName += " AS " + alias.getName();
      } else {
        tableName += " " + alias.getName();
      }
    }
    return tableName;
  }

  protected String getJoinAlias(SelectStatementMetaData pData, JoinReference pJoinReference) {
    StringBuffer result = new StringBuffer();
    if (pJoinReference.isLeftOuterJoin()) {
      result.append(" LEFT OUTER JOIN ");
    } else if (pJoinReference.isJoin()) {
      result.append(" JOIN ");
    } else {
      throw new IllegalStateException("Unknown join type");
    }
    result.append(getTableAlias(pJoinReference));
    String s = getWhereClause(pData, pJoinReference.getOn());
    if (s != null) {
      result.append(" ON ");
      result.append(s);
    }
    return result.toString();
  }

  protected String getEscapedString(String s) {
    if (s.indexOf('\n') > -||  s.indexOf('\r') > -||  s.indexOf('\f') > -1) {
      throw new IllegalArgumentException("Don't know how to handle line or page terminators.");
    }
    if (s.indexOf('\'') > -1) {
      throw new IllegalArgumentException("Don't know how to handle the char ' in strings.");
    }
    return "'" + s + "'";
  }

  protected String getParts(SelectStatementMetaData pData, Iterator pParts) {
    StringBuffer sb = new StringBuffer();
    while (pParts.hasNext()) {
      if (sb.length() > 0) {
        sb.append(", ");
      }
      sb.append(getBooleanConstraintPart(pData, pParts.next()));
    }
    return sb.toString();
  }

  protected String getBooleanConstraintPart(SelectStatementMetaData pData, Object o) {
    if (o instanceof Value) {
      return getValue((Value) o);
    } else if (o instanceof ColumnReference) {
      return getColumnAlias(pData, (ColumnReference) o);
    } else if (o instanceof ColumnReference[]) {
      return getColumnAlias(pData, (ColumnReference[]) o);
    } else if (o instanceof SelectStatement) {
      return '(' + getQuery((SelectStatement) o) + ')';
    } else if (o instanceof RawSQLCode) {
      return ((RawSQLCode) o).getRawSQL();
    } else if (o instanceof Function) {
      Function f = (Function) o;
      return f.getName() + '(' + getParts(pData, f.getParts()) + ')';
    } else {
      throw new IllegalArgumentException("Invalid part of a boolean constraint: " + o.getClass().getName());
    }
  }

  protected String getBooleanConstraintType(BooleanConstraint.Type pType) {
    if (BooleanConstraint.Type.EQ.equals(pType)) {
      return "=";
    } else if (BooleanConstraint.Type.NE.equals(pType)) {
      return "<>";
    } else if (BooleanConstraint.Type.GT.equals(pType)) {
      return ">";
    } else if (BooleanConstraint.Type.LT.equals(pType)) {
      return "<";
    } else if (BooleanConstraint.Type.GE.equals(pType)) {
      return ">=";
    } else if (BooleanConstraint.Type.LE.equals(pType)) {
      return "<=";
    } else if (BooleanConstraint.Type.LIKE.equals(pType)) {
      return " LIKE ";
    } else {
      throw new IllegalArgumentException("Invalid type: " + pType);
    }
  }

  protected String getBooleanConstraint(SelectStatementMetaData pData,
                                         BooleanConstraint pConstraint) {
    BooleanConstraint.Type type = pConstraint.getType();
    Iterator parts = pConstraint.getParts();
    if (!parts.hasNext()) {
      throw new NullPointerException("A boolean constraint must have its parts set.");
    }
    if (BooleanConstraint.Type.IN.equals(type)) {
      Object o = parts.next();
      return getBooleanConstraintPart(pData, o) + " IN (" + getParts(pData, parts) + ')';
    }
    StringBuffer result = new StringBuffer();
    int expected;
    if (BooleanConstraint.Type.EXISTS.equals(type)) {
      SelectStatement selectStatement = (SelectStatement) parts.next();
      result.append("EXISTS(");
      result.append(getSelectQuery(selectStatement, pData));
      result.append(")");
      expected = 1;
    } else {
      result.append(getBooleanConstraintPart(pData, parts.next()));
      if (BooleanConstraint.Type.EQ.equals(type||
          BooleanConstraint.Type.NE.equals(type||
          BooleanConstraint.Type.GT.equals(type||
          BooleanConstraint.Type.LT.equals(type||
          BooleanConstraint.Type.GE.equals(type||
          BooleanConstraint.Type.LE.equals(type||
          BooleanConstraint.Type.LIKE.equals(type)) {
        expected = 2;
        if (!parts.hasNext()) {
          throw new NullPointerException("The boolean constraint " + type +
          " must have exactly two parts set.");
        }
        result.append(getBooleanConstraintType(type));
        result.append(getBooleanConstraintPart(pData, parts.next()));
      } else if (BooleanConstraint.Type.ISNULL.equals(type)) {
        expected = 1;
        result.append(" IS NULL");
      } else {
        throw new IllegalArgumentException("Invalid boolean constraint type: " + type);
      }
    }
    if (expected != &&  parts.hasNext()) {
      throw new NullPointerException("The boolean constraint " + type +
                                      " must have exactly " + expected +
                                      " parts set, but has " + pConstraint.getNumParts());
    }
    return result.toString();
  }

  protected String getCombinedConstraint(SelectStatementMetaData pData,
                                          CombinedConstraint pConstraint) {
    if (pConstraint.getNumParts() == 0) {
      return null;
    }

    List parts = new ArrayList();
    for (Iterator iter = pConstraint.getParts();  iter.hasNext()) {
      String s;
      Object o = iter.next();
      if (o == null) {
        throw new NullPointerException("A CombinedConstraints part must not be null");
      }
      if (o instanceof CombinedConstraint) {
        s = getCombinedConstraint(pData, (CombinedConstraint) o);
      } else if (o instanceof BooleanConstraint) {
        s = getBooleanConstraint(pData, (BooleanConstraint) o);           
      } else {
        throw new IllegalArgumentException("Invalid part: " + o.getClass().getName());
      }
      if (s != null) {
        parts.add(s);
      }
    }
    switch (parts.size()) {
      case 0: return null;
      case 1: return (String) parts.get(0);
      default:
        StringBuffer sb = new StringBuffer();
        for (int i = 0;  i < parts.size();  i++) {
          if (i == 0) {
            sb.append("(");
          } else {
            sb.append(" ");
            sb.append(pConstraint.getType());
            sb.append(" ");
          }
          sb.append(parts.get(i));
        }
        if (parts.size() > 0) {
          sb.append(")");
        }
        return sb.toString();
    }
  }

  public String getConstraint(SelectStatementMetaData pData, Constraint pConstraint) {
    if (pConstraint instanceof CombinedConstraint) {
      return getWhereClause(pData, (CombinedConstraint) pConstraint);
    } else if (pConstraint instanceof BooleanConstraint) {
      return getBooleanConstraint(pData, (BooleanConstraint) pConstraint);
    } else {
      throw new IllegalArgumentException("Unknown constraint type: " +
                                          pConstraint.getClass().getName());
    }
  }

  protected String getWhereClause(SelectStatementMetaData pData,
                                   CombinedConstraint pWhereClause) {
    return getCombinedConstraint(pData, pWhereClause);
  }

  protected class SelectStatementMetaData {
    private final Map aliases = new HashMap();
    private final Map columnNames = new HashMap();
    private final List tables = new ArrayList();

    public SelectStatementMetaData(SelectStatement pQuery) {
      addSelectStatement(pQuery);
      createTableAliases();
      createColumnNames();
    }

    protected void addSelectStatement(SelectStatement pQuery) {
      for (Iterator tableIter = pQuery.getSelectTableReferences();  tableIter.hasNext()) {
        TableReference tableReference = (TableReference) tableIter.next();
        Table.Name alias = tableReference.getAlias();
        if (alias != null) {
          if (aliases.containsKey(alias.getName())) {
            throw new NullPointerException("The alias " + alias +
                " is used twice for the tables " +
                ((TableReference) aliases.get(alias)).getTable().getName() +
                " and " + tableReference.getTable().getName());
          }
          aliases.put(alias.getName(), tableReference);
        }
        tables.add(tableReference);

        if (tableReference instanceof JoinReference) {
          addCombinedConstraint(((JoinReference) tableReference).getOn());
        }
      }
      addCombinedConstraint(pQuery.getWhere());
    }

    protected void addCombinedConstraint(CombinedConstraint pConstraint) {
      for (Iterator iter = pConstraint.getParts();  iter.hasNext()) {
        Object o = iter.next();
        if (o instanceof CombinedConstraint) {
          addCombinedConstraint((CombinedConstraint) o);
        } else if (o instanceof BooleanConstraint) {
          addBooleanConstraint((BooleanConstraint) o);
        } else {
          throw new IllegalStateException("Invalid part type in CombinedConstraint: " + o);
        }
      }
    }

    protected void addParts(Parts pParts) {
        for (Iterator iter = pParts.getParts();  iter.hasNext()) {
            Object o = iter.next();
            if (o instanceof SelectStatement) {
                addSelectStatement((SelectStatement) o);
            } else if (o instanceof CombinedConstraint) {
                addCombinedConstraint((CombinedConstraint) o);
            } else if (o instanceof Function) {
                addParts((Function) o);
            } else if (o instanceof ColumnReference
                    ||  o instanceof Value
                    ||  o instanceof RawSQLCode) {
                // Ignore me
            } else {
                throw new IllegalStateException("Invalid part in boolean constraint: " + o);
            }
        }
    }

    protected void addBooleanConstraint(BooleanConstraint pConstraint) {
      BooleanConstraint.Type type = pConstraint.getType();
      if (BooleanConstraint.Type.EQ.equals(type)
          ||  BooleanConstraint.Type.EXISTS.equals(type)
          ||  BooleanConstraint.Type.GE.equals(type)
          ||  BooleanConstraint.Type.GT.equals(type)
          ||  BooleanConstraint.Type.IN.equals(type)
          ||  BooleanConstraint.Type.ISNULL.equals(type)
          ||  BooleanConstraint.Type.LE.equals(type)
          ||  BooleanConstraint.Type.LIKE.equals(type)
          ||  BooleanConstraint.Type.LT.equals(type)
          ||  BooleanConstraint.Type.NE.equals(type)) {
        addParts(pConstraint);
      } else {
        throw new IllegalStateException("Invalid part type in BooleanConstraint: " + type);
      }
    }

    protected String getUniqueAlias(String pSuggestion, Map pAliases) {
      String prefix;
      if (pSuggestion == null) {
        prefix = "";
      } else {
        prefix = pSuggestion;
      }
      if (!pAliases.containsKey(prefix)) {
        return prefix;
      }
      for (char c = '0';  c <= '9';  c++) {
        String s = prefix + c;
        if (!pAliases.containsKey(s)) {
          return s;
        }
      }
      for (char c = 'A';  c <= 'Z';  c++) {
        String s = prefix + c;
        if (!pAliases.containsKey(s)) {
          return s;
        }
      }
      return getUniqueAlias(prefix + '0', pAliases);
    }

    protected void createTableAliases() {
      if (tables.size() > 1) {
        // Make sure that all tables have an alias
        for (Iterator iter = tables.iterator();  iter.hasNext()) {
          TableReference tableReference = (TableReference) iter.next();
          if (tableReference.getAlias() == null) {
            String alias = getUniqueAlias(tableReference.getTable().getName().getName(), aliases);
            aliases.put(alias, tableReference);
            if (!alias.equals(tableReference.getTable().getName().getName())) {
              tableReference.setAlias(alias);
            }
          }
        }
      }
    }

    protected void createColumnNames() {
      // Create a Map of all column names, that may be referenced.
      // maps key is the column name, and the maps value is the
      // number of possible references. In other words: If an entry
      // in the map has a value > 1, then its column name must be
      // qualified, because it is used in multiple tables.
      for (int i = 0;  i < tables.size();  i++) {
        TableReference table = (TableReference) tables.get(i);
        for (Iterator iter = table.getTable().getColumns();  iter.hasNext()) {
          Column col = (Column) iter.next();
          String key = col.getName().toString().toUpperCase();
          Integer num = (Integer) columnNames.get(key);
          if (num == null) {
            num = new Integer(1);
          } else {
            num = new Integer(num.intValue() + 1);
          }
          columnNames.put(key, num);
        }
      }
    }

    public Map getColumnNames() {
      return columnNames;
    }
  }
 
  protected String getSelectQuery(SelectStatement pQuery) {
    SelectStatementMetaData selectStatementMetaData = new SelectStatementMetaData(pQuery);
    return getSelectQuery(pQuery, selectStatementMetaData);
  }


  protected String getSelectQuery(SelectStatement pQuery, SelectStatementMetaData pData) {
    StringBuffer sb = new StringBuffer("SELECT");
    if (pQuery.isDistinct()) {
      sb.append(" DISTINCT");
    }

    Iterator columnIter = pQuery.getResultColumns();
    if (!columnIter.hasNext()) {
      sb.append(" *");
    } else {
      boolean first = true;
      do {
        ColumnReference column = (ColumnReference) columnIter.next();
        if (first) {
          sb.append(" ");
          first = false;
        } else {
          sb.append(", ");
        }
        sb.append(getColumnAlias(pData, column));
      } while (columnIter.hasNext());
    }

    SelectTableReference selectTableReference = pQuery.getSelectTableReference();
    if (selectTableReference != null) {
      sb.append(" FROM ");
      sb.append(getTableAlias(selectTableReference));
      for (JoinReference joinReference = selectTableReference.getRightJoinedTableReference();
           joinReference != null;
           joinReference = joinReference.getRightJoinedTableReference()) {
        sb.append(getJoinAlias(pData, joinReference));              
      }
    }
    
    String whereClause = getWhereClause(pData, pQuery.getWhere());
    if (whereClause != null) {
      sb.append(" WHERE ");
      sb.append(whereClause);
    }
    
    return sb.toString();
  }

  public String getQuery(Statement pStatement) {
    String s;
    if (pStatement instanceof InsertStatement) {
      s = getInsertQuery((InsertStatement) pStatement);
    } else if (pStatement instanceof UpdateStatement) {
      s = getUpdateQuery((UpdateStatement) pStatement);
    } else if (pStatement instanceof DeleteStatement) {
      s =  getDeleteQuery((DeleteStatement) pStatement);
    } else if (pStatement instanceof SelectStatement) {
      s = getSelectQuery((SelectStatement) pStatement);
    } else {
      throw new IllegalArgumentException("The Statement is neither an INSERT, UPDATE, DELETE nor a SELECT statement.");
    }
    return newStatement(s);
  }

  public Collection getCreate(Schema pSchema, boolean pAll) {
    if (!pAll) { return getCreate(pSchema); }
    List result = new ArrayList();
    result.addAll(getCreate(pSchema));
    for (Iterator iter = pSchema.getTables();  iter.hasNext()) {
      Table table = (Table) iter.next();
      result.addAll(getCreate(table, true));
    }
    return result;
  }

  public Collection getDrop(Schema pSchema, boolean pAll) {
    if (!pAll) { return getDrop(pSchema); }
    List result = new ArrayList();
    List tables = new ArrayList();
    for (Iterator iter = pSchema.getTables();  iter.hasNext()) {
      tables.add(iter.next());
    }
    Collections.reverse(tables);
    for (Iterator iter = tables.iterator();  iter.hasNext()) {
      Table table = (Table) iter.next();
      result.addAll(getDrop(table, true));
    }
    result.addAll(getDrop(pSchema));
    return result;
  }

  public Collection getCreate(Table pTable, boolean pAll) {
    if (!pAll) { return getCreate(pTable); }
    List result = new ArrayList();
    result.addAll(getCreate(pTable));
    for (Iterator iter = pTable.getIndexes();  iter.hasNext()) {
      Index index = (Index) iter.next();
      if (index.isPrimaryKey() && !isPrimaryKeyUniqueIndex()) {
        if (isPrimaryKeyPartOfCreateTable()) {
          continue;
        }
      } else if (index.isUnique()) {
        if (isUniqueIndexPartOfCreateTable()) {
          continue;
        }
      } else {
        if (isNonUniqueIndexPartOfCreateTable()) {
          continue;
        }
      }
      result.addAll(getCreate(index));
    }
    if (!isForeignKeyPartOfCreateTable()) {
      for (Iterator iter = pTable.getForeignKeys();  iter.hasNext()) {
        ForeignKey key = (ForeignKey) iter.next();
        result.addAll(getCreate(key));
      }
    }
    return result;
  }

  public Collection getDrop(Table pTable, boolean pAll) {
    if (!pAll) { return getDrop(pTable); }
    List result = new ArrayList();
    for (Iterator iter = pTable.getIndexes();  iter.hasNext()) {
      Index index = (Index) iter.next();
      result.addAll(getDrop(index));
    }
    for (Iterator iter = pTable.getForeignKeys();  iter.hasNext()) {
      ForeignKey key = (ForeignKey) iter.next();
      result.addAll(getDrop(key));
    }
    result.addAll(getDrop(pTable));
    return result;
  }

  public Collection getCreate(Index pIndex) {
    List result = new ArrayList();
    String s = createIndexAsPartOfCreateTable(pIndex);
    if (s != null) {
      StringBuffer sb = new StringBuffer();
      sb.append("CREATE");
      if (pIndex.isUnique()) {
        sb.append(" UNIQUE");
      }
      sb.append(" INDEX");
      sb.append(" ");
        sb.append(pIndex.getName());
      sb.append(" ON ").append(pIndex.getTable().getQName()).append(" (");
      boolean first = true;
      for (Iterator iter = pIndex.getColumns();  iter.hasNext()) {
        if (first) {
          first = false;
        } else {
          sb.append(", ");
        }
        sb.append(((Column) iter.next()).getName().getName());
      }
      sb.append(")");
      result.add(newStatement(sb.toString()));
    }
    return result;
  }

  public Collection getDrop(Index pIndex) {
    return Collections.EMPTY_SET;
  }

  public Collection getCreate(ForeignKey pKey) {
    List result = new ArrayList();
    String s = createForeignKeyAsPartOfCreateTable(pKey);
    if (s != null) {
      result.add(newStatement("CREATE " + s));
    }
    return result;
  }

  public Collection getDrop(ForeignKey pKey) {
    return Collections.EMPTY_SET;
  }

  public String getConstraint(Constraint pConstraint) {
    if (pConstraint instanceof CombinedConstraint) {
      CombinedConstraint cc = (CombinedConstraint) pConstraint;
      Statement st = cc.getConstrainedStatement();
      if (st instanceof SelectStatement) {
        SelectStatementMetaData selectStatementMetaData = new SelectStatementMetaData((SelectStatement) st);
        return getCombinedConstraint(selectStatementMetaData, cc);
      } else {
        return getCombinedConstraint(null, cc);
      }
    } else if (pConstraint instanceof BooleanConstraint) {
      BooleanConstraint bc = (BooleanConstraint) pConstraint;
      Statement st = bc.getConstrainedStatement();
      if (st instanceof SelectStatement) {
        SelectStatementMetaData selectStatementMetaData = new SelectStatementMetaData((SelectStatement) st);
        return getBooleanConstraint(selectStatementMetaData, bc);
      } else {
        return getBooleanConstraint(null, bc);
      }
     } else {
       throw new IllegalStateException("Invalid type of Constraint: " + pConstraint);
     }
  }
}
TOP

Related Classes of org.apache.ws.jaxme.sqls.impl.SQLGeneratorImpl$SelectStatementMetaData

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.