org.jumpmind.db.platform.db2.Db2DdlReader.java Source code

Java tutorial

Introduction

Here is the source code for org.jumpmind.db.platform.db2.Db2DdlReader.java

Source

package org.jumpmind.db.platform.db2;

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.HashSet;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.jumpmind.db.model.Column;
import org.jumpmind.db.model.ForeignKey;
import org.jumpmind.db.model.IIndex;
import org.jumpmind.db.model.Table;
import org.jumpmind.db.model.TypeMap;
import org.jumpmind.db.platform.AbstractJdbcDdlReader;
import org.jumpmind.db.platform.DatabaseMetaDataWrapper;
import org.jumpmind.db.platform.IDatabasePlatform;
import org.jumpmind.db.sql.JdbcSqlTemplate;

/*
 * Reads a database model from a Db2 UDB database.
 */
public class Db2DdlReader extends AbstractJdbcDdlReader {
    /* Known system tables that Db2 creates (e.g. automatic maintenance). */
    private static final String[] KNOWN_SYSTEM_TABLES = { "STMG_DBSIZE_INFO", "HMON_ATM_INFO", "HMON_COLLECTION",
            "POLICY" };

    /* The regular expression pattern for the time values that Db2 returns. */
    private Pattern db2TimePattern = Pattern.compile("'(\\d{2}).(\\d{2}).(\\d{2})'");

    /* The regular expression pattern for the timestamp values that Db2 returns. */
    private Pattern db2TimestampPattern = Pattern
            .compile("'(\\d{4}\\-\\d{2}\\-\\d{2})\\-(\\d{2}).(\\d{2}).(\\d{2})(\\.\\d{1,8})?'");

    public Db2DdlReader(IDatabasePlatform platform) {
        super(platform);
        setDefaultCatalogPattern(null);
        setDefaultSchemaPattern(null);
    }

    @Override
    protected Table readTable(Connection connection, DatabaseMetaDataWrapper metaData, Map<String, Object> values)
            throws SQLException {
        String tableName = (String) values.get("TABLE_NAME");

        for (int idx = 0; idx < KNOWN_SYSTEM_TABLES.length; idx++) {
            if (KNOWN_SYSTEM_TABLES[idx].equals(tableName)) {
                return null;
            }
        }

        Table table = super.readTable(connection, metaData, values);
        if (table != null) {
            enhanceTableMetaData(connection, metaData, table);
        }
        return table;
    }

    protected void enhanceTableMetaData(Connection connection, DatabaseMetaDataWrapper metaData, Table table)
            throws SQLException {
        log.debug("about to read additional column data");
        /* DB2 does not return the auto-increment status via the database
         metadata */
        String sql = "SELECT NAME, IDENTITY FROM SYSIBM.SYSCOLUMNS WHERE TBNAME=?";
        if (StringUtils.isNotBlank(metaData.getSchemaPattern())) {
            sql = sql + " AND TBCREATOR=?";
        }

        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            pstmt = connection.prepareStatement(sql);
            pstmt.setString(1, table.getName());
            if (StringUtils.isNotBlank(metaData.getSchemaPattern())) {
                pstmt.setString(2, metaData.getSchemaPattern());
            }

            rs = pstmt.executeQuery();
            while (rs.next()) {
                String columnName = rs.getString(1);
                Column column = table.getColumnWithName(columnName);
                if (column != null) {
                    String isIdentity = rs.getString(2);
                    if (isIdentity != null && isIdentity.startsWith("Y")) {
                        column.setAutoIncrement(true);
                        if (log.isDebugEnabled()) {
                            log.debug("Found identity column {} on {}", columnName, table.getName());
                        }
                    }
                }
            }
        } finally {
            JdbcSqlTemplate.close(rs);
            JdbcSqlTemplate.close(pstmt);
        }
        log.debug("done reading additional column data");

    }

    @Override
    protected Column readColumn(DatabaseMetaDataWrapper metaData, Map<String, Object> values) throws SQLException {
        Column column = super.readColumn(metaData, values);

        if (column.getDefaultValue() != null) {
            if (column.getMappedTypeCode() == Types.TIME) {
                Matcher matcher = db2TimePattern.matcher(column.getDefaultValue());

                // Db2 returns "HH24.MI.SS"
                if (matcher.matches()) {
                    StringBuffer newDefault = new StringBuffer();

                    newDefault.append("'");
                    // the hour
                    newDefault.append(matcher.group(1));
                    newDefault.append(":");
                    // the minute
                    newDefault.append(matcher.group(2));
                    newDefault.append(":");
                    // the second
                    newDefault.append(matcher.group(3));
                    newDefault.append("'");

                    column.setDefaultValue(newDefault.toString());
                }
            } else if (column.getMappedTypeCode() == Types.TIMESTAMP) {

                Matcher matcher = db2TimestampPattern.matcher(column.getDefaultValue());

                // Db2 returns "YYYY-MM-DD-HH24.MI.SS.FF"
                if (matcher.matches()) {
                    StringBuffer newDefault = new StringBuffer();

                    newDefault.append("'");
                    // group 1 is the date which has the correct format
                    newDefault.append(matcher.group(1));
                    newDefault.append(" ");
                    // the hour
                    newDefault.append(matcher.group(2));
                    newDefault.append(":");
                    // the minute
                    newDefault.append(matcher.group(3));
                    newDefault.append(":");
                    // the second
                    newDefault.append(matcher.group(4));
                    // optionally, the fraction
                    if ((matcher.groupCount() > 4) && (matcher.group(4) != null)) {
                        newDefault.append(matcher.group(5));
                    }
                    newDefault.append("'");

                    column.setDefaultValue(newDefault.toString());
                }
            } else if (TypeMap.isTextType(column.getMappedTypeCode())) {
                String defaultValue = column.getDefaultValue();
                // DB2 stores default text values quoted
                if ((defaultValue.length() >= 2) && defaultValue.startsWith("'") && defaultValue.endsWith("'")) {
                    defaultValue = defaultValue.substring(1, defaultValue.length() - 1);
                }
                column.setDefaultValue(unescape(defaultValue, "'", "''"));
            }
        }
        return column;
    }

    @Override
    protected boolean isInternalPrimaryKeyIndex(Connection connection, DatabaseMetaDataWrapper metaData,
            Table table, IIndex index) throws SQLException {
        // Db2 uses the form "SQL060205225246220" if the primary key was defined
        // during table creation
        // When the ALTER TABLE way was used however, the index has the name of
        // the primary key
        if (index.getName().startsWith("SQL")) {
            try {
                Long.parseLong(index.getName().substring(3));
                return true;
            } catch (NumberFormatException ex) {
                // we ignore it
            }
            return false;
        } else {
            // we'll compare the index name to the names of all primary keys
            // TODO: Once primary key names are supported, this can be done
            // easier via the table object
            ResultSet pkData = null;
            HashSet<String> pkNames = new HashSet<String>();

            try {
                log.debug("getting pk info");
                pkData = metaData.getPrimaryKeys(table.getName());
                log.debug("done getting pk info");
                while (pkData.next()) {
                    Map<String, Object> values = readMetaData(pkData, getColumnsForPK());

                    pkNames.add((String) values.get("PK_NAME"));
                }
            } finally {
                if (pkData != null) {
                    pkData.close();
                }
            }

            return pkNames.contains(index.getName());
        }
    }

    @Override
    protected boolean isInternalForeignKeyIndex(Connection connection, DatabaseMetaDataWrapper metaData,
            Table table, ForeignKey fk, IIndex index) throws SQLException {
        return fk.getName().equalsIgnoreCase(index.getName());
    }

}