http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-server/src/main/java/org/apache/cayenne/dba/JdbcPkGenerator.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/JdbcPkGenerator.java 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/JdbcPkGenerator.java
index 1866944..6474d2d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/JdbcPkGenerator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/JdbcPkGenerator.java
@@ -19,19 +19,6 @@
 
 package org.apache.cayenne.dba;
 
-import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.ResultIterator;
-import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.access.OperationObserver;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbKeyGenerator;
-import org.apache.cayenne.query.Query;
-import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.util.IDUtil;
-
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.ResultSet;
@@ -45,385 +32,355 @@ import java.util.Queue;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.DataRow;
+import org.apache.cayenne.ObjectId;
+import org.apache.cayenne.ResultIterator;
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.access.OperationObserver;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbKeyGenerator;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.query.SQLTemplate;
+import org.apache.cayenne.util.IDUtil;
+
 /**
  * Default primary key generator implementation. Uses a lookup table named
  * "AUTO_PK_SUPPORT" to search and increment primary keys for tables.
  */
 public class JdbcPkGenerator implements PkGenerator {
 
-    public static final int DEFAULT_PK_CACHE_SIZE = 20;
-    static final long DEFAULT_PK_START_VALUE = 200;
-
-    protected JdbcAdapter adapter;
-    protected ConcurrentHashMap<String, Queue<Long>> pkCache = new 
ConcurrentHashMap<String, Queue<Long>>();
-    protected int pkCacheSize = DEFAULT_PK_CACHE_SIZE;
-    protected long pkStartValue = DEFAULT_PK_START_VALUE;
-
-    public JdbcPkGenerator(JdbcAdapter adapter) {
-        this.adapter = adapter;
-    }
-
-    public JdbcAdapter getAdapter() {
-        return adapter;
-    }
-
-    public void createAutoPk(DataNode node, List<DbEntity> dbEntities) throws 
Exception {
-        // check if a table exists
-
-        // create AUTO_PK_SUPPORT table
-        if (!autoPkTableExists(node)) {
-            runUpdate(node, pkTableCreateString());
-        }
-
-        // delete any existing pk entries
-        if (!dbEntities.isEmpty()) {
-            runUpdate(node, pkDeleteString(dbEntities));
-        }
-
-        // insert all needed entries
-        for (DbEntity ent : dbEntities) {
-            runUpdate(node, pkCreateString(ent.getName()));
-        }
-    }
-
-    public List<String> createAutoPkStatements(List<DbEntity> dbEntities) {
-        List<String> list = new ArrayList<String>(dbEntities.size() + 2);
-
-        list.add(pkTableCreateString());
-        list.add(pkDeleteString(dbEntities));
-
-        for (DbEntity ent : dbEntities) {
-            list.add(pkCreateString(ent.getName()));
-        }
-
-        return list;
-    }
-
-    /**
-     * Drops table named "AUTO_PK_SUPPORT" if it exists in the database.
-     */
-    public void dropAutoPk(DataNode node, List<DbEntity> dbEntities) throws 
Exception {
-        if (autoPkTableExists(node)) {
-            runUpdate(node, dropAutoPkString());
-        }
-    }
-
-    public List<String> dropAutoPkStatements(List<DbEntity> dbEntities) {
-        List<String> list = new ArrayList<String>(1);
-        list.add(dropAutoPkString());
-        return list;
-    }
-
-    protected String pkTableCreateString() {
-        StringBuilder buf = new StringBuilder();
-        buf
-                .append("CREATE TABLE AUTO_PK_SUPPORT (")
-                .append("  TABLE_NAME CHAR(100) NOT NULL,")
-                .append("  NEXT_ID BIGINT NOT NULL,")
-                .append("  PRIMARY KEY(TABLE_NAME)")
-                .append(")");
-
-        return buf.toString();
-    }
-
-    protected String pkDeleteString(List<DbEntity> dbEntities) {
-        StringBuilder buf = new StringBuilder();
-        buf.append("DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN (");
-        int len = dbEntities.size();
-        for (int i = 0; i < len; i++) {
-            if (i > 0) {
-                buf.append(", ");
-            }
-            DbEntity ent = dbEntities.get(i);
-            buf.append('\'').append(ent.getName()).append('\'');
-        }
-        buf.append(')');
-        return buf.toString();
-    }
-
-    protected String pkCreateString(String entName) {
-        StringBuilder buf = new StringBuilder();
-        buf
-                .append("INSERT INTO AUTO_PK_SUPPORT")
-                .append(" (TABLE_NAME, NEXT_ID)")
-                .append(" VALUES ('")
-                .append(entName)
-                .append("', ").append(pkStartValue).append(")");
-        return buf.toString();
-    }
-
-    protected String pkSelectString(String entName) {
-        StringBuilder buf = new StringBuilder();
-        buf
-                .append("SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE TABLE_NAME 
= '")
-                .append(entName)
-                .append('\'');
-        return buf.toString();
-    }
-
-    protected String pkUpdateString(String entName) {
-        StringBuilder buf = new StringBuilder();
-        buf
-                .append("UPDATE AUTO_PK_SUPPORT")
-                .append(" SET NEXT_ID = NEXT_ID + ")
-                .append(pkCacheSize)
-                .append(" WHERE TABLE_NAME = '")
-                .append(entName)
-                .append('\'');
-        return buf.toString();
-    }
-
-    protected String dropAutoPkString() {
-        return "DROP TABLE AUTO_PK_SUPPORT";
-    }
-
-    /**
-     * Checks if AUTO_PK_TABLE already exists in the database.
-     */
-    protected boolean autoPkTableExists(DataNode node) throws SQLException {
-        Connection con = node.getDataSource().getConnection();
-        boolean exists = false;
-        try {
-            DatabaseMetaData md = con.getMetaData();
-            ResultSet tables = md.getTables(null, null, "AUTO_PK_SUPPORT", 
null);
-            try {
-                exists = tables.next();
-            }
-            finally {
-                tables.close();
-            }
-        }
-        finally {
-            // return connection to the pool
-            con.close();
-        }
-
-        return exists;
-    }
-
-    /**
-     * Runs JDBC update over a Connection obtained from DataNode. Returns a 
number of
-     * objects returned from update.
-     * 
-     * @throws SQLException in case of query failure.
-     */
-    public int runUpdate(DataNode node, String sql) throws SQLException {
-        adapter.getJdbcEventLogger().logQuery(sql, Collections.EMPTY_LIST);
-
-        Connection con = node.getDataSource().getConnection();
-        try {
-            Statement upd = con.createStatement();
-            try {
-                return upd.executeUpdate(sql);
-            }
-            finally {
-                upd.close();
-            }
-        }
-        finally {
-            con.close();
-        }
-    }
-
-    /**
-     * Generates a unique and non-repeating primary key for specified dbEntity.
-     * <p>
-     * This implementation is naive since it does not lock the database rows 
when
-     * executing select and subsequent update. Adapter-specific 
implementations are more
-     * robust.
-     * </p>
-     * 
-     * @since 3.0
-     */
-    public Object generatePk(DataNode node, DbAttribute pk) throws Exception {
-
-        DbEntity entity = (DbEntity) pk.getEntity();
-
-        switch (pk.getType()) {
-            case Types.BINARY:
-            case Types.VARBINARY:
-                return 
IDUtil.pseudoUniqueSecureByteSequence(pk.getMaxLength());
-        }
-
-        DbKeyGenerator pkGenerator = entity.getPrimaryKeyGenerator();
-        long cacheSize;
-        if (pkGenerator != null && pkGenerator.getKeyCacheSize() != null)
-            cacheSize = pkGenerator.getKeyCacheSize().intValue();
-        else
-            cacheSize = pkCacheSize;
-
-        Long value;
-
-        // if no caching, always generate fresh
-        if (cacheSize <= 1) {
-            value = longPkFromDatabase(node, entity);
-        }
-        else {
-            Queue<Long> pks = pkCache.get(entity.getName());
-
-            if (pks == null) {
-                // created exhausted LongPkRange
-                pks = new ConcurrentLinkedQueue<Long>();
-                Queue<Long> previousPks = 
pkCache.putIfAbsent(entity.getName(), pks);
-                if (previousPks != null) {
-                       pks = previousPks;
-                }
-            }
-
-            value = pks.poll();
-            if (value == null) {
-               value = longPkFromDatabase(node, entity);
-               for (long i = value+1; i < value + cacheSize; i++) {
-                       pks.add(i);
-               }
-            }
-        }
-
-        if (pk.getType() == Types.BIGINT) {
-            return value;
-        }
-        else {
-            // leaving it up to the user to ensure that PK does not exceed max 
int...
-            return value.intValue();
-        }
-    }
+       public static final int DEFAULT_PK_CACHE_SIZE = 20;
+       static final long DEFAULT_PK_START_VALUE = 200;
+
+       protected JdbcAdapter adapter;
+       protected ConcurrentHashMap<String, Queue<Long>> pkCache = new 
ConcurrentHashMap<String, Queue<Long>>();
+       protected int pkCacheSize = DEFAULT_PK_CACHE_SIZE;
+       protected long pkStartValue = DEFAULT_PK_START_VALUE;
+
+       public JdbcPkGenerator(JdbcAdapter adapter) {
+               this.adapter = adapter;
+       }
+
+       public JdbcAdapter getAdapter() {
+               return adapter;
+       }
+
+       public void createAutoPk(DataNode node, List<DbEntity> dbEntities) 
throws Exception {
+               // check if a table exists
+
+               // create AUTO_PK_SUPPORT table
+               if (!autoPkTableExists(node)) {
+                       runUpdate(node, pkTableCreateString());
+               }
+
+               // delete any existing pk entries
+               if (!dbEntities.isEmpty()) {
+                       runUpdate(node, pkDeleteString(dbEntities));
+               }
+
+               // insert all needed entries
+               for (DbEntity ent : dbEntities) {
+                       runUpdate(node, pkCreateString(ent.getName()));
+               }
+       }
+
+       public List<String> createAutoPkStatements(List<DbEntity> dbEntities) {
+               List<String> list = new ArrayList<String>(dbEntities.size() + 
2);
+
+               list.add(pkTableCreateString());
+               list.add(pkDeleteString(dbEntities));
+
+               for (DbEntity ent : dbEntities) {
+                       list.add(pkCreateString(ent.getName()));
+               }
+
+               return list;
+       }
+
+       /**
+        * Drops table named "AUTO_PK_SUPPORT" if it exists in the database.
+        */
+       public void dropAutoPk(DataNode node, List<DbEntity> dbEntities) throws 
Exception {
+               if (autoPkTableExists(node)) {
+                       runUpdate(node, dropAutoPkString());
+               }
+       }
+
+       public List<String> dropAutoPkStatements(List<DbEntity> dbEntities) {
+               List<String> list = new ArrayList<String>(1);
+               list.add(dropAutoPkString());
+               return list;
+       }
+
+       protected String pkTableCreateString() {
+               StringBuilder buf = new StringBuilder();
+               buf.append("CREATE TABLE AUTO_PK_SUPPORT (").append("  
TABLE_NAME CHAR(100) NOT NULL,")
+                               .append("  NEXT_ID BIGINT NOT NULL,").append("  
PRIMARY KEY(TABLE_NAME)").append(")");
+
+               return buf.toString();
+       }
+
+       protected String pkDeleteString(List<DbEntity> dbEntities) {
+               StringBuilder buf = new StringBuilder();
+               buf.append("DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN (");
+               int len = dbEntities.size();
+               for (int i = 0; i < len; i++) {
+                       if (i > 0) {
+                               buf.append(", ");
+                       }
+                       DbEntity ent = dbEntities.get(i);
+                       buf.append('\'').append(ent.getName()).append('\'');
+               }
+               buf.append(')');
+               return buf.toString();
+       }
+
+       protected String pkCreateString(String entName) {
+               StringBuilder buf = new StringBuilder();
+               buf.append("INSERT INTO AUTO_PK_SUPPORT").append(" (TABLE_NAME, 
NEXT_ID)").append(" VALUES ('").append(entName)
+                               .append("', ").append(pkStartValue).append(")");
+               return buf.toString();
+       }
+
+       protected String pkSelectString(String entName) {
+               StringBuilder buf = new StringBuilder();
+               buf.append("SELECT NEXT_ID FROM AUTO_PK_SUPPORT WHERE 
TABLE_NAME = '").append(entName).append('\'');
+               return buf.toString();
+       }
+
+       protected String pkUpdateString(String entName) {
+               StringBuilder buf = new StringBuilder();
+               buf.append("UPDATE AUTO_PK_SUPPORT").append(" SET NEXT_ID = 
NEXT_ID + ").append(pkCacheSize)
+                               .append(" WHERE TABLE_NAME = 
'").append(entName).append('\'');
+               return buf.toString();
+       }
+
+       protected String dropAutoPkString() {
+               return "DROP TABLE AUTO_PK_SUPPORT";
+       }
+
+       /**
+        * Checks if AUTO_PK_TABLE already exists in the database.
+        */
+       protected boolean autoPkTableExists(DataNode node) throws SQLException {
+
+               try (Connection con = node.getDataSource().getConnection();) {
+                       DatabaseMetaData md = con.getMetaData();
+
+                       try (ResultSet tables = md.getTables(null, null, 
"AUTO_PK_SUPPORT", null);) {
+                               return tables.next();
+                       }
+               }
+       }
+
+       /**
+        * Runs JDBC update over a Connection obtained from DataNode. Returns a
+        * number of objects returned from update.
+        * 
+        * @throws SQLException
+        *             in case of query failure.
+        */
+       public int runUpdate(DataNode node, String sql) throws SQLException {
+               adapter.getJdbcEventLogger().logQuery(sql, 
Collections.EMPTY_LIST);
+
+               try (Connection con = node.getDataSource().getConnection();) {
+                       try (Statement upd = con.createStatement();) {
+                               return upd.executeUpdate(sql);
+                       }
+               }
+       }
+
+       /**
+        * Generates a unique and non-repeating primary key for specified 
dbEntity.
+        * <p>
+        * This implementation is naive since it does not lock the database rows
+        * when executing select and subsequent update. Adapter-specific
+        * implementations are more robust.
+        * </p>
+        * 
+        * @since 3.0
+        */
+       public Object generatePk(DataNode node, DbAttribute pk) throws 
Exception {
+
+               DbEntity entity = (DbEntity) pk.getEntity();
+
+               switch (pk.getType()) {
+               case Types.BINARY:
+               case Types.VARBINARY:
+                       return 
IDUtil.pseudoUniqueSecureByteSequence(pk.getMaxLength());
+               }
+
+               DbKeyGenerator pkGenerator = entity.getPrimaryKeyGenerator();
+               long cacheSize;
+               if (pkGenerator != null && pkGenerator.getKeyCacheSize() != 
null)
+                       cacheSize = pkGenerator.getKeyCacheSize().intValue();
+               else
+                       cacheSize = pkCacheSize;
+
+               Long value;
+
+               // if no caching, always generate fresh
+               if (cacheSize <= 1) {
+                       value = longPkFromDatabase(node, entity);
+               } else {
+                       Queue<Long> pks = pkCache.get(entity.getName());
+
+                       if (pks == null) {
+                               // created exhausted LongPkRange
+                               pks = new ConcurrentLinkedQueue<Long>();
+                               Queue<Long> previousPks = 
pkCache.putIfAbsent(entity.getName(), pks);
+                               if (previousPks != null) {
+                                       pks = previousPks;
+                               }
+                       }
+
+                       value = pks.poll();
+                       if (value == null) {
+                               value = longPkFromDatabase(node, entity);
+                               for (long i = value + 1; i < value + cacheSize; 
i++) {
+                                       pks.add(i);
+                               }
+                       }
+               }
+
+               if (pk.getType() == Types.BIGINT) {
+                       return value;
+               } else {
+                       // leaving it up to the user to ensure that PK does not 
exceed max
+                       // int...
+                       return value.intValue();
+               }
+       }
+
+       /**
+        * Performs primary key generation ignoring cache. Generates a range of
+        * primary keys as specified by "pkCacheSize" bean property.
+        * <p>
+        * This method is called internally from "generatePkForDbEntity" and 
then
+        * generated range of key values is saved in cache for performance.
+        * Subclasses that implement different primary key generation solutions
+        * should override this method, not "generatePkForDbEntity".
+        * </p>
+        * 
+        * @since 3.0
+        */
+       protected long longPkFromDatabase(DataNode node, DbEntity entity) 
throws Exception {
+               String select = "SELECT #result('NEXT_ID' 'long' 'NEXT_ID') " + 
"FROM AUTO_PK_SUPPORT "
+                               + "WHERE TABLE_NAME = '" + entity.getName() + 
'\'';
+
+               // run queries via DataNode to utilize its transactional 
behavior
+               List<Query> queries = new ArrayList<Query>(2);
+               queries.add(new SQLTemplate(entity, select));
+               queries.add(new SQLTemplate(entity, 
pkUpdateString(entity.getName())));
+
+               PkRetrieveProcessor observer = new 
PkRetrieveProcessor(entity.getName());
+               node.performQueries(queries, observer);
+               return observer.getId();
+       }
+
+       /**
+        * Returns a size of the entity primary key cache. Default value is 20. 
If
+        * cache size is set to a value less or equals than "one", no primary 
key
+        * caching is done.
+        */
+       public int getPkCacheSize() {
+               return pkCacheSize;
+       }
+
+       /**
+        * Sets the size of the entity primary key cache. If
+        * <code>pkCacheSize</code> parameter is less than 1, cache size is set 
to
+        * "one".
+        * <p>
+        * <i>Note that our tests show that setting primary key cache value to
+        * anything much bigger than 20 does not give any significant 
performance
+        * increase. Therefore it does not make sense to use bigger values, 
since
+        * this may potentially create big gaps in the database primary key
+        * sequences in cases like application crashes or restarts. </i>
+        * </p>
+        */
+       public void setPkCacheSize(int pkCacheSize) {
+               this.pkCacheSize = (pkCacheSize < 1) ? 1 : pkCacheSize;
+       }
+
+       long getPkStartValue() {
+               return pkStartValue;
+       }
+
+       void setPkStartValue(long startValue) {
+               this.pkStartValue = startValue;
+       }
+
+       public void reset() {
+               pkCache.clear();
+       }
 
        /**
-     * Performs primary key generation ignoring cache. Generates a range of 
primary keys
-     * as specified by "pkCacheSize" bean property.
-     * <p>
-     * This method is called internally from "generatePkForDbEntity" and then 
generated
-     * range of key values is saved in cache for performance. Subclasses that 
implement
-     * different primary key generation solutions should override this method, 
not
-     * "generatePkForDbEntity".
-     * </p>
-     * 
-     * @since 3.0
-     */
-    protected long longPkFromDatabase(DataNode node, DbEntity entity) throws 
Exception {
-        String select = "SELECT #result('NEXT_ID' 'long' 'NEXT_ID') "
-                + "FROM AUTO_PK_SUPPORT "
-                + "WHERE TABLE_NAME = '"
-                + entity.getName()
-                + '\'';
-
-        // run queries via DataNode to utilize its transactional behavior
-        List<Query> queries = new ArrayList<Query>(2);
-        queries.add(new SQLTemplate(entity, select));
-        queries.add(new SQLTemplate(entity, pkUpdateString(entity.getName())));
-
-        PkRetrieveProcessor observer = new 
PkRetrieveProcessor(entity.getName());
-        node.performQueries(queries, observer);
-        return observer.getId();
-    }
-
-    /**
-     * Returns a size of the entity primary key cache. Default value is 20. If 
cache size
-     * is set to a value less or equals than "one", no primary key caching is 
done.
-     */
-    public int getPkCacheSize() {
-        return pkCacheSize;
-    }
-
-    /**
-     * Sets the size of the entity primary key cache. If 
<code>pkCacheSize</code>
-     * parameter is less than 1, cache size is set to "one".
-     * <p>
-     * <i>Note that our tests show that setting primary key cache value to 
anything much
-     * bigger than 20 does not give any significant performance increase. 
Therefore it
-     * does not make sense to use bigger values, since this may potentially 
create big
-     * gaps in the database primary key sequences in cases like application 
crashes or
-     * restarts. </i>
-     * </p>
-     */
-    public void setPkCacheSize(int pkCacheSize) {
-        this.pkCacheSize = (pkCacheSize < 1) ? 1 : pkCacheSize;
-    }
-    
-    long getPkStartValue() {
-        return pkStartValue;
-    }
-    
-    void setPkStartValue(long startValue) {
-        this.pkStartValue = startValue;
-    }
-
-    public void reset() {
-        pkCache.clear();
-    }
-
-    /**
-     * OperationObserver for primary key retrieval.
-     */
-    final class PkRetrieveProcessor implements OperationObserver {
-
-        Number id;
-        String entityName;
-
-        PkRetrieveProcessor(String entityName) {
-            this.entityName = entityName;
-        }
-
-        public boolean isIteratedResult() {
-            return false;
-        }
-
-        public long getId() {
-            if (id == null) {
-                throw new CayenneRuntimeException("No key was retrieved for 
entity "
-                        + entityName);
-            }
-
-            return id.longValue();
-        }
-
-        public void nextRows(Query query, List<?> dataRows) {
-
-            // process selected object, issue an update query
-            if (dataRows == null || dataRows.size() == 0) {
-                throw new CayenneRuntimeException(
-                        "Error generating PK : entity not supported: " + 
entityName);
-            }
-
-            if (dataRows.size() > 1) {
-                throw new CayenneRuntimeException(
-                        "Error generating PK : too many rows for entity: " + 
entityName);
-            }
-
-            DataRow lastPk = (DataRow) dataRows.get(0);
-            id = (Number) lastPk.get("NEXT_ID");
-        }
-
-        public void nextCount(Query query, int resultCount) {
-            if (resultCount != 1) {
-                throw new CayenneRuntimeException("Error generating PK for 
entity '"
-                        + entityName
-                        + "': update count is wrong - "
-                        + resultCount);
-            }
-        }
-
-        public void nextBatchCount(Query query, int[] resultCount) {
-        }
-     
-        @Override
-        public void nextGeneratedRows(Query query, ResultIterator keys, 
ObjectId idToUpdate) {
-        }
-
-        public void nextRows(Query q, ResultIterator it) {
-        }
-
-        public void nextQueryException(Query query, Exception ex) {
-
-            throw new CayenneRuntimeException("Error generating PK for entity 
'"
-                    + entityName
-                    + "'.", ex);
-        }
-
-        public void nextGlobalException(Exception ex) {
-
-            throw new CayenneRuntimeException("Error generating PK for entity: 
"
-                    + entityName, ex);
-        }
-    }
+        * OperationObserver for primary key retrieval.
+        */
+       final class PkRetrieveProcessor implements OperationObserver {
+
+               Number id;
+               String entityName;
+
+               PkRetrieveProcessor(String entityName) {
+                       this.entityName = entityName;
+               }
+
+               public boolean isIteratedResult() {
+                       return false;
+               }
+
+               public long getId() {
+                       if (id == null) {
+                               throw new CayenneRuntimeException("No key was 
retrieved for entity " + entityName);
+                       }
+
+                       return id.longValue();
+               }
+
+               public void nextRows(Query query, List<?> dataRows) {
+
+                       // process selected object, issue an update query
+                       if (dataRows == null || dataRows.size() == 0) {
+                               throw new CayenneRuntimeException("Error 
generating PK : entity not supported: " + entityName);
+                       }
+
+                       if (dataRows.size() > 1) {
+                               throw new CayenneRuntimeException("Error 
generating PK : too many rows for entity: " + entityName);
+                       }
+
+                       DataRow lastPk = (DataRow) dataRows.get(0);
+                       id = (Number) lastPk.get("NEXT_ID");
+               }
+
+               public void nextCount(Query query, int resultCount) {
+                       if (resultCount != 1) {
+                               throw new CayenneRuntimeException("Error 
generating PK for entity '" + entityName
+                                               + "': update count is wrong - " 
+ resultCount);
+                       }
+               }
+
+               public void nextBatchCount(Query query, int[] resultCount) {
+               }
+
+               @Override
+               public void nextGeneratedRows(Query query, ResultIterator keys, 
ObjectId idToUpdate) {
+               }
+
+               public void nextRows(Query q, ResultIterator it) {
+               }
+
+               public void nextQueryException(Query query, Exception ex) {
+
+                       throw new CayenneRuntimeException("Error generating PK 
for entity '" + entityName + "'.", ex);
+               }
+
+               public void nextGlobalException(Exception ex) {
+
+                       throw new CayenneRuntimeException("Error generating PK 
for entity: " + entityName, ex);
+               }
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-server/src/main/java/org/apache/cayenne/dba/TypesHandler.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/TypesHandler.java 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/TypesHandler.java
index 1e1f3ea..100ca5c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/TypesHandler.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/TypesHandler.java
@@ -36,124 +36,98 @@ import org.xml.sax.SAXException;
 import org.xml.sax.XMLReader;
 import org.xml.sax.helpers.DefaultHandler;
 
-/** 
- * TypesHandler provides JDBC-RDBMS types mapping. Loads types info from 
- * an XML file.
+/**
+ * TypesHandler provides JDBC-RDBMS types mapping. Loads types info from an XML
+ * file.
  * 
  */
 public class TypesHandler {
 
-    private static Map<URL, TypesHandler> handlerMap = new HashMap<URL, 
TypesHandler>();
-
-    protected Map<Integer, String[]> typesMap;
-
-    /**
-     * @since 1.1
-     */
-    public static TypesHandler getHandler(URL typesConfig) {
-        synchronized (handlerMap) {
-            TypesHandler handler = handlerMap.get(typesConfig);
-
-            if (handler == null) {
-                handler = new TypesHandler(typesConfig);
-                handlerMap.put(typesConfig, handler);
-            }
-
-            return handler;
-        }
-    }
-
-    /**
-     * Creates new TypesHandler loading configuration info from the XML
-     * file specified as <code>typesConfigPath</code> parameter.
-     * 
-     * @since 1.1
-     */
-    public TypesHandler(URL typesConfig) {
-        try {
-            InputStream in = typesConfig.openStream();
-
-            try {
-                XMLReader parser = Util.createXmlReader();
-                TypesParseHandler ph = new TypesParseHandler();
-                parser.setContentHandler(ph);
-                parser.setErrorHandler(ph);
-                parser.parse(new InputSource(in));
-
-                typesMap = ph.getTypes();
-            }
-            catch (Exception ex) {
-                throw new CayenneRuntimeException(
-                    "Error creating TypesHandler '" + typesConfig + "'.",
-                    ex);
-            }
-            finally {
-                try {
-                    in.close();
-                }
-                catch (IOException ioex) {
-                }
-            }
-        }
-        catch (IOException ioex) {
-            throw new CayenneRuntimeException(
-                "Error opening config file '" + typesConfig + "'.",
-                ioex);
-        }
-    }
-
-    public String[] externalTypesForJdbcType(int type) {
-        return typesMap.get(type);
-    }
-
-    /** 
-     * Helper class to load types data from XML.
-     */
-    final class TypesParseHandler extends DefaultHandler {
-        private static final String JDBC_TYPE_TAG = "jdbc-type";
-        private static final String DB_TYPE_TAG = "db-type";
-        private static final String NAME_ATTR = "name";
-
-        private Map<Integer, String[]> types = new HashMap<Integer, 
String[]>();
-        private List<String> currentTypes = new ArrayList<String>();
-        private int currentType = TypesMapping.NOT_DEFINED;
-
-        public Map<Integer, String[]> getTypes() {
-            return types;
-        }
-
-        @Override
-        public void startElement(
-            String namespaceURI,
-            String localName,
-            String qName,
-            Attributes atts)
-            throws SAXException {
-            if (JDBC_TYPE_TAG.equals(localName)) {
-                currentTypes.clear();
-                String strType = atts.getValue("", NAME_ATTR);
-
-                // convert to Types int value
-                try {
-                    currentType = 
Types.class.getDeclaredField(strType).getInt(null);
-                }
-                catch (Exception ex) {
-                    currentType = TypesMapping.NOT_DEFINED;
-                }
-            }
-            else if (DB_TYPE_TAG.equals(localName)) {
-                currentTypes.add(atts.getValue("", NAME_ATTR));
-            }
-        }
-
-        @Override
-        public void endElement(String namespaceURI, String localName, String 
qName)
-            throws SAXException {
-            if (JDBC_TYPE_TAG.equals(localName)
-                && currentType != TypesMapping.NOT_DEFINED) {
-                String[] typesAsArray = new String[currentTypes.size()];
-                types.put(Integer.valueOf(currentType), 
currentTypes.toArray(typesAsArray));
-            }
-        }
-    }
+       private static Map<URL, TypesHandler> handlerMap = new HashMap<URL, 
TypesHandler>();
+
+       protected Map<Integer, String[]> typesMap;
+
+       /**
+        * @since 1.1
+        */
+       public static TypesHandler getHandler(URL typesConfig) {
+               synchronized (handlerMap) {
+                       TypesHandler handler = handlerMap.get(typesConfig);
+
+                       if (handler == null) {
+                               handler = new TypesHandler(typesConfig);
+                               handlerMap.put(typesConfig, handler);
+                       }
+
+                       return handler;
+               }
+       }
+
+       /**
+        * Creates new TypesHandler loading configuration info from the XML file
+        * specified as <code>typesConfigPath</code> parameter.
+        * 
+        * @since 1.1
+        */
+       public TypesHandler(URL typesConfig) {
+
+               try (InputStream in = typesConfig.openStream();) {
+                       XMLReader parser = Util.createXmlReader();
+                       TypesParseHandler ph = new TypesParseHandler();
+                       parser.setContentHandler(ph);
+                       parser.setErrorHandler(ph);
+                       parser.parse(new InputSource(in));
+
+                       typesMap = ph.getTypes();
+               } catch (Exception ex) {
+                       throw new CayenneRuntimeException("Error creating 
TypesHandler '" + typesConfig + "'.", ex);
+               }
+       }
+
+       public String[] externalTypesForJdbcType(int type) {
+               return typesMap.get(type);
+       }
+
+       /**
+        * Helper class to load types data from XML.
+        */
+       final class TypesParseHandler extends DefaultHandler {
+               private static final String JDBC_TYPE_TAG = "jdbc-type";
+               private static final String DB_TYPE_TAG = "db-type";
+               private static final String NAME_ATTR = "name";
+
+               private Map<Integer, String[]> types = new HashMap<Integer, 
String[]>();
+               private List<String> currentTypes = new ArrayList<String>();
+               private int currentType = TypesMapping.NOT_DEFINED;
+
+               public Map<Integer, String[]> getTypes() {
+                       return types;
+               }
+
+               @Override
+               public void startElement(String namespaceURI, String localName, 
String qName, Attributes atts)
+                               throws SAXException {
+                       if (JDBC_TYPE_TAG.equals(localName)) {
+                               currentTypes.clear();
+                               String strType = atts.getValue("", NAME_ATTR);
+
+                               // convert to Types int value
+                               try {
+                                       currentType = 
Types.class.getDeclaredField(strType).getInt(null);
+                               } catch (Exception ex) {
+                                       currentType = TypesMapping.NOT_DEFINED;
+                               }
+                       } else if (DB_TYPE_TAG.equals(localName)) {
+                               currentTypes.add(atts.getValue("", NAME_ATTR));
+                       }
+               }
+
+               @Override
+               public void endElement(String namespaceURI, String localName, 
String qName) throws SAXException {
+                       if (JDBC_TYPE_TAG.equals(localName) && currentType != 
TypesMapping.NOT_DEFINED) {
+                               String[] typesAsArray = new 
String[currentTypes.size()];
+                               types.put(Integer.valueOf(currentType), 
currentTypes.toArray(typesAsArray));
+                       }
+               }
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-server/src/main/java/org/apache/cayenne/dba/TypesMapping.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/TypesMapping.java 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/TypesMapping.java
index cfc5cda..e0f867e 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/TypesMapping.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/TypesMapping.java
@@ -36,505 +36,490 @@ import java.util.Map;
 import static java.sql.Types.*;
 
 /**
- * A utility class that handles mappings of JDBC data types to the database 
types and Java
- * types. Also contains methods that provide information about JDBC types.
+ * A utility class that handles mappings of JDBC data types to the database
+ * types and Java types. Also contains methods that provide information about
+ * JDBC types.
  */
 public class TypesMapping {
 
-    // Never use "-1" or any other normal integer, since there
-    // is a big chance it is being reserved in java.sql.Types
-    public static final int NOT_DEFINED = Integer.MAX_VALUE;
-
-    // char constants for the sql data types
-    public static final String SQL_ARRAY = "ARRAY";
-    public static final String SQL_BIGINT = "BIGINT";
-    public static final String SQL_BINARY = "BINARY";
-    public static final String SQL_BIT = "BIT";
-    public static final String SQL_BLOB = "BLOB";
-
-    /**
-     * @since 1.2
-     */
-    public static final String SQL_BOOLEAN = "BOOLEAN";
-
-    public static final String SQL_CLOB = "CLOB";
-    public static final String SQL_NCLOB = "NCLOB";
-    public static final String SQL_CHAR = "CHAR";
-    public static final String SQL_NCHAR = "NCHAR";
-    public static final String SQL_DATE = "DATE";
-    public static final String SQL_DECIMAL = "DECIMAL";
-    public static final String SQL_DOUBLE = "DOUBLE";
-    public static final String SQL_FLOAT = "FLOAT";
-    public static final String SQL_INTEGER = "INTEGER";
-    public static final String SQL_LONGVARCHAR = "LONGVARCHAR";
-    public static final String SQL_LONGNVARCHAR = "LONGNVARCHAR";
-    public static final String SQL_LONGVARBINARY = "LONGVARBINARY";
-    public static final String SQL_NUMERIC = "NUMERIC";
-    public static final String SQL_REAL = "REAL";
-    public static final String SQL_SMALLINT = "SMALLINT";
-    public static final String SQL_TINYINT = "TINYINT";
-    public static final String SQL_TIME = "TIME";
-    public static final String SQL_TIMESTAMP = "TIMESTAMP";
-    public static final String SQL_VARBINARY = "VARBINARY";
-    public static final String SQL_VARCHAR = "VARCHAR";
-    public static final String SQL_NVARCHAR = "NVARCHAR";
-    public static final String SQL_SQLXML = "SQLXML";
-    public static final String SQL_OTHER = "OTHER";
-    public static final String SQL_NULL = "NULL";
-
-    // char constants for Java data types
-    public static final String JAVA_LONG = "java.lang.Long";
-    public static final String JAVA_BYTES = "byte[]";
-    public static final String JAVA_BOOLEAN = "java.lang.Boolean";
-    public static final String JAVA_STRING = "java.lang.String";
-    public static final String JAVA_SQLDATE = "java.sql.Date";
-    public static final String JAVA_UTILDATE = "java.util.Date";
-    public static final String JAVA_BIGDECIMAL = "java.math.BigDecimal";
-    public static final String JAVA_DOUBLE = "java.lang.Double";
-    public static final String JAVA_FLOAT = "java.lang.Float";
-    public static final String JAVA_INTEGER = "java.lang.Integer";
-    public static final String JAVA_SHORT = "java.lang.Short";
-    public static final String JAVA_BYTE = "java.lang.Byte";
-    public static final String JAVA_TIME = "java.sql.Time";
-    public static final String JAVA_TIMESTAMP = "java.sql.Timestamp";
-    public static final String JAVA_BLOB = "java.sql.Blob";
-
-    /**
-     * Keys: SQL string type names, Values: SQL int type definitions from 
java.sql.Types
-     */
-    private static final Map<String, Integer> SQL_STRING_TYPE = new 
HashMap<String, Integer>();
-
-    /**
-     * Keys: SQL int type definitions from java.sql.Types, Values: SQL string 
type names
-     */
-    private static final Map<Integer, String> SQL_ENUM_TYPE = new 
HashMap<Integer, String>();
-
-    /**
-     * Keys: SQL int type definitions from java.sql.Types, Values: java class 
names
-     */
-    private static final Map<Integer, String> SQL_ENUM_JAVA = new 
HashMap<Integer, String>();
-
-    /**
-     * Keys: java class names, Values: SQL int type definitions from 
java.sql.Types
-     */
-    private static final Map<String, Integer> JAVA_SQL_ENUM = new 
HashMap<String, Integer>();
-
-    static {
-//        SQL_STRING_TYPE.put(SQL_ARRAY, ARRAY);
-        SQL_STRING_TYPE.put(SQL_BIGINT, BIGINT);
-        SQL_STRING_TYPE.put(SQL_BINARY, BINARY);
-        SQL_STRING_TYPE.put(SQL_BIT, BIT);
-        SQL_STRING_TYPE.put(SQL_BLOB, BLOB);
-        SQL_STRING_TYPE.put(SQL_BOOLEAN, BOOLEAN);
-        SQL_STRING_TYPE.put(SQL_CLOB, CLOB);
-        SQL_STRING_TYPE.put(SQL_NCLOB, NCLOB);
-        SQL_STRING_TYPE.put(SQL_CHAR, CHAR);
-        SQL_STRING_TYPE.put(SQL_NCHAR, NCHAR);
-        SQL_STRING_TYPE.put(SQL_DATE, DATE);
-        SQL_STRING_TYPE.put(SQL_DECIMAL, DECIMAL);
-        SQL_STRING_TYPE.put(SQL_DOUBLE, DOUBLE);
-        SQL_STRING_TYPE.put(SQL_FLOAT, FLOAT);
-        SQL_STRING_TYPE.put(SQL_INTEGER, INTEGER);
-        SQL_STRING_TYPE.put(SQL_LONGVARCHAR, LONGVARCHAR);
-        SQL_STRING_TYPE.put(SQL_LONGNVARCHAR, LONGNVARCHAR);
-        SQL_STRING_TYPE.put(SQL_LONGVARBINARY, LONGVARBINARY);
-        SQL_STRING_TYPE.put(SQL_NUMERIC, NUMERIC);
-        SQL_STRING_TYPE.put(SQL_REAL, REAL);
-        SQL_STRING_TYPE.put(SQL_SMALLINT, SMALLINT);
-        SQL_STRING_TYPE.put(SQL_TINYINT, TINYINT);
-        SQL_STRING_TYPE.put(SQL_TIME, TIME);
-        SQL_STRING_TYPE.put(SQL_TIMESTAMP, TIMESTAMP);
-        SQL_STRING_TYPE.put(SQL_VARBINARY, VARBINARY);
-        SQL_STRING_TYPE.put(SQL_VARCHAR, VARCHAR);
-        SQL_STRING_TYPE.put(SQL_NVARCHAR, NVARCHAR);
-        SQL_STRING_TYPE.put(SQL_OTHER, OTHER);
-        SQL_STRING_TYPE.put(SQL_NULL, NULL);
-
-        SQL_ENUM_TYPE.put(ARRAY, SQL_ARRAY);
-        SQL_ENUM_TYPE.put(BIGINT, SQL_BIGINT);
-        SQL_ENUM_TYPE.put(BINARY, SQL_BINARY);
-        SQL_ENUM_TYPE.put(BIT, SQL_BIT);
-        SQL_ENUM_TYPE.put(BOOLEAN, SQL_BOOLEAN);
-        SQL_ENUM_TYPE.put(BLOB, SQL_BLOB);
-        SQL_ENUM_TYPE.put(CLOB, SQL_CLOB);
-        SQL_ENUM_TYPE.put(NCLOB, SQL_NCLOB);
-        SQL_ENUM_TYPE.put(CHAR, SQL_CHAR);
-        SQL_ENUM_TYPE.put(NCHAR, SQL_NCHAR);
-        SQL_ENUM_TYPE.put(DATE, SQL_DATE);
-        SQL_ENUM_TYPE.put(DECIMAL, SQL_DECIMAL);
-        SQL_ENUM_TYPE.put(DOUBLE, SQL_DOUBLE);
-        SQL_ENUM_TYPE.put(FLOAT, SQL_FLOAT);
-        SQL_ENUM_TYPE.put(INTEGER, SQL_INTEGER);
-        SQL_ENUM_TYPE.put(LONGVARCHAR, SQL_LONGVARCHAR);
-        SQL_ENUM_TYPE.put(LONGNVARCHAR, SQL_LONGNVARCHAR);
-        SQL_ENUM_TYPE.put(LONGVARBINARY, SQL_LONGVARBINARY);
-        SQL_ENUM_TYPE.put(NUMERIC, SQL_NUMERIC);
-        SQL_ENUM_TYPE.put(REAL, SQL_REAL);
-        SQL_ENUM_TYPE.put(SMALLINT, SQL_SMALLINT);
-        SQL_ENUM_TYPE.put(TINYINT, SQL_TINYINT);
-        SQL_ENUM_TYPE.put(TIME, SQL_TIME);
-        SQL_ENUM_TYPE.put(TIMESTAMP, SQL_TIMESTAMP);
-        SQL_ENUM_TYPE.put(VARBINARY, SQL_VARBINARY);
-        SQL_ENUM_TYPE.put(VARCHAR, SQL_VARCHAR);
-        SQL_ENUM_TYPE.put(NVARCHAR, SQL_NVARCHAR);
-        SQL_ENUM_TYPE.put(SQLXML, SQL_SQLXML);
-        SQL_ENUM_TYPE.put(OTHER, SQL_OTHER);
-        SQL_ENUM_TYPE.put(NULL, SQL_NULL);
-
-        SQL_ENUM_JAVA.put(BIGINT, JAVA_LONG);
-        SQL_ENUM_JAVA.put(BINARY, JAVA_BYTES);
-        SQL_ENUM_JAVA.put(BIT, JAVA_BOOLEAN);
-        SQL_ENUM_JAVA.put(BOOLEAN, JAVA_BOOLEAN);
-        SQL_ENUM_JAVA.put(BLOB, JAVA_BYTES);
-        SQL_ENUM_JAVA.put(CLOB, JAVA_STRING);
-        SQL_ENUM_JAVA.put(NCLOB, JAVA_STRING);
-        SQL_ENUM_JAVA.put(CHAR, JAVA_STRING);
-        SQL_ENUM_JAVA.put(NCHAR, JAVA_STRING);
-        SQL_ENUM_JAVA.put(DATE, JAVA_UTILDATE);
-        SQL_ENUM_JAVA.put(DECIMAL, JAVA_BIGDECIMAL);
-        SQL_ENUM_JAVA.put(DOUBLE, JAVA_DOUBLE);
-        SQL_ENUM_JAVA.put(FLOAT, JAVA_FLOAT);
-        SQL_ENUM_JAVA.put(INTEGER, JAVA_INTEGER);
-        SQL_ENUM_JAVA.put(LONGVARCHAR, JAVA_STRING);
-        SQL_ENUM_JAVA.put(LONGNVARCHAR, JAVA_STRING);
-        SQL_ENUM_JAVA.put(LONGVARBINARY, JAVA_BYTES);
-        SQL_ENUM_JAVA.put(NUMERIC, JAVA_BIGDECIMAL);
-        SQL_ENUM_JAVA.put(REAL, JAVA_FLOAT);
-        SQL_ENUM_JAVA.put(SMALLINT, JAVA_SHORT);
-        SQL_ENUM_JAVA.put(TINYINT, JAVA_SHORT);
-        SQL_ENUM_JAVA.put(TIME, JAVA_UTILDATE);
-        SQL_ENUM_JAVA.put(TIMESTAMP, JAVA_UTILDATE);
-        SQL_ENUM_JAVA.put(VARBINARY, JAVA_BYTES);
-        SQL_ENUM_JAVA.put(VARCHAR, JAVA_STRING);
-        SQL_ENUM_JAVA.put(NVARCHAR, JAVA_STRING);
-        SQL_ENUM_JAVA.put(SQLXML, JAVA_STRING);
-
-        JAVA_SQL_ENUM.put(JAVA_LONG, BIGINT);
-        JAVA_SQL_ENUM.put(JAVA_BYTES, BINARY);
-        JAVA_SQL_ENUM.put(JAVA_BOOLEAN, BIT);
-        JAVA_SQL_ENUM.put(JAVA_STRING, VARCHAR);
-        JAVA_SQL_ENUM.put(JAVA_SQLDATE, DATE);
-        JAVA_SQL_ENUM.put(JAVA_UTILDATE, DATE);
-        JAVA_SQL_ENUM.put(JAVA_TIMESTAMP, TIMESTAMP);
-        JAVA_SQL_ENUM.put(JAVA_BIGDECIMAL, DECIMAL);
-        JAVA_SQL_ENUM.put(JAVA_DOUBLE, DOUBLE);
-        JAVA_SQL_ENUM.put(JAVA_FLOAT, FLOAT);
-        JAVA_SQL_ENUM.put(JAVA_INTEGER, INTEGER);
-        JAVA_SQL_ENUM.put(JAVA_SHORT, SMALLINT);
-        JAVA_SQL_ENUM.put(JAVA_BYTE, SMALLINT);
-        JAVA_SQL_ENUM.put(JAVA_TIME, TIME);
-        JAVA_SQL_ENUM.put(JAVA_TIMESTAMP, TIMESTAMP);
-
-        // add primitives
-        JAVA_SQL_ENUM.put("byte", TINYINT);
-        JAVA_SQL_ENUM.put("int", INTEGER);
-        JAVA_SQL_ENUM.put("short", SMALLINT);
-        JAVA_SQL_ENUM.put("char", CHAR);
-        JAVA_SQL_ENUM.put("double", DOUBLE);
-        JAVA_SQL_ENUM.put("long", BIGINT);
-        JAVA_SQL_ENUM.put("float", FLOAT);
-        JAVA_SQL_ENUM.put("boolean", BIT);
-    }
-
-    /**
-     * @deprecated
-     * 
-     * Returns true if supplied type can have a length attribute as a part of 
column
-     * definition.
-     */
-    public static boolean supportsLength(int type) {
-        return JdbcAdapter.supportsLength(type);
-    }
-
-    /**
-     * Returns true if supplied type is a numeric type.
-     */
-    public static boolean isNumeric(int type) {
-        return type == BIGINT
-                || type == BIT
-                || type == DECIMAL
-                || type == DOUBLE
-                || type == FLOAT
-                || type == INTEGER
-                || type == NUMERIC
-                || type == REAL
-                || type == SMALLINT
-                || type == TINYINT;
-    }
-
-    /**
-     * Returns true if supplied type is a decimal type.
-     */
-    public static boolean isDecimal(int type) {
-        return type == DECIMAL
-                || type == DOUBLE
-                || type == FLOAT
-                || type == REAL
-                || type == NUMERIC;
-    }
-
-    /**
-     * Returns an array of string names of the default JDBC data types.
-     */
-    public static String[] getDatabaseTypes() {
-        Collection<String> types = SQL_STRING_TYPE.keySet();
-        return types.toArray(new String[types.size()]);
-    }
-
-    /**
-     * Method implements an algorithm to pick a data type from a list of 
alternatives that
-     * most closely matches JDBC data type.
-     */
-    protected static String pickDataType(int jdbcType, TypeInfo[] alts) {
-        int len = alts.length;
-
-        if (len == 0) {
-            return null;
-        }
-
-        if (len == 1) {
-            return alts[0].name;
-        }
-
-        // now the fun starts.. try to guess the right type
-
-        String jdbcName = getSqlNameByType(jdbcType).toUpperCase();
-
-        // 1. exact match
-        for (TypeInfo alt : alts) {
-            if (jdbcName.equalsIgnoreCase(alt.name)) {
-                return alt.name;
-            }
-        }
-
-        // 2. filter those with biggest precision
-        long maxPrec = 0;
-        for (TypeInfo alt : alts) {
-            if (maxPrec < alt.precision) {
-                maxPrec = alt.precision;
-            }
-        }
-
-        List<TypeInfo> list = new ArrayList<TypeInfo>();
-        for (TypeInfo alt : alts) {
-            if (maxPrec == alt.precision) {
-                list.add(alt);
-            }
-        }
-
-        // work with smaller list now.....
-        int slen = list.size();
-        if (slen == 1) {
-            return list.get(0).name;
-        }
-
-        // start/end match
-        for (TypeInfo aList : list) {
-            String uppercase = aList.name.toUpperCase();
-            if (uppercase.startsWith(jdbcName) || 
uppercase.endsWith(jdbcName)) {
-                return aList.name;
-            }
-        }
-
-        // in the middle match
-        for (TypeInfo aList : list) {
-            String uppercase = aList.name.toUpperCase();
-
-            if (uppercase.contains(jdbcName)) {
-                return aList.name;
-            }
-        }
-
-        // out of ideas... return the first one
-        return list.get(0).name;
-    }
-
-    /**
-     * Returns a JDBC int type for SQL typem name.
-     */
-    public static int getSqlTypeByName(String typeName) {
-        Integer tmp = SQL_STRING_TYPE.get(typeName);
-        return tmp == null ? NOT_DEFINED : tmp;
-    }
-
-    /**
-     * Returns a String representation of the SQL type from its JDBC code.
-     */
-    public static String getSqlNameByType(int type) {
-        return SQL_ENUM_TYPE.get(type);
-    }
-
-    /**
-     * Returns default java.sql.Types type by the Java type name.
-     * 
-     * @param className Fully qualified Java Class name.
-     * @return The SQL type or NOT_DEFINED if no type found.
-     */
-    public static int getSqlTypeByJava(String className) {
-        if (className == null) {
-            return NOT_DEFINED;
-        }
-
-        Integer type = JAVA_SQL_ENUM.get(className);
-        if (type != null) {
-            return type;
-        }
-
-        // try to load a Java class - some nonstandard mappings may work
-
-        Class<?> aClass;
-        try {
-            aClass = Util.getJavaClass(className);
-        }
-        catch (Throwable th) {
-            return NOT_DEFINED;
-        }
-
-        return getSqlTypeByJava(aClass);
-    }
-
-    /**
-     * Guesses a default JDBC type for the Java class.
-     * 
-     * @since 1.1
-     */
-    public static int getSqlTypeByJava(Class<?> javaClass) {
-        if (javaClass == null) {
-            return NOT_DEFINED;
-        }
-
-        // check standard mapping of class and superclasses
-        Class<?> aClass = javaClass;
-        while (aClass != null) {
-
-            String name;
-
-            if (aClass.isArray()) {
-                name = aClass.getComponentType().getName() + "[]";
-            }
-            else {
-                name = aClass.getName();
-            }
-
-            Object type = JAVA_SQL_ENUM.get(name);
-            if (type != null) {
-                return ((Number) type).intValue();
-            }
-
-            aClass = aClass.getSuperclass();
-        }
-
-        // check non-standard JDBC types that are still supported by JPA
-        if (javaClass.isArray()) {
-
-            Class<?> elementType = javaClass.getComponentType();
-            if (Character.class.isAssignableFrom(elementType)
-                    || Character.TYPE.isAssignableFrom(elementType)) {
-                return VARCHAR;
-            }
-            else if (Byte.class.isAssignableFrom(elementType)
-                    || Byte.TYPE.isAssignableFrom(elementType)) {
-                return VARBINARY;
-            }
-        }
-
-        if (Calendar.class.isAssignableFrom(javaClass)) {
-            return TIMESTAMP;
-        }
-
-        if (BigInteger.class.isAssignableFrom(javaClass)) {
-            return BIGINT;
-        }
-
-        // serializable check should be the last one when all other mapping 
attempts
-        // failed
-        if (Serializable.class.isAssignableFrom(javaClass)) {
-            return VARBINARY;
-        }
-
-        return NOT_DEFINED;
-    }
-
-    /**
-     * Get the corresponding Java type by its java.sql.Types counterpart. Note 
that this
-     * method should be used as a last resort, with explicit mapping provided 
by user used
-     * as a first choice, as it can only guess how to map certain types, such 
as NUMERIC,
-     * etc.
-     * 
-     * @return Fully qualified Java type name or null if not found.
-     */
-    public static String getJavaBySqlType(int type) {
-        return SQL_ENUM_JAVA.get(type);
-    }
-
- 
-    protected Map<Integer, List<TypeInfo>> databaseTypes = new 
HashMap<Integer, List<TypeInfo>>();
-
-    public TypesMapping(DatabaseMetaData metaData) throws SQLException {
-        // map database types to standard JDBC types
-        ResultSet rs = metaData.getTypeInfo();
-
-        try {
-            while (rs.next()) {
-                TypeInfo info = new TypeInfo();
-                info.name = rs.getString("TYPE_NAME");
-                info.jdbcType = rs.getInt("DATA_TYPE");
-                info.precision = rs.getLong("PRECISION");
-
-                Integer key = info.jdbcType;
-                List<TypeInfo> infos = databaseTypes.get(key);
-
-                if (infos == null) {
-                    infos = new ArrayList<TypeInfo>();
-                    databaseTypes.put(key, infos);
-                }
-
-                infos.add(info);
-            }
-        }
-        finally {
-            rs.close();
-        }
-
-        // do some tricks to substitute for missing datatypes
-
-        // 1. swap TIMESTAMP - DATE
-        swapTypes(TIMESTAMP, DATE);
-
-        // 2. Swap CLOB - LONGVARCHAR
-        swapTypes(CLOB, LONGVARCHAR);
-
-        // 3. Swap BLOB - LONGVARBINARY
-        swapTypes(BLOB, LONGVARBINARY);
-
-        // 4. Swap NCLOB - LONGNVARCHAR
-        swapTypes(NCLOB, LONGNVARCHAR);
-    }
-
-    private void swapTypes(int type1, int type2) {
-        List<TypeInfo> type1Info = databaseTypes.get(type1);
-        List<TypeInfo> type2Info = databaseTypes.get(type2);
-
-        if (type1Info != null && type2Info == null) {
-            databaseTypes.put(type2, type1Info);
-        }
-        if (type2Info != null && type1Info == null) {
-            databaseTypes.put(type1, type2Info);
-        }
-    }
-
-    /** Stores (incomplete) information about database data type */
-    static class TypeInfo {
-
-        String name;
-        int jdbcType;
-        long precision;
-
-        @Override
-        public String toString() {
-            return "[   TypeInfo: " + name + "\n    JDBC Type: " + 
TypesMapping.getSqlNameByType(jdbcType)
-                    + "\n    Precision: " + precision + "\n]";
-        }
-    }
+       // Never use "-1" or any other normal integer, since there
+       // is a big chance it is being reserved in java.sql.Types
+       public static final int NOT_DEFINED = Integer.MAX_VALUE;
+
+       // char constants for the sql data types
+       public static final String SQL_ARRAY = "ARRAY";
+       public static final String SQL_BIGINT = "BIGINT";
+       public static final String SQL_BINARY = "BINARY";
+       public static final String SQL_BIT = "BIT";
+       public static final String SQL_BLOB = "BLOB";
+
+       /**
+        * @since 1.2
+        */
+       public static final String SQL_BOOLEAN = "BOOLEAN";
+
+       public static final String SQL_CLOB = "CLOB";
+       public static final String SQL_NCLOB = "NCLOB";
+       public static final String SQL_CHAR = "CHAR";
+       public static final String SQL_NCHAR = "NCHAR";
+       public static final String SQL_DATE = "DATE";
+       public static final String SQL_DECIMAL = "DECIMAL";
+       public static final String SQL_DOUBLE = "DOUBLE";
+       public static final String SQL_FLOAT = "FLOAT";
+       public static final String SQL_INTEGER = "INTEGER";
+       public static final String SQL_LONGVARCHAR = "LONGVARCHAR";
+       public static final String SQL_LONGNVARCHAR = "LONGNVARCHAR";
+       public static final String SQL_LONGVARBINARY = "LONGVARBINARY";
+       public static final String SQL_NUMERIC = "NUMERIC";
+       public static final String SQL_REAL = "REAL";
+       public static final String SQL_SMALLINT = "SMALLINT";
+       public static final String SQL_TINYINT = "TINYINT";
+       public static final String SQL_TIME = "TIME";
+       public static final String SQL_TIMESTAMP = "TIMESTAMP";
+       public static final String SQL_VARBINARY = "VARBINARY";
+       public static final String SQL_VARCHAR = "VARCHAR";
+       public static final String SQL_NVARCHAR = "NVARCHAR";
+       public static final String SQL_SQLXML = "SQLXML";
+       public static final String SQL_OTHER = "OTHER";
+       public static final String SQL_NULL = "NULL";
+
+       // char constants for Java data types
+       public static final String JAVA_LONG = "java.lang.Long";
+       public static final String JAVA_BYTES = "byte[]";
+       public static final String JAVA_BOOLEAN = "java.lang.Boolean";
+       public static final String JAVA_STRING = "java.lang.String";
+       public static final String JAVA_SQLDATE = "java.sql.Date";
+       public static final String JAVA_UTILDATE = "java.util.Date";
+       public static final String JAVA_BIGDECIMAL = "java.math.BigDecimal";
+       public static final String JAVA_DOUBLE = "java.lang.Double";
+       public static final String JAVA_FLOAT = "java.lang.Float";
+       public static final String JAVA_INTEGER = "java.lang.Integer";
+       public static final String JAVA_SHORT = "java.lang.Short";
+       public static final String JAVA_BYTE = "java.lang.Byte";
+       public static final String JAVA_TIME = "java.sql.Time";
+       public static final String JAVA_TIMESTAMP = "java.sql.Timestamp";
+       public static final String JAVA_BLOB = "java.sql.Blob";
+
+       /**
+        * Keys: SQL string type names, Values: SQL int type definitions from
+        * java.sql.Types
+        */
+       private static final Map<String, Integer> SQL_STRING_TYPE = new 
HashMap<String, Integer>();
+
+       /**
+        * Keys: SQL int type definitions from java.sql.Types, Values: SQL 
string
+        * type names
+        */
+       private static final Map<Integer, String> SQL_ENUM_TYPE = new 
HashMap<Integer, String>();
+
+       /**
+        * Keys: SQL int type definitions from java.sql.Types, Values: java 
class
+        * names
+        */
+       private static final Map<Integer, String> SQL_ENUM_JAVA = new 
HashMap<Integer, String>();
+
+       /**
+        * Keys: java class names, Values: SQL int type definitions from
+        * java.sql.Types
+        */
+       private static final Map<String, Integer> JAVA_SQL_ENUM = new 
HashMap<String, Integer>();
+
+       static {
+               // SQL_STRING_TYPE.put(SQL_ARRAY, ARRAY);
+               SQL_STRING_TYPE.put(SQL_BIGINT, BIGINT);
+               SQL_STRING_TYPE.put(SQL_BINARY, BINARY);
+               SQL_STRING_TYPE.put(SQL_BIT, BIT);
+               SQL_STRING_TYPE.put(SQL_BLOB, BLOB);
+               SQL_STRING_TYPE.put(SQL_BOOLEAN, BOOLEAN);
+               SQL_STRING_TYPE.put(SQL_CLOB, CLOB);
+               SQL_STRING_TYPE.put(SQL_NCLOB, NCLOB);
+               SQL_STRING_TYPE.put(SQL_CHAR, CHAR);
+               SQL_STRING_TYPE.put(SQL_NCHAR, NCHAR);
+               SQL_STRING_TYPE.put(SQL_DATE, DATE);
+               SQL_STRING_TYPE.put(SQL_DECIMAL, DECIMAL);
+               SQL_STRING_TYPE.put(SQL_DOUBLE, DOUBLE);
+               SQL_STRING_TYPE.put(SQL_FLOAT, FLOAT);
+               SQL_STRING_TYPE.put(SQL_INTEGER, INTEGER);
+               SQL_STRING_TYPE.put(SQL_LONGVARCHAR, LONGVARCHAR);
+               SQL_STRING_TYPE.put(SQL_LONGNVARCHAR, LONGNVARCHAR);
+               SQL_STRING_TYPE.put(SQL_LONGVARBINARY, LONGVARBINARY);
+               SQL_STRING_TYPE.put(SQL_NUMERIC, NUMERIC);
+               SQL_STRING_TYPE.put(SQL_REAL, REAL);
+               SQL_STRING_TYPE.put(SQL_SMALLINT, SMALLINT);
+               SQL_STRING_TYPE.put(SQL_TINYINT, TINYINT);
+               SQL_STRING_TYPE.put(SQL_TIME, TIME);
+               SQL_STRING_TYPE.put(SQL_TIMESTAMP, TIMESTAMP);
+               SQL_STRING_TYPE.put(SQL_VARBINARY, VARBINARY);
+               SQL_STRING_TYPE.put(SQL_VARCHAR, VARCHAR);
+               SQL_STRING_TYPE.put(SQL_NVARCHAR, NVARCHAR);
+               SQL_STRING_TYPE.put(SQL_OTHER, OTHER);
+               SQL_STRING_TYPE.put(SQL_NULL, NULL);
+
+               SQL_ENUM_TYPE.put(ARRAY, SQL_ARRAY);
+               SQL_ENUM_TYPE.put(BIGINT, SQL_BIGINT);
+               SQL_ENUM_TYPE.put(BINARY, SQL_BINARY);
+               SQL_ENUM_TYPE.put(BIT, SQL_BIT);
+               SQL_ENUM_TYPE.put(BOOLEAN, SQL_BOOLEAN);
+               SQL_ENUM_TYPE.put(BLOB, SQL_BLOB);
+               SQL_ENUM_TYPE.put(CLOB, SQL_CLOB);
+               SQL_ENUM_TYPE.put(NCLOB, SQL_NCLOB);
+               SQL_ENUM_TYPE.put(CHAR, SQL_CHAR);
+               SQL_ENUM_TYPE.put(NCHAR, SQL_NCHAR);
+               SQL_ENUM_TYPE.put(DATE, SQL_DATE);
+               SQL_ENUM_TYPE.put(DECIMAL, SQL_DECIMAL);
+               SQL_ENUM_TYPE.put(DOUBLE, SQL_DOUBLE);
+               SQL_ENUM_TYPE.put(FLOAT, SQL_FLOAT);
+               SQL_ENUM_TYPE.put(INTEGER, SQL_INTEGER);
+               SQL_ENUM_TYPE.put(LONGVARCHAR, SQL_LONGVARCHAR);
+               SQL_ENUM_TYPE.put(LONGNVARCHAR, SQL_LONGNVARCHAR);
+               SQL_ENUM_TYPE.put(LONGVARBINARY, SQL_LONGVARBINARY);
+               SQL_ENUM_TYPE.put(NUMERIC, SQL_NUMERIC);
+               SQL_ENUM_TYPE.put(REAL, SQL_REAL);
+               SQL_ENUM_TYPE.put(SMALLINT, SQL_SMALLINT);
+               SQL_ENUM_TYPE.put(TINYINT, SQL_TINYINT);
+               SQL_ENUM_TYPE.put(TIME, SQL_TIME);
+               SQL_ENUM_TYPE.put(TIMESTAMP, SQL_TIMESTAMP);
+               SQL_ENUM_TYPE.put(VARBINARY, SQL_VARBINARY);
+               SQL_ENUM_TYPE.put(VARCHAR, SQL_VARCHAR);
+               SQL_ENUM_TYPE.put(NVARCHAR, SQL_NVARCHAR);
+               SQL_ENUM_TYPE.put(SQLXML, SQL_SQLXML);
+               SQL_ENUM_TYPE.put(OTHER, SQL_OTHER);
+               SQL_ENUM_TYPE.put(NULL, SQL_NULL);
+
+               SQL_ENUM_JAVA.put(BIGINT, JAVA_LONG);
+               SQL_ENUM_JAVA.put(BINARY, JAVA_BYTES);
+               SQL_ENUM_JAVA.put(BIT, JAVA_BOOLEAN);
+               SQL_ENUM_JAVA.put(BOOLEAN, JAVA_BOOLEAN);
+               SQL_ENUM_JAVA.put(BLOB, JAVA_BYTES);
+               SQL_ENUM_JAVA.put(CLOB, JAVA_STRING);
+               SQL_ENUM_JAVA.put(NCLOB, JAVA_STRING);
+               SQL_ENUM_JAVA.put(CHAR, JAVA_STRING);
+               SQL_ENUM_JAVA.put(NCHAR, JAVA_STRING);
+               SQL_ENUM_JAVA.put(DATE, JAVA_UTILDATE);
+               SQL_ENUM_JAVA.put(DECIMAL, JAVA_BIGDECIMAL);
+               SQL_ENUM_JAVA.put(DOUBLE, JAVA_DOUBLE);
+               SQL_ENUM_JAVA.put(FLOAT, JAVA_FLOAT);
+               SQL_ENUM_JAVA.put(INTEGER, JAVA_INTEGER);
+               SQL_ENUM_JAVA.put(LONGVARCHAR, JAVA_STRING);
+               SQL_ENUM_JAVA.put(LONGNVARCHAR, JAVA_STRING);
+               SQL_ENUM_JAVA.put(LONGVARBINARY, JAVA_BYTES);
+               SQL_ENUM_JAVA.put(NUMERIC, JAVA_BIGDECIMAL);
+               SQL_ENUM_JAVA.put(REAL, JAVA_FLOAT);
+               SQL_ENUM_JAVA.put(SMALLINT, JAVA_SHORT);
+               SQL_ENUM_JAVA.put(TINYINT, JAVA_SHORT);
+               SQL_ENUM_JAVA.put(TIME, JAVA_UTILDATE);
+               SQL_ENUM_JAVA.put(TIMESTAMP, JAVA_UTILDATE);
+               SQL_ENUM_JAVA.put(VARBINARY, JAVA_BYTES);
+               SQL_ENUM_JAVA.put(VARCHAR, JAVA_STRING);
+               SQL_ENUM_JAVA.put(NVARCHAR, JAVA_STRING);
+               SQL_ENUM_JAVA.put(SQLXML, JAVA_STRING);
+
+               JAVA_SQL_ENUM.put(JAVA_LONG, BIGINT);
+               JAVA_SQL_ENUM.put(JAVA_BYTES, BINARY);
+               JAVA_SQL_ENUM.put(JAVA_BOOLEAN, BIT);
+               JAVA_SQL_ENUM.put(JAVA_STRING, VARCHAR);
+               JAVA_SQL_ENUM.put(JAVA_SQLDATE, DATE);
+               JAVA_SQL_ENUM.put(JAVA_UTILDATE, DATE);
+               JAVA_SQL_ENUM.put(JAVA_TIMESTAMP, TIMESTAMP);
+               JAVA_SQL_ENUM.put(JAVA_BIGDECIMAL, DECIMAL);
+               JAVA_SQL_ENUM.put(JAVA_DOUBLE, DOUBLE);
+               JAVA_SQL_ENUM.put(JAVA_FLOAT, FLOAT);
+               JAVA_SQL_ENUM.put(JAVA_INTEGER, INTEGER);
+               JAVA_SQL_ENUM.put(JAVA_SHORT, SMALLINT);
+               JAVA_SQL_ENUM.put(JAVA_BYTE, SMALLINT);
+               JAVA_SQL_ENUM.put(JAVA_TIME, TIME);
+               JAVA_SQL_ENUM.put(JAVA_TIMESTAMP, TIMESTAMP);
+
+               // add primitives
+               JAVA_SQL_ENUM.put("byte", TINYINT);
+               JAVA_SQL_ENUM.put("int", INTEGER);
+               JAVA_SQL_ENUM.put("short", SMALLINT);
+               JAVA_SQL_ENUM.put("char", CHAR);
+               JAVA_SQL_ENUM.put("double", DOUBLE);
+               JAVA_SQL_ENUM.put("long", BIGINT);
+               JAVA_SQL_ENUM.put("float", FLOAT);
+               JAVA_SQL_ENUM.put("boolean", BIT);
+       }
+
+       /**
+        * @deprecated
+        * 
+        *             Returns true if supplied type can have a length 
attribute as
+        *             a part of column definition.
+        */
+       public static boolean supportsLength(int type) {
+               return JdbcAdapter.supportsLength(type);
+       }
+
+       /**
+        * Returns true if supplied type is a numeric type.
+        */
+       public static boolean isNumeric(int type) {
+               return type == BIGINT || type == BIT || type == DECIMAL || type 
== DOUBLE || type == FLOAT || type == INTEGER
+                               || type == NUMERIC || type == REAL || type == 
SMALLINT || type == TINYINT;
+       }
+
+       /**
+        * Returns true if supplied type is a decimal type.
+        */
+       public static boolean isDecimal(int type) {
+               return type == DECIMAL || type == DOUBLE || type == FLOAT || 
type == REAL || type == NUMERIC;
+       }
+
+       /**
+        * Returns an array of string names of the default JDBC data types.
+        */
+       public static String[] getDatabaseTypes() {
+               Collection<String> types = SQL_STRING_TYPE.keySet();
+               return types.toArray(new String[types.size()]);
+       }
+
+       /**
+        * Method implements an algorithm to pick a data type from a list of
+        * alternatives that most closely matches JDBC data type.
+        */
+       protected static String pickDataType(int jdbcType, TypeInfo[] alts) {
+               int len = alts.length;
+
+               if (len == 0) {
+                       return null;
+               }
+
+               if (len == 1) {
+                       return alts[0].name;
+               }
+
+               // now the fun starts.. try to guess the right type
+
+               String jdbcName = getSqlNameByType(jdbcType).toUpperCase();
+
+               // 1. exact match
+               for (TypeInfo alt : alts) {
+                       if (jdbcName.equalsIgnoreCase(alt.name)) {
+                               return alt.name;
+                       }
+               }
+
+               // 2. filter those with biggest precision
+               long maxPrec = 0;
+               for (TypeInfo alt : alts) {
+                       if (maxPrec < alt.precision) {
+                               maxPrec = alt.precision;
+                       }
+               }
+
+               List<TypeInfo> list = new ArrayList<TypeInfo>();
+               for (TypeInfo alt : alts) {
+                       if (maxPrec == alt.precision) {
+                               list.add(alt);
+                       }
+               }
+
+               // work with smaller list now.....
+               int slen = list.size();
+               if (slen == 1) {
+                       return list.get(0).name;
+               }
+
+               // start/end match
+               for (TypeInfo aList : list) {
+                       String uppercase = aList.name.toUpperCase();
+                       if (uppercase.startsWith(jdbcName) || 
uppercase.endsWith(jdbcName)) {
+                               return aList.name;
+                       }
+               }
+
+               // in the middle match
+               for (TypeInfo aList : list) {
+                       String uppercase = aList.name.toUpperCase();
+
+                       if (uppercase.contains(jdbcName)) {
+                               return aList.name;
+                       }
+               }
+
+               // out of ideas... return the first one
+               return list.get(0).name;
+       }
+
+       /**
+        * Returns a JDBC int type for SQL typem name.
+        */
+       public static int getSqlTypeByName(String typeName) {
+               Integer tmp = SQL_STRING_TYPE.get(typeName);
+               return tmp == null ? NOT_DEFINED : tmp;
+       }
+
+       /**
+        * Returns a String representation of the SQL type from its JDBC code.
+        */
+       public static String getSqlNameByType(int type) {
+               return SQL_ENUM_TYPE.get(type);
+       }
+
+       /**
+        * Returns default java.sql.Types type by the Java type name.
+        * 
+        * @param className
+        *            Fully qualified Java Class name.
+        * @return The SQL type or NOT_DEFINED if no type found.
+        */
+       public static int getSqlTypeByJava(String className) {
+               if (className == null) {
+                       return NOT_DEFINED;
+               }
+
+               Integer type = JAVA_SQL_ENUM.get(className);
+               if (type != null) {
+                       return type;
+               }
+
+               // try to load a Java class - some nonstandard mappings may work
+
+               Class<?> aClass;
+               try {
+                       aClass = Util.getJavaClass(className);
+               } catch (Throwable th) {
+                       return NOT_DEFINED;
+               }
+
+               return getSqlTypeByJava(aClass);
+       }
+
+       /**
+        * Guesses a default JDBC type for the Java class.
+        * 
+        * @since 1.1
+        */
+       public static int getSqlTypeByJava(Class<?> javaClass) {
+               if (javaClass == null) {
+                       return NOT_DEFINED;
+               }
+
+               // check standard mapping of class and superclasses
+               Class<?> aClass = javaClass;
+               while (aClass != null) {
+
+                       String name;
+
+                       if (aClass.isArray()) {
+                               name = aClass.getComponentType().getName() + 
"[]";
+                       } else {
+                               name = aClass.getName();
+                       }
+
+                       Object type = JAVA_SQL_ENUM.get(name);
+                       if (type != null) {
+                               return ((Number) type).intValue();
+                       }
+
+                       aClass = aClass.getSuperclass();
+               }
+
+               // check non-standard JDBC types that are still supported by JPA
+               if (javaClass.isArray()) {
+
+                       Class<?> elementType = javaClass.getComponentType();
+                       if (Character.class.isAssignableFrom(elementType) || 
Character.TYPE.isAssignableFrom(elementType)) {
+                               return VARCHAR;
+                       } else if (Byte.class.isAssignableFrom(elementType) || 
Byte.TYPE.isAssignableFrom(elementType)) {
+                               return VARBINARY;
+                       }
+               }
+
+               if (Calendar.class.isAssignableFrom(javaClass)) {
+                       return TIMESTAMP;
+               }
+
+               if (BigInteger.class.isAssignableFrom(javaClass)) {
+                       return BIGINT;
+               }
+
+               // serializable check should be the last one when all other 
mapping
+               // attempts
+               // failed
+               if (Serializable.class.isAssignableFrom(javaClass)) {
+                       return VARBINARY;
+               }
+
+               return NOT_DEFINED;
+       }
+
+       /**
+        * Get the corresponding Java type by its java.sql.Types counterpart. 
Note
+        * that this method should be used as a last resort, with explicit 
mapping
+        * provided by user used as a first choice, as it can only guess how to 
map
+        * certain types, such as NUMERIC, etc.
+        * 
+        * @return Fully qualified Java type name or null if not found.
+        */
+       public static String getJavaBySqlType(int type) {
+               return SQL_ENUM_JAVA.get(type);
+       }
+
+       protected Map<Integer, List<TypeInfo>> databaseTypes = new 
HashMap<Integer, List<TypeInfo>>();
+
+       public TypesMapping(DatabaseMetaData metaData) throws SQLException {
+               // map database types to standard JDBC types
+
+               try (ResultSet rs = metaData.getTypeInfo();) {
+                       while (rs.next()) {
+                               TypeInfo info = new TypeInfo();
+                               info.name = rs.getString("TYPE_NAME");
+                               info.jdbcType = rs.getInt("DATA_TYPE");
+                               info.precision = rs.getLong("PRECISION");
+
+                               Integer key = info.jdbcType;
+                               List<TypeInfo> infos = databaseTypes.get(key);
+
+                               if (infos == null) {
+                                       infos = new ArrayList<TypeInfo>();
+                                       databaseTypes.put(key, infos);
+                               }
+
+                               infos.add(info);
+                       }
+               }
+
+               // do some tricks to substitute for missing datatypes
+
+               // 1. swap TIMESTAMP - DATE
+               swapTypes(TIMESTAMP, DATE);
+
+               // 2. Swap CLOB - LONGVARCHAR
+               swapTypes(CLOB, LONGVARCHAR);
+
+               // 3. Swap BLOB - LONGVARBINARY
+               swapTypes(BLOB, LONGVARBINARY);
+
+               // 4. Swap NCLOB - LONGNVARCHAR
+               swapTypes(NCLOB, LONGNVARCHAR);
+       }
+
+       private void swapTypes(int type1, int type2) {
+               List<TypeInfo> type1Info = databaseTypes.get(type1);
+               List<TypeInfo> type2Info = databaseTypes.get(type2);
+
+               if (type1Info != null && type2Info == null) {
+                       databaseTypes.put(type2, type1Info);
+               }
+               if (type2Info != null && type1Info == null) {
+                       databaseTypes.put(type1, type2Info);
+               }
+       }
+
+       /** Stores (incomplete) information about database data type */
+       static class TypeInfo {
+
+               String name;
+               int jdbcType;
+               long precision;
+
+               @Override
+               public String toString() {
+                       return "[   TypeInfo: " + name + "\n    JDBC Type: " + 
TypesMapping.getSqlNameByType(jdbcType)
+                                       + "\n    Precision: " + precision + 
"\n]";
+               }
+       }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2PkGenerator.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2PkGenerator.java 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2PkGenerator.java
index f487c2b..667d6db 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2PkGenerator.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2PkGenerator.java
@@ -39,164 +39,150 @@ import org.apache.cayenne.map.DbEntity;
  */
 public class DB2PkGenerator extends JdbcPkGenerator {
 
-    DB2PkGenerator(JdbcAdapter adapter) {
-        super(adapter);
-    }
-
-    private static final String _SEQUENCE_PREFIX = "S_";
-
-    /**
-     * @since 3.0
-     */
-    @Override
-    protected long longPkFromDatabase(DataNode node, DbEntity entity) throws 
Exception {
-
-        String pkGeneratingSequenceName = sequenceName(entity);
-
-        Connection con = node.getDataSource().getConnection();
-        try {
-            Statement st = con.createStatement();
-            try {
-                String sql = "SELECT NEXTVAL FOR " + pkGeneratingSequenceName 
+ " FROM SYSIBM.SYSDUMMY1";
-                adapter.getJdbcEventLogger().logQuery(sql, 
Collections.EMPTY_LIST);
-                ResultSet rs = st.executeQuery(sql);
-                try {
-                    // Object pk = null;
-                    if (!rs.next()) {
-                        throw new CayenneRuntimeException("Error generating pk 
for DbEntity " + entity.getName());
-                    }
-                    return rs.getLong(1);
-                } finally {
-                    rs.close();
-                }
-            } finally {
-                st.close();
-            }
-        } finally {
-            con.close();
-        }
-    }
-
-    @Override
-    public void createAutoPk(DataNode node, List<DbEntity> dbEntities) throws 
Exception {
-        Collection<String> sequences = getExistingSequences(node);
-        for (DbEntity entity : dbEntities) {
-            if (!sequences.contains(sequenceName(entity))) {
-                this.runUpdate(node, createSequenceString(entity));
-            }
-        }
-    }
-
-    /**
-     * Creates a list of CREATE SEQUENCE statements for the list of DbEntities.
-     */
-    @Override
-    public List<String> createAutoPkStatements(List<DbEntity> dbEntities) {
-        List<String> list = new ArrayList<String>(dbEntities.size());
-        for (DbEntity entity : dbEntities) {
-            list.add(createSequenceString(entity));
-        }
-        return list;
-    }
-
-    /**
-     * Drops PK sequences for all specified DbEntities.
-     */
-    @Override
-    public void dropAutoPk(DataNode node, List<DbEntity> dbEntities) throws 
Exception {
-        Collection<String> sequences = getExistingSequences(node);
-
-        for (DbEntity ent : dbEntities) {
-            String name;
-            if (ent.getDataMap().isQuotingSQLIdentifiers()) {
-                DbEntity tempEnt = new DbEntity();
-                DataMap dm = new DataMap();
-                dm.setQuotingSQLIdentifiers(false);
-                tempEnt.setDataMap(dm);
-                tempEnt.setName(ent.getName());
-                name = sequenceName(tempEnt);
-            } else {
-                name = sequenceName(ent);
-            }
-            if (sequences.contains(name)) {
-                runUpdate(node, dropSequenceString(ent));
-            }
-        }
-    }
-
-    /**
-     * Creates a list of DROP SEQUENCE statements for the list of DbEntities.
-     */
-    @Override
-    public List<String> dropAutoPkStatements(List<DbEntity> dbEntities) {
-        List<String> list = new ArrayList<String>(dbEntities.size());
-        for (DbEntity entity : dbEntities) {
-            list.add(dropSequenceString(entity));
-        }
-        return list;
-    }
-
-    /**
-     * Fetches a list of existing sequences that might match Cayenne generated
-     * ones.
-     */
-    protected List<String> getExistingSequences(DataNode node) throws 
SQLException {
-
-        // check existing sequences
-        Connection con = node.getDataSource().getConnection();
-
-        try {
-            Statement sel = con.createStatement();
-            try {
-                StringBuilder buffer = new StringBuilder();
-                buffer.append("SELECT SEQNAME FROM SYSCAT.SEQUENCES 
").append("WHERE SEQNAME LIKE '")
-                        .append(_SEQUENCE_PREFIX).append("%'");
-
-                String sql = buffer.toString();
-                adapter.getJdbcEventLogger().logQuery(sql, 
Collections.EMPTY_LIST);
-                ResultSet rs = sel.executeQuery(sql);
-                try {
-                    List<String> sequenceList = new ArrayList<String>();
-                    while (rs.next()) {
-                        sequenceList.add(rs.getString(1));
-                    }
-                    return sequenceList;
-                } finally {
-                    rs.close();
-                }
-            } finally {
-                sel.close();
-            }
-        } finally {
-            con.close();
-        }
-    }
-
-    /**
-     * Returns default sequence name for DbEntity.
-     */
-    protected String sequenceName(DbEntity entity) {
-        String entName = entity.getName();
-        String seqName = _SEQUENCE_PREFIX + entName;
-
-        return adapter.getQuotingStrategy().quotedIdentifier(entity, 
entity.getCatalog(), entity.getSchema(), seqName);
-    }
-
-    /**
-     * Returns DROP SEQUENCE statement.
-     */
-    protected String dropSequenceString(DbEntity entity) {
-        return "DROP SEQUENCE " + sequenceName(entity) + " RESTRICT ";
-    }
-
-    /**
-     * Returns CREATE SEQUENCE statement for entity.
-     */
-    protected String createSequenceString(DbEntity entity) {
-        StringBuilder buf = new StringBuilder();
-        buf.append("CREATE SEQUENCE ").append(sequenceName(entity)).append(" 
START WITH ").append(pkStartValue).append(" INCREMENT BY ")
-                .append(getPkCacheSize()).append(" NO MAXVALUE ").append(" NO 
CYCLE ").append(" CACHE ")
-                .append(getPkCacheSize());
-        return buf.toString();
-    }
+       DB2PkGenerator(JdbcAdapter adapter) {
+               super(adapter);
+       }
+
+       private static final String _SEQUENCE_PREFIX = "S_";
+
+       /**
+        * @since 3.0
+        */
+       @Override
+       protected long longPkFromDatabase(DataNode node, DbEntity entity) 
throws Exception {
+
+               String pkGeneratingSequenceName = sequenceName(entity);
+
+               try (Connection con = node.getDataSource().getConnection();) {
+
+                       try (Statement st = con.createStatement();) {
+                               String sql = "SELECT NEXTVAL FOR " + 
pkGeneratingSequenceName + " FROM SYSIBM.SYSDUMMY1";
+                               adapter.getJdbcEventLogger().logQuery(sql, 
Collections.EMPTY_LIST);
+
+                               try (ResultSet rs = st.executeQuery(sql);) {
+                                       // Object pk = null;
+                                       if (!rs.next()) {
+                                               throw new 
CayenneRuntimeException("Error generating pk for DbEntity " + entity.getName());
+                                       }
+                                       return rs.getLong(1);
+                               }
+                       }
+               }
+       }
+
+       @Override
+       public void createAutoPk(DataNode node, List<DbEntity> dbEntities) 
throws Exception {
+               Collection<String> sequences = getExistingSequences(node);
+               for (DbEntity entity : dbEntities) {
+                       if (!sequences.contains(sequenceName(entity))) {
+                               this.runUpdate(node, 
createSequenceString(entity));
+                       }
+               }
+       }
+
+       /**
+        * Creates a list of CREATE SEQUENCE statements for the list of 
DbEntities.
+        */
+       @Override
+       public List<String> createAutoPkStatements(List<DbEntity> dbEntities) {
+               List<String> list = new ArrayList<String>(dbEntities.size());
+               for (DbEntity entity : dbEntities) {
+                       list.add(createSequenceString(entity));
+               }
+               return list;
+       }
+
+       /**
+        * Drops PK sequences for all specified DbEntities.
+        */
+       @Override
+       public void dropAutoPk(DataNode node, List<DbEntity> dbEntities) throws 
Exception {
+               Collection<String> sequences = getExistingSequences(node);
+
+               for (DbEntity ent : dbEntities) {
+                       String name;
+                       if (ent.getDataMap().isQuotingSQLIdentifiers()) {
+                               DbEntity tempEnt = new DbEntity();
+                               DataMap dm = new DataMap();
+                               dm.setQuotingSQLIdentifiers(false);
+                               tempEnt.setDataMap(dm);
+                               tempEnt.setName(ent.getName());
+                               name = sequenceName(tempEnt);
+                       } else {
+                               name = sequenceName(ent);
+                       }
+                       if (sequences.contains(name)) {
+                               runUpdate(node, dropSequenceString(ent));
+                       }
+               }
+       }
+
+       /**
+        * Creates a list of DROP SEQUENCE statements for the list of 
DbEntities.
+        */
+       @Override
+       public List<String> dropAutoPkStatements(List<DbEntity> dbEntities) {
+               List<String> list = new ArrayList<String>(dbEntities.size());
+               for (DbEntity entity : dbEntities) {
+                       list.add(dropSequenceString(entity));
+               }
+               return list;
+       }
+
+       /**
+        * Fetches a list of existing sequences that might match Cayenne 
generated
+        * ones.
+        */
+       protected List<String> getExistingSequences(DataNode node) throws 
SQLException {
+
+               // check existing sequences
+
+               try (Connection con = node.getDataSource().getConnection();) {
+
+                       try (Statement sel = con.createStatement();) {
+                               StringBuilder buffer = new StringBuilder();
+                               buffer.append("SELECT SEQNAME FROM 
SYSCAT.SEQUENCES ").append("WHERE SEQNAME LIKE '")
+                                               
.append(_SEQUENCE_PREFIX).append("%'");
+
+                               String sql = buffer.toString();
+                               adapter.getJdbcEventLogger().logQuery(sql, 
Collections.EMPTY_LIST);
+
+                               try (ResultSet rs = sel.executeQuery(sql);) {
+                                       List<String> sequenceList = new 
ArrayList<String>();
+                                       while (rs.next()) {
+                                               
sequenceList.add(rs.getString(1));
+                                       }
+                                       return sequenceList;
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Returns default sequence name for DbEntity.
+        */
+       protected String sequenceName(DbEntity entity) {
+               String entName = entity.getName();
+               String seqName = _SEQUENCE_PREFIX + entName;
+
+               return adapter.getQuotingStrategy().quotedIdentifier(entity, 
entity.getCatalog(), entity.getSchema(), seqName);
+       }
+
+       /**
+        * Returns DROP SEQUENCE statement.
+        */
+       protected String dropSequenceString(DbEntity entity) {
+               return "DROP SEQUENCE " + sequenceName(entity) + " RESTRICT ";
+       }
+
+       /**
+        * Returns CREATE SEQUENCE statement for entity.
+        */
+       protected String createSequenceString(DbEntity entity) {
+               StringBuilder buf = new StringBuilder();
+               buf.append("CREATE SEQUENCE 
").append(sequenceName(entity)).append(" START WITH ").append(pkStartValue)
+                               .append(" INCREMENT BY 
").append(getPkCacheSize()).append(" NO MAXVALUE ").append(" NO CYCLE ")
+                               .append(" CACHE ").append(getPkCacheSize());
+               return buf.toString();
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2ProcedureAction.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2ProcedureAction.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2ProcedureAction.java
index b33e17a..aa9b61f 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2ProcedureAction.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2ProcedureAction.java
@@ -35,59 +35,45 @@ import org.apache.cayenne.query.ProcedureQuery;
  */
 class DB2ProcedureAction extends ProcedureAction {
 
-    DB2ProcedureAction(ProcedureQuery query, DataNode dataNode) {
-        super(query, dataNode);
-    }
+       DB2ProcedureAction(ProcedureQuery query, DataNode dataNode) {
+               super(query, dataNode);
+       }
 
-    @Override
-    public void performAction(Connection connection, OperationObserver 
observer) throws SQLException, Exception {
+       @Override
+       public void performAction(Connection connection, OperationObserver 
observer) throws SQLException, Exception {
 
-        // cloned from super except for result processing consistent with
-        // CAY-1874
-        
-        processedResultSets = 0;
+               // cloned from super except for result processing consistent 
with
+               // CAY-1874
 
-        ProcedureTranslator transl = createTranslator(connection);
+               processedResultSets = 0;
 
-        CallableStatement statement = (CallableStatement) 
transl.createStatement();
+               ProcedureTranslator transl = createTranslator(connection);
 
-        try {
-            initStatement(statement);
-            boolean hasResultSet = statement.execute();
+               try (CallableStatement statement = (CallableStatement) 
transl.createStatement();) {
+                       initStatement(statement);
+                       boolean hasResultSet = statement.execute();
 
-            // read out parameters
-            readProcedureOutParameters(statement, observer);
+                       // read out parameters
+                       readProcedureOutParameters(statement, observer);
 
-            // read the rest of the query
-            while (true) {
-                if (hasResultSet) {
-                    ResultSet rs = statement.getResultSet();
+                       // read the rest of the query
+                       while (true) {
+                               if (hasResultSet) {
 
-                    try {
-                        RowDescriptor descriptor = describeResultSet(rs, 
processedResultSets++);
-                        readResultSet(rs, descriptor, query, observer);
-                    } finally {
-                        try {
-                            rs.close();
-                        } catch (SQLException ex) {
-                        }
-                    }
-                } else {
-                    int updateCount = statement.getUpdateCount();
-                    if (updateCount == -1) {
-                        break;
-                    }
-                    dataNode.getJdbcEventLogger().logUpdateCount(updateCount);
-                    observer.nextCount(query, updateCount);
-                }
-                hasResultSet = statement.getMoreResults();
-            }
-        } finally {
-            try {
-                statement.close();
-            } catch (SQLException ex) {
-
-            }
-        }
-    }
+                                       try (ResultSet rs = 
statement.getResultSet();) {
+                                               RowDescriptor descriptor = 
describeResultSet(rs, processedResultSets++);
+                                               readResultSet(rs, descriptor, 
query, observer);
+                                       }
+                               } else {
+                                       int updateCount = 
statement.getUpdateCount();
+                                       if (updateCount == -1) {
+                                               break;
+                                       }
+                                       
dataNode.getJdbcEventLogger().logUpdateCount(updateCount);
+                                       observer.nextCount(query, updateCount);
+                               }
+                               hasResultSet = statement.getMoreResults();
+                       }
+               }
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/26d8434d/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyPkGenerator.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyPkGenerator.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyPkGenerator.java
index 583bb33..4ed7469 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyPkGenerator.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyPkGenerator.java
@@ -32,72 +32,55 @@ import org.apache.cayenne.log.JdbcEventLogger;
 import org.apache.cayenne.map.DbEntity;
 
 /**
- * Default PK generator for Derby that uses updateable ResultSet to get the 
next id from
- * the lookup table.
+ * Default PK generator for Derby that uses updateable ResultSet to get the 
next
+ * id from the lookup table.
  * 
  * @since 1.2
  */
 public class DerbyPkGenerator extends JdbcPkGenerator {
 
-    DerbyPkGenerator(JdbcAdapter adapter) {
-        super(adapter);
-    }
-
-    static final String SELECT_QUERY = "SELECT NEXT_ID FROM AUTO_PK_SUPPORT"
-            + " WHERE TABLE_NAME = ? FOR UPDATE";
-
-    /**
-     * @since 3.0
-     */
-    @Override
-    protected long longPkFromDatabase(DataNode node, DbEntity entity) throws 
Exception {
-
-        JdbcEventLogger logger = adapter.getJdbcEventLogger();
-        if (logger.isLoggable()) {
-            logger.logQuery(SELECT_QUERY, Collections
-                    .singletonList(entity.getName()));
-        }
-
-        Connection c = node.getDataSource().getConnection();
-        try {
-            PreparedStatement select = c.prepareStatement(
-                    SELECT_QUERY,
-                    ResultSet.TYPE_FORWARD_ONLY,
-                    ResultSet.CONCUR_UPDATABLE);
-            try {
-                select.setString(1, entity.getName());
-                ResultSet rs = select.executeQuery();
-    
-                try {
-                    if (!rs.next()) {
-                        throw new CayenneException("PK lookup failed for 
table: "
-                                + entity.getName());
-                    }
-        
-                    long nextId = rs.getLong(1);
-        
-                    rs.updateLong(1, nextId + pkCacheSize);
-                    rs.updateRow();
-        
-                    if (rs.next()) {
-                        throw new CayenneException("More than one PK record 
for table: "
-                                + entity.getName());
-                    }
-                    
-                    c.commit();
-
-                    return nextId;
-                }
-                finally {
-                    rs.close();
-                }
-            }
-            finally {
-                select.close();
-            }
-        }
-        finally {
-            c.close();
-        }
-    }
+       DerbyPkGenerator(JdbcAdapter adapter) {
+               super(adapter);
+       }
+
+       static final String SELECT_QUERY = "SELECT NEXT_ID FROM 
AUTO_PK_SUPPORT" + " WHERE TABLE_NAME = ? FOR UPDATE";
+
+       /**
+        * @since 3.0
+        */
+       @Override
+       protected long longPkFromDatabase(DataNode node, DbEntity entity) 
throws Exception {
+
+               JdbcEventLogger logger = adapter.getJdbcEventLogger();
+               if (logger.isLoggable()) {
+                       logger.logQuery(SELECT_QUERY, 
Collections.singletonList(entity.getName()));
+               }
+
+               try (Connection c = node.getDataSource().getConnection();) {
+
+                       try (PreparedStatement select = 
c.prepareStatement(SELECT_QUERY, ResultSet.TYPE_FORWARD_ONLY,
+                                       ResultSet.CONCUR_UPDATABLE);) {
+                               select.setString(1, entity.getName());
+
+                               try (ResultSet rs = select.executeQuery();) {
+                                       if (!rs.next()) {
+                                               throw new CayenneException("PK 
lookup failed for table: " + entity.getName());
+                                       }
+
+                                       long nextId = rs.getLong(1);
+
+                                       rs.updateLong(1, nextId + pkCacheSize);
+                                       rs.updateRow();
+
+                                       if (rs.next()) {
+                                               throw new 
CayenneException("More than one PK record for table: " + entity.getName());
+                                       }
+
+                                       c.commit();
+
+                                       return nextId;
+                               }
+                       }
+               }
+       }
 }

Reply via email to