1 2 12 package com.versant.core.jdbc.sql; 13 14 import com.versant.core.metadata.MDStatics; 15 import com.versant.core.jdbc.JdbcKeyGenerator; 16 import com.versant.core.jdbc.JdbcKeyGeneratorFactory; 17 import com.versant.core.jdbc.JdbcMetaDataBuilder; 18 import com.versant.core.jdbc.metadata.JdbcColumn; 19 import com.versant.core.jdbc.metadata.JdbcTable; 20 import com.versant.core.jdbc.metadata.JdbcMappingResolver; 21 22 import java.sql.*; 23 import java.util.HashSet ; 24 import java.util.Iterator ; 25 26 import com.versant.core.common.BindingSupportImpl; 27 28 32 public class HighLowJdbcKeyGenerator implements JdbcKeyGenerator { 33 34 37 public static class Args { 38 39 40 private String tableName = "jdo_keygen"; 41 42 43 private String keyColumnName = "table_name"; 44 private String valueColumnName = "last_used_id"; 45 private int keyColumnLength = 64; 46 private int grabSize = 10; 47 private int start; 48 private boolean createTable = true; 49 private String pkConstraint; 50 51 public Args() { 52 } 53 54 public String getTableName() { 55 return tableName; 56 } 57 58 public void setTableName(String tableName) { 59 this.tableName = tableName; 60 } 61 62 public String getKeyColumnName() { 63 return keyColumnName; 64 } 65 66 public void setKeyColumnName(String keyColumnName) { 67 this.keyColumnName = keyColumnName; 68 } 69 70 public String getValueColumnName() { 71 return valueColumnName; 72 } 73 74 public void setValueColumnName(String valueColumnName) { 75 this.valueColumnName = valueColumnName; 76 } 77 78 public int getKeyColumnLength() { 79 return keyColumnLength; 80 } 81 82 public void setKeyColumnLength(int keyColumnLength) { 83 this.keyColumnLength = keyColumnLength; 84 } 85 86 public int getGrabSize() { 87 return grabSize; 88 } 89 90 public void setGrabSize(int grabSize) { 91 this.grabSize = grabSize; 92 } 93 94 public int getStart() { 95 return start; 96 } 97 98 public void setStart(int start) { 99 this.start = start; 100 } 101 102 public boolean isCreateTable() { 103 return createTable; 104 } 105 106 public void setCreateTable(boolean createTable) { 107 this.createTable = createTable; 108 } 109 110 public String getPkConstraint() { 111 return pkConstraint; 112 } 113 114 public void setPkConstraint(String pkConstraint) { 115 this.pkConstraint = pkConstraint; 116 } 117 } 118 119 122 public static class Factory implements JdbcKeyGeneratorFactory{ 123 124 128 public Object createArgsBean() { 129 return new Args(); 130 } 131 132 136 public JdbcKeyGenerator createJdbcKeyGenerator(String className, 137 JdbcTable classTable, Object args) { 138 HighLowJdbcKeyGenerator kg = new HighLowJdbcKeyGenerator( 139 classTable, (Args)args); 140 return kg; 141 } 142 } 143 144 protected JdbcTable classTable; 145 protected JdbcColumn classPk; 146 protected int pkJavaTypeCode; 147 148 protected String tableName; 149 protected String keyColumnName; 150 protected String valueColumnName; 151 protected int keyColumnLength; 152 protected int grabSize; 153 protected int start; 154 protected boolean createTable; 155 protected String pkConstraint; 156 157 protected String updateSql; 158 protected String selectSql; 159 protected int lastUsed; 160 protected int grabLeft; 161 162 public HighLowJdbcKeyGenerator(JdbcTable classTable, Args args) { 163 if (classTable.pk.length > 1) { 164 throw new IllegalArgumentException ("Cannot use HIGH/LOW key generator on a table with multiple " + 165 "primary key columns"); 166 } 167 this.classTable = classTable; 168 classPk = classTable.pk[0]; 169 pkJavaTypeCode = classPk.javaTypeCode; 170 tableName = args.getTableName(); 171 keyColumnName = args.getKeyColumnName(); 172 valueColumnName = args.getValueColumnName(); 173 keyColumnLength = args.getKeyColumnLength(); 174 grabSize = args.getGrabSize(); 175 start = args.getStart(); 176 createTable = args.isCreateTable(); 177 pkConstraint = args.getPkConstraint(); 178 } 179 180 193 public void init(String className, JdbcTable classTable, 194 Connection con) throws SQLException { 195 196 String where = " where " + keyColumnName + " = '" + classTable.name + "'"; 198 updateSql = "update " + tableName + " set " + valueColumnName + 199 " = " + valueColumnName + " + ?" + 200 where; 201 selectSql = "select " + valueColumnName + " from " + tableName + 202 where; 203 204 Statement stat = null; 206 PreparedStatement ps = null; 207 try { 208 ps = con.prepareStatement(updateSql); 209 ps.setInt(1, 0); 210 if (ps.executeUpdate() == 0) { 211 stat = con.createStatement(); 212 int first = start; 213 if (first == 0) { 214 String sql = 215 "select max(" + classPk.name + ") from " + classTable.name; 216 ResultSet rs = null; 217 try { 218 rs = stat.executeQuery(sql); 219 rs.next(); 220 first = rs.getInt(1); 221 } finally { 222 cleanup(rs); 223 } 224 } 225 String sql = 226 "insert into " + tableName + " (" + keyColumnName + ", " + 227 valueColumnName + ") values ('" + classTable.name + "', " + 228 first + ")"; 229 stat.execute(sql); 230 } 231 } finally { 232 cleanup(ps); 233 cleanup(stat); 234 } 235 } 236 237 242 public boolean isPostInsertGenerator() { 243 return false; 244 } 245 246 251 public boolean isRequiresOwnConnection() { 252 return grabSize > 1 && grabLeft == 0; 253 } 254 255 263 public void addKeyGenTables(HashSet set, JdbcMetaDataBuilder mdb) { 264 if (!createTable) return; 265 266 for (Iterator i = set.iterator(); i.hasNext();) { 268 JdbcTable t = (JdbcTable)i.next(); 269 if (t.name.equals(tableName)) return; 270 } 271 272 JdbcTable t = new JdbcTable(); 274 t.sqlDriver = mdb.getSqlDriver(); 275 t.name = tableName; 276 t.comment = getClass().getName(); 277 t.pkConstraintName = pkConstraint == null ? "pk_" + tableName : pkConstraint; 278 JdbcMappingResolver mr = mdb.getMappingResolver(); 279 JdbcColumn keyCol = new JdbcColumn(mr.resolveMapping(String .class), mr); 280 keyCol.name = keyColumnName; 281 keyCol.length = keyColumnLength; 282 keyCol.nulls = false; 283 JdbcColumn valueCol = 284 new JdbcColumn(mr.resolveMapping(Integer.TYPE), mr); 285 286 valueCol.name = valueColumnName; 287 valueCol.nulls = false; 288 t.cols = new JdbcColumn[]{keyCol, valueCol}; 289 t.setPk(new JdbcColumn[]{keyCol}); 290 set.add(t); 291 } 292 293 313 public synchronized void generatePrimaryKeyPre(String className, 314 JdbcTable classTable, int newObjectCount, Object [] data, 315 Connection con) 316 throws SQLException { 317 int pk; 318 if (grabSize == 1) { 319 pk = lookupNewNumber(con, grabSize); 320 } else { 321 if (grabLeft == 0) { 322 int effectiveGrabSize = newObjectCount; 323 if (effectiveGrabSize < grabSize) effectiveGrabSize = grabSize; 324 lastUsed = lookupNewNumber(con, effectiveGrabSize); 325 grabLeft = effectiveGrabSize - 1; 326 } else { 327 --grabLeft; 328 } 329 pk = lastUsed++; 330 } 331 switch (pkJavaTypeCode) { 332 case MDStatics.INTW: 333 case MDStatics.INT: 334 data[0] = new Integer ((int)pk); 335 break; 336 case MDStatics.SHORTW: 337 case MDStatics.SHORT: 338 data[0] = new Short ((short)pk); 339 break; 340 case MDStatics.BYTEW: 341 case MDStatics.BYTE: 342 data[0] = new Byte ((byte)pk); 343 break; 344 case MDStatics.LONGW: 345 case MDStatics.LONG: 346 data[0] = new Long (pk); 347 break; 348 default: 349 throw BindingSupportImpl.getInstance().internal( 350 "Unhandled java type code: " + pkJavaTypeCode); 351 } 352 } 353 354 358 protected int lookupNewNumber(Connection con, int effectiveGrabSize) 359 throws SQLException { 360 PreparedStatement ps = null; 361 try { 362 ps = con.prepareStatement(updateSql); 363 ps.setInt(1, effectiveGrabSize); 364 if (ps.executeUpdate() == 0) { 365 throw BindingSupportImpl.getInstance().fatalDatastore("Row not found in keygen table:\n" + 366 updateSql); 367 } 368 Statement stat = null; 369 ResultSet rs = null; 370 try { 371 stat = con.createStatement(); 372 rs = stat.executeQuery(selectSql); 373 rs.next(); 374 return rs.getInt(1) - (effectiveGrabSize - 1); 375 } finally { 376 cleanup(rs); 377 cleanup(stat); 378 } 379 } finally { 380 cleanup(ps); 381 } 382 } 383 384 private void cleanup(ResultSet rs) { 385 try { 386 if (rs != null) rs.close(); 387 } catch (SQLException e) { 388 } 390 } 391 392 private void cleanup(Statement s) { 393 try { 394 if (s != null) s.close(); 395 } catch (SQLException e) { 396 } 398 } 399 400 414 public void generatePrimaryKeyPost(String className, 415 JdbcTable classTable, Object [] data, 416 Connection con, Statement stat) throws SQLException { 417 throw BindingSupportImpl.getInstance().internal("not a postInsertGenerator"); 418 } 419 420 426 public String getPostInsertSQLSuffix(JdbcTable classTable) { 427 throw BindingSupportImpl.getInstance().internal("not a postInsertGenerator"); 428 } 429 430 } 431 | Popular Tags |