All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gs.fw.common.mithra.util.TableColumnInfo Maven / Gradle / Ivy

There is a newer version: 18.1.0
Show newest version

/*
 Copyright 2016 Goldman Sachs.
 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 com.gs.fw.common.mithra.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gs.fw.common.mithra.attribute.SingleColumnAttribute;
import com.gs.collections.impl.map.mutable.UnifiedMap;

import java.sql.*;
import java.util.*;


public class TableColumnInfo
{

    private static final Logger logger = LoggerFactory.getLogger(TableColumnInfo.class.getName());

    private final String catalog;
    private final String schema;
    private final String name;
    private final ColumnInfo[] columns;

    private final Map columnsByName;

    /**
     * Creates the TableColumnInfo using the standard JDBC table metadata mechanisms.
     *
     * @param connection A connection to lookup the TableColumnInfo data on.
     * @param schema The schema of the table, or null if none should be used to lookup the table.
     * @param tableName The name of the table.
     * @param fullyQualifiedTableName
     * @return The metadata about the table.
     * @throws SQLException if there was a problem looking up the metadata.
     */
    public static TableColumnInfo createTableMetadata(Connection connection, String schema, String tableName, String fullyQualifiedTableName)
    throws SQLException
    {
        DatabaseMetaData metaData = connection.getMetaData();
        ResultSet resultSet = null;

        // Get hold of the table catalog and schema separately from the column metadata in case we have a zero-column table/view
        String catalog = null;
        String dbSchema = null;
        String dbName = null;
        boolean tableExists = false;

        try
        {
            resultSet = metaData.getTables(null, schema, tableName, null);

            if (resultSet.next())
            {
                catalog = resultSet.getString("TABLE_CAT");
                dbSchema = resultSet.getString("TABLE_SCHEM");
                dbName = resultSet.getString("TABLE_NAME");

                // TABLE_SCHEM could be null so use the passed in schema name if this is the case
                if (dbSchema == null)
                {
                    dbSchema = schema;
                }

                // Make sure we didn't get too many tables
                if (resultSet.next())
                {
                    throw new SQLException("Too many tables matching tablename '" + tableName + "' and schema '" + schema + "'.");
                }

                tableExists = true;
            }
        }
        finally
        {
            close(resultSet);
        }

        // Only continue if the table exists
        if (! tableExists)
        {
            return null;
        }

        // Get hold of the column metadata
        List columns = new ArrayList();
        try
        {
            resultSet = metaData.getColumns(null, schema, tableName, null);

            while (resultSet.next())
            {
                String columnName = resultSet.getString("COLUMN_NAME");
                int dataType = resultSet.getInt("DATA_TYPE");
                int columnSize = resultSet.getInt("COLUMN_SIZE");
                int scale = resultSet.getInt("DECIMAL_DIGITS");
                int ordinalPosition = resultSet.getInt("ORDINAL_POSITION");
                int nullable = resultSet.getInt("NULLABLE");
                ColumnInfo columnInfo = new ColumnInfo(
                        columnName,
                        dataType,
                        columnSize,
                        columnSize,
                        scale,
                        ordinalPosition,
                        nullable == DatabaseMetaData.columnNullable
                );

                columns.add(columnInfo);
            }
        }
        finally
        {
            close(resultSet);
        }

        return new TableColumnInfo(catalog, dbSchema, dbName, (ColumnInfo[]) columns.toArray(new ColumnInfo[columns.size()]));
    }

    public static TableColumnInfo createTableMetadataWithExtraSelect(Connection connection, String schema, String tableName, String fullyQualifiedTableName)
    throws SQLException
    {
        TableColumnInfo tableInfo = createTableMetadata(connection, schema, tableName, fullyQualifiedTableName);

        if (tableInfo == null || tableInfo.getColumns().length == 0)
        {
            List columns = new ArrayList();
            ResultSet resultSet = null;

            // Get hold of the table catalog and schema separately from the column metadata in case we have a zero-column table/view
            String catalog = null;
            String dbSchema = null;
            String dbName = null;
            Statement stm = null;
            try
            {
                stm = connection.createStatement();
                resultSet = stm.executeQuery("select * from "+fullyQualifiedTableName+" where 0 = 1");
                resultSet.next();
                ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
                int columnCount = resultSetMetaData.getColumnCount();
                dbName = resultSetMetaData.getTableName(1);
                dbSchema = resultSetMetaData.getSchemaName(1);
                if ("".equals(dbSchema))
                {
                    dbSchema = null;
                }
                for(int i=0;i< columnCount; i++)
                {
                    int col = i + 1;
                    ColumnInfo columnInfo = new ColumnInfo(resultSetMetaData.getColumnName(col),
                            resultSetMetaData.getColumnType(col),
                            resultSetMetaData.getColumnDisplaySize(col),
                            resultSetMetaData.getPrecision(col),
                            resultSetMetaData.getScale(col),
                            col,
                            resultSetMetaData.isNullable(col) == DatabaseMetaData.columnNullable);
                    columns.add(columnInfo);
                }
            }
            catch(SQLException e)
            {
                //ignore this; it's acceptable for the table to not be found.
            }
            finally
            {
                close(stm);
                close(resultSet);
            }
            if (columns.size() == 0)
            {
                return null;
            }
            tableInfo = new TableColumnInfo(catalog, dbSchema, dbName, (ColumnInfo[]) columns.toArray(new ColumnInfo[columns.size()]));
        }
        return tableInfo;
    }

    public TableColumnInfo(String catalog, String schema, String name, ColumnInfo[] columns)
    {
        this.catalog = catalog;
        this.schema = schema;
        this.name = name;

        // Sort the columns by the ordinal position
        this.columns = new ColumnInfo[columns.length];
        System.arraycopy(columns, 0, this.columns, 0, columns.length);

        Arrays.sort(this.columns, new Comparator()
        {
            public int compare(Object o1, Object o2)
            {
                return ((ColumnInfo) o1).getOrdinalPosition() - ((ColumnInfo) o2).getOrdinalPosition();
            }
        });

        // Also index the columns by name
        this.columnsByName = new UnifiedMap(this.columns.length);
        for (int i = 0; i < columns.length; i++)
        {
            ColumnInfo column = columns[i];
            this.columnsByName.put(column.getName(), column);
        }
    }

    /**
     * @return The catalog that the table resides in (this may be null).
     */
    public String getCatalog()
    {
        return this.catalog;
    }

    /**
     * @return The schema that the table resides in (this may be null).
     */
    public String getSchema()
    {
        return this.schema;
    }

    /**
     * @return The name of the table.
     */
    public String getName()
    {
        return this.name;
    }

    /**
     * @return The columns in the table (ordered by ordinal position).
     */
    public ColumnInfo[] getColumns()
    {
        return this.columns;
    }

    /**
     * @param name The name of the column to lookup.
     * @return The information about the column, or null if there is no column matching name.
     */
    public ColumnInfo getColumn(String name)
    {
        return (ColumnInfo) this.columnsByName.get(name);
    }

    private static void close(ResultSet resultSet)
    {
        if (resultSet != null)
        {
            try
            {
                resultSet.close();
            }
            catch (SQLException e)
            {
                logger.error("Could not close ResultSet", e);
            }
        }
    }

    private static void close(Statement stm)
    {
        if (stm != null)
        {
            try
            {
                stm.close();
            }
            catch (SQLException e)
            {
                logger.error("Could not close ResultSet", e);
            }
        }
    }

    /**
     * @return The number of columns that the table has.
     */
    public int getNumberOfColumns()
    {
        return this.columns.length;
    }

    public boolean hasColumn(SingleColumnAttribute attr)
    {
        ColumnInfo info = (ColumnInfo) this.columnsByName.get(attr.getColumnName().toUpperCase());
        if (info == null)
        {
            info = (ColumnInfo) this.columnsByName.get(attr.getColumnName());
        }
        return info != null && attr.verifyColumn(info);
    }

    /**
     * Does the table have a column matching the name, type, size
     * and isNullable status?
     * @param columnName The name of the column.
     * @param type The JDBC {@link Types} type.
     * @param size The size of the column.
     * @param isNullable true if the column should be nullable.
     * @return true if a matching column can be found, otherwise false.
     */
    public boolean hasColumn(String columnName, int type, int size, boolean isNullable)
    {
        ColumnInfo info = (ColumnInfo) this.columnsByName.get(columnName.toUpperCase());
        if (info == null)
        {
            info = (ColumnInfo) this.columnsByName.get(columnName);
        }
        if (info != null)
        {
            if (info.isNullable() != isNullable) return false;

            type = normalizeType(type, -1);
            int infoType = normalizeType(info.getType(), info.getSize());

            if (type == Types.VARCHAR && size != info.getSize())
            {
                return false;
            }
            if (type == Types.DOUBLE && info.getType() == Types.FLOAT)
            {
                return info.getSize() == 8;
            }

            if (type == Types.DOUBLE && (info.getType() == Types.DECIMAL || info.getType() == Types.NUMERIC))
            {
                return true;
            }

            if (type == Types.BIGINT)
            {
                return infoType == type || infoType == Types.NUMERIC;
            }

            return infoType == type;
        }

        return false;
    }

    private int normalizeType(int type, int size)
    {
        switch (type)
        {
            case Types.CHAR:
                type = Types.VARCHAR;
                break;
            case Types.BIT:
            case Types.BOOLEAN:
            case Types.TINYINT:
                type = Types.SMALLINT;
                break;
            case Types.FLOAT:
                type = Types.DOUBLE;
                break;
        }
        return type;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy