Made the addFooToTable() methods return true if they did something, false if

they did not. Unwrapped.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@1989 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2006-12-06 02:31:35 +00:00
parent 86767b91be
commit 5e61ec0641
+120 -156
View File
@@ -43,16 +43,16 @@ public class JDBCUtil
public interface BatchProcessor public interface BatchProcessor
{ {
/** /**
* Called for each row returned during our batch query. Do not advance * Called for each row returned during our batch query. Do not advance the result set,
* the result set, simply query its values with the get methods. * simply query its values with the get methods.
*/ */
public void process (ResultSet row) public void process (ResultSet row)
throws SQLException; throws SQLException;
}; };
/** /**
* Closes the supplied JDBC statement and gracefully handles being * Closes the supplied JDBC statement and gracefully handles being passed null (by doing
* passed null (by doing nothing). * nothing).
*/ */
public static void close (Statement stmt) public static void close (Statement stmt)
throws SQLException throws SQLException
@@ -63,8 +63,8 @@ public class JDBCUtil
} }
/** /**
* Closes the supplied JDBC connection and gracefully handles being * Closes the supplied JDBC connection and gracefully handles being passed null (by doing
* passed null (by doing nothing). * nothing).
*/ */
public static void close (Connection conn) public static void close (Connection conn)
throws SQLException throws SQLException
@@ -75,28 +75,24 @@ public class JDBCUtil
} }
/** /**
* Calls <code>stmt.executeUpdate()</code> on the supplied statement, * Calls <code>stmt.executeUpdate()</code> on the supplied statement, checking to see that it
* checking to see that it returns the expected update count and * returns the expected update count and throwing a persistence exception if it does not.
* throwing a persistence exception if it does not.
*/ */
public static void checkedUpdate ( public static void checkedUpdate (PreparedStatement stmt, int expectedCount)
PreparedStatement stmt, int expectedCount)
throws SQLException, PersistenceException throws SQLException, PersistenceException
{ {
int modified = stmt.executeUpdate(); int modified = stmt.executeUpdate();
if (modified != expectedCount) { if (modified != expectedCount) {
String err = "Statement did not modify expected number of rows " + String err = "Statement did not modify expected number of rows [stmt=" + stmt +
"[stmt=" + stmt + ", expected=" + expectedCount + ", expected=" + expectedCount + ", modified=" + modified + "]";
", modified=" + modified + "]";
throw new PersistenceException(err); throw new PersistenceException(err);
} }
} }
/** /**
* Calls <code>stmt.executeUpdate()</code> on the supplied statement * Calls <code>stmt.executeUpdate()</code> on the supplied statement with the supplied query,
* with the supplied query, checking to see that it returns the * checking to see that it returns the expected update count and throwing a persistence
* expected update count and throwing a persistence exception if it * exception if it does not.
* does not.
*/ */
public static void checkedUpdate ( public static void checkedUpdate (
Statement stmt, String query, int expectedCount) Statement stmt, String query, int expectedCount)
@@ -104,35 +100,30 @@ public class JDBCUtil
{ {
int modified = stmt.executeUpdate(query); int modified = stmt.executeUpdate(query);
if (modified != expectedCount) { if (modified != expectedCount) {
String err = "Statement did not modify expected number of rows " + String err = "Statement did not modify expected number of rows [stmt=" + stmt +
"[stmt=" + stmt + ", expected=" + expectedCount + ", expected=" + expectedCount + ", modified=" + modified + "]";
", modified=" + modified + "]";
throw new PersistenceException(err); throw new PersistenceException(err);
} }
} }
/** /**
* Calls <code>stmt.executeUpdate()</code> on the supplied statement, * Calls <code>stmt.executeUpdate()</code> on the supplied statement, checking to see that it
* checking to see that it returns the expected update count and * returns the expected update count and logging a warning if it does not.
* logging a warning if it does not.
*/ */
public static void warnedUpdate ( public static void warnedUpdate (PreparedStatement stmt, int expectedCount)
PreparedStatement stmt, int expectedCount)
throws SQLException throws SQLException
{ {
int modified = stmt.executeUpdate(); int modified = stmt.executeUpdate();
if (modified != expectedCount) { if (modified != expectedCount) {
Log.warning("Statement did not modify expected number of rows " + Log.warning("Statement did not modify expected number of rows [stmt=" + stmt +
"[stmt=" + stmt + ", expected=" + expectedCount + ", expected=" + expectedCount + ", modified=" + modified + "]");
", modified=" + modified + "]");
} }
} }
/** /**
* Issues a query with a potentially large number of keys in batches. * Issues a query with a potentially large number of keys in batches. For example, you might
* For example, you might have 10,000 ids that you wish to use in an "in" * have 10,000 ids that you wish to use in an "in" clause, but don't trust the database to be
* clause, but don't trust the database to be smart about optimizing that * smart about optimizing that many keys, so instead you use batchQuery like so:
* many keys, so instead you use batchQuery like so:
* <pre> * <pre>
* Collection<Integer> keys = ...; * Collection<Integer> keys = ...;
* String query = "select NAME from USERS where USER_ID in (#KEYS)"; * String query = "select NAME from USERS where USER_ID in (#KEYS)";
@@ -145,17 +136,14 @@ public class JDBCUtil
* JDBCUtil.batchQuery(conn, query, keys, false, 500, proc); * JDBCUtil.batchQuery(conn, query, keys, false, 500, proc);
* </pre> * </pre>
* *
* @param query the SQL query to run for each batch with the string * @param query the SQL query to run for each batch with the string <code>#KEYS#</code> in the
* <code>#KEYS#</code> in the place where the batch of keys should be * place where the batch of keys should be substituted.
* substituted. * @param escapeKeys if true, {@link #escape} will be called on each key to escape any
* @param escapeKeys if true, {@link #escape} will be called on each key to * dangerous characters and wrap the key in quotes.
* escape any dangerous characters and wrap the key in quotes. * @param batchSize the number of keys at a time to substitute in for <code>#KEYS#</code>.
* @param batchSize the number of keys at a time to substitute in for
* <code>#KEYS#</code>.
*/ */
public static void batchQuery ( public static void batchQuery (Connection conn, String query, Collection<?> keys,
Connection conn, String query, Collection<?> keys, boolean escapeKeys, int batchSize, BatchProcessor processor)
boolean escapeKeys, int batchSize, BatchProcessor processor)
throws SQLException throws SQLException
{ {
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
@@ -186,9 +174,9 @@ public class JDBCUtil
} }
/** /**
* Calls <code>stmt.executeUpdate()</code> on the supplied statement * Calls <code>stmt.executeUpdate()</code> on the supplied statement with the supplied query,
* with the supplied query, checking to see that it returns the * checking to see that it returns the expected update count and logging a warning if it does
* expected update count and logging a warning if it does not. * not.
*/ */
public static void warnedUpdate ( public static void warnedUpdate (
Statement stmt, String query, int expectedCount) Statement stmt, String query, int expectedCount)
@@ -196,15 +184,14 @@ public class JDBCUtil
{ {
int modified = stmt.executeUpdate(query); int modified = stmt.executeUpdate(query);
if (modified != expectedCount) { if (modified != expectedCount) {
Log.warning("Statement did not modify expected number of rows " + Log.warning("Statement did not modify expected number of rows [stmt=" + stmt +
"[stmt=" + stmt + ", expected=" + expectedCount + ", expected=" + expectedCount + ", modified=" + modified + "]");
", modified=" + modified + "]");
} }
} }
/** /**
* Escapes any single quotes in the supplied text and wraps it in * Escapes any single quotes in the supplied text and wraps it in single quotes to make it safe
* single quotes to make it safe for embedding into a database query. * for embedding into a database query.
*/ */
public static String escape (String text) public static String escape (String text)
{ {
@@ -213,8 +200,8 @@ public class JDBCUtil
} }
/** /**
* Escapes a list of values, separating the escaped values by * Escapes a list of values, separating the escaped values by commas. See {@link
* commas. See {@link #escape(String)}. * #escape(String)}.
*/ */
public static String escape (Object[] values) public static String escape (Object[] values)
{ {
@@ -229,13 +216,11 @@ public class JDBCUtil
} }
/** /**
* Many databases simply fail to handle Unicode text properly and this * Many databases simply fail to handle Unicode text properly and this routine provides a
* routine provides a common workaround which is to represent a UTF-8 * common workaround which is to represent a UTF-8 string as an ISO-8895-1 string. If you don't
* string as an ISO-8895-1 string. If you don't need to use the * need to use the database's collation routines, this allows you to do pretty much exactly
* database's collation routines, this allows you to do pretty much * what you want at the expense of having to jigger and dejigger every goddamned string that
* exactly what you want at the expense of having to jigger and * might contain multibyte characters every time you access the database. Three cheers for
* dejigger every goddamned string that might contain multibyte
* characters every time you access the database. Three cheers for
* progress! * progress!
*/ */
public static String jigger (String text) public static String jigger (String text)
@@ -268,8 +253,8 @@ public class JDBCUtil
} }
/** /**
* Utility method to jigger the specified string so that it's safe * Utility method to jigger the specified string so that it's safe to use in a regular
* to use in a regular Statement. * Statement.
*/ */
public static String safeJigger (String text) public static String safeJigger (String text)
{ {
@@ -277,32 +262,33 @@ public class JDBCUtil
} }
/** /**
* Used to programatically create a database table. Does nothing if the * Used to programatically create a database table. Does nothing if the table already exists.
* table already exists. *
* @return true if the table was created, false if it already existed.
*/ */
public static void createTableIfMissing ( public static boolean createTableIfMissing (
Connection conn, String table, String[] definition, String postamble) Connection conn, String table, String[] definition, String postamble)
throws SQLException throws SQLException
{ {
if (tableExists(conn, table)) { if (tableExists(conn, table)) {
return; return true;
} }
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
try { try {
stmt.executeUpdate("create table " + table + "(" + stmt.executeUpdate("create table " + table +
StringUtil.join(definition, ", ") + ") " + "(" + StringUtil.join(definition, ", ") + ") " + postamble);
postamble);
} finally { } finally {
close(stmt); close(stmt);
} }
Log.info("Database table '" + table + "' created."); Log.info("Database table '" + table + "' created.");
return true;
} }
/** /**
* Returns true if the table with the specified name exists, false if * Returns true if the table with the specified name exists, false if it does
* it does not. <em>Note:</em> the table name is case sensitive. * not. <em>Note:</em> the table name is case sensitive.
*/ */
public static boolean tableExists (Connection conn, String name) public static boolean tableExists (Connection conn, String name)
throws SQLException throws SQLException
@@ -319,13 +305,11 @@ public class JDBCUtil
} }
/** /**
* Returns true if the table with the specified name exists and * Returns true if the table with the specified name exists and contains a column with the
* contains a column with the specified name, false if either * specified name, false if either condition does not hold true. <em>Note:</em> the names are
* condition does not hold true. <em>Note:</em> the names are case * case sensitive.
* sensitive.
*/ */
public static boolean tableContainsColumn ( public static boolean tableContainsColumn (Connection conn, String table, String column)
Connection conn, String table, String column)
throws SQLException throws SQLException
{ {
boolean matched = false; boolean matched = false;
@@ -341,24 +325,21 @@ public class JDBCUtil
} }
/** /**
* Returns true if the index on the specified column exists for the * Returns true if the index on the specified column exists for the specified table, false if
* specified table, false if it does not. Optionally you can specifiy * it does not. Optionally you can specifiy a non null index name, and the table will be
* a non null index name, and the table will be checked to see if it * checked to see if it contains that specifically named index. <em>Note:</em> the names are
* contains that specifically named index. <em>Note:</em> the names * case sensitive.
* are case sensitive.
*/ */
public static boolean tableContainsIndex (Connection conn, String table, public static boolean tableContainsIndex (
String column, String index) Connection conn, String table, String column, String index)
throws SQLException throws SQLException
{ {
boolean matched = false; boolean matched = false;
ResultSet rs = conn.getMetaData().getIndexInfo("", "", table, false, ResultSet rs = conn.getMetaData().getIndexInfo("", "", table, false, true);
true);
while (rs.next()) { while (rs.next()) {
String tname = rs.getString("TABLE_NAME"); String tname = rs.getString("TABLE_NAME");
String cname = rs.getString("COLUMN_NAME"); String cname = rs.getString("COLUMN_NAME");
String iname = rs.getString("INDEX_NAME"); String iname = rs.getString("INDEX_NAME");
if (index == null) { if (index == null) {
if (tname.equals(table) && cname.equals(column)) { if (tname.equals(table) && cname.equals(column)) {
matched = true; matched = true;
@@ -371,11 +352,9 @@ public class JDBCUtil
} }
/** /**
* Returns true if the specified table contains a primary key on the * Returns true if the specified table contains a primary key on the specified column.
* specified column.
*/ */
public static boolean tableContainsPrimaryKey (Connection conn, public static boolean tableContainsPrimaryKey (Connection conn, String table, String column)
String table, String column)
throws SQLException throws SQLException
{ {
boolean matched = false; boolean matched = false;
@@ -383,7 +362,6 @@ public class JDBCUtil
while (rs.next()) { while (rs.next()) {
String tname = rs.getString("TABLE_NAME"); String tname = rs.getString("TABLE_NAME");
String cname = rs.getString("COLUMN_NAME"); String cname = rs.getString("COLUMN_NAME");
if (tname.equals(table) && cname.equals(column)) { if (tname.equals(table) && cname.equals(column)) {
matched = true; matched = true;
} }
@@ -392,16 +370,14 @@ public class JDBCUtil
} }
/** /**
* Returns the name of the index for the specified column in the * Returns the name of the index for the specified column in the specified table.
* specified table.
*/ */
public static String getIndexName (Connection conn, String table, public static String getIndexName (Connection conn, String table,
String column) String column)
throws SQLException throws SQLException
{ {
boolean matched = false; boolean matched = false;
ResultSet rs = conn.getMetaData().getIndexInfo("", "", table, false, ResultSet rs = conn.getMetaData().getIndexInfo("", "", table, false, true);
true);
while (rs.next()) { while (rs.next()) {
String tname = rs.getString("TABLE_NAME"); String tname = rs.getString("TABLE_NAME");
String cname = rs.getString("COLUMN_NAME"); String cname = rs.getString("COLUMN_NAME");
@@ -414,8 +390,8 @@ public class JDBCUtil
} }
/** /**
* Returns the type (as specified in {@link java.sql.Types} for the * Returns the type (as specified in {@link java.sql.Types} for the specified column in the
* specified column in the specified table. * specified table.
*/ */
public static int getColumnType (Connection conn, String table, public static int getColumnType (Connection conn, String table,
String column) String column)
@@ -432,8 +408,8 @@ public class JDBCUtil
/** /**
* Determines whether or not the specified column accepts null values. * Determines whether or not the specified column accepts null values.
* *
* @return true if the column accepts null values, false if it does not * @return true if the column accepts null values, false if it does not (or its nullability is
* (or its nullability is unknown) * unknown)
*/ */
public static boolean isColumnNullable (Connection conn, String table, public static boolean isColumnNullable (Connection conn, String table,
String column) String column)
@@ -448,12 +424,11 @@ public class JDBCUtil
} }
/** /**
* Returns the size for the specified column in the specified table. For * Returns the size for the specified column in the specified table. For char or date types
* char or date types this is the maximum number of characters, for numeric * this is the maximum number of characters, for numeric or decimal types this is the
* or decimal types this is the precision. * precision.
*/ */
public static int getColumnSize (Connection conn, String table, public static int getColumnSize (Connection conn, String table, String column)
String column)
throws SQLException throws SQLException
{ {
ResultSet rs = getColumnMetaData(conn, table, column); ResultSet rs = getColumnMetaData(conn, table, column);
@@ -465,28 +440,25 @@ public class JDBCUtil
} }
/** /**
* Adds a column (with name 'cname' and definition 'cdef') to the * Adds a column (with name 'cname' and definition 'cdef') to the specified table.
* specified table.
* *
* @param afterCname (optional) the name of the column after which to * @param afterCname (optional) the name of the column after which to add the new column.
* add the new column. *
* @return true if the column was added, false if it already existed.
*/ */
public static void addColumn (Connection conn, String table, public static boolean addColumn (
String cname, String cdef, String afterCname) Connection conn, String table, String cname, String cdef, String afterCname)
throws SQLException throws SQLException
{ {
if (tableContainsColumn(conn, table, cname)) { if (tableContainsColumn(conn, table, cname)) {
// Log.info("Database table '" + table + "' already has column '" + // Log.info("Database table '" + table + "' already has column '" + cname + "'.");
// cname + "'."); return false;
return;
} }
String update = "ALTER TABLE " + table + " ADD COLUMN " + String update = "ALTER TABLE " + table + " ADD COLUMN " + cname + " " + cdef;
cname + " " + cdef;
if (afterCname != null) { if (afterCname != null) {
update += " AFTER " + afterCname; update += " AFTER " + afterCname;
} }
PreparedStatement stmt = null; PreparedStatement stmt = null;
try { try {
stmt = conn.prepareStatement(update); stmt = conn.prepareStatement(update);
@@ -494,27 +466,21 @@ public class JDBCUtil
} finally { } finally {
close(stmt); close(stmt);
} }
Log.info("Database column '" + cname + "' added to table '" + table + "'.");
Log.info("Database column '" + cname + "' added to table '" + return true;
table + "'.");
} }
/** /**
* Changes a column's definition. Takes a full column definition * Changes a column's definition. Takes a full column definition 'cdef' (including the name of
* 'cdef' (including the name of the column) with which to replace the * the column) with which to replace the specified column 'cname'.
* specified column 'cname'.
* *
* NOTE: A handy thing you can do with this is to rename a column by * NOTE: A handy thing you can do with this is to rename a column by providing a column
* providing a column definition that has a different name, but the * definition that has a different name, but the same column type.
* same column type.
*/ */
public static void changeColumn (Connection conn, String table, public static void changeColumn (Connection conn, String table, String cname, String cdef)
String cname, String cdef)
throws SQLException throws SQLException
{ {
String update = "ALTER TABLE " + table + " CHANGE " + cname + " " + String update = "ALTER TABLE " + table + " CHANGE " + cname + " " + cdef;
cdef;
PreparedStatement stmt = null; PreparedStatement stmt = null;
try { try {
stmt = conn.prepareStatement(update); stmt = conn.prepareStatement(update);
@@ -522,19 +488,20 @@ public class JDBCUtil
} finally { } finally {
close(stmt); close(stmt);
} }
Log.info("Database column '" + cname + "' of table '" + table + Log.info("Database column '" + cname + "' of table '" + table +
"' modified to have this def '" + cdef + "'."); "' modified to have this def '" + cdef + "'.");
} }
/** /**
* Removes a column from the specified table. * Removes a column from the specified table.
*
* @return true if the column was dropped, false if it did not exist in the first place.
*/ */
public static void dropColumn (Connection conn, String table, String cname) public static boolean dropColumn (Connection conn, String table, String cname)
throws SQLException throws SQLException
{ {
if (!tableContainsColumn(conn, table, cname)) { if (!tableContainsColumn(conn, table, cname)) {
return; return false;
} }
String update = "ALTER TABLE " + table + " DROP COLUMN " + cname; String update = "ALTER TABLE " + table + " DROP COLUMN " + cname;
@@ -542,23 +509,24 @@ public class JDBCUtil
try { try {
stmt = conn.prepareStatement(update); stmt = conn.prepareStatement(update);
if (stmt.executeUpdate() == 1) { if (stmt.executeUpdate() == 1) {
Log.info("Database index '" + cname + "' removed from " + Log.info("Database index '" + cname + "' removed from table '" + table + "'.");
"table '" + table + "'.");
} }
} finally { } finally {
close(stmt); close(stmt);
} }
return true;
} }
/** /**
* Removes a named index from the specified table. * Removes a named index from the specified table.
*
* @return true if the index was dropped, false if it did not exist in the first place.
*/ */
public static void dropIndex (Connection conn, String table, public static boolean dropIndex (Connection conn, String table, String cname, String iname)
String cname, String iname)
throws SQLException throws SQLException
{ {
if (!tableContainsIndex(conn, table, cname, iname)) { if (!tableContainsIndex(conn, table, cname, iname)) {
return; return false;
} }
String update = "ALTER TABLE " + table + " DROP INDEX " + iname; String update = "ALTER TABLE " + table + " DROP INDEX " + iname;
@@ -566,12 +534,12 @@ public class JDBCUtil
try { try {
stmt = conn.prepareStatement(update); stmt = conn.prepareStatement(update);
if (stmt.executeUpdate() == 1) { if (stmt.executeUpdate() == 1) {
Log.info("Database index '" + iname + "' removed from " + Log.info("Database index '" + iname + "' removed from table '" + table + "'.");
"table '" + table + "'.");
} }
} finally { } finally {
close(stmt); close(stmt);
} }
return true;
} }
/** /**
@@ -581,7 +549,6 @@ public class JDBCUtil
throws SQLException throws SQLException
{ {
String update = "ALTER TABLE " + table + " DROP PRIMARY KEY"; String update = "ALTER TABLE " + table + " DROP PRIMARY KEY";
PreparedStatement stmt = null; PreparedStatement stmt = null;
try { try {
stmt = conn.prepareStatement(update); stmt = conn.prepareStatement(update);
@@ -594,25 +561,24 @@ public class JDBCUtil
} }
/** /**
* Adds an index on the specified column (cname) to the specified * Adds an index on the specified column (cname) to the specified table. Optionally supply an
* table. Optionally supply an index name, otherwise the index is * index name, otherwise the index is named after the column.
* named after the column. *
* @return true if the index was added, false if it already existed.
*/ */
public static void addIndexToTable (Connection conn, String table, public static boolean addIndexToTable (
String cname, String iname) Connection conn, String table, String cname, String iname)
throws SQLException throws SQLException
{ {
if (tableContainsIndex(conn, table, cname, iname)) { if (tableContainsIndex(conn, table, cname, iname)) {
// Log.info("Database table '" + table + "' already has an index " + // Log.info("Database table '" + table + "' already has an index " +
// "on column '" + cname + "'" + // "on column '" + cname + "'" +
// (iname != null ? " named '" + iname + "'." : ".")); // (iname != null ? " named '" + iname + "'." : "."));
return; return false;
} }
String idx_name = (iname != null ? iname : cname); String idx_name = (iname != null ? iname : cname);
String update = "CREATE INDEX " + idx_name + " on " + table + "(" + String update = "CREATE INDEX " + idx_name + " on " + table + "(" + cname + ")";
cname + ")";
PreparedStatement stmt = null; PreparedStatement stmt = null;
try { try {
stmt = conn.prepareStatement(update); stmt = conn.prepareStatement(update);
@@ -620,16 +586,14 @@ public class JDBCUtil
} finally { } finally {
close(stmt); close(stmt);
} }
Log.info("Database index '" + idx_name + "' added to table '" + table + "'");
Log.info("Database index '" + idx_name + "' added to table '" + return true;
table + "'");
} }
/** /**
* Helper function for {@link #getColumnType}, etc. * Helper function for {@link #getColumnType}, etc.
*/ */
protected static ResultSet getColumnMetaData ( protected static ResultSet getColumnMetaData (Connection conn, String table, String column)
Connection conn, String table, String column)
throws SQLException throws SQLException
{ {
ResultSet rs = conn.getMetaData().getColumns("", "", table, column); ResultSet rs = conn.getMetaData().getColumns("", "", table, column);