Author: tomdz
Date: Tue Dec 27 09:16:30 2005
New Revision: 359242

URL: http://svn.apache.org/viewcvs?rev=359242&view=rev
Log:
Started restructuring of the jdbc model reader to make it easier to sub class 
it and redefine portions for specific platforms

Added:
    
db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/MetaDataColumnDescriptor.java
Modified:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Database.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/DerbyPlatform.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/JdbcModelReader.java

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Database.java
URL: 
http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Database.java?rev=359242&r1=359241&r2=359242&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Database.java 
(original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Database.java Tue Dec 
27 09:16:30 2005
@@ -19,6 +19,7 @@
 import java.io.Serializable;
 import java.sql.Types;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
 
@@ -199,6 +200,19 @@
         if (table != null)
         {
             _tables.add(idx, table);
+        }
+    }
+
+    /**
+     * Adds the given tables.
+     * 
+     * @param tables The tables to add
+     */
+    public void addTables(Collection tables)
+    {
+        for (Iterator it = tables.iterator(); it.hasNext();)
+        {
+            addTable((Table)it.next());
         }
     }
 

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java
URL: 
http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java?rev=359242&r1=359241&r2=359242&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/model/Table.java Tue Dec 27 
09:16:30 2005
@@ -214,6 +214,19 @@
     }
 
     /**
+     * Adds the given columns.
+     * 
+     * @param columns The columns
+     */
+    public void addColumns(Collection columns)
+    {
+        for (Iterator it = columns.iterator(); it.hasNext();)
+        {
+            addColumn((Column)it.next());
+        }
+    }
+
+    /**
      * Removes the given column.
      * 
      * @param column The column to remove
@@ -295,6 +308,19 @@
     }
 
     /**
+     * Adds the given foreign keys.
+     * 
+     * @param foreignKeys The foreign keys
+     */
+    public void addForeignKeys(Collection foreignKeys)
+    {
+        for (Iterator it = foreignKeys.iterator(); it.hasNext();)
+        {
+            addForeignKey((ForeignKey)it.next());
+        }
+    }
+
+    /**
      * Removes the given foreign key.
      * 
      * @param foreignKey The foreign key to remove
@@ -362,6 +388,19 @@
         if (index != null)
         {
             _indices.add(idx, index);
+        }
+    }
+
+    /**
+     * Adds the given indices.
+     * 
+     * @param indices The indices
+     */
+    public void addIndices(Collection indices)
+    {
+        for (Iterator it = indices.iterator(); it.hasNext();)
+        {
+            addIndex((Index)it.next());
         }
     }
 

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=359242&r1=359241&r2=359242&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 
Tue Dec 27 09:16:30 2005
@@ -27,6 +27,10 @@
 /**
  * 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 $
  */

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=359242&r1=359241&r2=359242&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 
Tue Dec 27 09:16:30 2005
@@ -18,20 +18,16 @@
 
 import java.sql.Connection;
 import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.Types;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
-import org.apache.commons.collections.map.LinkedMap;
+import org.apache.commons.collections.map.ListOrderedMap;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ddlutils.model.Column;
@@ -56,6 +52,17 @@
     /** The Log to which logging calls will be made. */
     private final Log _log = LogFactory.getLog(JdbcModelReader.class);
 
+    /** The descriptors for the relevant columns in the table meta data. */
+    private final List _columnsForTable;
+    /** The descriptors for the relevant columns in the table column meta 
data. */
+    private final List _columnsForColumn;
+    /** The descriptors for the relevant columns in the primary key meta data. 
*/
+    private final List _columnsForPK;
+    /** The descriptors for the relevant columns in the foreign key meta data. 
*/
+    private final List _columnsForFK;
+    /** The descriptors for the relevant columns in the index meta data. */
+    private final List _columnsForIndex;
+
     /** Contains default column sizes (minimum sizes that a JDBC-compliant db 
must support). */
     private HashMap _defaultSizes = new HashMap();
     /** The default database catalog to read. */
@@ -64,8 +71,6 @@
     private String _defaultSchemaPattern = "%";
     /** The table types to recognize per default. */
     private String[] _defaultTableTypes = { "TABLE" };
