You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by ht...@apache.org on 2012/08/14 16:56:09 UTC

svn commit: r1372913 - in /openjpa/branches/2.0.x: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/

Author: hthomann
Date: Tue Aug 14 14:56:09 2012
New Revision: 1372913

URL: http://svn.apache.org/viewvc?rev=1372913&view=rev
Log:
OPENJPA-1682: Backported to 2.0.x this JIRA and revision 941362 from OPENJPA-1387 since the two issues are related/coupled.

Modified:
    openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java
    openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ForeignKey.java
    openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LocalConstraint.java
    openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Unique.java
    openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
    openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java
    openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java
    openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/NullValues.java
    openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/TestBasicFieldNullity.java

Modified: openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java?rev=1372913&r1=1372912&r2=1372913&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java (original)
+++ openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Column.java Tue Aug 14 14:56:09 2012
@@ -25,6 +25,8 @@ import java.sql.Date;
 import java.sql.Time;
 import java.sql.Timestamp;
 import java.sql.Types;
+import java.util.HashSet;
+import java.util.Set;
 
 import org.apache.commons.lang.StringUtils;
 import org.apache.openjpa.jdbc.identifier.DBIdentifier;
@@ -78,11 +80,15 @@ public class Column
     private String _comment = null;
     private boolean _XML = false;
     private boolean _isUni1MFK = false;
+    private Set<Constraint> _constraints = new HashSet<Constraint>();
     
     /**
      * Default constructor.
      */
     public Column() {
+        for (Constraint c : _constraints) {
+            addConstraint(c);
+        }
     }
 
     /**
@@ -886,4 +892,66 @@ public class Column
     public void setUni1MFK(boolean isUni1MFK) {
         _isUni1MFK = isUni1MFK;
     }
+
+    /**
+     * Adds the given constraint to this column.
+     */
+    public void addConstraint(Constraint c) {
+        _constraints.add(c);
+    }
+    
+    /**
+     * Removes the given constraint from this column.
+     */
+    public void removeConstraint(Constraint c) {
+        _constraints.remove(c);
+    }
+    
+    /**
+     * Affirms if this column has any constraint of given type.
+     */
+    public boolean hasConstraint(Class<? extends Constraint> type) {
+        return !getConstraints(type).isEmpty();
+    }
+    
+    /**
+     * Gets all constrains attached this column.
+     */
+    public Set<Constraint> getConstraints() {
+        return _constraints;
+    }
+    
+    /**
+     * Gets all constrains of the given type attached to this column.
+     */
+    public <T extends Constraint> Set<T> getConstraints(Class<T> type) {
+        Set<T> result = new HashSet<T>();
+        for (Constraint c : _constraints) {
+            if (c.getClass() == type) {
+                result.add((T)c);
+            }
+        }
+        return result;
+    }
+    
+    /**
+     * Affirms if any unique constraint is attached to this column.
+     */
+    public boolean isUniqueConstraint() {
+        return hasConstraint(Unique.class);
+    }
+    
+    /**
+     * Affirms if any index constraint is attached to this column.
+     */
+    public boolean isIndex() {
+        return hasConstraint(Index.class);
+    }
+    
+    /**
+     * Affirms if any foreign key constraint is attached to this column.
+     */
+    public boolean isForeignKey() {
+        return hasConstraint(ForeignKey.class);
+    }    
 }

Modified: openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ForeignKey.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ForeignKey.java?rev=1372913&r1=1372912&r2=1372913&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ForeignKey.java (original)
+++ openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ForeignKey.java Tue Aug 14 14:56:09 2012
@@ -573,6 +573,7 @@ public class ForeignKey
         if (_joins == null)
             _joins = new LinkedHashMap();
         _joins.put(local, toPK);
+        local.addConstraint(this);
         if (_joinsPK == null)
             _joinsPK = new LinkedHashMap();
         _joinsPK.put(toPK, local);
