Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2007 Daniel Spiewak
   *
   * 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 net.java.ao.schema.ddl;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 
 
 import static com.google.common.collect.Lists.newArrayList;
 import static net.java.ao.sql.SqlUtils.closeQuietly;

WARNING: Not part of the public API. This class is public only to allow its use within other packages in the ActiveObjects library.

Author(s):
Daniel Spiewak
 
 public final class SchemaReader
 {
     static
     {
         try
         {
              = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("0000-00-00 00:00:00").getTime();
         }
         catch (ParseException e)
         {
             throw new IllegalStateException(e);
         }
     }
 
     private static final long DEFAULT_MYSQL_TIME;

    
Currently doesn't account for:
  • setUnique
 
     public static DDLTable[] readSchema(DatabaseProvider providerNameConverters nameConvertersSchemaConfiguration schemaConfigurationthrows SQLException
     {
         return readSchema(providernameConvertersschemaConfigurationtrue);
     }
 
     public static DDLTable[] readSchema(DatabaseProvider providerNameConverters nameConvertersSchemaConfiguration schemaConfigurationfinal boolean includeForeignKeysthrows SQLException
     {
         Connection connection = null;
         try
         {
             connection = provider.getConnection();
             return readSchema(connectionprovidernameConvertersschemaConfigurationincludeForeignKeys);
         }
         finally
         {
             closeQuietly(connection);
         }
    }
    public static DDLTable[] readSchema(Connection connectionDatabaseProvider providerNameConverters nameConvertersSchemaConfiguration schemaConfigurationfinal boolean includeForeignKeysthrows SQLException
    {
        final DatabaseMetaDataReader databaseMetaDataReader = new DatabaseMetaDataReaderImpl(providernameConvertersschemaConfiguration);
        final DatabaseMetaData databaseMetaData = connection.getMetaData();
        final List<DDLTabletables = newArrayList(Iterables.transform(databaseMetaDataReader.getTableNames(databaseMetaData), new Function<StringDDLTable>()
        {
            public DDLTable apply(String tableName)
            {
                return readTable(databaseMetaDataReaderdatabaseMetaDatatableNameincludeForeignKeys);
            }
        }));
        return tables.toArray(new DDLTable[tables.size()]);
    }
    private static DDLTable readTable(DatabaseMetaDataReader databaseMetaDataReaderDatabaseMetaData databaseMetaDataString tableNameboolean includeForeignKeys)
    {
        DDLTable table = new DDLTable();
        table.setName(tableName);
        final List<DDLFieldfields = readFields(databaseMetaDataReaderdatabaseMetaDatatableName);
        table.setFields(fields.toArray(new DDLField[fields.size()]));
        if (includeForeignKeys)
        {
            final List<DDLForeignKeyforeignKeys = readForeignKeys(databaseMetaDataReaderdatabaseMetaDatatableName);
            table.setForeignKeys(foreignKeys.toArray(new DDLForeignKey[foreignKeys.size()]));
        }
        final List<DDLIndexindexes = readIndexes(databaseMetaDataReaderdatabaseMetaDatatableName);
        table.setIndexes(indexes.toArray(new DDLIndex[indexes.size()]));
        return table;
    }
    private static List<DDLFieldreadFields(DatabaseMetaDataReader databaseMetaDataReaderDatabaseMetaData databaseMetaDataString tableName)
    {
        return newArrayList(Iterables.transform(databaseMetaDataReader.
                getFields(databaseMetaDatatableName), new Function<FieldDDLField>()
        {
            public DDLField apply(Field from)
            {
                DDLField field = new DDLField();
                field.setAutoIncrement(from.isAutoIncrement());
                field.setDefaultValue(from.getDefaultValue());
                field.setName(from.getName());
                field.setNotNull(from.isNotNull());
                field.setPrimaryKey(from.isPrimaryKey());
                field.setType(from.getDatabaseType());
                field.setJdbcType(from.getJdbcType());
                field.setUnique(from.isUnique());
                return field;
            }
        }));
    }
    private static List<DDLForeignKeyreadForeignKeys(DatabaseMetaDataReader databaseMetaDataReaderDatabaseMetaData databaseMetaDataString tableName)
    {
        return newArrayList(Iterables.transform(databaseMetaDataReader.getForeignKeys(databaseMetaDatatableName), new Function<ForeignKeyDDLForeignKey>()
        {
            public DDLForeignKey apply(ForeignKey from)
            {
                DDLForeignKey key = new DDLForeignKey();
                key.setForeignField(from.getForeignFieldName());
                key.setField(from.getLocalFieldName());
                key.setTable(from.getForeignTableName());
                key.setDomesticTable(from.getLocalTableName());
                return key;
            }
        }));
    }
    private static List<DDLIndexreadIndexes(DatabaseMetaDataReader databaseMetaDataReaderDatabaseMetaData databaseMetaDatafinal String tableName)
    {
        return  newArrayList(Iterables.transform(databaseMetaDataReader.getIndexes(databaseMetaDatatableName), new Function<IndexDDLIndex>()
        {
            public DDLIndex apply(Index index)
            {
                DDLIndex ddl = new DDLIndex();
                ddl.setTable(tableName);
                ddl.setField(index.getFieldName());
                ddl.setIndexName(index.getIndexName());
                return ddl;
            }
        }));
    }

    
Returns the difference between from and onto with a bias toward from. Thus, if a table is present in from but not onto, a CREATE TABLE statement will be generated.
    public static DDLAction[] diffSchema(TypeManager typeManagerDDLTable[] fromArrayDDLTable[] ontoArrayboolean caseSensitive)
    {
        Set<DDLActionactions = new HashSet<DDLAction>();
        List<DDLTablecreateTables = new ArrayList<DDLTable>();
        List<DDLTabledropTables = new ArrayList<DDLTable>();
        List<DDLTablealterTables = new ArrayList<DDLTable>();
        Map<StringDDLTablefrom = new HashMap<StringDDLTable>();
        Map<StringDDLTableonto = new HashMap<StringDDLTable>();
        for (DDLTable table : fromArray)
        {
            final String tableName = transform(table.getName(), caseSensitive);
            from.put(tableNametable);
        }
        for (DDLTable table : ontoArray)
        {
            final String tableName = transform(table.getName(), caseSensitive);
            onto.put(tableNametable);
        }
        for (DDLTable table : fromArray)
        {
            final String tableName = transform(table.getName(), caseSensitive);
            if (onto.containsKey(tableName))
            {
                alterTables.add(table);
            }
            else
            {
                createTables.add(table);
            }
        }
        for (DDLTable table : ontoArray)
        {
            String tableName = transform(table.getName(), caseSensitive);
            if (!from.containsKey(tableName))
            {
                dropTables.add(table);
            }
        }
        for (DDLTable table : createTables)
        {
            DDLAction action = new DDLAction(.);
            action.setTable(table);
            actions.add(action);
        }
        List<DDLForeignKeydropKeys = new ArrayList<DDLForeignKey>();
        for (DDLTable table : dropTables)
        {
            DDLAction action = new DDLAction(.);
            action.setTable(table);
            actions.add(action);
            // remove all foreign keys on that table
            dropKeys.addAll(Arrays.asList(table.getForeignKeys()));
            // remove all foreign to that table
            for (DDLTable alterTable : alterTables)
            {
                for (DDLForeignKey fKey : alterTable.getForeignKeys())
                {
                    if (equals(fKey.getTable(), table.getName(), caseSensitive))
                    {
                        dropKeys.add(fKey);
                    }
                }
            }
        }
        for (DDLTable fromTable : alterTables)
        {
            final String s = fromTable.getName();
            String tableName = transform(scaseSensitive);
            DDLTable ontoTable = onto.get(tableName);
            List<DDLFieldcreateFields = new ArrayList<DDLField>();
            List<DDLFielddropFields = new ArrayList<DDLField>();
            List<DDLFieldalterFields = new ArrayList<DDLField>();
            Map<StringDDLFieldfromFields = new HashMap<StringDDLField>();
            Map<StringDDLFieldontoFields = new HashMap<StringDDLField>();
            for (DDLField field : fromTable.getFields())
            {
                String fieldName = transform(field.getName(), caseSensitive);
                fromFields.put(fieldNamefield);
            }
            for (DDLField field : ontoTable.getFields())
            {
                String fieldName = transform(field.getName(), caseSensitive);
                ontoFields.put(fieldNamefield);
            }
            for (DDLField field : fromTable.getFields())
            {
                String fieldName = transform(field.getName(), caseSensitive);
                if (ontoFields.containsKey(fieldName))
                {
                    alterFields.add(field);
                }
                else
                {
                    createFields.add(field);
                }
            }
            for (DDLField field : ontoTable.getFields())
            {
                String fieldName = transform(field.getName(), caseSensitive);
                if (!fromFields.containsKey(fieldName))
                {
                    dropFields.add(field);
                }
            }
            for (DDLField field : createFields)
            {
                DDLAction action = new DDLAction(.);
                action.setTable(fromTable);
                action.setField(field);
                actions.add(action);
            }
            for (DDLField field : dropFields)
            {
                DDLAction action = new DDLAction(.);
                action.setTable(fromTable);
                action.setField(field);
                actions.add(action);
            }
            for (DDLField fromField : alterFields)
            {
                final String fieldName = transform(fromField.getName(), caseSensitive);
                final DDLField ontoField = ontoFields.get(fieldName);
                if (fromField.getDefaultValue() == null && ontoField.getDefaultValue() != null)
                {
                    actions.add(createColumnAlterAction(fromTableontoFieldfromField));
                }
                else if (fromField.getDefaultValue() != null
                        && !Common.fuzzyCompare(typeManagerfromField.getDefaultValue(), ontoField.getDefaultValue()))
                {
                    actions.add(createColumnAlterAction(fromTableontoFieldfromField));
                }
                else if (!physicalTypesEqual(fromField.getType(), ontoField.getType()))
                {
                    actions.add(createColumnAlterAction(fromTableontoFieldfromField));
                }
                else if (fromField.isNotNull() != ontoField.isNotNull())
                {
                    actions.add(createColumnAlterAction(fromTableontoFieldfromField));
                }
                else if (!fromField.isPrimaryKey() && (fromField.isUnique() != ontoField.isUnique()))
                {
                    actions.add(createColumnAlterAction(fromTableontoFieldfromField));
                }
            }
            // foreign keys
            List<DDLForeignKeyaddKeys = new ArrayList<DDLForeignKey>();
            for (DDLForeignKey fromKey : fromTable.getForeignKeys())
            {
                for (DDLForeignKey ontoKey : ontoTable.getForeignKeys())
                {
                    if (!(fromKey.getTable().equalsIgnoreCase(ontoKey.getTable())
                            && fromKey.getForeignField().equalsIgnoreCase(ontoKey.getForeignField()))
                            && fromKey.getField().equalsIgnoreCase(ontoKey.getField())
                            && fromKey.getDomesticTable().equalsIgnoreCase(ontoKey.getDomesticTable()))
                    {
                        addKeys.add(fromKey);
                    }
                }
            }
            for (DDLForeignKey ontoKey : ontoTable.getForeignKeys())
            {
                if (containsField(dropFieldsontoKey.getField()))
                {
                    dropKeys.add(ontoKey);
                    continue;
                }
                for (DDLForeignKey fromKey : fromTable.getForeignKeys())
                {
                    if (!(ontoKey.getTable().equalsIgnoreCase(fromKey.getTable())
                            && ontoKey.getForeignField().equalsIgnoreCase(fromKey.getForeignField()))
                            && ontoKey.getField().equalsIgnoreCase(fromKey.getField())
                            && ontoKey.getDomesticTable().equalsIgnoreCase(fromKey.getDomesticTable()))
                    {
                        dropKeys.add(ontoKey);
                    }
                }
            }
            for (DDLForeignKey key : addKeys)
            {
                DDLAction action = new DDLAction(.);
                action.setKey(key);
                actions.add(action);
            }
            // field indexes
            List<DDLIndexaddIndexes = new ArrayList<DDLIndex>();
            List<DDLIndexdropIndexes = new ArrayList<DDLIndex>();
            for (DDLIndex fromIndex : fromTable.getIndexes())
            {
                boolean found = false;
                for (DDLIndex ontoIndex : ontoTable.getIndexes())
                {
                    if (fromIndex.getTable().equalsIgnoreCase(ontoIndex.getTable())
                            && fromIndex.getField().equalsIgnoreCase(ontoIndex.getField()))
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    addIndexes.add(fromIndex);
                }
            }
            for (DDLIndex ontoIndex : ontoTable.getIndexes())
            {
                boolean found = false;
                for (DDLIndex fromIndex : fromTable.getIndexes())
                {
                    if (ontoIndex.getTable().equalsIgnoreCase(fromIndex.getTable())
                            && ontoIndex.getField().equalsIgnoreCase(fromIndex.getField()))
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    dropIndexes.add(ontoIndex);
                }
            }
            for (DDLIndex index : addIndexes)
            {
                DDLAction action = new DDLAction(.);
                action.setIndex(index);
                actions.add(action);
            }
            for (DDLIndex index : dropIndexes)
            {
                DDLAction action = new DDLAction(.);
                action.setIndex(index);
                actions.add(action);
            }
        }
        for (DDLForeignKey key : dropKeys)
        {
            DDLAction action = new DDLAction(.);
            action.setKey(key);
            actions.add(action);
        }
        return actions.toArray(new DDLAction[actions.size()]);
    }
    private static boolean physicalTypesEqual(TypeInfo fromTypeInfo onto)
    {
        // We need to check qualifier compatibility instead of equality because there can be a mismatch between entity annotation derived
        // qualifiers vs. those derived from table metadata even when the schema hasn't changed.
        return TypeQualifiers.areCompatible(from.getQualifiers(), onto.getQualifiers()) && from.getSchemaProperties().equals(onto.getSchemaProperties());
    }
    private static boolean equals(String sString s1boolean caseSensitive)
    {
        return transform(scaseSensitive).equals(transform(s1caseSensitive));
    }
    private static String transform(String sboolean caseSensitive)
    {
        if (!caseSensitive)
        {
            return ..apply(s);
        }
        else
        {
            return s;
        }
    }
    public static DDLAction[] sortTopologically(DDLAction[] actions)
    {
        List<DDLActionback = new LinkedList<DDLAction>();
        Map<DDLActionSet<DDLAction>> deps = new HashMap<DDLActionSet<DDLAction>>();
        List<DDLActionroots = new LinkedList<DDLAction>();
        Set<DDLActioncovered = new HashSet<DDLAction>();
        performSort(actionsdepsroots);
        while (!roots.isEmpty())
        {
            DDLAction[] rootsArray = roots.toArray(new DDLAction[roots.size()]);
            roots.remove(rootsArray[0]);
            if (covered.contains(rootsArray[0]))
            {
                throw new RuntimeException("Circular dependency detected in or below " + rootsArray[0].getTable().getName());
            }
            covered.add(rootsArray[0]);
            back.add(rootsArray[0]);
            List<DDLActiontoRemove = new LinkedList<DDLAction>();
            Iterator<DDLActiondepIterator = deps.keySet().iterator();
            while (depIterator.hasNext())
            {
                DDLAction depAction = depIterator.next();
                Set<DDLActionindividualDeps = deps.get(depAction);
                individualDeps.remove(rootsArray[0]);
                if (individualDeps.isEmpty())
                {
                    roots.add(depAction);
                    toRemove.add(depAction);
                }
            }
            for (DDLAction action : toRemove)
            {
                deps.remove(action);
            }
        }
        return back.toArray(new DDLAction[back.size()]);
    }
    /*
      * DROP_KEY
      * DROP_INDEX
      * DROP_COLUMN
      * CHANGE_COLUMN
      * DROP
      * CREATE
      * ADD_COLUMN
      * ADD_KEY
      * CREATE_INDEX
      */
    private static void performSort(DDLAction[] actionsMap<DDLActionSet<DDLAction>> depsList<DDLActionroots)
    {
        List<DDLActiondropKeys = new LinkedList<DDLAction>();
        List<DDLActiondropIndexes = new LinkedList<DDLAction>();
        List<DDLActiondropColumns = new LinkedList<DDLAction>();
        List<DDLActionchangeColumns = new LinkedList<DDLAction>();
        List<DDLActiondrops = new LinkedList<DDLAction>();
        List<DDLActioncreates = new LinkedList<DDLAction>();
        List<DDLActionaddColumns = new LinkedList<DDLAction>();
        List<DDLActionaddKeys = new LinkedList<DDLAction>();
        List<DDLActioncreateIndexes = new LinkedList<DDLAction>();
        for (DDLAction action : actions)
        {
            switch (action.getActionType())
            {
                case :
                    dropKeys.add(action);
                    break;
                case :
                    dropIndexes.add(action);
                    break;
                case :
                    dropColumns.add(action);
                    break;
                case :
                    changeColumns.add(action);
                    break;
                case :
                    drops.add(action);
                    break;
                case :
                    creates.add(action);
                    break;
                case :
                    addColumns.add(action);
                    break;
                case :
                    addKeys.add(action);
                    break;
                case :
                    createIndexes.add(action);
                    break;
            }
        }
        roots.addAll(dropKeys);
        roots.addAll(dropIndexes);
        for (DDLAction action : dropColumns)
        {
            Set<DDLActiondependencies = new HashSet<DDLAction>();
            for (DDLAction depAction : dropKeys)
            {
                DDLForeignKey key = depAction.getKey();
                if ((key.getTable().equals(action.getTable().getName()) && key.getForeignField().equals(action.getField().getName()))
                        || (key.getDomesticTable().equals(action.getTable().getName()) && key.getField().equals(action.getField().getName())))
                {
                    dependencies.add(depAction);
                }
            }
            if (dependencies.size() == 0)
            {
                roots.add(action);
            }
            else
            {
                deps.put(actiondependencies);
            }
        }
        for (DDLAction action : changeColumns)
        {
            Set<DDLActiondependencies = new HashSet<DDLAction>();
            for (DDLAction depAction : dropKeys)
            {
                DDLForeignKey key = depAction.getKey();
                if ((key.getTable().equals(action.getTable().getName()) && key.getForeignField().equals(action.getField().getName()))
                        || (key.getDomesticTable().equals(action.getTable().getName()) && key.getField().equals(action.getField().getName())))
                {
                    dependencies.add(depAction);
                }
            }
            for (DDLAction depAction : dropColumns)
            {
                if ((depAction.getTable().equals(action.getTable()) && depAction.getField().equals(action.getField()))
                        || (depAction.getTable().equals(action.getTable()) && depAction.getField().equals(action.getOldField())))
                {
                    dependencies.add(depAction);
                }
            }
            if (dependencies.size() == 0)
            {
                roots.add(action);
            }
            else
            {
                deps.put(actiondependencies);
            }
        }
        for (DDLAction action : drops)
        {
            Set<DDLActiondependencies = new HashSet<DDLAction>();
            for (DDLAction depAction : dropKeys)
            {
                DDLForeignKey key = depAction.getKey();
                if (key.getTable().equals(action.getTable().getName()) || key.getDomesticTable().equals(action.getTable().getName()))
                {
                    dependencies.add(depAction);
                }
            }
            for (DDLAction depAction : dropColumns)
            {
                if (depAction.getTable().equals(action.getTable()))
                {
                    dependencies.add(depAction);
                }
            }
            for (DDLAction depAction : changeColumns)
            {
                if (depAction.getTable().equals(action.getTable()))
                {
                    dependencies.add(depAction);
                }
            }
            if (dependencies.size() == 0)
            {
                roots.add(action);
            }
            else
            {
                deps.put(actiondependencies);
            }
        }
        for (DDLAction action : creates)
        {
            Set<DDLActiondependencies = new HashSet<DDLAction>();
            for (DDLForeignKey key : action.getTable().getForeignKeys())
            {
                for (DDLAction depAction : creates)
                {
                    if (depAction != action && depAction.getTable().getName().equals(key.getTable()))
                    {
                        dependencies.add(depAction);
                    }
                }
                for (DDLAction depAction : addColumns)
                {
                    if (depAction.getTable().getName().equals(key.getTable())
                            && depAction.getField().getName().equals(key.getForeignField()))
                    {
                        dependencies.add(depAction);
                    }
                }
                for (DDLAction depAction : changeColumns)
                {
                    if (depAction.getTable().getName().equals(key.getTable())
                            && depAction.getField().getName().equals(key.getForeignField()))
                    {
                        dependencies.add(depAction);
                    }
                }
            }
            if (dependencies.size() == 0)
            {
                roots.add(action);
            }
            else
            {
                deps.put(actiondependencies);
            }
        }
        for (DDLAction action : addColumns)
        {
            Set<DDLActiondependencies = new HashSet<DDLAction>();
            for (DDLAction depAction : creates)
            {
                if (depAction.getTable().equals(action.getTable()))
                {
                    dependencies.add(depAction);
                }
            }
            if (dependencies.size() == 0)
            {
                roots.add(action);
            }
            else
            {
                deps.put(actiondependencies);
            }
        }
        for (DDLAction action : addKeys)
        {
            Set<DDLActiondependencies = new HashSet<DDLAction>();
            DDLForeignKey key = action.getKey();
            for (DDLAction depAction : creates)
            {
                if (depAction.getTable().getName().equals(key.getTable())
                        || depAction.getTable().getName().equals(key.getDomesticTable()))
                {
                    dependencies.add(depAction);
                }
            }
            for (DDLAction depAction : addColumns)
            {
                if ((depAction.getTable().getName().equals(key.getTable()) && depAction.getField().getName().equals(key.getForeignField()))
                        || (depAction.getTable().getName().equals(key.getDomesticTable())) && depAction.getField().getName().equals(key.getField()))
                {
                    dependencies.add(depAction);
                }
            }
            for (DDLAction depAction : changeColumns)
            {
                if ((depAction.getTable().getName().equals(key.getTable()) && depAction.getField().getName().equals(key.getForeignField()))
                        || (depAction.getTable().getName().equals(key.getDomesticTable())) && depAction.getField().getName().equals(key.getField()))
                {
                    dependencies.add(depAction);
                }
            }
            if (dependencies.size() == 0)
            {
                roots.add(action);
            }
            else
            {
                deps.put(actiondependencies);
            }
        }
        for (DDLAction action : createIndexes)
        {
            Set<DDLActiondependencies = new HashSet<DDLAction>();
            DDLIndex index = action.getIndex();
            for (DDLAction depAction : creates)
            {
                if (depAction.getTable().getName().equals(index.getTable()))
                {
                    dependencies.add(depAction);
                }
            }
            for (DDLAction depAction : addColumns)
            {
                if (depAction.getTable().getName().equals(index.getTable()) || depAction.getField().getName().equals(index.getField()))
                {
                    dependencies.add(depAction);
                }
            }
            for (DDLAction depAction : changeColumns)
            {
                if (depAction.getTable().getName().equals(index.getTable()) || depAction.getField().getName().equals(index.getField()))
                {
                    dependencies.add(depAction);
                }
            }
            if (dependencies.size() == 0)
            {
                roots.add(action);
            }
            else
            {
                deps.put(actiondependencies);
            }
        }
    }
    private static boolean containsField(Iterable<DDLFieldfieldsfinal String fieldName) {
        return Iterables.tryFind(fieldsnew Predicate<DDLField>()
        {
            @Override
            public boolean apply(DDLField field)
            {
                return field.getName().equalsIgnoreCase(fieldName);
            }
        }).isPresent();
    }
    private static DDLAction createColumnAlterAction(DDLTable tableDDLField oldFieldDDLField field)
    {
        DDLAction action = new DDLAction(.);
        action.setTable(table);
        action.setField(field);
        action.setOldField(oldField);
        return action;
    }
New to GrepCode? Check out our FAQ X