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 mv...@apache.org on 2006/01/17 22:43:32 UTC

svn commit: r369928 - in /db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird: FirebirdBuilder.java FirebirdModelReader.java FirebirdPlatform.java

Author: mvdb
Date: Tue Jan 17 13:43:27 2006
New Revision: 369928

URL: http://svn.apache.org/viewcvs?rev=369928&view=rev
Log:
First start of firebird database. Not all tests pass currently, but I've come a long way..

Added:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdBuilder.java
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdModelReader.java
Modified:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdPlatform.java

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdBuilder.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdBuilder.java?rev=369928&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdBuilder.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdBuilder.java Tue Jan 17 13:43:27 2006
@@ -0,0 +1,152 @@
+package org.apache.ddlutils.platform.firebird;
+
+/*
+ * Copyright 1999-2006 The Apache Software Foundation.
+ * 
+ * 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.
+ */
+
+import java.io.IOException;
+import java.sql.Types;
+import java.util.Map;
+
+import org.apache.ddlutils.PlatformInfo;
+import org.apache.ddlutils.model.Column;
+import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.Table;
+import org.apache.ddlutils.platform.SqlBuilder;
+
+/**
+ * The SQL Builder for the FireBird database.
+ * 
+ * @author Martin van den Bemt
+ * @version $Revision: 231306 $
+ */
+public class FirebirdBuilder extends SqlBuilder
+{
+    /**
+     * Creates a new builder instance.
+     * 
+     * @param info The platform info
+     */
+    public FirebirdBuilder(PlatformInfo info)
+    {
+        super(info);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void createTable(Database database, Table table, Map parameters) throws IOException
+    {
+        super.createTable(database, table, parameters);
+
+        // creating generator and trigger for auto-increment
+        Column[] columns = table.getAutoIncrementColumns();
+
+        for (int idx = 0; idx < columns.length; idx++)
+        {
+            print("CREATE GENERATOR ");
+            printIdentifier(getConstraintName("gen", table, columns[idx].getName(), null));
+            printEndOfStatement();
+            print("--TERM--");
+            printEndOfStatement();
+            print("CREATE TRIGGER ");
+            printIdentifier(getConstraintName("trg", table, columns[idx].getName(), null));
+            print(" FOR ");
+            printlnIdentifier(getTableName(table));
+            println("ACTIVE BEFORE INSERT POSITION 0 AS");
+            println("BEGIN");
+            print("IF (NEW.");
+            printIdentifier(getColumnName(columns[idx]));
+            println(" IS NULL) THEN");
+            print("NEW.");
+            printIdentifier(getColumnName(columns[idx]));
+            print(" = GEN_ID(");
+            printIdentifier(getConstraintName("gen", table, columns[idx].getName(), null));
+            println(", 1);");
+            println("END;");
+            print("--TERM--;");
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void dropTable(Table table) throws IOException
+    {
+        super.dropTable(table);
+        // dropping generators for auto-increment
+        Column[] columns = table.getAutoIncrementColumns();
+
+        for (int idx = 0; idx < columns.length; idx++)
+        {
+            print("DROP GENERATOR ");
+            printIdentifier(getConstraintName("gen", table, columns[idx].getName(), null));
+            printEndOfStatement();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void writeColumnAutoIncrementStmt(Table table, Column column) throws IOException
+    {
+        // we're using a generator
+    }
+
+    /**
+     * {@inheritDoc}
+     * @todo : we are kinf of stuck here, since last insert id needs the database name..
+     */
+    public String getSelectLastInsertId(Table table)
+    {
+        Column[] columns = table.getAutoIncrementColumns();
+
+        if (columns.length == 0)
+        {
+            return null;
+        }
+        else
+        {
+            StringBuffer result = new StringBuffer();
+    
+            for (int idx = 0; idx < columns.length; idx++)
+            {
+                result.append("SELECT GEN_ID (");
+                result.append(getConstraintName("gen", table, columns[idx].getName(), null));
+                result.append(",0 ) FROM RDB$DATABASE");
+                result.append(table.getName());
+                result.append(getDelimitedIdentifier(columns[idx].getName()));
+            }
+            return result.toString();
+        }
+    }
+
+    /**
+     * Returns the native default value for the column.
+     * 
+     * @param column The column
+     * @return The native default value
+     */
+    protected String getNativeDefaultValue(Column column)
+    {
+        String defaultValue = column.getDefaultValue();
+        if (column.getTypeCode() == Types.BIT || column.getTypeCode() == Types.BOOLEAN)
+        {
+            defaultValue = getDefaultValueHelper().convert(column.getDefaultValue(), column.getTypeCode(), Types.SMALLINT).toString();
+        }
+        return defaultValue;
+    }
+
+}

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdModelReader.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdModelReader.java?rev=369928&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdModelReader.java (added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdModelReader.java Tue Jan 17 13:43:27 2006
@@ -0,0 +1,143 @@
+/*
+ * Copyright 1999-2006 The Apache Software Foundation.
+ * 
+ * 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 org.apache.ddlutils.platform.firebird;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Iterator;
+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;
+import org.apache.ddlutils.platform.DatabaseMetaDataWrapper;
+import org.apache.ddlutils.platform.JdbcModelReader;
+
+/**
+ * The Jdbc Model Reader for FireBird.
+ *
+ * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
+ * @version $Revision: $
+ */
+public class FirebirdModelReader extends JdbcModelReader {
+
+    /**
+     * @param platformInfo the platformInfo
+     */
+    public FirebirdModelReader(PlatformInfo platformInfo) {
+        super(platformInfo);
+    }
+
+    /**
+     * (@inheritDoc)
+     */
+    protected void readIndex(DatabaseMetaDataWrapper metaData, Map values, Map knownIndices) throws SQLException {
+        super.readIndex(metaData, values, knownIndices);
+        Iterator indexNames = knownIndices.keySet().iterator();
+//        printIdentifier(getConstraintName(null, table, "PK", null));
+        
+        while (indexNames.hasNext())
+        {
+            String indexName = (String) indexNames.next();
+            if (indexName.indexOf("PRIMARY") != -1)
+            {
+                // we have hit a primary key, remove it..
+                indexNames.remove();
+            }
+        }
+    }
+    /**
+     * {@inheritDoc}
+     * @todo This needs some more work, since table names can be case sensitive or lowercase
+     *       depending on the platform (really cute).
+     *       See http://dev.mysql.com/doc/refman/4.1/en/name-case-sensitivity.html for more info.
+     */
+    protected Table readTable(DatabaseMetaDataWrapper metaData, Map values) throws SQLException
+    {
+        Table table =  super.readTable(metaData, values);
+
+        determineAutoIncrementFromResultSetMetaData(table, table.getColumns());
+        // fix the indexes.
+        fixIndexes(table);
+
+        return table;
+    }
+
+    /**
+     * Helper method that determines the auto increment status for the given columns via the
+     * {@link ResultSetMetaData#isAutoIncrement(int)} method.<br>
+     *
+     * @param table          The table
+     * @param columnsToCheck The columns to check (e.g. the primary key columns)
+     */
+    protected void determineAutoIncrementFromResultSetMetaData(Table table, Column[] columnsToCheck) throws SQLException
+    {
+        StringBuffer query = new StringBuffer();
+
+        String prefix = ("gen_"+table.getName()+"_").toUpperCase();
+
+        query.append("SELECT RDB$GENERATOR_NAME FROM RDB$GENERATORS WHERE RDB$GENERATOR_NAME STARTING WITH '");
+        query.append(prefix);
+        query.append("'");
+        Statement         stmt       = getConnection().createStatement();
+        ResultSet         rs         = stmt.executeQuery(query.toString());
+    
+
+        while(rs.next())
+        {
+            String generatorName = rs.getString(1).substring(prefix.length()).trim();
+            Column column = table.findColumn(generatorName, false);
+            if (column != null)
+            {
+                column.setAutoIncrement(true);
+            }
+        }
+        stmt.close();
+    }
+    
+    /**
+     * Firebird als returns indexes for foreignkeys and we need to strip
+     * them from the model.
+     * 
+     * @param table the table to fix.
+     */
+    private void fixIndexes(Table table)
+    {
+        if (table.getIndexCount() == 0 || table.getForeignKeyCount() == 0)
+        {
+            // we don't do anything when there are no indexes or foreignkeys.
+            return;
+        }
+        for (int i = 0; i < table.getForeignKeyCount(); i++)
+        {
+            ForeignKey fk = table.getForeignKey(i);
+            Index index = table.findIndex(fk.getName());
+            if (index != null)
+            {
+                // remove it from the indexes..
+                table.removeIndex(index);
+            }
+        }
+        // filter
+    }
+    
+
+}

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdPlatform.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdPlatform.java?rev=369928&r1=369927&r2=369928&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdPlatform.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/firebird/FirebirdPlatform.java Tue Jan 17 13:43:27 2006
@@ -16,16 +16,32 @@
  * limitations under the License.
  */
 
-import org.apache.ddlutils.platform.interbase.InterbasePlatform;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.StringTokenizer;
+
+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.Database;
+import org.apache.ddlutils.platform.PlatformImplBase;
 
 /**
  * The platform implementation for the Firebird database.
+ * It is assumed that the database is configured with sql dialect 3!
  * 
  * @author Thomas Dudziak
+ * @author Martin van den Bemt
  * @version $Revision: 231306 $
  */
-public class FirebirdPlatform extends InterbasePlatform
+public class FirebirdPlatform extends PlatformImplBase
 {
+    /** The log for this platform. */
+    private final Log _log = LogFactory.getLog(getClass());
     /** Database name of this platform. */
     public static final String DATABASENAME     = "Firebird";
     /** The standard Firebird jdbc driver. */
@@ -33,6 +49,52 @@
     /** The subprotocol used by the standard Firebird driver. */
     public static final String JDBC_SUBPROTOCOL = "firebirdsql";
 
+    public FirebirdPlatform() {
+        PlatformInfo info = new PlatformInfo();
+
+        info.setMaxIdentifierLength(31);
+        info.setRequiringNullAsDefaultValue(false);
+        info.setPrimaryKeyEmbedded(true);
+        info.setForeignKeysEmbedded(false);
+        info.setIndicesEmbedded(false);
+        info.setCommentPrefix("/*");
+        info.setCommentSuffix("*/");
+        info.setSupportingDelimitedIdentifiers(false);
+
+        // BINARY and VARBINARY are also handled by the InterbaseBuilder.getSqlType method
+        info.addNativeTypeMapping(Types.ARRAY,         "BLOB");
+        info.addNativeTypeMapping(Types.BINARY,        "BLOB", Types.LONGVARBINARY);
+        info.addNativeTypeMapping(Types.BIT,           "SMALLINT", Types.BIT);
+        info.addNativeTypeMapping(Types.CLOB,          "BLOB SUB_TYPE TEXT", Types.LONGVARCHAR);
+        info.addNativeTypeMapping(Types.DISTINCT,      "BLOB", Types.LONGVARBINARY);
+        info.addNativeTypeMapping(Types.BLOB,          "BLOB", Types.LONGVARBINARY);
+        info.addNativeTypeMapping(Types.DOUBLE,        "DOUBLE PRECISION");
+        info.addNativeTypeMapping(Types.FLOAT,         "DOUBLE PRECISION");
+        info.addNativeTypeMapping(Types.JAVA_OBJECT,   "BLOB", Types.LONGVARBINARY);
+        info.addNativeTypeMapping(Types.LONGVARBINARY, "BLOB", Types.LONGVARBINARY);
+        info.addNativeTypeMapping(Types.LONGVARCHAR,   "BLOB SUB_TYPE TEXT");
+        info.addNativeTypeMapping(Types.NULL,          "BLOB");
+        info.addNativeTypeMapping(Types.OTHER,         "BLOB");
+        info.addNativeTypeMapping(Types.REAL,          "FLOAT");
+        info.addNativeTypeMapping(Types.TINYINT,       "SMALLINT");
+        info.addNativeTypeMapping(Types.REF,           "BLOB");
+        info.addNativeTypeMapping(Types.STRUCT,        "BLOB");
+        info.addNativeTypeMapping(Types.VARBINARY,     "BLOB", Types.LONGVARBINARY);
+        info.addNativeTypeMapping(Types.BOOLEAN, "SMALLINT");
+        info.addNativeTypeMapping("DATALINK", "BLOB");
+
+        /**
+         * This value is set to 128, to give multiple column index a chance
+         * to stay below the maximum key size of 256.
+         * If you use different encodings, you most likely need to decrease this value.
+         */
+        info.addDefaultSize(Types.VARCHAR, 128);
+        info.addDefaultSize(Types.CHAR, 128);
+        info.addDefaultSize(Types.SMALLINT, 5);
+
+        setSqlBuilder(new FirebirdBuilder(info));
+        setModelReader(new FirebirdModelReader(info));
+    }
     /**
      * {@inheritDoc}
      */
@@ -40,4 +102,110 @@
     {
         return DATABASENAME;
     }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void createTables(Connection connection, Database model, boolean dropTablesFirst, boolean continueOnError) throws DynaSqlException
+    {
+        String sql = getCreateTablesSql(model, dropTablesFirst, continueOnError);
+        runBatch(connection, sql, continueOnError);
+    }
+
+    /**
+     * Runbatch is a replacement for evaluateBatch.
+     * Especially the <code>SET TERM !!;</code> blocks need to be executed in one go.
+     *
+     * @param connection the connection to use
+     * @param sql the sql to process
+     * @param continueOnError needs to continue when an error occurs.
+     */
+    public int runBatch(Connection connection, String sql, boolean continueOnError) throws DynaSqlException
+    {
+        int errors       = 0;
+        Statement statement    = null;
+        int commandCount = 0;
+
+        try {
+            statement = connection.createStatement();
+            StringTokenizer tokenizer = new StringTokenizer(sql, ";");
+    
+            while (tokenizer.hasMoreTokens())
+            {
+                String command = tokenizer.nextToken().trim();
+                if (command.equals("--TERM--"))
+                {
+                    command = "";
+                    while(tokenizer.hasMoreTokens())
+                    {
+                        String termSql = tokenizer.nextToken().trim();  
+                        if(termSql.equals("--TERM--"))
+                        {
+                            break;
+                        }
+                        if (termSql.length() > 0)
+                        {
+                            command+=termSql+";";
+                        }
+                        
+                    }
+                }
+                if (command.length() == 0)
+                {
+                    continue;
+                }
+                
+                System.err.println("SQL Command :\n" + command);
+                commandCount++;
+                
+                if (_log.isDebugEnabled())
+                {
+                    _log.debug("About to execute SQL " + command);
+                }
+                try
+                {
+                    int results = statement.executeUpdate(command);
+
+                    if (_log.isDebugEnabled())
+                    {
+                        _log.debug("After execution, " + results + " row(s) have been changed");
+                    }
+                }
+                catch (SQLException ex)
+                {
+                    if (continueOnError)
+                    {
+                        System.err.println("SQL Command " + command + " failed with " + ex.getMessage());
+                        errors++;
+                    }
+                    else
+                    {
+                        throw new DynaSqlException("Error while executing SQL "+command, ex);
+                    }
+                }
+
+                // lets display any warnings
+                SQLWarning warning = connection.getWarnings();
+
+                while (warning != null)
+                {
+                    _log.warn(warning.toString());
+                    warning = warning.getNextWarning();
+                }
+                connection.clearWarnings();
+            }
+            _log.info("Executed "+ commandCount + " SQL command(s) with " + errors + " error(s)");
+        }
+        catch (SQLException ex)
+        {
+            throw new DynaSqlException("Error while executing SQL", ex);
+        }
+        finally
+        {
+            closeStatement(statement);
+        }
+
+        return errors;
+    }
+
 }