List:Commits« Previous MessageNext Message »
From:Craig L Russell Date:September 26 2011 2:01pm
Subject:bzr push into mysql-5.1-telco-7.1 branch (Craig.Russell:4292 to 4293)
View as plain text  
 4293 Craig L Russell	2011-09-26
      Add support for value handling for jdbc 5.1.17

    added:
      storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBatching.java
      storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBindValuesImpl.java
    modified:
      storage/ndb/clusterj/clusterj-jdbc/Makefile.am
      storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/InterceptorImpl.java
      storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/QueryExecutionContextJDBCImpl.java
      storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/SQLExecutor.java
      storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerImpl.java
      storage/ndb/clusterj/clusterj-jdbc/src/test/java/jdbctest/BatchDeleteQueryAllPrimitivesTest.java
      storage/ndb/clusterj/clusterj-jdbc/src/test/java/jdbctest/BigIntegerTypesTest.java
      storage/ndb/clusterj/clusterj-jdbc/src/test/resources/clusterj.properties
 4292 Craig L Russell	2011-09-26
      Bump version number to 7.1.17 for clusterj

    modified:
      storage/ndb/clusterj/clusterj-api/pom.xml
      storage/ndb/clusterj/clusterj-bindings/pom.xml
      storage/ndb/clusterj/clusterj-core/pom.xml
      storage/ndb/clusterj/clusterj-jdbc/pom.xml
      storage/ndb/clusterj/clusterj-jpatest/pom.xml
      storage/ndb/clusterj/clusterj-openjpa/pom.xml
      storage/ndb/clusterj/clusterj-test/pom.xml
      storage/ndb/clusterj/clusterj-tie/pom.xml
      storage/ndb/clusterj/pom.xml
=== modified file 'storage/ndb/clusterj/clusterj-jdbc/Makefile.am'
--- a/storage/ndb/clusterj/clusterj-jdbc/Makefile.am	2011-07-04 15:58:21 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/Makefile.am	2011-09-26 13:57:18 +0000
@@ -43,6 +43,8 @@ clusterj_jdbc_java = \
   $(clusterj_jdbc_src)/com/mysql/clusterj/jdbc/ResultSetInternalMethodsUpdateCount.java \
   $(clusterj_jdbc_src)/com/mysql/clusterj/jdbc/SQLExecutor.java \
   $(clusterj_jdbc_src)/com/mysql/clusterj/jdbc/StatementInterceptor.java \
+  $(clusterj_jdbc_src)/com/mysql/clusterj/jdbc/ValueHandlerBatching.java \
+  $(clusterj_jdbc_src)/com/mysql/clusterj/jdbc/ValueHandlerBindValuesImpl.java \
   $(clusterj_jdbc_src)/com/mysql/clusterj/jdbc/ValueHandlerImpl.java \
   $(clusterj_jdbc_src)/com/mysql/clusterj/jdbc/antlr/ANTLRNoCaseFileStream.java \
   $(clusterj_jdbc_src)/com/mysql/clusterj/jdbc/antlr/ANTLRNoCaseStringStream.java \

=== modified file 'storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/InterceptorImpl.java'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/InterceptorImpl.java	2011-06-20 23:34:36 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/InterceptorImpl.java	2011-09-26 13:57:18 +0000
@@ -17,8 +17,10 @@
 
 package com.mysql.clusterj.jdbc;
 
+import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.ClusterJHelper;
 import com.mysql.clusterj.ClusterJUserException;
+import com.mysql.clusterj.LockMode;
 import com.mysql.clusterj.SessionFactory;
 import com.mysql.clusterj.core.query.QueryDomainTypeImpl;
 import com.mysql.clusterj.core.spi.SessionSPI;
@@ -28,7 +30,10 @@ import com.mysql.clusterj.core.util.Logg
 import com.mysql.clusterj.core.util.LoggerFactoryService;
 import com.mysql.jdbc.Connection;
 import com.mysql.jdbc.ResultSetInternalMethods;
+import com.mysql.jdbc.ServerPreparedStatement;
 import com.mysql.jdbc.Statement;
+import com.mysql.jdbc.ServerPreparedStatement.BatchedBindValues;
+import com.mysql.jdbc.ServerPreparedStatement.BindValue;
 import com.mysql.clusterj.jdbc.antlr.ANTLRNoCaseStringStream;
 import com.mysql.clusterj.jdbc.antlr.MySQL51Parser;
 import com.mysql.clusterj.jdbc.antlr.MySQL51Lexer;
@@ -40,6 +45,8 @@ import com.mysql.clusterj.jdbc.antlr.nod
 import com.mysql.clusterj.query.Predicate;
 
 import com.mysql.clusterj.jdbc.SQLExecutor.Executor;
+
+import java.io.InputStream;
 import java.sql.SQLException;
 import java.sql.Savepoint;
 import java.util.ArrayList;