-    /** The pattern to recognize when parsing a default value. */
-    private Pattern _defaultPattern = Pattern.compile("\\(\\'?(.*?)\\'?\\)");
 
     /**
      * Creates a new model reader instance.
@@ -85,6 +90,119 @@
         _defaultSizes.put(new Integer(Types.DOUBLE),        "15,0");
         _defaultSizes.put(new Integer(Types.DECIMAL),       "15,15");
         _defaultSizes.put(new Integer(Types.NUMERIC),       "15,15");
+
+        _columnsForTable  = initColumnsForTable();
+        _columnsForColumn = initColumnsForColumn();
+        _columnsForPK     = initColumnsForPK();
+        _columnsForFK     = initColumnsForFK();
+        _columnsForIndex  = initColumnsForIndex();
+    }
+
+    /**
+     * 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/>
+     * Redefine this method if you want more columns or a different order. 
+     * 
+     * @return The descriptors for the result set columns
+     */
+    protected List initColumnsForTable()
+    {
+        List result = new ArrayList();
+
+        result.add(new MetaDataColumnDescriptor("TABLE_NAME",  Types.VARCHAR));
+        result.add(new MetaDataColumnDescriptor("TABLE_TYPE",  Types.VARCHAR, 
"UNKNOWN"));
+        result.add(new MetaDataColumnDescriptor("TABLE_CAT",   Types.VARCHAR));
+        result.add(new MetaDataColumnDescriptor("TABLE_SCHEM", Types.VARCHAR));
+        result.add(new MetaDataColumnDescriptor("REMARKS",     Types.VARCHAR));
+
+        return result;
+    }
+
+    /**
+     * Returns descriptors for the columns that shall be read from the result 
set when
+     * reading the meta data for table columns. Note that the columns are read 
in the order
+     * defined by this list.<br/>
+     * Redefine this method if you want more columns or a different order.
+     * 
+     * @return The map column name -> descriptor for the result set columns
+     */
+    protected List initColumnsForColumn()
+    {
+        List result = new ArrayList();
+
+        // As suggested by Alexandre Borgoltz, we're reading the COLUMN_DEF 
first because Oracle
+        // has problems otherwise (it seemingly requires a LONG column to be 
the first to be read)
+        // See also DDLUTILS-29
+        result.add(new MetaDataColumnDescriptor("COLUMN_DEF",     
Types.VARCHAR));
+        result.add(new MetaDataColumnDescriptor("COLUMN_NAME",    
Types.VARCHAR));
+        result.add(new MetaDataColumnDescriptor("DATA_TYPE",      
Types.INTEGER, new Integer(java.sql.Types.OTHER)));
+        result.add(new MetaDataColumnDescriptor("NUM_PREC_RADIX", 
Types.INTEGER, new Integer(10)));
+        result.add(new MetaDataColumnDescriptor("DECIMAL_DIGITS", 
Types.INTEGER, new Integer(0)));
+        result.add(new MetaDataColumnDescriptor("COLUMN_SIZE",    
Types.VARCHAR));
+        result.add(new MetaDataColumnDescriptor("IS_NULLABLE",    
Types.VARCHAR, "YES"));
+        result.add(new MetaDataColumnDescriptor("REMARKS",        
Types.VARCHAR));
+
+        return result;
+    }
+
+    /**
+     * Returns descriptors for the columns that shall be read from the result 
set when
+     * reading the meta data for primary keys. Note that the columns are read 
in the order
+     * defined by this list.<br/>
+     * Redefine this method if you want more columns or a different order.
+     * 
+     * @return The map column name -> descriptor for the result set columns
+     */
+    protected List initColumnsForPK()
+    {
+        List result = new ArrayList();
+
+        result.add(new MetaDataColumnDescriptor("COLUMN_NAME", Types.VARCHAR));
+
+        return result;
+    }
+
+    /**
+     * Returns descriptors for the columns that shall be read from the result 
set when
+     * reading the meta data for foreign keys originating from a table. Note 
that the
+     * columns are read in the order defined by this list.<br/>
+     * Redefine this method if you want more columns or a different order.
+     * 
+     * @return The map column name -> descriptor for the result set columns
+     */
+    protected List initColumnsForFK()
+    {
+        List result = new ArrayList();
+
+        result.add(new MetaDataColumnDescriptor("PKTABLE_NAME",  
Types.VARCHAR));
+        result.add(new MetaDataColumnDescriptor("KEY_SEQ",       
Types.TINYINT, new Short((short)0)));
+        result.add(new MetaDataColumnDescriptor("FK_NAME",       
Types.VARCHAR));
+        result.add(new MetaDataColumnDescriptor("PKCOLUMN_NAME", 
Types.VARCHAR));
+        result.add(new MetaDataColumnDescriptor("FKCOLUMN_NAME", 
Types.VARCHAR));
+
+        return result;
+    }
+
+    /**
+     * Returns descriptors for the columns that shall be read from the result 
set when
+     * reading the meta data for indices. Note that the columns are read in 
the order
+     * defined by this list.<br/>
+     * Redefine this method if you want more columns or a different order.
+     * 
+     * @return The map column name -> descriptor for the result set columns
+     */
+    protected List initColumnsForIndex()
+    {
+        List result = new ArrayList();
+
+        result.add(new MetaDataColumnDescriptor("INDEX_NAME",       
Types.VARCHAR));
+        result.add(new MetaDataColumnDescriptor("NON_UNIQUE",       Types.BIT, 
Boolean.TRUE));
+        result.add(new MetaDataColumnDescriptor("ORDINAL_POSITION", 
Types.TINYINT, new Short((short)0)));
+        result.add(new MetaDataColumnDescriptor("COLUMN_NAME",      
Types.VARCHAR));
+        
+
+        return result;
     }
 
     /**
@@ -149,6 +267,56 @@
     }
 
     /**
+     * Returns the descriptors for the columns to be read from the table meta 
data result set.
+     *
+     * @return The column descriptors
+     */
+    protected List getColumnsForTable()
+    {
+        return _columnsForTable;
+    }
+
+    /**
+     * Returns the descriptors for the columns to be read from the column meta 
data result set.
+     *
+     * @return The column descriptors
+     */
+    protected List getColumnsForColumn()
+    {
+        return _columnsForColumn;
+    }
+
+    /**
+     * Returns the descriptors for the columns to be read from the primary key 
meta data result set.
+     *
+     * @return The column descriptors
+     */
+    protected List getColumnsForPK()
+    {
+        return _columnsForPK;
+    }
+
+    /**
+     * Returns the descriptors for the columns to be read from the foreign key 
meta data result set.
+     *
+     * @return The column descriptors
+     */
+    protected List getColumnsForFK()
+    {
+        return _columnsForFK;
+    }
+
+    /**
+     * Returns the descriptors for the columns to be read from the index meta 
data result set.
+     *
+     * @return The column descriptors
+     */
+    protected List getColumnsForIndex()
+    {
+        return _columnsForIndex;
+    }
+
+    /**
      * Reads the database model from the given connection.
      * 
      * @param connection The connection
@@ -195,23 +363,20 @@
         {
             db.setName(name);
         }
-        for (Iterator it = getTables(connection, catalog, schema, 
tableTypes).iterator(); it.hasNext();)
-        {
-            db.addTable((Table)it.next());
-        }
+        db.addTables(readTables(connection, catalog, schema, tableTypes));
         return db;
     }
 
     /**
-     * Returns a list of [EMAIL PROTECTED] Table} instances for the tables in 
the database.
+     * Reads the tables from the database metadata.
      * 
      * @param connection    The connection
      * @param catalog       The catalog to acess in the database; use 
<code>null</code> for the default value
      * @param schemaPattern The schema(s) to acess in the database; use 
<code>null</code> for the default value
      * @param tableTypes    The table types to process; use <code>null</code> 
or an empty list for the default ones
-     * @return The list of tables
+     * @return The tables
      */
-    private List getTables(Connection connection, String catalog, String 
schemaPattern, String[] tableTypes) throws SQLException
+    protected Collection readTables(Connection connection, String catalog, 
String schemaPattern, String[] tableTypes) throws SQLException
     {
         ResultSet tableData = null;
 
@@ -226,41 +391,15 @@
             
             tableData = metaData.getTables("%");
 
-            Set  availableColumns = determineAvailableColumns(tableData);
-            List tables           = new ArrayList();
+            List tables = new ArrayList();
 
             while (tableData.next())
             {
-                String tableName = getValueAsString(tableData, "TABLE_NAME", 
availableColumns, null);
-                
-                if ((tableName != null) && (tableName.length() > 0))
-                {
-                    Table table = new Table();
-    
-                    table.setName(tableName);
-                    table.setType(getValueAsString(tableData, "TABLE_TYPE", 
availableColumns, "UNKNOWN"));
-                    table.setCatalog(getValueAsString(tableData, "TABLE_CAT", 
availableColumns, null));
-                    table.setSchema(getValueAsString(tableData, "TABLE_SCHEM", 
availableColumns, null));
-                    table.setDescription(getValueAsString(tableData, 
"REMARKS", availableColumns, ""));
-                    tables.add(table);
-                }
-            }
-
-            for (Iterator it = tables.iterator(); it.hasNext();)
-            {
-                Table table = (Table)it.next();
+                Table table = readTable(metaData, tableData);
 
-                for (Iterator columnIt = getColumnsForTable(metaData, 
table.getName()).iterator(); columnIt.hasNext();)
-                {
-                    table.addColumn((Column)columnIt.next());
-                }
-                for (Iterator fkIt = getForeignKeysForTable(metaData, 
table.getName()).iterator(); fkIt.hasNext();)
+                if (table != null)
                 {
-                    table.addForeignKey((ForeignKey)fkIt.next());
-                }
-                for (Iterator idxIt = getIndicesForTable(metaData, 
table.getName()).iterator(); idxIt.hasNext();)
-                {
-                    table.addIndex((Index)idxIt.next());
+                    tables.add(table);
                 }
             }
             return tables;
@@ -275,13 +414,50 @@
     }
 
     /**
-     * Returns a list of [EMAIL PROTECTED] Column} instances for the indicated 
table.
+     * Reads the next table from the meta data.
+     * 
+     * @param metaData      The database meta data
+     * @param tableMetaData The result set containing the table metadata
+     * @return The table or <code>null</code> if the result set row did not 
contain a valid table
+     */
+    protected Table readTable(DatabaseMetaDataWrapper metaData, ResultSet 
tableMetaData) throws SQLException
+    {
+        Map    values    = readColumns(tableMetaData, getColumnsForTable());
+        String tableName = (String)values.get("TABLE_NAME");
+        Table  table     = null;
+        
+        if ((tableName != null) && (tableName.length() > 0))
+        {
+            table = new Table();
+
+            table.setName(tableName);
+            table.setType((String)values.get("TABLE_TYPE"));
+            table.setCatalog((String)values.get("TABLE_CAT"));
+            table.setSchema((String)values.get("TABLE_SCHEM"));
+            table.setDescription((String)values.get("REMARKS"));
+
+            table.addColumns(readColumns(metaData, tableName));
+            table.addForeignKeys(readForeignKeys(metaData, tableName));
+            table.addIndices(readIndices(metaData, tableName));
+
+            Collection primaryKeys = readPrimaryKeyNames(metaData, tableName);
+
+            for (Iterator it = primaryKeys.iterator(); it.hasNext();)
+            {
+                table.findColumn((String)it.next(), true).setPrimaryKey(true);
+            }
+        }
+        return table;
+    }
+
+    /**
+     * Reads the column definitions for the indicated table.
      * 
      * @param metaData  The database meta data
      * @param tableName The name of the table
-     * @return The list of columns
+     * @return The columns
      */
