Skip to content

Commit cbd3417

Browse files
committed
Add MysqlErrorDetailsProvider
1 parent b4b3db2 commit cbd3417

File tree

2 files changed

+161
-0
lines changed

2 files changed

+161
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright © 2024 Cask Data, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package io.cdap.plugin.db;
18+
19+
import com.google.common.base.Throwables;
20+
import io.cdap.cdap.api.exception.ErrorCategory;
21+
import io.cdap.cdap.api.exception.ErrorType;
22+
import io.cdap.cdap.api.exception.ErrorUtils;
23+
import io.cdap.cdap.api.exception.ProgramFailureException;
24+
import io.cdap.cdap.etl.api.exception.ErrorContext;
25+
import io.cdap.cdap.etl.api.exception.ErrorDetailsProvider;
26+
27+
import java.sql.SQLException;
28+
import java.util.List;
29+
30+
/**
31+
* A custom ErrorDetailsProvider for Database plugins.
32+
*/
33+
public class DBErrorDetailsProvider implements ErrorDetailsProvider {
34+
35+
public ProgramFailureException getExceptionDetails(Exception e, ErrorContext errorContext) {
36+
List<Throwable> causalChain = Throwables.getCausalChain(e);
37+
for (Throwable t : causalChain) {
38+
if (t instanceof ProgramFailureException) {
39+
// if causal chain already has program failure exception, return null to avoid double wrap.
40+
return null;
41+
}
42+
if (t instanceof SQLException) {
43+
return getProgramFailureException((SQLException) t, errorContext);
44+
}
45+
if (t instanceof IllegalArgumentException) {
46+
return getProgramFailureException((IllegalArgumentException) t, errorContext);
47+
}
48+
if (t instanceof IllegalStateException) {
49+
return getProgramFailureException((IllegalStateException) t, errorContext);
50+
}
51+
52+
}
53+
return null;
54+
}
55+
56+
/**
57+
* Get a ProgramFailureException with the given error
58+
* information from {@link SQLException}.
59+
*
60+
* @param e The SQLException to get the error information from.
61+
* @return A ProgramFailureException with the given error information.
62+
*/
63+
private ProgramFailureException getProgramFailureException(SQLException e, ErrorContext errorContext) {
64+
String errorMessage = e.getMessage();
65+
String sqlState = e.getSQLState();
66+
int errorCode = e.getErrorCode();
67+
String errorMessageWithDetails = String.format(
68+
"Error occurred in the phase: '%s'. Error message: '%s'. Error code: '%s'. sqlState: '%s'",
69+
errorContext.getPhase(), errorMessage, errorCode, sqlState);
70+
return ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN),
71+
errorMessage, errorMessageWithDetails, getErrorTypeFromErrorCode(errorCode), false, e);
72+
}
73+
74+
/**
75+
* Get a ProgramFailureException with the given error
76+
* information from {@link IllegalArgumentException}.
77+
*
78+
* @param e The IllegalArgumentException to get the error information from.
79+
* @return A ProgramFailureException with the given error information.
80+
*/
81+
private ProgramFailureException getProgramFailureException(IllegalArgumentException e, ErrorContext errorContext) {
82+
String errorMessage = e.getMessage();
83+
String errorMessageFormat = "Error occurred in the phase: '%s'. Error message: %s";
84+
return ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN),
85+
errorMessage,
86+
String.format(errorMessageFormat, errorContext.getPhase(), errorMessage), ErrorType.USER, false, e);
87+
}
88+
89+
/**
90+
* Get a ProgramFailureException with the given error
91+
* information from {@link IllegalStateException}.
92+
*
93+
* @param e The IllegalStateException to get the error information from.
94+
* @return A ProgramFailureException with the given error information.
95+
*/
96+
private ProgramFailureException getProgramFailureException(IllegalStateException e, ErrorContext errorContext) {
97+
String errorMessage = e.getMessage();
98+
String errorMessageFormat = "Error occurred in the phase: '%s'. Error message: %s";
99+
return ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN),
100+
errorMessage,
101+
String.format(errorMessageFormat, errorContext.getPhase(), errorMessage), ErrorType.SYSTEM, false, e);
102+
103+
}
104+
105+
/**
106+
* Get the external documentation link for the client errors if available.
107+
*
108+
* @return The external documentation link as a {@link String}.
109+
*/
110+
protected String getExternalDocumentationLink() {
111+
return null;
112+
}
113+
114+
protected ErrorType getErrorTypeFromErrorCode(int errorCode) {
115+
return ErrorType.UNKNOWN;
116+
}
117+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright © 2024 Cask Data, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
17+
package io.cdap.plugin.mysql;
18+
19+
import io.cdap.cdap.api.exception.ErrorType;
20+
import io.cdap.plugin.db.DBErrorDetailsProvider;
21+
22+
/**
23+
* A custom ErrorDetailsProvider for MySQL plugins.
24+
*/
25+
public class MysqlErrorDetailsProvider extends DBErrorDetailsProvider {
26+
27+
@Override
28+
protected String getExternalDocumentationLink() {
29+
return "https://dev.mysql.com/doc/mysql-errors/9.0/en/";
30+
}
31+
32+
@Override
33+
protected ErrorType getErrorTypeFromErrorCode(int errorCode) {
34+
// https://dev.mysql.com/doc/refman/9.0/en/error-message-elements.html#error-code-ranges
35+
if (errorCode >= 1000 && errorCode <= 1999 || errorCode >= 2000 && errorCode <= 2999 ||
36+
errorCode >= 3000 && errorCode <= 4999 || errorCode >= 5000 && errorCode <= 5999) {
37+
return ErrorType.USER;
38+
} else if (errorCode >= 10000 && errorCode <= 49999 || errorCode >= 50000 && errorCode <= 51999) {
39+
return ErrorType.SYSTEM;
40+
} else {
41+
return ErrorType.UNKNOWN;
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)