Open Source Repository

Home /hibernate/hibernate-3.2.6.ga | Repository Home


org/hibernate/mapping/Table.java
//$Id: Table.java 14034 2007-09-29 17:18:42Z d.plentz $
package org.hibernate.mapping;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.SequencedHashMap;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.Mapping;
import org.hibernate.tool.hbm2ddl.ColumnMetadata;
import org.hibernate.tool.hbm2ddl.TableMetadata;
import org.hibernate.util.CollectionHelper;

/**
 * A relational table
 *
 @author Gavin King
 */
public class Table implements RelationalModel, Serializable {

  private String name;
  private String schema;
  private String catalog;
  /**
   * contains all columns, including the primary key
   */
  private Map columns = new SequencedHashMap();
  private KeyValue idValue;
  private PrimaryKey primaryKey;
  private Map indexes = new HashMap();
  private Map foreignKeys = new HashMap();
  private Map uniqueKeys = new HashMap();
  private final int uniqueInteger;
  private boolean quoted;
  private boolean schemaQuoted;
  private static int tableCounter = 0;
  private List checkConstraints = new ArrayList();
  private String rowId;
  private String subselect;
  private boolean isAbstract;
  private boolean hasDenormalizedTables = false;
  private String comment;

  static class ForeignKeyKey implements Serializable {
    String referencedClassName;
    List columns;
    List referencedColumns;

    ForeignKeyKey(List columns, String referencedClassName, List referencedColumns) {
      this.referencedClassName = referencedClassName;
      this.columns = new ArrayList();
      this.columns.addAllcolumns );
      if referencedColumns != null ) {
        this.referencedColumns = new ArrayList();
        this.referencedColumns.addAllreferencedColumns );
      }
      else {
        this.referencedColumns = CollectionHelper.EMPTY_LIST;
      }
    }

    public int hashCode() {
      return columns.hashCode() + referencedColumns.hashCode();
    }

    public boolean equals(Object other) {
      ForeignKeyKey fkk = (ForeignKeyKeyother;
      return fkk.columns.equalscolumns &&
          fkk.referencedClassName.equalsreferencedClassName && fkk.referencedColumns
          .equalsreferencedColumns );
    }
  }

  public Table() {
    uniqueInteger = tableCounter++;
  }

  public Table(String name) {
    this();
    setNamename );
  }

  public String getQualifiedName(Dialect dialect, String defaultCatalog, String defaultSchema) {
    if subselect != null ) {
      return "( " + subselect + " )";
    }
    String quotedName = getQuotedNamedialect );
    String usedSchema = schema == null ?
        defaultSchema :
        getQuotedSchemadialect );
    String usedCatalog = catalog == null ?
        defaultCatalog :
        catalog;
    return qualifyusedCatalog, usedSchema, quotedName );
  }

  public static String qualify(String catalog, String schema, String table) {
    StringBuffer qualifiedName = new StringBuffer();
    if catalog != null ) {
      qualifiedName.appendcatalog ).append'.' );
    }
    if schema != null ) {
      qualifiedName.appendschema ).append'.' );
    }
    return qualifiedName.appendtable ).toString();
  }

  public String getName() {
    return name;
  }

  /**
   * returns quoted name as it would be in the mapping file.
   */
  public String getQuotedName() {
    return quoted ?
        "`" + name + "`" :
        name;
  }

  public String getQuotedName(Dialect dialect) {
    return quoted ?
        dialect.openQuote() + name + dialect.closeQuote() :
        name;
  }

  /**
   * returns quoted name as it is in the mapping file.
   */
  public String getQuotedSchema() {
    return schemaQuoted ?
        "`" + schema + "`" :
        schema;
  }

  public String getQuotedSchema(Dialect dialect) {
    return schemaQuoted ?
        dialect.openQuote() + schema + dialect.closeQuote() :
        schema;
  }

  public void setName(String name) {
    if name.charAt== '`' ) {
      quoted = true;
      this.name = name.substring1, name.length() );
    }
    else {
      this.name = name;
    }
  }

  /**
   * Return the column which is identified by column provided as argument.
   *
   @param column column with atleast a name.
   @return the underlying column or null if not inside this table. Note: the instance *can* be different than the input parameter, but the name will be the same.
   */
  public Column getColumn(Column column) {
    if column == null ) {
      return null;
    }

    Column myColumn = (Columncolumns.getcolumn.getCanonicalName() );

    return column.equalsmyColumn ?
        myColumn :
        null;
  }

  public Column getColumn(int n) {
    Iterator iter = columns.values().iterator();
    for int i = 0; i < n - 1; i++ ) {
      iter.next();
    }
    return (Columniter.next();
  }

  public void addColumn(Column column) {
    Column old = (ColumngetColumncolumn );
    if old == null ) {
      columns.putcolumn.getCanonicalName(), column );
      column.uniqueInteger = columns.size();
    }
    else {
      column.uniqueInteger = old.uniqueInteger;
    }
  }

  public int getColumnSpan() {
    return columns.size();
  }

  public Iterator getColumnIterator() {
    return columns.values().iterator();
  }

  public Iterator getIndexIterator() {
    return indexes.values().iterator();
  }

  public Iterator getForeignKeyIterator() {
    return foreignKeys.values().iterator();
  }

  public Iterator getUniqueKeyIterator() {
    return getUniqueKeys().values().iterator();
  }

  Map getUniqueKeys() {
    if uniqueKeys.size() ) {
      //deduplicate unique constraints sharing the same columns
      //this is needed by Hibernate Annotations since it creates automagically
      // unique constraints for the user
      Iterator it = uniqueKeys.entrySet().iterator();
      Map finalUniqueKeys = new HashMapuniqueKeys.size() );
      while it.hasNext() ) {
        Map.Entry entry = (Map.Entryit.next();
        UniqueKey uk = (UniqueKeyentry.getValue();
        List columns = uk.getColumns();
        int size = finalUniqueKeys.size();
        boolean skip = false;
        Iterator tempUks = finalUniqueKeys.entrySet().iterator();
        while tempUks.hasNext() ) {
          final UniqueKey currentUk = (UniqueKey) ( (Map.EntrytempUks.next() ).getValue();
          if currentUk.getColumns().containsAllcolumns && columns
              .containsAllcurrentUk.getColumns() ) ) {
            skip = true;
            break;
          }
        }
        if !skip finalUniqueKeys.putentry.getKey(), uk );
      }
      return finalUniqueKeys;
    }
    else {
      return uniqueKeys;
    }
  }

  public void validateColumns(Dialect dialect, Mapping mapping, TableMetadata tableInfo) {
    Iterator iter = getColumnIterator();
    while iter.hasNext() ) {
      Column col = (Columniter.next();

      ColumnMetadata columnInfo = tableInfo.getColumnMetadatacol.getName() );

      if columnInfo == null ) {
        throw new HibernateException"Missing column: " + col.getName() " in " + Table.qualifytableInfo.getCatalog(), tableInfo.getSchema(), tableInfo.getName()));
      }
      else {
        final boolean typesMatch = col.getSqlTypedialect, mapping ).toLowerCase()
            .startsWithcolumnInfo.getTypeName().toLowerCase() )
            || columnInfo.getTypeCode() == col.getSqlTypeCodemapping );
        if !typesMatch ) {
          throw new HibernateException(
              "Wrong column type in " +
              Table.qualifytableInfo.getCatalog(), tableInfo.getSchema(), tableInfo.getName()) +
              " for column " + col.getName() +
              ". Found: " + columnInfo.getTypeName().toLowerCase() +
              ", expected: " + col.getSqlTypedialect, mapping )
          );
        }
      }
    }

  }

  public Iterator sqlAlterStrings(Dialect dialect, Mapping p, TableMetadata tableInfo, String defaultCatalog,
                  String defaultSchema)
      throws HibernateException {

    StringBuffer root = new StringBuffer"alter table " )
        .appendgetQualifiedNamedialect, defaultCatalog, defaultSchema ) )
        .append' ' )
        .appenddialect.getAddColumnString() );

    Iterator iter = getColumnIterator();
    List results = new ArrayList();
    while iter.hasNext() ) {
      Column column = (Columniter.next();

      ColumnMetadata columnInfo = tableInfo.getColumnMetadatacolumn.getName() );

      if columnInfo == null ) {
        // the column doesnt exist at all.
        StringBuffer alter = new StringBufferroot.toString() )
            .append' ' )
            .appendcolumn.getQuotedNamedialect ) )
            .append' ' )
            .appendcolumn.getSqlTypedialect, p ) );

        String defaultValue = column.getDefaultValue();
        if defaultValue != null ) {
          alter.append" default " ).appenddefaultValue );

          if column.isNullable() ) {
            alter.appenddialect.getNullColumnString() );
          }
          else {
            alter.append" not null" );
          }

        }

        boolean useUniqueConstraint = column.isUnique() &&
            dialect.supportsUnique() &&
            !column.isNullable() || dialect.supportsNotNullUnique() );
        if useUniqueConstraint ) {
          alter.append" unique" );
        }

        if column.hasCheckConstraint() && dialect.supportsColumnCheck() ) {
          alter.append" check(" )
              .appendcolumn.getCheckConstraint() )
              .append")" );
        }

        String columnComment = column.getComment();
        if columnComment != null ) {
          alter.appenddialect.getColumnCommentcolumnComment ) );
        }

        results.addalter.toString() );
      }

    }

    return results.iterator();
  }

  public boolean hasPrimaryKey() {
    return getPrimaryKey() != null;
  }

  public String sqlTemporaryTableCreateString(Dialect dialect, Mapping mappingthrows HibernateException {
    StringBuffer buffer = new StringBufferdialect.getCreateTemporaryTableString() )
        .append' ' )
        .appendname )
        .append" (" );
    Iterator itr = getColumnIterator();
    while itr.hasNext() ) {
      final Column column = (Columnitr.next();
      buffer.appendcolumn.getQuotedNamedialect ) ).append' ' );
      buffer.appendcolumn.getSqlTypedialect, mapping ) );
      if column.isNullable() ) {
        buffer.appenddialect.getNullColumnString() );
      }
      else {
        buffer.append" not null" );
      }
      if itr.hasNext() ) {
        buffer.append", " );
      }
    }
    buffer.append") " );
    buffer.appenddialect.getCreateTemporaryTablePostfix() );
    return buffer.toString();
  }

  public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) {
    StringBuffer buf = new StringBufferhasPrimaryKey() ? dialect.getCreateTableString() : dialect.getCreateMultisetTableString() )
        .append' ' )
        .appendgetQualifiedNamedialect, defaultCatalog, defaultSchema ) )
        .append" (" );

    boolean identityColumn = idValue != null && idValue.isIdentityColumndialect );

    // Try to find out the name of the primary key to create it as identity if the IdentityGenerator is used
    String pkname = null;
    if hasPrimaryKey() && identityColumn ) {
      pkname = ( (ColumngetPrimaryKey().getColumnIterator().next() ).getQuotedNamedialect );
    }

    Iterator iter = getColumnIterator();
    while iter.hasNext() ) {
      Column col = (Columniter.next();

      buf.appendcol.getQuotedNamedialect ) )
          .append' ' );

      if identityColumn && col.getQuotedNamedialect ).equalspkname ) ) {
        // to support dialects that have their own identity data type
        if dialect.hasDataTypeInIdentityColumn() ) {
          buf.appendcol.getSqlTypedialect, p ) );
        }
        buf.append' ' )
            .appenddialect.getIdentityColumnStringcol.getSqlTypeCode) ) );
      }
      else {

        buf.appendcol.getSqlTypedialect, p ) );

        String defaultValue = col.getDefaultValue();
        if defaultValue != null ) {
          buf.append" default " ).appenddefaultValue );
        }

        if col.isNullable() ) {
          buf.appenddialect.getNullColumnString() );
        }
        else {
          buf.append" not null" );
        }

      }

      boolean useUniqueConstraint = col.isUnique() &&
          !col.isNullable() || dialect.supportsNotNullUnique() );
      if useUniqueConstraint ) {
        if dialect.supportsUnique() ) {
          buf.append" unique" );
        }
        else {
          UniqueKey uk = getOrCreateUniqueKeycol.getQuotedNamedialect '_' );
          uk.addColumncol );
        }
      }

      if col.hasCheckConstraint() && dialect.supportsColumnCheck() ) {
        buf.append" check (" )
            .appendcol.getCheckConstraint() )
            .append")" );
      }

      String columnComment = col.getComment();
      if columnComment != null ) {
        buf.appenddialect.getColumnCommentcolumnComment ) );
      }

      if iter.hasNext() ) {
        buf.append", " );
      }

    }
    if hasPrimaryKey() ) {
      buf.append", " )
          .appendgetPrimaryKey().sqlConstraintStringdialect ) );
    }

    if dialect.supportsUniqueConstraintInCreateAlterTable() ) {
      Iterator ukiter = getUniqueKeyIterator();
      while ukiter.hasNext() ) {
        UniqueKey uk = (UniqueKeyukiter.next();
        String constraint = uk.sqlConstraintStringdialect );
        if constraint != null ) {
          buf.append", " ).appendconstraint );
        }
      }
    }
    /*Iterator idxiter = getIndexIterator();
    while ( idxiter.hasNext() ) {
      Index idx = (Index) idxiter.next();
      buf.append(',').append( idx.sqlConstraintString(dialect) );
    }*/

    if dialect.supportsTableCheck() ) {
      Iterator chiter = checkConstraints.iterator();
      while chiter.hasNext() ) {
        buf.append", check (" )
            .appendchiter.next() )
            .append')' );
      }
    }

    buf.append')' );

    if comment != null ) {
      buf.appenddialect.getTableCommentcomment ) );
    }

    return buf.appenddialect.getTableTypeString() ).toString();
  }

  public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
    StringBuffer buf = new StringBuffer"drop table " );
    if dialect.supportsIfExistsBeforeTableName() ) {
      buf.append"if exists " );
    }
    buf.appendgetQualifiedNamedialect, defaultCatalog, defaultSchema ) )
        .appenddialect.getCascadeConstraintsString() );
    if dialect.supportsIfExistsAfterTableName() ) {
      buf.append" if exists" );
    }
    return buf.toString();
  }

  public PrimaryKey getPrimaryKey() {
    return primaryKey;
  }

  public void setPrimaryKey(PrimaryKey primaryKey) {
    this.primaryKey = primaryKey;
  }

  public Index getOrCreateIndex(String indexName) {

    Index index = (Indexindexes.getindexName );

    if index == null ) {
      index = new Index();
      index.setNameindexName );
      index.setTablethis );
      indexes.putindexName, index );
    }

    return index;
  }

  public Index getIndex(String indexName) {
    return (Indexindexes.getindexName );
  }

  public Index addIndex(Index index) {
    Index current = (Indexindexes.getindex.getName() );
    if current != null ) {
      throw new MappingException"Index " + index.getName() " already exists!" );
    }
    indexes.putindex.getName(), index );
    return index;
  }

  public UniqueKey addUniqueKey(UniqueKey uniqueKey) {
    UniqueKey current = (UniqueKeyuniqueKeys.getuniqueKey.getName() );
    if current != null ) {
      throw new MappingException"UniqueKey " + uniqueKey.getName() " already exists!" );
    }
    uniqueKeys.putuniqueKey.getName(), uniqueKey );
    return uniqueKey;
  }

  public UniqueKey createUniqueKey(List keyColumns) {
    String keyName = "UK" + uniqueColumnStringkeyColumns.iterator() );
    UniqueKey uk = getOrCreateUniqueKeykeyName );
    uk.addColumnskeyColumns.iterator() );
    return uk;
  }

  public UniqueKey getUniqueKey(String keyName) {
    return (UniqueKeyuniqueKeys.getkeyName );
  }

  public UniqueKey getOrCreateUniqueKey(String keyName) {
    UniqueKey uk = (UniqueKeyuniqueKeys.getkeyName );

    if uk == null ) {
      uk = new UniqueKey();
      uk.setNamekeyName );
      uk.setTablethis );
      uniqueKeys.putkeyName, uk );
    }
    return uk;
  }

  public void createForeignKeys() {
  }

  public ForeignKey createForeignKey(String keyName, List keyColumns, String referencedEntityName) {
    return createForeignKeykeyName, keyColumns, referencedEntityName, null );
  }

  public ForeignKey createForeignKey(String keyName, List keyColumns, String referencedEntityName,
                     List referencedColumns) {
    Object key = new ForeignKeyKeykeyColumns, referencedEntityName, referencedColumns );

    ForeignKey fk = (ForeignKeyforeignKeys.getkey );
    if fk == null ) {
      fk = new ForeignKey();
      if keyName != null ) {
        fk.setNamekeyName );
      }
      else {
        fk.setName"FK" + uniqueColumnStringkeyColumns.iterator(), referencedEntityName ) );
        //TODO: add referencedClass to disambiguate to FKs on the same
        //      columns, pointing to different tables
      }
      fk.setTablethis );
      foreignKeys.putkey, fk );
      fk.setReferencedEntityNamereferencedEntityName );
      fk.addColumnskeyColumns.iterator() );
      if referencedColumns != null ) {
        fk.addReferencedColumnsreferencedColumns.iterator() );
      }
    }

    if keyName != null ) {
      fk.setNamekeyName );
    }

    return fk;
  }


  public String uniqueColumnString(Iterator iterator) {
    return uniqueColumnStringiterator, null );
  }

  public String uniqueColumnString(Iterator iterator, String referencedEntityName) {
    int result = 0;
    if referencedEntityName != null ) {
      result += referencedEntityName.hashCode();
    }
    while iterator.hasNext() ) {
      result += iterator.next().hashCode();
    }
    return Integer.toHexStringname.hashCode() ) + Integer.toHexStringresult ) ).toUpperCase();
  }


  public String getSchema() {
    return schema;
  }

  public void setSchema(String schema) {
    if schema != null && schema.charAt== '`' ) {
      schemaQuoted = true;
      this.schema = schema.substring1, schema.length() );
    }
    else {
      this.schema = schema;
    }
  }

  public String getCatalog() {
    return catalog;
  }

  public void setCatalog(String catalog) {
    this.catalog = catalog;
  }

  public int getUniqueInteger() {
    return uniqueInteger;
  }

  public void setIdentifierValue(KeyValue idValue) {
    this.idValue = idValue;
  }

  public KeyValue getIdentifierValue() {
    return idValue;
  }

  public boolean isSchemaQuoted() {
    return schemaQuoted;
  }

  public boolean isQuoted() {
    return quoted;
  }

  public void setQuoted(boolean quoted) {
    this.quoted = quoted;
  }

  public void addCheckConstraint(String constraint) {
    checkConstraints.addconstraint );
  }

  public boolean containsColumn(Column column) {
    return columns.containsValuecolumn );
  }

  public String getRowId() {
    return rowId;
  }

  public void setRowId(String rowId) {
    this.rowId = rowId;
  }

  public String toString() {
    StringBuffer buf = new StringBuffer().appendgetClass().getName() )
        .append'(' );
    if getCatalog() != null ) {
      buf.appendgetCatalog() "." );
    }
    if getSchema() != null ) {
      buf.appendgetSchema() "." );
    }
    buf.appendgetName() ).append')' );
    return buf.toString();
  }

  public String getSubselect() {
    return subselect;
  }

  public void setSubselect(String subselect) {
    this.subselect = subselect;
  }

  public boolean isSubselect() {
    return subselect != null;
  }

  public boolean isAbstractUnionTable() {
    return hasDenormalizedTables() && isAbstract;
  }

  public boolean hasDenormalizedTables() {
    return hasDenormalizedTables;
  }

  void setHasDenormalizedTables() {
    hasDenormalizedTables = true;
  }

  public void setAbstract(boolean isAbstract) {
    this.isAbstract = isAbstract;
  }

  public boolean isAbstract() {
    return isAbstract;
  }

  public boolean isPhysicalTable() {
    return !isSubselect() && !isAbstractUnionTable();
  }

  public String getComment() {
    return comment;
  }

  public void setComment(String comment) {
    this.comment = comment;
  }

  public Iterator getCheckConstraintsIterator() {
    return checkConstraints.iterator();
  }

  public Iterator sqlCommentStrings(Dialect dialect, String defaultCatalog, String defaultSchema) {
    List comments = new ArrayList();
    if dialect.supportsCommentOn() ) {
      String tableName = getQualifiedNamedialect, defaultCatalog, defaultSchema );
      if comment != null ) {
        StringBuffer buf = new StringBuffer()
            .append"comment on table " )
            .appendtableName )
            .append" is '" )
            .appendcomment )
            .append"'" );
        comments.addbuf.toString() );
      }
      Iterator iter = getColumnIterator();
      while iter.hasNext() ) {
        Column column = (Columniter.next();
        String columnComment = column.getComment();
        if columnComment != null ) {
          StringBuffer buf = new StringBuffer()
              .append"comment on column " )
              .appendtableName )
              .append'.' )
              .appendcolumn.getQuotedNamedialect ) )
              .append" is '" )
              .appendcolumnComment )
              .append"'" );
          comments.addbuf.toString() );
        }
      }
    }
    return comments.iterator();
  }

}