Fix JdbcStorage support for PostgreSQL, adding a new parameter which BLD200411281900
authorjsichi@netbeans.org
Sun, 28 Nov 2004 06:38:58 +0000
changeset 163523425834f4fe
parent 1634 813279b33f96
child 1636 d059b2880963
Fix JdbcStorage support for PostgreSQL, adding a new parameter which
enables a workaround for the broken subtransaction stupport in that
DBMS. Add a debugging parameter for printing out exceptions before throwing
them.
mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/JdbcMultivaluedIndex.java
mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/JdbcStorage.java
mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/JdbcStorageFactory.java
mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/package.html
     1.1 --- a/mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/JdbcMultivaluedIndex.java	Sat Nov 27 22:16:17 2004 +0000
     1.2 +++ b/mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/JdbcMultivaluedIndex.java	Sun Nov 28 06:38:58 2004 +0000
     1.3 @@ -30,9 +30,12 @@
     1.4  class JdbcMultivaluedIndex
     1.5      extends JdbcIndex implements MultivaluedIndex
     1.6  {
     1.7 +    protected boolean queryDuplicates;
     1.8 +    
     1.9      protected LazyPreparedStatement sqlDeleteWithValue;
    1.10      protected LazyPreparedStatement sqlDeleteWithSurrogate;
    1.11      protected LazyPreparedStatement sqlFindCount;
    1.12 +    protected LazyPreparedStatement sqlFindCountWithValue;
    1.13      protected LazyPreparedStatement sqlFindSurrogate;
    1.14      
    1.15      protected void defineSql()
    1.16 @@ -53,6 +56,11 @@
    1.17              "select count(*) from " + tableName
    1.18              + " where " + keyColName + " = ?");
    1.19  
    1.20 +        sqlFindCountWithValue = new LazyPreparedStatement(
    1.21 +            "select count(*) from " + tableName
    1.22 +            + " where " + keyColName + " = ?"
    1.23 +            + " and " + valColName + " = ?");
    1.24 +
    1.25          sqlFindSurrogate = new LazyPreparedStatement(
    1.26              "select " + JdbcStorage.SURROGATE_COL_NAME
    1.27              + " from " + tableName
    1.28 @@ -83,6 +91,20 @@
    1.29          return !needSurrogate;
    1.30      }
    1.31  
    1.32 +    // override JdbcIndex
    1.33 +    public void add(Object key, Object value) throws StorageException
    1.34 +    {
    1.35 +        if (queryDuplicates) {
    1.36 +            int n = storage.getSingletonInt(
    1.37 +                sqlFindCountWithValue,
    1.38 +                new Object [] { key, value } );
    1.39 +            if (n > 0) {
    1.40 +                throw new StorageBadRequestException("duplicate detected");
    1.41 +            }
    1.42 +        }
    1.43 +        addImpl(key, value);
    1.44 +    }
    1.45 +
    1.46      // implement MultivaluedIndex
    1.47      public boolean remove(Object key, Object value) throws StorageException
    1.48      {
     2.1 --- a/mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/JdbcStorage.java	Sat Nov 27 22:16:17 2004 +0000
     2.2 +++ b/mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/JdbcStorage.java	Sun Nov 28 06:38:58 2004 +0000
     2.3 @@ -57,6 +57,10 @@
     2.4  
     2.5      private final boolean realSchema;
     2.6  
     2.7 +    private final boolean debugPrint;
     2.8 +
     2.9 +    private final boolean queryDuplicates;
    2.10 +
    2.11      private final Map entryTypeToDataTypeMap;
    2.12  
    2.13      private Statement jdbcStmt;
    2.14 @@ -110,6 +114,15 @@
    2.15                  throw new StorageBadRequestException(ex.toString());
    2.16              }
    2.17          }
    2.18 +        debugPrint = getBooleanProperty(
    2.19 +            properties, 
    2.20 +            JdbcStorageFactory.STORAGE_DEBUG_PRINT,
    2.21 +            false);
    2.22 +        queryDuplicates = getBooleanProperty(
    2.23 +            properties, 
    2.24 +            JdbcStorageFactory.STORAGE_QUERY_DUPLICATES,
    2.25 +            false);
    2.26 +        
    2.27          boolean success = false;
    2.28          
    2.29          try {
    2.30 @@ -124,7 +137,7 @@
    2.31              idQuote = dbMetaData.getIdentifierQuoteString();
    2.32              success = true;
    2.33          } catch (SQLException ex) {
    2.34 -            throw new JdbcStorageException(ex);
    2.35 +            throw newJdbcException(ex);
    2.36          } finally {
    2.37              if (!success) {
    2.38                  rollbackConnection();
    2.39 @@ -133,6 +146,26 @@
    2.40          }
    2.41      }
    2.42  
    2.43 +    private static boolean getBooleanProperty(
    2.44 +        Properties properties,
    2.45 +        String propName,
    2.46 +        boolean defaultValue)
    2.47 +    {
    2.48 +        String value = properties.getProperty(propName);
    2.49 +        if (value == null) {
    2.50 +            return defaultValue;
    2.51 +        }
    2.52 +        return value.equalsIgnoreCase("true");
    2.53 +    }
    2.54 +
    2.55 +    private JdbcStorageException newJdbcException(SQLException ex)
    2.56 +    {
    2.57 +        if (debugPrint) {
    2.58 +            ex.printStackTrace();
    2.59 +        }
    2.60 +        return new JdbcStorageException(ex);
    2.61 +    }
    2.62 +
    2.63      private void createTypeMap(Properties properties)
    2.64      {
    2.65          entryTypeToDataTypeMap.put(
    2.66 @@ -356,7 +389,7 @@
    2.67              jdbcConnection.commit();
    2.68          } catch (SQLException ex) {
    2.69              rollbackConnection();
    2.70 -            throw new JdbcStorageException(ex);
    2.71 +            throw newJdbcException(ex);
    2.72          }
    2.73      }
    2.74      
    2.75 @@ -379,7 +412,7 @@
    2.76              openImpl();
    2.77              loadPrimaryIndex();
    2.78          } catch (SQLException ex) {
    2.79 -            throw new JdbcStorageException(ex);
    2.80 +            throw newJdbcException(ex);
    2.81          }
    2.82      }
    2.83  
    2.84 @@ -611,7 +644,7 @@
    2.85                      // NOTE: could use just (KEY,ORDINAL) as primary key.
    2.86                      // However, we have to be able to modify ordinals, and even
    2.87                      // PostgreSQL doesn't get the deferred constraint
    2.88 -                    // enforcement right in that case).  So, throw in both the
    2.89 +                    // enforcement right in that case.  So, throw in both the
    2.90                      // ORDINAL and the SURROGATE so that ORDER BY can use the
    2.91                      // index.
    2.92                      sb.append(",");
    2.93 @@ -625,7 +658,7 @@
    2.94              sb.append(")");
    2.95              jdbcStmt.execute(sb.toString());
    2.96          } catch (SQLException ex) {
    2.97 -            throw new JdbcStorageException(ex);
    2.98 +            throw newJdbcException(ex);
    2.99          }
   2.100      }
   2.101  
   2.102 @@ -687,6 +720,9 @@
   2.103                  } else {
   2.104                      index = new JdbcMultivaluedIndex();
   2.105                  }
   2.106 +                if (queryDuplicates && !needSurrogate) {
   2.107 +                    ((JdbcMultivaluedIndex) index).queryDuplicates = true;
   2.108 +                }
   2.109              }
   2.110              index.init(
   2.111                  this,
   2.112 @@ -696,7 +732,7 @@
   2.113              nameToIndexMap.put(name,index);
   2.114              return index;
   2.115          } catch (SQLException ex) {
   2.116 -            throw new JdbcStorageException(ex);
   2.117 +            throw newJdbcException(ex);
   2.118          } finally {
   2.119              closeResultSet();
   2.120              closePreparedStatement(ps);
   2.121 @@ -742,7 +778,7 @@
   2.122          try {
   2.123              jdbcStmt.execute("drop table "+getTableNameForIndex(name));
   2.124          } catch (SQLException ex) {
   2.125 -            throw new JdbcStorageException(ex);
   2.126 +            throw newJdbcException(ex);
   2.127          }
   2.128          nameToIndexMap.remove(name);
   2.129      }
   2.130 @@ -771,7 +807,7 @@
   2.131              }
   2.132              jdbcConnection.commit();
   2.133          } catch (SQLException ex) {
   2.134 -            throw new JdbcStorageException(ex);
   2.135 +            throw newJdbcException(ex);
   2.136          }
   2.137      }
   2.138  
   2.139 @@ -784,7 +820,7 @@
   2.140              }
   2.141              jdbcConnection.rollback();
   2.142          } catch (SQLException ex) {
   2.143 -            throw new JdbcStorageException(ex);
   2.144 +            throw newJdbcException(ex);
   2.145          }
   2.146          if (primaryIndex != null) {
   2.147              primaryIndex.shutDown();
   2.148 @@ -822,7 +858,7 @@
   2.149              lps.ps = ps;
   2.150              return ps;
   2.151          } catch (SQLException ex) {
   2.152 -            throw new JdbcStorageException(ex);
   2.153 +            throw newJdbcException(ex);
   2.154          }
   2.155      }
   2.156  
   2.157 @@ -905,7 +941,7 @@
   2.158              }
   2.159              return list.listIterator();
   2.160          } catch (SQLException ex) {
   2.161 -            throw new JdbcStorageException(ex);
   2.162 +            throw newJdbcException(ex);
   2.163          }
   2.164      }
   2.165  
   2.166 @@ -927,7 +963,7 @@
   2.167                  closeResultSet();
   2.168              }
   2.169          } catch (SQLException ex) {
   2.170 -            throw new JdbcStorageException(ex);
   2.171 +            throw newJdbcException(ex);
   2.172          }
   2.173      }
   2.174  
   2.175 @@ -950,7 +986,7 @@
   2.176                  closeResultSet();
   2.177              }
   2.178          } catch (SQLException ex) {
   2.179 -            throw new JdbcStorageException(ex);
   2.180 +            throw newJdbcException(ex);
   2.181          }
   2.182      }
   2.183  
   2.184 @@ -1005,7 +1041,7 @@
   2.185              bindArgs(ps,args);
   2.186              return ps.executeUpdate();
   2.187          } catch (SQLException ex) {
   2.188 -            throw new JdbcStorageException(ex);
   2.189 +            throw newJdbcException(ex);
   2.190          }
   2.191      }
   2.192  }
     3.1 --- a/mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/JdbcStorageFactory.java	Sat Nov 27 22:16:17 2004 +0000
     3.2 +++ b/mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/JdbcStorageFactory.java	Sun Nov 28 06:38:58 2004 +0000
     3.3 @@ -51,6 +51,12 @@
     3.4      public static final String STORAGE_FIRST_SERIAL_NUMBER =
     3.5      PROPERTY_PREFIX + "firstSerialNumber";
     3.6      
     3.7 +    public static final String STORAGE_DEBUG_PRINT =
     3.8 +    PROPERTY_PREFIX + "debugPrint";
     3.9 +    
    3.10 +    public static final String STORAGE_QUERY_DUPLICATES =
    3.11 +    PROPERTY_PREFIX + "queryDuplicates";
    3.12 +    
    3.13      public static final String STORAGE_DATATYPE_MOFID =
    3.14      PROPERTY_PREFIX + "datatype.mofid";
    3.15  
     4.1 --- a/mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/package.html	Sat Nov 27 22:16:17 2004 +0000
     4.2 +++ b/mdr/extras/jdbcstorage/src/org/netbeans/mdr/persistence/jdbcimpl/package.html	Sun Nov 28 06:38:58 2004 +0000
     4.3 @@ -65,11 +65,37 @@
     4.4  <li>MDRStorageProperty.org.netbeans.mdr.persistence.jdbcimpl.password = 
     4.5  password corresponding to userName
     4.6  
     4.7 +<li>MDRStorageProperty.org.netbeans.mdr.persistence.jdbcimpl.queryDuplicates
     4.8 += true to force JdbcStorage to issue pre-updated queries to detect
     4.9 +duplicates in unique indexes (instead of letting the DBMS do the job
    4.10 +during update).  This must be enabled for databases such as PostgreSQL
    4.11 +(pre-1.7.5) without proper subtransaction support.  It should be left
    4.12 +disabled for all others since it adds a performance penalty.
    4.13 +
    4.14 +<li>MDRStorageProperty.org.netbeans.mdr.persistence.jdbcimpl.firstSerialNumber
    4.15 += lowest MOFID serial number to assign.  When federating multiple
    4.16 +storages, this can be used to prevent conflicts by partitioning the
    4.17 +MOFID space into non-overlapping ranges.  This parameter only takes
    4.18 +effect when the storage is initially created; the value can be either
    4.19 +decimal, hexadecimal, or octal as interpreted by {@link
    4.20 +java.lang.Long#decode}.
    4.21 +
    4.22 +<li>MDRStorageProperty.org.netbeans.mdr.persistence.jdbcimpl.debugPrint
    4.23 += true to request that whenever an SQLException is caught and
    4.24 +rethrown, the error message and its stack trace will be printed to
    4.25 +standard error.  Sometimes exception messages get swallowed by upper
    4.26 +layers of MDR, so this can be useful for debugging configuration
    4.27 +problems.  However, the output can be misleading, because some valid
    4.28 +exceptions thrown from the storage layer (e.g. uniqueness violation)
    4.29 +are caught and handled by MDR.
    4.30 +
    4.31 +</ul>
    4.32 +
    4.33 +<p>
    4.34 +
    4.35  The next section defines additional parameters affecting
    4.36  DBMS-specific usage of SQL.
    4.37  
    4.38 -</ul>
    4.39 -
    4.40  <h3>Index to Table Mapping</h3>
    4.41  
    4.42  JdbcStorage creates one table per MDR index.  It also creates one
    4.43 @@ -220,13 +246,13 @@
    4.44  <li>
    4.45  The StorageId prefix "j" is used for all MOFID's, and all MOFID's
    4.46  stored via JdbcStorage must have this prefix.  MOFID's are stored as
    4.47 -integer serial numbers with no prefix.  This means a JdbcStorage-based
    4.48 -repository cannot be used for federation of any kind.  For some
    4.49 -applications, this may be acceptable, and using integers for keys is
    4.50 -generally good for SQL performance.  Probably we should allow the user
    4.51 -a choice on a per-storage basis: either store MOFID's as integers and
    4.52 -disallow federation, or store MOFID's as strings or byte arrays and
    4.53 -allow federation (factoring out some commonality from btreeimpl).
    4.54 +integer serial numbers with no prefix.  This makes JdbcStorage-based
    4.55 +federation difficult.  For some applications, this may be acceptable,
    4.56 +and using integers for keys is generally good for SQL performance.
    4.57 +Probably we should allow the user a choice on a per-storage basis:
    4.58 +either store MOFID's as integers and disallow federation, or store
    4.59 +MOFID's as strings or byte arrays and allow federation (factoring out
    4.60 +some commonality from btreeimpl).
    4.61  
    4.62  <li>
    4.63  Caching for non-primary indexes is probably required for acceptable