EMPIREDB-362 SampleAdvApp rework
diff --git a/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/SampleAdvApp.java b/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/SampleAdvApp.java
index 291bb32..f9b7981 100644
--- a/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/SampleAdvApp.java
+++ b/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/SampleAdvApp.java
@@ -25,14 +25,14 @@
 import java.sql.DriverManager;
 import java.time.LocalDate;
 import java.util.List;
+import java.util.Locale;
 
+import org.apache.empire.commons.DateUtils;
 import org.apache.empire.commons.ObjectUtils;
-import org.apache.empire.commons.Options;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.data.DataType;
 import org.apache.empire.data.list.DataListEntry;
 import org.apache.empire.db.DBCmdParam;
-import org.apache.empire.db.DBColumnExpr;
 import org.apache.empire.db.DBCommand;
 import org.apache.empire.db.DBDDLGenerator.DDLActionType;
 import org.apache.empire.db.DBQuery;
@@ -46,6 +46,7 @@
 import org.apache.empire.db.expr.compare.DBCompareExpr;
 import org.apache.empire.dbms.DBMSHandler;
 import org.apache.empire.samples.db.advanced.db.CarSalesDB;
+import org.apache.empire.samples.db.advanced.db.CarSalesDB.DealerRating;
 import org.apache.empire.samples.db.advanced.db.CarSalesDB.DealershipType;
 import org.apache.empire.samples.db.advanced.db.CarSalesDB.EngineType;
 import org.apache.empire.samples.db.advanced.db.DealerSalesView;
@@ -67,12 +68,6 @@
     private final CarSalesDB carSales = new CarSalesDB();
     
     private SampleContext context;
-    
-    // Shortcuts
-    private final SampleAdvDB db = new SampleAdvDB();
-    private SampleAdvDB.Employees T_EMP = db.T_EMPLOYEES;
-    private SampleAdvDB.Departments T_DEP = db.T_DEPARTMENTS;
-    private SampleAdvDB.EmployeeDepartmentHistory T_EDH = db.T_EMP_DEP_HIST;
 
     /**
      * <PRE>
@@ -134,14 +129,16 @@
             context.commit();
         }
         
-        // do simple stuff
-        simpleUpdateDemo();
-
-        
+        // DQL-Demos
         simpleQueryDemo();
         queryViewDemo();
         subqueryQueryDemo();
         paramQueryDemo();
+
+        // DML-Demos
+        modelPriceIncrease();
+        modelPriceDecrease();
+        dealerRatingUpdate();
         
         // Remember RollbackHandling
         boolean prevRBHandling = context.isRollbackHandlingEnabled(); 
@@ -158,100 +155,8 @@
         
         ddlDemo("Beadles Volkswagen", "www.group1auto.co.uk", "https://www.group1auto.co.uk/volkswagen/locations/beadles-volkswagen-dartford");
         
-
-        /*
-        // STEP 5: Clear Database (Delete all records)
-        System.out.println("*** Step 5: clearDatabase() ***");
-        clearDatabase();
-
-        // STEP 6: Insert Records
-        // Insert Departments
-        System.out.println("*** Step 6: inserting departments, employees and employee_department_history records ***");
-        int idDevDep  = insertDepartment("Development", "ITTK");
-        int idProdDep = insertDepartment("Production", "ITTK");
-        int idSalDep  = insertDepartment("Sales", "ITTK");
-
-        // Insert Employees
-        int idEmp1 = insertEmployee("Peter", "Sharp", "M");
-        int idEmp2 = insertEmployee("Fred", "Bloggs", "M");
-        int idEmp3 = insertEmployee("Emma", "White", "F");
-        
-        // Insert History as batch
-        DBSQLScript batch = new DBSQLScript(context);
-        insertEmpDepHistory(batch, idEmp1,  idDevDep,  DateUtils.getDate(2007, 12,  1));            
-        insertEmpDepHistory(batch, idEmp1,  idProdDep, DateUtils.getDate(2008,  9,  1));           
-        insertEmpDepHistory(batch, idEmp1,  idSalDep,  DateUtils.getDate(2009,  5, 15));           
-
-        insertEmpDepHistory(batch, idEmp2,  idSalDep,  DateUtils.getDate(2006,  3,  1));            
-        insertEmpDepHistory(batch, idEmp2,  idDevDep,  DateUtils.getDate(2008, 11, 15));
-        
-        insertEmpDepHistory(batch, idEmp3,  idDevDep,  DateUtils.getDate(2006,  9, 15));            
-        insertEmpDepHistory(batch, idEmp3,  idSalDep,  DateUtils.getDate(2007,  6,  1));           
-        insertEmpDepHistory(batch, idEmp3,  idProdDep, DateUtils.getDate(2008,  7, 31));
-        batch.executeBatch();
-        
-        // commit
-        context.commit();
-        
-        // STEP 7: read from Employee_Info_View
-        System.out.println("--------------------------------------------------------");
-        System.out.println("*** read from EMPLOYEE_INFO_VIEW ***");
-        DBCommand cmd = context.createCommand();
-        cmd.select (db.V_EMPLOYEE_INFO.getColumns());
-        cmd.orderBy(db.V_EMPLOYEE_INFO.C_NAME_AND_DEP);
-        printQueryResults(cmd);
-
-        // STEP 8: prepared Statement sample
-        System.out.println("--------------------------------------------------------");
-        System.out.println("*** commandParamsSample: shows how to use command parameters for the generation of prepared statements ***");
-        commandParamsSample(idProdDep, idDevDep);
-
-        // STEP 9: bulkReadRecords
-        System.out.println("--------------------------------------------------------");
-        System.out.println("*** bulkReadRecords: reads employee records into a hashmap, reads employee from hashmap and updates employee ***");
-        HashMap<Integer, DBRecord> employeeMap = bulkReadRecords(conn);
-        DBRecord rec = employeeMap.get(idEmp2);
-        rec.set(db.T_EMPLOYEES.C_SALUTATION, "Mr.");
-        rec.update();
-
-        // STEP 10: bulkProcessRecords
-        System.out.println("--------------------------------------------------------");
-        System.out.println("*** bulkProcessRecords: creates a checksum for every employee in the employees table ***");
-        bulkProcessRecords();
-
-        // STEP 11: querySample
-        System.out.println("--------------------------------------------------------");
-        System.out.println("*** querySample: shows how to use DBQuery class for subqueries and multi table records ***");
-        querySample(idEmp2);
-
-        // STEP 12: ddlSample
-        System.out.println("--------------------------------------------------------");
-        System.out.println("*** ddlSample: shows how to add a column at runtime and update a record with the added column ***");
-        if (db.getDbms() instanceof DBMSHandlerH2) {
-        	log.info("As H2 does not support changing a table with a view defined we remove the view");
-        	System.out.println("*** drop EMPLOYEE_INFO_VIEW ***");
-        	DBSQLScript script = new DBSQLScript(context);
-        	db.getDbms().getDDLScript(DDLActionType.DROP, db.V_EMPLOYEE_INFO, script);
-        	script.executeAll();
-        }
-        ddlSample(idEmp2);
-        if (db.getDbms() instanceof DBMSHandlerH2) {
-        	log.info("And put back the view");
-        	System.out.println("*** create EMPLOYEE_INFO_VIEW ***");
-        	DBSQLScript script = new DBSQLScript(context);
-        	db.getDbms().getDDLScript(DDLActionType.CREATE, db.V_EMPLOYEE_INFO, script);
-        	script.executeAll();
-        }
-
-        // STEP 13: delete records
-        System.out.println("--------------------------------------------------------");
-        System.out.println("*** deleteRecordSample: shows how to delete records (with and without cascade) ***");
-        deleteRecordSample(idEmp3, idSalDep);
-        */
-        
         // Done
-        System.out.println("--------------------------------------------------------");
-        System.out.println("DB Sample Advanced finished successfully.");
+        log.info("DB Sample Advanced finished successfully.");
     }
 
     public void populateDatabase()
@@ -264,23 +169,24 @@
         
         // Add some models
         ModelRecord model = new ModelRecord(context);
-        model.insert(brandVW,   "Golf",     "Golf Style 1,5 l TSI",         "Style",         EngineType.P, 130, 30970d);
-        model.insert(brandVW,   "Golf",     "Golf R-Line 2,0 l TSI 4MOTION","R-Line",        EngineType.P, 190, 38650d);
-        model.insert(brandVW,   "Tiguan",   "Tiguan Life 1,5 l TSI",        "Life",          EngineType.P, 150, 32545d);
-        model.insert(brandVW,   "Tiguan",   "Tiguan Elegance 2,0 l TDI SCR","Elegance",      EngineType.D, 150, 40845d);
-        model.insert(brandVW,   "Tiguan",   "Tiguan R-Line 1,4 l eHybrid",  "R-Line",        EngineType.H, 150, 48090d);
+        model.insert(brandVW,   "Golf",     "Golf Style 1,5 l TSI",         "Style",         EngineType.P, 130, 30970d, LocalDate.of(2019, 10, 24));
+        model.insert(brandVW,   "Golf",     "Golf R-Line 2,0 l TSI 4MOTION","R-Line",        EngineType.P, 190, 38650d, LocalDate.of(2019, 10, 24));
+        model.insert(brandVW,   "Tiguan",   "Tiguan Life 1,5 l TSI",        "Life",          EngineType.P, 150, 32545d, LocalDate.of(2016, 01, 01));
+        model.insert(brandVW,   "Tiguan",   "Tiguan Elegance 2,0 l TDI SCR","Elegance",      EngineType.D, 150, 40845d, LocalDate.of(2016, 01, 01));
+        model.insert(brandVW,   "Tiguan",   "Tiguan R-Line 1,4 l eHybrid",  "R-Line",        EngineType.H, 150, 48090d, LocalDate.of(2016, 01, 01));
+        model.insert(brandVW,   "Mulitvan", "Multivan 6.1 Highline 2.0TDI", "Highline",      EngineType.D, 204, 84269d, LocalDate.of(2019, 10, 21));
         // Tesla
-        model.insert(brandTesla,"Model 3",  "Model 3 LR",                   "Long Range",    EngineType.E, 261, 45940d);
-        model.insert(brandTesla,"Model 3",  "Model 3 Performance",          "Performance",   EngineType.E, 487, 53940d);
-        model.insert(brandTesla,"Model Y",  "Model Y LR",                   "Long Range",    EngineType.E, 345, 53940d);
-        model.insert(brandTesla,"Model Y",  "Model Y Performance",          "Performance",   EngineType.E, 450, 58940d);
-        model.insert(brandTesla,"Model S",  "Model S Plaid",                "Plaid",         EngineType.E, 1020,0d);
+        model.insert(brandTesla,"Model 3",  "Model 3 LR",                   "Long Range",    EngineType.E, 261, 45940d, LocalDate.of(2017, 07, 01));
+        model.insert(brandTesla,"Model 3",  "Model 3 Performance",          "Performance",   EngineType.E, 487, 53940d, LocalDate.of(2017, 07, 01));
+        model.insert(brandTesla,"Model Y",  "Model Y LR",                   "Long Range",    EngineType.E, 345, 53940d, LocalDate.of(2020, 03, 13));
+        model.insert(brandTesla,"Model Y",  "Model Y Performance",          "Performance",   EngineType.E, 450, 58940d, LocalDate.of(2020, 03, 13));
+        model.insert(brandTesla,"Model S",  "Model S Plaid",                "Plaid",         EngineType.E, 1020,    0d, LocalDate.of(2021, 12, 01));
         // Ford
-        model.insert(brandFord, "Mustang",  "Mustang GT 5,0 l Ti-VCT V8",           "GT",    EngineType.P, 449, 54300d);
-        model.insert(brandFord, "Mustang",  "Mustang Mach1 5,0 l Ti-VCT V8",        "Mach1", EngineType.P, 460, 62800d);
+        model.insert(brandFord, "Mustang",  "Mustang GT 5,0 l Ti-VCT V8",           "GT",    EngineType.P, 449, 54300d, LocalDate.of(2017, 01, 01));
+        model.insert(brandFord, "Mustang",  "Mustang Mach1 5,0 l Ti-VCT V8",        "Mach1", EngineType.P, 460, 62800d, LocalDate.of(2020, 10, 16));
         // Toyota
-        model.insert(brandToy,  "Prius",    "Prius Hybrid 1,8-l-VVT-i",             "Basis", EngineType.H, 122, 38000d);    
-        model.insert(brandToy,  "Supra",    "GR Supra Pure 2,0 l Twin-Scroll Turbo","Pure",  EngineType.P, 258, 49290d);
+        model.insert(brandToy,  "Prius",    "Prius Hybrid 1,8-l-VVT-i",             "Basis", EngineType.H, 122, 38000d, LocalDate.of(2017, 01, 01));    
+        model.insert(brandToy,  "Supra",    "GR Supra Pure 2,0 l Twin-Scroll Turbo","Pure",  EngineType.P, 258, 49290d, LocalDate.of(2020, 03, 31));
         
         // Add some dealers
         DealerRecord dealerDE = (new DealerRecord(context)).insert("Autozentrum Schmitz",      "Munich",       "Germany");
@@ -526,62 +432,123 @@
         
     }
     
-    public void simpleUpdateDemo()
+    public void modelPriceIncrease()
     {
         // shortcuts (for convenience)
         CarSalesDB.Brand BRAND = carSales.BRAND;
         CarSalesDB.Model MODEL = carSales.MODEL;
         // create command
-        /*
-        DBCommand cmd = context.createCommand()
-            .set  (MODEL.BASE_PRICE.to(55000))  // set the price-tag
-            .join (MODEL.WMI, BRAND.WMI)
-            .where(BRAND.NAME.is("Tesla"))
-            .where(MODEL.NAME.is("Model 3").and(MODEL.TRIM.is("Performance")));
-        */
-        
-        DBCommand sub = context.createCommand();
-        sub.select(BRAND.WMI, BRAND.NAME);
-        sub.where (BRAND.COUNTRY.is("Deutschland"));
-        DBQuery qqry = new DBQuery(sub, "qt");
 
+        // Sales-Info
+        String salesInfo = "Price update "+DateUtils.formatDate(LocalDate.now(), Locale.US);
         // create command
         DBCommand cmd = context.createCommand()
             // increase model base prices by 5%
-            .select(MODEL.BASE_PRICE.multiplyWith(105).divideBy(100).round(0))
-            .set  (MODEL.BASE_PRICE.to(55225))
-            .join (MODEL.WMI, BRAND.WMI) // , BRAND.NAME.is("Tesla")
-            // .join (MODEL.WMI, qqry.column(BRAND.WMI), qqry.column(BRAND.NAME).like("V%"))
-            // on all Volkswagen Tiguan with Diesel engine
-            .where(BRAND.NAME.like("Volkswagen%"))
-            .where(MODEL.NAME.is("Tiguan").and(MODEL.ENGINE_TYPE.is(EngineType.D)));
+            .select(BRAND.NAME, MODEL.SPECIFICATION,  MODEL.BASE_PRICE, MODEL.BASE_PRICE.multiplyWith(105).divideBy(100).round(2).as("NEW_PRICE"))
+            // set update fields
+            .set   (MODEL.BASE_PRICE.to(MODEL.BASE_PRICE.multiplyWith(105).divideBy(100).round(2)))
+            .set   (MODEL.SALES_INFO.to(salesInfo))
+            // join with BRANDS
+            .join  (MODEL.WMI, BRAND.WMI) // , BRAND.NAME.is("Tesla")
+            // on all Volkswagen with Diesel engine
+            .where(BRAND.NAME.upper().like("VOLKSWAGEN"))
+            .where(MODEL.ENGINE_TYPE.is(EngineType.D)); // (MODEL.NAME.is("Tiguan").and(
         
+        // Preview the change
+        for (DataListEntry item : context.getUtils().queryDataList(cmd))
+            System.out.println(item.toString());
 
-        String sql = cmd.getSelect();
-        Object[] params = cmd.getParamValues();
-        System.out.println(sql);
-        System.out.println(StringUtils.arrayToString(params, "|"));
-        
+        /*
         // cmd.removeWhereConstraint(MODEL.NAME.is("Tiguan").and(MODEL.ENGINE_TYPE.is(EngineType.D)));
         // cmd.removeWhereConstraintOn(BRAND.NAME);
         sql = cmd.getUpdate();
         params = cmd.getParamValues();
         System.out.println(sql);
         System.out.println(StringUtils.arrayToString(params, "|"));
+        */
         
-        // execute Update statement
+        // Execute the change
         int count = context.executeUpdate(cmd);
         log.info("{} models affected", count);
-        
-        /*
-         * Clone test
-        DBCommand cl1 = cmd.clone();
-        cl1.set(MODEL.BASE_PRICE.to(66000));  // set the price-tag
-        cl1.where(BRAND.NAME.is("Foo"));
-        log.info("cmd= {} params={}", cmd.getUpdate(), cmd.getParamValues());
-        log.info("cmd= {} params={}", cl1.getUpdate(), cl1.getParamValues());
-         */
+        context.commit();
+    }
+    
+    public void modelPriceDecrease()
+    {
+        // shortcuts (for convenience)
+        CarSalesDB.Brand BRAND = carSales.BRAND;
+        CarSalesDB.Model MODEL = carSales.MODEL;
+        // create command
+        DBCommand cmd = context.createCommand()
+            .select(MODEL.getColumns())
+            .join (MODEL.WMI, BRAND.WMI)
+            .where(BRAND.NAME.upper().like("VOLKSWAGEN"))
+            .where(MODEL.ENGINE_TYPE.is(EngineType.D)); // (MODEL.NAME.is("Tiguan").and(
 
+        // Use DBReader to process query result
+        DBReader reader = new DBReader(context);
+        try
+        {   // Open Reader
+            log.info("running modelPriceDecrease for cmd {}", cmd.getSelect());
+            reader.open(cmd);
+            // Print output
+            ModelRecord record = new ModelRecord(context);
+            // Disable rollback handling to improve performance
+            record.setRollbackHandlingEnabled(false);
+            BigDecimal factor = (new BigDecimal(1.05d)).setScale(2, RoundingMode.HALF_UP);
+            while (reader.moveNext())
+            {   // Init updateable record
+                reader.initRecord(record);
+                // Calculate Base-Price
+                BigDecimal oldPrice = reader.getDecimal(MODEL.BASE_PRICE);
+                BigDecimal newPrice = oldPrice.divide(factor, 2, RoundingMode.HALF_UP);
+                record.set(MODEL.BASE_PRICE, newPrice);
+                // update
+                record.update();
+            }
+            // Done
+            context.commit();
+        } finally {
+            // always close Reader
+            reader.close();
+        }
+    }
+
+    private void dealerRatingUpdate()
+    {
+        CarSalesDB.Dealer DEALER = carSales.DEALER;
+        // Clear all dealer ratings
+        DBCommand cmd = context.createCommand()
+                .set(DEALER.RATING.to(DealerRating.X))
+                .where(DEALER.RATING.isNot(null));
+        context.executeUpdate(cmd);
+        context.commit();
+        
+        // Subquery to find TOP 3 dealers
+        CarSalesDB.Sales SALES = carSales.SALES;
+        DBCommand qryCmd = context.createCommand()
+            .select(SALES.DEALER_ID)
+            .where(SALES.YEAR.is(LocalDate.now().getYear()-1))
+            .groupBy(SALES.DEALER_ID)
+            .orderBy(SALES.PRICE.sum().desc())
+            .limitRows(3);
+        DBQuery qryTop = new DBQuery(qryCmd, "qtop");
+        
+        // Dealer-Query
+        cmd.clear();
+        cmd.join(DEALER.ID, qryTop.column(SALES.DEALER_ID));
+        
+        int index = 0;
+        List<DealerRecord> list = context.getUtils().queryRecordList(cmd, DEALER, DealerRecord.class);
+        for (DealerRecord dealer : list)
+        {
+             DealerRating oldRating = dealer.getEnum(DEALER.RATING);
+             DealerRating newRating = DealerRating.values()[index++];
+             log.info("Dealer \"{}\" rating changed from {} to {}", dealer.getString(DEALER.COMPANY_NAME), oldRating, newRating);
+             dealer.set(DEALER.RATING, newRating);
+             dealer.update();
+        }
+        context.commit();
     }
     
     private void queryViewDemo()
