001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jdbc.support;
018
019import org.springframework.lang.Nullable;
020import org.springframework.util.ReflectionUtils;
021import org.springframework.util.StringUtils;
022
023/**
024 * JavaBean for holding JDBC error codes for a particular database.
025 * Instances of this class are normally loaded through a bean factory.
026 *
027 * <p>Used by Spring's {@link SQLErrorCodeSQLExceptionTranslator}.
028 * The file "sql-error-codes.xml" in this package contains default
029 * {@code SQLErrorCodes} instances for various databases.
030 *
031 * @author Thomas Risberg
032 * @author Juergen Hoeller
033 * @see SQLErrorCodesFactory
034 * @see SQLErrorCodeSQLExceptionTranslator
035 */
036public class SQLErrorCodes {
037
038        @Nullable
039        private String[] databaseProductNames;
040
041        private boolean useSqlStateForTranslation = false;
042
043        private String[] badSqlGrammarCodes = new String[0];
044
045        private String[] invalidResultSetAccessCodes = new String[0];
046
047        private String[] duplicateKeyCodes = new String[0];
048
049        private String[] dataIntegrityViolationCodes = new String[0];
050
051        private String[] permissionDeniedCodes = new String[0];
052
053        private String[] dataAccessResourceFailureCodes = new String[0];
054
055        private String[] transientDataAccessResourceCodes = new String[0];
056
057        private String[] cannotAcquireLockCodes = new String[0];
058
059        private String[] deadlockLoserCodes = new String[0];
060
061        private String[] cannotSerializeTransactionCodes = new String[0];
062
063        @Nullable
064        private CustomSQLErrorCodesTranslation[] customTranslations;
065
066        @Nullable
067        private SQLExceptionTranslator customSqlExceptionTranslator;
068
069
070        /**
071         * Set this property if the database name contains spaces,
072         * in which case we can not use the bean name for lookup.
073         */
074        public void setDatabaseProductName(@Nullable String databaseProductName) {
075                this.databaseProductNames = new String[] {databaseProductName};
076        }
077
078        @Nullable
079        public String getDatabaseProductName() {
080                return (this.databaseProductNames != null && this.databaseProductNames.length > 0 ?
081                                this.databaseProductNames[0] : null);
082        }
083
084        /**
085         * Set this property to specify multiple database names that contains spaces,
086         * in which case we can not use bean names for lookup.
087         */
088        public void setDatabaseProductNames(@Nullable String... databaseProductNames) {
089                this.databaseProductNames = databaseProductNames;
090        }
091
092        @Nullable
093        public String[] getDatabaseProductNames() {
094                return this.databaseProductNames;
095        }
096
097        /**
098         * Set this property to true for databases that do not provide an error code
099         * but that do provide SQL State (this includes PostgreSQL).
100         */
101        public void setUseSqlStateForTranslation(boolean useStateCodeForTranslation) {
102                this.useSqlStateForTranslation = useStateCodeForTranslation;
103        }
104
105        public boolean isUseSqlStateForTranslation() {
106                return this.useSqlStateForTranslation;
107        }
108
109        public void setBadSqlGrammarCodes(String... badSqlGrammarCodes) {
110                this.badSqlGrammarCodes = StringUtils.sortStringArray(badSqlGrammarCodes);
111        }
112
113        public String[] getBadSqlGrammarCodes() {
114                return this.badSqlGrammarCodes;
115        }
116
117        public void setInvalidResultSetAccessCodes(String... invalidResultSetAccessCodes) {
118                this.invalidResultSetAccessCodes = StringUtils.sortStringArray(invalidResultSetAccessCodes);
119        }
120
121        public String[] getInvalidResultSetAccessCodes() {
122                return this.invalidResultSetAccessCodes;
123        }
124
125        public String[] getDuplicateKeyCodes() {
126                return this.duplicateKeyCodes;
127        }
128
129        public void setDuplicateKeyCodes(String... duplicateKeyCodes) {
130                this.duplicateKeyCodes = duplicateKeyCodes;
131        }
132
133        public void setDataIntegrityViolationCodes(String... dataIntegrityViolationCodes) {
134                this.dataIntegrityViolationCodes = StringUtils.sortStringArray(dataIntegrityViolationCodes);
135        }
136
137        public String[] getDataIntegrityViolationCodes() {
138                return this.dataIntegrityViolationCodes;
139        }
140
141        public void setPermissionDeniedCodes(String... permissionDeniedCodes) {
142                this.permissionDeniedCodes = StringUtils.sortStringArray(permissionDeniedCodes);
143        }
144
145        public String[] getPermissionDeniedCodes() {
146                return this.permissionDeniedCodes;
147        }
148
149        public void setDataAccessResourceFailureCodes(String... dataAccessResourceFailureCodes) {
150                this.dataAccessResourceFailureCodes = StringUtils.sortStringArray(dataAccessResourceFailureCodes);
151        }
152
153        public String[] getDataAccessResourceFailureCodes() {
154                return this.dataAccessResourceFailureCodes;
155        }
156
157        public void setTransientDataAccessResourceCodes(String... transientDataAccessResourceCodes) {
158                this.transientDataAccessResourceCodes = StringUtils.sortStringArray(transientDataAccessResourceCodes);
159        }
160
161        public String[] getTransientDataAccessResourceCodes() {
162                return this.transientDataAccessResourceCodes;
163        }
164
165        public void setCannotAcquireLockCodes(String... cannotAcquireLockCodes) {
166                this.cannotAcquireLockCodes = StringUtils.sortStringArray(cannotAcquireLockCodes);
167        }
168
169        public String[] getCannotAcquireLockCodes() {
170                return this.cannotAcquireLockCodes;
171        }
172
173        public void setDeadlockLoserCodes(String... deadlockLoserCodes) {
174                this.deadlockLoserCodes = StringUtils.sortStringArray(deadlockLoserCodes);
175        }
176
177        public String[] getDeadlockLoserCodes() {
178                return this.deadlockLoserCodes;
179        }
180
181        public void setCannotSerializeTransactionCodes(String... cannotSerializeTransactionCodes) {
182                this.cannotSerializeTransactionCodes = StringUtils.sortStringArray(cannotSerializeTransactionCodes);
183        }
184
185        public String[] getCannotSerializeTransactionCodes() {
186                return this.cannotSerializeTransactionCodes;
187        }
188
189        public void setCustomTranslations(CustomSQLErrorCodesTranslation... customTranslations) {
190                this.customTranslations = customTranslations;
191        }
192
193        @Nullable
194        public CustomSQLErrorCodesTranslation[] getCustomTranslations() {
195                return this.customTranslations;
196        }
197
198        public void setCustomSqlExceptionTranslatorClass(@Nullable Class<? extends SQLExceptionTranslator> customTranslatorClass) {
199                if (customTranslatorClass != null) {
200                        try {
201                                this.customSqlExceptionTranslator =
202                                                ReflectionUtils.accessibleConstructor(customTranslatorClass).newInstance();
203                        }
204                        catch (Throwable ex) {
205                                throw new IllegalStateException("Unable to instantiate custom translator", ex);
206                        }
207                }
208                else {
209                        this.customSqlExceptionTranslator = null;
210                }
211        }
212
213        public void setCustomSqlExceptionTranslator(@Nullable SQLExceptionTranslator customSqlExceptionTranslator) {
214                this.customSqlExceptionTranslator = customSqlExceptionTranslator;
215        }
216
217        @Nullable
218        public SQLExceptionTranslator getCustomSqlExceptionTranslator() {
219                return this.customSqlExceptionTranslator;
220        }
221
222}