-    private List getColumnsForTable(DatabaseMetaDataWrapper metaData, String 
tableName) throws SQLException
+    private Collection readColumns(DatabaseMetaDataWrapper metaData, String 
tableName) throws SQLException
     {
         ResultSet columnData = null;
 
@@ -289,57 +465,11 @@
         {
             columnData = metaData.getColumns(tableName, null);
 
-            Set  availableColumns = determineAvailableColumns(columnData);
-            List columns          = new ArrayList();
-            List primaryKeys      = getPrimaryKeysForTable(metaData, 
tableName);
+            List columns = new ArrayList();
 
             while (columnData.next())
             {
-                Column col = new Column();
-
-                // As suggested by Alexandre Borgoltz, we're reading the 
COLUMN_DEF first because Oracle
-                // has problems otherwise (it seemingly requires a LONG column 
to be the first to be read)
-                // See also DDLUTILS-29
-                String columnDefaultValue = getValueAsString(columnData, 
"COLUMN_DEF", availableColumns, null);
-
-                if (columnDefaultValue != null)
-                {
-                    // Sometimes the default comes back with parenthesis 
around it (jTDS/mssql)
-                    Matcher m = _defaultPattern.matcher(columnDefaultValue);
-
-                    if (m.matches())
-                    {
-                        columnDefaultValue = m.group(1);
-                    }
-                    col.setDefaultValue(columnDefaultValue);
-                }
-                col.setName(getValueAsString(columnData, "COLUMN_NAME", 
availableColumns, "UNKNOWN"));
-                col.setTypeCode(getValueAsInt(columnData, "DATA_TYPE", 
availableColumns, java.sql.Types.OTHER));
-                col.setPrecisionRadix(getValueAsInt(columnData, 
"NUM_PREC_RADIX", availableColumns, 10));
-
-                int scale = getValueAsInt(columnData, "DECIMAL_DIGITS", 
availableColumns, 0);
-
-                // we're setting the size after the precision and radix in case
-                // the database prefers to return them in the size value 
-                col.setSize(getValueAsString(columnData, "COLUMN_SIZE", 
availableColumns, (String)_defaultSizes.get(new Integer(col.getTypeCode()))));
-                if (scale != 0)
-                {
-                    // if there is a scale value, set it after the size (which 
probably did not contain
-                    // a scale specification)
-                    col.setScale(scale);
-                }
-                
col.setRequired("NO".equalsIgnoreCase(getValueAsString(columnData, 
"IS_NULLABLE", availableColumns, "YES").trim()));
-                col.setDescription(getValueAsString(columnData, "REMARKS", 
availableColumns, null));                
-                if (primaryKeys.contains(col.getName()))
-                {
-                    col.setPrimaryKey(true);
-                }
-                else
-                {
-                    col.setPrimaryKey(false);
-                }
-
-                columns.add(col);
+                columns.add(readColumn(metaData, columnData));
             }
             return columns;
         }
