You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by fa...@apache.org on 2008/10/03 23:16:50 UTC

svn commit: r701537 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/

Author: faywang
Date: Fri Oct  3 14:16:50 2008
New Revision: 701537

URL: http://svn.apache.org/viewvc?rev=701537&view=rev
Log:
OPENJPA-736 use jdbc api getGeneratedKey to combine insert 
and select SQL for generated id strategy = GenerationType.IDENTITY

Modified:
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedStatementManagerImpl.java
    openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingPreparedStatement.java

Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedStatementManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedStatementManagerImpl.java?rev=701537&r1=701536&r2=701537&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedStatementManagerImpl.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/PreparedStatementManagerImpl.java Fri Oct  3 14:16:50 2008
@@ -20,9 +20,12 @@
 
 import java.sql.Connection;
 import java.sql.PreparedStatement;
+import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedList;
+import java.util.List;
 
 import org.apache.openjpa.jdbc.meta.ClassMapping;
 import org.apache.openjpa.jdbc.schema.Column;
@@ -81,27 +84,7 @@
      * Flush the given row.
      */
     protected void flushInternal(RowImpl row) throws SQLException {
-        // can't batch rows with auto-inc columns
-        Column[] autoAssign = null;
-        if (row.getAction() == Row.ACTION_INSERT)
-            autoAssign = row.getTable().getAutoAssignedColumns();
-
         flushAndUpdate(row);
-
-        // set auto assign values
-        if (autoAssign != null && autoAssign.length > 0
-            && row.getPrimaryKey() != null) {
-            OpenJPAStateManager sm = row.getPrimaryKey();
-            ClassMapping mapping = (ClassMapping) sm.getMetaData();
-            Object val;
-            for (int i = 0; i < autoAssign.length; i++) {
-                val = _dict.getGeneratedKey(autoAssign[i], _conn);
-                mapping.assertJoinable(autoAssign[i]).setAutoAssignedValue(sm,
-                    _store, autoAssign[i], val);
-            }
-            sm.setObjectId(
-                ApplicationIds.create(sm.getPersistenceCapable(), mapping));
-        }
     }
 
     /**
@@ -109,9 +92,12 @@
      */
     protected void flushAndUpdate(RowImpl row)
         throws SQLException {
+    	Column[] autoAssign = getAutoAssignColumns(row);
+    	String[] autoAssignColNames = getAutoAssignColNames(autoAssign, row);
+        
         // prepare statement
         String sql = row.getSQL(_dict);
-        PreparedStatement stmnt = prepareStatement(sql);
+        PreparedStatement stmnt = prepareStatement(sql, autoAssignColNames);
 
         // setup parameters and execute statement
         if (stmnt != null)
@@ -127,6 +113,9 @@
                         "update-failed-no-failed-obj", String.valueOf(count),
                         sql).getMessage());
             }
+            if (autoAssignColNames != null)
+            	populateAutoAssignCols(stmnt, autoAssign, autoAssignColNames, row);
+            
         } catch (SQLException se) {
             throw SQLExceptions.getStore(se, row.getFailedObject(), _dict);
         } finally {
@@ -138,6 +127,78 @@
             }
         }
     }
