You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ddlutils-dev@db.apache.org by to...@apache.org on 2005/12/28 22:58:33 UTC

svn commit: r359648 - in /db/ddlutils/trunk/src/java/org/apache/ddlutils: Platform.java PlatformInfo.java platform/DerbyModelReader.java platform/DerbyPlatform.java platform/JdbcModelReader.java platform/PlatformImplBase.java platform/SqlBuilder.java

Author: tomdz
Date: Wed Dec 28 13:58:24 2005
New Revision: 359648

URL: http://svn.apache.org/viewcvs?rev=359648&view=rev
Log:
Added platform method to perform a database shutdown (for embedded databases that require it)
Moved removal of database-generated interla indices from a read model to the base jdbc model reader, controlled by a new flag in the platform info
Added check and new flag to control generation of non-primary key identity columns

Modified:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/Platform.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/PlatformInfo.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyModelReader.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyPlatform.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/Platform.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/Platform.java?rev=359648&r1=359647&r2=359648&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/Platform.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/Platform.java Wed Dec 28 13:58:24 2005
@@ -151,6 +151,22 @@
     public int evaluateBatch(Connection connection, String sql, boolean continueOnError) throws DynaSqlException;
 
     /**
+     * Performs a shutdown at the database. This is necessary for some embedded databases which otherwise
+     * would be locked and thus would refuse other connections. Note that this does not change the database
+     * structure or data in it in any way.
+     */
+    public void shutdownDatabase() throws DynaSqlException;
+
+    /**
+     * Performs a shutdown at the database. This is necessary for some embedded databases which otherwise
+     * would be locked and thus would refuse other connections. Note that this does not change the database
+     * structure or data in it in any way.
+     * 
+     * @param connection The connection to the database
+     */
+    public void shutdownDatabase(Connection connection) throws DynaSqlException;
+
+    /**
      * Creates the database specified by the given parameters. Please note that this method does not
      * use a data source set via {@link #setDataSource(DataSource)} because it is not possible to
      * retrieve the connection information from it without establishing a connection.<br/>

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/PlatformInfo.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/PlatformInfo.java?rev=359648&r1=359647&r2=359648&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/PlatformInfo.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/PlatformInfo.java Wed Dec 28 13:58:24 2005
@@ -50,6 +50,9 @@
     /** Whether embedded foreign key constraints are explicitly named. */
     private boolean _embeddedForeignKeysNamed = false;
 
+    /** Whether identity specification is supported for non-primary key columns. */
+    private boolean _supportingNonPKIdentityColumns = true;
+
     /** Whether an ALTER TABLE is needed to drop indexes. */
     private boolean _useAlterTableForDrop = false;
 
@@ -99,6 +102,10 @@
     /** Contains those JDBC types whose corresponding native types are types that have precision and scale on this platform. */
     private HashSet _typesWithPrecisionAndScale = new HashSet();
 
+    /** Whether system indices (database-generated indices for primary and foreign keys) are returned when
+        reading a model from a database. */
+    private boolean _returningSystemIndices = true;
+
     /**
      * Creates a new platform info object.
      */
@@ -233,6 +240,27 @@
     }
 
     /**
+     * Determines whether non-primary key columns can be auto-incrementing (IDENTITY columns).
+     *
+     * @return <code>true</code> if normal non-PK columns can be auto-incrementing
+     */
+    public boolean isSupportingNonPKIdentityColumns()
+    {
+        return _supportingNonPKIdentityColumns;
+    }
+
+    /**
+     * Specifies whether non-primary key columns can be auto-incrementing (IDENTITY columns).
+     *
+     * @param supportingNonPKIdentityColumns <code>true</code> if normal non-PK columns can
+     *                                       be auto-incrementing
+     */
+    public void setSupportingNonPKIdentityColumns(boolean supportingNonPKIdentityColumns)
+    {
+        _supportingNonPKIdentityColumns = supportingNonPKIdentityColumns;
+    }
+
+    /**
      * Determines whether an ALTER TABLE statement shall be used for dropping indices
      * or constraints.  The default is false.
      * 
@@ -696,4 +724,27 @@
     {
         return _typesWithPrecisionAndScale.contains(new Integer(sqlTypeCode));
     }
+
+    /**
+     * Determines whether database-generated indices for primary and foreign keys are
+     * returned when reading a model from a database.
+     *
+     * @return <code>true</code> if system indices are read from a live database
+     */
+    public boolean isReturningSystemIndices()
+    {
+        return _returningSystemIndices;
+    }
+
+    /**
+     * Specifies whether database-generated indices for primary and foreign keys are
+     * returned when reading a model from a database.
+     *
+     * @param returningSystemIndices <code>true</code> if system indices are read from a live database
+     */
+    public void setReturningSystemIndices(boolean returningSystemIndices)
+    {
+        _returningSystemIndices = returningSystemIndices;
+    }
+
 }

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyModelReader.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyModelReader.java?rev=359648&r1=359647&r2=359648&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyModelReader.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyModelReader.java Wed Dec 28 13:58:24 2005
@@ -17,14 +17,11 @@
  */
 
 import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Map;
 