@@ -353,14 +483,51 @@
     }
 
     /**
-     * Retrieves a list of the columns composing the primary key for a given
-     * table.
+     * Extracts a column definition from the result set.
+     * 
+     * @param metaData   The database meta data
+     * @param columnData The column meta data result set
+     * @return The column
+     */
+    protected Column readColumn(DatabaseMetaDataWrapper metaData, ResultSet 
columnData) throws SQLException
+    {
+        Column column = new Column();
+        Map    values = readColumns(columnData, getColumnsForColumn());
+
+        column.setName((String)values.get("COLUMN_NAME"));
+        column.setDefaultValue((String)values.get("COLUMN_DEF"));
+        column.setTypeCode(((Integer)values.get("DATA_TYPE")).intValue());
+        
column.setPrecisionRadix(((Integer)values.get("NUM_PREC_RADIX")).intValue());
+
+        String size  = (String)values.get("COLUMN_SIZE");
+        int    scale = ((Integer)values.get("DECIMAL_DIGITS")).intValue();
+
+        if (size == null)
+        {
+            size = (String)_defaultSizes.get(new 
Integer(column.getTypeCode()));
+        }
+        // we're setting the size after the precision and radix in case
+        // the database prefers to return them in the size value
+        column.setSize(size);
+        if (scale != 0)
+        {
+            // if there is a scale value, set it after the size (which 
probably did not contain
+            // a scale specification)
+            column.setScale(scale);
+        }
+        
column.setRequired("NO".equalsIgnoreCase(((String)values.get("IS_NULLABLE")).trim()));
+        column.setDescription((String)values.get("REMAKRS"));
+        return column;
+    }
+
+    /**
+     * Retrieves the names of the columns that make up the primary key for a 
given table.
      *
      * @param metaData  The database meta data
      * @param tableName The name of the table from which to retrieve PK 
information
-     * @return The list of the primary key column names
+     * @return The primary key column names
      */
-    private List getPrimaryKeysForTable(DatabaseMetaDataWrapper metaData, 
String tableName) throws SQLException
+    protected Collection readPrimaryKeyNames(DatabaseMetaDataWrapper metaData, 
String tableName) throws SQLException
     {
         List      pks   = new ArrayList();
         ResultSet pkData = null;
@@ -370,13 +537,9 @@
             pkData = metaData.getPrimaryKeys(tableName);
             while (pkData.next())
             {
-                pks.add(pkData.getString("COLUMN_NAME"));
+                pks.add(readPrimaryKeyName(metaData, pkData));
             }
         }
