Author: ppoddar
Date: Wed Jun 18 16:25:59 2008
New Revision: 669332

URL: http://svn.apache.org/viewvc?rev=669332&view=rev
Log:
OPENJPA-533: Update query can set single-valued association to NULL or non-NULL.

Added:
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestUpdateSingleValuedAssociation.java
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Applicant.java
    
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Application.java
Modified:
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Null.java
    
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Null.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Null.java?rev=669332&r1=669331&r2=669332&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Null.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Null.java
 Wed Jun 18 16:25:59 2008
@@ -26,7 +26,7 @@
  *
  * @author Abe White
  */
-class Null
+public class Null
     extends Const {
 
     public Class getType() {

Modified: 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=669332&r1=669331&r2=669332&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
 (original)
+++ 
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
 Wed Jun 18 16:25:59 2008
@@ -71,6 +71,7 @@
 import org.apache.openjpa.jdbc.kernel.exps.ExpContext;
 import org.apache.openjpa.jdbc.kernel.exps.ExpState;
 import org.apache.openjpa.jdbc.kernel.exps.FilterValue;
+import org.apache.openjpa.jdbc.kernel.exps.Null;
 import org.apache.openjpa.jdbc.kernel.exps.Val;
 import org.apache.openjpa.jdbc.meta.ClassMapping;
 import org.apache.openjpa.jdbc.meta.FieldMapping;
@@ -2047,7 +2048,8 @@
                 augmentUpdates = false;
 
             Val val = (Val) next.getValue();
-
+            if (val == null)
+               val = new Null();
             Column col = fmd.getColumns()[0];
             if (allowAlias) {
               sql.append(sel.getColumnAlias(col));

Modified: 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java?rev=669332&r1=669331&r2=669332&view=diff
==============================================================================
--- 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
 (original)
+++ 
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
 Wed Jun 18 16:25:59 2008
@@ -483,7 +483,9 @@
         JPQLNode[] nodes = root().findChildrenByID(JJTUPDATEITEM);
         for (int i = 0; nodes != null && i < nodes.length; i++) {
             Path path = getPath(firstChild(nodes[i]));
-            Value val = getValue(onlyChild(lastChild(nodes[i])));
+            JPQLNode lastChild = lastChild(nodes[i]);
+            Value val = (lastChild.children == null) 
+                      ? null : getValue(onlyChild(lastChild));
             exps.putUpdate(path, val);
         }
     }

Added: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestUpdateSingleValuedAssociation.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestUpdateSingleValuedAssociation.java?rev=669332&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestUpdateSingleValuedAssociation.java
 (added)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/TestUpdateSingleValuedAssociation.java
 Wed Jun 18 16:25:59 2008
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.persistence.jdbc.query;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+
+import org.apache.openjpa.persistence.jdbc.query.domain.Application;
+import org.apache.openjpa.persistence.jdbc.query.domain.Applicant;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+/**
+ * Tests that update query can set single-valued association field to non-null
+ * or null values.
+ * 
+ * Originally reported in 
+ * <A HRE="http://issues.apache.org/jira/browse/OPENJPA-533>OPENJPA-533</A>
+ *  
+ * @author Pinaki Poddar
+ *
+ */
+public class TestUpdateSingleValuedAssociation extends SingleEMFTestCase {
+       private static boolean MUST_BE_NULL = true;
+       
+       @Override
+       public void setUp() throws Exception {
+               super.setUp(CLEAR_TABLES, Application.class, Applicant.class);
+       }
+       
+       public void testUpdateSingleValuedAssociationToNullViaParameter() {
+               createApplicationWithNonNullApplicant();
+               assertUserNullity(!MUST_BE_NULL);
+               
+               String jpql = "UPDATE Application a SET a.user = :user";
+               updateByQuery(jpql, "user", null);
+               
+               assertUserNullity(MUST_BE_NULL);
+       }
+       
+       public void testUpdateSingleValuedAssociationToNullViaLiteral() {
+               createApplicationWithNonNullApplicant();
+               assertUserNullity(!MUST_BE_NULL);
+               
+               String jpql = "UPDATE Application a SET a.user = NULL";
+               updateByQuery(jpql);
+               
+               assertUserNullity(MUST_BE_NULL);
+       }
+       
+       public void testUpdateSingleValuedAssociationToNonNullViaParameter() {
+               Application pc = createApplicationWithNullApplicant();
+               assertNull(pc.getUser());
+               
+               String jpql = "UPDATE Application a SET a.user = :user";
+               Applicant newUser = createApplicant();
+               updateByQuery(jpql, "user", newUser);
+               
+               assertUserNullity(!MUST_BE_NULL);
+       }
+       
+       void assertUserNullity(boolean shouldBeNull) {
+               EntityManager em = emf.createEntityManager();
+               em.getTransaction().begin();
+               List<Application> result = 
+                       em.createQuery("SELECT a FROM Application 
a").getResultList();
+               assertFalse(result.isEmpty());
+               for (Application pc : result) {
+                       Applicant user = pc.getUser();
+                       if (shouldBeNull)
+                               assertNull(user);
+                       else
+                               assertNotNull(user);
+               }
+               em.getTransaction().rollback();
+       }
+       
+       Application createApplicationWithNonNullApplicant() {
+               EntityManager em = emf.createEntityManager();
+               em.getTransaction().begin();
+               Application app = new Application();
+               Applicant user = new Applicant();
+               user.setName("Non-Null User");
+               app.setUser(user);
+               em.persist(app);
+               em.persist(user);
+               em.getTransaction().commit();
+               return app;
+       }
+       
+       Application createApplicationWithNullApplicant() {
+               EntityManager em = emf.createEntityManager();
+               em.getTransaction().begin();
+               Application app = new Application();
+               em.persist(app);
+               em.getTransaction().commit();
+               return app;
+       }
+       
+       Applicant createApplicant() {
+               EntityManager em = emf.createEntityManager();
+               em.getTransaction().begin();
+               Applicant user = new Applicant();
+               user.setName("Non-Null User");
+               em.persist(user);
+               em.getTransaction().commit();
+               return user;
+       }
+       
+       public void updateByQuery(String jpql, Object...params) {
+               EntityManager em = emf.createEntityManager();
+               em.getTransaction().begin();
+               Query query = em.createQuery(jpql);
+               for (int i=0; params != null && i<params.length; i=+2) {
+                       query.setParameter(params[i].toString(), params[i+1]);
+               }
+               query.executeUpdate();
+               em.getTransaction().commit();
+       }
+}

Added: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Applicant.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Applicant.java?rev=669332&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Applicant.java
 (added)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Applicant.java
 Wed Jun 18 16:25:59 2008
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.jdbc.query.domain;
+
+import javax.persistence.*;
+
+/**
+ * Simple persistent entity as a target of uni-directional one-to-one 
+ * association.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
[EMAIL PROTECTED]
+public class Applicant {
+       @Id
+       @GeneratedValue
+       private long id;
+
+       private String name;
+
+       public String getName() {
+               return name;
+       }
+
+       public void setName(String name) {
+               this.name = name;
+       }
+
+       public long getId() {
+               return id;
+       }
+
+}

Added: 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Application.java
URL: 
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Application.java?rev=669332&view=auto
==============================================================================
--- 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Application.java
 (added)
+++ 
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/query/domain/Application.java
 Wed Jun 18 16:25:59 2008
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.    
+ */
+package org.apache.openjpa.persistence.jdbc.query.domain;
+
+import javax.persistence.*;
+
+import org.apache.openjpa.persistence.jdbc.ForeignKey;
+import org.apache.openjpa.persistence.jdbc.ForeignKeyAction;
+
+/**
+ * Simple persistent entity as a source of uni-directional one-to-one 
+ * association.
+ * 
+ * @author Pinaki Poddar
+ *
+ */
[EMAIL PROTECTED]
+public class Application {
+       @Id
+       @GeneratedValue
+       private long id;
+
+       @ManyToOne
+       @JoinColumn(nullable = true)
+       @ForeignKey(deleteAction = ForeignKeyAction.NULL)
+       private Applicant user;
+
+       public Applicant getUser() {
+               return user;
+       }
+
+       public void setUser(Applicant user) {
+               this.user = user;
+       }
+
+       public long getId() {
+               return id;
+       }
+}


Reply via email to