Uploaded image for project: 'DdlUtils'
  1. DdlUtils
  2. DDLUTILS-214

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

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Resolved
    • Critical
    • Resolution: Fixed
    • 1.1
    • 1.1
    • None
    • Any

    Description

      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(); ... }

      Attachments

        Activity

          People

            tomdz Thomas Dudziak
            cordeo Cordeo
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: