/* * Copyright 2018-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dev.miku.r2dbc.mysql; import dev.miku.r2dbc.mysql.message.server.ErrorMessage; import io.r2dbc.spi.R2dbcBadGrammarException; import io.r2dbc.spi.R2dbcDataIntegrityViolationException; import io.r2dbc.spi.R2dbcException; import io.r2dbc.spi.R2dbcNonTransientResourceException; import io.r2dbc.spi.R2dbcPermissionDeniedException; import io.r2dbc.spi.R2dbcRollbackException; import io.r2dbc.spi.R2dbcTimeoutException; import io.r2dbc.spi.R2dbcTransientResourceException; import reactor.util.annotation.Nullable; import static dev.miku.r2dbc.mysql.util.AssertUtils.requireNonNull; /** * A factory for generate {@link R2dbcException}s. */ final class ExceptionFactory { private static final String CONSTRAINT_VIOLATION_PREFIX = "23"; private static final String TRANSACTION_ROLLBACK_PREFIX = "40"; private static final String SYNTAX_ERROR_PREFIX = "42"; static R2dbcException createException(ErrorMessage message, @Nullable String sql) { requireNonNull(message, "error message must not be null"); int errorCode = message.getErrorCode(); String sqlState = message.getSqlState(); String errorMessage = message.getErrorMessage(); // Should keep looking more error codes switch (errorCode) { case 1044: // Database access denied case 1045: // Wrong password case 1095: // Kill thread denied case 1142: // Table access denied case 1143: // Column access denied case 1227: // Operation has no privilege(s) case 1370: // Routine or process access denied case 1698: // User need password but has no password case 1873: // Change user denied return new R2dbcPermissionDeniedException(errorMessage, sqlState, errorCode); case 1159: // Read interrupted, reading basic packet timeout because of network jitter in most cases case 1161: // Write interrupted, writing basic packet timeout because of network jitter in most cases case 1213: // Dead lock :-( no one wants this case 1317: // Statement execution interrupted return new R2dbcTransientResourceException(errorMessage, sqlState, errorCode); case 1205: // Wait lock timeout case 1907: // Statement executing timeout return new R2dbcTimeoutException(errorMessage, sqlState, errorCode); case 1613: // Transaction rollback because of took too long return new R2dbcRollbackException(errorMessage, sqlState, errorCode); case 1050: // Table already exists case 1051: // Unknown table case 1054: // Unknown column name in existing table case 1064: // Bad syntax case 1247: // Unsupported reference case 1146: // Unknown table name case 1304: // Something already exists, like savepoint case 1305: // Something does not exists, like savepoint case 1630: // Function not exists return new R2dbcBadGrammarException(errorMessage, sqlState, errorCode, sql); case 1022: // Duplicate key case 1048: // Field cannot be null case 1062: // Duplicate entry for key constraint case 1169: // Violation of an unique constraint case 1215: // Add a foreign key has a violation case 1216: // Child row has a violation of foreign key constraint when inserting or updating case 1217: // Parent row has a violation of foreign key constraint when deleting or updating case 1364: // Field has no default value but user try set it to DEFAULT case 1451: // Parent row has a violation of foreign key constraint when deleting or updating case 1452: // Child row has a violation of foreign key constraint when inserting or updating case 1557: // Conflicting foreign key constraints and unique constraints case 1859: // Duplicate unknown entry for key constraint return new R2dbcDataIntegrityViolationException(errorMessage, sqlState, errorCode); } if (sqlState == null) { // Has no SQL state, all exceptions mismatch, fallback. return new R2dbcNonTransientResourceException(errorMessage, null, errorCode); } return mappingSqlState(errorMessage, sqlState, errorCode, sql); } private static R2dbcException mappingSqlState(String errorMessage, String sqlState, int errorCode, @Nullable String sql) { if (sqlState.startsWith(SYNTAX_ERROR_PREFIX)) { return new R2dbcBadGrammarException(errorMessage, sqlState, errorCode, sql); } else if (sqlState.startsWith(CONSTRAINT_VIOLATION_PREFIX)) { return new R2dbcDataIntegrityViolationException(errorMessage, sqlState, errorCode); } else if (sqlState.startsWith(TRANSACTION_ROLLBACK_PREFIX)) { return new R2dbcRollbackException(errorMessage, sqlState, errorCode); } // Uncertain SQL state, all exceptions mismatch, fallback. return new R2dbcNonTransientResourceException(errorMessage, null, errorCode); } }