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
|
// 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
|
throws SQLException
|
||||||
{
|
{
|
||||||
|
String defStr = expandDefinition(
|
||||||
|
type, nullable != null ? nullable : false, unique != null ? unique : false,
|
||||||
|
defaultValue);
|
||||||
|
|
||||||
executeQuery(conn, "ALTER TABLE " + tableSQL(table) + " CHANGE " +
|
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 " +
|
Log.info("Database column '" + column + "' of table '" + table + "' modified to have " +
|
||||||
"definition '" + definition + "'.");
|
"definition '" + defStr + "'.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// from DatabaseLiaison
|
// from DatabaseLiaison
|
||||||
public boolean renameColumn (Connection conn, String table, String from, String to,
|
public boolean renameColumn (Connection conn, String table, String from, String to,
|
||||||
String newColumnDef)
|
ColumnDefinition newColumnDef)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
executeQuery(conn, "ALTER TABLE " + tableSQL(table) + " RENAME COLUMN " +
|
executeQuery(conn, "ALTER TABLE " + tableSQL(table) + " RENAME COLUMN " +
|
||||||
@@ -194,7 +199,7 @@ public abstract class BaseLiaison implements DatabaseLiaison
|
|||||||
|
|
||||||
// from DatabaseLiaison
|
// from DatabaseLiaison
|
||||||
public boolean createTableIfMissing (
|
public boolean createTableIfMissing (
|
||||||
Connection conn, String table, String[] columns, String[] definitions,
|
Connection conn, String table, String[] columns, ColumnDefinition[] definitions,
|
||||||
String[][] uniqueConstraintColumns, String[] primaryKeyColumns)
|
String[][] uniqueConstraintColumns, String[] primaryKeyColumns)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
@@ -211,7 +216,8 @@ public abstract class BaseLiaison implements DatabaseLiaison
|
|||||||
if (ii > 0) {
|
if (ii > 0) {
|
||||||
builder.append(", ");
|
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) {
|
if (uniqueConstraintColumns != null && uniqueConstraintColumns.length > 0) {
|
||||||
@@ -245,6 +251,17 @@ public abstract class BaseLiaison implements DatabaseLiaison
|
|||||||
return true;
|
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)
|
protected int executeQuery (Connection conn, String query)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
@@ -255,4 +272,24 @@ public abstract class BaseLiaison implements DatabaseLiaison
|
|||||||
JDBCUtil.close(stmt);
|
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)
|
Connection conn, String table, String column, int first, int step)
|
||||||
throws SQLException;
|
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
|
* 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
|
* 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
|
* 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.
|
* 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
|
||||||
* TODO: We may wish to further split column definitions into type, nullability, etc.
|
* will attempt to leave that aspect of the column unchanged.
|
||||||
*/
|
*/
|
||||||
public boolean changeColumn (
|
public boolean changeColumn (
|
||||||
Connection conn, String table, String column, String definition)
|
Connection conn, String table, String column, String type, Boolean nullable,
|
||||||
throws SQLException;
|
Boolean unique, String defaultValue)
|
||||||
|
throws SQLException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alter the name, but not the definition, of a given column on a given table. Returns true or
|
* 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.
|
* 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).
|
* requires this for a column rename).
|
||||||
*/
|
*/
|
||||||
public boolean renameColumn (
|
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;
|
throws SQLException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -142,10 +151,17 @@ public interface DatabaseLiaison
|
|||||||
* Returns true if the table was successfully created, false if it already existed.
|
* Returns true if the table was successfully created, false if it already existed.
|
||||||
*/
|
*/
|
||||||
public boolean createTableIfMissing (
|
public boolean createTableIfMissing (
|
||||||
Connection conn, String table, String[] columns, String[] definitions,
|
Connection conn, String table, String[] columns, ColumnDefinition[] declarations,
|
||||||
String[][] uniqueConstraintColumns, String[] primaryKeyColumns)
|
String[][] uniqueConstraintColumns, String[] primaryKeyColumns)
|
||||||
throws SQLException;
|
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;
|
* 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.
|
* 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
|
// samskivert library - useful routines for java programs
|
||||||
// Copyright (C) 2001-2007 Michael Bayne
|
// Copyright (C) 2001-2007 Michael Bayne
|
||||||
//
|
//
|
||||||
// This library is free software; you can redistribute it and/or modify it
|
// 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
|
// 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
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
@@ -47,6 +47,13 @@ public class DefaultLiaison extends BaseLiaison
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// from DatabaseLiaison
|
||||||
|
public void deleteGenerator (Connection conn, String tableName, String columnName)
|
||||||
|
throws SQLException
|
||||||
|
{
|
||||||
|
// nothing doing
|
||||||
|
}
|
||||||
|
|
||||||
// from DatabaseLiaison
|
// from DatabaseLiaison
|
||||||
public void initializeGenerator (
|
public void initializeGenerator (
|
||||||
Connection conn, String table, String column, int value, int size)
|
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
|
// 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
|
// from DatabaseLiaison
|
||||||
public int lastInsertedId (Connection conn, String table, String column) throws SQLException
|
public int lastInsertedId (Connection conn, String table, String column) throws SQLException
|
||||||
{
|
{
|
||||||
@@ -120,14 +127,14 @@ public class MySQLLiaison extends BaseLiaison
|
|||||||
|
|
||||||
@Override // from BaseLiaison
|
@Override // from BaseLiaison
|
||||||
public boolean renameColumn (Connection conn, String table, String oldColumnName,
|
public boolean renameColumn (Connection conn, String table, String oldColumnName,
|
||||||
String newColumnName, String newColumnDef)
|
String newColumnName, ColumnDefinition newColumnDef)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
if (!tableContainsColumn(conn, table, oldColumnName)) {
|
if (!tableContainsColumn(conn, table, oldColumnName)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
executeQuery(conn, "ALTER TABLE " + table + " CHANGE " + oldColumnName + " " +
|
executeQuery(conn, "ALTER TABLE " + table + " CHANGE " + oldColumnName + " " +
|
||||||
newColumnName + " " + newColumnDef);
|
newColumnName + " " + expandDefinition(newColumnDef));
|
||||||
Log.info("Renamed column '" + oldColumnName + "' on table '" + table + "' to '" +
|
Log.info("Renamed column '" + oldColumnName + "' on table '" + table + "' to '" +
|
||||||
newColumnName + "'");
|
newColumnName + "'");
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -21,8 +21,6 @@
|
|||||||
package com.samskivert.jdbc;
|
package com.samskivert.jdbc;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import com.samskivert.Log;
|
import com.samskivert.Log;
|
||||||
|
|
||||||
@@ -85,23 +83,46 @@ public class PostgreSQLLiaison extends BaseLiaison
|
|||||||
" restart with " + first + " increment " + step);
|
" restart with " + first + " increment " + step);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override // from DatabaseLiaison
|
// from DatabaseLiaison
|
||||||
public boolean changeColumn (Connection conn, String table, String column, String definition)
|
public void deleteGenerator (Connection conn, String table, String column)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
// we need to handle nullability separately; TODO: make this less of a hack
|
executeQuery(conn, "drop sequence if exists \"" + table + "_" + column + "_seq\"");
|
||||||
boolean notNull = false;
|
}
|
||||||
Matcher match = NOT_NULL.matcher(definition);
|
|
||||||
if (match.find()) {
|
@Override // from DatabaseLiaison
|
||||||
definition = match.replaceFirst("");
|
public boolean changeColumn (Connection conn, String table, String column, String type,
|
||||||
notNull = true;
|
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 " +
|
Log.info("Database column '" + column + "' of table '" + table + "' modified to have " +
|
||||||
"definition '" + definition + "'.");
|
"definition [" + log + "].");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +143,4 @@ public class PostgreSQLLiaison extends BaseLiaison
|
|||||||
{
|
{
|
||||||
return "\"" + index + "\"";
|
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,
|
conn,
|
||||||
"TRANSITIONS",
|
"TRANSITIONS",
|
||||||
new String[] { "CLASS", "NAME", "APPLIED" },
|
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,
|
null,
|
||||||
new String[] { "CLASS", "NAME" });
|
new String[] { "CLASS", "NAME" });
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user