diff --git a/src/main/java/com/samskivert/depot/impl/DepotMarshaller.java b/src/main/java/com/samskivert/depot/impl/DepotMarshaller.java index 1fceafb..b700b90 100644 --- a/src/main/java/com/samskivert/depot/impl/DepotMarshaller.java +++ b/src/main/java/com/samskivert/depot/impl/DepotMarshaller.java @@ -133,7 +133,7 @@ public class DepotMarshaller implements QueryMarshal try { _schemaVersion = (Integer)field.get(null); } catch (Exception e) { - log.warning("Failed to read schema version [class=" + _pClass + "].", e); + log.warning("Failed to read schema version", "class", pClass, e); } } @@ -545,9 +545,10 @@ public class DepotMarshaller implements QueryMarshal // now check whether we need to migrate our database schema while (true) { if (currentVersion >= _schemaVersion) { - // TODO: we used to check for staleness here, but that's slow; currently we do it - // only after migration, we should reinstate a check maybe the first time a table - // is read or something so that developers are more likely to get the warning + // no migrations to do, but maybe we should do an explicit staleness check + if (Boolean.getBoolean("com.samskivert.depot.verifyschema")) { + checkForStaleness(TableMetaData.load(ctx, getTableName()), ctx, builder); + } return; } @@ -1003,11 +1004,22 @@ public class DepotMarshaller implements QueryMarshal meta.tableColumns.remove(fmarsh.getColumnName()); } for (String column : meta.tableColumns) { - if (builder.isPrivateColumn(column)) { + if (builder.isPrivateColumn(column, _fullTextIndexes)) { continue; } - log.warning(getTableName() + " contains stale column '" + column + "'."); + log.warning("Stale column", "table", getTableName(), "column", column); } + + for (CreateIndexClause clause : _indexes) { + meta.indexColumns.remove(clause.getName()); + } + for (String index : meta.indexColumns.keySet()) { + if (builder.isPrivateIndex(index, _fullTextIndexes)) { + continue; + } + log.warning("Stale index", "table", getTableName(), "index", index); + } + } protected void checkHasPrimaryKey () diff --git a/src/main/java/com/samskivert/depot/impl/HSQLBuilder.java b/src/main/java/com/samskivert/depot/impl/HSQLBuilder.java index c740fd6..1d6a4a0 100644 --- a/src/main/java/com/samskivert/depot/impl/HSQLBuilder.java +++ b/src/main/java/com/samskivert/depot/impl/HSQLBuilder.java @@ -24,6 +24,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.List; +import java.util.Map; import java.util.Set; import com.google.common.collect.Lists; @@ -223,12 +224,19 @@ public class HSQLBuilder } @Override - public boolean isPrivateColumn (String column) + public boolean isPrivateColumn (String column, Map fullTextIndexes) { // The HSQLDB builder does not yet have any private columns. return false; } + @Override + public boolean isPrivateIndex (String index, Map fullTextIndexes) + { + // The HSQLDB builder does not yet have any private indexes; + return false; + } + @Override protected String getBooleanDefault () { diff --git a/src/main/java/com/samskivert/depot/impl/MySQLBuilder.java b/src/main/java/com/samskivert/depot/impl/MySQLBuilder.java index cf89169..3b3820b 100644 --- a/src/main/java/com/samskivert/depot/impl/MySQLBuilder.java +++ b/src/main/java/com/samskivert/depot/impl/MySQLBuilder.java @@ -22,6 +22,8 @@ package com.samskivert.depot.impl; import java.sql.Connection; import java.sql.SQLException; + +import java.util.Map; import java.util.Set; import com.samskivert.depot.PersistentRecord; @@ -208,12 +210,19 @@ public class MySQLBuilder } @Override - public boolean isPrivateColumn (String column) + public boolean isPrivateColumn (String column, Map fullTextIndexes) { // The MySQL builder does not yet have any private columns. return false; } + @Override + public boolean isPrivateIndex (String index, Map fullTextIndexes) + { + // The MySQL builder does not yet have any private indexes. + return false; + } + @Override protected String getBooleanDefault () { diff --git a/src/main/java/com/samskivert/depot/impl/PostgreSQLBuilder.java b/src/main/java/com/samskivert/depot/impl/PostgreSQLBuilder.java index 73340f5..3e6ce94 100644 --- a/src/main/java/com/samskivert/depot/impl/PostgreSQLBuilder.java +++ b/src/main/java/com/samskivert/depot/impl/PostgreSQLBuilder.java @@ -23,6 +23,8 @@ package com.samskivert.depot.impl; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; + +import java.util.Map; import java.util.Set; import com.samskivert.jdbc.DatabaseLiaison; @@ -243,10 +245,32 @@ public class PostgreSQLBuilder } @Override - public boolean isPrivateColumn (String column) + public boolean isPrivateColumn (String column, Map fullTextIndexes) { // filter out any column that we created as part of FTS support - return column.startsWith("ftsCol_"); + for (FullTextIndex fti : fullTextIndexes.values()) { + if (("ftsCol_" + fti.name()).equals(column)) { + return true; + } + } + return false; + } + + @Override + public boolean isPrivateIndex (String index, Map fullTextIndexes) + { + // filter out any index that looks like PostgreSQL created it + if (index.endsWith("_key") || index.endsWith("_pkey")) { + return true; + } + + // filter out any index that we created as part of FTS support + for (FullTextIndex fti : fullTextIndexes.values()) { + if (index.endsWith("_ftsIx_" + fti.name())) { + return true; + } + } + return false; } @Override diff --git a/src/main/java/com/samskivert/depot/impl/SQLBuilder.java b/src/main/java/com/samskivert/depot/impl/SQLBuilder.java index 97ae30a..a0d86f8 100644 --- a/src/main/java/com/samskivert/depot/impl/SQLBuilder.java +++ b/src/main/java/com/samskivert/depot/impl/SQLBuilder.java @@ -21,6 +21,8 @@ package com.samskivert.depot.impl; import java.lang.reflect.Field; + +import java.util.Map; import java.util.Set; import java.sql.Connection; @@ -203,7 +205,16 @@ public abstract class SQLBuilder * e.g. PostgreSQL's full text search data is stored in a table column that should otherwise * not be visible to Depot; this method helps mask it. */ - public abstract boolean isPrivateColumn (String column); + public abstract boolean isPrivateColumn ( + String column, Map fullTextIndexes); + + /** + * Return true if the supplied index is an internal consideration of this {@link SQLBuilder}, + * e.g. PostgreSQL automatically creates indexes that end in _key for unique columns, and its + * primary keys have indices ending in _pkey. + */ + public abstract boolean isPrivateIndex ( + String index, Map fullTextIndexes); /** * Figure out what full text search indexes already exist on this table and add the names of