OPENJPA-340: Let DBDictionary generate Unique Constraint names rather than Unique trying to auto-generate such names in lesser scope. Strengthen the tests to have exactly same named unique columns in two classes to verify that the unique constraint names are unique across tables.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@713778 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Pinaki Poddar 2008-11-13 18:33:07 +00:00
parent 25c31398f1
commit 9d40841d48
6 changed files with 76 additions and 126 deletions

View File

@ -18,8 +18,6 @@
*/ */
package org.apache.openjpa.jdbc.schema; package org.apache.openjpa.jdbc.schema;
import org.apache.commons.lang.StringUtils;
/** /**
* Represents a unique constraint. It can also represent a partial constraint. * Represents a unique constraint. It can also represent a partial constraint.
* *
@ -28,28 +26,19 @@ import org.apache.commons.lang.StringUtils;
*/ */
public class Unique public class Unique
extends LocalConstraint { extends LocalConstraint {
private boolean _autoNaming = false;
private static int _counter = 1; public Unique() {
super();
}
/**
* Default constructor without a name.
* Implies that this constraint will auto-generate its name from the names
* of its columns, unless later the name is set explicitly.
*/
public Unique() {
_autoNaming = true;
}
/** /**
* Construct with given name. * Construct with given name.
* Implies that this constraint will not auto-generate its name.
* *
* @param name the name of the constraint, if any * @param name the name of the constraint, if any
* @param table the table of the constraint * @param table the table of the constraint
*/ */
public Unique(String name, Table table) { public Unique(String name, Table table) {
super(name, table); super(name, table);
_autoNaming = false;
} }
public boolean isLogical() { public boolean isLogical() {
@ -69,28 +58,12 @@ public class Unique
/** /**
* Set the name of the constraint. This method cannot be called if the * Set the name of the constraint. This method cannot be called if the
* constraint already belongs to a table. Calling this method also has the * constraint already belongs to a table.
* side-effect of implying that the instance will not auto-generate its
* name.
*/ */
public void setName(String name) { public void setName(String name) {
super.setName(name); super.setName(name);
_autoNaming = false;
} }
/**
* Gets the name of the constraint. If no name has been set by the user
* then this method has the side-effect of auto-generating a name from
* the name of its columns.
*/
public String getName() {
if (getTable() == null && _autoNaming) {
setName(createAutoName());
_autoNaming = true;
}
return super.getName();
}
/** /**
* Return true if the structure of this primary key matches that of * Return true if the structure of this primary key matches that of
* the given one (same table, same columns). * the given one (same table, same columns).
@ -98,30 +71,4 @@ public class Unique
public boolean equalsUnique(Unique unq) { public boolean equalsUnique(Unique unq) {
return equalsLocalConstraint(unq); return equalsLocalConstraint(unq);
} }
/*
* Affirms if this instance is currently generating its own name. No
* mutator because auto-naming is switched off as side-effect of user
* calling setName() directly.
*/
public boolean isAutoNaming() {
return _autoNaming;
}
private String createAutoName() {
Column[] columns = getColumns();
int l = 32/Math.max(columns.length,1);
StringBuffer autoName = new StringBuffer("UNQ_");
if (columns.length == 0)
autoName.append(_counter++);
for (Column column : columns)
autoName.append(chop(column.getName(),l));
return autoName.toString();
}
private String chop(String name, int head) {
if (StringUtils.isEmpty(name))
return name;
return name.substring(0, Math.min(Math.max(1,head), name.length()));
}
} }

View File

@ -53,20 +53,20 @@ public class TestUniqueConstraint extends SQLListenerTestCase {
List<String> sqls = super.sql; List<String> sqls = super.sql;
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_A", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_A",
"UNIQUE .*\\(a1, a2\\)", "UNIQUE .*\\(f1, f2\\)",
"UNIQUE .*\\(a3, a4\\).*"); "UNIQUE .*\\(f3, f4\\).*");
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_B", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_B",
"UNIQUE .*\\(b1, b2\\).*"); "UNIQUE .*\\(f1, f2\\).*");
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_SECONDARY", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_SECONDARY",
"UNIQUE .*\\(sa1\\)"); "UNIQUE .*\\(sf1\\)");
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_GENERATOR", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_GENERATOR",
"UNIQUE .*\\(GEN1, GEN2\\)"); "UNIQUE .*\\(GEN1, GEN2\\)");
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_JOINTABLE", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_JOINTABLE",
"UNIQUE .*\\(FK_A, FK_B\\)"); "UNIQUE .*\\(FK_A, FK_B\\)");
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_A", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_A",
"UNIQUE .*\\(SAME\\)"); "UNIQUE .*\\(f1\\)");
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_B", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_B",
"UNIQUE .*\\(SAME\\)"); "UNIQUE .*\\(f1\\)");
} }
void assertSQLFragnments(List<String> list, String... keys) { void assertSQLFragnments(List<String> list, String... keys) {

View File

@ -60,12 +60,12 @@ public class TestUniqueConstraintWithXMLDescriptor extends SQLListenerTestCase {
// Following verification techniques is fragile as databases DDL // Following verification techniques is fragile as databases DDL
// syntax vary greatly on UNIQUE CONSTRAINT // syntax vary greatly on UNIQUE CONSTRAINT
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_A_XML", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_A_XML",
"UNIQUE .*\\(a1x, a2x\\)", "UNIQUE .*\\(f1x, f2x\\)",
"UNIQUE .*\\(a3x, a4x\\)"); "UNIQUE .*\\(f3x, f4x\\)");
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_B_XML", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_B_XML",
"UNIQUE .*\\(b1x, b2x\\)"); "UNIQUE .*\\(f1x, f2x\\)");
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_SECONDARY_XML", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_SECONDARY_XML",
"UNIQUE .*\\(sa1x\\)"); "UNIQUE .*\\(sf1x\\)");
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_GENERATOR_XML", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_GENERATOR_XML",
"UNIQUE .*\\(GEN1_XML, GEN2_XML\\)"); "UNIQUE .*\\(GEN1_XML, GEN2_XML\\)");
assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_JOINTABLE_XML", assertSQLFragnments(sqls, "CREATE TABLE UNIQUE_JOINTABLE_XML",

