001package io.ebean.config.dbplatform; 002 003import io.ebean.AcquireLockException; 004import io.ebean.DataIntegrityException; 005import io.ebean.DuplicateKeyException; 006import io.ebean.SerializableConflictException; 007 008import javax.persistence.PersistenceException; 009import java.sql.SQLException; 010import java.util.Collections; 011import java.util.Map; 012 013/** 014 * Translate SQLException based on SQLState codes. 015 */ 016public class SqlCodeTranslator implements SqlExceptionTranslator { 017 018 private final Map<String, DataErrorType> map; 019 020 /** 021 * Create given the map of SQLState codes to error types. 022 */ 023 public SqlCodeTranslator(Map<String, DataErrorType> map) { 024 this.map = map; 025 } 026 027 /** 028 * Create "No-op" implementation. 029 */ 030 public SqlCodeTranslator() { 031 this.map = Collections.emptyMap(); 032 } 033 034 private DataErrorType getErrorType(SQLException e) { 035 DataErrorType errorType = map.get(e.getSQLState()); 036 if (errorType == null) { 037 // fall back to error code 038 errorType = map.get(String.valueOf(e.getErrorCode())); 039 } 040 return errorType; 041 } 042 043 @Override 044 public PersistenceException translate(String message, SQLException e) { 045 046 DataErrorType errorType = getErrorType(e); 047 // for DB2 we must inspect the sql exception chain to determine which 048 // persistence error occurred in a batch execution. We also concatenate 049 // the error messages to improve error analysis. 050 SQLException chain = e.getNextException(); 051 if (chain != null) { 052 StringBuilder sb = new StringBuilder(message); 053 int i = 1; 054 while (chain != null && i < 100000) { // prevents from endless loop 055 sb.append("\n\t#").append(i++).append(": ").append(chain.getMessage()); 056 if (errorType == null) { 057 errorType = getErrorType(chain); 058 if (errorType != null) { 059 sb.append(" (causing error)"); // mark the line, where we found a matching error code 060 } 061 } 062 chain = chain.getNextException(); 063 } 064 message = sb.toString(); 065 } 066 067 if (errorType != null) { 068 switch (errorType) { 069 case AcquireLock: 070 return new AcquireLockException(message, e); 071 case DuplicateKey: 072 return new DuplicateKeyException(message, e); 073 case DataIntegrity: 074 return new DataIntegrityException(message, e); 075 case SerializableConflict: 076 return new SerializableConflictException(message, e); 077 } 078 } 079 // return a generic exception 080 return new PersistenceException(message, e); 081 } 082}