Added auto-migration for adding new columns.
This commit is contained in:
@@ -22,6 +22,7 @@ import java.lang.reflect.Field;
|
|||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
|
import java.sql.DatabaseMetaData;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
@@ -29,6 +30,7 @@ import java.sql.Statement;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import javax.persistence.GeneratedValue;
|
import javax.persistence.GeneratedValue;
|
||||||
@@ -37,6 +39,7 @@ import javax.persistence.TableGenerator;
|
|||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
|
|
||||||
import com.samskivert.jdbc.JDBCUtil;
|
import com.samskivert.jdbc.JDBCUtil;
|
||||||
|
import com.samskivert.util.ListUtil;
|
||||||
import com.samskivert.util.StringUtil;
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
import static com.samskivert.jdbc.depot.Log.log;
|
import static com.samskivert.jdbc.depot.Log.log;
|
||||||
@@ -231,7 +234,7 @@ public class DepotMarshaller<T>
|
|||||||
_postamble);
|
_postamble);
|
||||||
JDBCUtil.createTableIfMissing(
|
JDBCUtil.createTableIfMissing(
|
||||||
conn, getTableName(), _columnDefinitions, _postamble);
|
conn, getTableName(), _columnDefinitions, _postamble);
|
||||||
// TODO: insert current version into version table
|
updateVersion(conn, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we have a key generator, initialize that too
|
// if we have a key generator, initialize that too
|
||||||
@@ -244,16 +247,56 @@ public class DepotMarshaller<T>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise, then make sure the versions match and do some migration
|
// make sure the versions match
|
||||||
// if they don't
|
int currentVersion = readVersion(conn);
|
||||||
|
if (currentVersion == _schemaVersion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Migrating " + getTableName() + " from " + currentVersion +
|
||||||
|
" to " + _schemaVersion + "...");
|
||||||
|
|
||||||
|
// otherwise try to migrate the schema; doing column additions
|
||||||
|
// magically and running any registered hand-migrations
|
||||||
|
DatabaseMetaData meta = conn.getMetaData();
|
||||||
|
ResultSet rs = meta.getColumns(null, null, getTableName(), "%");
|
||||||
|
HashSet<String> columns = new HashSet<String>();
|
||||||
|
while (rs.next()) {
|
||||||
|
columns.add(rs.getString("COLUMN_NAME"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FieldMarshaller fmarsh : _fields.values()) {
|
||||||
|
if (columns.contains(fmarsh.getColumnName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// otherwise add the column
|
||||||
|
String coldef = fmarsh.getColumnDefinition();
|
||||||
|
String query = "alter table " + getTableName() +
|
||||||
|
" add column " + coldef;
|
||||||
|
|
||||||
|
// try to add it to the appropriate spot
|
||||||
|
int fidx = ListUtil.indexOf(_allFields, fmarsh.getColumnName());
|
||||||
|
if (fidx == 0) {
|
||||||
|
query += " first";
|
||||||
|
} else {
|
||||||
|
query += " after " + _allFields[fidx-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("Adding column to " + getTableName() + ": " + coldef);
|
||||||
Statement stmt = conn.createStatement();
|
Statement stmt = conn.createStatement();
|
||||||
try {
|
try {
|
||||||
// TODO: magical migration; execute registered migration actions
|
stmt.executeUpdate(query);
|
||||||
} finally {
|
} finally {
|
||||||
stmt.close();
|
stmt.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: run any registered hand migrations
|
||||||
|
|
||||||
|
updateVersion(conn, _schemaVersion);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a query for instances of this persistent object type using the
|
* Creates a query for instances of this persistent object type using the
|
||||||
* supplied key. If null is supplied all instances will be loaded.
|
* supplied key. If null is supplied all instances will be loaded.
|
||||||
@@ -494,6 +537,36 @@ public class DepotMarshaller<T>
|
|||||||
return pstmt;
|
return pstmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void updateVersion (Connection conn, int version)
|
||||||
|
throws SQLException
|
||||||
|
{
|
||||||
|
String query = (version == 1) ?
|
||||||
|
"insert into " + SCHEMA_VERSION_TABLE +
|
||||||
|
" values('" + getTableName() + "', " + version + ")" :
|
||||||
|
"update " + SCHEMA_VERSION_TABLE + " set version = " + version +
|
||||||
|
" where persistentClass = '" + getTableName() + "'";
|
||||||
|
Statement stmt = conn.createStatement();
|
||||||
|
try {
|
||||||
|
stmt.executeUpdate(query);
|
||||||
|
} finally {
|
||||||
|
stmt.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int readVersion (Connection conn)
|
||||||
|
throws SQLException
|
||||||
|
{
|
||||||
|
String query = "select version from " + SCHEMA_VERSION_TABLE +
|
||||||
|
" where persistentClass = '" + getTableName() + "'";
|
||||||
|
Statement stmt = conn.createStatement();
|
||||||
|
try {
|
||||||
|
ResultSet rs = stmt.executeQuery(query);
|
||||||
|
return (rs.next()) ? rs.getInt(1) : 1;
|
||||||
|
} finally {
|
||||||
|
stmt.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** The persistent object class that we manage. */
|
/** The persistent object class that we manage. */
|
||||||
protected Class<T> _pclass;
|
protected Class<T> _pclass;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user