+import org.apache.ddlutils.PlatformInfo;
 import org.apache.ddlutils.model.Column;
-import org.apache.ddlutils.model.ForeignKey;
 import org.apache.ddlutils.model.Index;
-import org.apache.ddlutils.model.Table;
 
 /**
  * Reads a database model from a Derby database.
@@ -35,6 +32,16 @@
 public class DerbyModelReader extends JdbcModelReader
 {
     /**
+     * Creates a new model reader for Derby databases.
+     * 
+     * @param platformInfo The platform specific settings
+     */
+    public DerbyModelReader(PlatformInfo platformInfo)
+    {
+        super(platformInfo);
+    }
+    
+    /**
      * {@inheritDoc}
      */
     protected Column readColumn(DatabaseMetaDataWrapper metaData, Map values) throws SQLException
@@ -57,89 +64,12 @@
     }
 
     /**
-     * {@inheritDoc}
-     */
-    protected Table readTable(DatabaseMetaDataWrapper metaData, Map values) throws SQLException
-    {
-        Table    table       = super.readTable(metaData, values);
-        Column[] pks         = table.getPrimaryKeyColumns();
-        List     columnNames = new ArrayList();
-
-        for (int columnIdx = 0; columnIdx < pks.length; columnIdx++)
-        {
-            columnNames.add(pks[columnIdx].getName());
-        }
-
-        // Derby returns a unique index for the pk which we don't want however
-        int indexIdx = findMatchingInternalIndex(table, columnNames, true);
-
-        if (indexIdx >= 0)
-        {
-            table.removeIndex(indexIdx);
-        }
-
-        // Likewise, Derby returns a non-unique index for every foreign key
-        for (int fkIdx = 0; fkIdx < table.getForeignKeyCount(); fkIdx++)
-        {
-            ForeignKey fk = table.getForeignKey(fkIdx);
-
-            columnNames.clear();
-            for (int columnIdx = 0; columnIdx < fk.getReferenceCount(); columnIdx++)
-            {
-                columnNames.add(fk.getReference(columnIdx).getLocalColumnName());
-            }
-            indexIdx = findMatchingInternalIndex(table, columnNames, false);
-            if (indexIdx >= 0)
-            {
-                table.removeIndex(indexIdx);
-            }
-        }
-        return table;
-    }
-
-    /**
-     * Tries to find an internal index that matches the given columns.
-     * 
-     * @param table              The table
-     * @param columnsToSearchFor The names of the columns that the index should be for
-     * @param unique             Whether to search for an unique index
-     * @return The position of the index or <code>-1</code> if no such index was found
-     */
-    private int findMatchingInternalIndex(Table table, List columnsToSearchFor, boolean unique)
-    {
-        for (int indexIdx = 0; indexIdx < table.getIndexCount(); indexIdx++)
-        {
-            Index index = table.getIndex(indexIdx);
-
-            if ((unique == index.isUnique()) && (index.getColumnCount() == columnsToSearchFor.size()))
-            {
-                boolean found = true;
-
-                for (int columnIdx = 0; found && (columnIdx < index.getColumnCount()); columnIdx++)
-                {
-                    if (!columnsToSearchFor.get(columnIdx).equals(index.getColumn(columnIdx).getName()))
-                    {
-                        found = false;
-                    }
-                }
-
-                // if the index seems to be internal, we immediately return it
-                if (found && mightBeInternalIndex(index))
-                {
-                    return indexIdx;
-                }
-            }
-        }
-        return -1;
-    }
-
-    /**
      * Guesses whether the index might be an internal index, i.e. one created by Derby.
      * 
      * @param index The index to check
      * @return <code>true</code> if the index seems to be an internal one
      */
