/* * RHQ Management Platform * Copyright (C) 2005-2008 Red Hat, Inc. * All rights reserved. * * This program 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 version 2 of the License. * * This program 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.rhq.core.db; import java.math.BigInteger; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; /** * Superclass of all versions of the Postgres database. * * @author John Mazzitelli * */ public abstract class PostgresqlDatabaseType extends DatabaseType { /** * The vendor name for all PostgresQL databases. */ public static final String VENDOR_NAME = "postgresql"; /** * Returns {@link #VENDOR_NAME}. * * @see DatabaseType#getVendor() */ @Override public String getVendor() { return VENDOR_NAME; } @Override public String getHibernateDialect() { return "org.hibernate.dialect.PostgreSQLDialect"; } /** * @see DatabaseType#isTableNotFoundException(SQLException) */ @Override public boolean isTableNotFoundException(SQLException e) { return (e.getSQLState().toUpperCase().equals("42P01")); } /** * Assumes the sequence table is the value of the table argument followed by "_", the value of the key argument and * then "_seq". * * @see DatabaseType#getSequenceValue(Connection, String, String) */ @Override public int getSequenceValue(Connection conn, String table, String key) throws SQLException { String query = "SELECT currval('" + table + "_" + key + "_seq')"; PreparedStatement selectPS = null; ResultSet rs = null; try { selectPS = conn.prepareStatement(query); rs = selectPS.executeQuery(); if (rs.next()) { return rs.getInt(1); } throw new RuntimeException(DbUtilsI18NFactory.getMsg() .getMsg(DbUtilsI18NResourceKeys.NOT_A_SEQUENCE, query)); } finally { closeJDBCObjects(null, selectPS, rs); } } /** * @see DatabaseType#getNextSequenceValue(Connection, String, String) */ @Override public int getNextSequenceValue(Connection conn, String table, String key) throws SQLException { String query = "SELECT nextval('" + table + "_" + key + "_seq'::text)"; PreparedStatement selectPS = null; ResultSet rs = null; try { selectPS = conn.prepareStatement(query); rs = selectPS.executeQuery(); if (rs.next()) { return rs.getInt(1); } throw new RuntimeException(DbUtilsI18NFactory.getMsg() .getMsg(DbUtilsI18NResourceKeys.NOT_A_SEQUENCE, query)); } finally { closeJDBCObjects(null, selectPS, rs); } } /** * @see DatabaseType#alterColumn(Connection, String, String, String, String, String, Boolean, Boolean) */ @Override public void alterColumn(Connection conn, String table, String column, String generic_column_type, String default_value, String precision, Boolean nullable, Boolean reindex) throws SQLException { String db_column_type = null; List<String> sql_list = new ArrayList<String>(); if (generic_column_type != null) { db_column_type = getDBTypeFromGenericType(generic_column_type); if (precision != null) { db_column_type += " (" + precision + ")"; } sql_list.add("ALTER TABLE " + table + " ALTER COLUMN " + column + " TYPE " + db_column_type); } if (default_value != null) { sql_list.add("ALTER TABLE " + table + " ALTER COLUMN " + column + " SET DEFAULT '" + default_value + "'"); } if (nullable != null) { if (nullable.booleanValue()) { sql_list.add("ALTER TABLE " + table + " ALTER " + column + " DROP NOT NULL"); } else { sql_list.add("ALTER TABLE " + table + " ALTER " + column + " SET NOT NULL"); } } executeSql(conn, sql_list); // now that we've altered the column, let's reindex if we were told to do so if ((reindex != null) && reindex.booleanValue()) { reindexTable(conn, table); } return; } /** * @see DatabaseType#reindexTable(Connection, String) */ @Override public void reindexTable(Connection conn, String table) throws SQLException { executeSql(conn, "REINDEX TABLE " + table); } /** * This is overridden for Postgres because by default (at least in our currently supported versions) * postgres treats '\' as an escape character in a string literal and the ESCAPE character for * LIKE syntax is specified as a string literal. Therefore, ESCAPE '\\' is required to * specify that the escape character is in fact a single backslash. * Note 1: The default behavior may change in a future version of postgres given that * the standard_conforming_strings setting may change from 'off' to 'on' out of the box. * Note 2: Also related, http://opensource.atlassian.com/projects/hibernate/browse/HHH-2674 for more. * * @see DatabaseType#getEscapeCharacter() */ @Override public String getEscapeCharacter() { String result = System.getProperty("rhq.server.database.escape-character"); return (null == result) ? "\\\\" : result; } /* (non-Javadoc) * @see org.rhq.core.db.DatabaseType#getLong(java.lang.Object) * * Postgres stores long fields as BigInteger and returns a BigInteger. It is assumed <code>number</code> is actually * a long value, otherwise precision will be lost in this conversion. */ @Override public Long getLong(Object number) { BigInteger longField = (BigInteger) number; return longField.longValue(); } }