List:Commits« Previous MessageNext Message »
From:Craig L Russell Date:March 5 2012 10:31pm
Subject:bzr push into mysql-5.1-telco-7.1 branch (Craig.Russell:4471 to 4472)
View as plain text  
 4472 Craig L Russell	2012-03-05
      Use NdbRecord-formatted data buffer to store values for domain model
      Both the original Object[ ] implementation and the NdbRecord implementation
        are available, statically configured via a -D option or system environment
      Improve error reporting for tests
      NdbRecord domain model is implemented for insert, delete, update, and write
      Optimized use of NdbRecord domain model for find, query, load is not yet implemented

    added:
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/SmartValueHandler.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/ValueHandlerFactory.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordSmartValueHandlerFactoryImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordSmartValueHandlerImpl.java
    modified:
      storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/ClusterJHelper.java
      storage/ndb/clusterj/clusterj-core/Makefile.am
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionFactoryImpl.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionImpl.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainFieldHandlerImpl.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainTypeHandlerImpl.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainFieldHandlerImpl.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerFactoryImpl.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerImpl.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/InvocationHandlerImpl.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/KeyValueHandlerImpl.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainFieldHandler.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainTypeHandler.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainTypeHandlerFactory.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/ValueHandler.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/ClusterConnection.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Column.java
      storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Operation.java
      storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBatchingJDBCSetImpl.java
      storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBindValuesImpl.java
      storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerImpl.java
      storage/ndb/clusterj/clusterj-jdbc/src/main/resources/com/mysql/clusterj/jdbc/Bundle.properties
      storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPAConfigurationImpl.java
      storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPADomainFieldHandlerImpl.java
      storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPADomainTypeHandlerImpl.java
      storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPAValueHandler.java
      storage/ndb/clusterj/clusterj-openjpa/src/main/resources/com/mysql/clusterj/openjpa/Bundle.properties
      storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractClusterJModelTest.java
      storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractClusterJTest.java
      storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AutoCommitTest.java
      storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/BinaryPKTest.java
      storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/CharsetTest.java
      storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/LoadTest.java
      storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/MultithreadedTest.java
      storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/StressTest.java
      storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/VarcharStringLengthTest.java
      storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/domaintypehandler/CrazyDomainTypeHandlerFactoryImpl.java
      storage/ndb/clusterj/clusterj-test/src/main/resources/schema.sql
      storage/ndb/clusterj/clusterj-tie/Makefile.am
      storage/ndb/clusterj/clusterj-tie/pom.xml
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/BlobImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterConnectionImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterTransactionImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ColumnImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/DbImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordBlobImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordDeleteOperationImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordInsertOperationImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordKeyOperationImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordOperationImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordResultDataImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/OperationImpl.java
      storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/Utility.java
      storage/ndb/clusterj/clusterj-tie/src/main/resources/com/mysql/clusterj/tie/Bundle.properties
      storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/ConnectionPoolTest.java
 4471 magnus.blaudd@stripped	2012-03-05 [merge]
      Merge 7.0 -> 7.1

    modified:
      storage/ndb/src/kernel/blocks/pgman.cpp
      storage/ndb/src/ndbapi/NdbOperationSearch.cpp
      storage/ndb/src/ndbapi/ndb_cluster_connection.cpp
=== modified file 'storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/ClusterJHelper.java'
--- a/storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/ClusterJHelper.java	2011-12-14 19:26:46 +0000
+++ b/storage/ndb/clusterj/clusterj-api/src/main/java/com/mysql/clusterj/ClusterJHelper.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -198,4 +198,32 @@ public class ClusterJHelper {
         }
     }
 
+    /** Get the named boolean property from either the environment or system properties.
+     * If the property is not 'true' then return false.
+     * @param propertyName the name of the property
+     * @param def the default if the property is not set 
+     * @return the system property if it is set via -D or the system environment
+     */
+    public static boolean getBooleanProperty(String propertyName, String def) {
+        String propertyFromEnvironment = System.getenv(propertyName);
+        // system property overrides environment variable
+        String propertyFromSystem = System.getProperty(propertyName,
+                propertyFromEnvironment==null?def:propertyFromEnvironment);
+        boolean result = propertyFromSystem.equals("true")?true:false;
+        return result;
+    }
+
+    /** Get the named String property from either the environment or system properties.
+     * @param propertyName the name of the property
+     * @param def the default if the property is not set 
+     * @return the system property if it is set via -D or the system environment
+     */
+    public static String getStringProperty(String propertyName, String def) {
+        String propertyFromEnvironment = System.getenv(propertyName);
+        // system property overrides environment variable
+        String result = System.getProperty(propertyName,
+                propertyFromEnvironment==null?def:propertyFromEnvironment);
+        return result;
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-core/Makefile.am'
--- a/storage/ndb/clusterj/clusterj-core/Makefile.am	2011-11-22 22:01:23 +0000
+++ b/storage/ndb/clusterj/clusterj-core/Makefile.am	2012-03-05 22:28:15 +0000
@@ -1,4 +1,4 @@
-#   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+#   Copyright (c) 2010, 2012, 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
@@ -64,7 +64,9 @@ clusterj_core_java = \
   $(clusterj_core_src)/com/mysql/clusterj/core/spi/DomainTypeHandlerFactory.java \
   $(clusterj_core_src)/com/mysql/clusterj/core/spi/QueryExecutionContext.java \
   $(clusterj_core_src)/com/mysql/clusterj/core/spi/SessionSPI.java \
+  $(clusterj_core_src)/com/mysql/clusterj/core/spi/SmartValueHandler.java \
   $(clusterj_core_src)/com/mysql/clusterj/core/spi/ValueHandler.java \
+  $(clusterj_core_src)/com/mysql/clusterj/core/spi/ValueHandlerFactory.java \
   $(clusterj_core_src)/com/mysql/clusterj/core/spi/ValueHandlerBatching.java \
   $(clusterj_core_src)/com/mysql/clusterj/core/StateManager.java \
   $(clusterj_core_src)/com/mysql/clusterj/core/store/Blob.java \

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionFactoryImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionFactoryImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionFactoryImpl.java	2012-03-05 22:28:15 +0000
@@ -29,6 +29,7 @@ import com.mysql.clusterj.SessionFactory
 
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
 import com.mysql.clusterj.core.spi.DomainTypeHandlerFactory;
+import com.mysql.clusterj.core.spi.ValueHandlerFactory;
 
 import com.mysql.clusterj.core.metadata.DomainTypeHandlerFactoryImpl;
 
@@ -87,10 +88,6 @@ public class SessionFactoryImpl implemen
     /** DomainTypeHandlerFactory for this session factory. */
     DomainTypeHandlerFactory domainTypeHandlerFactory = new DomainTypeHandlerFactoryImpl();
 
-    /** The tables. */
-    // TODO make this non-static
-//    static final protected Map<String,Table> Tables = new HashMap<String,Table>();
-
     /** The session factories. */
     static final protected Map<String, SessionFactoryImpl> sessionFactoryMap =
             new HashMap<String, SessionFactoryImpl>();
@@ -109,6 +106,9 @@ public class SessionFactoryImpl implemen
                     CLUSTER_CONNECTION_SERVICE);
     }
 
+    /** The smart value handler factory */
+    protected ValueHandlerFactory smartValueHandlerFactory;
+
     /** Get a session factory. If using connection pooling and there is already a session factory
      * with the same connect string and database, return it, regardless of whether other
      * properties of the factory are the same as specified in the Map.
@@ -230,6 +230,10 @@ public class SessionFactoryImpl implemen
                 createClusterConnection(service, props, nodeIds.get(i));
             }
         }
+        // get the smart value handler factory for this connection; it will be the same for all connections
+        if (pooledConnections.size() != 0) {
+            smartValueHandlerFactory = pooledConnections.get(0).getSmartValueHandlerFactory();
+        }
     }
 
     protected ClusterConnection createClusterConnection(
@@ -330,8 +334,7 @@ public class SessionFactoryImpl implemen
      * @return the type handler
      */
     
