1 23 24 30 31 package com.sun.jdo.spi.persistence.support.sqlstore; 32 33 35 import com.sun.jdo.api.persistence.support.*; 36 import com.sun.jdo.spi.persistence.support.sqlstore.database.DBVendorType; 37 import com.sun.jdo.spi.persistence.support.sqlstore.model.*; 38 import com.sun.jdo.spi.persistence.support.sqlstore.sql.RetrieveDescImpl; 39 import com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl; 40 import com.sun.jdo.spi.persistence.support.sqlstore.sql.concurrency.Concurrency; 41 import com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.*; 42 import com.sun.jdo.spi.persistence.utility.I18NHelper; 43 import com.sun.jdo.spi.persistence.utility.StringHelper; 44 import com.sun.jdo.spi.persistence.utility.logging.Logger; 45 46 import java.sql.*; 47 import java.util.*; 48 49 55 public class SQLStoreManager implements PersistenceStore { 56 57 58 private ConfigCache configCache; 59 60 61 private DBVendorType vendorType; 62 63 64 private static Logger logger = LogHelperSQLStore.getLogger(); 65 66 67 private static Logger sqlLogger = LogHelperSQLStore.getSqlLogger(); 68 69 70 private final static ResourceBundle messages = I18NHelper.loadBundle( 71 SQLStoreManager.class); 72 73 74 private static int fetchSize = 75 Integer.getInteger("com.sun.jdo.spi.persistence.support.sqlstore.SQLStoreManager.fetchSize", -1).intValue(); 78 85 public PersistenceConfig getPersistenceConfig(Class classType) { 86 if (logger.isLoggable(Logger.FINER)) { 87 logger.finer("sqlstore.sqlstoremanager.getpersistenceconfig", 88 classType.getName()); } 90 return configCache.getPersistenceConfig(classType); 91 } 92 93 96 public ConfigCache getConfigCache() { 97 return configCache; 98 } 99 100 108 public void execute(PersistenceManager pm, Collection actions) { 109 Iterator iter = actions.iterator(); 110 111 while (iter.hasNext()) { 112 ActionDesc action = (ActionDesc) iter.next(); 113 114 if (action instanceof UpdateObjectDescImpl) { 115 UpdateObjectDescImpl request = (UpdateObjectDescImpl) action; 116 UpdateQueryPlan plan = new UpdateQueryPlan(request, this); 117 118 plan.build(); 119 120 for (int i = 0, size = plan.statements.size(); i < size; i++) { 121 UpdateStatement s = (UpdateStatement) plan.statements.get(i); 122 123 if (s != null) { 124 executeUpdate(pm, s, request); 125 } 126 } 127 } else { 128 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 129 "core.generic.notinstanceof", action.getClass().getName(), 131 "UpdateObjectDescImpl")); } 133 } 134 } 135 136 139 private void rollbackXact(Transaction tran) { 140 141 try { 142 tran.setRollbackOnly(); 143 } catch (Exception e) { 145 } 146 } 147 148 166 private void executeUpdate(PersistenceManager pm, 167 UpdateStatement updateStatement, 168 UpdateObjectDescImpl updateDesc) { 169 int affectedRows = 0; 170 boolean debug = logger.isLoggable(); 171 172 if (debug) { 173 logger.fine("sqlstore.sqlstoremanager.executeupdate"); } 175 176 String sqlText = updateStatement.getText(); 177 if (sqlText.length() > 0) { 178 if (sqlLogger.isLoggable()) { 179 sqlLogger.fine(updateStatement.getFormattedSQLText()); 180 } 181 182 Transaction tran = (Transaction) pm.currentTransaction(); 183 Connection conn = tran.getConnection(); 184 DBStatement s = null; 185 boolean preparationSuccessful = false; 186 187 try { 188 s = new DBStatement(conn, sqlText, tran.getUpdateTimeout()); 190 updateStatement.bindInputValues(s); 191 preparationSuccessful = true; 192 193 affectedRows = s.executeUpdate(); 195 196 if (affectedRows < updateStatement.minAffectedRows) { 199 updateDesc.setVerificationFailed(); 201 202 rollbackXact(tran); 203 throwJDOConcurrentAccessException(sqlText); 204 } 205 } catch (SQLException e) { 206 if (preparationSuccessful) { 210 updateDesc.setVerificationFailed(); 211 } 212 213 rollbackXact(tran); 214 throwJDOSqlException(e, updateStatement.getFormattedSQLText()); 215 } finally { 216 close(s); 217 closeConnection(tran, conn); 218 } 219 } 220 221 if (debug) { 222 logger.fine("sqlstore.sqlstoremanager.executeupdate.exit", new Integer (affectedRows)); 224 } 225 } 226 227 230 public Class getClassByOidClass(Class oidType) { 231 return configCache.getClassByOidClass(oidType); 232 } 233 234 237 public StateManager getStateManager(Class classType) { 238 ClassDesc c = (ClassDesc) getPersistenceConfig(classType); 239 240 if (c != null) { 241 return c.newStateManagerInstance(this); 242 } 243 244 return null; 245 } 246 247 253 public RetrieveDesc getRetrieveDesc(Class classType) { 254 return new RetrieveDescImpl(classType, (ClassDesc) getPersistenceConfig(classType)); 255 } 256 257 266 public RetrieveDesc getRetrieveDesc(String fieldName, Class classType) { 267 ClassDesc c = (ClassDesc) getPersistenceConfig(classType); 268 269 if (c != null) { 270 FieldDesc f = c.getField(fieldName); 271 272 if (f instanceof ForeignFieldDesc) { 273 ForeignFieldDesc ff = (ForeignFieldDesc) f; 274 return getRetrieveDesc(ff.foreignConfig.getPersistenceCapableClass()); 275 } 276 } 277 278 return null; 279 } 280 281 283 public UpdateObjectDesc getUpdateObjectDesc(Class classType) { 284 return new UpdateObjectDescImpl(classType); 285 } 286 287 293 public SQLStoreManager(DatabaseMetaData databaseMetaData, 294 String identifier) { 295 super(); 296 configCache = new ConfigCacheImpl(); 297 setVendorType(databaseMetaData, identifier); 298 } 299 300 306 private void setVendorType(DatabaseMetaData databaseMetaData, 307 String identifier) { 308 try { 309 vendorType = new DBVendorType(databaseMetaData, identifier); 310 311 if (logger.isLoggable()) { 312 logger.fine("sqlstore.sqlstoremanager.vendortype",vendorType.getName()); 314 } 315 316 } catch (Exception e) { 317 if (e instanceof JDOException) { 318 throw (JDOException) e; 319 } else { 320 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 321 "core.configuration.getvendortypefailed"), e); } 323 } 324 } 325 326 public DBVendorType getVendorType() { 327 return vendorType; 328 } 329 330 341 public Object retrieve(PersistenceManager pm, RetrieveDesc action, ValueFetcher parameters) { 342 343 if (action == null) { 344 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 345 "core.generic.nullparam", "action")); } 347 348 if (!(action instanceof RetrieveDescImpl)) { 349 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 350 "core.generic.notinstanceof", action.getClass().getName(), 352 "RetrieveDescImpl")); } 354 355 RetrieveDescImpl retrieveAction = ((RetrieveDescImpl) action); 356 ClassDesc config = retrieveAction.getConfig(); 357 Concurrency concurrency = config.getConcurrency(pm.isOptimisticTransaction()); 358 SelectQueryPlan plan = retrieveAction.buildQueryPlan(this, concurrency); 359 ArrayList statements = plan.getStatements(); 360 Object result = null; 361 362 SelectStatement s = (SelectStatement) statements.get(0); 363 result = executeQuery(pm, s, concurrency, parameters); 364 365 if ((plan.options & RetrieveDescImpl.OPT_AGGREGATE) == 0) { 366 368 if ((plan.options & RetrieveDescImpl.OPT_DISTINCT) > 0) { 369 371 if (((plan.options & RetrieveDescImpl.OPT_FOR_UPDATE) > 0 && 372 !vendorType.isDistinctSupportedWithUpdateLock()) ) { 373 374 HashSet hash = new HashSet(); 375 for (Iterator iter = ((Collection)result).iterator(); iter.hasNext(); ) { 376 Object temp = iter.next(); 377 if (!hash.contains(temp)) { 378 hash.add(temp); 379 } else { 380 iter.remove(); 381 } 382 } 383 } 384 } 385 } 386 387 return result; 388 } 389 390 404 private Object executeQuery(PersistenceManager pm, 405 SelectStatement statement, 406 Concurrency concurrency, 407 ValueFetcher parameters) { 408 409 Object result = null; 410 boolean debug = logger.isLoggable(); 411 if (debug) { 412 logger.fine("sqlstore.sqlstoremanager.executeQuery"); } 414 415 String sqlText = statement.getText(); 416 if (sqlText.length() > 0) { 417 if (sqlLogger.isLoggable()) { 418 sqlLogger.fine(statement.getFormattedSQLText(parameters)); 419 } 420 421 Transaction tran = null; 422 if (concurrency != null) { 423 tran = concurrency.suspend(); 426 } 427 428 if (tran == null) { 429 tran = (Transaction) pm.currentTransaction(); 430 } 431 432 ResultSet resultData = null; 433 DBStatement s = null; 434 Connection conn = tran.getConnection(); 435 try { 436 s = new DBStatement(conn, sqlText, tran.getQueryTimeout()); 438 439 statement.bindInputValues(s, parameters); 441 442 if (fetchSize > -1) { 447 s.getPreparedStatement().setFetchSize(fetchSize); 448 } 449 450 if (statement.isColumnTypeDefinitionNeeded()) { 451 vendorType.getSpecialDBOperation().defineColumnTypeForResult( 452 s.getPreparedStatement(), statement.getColumnRefs()); 453 } 454 455 resultData = s.executeQuery(); 456 457 if (concurrency != null) { 458 concurrency.resume(tran); 461 } 462 463 SelectQueryPlan plan = (SelectQueryPlan) statement.getQueryPlan(); 464 result = plan.getResult(pm, resultData); 465 } catch (SQLException e) { 466 throwJDOSqlException(e, statement.getFormattedSQLText(parameters)); 467 } finally { 468 close(resultData); 469 close(s); 470 closeConnection(tran, conn); 471 } 472 } 473 474 if (debug) { 475 logger.fine("sqlstore.sqlstoremanager.executeQuery.exit"); } 477 478 return result; 479 } 480 481 485 492 public void executeBatch(PersistenceManager pm, 493 UpdateObjectDesc request, 494 boolean forceFlush) 495 { 496 boolean cleanup = true; 497 UpdateObjectDescImpl objectRequest = null; 498 499 if (request instanceof UpdateObjectDescImpl) { 500 objectRequest = (UpdateObjectDescImpl) request; 501 } else { 502 throw new JDOFatalInternalException(I18NHelper.getMessage(messages, 503 "core.generic.notinstanceof", request.getClass().getName(), 505 "UpdateObjectDescImpl")); } 507 508 ClassDesc config = objectRequest.getConfig(); 509 UpdateQueryPlan plan = config.getUpdateQueryPlan(objectRequest, this); 510 Transaction tran = (Transaction) pm.currentTransaction(); 511 Connection conn = tran.getConnection(); 512 513 boolean doFlush = forceFlush || plan.checkBatchThreshold(tran); 519 520 try { 521 for (int i = 0, size = plan.statements.size(); i < size; i++) { 522 UpdateStatement s = (UpdateStatement) plan.statements.get(i); 523 executeUpdateBatch(tran, conn, s, objectRequest, doFlush); 524 } 525 526 cleanup = forceFlush; 535 } finally { 536 if (cleanup) 537 closeDBStatements(plan, tran); 538 closeConnection(tran, conn); 539 } 540 } 541 542 551 private void executeUpdateBatch(Transaction tran, 552 Connection conn, 553 UpdateStatement updateStatement, 554 UpdateObjectDescImpl updateDesc, 555 boolean doFlush) 556 { 557 int[] affectedRows = null; 558 boolean debug = logger.isLoggable(); 559 560 if (debug) { 561 logger.fine("sqlstore.sqlstoremanager.executeupdatebatch"); } 563 564 String sqlText = updateStatement.getText(); 565 if (sqlText.length() > 0) { 566 if (sqlLogger.isLoggable()) { 567 String formattedText = updateStatement.getFormattedSQLText(updateDesc); 568 if (doFlush) { 569 sqlLogger.fine("sqlstore.sqlstoremanager.executeupdatebatch.flushbatch", formattedText); 570 } else { 571 sqlLogger.fine("sqlstore.sqlstoremanager.executeupdatebatch.addbatch", formattedText); 572 } 573 } 574 575 DBStatement s = null; 576 577 try { 578 s = updateStatement.getDBStatement(tran, conn); 580 updateStatement.bindInputColumns(s, updateDesc); 581 s.addBatch(); 582 583 if (doFlush) { 584 affectedRows = s.executeBatch(); 586 587 for (int i = 0; i < affectedRows.length; i++) { 589 if (affectedRows[i] < updateStatement.minAffectedRows && 592 affectedRows[i] != java.sql.Statement.SUCCESS_NO_INFO) { 593 594 rollbackXact(tran); 595 throwJDOConcurrentAccessException(sqlText); 596 } 597 } 598 } 599 } catch (SQLException e) { 600 rollbackXact(tran); 601 throwJDOSqlException(e, sqlText); 602 } 603 } 604 605 if (debug) { 606 if (doFlush) { 607 logger.fine("sqlstore.sqlstoremanager.executeupdatebatch.exit.flush", '[' + StringHelper.intArrayToSeparatedList(affectedRows, ",") + ']'); } else { 610 logger.fine("sqlstore.sqlstoremanager.executeupdatebatch.exit"); } 612 } 613 } 614 615 619 627 static private void throwJDOSqlException(SQLException e, String sqlText) { 628 629 String exceptionMessage = I18NHelper.getMessage(messages, 630 "core.persistencestore.jdbcerror", sqlText); 632 throw new JDODataStoreException(exceptionMessage, e); 633 } 634 635 641 static private void throwJDOConcurrentAccessException(String sqlText) { 642 String operation = sqlText.substring(0, sqlText.indexOf(' ')); 644 throw new JDODataStoreException(I18NHelper.getMessage(messages, 645 "core.store.concurrentaccess", operation)); } 647 648 652 static private void close(ResultSet r) { 653 if (r != null) { 654 try { 655 r.close(); 656 } catch (SQLException ex) { 657 logger.finest(I18NHelper.getMessage(messages, 659 "sqlstore.sqlstoremanager.errorcloseresultset", ex.getLocalizedMessage())); 661 } 662 } 663 } 664 665 669 static private void close(DBStatement s) { 670 if (s != null) { 671 try { 672 s.close(); 673 } catch (SQLException ex) { 674 logger.finest(I18NHelper.getMessage(messages, 676 "sqlstore.sqlstoremanager.errorclosestatement", ex.getLocalizedMessage())); 678 } 679 } 680 } 681 682 686 static private void closeConnection(Transaction t, Connection c) { 687 if (t != null && c != null) { 688 t.releaseConnection(); 689 } 690 } 691 692 696 static private void closeDBStatements(UpdateQueryPlan plan, Transaction tran) { 697 if ((plan != null) && (tran != null)) { 698 for (Iterator i = plan.getStatements().iterator(); i.hasNext(); ) { 699 UpdateStatement updateStmt = (UpdateStatement)i.next(); 700 DBStatement s = updateStmt.removeDBStatement(tran); 701 close(s); 702 } 703 } 704 } 705 706 } 707 | Popular Tags |