View File

@ -31,52 +31,61 @@ import javax.persistence.Table;
import javax.persistence.UniqueConstraint; import javax.persistence.UniqueConstraint;
/** /**
* Data structures for testing unique constraint settings * Data structures for testing unique constraint settings on ORM Annotations.
* on ORM Annotations. * @UniqueConstraint annotation is declared at class-level with
* @UniqueConstraint annotation is declared at class-level with @Table, * @Table,
* @SecondaryTable annotations and at field-level with @JoinTable annotation. * @SecondaryTable annotations
* and at field-level with
* @JoinTable annotation.
* also with
* @Column(unique=true) on single column.
* *
* The columns included in unique constraint must be non-nullable. This is * The columns included in unique constraint must be non-nullable. This is
* recommended that the non-nullability of the column is explictly set by the * recommended that the non-nullability of the column is explictly set by the
* user, though the implementation forces a column to non-nullable as a column * user, though the implementation forces a column to non-nullable as a column
* is included in a unique constraint. * is included in a unique constraint.
* *
* The name of the constraint is generated by the implementation as JPA ORM
* specification has not allowed to specify a name for the constraint via the
* annotation or XML descriptor. Some databases allow two constraints having the
* same name but applied to different tables, while some other databases do not.
*
*
* @author Pinaki Poddar * @author Pinaki Poddar
* *
*/ */
@Entity @Entity
@Table(name="UNIQUE_A", @Table(name="UNIQUE_A",
uniqueConstraints={@UniqueConstraint(columnNames={"a1","a2"}), uniqueConstraints={@UniqueConstraint(columnNames={"f1","f2"}),
@UniqueConstraint(columnNames={"a3","a4"})}) @UniqueConstraint(columnNames={"f3","f4"})})
@SecondaryTable(name="UNIQUE_SECONDARY", @SecondaryTable(name="UNIQUE_SECONDARY",
uniqueConstraints=@UniqueConstraint(columnNames={"sa1"})) uniqueConstraints=@UniqueConstraint(columnNames={"sf1"}))
public class UniqueA { public class UniqueA {
@Id @Id
private int aid; private int aid;
// Same named field in UniqueB also is defined as unique
@Column(unique=true, nullable=false) @Column(unique=true, nullable=false)
private int a1; private int f1;
@Column(nullable=false) @Column(nullable=false)
private int a2; private int f2;
@Column(nullable=false) @Column(nullable=false)
private int a3; private int f3;
@Column(nullable=false) @Column(nullable=false)
private int a4; private int f4;
@Column(name="SAME", unique=true) private int f5;
private int same; private int f6;
private int a5;
private int a6;
@Column(table="UNIQUE_SECONDARY", nullable=false) @Column(table="UNIQUE_SECONDARY", nullable=false)
private short sa1; private short sf1;
@Column(table="UNIQUE_SECONDARY") @Column(table="UNIQUE_SECONDARY")
private short sa2; private short sf2;
@ManyToMany @ManyToMany
@JoinTable(name="UNIQUE_JOINTABLE", @JoinTable(name="UNIQUE_JOINTABLE",

View File

@ -22,7 +22,7 @@ import javax.persistence.*;
@Entity @Entity
@Table(name="UNIQUE_B", @Table(name="UNIQUE_B",
uniqueConstraints={@UniqueConstraint(columnNames={"b1","b2"})}) uniqueConstraints={@UniqueConstraint(columnNames={"f1","f2"})})
public class UniqueB { public class UniqueB {
@Id @Id
@GeneratedValue(strategy=GenerationType.TABLE, generator="testGenerator") @GeneratedValue(strategy=GenerationType.TABLE, generator="testGenerator")
@ -31,10 +31,10 @@ public class UniqueB {
uniqueConstraints={@UniqueConstraint(columnNames={"GEN1","GEN2"})}) uniqueConstraints={@UniqueConstraint(columnNames={"GEN1","GEN2"})})
private int bid; private int bid;
// Same named field in UniqueA also is defined as unique
@Column(unique=true, nullable=false)
private int f1;
@Column(nullable=false) @Column(nullable=false)
private int b1; private int f2;
@Column(nullable=false)
private int b2;
@Column(name="SAME", unique=true)
private int same;
} }

View File

@ -19,7 +19,7 @@
--> -->
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_1_0.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence orm_1_0.xsd"
version="1.0"> version="1.0">
<persistence-unit-metadata> <persistence-unit-metadata>
@ -31,48 +31,45 @@
<entity name="UniqueA" class="UniqueA"> <entity name="UniqueA" class="UniqueA">
<table name="UNIQUE_A_XML"> <table name="UNIQUE_A_XML">
<unique-constraint> <unique-constraint>
<column-name>a1x</column-name> <column-name>f1x</column-name>
<column-name>a2x</column-name> <column-name>f2x</column-name>
</unique-constraint> </unique-constraint>
<unique-constraint> <unique-constraint>
<column-name>a3x</column-name> <column-name>f3x</column-name>
<column-name>a4x</column-name> <column-name>f4x</column-name>
</unique-constraint> </unique-constraint>
</table> </table>
<secondary-table name="UNIQUE_SECONDARY_XML"> <secondary-table name="UNIQUE_SECONDARY_XML">
<unique-constraint> <unique-constraint>
<column-name>sa1x</column-name> <column-name>sf1x</column-name>
</unique-constraint> </unique-constraint>
</secondary-table> </secondary-table>
<attributes> <attributes>
<id name="aid"> <id name="aid">
</id> </id>
<basic name="a1"> <basic name="f1">
<column name="a1x"/> <column name="f1x" unique="true"/>
</basic> </basic>
<basic name="a2"> <basic name="f2">
<column name="a2x"/> <column name="f2x"/>
</basic> </basic>
<basic name="a3"> <basic name="f3">
<column name="a3x"/> <column name="f3x"/>
</basic> </basic>
<basic name="a4"> <basic name="f4">
<column name="a4x"/> <column name="f4x"/>
</basic> </basic>
<basic name="a5"> <basic name="f5">
<column name="a5x"/> <column name="f5x"/>
</basic> </basic>
<basic name="a6"> <basic name="f6">
<column name="a6x"/> <column name="f6x"/>
</basic> </basic>
<basic name="same"> <basic name="sf1">
<column name="SAME" unique="true"/> <column name="sf1x" table="UNIQUE_SECONDARY_XML" />
</basic> </basic>
<basic name="sa1"> <basic name="sf2">
<column name="sa1x" table="UNIQUE_SECONDARY_XML" /> <column name="sf2x" table="UNIQUE_SECONDARY_XML" />
</basic>
<basic name="sa2">
<column name="sa2x" table="UNIQUE_SECONDARY_XML" />
</basic> </basic>
<many-to-many name="bs"> <many-to-many name="bs">
@ -91,8 +88,8 @@
<entity name="UniqueB" class="UniqueB"> <entity name="UniqueB" class="UniqueB">
<table name="UNIQUE_B_XML"> <table name="UNIQUE_B_XML">
<unique-constraint> <unique-constraint>
<column-name>b1x</column-name> <column-name>f1x</column-name>
<column-name>b2x</column-name> <column-name>f2x</column-name>
</unique-constraint> </unique-constraint>
</table> </table>
<attributes> <attributes>
@ -108,15 +105,12 @@
</unique-constraint> </unique-constraint>
</table-generator> </table-generator>
</id> </id>
<basic name="b1"> <basic name="f1">
<column name="b1x"/> <column name="f1x" unique="true"/>
</basic> </basic>
<basic name="b2"> <basic name="f2">
<column name="b2x"/> <column name="f2x"/>
</basic> </basic>
<basic name="same">
<column name="SAME" unique="true"/>
</basic>
</attributes> </attributes>
</entity> </entity>
</entity-mappings> </entity-mappings>