-    private boolean mightBeInternalIndex(Index index)
+    protected boolean mightBeInternalIndex(Index index)
     {
         String name = index.getName();
 

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyPlatform.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyPlatform.java?rev=359648&r1=359647&r2=359648&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyPlatform.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyPlatform.java Wed Dec 28 13:58:24 2005
@@ -27,10 +27,6 @@
 /**
  * The platform implementation for Derby.
  * 
- * TODO: Add jdbc model reader refinement for auto-increment columns:
- *       * COLUMN_DEF = GENERATED_BY_DEFAULT               -> 'GENERATED BY DEFAULT AS IDENTITY'
- *       * COLUMN_DEF = AUTOINCREMENT: start 1 increment 1 -> 'GENERATED ALWAYS AS IDENTITY'
- * 
  * @author Thomas Dudziak
  * @version $Revision: 231306 $
  */
@@ -51,9 +47,8 @@
     public DerbyPlatform()
     {
         super();
-        // we override the builder
         setSqlBuilder(new DerbyBuilder(getSqlBuilder().getPlatformInfo()));
-        setModelReader(new DerbyModelReader());
+        setModelReader(new DerbyModelReader(getSqlBuilder().getPlatformInfo()));
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java?rev=359648&r1=359647&r2=359648&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java Wed Dec 28 13:58:24 2005
@@ -30,6 +30,7 @@
 import org.apache.commons.collections.map.ListOrderedMap;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.ddlutils.PlatformInfo;
 import org.apache.ddlutils.model.Column;
 import org.apache.ddlutils.model.Database;
 import org.apache.ddlutils.model.ForeignKey;
@@ -63,20 +64,28 @@
     /** The descriptors for the relevant columns in the index meta data. */
     private final List _columnsForIndex;
 
+    /** The platform specific settings. */
+    private PlatformInfo _platformInfo;
     /** Contains default column sizes (minimum sizes that a JDBC-compliant db must support). */
     private HashMap _defaultSizes = new HashMap();
     /** The default database catalog to read. */
-    private String _defaultCatalog = "%";
-    /** The sefault database schema(s) to read. */
+    private String _defaultCatalogPattern = "%";
+    /** The default database schema(s) to read. */
     private String _defaultSchemaPattern = "%";
+    /** The default pattern for reading all tables. */
+    private String _defaultTablePattern = "%";
     /** The table types to recognize per default. */
     private String[] _defaultTableTypes = { "TABLE" };
 
     /**
      * Creates a new model reader instance.
+     * 
+     * @param platformInfo The platform specific settings
      */
-    public JdbcModelReader()
+    public JdbcModelReader(PlatformInfo platformInfo)
     {
+        _platformInfo = platformInfo;
+
         _defaultSizes.put(new Integer(Types.CHAR),          "254");
         _defaultSizes.put(new Integer(Types.VARCHAR),       "254");
         _defaultSizes.put(new Integer(Types.LONGVARCHAR),   "254");
@@ -99,6 +108,16 @@
     }
 
     /**
+     * Returns the platform specific settings.
+     *
+     * @return The platform settings
+     */
+    public PlatformInfo getPlatformInfo()
+    {
+        return _platformInfo;
+    }
+
+    /**
      * Returns descriptors for the columns that shall be read from the result set when
      * reading the meta data for a table. Note that the columns are read in the order
      * defined by this list.<br/>
@@ -206,29 +225,29 @@
     }
 
     /**
-     * Returns the catalog in the database to read per default.
+     * Returns the catalog(s) in the database to read per default.
      *
-     * @return The default catalog
+     * @return The default catalog(s)
      */
-    public String getDefaultCatalog()
+    public String getDefaultCatalogPattern()
     {
-        return _defaultCatalog;
+        return _defaultCatalogPattern;
     }
 
     /**
-     * Sets the catalog in the database to read per default.
+     * Sets the catalog(s) in the database to read per default.
      * 
-     * @param catalog The catalog
+     * @param catalogPattern The catalog(s)
      */
-    public void setDefaultCatalog(String catalog)
+    public void setDefaultCatalogPattern(String catalogPattern)
     {
-        _defaultCatalog = catalog;
+        _defaultCatalogPattern = catalogPattern;
     }
 
     /**
-     * Returns the schema in the database to read per default.
+     * Returns the schema(s) in the database to read per default.
      *
-     * @return The default schema
+     * @return The default schema(s)
      */
     public String getDefaultSchemaPattern()
     {
@@ -236,9 +255,9 @@
     }
 
     /**
-     * Sets the schema in the database to read per default.
+     * Sets the schema(s) in the database to read per default.
      * 
-     * @param schemaPattern The schema
+     * @param schemaPattern The schema(s)
      */
     public void setDefaultSchemaPattern(String schemaPattern)
     {
@@ -246,6 +265,26 @@
     }
 
     /**
+     * Returns the default pattern to read the relevant tables from the database.
+     *
+     * @return The table pattern
+     */
+    public String getDefaultTablePattern()
+    {
+        return _defaultTablePattern;
+    }
+
+    /**
+     * Sets the default pattern to read the relevant tables from the database.
+     *
+     * @param tablePattern The table pattern
+     */
+    public void setDefaultTablePattern(String tablePattern)
+    {
+        _defaultTablePattern = tablePattern;
+    }
+
+    /**
      * Returns the table types to recognize per default.
      *
      * @return The default table types
@@ -385,11 +424,11 @@
             DatabaseMetaDataWrapper metaData = new DatabaseMetaDataWrapper();
 
             metaData.setMetaData(connection.getMetaData());
-            metaData.setCatalog(catalog == null ? getDefaultCatalog() : catalog);
+            metaData.setCatalog(catalog == null ? getDefaultCatalogPattern() : catalog);
             metaData.setSchemaPattern(schemaPattern == null ? getDefaultSchemaPattern() : schemaPattern);
             metaData.setTableTypes((tableTypes == null) || (tableTypes.length == 0) ? getDefaultTableTypes() : tableTypes);
             
-            tableData = metaData.getTables("%");
+            tableData = metaData.getTables(getDefaultTablePattern());
 
             List tables = new ArrayList();
 
@@ -446,8 +485,107 @@
             {
                 table.findColumn((String)it.next(), true).setPrimaryKey(true);
             }
+
+            if (getPlatformInfo().isReturningSystemIndices())
+            {
+                removeSystemIndices(table);
+            }
         }
         return table;
+    }
+
+
+    /**
+     * Removes system indices (generated by the database for primary and foreign keys)
+     * from the table.
+     * 
+     * @param table The table
+     */
+    protected void removeSystemIndices(Table table)
+    {
+        Column[] pks         = table.getPrimaryKeyColumns();
+        List     columnNames = new ArrayList();
+
+        for (int columnIdx = 0; columnIdx < pks.length; columnIdx++)
+        {
+            columnNames.add(pks[columnIdx].getName());
+        }
+
+        // Derby returns a unique index for the pk which we don't want however
+        int indexIdx = findMatchingInternalIndex(table, columnNames, true);
+
+        if (indexIdx >= 0)
+        {
+            table.removeIndex(indexIdx);
+        }
+
+        // Likewise, Derby returns a non-unique index for every foreign key
+        for (int fkIdx = 0; fkIdx < table.getForeignKeyCount(); fkIdx++)
+        {
+            ForeignKey fk = table.getForeignKey(fkIdx);
+
+            columnNames.clear();
+            for (int columnIdx = 0; columnIdx < fk.getReferenceCount(); columnIdx++)
+            {
+                columnNames.add(fk.getReference(columnIdx).getLocalColumnName());
+            }
+            indexIdx = findMatchingInternalIndex(table, columnNames, false);
+            if (indexIdx >= 0)
+            {
+                table.removeIndex(indexIdx);
+            }
+        }
+    }
+
+
+    /**
+     * Tries to find an internal index that matches the given columns.
+     * 
+     * @param table              The table
+     * @param columnsToSearchFor The names of the columns that the index should be for
+     * @param unique             Whether to search for an unique index
+     * @return The position of the index or <code>-1</code> if no such index was found
+     */
+    protected int findMatchingInternalIndex(Table table, List columnsToSearchFor, boolean unique)
+    {
+        for (int indexIdx = 0; indexIdx < table.getIndexCount(); indexIdx++)
+        {
+            Index index = table.getIndex(indexIdx);
+
+            if ((unique == index.isUnique()) && (index.getColumnCount() == columnsToSearchFor.size()))
+            {
+                boolean found = true;
+
+                for (int columnIdx = 0; found && (columnIdx < index.getColumnCount()); columnIdx++)
+                {
+                    if (!columnsToSearchFor.get(columnIdx).equals(index.getColumn(columnIdx).getName()))
+                    {
+                        found = false;
+                    }
+                }
+
+                // if the index seems to be internal, we immediately return it
+                if (found && mightBeInternalIndex(index))
+                {
+                    return indexIdx;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Guesses whether the index might be an internal database-generated index.
+     * Note that only indices with the correct columns are fed to this method.
+     * Redefine this method for specific platforms if there are better ways
+     * to determine internal indices.
+     * 
+     * @param index The index to check
+     * @return <code>true</code> if the index seems to be an internal one
+     */
+    protected boolean mightBeInternalIndex(Index index)
+    {
+        return true;
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java?rev=359648&r1=359647&r2=359648&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java Wed Dec 28 13:58:24 2005
@@ -68,7 +68,7 @@
     /** The sql builder for this platform. */
     private SqlBuilder _builder;
     /** The model reader for this platform. */
-    private JdbcModelReader _modelReader = new JdbcModelReader();
+    private JdbcModelReader _modelReader;
 
     /**
      * {@inheritDoc}
@@ -93,6 +93,10 @@
      */
     public JdbcModelReader getModelReader()
     {
+        if (_modelReader == null)
+        {
+            _modelReader = new JdbcModelReader(getPlatformInfo());
+        }
         return _modelReader;
     }
 
@@ -234,6 +238,31 @@
         }
 
         return errors;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void shutdownDatabase() throws DynaSqlException
+    {
+        Connection connection = borrowConnection();
+
+        try
+        {
+            shutdownDatabase(connection);
+        }
+        finally
+        {
+            returnConnection(connection);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void shutdownDatabase(Connection connection) throws DynaSqlException
+    {
+        // Per default do nothing as most databases don't need this
     }
 
     /**

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java?rev=359648&r1=359647&r2=359648&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java Wed Dec 28 13:58:24 2005
@@ -28,6 +28,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.ddlutils.DynaSqlException;
 import org.apache.ddlutils.PlatformInfo;
 import org.apache.ddlutils.model.Column;
 import org.apache.ddlutils.model.Database;
@@ -1130,6 +1131,10 @@
         }
         if (column.isAutoIncrement())
         {
+            if (!getPlatformInfo().isSupportingNonPKIdentityColumns() && !column.isPrimaryKey())
+            {
+                throw new DynaSqlException("Column "+column.getName()+" in table "+table.getName()+" is auto-incrementing but not a primary key column, which is not supported by the platform");
+            }
             print(" ");
             writeColumnAutoIncrementStmt(table, column);
         }
@@ -1531,7 +1536,7 @@
                 if (col == null)
                 {
                     //would get null pointer on next line anyway, so throw exception
-                    throw new RuntimeException("Invalid column '" + idxColumn.getName() + "' on index " + index.getName() + " for table " + table.getName());
+                    throw new DynaSqlException("Invalid column '" + idxColumn.getName() + "' on index " + index.getName() + " for table " + table.getName());
                 }
                 if (idx > 0)
                 {