/* * * Copyright (c) 2013 - 2017 Lijun Liao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT * OF THIRD PARTY RIGHTS. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the XiPKI software without * disclosing the source code of your own applications. * * For more information, please contact Lijun Liao at this * address: lijun.liao@gmail.com */ package org.xipki.commons.datasource.internal; import java.util.Collections; import java.util.HashSet; import java.util.Set; import org.xipki.commons.common.util.ParamUtil; import org.xipki.commons.datasource.DatabaseType; /** * JDBC state codes for a particular database. It is the first two digits (the SQL state "class"). * * @author Lijun Liao * @since 2.0.0 */ public class SqlStateCodes { private static class DB2 extends SqlStateCodes { DB2() { super(); // 57: out-of-memory exception / database not started // 58: unexpected system error dataAccessResourceFailureCodes = addToSet(dataAccessResourceFailureCodes, "57", "58"); // 51: communication failure transientDataAccessResourceCodes = addToSet(transientDataAccessResourceCodes, "51"); } } // class DB2 private static class H2 extends SqlStateCodes { H2() { super(); } } // class H2 // CHECKSTYLE:SKIP private static class HSQL extends SqlStateCodes { HSQL() { super(); } } // class HSQL // CHECKSTYLE:SKIP private static class MySQL extends SqlStateCodes { MySQL() { super(); } } // CHECKSTYLE:SKIP private static class MariaDB extends MySQL { MariaDB() { super(); } } private static class Oracle extends SqlStateCodes { Oracle() { super(); // 65: unknown identifier badSqlGrammarCodes = addToSet(badSqlGrammarCodes, "65"); // 61: deadlock concurrencyFailureCodes = addToSet(concurrencyFailureCodes, "61"); } } // class Oracle // CHECKSTYLE:SKIP private static class PostgreSQL extends SqlStateCodes { PostgreSQL() { super(); // 53: insufficient resources (e.g. disk full) // 54: program limit exceeded (e.g. statement too complex) dataAccessResourceFailureCodes = addToSet(dataAccessResourceFailureCodes, "53", "54"); } } // class PostgreSQL // bad grammar error private static final String BGE_DYNAMIC_SQL_ERROR = "07"; private static final String BGE_CARDINALITY_VIOLATION = "21"; private static final String BGE_SYNTAX_ERROR_DIRECT_SQL = "2A"; private static final String BGE_SYNTAX_ERROR_DYNAMIC_SQL = "37"; private static final String BGE_GENERAL_SQL_SYNTAX_ERROR = "42"; // data integrity violation private static final String DIV_DATA_TRUNCATION = "01"; private static final String DIV_NO_DATA_FOUND = "02"; private static final String DIV_VALUE_OUTOF_RANGE = "22"; private static final String DIV_INTEGRITY_CONSTRAINT_VIOLATION = "23"; private static final String DIV_TRIGGERED_DATA_CHANGE_VIOLATION = "27"; private static final String DIV_WITH_CHECK_VIOLATION = "44"; // data access resource failure private static final String DRF_CONNECTION_EXCEPTION = "08"; // transient data access resource private static final String TDR_COMMUNICATION_FAILURE = "S1"; // concurrency failure private static final String CF_TRANSACTION_ROLLBACK = "40"; protected Set<String> badSqlGrammarCodes; protected Set<String> dataIntegrityViolationCodes; protected Set<String> dataAccessResourceFailureCodes; protected Set<String> transientDataAccessResourceCodes; protected Set<String> concurrencyFailureCodes; private SqlStateCodes() { badSqlGrammarCodes = toSet(BGE_DYNAMIC_SQL_ERROR, BGE_CARDINALITY_VIOLATION, BGE_SYNTAX_ERROR_DIRECT_SQL, BGE_SYNTAX_ERROR_DYNAMIC_SQL, BGE_GENERAL_SQL_SYNTAX_ERROR); dataIntegrityViolationCodes = toSet(DIV_DATA_TRUNCATION, DIV_INTEGRITY_CONSTRAINT_VIOLATION, DIV_NO_DATA_FOUND, DIV_TRIGGERED_DATA_CHANGE_VIOLATION, DIV_VALUE_OUTOF_RANGE, DIV_WITH_CHECK_VIOLATION); dataAccessResourceFailureCodes = toSet(DRF_CONNECTION_EXCEPTION); transientDataAccessResourceCodes = toSet(TDR_COMMUNICATION_FAILURE); concurrencyFailureCodes = toSet(CF_TRANSACTION_ROLLBACK); } public Set<String> getBadSqlGrammarCodes() { return badSqlGrammarCodes; } public Set<String> getDataIntegrityViolationCodes() { return dataIntegrityViolationCodes; } public Set<String> getDataAccessResourceFailureCodes() { return dataAccessResourceFailureCodes; } public Set<String> getTransientDataAccessResourceCodes() { return transientDataAccessResourceCodes; } public Set<String> getConcurrencyFailureCodes() { return concurrencyFailureCodes; } public static SqlStateCodes newInstance(DatabaseType dbType) { ParamUtil.requireNonNull("dbType", dbType); switch (dbType) { case DB2: return new DB2(); case H2: return new H2(); case HSQL: return new HSQL(); case MYSQL: return new MySQL(); case MARIADB: return new MariaDB(); case ORACLE: return new Oracle(); case POSTGRES: return new PostgreSQL(); case UNKNOWN: return new SqlStateCodes(); default: throw new RuntimeException("should not reach here, unknown database type " + dbType); } } private static Set<String> toSet(final String... strs) { if (strs == null || strs.length == 0) { return Collections.emptySet(); } Set<String> set = new HashSet<String>(); for (String str : strs) { set.add(str); } return Collections.unmodifiableSet(set); } private static Set<String> addToSet(final Set<String> baseSet, final String... strs) { if (strs == null || strs.length == 0) { return baseSet; } Set<String> newSet = new HashSet<String>(baseSet.size() + strs.length); newSet.addAll(baseSet); for (String str : strs) { newSet.add(str); } return Collections.unmodifiableSet(newSet); } }