@@ -244,29 +251,45 @@ public class InterceptorImpl {
     public ResultSetInternalMethods preProcess(String sql, Statement statement,
             Connection connection) throws SQLException {
         assertReady();
+        if (logger.isDebugEnabled() && statement != null) 
+            logger.debug(statement.getClass().getName() + ": " + sql);
         if (statement instanceof com.mysql.jdbc.PreparedStatement) {
             com.mysql.jdbc.PreparedStatement preparedStatement =
                 (com.mysql.jdbc.PreparedStatement)statement;
             // key must be interned because we are using IdentityHashMap
-            String preparedSql = preparedStatement.getPreparedSql().intern();
+            // TODO: in case of DELETE, the SQL has already been rewritten at this point, 
+            // and the original SQL is gone
+            // so the key in the table is the rewritten DELETE SQL -- not what we want at all
+            String nonRewrittenSql = preparedStatement.getNonRewrittenSql();
+            String internedSql = nonRewrittenSql.intern();
+            
             // see if we have a parsed version of this query
             Executor sQLExecutor = null;
             synchronized(parsedSqlMap) {
-                sQLExecutor = parsedSqlMap.get(preparedSql);
+                sQLExecutor = parsedSqlMap.get(internedSql);
             }
             // if no cached SQLExecutor, create it, which might take some time
             if (sQLExecutor == null) {
-                sQLExecutor = createSQLExecutor(preparedSql);
+                sQLExecutor = createSQLExecutor(internedSql);
                 if (sQLExecutor != null) {
                     // multiple thread might have created a SQLExecutor but it's ok
                     synchronized(parsedSqlMap) {
-                        parsedSqlMap.put(preparedSql, sQLExecutor);
+                        parsedSqlMap.put(internedSql, sQLExecutor);
                     }
                 }
             }
-            return sQLExecutor.execute(this, preparedStatement.getParameterBindings());
+            try {
+                return sQLExecutor.execute(this, preparedStatement);
+            } catch (Throwable t) {
+                t.printStackTrace();
+                return null;
+            }
+        } else {
+            if (logger.isDebugEnabled() && statement != null) 
+                logger.debug(statement.getClass().getName() + " is not instanceof com.mysql.jdbc.PreparedStatement");
+            // not a prepared statement; won't execute this
+            return null;
         }
-        return null;
     }
 
     /**
@@ -323,6 +346,14 @@ public class InterceptorImpl {
                     result = new SQLExecutor.Noop();
                     break;
                 }
+                boolean forUpdate = null != (CommonTree)root.getFirstChildWithType(MySQL51Parser.FOR);
+                boolean lockShared = null != (CommonTree)root.getFirstChildWithType(MySQL51Parser.LOCK);
+                LockMode lockMode = LockMode.READ_COMMITTED;
+                if (forUpdate) {
+                    lockMode = LockMode.EXCLUSIVE;
+                } else if (lockShared) {
+                    lockMode = LockMode.SHARED;
+                }
                 getSession();
                 dictionary = session.getDictionary();
                 domainTypeHandler = getDomainTypeHandler(tableName, dictionary);
@@ -343,14 +374,15 @@ public class InterceptorImpl {
                 queryDomainType = (QueryDomainTypeImpl<?>) session.createQueryDomainType(domainTypeHandler);
                 if (whereNode == null) {
                     // no where clause (select all rows)
-                    result = new SQLExecutor.Select(domainTypeHandler, columnNames, queryDomainType);
+                    result = new SQLExecutor.Select(domainTypeHandler, columnNames, queryDomainType, lockMode);
                 } else {
                     // create a predicate from the tree
                     Predicate predicate = whereNode.getPredicate(queryDomainType);
                     if (predicate != null) {
                         // where clause that can be executed by clusterj
                         queryDomainType.where(predicate);
-                        result = new SQLExecutor.Select(domainTypeHandler, columnNames, queryDomainType);
+                        int numberOfParameters = whereNode.getNumberOfParameters();
+                        result = new SQLExecutor.Select(domainTypeHandler, columnNames, queryDomainType, lockMode, numberOfParameters);
                         whereType = "clusterj";
                     } else {
                         // where clause that cannot be executed by clusterj
@@ -461,7 +493,7 @@ public class InterceptorImpl {
         lexer.setErrorListener(new QueuingErrorListener(lexer));
         tokens.getTokens();
         if (lexer.getErrorListener().hasErrors()) {
-            logger.warn(local.message("ERR_Lexing_SQ",preparedSql));
+            logger.warn(local.message("ERR_Lexing_SQL",preparedSql));
             return result;
         }
         PlaceholderNode.resetId();

=== modified file 'storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/QueryExecutionContextJDBCImpl.java'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/QueryExecutionContextJDBCImpl.java	2011-06-20 23:34:36 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/QueryExecutionContextJDBCImpl.java	2011-09-26 13:57:18 +0000
@@ -20,17 +20,16 @@ package com.mysql.clusterj.jdbc;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.sql.Date;
-import java.sql.SQLException;
 import java.sql.Time;
 import java.sql.Timestamp;
 
-import com.mysql.clusterj.ClusterJUserException;
+import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.core.query.QueryExecutionContextImpl;
 import com.mysql.clusterj.core.spi.SessionSPI;
+import com.mysql.clusterj.core.spi.ValueHandler;
 import com.mysql.clusterj.core.util.I18NHelper;
 import com.mysql.clusterj.core.util.Logger;
 import com.mysql.clusterj.core.util.LoggerFactoryService;
-import com.mysql.jdbc.ParameterBindings;
 
 /** This class handles retrieving parameter values from the parameterBindings
  * associated with a PreparedStatement.
@@ -44,10 +43,7 @@ public class QueryExecutionContextJDBCIm
     static final Logger logger = LoggerFactoryService.getFactory().getInstance(QueryExecutionContextJDBCImpl.class);
 
     /** The wrapped ParameterBindings */
-    ParameterBindings parameterBindings;
-
-    /** The current offset */
-    int offset = 0;
+    ValueHandler parameterBindings;
 
     /** The number of parameters */
     int numberOfParameters;
@@ -58,176 +54,104 @@ public class QueryExecutionContextJDBCIm
      * @param numberOfParameters the number of parameters per statement
      */
     public QueryExecutionContextJDBCImpl(SessionSPI session,
-            ParameterBindings parameterBindings, int numberOfParameters) {
+            ValueHandler parameterBindings, int numberOfParameters) {
         super(session);
         this.parameterBindings = parameterBindings;
         this.numberOfParameters = numberOfParameters;
     }
 
-    /** Advance to the next statement (and next number of affected rows).
-     */
-    public void nextStatement() {
-        offset += numberOfParameters;
-    }
-
     public Byte getByte(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            Byte result = parameterBindings.getByte(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        Byte result = parameterBindings.getByte(parameterIndex);
+        return result;
     }
 
     public BigDecimal getBigDecimal(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            BigDecimal result = parameterBindings.getBigDecimal(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        BigDecimal result = parameterBindings.getBigDecimal(parameterIndex);
+        return result;
     }
 
     public BigInteger getBigInteger(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            BigInteger result = parameterBindings.getBigDecimal(parameterIndex).toBigInteger();
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        BigInteger result = parameterBindings.getBigDecimal(parameterIndex).toBigInteger();
+        return result;
     }
 
     public Boolean getBoolean(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            Boolean result = parameterBindings.getBoolean(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        Boolean result = parameterBindings.getBoolean(parameterIndex);
+        return result;
     }
 
     public byte[] getBytes(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            byte[] result = parameterBindings.getBytes(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        byte[] result = parameterBindings.getBytes(parameterIndex);
+        return result;
     }
 
     public Double getDouble(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            Double result = parameterBindings.getDouble(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        Double result = parameterBindings.getDouble(parameterIndex);
+        return result;
     }
 
     public Float getFloat(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            Float result = parameterBindings.getFloat(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        Float result = parameterBindings.getFloat(parameterIndex);
+        return result;
     }
 
     public Integer getInt(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            Integer result = parameterBindings.getInt(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        Integer result = parameterBindings.getInt(parameterIndex);
+        return result;
     }
 
     public Date getJavaSqlDate(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            java.sql.Date result = parameterBindings.getDate(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        java.sql.Date result = parameterBindings.getJavaSqlDate(parameterIndex);
+        return result;
     }
 
     public Time getJavaSqlTime(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            Time result = parameterBindings.getTime(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        Time result = parameterBindings.getJavaSqlTime(parameterIndex);
+        return result;
     }
 
     public Timestamp getJavaSqlTimestamp(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            java.sql.Timestamp result = parameterBindings.getTimestamp(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        java.sql.Timestamp result = parameterBindings.getJavaSqlTimestamp(parameterIndex);
+        return result;
     }
 
     public java.util.Date getJavaUtilDate(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            java.util.Date result = parameterBindings.getDate(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        java.util.Date result = parameterBindings.getJavaUtilDate(parameterIndex);
+        return result;
     }
 
     public Long getLong(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            Long result = parameterBindings.getLong(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        Long result = parameterBindings.getLong(parameterIndex);
+        return result;
     }
 
     public Short getShort(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            Short result = parameterBindings.getShort(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        Short result = parameterBindings.getShort(parameterIndex);
+        return result;
     }
 
     public String getString(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            String result = parameterBindings.getString(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        int parameterIndex = Integer.valueOf(index);
+        String result = parameterBindings.getString(parameterIndex);
+        return result;
     }
 
     public Object getObject(String index) {
-        try {
-            int parameterIndex = Integer.valueOf(index) + offset;
-            Object result = parameterBindings.getObject(parameterIndex);
-            return result;
-        } catch (SQLException ex) {
-                throw new ClusterJUserException(local.message("ERR_Getting_Parameter_Value", offset, index), ex);
-        }
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
     }
 
 }

=== modified file 'storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/SQLExecutor.java'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/SQLExecutor.java	2011-06-20 23:34:36 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/SQLExecutor.java	2011-09-26 13:57:18 +0000
@@ -17,26 +17,28 @@
 
 package com.mysql.clusterj.jdbc;
 
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.mysql.clusterj.ClusterJDatastoreException;
 import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.ClusterJUserException;
+import com.mysql.clusterj.LockMode;
 import com.mysql.clusterj.core.query.QueryDomainTypeImpl;
-import com.mysql.clusterj.core.query.QueryExecutionContextImpl;
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
-import com.mysql.clusterj.core.spi.QueryExecutionContext;
 import com.mysql.clusterj.core.spi.SessionSPI;
-import com.mysql.clusterj.core.spi.ValueHandler;
 import com.mysql.clusterj.core.store.ResultData;
 import com.mysql.clusterj.core.util.I18NHelper;
 import com.mysql.clusterj.core.util.Logger;
 import com.mysql.clusterj.core.util.LoggerFactoryService;
 import com.mysql.jdbc.ParameterBindings;
+import com.mysql.jdbc.PreparedStatement;
 import com.mysql.jdbc.ResultSetInternalMethods;
-
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import com.mysql.jdbc.ServerPreparedStatement;
+import com.mysql.jdbc.ServerPreparedStatement.BindValue;
 
 /** This class contains behavior to execute various SQL commands. There is one subclass for each
  * command to be executed. 
@@ -73,6 +75,18 @@ public class SQLExecutor {
     /** The query domain type for qualified SELECT and DELETE operations */
     protected QueryDomainTypeImpl<?> queryDomainType;
 
+    /** Does the jdbc driver support bind values (mysql 5.1.17 and later)? */
+    static boolean bindValueSupport = getBindValueSupport();
+
+    static boolean getBindValueSupport() {
+        try {
+            com.mysql.jdbc.ServerPreparedStatement.class.getMethod("getParameterBindValues", (Class<?>[])null);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
     public SQLExecutor(DomainTypeHandlerImpl<?> domainTypeHandler, List<String> columnNames, int numberOfParameters) {
         this(domainTypeHandler, columnNames);
         this.numberOfParameters = numberOfParameters;
@@ -110,12 +124,12 @@ public class SQLExecutor {
 
         /** Execute the SQL command
          * @param session the clusterj session which must not be null
-         * @param parameterBindings the parameter bindings from the prepared statement
+         * @param preparedStatement the prepared statement
          * @return the result of executing the statement, or null
          * @throws SQLException
          */
         ResultSetInternalMethods execute(InterceptorImpl interceptor,
-                ParameterBindings parameterBindings) throws SQLException;
+                PreparedStatement preparedStatement) throws SQLException;
     }
 
     /** This class implements the Executor contract but returns null, indicating that
@@ -124,7 +138,7 @@ public class SQLExecutor {
     public static class Noop implements Executor {
 
         public ResultSetInternalMethods execute(InterceptorImpl interceptor,
-                ParameterBindings parameterBindings) throws SQLException {
+                PreparedStatement preparedStatement) throws SQLException {
             return null;
         }
     }
@@ -133,23 +147,41 @@ public class SQLExecutor {
      */
     public static class Select extends SQLExecutor implements Executor {
 
-        public Select(DomainTypeHandlerImpl<?> domainTypeHandler, List<String> columnNames, QueryDomainTypeImpl<?> queryDomainType) {
+        private LockMode lockMode;
+
+        public Select(DomainTypeHandlerImpl<?> domainTypeHandler, List<String> columnNames,
+                QueryDomainTypeImpl<?> queryDomainType, LockMode lockMode, int numberOfParameters) {
             super(domainTypeHandler, columnNames, queryDomainType);
+            this.numberOfParameters = numberOfParameters;
+            this.lockMode = lockMode;
             if (queryDomainType == null) {
                 throw new ClusterJFatalInternalException("queryDomainType must not be null for Select.");
             }
         }
 
+        public Select(DomainTypeHandlerImpl<?> domainTypeHandler,
+                List<String> columnNames, QueryDomainTypeImpl<?> queryDomainType, LockMode lockMode) {
+            this(domainTypeHandler, columnNames, queryDomainType, lockMode, 0);
+        }
+
         public ResultSetInternalMethods execute(InterceptorImpl interceptor,
-                ParameterBindings parameterBindings) throws SQLException {
-            // create value handler to copy data from parameters to ndb
-            // count the parameters
-            int count = countParameters(parameterBindings);
+                PreparedStatement preparedStatement) throws SQLException {
             SessionSPI session = interceptor.getSession();
-            Map<String, Object> parameters = createParameterMap(queryDomainType, parameterBindings, 0, count);
-            QueryExecutionContext context = new QueryExecutionContextImpl(session, parameters);
+            session.setLockMode(lockMode);
+            // create value handler to copy data from parameters to ndb
+            ValueHandlerBatching valueHandlerBatching = getValueHandler(preparedStatement, null);
+            if (valueHandlerBatching == null) {
+                return null;
+            }
+            int numberOfStatements = valueHandlerBatching.getNumberOfStatements();
+            if (numberOfStatements != 1) {
+                return null;
+            }
+            QueryExecutionContextJDBCImpl context = 
+                new QueryExecutionContextJDBCImpl(session, valueHandlerBatching, numberOfParameters);
             session.startAutoTransaction();
             try {
+                valueHandlerBatching.next();
                 ResultData resultData = queryDomainType.getResultData(context);
                 // session.endAutoTransaction();
                 return new ResultSetInternalMethodsImpl(resultData, columnNumberToFieldNumberMap, 
@@ -176,30 +208,32 @@ public class SQLExecutor {
         }
 
         public ResultSetInternalMethods execute(InterceptorImpl interceptor,
-                ParameterBindings parameterBindings) throws SQLException {
+                PreparedStatement preparedStatement) throws SQLException {
             SessionSPI session = interceptor.getSession();
             if (queryDomainType == null) {
                 int rowsDeleted = session.deletePersistentAll(domainTypeHandler);
-                if (logger.isDebugEnabled()) logger.debug("deleteAll deleted: " + rowsDeleted);
+                if (logger.isDebugEnabled()) 
+                    logger.debug("deleteAll deleted: " + rowsDeleted);
                 return new ResultSetInternalMethodsUpdateCount(rowsDeleted);
             } else {
-                int numberOfBoundParameters = countParameters(parameterBindings);
-                int numberOfStatements = numberOfBoundParameters / numberOfParameters;
+                ValueHandlerBatching valueHandlerBatching = getValueHandler(preparedStatement, null);
+                if (valueHandlerBatching == null) {
+                    return null;
+                }
+                int numberOfStatements = valueHandlerBatching.getNumberOfStatements();
+                if (logger.isDebugEnabled()) 
+                    logger.debug("executing numberOfStatements: " + numberOfStatements 
+                            + " with numberOfParameters: " + numberOfParameters);
                 long[] deleteResults = new long[numberOfStatements];
-                if (logger.isDebugEnabled()) logger.debug(
-                        " numberOfParameters: " + numberOfParameters
-                        + " numberOfBoundParameters: " + numberOfBoundParameters
-                        + " numberOfStatements: " + numberOfStatements
-                        );
                 QueryExecutionContextJDBCImpl context = 
-                    new QueryExecutionContextJDBCImpl(session, parameterBindings, numberOfParameters);
-                for (int i = 0; i < numberOfStatements; ++i) {
+                    new QueryExecutionContextJDBCImpl(session, valueHandlerBatching, numberOfParameters);
+                int i = 0;
+                while (valueHandlerBatching.next()) {
                     // this will execute each statement in the batch using different parameters
                     int statementRowsDeleted = queryDomainType.deletePersistentAll(context);
-                    if (logger.isDebugEnabled()) logger.debug("statement " + i
-                            + " deleted " + statementRowsDeleted);
-                    deleteResults[i] = statementRowsDeleted;
-                    context.nextStatement();
+                    if (logger.isDebugEnabled())
+                        logger.debug("statement " + i + " deleted " + statementRowsDeleted);
+                    deleteResults[i++] = statementRowsDeleted;
                 }
                 return new ResultSetInternalMethodsUpdateCount(deleteResults);
             }
@@ -215,20 +249,26 @@ public class SQLExecutor {
         }
 
         public ResultSetInternalMethods execute(InterceptorImpl interceptor,
-                ParameterBindings parameterBindings) throws SQLException {
+                PreparedStatement preparedStatement) throws SQLException {
             SessionSPI session = interceptor.getSession();
-            int numberOfBoundParameters = countParameters(parameterBindings);
+            int numberOfBoundParameters = preparedStatement.getParameterMetaData().getParameterCount();
             int numberOfStatements = numberOfBoundParameters / numberOfParameters;
-            if (logger.isDebugEnabled()) logger.debug("SQLExecutor.Insert.execute"
-                    + " numberOfParameters: " + numberOfParameters
+            if (logger.isDebugEnabled())
+                logger.debug("numberOfParameters: " + numberOfParameters
                     + " numberOfBoundParameters: " + numberOfBoundParameters
                     + " numberOfFields: " + numberOfFields
                     + " numberOfStatements: " + numberOfStatements
                     );
             // interceptor.beforeClusterjStart();
             // session asks for values by field number which are converted to parameter number
-            for (int offset = 0; offset < numberOfBoundParameters; offset += numberOfParameters) {
-                ValueHandler valueHandler = getValueHandler(parameterBindings, fieldNumberToColumnNumberMap, offset);
+            ValueHandlerBatching valueHandler = getValueHandler(preparedStatement, fieldNumberToColumnNumberMap);
+            if (valueHandler == null) {
+                // we cannot handle this request
+                return null;
+            }
+            int count = 0;
+            while(valueHandler.next()) {
+                if (logger.isDetailEnabled()) logger.detail("inserting row " + count++);
                 session.insert(domainTypeHandler, valueHandler);
             }
             session.flush();
@@ -237,6 +277,43 @@ public class SQLExecutor {
         }
     }
 
+    protected ValueHandlerBatching getValueHandler(
+            PreparedStatement preparedStatement, int[] fieldNumberToColumnNumberMap) {
+        ValueHandlerBatching result = null;
+        try {
+            int numberOfBoundParameters = preparedStatement.getParameterMetaData().getParameterCount();
+            int numberOfStatements = numberOfParameters == 0 ? 1 : numberOfBoundParameters / numberOfParameters;
+            if (logger.isDebugEnabled()) logger.debug(
+                    " numberOfParameters: " + numberOfParameters
+                    + " numberOfBoundParameters: " + numberOfBoundParameters
+                    + " numberOfStatements: " + numberOfStatements
+                    + " fieldNumberToColumnNumberMap: " + Arrays.toString(fieldNumberToColumnNumberMap)
+                    );
+            if (preparedStatement instanceof ServerPreparedStatement) {
+                if (bindValueSupport) {
+                    ServerPreparedStatement serverPreparedStatement = (ServerPreparedStatement)preparedStatement;
+                    BindValue[] bindValues = serverPreparedStatement.getParameterBindValues();
+                    result = new ValueHandlerBindValuesImpl(bindValues, fieldNumberToColumnNumberMap,
+                            numberOfStatements, numberOfParameters);
+                } else {
+                    // note if you try to get parameter bindings from a server prepared statement, NPE in the driver
+                    // so if it's a server prepared statement without bind value support, e.g. using a JDBC driver
+                    // earlier than 5.1.17, returning null will allow the driver to pursue its normal path.
+                }
+            } else {
+            // not a server prepared statement; treat as regular prepared statement
+            ParameterBindings parameterBindings = preparedStatement.getParameterBindings();
+            result = new ValueHandlerImpl(parameterBindings, fieldNumberToColumnNumberMap, 
+                    numberOfStatements, numberOfParameters);
+            }
+        } catch (SQLException ex) {
+            throw new ClusterJDatastoreException(ex);
+        } catch (Throwable t) {
+            t.printStackTrace();
+        }
+        return result;
+    }
+
     /** Create the parameter map assigning each bound parameter a number.
      * The result is a map in which the key is a String whose key is a cardinal number
      * starting with 1 (for JDBC which uses 1-origin for numbering)
@@ -316,17 +393,6 @@ public class SQLExecutor {
         }
     }
 
-    /** Create a value handler (part of the clusterj spi) to retrieve values from jdbc parameter bindings.
-     * @param parameterBindings the jdbc parameter bindings from prepared statements
-     * @param fieldNumberToParameterNumberMap map from field number to parameter number
-     * @param offset into the parameter bindings for this instance (used for batch execution)
-     * @return
-     */
-    protected ValueHandler getValueHandler(ParameterBindings parameterBindings,
-            int[] fieldNumberToParameterNumberMap, int offset) {
-        return new ValueHandlerImpl(parameterBindings, fieldNumberToParameterNumberMap, offset);
-    }
-
     /** If detailed logging is enabled write the parameter bindings to the log.
      * @param parameterBindings the jdbc parameter bindings
      */
@@ -346,30 +412,4 @@ public class SQLExecutor {
         }
     }
 
-    /** Count the number of bound parameters. If this is a batch execution, then the
-     * number of bound parameters is the number of statements in the batch times the
-     * number of parameters per statement.
-     * If detailed logging is enabled write the parameter bindings to the log.
-     * @param parameterBindings the jdbc parameter bindings
-     */
-    protected static int countParameters(ParameterBindings parameterBindings) {
-        int i = 0;
-        while (true) {
-            try {
-                ++i;
-                // parameters are 1-origin per jdbc specification
-                Object objectValue = parameterBindings.getObject(i);
-                if (logger.isDetailEnabled()) {
-                    logger.detail("parameterBinding: parameter " + i
-                            + " has value: " + objectValue
-                            + " of type " + objectValue.getClass());
-                }
-            } catch (Exception e) {
-                // we don't know how many parameters are bound...
-                break;
-            }
-        }
-        return i - 1;
-    }
-
 }

=== added file 'storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBatching.java'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBatching.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBatching.java	2011-09-26 13:57:18 +0000
@@ -0,0 +1,45 @@
+/*
+ *  Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+package com.mysql.clusterj.jdbc;
+
+import com.mysql.clusterj.core.spi.ValueHandler;
+import com.mysql.clusterj.core.util.I18NHelper;
+import com.mysql.clusterj.core.util.Logger;
+import com.mysql.clusterj.core.util.LoggerFactoryService;
+
+/** This interface handles retrieving parameter values from the parameterBindings
+ * associated with a PreparedStatement or batchedBindValues from a ServerPreparedStatement.
+ */
+public interface ValueHandlerBatching extends ValueHandler {
+
+    /** My message translator */
+    static final I18NHelper local = I18NHelper.getInstance(ValueHandlerBatching.class);
+
+    /** My logger */
+    static final Logger logger = LoggerFactoryService.getFactory().getInstance(ValueHandlerBatching.class);
+
+    /**
+     * Advance to the next parameter set. If successful, return true. If there are no more
+     * parameter sets, return false.
+     * @return true if positioned to a valid parameter set
+     */
+    public boolean next();
+
+    public int getNumberOfStatements();
+
+}

=== added file 'storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBindValuesImpl.java'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBindValuesImpl.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBindValuesImpl.java	2011-09-26 13:57:18 +0000
@@ -0,0 +1,477 @@
+/*
+ *  Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+package com.mysql.clusterj.jdbc;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Iterator;
+import java.util.List;
+
+import com.mysql.clusterj.ClusterJFatalInternalException;
+import com.mysql.clusterj.ClusterJUserException;
+import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.core.spi.DomainTypeHandler;
+import com.mysql.clusterj.core.util.I18NHelper;
+import com.mysql.clusterj.core.util.Logger;
+import com.mysql.clusterj.core.util.LoggerFactoryService;
+import com.mysql.jdbc.ServerPreparedStatement.BatchedBindValues;
+import com.mysql.jdbc.ServerPreparedStatement.BindValue;
+
+/** This class handles retrieving parameter values from the parameterBindings
+ * associated with a PreparedStatement.
+ */
+public class ValueHandlerBindValuesImpl implements ValueHandlerBatching {
+
+    /** My message translator */
+    static final I18NHelper local = I18NHelper.getInstance(ValueHandlerBindValuesImpl.class);
+
+    /** My logger */
+    static final Logger logger = LoggerFactoryService.getFactory().getInstance(ValueHandlerBindValuesImpl.class);
+
+    private Iterator<?> parameterSetListIterator;
+    private BindValue[] bindValues;
+    private int[] fieldNumberToColumnNumberMap;
+    private int numberOfStatements;
+    private int currentStatement = 0;
+    private int offset;
+    private int numberOfParameters;
+
+    public ValueHandlerBindValuesImpl(List<?> parameterSetList, int[] fieldNumberToColumnNumberMap) {
+        this.parameterSetListIterator = parameterSetList.iterator();
+        this.numberOfStatements = parameterSetList.size();
+        this.fieldNumberToColumnNumberMap = fieldNumberToColumnNumberMap;
+    }
+
+    public ValueHandlerBindValuesImpl(BindValue[] bindValues, int[] fieldNumberToColumnNumberMap,
+            int numberOfStatements, int numberOfParameters) {
+        this.bindValues = bindValues;
+        this.fieldNumberToColumnNumberMap = fieldNumberToColumnNumberMap;
+        this.numberOfStatements = numberOfStatements;
+        this.numberOfParameters = numberOfParameters;
+        this.offset = -numberOfParameters;
+    }
+
+    /** Position to the next parameter set. If no more parameter sets, return false.
+     * @result true if positioned on a valid parameter set
+     */
+    @Override
+    public boolean next() {
+        if (parameterSetListIterator == null) {
+            offset += numberOfParameters;
+            return currentStatement++ < numberOfStatements;
+        }
+        if (parameterSetListIterator.hasNext()) {
+            Object parameterSet = parameterSetListIterator.next();
+            if (parameterSet instanceof BatchedBindValues) {
+                bindValues = ((BatchedBindValues)parameterSet).batchedParameterValues;
+            } else {
+                throw new ClusterJFatalInternalException(
+                        local.message("ERR_Mixed_Server_Prepared_Statement_Values", parameterSet.getClass().getName()));
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public int getNumberOfStatements() {
+        return numberOfStatements;
+    }
+
+    /** Get the index into the BindValue array. The number needs to be increased by 1
+     * because SQL is 1-origin while the java array is 0-origin.
+     * @param fieldNumber the field number for the requested field
+     * @return the 0-origin index into the BindValue array
+     */
+    private int getIndex(int fieldNumber) {
+        return fieldNumberToColumnNumberMap==null? fieldNumber + offset - 1:
+            fieldNumberToColumnNumberMap[fieldNumber] + offset - 1;
+    }
+
+    @Override
+    public BigDecimal getBigDecimal(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        Object value = bindValue.value;
+        if (value instanceof BigDecimal) {
+            return (BigDecimal) value;
+        } else if (value instanceof String) {
+            return new BigDecimal((String)value);
+        } else {
+            throw new ClusterJUserException(
+                    local.message("ERR_Parameter_Wrong_Type", "BigDecimal", value.getClass().getName()));
+        }
+    }
+
+    @Override
+    public BigInteger getBigInteger(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        Object value = bindValue.value;
+        if (value instanceof BigDecimal) {
+            return ((BigDecimal)value).toBigInteger();
+        } else if (value instanceof String) {
+                return new BigDecimal((String)value).toBigInteger();
+        } else {
+            throw new ClusterJUserException(
+                    local.message("ERR_Parameter_Wrong_Type", "BigDecimal", value.getClass().getName()));
+        }
+    }
+
+    @Override
+    public boolean getBoolean(int fieldNumber) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public boolean[] getBooleans(int fieldNumber) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public byte getByte(int fieldNumber) {
+        return (byte)bindValues[getIndex(fieldNumber)].longBinding;
+    }
+
+    @Override
+    public byte[] getBytes(int fieldNumber) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public double getDouble(int fieldNumber) {
+        return bindValues[getIndex(fieldNumber)].doubleBinding;
+    }
+
+    @Override
+    public float getFloat(int fieldNumber) {
+        return bindValues[getIndex(fieldNumber)].floatBinding;
+    }
+
+    @Override
+    public int getInt(int fieldNumber) {
+        return (int)bindValues[getIndex(fieldNumber)].longBinding;
+    }
+
+    @Override
+    public Date getJavaSqlDate(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        Object value = bindValue.value;
+        if (value instanceof java.sql.Date) {
+            return (java.sql.Date) value;
+        } else {
+            throw new ClusterJUserException(
+                    local.message("ERR_Parameter_Wrong_Type", "java.sql.Date", value.getClass().getName()));
+        }
+    }
+
+    @Override
+    public Time getJavaSqlTime(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        Object value = bindValue.value;
+        if (value instanceof java.sql.Time) {
+            return (java.sql.Time) value;
+        } else {
+            throw new ClusterJUserException(
+                    local.message("ERR_Parameter_Wrong_Type", "java.sql.Time", value.getClass().getName()));
+        }
+    }
+
+    @Override
+    public Timestamp getJavaSqlTimestamp(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        Object value = bindValue.value;
+        if (value instanceof java.sql.Timestamp) {
+            return (java.sql.Timestamp) value;
+        } else {
+            throw new ClusterJUserException(
+                    local.message("ERR_Parameter_Wrong_Type", "java.sql.Timestamp", value.getClass().getName()));
+        }
+    }
+
+    @Override
+    public java.util.Date getJavaUtilDate(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        Object value = bindValue.value;
+        if (value instanceof java.util.Date) {
+            return (java.util.Date) value;
+        } else {
+            throw new ClusterJUserException(
+                    local.message("ERR_Parameter_Wrong_Type", "java.util.Date", value.getClass().getName()));
+        }
+    }
+
+    @Override
+    public long getLong(int fieldNumber) {
+        return bindValues[getIndex(fieldNumber)].longBinding;
+    }
+
+    @Override
+    public Boolean getObjectBoolean(int fieldNumber) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public Byte getObjectByte(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        if (bindValue.isNull) {
+            return null;
+        } else {
+            return (byte)bindValue.longBinding;
+        }
+    }
+
+    @Override
+    public Double getObjectDouble(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        if (bindValue.isNull) {
+            return null;
+        } else {
+            return bindValue.doubleBinding;
+        }
+    }
+
+    @Override
+    public Float getObjectFloat(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        if (bindValue.isNull) {
+            return null;
+        } else {
+            return bindValue.floatBinding;
+        }
+    }
+
+    @Override
+    public Integer getObjectInt(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        if (bindValue.isNull) {
+            return null;
+        } else {
+            return (int)bindValue.longBinding;
+        }
+    }
+
+    @Override
+    public Long getObjectLong(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        if (bindValue.isNull) {
+            return null;
+        } else {
+            return bindValue.longBinding;
+        }
+    }
+
+    @Override
+    public Short getObjectShort(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        if (bindValue.isNull) {
+            return null;
+        } else {
+            return (short)bindValue.longBinding;
+        }
+    }
+
+    @Override
+    public short getShort(int fieldNumber) {
+        return (short)bindValues[getIndex(fieldNumber)].longBinding;
+    }
+
+    @Override
+    public String getString(int fieldNumber) {
+        BindValue bindValue = bindValues[getIndex(fieldNumber)];
+        Object value = bindValue.value;
+        if (value instanceof String) {
+            return (String) value;
+        } else {
+            throw new ClusterJUserException(
+                    local.message("ERR_Parameter_Wrong_Type", "String", value.getClass().getName()));
+        }
+    }
+
+    @Override
+    public boolean isNull(int fieldNumber) {
+        return bindValues[getIndex(fieldNumber)].isNull;
+    }
+
+    @Override
+    public boolean isModified(int fieldNumber) {
+        return fieldNumberToColumnNumberMap[fieldNumber] != -1;
+    }
+
+    @Override
+    public void markModified(int fieldNumber) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public String pkToString(DomainTypeHandler<?> domainTypeHandler) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void resetModified() {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setBigDecimal(int fieldNumber, BigDecimal value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setBigInteger(int fieldNumber, BigInteger bigIntegerExact) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setBoolean(int fieldNumber, boolean b) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setBooleans(int fieldNumber, boolean[] b) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setByte(int fieldNumber, byte value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setBytes(int fieldNumber, byte[] value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setDouble(int fieldNumber, double value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setFloat(int fieldNumber, float value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    public void setInt(int fieldNumber, int value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setJavaSqlDate(int fieldNumber, Date value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setJavaSqlTime(int fieldNumber, Time value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setJavaSqlTimestamp(int fieldNumber, Timestamp value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setJavaUtilDate(int fieldNumber, java.util.Date value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setLong(int fieldNumber, long value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setObject(int fieldNumber, Object value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setObjectBoolean(int fieldNumber, Boolean value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setObjectByte(int fieldNumber, Byte value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setObjectDouble(int fieldNumber, Double value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setObjectFloat(int fieldNumber, Float value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setObjectInt(int fieldNumber, Integer value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setObjectLong(int fieldNumber, Long value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setObjectShort(int fieldNumber, Short value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setShort(int fieldNumber, short value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void setString(int fieldNumber, String value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public ColumnMetadata[] columnMetadata() {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public Boolean found() {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void found(Boolean found) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public Object get(int columnNumber) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
+    public void set(int columnNumber, Object value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+}

=== modified file 'storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerImpl.java	2011-06-20 23:34:36 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerImpl.java	2011-09-26 13:57:18 +0000
@@ -28,17 +28,15 @@ import com.mysql.clusterj.ClusterJDatast
 import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.ColumnMetadata;
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
-import com.mysql.clusterj.core.spi.ValueHandler;
 import com.mysql.clusterj.core.util.I18NHelper;
 import com.mysql.clusterj.core.util.Logger;
 import com.mysql.clusterj.core.util.LoggerFactoryService;
-
 import com.mysql.jdbc.ParameterBindings;
 
 /** This class handles retrieving parameter values from the parameterBindings
  * associated with a PreparedStatement.
  */
-public class ValueHandlerImpl implements ValueHandler {
+public class ValueHandlerImpl implements ValueHandlerBatching {
 
     /** My message translator */
     static final I18NHelper local = I18NHelper.getInstance(ValueHandlerImpl.class);
@@ -47,24 +45,48 @@ public class ValueHandlerImpl implements
     static final Logger logger = LoggerFactoryService.getFactory().getInstance(ValueHandlerImpl.class);
 
     private ParameterBindings parameterBindings;
-    private int[] fieldNumberMap;
-
+    private final int[] fieldNumberMap;
+    private final int numberOfBoundParameters;
+    private final int numberOfStatements;
+    private final int numberOfParameters;
     /** The offset into the parameter bindings, used for batch processing */
     private int offset;
 
-    public ValueHandlerImpl(ParameterBindings parameterBindings, int[] fieldNumberMap, int offset) {
+    public ValueHandlerImpl(ParameterBindings parameterBindings, int[] fieldNumberMap, 
+            int numberOfStatements, int numberOfParameters) {
         this.parameterBindings = parameterBindings;
         this.fieldNumberMap = fieldNumberMap;
-        this.offset = offset;
-    }
-
-    public ValueHandlerImpl(ParameterBindings parameterBindings, int[] fieldNumberMap) {
-        this(parameterBindings, fieldNumberMap, 0);
+        this.numberOfParameters = numberOfParameters;
+        this.offset = -numberOfParameters;
+        this.numberOfBoundParameters = numberOfStatements * numberOfParameters;
+        this.numberOfStatements = numberOfStatements;
+    }
+
+    @Override
+    public int getNumberOfStatements() {
+        return numberOfStatements;
+    }
+
+    @Override
+    public boolean next() {
+        offset += numberOfParameters;
+        return offset < numberOfBoundParameters;
+    }
+
+    /** Return the index into the parameterBindings for this offset and field number.
+     * Offset moves the "window" to the next set of parameters for multi-statement
+     * (batched) statements.
+     * @param fieldNumber the origin-0 number
+     * @return the index into the parameterBindings
+     */
+    private int getIndex(int fieldNumber) {
+        int result = fieldNumberMap == null ? offset + fieldNumber : offset + fieldNumberMap[fieldNumber];
+        return result;
     }
 
     public BigDecimal getBigDecimal(int fieldNumber) {
         try {
-            return parameterBindings.getBigDecimal(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getBigDecimal(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -72,7 +94,7 @@ public class ValueHandlerImpl implements
 
     public BigInteger getBigInteger(int fieldNumber) {
         try {
-            return parameterBindings.getBigDecimal(offset + fieldNumberMap[fieldNumber]).toBigInteger();
+            return parameterBindings.getBigDecimal(getIndex(fieldNumber)).toBigInteger();
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -80,7 +102,7 @@ public class ValueHandlerImpl implements
 
     public boolean getBoolean(int fieldNumber) {
         try {
-            return parameterBindings.getBoolean(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getBoolean(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -92,7 +114,7 @@ public class ValueHandlerImpl implements
 
     public byte getByte(int fieldNumber) {
         try {
-            return parameterBindings.getByte(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getByte(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -104,7 +126,7 @@ public class ValueHandlerImpl implements
 
     public double getDouble(int fieldNumber) {
         try {
-            return parameterBindings.getDouble(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getDouble(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -112,7 +134,7 @@ public class ValueHandlerImpl implements
 
     public float getFloat(int fieldNumber) {
         try {
-            return parameterBindings.getFloat(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getFloat(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -120,7 +142,7 @@ public class ValueHandlerImpl implements
 
     public int getInt(int fieldNumber) {
         try {
-            return parameterBindings.getInt(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getInt(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -128,7 +150,7 @@ public class ValueHandlerImpl implements
 
     public Date getJavaSqlDate(int fieldNumber) {
         try {
-            return parameterBindings.getDate(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getDate(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -136,7 +158,7 @@ public class ValueHandlerImpl implements
 
     public Time getJavaSqlTime(int fieldNumber) {
         try {
-            return parameterBindings.getTime(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getTime(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -144,7 +166,7 @@ public class ValueHandlerImpl implements
 
     public Timestamp getJavaSqlTimestamp(int fieldNumber) {
         try {
-            return parameterBindings.getTimestamp(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getTimestamp(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -152,7 +174,7 @@ public class ValueHandlerImpl implements
 
     public java.util.Date getJavaUtilDate(int fieldNumber) {
         try {
-            return parameterBindings.getDate(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getDate(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -160,7 +182,7 @@ public class ValueHandlerImpl implements
 
     public long getLong(int fieldNumber) {
         try {
-            return parameterBindings.getLong(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getLong(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -172,7 +194,7 @@ public class ValueHandlerImpl implements
 
     public Byte getObjectByte(int fieldNumber) {
         try {
-            return parameterBindings.getByte(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getByte(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -180,7 +202,7 @@ public class ValueHandlerImpl implements
 
     public Double getObjectDouble(int fieldNumber) {
         try {
-            return parameterBindings.getDouble(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getDouble(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -188,7 +210,7 @@ public class ValueHandlerImpl implements
 
     public Float getObjectFloat(int fieldNumber) {
         try {
-            return parameterBindings.getFloat(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getFloat(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -196,7 +218,7 @@ public class ValueHandlerImpl implements
 
     public Integer getObjectInt(int fieldNumber) {
         try {
-            return parameterBindings.getInt(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getInt(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -204,7 +226,7 @@ public class ValueHandlerImpl implements
 
     public Long getObjectLong(int fieldNumber) {
         try {
-            return parameterBindings.getLong(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getLong(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -212,7 +234,7 @@ public class ValueHandlerImpl implements
 
     public Short getObjectShort(int fieldNumber) {
         try {
-            return parameterBindings.getShort(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getShort(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -220,7 +242,7 @@ public class ValueHandlerImpl implements
 
     public short getShort(int fieldNumber) {
         try {
-            return parameterBindings.getShort(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getShort(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -228,7 +250,7 @@ public class ValueHandlerImpl implements
 
     public String getString(int fieldNumber) {
         try {
-            return parameterBindings.getString(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.getString(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }
@@ -240,7 +262,7 @@ public class ValueHandlerImpl implements
 
     public boolean isNull(int fieldNumber) {
         try {
-            return parameterBindings.isNull(offset + fieldNumberMap[fieldNumber]);
+            return parameterBindings.isNull(getIndex(fieldNumber));
         } catch (SQLException e) {
             throw new ClusterJDatastoreException(e);
         }

=== modified file 'storage/ndb/clusterj/clusterj-jdbc/src/test/java/jdbctest/BatchDeleteQueryAllPrimitivesTest.java'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/test/java/jdbctest/BatchDeleteQueryAllPrimitivesTest.java	2011-06-20 23:34:36 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/test/java/jdbctest/BatchDeleteQueryAllPrimitivesTest.java	2011-09-26 13:57:18 +0000
@@ -81,7 +81,7 @@ create table allprimitives (
         deleteEqualQuery("id", "PRIMARY", 5, 0);
         try {
             connection.setAutoCommit(false);
-            PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM allprimitives where id = ?");
+            PreparedStatement preparedStatement = ((com.mysql.jdbc.Connection)connection).serverPrepareStatement("DELETE FROM allprimitives where id = ?");
             // delete 4 through 9 (excluding 5 which is already gone)
             for (int i = 4; i < 9; ++i) {
                 preparedStatement.setInt(1, i);

=== modified file 'storage/ndb/clusterj/clusterj-jdbc/src/test/java/jdbctest/BigIntegerTypesTest.java'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/test/java/jdbctest/BigIntegerTypesTest.java	2011-02-21 11:53:51 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/test/java/jdbctest/BigIntegerTypesTest.java	2011-09-26 13:57:18 +0000
@@ -36,6 +36,11 @@ create index idx_decimal_null_btree on b
 create unique index idx_decimal_null_both on bigintegertypes(decimal_null_both);
      */
 
+    @Override
+    protected boolean getCleanupAfterTest() {
+        return false;
+    }
+
     /** One of two tests in the superclass that we don't want to run */
     @Override
     public void testWriteJDBCReadNDB() {

=== modified file 'storage/ndb/clusterj/clusterj-jdbc/src/test/resources/clusterj.properties'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/test/resources/clusterj.properties	2011-06-30 16:04:23 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/test/resources/clusterj.properties	2011-09-26 13:57:18 +0000
@@ -19,7 +19,7 @@ com.mysql.clusterj.connect.delay=5
 com.mysql.clusterj.connect.verbose=1
 com.mysql.clusterj.connect.timeout.before=30
 com.mysql.clusterj.connect.timeout.after=20
-com.mysql.clusterj.jdbc.url=jdbc:mysql://localhost:9306/test?statementInterceptors=com.mysql.clusterj.jdbc.StatementInterceptor&connectionLifecycleInterceptors=com.mysql.clusterj.jdbc.ConnectionLifecycleInterceptor&poop=doop&com.mysql.clusterj.connectstring=localhost:9311&rewriteBatchedStatements=true&cachePrepStmts=true
+com.mysql.clusterj.jdbc.url=jdbc:mysql://localhost:9306/test?statementInterceptors=com.mysql.clusterj.jdbc.StatementInterceptor&connectionLifecycleInterceptors=com.mysql.clusterj.jdbc.ConnectionLifecycleInterceptor&com.mysql.clusterj.connectstring=localhost:9311&cachePrepStmts=true&rewriteBatchedStatements=true
 com.mysql.clusterj.jdbc.driver=com.mysql.jdbc.Driver
 com.mysql.clusterj.jdbc.username=root
 com.mysql.clusterj.jdbc.password=

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-5.1-telco-7.1 branch (Craig.Russell:4292 to 4293) Craig L Russell26 Sep