/* * Copyright (c) 2008, SQL Power Group Inc. * * This file is part of SQL Power Library. * * SQL Power Library is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * SQL Power Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.sql.jdbcwrapper; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.HashMap; import java.util.Map; import org.apache.log4j.Logger; import ca.sqlpower.sql.CachedRowSet; import ca.sqlpower.sql.SQL; public class MySQLDatabaseMetaDataDecorator extends DatabaseMetaDataDecorator { private static final Logger logger = Logger .getLogger(MySQLDatabaseMetaDataDecorator.class); public MySQLDatabaseMetaDataDecorator(DatabaseMetaData delegate, ConnectionDecorator connectionDecorator) { super(delegate, connectionDecorator); } /** * Overriding the getColumns method to properly quote varchar defaults as * they are retrieved without quotes which prevents using them in later SQL * statements. */ @Override public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { ResultSet rs = super.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern); CachedRowSet crs = new CachedRowSet(); crs.populate(rs); rs.close(); while (crs.next()) { if (crs.getInt(5) == Types.VARCHAR && crs.getString(13) != null) { crs.updateString(13, SQL.quote(crs.getString(13))); } } crs.beforeFirst(); return crs; } /** * This wrapper has a several functions: * <ul> * <li>augments the result set with an SPG_INDEX_TYPE column which contains * the native index type as a string * <li>ensures the type of column 4 (NON_UNIQUE) is <code>boolean</code> (the MySQL * driver was complaining when we called getBoolean(4)) * <li>ensures the type of column 7 (TYPE) is <code>short</code> (the MySQL * driver was complaining when we called getShort(7)) * <li>Name-mangles the primary key index name in the same way as our wrapper for * {@link #getPrimaryKeys(String, String, String)} * </ul> */ @Override public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { ResultSet rs = super.getIndexInfo(catalog, schema, table, unique, approximate); CachedRowSet crs = new CachedRowSet(); crs.populate(rs, null, "SPG_INDEX_TYPE"); rs.close(); Map<String, String> indexTypes = getIndexType(catalog, table); while (crs.next()) { if ("true".equals(crs.getString(4))) { crs.updateBoolean(4, true); } else { crs.updateBoolean(4, false); } crs.updateShort(7, Short.valueOf(crs.getString(7))); if ("PRIMARY".equals(crs.getString(6))) { String tableName = crs.getString(3); crs.updateString(6, pkNameForTable(tableName)); } crs.updateString("SPG_INDEX_TYPE", indexTypes.get(crs.getString(6))); logger.debug("Name: " + crs.getString(6)); logger.debug("JDBC Type?: " + crs.getShort(7)); logger.debug("Unique?: " + crs.getBoolean(4)); logger.debug("Index Type?: " + crs.getString("SPG_INDEX_TYPE")); } crs.beforeFirst(); return crs; } /** * This uses an index name and a table name to find out the index type. The * index type is returned as a map of index names to index types */ private Map<String, String> getIndexType(String catalog, String tableName) throws SQLException { Map<String, String> indexTypes = new HashMap<String, String>(); Statement stmt = null; ResultSet rs = null; String type = ""; String name = ""; try { stmt = getConnection().createStatement(); String sql = "SHOW INDEXES FROM " + (catalog == null ? "" : catalog + ".") + tableName; logger.debug("SQL statement was " + sql); rs = stmt.executeQuery(sql); while (rs.next()) { name = rs.getString("key_name"); type = rs.getString("index_type"); indexTypes.put(name, type); } return indexTypes; } finally { if (rs != null) rs.close(); if (stmt != null) stmt.close(); } } /** * Augments the primary key info with made-up PK names based on the name of * the table they belong to. In InnoDB, all primary keys are called PRIMARY. */ @Override public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { CachedRowSet crs = new CachedRowSet(); ResultSet origRS = null; try { origRS = super.getPrimaryKeys(catalog, schema, table); crs.populate(origRS); } finally { if (origRS != null) { origRS.close(); } } while (crs.next()) { String tableName = crs.getString(3); if ("PRIMARY".equals(crs.getString(6))) { crs.updateString(6, pkNameForTable(tableName)); } } crs.beforeFirst(); return crs; } private String pkNameForTable(String tableName) { return tableName + "_PK"; } @Override protected ResultSetDecorator wrap (ResultSet rs) throws SQLException { return new GenericResultSetDecorator(wrap(rs.getStatement()), rs); } @Override protected StatementDecorator wrap (Statement statement) { return new GenericStatementDecorator(connectionDecorator, statement); } }