-        catch (SQLException ex)
-        {
-            _log.warn("Could not determine the primary keys of table 
"+tableName, ex);
-        }
         finally
         {
             if (pkData != null)
@@ -388,56 +551,39 @@
     }
 
     /**
-     * Retrieves a list of the foreign keys of the indicated table.
+     * Extracts a primary key name from the result set.
+     *
+     * @param metaData The database meta data
+     * @param pkData   The result set containing the meta data for the current 
pk definition
+     * @return The primary key name
+     */
+    protected String readPrimaryKeyName(DatabaseMetaDataWrapper metaData, 
ResultSet pkData) throws SQLException
+    {
+        Map values = readColumns(pkData, getColumnsForPK());
+
+        return (String)values.get("COLUMN_NAME");
+    }
+
+    /**
+     * Retrieves the foreign keys of the indicated table.
      *
      * @param metaData  The database meta data
      * @param tableName The name of the table from which to retrieve FK 
information
-     * @return The list of foreign keys
+     * @return The foreign keys
      */
-    private List getForeignKeysForTable(DatabaseMetaDataWrapper metaData, 
String tableName) throws SQLException
+    protected Collection readForeignKeys(DatabaseMetaDataWrapper metaData, 
String tableName) throws SQLException
     {
-        List      fks    = new ArrayList();
+        Map       fks    = new ListOrderedMap();
         ResultSet fkData = null;
 
         try
         {
             fkData = metaData.getForeignKeys(tableName);
 
-            Set        availableColumns = determineAvailableColumns(fkData);
-            String     prevPkTable      = null;
-            ForeignKey currFk           = null;
-
             while (fkData.next())
             {
-                String pkTable     = getValueAsString(fkData, "PKTABLE_NAME", 
availableColumns, null);
-                short  keySequence = getValueAsShort(fkData, "KEY_SEQ", 
availableColumns, (short)0);
-
-                // a new foreign key definition can only be identified by the 
changed referenced table
-                if (!pkTable.equals(prevPkTable) || (keySequence == 1))
-                {
-                    if (currFk != null)
-                    {
-                        fks.add(currFk);
-                    }
-                    currFk = new ForeignKey(getValueAsString(fkData, 
"FK_NAME", availableColumns, null));
-                    currFk.setForeignTableName(pkTable);
-                    prevPkTable = pkTable;
-                }
-                Reference ref = new Reference();
-
-                ref.setForeignColumnName(getValueAsString(fkData, 
"PKCOLUMN_NAME", availableColumns, null));
-                ref.setLocalColumnName(getValueAsString(fkData, 
"FKCOLUMN_NAME", availableColumns, null));
-                currFk.addReference(ref);
+                readForeignKey(metaData, fkData, fks);
             }
-            if (currFk != null)
-            {
-                fks.add(currFk);
-                currFk = null;
-            }
-        }
-        catch (SQLException ex)
-        {
-            _log.warn("Could not determine the foreignkeys of table 
"+tableName, ex);
         }
         finally
         {
@@ -446,7 +592,36 @@
                 fkData.close();
             }
         }
-        return fks;
+        return fks.values();
+    }
+
+    /**
+     * Reads the next foreign key spec from the result set.
+     *
+     * @param metaData The database meta data
+     * @param fkData   The foreign key meta data
+     * @param lastFk   The foreign key that was read last
+     */
+    protected void readForeignKey(DatabaseMetaDataWrapper metaData, ResultSet 
fkData, Map knownFks) throws SQLException
+    {
+        Map        values      = readColumns(fkData, getColumnsForFK());
+        String     fkName      = (String)values.get("FK_NAME");
+        ForeignKey fk          = (ForeignKey)knownFks.get(fkName);
+
+        if (fk == null)
+        {
+            fk = new ForeignKey(fkName);
+            fk.setForeignTableName((String)values.get("PKTABLE_NAME"));
+        }
+
+        Reference ref      = new Reference();
+        short     position = ((Short)values.get("KEY_SEQ")).shortValue();
+
+        ref.setForeignColumnName((String)values.get("PKCOLUMN_NAME"));
+        ref.setLocalColumnName((String)values.get("FKCOLUMN_NAME"));
+
+        // TODO: use position
+        fk.addReference(ref);
     }
 
     /**
@@ -456,51 +631,19 @@
      * @param tableName The name of the table
      * @return The list of indices
      */
-    private List getIndicesForTable(DatabaseMetaDataWrapper metaData, String 
tableName) throws SQLException
+    protected Collection readIndices(DatabaseMetaDataWrapper metaData, String 
tableName) throws SQLException
     {
+        Map       indices   = new ListOrderedMap();
         ResultSet indexData = null;
-        List      indices   = new ArrayList();
 
         try 
         {
             indexData = metaData.getIndices(tableName, false, false);
 
-            Set availableColumns = determineAvailableColumns(indexData);
-            Map indicesByName    = new LinkedMap();
-
             while (indexData.next())
             {
-                String  indexName = getValueAsString(indexData, "INDEX_NAME", 
availableColumns, null);
-                boolean isUnique  = !getValueAsBoolean(indexData, 
"NON_UNIQUE", availableColumns, true);
-                Index   index     = (Index)indicesByName.get(indexName);
-
-                if ((index == null) && (indexName != null))
-                {
-                    if (isUnique)
-                    {
-                        index = new UniqueIndex();
-                    }
-                    else
-                    {
-                        index = new NonUniqueIndex();
-                    }
-
-                    index.setName(indexName);
-                    indicesByName.put(indexName, index);
-                }
-                if (index != null)
-                {
-                    IndexColumn ic = new IndexColumn();
-
-                    ic.setName(getValueAsString(indexData, "COLUMN_NAME", 
availableColumns, null));
-                    index.addColumn(ic);
-                }
+                readIndex(metaData, indexData, indices);
             }
-            indices.addAll(indicesByName.values());
-        }
-        catch (SQLException ex)
-        {
-            _log.trace("Could determine the indices for the table "+tableName, 
ex);
         }
         finally
         {
@@ -509,85 +652,62 @@
                 indexData.close();
             }
         }
-        return indices;
+        return indices.values();
     }
 
     /**
-     * Determines the columns available in the given result set, and returns 
them (in upper case)
-     * in a set.
-     *  
-     * @param data The result set
-     * @return The columns present in the result set
+     * Reads the next index spec from the result set.
+     * 
+     * @param metaData     The database meta data
+     * @param indexData    The index meta data
+     * @param knownIndices The already known indices
      */
