Skip to content

Commit 5f51a10

Browse files
committed
Implements generic error types based on the SQL state.
1 parent 934821c commit 5f51a10

File tree

3 files changed

+164
-8
lines changed

3 files changed

+164
-8
lines changed

database-commons/src/main/java/io/cdap/plugin/db/DBErrorDetailsProvider.java

Lines changed: 162 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,138 @@
2727
import io.cdap.cdap.etl.api.exception.ErrorDetailsProvider;
2828

2929
import java.sql.SQLException;
30+
import java.util.HashMap;
3031
import java.util.List;
32+
import java.util.Map;
3133

3234
/**
3335
* A custom ErrorDetailsProvider for Database plugins.
3436
*/
3537
public class DBErrorDetailsProvider implements ErrorDetailsProvider {
3638

39+
private static final Map<String, ErrorType> ERROR_CODE_TO_ERROR_TYPE;
40+
private static final Map<String, ErrorCategory> ERROR_CODE_TO_ERROR_CATEGORY;
41+
42+
static {
43+
// https://en.wikipedia.org/wiki/SQLSTATE
44+
ERROR_CODE_TO_ERROR_TYPE = new HashMap<>();
45+
ERROR_CODE_TO_ERROR_TYPE.put("01", ErrorType.USER);
46+
ERROR_CODE_TO_ERROR_TYPE.put("02", ErrorType.USER);
47+
ERROR_CODE_TO_ERROR_TYPE.put("07", ErrorType.USER);
48+
ERROR_CODE_TO_ERROR_TYPE.put("08", ErrorType.SYSTEM);
49+
ERROR_CODE_TO_ERROR_TYPE.put("09", ErrorType.USER);
50+
ERROR_CODE_TO_ERROR_TYPE.put("0A", ErrorType.SYSTEM);
51+
ERROR_CODE_TO_ERROR_TYPE.put("0D", ErrorType.USER);
52+
ERROR_CODE_TO_ERROR_TYPE.put("0E", ErrorType.USER);
53+
ERROR_CODE_TO_ERROR_TYPE.put("0F", ErrorType.USER);
54+
ERROR_CODE_TO_ERROR_TYPE.put("0K", ErrorType.USER);
55+
ERROR_CODE_TO_ERROR_TYPE.put("0L", ErrorType.USER);
56+
ERROR_CODE_TO_ERROR_TYPE.put("0M", ErrorType.USER);
57+
ERROR_CODE_TO_ERROR_TYPE.put("0N", ErrorType.USER);
58+
ERROR_CODE_TO_ERROR_TYPE.put("0P", ErrorType.USER);
59+
ERROR_CODE_TO_ERROR_TYPE.put("0S", ErrorType.USER);
60+
ERROR_CODE_TO_ERROR_TYPE.put("0T", ErrorType.USER);
61+
ERROR_CODE_TO_ERROR_TYPE.put("0U", ErrorType.USER);
62+
ERROR_CODE_TO_ERROR_TYPE.put("0V", ErrorType.USER);
63+
ERROR_CODE_TO_ERROR_TYPE.put("0W", ErrorType.USER);
64+
ERROR_CODE_TO_ERROR_TYPE.put("0X", ErrorType.USER);
65+
ERROR_CODE_TO_ERROR_TYPE.put("0Y", ErrorType.USER);
66+
ERROR_CODE_TO_ERROR_TYPE.put("0Z", ErrorType.SYSTEM);
67+
ERROR_CODE_TO_ERROR_TYPE.put("10", ErrorType.USER);
68+
ERROR_CODE_TO_ERROR_TYPE.put("20", ErrorType.USER);
69+
ERROR_CODE_TO_ERROR_TYPE.put("21", ErrorType.USER);
70+
ERROR_CODE_TO_ERROR_TYPE.put("22", ErrorType.USER);
71+
ERROR_CODE_TO_ERROR_TYPE.put("23", ErrorType.USER);
72+
ERROR_CODE_TO_ERROR_TYPE.put("24", ErrorType.USER);
73+
ERROR_CODE_TO_ERROR_TYPE.put("25", ErrorType.SYSTEM);
74+
ERROR_CODE_TO_ERROR_TYPE.put("26", ErrorType.USER);
75+
ERROR_CODE_TO_ERROR_TYPE.put("27", ErrorType.SYSTEM);
76+
ERROR_CODE_TO_ERROR_TYPE.put("28", ErrorType.USER);
77+
ERROR_CODE_TO_ERROR_TYPE.put("2B", ErrorType.USER);
78+
ERROR_CODE_TO_ERROR_TYPE.put("2C", ErrorType.USER);
79+
ERROR_CODE_TO_ERROR_TYPE.put("2D", ErrorType.USER);
80+
ERROR_CODE_TO_ERROR_TYPE.put("2E", ErrorType.USER);
81+
ERROR_CODE_TO_ERROR_TYPE.put("2F", ErrorType.SYSTEM);
82+
ERROR_CODE_TO_ERROR_TYPE.put("2H", ErrorType.USER);
83+
ERROR_CODE_TO_ERROR_TYPE.put("30", ErrorType.USER);
84+
ERROR_CODE_TO_ERROR_TYPE.put("33", ErrorType.USER);
85+
ERROR_CODE_TO_ERROR_TYPE.put("34", ErrorType.USER);
86+
ERROR_CODE_TO_ERROR_TYPE.put("35", ErrorType.USER);
87+
ERROR_CODE_TO_ERROR_TYPE.put("36", ErrorType.SYSTEM);
88+
ERROR_CODE_TO_ERROR_TYPE.put("38", ErrorType.SYSTEM);
89+
ERROR_CODE_TO_ERROR_TYPE.put("39", ErrorType.SYSTEM);
90+
ERROR_CODE_TO_ERROR_TYPE.put("3B", ErrorType.SYSTEM);
91+
ERROR_CODE_TO_ERROR_TYPE.put("3C", ErrorType.USER);
92+
ERROR_CODE_TO_ERROR_TYPE.put("3D", ErrorType.USER);
93+
ERROR_CODE_TO_ERROR_TYPE.put("3F", ErrorType.USER);
94+
ERROR_CODE_TO_ERROR_TYPE.put("40", ErrorType.SYSTEM);
95+
ERROR_CODE_TO_ERROR_TYPE.put("42", ErrorType.USER);
96+
ERROR_CODE_TO_ERROR_TYPE.put("44", ErrorType.USER);
97+
ERROR_CODE_TO_ERROR_TYPE.put("45", ErrorType.USER);
98+
ERROR_CODE_TO_ERROR_TYPE.put("46", ErrorType.SYSTEM);
99+
ERROR_CODE_TO_ERROR_TYPE.put("HW", ErrorType.SYSTEM);
100+
101+
ERROR_CODE_TO_ERROR_CATEGORY = new HashMap<>();
102+
ErrorCategory.ErrorCategoryEnum plugin = ErrorCategory.ErrorCategoryEnum.PLUGIN;
103+
ERROR_CODE_TO_ERROR_CATEGORY.put("01", new ErrorCategory(plugin, "DB Warning"));
104+
ERROR_CODE_TO_ERROR_CATEGORY.put("02", new ErrorCategory(plugin, "DB No Data"));
105+
ERROR_CODE_TO_ERROR_CATEGORY.put("07", new ErrorCategory(plugin, "DB Dynamic SQL error"));
106+
ERROR_CODE_TO_ERROR_CATEGORY.put("08", new ErrorCategory(plugin, "DB Connection Exception"));
107+
ERROR_CODE_TO_ERROR_CATEGORY.put("09", new ErrorCategory(plugin, "DB Triggered Action Exception"));
108+
ERROR_CODE_TO_ERROR_CATEGORY.put("0A", new ErrorCategory(plugin, "DB Feature Not Supported"));
109+
ERROR_CODE_TO_ERROR_CATEGORY.put("0D", new ErrorCategory(plugin, "DB Invalid Target Type Specification"));
110+
ERROR_CODE_TO_ERROR_CATEGORY.put("0E", new ErrorCategory(plugin, "DB Invalid Schema Name List Specification"));
111+
ERROR_CODE_TO_ERROR_CATEGORY.put("0F", new ErrorCategory(plugin, "DB Locator Exception"));
112+
ERROR_CODE_TO_ERROR_CATEGORY.put("0K", new ErrorCategory(plugin, "DB Resignal When Handler Not Active"));
113+
ERROR_CODE_TO_ERROR_CATEGORY.put("0L", new ErrorCategory(plugin, "DB Invalid Grantor"));
114+
ERROR_CODE_TO_ERROR_CATEGORY.put("0M", new ErrorCategory(plugin, "DB Invalid SQL-Invoked Procedure Reference"));
115+
ERROR_CODE_TO_ERROR_CATEGORY.put("0N", new ErrorCategory(plugin, "DB SQL/XML Mapping Error"));
116+
ERROR_CODE_TO_ERROR_CATEGORY.put("0P", new ErrorCategory(plugin, "DB Invalid Role Specification"));
117+
ERROR_CODE_TO_ERROR_CATEGORY.put("0S", new ErrorCategory(plugin, "DB Invalid Transform Group Name Specification"));
118+
ERROR_CODE_TO_ERROR_CATEGORY.put("0T",
119+
new ErrorCategory(plugin, "DB Target Table Disagrees With Cursor Specification"));
120+
ERROR_CODE_TO_ERROR_CATEGORY.put("0U", new ErrorCategory(plugin, "DB Attempt To Assign To Non-Updatable Column"));
121+
ERROR_CODE_TO_ERROR_CATEGORY.put("0V", new ErrorCategory(plugin, "DB Attempt To Assign To Ordering Column"));
122+
ERROR_CODE_TO_ERROR_CATEGORY.put("0W", new ErrorCategory(plugin, "DB Prohibited Statement Encountered"));
123+
ERROR_CODE_TO_ERROR_CATEGORY.put("0X", new ErrorCategory(plugin, "DB Invalid Foreign Server Specification"));
124+
ERROR_CODE_TO_ERROR_CATEGORY.put("0Y", new ErrorCategory(plugin, "DB Pass-Through Specific Condition"));
125+
ERROR_CODE_TO_ERROR_CATEGORY.put("0Z", new ErrorCategory(plugin, "DB Diagnostics Exception"));
126+
ERROR_CODE_TO_ERROR_CATEGORY.put("10", new ErrorCategory(plugin, "DB XQuery Error"));
127+
ERROR_CODE_TO_ERROR_CATEGORY.put("20", new ErrorCategory(plugin, "DB Case Not Found For Case Statement"));
128+
ERROR_CODE_TO_ERROR_CATEGORY.put("21", new ErrorCategory(plugin, "DB Cardinality Violation"));
129+
ERROR_CODE_TO_ERROR_CATEGORY.put("22", new ErrorCategory(plugin, "DB Data Exception"));
130+
ERROR_CODE_TO_ERROR_CATEGORY.put("23", new ErrorCategory(plugin, "DB Integrity Constraint Violation"));
131+
ERROR_CODE_TO_ERROR_CATEGORY.put("24", new ErrorCategory(plugin, "DB Invalid Cursor State"));
132+
ERROR_CODE_TO_ERROR_CATEGORY.put("25", new ErrorCategory(plugin, "DB Invalid Transaction State"));
133+
ERROR_CODE_TO_ERROR_CATEGORY.put("26", new ErrorCategory(plugin, "DB Invalid SQL Statement Name"));
134+
ERROR_CODE_TO_ERROR_CATEGORY.put("27", new ErrorCategory(plugin, "DB Triggered Data Change Violation"));
135+
ERROR_CODE_TO_ERROR_CATEGORY.put("28", new ErrorCategory(plugin, "DB Invalid Authorization Specification"));
136+
ERROR_CODE_TO_ERROR_CATEGORY.put("2B", new ErrorCategory(plugin, "DB Dependent Privilege Descriptors Still Exist"));
137+
ERROR_CODE_TO_ERROR_CATEGORY.put("2C", new ErrorCategory(plugin, "DB Invalid Character Set Name"));
138+
ERROR_CODE_TO_ERROR_CATEGORY.put("2D", new ErrorCategory(plugin, "DB Invalid Transaction Termination"));
139+
ERROR_CODE_TO_ERROR_CATEGORY.put("2E", new ErrorCategory(plugin, "DB Invalid Connection Name"));
140+
ERROR_CODE_TO_ERROR_CATEGORY.put("2F", new ErrorCategory(plugin, "DB SQL Routine Exception"));
141+
ERROR_CODE_TO_ERROR_CATEGORY.put("2H", new ErrorCategory(plugin, "DB Invalid Collation Name"));
142+
ERROR_CODE_TO_ERROR_CATEGORY.put("30", new ErrorCategory(plugin, "DB Invalid SQL Statement Identifier"));
143+
ERROR_CODE_TO_ERROR_CATEGORY.put("33", new ErrorCategory(plugin, "DB Invalid SQL Descriptor Name"));
144+
ERROR_CODE_TO_ERROR_CATEGORY.put("34", new ErrorCategory(plugin, "DB Invalid Cursor Name"));
145+
ERROR_CODE_TO_ERROR_CATEGORY.put("35", new ErrorCategory(plugin, "DB Invalid Condition Number"));
146+
ERROR_CODE_TO_ERROR_CATEGORY.put("36", new ErrorCategory(plugin, "DB Cursor Sensitivity Exception"));
147+
ERROR_CODE_TO_ERROR_CATEGORY.put("38", new ErrorCategory(plugin, "DB External Routine Exception"));
148+
ERROR_CODE_TO_ERROR_CATEGORY.put("39", new ErrorCategory(plugin, "DB External Routine Invocation Exception"));
149+
ERROR_CODE_TO_ERROR_CATEGORY.put("3B", new ErrorCategory(plugin, "DB Savepoint Exception"));
150+
ERROR_CODE_TO_ERROR_CATEGORY.put("3C", new ErrorCategory(plugin, "DB Ambiguous Cursor Name"));
151+
ERROR_CODE_TO_ERROR_CATEGORY.put("3D", new ErrorCategory(plugin, "DB Invalid Catalog Name"));
152+
ERROR_CODE_TO_ERROR_CATEGORY.put("3F", new ErrorCategory(plugin, "DB Invalid Schema Name"));
153+
ERROR_CODE_TO_ERROR_CATEGORY.put("40", new ErrorCategory(plugin, "DB Transaction Rollback"));
154+
ERROR_CODE_TO_ERROR_CATEGORY.put("42", new ErrorCategory(plugin, "DB Syntax Error or Access Rule Violation"));
155+
ERROR_CODE_TO_ERROR_CATEGORY.put("44", new ErrorCategory(plugin, "DB With Check Option Violation"));
156+
ERROR_CODE_TO_ERROR_CATEGORY.put("45", new ErrorCategory(plugin, "DB Unhandled User-Defined Exception"));
157+
ERROR_CODE_TO_ERROR_CATEGORY.put("46", new ErrorCategory(plugin, "DB JAVA DDL"));
158+
ERROR_CODE_TO_ERROR_CATEGORY.put("HW", new ErrorCategory(plugin, "DB Datalink Exception"));
159+
}
160+
161+
37162
public ProgramFailureException getExceptionDetails(Exception e, ErrorContext errorContext) {
38163
List<Throwable> causalChain = Throwables.getCausalChain(e);
39164
for (Throwable t : causalChain) {
@@ -70,15 +195,15 @@ private ProgramFailureException getProgramFailureException(SQLException e, Error
70195
errorContext.getPhase(), sqlState, errorCode, errorMessage);
71196
String externalDocumentationLink = getExternalDocumentationLink();
72197
if (!Strings.isNullOrEmpty(externalDocumentationLink)) {
73-
if (!errorMessageWithDetails.endsWith(".")) {
74-
errorMessageWithDetails = errorMessageWithDetails + ".";
198+
if (!errorMessage.endsWith(".")) {
199+
errorMessage = errorMessage + ".";
75200
}
76-
errorMessageWithDetails = String.format("%s For more details, see %s", errorMessageWithDetails,
201+
errorMessage = String.format("%s For more details, see %s", errorMessage,
77202
externalDocumentationLink);
78203
}
79204
return ErrorUtils.getProgramFailureException(Strings.isNullOrEmpty(sqlState) ?
80205
new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN) : getErrorCategoryFromSqlState(sqlState),
81-
errorMessage, errorMessageWithDetails, getErrorTypeFromErrorCode(errorCode, sqlState), true,
206+
errorMessage, errorMessageWithDetails, getErrorTypeFromErrorCodeAndSqlState(errorCode, sqlState), true,
82207
ErrorCodeType.SQLSTATE, sqlState, externalDocumentationLink, e);
83208
}
84209

@@ -121,11 +246,42 @@ protected String getExternalDocumentationLink() {
121246
return null;
122247
}
123248

124-
protected ErrorType getErrorTypeFromErrorCode(int errorCode, String sqlState) {
125-
return ErrorType.UNKNOWN;
249+
/**
250+
* Get the {@link ErrorType} for the given error code and SQL state.
251+
* Override this method to provide custom error types based on the error code and SQL state.
252+
*
253+
* @param errorCode The error code.
254+
* @param sqlState The SQL state.
255+
* @return The {@link ErrorType} for the given error code and SQL state.
256+
*/
257+
protected ErrorType getErrorTypeFromErrorCodeAndSqlState(int errorCode, String sqlState) {
258+
// Default implementation uses the SQL state to determine the error type.
259+
return getErrorTypeFromSqlState(sqlState);
126260
}
127261

262+
/**
263+
* Get the {@link ErrorCategory} for the given SQL state.
264+
* Implements generic error categories based on the SQL state.
265+
* See <a href="https://en.wikipedia.org/wiki/SQLSTATE">SQLSTATE</a> for more information.
266+
* Override this method to provide custom error categories based on the SQL state.
267+
*
268+
* @param sqlState The SQL state.
269+
* @return The {@link ErrorCategory} for the given SQL state.
270+
*/
128271
protected ErrorCategory getErrorCategoryFromSqlState(String sqlState) {
272+
if (!Strings.isNullOrEmpty(sqlState) && sqlState.length() >= 2 &&
273+
ERROR_CODE_TO_ERROR_CATEGORY.containsKey(sqlState.substring(0, 2))) {
274+
return ERROR_CODE_TO_ERROR_CATEGORY.get(sqlState.substring(0, 2));
275+
}
129276
return new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN);
130277
}
278+
279+
private ErrorType getErrorTypeFromSqlState(String sqlState) {
280+
if (!Strings.isNullOrEmpty(sqlState) && sqlState.length() >= 2 &&
281+
ERROR_CODE_TO_ERROR_TYPE.containsKey(sqlState.substring(0, 2))) {
282+
return ERROR_CODE_TO_ERROR_TYPE.get(sqlState.substring(0, 2));
283+
}
284+
return ErrorType.UNKNOWN;
285+
}
286+
131287
}

mysql-plugin/src/main/java/io/cdap/plugin/mysql/MysqlErrorDetailsProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ protected String getExternalDocumentationLink() {
3131
}
3232

3333
@Override
34-
protected ErrorType getErrorTypeFromErrorCode(int errorCode, String sqlState) {
34+
protected ErrorType getErrorTypeFromErrorCodeAndSqlState(int errorCode, String sqlState) {
3535
// https://dev.mysql.com/doc/refman/9.0/en/error-message-elements.html#error-code-ranges
3636
if (errorCode >= 1000 && errorCode <= 5999) {
3737
return ErrorType.USER;

postgresql-plugin/src/main/java/io/cdap/plugin/postgres/PostgresErrorDetailsProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ protected String getExternalDocumentationLink() {
7777
}
7878

7979
@Override
80-
protected ErrorType getErrorTypeFromErrorCode(int errorCode, String sqlState) {
80+
protected ErrorType getErrorTypeFromErrorCodeAndSqlState(int errorCode, String sqlState) {
8181
if (!Strings.isNullOrEmpty(sqlState) && sqlState.length() >= 2 &&
8282
ERROR_CODE_TO_ERROR_TYPE.containsKey(sqlState.substring(0, 2))) {
8383
return ERROR_CODE_TO_ERROR_TYPE.get(sqlState.substring(0, 2));

0 commit comments

Comments
 (0)