Primary Key Column order lost (a problem if there are multiple Primary Keys)
----------------------------------------------------------------------------

                 Key: DDLUTILS-214
                 URL: https://issues.apache.org/jira/browse/DDLUTILS-214
             Project: DdlUtils
          Issue Type: Bug
          Components: Core (No specific database)
    Affects Versions: 1.0
         Environment: Any
            Reporter: Rijk van Haaften
            Assignee: Thomas Dudziak
            Priority: Critical
             Fix For: 1.0


Symptom:
14558 [btpool0-5] DEBUG 
org.apache.ddlutils.platform.postgresql.PostgreSqlPlatform  - About to execute 
SQL DELETE FROM "a" WHERE "p" = ? AND "q" = ?
The delete sometimes works, sometimes I get this:
14569 [btpool0-5] WARN  
org.apache.ddlutils.platform.postgresql.PostgreSqlPlatform  - Attempted to 
delete a single row "a": q = 6, p = 3 in table "a" but changed 0 row(s).

Symptom analysis:
The query
DELETE FROM "a" WHERE "p" = ? AND "q" = ?
is filled in order (6,3), without regarding the field names (q = 6, p = 3) 
resulting in
DELETE FROM "a" WHERE "p" = 6 AND "q" = 3

Code analysis
1. SqlBuilder.getDeleteSql
SqlBuilder.getDeleteSql uses the Map pkValues iterator to generate the prepared 
statement.

2. PlatformImplBase.toColumknValues
This has a major problem: Map iterator order is not defined. Java 
documentation: "Some map implementations, like the TreeMap class, make specific 
guarantees as to their order; others, like the HashMap class, do not." In this 
case, the Map used is created by PlatformImplBase.toColumknValues:
    protected HashMap toColumnValues(SqlDynaProperty[] properties, DynaBean 
bean) {
        HashMap result = new HashMap();
        ...
    }
so iterator order is undefined.

3. PlatformImplBase.delete (for example)
a)
            String sql = createDeleteSql(model, dynaClass, primaryKeys, null);
createDeleteSql uses getDeleteSql (1) and due to (2), the order the columns in 
the generated String sql is undefined. So, this could generate either
 DELETE FROM "a" WHERE "p" = ? AND "q" = ?
 DELETE FROM "a" WHERE "q" = ? AND "p" = ?
which one cannot be determined
b) setObject uses a deterministic array order sqlIndex to fill the ? - marks
            SqlDynaProperty[] primaryKeys = dynaClass.getPrimaryKeyProperties();
            for (int idx = 0; idx < primaryKeys.length; idx++)
            {
                setObject(statement, idx + 1, dynaBean, primaryKeys[idx]);
            }
so there is a chance of 1/(number of PK columns) this will run correctly.

Solution:
use LinkedHashMap or TreeMap: they retain put-order, which is based on the 
SqlDynaProperty[] so by definition has the same order as the setObject loop:
    protected HashMap toColumnValues(SqlDynaProperty[] properties, DynaBean 
bean)
    {
        HashMap result = new LinkedHashMap();
        ...
    }


-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to