@@ -685,70 +652,6 @@
     }
 
     /**
-     * This function performs a query to select non-retired employees,<BR>
-     * then it calculates a checksum for every record<BR>
-     * and writes that checksum back to the database.<BR>
-     * <P>
-     * @param conn a connection to the database
-     */
-    private void bulkProcessRecords()
-    {
-        // Define the query
-        DBCommand cmd = context.createCommand();
-        // Define shortcuts for tables used - not necessary but convenient
-        SampleAdvDB.Employees EMP = T_EMP;
-        // Select required columns
-        cmd.select(T_EMP.getColumns());
-        // Set Constraints
-        cmd.where(T_EMP.C_RETIRED.is(false));
-
-        // Query Records and print output
-        DBReader reader = new DBReader(context);
-        try
-        {
-            // Open Reader
-            System.out.println("Running Query:");
-            System.out.println(cmd.getSelect());
-            reader.open(cmd);
-            // Print output
-            DBRecord record = new DBRecord(context, EMP);
-            // Disable rollback handling to improve performance
-            record.setRollbackHandlingEnabled(false);
-            while (reader.moveNext())
-            {
-                // Calculate sum
-                int sum = 0;
-                for (int i=0; i<reader.getFieldCount(); i++)
-                    sum += calcCharSum(reader.getString(i));
-                // Init updateable record
-                reader.initRecord(record);
-                // reader
-                record.set(T_EMP.C_CHECKSUM, sum);
-                record.update();
-            }
-            // Done
-            context.commit();
-
-        } finally
-        {
-            // always close Reader
-            reader.close();
-        }
-    }
-    
-	private int calcCharSum(String value)
-    {
-        int sum = 0;
-        if (value!=null)
-        {	// calcCharSum
-            int len = value.length();
-            for (int i=0; i<len; i++)
-                sum += value.charAt(i);
-        }
-        return sum;    
-    }
-    
-    /**
      * This method demonstrates how to add, modify and delete a database column.<BR>
      * This function demonstrates the use of the {@link DBMSHandler#getDDLScript(org.apache.empire.db.DDLActionType, org.apache.empire.db.DBObject, DBSQLScript)}<BR>
      * 
@@ -795,61 +698,6 @@
     }
 
     /**
-     * This function demonstrates the use of the DBQuery object.<BR>
-     * First a DBQuery is used to define a subquery that gets the latest employee department history record.<BR>
-     * This subquery is then used inside another query to list all employees with the current department.<BR>
-     * <P>
-     * In the second part, another DBQuery object is used to read a record that holds information from both 
-     * the employee and department table. When the information is modified and the record's update method is
-     * called, then both tables are updated.
-     * <P>
-     * @param conn
-     * @param employeeId
-     */
-    private void querySample(int employeeId)
-    {
-        // Define the sub query
-        DBCommand subCmd = context.createCommand();
-        DBColumnExpr MAX_DATE_FROM = T_EDH.C_DATE_FROM.max().as(T_EDH.C_DATE_FROM);
-        subCmd.select(T_EDH.C_EMPLOYEE_ID, MAX_DATE_FROM);
-        subCmd.groupBy(T_EDH.C_EMPLOYEE_ID);
-        DBQuery Q_MAX_DATE = new DBQuery(subCmd);
-
-        // Define the query
-        DBCommand cmd = context.createCommand();
-        // Select required columns
-        cmd.select(T_EMP.C_EMPLOYEE_ID, T_EMP.C_FULLNAME);
-        cmd.select(T_EMP.C_GENDER, T_EMP.C_PHONE_NUMBER);
-        cmd.select(T_DEP.C_DEPARTMENT_ID, T_DEP.C_NAME, T_DEP.C_BUSINESS_UNIT);
-        cmd.select(T_EMP.C_UPDATE_TIMESTAMP, T_DEP.C_UPDATE_TIMESTAMP);
-        // Set Joins
-        cmd.join(T_EDH.C_EMPLOYEE_ID, Q_MAX_DATE.column(T_EDH.C_EMPLOYEE_ID),
-                 T_EDH.C_DATE_FROM.is(Q_MAX_DATE.column(MAX_DATE_FROM)));
-        cmd.join(T_EMP.C_EMPLOYEE_ID, T_EDH.C_EMPLOYEE_ID);
-        cmd.join(T_DEP.C_DEPARTMENT_ID, T_EDH.C_DEPARTMENT_ID);
-        // Set Constraints
-        cmd.where(T_EMP.C_RETIRED.is(false));
-        // Set Order
-        cmd.orderBy(T_EMP.C_LASTNAME);
-        cmd.orderBy(T_EMP.C_FIRSTNAME);
-
-        // Query Records and print output
-        printQueryResults(cmd);
-        
-        // Define an updateable query
-        DBQuery Q_EMP_DEP = new DBQuery(cmd, T_EMP.C_EMPLOYEE_ID);
-        DBRecord rec = new DBRecord(context, Q_EMP_DEP);
-        // Modify and Update fields from both Employee and Department
-        rec.read(employeeId)
-           .set(T_EMP.C_PHONE_NUMBER, "0815-4711")
-           .set(T_DEP.C_BUSINESS_UNIT, "AUTO")
-           .update();
-        // Successfully updated
-        System.out.println("The employee has been sucessfully updated");
-    }    
-    
-
-    /**
      * testTransactionCreate
      * @param context
      * @param idDep
@@ -873,10 +721,11 @@
         model.create()
             .set(MODEL.WMI             , "WVW")  // = Volkswagen
             .set(MODEL.NAME            , "ID.4")
-            .set(MODEL.SPECIFICATION     , "ID.4 Pro Performance 150 kW 77 kWh")
+            .set(MODEL.SPECIFICATION   , "ID.4 Pro Performance 150 kW 77 kWh")
             .set(MODEL.TRIM            , "Pro")
             .set(MODEL.ENGINE_TYPE     , EngineType.E)
-            .set(MODEL.ENGINE_POWER    , 204);
+            .set(MODEL.ENGINE_POWER    , 204)
+            .set(MODEL.FIRST_SALE      , LocalDate.of(2021, 04, 04));
         // State and timestampe before and after insert
         log.debug("Record state={}, key={}, Timestamp={}", model.getState(), model.getKey(), model.get(MODEL.UPDATE_TIMESTAMP));
         model.update();
@@ -1009,7 +858,6 @@
      * This functions prints the results of a query which is performed using the supplied command
      * @param cmd the command to be used for performing the query
      * @param conn the connection
-     */
     private void printQueryResults(DBCommand cmd)
     {
         // Query Records and print output
@@ -1058,6 +906,7 @@
             reader.close();
         }
     }
