Don't pass around and store column definitions as SQL strings, but introduce an object to contain that data. PostgreSQL's extensions does column alteration in individual tweaks, where MySQL just accepts a raw string and figures out what to do.
git-svn-id: https://samskivert.googlecode.com/svn/trunk@2233 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -160,19 +160,24 @@ public abstract class BaseLiaison implements DatabaseLiaison
|
||||
}
|
||||
|
||||
// from DatabaseLiaison
|
||||
public boolean changeColumn (Connection conn, String table, String column, String definition)
|
||||
public boolean changeColumn (Connection conn, String table, String column, String type,
|
||||
Boolean nullable, Boolean unique, String defaultValue)
|
||||
throws SQLException
|
||||
{
|
||||
String defStr = expandDefinition(
|
||||
type, nullable != null ? nullable : false, unique != null ? unique : false,
|
||||
defaultValue);
|
||||
|
||||
executeQuery(conn, "ALTER TABLE " + tableSQL(table) + " CHANGE " +
|
||||
columnSQL(column) + " " + columnSQL(column) + " " + definition);
|
||||
columnSQL(column) + " " + columnSQL(column) + " " + defStr);
|
||||
Log.info("Database column '" + column + "' of table '" + table + "' modified to have " +
|
||||
"definition '" + definition + "'.");
|
||||
"definition '" + defStr + "'.");
|
||||
return true;
|
||||
}
|
||||
|
||||
// from DatabaseLiaison
|
||||
public boolean renameColumn (Connection conn, String table, String from, String to,
|
||||
String newColumnDef)
|
||||
ColumnDefinition newColumnDef)
|
||||
throws SQLException
|
||||
{
|
||||
executeQuery(conn, "ALTER TABLE " + tableSQL(table) + " RENAME COLUMN " +
|
||||
@@ -194,7 +199,7 @@ public abstract class BaseLiaison implements DatabaseLiaison
|
||||
|
||||
// from DatabaseLiaison
|
||||
public boolean createTableIfMissing (
|
||||
Connection conn, String table, String[] columns, String[] definitions,
|
||||
Connection conn, String table, String[] columns, ColumnDefinition[] definitions,
|
||||
String[][] uniqueConstraintColumns, String[] primaryKeyColumns)
|
||||
throws SQLException
|
||||
{
|
||||
@@ -211,7 +216,8 @@ public abstract class BaseLiaison implements DatabaseLiaison
|
||||
if (ii > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append(columnSQL(columns[ii])).append(" ").append(definitions[ii]);
|
||||
builder.append(columnSQL(columns[ii])).append(" ");
|
||||
builder.append(expandDefinition(definitions[ii]));
|
||||
}
|
||||
|
||||
if (uniqueConstraintColumns != null && uniqueConstraintColumns.length > 0) {
|
||||
@@ -245,6 +251,17 @@ public abstract class BaseLiaison implements DatabaseLiaison
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an SQL string that summarizes a column definition in that format generally
|
||||
* accepted in table creation and column addition statements, e.g.
|
||||
* INTEGER UNIQUE NOT NULL DEFAULT 100
|
||||
*/
|
||||
public String expandDefinition (ColumnDefinition def)
|
||||
{
|
||||
return expandDefinition(
|
||||
def.getType(), def.isNullable(), def.isUnique(), def.getDefaultValue());
|
||||
}
|
||||
|
||||
protected int executeQuery (Connection conn, String query)
|
||||
throws SQLException
|
||||
{
|
||||
@@ -255,4 +272,24 @@ public abstract class BaseLiaison implements DatabaseLiaison
|
||||
JDBCUtil.close(stmt);
|
||||
}
|
||||
}
|
||||
|
||||
protected String expandDefinition (
|
||||
String type, boolean nullable, boolean unique, String defaultValue)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(type);
|
||||
|
||||
if (!nullable) {
|
||||
builder.append(" NOT NULL");
|
||||
}
|
||||
if (unique) {
|
||||
builder.append(" UNIQUE");
|
||||
}
|
||||
|
||||
// append the default value if one was specified
|
||||
if (defaultValue != null) {
|
||||
builder.append(" DEFAULT ").append(defaultValue);
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.samskivert.jdbc;
|
||||
|
||||
/**
|
||||
* An object representing the configuration of a typical SQL column.
|
||||
*/
|
||||
public class ColumnDefinition
|
||||
{
|
||||
public ColumnDefinition (String type)
|
||||
{
|
||||
this(type, false, false, null);
|
||||
}
|
||||
|
||||
public ColumnDefinition (
|
||||
String type, boolean nullable, boolean unique, String defaultValue)
|
||||
{
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("cannot build column definition without type");
|
||||
}
|
||||
|
||||
_type = type;
|
||||
_nullable = nullable;
|
||||
_unique = unique;
|
||||
_defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
/** Returns the SQL type of this column, e.g. INTEGER. */
|
||||
public String getType ()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
/** Determines whether or not this column should allow NULL values. */
|
||||
public boolean isNullable ()
|
||||
{
|
||||
return _nullable;
|
||||
}
|
||||
|
||||
/** Determines whether or not this column should reject duplicate values. */
|
||||
public boolean isUnique ()
|
||||
{
|
||||
return _unique;
|
||||
}
|
||||
|
||||
/** Returns the value to insert into this column instead of nulls, if any. */
|
||||
public String getDefaultValue ()
|
||||
{
|
||||
return _defaultValue;
|
||||
}
|
||||
|
||||
protected String _type;
|
||||
protected boolean _nullable;
|
||||
protected boolean _unique;
|
||||
protected String _defaultValue;
|
||||
}
|
||||
@@ -65,6 +65,13 @@ public interface DatabaseLiaison
|
||||
Connection conn, String table, String column, int first, int step)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* This method deletes the column value auto-generator described in {@link
|
||||
* #lastInsertedId}.
|
||||
*/
|
||||
public void deleteGenerator (Connection conn, String tableName, String columnName)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* This method attempts as dialect-agnostic an interface as possible to the ability of certain
|
||||
* databases to auto-generated numerical values for i.e. key columns; there is MySQL's
|
||||
@@ -117,23 +124,25 @@ public interface DatabaseLiaison
|
||||
|
||||
/**
|
||||
* Alter the definition, but not the name, of a given column on a given table. Returns true or
|
||||
* false if the database did or did not report a schema modification.
|
||||
*
|
||||
* TODO: We may wish to further split column definitions into type, nullability, etc.
|
||||
* false if the database did or did not report a schema modification. Any of the type,
|
||||
* nullable, unique and defaultValue arguments may be null, in which case the implementation
|
||||
* will attempt to leave that aspect of the column unchanged.
|
||||
*/
|
||||
public boolean changeColumn (
|
||||
Connection conn, String table, String column, String definition)
|
||||
throws SQLException;
|
||||
Connection conn, String table, String column, String type, Boolean nullable,
|
||||
Boolean unique, String defaultValue)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Alter the name, but not the definition, of a given column on a given table. Returns true or
|
||||
* false if the database did or did not report a schema modification.
|
||||
*
|
||||
* @param newColumnDef the full definition of the new column, including its new name (MySQL
|
||||
* @param columnDef the full definition of the new column, including its new name (MySQL
|
||||
* requires this for a column rename).
|
||||
*/
|
||||
public boolean renameColumn (
|
||||
Connection conn, String table, String oldColumn, String newColumn, String newColumnDef)
|
||||
Connection conn, String table, String oldColumn, String newColumn,
|
||||
ColumnDefinition columnDef)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
@@ -142,10 +151,17 @@ public interface DatabaseLiaison
|
||||
* Returns true if the table was successfully created, false if it already existed.
|
||||
*/
|
||||
public boolean createTableIfMissing (
|
||||
Connection conn, String table, String[] columns, String[] definitions,
|
||||
Connection conn, String table, String[] columns, ColumnDefinition[] declarations,
|
||||
String[][] uniqueConstraintColumns, String[] primaryKeyColumns)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Create an SQL string that summarizes a column definition in that format generally
|
||||
* accepted in table creation and column addition statements, e.g.
|
||||
* INTEGER UNIQUE NOT NULL DEFAULT 100
|
||||
*/
|
||||
public String expandDefinition (ColumnDefinition coldef);
|
||||
|
||||
/**
|
||||
* Returns true if the specified table exists and contains an index of the specified name;
|
||||
* false if either conditions does not hold true. <em>Note:</em> the names are case sensitive.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
//
|
||||
// samskivert library - useful routines for java programs
|
||||
// Copyright (C) 2001-2007 Michael Bayne
|
||||
//
|
||||
//
|
||||
// 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
|
||||
@@ -47,6 +47,13 @@ public class DefaultLiaison extends BaseLiaison
|
||||
return false;
|
||||
}
|
||||
|
||||
// from DatabaseLiaison
|
||||
public void deleteGenerator (Connection conn, String tableName, String columnName)
|
||||
throws SQLException
|
||||
{
|
||||
// nothing doing
|
||||
}
|
||||
|
||||
// from DatabaseLiaison
|
||||
public void initializeGenerator (
|
||||
Connection conn, String table, String column, int value, int size)
|
||||
|
||||
@@ -59,6 +59,13 @@ public class MySQLLiaison extends BaseLiaison
|
||||
// AUTO_INCREMENT does not allow this kind of control
|
||||
}
|
||||
|
||||
public void deleteGenerator (Connection conn, String tableName, String columnName)
|
||||
throws SQLException
|
||||
{
|
||||
// AUTO_INCREMENT does not create any database entities that we need to delete
|
||||
}
|
||||
|
||||
|
||||
// from DatabaseLiaison
|
||||
public int lastInsertedId (Connection conn, String table, String column) throws SQLException
|
||||
{
|
||||
@@ -120,14 +127,14 @@ public class MySQLLiaison extends BaseLiaison
|
||||
|
||||
@Override // from BaseLiaison
|
||||
public boolean renameColumn (Connection conn, String table, String oldColumnName,
|
||||
String newColumnName, String newColumnDef)
|
||||
String newColumnName, ColumnDefinition newColumnDef)
|
||||
throws SQLException
|
||||
{
|
||||
if (!tableContainsColumn(conn, table, oldColumnName)) {
|
||||
return false;
|
||||
}
|
||||
executeQuery(conn, "ALTER TABLE " + table + " CHANGE " + oldColumnName + " " +
|
||||
newColumnName + " " + newColumnDef);
|
||||
newColumnName + " " + expandDefinition(newColumnDef));
|
||||
Log.info("Renamed column '" + oldColumnName + "' on table '" + table + "' to '" +
|
||||
newColumnName + "'");
|
||||
return true;
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
package com.samskivert.jdbc;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.samskivert.Log;
|
||||
|
||||
@@ -85,23 +83,46 @@ public class PostgreSQLLiaison extends BaseLiaison
|
||||
" restart with " + first + " increment " + step);
|
||||
}
|
||||
|
||||
@Override // from DatabaseLiaison
|
||||
public boolean changeColumn (Connection conn, String table, String column, String definition)
|
||||
// from DatabaseLiaison
|
||||
public void deleteGenerator (Connection conn, String table, String column)
|
||||
throws SQLException
|
||||
{
|
||||
// we need to handle nullability separately; TODO: make this less of a hack
|
||||
boolean notNull = false;
|
||||
Matcher match = NOT_NULL.matcher(definition);
|
||||
if (match.find()) {
|
||||
definition = match.replaceFirst("");
|
||||
notNull = true;
|
||||
executeQuery(conn, "drop sequence if exists \"" + table + "_" + column + "_seq\"");
|
||||
}
|
||||
|
||||
@Override // from DatabaseLiaison
|
||||
public boolean changeColumn (Connection conn, String table, String column, String type,
|
||||
Boolean nullable, Boolean unique, String defaultValue)
|
||||
throws SQLException
|
||||
{
|
||||
StringBuilder log = new StringBuilder();
|
||||
if (type != null) {
|
||||
executeQuery(
|
||||
conn, "ALTER TABLE " + tableSQL(table) + " ALTER COLUMN " + columnSQL(column) +
|
||||
" TYPE " + type);
|
||||
log.append("type=" + type);
|
||||
}
|
||||
if (nullable != null) {
|
||||
executeQuery(
|
||||
conn, "ALTER TABLE " + tableSQL(table) + " ALTER COLUMN " + columnSQL(column) +
|
||||
" " + (nullable.booleanValue() ? "SET NOT NULL" : "DROP NOT NULL"));
|
||||
if (log.length() > 0) log.append(", ");
|
||||
log.append("nullable=" + nullable);
|
||||
}
|
||||
if (unique != null) {
|
||||
// TODO: I think this requires ALTER TABLE DROP CONSTRAINT and so on
|
||||
if (log.length() > 0) log.append(", ");
|
||||
log.append("unique=" + unique + " (not implemented yet)");
|
||||
}
|
||||
if (defaultValue != null) {
|
||||
executeQuery(
|
||||
conn, "ALTER TABLE " + tableSQL(table) + " ALTER COLUMN " + columnSQL(column) +
|
||||
" " + (defaultValue.length() > 0 ? "SET DEFAULT " + defaultValue : "DROP DEFAULT"));
|
||||
if (log.length() > 0) log.append(", ");
|
||||
log.append("defaultValue=" + defaultValue);
|
||||
}
|
||||
executeQuery(conn, "ALTER TABLE " + tableSQL(table) + " ALTER COLUMN " +
|
||||
columnSQL(column) + " TYPE " + definition);
|
||||
executeQuery(conn, "ALTER TABLE " + tableSQL(table) + " ALTER COLUMN " +
|
||||
columnSQL(column) + " " + (notNull ? "SET NOT NULL" : "DROP NOT NULL"));
|
||||
Log.info("Database column '" + column + "' of table '" + table + "' modified to have " +
|
||||
"definition '" + definition + "'.");
|
||||
"definition [" + log + "].");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -122,7 +143,4 @@ public class PostgreSQLLiaison extends BaseLiaison
|
||||
{
|
||||
return "\"" + index + "\"";
|
||||
}
|
||||
|
||||
protected static final Pattern NOT_NULL =
|
||||
Pattern.compile(" NOT NULL", Pattern.CASE_INSENSITIVE);
|
||||
}
|
||||
|
||||
@@ -203,7 +203,11 @@ public class TransitionRepository extends SimpleRepository
|
||||
conn,
|
||||
"TRANSITIONS",
|
||||
new String[] { "CLASS", "NAME", "APPLIED" },
|
||||
new String[] { "VARCHAR(200)", "VARCHAR(50)", "TIMESTAMP NOT NULL" },
|
||||
new ColumnDefinition[] {
|
||||
new ColumnDefinition("VARCHAR(200)", true, false, null),
|
||||
new ColumnDefinition("VARCHAR(50)", true, false, null),
|
||||
new ColumnDefinition("TIMESTAMP")
|
||||
},
|
||||
null,
|
||||
new String[] { "CLASS", "NAME" });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user