Oracle.java
/*
* Copyright (C) 2004 Tim Pizey
*
* 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:
*
* Tim Pizey (timp At paneris.org)
*
*/
package org.melati.poem.dbms;
import org.melati.poem.*;
import org.melati.poem.SQLType;
import java.sql.*;
/**
* A Driver for Oracle (http://www.oracle.com/).
*/
public class Oracle extends AnsiStandard {
/**
* Oracle does not have a pleasant <code>TEXT</code>
* datatype, so we use an arbetary value in a
* <code>VARCHAR</code>.
*/
public static int oracleTextHack = 4000;
/**
* Constructor.
*/
public Oracle() {
setDriverClassName("oracle.jdbc.OracleDriver");
}
/*
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/CLOB distinction.
*
* @param size the string length (-1 means no limit)
* @return the SQL definition for a string of this size
* @see org.melati.poem.dbms.AnsiStandard#getStringSqlDefinition(int)
*/
@Override
public String getStringSqlDefinition(int size) throws SQLException {
if (size < 0) {
return "CLOB";
}
return super.getStringSqlDefinition(size);
}
@Override
public String getLongSqlDefinition() {
return "NUMBER";
}
@Override
public String getSqlDefinition(String sqlTypeName) {
if (sqlTypeName.equals("BOOLEAN")) {
return ("CHAR(1)");
}
return super.getSqlDefinition(sqlTypeName);
}
@Override
public String sqlBooleanValueOfRaw(Object raw) {
if ((Boolean) raw)
return "1";
else
return "0";
}
/**
* Translates a Oracle String into a Poem <code>StringPoemType</code>.
*/
public static class OracleStringPoemType extends StringPoemType {
/**
* Constructor.
*
* @param nullable nullability
* @param size size
*/
public OracleStringPoemType(boolean nullable, int size) {
super(nullable, size);
}
protected boolean _canRepresent(SQLPoemType<?> other) {
return ((sqlTypeCode() == Types.VARCHAR || sqlTypeCode() == Types.CLOB)
&& (other.sqlTypeCode() == Types.VARCHAR || other.sqlTypeCode() == Types.CLOB)
) &&
(
(getSize() == oracleTextHack && ((StringPoemType) other).getSize() == -1)
||
(getSize() == -1 &&
((StringPoemType) other).getSize() == oracleTextHack)
||
((getSize() >= ((StringPoemType) other).getSize())));
}
/**
* {@inheritDoc}
*
* @see org.melati.poem.BasePoemType#canRepresent(PoemType)
*/
public <O> PoemType<O> canRepresent(PoemType<O> other) {
return other instanceof StringPoemType &&
_canRepresent((StringPoemType) other) &&
!(!getNullable() && (other).getNullable()) ?
other : null;
}
}
@Override
public String getBinarySqlDefinition(int size) throws SQLException {
return "BLOB";
}
@Override
public String unreservedName(String name) {
if (name.equalsIgnoreCase("user")) name = "melati_" + name;
if (name.equalsIgnoreCase("group")) name = "melati_" + name;
return name.toUpperCase();
}
@Override
public String melatiName(String name) {
if (name == null) return null;
if (name.equalsIgnoreCase("melati_user")) name = "user";
if (name.equalsIgnoreCase("melati_group")) name = "group";
return name.toLowerCase();
}
@Override
public <S, O> PoemType<O> canRepresent(PoemType<S> storage, PoemType<O> type) {
if ((storage instanceof IntegerPoemType &&
type instanceof BigDecimalPoemType) &&
!(!storage.getNullable() && type.getNullable())) {
return type;
}
if ((storage instanceof IntegerPoemType &&
type instanceof LongPoemType) &&
!(!storage.getNullable() && type.getNullable())) {
return type;
} else {
return storage.canRepresent(type);
}
}
@Override
public SQLPoemType<?> defaultPoemTypeOfColumnMetaData(ResultSet md)
throws SQLException {
System.err.println("TYPE_NAME:" + md.getString("TYPE_NAME"));
//ResultSetMetaData rsmd = md.getMetaData();
//int cols = rsmd.getColumnCount();
//for (int i = 1; i <= cols; i++) {
//String table = rsmd.getTableName(i);
//System.err.println("table name: " + table);
//String column = rsmd.getColumnName(i);
//System.err.println("column name: " + column);
//int type = rsmd.getColumnType(i);
//System.err.println("type: " + type);
//String typeName = rsmd.getColumnTypeName(i);
//System.err.println("type Name: " + typeName);
//String className = rsmd.getColumnClassName(i);
//System.err.println("class Name: " + className);
//System.err.println("String val: " + md.getString(i));
//System.err.println("");
//}
if (md.getString("TYPE_NAME").equals("VARCHAR2"))
return
new OracleStringPoemType(
md.getInt("NULLABLE") ==
DatabaseMetaData.columnNullable,
md.getInt("COLUMN_SIZE"));
if (md.getString("TYPE_NAME").equals("CLOB"))
return
new OracleStringPoemType(
md.getInt("NULLABLE") ==
DatabaseMetaData.columnNullable,
md.getInt("COLUMN_SIZE"));
if (md.getString("TYPE_NAME").equals("CHAR"))
return
new OracleBooleanPoemType(
md.getInt("NULLABLE") ==
DatabaseMetaData.columnNullable);
if (md.getString("TYPE_NAME").equals("BLOB"))
return new BinaryPoemType(
md.getInt("NULLABLE") == DatabaseMetaData.columnNullable,
md.getInt("COLUMN_SIZE"));
if (md.getString("TYPE_NAME").equals("FLOAT"))
return new DoublePoemType(
md.getInt("NULLABLE") == DatabaseMetaData.columnNullable);
if (
md.getString("TYPE_NAME").equals("NUMBER"))
return new IntegerPoemType(
md.getInt("NULLABLE") == DatabaseMetaData.columnNullable);
return super.defaultPoemTypeOfColumnMetaData(md);
}
@Override
public String getForeignKeyDefinition(String tableName, String fieldName,
String targetTableName, String targetTableFieldName, String fixName) {
String q = " ADD (CONSTRAINT FK_" + tableName + "_" + fieldName + ") " +
"FOREIGN KEY (" + getQuotedName(fieldName) + ") " +
"REFERENCES " + getQuotedName(targetTableName) +
"(" + getQuotedName(targetTableFieldName) + ")";
// Not currently implemented by Oracle,
// another reason for not using the DB to control these things
//if (fixName.equals("prevent"))
// q += " ON DELETE NO ACTION";
if (fixName.equals("delete"))
q += " ON DELETE CASCADE";
if (fixName.equals("clear"))
q += " ON DELETE SET NULL";
return q;
}
@Override
public String getPrimaryKeyDefinition(String fieldName) {
return " ADD (CONSTRAINT PK_" + fieldName +
" PRIMARY KEY(" + getQuotedName(fieldName) + "))";
}
@Override
public String booleanTrueExpression(Column<Boolean> booleanColumn) {
return booleanColumn.fullQuotedName() + "=1";
}
@Override
public String getSqlDefaultValue(SQLType<?> sqlType) {
if (sqlType instanceof BooleanPoemType) {
return ("0");
}
return super.getSqlDefaultValue(sqlType);
}
/**
* Translates an Oracle Boolean into a Poem <code>BooleanPoemType</code>.
*/
public static class OracleBooleanPoemType extends BooleanPoemType {
/**
* Constructor.
*
* @param nullable nullability
*/
public OracleBooleanPoemType(boolean nullable) {
super(nullable);
}
protected Boolean _getRaw(ResultSet rs, int col) throws SQLException {
synchronized (rs) {
boolean v = rs.getBoolean(col);
return rs.wasNull() ? null : (v ? Boolean.TRUE : Boolean.FALSE);
}
}
protected void _setRaw(PreparedStatement ps, int col, Object bool)
throws SQLException {
ps.setInt(col, (Boolean) bool ? 1 : 0);
}
}
}