+     */
     
     
 }
diff --git a/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/SampleAdvDB.java b/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/SampleAdvDB.java
deleted file mode 100644
index 7a822e8..0000000
--- a/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/SampleAdvDB.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.empire.samples.db.advanced;
-
-import java.sql.SQLException;
-
-import org.apache.empire.commons.Options;
-import org.apache.empire.data.DataType;
-import org.apache.empire.db.DBColumn;
-import org.apache.empire.db.DBColumnExpr;
-import org.apache.empire.db.DBCommand;
-import org.apache.empire.db.DBCommandExpr;
-import org.apache.empire.db.DBContext;
-import org.apache.empire.db.DBDatabase;
-import org.apache.empire.db.DBSQLScript;
-import org.apache.empire.db.DBTableColumn;
-import org.apache.empire.db.generic.TDatabase;
-import org.apache.empire.db.generic.TTable;
-import org.apache.empire.db.generic.TView;
-import org.apache.empire.db.validation.DBModelChecker;
-import org.apache.empire.db.validation.DBModelErrorLogger;
-import org.apache.empire.dbms.DBMSHandler;
-import org.apache.empire.dbms.postgresql.DBMSHandlerPostgreSQL;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * <PRE>
- * This file contains the definition of the data model in Java.
- * The SampleDB data model consists of two tables and a foreign key relation.
- * The tables are defined as nested classes here, but you may put the in separate files if you want.
- *
- * PLEASE NOTE THE NAMING CONVENTION:
- * Since all tables, views and columns are declared as "final" constants they are all in upper case.
- * We recommend using a prefix of T_ for tables and C_ for columns in order to keep them together
- * when listed in your IDE's code completion.
- * There is no need to stick to this convention but it makes life just another little bit easier.
- *
- * You may declare other database tables or views in the same way.
- * </PRE>
- */
-public class SampleAdvDB extends TDatabase<SampleAdvDB>
-{
-    // *Deprecated* private static final long serialVersionUID = 1L;
-
-    // Logger
-    private static final Logger log = LoggerFactory.getLogger(SampleAdvDB.class);
-
-    /**
-     * This class represents the definition of the Departments table.
-     */
-    public static class Departments extends TTable<SampleAdvDB>
-    {
-        // *Deprecated* private static final long serialVersionUID = 1L;
-
-        public final DBTableColumn C_DEPARTMENT_ID;
-        public final DBTableColumn C_NAME;
-        public final DBTableColumn C_HEAD;
-        public final DBTableColumn C_BUSINESS_UNIT;
-        public final DBTableColumn C_UPDATE_TIMESTAMP;
-
-        public Departments(SampleAdvDB db)
-        {
-            super("DEPARTMENTS", db);
-            // ID
-            C_DEPARTMENT_ID   = addColumn("DEPARTMENT_ID",    DataType.AUTOINC,       0, true, "DEP_ID_SEQUENCE");
-            C_NAME            = addColumn("NAME",             DataType.VARCHAR,      80, true);
-            C_HEAD            = addColumn("HEAD",             DataType.VARCHAR,      80, false);
-            C_BUSINESS_UNIT   = addColumn("BUSINESS_UNIT",    DataType.VARCHAR,       4, true, "ITTK");
-            C_UPDATE_TIMESTAMP= addColumn("UPDATE_TIMESTAMP", DataType.TIMESTAMP,     0, true);
-
-            // Primary Key
-            setPrimaryKey(C_DEPARTMENT_ID);
-            // Set other Indexes
-            addIndex("DEARTMENT_NAME_IDX", true, new DBColumn[] { C_NAME });
-        }
-    }
-
-    /**
-     * This class represents the definition of the Employees table.
-     */
-    public static class Employees extends TTable<SampleAdvDB>
-    {
-        // *Deprecated* private static final long serialVersionUID = 1L;
-      
-        public final DBTableColumn C_EMPLOYEE_ID;
-        public final DBTableColumn C_SALUTATION;
-        public final DBTableColumn C_FIRSTNAME;
-        public final DBTableColumn C_LASTNAME;
-        public final DBTableColumn C_DATE_OF_BIRTH;
-        public final DBTableColumn C_GENDER;
-        public final DBTableColumn C_PHONE_NUMBER;
-        public final DBTableColumn C_EMAIL;
-        public final DBTableColumn C_RETIRED;
-        public final DBTableColumn C_CHECKSUM;
-        public final DBTableColumn C_UPDATE_TIMESTAMP;
-
-        // Useful column expressions
-        public final DBColumnExpr  C_FULLNAME;
-        
-        public Employees(SampleAdvDB db)
-        {
-            super("EMPLOYEES", db);
-            // ID
-            C_EMPLOYEE_ID     = addColumn("EMPLOYEE_ID",      DataType.AUTOINC,      0, true, "EMPLOYEE_ID_SEQUENCE");
-            C_SALUTATION      = addColumn("SALUTATION",       DataType.VARCHAR,     20, false);
-            C_FIRSTNAME       = addColumn("FIRSTNAME",        DataType.VARCHAR,     40, true);
-            C_LASTNAME        = addColumn("LASTNAME",         DataType.VARCHAR,     40, true);
-            C_DATE_OF_BIRTH   = addColumn("DATE_OF_BIRTH",    DataType.DATE,         0, false);
-            C_GENDER          = addColumn("GENDER",           DataType.VARCHAR,      1, false);
-            C_PHONE_NUMBER    = addColumn("PHONE_NUMBER",     DataType.VARCHAR,     40, false);
-            C_EMAIL           = addColumn("EMAIL",            DataType.VARCHAR,     80, false);
-            C_RETIRED         = addColumn("RETIRED",          DataType.BOOL,         0, true, false);
-            C_CHECKSUM        = addColumn("CHECKSUM",         DataType.INTEGER,      0, false);
-            C_UPDATE_TIMESTAMP= addColumn("UPDATE_TIMESTAMP", DataType.TIMESTAMP,    0, true);
-
-            // Primary Key
-            setPrimaryKey(C_EMPLOYEE_ID);
-            // Set other Indexes
-            addIndex("EMPLOYEE_NAME_IDX", true, new DBColumn[] { C_FIRSTNAME, C_LASTNAME, C_DATE_OF_BIRTH });
-
-            // Create Options for GENDER column
-            Options genders = new Options();
-            genders.set("M", "Male");
-            genders.set("F", "Female");
-            C_GENDER.setOptions(genders);
-            
-            // Define Column Expressions
-            C_FULLNAME = C_LASTNAME.append(", ").append(C_FIRSTNAME).as("FULL_NAME");
-            
-        }
-    }
-    
-    /**
-     * This class represents the definition of the Departments table.
-     */
-    public static class EmployeeDepartmentHistory extends TTable<SampleAdvDB>
-    {
-        // *Deprecated* private static final long serialVersionUID = 1L;
-      
-        public final DBTableColumn C_EMPLOYEE_ID;
-        public final DBTableColumn C_DEPARTMENT_ID;
-        public final DBTableColumn C_DATE_FROM;
-
-        public EmployeeDepartmentHistory(SampleAdvDB db)
-        {
-            super("EMPLOYEE_DEPARTMENT_HIST", db);
-            // ID
-            C_EMPLOYEE_ID   = addColumn("EMPLOYEE_ID",      DataType.INTEGER,       0, true);
-            C_DEPARTMENT_ID = addColumn("DEPARTMENT_ID",    DataType.INTEGER,       0, true);
-            C_DATE_FROM     = addColumn("DATE_FROM",        DataType.DATE,          0, true);
-
-            // Primary Key
-            setPrimaryKey(C_EMPLOYEE_ID, C_DATE_FROM);
-        }
-    }
-
-    /**
-     * This class represents the definition of the EmployeeDepSinceView table.
-     */
-    public static class EmployeeDepSinceView extends TView<SampleAdvDB>
-    {
-        // *Deprecated* private static final long serialVersionUID = 1L;
-      
-        public final DBViewColumn C_EMPLOYEE_ID;
-        public final DBViewColumn C_MAX_DATE_FROM;
-        
-        public EmployeeDepSinceView(SampleAdvDB db, EmployeeDepartmentHistory T_EDH)
-        {
-            super("EMPLOYEE_DEP_SINCE_VIEW", db);
-            // ID
-            C_EMPLOYEE_ID     = addColumn(T_EDH.C_EMPLOYEE_ID);
-            C_MAX_DATE_FROM   = addColumn("MAX_DATE_FROM", T_EDH.C_DATE_FROM); 
-
-            // set Key-column (if any)
-            setKeyColumn(C_EMPLOYEE_ID);
-        }
-
-        @Override
-        public DBCommandExpr createCommand()
-        {
-            /* Sample DDL for this View:
-            CREATE VIEW EMPLOYEE_DEP_SINCE_VIEW (EMPLOYEE_ID, MAX_DATE_FROM)
-            AS (SELECT t3.EMPLOYEE_ID, max(t3.DATE_FROM)
-                FROM EMPLOYEE_DEPARTMENT_HIST t3
-                GROUP BY t3.EMPLOYEE_ID);
-            */
-
-            SampleAdvDB.EmployeeDepartmentHistory EDH = DB.T_EMP_DEP_HIST;
-            
-            // Define the sub query
-            DBCommand cmd = newCommand();
-            cmd.select (EDH.C_EMPLOYEE_ID, EDH.C_DATE_FROM.max());
-            cmd.groupBy(EDH.C_EMPLOYEE_ID);
-            return cmd;
-        }
-    }
-
-    /**
-     * This class represents the definition of the EmployeeInfoView table.
-     */
-    public static class EmployeeInfoView extends TView<SampleAdvDB>
-    {
-        // *Deprecated* private static final long serialVersionUID = 1L;
-      
-        public final DBViewColumn C_EMPLOYEE_ID;
-        public final DBViewColumn C_CURRENT_DEP_ID;
-        public final DBViewColumn C_NAME_AND_DEP;
-
-        public EmployeeInfoView(SampleAdvDB db, Employees T_EMP, Departments T_DEP)
-        {
-            super("EMPLOYEE_INFO_VIEW", db);
-            // ID
-            C_EMPLOYEE_ID     = addColumn(T_EMP.C_EMPLOYEE_ID);
-            C_CURRENT_DEP_ID  = addColumn("CURRENT_DEP_ID", T_DEP.C_DEPARTMENT_ID); 
-            C_NAME_AND_DEP    = addColumn("NAME_AND_DEP",   DataType.VARCHAR);
-
-            // set Key-column (if any)
-            setKeyColumn(C_EMPLOYEE_ID);
-        }
-
-        @Override
-        public DBCommandExpr createCommand()
-        {
-            /* Sample DDL for this View:
-            CREATE VIEW EMPLOYEE_INFO_VIEW (EMPLOYEE_ID, CURRENT_DEP_ID, NAME_AND_DEP)
-            AS (SELECT t2.EMPLOYEE_ID, t1.DEPARTMENT_ID, t2.LASTNAME + ', ' + coalesce(t2.FIRSTNAME, '') + ' (' + t1.NAME + ')'
-                FROM EMPLOYEE_DEPARTMENT_HIST t3 
-                INNER JOIN EMPLOYEE_DEP_SINCE_VIEW v1 ON v1.EMPLOYEE_ID = t3.EMPLOYEE_ID AND t3.DATE_FROM=v1.MAX_DATE_FROM
-                INNER JOIN EMPLOYEES t2 ON t2.EMPLOYEE_ID = t3.EMPLOYEE_ID
-                INNER JOIN DEPARTMENTS t1 ON t1.DEPARTMENT_ID = t3.DEPARTMENT_ID);
-            */
-            
-            SampleAdvDB.Employees   EMP = DB.T_EMPLOYEES;
-            SampleAdvDB.EmployeeDepartmentHistory EDH = DB.T_EMP_DEP_HIST;
-            SampleAdvDB.EmployeeDepSinceView EDS = DB.V_EMP_DEP_SINCE_VIEW;
-            SampleAdvDB.Departments DEP = DB.T_DEPARTMENTS;
-
-            // Define the query
-            DBCommand cmd = newCommand();
-            // Select required columns
-            cmd.select(EMP.C_EMPLOYEE_ID);
-            cmd.select(DEP.C_DEPARTMENT_ID);
-            cmd.select(EMP.C_LASTNAME.append(", ")
-                       .append(EMP.C_FIRSTNAME.coalesce(DBDatabase.EMPTY_STRING))
-                       .append(" (").append(DEP.C_NAME).append(")"));
-            // Set Joins
-            cmd.join(EDH.C_EMPLOYEE_ID, EDS.C_EMPLOYEE_ID, EDH.C_DATE_FROM.is(EDS.C_MAX_DATE_FROM));
-            cmd.join(EMP.C_EMPLOYEE_ID, EDH.C_EMPLOYEE_ID);
-            cmd.join(DEP.C_DEPARTMENT_ID, EDH.C_DEPARTMENT_ID);
-            // done
-            return cmd;
-        }
-    }
-    
-    // Declare all Tables
-    public final Departments  T_DEPARTMENTS = new Departments(this);
-    public final Employees    T_EMPLOYEES   = new Employees(this);
-    public final EmployeeDepartmentHistory  T_EMP_DEP_HIST = new EmployeeDepartmentHistory(this);
-    // Declare all Views
-    public final EmployeeDepSinceView V_EMP_DEP_SINCE_VIEW;
-    public final EmployeeInfoView V_EMPLOYEE_INFO; 
-    
-    /**
-     * Constructor of the SampleDB data model description
-     *
-     * Put all foreign key relations here.
-     */
-    public SampleAdvDB()
-    {
-        // Create views
-        V_EMP_DEP_SINCE_VIEW = new EmployeeDepSinceView(this, T_EMP_DEP_HIST);
-        V_EMPLOYEE_INFO      = new EmployeeInfoView(this, T_EMPLOYEES, T_DEPARTMENTS);
-        
-        // Define Foreign-Key Relations
-        addRelation( T_EMP_DEP_HIST.C_EMPLOYEE_ID  .referenceOn( T_EMPLOYEES.C_EMPLOYEE_ID )).onDeleteCascade();
-        addRelation( T_EMP_DEP_HIST.C_DEPARTMENT_ID.referenceOn( T_DEPARTMENTS.C_DEPARTMENT_ID ));
-    }
-    
-    @Override
-    public void open(DBContext context)
-    {
-        // Enable prepared statements
-        setPreparedStatementsEnabled(true);
-        // Check exists
-        if (checkExists(context))
-        {   // attach to driver
-            super.open(context);
-            // yes, it exists, then check the model
-            checkDataModel(context);
-        }
-        else
-        {   // PostgreSQL does not support DDL in transaction
-            DBMSHandler dbms = context.getDbms();
-            if (dbms instanceof DBMSHandlerPostgreSQL)
-                setAutoCommit(context, true);
-            // create the database
-            createDatabase(context);
-            // PostgreSQL does not support DDL in transaction
-            if (dbms instanceof DBMSHandlerPostgreSQL)
-                setAutoCommit(context, false);
-            // attach to driver
-            super.open(context);
-        }
-    }
-
-    private void createDatabase(DBContext context)
-    {
-        // create DDL for Database Definition
-        DBSQLScript script = new DBSQLScript(context);
-        getCreateDDLScript(script);
-        // Show DDL Statement
-        log.info(script.toString());
-        // Execute Script
-        script.executeAll(false);
-        // Commit
-        context.commit();
-    }
-    
-    private void checkDataModel(DBContext context)
-    {   try {
-            DBModelChecker modelChecker = context.getDbms().createModelChecker(this);
-            // Check data model   
-            log.info("Checking DataModel for {} using {}", getClass().getSimpleName(), modelChecker.getClass().getSimpleName());
-            // dbo schema
-            DBModelErrorLogger logger = new DBModelErrorLogger();
-            modelChecker.checkModel(this, context.getConnection(), logger);
-            // show result
-            log.info("Data model check done. Found {} errors and {} warnings.", logger.getErrorCount(), logger.getWarnCount());
-        } catch(Exception e) {
-            log.error("FATAL error when checking data model. Probably not properly implemented by DBMSHandler!");
-        }
-    }
-    
-    private void setAutoCommit(DBContext context, boolean enable)
-    {   try {
-            context.getConnection().setAutoCommit(enable);
-        } catch (SQLException e) {
-            log.error("Unable to set AutoCommit on Connection", e);
-        }
-    }
-
-}
diff --git a/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/db/CarSalesDB.java b/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/db/CarSalesDB.java
index a378dc3..30d32b2 100644
--- a/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/db/CarSalesDB.java
+++ b/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/db/CarSalesDB.java
@@ -20,6 +20,7 @@
 
 import java.sql.SQLException;
 
