From f9b64142702dc4f75d2bc9aa90540fc53f09a209 Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Wed, 8 Aug 2007 23:58:43 +0000 Subject: [PATCH] Patch from Zell to properly walk the inheritance tree and aggregate all index-related annotations. --- .../jdbc/depot/DepotMarshaller.java | 163 ++++++++++-------- 1 file changed, 93 insertions(+), 70 deletions(-) diff --git a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java index d332dc9..c066c44 100644 --- a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java +++ b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java @@ -31,7 +31,6 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -489,13 +488,18 @@ public class DepotMarshaller fm.init(builder); } + // if we have no table (i.e. we're a computed entity), we have nothing to create + if (getTableName() == null) { + return; + } + // figure out the list of fields that correspond to actual table columns and generate the // SQL used to create and migrate our table (unless we're a computed entity) _columnFields = new String[_allFields.length]; String[] declarations = new String[_allFields.length]; int jj = 0; for (int ii = 0; ii < _allFields.length; ii++) { - @SuppressWarnings("unchecked") FieldMarshaller fm = _fields.get(_allFields[ii]); + FieldMarshaller fm = _fields.get(_allFields[ii]); // include all persistent non-computed fields String colDef = fm.getColumnDefinition(); if (colDef != null) { @@ -507,31 +511,6 @@ public class DepotMarshaller _columnFields = ArrayUtil.splice(_columnFields, jj); declarations = ArrayUtil.splice(declarations, jj); - // if we have no table (i.e. we're a computed entity), we have nothing to create - if (getTableName() == null) { - return; - } - - // add any additional unique constraints - String[][] uniqueConstraintColumns = null; - Table table = _pclass.getAnnotation(Table.class); - if (table != null) { - UniqueConstraint[] uCons = table.uniqueConstraints(); - uniqueConstraintColumns = new String[uCons.length][]; - for (int kk = 0; kk < uCons.length; kk ++) { - String[] columns = uCons[kk].fieldNames(); - for (int ii = 0; ii < columns.length; ii ++) { - FieldMarshaller fm = getFieldMarshaller(columns[ii]); - if (fm == null) { - throw new IllegalArgumentException( - "Unknown field in @UniqueConstraint: " + columns[ii]); - } - columns[ii] = fm.getColumnName(); - } - uniqueConstraintColumns[kk] = columns; - } - } - // if we did not find a schema version field, complain if (_schemaVersion < 0) { log.warning("Unable to read " + _pclass.getName() + "." + SCHEMA_VERSION_FIELD + @@ -558,13 +537,12 @@ public class DepotMarshaller } }); - final Entity entity = _pclass.getAnnotation(Entity.class); + // compute relevant information from our persistent record, too + final RecordMetaData rMeta = new RecordMetaData(_pclass, _fields); // if the table does not exist, create it if (!metaData.tableExists) { final String[] fDeclarations = declarations; - final String[][] fUniqueConstraintColumns = uniqueConstraintColumns; - ctx.invoke(new Modifier() { public int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { // create the table @@ -579,15 +557,19 @@ public class DepotMarshaller primaryKeyColumns[ii] = _pkColumns.get(ii).getColumnName(); } } + String[][] uniqueConCols = new String[rMeta.uniqueConstraints.size()][]; + int kk = 0; + for (Set colSet : rMeta.uniqueConstraints) { + uniqueConCols[kk++] = colSet.toArray(new String[colSet.size()]); + } liaison.createTableIfMissing(conn, getTableName(), columns, fDeclarations, - fUniqueConstraintColumns, primaryKeyColumns); + uniqueConCols, primaryKeyColumns); // add its indexen - if (entity != null) { - for (Index idx : entity.indices()) { - liaison.addIndexToTable( - conn, getTableName(), idx.columns(), idx.name(), idx.unique()); - } + for (Index idx : rMeta.indices.values()) { + liaison.addIndexToTable( + conn, getTableName(), idx.columns(), + getTableName() + "_" + idx.name(), idx.unique()); } if (_keyGenerator != null) { _keyGenerator.init(conn, liaison); @@ -708,15 +690,16 @@ public class DepotMarshaller } // add any missing indices - for (final Index index : (entity == null ? new Index[0] : entity.indices())) { - if (metaData.indexColumns.containsKey(index.name())) { - metaData.indexColumns.remove(index.name()); + for (final Index index : rMeta.indices.values()) { + final String ixName = getTableName() + "_" + index.name(); + if (metaData.indexColumns.containsKey(ixName)) { + metaData.indexColumns.remove(ixName); continue; } ctx.invoke(new Modifier() { public int invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { liaison.addIndexToTable( - conn, getTableName(), index.columns(), index.name(), index.unique()); + conn, getTableName(), index.columns(), ixName, index.unique()); return 0; } }); @@ -725,37 +708,32 @@ public class DepotMarshaller // to get the @Table(uniqueIndices...) indices, we use our clever set of column name sets Set> uniqueIndices = new HashSet>(metaData.indexColumns.values()); - if (getTableName() != null && table != null) { - for (UniqueConstraint constraint : table.uniqueConstraints()) { - // for each given UniqueConstraint, build a new column set - Set colSet = new HashSet(Arrays.asList(constraint.fieldNames())); - - // and check if the table contained this set - if (uniqueIndices.contains(colSet)) { - continue; // good, carry on - } - - // else build the index; we'll use mysql's convention of naming it after a column, - // with possible _N disambiguation; luckily we made a copy of the index names! - String indexName = colSet.iterator().next(); - if (indicesCopy.contains(indexName)) { - int num = 1; - indexName += "_"; - while (indicesCopy.contains(indexName + num)) { - num ++; - } - indexName += num; - } - - final String[] colArr = colSet.toArray(new String[colSet.size()]); - final String fName = indexName; - ctx.invoke(new Modifier() { - public int invoke (Connection conn, DatabaseLiaison dl) throws SQLException { - dl.addIndexToTable(conn, getTableName(), colArr, fName, true); - return 0; - } - }); + for (Set colSet : rMeta.uniqueConstraints) { + // check if the table contained this set + if (uniqueIndices.contains(colSet)) { + continue; // good, carry on } + + // else build the index; we'll use mysql's convention of naming it after a column, + // with possible _N disambiguation; luckily we made a copy of the index names! + String indexName = colSet.iterator().next(); + if (indicesCopy.contains(indexName)) { + int num = 1; + indexName += "_"; + while (indicesCopy.contains(indexName + num)) { + num ++; + } + indexName += num; + } + + final String[] colArr = colSet.toArray(new String[colSet.size()]); + final String fName = indexName; + ctx.invoke(new Modifier() { + public int invoke (Connection conn, DatabaseLiaison dl) throws SQLException { + dl.addIndexToTable(conn, getTableName(), colArr, fName, true); + return 0; + } + }); } // we do not auto-remove columns but rather require that EntityMigration.Drop records be @@ -867,6 +845,51 @@ public class DepotMarshaller } } + protected static class RecordMetaData + { + public Map indices = new HashMap(); + public Set> uniqueConstraints = new HashSet>(); + + public RecordMetaData (Class pClass, Map fmap) + { + recurse(pClass, fmap); + } + + protected void recurse (Class pClass, Map fmap) + { + // recurse first so subclass definitions overwrite superclass ones + Class superClass = pClass.getSuperclass(); + if (PersistentRecord.class.isAssignableFrom(superClass) && + !PersistentRecord.class.equals(superClass)) { + recurse(superClass, fmap); + } + + Table table = pClass.getAnnotation(Table.class); + if (table != null) { + for (UniqueConstraint constraint : table.uniqueConstraints()) { + String[] fields = constraint.fieldNames(); + Set colSet = new HashSet(); + for (int ii = 0; ii < fields.length; ii ++) { + FieldMarshaller fm = fmap.get(fields[ii]); + if (fm == null) { + throw new IllegalArgumentException( + "Unknown unique constraint field: " + fields[ii]); + } + colSet.add(fm.getColumnName()); + } + uniqueConstraints.add(colSet); + } + } + + Entity entity = pClass.getAnnotation(Entity.class); + if (entity != null) { + for (Index index : entity.indices()) { + indices.put(index.name(), index); + } + } + } + } + /** The persistent object class that we manage. */ protected Class _pclass;