@@ -629,6 +630,7 @@ public class ForeignKey
 
         if (_joins != null) {
             rem = _joins.remove(col);
+            col.removeConstraint(this);
             if (rem != null) {
                 _locals = null;
                 _pks = null;

Modified: openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LocalConstraint.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LocalConstraint.java?rev=1372913&r1=1372912&r2=1372913&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LocalConstraint.java (original)
+++ openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LocalConstraint.java Tue Aug 14 14:56:09 2012
@@ -67,6 +67,9 @@ public abstract class LocalConstraint
      */
     void remove() {
         // remove all columns
+        for (Column c : _cols) {
+            c.removeConstraint(this);
+        }
         setColumns(null);
         super.remove();
     }
@@ -110,6 +113,7 @@ public abstract class LocalConstraint
 
         _colList.add(col);
         _cols = null;
+        col.addConstraint(this);
     }
 
     /**
@@ -123,6 +127,7 @@ public abstract class LocalConstraint
             return false;
         if (_colList.remove(col)) {
             _cols = null;
+            col.removeConstraint(this);
             return true;
         }
         return false;

Modified: openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Unique.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Unique.java?rev=1372913&r1=1372912&r2=1372913&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Unique.java (original)
+++ openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Unique.java Tue Aug 14 14:56:09 2012
@@ -54,17 +54,6 @@ public class Unique
     }
     
     /**
-     * Adds the given column. 
-     * The added column is set to non-nullable because a unique constraint
-     * on the database requires that its constituent columns are NOT NULL. 
-     * @see Column#setNotNull(boolean)
-     */
-    public void addColumn(Column col) {
-    	super.addColumn(col);
-    	col.setNotNull(true);
-    }
-    
-    /**
      * Set the name of the constraint. This method cannot be called if the
      * constraint already belongs to a table. 
      * @deprecated

Modified: openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java?rev=1372913&r1=1372912&r2=1372913&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java (original)
+++ openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java Tue Aug 14 14:56:09 2012
@@ -128,6 +128,7 @@ public class DB2Dictionary
         supportsDefaultDeleteAction = false;
         supportsAlterTableWithDropColumn = false;
         supportsLockingWithOrderClause = true;
+        supportsNullUniqueColumn = false;
 
         supportsNullTableForGetColumns = false;
         requiresCastForMathFunctions = true;

Modified: openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=1372913&r1=1372912&r2=1372913&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java (original)
+++ openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java Tue Aug 14 14:56:09 2012
@@ -196,6 +196,7 @@ public class DBDictionary
     public boolean supportsRestrictDeleteAction = true;
     public boolean supportsCascadeDeleteAction = true;
     public boolean supportsNullDeleteAction = true;
+    public boolean supportsNullUniqueColumn = true;
     public boolean supportsDefaultDeleteAction = true;
     public boolean supportsRestrictUpdateAction = true;
     public boolean supportsCascadeUpdateAction = true;
@@ -1303,8 +1304,12 @@ public class DBDictionary
                 if (col != null && (col.getType() == Types.CLOB
                     || col.getType() == Types.LONGVARCHAR))
                     setClobString(stmnt, idx, (String) val, col);
-                else
-                    setString(stmnt, idx, (String) val, col);
+                else {
+                    if (val instanceof String)
+                        setString(stmnt, idx, (String) val, col);
+                    else
+                        setString(stmnt, idx, val.toString(), col);
+                }
                 break;
             case JavaTypes.OBJECT:
                 setBlobObject(stmnt, idx, val, col, store);
@@ -3589,7 +3594,7 @@ public class DBDictionary
         if (!alter) {
             if (col.getDefaultString() != null && !col.isAutoAssigned())
                 buf.append(" DEFAULT ").append(col.getDefaultString());
-            if (col.isNotNull())
+            if (col.isNotNull() || (!supportsNullUniqueColumn && col.hasConstraint(Unique.class)))
                 buf.append(" NOT NULL");
         }
         if (col.isAutoAssigned()) {

Modified: openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java?rev=1372913&r1=1372912&r2=1372913&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java (original)
+++ openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java Tue Aug 14 14:56:09 2012
@@ -68,6 +68,7 @@ public class DerbyDictionary
         supportsSimpleCaseExpression = false;
 
         supportsComments = true;
+        supportsNullUniqueColumn = false;
 
         fixedSizeTypeNameSet.addAll(Arrays.asList(new String[]{
             "BIGINT", "INTEGER",

Modified: openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java?rev=1372913&r1=1372912&r2=1372913&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java (original)
+++ openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java Tue Aug 14 14:56:09 2012
@@ -690,8 +690,6 @@ public class RowImpl
                 && col.getDefaultString() != null)
                 return;
         }
-        if (val == null && col.isNotNull())
-            val = JavaSQLTypes.getEmptyValue(col.getJavaType());
         flush(col, val, metaType, true);
     }
 

Modified: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/NullValues.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/NullValues.java?rev=1372913&r1=1372912&r2=1372913&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/NullValues.java (original)
+++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/NullValues.java Tue Aug 14 14:56:09 2012
@@ -23,6 +23,8 @@ import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
 import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
 import javax.persistence.Version;
 
 /**
@@ -32,6 +34,7 @@ import javax.persistence.Version;
  *
  */
 @Entity
+@Table(uniqueConstraints=@UniqueConstraint(columnNames={"UNS"}))
 public class NullValues {
 	@Id
 	@GeneratedValue
@@ -61,6 +64,9 @@ public class NullValues {
 	@Basic(optional=false)
 	private BlobValue notOptionalBlob;
 	
+	@Column(name="UNS")
+	private String uniqueNullable;
+	
 	@Version
 	private int version;
 	
@@ -78,6 +84,7 @@ public class NullValues {
 		setNotNullableBlob(new BlobValue());
 		setOptionalBlob(new BlobValue());
 		setNotOptionalBlob(new BlobValue());
+		setUniqueNullable("");
 	}
 	
 	public long getId() {
@@ -148,6 +155,14 @@ public class NullValues {
 		this.notOptionalBlob = notOptionalBlob;
 	}
 	
+    public String getUniqueNullable() {
+        return uniqueNullable;
+    }
+	
+    public void setUniqueNullable(String s) {
+        uniqueNullable = s;
+    }
+    
 	public int getVersion() { 
 	    return version;
 	}

Modified: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/TestBasicFieldNullity.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/TestBasicFieldNullity.java?rev=1372913&r1=1372912&r2=1372913&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/TestBasicFieldNullity.java (original)
+++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/nullity/TestBasicFieldNullity.java Tue Aug 14 14:56:09 2012
@@ -18,8 +18,16 @@
  */
 package org.apache.openjpa.persistence.nullity;
 
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
 import javax.persistence.RollbackException;
 
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.OracleDictionary;
+import org.apache.openjpa.jdbc.sql.SybaseDictionary;
 import org.apache.openjpa.persistence.InvalidStateException;
 import org.apache.openjpa.persistence.OpenJPAPersistence;
 
@@ -33,8 +41,10 @@ import org.apache.openjpa.persistence.Op
  */
 public class TestBasicFieldNullity extends AbstractNullityTestCase {
 
+    private DBDictionary dict = null;
     public void setUp() {
         setUp(CLEAR_TABLES, NullValues.class);
+        dict = ((JDBCConfiguration)emf.getConfiguration()).getDBDictionaryInstance();
     }
 
     public void testNullOnOptionalFieldIsAllowed() {
@@ -113,5 +123,65 @@ public class TestBasicFieldNullity exten
     	pc.setNotNullableBlob(null);
     	assertCommitFails(pc, !NEW, RollbackException.class);
     }
+        
+    public void testUniqueStringColumnCanBeNull() {
+        if (!isUniqueColumnNullable()) {
+            return;
+        }
+        NullValues pc = new NullValues();
+        pc.setUniqueNullable(null);
+        assertCommitSucceeds(pc, NEW);
+    }
+    
+    public void testUniqueStringColumnAsNull() {
+        if (!isUniqueColumnNullable()) {
+            return;
+        }
+        NullValues pc = new NullValues();
+        pc.setUniqueNullable(null);
+        assertCommitSucceeds(pc, NEW);
+        
+        String jpql = "select n from NullValues n where n.uniqueNullable = :p";
+        EntityManager em = emf.createEntityManager();
+        List<NullValues> result = em.createQuery(jpql)
+                                    .setParameter("p", null)
+                                    .getResultList();
+        assertFalse(result.isEmpty());
+        for (NullValues n : result)
+            assertNull(n.getUniqueNullable());
+    }
+    
+    public void testUniqueStringColumnAsEmpty() {
+        String EMPTY_STRING = "";
+        NullValues pc = new NullValues();
+        pc.setUniqueNullable(EMPTY_STRING);
+        assertCommitSucceeds(pc, NEW);
+        
+        String jpql = "select n from NullValues n where n.uniqueNullable = :p";
+        if (dict instanceof OracleDictionary)
+            jpql = "select n from NullValues n where n.uniqueNullable IS NULL";
+        EntityManager em = emf.createEntityManager();
+        Query  query = em.createQuery(jpql);
+        if (!(dict instanceof OracleDictionary))
+            query.setParameter("p", EMPTY_STRING);
+        List<NullValues> result = query.getResultList();
+        assertFalse(result.isEmpty());
+        for (NullValues n : result) {
+            if (dict instanceof OracleDictionary) {
+                assertNull(n.getUniqueNullable());
+            }
+            else if (dict instanceof SybaseDictionary) { 
+                // Sybase converts empty strings to "" 
+                assertEquals(" ", n.getUniqueNullable());
+            }
+            else {
+                assertEquals(EMPTY_STRING, n.getUniqueNullable());
+            }
+        }
+    }
+    
+    boolean isUniqueColumnNullable() {
+        return ((JDBCConfiguration)emf.getConfiguration()).getDBDictionaryInstance().supportsNullUniqueColumn;
+    }
 }