+import org.apache.empire.commons.EnumValue;
 import org.apache.empire.data.DataType;
 import org.apache.empire.db.DBContext;
 import org.apache.empire.db.DBSQLScript;
@@ -59,7 +60,7 @@
     public enum EngineType
     {
         P("Petrol"),
-        D("Diese"),
+        D("Diesel"),
         H("Hybrid"),
         E("Electric");
         
@@ -99,6 +100,34 @@
     }
 
     /**
+     * Dealer Rating
+     */
+    public enum DealerRating implements EnumValue
+    {
+        A,
+        B,
+        C,
+        X;
+
+        /**
+         * Override to use Minus '-' instead of 'X' in Database
+         */
+        @Override
+        public Object toValue(boolean numeric)
+        {
+            if (this==X)
+                return "-"; 
+            return (numeric ? ordinal() : name());
+        }
+
+        @Override
+        public String toString()
+        {
+            return name();
+        }
+    }
+    
+    /**
      * This class represents the Brand table.
      */
     public static class Brand extends TTable<CarSalesDB>
@@ -135,6 +164,11 @@
         public final DBTableColumn ENGINE_TYPE;
         public final DBTableColumn ENGINE_POWER;
         public final DBTableColumn BASE_PRICE;
+        public final DBTableColumn FIRST_SALE;
+        public final DBTableColumn LAST_SALE;
+        public final DBTableColumn MODEL_BINARY;
+        public final DBTableColumn MODEL_XML;
+        public final DBTableColumn SALES_INFO;
         public final DBTableColumn UPDATE_TIMESTAMP;
 
         public Model(CarSalesDB db)
