From 689ec8c231648729112d575f71ab0d7dc8804266 Mon Sep 17 00:00:00 2001 From: mdb Date: Mon, 15 Jan 2007 01:57:35 +0000 Subject: [PATCH] @Table(uniqueConstraints) support from Zell. git-svn-id: https://samskivert.googlecode.com/svn/trunk@2033 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- .../jdbc/depot/DepotMarshaller.java | 89 +++++++++++++++++-- 1 file changed, 82 insertions(+), 7 deletions(-) diff --git a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java index c948b1ab..1206d890 100644 --- a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java +++ b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java @@ -31,8 +31,12 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.logging.Level; @@ -42,8 +46,10 @@ import com.samskivert.jdbc.depot.annotation.Entity; import com.samskivert.jdbc.depot.annotation.GeneratedValue; import com.samskivert.jdbc.depot.annotation.Id; import com.samskivert.jdbc.depot.annotation.Index; +import com.samskivert.jdbc.depot.annotation.Table; import com.samskivert.jdbc.depot.annotation.TableGenerator; import com.samskivert.jdbc.depot.annotation.Transient; +import com.samskivert.jdbc.depot.annotation.UniqueConstraint; import com.samskivert.jdbc.JDBCUtil; import com.samskivert.jdbc.depot.clause.Where; @@ -71,8 +77,10 @@ public class DepotMarshaller { _pclass = pclass; - // see if this is a computed entity Entity entity = pclass.getAnnotation(Entity.class); + Table table = null; + + // see if this is a computed entity Computed computed = pclass.getAnnotation(Computed.class); if (computed == null) { // if not, this class has a corresponding SQL table @@ -86,6 +94,9 @@ public class DepotMarshaller } _postamble = entity.postamble(); } + + // check for a Table annotation, for unique constraints + table = pclass.getAnnotation(Table.class); } // if the entity defines a new TableGenerator, map that in our static table as those are @@ -221,6 +232,14 @@ public class DepotMarshaller } } + // add any unique constraints given + if (table != null) { + for (UniqueConstraint constraint : table.uniqueConstraints()) { + _declarations.add( + "UNIQUE (" + StringUtil.join(constraint.columnNames(), ", ") + ")"); + } + } + // add the primary key, if we have one if (hasPrimaryKey()) { _declarations.add("PRIMARY KEY (" + getPrimaryKeyColumns() + ")"); @@ -666,8 +685,8 @@ public class DepotMarshaller } // enumerate all of the columns now that we've run our pre-migrations - final HashSet columns = new HashSet(); - final HashSet indices = new HashSet(); + final Set columns = new HashSet(); + final Map> indexColumns = new HashMap>(); ctx.invoke(new Modifier() { public int invoke (Connection conn) throws SQLException { DatabaseMetaData meta = conn.getMetaData(); @@ -675,14 +694,34 @@ public class DepotMarshaller while (rs.next()) { columns.add(rs.getString("COLUMN_NAME")); } + rs = meta.getIndexInfo(null, null, getTableName(), false, false); while (rs.next()) { - indices.add(rs.getString("INDEX_NAME")); + String indexName = rs.getString("INDEX_NAME"); + Set set = indexColumns.get(indexName); + if (rs.getBoolean("NON_UNIQUE")) { + // not a unique index: just make sure there's an entry in the keyset + if (set == null) { + indexColumns.put(indexName, null); + } + + } else { + // for unique indices we collect the column names + if (set == null) { + set = new HashSet(); + indexColumns.put(indexName, set); + } + set.add(rs.getString("COLUMN_NAME")); + } } + return 0; } }); + // this is a little silly, but we need a copy for name disambiguation later + Set indicesCopy = new HashSet(indexColumns.keySet()); + // add any missing columns for (String fname : _columnFields) { FieldMarshaller fmarsh = _fields.get(fname); @@ -717,12 +756,12 @@ public class DepotMarshaller } // add or remove the primary key as needed - if (hasPrimaryKey() && !indices.remove("PRIMARY")) { + if (hasPrimaryKey() && !indexColumns.containsKey("PRIMARY")) { String pkdef = "primary key (" + getPrimaryKeyColumns() + ")"; log.info("Adding primary key to " + getTableName() + ": " + pkdef); ctx.invoke(new Modifier.Simple("alter table " + getTableName() + " add " + pkdef)); - } else if (!hasPrimaryKey() && indices.remove("PRIMARY")) { + } else if (!hasPrimaryKey() && indexColumns.remove("PRIMARY") != null) { log.info("Dropping primary from " + getTableName()); ctx.invoke(new Modifier.Simple("alter table " + getTableName() + " drop primary key")); } @@ -730,7 +769,7 @@ public class DepotMarshaller // add any missing indices Entity entity = _pclass.getAnnotation(Entity.class); for (Index index : (entity == null ? new Index[0] : entity.indices())) { - if (indices.remove(index.name())) { + if (indexColumns.remove(index.name()) != null) { continue; } String indexdef = "create " + index.type() + " index " + index.name() + @@ -739,6 +778,42 @@ public class DepotMarshaller ctx.invoke(new Modifier.Simple(indexdef)); } + // to get the @Table(uniqueIndices...) indices, we use our clever set of column name sets + Set> uniqueIndices = new HashSet>(indexColumns.values()); + Table table; + if (getTableName() != null && (table = _pclass.getAnnotation(Table.class)) != null) { + Set colSet = new HashSet(); + for (UniqueConstraint constraint : table.uniqueConstraints()) { + // for each given UniqueConstraint, build a new column set + colSet.clear(); + for (String column : constraint.columnNames()) { + colSet.add(column); + } + // 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; + } + + String[] columnArr = colSet.toArray(new String[colSet.size()]); + String indexdef = "create unique index " + indexName + " on " + + getTableName() + " (" + StringUtil.join(columnArr, ", ") + ")"; + log.info("Adding unique index: " + indexdef); + ctx.invoke(new Modifier.Simple(indexdef)); + } + } + // we do not auto-remove columns but rather require that EntityMigration.Drop records be // registered by hand to avoid accidentally causin the loss of data