Postgresql.java
/*
* $Source$
* $Revision$
*
* Copyright (C) 2000 David Warnock
*
* Part of Melati (http://melati.org), a framework for the rapid
* development of clean, maintainable web applications.
*
* Melati is free software; Permission is granted to copy, distribute
* and/or modify this software under the terms either:
*
* a) the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version,
*
* or
*
* b) any version of the Melati Software License, as published
* at http://melati.org
*
* You should have received a copy of the GNU General Public License and
* the Melati Software License along with this program;
* if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
* GNU General Public License and visit http://melati.org to obtain the
* Melati Software License.
*
* Feel free to contact the Developers of Melati (http://melati.org),
* if you would like to work out a different arrangement than the options
* outlined here. It is our intention to allow Melati to be used by as
* wide an audience as possible.
*
* 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.
*
* Contact details for copyright holder:
*
* David Warnock (david At sundayta.co.uk)
* Sundayta Ltd
* International House,
* 174 Three Bridges Road,
* Crawley, West Sussex
* RH10 1LE, UK
*
*/
package org.melati.poem.dbms;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.melati.poem.Table;
import org.melati.poem.PoemType;
import org.melati.poem.SQLPoemType;
import org.melati.poem.BinaryPoemType;
import org.melati.poem.DoublePoemType;
import org.melati.poem.IntegerPoemType;
import org.melati.poem.LongPoemType;
import org.melati.poem.NoSuchColumnPoemException;
import org.melati.poem.SeriousPoemException;
import org.melati.poem.SQLPoemException;
/**
* A Driver for Postgresql.
* See http://www.postgresql.org/
*
* <b>Backwards compatabilty</b>
* Previous (7.4) versions allowed single quotes to be quoted using C style escaping.
* In version 9.1 you need to explicitly allow this escaping by configuring the server:
* <code>
* backslash_quote = on
* standard_conforming_strings = off
* </code>
**/
public class Postgresql extends AnsiStandard {
/**
* Constructor.
*/
public Postgresql() {
setDriverClassName("org.postgresql.Driver");
}
/**
* Whether this DBMS can drop columns.
*
* Postgresql has been able to since 7.4
*
* @return true if we can
*/
@Override
public boolean canDropColumns() {
return true;
}
/**
* Accommodate casting in placeholders.
*
* @param type the type to cast
* @return the place holder string
*/
@Override
public String preparedStatementPlaceholder(PoemType<?> type) {
if (type instanceof IntegerPoemType)
return "CAST(? AS INT4)";
else if (type instanceof LongPoemType)
return "CAST(? AS INT8)";
else if (type instanceof DoublePoemType)
return "CAST(? AS FLOAT8)";
else
return "?";
}
/**
* Accommodate String/Text distinction.
*
* @param size the string length (-1 means no limit)
* @return the SQL definition for a string of this size
* @throws SQLException
* @see org.melati.poem.dbms.AnsiStandard#getStringSqlDefinition(int)
*/
@Override
public String getStringSqlDefinition(int size) throws SQLException {
if (size < 0) {
return "TEXT";
}
return super.getStringSqlDefinition(size);
}
@Override
public String getBinarySqlDefinition(int size) throws SQLException {
return "BYTEA";
}
/*
public String getBinarySqlDefinition(int size) {
// BLOBs in Postgres are represented as OIDs pointing to the data
return "OID";
}
*/
/**
* An Object Id <code>PoemType</code>.
*/
/*
public static class OidPoemType extends IntegerPoemType {
public OidPoemType(boolean nullable) {
super(Types.INTEGER, "OID", nullable);
}
protected boolean _canRepresent(SQLPoemType other) {
return other instanceof BinaryPoemType;
}
public PoemType canRepresent(PoemType other) {
return other instanceof BinaryPoemType &&
!(!getNullable() &&
((BinaryPoemType)other).getNullable()) ? other : null;
}
}
*/
@Override
public SQLPoemType<?> defaultPoemTypeOfColumnMetaData(ResultSet md)
throws SQLException {
return
md.getString("TYPE_NAME").equals("bytea") ?
new BinaryPoemType(md.getInt("NULLABLE") ==
DatabaseMetaData.columnNullable, -1) :
super.defaultPoemTypeOfColumnMetaData(md);
// md.getString("TYPE_NAME").equals("oid") ?
// new OidPoemType(md.getInt("NULLABLE") ==
// DatabaseMetaData.columnNullable) :
// super.defaultPoemTypeOfColumnMetaData(md);
}
@Override
public SQLPoemException exceptionForUpdate(
Table<?> table, String sql, boolean insert, SQLException e) {
String m = e.getMessage();
// Postgres's duplicate key message is:
// "Cannot insert a duplicate key into unique index user_login_index"
if (m != null &&
m.indexOf("duplicate key") >= 0) {
// We call POEM's own indexes <table>_<column>_index:
// see Table.dbCreateIndex
int s, u;
if (m.endsWith("_index\n") &&
(s = m.lastIndexOf(' ')) >= 0 && (u = m.indexOf('_', s+1)) >= 0) {
String colname = m.substring(u+1, m.length() - 7);
try {
return new DuplicateKeySQLPoemException(table.getColumn(colname),
sql, insert, e);
}
catch (NoSuchColumnPoemException f) {
throw new SeriousPoemException(
"Duplicate Key exception thrown on a non-existant column",f);
}
}
return new DuplicateKeySQLPoemException(table, sql, insert, e);
}
else
return super.exceptionForUpdate(table, sql, insert, e);
}
}