@@ -150,6 +184,11 @@
             ENGINE_TYPE     = addColumn    ("ENGINE_TYPE",      DataType.CHAR,         1, true, EngineType.class);
             ENGINE_POWER    = addColumn    ("ENGINE_POWER",     DataType.DECIMAL,    4.0, true);
             BASE_PRICE      = addColumn    ("BASE_PRICE",       DataType.DECIMAL,    8.2, false);
+            FIRST_SALE      = addColumn    ("FIRST_SALE",       DataType.DATE,         0, true);
+            LAST_SALE       = addColumn    ("LAST_SALE",        DataType.DATE,         0, false);
+            MODEL_BINARY    = addColumn    ("MODEL_BINARY",     DataType.BLOB,         0, false);
+            MODEL_XML       = addColumn    ("MODEL_XML",        DataType.CLOB,         0, false);
+            SALES_INFO      = addColumn    ("SALES_INFO",       DataType.VARCHAR,     80, false); 
             UPDATE_TIMESTAMP= addTimestamp ("UPDATE_TIMESTAMP");
             
             // Primary Key (automatically set due to addIdentity()) otherwise use 
@@ -168,6 +207,7 @@
         public final DBTableColumn CITY;
         public final DBTableColumn COUNTRY;
         public final DBTableColumn YEAR_FOUNDED;
+        public final DBTableColumn RATING;
         public final DBTableColumn UPDATE_TIMESTAMP;
 
         public Dealer(CarSalesDB db)
@@ -181,6 +221,7 @@
             CITY            = addColumn   ("CITY",             DataType.VARCHAR,     20, true);
             COUNTRY         = addColumn   ("COUNTRY",          DataType.VARCHAR,     40, true);
             YEAR_FOUNDED    = addColumn   ("YEAR_FOUNDED",     DataType.DECIMAL,    4.0, false);
+            RATING          = addColumn   ("RATING",           DataType.CHAR,         1, true, DealerRating.X);
             UPDATE_TIMESTAMP= addTimestamp("UPDATE_TIMESTAMP");
             
             // Primary Key (automatically set due to addIdentity()) otherwise use 
diff --git a/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/records/ModelRecord.java b/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/records/ModelRecord.java
index 446bb72..31bc745 100644
--- a/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/records/ModelRecord.java
+++ b/empire-db-examples/empire-db-example-advanced/src/main/java/org/apache/empire/samples/db/advanced/records/ModelRecord.java
@@ -1,12 +1,24 @@
 package org.apache.empire.samples.db.advanced.records;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.StringWriter;
+import java.time.LocalDate;
+
 import org.apache.empire.db.generic.TRecord;
 import org.apache.empire.samples.db.advanced.SampleContext;
 import org.apache.empire.samples.db.advanced.db.CarSalesDB;
 import org.apache.empire.samples.db.advanced.db.CarSalesDB.EngineType;
+import org.apache.empire.xml.XMLWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
 
 public class ModelRecord extends TRecord<CarSalesDB.Model>
 {
+    private static final Logger log = LoggerFactory.getLogger(ModelRecord.class);
+
     private static final long serialVersionUID = 1L;
 
     public ModelRecord(SampleContext context)
@@ -14,7 +26,8 @@
         super(context, context.getDatabase().MODEL);
     }
     
-    public void insert(BrandRecord brand, String modelName, String configName, String trim, EngineType engineType, int enginePower, double basePrice)
+    public void insert(BrandRecord brand, String modelName, String configName, String trim
+                       , EngineType engineType, int enginePower, double basePrice, LocalDate firstSale)
     {
         // T = RowSet (Table/View)
         create();
@@ -25,6 +38,50 @@
         set(T.ENGINE_TYPE     , engineType);
         set(T.ENGINE_POWER    , enginePower);
         set(T.BASE_PRICE      , basePrice);
+        set(T.FIRST_SALE      , firstSale);
         update();
     }
+    
+    @Override
+    public void update()
+    {
+        if (isModified())
+        {   // Record was modified
+            // Clear and reset MODEL_BINARY and MODEL_XML
+            set(T.MODEL_XML, null);
+            set(T.MODEL_BINARY, null);
+            // Reset
+            set(T.MODEL_XML, getModelXml());
+            set(T.MODEL_BINARY, getModelBinary());
+        }
+        super.update();
+    }
+    
+    private String getModelXml()
+    {
+        Document modelDoc = this.getXmlDocument();
+        StringWriter writer = new StringWriter();
+        XMLWriter xmlWriter = new XMLWriter(writer, "utf-8");
+        xmlWriter.print(modelDoc);
+        return writer.toString();
+    }
+    
+    private byte[] getModelBinary()
+    {
+        try
+        {   // All fields, but without MODEL_BINARY
+            Object[] fields = this.getFields();
+            fields[getFieldIndex(T.MODEL_BINARY)]=null;
+            // Serialize the record fields
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutputStream oos = new ObjectOutputStream(baos);
+            oos.writeObject(fields);
+            return baos.toByteArray();
+        }
+        catch (IOException e)
+        {
+            log.error("Unable to serialize the record fields", e);
+            return null;
+        }
+    }
 }
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBCommand.java b/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
index 6883adb..9599bf0 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
@@ -30,8 +30,6 @@
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.commons.Unwrappable;
 import org.apache.empire.data.DataType;
-import org.apache.empire.db.expr.column.DBAliasExpr;
-import org.apache.empire.db.expr.column.DBValueExpr;
 import org.apache.empire.db.expr.compare.DBCompareAndOrExpr;
 import org.apache.empire.db.expr.compare.DBCompareColExpr;
 import org.apache.empire.db.expr.compare.DBCompareExpr;
@@ -45,7 +43,6 @@
 import org.apache.empire.dbms.DBSqlPhrase;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.ItemNotFoundException;
-import org.apache.empire.exceptions.NotSupportedException;
 import org.apache.empire.exceptions.ObjectNotValidException;
 import org.apache.empire.exceptions.UnspecifiedErrorException;
 import org.slf4j.Logger;