+    
+    /** 
+     * This method will only be called when there is auto assign columns.
+     * If database supports getGeneratedKeys, the keys will be obtained
+     * from the result set associated with the stmnt. If not, a separate 
+     * sql to select the key will be issued from DBDictionary. 
+     */
+    protected List populateAutoAssignCols(PreparedStatement stmnt, 
+    	Column[] autoAssign, String[] autoAssignColNames, RowImpl row) 
+    	throws SQLException {
+    	List vals = null;
+       	if (_dict.supportsGetGeneratedKeys) {
+        	// set auto assign values to id col
+	   		vals = getGeneratedKeys(stmnt, autoAssignColNames);
+   		}
+       	setObjectId(vals, autoAssign, autoAssignColNames, row);
+       	return vals;
+    }
+    
+    protected void setObjectId(List vals, Column[] autoAssign, 
+    	String[] autoAssignColNames, RowImpl row) 
+    	throws SQLException{
+   		OpenJPAStateManager sm = row.getPrimaryKey();
+   		ClassMapping mapping = (ClassMapping) sm.getMetaData();
+   		Object val = null;
+   		for (int i = 0; i < autoAssign.length; i++) {
+   			if (_dict.supportsGetGeneratedKeys && vals != null && 
+   				vals.size() > 0)
+   				val = vals.get(i);
+   			else
+   				val = _dict.getGeneratedKey(autoAssign[i], _conn);
+   			mapping.assertJoinable(autoAssign[i]).setAutoAssignedValue(sm,
+   				_store, autoAssign[i], val);
+   		}
+   		sm.setObjectId(
+   			ApplicationIds.create(sm.getPersistenceCapable(), mapping));
+    }
+    
+    /**
+     * This method will only be called when the database supports
+     * getGeneratedKeys.
+     */
+    protected List getGeneratedKeys(PreparedStatement stmnt, 
+    	String[] autoAssignColNames) 
+    	throws SQLException {
+        ResultSet rs = stmnt.getGeneratedKeys();
+    	List vals = new ArrayList();
+    	while (rs.next()) {
+    		for (int i = 0; i < autoAssignColNames.length; i++)
+    			vals.add(rs.getObject(autoAssignColNames[i]));
+    	}
+    	rs.close();
+    	return vals;
+    }
+    
+    protected Column[] getAutoAssignColumns(RowImpl row) {
+        Column[] autoAssign = null;
+        if (row.getAction() == Row.ACTION_INSERT)
+            autoAssign = row.getTable().getAutoAssignedColumns();
+        return autoAssign;
+    }
+    
+    protected String[] getAutoAssignColNames(Column[] autoAssign, RowImpl row) {
+    	String[] autoAssignColNames = null;
+        if (autoAssign != null && autoAssign.length > 0
+            && row.getPrimaryKey() != null) {
+        	autoAssignColNames = new String[autoAssign.length];
+        	for (int i = 0; i < autoAssign.length; i++)
+        		autoAssignColNames[i] = autoAssign[i].getName();
+        }
+        return autoAssignColNames;
+    }
 
     public void flush() {
     }
@@ -150,13 +211,26 @@
         RowImpl row) throws SQLException {
         return stmnt.executeUpdate();
     }
-        
+
+    /**
+     * This method is to provide override for non-JDBC or JDBC-like 
+     * implementation of preparing statement.
+     */
+    protected PreparedStatement prepareStatement(String sql) 
+    	throws SQLException {
+    	return prepareStatement(sql, null);
+	}    
     /**
      * This method is to provide override for non-JDBC or JDBC-like 
      * implementation of preparing statement.
      */
-    protected PreparedStatement prepareStatement(String sql)
+    protected PreparedStatement prepareStatement(String sql, 
+    	String[] autoAssignColNames)
         throws SQLException {
-        return _conn.prepareStatement(sql);
+    	// pass in AutoAssignColumn names
+    	if (autoAssignColNames != null && _dict.supportsGetGeneratedKeys) 
+   	    	return _conn.prepareStatement(sql, autoAssignColNames);
+    	else
+    		return _conn.prepareStatement(sql);
     }
 }

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=701537&r1=701536&r2=701537&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 Fri Oct  3 14:16:50 2008
@@ -193,6 +193,7 @@
     public boolean supportsAlterTableWithAddColumn = true;
     public boolean supportsAlterTableWithDropColumn = true;
     public boolean supportsComments = false;
+    public boolean supportsGetGeneratedKeys = false;
     public String reservedWords = null;
     public String systemSchemas = null;
     public String systemTables = null;
@@ -393,6 +394,7 @@
                     // JDBC3-only method, so it might throw a 
                     // AbstractMethodError
                     isJDBC3 = metaData.getJDBCMajorVersion() >= 3;
+                    supportsGetGeneratedKeys = metaData.supportsGetGeneratedKeys();
                 } catch (Throwable t) {
                     // ignore if not JDBC3
                 }

Modified: openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingPreparedStatement.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingPreparedStatement.java?rev=701537&r1=701536&r2=701537&view=diff
==============================================================================
--- openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingPreparedStatement.java (original)
+++ openjpa/trunk/openjpa-lib/src/main/java/org/apache/openjpa/lib/jdbc/DelegatingPreparedStatement.java Fri Oct  3 14:16:50 2008
@@ -415,7 +415,7 @@
     }
 
     public ResultSet getGeneratedKeys() throws SQLException {
-        throw new UnsupportedOperationException();
+        return _stmnt.getGeneratedKeys();
     }
 
     public int executeUpdate(String s, int i) throws SQLException {