/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This 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 Lesser General Public License for more * details. */ package com.liferay.portal.kernel.dao.db; import com.liferay.portal.kernel.dao.jdbc.DataAccess; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.upgrade.UpgradeException; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import java.lang.reflect.Field; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author Adolfo PĂ©rez */ public class DBInspector { public DBInspector(Connection connection) { _connection = connection; } public String getCatalog() throws SQLException { return _connection.getCatalog(); } public String getSchema() { try { return _connection.getSchema(); } catch (Throwable t) { if (_log.isDebugEnabled()) { _log.debug(t, t); } return null; } } public boolean hasColumn(String tableName, String columnName) throws Exception { try (PreparedStatement ps = _connection.prepareStatement( "select * from " + tableName); ResultSet rs = ps.executeQuery()) { ResultSetMetaData rsmd = rs.getMetaData(); for (int i = 0; i < rsmd.getColumnCount(); i++) { String curColumnName = rsmd.getColumnName(i + 1); if (StringUtil.equalsIgnoreCase(curColumnName, columnName)) { return true; } } } catch (Exception e) { _log.error(e, e); } return false; } public boolean hasColumnType( Class<?> tableClass, String columnName, String columnType) throws Exception { Field tableNameField = tableClass.getField("TABLE_NAME"); String tableName = (String)tableNameField.get(null); DatabaseMetaData databaseMetaData = _connection.getMetaData(); try (ResultSet rs = databaseMetaData.getColumns( getCatalog(), getSchema(), tableName, columnName)) { if (!rs.next()) { return false; } int expectedColumnDataType = _getColumnDataType( tableClass, columnName); int expectedColumnSize = _getColumnSize(columnType); boolean expectedColumnNullable = _isColumnNullable(columnType); int actualColumnDataType = rs.getInt("DATA_TYPE"); int actualColumnSize = rs.getInt("COLUMN_SIZE"); int actualColumnNullable = rs.getInt("NULLABLE"); if ((expectedColumnSize != -1) && (expectedColumnSize != actualColumnSize)) { return false; } if (actualColumnDataType != expectedColumnDataType) { return false; } if ((expectedColumnNullable && (actualColumnNullable != DatabaseMetaData.columnNullable)) || (!expectedColumnNullable && (actualColumnNullable != DatabaseMetaData.columnNoNulls))) { return false; } return true; } } public boolean hasRows(String tableName) { try (PreparedStatement ps = _connection.prepareStatement( "select count(*) from " + tableName); ResultSet rs = ps.executeQuery()) { while (rs.next()) { int count = rs.getInt(1); if (count > 0) { return true; } } } catch (Exception e) { _log.error(e, e); } return false; } public boolean hasTable(String tableName) throws Exception { return hasTable(tableName, false); } public boolean hasTable(String tableName, boolean caseSensitive) throws Exception { if (caseSensitive) { if (_hasTable(tableName)) { return true; } return false; } if (_hasTable(StringUtil.toLowerCase(tableName)) || _hasTable(StringUtil.toUpperCase(tableName)) || _hasTable(tableName)) { return true; } return false; } private int _getColumnDataType(Class<?> tableClass, String columnName) throws Exception { Field tableColumnsField = tableClass.getField("TABLE_COLUMNS"); Object[][] tableColumns = (Object[][])tableColumnsField.get(null); for (Object[] tableColumn : tableColumns) { if (tableColumn[0].equals(columnName)) { return (int)tableColumn[1]; } } throw new UpgradeException( "Table class " + tableClass + " does not have column " + columnName); } private int _getColumnSize(String columnType) throws UpgradeException { Matcher matcher = _columnSizePattern.matcher(columnType); if (!matcher.matches()) { return -1; } String columnSize = matcher.group(1); if (Validator.isNotNull(columnSize)) { try { return Integer.parseInt(columnSize); } catch (NumberFormatException nfe) { throw new UpgradeException( "Column type " + columnType + " has an invalid column size " + columnSize, nfe); } } return -1; } private boolean _hasTable(String tableName) throws Exception { PreparedStatement ps = null; ResultSet rs = null; try { DatabaseMetaData metadata = _connection.getMetaData(); rs = metadata.getTables(getCatalog(), getSchema(), tableName, null); while (rs.next()) { return true; } } finally { DataAccess.cleanUp(ps, rs); } return false; } private boolean _isColumnNullable(String typeName) { typeName = typeName.trim(); int i = typeName.indexOf("null"); if (i == -1) { return false; } if ((i > 0) && !Character.isSpaceChar(typeName.charAt(i - 1))) { return false; } if ((i + 4) < typeName.length()) { return false; } return true; } private static final Log _log = LogFactoryUtil.getLog(DBInspector.class); private static final Pattern _columnSizePattern = Pattern.compile( "^\\w+(?:\\((\\d+)\\))?.*", Pattern.CASE_INSENSITIVE); private final Connection _connection; }