-    private Set determineAvailableColumns(ResultSet data) throws SQLException
+    protected void readIndex(DatabaseMetaDataWrapper metaData, ResultSet 
indexData, Map knownIndices) throws SQLException
     {
-        Set               result   = new HashSet();
-        ResultSetMetaData metaData = data.getMetaData();
+        Map     values    = readColumns(indexData, getColumnsForIndex());
+        String  indexName = (String)values.get("INDEX_NAME");
+        Index   index     = (Index)knownIndices.get(indexName);
 
-        for (int idx = 1; idx <= metaData.getColumnCount(); idx++)
+        if ((index == null) && (indexName != null))
         {
-            result.add(metaData.getColumnName(idx).toUpperCase());
+            if (((Boolean)values.get("NON_UNIQUE")).booleanValue())
+            {
+                index = new NonUniqueIndex();
+            }
+            else
+            {
+                index = new UniqueIndex();
+            }
+
+            index.setName(indexName);
+            knownIndices.put(indexName, index);
         }
-        return result;
-    }
 
-    /**
-     * Retrieves the value of the specified column as a string. If the column 
is not present, then
-     * the default value is returned.
-     * 
-     * @param data             The data
-     * @param columnName       The name of the column
-     * @param availableColumns The available columns
-     * @param defaultValue     The default value to use if the column is not 
present
-     * @return The value
-     */
-    private String getValueAsString(ResultSet data, String columnName, Set 
availableColumns, String defaultValue) throws SQLException
-    {
-        return availableColumns.contains(columnName) ? 
data.getString(columnName) : defaultValue;
-    }
+        IndexColumn ic       = new IndexColumn();
+        short       position = 
((Short)values.get("ORDINAL_POSITION")).shortValue();
 
-    /**
-     * Retrieves the value of the specified column as an integer. If the 
column is not present, then
-     * the default value is returned.
-     * 
-     * @param data             The data
-     * @param columnName       The name of the column
-     * @param availableColumns The available columns
-     * @param defaultValue     The default value to use if the column is not 
present
-     * @return The value
-     */
-    private int getValueAsInt(ResultSet data, String columnName, Set 
availableColumns, int defaultValue) throws SQLException
-    {
-        return availableColumns.contains(columnName) ? data.getInt(columnName) 
: defaultValue;
+        ic.setName((String)values.get("COLUMN_NAME"));
+        // TODO: use position
+        index.addColumn(ic);
     }
 
     /**
-     * Retrieves the value of the specified column as a short integer. If the 
column is not present, then
-     * the default value is returned.
+     * Reads the indicated columns from the result set.
      * 
-     * @param data             The data
-     * @param columnName       The name of the column
-     * @param availableColumns The available columns
-     * @param defaultValue     The default value to use if the column is not 
present
-     * @return The value
+     * @param resultSet         The result set
+     * @param columnDescriptors The dscriptors of the columns to read
+     * @return The read values keyed by the column name
      */
-    private short getValueAsShort(ResultSet data, String columnName, Set 
availableColumns, short defaultValue) throws SQLException
+    protected Map readColumns(ResultSet resultSet, List columnDescriptors) 
throws SQLException
     {
-        return availableColumns.contains(columnName) ? 
data.getShort(columnName) : defaultValue;
-    }
+        HashMap values = new HashMap();
 
-    /**
-     * Retrieves the value of the specified column as a boolean value. If the 
column is not present, then
-     * the default value is returned.
-     * 
-     * @param data             The data
-     * @param columnName       The name of the column
-     * @param availableColumns The available columns
-     * @param defaultValue     The default value to use if the column is not 
present
-     * @return The value
-     */
-    private boolean getValueAsBoolean(ResultSet data, String columnName, Set 
availableColumns, boolean defaultValue) throws SQLException
-    {
-        return availableColumns.contains(columnName) ? 
data.getBoolean(columnName) : defaultValue;
+        for (Iterator it = columnDescriptors.iterator(); it.hasNext();)
+        {
+            MetaDataColumnDescriptor descriptor = 
(MetaDataColumnDescriptor)it.next();
+
+            values.put(descriptor.getName(), descriptor.readColumn(resultSet));
+        }
+        return values;
     }
 }

Added: 
db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/MetaDataColumnDescriptor.java
URL: 
http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/MetaDataColumnDescriptor.java?rev=359242&view=auto
==============================================================================
--- 
db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/MetaDataColumnDescriptor.java
 (added)
+++ 
db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/MetaDataColumnDescriptor.java
 Tue Dec 27 09:16:30 2005
@@ -0,0 +1,117 @@
+package org.apache.ddlutils.platform;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Types;
+
+/**
+ * Describes a column in a metadata result set.
+ * 
+ * @author tomdz
+ * @version $Revision: $
+ */
+public class MetaDataColumnDescriptor
+{
+    /** The name of the column. */
+    private String _columnName;
+    /** The jdbc type to read from the result set. */
+    private int _jdbcType;
+    /** The default value if the column is not present in the result set. */
+    private Object _defaultValue;
+
+    /**
+     * Creates a new descriptor instance.
+     * 
+     * @param columnName The name of the column
+     * @param jdbcType   The jdbc type for reading from the result set, one of
+     *                   VARCHAR, INTEGER, TINYINT, BIT
+     */
+    public MetaDataColumnDescriptor(String columnName, int jdbcType)
+    {
+        this(columnName, jdbcType, null);
+    }
+
+    /**
+     * Creates a new descriptor instance.
+     * 
+     * @param columnName   The name of the column
+     * @param jdbcType   The jdbc type for reading from the result set, one of
+     *                   VARCHAR, INTEGER, TINYINT, BIT
+     * @param defaultValue The default value if the column is not present in 
the result set
+     */
+    public MetaDataColumnDescriptor(String columnName, int jdbcType, Object 
defaultValue)
+    {
+        _columnName   = columnName.toUpperCase();
+        _jdbcType     = jdbcType;
+        _defaultValue = defaultValue;
+    }
+
+    /**
+     * Returns the name.
+     *
+     * @return The name
+     */
+    public String getName()
+    {
+        return _columnName;
+    }
+
+    /**
+     * Returns the default value.
+     *
+     * @return The default value
+     */
+    public Object getDefaultValue()
+    {
+        return _defaultValue;
+    }
+
+    /**
+     * Returns the jdbc type to read from the result set.
+     *
+     * @return The jdbc type
+     */
+    public int getJdbcType()
+    {
+        return _jdbcType;
+    }
+
+    /**
+     * Reads the column from the result set.
+     * 
+     * @param resultSet The result set
+     * @return The column value or the default value if the column is not 
present in the result set
+     */
+    public Object readColumn(ResultSet resultSet) throws SQLException
+    {
+        ResultSetMetaData metaData = resultSet.getMetaData();
+        int               foundIdx = -1;
+
+        for (int idx = 1; (foundIdx < 0) && (idx <= 
metaData.getColumnCount()); idx++)
+        {
+            if (_columnName.equals(metaData.getColumnName(idx).toUpperCase()))
+            {
+                foundIdx = idx;
+            }
+        }
+        if (foundIdx > 0)
+        {
+            switch (_jdbcType)
+            {
+                case Types.BIT:
+                    return new Boolean(resultSet.getBoolean(foundIdx));
+                case Types.INTEGER:
+                    return new Integer(resultSet.getInt(foundIdx));
+                case Types.TINYINT:
+                    return new Short(resultSet.getShort(foundIdx));
+                default:
+                    return resultSet.getString(foundIdx);
+            }
+        }
+        else
+        {
+            return _defaultValue;
+        }
+    }
+}


Reply via email to