@@ -61,172 +58,6 @@
     implements Cloneable
 {
     // *Deprecated* private static final long serialVersionUID = 1L;
-
-    /**
-     * DBMergeCommand
-     * @author rainer
-     */
-    protected static class DBMergeCommand extends DBCommand
-    {
-        private final DBCommand parent;
-        
-        protected DBMergeCommand(DBCommand parent)
-        {
-            super(parent.isAutoPrepareStmt());
-            this.parent = parent;
-            // set 
-            List<DBSetExpr> set = parent.getSetExpressions();
-            if (set!=null)
-                this.set = new ArrayList<DBSetExpr>(set);
-            // joins
-            List<DBJoinExpr> joins = parent.getJoins();
-            if (joins!=null)
-                this.joins = new ArrayList<DBJoinExpr>(joins);
-            // where
-            List<DBCompareExpr> where = parent.getWhereConstraints();
-            if (where!=null)
-                this.where = new ArrayList<DBCompareExpr>(where);
-            // groupBy
-            List<DBColumnExpr> groupBy = parent.getGroupBy();
-            if (groupBy!=null)
-                this.groupBy = new ArrayList<DBColumnExpr>(groupBy);
-            // having
-            List<DBCompareExpr> having = parent.getHavingConstraints();
-            if (having!=null)
-                this.having = new ArrayList<DBCompareExpr>(having);
-        }   
-        
-        @Override
-        protected void notifyParamUsage(DBCmdParam param)
-        {
-            throw new NotSupportedException(this, "notifyParamUsage");
-        }
-        
-        @Override
-        protected void resetParamUsage()
-        {
-            /* Nothing */
-        }
-        
-        @Override
-        protected void completeParamUsage()
-        {
-            /* Nothing */
-        }
-        
-        @Override
-        protected void mergeSubqueryParams(Object[] subQueryParams)
-        {
-            parent.mergeSubqueryParams(subQueryParams);
-        }
-        
-        @Override
-        protected void addJoin(StringBuilder buf, DBJoinExpr join, long context, int whichParams)
-        {
-            parent.addJoin(buf, join, context, whichParams);
-        }
-        
-        public List<DBSetExpr> addUsing(StringBuilder buf, DBRowSet table, DBColumnJoinExpr updateJoin)
-        {
-            buf.append("\r\nUSING ");
-            // clearSelect();
-            // clearOrderBy();
-            DBRowSet outerTable = updateJoin.getOuterTable();
-            if (outerTable==null)
-                outerTable=table;
-            Set<DBColumn> joinColumns = new HashSet<DBColumn>();
-            updateJoin.addReferencedColumns(joinColumns);
-            for (DBColumn jcol : joinColumns)
-            {   // Select join columns
-                if (jcol.getRowSet().equals(outerTable)==false)
-                    select(jcol);
-            }
-            // find the source table
-            DBColumnExpr left  = updateJoin.getLeft();
-            DBColumnExpr right = updateJoin.getRight();
-            DBRowSet source = right.getUpdateColumn().getRowSet();
-            if (source==table)
-                source = left.getUpdateColumn().getRowSet();
-            // Add set expressions
-            String sourceAliasPrefix = source.getAlias()+".";
-            List<DBSetExpr> mergeSet = new ArrayList<DBSetExpr>(set.size());   
-            for (DBSetExpr sex : set)
-            {   // Select set expressions
-                Object val = sex.getValue();
-                if (val instanceof DBColumnExpr)
-                {
-                    DBColumnExpr expr = ((DBColumnExpr)val);
-                    if (!(expr instanceof DBColumn) && !(expr instanceof DBAliasExpr))
-                    {   // rename column
-                        String name = "COL_"+String.valueOf(mergeSet.size());
-                        expr = expr.as(name);
-                    }
-                    // select
-                    select(expr);
-                    // Name
-                    DBValueExpr NAME_EXPR = getDatabase().getValueExpr(sourceAliasPrefix+expr.getName(), DataType.UNKNOWN);
-                    mergeSet.add(sex.getColumn().to(NAME_EXPR));
-                }
-                else
-                {   // add original
-                    mergeSet.add(sex);
-                }
-            }
-            // remove join (if not necessary)
-            if (hasConstraintOn(table)==false)
-                removeJoinsOn(table);
-            // add SQL for inner statement
-            addSQL(buf, CTX_DEFAULT);
-            // add Alias
-            buf.append(" ");
-            buf.append(source.getAlias());
-            buf.append("\r\nON (");
-            left.addSQL(buf, CTX_DEFAULT);
-            buf.append(" = ");
-            right.addSQL(buf, CTX_DEFAULT);
-            // Compare Expression
-            if (updateJoin.getWhere() != null)
-                appendMergeConstraint(buf, table, updateJoin.getWhere());
-            // More constraints
-            for (DBCompareExpr cmpExpr : this.where) 
-            {
-                appendMergeConstraint(buf, table, cmpExpr);
-            }
-            // done
-            return mergeSet;
-        }
-    
-        protected void appendMergeConstraint(StringBuilder buf, DBRowSet table, DBCompareExpr cmpExpr)
-        {
-            if (cmpExpr instanceof DBCompareColExpr)
-            {   // a compare column expression
-                DBCompareColExpr cce = (DBCompareColExpr)cmpExpr;
-                DBColumn ccecol = cce.getColumn().getUpdateColumn();
-                if (table.isKeyColumn(ccecol)&& !isSetColumn(ccecol))  
-                {   // yes, add
-                    buf.append(" AND ");
-                    cce.addSQL(buf, CTX_DEFAULT);
-                }
-            }
-            // else if (cmpExpr instanceof DBCompareAndOrExpr)
-            // else if (cmpExpr instanceof DBCompareNotExpr)
-            else  
-            {   // just add
-                buf.append(" AND ");
-                cmpExpr.addSQL(buf, CTX_DEFAULT);
-            }
-        }
-            
-        protected boolean isSetColumn(DBColumn col)
-        {
-            for (DBSetExpr se : this.set)
-            {
-                if (se.getColumn().equals(col))
-                    return true;
-            }
-            return false;
-        }
-    }
     
     // Logger
     protected static final Logger log             = LoggerFactory.getLogger(DBCommand.class);
@@ -1465,16 +1296,6 @@
         clearLimit();
         resetParamUsage();
     }
-
-    /**
-     * Create a special Merge-command
-     * This forwards parameter usage to the parent command 
-     * @return the merge command
-     */
-    protected DBMergeCommand createMergeCommand()
-    {
-        return new DBMergeCommand(this); 
-    }
     
     /**
      * returns true if prepared statements are enabled for this command
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBDatabase.java b/empire-db/src/main/java/org/apache/empire/db/DBDatabase.java
index 6d32eda..bf1c688 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBDatabase.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBDatabase.java
@@ -1088,8 +1088,8 @@
                 break;
                 
             default:
-                if (log.isDebugEnabled())
-                    log.debug("No column validation has been implemented for data type " + type);
+                if (log.isTraceEnabled())
+                    log.trace("No column validation has been implemented for data type " + type);
                 break;
         }
         return value;
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBTable.java b/empire-db/src/main/java/org/apache/empire/db/DBTable.java
index 556fa1d..d1f51a8 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBTable.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBTable.java
@@ -37,6 +37,7 @@
 import org.apache.empire.db.exceptions.RecordUpdateFailedException;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.ItemExistsException;
+import org.apache.empire.exceptions.NotSupportedException;
 import org.apache.empire.exceptions.ObjectNotValidException;
 import org.apache.empire.exceptions.UnexpectedReturnValueException;
 import org.apache.empire.exceptions.UnspecifiedErrorException;
@@ -52,10 +53,10 @@
     // *Deprecated* private static final long serialVersionUID = 1L;
     
     // Integer size definitions
-    public static final int DEFAULT   = 0;
-    public static final int SMALLINT  = 2;
-    public static final int MEDIUMINT = 4;
-    public static final int BIGINT    = 8;
+    public static final int INT_SIZE_DEFAULT = 0;
+    public static final int INT_SIZE_SMALL   = 2;
+    public static final int INT_SIZE_MEDIUM  = 4;
+    public static final int INT_SIZE_BIG     = 8;
 
     private static AtomicInteger tableCount          = new AtomicInteger(0);
 
@@ -428,7 +429,7 @@
      */
     public DBTableColumn addIdentity(String name, String seqName)
     {
-        return addColumn("ID", DataType.AUTOINC, 0, true, seqName);
+        return addColumn(name, DataType.AUTOINC, INT_SIZE_BIG, true, seqName);
     }
     
     /**
@@ -448,7 +449,7 @@
         // Check key
         DBColumn[] keyCols = target.getKeyColumns();
         if (keyCols==null || keyCols.length!=1)
-            throw new InvalidArgumentException("target", target);
+            throw new NotSupportedException(target, "addForeignKey");
         // add column
         DBTableColumn keyCol = (DBTableColumn)keyCols[0];
         DataType keyDataType = keyCol.getDataType();
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBUtils.java b/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
index e65651b..1a29c3e 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
@@ -76,6 +76,34 @@
     }
 
     /**
+     * Log Query Statement
+     * @param sqlCmd
+     * @param sqlParams
+     */
+    protected void logQueryStatement(String sqlCmd, Object[] sqlParams)
+    {
+        if (log.isDebugEnabled())
+        {   log.debug("Executing DQL: " + sqlCmd);
+            if (sqlParams!=null && sqlParams.length>0)
+                log.debug("Parameters: " + StringUtils.arrayToString(sqlParams, "|"));
+        }
+    }
+
+    /**
+     * Log Update Statement
+     * @param sqlCmd
+     * @param sqlParams
+     */
+    protected void logUpdateStatement(String sqlCmd, Object[] sqlParams)
+    {
+        if (log.isInfoEnabled())
+        {   log.info("Executing DML: " + sqlCmd);
+            if (sqlParams!=null && sqlParams.length>0)
+                log.info("Parameters: " + StringUtils.arrayToString(sqlParams, "|"));
+        }
+    }
+
+    /**
      * Executes an update, insert or delete SQL-Statement.<BR>
      * We recommend to use a DBCommand object in order to build the sqlCmd.<BR>
      * <P>
@@ -88,8 +116,7 @@
     {
         try 
         {   // Debug
-            if (log.isInfoEnabled())
-                log.info("Executing: " + sqlCmd);
+            logUpdateStatement(sqlCmd, sqlParams);
             // execute SQL
             long start = System.currentTimeMillis();
             int affected = dbms.executeSQL(sqlCmd, sqlParams, context.getConnection(), setGenKeys);
@@ -128,8 +155,7 @@
     {
         try
         {   // Debug
-            if (log.isDebugEnabled())
-                log.debug("Executing: " + sqlCmd);
+            logQueryStatement(sqlCmd, sqlParams);
             // Execute the Statement
             long start = System.currentTimeMillis();
             ResultSet rs = dbms.executeQuery(sqlCmd, sqlParams, scrollable, context.getConnection());
@@ -164,10 +190,9 @@
     public Object querySingleValue(String sqlCmd, Object[] sqlParams, DataType dataType, boolean failOnNoResult)
     {
         // Debug
-        long start = System.currentTimeMillis();
-        if (log.isDebugEnabled())
-            log.debug("Executing: " + sqlCmd);
+        logQueryStatement(sqlCmd, sqlParams);
         // Read value
+        long start = System.currentTimeMillis();
         Object result = dbms.querySingleValue(sqlCmd, sqlParams, dataType, context.getConnection());
         if (result==ObjectUtils.NO_VALUE)
         {   // Query returned no result
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java b/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java
index be53a54..bc829a6 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java
@@ -18,10 +18,17 @@
  */
 package org.apache.empire.dbms.hsql;
 