-    public <T> DomainTypeHandler<T> getDomainTypeHandler(Class<T> cls,
-            Dictionary dictionary) {
+    public <T> DomainTypeHandler<T> getDomainTypeHandler(Class<T> cls, Dictionary dictionary) {
         // synchronize here because the map is not synchronized
         synchronized(typeToHandlerMap) {
             @SuppressWarnings("unchecked")
@@ -341,7 +344,7 @@ public class SessionFactoryImpl implemen
                     + ") returned " + domainTypeHandler);
             if (domainTypeHandler == null) {
                 domainTypeHandler = domainTypeHandlerFactory.createDomainTypeHandler(cls,
-                        dictionary);
+                        dictionary, smartValueHandlerFactory);
                 if (logger.isDetailEnabled()) logger.detail("createDomainTypeHandler for "
                         + cls.getName() + "(" + cls
                         + ") returned " + domainTypeHandler);
@@ -380,9 +383,9 @@ public class SessionFactoryImpl implemen
         return cls;        
     }
 
-    public <T> T newInstance(Class<T> cls, Dictionary dictionary) {
+    public <T> T newInstance(Class<T> cls, Dictionary dictionary, Db db) {
         DomainTypeHandler<T> domainTypeHandler = getDomainTypeHandler(cls, dictionary);
-        return domainTypeHandler.newInstance();
+        return domainTypeHandler.newInstance(db);
     }
 
     public Table getTable(String tableName, Dictionary dictionary) {

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/SessionImpl.java	2012-03-05 22:28:15 +0000
@@ -26,6 +26,7 @@ import com.mysql.clusterj.Query;
 import com.mysql.clusterj.Transaction;
 
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
+import com.mysql.clusterj.core.spi.SmartValueHandler;
 import com.mysql.clusterj.core.spi.ValueHandler;
 
 import com.mysql.clusterj.core.query.QueryDomainTypeImpl;
@@ -131,8 +132,7 @@ public class SessionImpl implements Sess
 
     /** Create a SessionImpl with factory, properties, Db, and dictionary
      */
-    SessionImpl(SessionFactoryImpl factory, Map properties, 
-            Db db, Dictionary dictionary) {
+    SessionImpl(SessionFactoryImpl factory, Map properties, Db db, Dictionary dictionary) {
         this.factory = factory;
         this.db = db;
         this.dictionary = dictionary;
@@ -195,7 +195,7 @@ public class SessionImpl implements Sess
                 if (instanceHandler == null) {
                     if (logger.isDetailEnabled()) logger.detail("Creating instanceHandler for class " + domainTypeHandler.getName() + " table: " + domainTypeHandler.getTableName() + keyHandler.pkToString(domainTypeHandler));
                     // we need both a new instance and its handler
-                    instance = domainTypeHandler.newInstance();
+                    instance = domainTypeHandler.newInstance(db);
                     instanceHandler = domainTypeHandler.getValueHandler(instance);
                 } else if (instance == null) {
                 if (logger.isDetailEnabled()) logger.detail("Creating instance for class " + domainTypeHandler.getName() + " table: " + domainTypeHandler.getTableName() + keyHandler.pkToString(domainTypeHandler));
@@ -249,7 +249,7 @@ public class SessionImpl implements Sess
      * @return a new instance that can be used with makePersistent
      */
     public <T> T newInstance(Class<T> cls) {
-        return factory.newInstance(cls, dictionary);
+        return factory.newInstance(cls, dictionary, db);
     }
 
     /** Create an instance of a class to be persisted and set the primary key.
@@ -260,7 +260,7 @@ public class SessionImpl implements Sess
      */
     public <T> T newInstance(Class<T> cls, Object key) {
         DomainTypeHandler<T> domainTypeHandler = getDomainTypeHandler(cls);
-        T instance = factory.newInstance(cls, dictionary);
+        T instance = factory.newInstance(cls, dictionary, db);
         domainTypeHandler.objectSetKeys(key, instance);
         return instance;
     }
@@ -384,10 +384,21 @@ public class SessionImpl implements Sess
         return object;
     }
 
-    public Operation insert(
-            DomainTypeHandler<?> domainTypeHandler, ValueHandler valueHandler) {
+    public Operation insert( DomainTypeHandler<?> domainTypeHandler, ValueHandler valueHandler) {
         startAutoTransaction();
         setPartitionKey(domainTypeHandler, valueHandler);
+        if (valueHandler instanceof SmartValueHandler) {
+            try {
+            SmartValueHandler smartValueHandler = (SmartValueHandler)valueHandler;
+            Operation result = smartValueHandler.insert(clusterTransaction);
+            valueHandler.resetModified();
+            endAutoTransaction();
+            return result;
+            } catch (ClusterJException cjex) {
+                failAutoTransaction();
+                throw cjex;
+            }
+        }
         Operation op = null;
         Table storeTable = null;
         try {
@@ -464,6 +475,17 @@ public class SessionImpl implements Sess
         startAutoTransaction();
         Table storeTable = domainTypeHandler.getStoreTable();
         setPartitionKey(domainTypeHandler, valueHandler);
+        if (valueHandler instanceof SmartValueHandler) {
+            try {
+            SmartValueHandler smartValueHandler = (SmartValueHandler)valueHandler;
+            Operation result = smartValueHandler.delete(clusterTransaction);
+            endAutoTransaction();
+            return result;
+            } catch (ClusterJException cjex) {
+                failAutoTransaction();
+                throw cjex;
+            }
+        }
         Operation op = null;
         try {
             op = clusterTransaction.getDeleteOperation(storeTable);
@@ -573,7 +595,7 @@ public class SessionImpl implements Sess
      * @param fields the fields to select; null to select all fields
      * @return the ResultData from the database
      */
-    public ResultData selectUnique(DomainTypeHandler domainTypeHandler,
+    public ResultData selectUnique(DomainTypeHandler<?> domainTypeHandler,
             ValueHandler keyHandler, BitSet fields) {
         assertActive();
         setPartitionKey(domainTypeHandler, keyHandler);
@@ -601,15 +623,26 @@ public class SessionImpl implements Sess
         if (object == null) {
             return;
         }
-        DomainTypeHandler domainTypeHandler = getDomainTypeHandler(object);
+        DomainTypeHandler<?> domainTypeHandler = getDomainTypeHandler(object);
         if (logger.isDetailEnabled()) logger.detail("UpdatePersistent on object " + object);
         ValueHandler valueHandler = domainTypeHandler.getValueHandler(object);
         update(domainTypeHandler, valueHandler);
     }
 
-    public Operation update(DomainTypeHandler domainTypeHandler, ValueHandler valueHandler) {
+    public Operation update(DomainTypeHandler<?> domainTypeHandler, ValueHandler valueHandler) {
         startAutoTransaction();
         setPartitionKey(domainTypeHandler, valueHandler);
+        if (valueHandler instanceof SmartValueHandler) {
+            try {
+            SmartValueHandler smartValueHandler = (SmartValueHandler)valueHandler;
+            Operation result = smartValueHandler.update(clusterTransaction);
+            endAutoTransaction();
+            return result;
+            } catch (ClusterJException cjex) {
+                failAutoTransaction();
+                throw cjex;
+            }
+        }
         Table storeTable = null;
         Operation op = null;
         try {
@@ -643,11 +676,23 @@ public class SessionImpl implements Sess
      * @param instance the instance to save
      */
     public <T> T savePersistent(T instance) {
-        DomainTypeHandler domainTypeHandler = getDomainTypeHandler(instance);
+        DomainTypeHandler<T> domainTypeHandler = getDomainTypeHandler(instance);
         if (logger.isDetailEnabled()) logger.detail("UpdatePersistent on object " + instance);
         ValueHandler valueHandler = domainTypeHandler.getValueHandler(instance);
         startAutoTransaction();
         setPartitionKey(domainTypeHandler, valueHandler);
+        if (valueHandler instanceof SmartValueHandler) {
+            try {
+            SmartValueHandler smartValueHandler = (SmartValueHandler)valueHandler;
+            smartValueHandler.write(clusterTransaction);
+            valueHandler.resetModified();
+            endAutoTransaction();
+            return instance;
+            } catch (ClusterJException cjex) {
+                failAutoTransaction();
+                throw cjex;
+            }
+        }
         Table storeTable = null;
         try {
             storeTable = domainTypeHandler.getStoreTable();
@@ -655,8 +700,6 @@ public class SessionImpl implements Sess
             op = clusterTransaction.getWriteOperation(storeTable);
             domainTypeHandler.operationSetKeys(valueHandler, op);
             domainTypeHandler.operationSetModifiedNonPKValues(valueHandler, op);
-            if (logger.isDetailEnabled()) logger.detail("Wrote object " +
-                    valueHandler);
         } catch (ClusterJException ex) {
             failAutoTransaction();
             throw new ClusterJException(

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainFieldHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainFieldHandlerImpl.java	2011-12-29 14:39:37 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainFieldHandlerImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -18,6 +18,7 @@
 package com.mysql.clusterj.core.metadata;
 
 import com.mysql.clusterj.ClusterJDatastoreException;
+import com.mysql.clusterj.ClusterJException;
 import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.ClusterJUserException;
 import com.mysql.clusterj.ColumnMetadata;
@@ -262,11 +263,15 @@ public abstract class AbstractDomainFiel
         objectOperationHandlerDelegate.objectInitializeJavaDefaultValue(this, handler);
     }
 
+    Object getDefaultValue() {
+        return defaultValue;
+    }
+
     public void objectSetKeyValue(Object key, ValueHandler handler) {
         if (logger.isDetailEnabled()) {
             logger.detail("Setting value " + key + ".");
         }
-        handler.setObject(fieldNumber, key);
+        objectOperationHandlerDelegate.objectSetValue(this, key, handler);
     }
 
     public void objectSetValue(ResultData rs, ValueHandler handler) {
@@ -277,6 +282,22 @@ public abstract class AbstractDomainFiel
         }
     }
 
+    public void objectSetValue(Object value, ValueHandler handler) {
+        try {
+            objectOperationHandlerDelegate.objectSetValue(this, value, handler);
+        } catch (Exception ex) {
+            throw new ClusterJDatastoreException(local.message("ERR_Value_Delegate", name, columnName, objectOperationHandlerDelegate.handler(), "objectSetValue"), ex);
+        }
+    }
+
+    public Object objectGetValue(ValueHandler handler) {
+        try {
+            return objectOperationHandlerDelegate.objectGetValue(this, handler);
+        } catch (Exception ex) {
+            throw new ClusterJDatastoreException(local.message("ERR_Value_Delegate", name, columnName, objectOperationHandlerDelegate.handler(), "objectGetValue"), ex);
+        }
+    }
+
     public void objectSetValueExceptIndex(ResultData rs, ValueHandler handler, String indexName) {
         try {
             if (!includedInIndex(indexName)) {
@@ -372,7 +393,7 @@ public abstract class AbstractDomainFiel
         } catch (NullPointerException npe) {
             throw new ClusterJUserException(
                     local.message("ERR_Key_Must_Not_Be_Null",
-                            domainTypeHandler.getName(), getName()));
+                            domainTypeHandler.getName(), getName()), npe);
         }
     }
 
@@ -437,6 +458,8 @@ public abstract class AbstractDomainFiel
 
         boolean isPrimitive();
 
+        Object objectGetValue(AbstractDomainFieldHandlerImpl abstractDomainFieldHandlerImpl, ValueHandler handler);
+
         Object getValue(QueryExecutionContext context, String index);
 
         void objectInitializeJavaDefaultValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler);
@@ -453,6 +476,8 @@ public abstract class AbstractDomainFiel
 
         void objectSetValue(AbstractDomainFieldHandlerImpl fmd, ResultData rs, ValueHandler handler);
 
+        void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler);
+
         void operationSetBounds(AbstractDomainFieldHandlerImpl fmd, Object value, IndexScanOperation.BoundType type, IndexScanOperation op);
 
         void filterCompareValue(AbstractDomainFieldHandlerImpl fmd, Object value, ScanFilter.BinaryCondition condition, ScanFilter filter);
@@ -530,6 +555,14 @@ public abstract class AbstractDomainFiel
             return context.getByte(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getByte(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setByte(fmd.fieldNumber, (Byte)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerBoolean = new ObjectOperationHandler() {
@@ -592,6 +625,14 @@ public abstract class AbstractDomainFiel
             return context.getBoolean(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getBoolean(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setBoolean(fmd.fieldNumber, (Boolean)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerObjectBoolean = new ObjectOperationHandler() {
@@ -658,6 +699,14 @@ public abstract class AbstractDomainFiel
             return context.getBoolean(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getObjectBoolean(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setObjectBoolean(fmd.fieldNumber, (Boolean)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerBytes = new ObjectOperationHandler() {
@@ -735,6 +784,14 @@ public abstract class AbstractDomainFiel
             return context.getBytes(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getBytes(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setBytes(fmd.fieldNumber, (byte[])value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerKeyBytes = new ObjectOperationHandler() {
@@ -803,6 +860,14 @@ public abstract class AbstractDomainFiel
             return context.getBytes(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getBytes(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setBytes(fmd.fieldNumber, (byte[])value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerBytesLob = new ObjectOperationHandler() {
@@ -860,7 +925,7 @@ public abstract class AbstractDomainFiel
 
                     public void run() {
                         Blob blob = op.getBlobHandle(fmd.storeColumn);
-                        byte[] data = handler.getBytes(fmd.fieldNumber);
+                        byte[] data = handler.getLobBytes(fmd.fieldNumber);
                         int length = data.length;
                         if (logger.isDetailEnabled()) {
                             logger.detail("Value to operation set blob value for field " + fmd.name + " for column " + fmd.columnName + " wrote length " + length + formatBytes(16, data));
@@ -885,7 +950,7 @@ public abstract class AbstractDomainFiel
                 logger.detail("ResultSet get blob value for field " + fmd.name + " for column " + fmd.columnName + " returned length " + length + formatBytes(16, data));
             }
             blob.close();
-            handler.setBytes(fmd.fieldNumber, data);
+            handler.setLobBytes(fmd.fieldNumber, data);
         }
 
         public void operationSetBounds(AbstractDomainFieldHandlerImpl fmd, Object value, IndexScanOperation.BoundType type, IndexScanOperation op) {
@@ -914,6 +979,14 @@ public abstract class AbstractDomainFiel
             return context.getBoolean(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getLobBytes(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setLobBytes(fmd.fieldNumber, (byte[])value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerStringLob = new ObjectOperationHandler() {
@@ -971,7 +1044,7 @@ public abstract class AbstractDomainFiel
 
                     public void run() {
                         Blob blob = op.getBlobHandle(fmd.storeColumn);
-                        byte[] data = fmd.storeColumn.encode(handler.getString(fmd.fieldNumber));
+                        byte[] data = fmd.storeColumn.encode(handler.getLobString(fmd.fieldNumber));
                         int length = data.length;
                         if (logger.isDetailEnabled()) {
                             logger.detail("Value to operation set text value for field " + fmd.name + " for column " + fmd.columnName + " wrote length " + length + formatBytes(16, data));
@@ -996,7 +1069,12 @@ public abstract class AbstractDomainFiel
                 logger.detail("ResultSet get text value for field " + fmd.name + " for column " + fmd.columnName + " returned length " + length + formatBytes(16, data));
             }
             blob.close();
-            handler.setString(fmd.fieldNumber, fmd.storeColumn.decode(data));
+            try {
+                handler.setLobString(fmd.fieldNumber, fmd.storeColumn.decode(data));
+            } catch (ClusterJException ex) {
+                System.out.println(ex.getMessage() + " length: " + data.length + " " + formatBytes(data.length, data));
+                throw ex;
+            }
         }
 
         public void operationSetBounds(AbstractDomainFieldHandlerImpl fmd, Object value, IndexScanOperation.BoundType type, IndexScanOperation op) {
@@ -1025,6 +1103,14 @@ public abstract class AbstractDomainFiel
             return context.getString(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getLobString(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setLobString(fmd.fieldNumber, (String)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerDecimal = new ObjectOperationHandler() {
@@ -1093,6 +1179,14 @@ public abstract class AbstractDomainFiel
             return context.getBigDecimal(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getBigDecimal(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setBigDecimal(fmd.fieldNumber, (BigDecimal)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerBigInteger = new ObjectOperationHandler() {
@@ -1161,6 +1255,14 @@ public abstract class AbstractDomainFiel
             return context.getBigInteger(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getBigInteger(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setBigInteger(fmd.fieldNumber, (BigInteger)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerDouble = new ObjectOperationHandler() {
@@ -1223,6 +1325,14 @@ public abstract class AbstractDomainFiel
             return context.getDouble(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getDouble(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setDouble(fmd.fieldNumber, (Double)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerFloat = new ObjectOperationHandler() {
@@ -1285,6 +1395,14 @@ public abstract class AbstractDomainFiel
             return context.getFloat(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getFloat(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setFloat(fmd.fieldNumber, (Float)value);
+        }
+
     };
 
     protected abstract static class ObjectOperationHandlerInt implements ObjectOperationHandler {
@@ -1302,7 +1420,8 @@ public abstract class AbstractDomainFiel
         }
 
         public Object getDefaultValueFor(AbstractDomainFieldHandlerImpl fmd, String columnDefaultValue) {
-            return (Integer) (columnDefaultValue == null ? Integer.valueOf(0) : Integer.valueOf(columnDefaultValue));
+            Object result = (Integer) (columnDefaultValue == null ? Integer.valueOf(0) : Integer.valueOf(columnDefaultValue));
+            return result;
         }
 
         public void operationSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, Operation op) {
@@ -1340,6 +1459,14 @@ public abstract class AbstractDomainFiel
             return context.getInt(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getInt(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setInt(fmd.fieldNumber, (Integer)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerInt = new ObjectOperationHandlerInt() {
@@ -1455,6 +1582,14 @@ public abstract class AbstractDomainFiel
             return context.getJavaSqlDate(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getJavaSqlDate(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setJavaSqlDate(fmd.fieldNumber, (java.sql.Date)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerJavaSqlTime = new ObjectOperationHandler() {
@@ -1525,6 +1660,14 @@ public abstract class AbstractDomainFiel
             return context.getJavaSqlTime(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getJavaSqlTime(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setJavaSqlTime(fmd.fieldNumber, (java.sql.Time)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerJavaSqlTimestamp = new ObjectOperationHandler() {
@@ -1595,6 +1738,14 @@ public abstract class AbstractDomainFiel
             return context.getJavaSqlTimestamp(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getJavaSqlTimestamp(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setJavaSqlTimestamp(fmd.fieldNumber, (java.sql.Timestamp)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerJavaUtilDate = new ObjectOperationHandler() {
@@ -1665,6 +1816,14 @@ public abstract class AbstractDomainFiel
             return context.getJavaUtilDate(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getJavaUtilDate(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setJavaUtilDate(fmd.fieldNumber, (java.util.Date)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerKeyString = new ObjectOperationHandler() {
@@ -1728,6 +1887,14 @@ public abstract class AbstractDomainFiel
             return context.getString(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getString(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setString(fmd.fieldNumber, (String)value);
+        }
+
     };
 
     public abstract static class ObjectOperationHandlerLong implements ObjectOperationHandler {
@@ -1779,6 +1946,14 @@ public abstract class AbstractDomainFiel
             return context.getLong(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getLong(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setLong(fmd.fieldNumber, (Long)value);
+        }
+
     }
 
     protected static ObjectOperationHandler objectOperationHandlerLong = new ObjectOperationHandlerLong() {
@@ -1887,6 +2062,14 @@ public abstract class AbstractDomainFiel
             return context.getByte(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getObjectByte(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setObjectByte(fmd.fieldNumber, (Byte)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerObjectDouble = new ObjectOperationHandler() {
@@ -1952,6 +2135,14 @@ public abstract class AbstractDomainFiel
             return context.getDouble(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getObjectDouble(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setObjectDouble(fmd.fieldNumber, (Double)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerObjectFloat = new ObjectOperationHandler() {
@@ -2017,6 +2208,14 @@ public abstract class AbstractDomainFiel
             return context.getFloat(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getObjectFloat(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setObjectFloat(fmd.fieldNumber, (Float)value);
+        }
+
     };
 
     protected abstract static class ObjectOperationHandlerInteger implements ObjectOperationHandler {
@@ -2067,6 +2266,14 @@ public abstract class AbstractDomainFiel
             return context.getInt(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getObjectInt(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setObjectInt(fmd.fieldNumber, (Integer)value);
+        }
+
     }
 
     protected static ObjectOperationHandler objectOperationHandlerObjectInteger = new ObjectOperationHandlerInteger() {
@@ -2160,6 +2367,14 @@ public abstract class AbstractDomainFiel
             return context.getLong(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getObjectLong(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setObjectLong(fmd.fieldNumber, (Long)value);
+        }
+
     }
 
     protected static ObjectOperationHandler objectOperationHandlerObjectLong = new ObjectOperationHandlerObjectLong() {
@@ -2276,6 +2491,14 @@ public abstract class AbstractDomainFiel
             return context.getShort(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getObjectShort(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setObjectShort(fmd.fieldNumber, (Short)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerShort = new ObjectOperationHandler() {
@@ -2349,6 +2572,14 @@ public abstract class AbstractDomainFiel
             return context.getShort(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getShort(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setShort(fmd.fieldNumber, (Short)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerShortYear = new ObjectOperationHandler() {
@@ -2419,6 +2650,19 @@ public abstract class AbstractDomainFiel
             return context.getShort(index);
         }
 
+        /** Years are stored in the domain model as short and in the database as byte.
+         * @param fmd the domain field handler
+         * @param handler the handler
+         * @return the handler's byte value plus 1900 (the year's base year) as a short
+         */
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return (short)(handler.getByte(fmd.fieldNumber) + 1900);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setByte(fmd.fieldNumber, (byte)((Short)value - 1900));
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerObjectShortYear = new ObjectOperationHandler() {
@@ -2493,6 +2737,24 @@ public abstract class AbstractDomainFiel
             return context.getShort(index);
         }
 
+        /** Years are stored in the domain model as short and in the database as byte.
+         * @param fmd the domain field handler
+         * @param handler the handler
+         * @return the handler's byte value plus 1900 (the year's base year) as a short
+         */
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            Byte value = handler.getObjectByte(fmd.fieldNumber);
+            return value==null?null:(short)(value + 1900);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            if (value == null) {
+                handler.setObjectByte(fmd.fieldNumber, null);
+            } else {
+                handler.setByte(fmd.fieldNumber, (byte)(((Short)value) - 1900));
+            }
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerString = new ObjectOperationHandler() {
@@ -2565,6 +2827,14 @@ public abstract class AbstractDomainFiel
             return context.getString(index);
         }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getString(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setString(fmd.fieldNumber, (String)value);
+        }
+
     };
 
     protected static ObjectOperationHandler objectOperationHandlerUnsupportedType = new ObjectOperationHandler() {
@@ -2625,6 +2895,14 @@ public abstract class AbstractDomainFiel
             throw new ClusterJFatalInternalException(local.message("ERR_Implementation_Should_Not_Occur"));
        }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            throw new ClusterJUserException(local.message("ERR_Unsupported_Field_Type", fmd.getTypeName(), fmd.getName()));
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            throw new ClusterJUserException(local.message("ERR_Unsupported_Field_Type", fmd.getTypeName(), fmd.getName()));
+        }
+
     };
 
     /** This operation handler is a no-op for getting and setting values that don't
@@ -2692,6 +2970,14 @@ public abstract class AbstractDomainFiel
             throw new ClusterJFatalInternalException(local.message("ERR_Implementation_Should_Not_Occur"));
        }
 
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            throw new ClusterJFatalInternalException(local.message("ERR_Implementation_Should_Not_Occur"));
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            return;
+        }
+
     };
 
     protected static abstract class ObjectOperationHandlerNotPersistent implements ObjectOperationHandler {
@@ -2705,7 +2991,7 @@ public abstract class AbstractDomainFiel
         }
 
         public Object getDefaultValueFor(AbstractDomainFieldHandlerImpl fmd, String columnDefaultValue) {
-            // this value is never used
+            // this value is used for transient default values; overridden by a subclass
             return null;
         }
 
@@ -2758,6 +3044,19 @@ public abstract class AbstractDomainFiel
         public void objectInitializeJavaDefaultValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
             handler.setByte(fmd.fieldNumber, (byte) 0);
         }
+
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getByte(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setByte(fmd.fieldNumber, (Byte)value);
+        }
+
+        public Object getDefaultValueFor(AbstractDomainFieldHandlerImpl fmd, String columnDefaultValue) {
+            return Byte.valueOf((byte) 0);
+        }
+
     };
     protected static ObjectOperationHandler objectOperationHandlerNotPersistentDouble = new ObjectOperationHandlerNotPersistent() {
 
@@ -2768,6 +3067,19 @@ public abstract class AbstractDomainFiel
         public void objectInitializeJavaDefaultValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
             handler.setDouble(fmd.fieldNumber, 0.0D);
         }
+
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getDouble(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setDouble(fmd.fieldNumber, (Double)value);
+        }
+
+        public Object getDefaultValueFor(AbstractDomainFieldHandlerImpl fmd, String columnDefaultValue) {
+            return Double.valueOf((double)0.0D);
+        }
+
     };
     protected static ObjectOperationHandler objectOperationHandlerNotPersistentFloat = new ObjectOperationHandlerNotPersistent() {
 
@@ -2778,6 +3090,19 @@ public abstract class AbstractDomainFiel
         public void objectInitializeJavaDefaultValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
             handler.setFloat(fmd.fieldNumber, 0.0F);
         }
+
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getFloat(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setFloat(fmd.fieldNumber, (Float)value);
+        }
+
+        public Object getDefaultValueFor(AbstractDomainFieldHandlerImpl fmd, String columnDefaultValue) {
+            return Float.valueOf((float) 0.0);
+        }
+
     };
     protected static ObjectOperationHandler objectOperationHandlerNotPersistentInt = new ObjectOperationHandlerNotPersistent() {
 
@@ -2788,6 +3113,19 @@ public abstract class AbstractDomainFiel
         public void objectInitializeJavaDefaultValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
             handler.setInt(fmd.fieldNumber, 0);
         }
+
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getInt(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setInt(fmd.fieldNumber, (Integer)value);
+        }
+
+        public Object getDefaultValueFor(AbstractDomainFieldHandlerImpl fmd, String columnDefaultValue) {
+            return Integer.valueOf((int) 0);
+        }
+
     };
     protected static ObjectOperationHandler objectOperationHandlerNotPersistentLong = new ObjectOperationHandlerNotPersistent() {
 
@@ -2798,6 +3136,19 @@ public abstract class AbstractDomainFiel
         public void objectInitializeJavaDefaultValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
             handler.setLong(fmd.fieldNumber, 0L);
         }
+
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getLong(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setLong(fmd.fieldNumber, (Long)value);
+        }
+
+        public Object getDefaultValueFor(AbstractDomainFieldHandlerImpl fmd, String columnDefaultValue) {
+            return Long.valueOf((long) 0);
+        }
+
     };
     protected static ObjectOperationHandler objectOperationHandlerNotPersistentObject = new ObjectOperationHandlerNotPersistent() {
 
@@ -2812,6 +3163,15 @@ public abstract class AbstractDomainFiel
 
         public void objectInitializeJavaDefaultValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
         }
+
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.get(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setObject(fmd.fieldNumber, value);
+        }
+
     };
     protected static ObjectOperationHandler objectOperationHandlerNotPersistentShort = new ObjectOperationHandlerNotPersistent() {
 
@@ -2822,6 +3182,19 @@ public abstract class AbstractDomainFiel
         public void objectInitializeJavaDefaultValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
             handler.setShort(fmd.fieldNumber, (short) 0);
         }
+
+        public Object objectGetValue(AbstractDomainFieldHandlerImpl fmd, ValueHandler handler) {
+            return handler.getShort(fmd.fieldNumber);
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd, Object value, ValueHandler handler) {
+            handler.setShort(fmd.fieldNumber, (Short)value);
+        }
+
+        public Object getDefaultValueFor(AbstractDomainFieldHandlerImpl fmd, String columnDefaultValue) {
+            return Short.valueOf((short) 0);
+        }
+
     };
 
     /* These methods implement ColumnMetadata
@@ -2879,4 +3252,11 @@ public abstract class AbstractDomainFiel
         return this.charsetName;
     }
 
+    public boolean isLob() {
+        // should implement this in a subclass
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Operation_Not_Supported",
+                "isLob()", "AbstractDomainFieldHandlerImpl"));
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainTypeHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainTypeHandlerImpl.java	2011-12-29 14:39:37 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/AbstractDomainTypeHandlerImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -34,6 +34,7 @@ import com.mysql.clusterj.core.spi.Domai
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
 import com.mysql.clusterj.core.spi.ValueHandler;
 import com.mysql.clusterj.core.store.Column;
+import com.mysql.clusterj.core.store.Db;
 import com.mysql.clusterj.core.store.Dictionary;
 import com.mysql.clusterj.core.store.IndexOperation;
 import com.mysql.clusterj.core.store.Operation;
@@ -75,6 +76,9 @@ public abstract class AbstractDomainType
     /** The id field(s) for the class, mapped to primary key columns */
     protected DomainFieldHandler[] idFieldHandlers;
 
+    /** The field(s) for the class */
+    protected DomainFieldHandler[] fieldHandlers;
+
     /** The PrimaryKey column names. */
     protected String[] primaryKeyColumnNames;
 
@@ -238,6 +242,10 @@ public abstract class AbstractDomainType
         return idFieldHandlers;
     }
 
+    public DomainFieldHandler[] getFieldHandlers() {
+        return fieldHandlers;
+    }
+
     public DomainFieldHandler getFieldHandler(String fieldName) {
         for (DomainFieldHandler fmd: persistentFieldHandlers) {
             if (fmd.getName().equals(fieldName)) {
@@ -401,7 +409,7 @@ public abstract class AbstractDomainType
         throw new ClusterJFatalInternalException(local.message("ERR_Implementation_Should_Not_Occur"));
     }
 
-    public T newInstance() {
+    public T newInstance(Db db) {
         throw new ClusterJFatalInternalException(local.message("ERR_Implementation_Should_Not_Occur"));
     }
 

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainFieldHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainFieldHandlerImpl.java	2012-01-21 02:12:23 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainFieldHandlerImpl.java	2012-03-05 22:28:15 +0000
@@ -75,6 +75,9 @@ public class DomainFieldHandlerImpl exte
     /** Lob annotation is not null if annotated with @Lob. */
     protected Lob lobAnnotation;
 
+    /** Lob is true if annotated or mapped to a text or blob column. */
+    protected boolean lob = false;
+
     /** The NotPersistent annotation indicates that this field is not
      * persistent, but can be used as a property that holds data not
      * stored in the datastore.
@@ -171,6 +174,7 @@ public class DomainFieldHandlerImpl exte
                         local.message("ERR_Primary_Field_Type", domainTypeHandler.getName(), name, printableName(type)));
             }
         } else if (lobAnnotation != null) {
+            this.lob = true;
             // large object support for byte[]
             if (type.equals(byte[].class)) {
                 objectOperationHandlerDelegate = objectOperationHandlerBytesLob;
@@ -370,6 +374,7 @@ public class DomainFieldHandlerImpl exte
                     }
                     break;
                 case Blob:
+                    this.lob = true;
                     this.objectOperationHandlerDelegate = objectOperationHandlerBytesLob;
                     this.type = byte[].class;
                     break;
@@ -454,6 +459,7 @@ public class DomainFieldHandlerImpl exte
                     }
                     break;
                 case Text:
+                    this.lob = true;
                     this.objectOperationHandlerDelegate = objectOperationHandlerStringLob;
                     this.type = String.class;
                     break;
@@ -582,4 +588,13 @@ public class DomainFieldHandlerImpl exte
         };
     };
 
+    public boolean isLob() {
+        return lob;
+    }
+
+    public Object getDefaultValue() {
+        Object value = objectOperationHandlerDelegate.getDefaultValueFor(this, null);
+        return value;
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerFactoryImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerFactoryImpl.java	2011-10-27 23:43:25 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerFactoryImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -22,6 +22,7 @@ import com.mysql.clusterj.ClusterJHelper
 import com.mysql.clusterj.ClusterJUserException;
 import com.mysql.clusterj.core.spi.DomainTypeHandlerFactory;
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
+import com.mysql.clusterj.core.spi.ValueHandlerFactory;
 import com.mysql.clusterj.core.store.Dictionary;
 import com.mysql.clusterj.core.util.I18NHelper;
 import com.mysql.clusterj.core.util.Logger;
@@ -52,7 +53,8 @@ public class DomainTypeHandlerFactoryImp
         }
     }
 
-    public <T> DomainTypeHandler<T> createDomainTypeHandler(Class<T> domainClass, Dictionary dictionary) {
+    public <T> DomainTypeHandler<T> createDomainTypeHandler(Class<T> domainClass, Dictionary dictionary,
+            ValueHandlerFactory valueHandlerFactory) {
         DomainTypeHandler<T> handler = null;
         StringBuffer errorMessages = new StringBuffer();
         for (DomainTypeHandlerFactory factory: domainTypeHandlerFactories) {
@@ -60,7 +62,7 @@ public class DomainTypeHandlerFactoryImp
                 errorMessages.append("Trying factory ");
                 errorMessages.append(factory.toString());
                 errorMessages.append("\n");
-                handler = factory.createDomainTypeHandler(domainClass, dictionary);
+                handler = factory.createDomainTypeHandler(domainClass, dictionary, valueHandlerFactory);
                 if (handler != null) {
                     return handler;
                 }
@@ -74,7 +76,7 @@ public class DomainTypeHandlerFactoryImp
 
         try {
             errorMessages.append("Trying standard factory com.mysql.clusterj.core.metadata.DomainTypeHandlerImpl.\n");
-            handler = new DomainTypeHandlerImpl<T>(domainClass, dictionary);
+            handler = new DomainTypeHandlerImpl<T>(domainClass, dictionary, valueHandlerFactory);
             return handler;
         } catch (ClusterJException e) {
             errorMessages.append(e.toString());

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerImpl.java	2011-12-29 14:39:37 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/DomainTypeHandlerImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -18,6 +18,7 @@
 package com.mysql.clusterj.core.metadata;
 
 import com.mysql.clusterj.core.spi.DomainFieldHandler;
+import com.mysql.clusterj.core.spi.ValueHandlerFactory;
 import com.mysql.clusterj.core.spi.ValueHandler;
 import com.mysql.clusterj.ClusterJException;
 import com.mysql.clusterj.ClusterJFatalInternalException;
@@ -31,6 +32,7 @@ import com.mysql.clusterj.annotation.Per
 import com.mysql.clusterj.core.CacheManager;
 
 import com.mysql.clusterj.core.store.Column;
+import com.mysql.clusterj.core.store.Db;
 import com.mysql.clusterj.core.store.Index;
 import com.mysql.clusterj.core.store.Dictionary;
 import com.mysql.clusterj.core.store.Operation;
@@ -49,8 +51,8 @@ import java.util.List;
 import java.util.Map;
 
 /** This instance manages a persistence-capable type.
- * Currently, only interfaces can be persistence-capable. Persistent
- * properties consist of a pair of bean-pattern methods for which the
+ * Currently, only interfaces or subclasses of DynamicObject can be persistence-capable.
+ * Persistent properties consist of a pair of bean-pattern methods for which the
  * get method returns the same type as the parameter of the 
  * similarly-named set method.
  * @param T the class of the persistence-capable type
@@ -76,22 +78,41 @@ public class DomainTypeHandlerImpl<T> ex
     /** The PersistenceCapable annotation for this class. */
     PersistenceCapable persistenceCapable;
 
+    /** The smart value handler factory */
+    ValueHandlerFactory valueHandlerFactory;
+
+    /* The column number is the entry indexed by field number */
+    private int[] fieldNumberToColumnNumberMap;
+
+    /* The number of transient (non-persistent) fields in the domain model */
+    private int numberOfTransientFields;
+
+    /* The field handlers for transient fields */
+    private DomainFieldHandlerImpl[] transientFieldHandlers;
+
     /** Helper parameter for constructor. */
     protected static final Class<?>[] invocationHandlerClassArray = 
             new Class[]{InvocationHandler.class};
 
     /** Initialize DomainTypeHandler for a class.
      * 
-     * @param cls the domain class (this is the only class 
-     * known to the rest of the implementation)
+     * @param cls the domain class (this is the only class known to the rest of the implementation)
      * @param dictionary NdbDictionary instance used for metadata access
      */
-    @SuppressWarnings( "unchecked" )
     public DomainTypeHandlerImpl(Class<T> cls, Dictionary dictionary) {
+        this(cls, dictionary, null);
+    }
+
+    @SuppressWarnings( "unchecked" )
+    public DomainTypeHandlerImpl(Class<T> cls, Dictionary dictionary,
+            ValueHandlerFactory smartValueHandlerFactory) {
+        this.valueHandlerFactory = smartValueHandlerFactory!=null?
+                smartValueHandlerFactory:
+                defaultInvocationHandlerFactory;
         this.cls = cls;
         this.name = cls.getName();
-        this.dynamic = DynamicObject.class.isAssignableFrom(cls);
-        if (dynamic) {
+        if (DynamicObject.class.isAssignableFrom(cls)) {
+            this.dynamic = true;
             // Dynamic object has a handler but no proxy
             this.tableName = getTableNameForDynamicObject((Class<DynamicObject>)cls);
         } else {
@@ -130,6 +151,7 @@ public class DomainTypeHandlerImpl<T> ex
         IndexHandlerImpl primaryIndexHandler =
             new IndexHandlerImpl(this, dictionary, primaryIndex, primaryKeyColumnNames);
         indexHandlerImpls.add(primaryIndexHandler);
+        List<DomainFieldHandler> fieldHandlerList = new ArrayList<DomainFieldHandler>();
 
         String[] indexNames = table.getIndexNames();
         for (String indexName: indexNames) {
@@ -153,6 +175,7 @@ public class DomainTypeHandlerImpl<T> ex
                 fieldNameList.add(fieldName);
                 fieldNameToNumber.put(domainFieldHandler.getName(), domainFieldHandler.getFieldNumber());
                 persistentFieldHandlers.add(domainFieldHandler);
+                fieldHandlerList.add(domainFieldHandler);
                 if (!storeColumn.isPrimaryKey()) {
                     nonPKFieldHandlers.add(domainFieldHandler);
                 }
@@ -219,6 +242,7 @@ public class DomainTypeHandlerImpl<T> ex
                     if (domainFieldHandler.isPrimitive()) {
                         primitiveFieldHandlers.add(domainFieldHandler);
                     }
+                    fieldHandlerList.add(domainFieldHandler);
                 }
             }
             fieldNames = fieldNameList.toArray(new String[fieldNameList.size()]);
@@ -248,12 +272,45 @@ public class DomainTypeHandlerImpl<T> ex
             logger.debug(toString());
             logger.debug("DomainTypeHandlerImpl " + name + "Indices " + indexHandlerImpls);
         }
+
+        // Compute the column for each field handler. 
+        // If no column for this field, increment the transient field counter.
+        // For persistent fields, column number is positive.
+        // For transient fields, column number is negative (index into transient field handler).
+        fieldNumberToColumnNumberMap = new int[numberOfFields];
+        String[] columnNames = table.getColumnNames();
+        this.fieldHandlers = fieldHandlerList.toArray(new DomainFieldHandlerImpl[numberOfFields]);
+
+        int transientFieldNumber = 0;
+        List<DomainFieldHandlerImpl> transientFieldHandlerList = new ArrayList<DomainFieldHandlerImpl>();
+        for (int fieldNumber = 0; fieldNumber < numberOfFields; ++fieldNumber) {
+            DomainFieldHandler fieldHandler = fieldHandlerList.get(fieldNumber);
+            // find the column name for the field
+            String columnName = fieldHandler.getColumnName();
+            boolean found = false;
+            for (int columnNumber = 0; columnNumber < columnNames.length; ++columnNumber) {
+                if (columnNames[columnNumber].equals(columnName)) {
+                    fieldNumberToColumnNumberMap[fieldNumber] = columnNumber;
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                // no column for this field; it is a transient field
+                fieldNumberToColumnNumberMap[fieldNumber] = --transientFieldNumber;
+                transientFieldHandlerList.add((DomainFieldHandlerImpl) fieldHandler);
+            }
+        }
+        numberOfTransientFields = 0 - transientFieldNumber;
+        transientFieldHandlers = 
+            transientFieldHandlerList.toArray(new DomainFieldHandlerImpl[transientFieldHandlerList.size()]);
     }
 
     /** Get the table name mapped to the domain class.
      * @param cls the domain class
      * @return the table name for the domain class
      */
+    @SuppressWarnings("unchecked")
     protected static String getTableName(Class<?> cls) {
         String tableName = null;
         if (DynamicObject.class.isAssignableFrom(cls)) {
@@ -358,17 +415,14 @@ public class DomainTypeHandlerImpl<T> ex
         handler.resetModified();
     }
 
-    @SuppressWarnings("unchecked")
     public void objectSetCacheManager(CacheManager cm, Object instance) {
-        InvocationHandlerImpl<T> handler =
-                (InvocationHandlerImpl<T>)getValueHandler(instance);
-        handler.setCacheManager(cm);
+        getValueHandler(instance).setCacheManager(cm);
     }
 
-    public T newInstance() {
+    public T newInstance(Db db) {
         T instance;
         try {
-            InvocationHandlerImpl<T> handler = new InvocationHandlerImpl<T>(this);
+            ValueHandler handler = valueHandlerFactory.getValueHandler(this, db);
             if (dynamic) {
                 instance = cls.newInstance();
                 ((DynamicObject)instance).delegate((DynamicObjectDelegate)handler);
@@ -396,10 +450,11 @@ public class DomainTypeHandlerImpl<T> ex
     }
 
 
-    public void initializeNotPersistentFields(InvocationHandlerImpl<T> handler) {
+    public void initializePrimitiveFields(ValueHandler handler) {
         for (DomainFieldHandler fmd:primitiveFieldHandlers) {
             ((AbstractDomainFieldHandlerImpl) fmd).objectSetDefaultValue(handler);
         }
+        handler.resetModified();
     }
 
     /** Convert a method name to a javabeans property name.
@@ -519,9 +574,38 @@ public class DomainTypeHandlerImpl<T> ex
         throw new ClusterJFatalInternalException(local.message("ERR_Implementation_Should_Not_Occur"));
     }
 
-    protected ColumnMetadata[] columnMetadata() {
+    public ColumnMetadata[] columnMetadata() {
         ColumnMetadata[] result = new ColumnMetadata[numberOfFields];
         return persistentFieldHandlers.toArray(result);
     }
 
+    /** Factory for default InvocationHandlerImpl */
+    protected ValueHandlerFactory defaultInvocationHandlerFactory = new ValueHandlerFactory()  {
+        public <V> ValueHandler getValueHandler(DomainTypeHandlerImpl<V> domainTypeHandler, Db db) {
+            return new InvocationHandlerImpl<V>(domainTypeHandler);
+        }
+    };
+
+    public int getNumberOfTransientFields() {
+        return numberOfTransientFields;
+    }
+
+    public int[] getFieldNumberToColumnNumberMap() {
+        return fieldNumberToColumnNumberMap;
+    }
+
+    /** Create a new object array containing default values for all transient fields.
+     * 
+     * @return default transient field values
+     */
+    public Object[] newTransientValues() {
+        Object[] result = new Object[numberOfTransientFields];
+        int i = 0;
+        for (DomainFieldHandlerImpl transientFieldHandler: transientFieldHandlers) {
+            Object value = transientFieldHandler.getDefaultValue();
+            result[i++] = value;
+        }
+        return result;
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/InvocationHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/InvocationHandlerImpl.java	2011-06-09 22:56:27 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/InvocationHandlerImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -85,7 +85,7 @@ public class InvocationHandlerImpl<T> im
         numberOfFields = domainTypeHandler.getNumberOfFields();
         properties = new Object[numberOfFields];
         modifiedFields = new BitSet(numberOfFields);
-        domainTypeHandler.initializeNotPersistentFields(this);
+        domainTypeHandler.initializePrimitiveFields(this);
     }
 
     public void setProxy(Object proxy) {
@@ -304,6 +304,14 @@ public class InvocationHandlerImpl<T> im
         return doubleValue(fieldNumber);
     }
 
+    public byte[] getLobBytes(int fieldNumber) {
+        return bytesValue(fieldNumber);
+    }
+
+    public String getLobString(int fieldNumber) {
+        return stringValue(fieldNumber);
+    }
+
     public Byte getObjectByte(int fieldNumber) {
         return (Byte)properties[fieldNumber];
     }
@@ -372,6 +380,14 @@ public class InvocationHandlerImpl<T> im
         properties[fieldNumber] = value;
     }
 
+    public void setLobBytes(int fieldNumber, byte[] value) {
+        properties[fieldNumber] = value;
+    }
+
+    public void setLobString(int fieldNumber, String value) {
+        properties[fieldNumber] = value;
+    }
+
     public void setShort(int fieldNumber, short value) {
         properties[fieldNumber] = value;
     }

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/KeyValueHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/KeyValueHandlerImpl.java	2011-06-09 22:56:27 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/metadata/KeyValueHandlerImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -19,11 +19,14 @@ package com.mysql.clusterj.core.metadata
 
 import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.core.CacheManager;
 import com.mysql.clusterj.core.spi.ValueHandler;
 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 java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.sql.Date;
@@ -199,6 +202,18 @@ public class KeyValueHandlerImpl impleme
                 "getJavaSqlTimestamp", "KeyValueHandlerImpl"));
     }
 
+    public byte[] getLobBytes(int fieldNumber) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Operation_Not_Supported",
+                "getLobBytes", "KeyValueHandlerImpl"));
+    }
+
+    public String getLobString(int fieldNumber) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Operation_Not_Supported",
+                "getLobString", "KeyValueHandlerImpl"));
+    }
+
     public void setBoolean(int fieldNumber, boolean b) {
         throw new ClusterJFatalInternalException(
                 local.message("ERR_Operation_Not_Supported",
@@ -229,6 +244,18 @@ public class KeyValueHandlerImpl impleme
                 "setBytes", "KeyValueHandlerImpl"));
     }
 
+    public void setLobBytes(int fieldNumber, byte[] value) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Operation_Not_Supported",
+                "setLobBytes", "KeyValueHandlerImpl"));
+    }
+
+    public void setLobString(int fieldNumber, String value) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Operation_Not_Supported",
+                "setLobString", "KeyValueHandlerImpl"));
+    }
+
     public void setShort(int fieldNumber, short value) {
         throw new ClusterJFatalInternalException(
                 local.message("ERR_Operation_Not_Supported",
@@ -394,4 +421,23 @@ public class KeyValueHandlerImpl impleme
                 "set(int, Object)", "KeyValueHandlerImpl"));
     }
 
+    public void setProxy(Object proxy) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Operation_Not_Supported",
+                "setProxy(Object)", "KeyValueHandlerImpl"));
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args)
+            throws Throwable {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Operation_Not_Supported",
+                "invoke(Object, Method, Object[])", "KeyValueHandlerImpl"));
+    }
+
+    public void setCacheManager(CacheManager cm) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Operation_Not_Supported",
+                "setCacheManager(CacheManager)", "KeyValueHandlerImpl"));
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainFieldHandler.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainFieldHandler.java	2011-10-02 21:20:50 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainFieldHandler.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -57,10 +57,16 @@ public interface DomainFieldHandler {
 
     void objectSetValue(ResultData rs, ValueHandler handler);
 
+    void objectSetValue(Object value, ValueHandler handler);
+
+    Object objectGetValue(ValueHandler handler);
+
     Class<?> getType();
 
     String getName();
 
+    String getColumnName();
+
     int getFieldNumber();
 
     void partitionKeySetPart(PartitionKey result, ValueHandler handler);
@@ -76,6 +82,8 @@ public interface DomainFieldHandler {
 
     boolean isPrimaryKey();
 
+    boolean isLob();
+
     Object getValue(QueryExecutionContext context, String parameterName);
 
     void filterIsNull(ScanFilter filter);

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainTypeHandler.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainTypeHandler.java	2011-12-29 14:39:37 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainTypeHandler.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -20,6 +20,7 @@ package com.mysql.clusterj.core.spi;
 import com.mysql.clusterj.core.CacheManager;
 import com.mysql.clusterj.core.query.CandidateIndexImpl;
 import com.mysql.clusterj.core.store.Column;
+import com.mysql.clusterj.core.store.Db;
 import com.mysql.clusterj.core.store.Operation;
 import com.mysql.clusterj.core.store.PartitionKey;
 import com.mysql.clusterj.core.store.ResultData;
@@ -48,7 +49,7 @@ public interface DomainTypeHandler<T> {
 
     public Class<T> getProxyClass();
 
-    public T newInstance();
+    public T newInstance(Db db);
 
     public ValueHandler getValueHandler(Object instance);
 

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainTypeHandlerFactory.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainTypeHandlerFactory.java	2011-06-30 16:04:23 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/DomainTypeHandlerFactory.java	2012-03-05 22:28:15 +0000
@@ -1,6 +1,5 @@
 /*
-   Copyright (c) 2010 Sun Microsystems, Inc.
-   Use is subject to license terms.
+   Copyright (c) 2010, 2012, 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
@@ -25,6 +24,7 @@ import com.mysql.clusterj.core.store.Dic
  */
 public interface DomainTypeHandlerFactory {
 
-    public <T> DomainTypeHandler<T> createDomainTypeHandler(Class<T> domainClass, Dictionary dictionary);
+    public <T> DomainTypeHandler<T> createDomainTypeHandler(Class<T> domainClass, Dictionary dictionary,
+            ValueHandlerFactory valueHandlerFactory);
 
 }

=== added file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/SmartValueHandler.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/SmartValueHandler.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/SmartValueHandler.java	2012-03-05 22:28:15 +0000
@@ -0,0 +1,37 @@
+/*
+   Copyright (c) 2012, 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.core.spi;
+
+import com.mysql.clusterj.core.store.ClusterTransaction;
+import com.mysql.clusterj.core.store.Operation;
+
+/** SmartValueHandler is the interface that must be implemented for
+ * operations that bypass the normal value handler and directly
+ * perform database operations.
+ */
+public interface SmartValueHandler extends ValueHandler {
+
+    Operation insert(ClusterTransaction clusterTransaction);
+
+    Operation delete(ClusterTransaction clusterTransaction);
+
+    Operation update(ClusterTransaction clusterTransaction);
+
+    Operation write(ClusterTransaction clusterTransaction);
+
+}

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/ValueHandler.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/ValueHandler.java	2011-02-02 09:52:33 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/ValueHandler.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -17,16 +17,18 @@
 
 package com.mysql.clusterj.core.spi;
 
+import java.lang.reflect.InvocationHandler;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 
 import com.mysql.clusterj.DynamicObjectDelegate;
+import com.mysql.clusterj.core.CacheManager;
 
 /** ValueHandler is the interface that must be implemented for core
  * components to access values of a managed instance.
  *
  */
-public interface ValueHandler extends DynamicObjectDelegate {
+public interface ValueHandler extends DynamicObjectDelegate, InvocationHandler {
 
     public String pkToString(DomainTypeHandler<?> domainTypeHandler);
 
@@ -42,6 +44,8 @@ public interface ValueHandler extends Dy
     byte[] getBytes(int fieldNumber);
     short getShort(int fieldNumber);
     int getInt(int fieldNumber);
+    byte[] getLobBytes(int fieldNumber);
+    String getLobString(int fieldNumber);
     long getLong(int fieldNumber);
     float getFloat(int fieldNumber);
     double getDouble(int fieldNumber);
@@ -69,6 +73,8 @@ public interface ValueHandler extends Dy
     void setLong(int fieldNumber, long value);
     void setFloat(int fieldNumber, float value);
     void setDouble(int fieldNumber, double value);
+    void setLobBytes(int fieldNumber, byte[] value);
+    void setLobString(int fieldNumber, String value);
     void setObjectBoolean(int fieldNumber, Boolean value);
     void setObjectByte(int fieldNumber, Byte value);
     void setObjectShort(int fieldNumber, Short value);
@@ -84,4 +90,7 @@ public interface ValueHandler extends Dy
     void setJavaSqlTime(int fieldNumber, java.sql.Time value);
     void setJavaSqlTimestamp(int fieldNumber, java.sql.Timestamp value);
 
+    void setCacheManager(CacheManager cm);
+    void setProxy(Object proxy);
+
 }

=== added file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/ValueHandlerFactory.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/ValueHandlerFactory.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/spi/ValueHandlerFactory.java	2012-03-05 22:28:15 +0000
@@ -0,0 +1,30 @@
+/*
+   Copyright (c) 2012, 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.core.spi;
+
+import com.mysql.clusterj.core.metadata.DomainTypeHandlerImpl;
+import com.mysql.clusterj.core.store.Db;
+
+/** ValueHandlerFactory allows a component to provide an alternative value handler.
+ *
+ */
+public interface ValueHandlerFactory {
+
+    <T> ValueHandler getValueHandler(DomainTypeHandlerImpl<T> domainTypeHandler, Db db);
+
+}

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/ClusterConnection.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/ClusterConnection.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/ClusterConnection.java	2012-03-05 22:28:15 +0000
@@ -17,6 +17,8 @@
 
 package com.mysql.clusterj.core.store;
 
+import com.mysql.clusterj.core.spi.ValueHandlerFactory;
+
 /**
  *
  */
@@ -36,4 +38,6 @@ public interface ClusterConnection {
 
     public void unloadSchema(String tableName);
 
+    public ValueHandlerFactory getSmartValueHandlerFactory();
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Column.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Column.java	2011-03-23 22:41:01 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Column.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -70,6 +70,12 @@ public interface Column {
      */
     public int getPrefixLength();
 
+    /** The size of a column in bytes. Integral types return the "precision" in bytes of the type
+     * (1, 2, 4, or 8 bytes). Character and byte types return 1. See getLength() for character and byte types.
+     * @return the size
+     */
+    public int getSize();
+
     /** The column ID, used for scans to compare column values.
      * 
      * @return the column id

=== modified file 'storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Operation.java'
--- a/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Operation.java	2012-01-23 00:44:39 +0000
+++ b/storage/ndb/clusterj/clusterj-core/src/main/java/com/mysql/clusterj/core/store/Operation.java	2012-03-05 22:28:15 +0000
@@ -89,4 +89,12 @@ public interface Operation {
 
     public void endDefinition();
 
+    public int getErrorCode();
+
+    public int getMysqlCode();
+
+    public int getStatus();
+
+    public int getClassification();
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBatchingJDBCSetImpl.java'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBatchingJDBCSetImpl.java	2011-11-22 22:53:33 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBatchingJDBCSetImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ *  Copyright (c) 2011, 2012, 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
@@ -17,6 +17,7 @@
 
 package com.mysql.clusterj.jdbc;
 
+import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.sql.Date;
@@ -25,6 +26,7 @@ import java.sql.Timestamp;
 
 import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.core.CacheManager;
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
 import com.mysql.clusterj.core.spi.ValueHandlerBatching;
 import com.mysql.clusterj.core.util.I18NHelper;
@@ -102,6 +104,11 @@ public class ValueHandlerBatchingJDBCSet
     }
 
     @Override
+    public byte[] getLobBytes(int arg0) {
+        return delegate.getBytes(fieldNumberToParameterNumber[arg0]);
+    }
+
+    @Override
     public double getDouble(int arg0) {
         return delegate.getDouble(fieldNumberToParameterNumber[arg0]);
     }
@@ -187,6 +194,11 @@ public class ValueHandlerBatchingJDBCSet
     }
 
     @Override
+    public String getLobString(int arg0) {
+        return delegate.getString(fieldNumberToParameterNumber[arg0]);
+    }
+
+    @Override
     public boolean isModified(int arg0) {
         return fieldNumberToParameterNumber[arg0] != -1;
     }
@@ -251,6 +263,12 @@ public class ValueHandlerBatchingJDBCSet
     }
 
     @Override
+    public void setLobBytes(int arg0, byte[] arg1) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
     public void setDouble(int arg0, double arg1) {
         throw new ClusterJFatalInternalException(
                 local.message("ERR_Should_Not_Occur"));
@@ -359,6 +377,12 @@ public class ValueHandlerBatchingJDBCSet
     }
 
     @Override
+    public void setLobString(int arg0, String arg1) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
     public ColumnMetadata[] columnMetadata() {
         throw new ClusterJFatalInternalException(
                 local.message("ERR_Should_Not_Occur"));
@@ -397,4 +421,25 @@ public class ValueHandlerBatchingJDBCSet
         return delegate.next();
     }
 
+    @Override
+    public void setCacheManager(CacheManager cm) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Unsupported_Method",
+                "setCacheManager(CacheManager)", "ValueHandlerBatching"));
+    }
+
+    @Override
+    public void setProxy(Object proxy) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Unsupported_Method",
+                "setProxy(Object)", "ValueHandlerBatching"));
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Unsupported_Method",
+                "invoke(Object, Method, Object[])", "ValueHandlerBatching"));
+    }
+
 }

=== modified 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	2011-12-05 23:29:53 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerBindValuesImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ *  Copyright (c) 2011, 2012, 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
@@ -17,6 +17,7 @@
 
 package com.mysql.clusterj.jdbc;
 
+import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.sql.Date;
@@ -28,6 +29,7 @@ import java.util.List;
 import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.ClusterJUserException;
 import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.core.CacheManager;
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
 import com.mysql.clusterj.core.spi.ValueHandlerBatching;
 import com.mysql.clusterj.core.util.I18NHelper;
@@ -180,6 +182,11 @@ public class ValueHandlerBindValuesImpl 
     }
 
     @Override
+    public byte[] getLobBytes(int fieldNumber) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
+    @Override
     public double getDouble(int fieldNumber) {
         BindValue bindValue = bindValues[getIndex(fieldNumber)];
         switch(bindValue.bufferType) {
@@ -400,6 +407,18 @@ public class ValueHandlerBindValuesImpl 
     }
 
     @Override
+    public String getLobString(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;
     }
@@ -455,6 +474,11 @@ public class ValueHandlerBindValuesImpl 
     }
 
     @Override
+    public void setLobBytes(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"));
     }
@@ -544,6 +568,11 @@ public class ValueHandlerBindValuesImpl 
     }
 
     @Override
+    public void setLobString(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"));
     }
@@ -568,4 +597,25 @@ public class ValueHandlerBindValuesImpl 
         throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
     }
 
+    @Override
+    public void setCacheManager(CacheManager cm) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Unsupported_Method",
+                "setCacheManager(CacheManager)", "ValueHandlerBindValuesImpl"));
+    }
+
+    @Override
+    public void setProxy(Object proxy) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Unsupported_Method",
+                "setProxy(Object)", "ValueHandlerBindValuesImpl"));
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Unsupported_Method",
+                "invoke(Object, Method, Object[])", "ValueHandlerBindValuesImpl"));
+    }
+
 }

=== 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-11-22 22:53:33 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/java/com/mysql/clusterj/jdbc/ValueHandlerImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ *  Copyright (c) 2011, 2012, 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
@@ -17,6 +17,7 @@
 
 package com.mysql.clusterj.jdbc;
 
+import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.sql.Date;
@@ -27,6 +28,7 @@ import java.sql.Timestamp;
 import com.mysql.clusterj.ClusterJDatastoreException;
 import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.core.CacheManager;
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
 import com.mysql.clusterj.core.spi.ValueHandlerBatching;
 import com.mysql.clusterj.core.util.I18NHelper;
@@ -125,6 +127,10 @@ public class ValueHandlerImpl implements
         throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
     }
 
+    public byte[] getLobBytes(int fieldNumber) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
     public double getDouble(int fieldNumber) {
         try {
             return parameterBindings.getDouble(getIndex(fieldNumber));
@@ -257,6 +263,14 @@ public class ValueHandlerImpl implements
         }
     }
 
+    public String getLobString(int fieldNumber) {
+        try {
+            return parameterBindings.getString(getIndex(fieldNumber));
+        } catch (SQLException e) {
+            throw new ClusterJDatastoreException(e);
+        }
+    }
+
     public boolean isModified(int fieldNumber) {
         return fieldNumberMap[fieldNumber] != -1;
     }
@@ -305,6 +319,10 @@ public class ValueHandlerImpl implements
         throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
     }
 
+    public void setLobBytes(int fieldNumber, byte[] value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
     public void setDouble(int fieldNumber, double value) {
         throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
     }
@@ -377,6 +395,10 @@ public class ValueHandlerImpl implements
         throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
     }
 
+    public void setLobString(int fieldNumber, String value) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
+    }
+
     public ColumnMetadata[] columnMetadata() {
         throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
     }
@@ -397,4 +419,25 @@ public class ValueHandlerImpl implements
         throw new ClusterJFatalInternalException(local.message("ERR_Should_Not_Occur"));
     }
 
+    @Override
+    public void setCacheManager(CacheManager cm) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Unsupported_Method",
+                "setCacheManager(CacheManager)", "ValueHandlerImpl"));
+    }
+
+    @Override
+    public void setProxy(Object proxy) {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Unsupported_Method",
+                "setProxy(Object)", "ValueHandlerImpl"));
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        throw new ClusterJFatalInternalException(
+                local.message("ERR_Unsupported_Method",
+                "invoke(Object, Method, Object[])", "ValueHandlerImpl"));
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-jdbc/src/main/resources/com/mysql/clusterj/jdbc/Bundle.properties'
--- a/storage/ndb/clusterj/clusterj-jdbc/src/main/resources/com/mysql/clusterj/jdbc/Bundle.properties	2011-09-05 09:27:51 +0000
+++ b/storage/ndb/clusterj/clusterj-jdbc/src/main/resources/com/mysql/clusterj/jdbc/Bundle.properties	2012-03-05 22:28:15 +0000
@@ -1,4 +1,4 @@
-# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2012, 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
@@ -20,6 +20,7 @@ statementInterceptors=com.mysql.clusterj
 ERR_No_Connection_Lifecycle_Interceptor:You must register a connection lifecycle interceptor using connection property \
 connectionLifecycleInterceptors=com.mysql.clusterj.jdbc.ConnectionLifecycleInterceptor
 ERR_Should_Not_Occur:Implementation error; please file a bug with a patch.
+ERR_Unsupported_Method:Method {0} is not supported by {1}.
 ERR_Column_Name_Not_In_Result:The column {0} is not part of the result.
 ERR_Column_Name_Not_In_Table:The column {0} is not in the list of columns {1} for the table {2}.
 ERR_Lexing_SQL:Error Lexing SQL: {0}.

=== modified file 'storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPAConfigurationImpl.java'
--- a/storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPAConfigurationImpl.java	2011-08-03 01:02:19 +0000
+++ b/storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPAConfigurationImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -25,6 +25,7 @@ import com.mysql.clusterj.core.SessionFa
 
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
 import com.mysql.clusterj.core.spi.DomainTypeHandlerFactory;
+import com.mysql.clusterj.core.spi.ValueHandlerFactory;
 import com.mysql.clusterj.core.store.Dictionary;
 import com.mysql.clusterj.core.util.I18NHelper;
 import com.mysql.clusterj.core.util.Logger;
@@ -378,7 +379,8 @@ public class NdbOpenJPAConfigurationImpl
      * must have already been registered via the openjpa clusterj path.
      */
     public <T> DomainTypeHandler<T> createDomainTypeHandler(
-            Class<T> domainClass, Dictionary dictionary) {
+            Class<T> domainClass, Dictionary dictionary,
+            ValueHandlerFactory valueHandlerFactory) {
         DomainTypeHandler<T> result = (DomainTypeHandler<T>) domainTypeHandlerMap.get(domainClass);
         if (result == null) {
             throw new ClusterJFatalInternalException(

=== modified file 'storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPADomainFieldHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPADomainFieldHandlerImpl.java	2011-08-03 01:02:19 +0000
+++ b/storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPADomainFieldHandlerImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -946,6 +946,20 @@ public class NdbOpenJPADomainFieldHandle
         public Object getValue(QueryExecutionContext context, String index) {
             return context.getObject(index);
         }
+
+        public Object objectGetValue(
+                AbstractDomainFieldHandlerImpl abstractDomainFieldHandlerImpl,
+                ValueHandler handler) {
+            throw new ClusterJFatalInternalException(
+                    local.message("ERR_Unsupported_Method","objectGetValue", "ObjectOperationHandlerRelationField"));
+        }
+
+        public void objectSetValue(AbstractDomainFieldHandlerImpl fmd,
+                Object value, ValueHandler handler) {
+            throw new ClusterJFatalInternalException(
+                    local.message("ERR_Unsupported_Method","objectSetValue", "ObjectOperationHandlerRelationField"));
+        }
+
     };
 
     static ObjectOperationHandler objectOperationHandlerRelationIntField =

=== modified file 'storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPADomainTypeHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPADomainTypeHandlerImpl.java	2011-12-29 14:39:37 +0000
+++ b/storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPADomainTypeHandlerImpl.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011 Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -40,6 +40,7 @@ import com.mysql.clusterj.core.query.Can
 import com.mysql.clusterj.core.spi.DomainFieldHandler;
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
 import com.mysql.clusterj.core.spi.ValueHandler;
+import com.mysql.clusterj.core.store.Db;
 import com.mysql.clusterj.core.store.Dictionary;
 import com.mysql.clusterj.core.store.Operation;
 import com.mysql.clusterj.core.store.PartitionKey;
@@ -249,7 +250,7 @@ public class NdbOpenJPADomainTypeHandler
         return null;
     }
 
-    public T newInstance() {
+    public T newInstance(Db db) {
         throw new ClusterJFatalInternalException(
                 local.message("ERR_Implementation_Should_Not_Occur"));
     }

=== modified file 'storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPAValueHandler.java'
--- a/storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPAValueHandler.java	2011-02-02 09:52:33 +0000
+++ b/storage/ndb/clusterj/clusterj-openjpa/src/main/java/com/mysql/clusterj/openjpa/NdbOpenJPAValueHandler.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -18,10 +18,13 @@
 package com.mysql.clusterj.openjpa;
 
 import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.core.CacheManager;
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
 import com.mysql.clusterj.core.spi.ValueHandler;
 import com.mysql.clusterj.core.util.Logger;
 import com.mysql.clusterj.core.util.LoggerFactoryService;
+
+import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.sql.Date;
@@ -312,4 +315,33 @@ public class NdbOpenJPAValueHandler impl
         throw new UnsupportedOperationException("Not supported yet.");
     }
 
+    public byte[] getLobBytes(int fieldNumber) {
+        return (byte[])sm.fetchObject(fieldNumber);
+    }
+
+    public String getLobString(int fieldNumber) {
+        return sm.fetchString(fieldNumber);
+    }
+
+    public void setCacheManager(CacheManager cm) {
+        // we do not need a cache manager...
+    }
+
+    public void setLobBytes(int fieldNumber, byte[] value) {
+        sm.storeObject(fieldNumber, value);
+    }
+
+    public void setLobString(int fieldNumber, String value) {
+        sm.storeString(fieldNumber, value);
+    }
+
+    public void setProxy(Object proxy) {
+        // we do not support Proxy domain model
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args)
+            throws Throwable {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-openjpa/src/main/resources/com/mysql/clusterj/openjpa/Bundle.properties'
--- a/storage/ndb/clusterj/clusterj-openjpa/src/main/resources/com/mysql/clusterj/openjpa/Bundle.properties	2011-01-31 09:07:01 +0000
+++ b/storage/ndb/clusterj/clusterj-openjpa/src/main/resources/com/mysql/clusterj/openjpa/Bundle.properties	2012-03-05 22:28:15 +0000
@@ -1,4 +1,4 @@
-# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2012, 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
@@ -27,6 +27,7 @@ ERR_Unsupported_Meta_Type:MetaType {0} n
 ERR_Datastore_Exception:Exception caught.
 ERR_Unsupported_Object_Type_For_Resolve:Unsupported object type {0} for resolve.
 ERR_Implementation_Should_Not_Occur:Implementation error; should not occur.
+ERR_Unsupported_Method:Method {0} is not supported by {1}.
 ERR_No_Oid_Field:There is no oid field defined for column {0}.
 ERR_No_Field_In_Oid_Class:Oid class {0} does not have a field named {1}.
 ERR_Security_Violation_For_Oid_Class:Security violation getting field for oid class {0}.

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractClusterJModelTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractClusterJModelTest.java	2011-11-22 22:41:42 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractClusterJModelTest.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -496,13 +496,18 @@ public abstract class AbstractClusterJMo
             int j = 0;
             for (ColumnDescriptor columnDescriptor: columnDescriptors) {
                 Object value = getColumnValue(i, j);
+                if (debug) System.out.println("generateInstances set field " + columnDescriptor.getColumnName()
+                        + " to value "  + value);
                 // set the column value in the instance
                 columnDescriptor.setFieldValue(instance, value);
-                // set the column value in the expected result
-                if (debug) System.out.println("generateInstances set field " + columnDescriptor.getColumnName() + " to value "  + value);
+                // check that the value was set correctly
+                Object actual = columnDescriptor.getFieldValue(instance);
+                errorIfNotEqual("generateInstances value mismatch for " + columnDescriptor.getColumnName(),
+                        dump(value), dump(actual));
                 ++j;
             }
             instances.add(instance);
+            // set the column values in the expected result
             Object[] expectedRow = createRow(columnDescriptors, instance);
             expected.add(expectedRow);
         }

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractClusterJTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractClusterJTest.java	2011-10-28 23:29:26 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AbstractClusterJTest.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2009, 2012, 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
@@ -628,6 +628,31 @@ public abstract class AbstractClusterJTe
         return result.toString();
     }
 
+    /** Convert the byte[] into a String to be used for logging and debugging.
+     * 
+     * @param bytes the byte[] to be dumped
+     * @return the String representation
+     */
+    public static String dumpBytes (byte[] bytes) {
+        StringBuffer buffer = new StringBuffer("byte[");
+        buffer.append(bytes.length);
+        buffer.append("]: [");
+        for (int i = 0; i < bytes.length; ++i) {
+            buffer.append((int)bytes[i]);
+            buffer.append(" ");
+        }
+        buffer.append("]");
+        return buffer.toString();
+    }
+
+    public static String dump(Object object) {
+        if (object instanceof byte[]) {
+            return dumpBytes((byte[])object);
+        } else {
+            return object.toString();
+        }
+    }
+
     /** Catch otherwise uncaught exceptions and maintain a list of them.
      * When needed, they can be obtained via the getUncaughtExceptions method.
      */

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AutoCommitTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AutoCommitTest.java	2011-06-30 16:04:23 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/AutoCommitTest.java	2012-03-05 22:28:15 +0000
@@ -1,6 +1,5 @@
 /*
-   Copyright (c) 2010 Sun Microsystems, Inc.
-   Use is subject to license terms.
+   Copyright (c) 2010, 2012, 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
@@ -101,8 +100,8 @@ public class AutoCommitTest extends Abst
         // QueryBuilder is the sessionFactory for queries
         QueryBuilder builder = session.getQueryBuilder();
         // QueryDomainType is the main interface
-        QueryDomainType dobj = builder.createQueryDefinition(Employee.class);
-        Query query = session.createQuery(dobj);
+        QueryDomainType<Employee> dobj = builder.createQueryDefinition(Employee.class);
+        Query<Employee> query = session.createQuery(dobj);
         List<Employee> result = query.getResultList();
         Set<Integer> expectedList = new HashSet<Integer>();
         for (int i: expected) {
@@ -112,7 +111,7 @@ public class AutoCommitTest extends Abst
         for (Employee e: result) {
             actualList.add(e.getId());
         }
-        errorIfNotEqual("Mismatch in query result", expectedList, actualList);
+        errorIfNotEqual("Mismatch in query result list", expectedList, actualList);
     }
 
     protected void nontransactionalUpdate(int which, int newAge) {
@@ -120,7 +119,7 @@ public class AutoCommitTest extends Abst
         e.setAge(newAge);
         session.updatePersistent(e);
         e = session.find(Employee.class, which);
-        errorIfNotEqual("Mismatch in updateAll result", newAge, e.getAge());
+        errorIfNotEqual("Mismatch in nontransactionalUpdate result age", newAge, e.getAge());
     }
 
     protected void nontransactionalUpdateAll(int low, int high, int newAge) {
@@ -133,7 +132,7 @@ public class AutoCommitTest extends Abst
         session.updatePersistentAll(emps);
         for (int i = low; i < high; ++i) {
             Employee e = session.find(Employee.class, i);
-            errorIfNotEqual("Mismatch in updateAll result", newAge, e.getAge());
+            errorIfNotEqual("Mismatch in nontransactionalUpdateAll result age", newAge, e.getAge());
         }
     }
 
@@ -144,6 +143,6 @@ public class AutoCommitTest extends Abst
     }
 
     private void nontransactionalFind(int which) {
-        Employee e = session.find(Employee.class, which);
+        session.find(Employee.class, which);
     }
 }

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/BinaryPKTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/BinaryPKTest.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/BinaryPKTest.java	2012-03-05 22:28:15 +0000
@@ -160,7 +160,6 @@ public class BinaryPKTest extends Abstra
     }
 
     protected void verifyStorage(String where, BinaryPK instance, int index, boolean updated) {
-        errorIfNotEqual(where + "mismatch on id", toString(getStoragePK(index)), toString(instance.getId()));
         errorIfNotEqual(where + "mismatch on number", index, instance.getNumber());
         if (updated) {
             errorIfNotEqual(where + "mismatch on name", getValue(NUMBER_OF_INSTANCES - index), instance.getName());

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/CharsetTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/CharsetTest.java	2011-06-30 16:04:23 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/CharsetTest.java	2012-03-05 22:28:15 +0000
@@ -1,6 +1,5 @@
 /*
-   Copyright (c) 2010 Sun Microsystems, Inc.
-   Use is subject to license terms.
+   Copyright (c) 2010, 2012, 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
@@ -166,8 +165,7 @@ public class CharsetTest extends Abstrac
         writeToJDBC(columnDescriptor, tableName, instances);
         result = readFromJDBC(columnDescriptor, tableName);
         if (debug) System.out.println("Returned results of size " + result.size());
-//        if (debug) System.out.println("Results:\n" + dump(result));
-        verify("writeJDBCreadJDBC", strings, result, columnDescriptor);
+        verify("writeJDBCreadJDBC ", strings, result, columnDescriptor);
     }
 
     protected void writeJDBCreadNDB(String charsetName, String tableName, Class<? extends CharsetModel> modelClass,
@@ -179,8 +177,7 @@ public class CharsetTest extends Abstrac
         writeToJDBC(columnDescriptor, tableName, instances);
         result = readFromNDB(columnDescriptor, modelClass);
         if (debug) System.out.println("Returned results of size " + result.size());
-//        if (debug) System.out.println("Results: " + dump(result));
-        verify("writeJDBCreadNDB", strings, result, columnDescriptor);
+        verify("writeJDBCreadNDB ", strings, result, columnDescriptor);
     }
 
     protected void writeNDBreadJDBC(String charsetName, String tableName, Class<? extends CharsetModel> modelClass,
@@ -192,8 +189,7 @@ public class CharsetTest extends Abstrac
         writeToNDB(columnDescriptor, instances);
         result = readFromJDBC(columnDescriptor, tableName);
         if (debug) System.out.println("Returned results of size " + result.size());
-//        if (debug) System.out.println("Results: " + dump(result));
-        verify("writeNDBreadJDBC", strings, result, columnDescriptor);
+        verify("writeNDBreadJDBC ", strings, result, columnDescriptor);
     }
 
     protected void writeNDBreadNDB(String charsetName, String tableName, Class<? extends CharsetModel> modelClass,
@@ -205,8 +201,7 @@ public class CharsetTest extends Abstrac
         writeToNDB(columnDescriptor, instances);
         result = readFromNDB(columnDescriptor, modelClass);
         if (debug) System.out.println("Returned results of size " + result.size());
-//        if (debug) System.out.println("Results: " + dump(result));
-        verify("writeNDBreadNDB", strings, result, columnDescriptor);
+        verify("writeNDBreadNDB ", strings, result, columnDescriptor);
     }
 
     private void verify(String where, List<String> expecteds, List<String> actuals, ColumnDescriptor columnDescriptor) {
@@ -214,15 +209,19 @@ public class CharsetTest extends Abstrac
         for (int i = 0; i < expecteds.size(); ++i) {
             String expected = expecteds.get(i);
             String actual = actuals.get(i);
-            int expectedLength = expected.length();
-            int actualLength = actual.length();
-            errorIfNotEqual(where + " got failure on size of column data for column width " + columnDescriptor.columnWidth + " at row " + i, expectedLength, actualLength);
-            if (expectedLength != actualLength) 
-                continue;
-            for (int j = 0; j < expected.length(); ++j) {
-                if (--maxErrors > 0) {
-                    errorIfNotEqual("Failure to match column data for column width " + columnDescriptor.columnWidth + " at row " + i + " column " + j,
-                            expected.codePointAt(j), actual.codePointAt(j));
+            if (actual == null) {
+                error(where + columnDescriptor.columnName + " actual column " + i + " was null.");
+            } else {
+                int expectedLength = expected.length();
+                int actualLength = actual.length();
+                errorIfNotEqual(where + "got failure on size of column data for column width " + columnDescriptor.columnWidth + " at row " + i, expectedLength, actualLength);
+                if (expectedLength != actualLength) 
+                    continue;
+                for (int j = 0; j < expected.length(); ++j) {
+                    if (--maxErrors > 0) {
+                        errorIfNotEqual("Failure to match column data for column width " + columnDescriptor.columnWidth + " at row " + i + " column " + j,
+                                expected.codePointAt(j), actual.codePointAt(j));
+                    }
                 }
             }
         }
@@ -236,7 +235,6 @@ public class CharsetTest extends Abstrac
         CharsetEncoder encoder = charset.newEncoder();
        // add all encodable characters to the buffer
         int count = 0;
-//        for (int i = 0; i < 65536; ++i) {
         for (int i = 0; i < 65536; ++i) {
             Character ch = (char)i;
             if (encoder.canEncode(ch)) {

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/LoadTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/LoadTest.java	2011-06-30 16:04:23 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/LoadTest.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2011, 2012, 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
@@ -88,7 +88,7 @@ public class LoadTest extends AbstractCl
             // see if it is the right Employee
             errorIfNotEqual("load after flush employee id mismatch", i, e.getId());
             // make sure all fields were fetched
-            consistencyCheckDynamicEmployee(e);
+            consistencyCheckDynamicEmployee("load after flush", e);
         }
         tx.commit();
     }
@@ -113,17 +113,17 @@ public class LoadTest extends AbstractCl
             // see if it is the right Employee
             errorIfNotEqual("loadFindNoFlush after find employee id mismatch", i, e.getId());
             // make sure all fields were fetched
-            consistencyCheckDynamicEmployee(e);
+            consistencyCheckDynamicEmployee("loadFindNoFlush", e);
         }
         tx.commit();
     }
 
-    private void consistencyCheckDynamicEmployee(DynamicEmployee e) {
+    private void consistencyCheckDynamicEmployee(String where, DynamicEmployee e) {
         int id = e.getId();
         String name = e.getName();
-        errorIfNotEqual("consistencyCheckDynamicEmployee name mismatch", "Employee number " + id, name);
-        errorIfNotEqual("consistencyCheckDynamicEmployee age mismatch", id, e.getAge());
-        errorIfNotEqual("consistencyCheckDynamicEmployee magic mismatch", id, e.getMagic());
+        errorIfNotEqual(where + " consistencyCheckDynamicEmployee name mismatch", "Employee number " + id, name);
+        errorIfNotEqual(where + " consistencyCheckDynamicEmployee age mismatch", id, e.getAge());
+        errorIfNotEqual(where + " consistencyCheckDynamicEmployee magic mismatch", id, e.getMagic());
     }
 
     private void loadNoFlush() {
@@ -131,11 +131,13 @@ public class LoadTest extends AbstractCl
         loaded.clear();
         tx.begin();
         e = session.newInstance(DynamicEmployee.class, 0);
+        // default value is 0 for int
         errorIfNotEqual("loadNoFlush after newInstance employee id mismatch", 0, e.getId());
+        // default value is null for String
+        errorIfNotEqual("loadNoFlush after newInstance employee name mismatch", null, e.getName());
         session.load(e);
         errorIfNotEqual("loadNoFlush after load employee id mismatch", 0, e.getId());
-        errorIfNotEqual("loadNoFlush after load employee name mismatch",
-                null, e.getName());
+        errorIfNotEqual("loadNoFlush after load employee name mismatch", null, e.getName());
         tx.commit();
     }
 

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/MultithreadedTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/MultithreadedTest.java	2011-02-02 09:52:33 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/MultithreadedTest.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -103,7 +103,7 @@ public class MultithreadedTest extends A
         for (int i = 0; i < numberToCreate; ++i) {
             Customer customer = session.newInstance(Customer.class);
             customer.setId(i);
-            customer.setName("Customer number " + i);
+            customer.setName("Customer number " + i + " (initial)");
             customer.setMagic(i * 100);
             customers.add(customer);
         }
@@ -167,14 +167,20 @@ public class MultithreadedTest extends A
         Query<OrderLine> query = session.createQuery(queryOrderType);        
         for (Order order: orders) {
             int orderId = order.getId();
+            if (getDebug()) System.out.println("Read order " + orderId + " total " + order.getValue());
             // replace order with its persistent representation
             order = session.find(Order.class, orderId);
             double expectedTotal = order.getValue();
             double actualTotal = 0.0d;
+            List<OrderLine> orderLines = new ArrayList<OrderLine>();
             for (OrderLine orderLine: getOrderLines(session, query, orderId)) {
+                orderLines.add(orderLine);
+                if (getDebug()) System.out.println("order " + orderLine.getOrderId() +
+                        " orderline " + orderLine.getId() + " value " + orderLine.getTotalValue());
                 actualTotal += orderLine.getTotalValue();
             }
-            errorIfNotEqual("For order " + orderId + ", order value does not equal sum of order line values.",
+            errorIfNotEqual("For order " + orderId + ", order value does not equal sum of order line values."
+                    + " orderLines: " + dump(orderLines),
                     expectedTotal, actualTotal);
         }
         failOnError();
@@ -253,6 +259,8 @@ public class MultithreadedTest extends A
         Double orderValue = 0.0d;
         // now create some order lines
         int numberOfOrderLines = random.nextInt(maximumOrderLinesPerOrder);
+        if (getDebug()) System.out.println("Create Order " + orderid
+                + " with numberOfOrderLines: " + numberOfOrderLines);
         for (int i = 0; i < numberOfOrderLines; ++i) {
             int orderLineNumber = getNextOrderLineId();
             OrderLine orderLine = session.newInstance(OrderLine.class);
@@ -264,8 +272,9 @@ public class MultithreadedTest extends A
             orderLine.setUnitPrice(unitPrice);
             double orderLineValue = unitPrice * quantity;
             orderValue += orderLineValue;
-            if (getDebug()) System.out.println("For order " + orderid + " orderline " + orderLineNumber + 
-                    " order line value " + orderLineValue + " order value " + orderValue);
+            if (getDebug()) System.out.println("Create orderline " + orderLineNumber + " for Order " + orderid
+                    + " quantity " + quantity + " price " + unitPrice
+                    + " order line value " + orderLineValue + " order value " + orderValue);
             orderLine.setTotalValue(orderLineValue);
             addOrderLine(orderLine);
             session.persist(orderLine);
@@ -367,9 +376,9 @@ public class MultithreadedTest extends A
             if (numberOfOrders < 10) {
                 return null;
             }
-            int orderId = random.nextInt(numberOfOrders);
+            int which = random.nextInt(numberOfOrders);
             ++numberOfDeletedOrders;
-            return orders.remove(orderId);
+            return orders.remove(which);
         }
     }
 
@@ -394,7 +403,8 @@ public class MultithreadedTest extends A
      */
     private int getNextCustomerId() {
         synchronized(customers) {
-            return nextCustomerId++;
+            int result = nextCustomerId++;
+            return result;
         }
     }
     
@@ -403,7 +413,8 @@ public class MultithreadedTest extends A
      */
     private int getNextOrderId() {
         synchronized(orders) {
-            return nextOrderId++;
+            int result = nextOrderId++;
+            return result;
         }
     }
 
@@ -412,7 +423,8 @@ public class MultithreadedTest extends A
      */
     private int getNextOrderLineId() {
         synchronized(orderlines) {
-            return nextOrderLineId++;
+            int result = nextOrderLineId++;
+            return result;
         }
     }
     

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/StressTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/StressTest.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/StressTest.java	2012-03-05 22:28:15 +0000
@@ -22,7 +22,9 @@ import java.nio.ByteBuffer;
 import org.junit.Ignore;
 
 import com.mysql.clusterj.ClusterJFatalUserException;
+import com.mysql.clusterj.ClusterJHelper;
 import com.mysql.clusterj.ColumnMetadata;
+import com.mysql.clusterj.ColumnType;
 import com.mysql.clusterj.DynamicObject;
 
 import testsuite.clusterj.AbstractClusterJModelTest;
@@ -39,18 +41,14 @@ public class StressTest extends Abstract
 
     private static final int ITERATIONS_TO_DROP = 3;
 
-    private static String tableName;
-
     private static final String STRESS_TEST_TABLE_PROPERTY_NAME = "com.mysql.clusterj.StressTestTable";
 
-    static {
-        String env = System.getenv(STRESS_TEST_TABLE_PROPERTY_NAME);
-        String def = (env == null)?"stress":env;
-        tableName = System.getProperty(STRESS_TEST_TABLE_PROPERTY_NAME, def);
-    }
+    private static String tableName = ClusterJHelper.getStringProperty(STRESS_TEST_TABLE_PROPERTY_NAME, "stress");
 
     private ColumnMetadata[] columnMetadatas;
 
+    private ColumnMetadata keyMetadata;
+
     private Timer timer = new Timer();
 
     private static int BYTES_LENGTH = 12000;
@@ -64,6 +62,8 @@ public class StressTest extends Abstract
         }
     }
 
+    private static final byte[] DIGITS = new byte[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
+
     private static int STRING_LENGTH = 12000;
 
     private static String STRING;
@@ -89,6 +89,7 @@ public class StressTest extends Abstract
         tx = session.currentTransaction();
         session.deletePersistentAll(Stress.class);
         columnMetadatas = session.newInstance(Stress.class).columnMetadata();
+        findKeyMetadata();
     }
 
     public void testIndy() {
@@ -112,6 +113,9 @@ public class StressTest extends Abstract
     public void insAattr_indy() {
         long total = 0;
         for (int i = 0; i < ITERATIONS; ++i) {
+            // first delete existing rows
+            if (tx.isActive()) tx.rollback();
+            session.deletePersistentAll(Stress.class);
             // garbage collect what we can before each test
             gc();
             timer.start();
@@ -119,7 +123,7 @@ public class StressTest extends Abstract
                 Stress instance = createObject(key);
                 session.makePersistent(instance);
             }
-            // drop the first iteration
+            // drop the first 'n' iterations
             timer.stop();
             if (i >= ITERATIONS_TO_DROP) total += timer.time();
             System.out.println("insAattr_indy: " + timer.time());
@@ -130,6 +134,9 @@ public class StressTest extends Abstract
     public void insAattr_each() {
         long total = 0;
         for (int i = 0; i < ITERATIONS; ++i) {
+            // first delete existing rows
+            if (tx.isActive()) tx.rollback();
+            session.deletePersistentAll(Stress.class);
             // garbage collect what we can before each test
             gc();
             timer.start();
@@ -140,7 +147,7 @@ public class StressTest extends Abstract
                 session.flush();
             }
             session.currentTransaction().commit();
-            // drop the first iteration
+            // drop the first 'n' iterations
             timer.stop();
             if (i >= ITERATIONS_TO_DROP) total += timer.time();
             System.out.println("insAattr_each: " + timer.time());
@@ -151,6 +158,9 @@ public class StressTest extends Abstract
     public void insAattr_bulk() {
         long total = 0;
         for (int i = 0; i < ITERATIONS; ++i) {
+            // first delete existing rows
+            if (tx.isActive()) tx.rollback();
+            session.deletePersistentAll(Stress.class);
             // garbage collect what we can before each test
             gc();
             timer.start();
@@ -160,7 +170,7 @@ public class StressTest extends Abstract
                 session.makePersistent(instance);
             }
             session.currentTransaction().commit();
-            // drop the first iteration
+            // drop the first 'n' iterations
             timer.stop();
             if (i >= ITERATIONS_TO_DROP) total += timer.time();
             System.out.println("insAattr_bulk: " + timer.time());
@@ -175,9 +185,9 @@ public class StressTest extends Abstract
             gc();
             timer.start();
             for (int key = 0; key < NUMBER_TO_INSERT; ++key) {
-                session.find(Stress.class, key);
+                session.find(Stress.class, createKey(key));
             }
-            // drop the first iteration
+            // drop the first 'n' iterations
             timer.stop();
             if (i >= ITERATIONS_TO_DROP) total += timer.time();
             System.out.println("getA_indy: " + timer.time());
@@ -193,10 +203,10 @@ public class StressTest extends Abstract
             timer.start();
             session.currentTransaction().begin();
             for (int key = 0; key < NUMBER_TO_INSERT; ++key) {
-                session.find(Stress.class, key);
+                session.find(Stress.class, createKey(key));
             }
             session.currentTransaction().commit();
-            // drop the first iteration
+            // drop the first 'n' iterations
             timer.stop();
             if (i >= ITERATIONS_TO_DROP) total += timer.time();
             System.out.println("getA_each: " + timer.time());
@@ -212,11 +222,11 @@ public class StressTest extends Abstract
             timer.start();
             session.currentTransaction().begin();
             for (int key = 0; key < NUMBER_TO_INSERT; ++key) {
-                Stress instance = createObject(key);
+                Stress instance = session.newInstance(Stress.class, createKey(key));
                 session.load(instance);
             }
             session.currentTransaction().commit();
-            // drop the first iteration
+            // drop the first 'n' iterations
             timer.stop();
             if (i >= ITERATIONS_TO_DROP) total += timer.time();
             System.out.println("getA_bulk: " + timer.time());
@@ -231,9 +241,9 @@ public class StressTest extends Abstract
             gc();
             timer.start();
             for (int key = 0; key < NUMBER_TO_INSERT; ++key) {
-                session.deletePersistent(Stress.class, key);
+                session.deletePersistent(Stress.class, createKey(key));
             }
-            // drop the first iteration
+            // drop the first 'n' iterations
             timer.stop();
             if (i >= ITERATIONS_TO_DROP) total += timer.time();
             System.out.println("delA_indy: " + timer.time());
@@ -249,11 +259,11 @@ public class StressTest extends Abstract
             timer.start();
             session.currentTransaction().begin();
             for (int key = 0; key < NUMBER_TO_INSERT; ++key) {
-                session.deletePersistent(Stress.class, key);
+                session.deletePersistent(Stress.class, createKey(key));
                 session.flush();
             }
             session.currentTransaction().commit();
-            // drop the first iteration
+            // drop the first 'n' iterations
             timer.stop();
             if (i >= ITERATIONS_TO_DROP) total += timer.time();
             System.out.println("delA_each: " + timer.time());
@@ -269,10 +279,10 @@ public class StressTest extends Abstract
             timer.start();
             session.currentTransaction().begin();
             for (int key = 0; key < NUMBER_TO_INSERT; ++key) {
-                session.deletePersistent(Stress.class, key);
+                session.deletePersistent(Stress.class, createKey(key));
             }
             session.currentTransaction().commit();
-            // drop the first iteration
+            // drop the first 'n' iterations
             timer.stop();
             if (i >= ITERATIONS_TO_DROP) total += timer.time();
             System.out.println("delA_bulk: " + timer.time());
@@ -281,18 +291,16 @@ public class StressTest extends Abstract
     }
 
     protected Stress createObject(int key) {
-        Stress instance = session.newInstance(Stress.class, key);
+        Stress instance = session.newInstance(Stress.class);
         for (int columnNumber = 0; columnNumber < columnMetadatas.length; ++columnNumber) {
             Object value = null;
             // create value based on java type
             ColumnMetadata columnMetadata = columnMetadatas[columnNumber];
-            if (columnMetadata.isPrimaryKey()) {
-                // we have already set the value of the primary key in newInstance
-                continue;
-            }
             Class<?> cls = columnMetadata.javaType();
             int length = columnMetadata.maximumLength();
-            if (int.class == cls) {
+            if (columnMetadata.isPrimaryKey()) {
+                value = createKey(key);
+            } else if (int.class == cls) {
                 value = key + columnNumber;
             } else if (long.class == cls) {
                 value = (long)(key + columnNumber);
@@ -333,7 +341,72 @@ public class StressTest extends Abstract
         return instance;
     }
 
+    private Object createKey(int key) {
+        Object value = null;
+        Class<?> cls = keyMetadata.javaType();
+        int length = keyMetadata.maximumLength();
+        if (int.class == cls) {
+            value = key;
+        } else if (long.class == cls) {
+            value = (long)key;
+        } else if (String.class == cls) {
+            value = String.valueOf(key);
+        } else if (byte[].class == cls) {
+            String digits = String.valueOf(key);
+            if (keyMetadata.columnType() == ColumnType.Binary) {
+                // fixed length
+                value = new byte[length];
+            } else if (keyMetadata.columnType() == ColumnType.Varbinary) {
+                // variable length
+                value = new byte[digits.length()];
+            }
+            convertToBytes((byte[])value, digits);
+            if (debug) System.out.println("Key: " + dump((byte[])value));
+        } else throw new ClusterJFatalUserException("Unsupported column type " + cls.getName()
+                + " for column " + keyMetadata.name());
+        return value;
+    }
+
+    private void findKeyMetadata() {
+        // TODO currently only supports a single key column
+        for (ColumnMetadata columnMetadata: columnMetadatas) {
+            if (columnMetadata.isPrimaryKey()) {
+                if (keyMetadata != null) {
+                    throw new RuntimeException("Compound primary keys are not supported.");
+                }
+                keyMetadata = columnMetadata;
+            }
+        }
+    }
+
+    private String dump(byte[] value) {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < value.length; ++i) {
+            builder.append("0123456789".charAt(value[i] - '0'));
+        }
+        return builder.toString();
+    }
+
+    /** Convert the digits into a byte[] by translating each digit to a byte
+     * 
+     * @param value the byte [] to convert
+     * @param digits the value
+     */
+    private void convertToBytes(byte[] value, String digits) {
+        int j = digits.length();
+        for (int i = value.length - 1; i >= 0; --i) {
+            if (j-- > 0) {
+                int digit = digits.charAt(j) - '0';
+                value[i] = DIGITS[digit];
+            } else {
+                // done with digits
+                value[i] = '0';
+            }
+        }
+    }
+
     public static class Stress extends DynamicObject implements IdBase {
+
         public Stress() {}
 
         public String table() {

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/VarcharStringLengthTest.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/VarcharStringLengthTest.java	2011-06-30 16:04:23 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/VarcharStringLengthTest.java	2012-03-05 22:28:15 +0000
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2010, 2012, 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
@@ -45,11 +45,11 @@ public class VarcharStringLengthTest ext
 
     public void test() {
         for (int i = 0; i < 500; ++i) {
+            try {
             Employee e = session.newInstance(Employee.class, i);
             e.setName(name.substring(0, i));
             e.setAge(i);
             e.setMagic(i);
-            try {
                 session.makePersistent(e);
                 if (i > 32) {
                     // unexpected success for lengths greater than varchar size

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/domaintypehandler/CrazyDomainTypeHandlerFactoryImpl.java'
--- a/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/domaintypehandler/CrazyDomainTypeHandlerFactoryImpl.java	2011-12-29 14:39:37 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/java/testsuite/clusterj/domaintypehandler/CrazyDomainTypeHandlerFactoryImpl.java	2012-03-05 22:28:15 +0000
@@ -23,8 +23,10 @@ import com.mysql.clusterj.core.spi.Domai
 import com.mysql.clusterj.core.spi.DomainTypeHandler;
 import com.mysql.clusterj.core.spi.DomainTypeHandlerFactory;
 import com.mysql.clusterj.core.spi.ValueHandler;
+import com.mysql.clusterj.core.spi.ValueHandlerFactory;
 import com.mysql.clusterj.core.store.ClusterTransaction;
 import com.mysql.clusterj.core.store.Column;
+import com.mysql.clusterj.core.store.Db;
 import com.mysql.clusterj.core.store.Dictionary;
 import com.mysql.clusterj.core.store.Operation;
 import com.mysql.clusterj.core.store.PartitionKey;
@@ -56,7 +58,8 @@ public class CrazyDomainTypeHandlerFacto
         }
     }
 
-    public <T> DomainTypeHandler<T> createDomainTypeHandler(Class<T> domainClass, Dictionary dictionary) {
+    public <T> DomainTypeHandler<T> createDomainTypeHandler(Class<T> domainClass, Dictionary dictionary,
+            ValueHandlerFactory valueHandlerFactory) {
         String className = domainClass.getSimpleName();
         if (className.startsWith("Throw")) {
             String throwClassName = className.substring(5);
@@ -103,7 +106,7 @@ public class CrazyDomainTypeHandlerFacto
                     throw new UnsupportedOperationException("Nice Job!");
                 }
 
-                public T newInstance() {
+                public T newInstance(Db db) {
                     throw new UnsupportedOperationException("Not supported yet.");
                 }
 

=== modified file 'storage/ndb/clusterj/clusterj-test/src/main/resources/schema.sql'
--- a/storage/ndb/clusterj/clusterj-test/src/main/resources/schema.sql	2012-01-21 02:22:20 +0000
+++ b/storage/ndb/clusterj/clusterj-test/src/main/resources/schema.sql	2012-03-05 22:28:15 +0000
@@ -706,6 +706,26 @@ create table longintstringix (
  KEY idx_long_int_string (longix, intix, stringix)
 ) ENGINE=ndbcluster DEFAULT CHARSET=latin1;
 
+drop table if exists cassandra_string;
+create table cassandra_string (
+  id varchar(10),
+  c1 varchar(34),
+  c2 varchar(34),
+  c3 varchar(34),
+  c4 varchar(34),
+  c5 varchar(34)
+) ENGINE=ndbcluster DEFAULT CHARSET=latin1;
+
+drop table if exists cassandra_byte_array;
+create table cassandra_byte_array (
+  id binary(10) primary key,
+  c1 binary(34),
+  c2 binary(34),
+  c3 binary(34),
+  c4 binary(34),
+  c5 binary(34)
+) ENGINE=ndbcluster DEFAULT CHARSET=latin1;
+
 drop table if exists stress;
 create table stress (
   id int not null primary key,

=== modified file 'storage/ndb/clusterj/clusterj-tie/Makefile.am'
--- a/storage/ndb/clusterj/clusterj-tie/Makefile.am	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/Makefile.am	2012-03-05 22:28:15 +0000
@@ -46,6 +46,8 @@ clusterj_tie_java= \
   $(clusterj_tie_src)/com/mysql/clusterj/tie/NdbRecordKeyOperationImpl.java \
   $(clusterj_tie_src)/com/mysql/clusterj/tie/NdbRecordOperationImpl.java \
   $(clusterj_tie_src)/com/mysql/clusterj/tie/NdbRecordResultDataImpl.java \
+  $(clusterj_tie_src)/com/mysql/clusterj/tie/NdbRecordSmartValueHandlerFactoryImpl.java \
+  $(clusterj_tie_src)/com/mysql/clusterj/tie/NdbRecordSmartValueHandlerImpl.java \
   $(clusterj_tie_src)/com/mysql/clusterj/tie/OperationImpl.java \
   $(clusterj_tie_src)/com/mysql/clusterj/tie/ResultDataImpl.java \
   $(clusterj_tie_src)/com/mysql/clusterj/tie/ScanFilterImpl.java \

=== modified file 'storage/ndb/clusterj/clusterj-tie/pom.xml'
--- a/storage/ndb/clusterj/clusterj-tie/pom.xml	2012-01-21 02:01:48 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/pom.xml	2012-03-05 22:28:15 +0000
@@ -117,7 +117,7 @@
         <configuration>
           <instructions>
             <Export-Package>com.mysql.clusterj.tie.*</Export-Package>
-            <Import-Package>com.mysql.clusterj,com.mysql.clusterj.core.store,com.mysql.clusterj.core.spi,com.mysql.clusterj.core.util,com.mysql.ndbjtie.mysql,com.mysql.ndbjtie.ndbapi</Import-Package>
+            <Import-Package>com.mysql.clusterj,com.mysql.clusterj.core, com.mysql.clusterj.core.metadata,com.mysql.clusterj.core.store,com.mysql.clusterj.core.spi,com.mysql.clusterj.core.util,com.mysql.ndbjtie.mysql,com.mysql.ndbjtie.ndbapi</Import-Package>
           </instructions>
         </configuration>
       </plugin>

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/BlobImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/BlobImpl.java	2012-01-23 00:44:39 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/BlobImpl.java	2012-03-05 22:28:15 +0000
@@ -74,6 +74,10 @@ class BlobImpl implements Blob {
     }
 
     public void writeData(byte[] array) {
+        if (array == null) {
+            setNull();
+            return;
+        }
         // TODO can we really skip this when updating to an empty blob?
         if (array.length == 0) return;
         ByteBuffer buffer = null;
@@ -87,6 +91,10 @@ class BlobImpl implements Blob {
     }
 
     public void setValue(byte[] array) {
+        if (array == null) {
+            setNull();
+            return;
+        }
         // TODO can we really skip this when updating to an empty blob?
         if (array.length == 0) return;
         ByteBuffer buffer = null;

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterConnectionImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterConnectionImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterConnectionImpl.java	2012-03-05 22:28:15 +0000
@@ -29,7 +29,9 @@ import com.mysql.ndbjtie.ndbapi.NdbDicti
 
 import com.mysql.clusterj.ClusterJDatastoreException;
 import com.mysql.clusterj.ClusterJFatalInternalException;
+import com.mysql.clusterj.ClusterJHelper;
 
+import com.mysql.clusterj.core.spi.ValueHandlerFactory;
 import com.mysql.clusterj.core.store.Db;
 import com.mysql.clusterj.core.store.Table;
 
@@ -68,6 +70,11 @@ public class ClusterConnectionImpl
     /** The dictionary used to create NdbRecords */
     Dictionary dictionaryForNdbRecord = null;
 
+    private static final String USE_SMART_VALUE_HANDLER_NAME = "com.mysql.clusterj.UseSmartValueHandler";
+
+    private static final boolean USE_SMART_VALUE_HANDLER =
+            ClusterJHelper.getBooleanProperty(USE_SMART_VALUE_HANDLER_NAME, "true");
+
     /** Connect to the MySQL Cluster
      * 
      * @param connectString the connect string
@@ -235,4 +242,16 @@ public class ClusterConnectionImpl
         dictionaryForNdbRecord.removeCachedTable(tableName);
     }
 
+    public ValueHandlerFactory getSmartValueHandlerFactory() {
+        ValueHandlerFactory result = null;
+        if (USE_SMART_VALUE_HANDLER) {
+            result = new NdbRecordSmartValueHandlerFactoryImpl();
+        }
+        return result;
+    }
+
+    public NdbRecordOperationImpl newNdbRecordOperationImpl(DbImpl db, Table storeTable) {
+        return new NdbRecordOperationImpl(this, db, storeTable);
+    }
+            
 }

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterTransactionImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterTransactionImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ClusterTransactionImpl.java	2012-03-05 22:28:15 +0000
@@ -22,7 +22,9 @@ import java.util.ArrayList;
 import java.util.List;
 
 import com.mysql.clusterj.ClusterJDatastoreException;
+import com.mysql.clusterj.ClusterJException;
 import com.mysql.clusterj.ClusterJFatalInternalException;
+import com.mysql.clusterj.ClusterJHelper;
 import com.mysql.clusterj.LockMode;
 
 import com.mysql.clusterj.core.store.ClusterTransaction;
@@ -68,7 +70,7 @@ class ClusterTransactionImpl implements 
             .getInstance(ClusterTransactionImpl.class);
 
     protected final static String USE_NDBRECORD_NAME = "com.mysql.clusterj.UseNdbRecord";
-    private static boolean USE_NDBRECORD = getUseNdbRecord();
+    private static boolean USE_NDBRECORD = ClusterJHelper.getBooleanProperty(USE_NDBRECORD_NAME, "true");
 
     protected NdbTransaction ndbTransaction;
     private List<Runnable> postExecuteCallbacks = new ArrayList<Runnable>();
@@ -114,6 +116,8 @@ class ClusterTransactionImpl implements 
 
     private BufferManager bufferManager;
 
+    private List<Operation> operationsToCheck = new ArrayList<Operation>();
+
     public ClusterTransactionImpl(ClusterConnectionImpl clusterConnectionImpl,
             DbImpl db, Dictionary ndbDictionary, String joinTransactionId) {
         this.db = db;
@@ -400,11 +404,11 @@ class ClusterTransactionImpl implements 
      * @param buffer the buffer with data for the operation
      * @param mask the mask of column values already set in the buffer
      * @param options the OperationOptions for this operation
-     * @param i 
-     * @return
+     * @return the insert operation
      */
     public NdbOperationConst insertTuple(NdbRecordConst ndbRecord,
             ByteBuffer buffer, byte[] mask, OperationOptionsConst options) {
+        enlist();
         NdbOperationConst operation = ndbTransaction.insertTuple(ndbRecord, buffer, mask, options, 0);
         handleError(operation, ndbTransaction);
         return operation;
@@ -420,11 +424,44 @@ class ClusterTransactionImpl implements 
      */
     public NdbOperationConst deleteTuple(NdbRecordConst ndbRecord,
             ByteBuffer buffer, byte[] mask, OperationOptionsConst options) {
+        enlist();
         NdbOperationConst operation = ndbTransaction.deleteTuple(ndbRecord, buffer, ndbRecord, null, mask, options, 0);
         handleError(operation, ndbTransaction);
         return operation;
     }
 
+    /** Create an NdbOperation for update using NdbRecord.
+     * 
+     * @param ndbRecord the NdbRecord
+     * @param buffer the buffer with data for the operation
+     * @param mask the mask of column values already set in the buffer
+     * @param options the OperationOptions for this operation
+     * @return the update operation
+     */
+    public NdbOperationConst updateTuple(NdbRecordConst ndbRecord,
+            ByteBuffer buffer, byte[] mask, OperationOptionsConst options) {
+        enlist();
+        NdbOperationConst operation = ndbTransaction.updateTuple(ndbRecord, buffer, ndbRecord, buffer, mask, options, 0);
+        handleError(operation, ndbTransaction);
+        return operation;
+    }
+
+    /** Create an NdbOperation for write using NdbRecord.
+     * 
+     * @param ndbRecord the NdbRecord
+     * @param buffer the buffer with data for the operation
+     * @param mask the mask of column values already set in the buffer
+     * @param options the OperationOptions for this operation
+     * @return the update operation
+     */
+    public NdbOperationConst writeTuple(NdbRecordConst ndbRecord,
+            ByteBuffer buffer, byte[] mask, OperationOptionsConst options) {
+        enlist();
+        NdbOperationConst operation = ndbTransaction.writeTuple(ndbRecord, buffer, ndbRecord, buffer, mask, options, 0);
+        handleError(operation, ndbTransaction);
+        return operation;
+    }
+
     /** Create an NdbOperation for key read using NdbRecord. The 'find' lock mode is used.
      * 
      * @param ndbRecordKeys the NdbRecord for the key
@@ -460,20 +497,37 @@ class ClusterTransactionImpl implements 
     }
 
     private void performPostExecuteCallbacks() {
-        // TODO this will abort on the first postExecute failure
+        // check completed operations
+        StringBuilder exceptionMessages = new StringBuilder();
+        for (Operation op: operationsToCheck) {
+            int code = op.getErrorCode();
+            if (code != 0) {
+                int mysqlCode = op.getMysqlCode();
+                int status = op.getStatus();
+                int classification = op.getClassification();
+                String message = local.message("ERR_Datastore", -1, code, mysqlCode, status, classification,
+                        op.toString());
+                exceptionMessages.append(message);
+                exceptionMessages.append('\n');
+            }
+        }
+        operationsToCheck.clear();
         // TODO should this set rollback only?
         try {
             for (Runnable runnable: postExecuteCallbacks) {
                 try {
                     runnable.run();
                 } catch (Throwable t) {
-                    throw new ClusterJDatastoreException(
-                            local.message("ERR_Datastore"), t);
+                    exceptionMessages.append(t.getMessage());
+                    exceptionMessages.append('\n');
                 }
             }
         } finally {
             clearPostExecuteCallbacks();
         }
+        if (exceptionMessages.length() > 0) {
+            throw new ClusterJDatastoreException(exceptionMessages.toString());
+        }
     }
 
     /** Handle errors from ScanOperation where the error returnCode is -1.
@@ -591,21 +645,21 @@ class ClusterTransactionImpl implements 
         return bufferManager;
     }
 
+    /** Get the cached NdbRecordImpl for this table. The NdbRecordImpl is cached in the
+     * cluster connection.
+     * @param storeTable the table
+     * @return
+     */
     protected NdbRecordImpl getCachedNdbRecordImpl(Table storeTable) {
         return clusterConnectionImpl.getCachedNdbRecordImpl(storeTable);
     }
 
-    /** Get the UseNdbRecord property from either the environment or system properties.
-     * 
-     * @return the system property if it is set via -D or the system environment
+    /** 
+     * Add an operation to check for errors after execute.
+     * @param op the operation to check
      */
-    protected static boolean getUseNdbRecord() {
-        String useNdbRecordENV = System.getenv(USE_NDBRECORD_NAME);
-        // system property overrides environment variable
-        boolean result = System.getProperty(USE_NDBRECORD_NAME, useNdbRecordENV==null?"true":useNdbRecordENV)
-                .equals("true")?true:false;
-        logger.info("useNdbRecordENV: " + useNdbRecordENV + " UseNdbRecord: " + result);
-        return result;
+    public void addOperationToCheck(Operation op) {
+        operationsToCheck.add(op);
     }
 
 }

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ColumnImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ColumnImpl.java	2012-01-23 00:44:39 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/ColumnImpl.java	2012-03-05 22:28:15 +0000
@@ -310,6 +310,10 @@ class ColumnImpl implements Column {
         }
     }
 
+    public int getSize() {
+        return size;
+    }
+
     public int getColumnId() {
         return columnId;
     }

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/DbImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/DbImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/DbImpl.java	2012-03-05 22:28:15 +0000
@@ -33,6 +33,7 @@ import com.mysql.ndbjtie.ndbapi.NdbDicti
 import com.mysql.clusterj.ClusterJDatastoreException;
 import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.core.store.ClusterTransaction;
+import com.mysql.clusterj.core.store.Table;
 
 import com.mysql.clusterj.core.util.I18NHelper;
 import com.mysql.clusterj.core.util.Logger;
@@ -368,4 +369,8 @@ class DbImpl implements com.mysql.cluste
 
     }
 
+    public NdbRecordOperationImpl newNdbRecordOperationImpl(Table storeTable) {
+        return clusterConnection.newNdbRecordOperationImpl(this, storeTable);
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordBlobImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordBlobImpl.java	2012-01-23 00:44:39 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordBlobImpl.java	2012-03-05 22:28:15 +0000
@@ -41,6 +41,9 @@ class NdbRecordBlobImpl extends BlobImpl
     /** The store column for this blob */
     private Column storeColumn;
 
+    /** The data for this blob */
+    private byte[] data;
+
     /** The operation */
     private NdbRecordOperationImpl operation;
 
@@ -53,4 +56,24 @@ class NdbRecordBlobImpl extends BlobImpl
         this.ndbBlob = operation.getNdbBlob(storeColumn);
     }
 
+    public void setValue() {
+        setValue(data);
+    }
+
+    public void setData(byte[] bytes) {
+        data = bytes;
+    }
+
+    public void setData(String string) {
+        data = storeColumn.encode(string);
+    }
+
+    public byte[] getBytesData() {
+        return data;
+    }
+
+    public String getStringData() {
+        return storeColumn.decode(data);
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordDeleteOperationImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordDeleteOperationImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordDeleteOperationImpl.java	2012-03-05 22:28:15 +0000
@@ -24,15 +24,13 @@ import com.mysql.clusterj.core.store.Tab
 
 public class NdbRecordDeleteOperationImpl extends NdbRecordOperationImpl {
 
-    /** The number of columns for this operation */
-    protected int numberOfColumns;
-
     public NdbRecordDeleteOperationImpl(
             ClusterTransactionImpl clusterTransaction, Table storeTable) {
-        super(clusterTransaction);
+        super(clusterTransaction, storeTable);
         this.ndbRecordKeys = clusterTransaction.getCachedNdbRecordImpl(storeTable);
         this.keyBufferSize = ndbRecordKeys.getBufferSize();
         this.numberOfColumns = ndbRecordKeys.getNumberOfColumns();
+        resetMask();
     }
 
     public void beginDefinition() {
@@ -40,15 +38,16 @@ public class NdbRecordDeleteOperationImp
         keyBuffer = ByteBuffer.allocateDirect(keyBufferSize);
         // use platform's native byte ordering
         keyBuffer.order(ByteOrder.nativeOrder());
-        mask = new byte[1 + (numberOfColumns/8)];
     }
 
     public void endDefinition() {
-        // position the buffer at the beginning for ndbjtie
-        keyBuffer.position(0);
-        keyBuffer.limit(keyBufferSize);
         // create the delete operation
-        ndbOperation = clusterTransaction.deleteTuple(ndbRecordKeys.getNdbRecord(), keyBuffer, mask, null);
+        ndbOperation = delete(clusterTransaction);
+    }
+
+    @Override
+    public String toString() {
+        return " delete " + tableName;
     }
 
 }

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordImpl.java	2012-03-05 22:28:15 +0000
@@ -21,15 +21,19 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import com.mysql.clusterj.ClusterJDatastoreException;
 import com.mysql.clusterj.ClusterJFatalInternalException;
 import com.mysql.clusterj.ClusterJFatalUserException;
+import com.mysql.clusterj.ClusterJUserException;
 
 import com.mysql.clusterj.core.store.Column;
 import com.mysql.clusterj.core.store.Table;
+
 import com.mysql.clusterj.core.util.I18NHelper;
 import com.mysql.clusterj.core.util.Logger;
 import com.mysql.clusterj.core.util.LoggerFactoryService;
@@ -89,9 +93,12 @@ public class NdbRecordImpl {
     /** The lengths of the column data */
     protected int[] lengths;
 
-    /** Values for setting column mask and null bit mask */
+    /** Values for setting column mask and null bit mask: 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 */
     protected final static byte[] BIT_IN_BYTE_MASK = new byte[] {1, 2, 4, 8, 16, 32, 64, -128};
 
+    /** Values for resetting column mask and null bit mask: 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f */
+    protected static final byte[] RESET_BIT_IN_BYTE_MASK = new byte[] {-2, -3, -5, -9, -17, -33, -65, 127};
+
     /** The null indicator for the field bit in the byte */
     protected int nullbitBitInByte[] = null;
 
@@ -113,6 +120,7 @@ public class NdbRecordImpl {
     /** These fields are only used during construction of the RecordSpecificationArray */
     int offset = 0;
     int nullablePosition = 0;
+    byte[] defaultValues;
 
     /** Constructor used for insert operations that do not need to read data.
      * 
@@ -130,18 +138,84 @@ public class NdbRecordImpl {
         this.nullbitByteOffset = new int[numberOfColumns];
         this.storeColumns = new Column[numberOfColumns];
         this.ndbRecord = createNdbRecord(storeTable, ndbDictionary);
+        initializeDefaultBuffer();
+    }
+
+    /** Initialize the byte buffer containing default values for all columns.
+     * Non-null columns are initialized to zero. Nullable columns are initialized to null.
+     * When a new byte buffer is required, the byte buffer is used for initialization.
+     */
+    private void initializeDefaultBuffer() {
+        // create the default value for the buffer: null values or zeros for all columns
+        defaultValues = new byte[bufferSize];
+        ByteBuffer zeros = ByteBuffer.allocateDirect(bufferSize);
+        zeros.order(ByteOrder.nativeOrder());
+        // just to be sure, initialize with zeros
+        zeros.put(defaultValues);
+        for (Column storeColumn: storeColumns) {
+            // nullable columns get the null bit set
+            if (storeColumn.getNullable()) {
+                setNull(zeros, storeColumn);
+            }
+        }
+        zeros.position(0);
+        zeros.limit(bufferSize);
+        zeros.get(defaultValues);
+        // default values is now immutable and can be used thread-safe
+    }
+
+    /** Initialize a new direct buffer with default values for all columns.
+     * The buffer returned is positioned at 0 with the limit set to the buffer size.
+     * @return a new byte buffer for use with this NdbRecord.
+     */
+    protected ByteBuffer newBuffer() {
+        ByteBuffer result = ByteBuffer.allocateDirect(bufferSize);
+        result.order(ByteOrder.nativeOrder());
+        result.put(defaultValues);
+        result.limit(bufferSize);
+        result.position(0);
+        return result;
+    }
+
+    public int setNull(ByteBuffer buffer, Column storeColumn) {
+        int columnId = storeColumn.getColumnId();
+        if (!storeColumn.getNullable()) {
+            return columnId;
+        }
+        int index = nullbitByteOffset[columnId];
+        byte mask = BIT_IN_BYTE_MASK[nullbitBitInByte[columnId]];
+        byte nullbyte = buffer.get(index);
+        buffer.put(index, (byte)(nullbyte|mask));
+        return columnId;
+    }
+
+    public int resetNull(ByteBuffer buffer, Column storeColumn) {
+        int columnId = storeColumn.getColumnId();
+        if (!storeColumn.getNullable()) {
+            return columnId;
+        }
+        int index = nullbitByteOffset[columnId];
+        byte mask = RESET_BIT_IN_BYTE_MASK[nullbitBitInByte[columnId]];
+        byte nullbyte = buffer.get(index);
+        buffer.put(index, (byte)(nullbyte & mask));
+        return columnId;
     }
 
     public int setBigInteger(ByteBuffer buffer, Column storeColumn, BigInteger value) {
+        resetNull(buffer, storeColumn);
         int columnId = storeColumn.getColumnId();
         int newPosition = offsets[columnId];
         buffer.position(newPosition);
+        // TODO provide the buffer to Utility.convertValue to avoid copying
         ByteBuffer bigIntegerBuffer = Utility.convertValue(storeColumn, value);
         buffer.put(bigIntegerBuffer);
+        buffer.limit(bufferSize);
+        buffer.position(0);
         return columnId;
     }
 
     public int setByte(ByteBuffer buffer, Column storeColumn, byte value) {
+        resetNull(buffer, storeColumn);
         int columnId = storeColumn.getColumnId();
         if (storeColumn.getLength() == 4) {
             // the byte is stored as a BIT array of four bytes
@@ -149,18 +223,26 @@ public class NdbRecordImpl {
         } else {
             buffer.put(offsets[columnId], (byte)value);
         }
+        buffer.limit(bufferSize);
+        buffer.position(0);
         return columnId;
     }
 
     public int setBytes(ByteBuffer buffer, Column storeColumn, byte[] value) {
+        resetNull(buffer, storeColumn);
         int columnId = storeColumn.getColumnId();
-        int newPosition = offsets[columnId];
-        buffer.position(newPosition);
+        int offset = offsets[columnId];
+        int length = storeColumn.getLength() + storeColumn.getPrefixLength();
+        buffer.limit(offset + length);
+        buffer.position(offset);
         Utility.convertValue(buffer, storeColumn, value);
+        buffer.limit(bufferSize);
+        buffer.position(0);
         return columnId;
     }
 
     public int setDecimal(ByteBuffer buffer, Column storeColumn, BigDecimal value) {
+        resetNull(buffer, storeColumn);
         int columnId = storeColumn.getColumnId();
         int newPosition = offsets[columnId];
         buffer.position(newPosition);
@@ -170,19 +252,22 @@ public class NdbRecordImpl {
         return columnId;
     }
 
-    public int setDouble(ByteBuffer buffer, Column storeColumn, Double value) {
+    public int setDouble(ByteBuffer buffer, Column storeColumn, double value) {
+        resetNull(buffer, storeColumn);
         int columnId = storeColumn.getColumnId();
         buffer.putDouble(offsets[columnId], value);
         return columnId;
     }
 
-    public int setFloat(ByteBuffer buffer, Column storeColumn, Float value) {
+    public int setFloat(ByteBuffer buffer, Column storeColumn, float value) {
+        resetNull(buffer, storeColumn);
         int columnId = storeColumn.getColumnId();
         buffer.putFloat(offsets[columnId], value);
         return columnId;
     }
 
-    public int setInt(ByteBuffer buffer, Column storeColumn, Integer value) {
+    public int setInt(ByteBuffer buffer, Column storeColumn, int value) {
+        resetNull(buffer, storeColumn);
         int columnId = storeColumn.getColumnId();
         int storageValue = Utility.convertIntValueForStorage(storeColumn, value);
         buffer.putInt(offsets[columnId], storageValue);
@@ -190,22 +275,15 @@ public class NdbRecordImpl {
     }
 
     public int setLong(ByteBuffer buffer, Column storeColumn, long value) {
+        resetNull(buffer, storeColumn);
         int columnId = storeColumn.getColumnId();
         long storeValue = Utility.convertLongValueForStorage(storeColumn, value);
         buffer.putLong(offsets[columnId], storeValue);
         return columnId;
     }
 
-    public int setNull(ByteBuffer buffer, Column storeColumn) {
-        int columnId = storeColumn.getColumnId();
-        int index = nullbitByteOffset[columnId];
-        byte mask = BIT_IN_BYTE_MASK[nullbitBitInByte[columnId]];
-        byte nullbyte = buffer.get(index);
-        buffer.put(index, (byte)(nullbyte|mask));
-        return columnId;
-    }
-
-    public int setShort(ByteBuffer buffer, Column storeColumn, Short value) {
+    public int setShort(ByteBuffer buffer, Column storeColumn, short value) {
+        resetNull(buffer, storeColumn);
         int columnId = storeColumn.getColumnId();
         if (storeColumn.getLength() == 4) {
             // the short is stored as a BIT array of four bytes
@@ -217,12 +295,22 @@ public class NdbRecordImpl {
     }
 
     public int setString(ByteBuffer buffer, BufferManager bufferManager, Column storeColumn, String value) {
+        resetNull(buffer, storeColumn);
         int columnId = storeColumn.getColumnId();
-        buffer.position(offsets[columnId]);
+        int offset = offsets[columnId];
+        int length = storeColumn.getLength() + storeColumn.getPrefixLength();
+        buffer.limit(offset + length);
+        buffer.position(offset);
         // TODO provide the buffer to Utility.encode to avoid copying
         // for now, use the encode method to encode the value then copy it
         ByteBuffer converted = Utility.encode(value, storeColumn, bufferManager);
+        if (length < converted.remaining()) {
+            throw new ClusterJUserException(local.message("ERR_Data_Too_Large",
+                    storeColumn.getName(), length, converted.remaining()));
+        }
         buffer.put(converted);
+        buffer.limit(bufferSize);
+        buffer.position(0);
         return columnId;
     }
 
@@ -274,30 +362,28 @@ public class NdbRecordImpl {
         byteBuffer.position(offset);
         byte[] result = new byte[actualLength];
         byteBuffer.get(result);
+        byteBuffer.limit(bufferSize);
+        byteBuffer.position(0);
         return result;
      }
 
     public double getDouble(ByteBuffer buffer, int columnId) {
-        buffer.position(offsets[columnId]);
-        double result = buffer.getDouble();
+        double result = buffer.getDouble(offsets[columnId]);
         return result;
     }
 
     public float getFloat(ByteBuffer buffer, int columnId) {
-        buffer.position(offsets[columnId]);
-        float result = buffer.getFloat();
+        float result = buffer.getFloat(offsets[columnId]);
         return result;
     }
 
     public int getInt(ByteBuffer buffer, int columnId) {
-        buffer.position(offsets[columnId]);
-        int value = buffer.getInt();
+        int value = buffer.getInt(offsets[columnId]);
         return Utility.getInt(storeColumns[columnId], value);
     }
 
     public long getLong(ByteBuffer buffer, int columnId) {
-        buffer.position(offsets[columnId]);
-        long value = buffer.getLong();
+        long value = buffer.getLong(offsets[columnId]);
         return Utility.getLong(storeColumns[columnId], value);
     }
 
@@ -343,6 +429,8 @@ public class NdbRecordImpl {
       byteBuffer.limit(offset + actualLength);
 
       String result = Utility.decode(byteBuffer, storeColumn.getCharsetNumber(), bufferManager);
+      byteBuffer.limit(bufferSize);
+      byteBuffer.position(0);
       return result;
     }
 
@@ -354,7 +442,10 @@ public class NdbRecordImpl {
         int scale = storeColumn.getScale();
         int length = Utility.getDecimalColumnSpace(precision, scale);
         byteBuffer.position(offset);
-        return Utility.getBigInteger(byteBuffer, length, precision, scale);
+        BigInteger result = Utility.getBigInteger(byteBuffer, length, precision, scale);
+        byteBuffer.limit(bufferSize);
+        byteBuffer.position(0);
+        return result;
     }
 
     public BigInteger getBigInteger(ByteBuffer byteBuffer, Column storeColumn) {
@@ -364,7 +455,10 @@ public class NdbRecordImpl {
         int scale = storeColumn.getScale();
         int length = Utility.getDecimalColumnSpace(precision, scale);
         byteBuffer.position(offset);
-        return Utility.getBigInteger(byteBuffer, length, precision, scale);
+        BigInteger result = Utility.getBigInteger(byteBuffer, length, precision, scale);
+        byteBuffer.limit(bufferSize);
+        byteBuffer.position(0);
+        return result;
     }
 
     public BigDecimal getDecimal(ByteBuffer byteBuffer, int columnId) {
@@ -375,7 +469,10 @@ public class NdbRecordImpl {
         int scale = storeColumn.getScale();
         int length = Utility.getDecimalColumnSpace(precision, scale);
         byteBuffer.position(offset);
-        return Utility.getDecimal(byteBuffer, length, precision, scale);
+        BigDecimal result = Utility.getDecimal(byteBuffer, length, precision, scale);
+        byteBuffer.limit(bufferSize);
+        byteBuffer.position(0);
+        return result;
       }
 
     public BigDecimal getDecimal(ByteBuffer byteBuffer, Column storeColumn) {
@@ -385,7 +482,10 @@ public class NdbRecordImpl {
       int scale = storeColumn.getScale();
       int length = Utility.getDecimalColumnSpace(precision, scale);
       byteBuffer.position(offset);
-      return Utility.getDecimal(byteBuffer, length, precision, scale);
+      BigDecimal result = Utility.getDecimal(byteBuffer, length, precision, scale);
+      byteBuffer.limit(bufferSize);
+      byteBuffer.position(0);
+      return result;
     }
 
     public Boolean getObjectBoolean(ByteBuffer byteBuffer, int columnId) {
@@ -469,10 +569,25 @@ public class NdbRecordImpl {
         if (!storeColumns[columnId].getNullable()) {
             return false;
         }
-        int index = nullbitByteOffset[columnId];
-        byte mask = BIT_IN_BYTE_MASK[nullbitBitInByte[columnId]];
-        byte nullbyte = buffer.get(index);
-        boolean result = (nullbyte & mask) != 0;
+        byte nullbyte = buffer.get(nullbitByteOffset[columnId]);
+        boolean result = isSet(nullbyte, nullbitBitInByte[columnId]);
+        return result;
+    }
+
+    public boolean isPresent(byte[] mask, int columnId) {
+        byte present = mask[columnId/8];
+        return isSet(present, columnId % 8);
+    }
+
+    public void markPresent(byte[] mask, int columnId) {
+        int offset = columnId/8;
+        int bitMask = BIT_IN_BYTE_MASK[columnId % 8];
+        mask[offset] |= (byte)bitMask;
+    }
+
+    protected boolean isSet(byte test, int bitInByte) {
+        int mask = BIT_IN_BYTE_MASK[bitInByte];
+        boolean result = (test & mask) != 0;
         return result;
     }
 
@@ -494,6 +609,7 @@ public class NdbRecordImpl {
         int i = 0;
         for (String columnName: columnNames) {
             Column storeColumn = storeTable.getColumn(columnName);
+            if (logger.isDetailEnabled()) logger.detail("storeColumn: " + storeColumn.getName() + " id: " + storeColumn.getColumnId() + " index: " + i);
             lengths[i] = storeColumn.getLength();
             storeColumns[i++] = storeColumn;
             // for each column, put into alignment bucket
@@ -568,7 +684,7 @@ public class NdbRecordImpl {
         }
         bufferSize = offset;
 
-        if (logger.isDebugEnabled()) logger.debug(dump());
+        if (logger.isDebugEnabled()) logger.debug(dumpDefinition());
 
         // now create an NdbRecord
         NdbRecord result = ndbDictionary.createRecord(tableConst, recordSpecificationArray,
@@ -608,7 +724,7 @@ public class NdbRecordImpl {
         }
     }
 
-    private String dump() {
+    private String dumpDefinition() {
         StringBuilder builder = new StringBuilder(tableConst.getName());
         builder.append(" numberOfColumns: ");
         builder.append(numberOfColumns);
@@ -630,6 +746,45 @@ public class NdbRecordImpl {
         return builder.toString();
     }
 
+    public String dumpValues(ByteBuffer data, byte[] mask) {
+        StringBuilder builder = new StringBuilder(tableConst.getName());
+        builder.append(" numberOfColumns: ");
+        builder.append(numberOfColumns);
+        builder.append('\n');
+        for (int columnId = 0; columnId < numberOfColumns; ++columnId) {
+            Column storeColumn = storeColumns[columnId];
+            builder.append(" column: ");
+            builder.append(storeColumn.getName());
+            builder.append(" offset: ");
+            builder.append(offsets[columnId]);
+            builder.append(" length: ");
+            builder.append(lengths[columnId]);
+            builder.append(" nullbitBitInByte: ");
+            int nullBitInByte = nullbitBitInByte[columnId];
+            builder.append(nullBitInByte);
+            builder.append(" nullbitByteOffset: ");
+            int nullByteOffset = nullbitByteOffset[columnId];
+            builder.append(nullByteOffset);
+            builder.append(" data: ");
+            int size = storeColumn.getColumnSpace() != 0 ? storeColumn.getColumnSpace():storeColumn.getSize();
+            int offset = offsets[columnId];
+            data.limit(bufferSize);
+            data.position(0);
+            for (int index = offset; index < offset + size; ++index) {
+                builder.append(String.format("%2x ", data.get(index)));
+            }
+            builder.append(" null: ");
+            builder.append(isNull(data, columnId));
+            builder.append(" present: ");
+            if (mask != null) {
+                builder.append(isPresent(mask, columnId));
+            }
+            builder.append('\n');
+        }
+        data.position(0);
+        return builder.toString();
+    }
+
     TableConst getNdbTable(String tableName) {
         TableConst ndbTable = ndbDictionary.getTable(tableName);
         if (ndbTable == null) {

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordInsertOperationImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordInsertOperationImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordInsertOperationImpl.java	2012-03-05 22:28:15 +0000
@@ -17,47 +17,33 @@
 
 package com.mysql.clusterj.tie;
 
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
 import com.mysql.clusterj.core.store.Table;
 
 public class NdbRecordInsertOperationImpl extends NdbRecordOperationImpl {
 
-    /** The number of columns for this operation */
-    protected int numberOfColumns;
-
     public NdbRecordInsertOperationImpl(ClusterTransactionImpl clusterTransaction, Table storeTable) {
-        super(clusterTransaction);
+        super(clusterTransaction, storeTable);
         this.ndbRecordValues = clusterTransaction.getCachedNdbRecordImpl(storeTable);
         this.ndbRecordKeys = ndbRecordValues;
         this.valueBufferSize = ndbRecordValues.getBufferSize();
         this.numberOfColumns = ndbRecordValues.getNumberOfColumns();
         this.blobs = new NdbRecordBlobImpl[this.numberOfColumns];
+        resetMask();
     }
 
     public void beginDefinition() {
         // allocate a buffer for the operation data
-        valueBuffer = ByteBuffer.allocateDirect(valueBufferSize);
-        // use platform's native byte ordering
-        valueBuffer.order(ByteOrder.nativeOrder());
-        // use value buffer for key buffer also
+        valueBuffer = ndbRecordValues.newBuffer();
         keyBuffer = valueBuffer;
-        mask = new byte[1 + (numberOfColumns/8)];
     }
 
     public void endDefinition() {
-        // position the buffer at the beginning for ndbjtie
-        valueBuffer.position(0);
-        valueBuffer.limit(valueBufferSize);
-        // create the insert operation
-        ndbOperation = clusterTransaction.insertTuple(ndbRecordValues.getNdbRecord(), valueBuffer, mask, null);
-        // now set the NdbBlob into the blobs
-        for (NdbRecordBlobImpl blob: activeBlobs) {
-            if (blob != null) {
-                blob.setNdbBlob();
-            }
-        }
+        ndbOperation = insert(clusterTransaction);
+    }
+
+    @Override
+    public String toString() {
+        return " insert " + tableName;
     }
 
 }

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordKeyOperationImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordKeyOperationImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordKeyOperationImpl.java	2012-03-05 22:28:15 +0000
@@ -26,17 +26,15 @@ import com.mysql.clusterj.core.store.Tab
 
 public class NdbRecordKeyOperationImpl extends NdbRecordOperationImpl {
 
-    /** The number of columns in the table */
-    protected int numberOfColumns;
-
     public NdbRecordKeyOperationImpl(ClusterTransactionImpl clusterTransaction, Table storeTable) {
-        super(clusterTransaction);
+        super(clusterTransaction, storeTable);
         this.ndbRecordKeys = clusterTransaction.getCachedNdbRecordImpl(storeTable);
         this.keyBufferSize = ndbRecordKeys.getBufferSize();
         this.ndbRecordValues = clusterTransaction.getCachedNdbRecordImpl(storeTable);
         this.valueBufferSize = ndbRecordValues.getBufferSize();
         this.numberOfColumns = ndbRecordValues.getNumberOfColumns();
         this.blobs = new NdbRecordBlobImpl[this.numberOfColumns];
+        resetMask();
     }
 
     public void beginDefinition() {
@@ -44,9 +42,9 @@ public class NdbRecordKeyOperationImpl e
         keyBuffer = ByteBuffer.allocateDirect(keyBufferSize);
         keyBuffer.order(ByteOrder.nativeOrder());
         // allocate a buffer for the value result data
+        // TODO: we should not need another buffer
         valueBuffer = ByteBuffer.allocateDirect(valueBufferSize);
         valueBuffer.order(ByteOrder.nativeOrder());
-        mask = new byte[1 + (numberOfColumns/8)];
     }
 
     /** Specify the columns to be used for the operation.
@@ -104,11 +102,16 @@ public class NdbRecordKeyOperationImpl e
     @Override
     public ResultData resultData(boolean execute) {
         NdbRecordResultDataImpl result =
-            new NdbRecordResultDataImpl(this, ndbRecordValues, valueBuffer, bufferManager);
+            new NdbRecordResultDataImpl(this);
         if (execute) {
             clusterTransaction.executeNoCommit(false, true);
         }
         return result;
     }
 
+    @Override
+    public String toString() {
+        return " key " + tableName;
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordOperationImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordOperationImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordOperationImpl.java	2012-03-05 22:28:15 +0000
@@ -21,7 +21,6 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 
 import java.nio.ByteBuffer;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -29,8 +28,10 @@ import com.mysql.clusterj.ClusterJFatalI
 
 import com.mysql.clusterj.core.store.Blob;
 import com.mysql.clusterj.core.store.Column;
+import com.mysql.clusterj.core.store.Db;
 import com.mysql.clusterj.core.store.Operation;
 import com.mysql.clusterj.core.store.ResultData;
+import com.mysql.clusterj.core.store.Table;
 import com.mysql.clusterj.core.util.I18NHelper;
 import com.mysql.clusterj.core.util.Logger;
 import com.mysql.clusterj.core.util.LoggerFactoryService;
@@ -44,7 +45,7 @@ import com.mysql.ndbjtie.ndbapi.NdbDicti
 /**
  * Implementation of store operation that uses NdbRecord.
  */
-public abstract class NdbRecordOperationImpl implements Operation {
+public class NdbRecordOperationImpl implements Operation {
 
     /** My message translator */
     static final I18NHelper local = I18NHelper
@@ -55,7 +56,7 @@ public abstract class NdbRecordOperation
             .getInstance(NdbRecordOperationImpl.class);
 
     /** The ClusterTransaction that this operation belongs to */
-    protected ClusterTransactionImpl clusterTransaction;
+    protected ClusterTransactionImpl clusterTransaction = null;
 
     /** The NdbOperation wrapped by this object */
     protected NdbOperationConst ndbOperation = null;
@@ -93,15 +94,105 @@ public abstract class NdbRecordOperation
     /** The buffer manager for string encode and decode */
     protected BufferManager bufferManager;
 
+    /** The table name */
+    protected String tableName;
+
+    /** The store columns. */
+    protected Column[] storeColumns;
+
+    /** The number of columns */
+    int numberOfColumns;
+
+    /** Constructor used for smart value handler.
+     * 
+     * @param clusterConnection the cluster connection
+     * @param storeTable the store table
+     */
+    public NdbRecordOperationImpl(ClusterConnectionImpl clusterConnection, Db db, Table storeTable) {
+        this.tableName = storeTable.getName();
+        this.ndbRecordValues = clusterConnection.getCachedNdbRecordImpl(storeTable);
+        this.ndbRecordKeys = ndbRecordValues;
+        this.valueBufferSize = ndbRecordValues.getBufferSize();
+        this.keyBufferSize = ndbRecordKeys.getBufferSize();
+        this.valueBuffer = ndbRecordValues.newBuffer();
+        this.keyBuffer = valueBuffer;
+        this.storeColumns = ndbRecordValues.storeColumns;
+        this.numberOfColumns = storeColumns.length;
+        this.blobs = new NdbRecordBlobImpl[this.numberOfColumns];
+        this.bufferManager = ((DbImpl)db).getBufferManager();
+        resetMask();
+    }
+
+    protected void resetMask() {
+        this.mask = new byte[1 + (numberOfColumns/8)];
+    }
+
     /** Constructor used for insert and delete operations that do not need to read data.
      * 
      * @param clusterTransaction the cluster transaction
      */
-    public NdbRecordOperationImpl(ClusterTransactionImpl clusterTransaction) {
+    public NdbRecordOperationImpl(ClusterTransactionImpl clusterTransaction, Table storeTable) {
+        this.tableName = storeTable.getName();
         this.clusterTransaction = clusterTransaction;
         this.bufferManager = clusterTransaction.getBufferManager();
     }
 
+    public NdbOperationConst insert(ClusterTransactionImpl clusterTransactionImpl) {
+        // position the buffer at the beginning for ndbjtie
+        valueBuffer.limit(valueBufferSize);
+        valueBuffer.position(0);
+        ndbOperation = clusterTransactionImpl.insertTuple(ndbRecordValues.getNdbRecord(), valueBuffer, mask, null);
+        clusterTransactionImpl.addOperationToCheck(this);
+        // for each blob column set, get the blob handle and write the values
+        for (NdbRecordBlobImpl blob: activeBlobs) {
+            // activate the blob
+            blob.setNdbBlob();
+            // set values into the blob
+            blob.setValue();
+        }
+        return ndbOperation;
+    }
+
+    public NdbOperationConst delete(ClusterTransactionImpl clusterTransactionImpl) {
+        // position the buffer at the beginning for ndbjtie
+        keyBuffer.limit(keyBufferSize);
+        keyBuffer.position(0);
+        ndbOperation = clusterTransactionImpl.deleteTuple(ndbRecordKeys.getNdbRecord(), keyBuffer, mask, null);
+        return ndbOperation;
+    }
+
+    public void update(ClusterTransactionImpl clusterTransactionImpl) {
+        // position the buffer at the beginning for ndbjtie
+        valueBuffer.limit(valueBufferSize);
+        valueBuffer.position(0);
+        ndbOperation = clusterTransactionImpl.updateTuple(ndbRecordValues.getNdbRecord(), valueBuffer, mask, null);
+        clusterTransactionImpl.addOperationToCheck(this);
+        // for each blob column set, get the blob handle and write the values
+        for (NdbRecordBlobImpl blob: activeBlobs) {
+            // activate the blob
+            blob.setNdbBlob();
+            // set values into the blob
+            blob.setValue();
+        }
+        return;
+    }
+
+    public void write(ClusterTransactionImpl clusterTransactionImpl) {
+        // position the buffer at the beginning for ndbjtie
+        valueBuffer.limit(valueBufferSize);
+        valueBuffer.position(0);
+        ndbOperation = clusterTransactionImpl.writeTuple(ndbRecordValues.getNdbRecord(), valueBuffer, mask, null);
+        clusterTransactionImpl.addOperationToCheck(this);
+        // for each blob column set, get the blob handle and write the values
+        for (NdbRecordBlobImpl blob: activeBlobs) {
+            // activate the blob
+            blob.setNdbBlob();
+            // set values into the blob
+            blob.setValue();
+        }
+        return;
+    }
+
     public void equalBigInteger(Column storeColumn, BigInteger value) {
         int columnId = ndbRecordKeys.setBigInteger(keyBuffer, storeColumn, value);
         columnSet(columnId);
@@ -142,13 +233,13 @@ public abstract class NdbRecordOperation
         columnSet(columnId);
     }
 
-    public void equalShort(Column storeColumn, short value) {
-        int columnId = ndbRecordKeys.setShort(keyBuffer, storeColumn, value);
+    public void equalLong(Column storeColumn, long value) {
+        int columnId = ndbRecordKeys.setLong(keyBuffer, storeColumn, value);
         columnSet(columnId);
     }
 
-    public void equalLong(Column storeColumn, long value) {
-        int columnId = ndbRecordKeys.setLong(keyBuffer, storeColumn, value);
+    public void equalShort(Column storeColumn, short value) {
+        int columnId = ndbRecordKeys.setShort(keyBuffer, storeColumn, value);
         columnSet(columnId);
     }
 
@@ -209,8 +300,16 @@ public abstract class NdbRecordOperation
     }
 
     public void setBigInteger(Column storeColumn, BigInteger value) {
-        int columnId = ndbRecordValues.setBigInteger(valueBuffer, storeColumn, value);
-        columnSet(columnId);
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            int columnId = ndbRecordValues.setBigInteger(valueBuffer, storeColumn, value);
+            columnSet(columnId);
+        }
+    }
+
+    public void setBigInteger(int columnId, BigInteger value) {
+        setBigInteger(storeColumns[columnId], value);
     }
 
     public void setBoolean(Column storeColumn, Boolean booleanValue) {
@@ -218,19 +317,43 @@ public abstract class NdbRecordOperation
         setByte(storeColumn, value);
     }
 
+    public void setBoolean(int columnId, boolean value) {
+        setBoolean(storeColumns[columnId], value);
+    }
+
     public void setByte(Column storeColumn, byte value) {
         int columnId = ndbRecordValues.setByte(valueBuffer, storeColumn, value);
         columnSet(columnId);
     }
 
+    public void setByte(int columnId, byte value) {
+        setByte(storeColumns[columnId], value);
+    }
+
     public void setBytes(Column storeColumn, byte[] value) {
-        int columnId = ndbRecordValues.setBytes(valueBuffer, storeColumn, value);
-        columnSet(columnId);
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            int columnId = ndbRecordValues.setBytes(valueBuffer, storeColumn, value);
+            columnSet(columnId);
+        }
+    }
+
+    public void setBytes(int columnId, byte[] value) {
+        setBytes(storeColumns[columnId], value);
     }
 
     public void setDecimal(Column storeColumn, BigDecimal value) {
-        int columnId = ndbRecordValues.setDecimal(valueBuffer, storeColumn, value);
-        columnSet(columnId);
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            int columnId = ndbRecordValues.setDecimal(valueBuffer, storeColumn, value);
+            columnSet(columnId);
+        }
+    }
+
+    public void setDecimal(int columnId, BigDecimal value) {
+        setDecimal(storeColumns[columnId], value);
     }
 
     public void setDouble(Column storeColumn, Double value) {
@@ -238,34 +361,129 @@ public abstract class NdbRecordOperation
         columnSet(columnId);
     }
 
+    public void setDouble(int columnId, double value) {
+        setDouble(storeColumns[columnId], value);
+    }
+
     public void setFloat(Column storeColumn, Float value) {
         int columnId = ndbRecordValues.setFloat(valueBuffer, storeColumn, value);
         columnSet(columnId);
     }
 
+    public void setFloat(int columnId, float value) {
+        setFloat(storeColumns[columnId], value);
+    }
+
     public void setInt(Column storeColumn, Integer value) {
         int columnId = ndbRecordValues.setInt(valueBuffer, storeColumn, value);
         columnSet(columnId);
     }
 
+    public void setInt(int columnId, int value) {
+        setInt(storeColumns[columnId], value);
+    }
+
     public void setLong(Column storeColumn, long value) {
         int columnId = ndbRecordValues.setLong(valueBuffer, storeColumn, value);
         columnSet(columnId);
     }
 
+    public void setLong(int columnId, long value) {
+        setLong(storeColumns[columnId], value);
+    }
+
     public void setNull(Column storeColumn) {
         int columnId = ndbRecordValues.setNull(valueBuffer, storeColumn);
         columnSet(columnId);
     }
 
+    public void setNull(int columnId) {
+        setNull(storeColumns[columnId]);
+    }
+
     public void setShort(Column storeColumn, Short value) {
         int columnId = ndbRecordValues.setShort(valueBuffer, storeColumn, value);
         columnSet(columnId);
     }
 
+    public void setShort(int columnId, short value) {
+        setShort(storeColumns[columnId], value);
+    }
+
+    public void setObjectBoolean(int columnId, Boolean value) {
+        Column storeColumn = storeColumns[columnId];
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            setBoolean(storeColumn, value);
+        }
+    }
+
+    public void setObjectByte(int columnId, Byte value) {
+        Column storeColumn = storeColumns[columnId];
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            setByte(storeColumn, value);
+        }
+    }
+
+    public void setObjectDouble(int columnId, Double value) {
+        Column storeColumn = storeColumns[columnId];
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            setDouble(storeColumn, value);
+        }
+    }
+
+    public void setObjectFloat(int columnId, Float value) {
+        Column storeColumn = storeColumns[columnId];
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            setFloat(storeColumn, value);
+        }
+    }
+
+    public void setObjectInt(int columnId, Integer value) {
+        Column storeColumn = storeColumns[columnId];
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            setInt(storeColumn, value);
+        }
+    }
+
+    public void setObjectLong(int columnId, Long value) {
+        Column storeColumn = storeColumns[columnId];
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            setLong(storeColumn, value);
+        }
+    }
+
+    public void setObjectShort(int columnId, Short value) {
+        Column storeColumn = storeColumns[columnId];
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            setShort(storeColumn, value);
+        }
+    }
+
     public void setString(Column storeColumn, String value) {
-        int columnId = ndbRecordValues.setString(valueBuffer, bufferManager, storeColumn, value);
-        columnSet(columnId);
+        if (value == null) {
+            setNull(storeColumn);
+        } else {
+            int columnId = ndbRecordValues.setString(valueBuffer, bufferManager, storeColumn, value);
+            columnSet(columnId);
+        }
+    }
+
+    public void setString(int columnId, String value) {
+        setString(storeColumns[columnId], value);
     }
 
     public int errorCode() {
@@ -317,4 +535,228 @@ public abstract class NdbRecordOperation
         return ndbRecordValues;
     }
 
+    public boolean getBoolean(int columnId) {
+        return ndbRecordValues.getBoolean(valueBuffer, columnId);
+    }
+
+    public boolean getBoolean(Column storeColumn) {
+        return ndbRecordValues.getBoolean(valueBuffer, storeColumn.getColumnId());
+    }
+
+    public boolean[] getBooleans(int column) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
+                "NdbRecordResultDataImpl.getBooleans(int)"));
+    }
+
+    public boolean[] getBooleans(Column storeColumn) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
+                "NdbRecordResultDataImpl.getBooleans(Column)"));
+    }
+
+    public byte getByte(int columnId) {
+        return ndbRecordValues.getByte(valueBuffer, columnId);
+    }
+
+    public byte getByte(Column storeColumn) {
+        return ndbRecordValues.getByte(valueBuffer, storeColumn.getColumnId());
+    }
+
+    public short getShort(int columnId) {
+        return ndbRecordValues.getShort(valueBuffer, columnId);
+    }
+
+    public short getShort(Column storeColumn) {
+        return ndbRecordValues.getShort(valueBuffer, storeColumn.getColumnId());
+     }
+
+    public int getInt(int columnId) {
+        return ndbRecordValues.getInt(valueBuffer, columnId);
+    }
+
+    public int getInt(Column storeColumn) {
+        return getInt(storeColumn.getColumnId());
+    }
+
+    public long getLong(int columnId) {
+        return ndbRecordValues.getLong(valueBuffer, columnId);
+    }
+
+    public long getLong(Column storeColumn) {
+        return getLong(storeColumn.getColumnId());
+     }
+
+    public float getFloat(int columnId) {
+        return ndbRecordValues.getFloat(valueBuffer, columnId);
+    }
+
+    public float getFloat(Column storeColumn) {
+        return getFloat(storeColumn.getColumnId());
+    }
+
+    public double getDouble(int columnId) {
+        return ndbRecordValues.getDouble(valueBuffer, columnId);
+    }
+
+    public double getDouble(Column storeColumn) {
+        return getDouble(storeColumn.getColumnId());
+    }
+
+    public String getString(int columnId) {
+        return ndbRecordValues.getString(valueBuffer, columnId, bufferManager);
+    }
+
+    public String getString(Column storeColumn) {
+        return ndbRecordValues.getString(valueBuffer, storeColumn.getColumnId(), bufferManager);
+    }
+
+    public byte[] getBytes(int column) {
+        return ndbRecordValues.getBytes(valueBuffer, column);
+    }
+
+    public byte[] getBytes(Column storeColumn) {
+        return ndbRecordValues.getBytes(valueBuffer, storeColumn);
+     }
+
+    public Object getObject(int column) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
+        "NdbRecordResultDataImpl.getObject(int)"));
+    }
+
+    public Object getObject(Column storeColumn) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
+        "NdbRecordResultDataImpl.getObject(Column)"));
+    }
+
+    public boolean wasNull(Column storeColumn) {
+        throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
+        "NdbRecordResultDataImpl.wasNull(Column)"));
+    }
+
+    public Boolean getObjectBoolean(int column) {
+        return ndbRecordValues.getObjectBoolean(valueBuffer, column);
+    }
+
+    public Boolean getObjectBoolean(Column storeColumn) {
+        return ndbRecordValues.getObjectBoolean(valueBuffer, storeColumn.getColumnId());
+    }
+
+    public Byte getObjectByte(int columnId) {
+        return ndbRecordValues.getObjectByte(valueBuffer, columnId);
+    }
+
+    public Byte getObjectByte(Column storeColumn) {
+        return ndbRecordValues.getObjectByte(valueBuffer, storeColumn.getColumnId());
+    }
+
+    public Float getObjectFloat(int column) {
+        return ndbRecordValues.getObjectFloat(valueBuffer, column);
+    }
+
+    public Float getObjectFloat(Column storeColumn) {
+        return ndbRecordValues.getObjectFloat(valueBuffer, storeColumn.getColumnId());
+    }
+
+    public Double getObjectDouble(int column) {
+        return ndbRecordValues.getObjectDouble(valueBuffer, column);
+    }
+
+    public Double getObjectDouble(Column storeColumn) {
+        return ndbRecordValues.getObjectDouble(valueBuffer, storeColumn.getColumnId());
+    }
+
+    public Integer getObjectInteger(int columnId) {
+        return ndbRecordValues.getObjectInteger(valueBuffer, columnId);
+    }
+
+    public Integer getObjectInteger(Column storeColumn) {
+        return ndbRecordValues.getObjectInteger(valueBuffer, storeColumn.getColumnId());
+    }
+
+    public Long getObjectLong(int column) {
+        return ndbRecordValues.getObjectLong(valueBuffer, column);
+    }
+
+    public Long getObjectLong(Column storeColumn) {
+        return ndbRecordValues.getObjectLong(valueBuffer, storeColumn.getColumnId());
+    }
+
+    public Short getObjectShort(int columnId) {
+        return ndbRecordValues.getObjectShort(valueBuffer, columnId);
+    }
+
+    public Short getObjectShort(Column storeColumn) {
+        return ndbRecordValues.getObjectShort(valueBuffer, storeColumn.getColumnId());
+    }
+
+    public BigInteger getBigInteger(int column) {
+        return ndbRecordValues.getBigInteger(valueBuffer, column);
+    }
+
+    public BigInteger getBigInteger(Column storeColumn) {
+        return ndbRecordValues.getBigInteger(valueBuffer, storeColumn);
+    }
+
+    public BigDecimal getDecimal(int column) {
+        return ndbRecordValues.getDecimal(valueBuffer, column);
+    }
+
+    public BigDecimal getDecimal(Column storeColumn) {
+        return ndbRecordValues.getDecimal(valueBuffer, storeColumn);
+    }
+
+    public void beginDefinition() {
+        throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
+        "NdbRecordResultDataImpl.beginDefinition()"));
+    }
+
+    public void endDefinition() {
+        throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
+        "NdbRecordResultDataImpl.endDefinition()"));
+    }
+
+    public String dumpValues() {
+        return ndbRecordValues.dumpValues(valueBuffer, mask);
+    }
+
+    public boolean isModified(int columnId) {
+        return ndbRecordValues.isPresent(mask, columnId);
+    }
+
+    public boolean isNull(int columnId) {
+        return ndbRecordValues.isNull(valueBuffer, columnId);
+    }
+
+    public void markModified(int columnId) {
+        ndbRecordValues.markPresent(mask, columnId);
+    }
+
+    public void resetModified() {
+        this.mask = new byte[1 + (numberOfColumns/8)];
+    }
+
+    public NdbRecordBlobImpl getBlobHandle(int columnId) {
+        return (NdbRecordBlobImpl) getBlobHandle(storeColumns[columnId]);
+    }
+
+    public int getErrorCode() {
+        return ndbOperation.getNdbError().code();
+    }
+
+    public int getClassification() {
+        return ndbOperation.getNdbError().classification();
+    }
+
+    public int getMysqlCode() {
+        return ndbOperation.getNdbError().mysql_code();
+    }
+
+    public int getStatus() {
+        return ndbOperation.getNdbError().status();
+    }
+
+    @Override
+    public String toString() {
+        return tableName;
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordResultDataImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordResultDataImpl.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordResultDataImpl.java	2012-03-05 22:28:15 +0000
@@ -20,7 +20,6 @@ package com.mysql.clusterj.tie;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 
-import java.nio.ByteBuffer;
 import com.mysql.clusterj.ClusterJFatalInternalException;
 
 import com.mysql.clusterj.core.store.Blob;
@@ -30,7 +29,6 @@ import com.mysql.clusterj.core.store.Res
 import com.mysql.clusterj.core.util.I18NHelper;
 import com.mysql.clusterj.core.util.Logger;
 import com.mysql.clusterj.core.util.LoggerFactoryService;
-import com.mysql.clusterj.tie.DbImpl.BufferManager;
 
 /**
  *
@@ -53,29 +51,16 @@ class NdbRecordResultDataImpl implements
     /** The NdbOperation that defines the result */
     private NdbRecordOperationImpl operation = null;
 
-    /** The NdbRecordImpl that defines the buffer layout */
-    private NdbRecordImpl record = null;
-
     /** The flag indicating that there are no more results */
     private boolean nextDone;
 
-    /** The ByteBuffer containing the results */
-    private ByteBuffer buffer = null;
-
-    /** The buffer manager */
-    private BufferManager bufferManager;
-
     /** Construct the ResultDataImpl based on an NdbRecordOperationImpl, and the 
      * buffer manager to help with string columns.
      * @param operation the NdbRecordOperationImpl
      * @param bufferManager the buffer manager
      */
-    public NdbRecordResultDataImpl(NdbRecordOperationImpl operation, NdbRecordImpl ndbRecordImpl,
-            ByteBuffer buffer, BufferManager bufferManager) {
+    public NdbRecordResultDataImpl(NdbRecordOperationImpl operation) {
         this.operation = operation;
-        this.record = ndbRecordImpl;
-        this.bufferManager = bufferManager;
-        this.buffer = buffer;
     }
 
     public boolean next() {
@@ -103,11 +88,11 @@ class NdbRecordResultDataImpl implements
     }
 
     public boolean getBoolean(int columnId) {
-        return record.getBoolean(buffer, columnId);
+        return operation.getBoolean(columnId);
     }
 
     public boolean getBoolean(Column storeColumn) {
-        return record.getBoolean(buffer, storeColumn.getColumnId());
+        return operation.getBoolean(storeColumn.getColumnId());
     }
 
     public boolean[] getBooleans(int column) {
@@ -121,23 +106,23 @@ class NdbRecordResultDataImpl implements
     }
 
     public byte getByte(int columnId) {
-        return record.getByte(buffer, columnId);
+        return operation.getByte(columnId);
     }
 
     public byte getByte(Column storeColumn) {
-        return record.getByte(buffer, storeColumn.getColumnId());
+        return operation.getByte(storeColumn.getColumnId());
     }
 
     public short getShort(int columnId) {
-        return record.getShort(buffer, columnId);
+        return operation.getShort(columnId);
     }
 
     public short getShort(Column storeColumn) {
-        return record.getShort(buffer, storeColumn.getColumnId());
+        return operation.getShort(storeColumn.getColumnId());
      }
 
     public int getInt(int columnId) {
-        return record.getInt(buffer, columnId);
+        return operation.getInt(columnId);
     }
 
     public int getInt(Column storeColumn) {
@@ -145,7 +130,7 @@ class NdbRecordResultDataImpl implements
     }
 
     public long getLong(int columnId) {
-        return record.getLong(buffer, columnId);
+        return operation.getLong(columnId);
     }
 
     public long getLong(Column storeColumn) {
@@ -153,7 +138,7 @@ class NdbRecordResultDataImpl implements
      }
 
     public float getFloat(int columnId) {
-        return record.getFloat(buffer, columnId);
+        return operation.getFloat(columnId);
     }
 
     public float getFloat(Column storeColumn) {
@@ -161,7 +146,7 @@ class NdbRecordResultDataImpl implements
     }
 
     public double getDouble(int columnId) {
-        return record.getDouble(buffer, columnId);
+        return operation.getDouble(columnId);
     }
 
     public double getDouble(Column storeColumn) {
@@ -169,19 +154,19 @@ class NdbRecordResultDataImpl implements
     }
 
     public String getString(int columnId) {
-        return record.getString(buffer, columnId, bufferManager);
+        return operation.getString(columnId);
     }
 
     public String getString(Column storeColumn) {
-        return record.getString(buffer, storeColumn.getColumnId(), bufferManager);
+        return operation.getString(storeColumn.getColumnId());
     }
 
     public byte[] getBytes(int column) {
-        return record.getBytes(buffer, column);
+        return operation.getBytes(column);
     }
 
     public byte[] getBytes(Column storeColumn) {
-        return record.getBytes(buffer, storeColumn);
+        return operation.getBytes(storeColumn);
      }
 
     public Object getObject(int column) {
@@ -200,75 +185,75 @@ class NdbRecordResultDataImpl implements
     }
 
     public Boolean getObjectBoolean(int column) {
-        return record.getObjectBoolean(buffer, column);
+        return operation.getObjectBoolean(column);
     }
 
     public Boolean getObjectBoolean(Column storeColumn) {
-        return record.getObjectBoolean(buffer, storeColumn.getColumnId());
+        return operation.getObjectBoolean(storeColumn.getColumnId());
     }
 
     public Byte getObjectByte(int columnId) {
-        return record.getObjectByte(buffer, columnId);
+        return operation.getObjectByte(columnId);
     }
 
     public Byte getObjectByte(Column storeColumn) {
-        return record.getObjectByte(buffer, storeColumn.getColumnId());
+        return operation.getObjectByte(storeColumn.getColumnId());
     }
 
     public Float getObjectFloat(int column) {
-        return record.getObjectFloat(buffer, column);
+        return operation.getObjectFloat(column);
     }
 
     public Float getObjectFloat(Column storeColumn) {
-        return record.getObjectFloat(buffer, storeColumn.getColumnId());
+        return operation.getObjectFloat(storeColumn.getColumnId());
     }
 
     public Double getObjectDouble(int column) {
-        return record.getObjectDouble(buffer, column);
+        return operation.getObjectDouble(column);
     }
 
     public Double getObjectDouble(Column storeColumn) {
-        return record.getObjectDouble(buffer, storeColumn.getColumnId());
+        return operation.getObjectDouble(storeColumn.getColumnId());
     }
 
     public Integer getObjectInteger(int columnId) {
-        return record.getObjectInteger(buffer, columnId);
+        return operation.getObjectInteger(columnId);
     }
 
     public Integer getObjectInteger(Column storeColumn) {
-        return record.getObjectInteger(buffer, storeColumn.getColumnId());
+        return operation.getObjectInteger(storeColumn.getColumnId());
     }
 
     public Long getObjectLong(int column) {
-        return record.getObjectLong(buffer, column);
+        return operation.getObjectLong(column);
     }
 
     public Long getObjectLong(Column storeColumn) {
-        return record.getObjectLong(buffer, storeColumn.getColumnId());
+        return operation.getObjectLong(storeColumn.getColumnId());
     }
 
     public Short getObjectShort(int columnId) {
-        return record.getObjectShort(buffer, columnId);
+        return operation.getObjectShort(columnId);
     }
 
     public Short getObjectShort(Column storeColumn) {
-        return record.getObjectShort(buffer, storeColumn.getColumnId());
+        return operation.getObjectShort(storeColumn.getColumnId());
     }
 
     public BigInteger getBigInteger(int column) {
-        return record.getBigInteger(buffer, column);
+        return operation.getBigInteger(column);
     }
 
     public BigInteger getBigInteger(Column storeColumn) {
-        return record.getBigInteger(buffer, storeColumn);
+        return operation.getBigInteger(storeColumn);
     }
 
     public BigDecimal getDecimal(int column) {
-        return record.getDecimal(buffer, column);
+        return operation.getDecimal(column);
     }
 
     public BigDecimal getDecimal(Column storeColumn) {
-        return record.getDecimal(buffer, storeColumn);
+        return operation.getDecimal(storeColumn);
     }
 
     public void setNoResult() {

=== added file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordSmartValueHandlerFactoryImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordSmartValueHandlerFactoryImpl.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordSmartValueHandlerFactoryImpl.java	2012-03-05 22:28:15 +0000
@@ -0,0 +1,31 @@
+/*
+   Copyright (c) 2012, 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.tie;
+
+import com.mysql.clusterj.core.metadata.DomainTypeHandlerImpl;
+import com.mysql.clusterj.core.spi.ValueHandler;
+import com.mysql.clusterj.core.spi.ValueHandlerFactory;
+import com.mysql.clusterj.core.store.Db;
+
+public class NdbRecordSmartValueHandlerFactoryImpl implements ValueHandlerFactory {
+
+    public <T> ValueHandler getValueHandler(DomainTypeHandlerImpl<T> domainTypeHandler, Db db) {
+        return new NdbRecordSmartValueHandlerImpl(domainTypeHandler, db);
+    }
+
+}

=== added file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordSmartValueHandlerImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordSmartValueHandlerImpl.java	1970-01-01 00:00:00 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/NdbRecordSmartValueHandlerImpl.java	2012-03-05 22:28:15 +0000
@@ -0,0 +1,696 @@
+/*
+   Copyright (c) 2012, 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.tie;
+
+import java.lang.reflect.Method;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+
+import com.mysql.clusterj.ClusterJFatalInternalException;
+import com.mysql.clusterj.ClusterJUserException;
+import com.mysql.clusterj.ColumnMetadata;
+
+import com.mysql.clusterj.core.CacheManager;
+
+import com.mysql.clusterj.core.metadata.DomainTypeHandlerImpl;
+import com.mysql.clusterj.core.metadata.InvocationHandlerImpl;
+
+import com.mysql.clusterj.core.spi.DomainFieldHandler;
+import com.mysql.clusterj.core.spi.DomainTypeHandler;
+import com.mysql.clusterj.core.spi.SmartValueHandler;
+
+import com.mysql.clusterj.core.store.ClusterTransaction;
+import com.mysql.clusterj.core.store.Db;
+import com.mysql.clusterj.core.store.Operation;
+import com.mysql.clusterj.core.store.Table;
+
+import com.mysql.clusterj.core.util.I18NHelper;
+import com.mysql.clusterj.core.util.Logger;
+import com.mysql.clusterj.core.util.LoggerFactoryService;
+
+/** NdbRecordSmartValueHandlerImpl is the implementation class that
+ * provides a value handler for a proxy or dynamic object that stores
+ * values in an ndb record buffer instead of an object array. 
+ * Subsequent database operations (insert, update, delete) use the
+ * already-stored data instead of constructing a new data buffer. This class
+ * replaces the InvocationHandler and uses the type-specific data transforms
+ * done by DomainFieldHandler.
+ * There are two separate numbering patterns used by this class: ValueHandler
+ * methods access data using field numbers indexed according to the domain model.
+ * Field numbers are translated to column numbers when calling NdbRecordOperationImpl.
+ * Transient fields are implemented here, since NdbRecord knows nothing about
+ * transient fields in the domain model.
+ * The operation wrapper (NdbRecordOperationImpl) is initialized when the domain object
+ * is created. But the operation to be performed (insert, delete, update, write) is only known
+ * when the domain object is involved in a user operation. So the initialization of 
+ * the corresponding NdbOperation is deferred.
+ */
+public class NdbRecordSmartValueHandlerImpl implements SmartValueHandler {
+
+    /** My message translator */
+    static final I18NHelper local = I18NHelper.getInstance(InvocationHandlerImpl.class);
+
+    /** My logger */
+    static final Logger logger = LoggerFactoryService.getFactory().getInstance(InvocationHandlerImpl.class);
+
+    protected NdbRecordOperationImpl operation;
+
+    protected DomainTypeHandlerImpl<?> domainTypeHandler;
+
+    protected DomainFieldHandler[] domainFieldHandlers;
+
+    private int[] fieldNumberToColumnNumberMap;
+
+    private Boolean found = null;
+
+    /** The number of transient fields (that do not have a column and so cannot be stored in the NdbRecord) */
+    private int numberOfTransientFields;
+
+    /** Values of transient fields; only initialized if there are transient fields */
+    private Object[] transientValues = null;
+
+    private boolean[] transientModified; 
+
+    public NdbRecordSmartValueHandlerImpl(DomainTypeHandlerImpl<?> domainTypeHandler, Db db) {
+        this.domainTypeHandler = domainTypeHandler;
+        this.domainFieldHandlers = domainTypeHandler.getFieldHandlers();
+        fieldNumberToColumnNumberMap = domainTypeHandler.getFieldNumberToColumnNumberMap();
+
+        Table storeTable = domainTypeHandler.getStoreTable();
+        this.operation = ((DbImpl)db).newNdbRecordOperationImpl(storeTable);
+
+        numberOfTransientFields = domainTypeHandler.getNumberOfTransientFields();
+        transientModified = new boolean[numberOfTransientFields];
+        if (numberOfTransientFields != 0) {
+            transientValues = this.domainTypeHandler.newTransientValues();
+        }
+    }
+
+    public Operation insert(ClusterTransaction clusterTransaction) {
+        if (logger.isDetailEnabled()) logger.detail("smart insert for type: " + domainTypeHandler.getName()
+                + "\n" + operation.dumpValues());
+        ClusterTransactionImpl clusterTransactionImpl = (ClusterTransactionImpl)clusterTransaction;
+        operation.insert(clusterTransactionImpl);
+        return operation;
+    }
+
+    public Operation delete(ClusterTransaction clusterTransaction) {
+        if (logger.isDetailEnabled()) logger.detail("smart delete for type: " + domainTypeHandler.getName()
+                + "\n" + operation.dumpValues());
+        operation.delete((ClusterTransactionImpl)clusterTransaction);
+        return operation;
+    }
+
+    public Operation update(ClusterTransaction clusterTransaction) {
+        if (logger.isDetailEnabled()) logger.detail("smart update for type: " + domainTypeHandler.getName()
+                + " record: " + operation.dumpValues());
+        operation.update((ClusterTransactionImpl)clusterTransaction);
+        return operation;
+    }
+
+    public Operation write(ClusterTransaction clusterTransaction) {
+        if (logger.isDetailEnabled()) logger.detail("smart write for type: " + domainTypeHandler.getName()
+                + " record: " + operation.dumpValues());
+        operation.write((ClusterTransactionImpl)clusterTransaction);
+        return operation;
+    }
+
+    public BigDecimal getBigDecimal(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getDecimal(columnId);
+        }
+        return (BigDecimal)transientValues[-1 - columnId];
+    }
+
+    public BigInteger getBigInteger(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getBigInteger(columnId);
+        }
+        return (BigInteger)transientValues[-1 - columnId];
+    }
+
+    public boolean getBoolean(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getBoolean(columnId);
+        }
+        Boolean value = (Boolean)transientValues[-1 - columnId];
+        return value == null?false:value;
+    }
+
+    public boolean[] getBooleans(int fieldNumber) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public byte getByte(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getByte(columnId);
+        }
+        Byte value = (Byte)transientValues[-1 - columnId];
+        return value == null?0:value;
+    }
+
+    public byte[] getBytes(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getBytes(columnId);
+        }
+        return (byte[])transientValues[-1 - columnId];
+    }
+
+    public double getDouble(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getDouble(columnId);
+        }
+        Double value = (Double)transientValues[-1 - columnId];
+        return value == null?0.0D:value;
+    }
+
+    public float getFloat(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getFloat(columnId);
+        }
+        Float value = (Float)transientValues[-1 - columnId];
+        return value == null?0.0F:value;
+    }
+
+    public int getInt(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            int result = operation.getInt(columnId);
+            return result;
+        }
+        Integer value = (Integer)transientValues[-1 - columnId];
+        return (value == null)?0:value;
+    }
+
+    public Date getJavaSqlDate(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            Long millis = operation.getObjectLong(columnId);
+            return millis == null? null:new java.sql.Date(millis);
+        }
+        return (java.sql.Date)transientValues[-1 - columnId];
+    }
+
+    public Time getJavaSqlTime(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            Long millis = operation.getObjectLong(columnId);
+            return millis == null? null:new java.sql.Time(millis);
+        }
+        return (java.sql.Time)transientValues[-1 - columnId];
+    }
+
+    public Timestamp getJavaSqlTimestamp(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            Long millis = operation.getObjectLong(columnId);
+            return millis == null? null:new java.sql.Timestamp(millis);
+        }
+        return (java.sql.Timestamp)transientValues[-1 - columnId];
+    }
+
+    public java.util.Date getJavaUtilDate(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            Long millis = operation.getObjectLong(columnId);
+            return millis == null? null:new java.util.Date(millis);
+        }
+        return (java.util.Date)transientValues[-1 - columnId];
+    }
+
+    public byte[] getLobBytes(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        NdbRecordBlobImpl blob = operation.getBlobHandle(columnId);
+        return blob.getBytesData();
+    }
+
+    public String getLobString(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        NdbRecordBlobImpl blob = operation.getBlobHandle(columnId);
+        String result = blob.getStringData();
+        return result;
+    }
+
+    public long getLong(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getLong(columnId);
+        }
+         Long value = (Long)transientValues[-1 - columnId];
+         return value == null?0L:value;
+    }
+
+    public Boolean getObjectBoolean(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getObjectBoolean(columnId);
+        }
+        return (Boolean)transientValues[-1 - columnId];
+    }
+
+    public Byte getObjectByte(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getObjectByte(columnId);
+        }
+        return (Byte)transientValues[-1 - columnId];
+    }
+
+    public Double getObjectDouble(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getObjectDouble(columnId);
+        }
+        return (Double)transientValues[-1 - columnId];
+    }
+
+    public Float getObjectFloat(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getObjectFloat(columnId);
+        }
+        return (Float)transientValues[-1 - columnId];
+    }
+
+    public Integer getObjectInt(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getObjectInteger(columnId);
+        }
+        return (Integer)transientValues[-1 - columnId];
+    }
+
+    public Long getObjectLong(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getObjectLong(columnId);
+        }
+        return (Long)transientValues[-1 - columnId];
+    }
+
+    public Short getObjectShort(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getObjectShort(columnId);
+        }
+        return (Short)transientValues[-1 - columnId];
+    }
+
+    public short getShort(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getShort(columnId);
+        }
+        Short value = (Short)transientValues[-1 - columnId];
+        return value == null?0:value;
+    }
+
+    public String getString(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.getString(columnId);
+        }
+        return (String)transientValues[-1 - columnId];
+    }
+
+    public boolean isModified(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.isModified(columnId);
+        }
+        return transientModified[-1 - columnId];
+    }
+
+    public boolean isNull(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            return operation.isNull(columnId);
+        }
+        return transientValues[-1 - columnId] == null;
+    }
+
+    public void markModified(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.markModified(columnId);
+            return;
+        }
+        transientModified[-1 - columnId] = true;
+    }
+
+    public String pkToString(DomainTypeHandler<?> domainTypeHandler) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public void resetModified() {
+        operation.resetModified();
+        transientModified = new boolean[numberOfTransientFields];
+    }
+
+    public void setBigDecimal(int fieldNumber, BigDecimal value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setDecimal(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setBigInteger(int fieldNumber, BigInteger bigIntegerExact) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setBigInteger(columnId, bigIntegerExact);
+        } else {
+            transientValues[-1 - columnId] = bigIntegerExact;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setBoolean(int fieldNumber, boolean b) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setBoolean(columnId, b);
+        } else {
+            transientValues[-1 - columnId] = b;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setBooleans(int fieldNumber, boolean[] b) {
+        // TODO Auto-generated method stub
+        
+    }
+
+    public void setByte(int fieldNumber, byte value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setByte(columnId, value);
+        } else {
+            transientModified[-1 - columnId] = true;
+            transientValues[-1 - columnId] = value;
+        }
+    }
+
+    public void setBytes(int fieldNumber, byte[] value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setBytes(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setDouble(int fieldNumber, double value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setDouble(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setFloat(int fieldNumber, float value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setFloat(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setInt(int fieldNumber, int value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setInt(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setJavaSqlDate(int fieldNumber, Date value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (value == null) {
+            operation.setNull(columnId);
+        } else {
+            setLong(fieldNumber, value.getTime());            
+        }
+    }
+
+    public void setJavaSqlTime(int fieldNumber, Time value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (value == null) {
+            operation.setNull(columnId);
+        } else {
+            setLong(fieldNumber, value.getTime());            
+        }
+    }
+
+    public void setJavaSqlTimestamp(int fieldNumber, Timestamp value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (value == null) {
+            operation.setNull(columnId);
+        } else {
+            setLong(fieldNumber, value.getTime());            
+        }
+    }
+
+    public void setJavaUtilDate(int fieldNumber, java.util.Date value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (value == null) {
+            operation.setNull(columnId);
+        } else {
+            setLong(fieldNumber, value.getTime());            
+        }
+    }
+
+    public void setLobBytes(int fieldNumber, byte[] value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        NdbRecordBlobImpl blob = operation.getBlobHandle(columnId);
+        blob.setData(value);
+    }
+
+    public void setLobString(int fieldNumber, String value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        NdbRecordBlobImpl blob = operation.getBlobHandle(columnId);
+        blob.setData(value);
+    }
+
+    public void setLong(int fieldNumber, long value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setLong(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setObject(int fieldNumber, Object value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            throw new ClusterJFatalInternalException(local.message("ERR_Method_Not_Implemented",
+            "NdbRecordSmartValueHandler.setObject(int, Object) for persistent values"));
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setObjectBoolean(int fieldNumber, Boolean value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setObjectBoolean(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setObjectByte(int fieldNumber, Byte value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setObjectByte(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setObjectDouble(int fieldNumber, Double value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setObjectDouble(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setObjectFloat(int fieldNumber, Float value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setObjectFloat(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setObjectInt(int fieldNumber, Integer value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setObjectInt(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setObjectLong(int fieldNumber, Long value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setObjectLong(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setObjectShort(int fieldNumber, Short value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setObjectShort(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setShort(int fieldNumber, short value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setObjectShort(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public void setString(int fieldNumber, String value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId >= 0) {
+            operation.setString(columnId, value);
+        } else {
+            transientValues[-1 - columnId] = value;
+            transientModified[-1 - columnId] = true;
+        }
+    }
+
+    public ColumnMetadata[] columnMetadata() {
+        return domainTypeHandler.columnMetadata();
+    }
+
+    public Boolean found() {
+        return found;
+    }
+
+    public void found(Boolean found) {
+        this.found = found;
+    }
+
+    /** Return the value of a dynamic field stored in the NdbRecord buffer.
+     * @param fieldNumber the field number
+     * @return the value from data storage
+     */
+    public Object get(int fieldNumber) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId < 0) {
+            return transientValues[-1 - columnId];
+        }
+        return domainFieldHandlers[fieldNumber].objectGetValue(this);
+    }
+
+    public void set(int fieldNumber, Object value) {
+        int columnId = fieldNumberToColumnNumberMap[fieldNumber];
+        if (columnId < 0) {
+            transientValues[-1 - columnId] = value;
+        }
+        domainFieldHandlers[fieldNumber].objectSetValue(value, this);
+    }
+
+    public Object invoke(Object proxy, Method method, Object[] args)
+            throws Throwable {
+        String methodName = method.getName();
+        if (logger.isDetailEnabled()) logger.detail("invoke with Method: " + method.getName());
+        
+        String propertyHead = methodName.substring(3,4);
+        String propertyTail = methodName.substring(4);
+        String propertyName = propertyHead.toLowerCase() + propertyTail;
+        int fieldNumber;
+        Object result;
+        if (methodName.startsWith("get")) {
+            // get the field number from the name
+            fieldNumber = domainTypeHandler.getFieldNumber(propertyName);
+            result = get(fieldNumber);
+            if (logger.isDetailEnabled()) logger.detail(methodName + ": Returning field number " + fieldNumber
+                + " value: " + result);
+            return result;
+        } else if (methodName.startsWith("set")) {
+            if (logger.isDetailEnabled()) logger.detail("Property name: " + propertyName
+                    + " value: " + args[0]);
+            // get the field number from the name
+            fieldNumber = domainTypeHandler.getFieldNumber(propertyName);
+            set(fieldNumber, args[0]);
+        } else if ("toString".equals(methodName)) {
+            return(domainTypeHandler.getDomainClass().getName()
+                    + pkToString(domainTypeHandler));
+        } else if ("hashCode".equals(methodName)) {
+            return(this.hashCode());
+        } else {
+            throw new ClusterJUserException(
+                    local.message("ERR_Method_Name", methodName));
+        }
+        return null;
+    }
+
+    public void setCacheManager(CacheManager cm) {
+    }
+
+    public void setProxy(Object proxy) {
+    }
+
+}

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/OperationImpl.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/OperationImpl.java	2012-01-23 00:44:39 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/OperationImpl.java	2012-03-05 22:28:15 +0000
@@ -313,4 +313,20 @@ class OperationImpl implements Operation
         // nothing to do
     }
 
+    public int getErrorCode() {
+        return ndbOperation.getNdbError().code();
+    }
+
+    public int getClassification() {
+        return ndbOperation.getNdbError().classification();
+    }
+
+    public int getMysqlCode() {
+        return ndbOperation.getNdbError().mysql_code();
+    }
+
+    public int getStatus() {
+        return ndbOperation.getNdbError().status();
+    }
+
 }

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/Utility.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/Utility.java	2012-02-08 17:27:45 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/java/com/mysql/clusterj/tie/Utility.java	2012-03-05 22:28:15 +0000
@@ -101,6 +101,19 @@ public class Utility {
 
     static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
 
+    /* Error codes that are not severe, and simply reflect expected conditions */
+    private static Set<Integer> NonSevereErrorCodes = new HashSet<Integer>();
+
+    public static final int SET_NOT_NULL_TO_NULL = 4203;
+    public static final int INDEX_NOT_FOUND = 4243;
+    public static final int ROW_NOT_FOUND = 626;
+
+    static {
+        NonSevereErrorCodes.add(SET_NOT_NULL_TO_NULL); // Attempt to set a NOT NULL attribute to NULL
+        NonSevereErrorCodes.add(INDEX_NOT_FOUND); // Index not found
+        NonSevereErrorCodes.add(ROW_NOT_FOUND); // Tuple did not exist
+    }
+
     // TODO: this is intended to investigate a class loader issue with Sparc java
     // The idea is to force loading the CharsetMap native class prior to calling the static create method
     static Class<?> charsetMapClass = loadClass("com.mysql.ndbjtie.mysql.CharsetMap");
@@ -863,15 +876,6 @@ public class Utility {
 
     };
 
-    /* Error codes that are not severe, and simply reflect expected conditions */
-    private static Set<Integer> NonSevereErrorCodes = new HashSet<Integer>();
-
-    static {
-        NonSevereErrorCodes.add(4203); // Trying to set a NOT NULL attribute to NULL
-        NonSevereErrorCodes.add(4243); // Index not found
-        NonSevereErrorCodes.add(626); // Tuple did not exist
-    }
-
     protected static interface EndianManager {
         public void put3byteInt(ByteBuffer byteBuffer, int value);
         public int getInt(Column storeColumn, int value);
@@ -1640,6 +1644,10 @@ public class Utility {
      */
     public static ByteBuffer encode(String input, Column storeColumn, BufferManager bufferManager) {
         int collation = storeColumn.getCharsetNumber();
+//        System.out.println("Utility.encode storeColumn: " + storeColumn.getName() + 
+//                " charsetName " + storeColumn.getCharsetName() +
+//                " charsetNumber " + collation +
+//                " input '" + input + "'");
         CharsetConverter charsetConverter = getCharsetConverter(collation);
         CharSequence chars = input;
         int prefixLength = storeColumn.getPrefixLength();

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/main/resources/com/mysql/clusterj/tie/Bundle.properties'
--- a/storage/ndb/clusterj/clusterj-tie/src/main/resources/com/mysql/clusterj/tie/Bundle.properties	2012-01-23 00:44:39 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/main/resources/com/mysql/clusterj/tie/Bundle.properties	2012-03-05 22:28:15 +0000
@@ -56,6 +56,7 @@ ERR_Encode_Bad_Source:Error encoding cha
 ERR_Encode_Buffer_Too_Small:Error encoding characters, buffer too small: character set number {0}, before input length {1}, \
 before output length {2}, after input length {3}, after output length {4}.
 ERR_Encode_Bad_Return_Code:Error encoding characters, unknown return code {0}.
+ERR_Data_Too_Large:Error writing characters for column {0}; maximum size {1}, actual size {2}.
 ERR_Mismatch_No_Of_Primary_Key_Columns:For table {0} number of primary key columns {1} doesn't match \
 number of columns in primary key index {2}.
 ERR_Failed_Loading_Library:Attempt to load native library {0} from path {1} failed with {2} ({3}).

=== modified file 'storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/ConnectionPoolTest.java'
--- a/storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/ConnectionPoolTest.java	2011-03-08 00:44:56 +0000
+++ b/storage/ndb/clusterj/clusterj-tie/src/test/java/testsuite/clusterj/tie/ConnectionPoolTest.java	2012-03-05 22:28:15 +0000
@@ -17,6 +17,8 @@
 
 package testsuite.clusterj.tie;
 
+import org.junit.Ignore;
+
 public class ConnectionPoolTest extends testsuite.clusterj.ConnectionPoolTest {
 
 }

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-5.1-telco-7.1 branch (Craig.Russell:4471 to 4472) Craig L Russell6 Mar