+import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.empire.data.DataType;
+import org.apache.empire.db.DBColumn;
+import org.apache.empire.db.DBColumnExpr;
 import org.apache.empire.db.DBCommand;
 import org.apache.empire.db.DBRowSet;
+import org.apache.empire.db.exceptions.NoPrimaryKeyException;
+import org.apache.empire.db.expr.column.DBAliasExpr;
+import org.apache.empire.db.expr.column.DBValueExpr;
 import org.apache.empire.db.expr.join.DBColumnJoinExpr;
 import org.apache.empire.db.expr.join.DBJoinExpr;
 import org.apache.empire.db.expr.set.DBSetExpr;
@@ -88,27 +95,65 @@
     @Override
     protected void addUpdateWithJoins(StringBuilder buf, DBRowSet table)
     {
+        // The update table
+        DBColumn[] keyColumns = table.getKeyColumns();
+        if (keyColumns==null || keyColumns.length==0)
+            throw new NoPrimaryKeyException(table);
         // Generate Merge expression
         buf.setLength(0);
         buf.append("MERGE INTO ");
         table.addSQL(buf, CTX_FULLNAME|CTX_ALIAS);
-        // join (only one allowed yet)
-        DBColumnJoinExpr updateJoin = null;
-        for (DBJoinExpr jex : joins)
-        {   // The join
-            if (!(jex instanceof DBColumnJoinExpr))
-                continue;
-            if (jex.isJoinOn(table)==false)
-                continue;
-            // found the join
-            updateJoin = (DBColumnJoinExpr)jex;
-            break;
+        // Using
+        buf.append("\r\nUSING (");
+        // Add set expressions
+        List<DBColumnExpr> using = new ArrayList<DBColumnExpr>();
+        // Add key columns
+        for (DBColumn col : keyColumns)
+            using.add(col);
+        // Select Set-Expressions
+        List<DBSetExpr> mergeSet = new ArrayList<DBSetExpr>(set.size());   
+        for (DBSetExpr sex : set)
+        {   // Select set expressions
+            Object val = sex.getValue();
+            if (val instanceof DBColumnExpr)
+            {
+                DBColumnExpr expr = ((DBColumnExpr)val);
+                if (!(expr instanceof DBColumn) && !(expr instanceof DBAliasExpr))
+                {   // rename column
+                    String name = "COL_"+String.valueOf(mergeSet.size());
+                    expr = expr.as(name);
+                }
+                // select
+                using.add(expr);
+                // Name
+                DBValueExpr NAME_EXPR = getDatabase().getValueExpr("q0."+expr.getName(), DataType.UNKNOWN);
+                mergeSet.add(sex.getColumn().to(NAME_EXPR));
+            }
+            else
+            {   // add original
+                mergeSet.add(sex);
+            }
         }
-        if (updateJoin==null)
-            throw new ObjectNotValidException(this);
-        // using
-        DBMergeCommand merge = createMergeCommand();
-        List<DBSetExpr> mergeSet = merge.addUsing(buf, table, updateJoin);
+        // Add select
+        buf.append("SELECT ");
+        addListExpr(buf, using, CTX_ALL, ", ");
+        // From clause
+        addFrom(buf);
+        // Add Where
+        addWhere(buf);
+        // Add Grouping
+        addGrouping(buf);
+        // on
+        buf.append(") q0\r\nON (");
+        for (DBColumn col : keyColumns)
+        {   // compare 
+            buf.append(" q0.");
+            col.addSQL(buf, CTX_NAME);
+            buf.append("=");
+            buf.append(table.getAlias());
+            buf.append(".");
+            col.addSQL(buf, CTX_NAME);
+        }
         // Set Expressions
         buf.append(")\r\nWHEN MATCHED THEN UPDATE ");
         buf.append("\r\nSET ");
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java b/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java
index 3791a1b..76885fd 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java
@@ -18,15 +18,20 @@
  */
 package org.apache.empire.dbms.oracle;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.empire.commons.StringUtils;
+import org.apache.empire.data.DataType;
+import org.apache.empire.db.DBColumn;
+import org.apache.empire.db.DBColumnExpr;
 import org.apache.empire.db.DBCommand;
 import org.apache.empire.db.DBIndex;
 import org.apache.empire.db.DBRowSet;
+import org.apache.empire.db.exceptions.NoPrimaryKeyException;
+import org.apache.empire.db.expr.column.DBAliasExpr;
+import org.apache.empire.db.expr.column.DBValueExpr;
 import org.apache.empire.db.expr.compare.DBCompareExpr;
-import org.apache.empire.db.expr.join.DBColumnJoinExpr;
-import org.apache.empire.db.expr.join.DBJoinExpr;
 import org.apache.empire.db.expr.set.DBSetExpr;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.ObjectNotValidException;
@@ -259,27 +264,65 @@
     @Override
     protected void addUpdateWithJoins(StringBuilder buf, DBRowSet table)
     {
+        // The update table
+        DBColumn[] keyColumns = table.getKeyColumns();
+        if (keyColumns==null || keyColumns.length==0)
+            throw new NoPrimaryKeyException(table);
         // Generate Merge expression
         buf.setLength(0);
         buf.append("MERGE INTO ");
         table.addSQL(buf, CTX_FULLNAME|CTX_ALIAS);
-        // join (only one allowed yet)
-        DBColumnJoinExpr updateJoin = null;
-        for (DBJoinExpr jex : joins)
-        {   // The join
-            if (!(jex instanceof DBColumnJoinExpr))
-                continue;
-            if (jex.isJoinOn(table)==false)
-                continue;
-            // found the join
-            updateJoin = (DBColumnJoinExpr)jex;
-            break;
+        // Using
+        buf.append("\r\nUSING (");
+        // Add set expressions
+        List<DBColumnExpr> using = new ArrayList<DBColumnExpr>();
+        // Add key columns
+        for (DBColumn col : keyColumns)
+            using.add(col);
+        // Select Set-Expressions
+        List<DBSetExpr> mergeSet = new ArrayList<DBSetExpr>(set.size());   
+        for (DBSetExpr sex : set)
+        {   // Select set expressions
+            Object val = sex.getValue();
+            if (val instanceof DBColumnExpr)
+            {
+                DBColumnExpr expr = ((DBColumnExpr)val);
+                if (!(expr instanceof DBColumn) && !(expr instanceof DBAliasExpr))
+                {   // rename column
+                    String name = "COL_"+String.valueOf(mergeSet.size());
+                    expr = expr.as(name);
+                }
+                // select
+                using.add(expr);
+                // Name
+                DBValueExpr NAME_EXPR = getDatabase().getValueExpr("q0."+expr.getName(), DataType.UNKNOWN);
+                mergeSet.add(sex.getColumn().to(NAME_EXPR));
+            }
+            else
+            {   // add original
+                mergeSet.add(sex);
+            }
         }
-        if (updateJoin==null)
-            throw new ObjectNotValidException(this);
-        // using
-        DBMergeCommand merge = createMergeCommand();
-        List<DBSetExpr> mergeSet = merge.addUsing(buf, table, updateJoin);
+        // Add select
+        buf.append("SELECT ");
+        addListExpr(buf, using, CTX_ALL, ", ");
+        // From clause
+        addFrom(buf);
+        // Add Where
+        addWhere(buf);
+        // Add Grouping
+        addGrouping(buf);
+        // on
+        buf.append(") q0\r\nON (");
+        for (DBColumn col : keyColumns)
+        {   // compare 
+            buf.append(" q0.");
+            col.addSQL(buf, CTX_NAME);
+            buf.append("=");
+            buf.append(table.getAlias());
+            buf.append(".");
+            col.addSQL(buf, CTX_NAME);
+        }
         // Set Expressions
         buf.append(")\r\nWHEN MATCHED THEN UPDATE ");
         buf.append("\r\nSET ");
diff --git a/empire-db/src/main/java/org/apache/empire/xml/XMLWriter.java b/empire-db/src/main/java/org/apache/empire/xml/XMLWriter.java
index 3a2219e..21c8f31 100644
--- a/empire-db/src/main/java/org/apache/empire/xml/XMLWriter.java
+++ b/empire-db/src/main/java/org/apache/empire/xml/XMLWriter.java
@@ -163,7 +163,8 @@
     public XMLWriter(Writer writer, String charsetEncoding)
     { 
         this.out = new PrintWriter(writer);
-        this.charsetEncoding = charsetEncoding; 
+        if (charsetEncoding!=null)
+            this.charsetEncoding = charsetEncoding; 
         this.canonical = false;
     }