Skip to content

Commit 5af79a6

Browse files
authored
Merge pull request #527 from cloudsufi/fem/postgresql
[PLUGIN-1830] Add PostgresErrorDetailsProvider
2 parents 0ef198a + 9b9d979 commit 5af79a6

File tree

8 files changed

+134
-9
lines changed

8 files changed

+134
-9
lines changed

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

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import io.cdap.cdap.api.exception.ProgramFailureException;
2626
import io.cdap.cdap.etl.api.exception.ErrorContext;
2727
import io.cdap.cdap.etl.api.exception.ErrorDetailsProvider;
28-
import io.cdap.plugin.util.DBUtils;
2928

3029
import java.sql.SQLException;
3130
import java.util.List;
@@ -67,8 +66,8 @@ private ProgramFailureException getProgramFailureException(SQLException e, Error
6766
String sqlState = e.getSQLState();
6867
int errorCode = e.getErrorCode();
6968
String errorMessageWithDetails = String.format(
70-
"Error occurred in the phase: '%s'. Error message: '%s'. Error code: '%s'. sqlState: '%s'",
71-
errorContext.getPhase(), errorMessage, errorCode, sqlState);
69+
"Error occurred in the phase: '%s' with sqlState: '%s', errorCode: '%s', errorMessage: %s",
70+
errorContext.getPhase(), sqlState, errorCode, errorMessage);
7271
String externalDocumentationLink = getExternalDocumentationLink();
7372
if (!Strings.isNullOrEmpty(externalDocumentationLink)) {
7473
if (!errorMessageWithDetails.endsWith(".")) {
@@ -77,9 +76,10 @@ private ProgramFailureException getProgramFailureException(SQLException e, Error
7776
errorMessageWithDetails = String.format("%s For more details, see %s", errorMessageWithDetails,
7877
externalDocumentationLink);
7978
}
80-
return ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN),
81-
errorMessage, errorMessageWithDetails, getErrorTypeFromErrorCode(errorCode), false, ErrorCodeType.SQLSTATE,
82-
sqlState, externalDocumentationLink, e);
79+
return ErrorUtils.getProgramFailureException(Strings.isNullOrEmpty(sqlState) ?
80+
new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN) : getErrorCategoryFromSqlState(sqlState),
81+
errorMessage, errorMessageWithDetails, getErrorTypeFromErrorCode(errorCode, sqlState), true,
82+
ErrorCodeType.SQLSTATE, sqlState, externalDocumentationLink, e);
8383
}
8484

8585
/**
@@ -121,7 +121,11 @@ protected String getExternalDocumentationLink() {
121121
return null;
122122
}
123123

124-
protected ErrorType getErrorTypeFromErrorCode(int errorCode) {
124+
protected ErrorType getErrorTypeFromErrorCode(int errorCode, String sqlState) {
125125
return ErrorType.UNKNOWN;
126126
}
127+
128+
protected ErrorCategory getErrorCategoryFromSqlState(String sqlState) {
129+
return new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN);
130+
}
127131
}

database-commons/src/main/java/io/cdap/plugin/util/DBUtils.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ public final class DBUtils {
6262
public static final Calendar PURE_GREGORIAN_CALENDAR = createPureGregorianCalender();
6363
public static final String MYSQL_SUPPORTED_DOC_URL = "https://dev.mysql.com/doc/mysql-errors/9.0/en/";
6464
public static final String CLOUDSQLMYSQL_SUPPORTED_DOC_URL = "https://cloud.google.com/sql/docs/mysql/error-messages";
65+
public static final String POSTGRES_SUPPORTED_DOC_URL =
66+
"https://www.postgresql.org/docs/current/errcodes-appendix.html";
6567

6668
// Java by default uses October 15, 1582 as a Gregorian cut over date.
6769
// Any timestamp created with time less than this cut over date is treated as Julian date.

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) {
34+
protected ErrorType getErrorTypeFromErrorCode(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/e2e-test/features/postgresql/source/PostgresqlRunTime.feature

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ Feature: PostgreSQL - Verify data transfer from PostgreSQL source to BigQuery si
147147
And Save and Deploy Pipeline
148148
And Run the Pipeline in Runtime
149149
And Wait till pipeline is in running state
150+
And Open and capture logs
150151
And Verify the pipeline status is "Failed"
152+
And Close the pipeline logs
151153
Then Open Pipeline logs and verify Log entries having below listed Level and Message:
152154
| Level | Message |
153155
| ERROR | errorLogsMessageInvalidBoundingQuery |

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,19 @@
1616

1717
package io.cdap.plugin.postgres;
1818

19+
import io.cdap.cdap.api.exception.ErrorCategory;
20+
import io.cdap.cdap.api.exception.ErrorType;
21+
import io.cdap.cdap.api.exception.ErrorUtils;
22+
1923
/**
2024
* Postgres constants.
2125
*/
2226
public final class PostgresConstants {
2327

2428
private PostgresConstants() {
25-
throw new AssertionError("Should not instantiate static utility class.");
29+
String errorMessage = "Should not instantiate static utility class.";
30+
throw ErrorUtils.getProgramFailureException(new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN),
31+
errorMessage, errorMessage, ErrorType.SYSTEM, false, new AssertionError(errorMessage));
2632
}
2733

2834
public static final String PLUGIN_NAME = "Postgres";
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
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.postgres;
18+
19+
import com.google.common.base.Strings;
20+
import io.cdap.cdap.api.exception.ErrorCategory;
21+
import io.cdap.cdap.api.exception.ErrorType;
22+
import io.cdap.plugin.db.DBErrorDetailsProvider;
23+
import io.cdap.plugin.util.DBUtils;
24+
25+
import java.util.HashMap;
26+
import java.util.Map;
27+
28+
/**
29+
* A custom ErrorDetailsProvider for Postgres plugins.
30+
*/
31+
public class PostgresErrorDetailsProvider extends DBErrorDetailsProvider {
32+
// https://www.postgresql.org/docs/current/errcodes-appendix.html
33+
private static final Map<String, ErrorType> ERROR_CODE_TO_ERROR_TYPE;
34+
private static final Map<String, ErrorCategory> ERROR_CODE_TO_ERROR_CATEGORY;
35+
static {
36+
ERROR_CODE_TO_ERROR_TYPE = new HashMap<>();
37+
ERROR_CODE_TO_ERROR_TYPE.put("01", ErrorType.USER);
38+
ERROR_CODE_TO_ERROR_TYPE.put("02", ErrorType.USER);
39+
ERROR_CODE_TO_ERROR_TYPE.put("08", ErrorType.SYSTEM);
40+
ERROR_CODE_TO_ERROR_TYPE.put("0A", ErrorType.USER);
41+
ERROR_CODE_TO_ERROR_TYPE.put("22", ErrorType.USER);
42+
ERROR_CODE_TO_ERROR_TYPE.put("23", ErrorType.USER);
43+
ERROR_CODE_TO_ERROR_TYPE.put("28", ErrorType.USER);
44+
ERROR_CODE_TO_ERROR_TYPE.put("40", ErrorType.SYSTEM);
45+
ERROR_CODE_TO_ERROR_TYPE.put("42", ErrorType.USER);
46+
ERROR_CODE_TO_ERROR_TYPE.put("53", ErrorType.SYSTEM);
47+
ERROR_CODE_TO_ERROR_TYPE.put("54", ErrorType.SYSTEM);
48+
ERROR_CODE_TO_ERROR_TYPE.put("55", ErrorType.USER);
49+
ERROR_CODE_TO_ERROR_TYPE.put("57", ErrorType.SYSTEM);
50+
ERROR_CODE_TO_ERROR_TYPE.put("58", ErrorType.SYSTEM);
51+
ERROR_CODE_TO_ERROR_TYPE.put("P0", ErrorType.SYSTEM);
52+
ERROR_CODE_TO_ERROR_TYPE.put("XX", ErrorType.SYSTEM);
53+
54+
ErrorCategory.ErrorCategoryEnum plugin = ErrorCategory.ErrorCategoryEnum.PLUGIN;
55+
ERROR_CODE_TO_ERROR_CATEGORY = new HashMap<>();
56+
ERROR_CODE_TO_ERROR_CATEGORY.put("01", new ErrorCategory(plugin, "Warning"));
57+
ERROR_CODE_TO_ERROR_CATEGORY.put("02", new ErrorCategory(plugin, "No Data"));
58+
ERROR_CODE_TO_ERROR_CATEGORY.put("08", new ErrorCategory(plugin, "Postgres Server Connection Exception"));
59+
ERROR_CODE_TO_ERROR_CATEGORY.put("0A", new ErrorCategory(plugin, "Postgres Server Feature Not Supported"));
60+
ERROR_CODE_TO_ERROR_CATEGORY.put("22", new ErrorCategory(plugin, "Postgres Server Data Exception"));
61+
ERROR_CODE_TO_ERROR_CATEGORY.put("23", new ErrorCategory(plugin, "Postgres Integrity Constraint Violation"));
62+
ERROR_CODE_TO_ERROR_CATEGORY.put("28", new ErrorCategory(plugin, "Postgres Invalid Authorization Specification"));
63+
ERROR_CODE_TO_ERROR_CATEGORY.put("40", new ErrorCategory(plugin, "Transaction Rollback"));
64+
ERROR_CODE_TO_ERROR_CATEGORY.put("42", new ErrorCategory(plugin, "Syntax Error or Access Rule Violation"));
65+
ERROR_CODE_TO_ERROR_CATEGORY.put("53", new ErrorCategory(plugin, "Postgres Server Insufficient Resources"));
66+
ERROR_CODE_TO_ERROR_CATEGORY.put("54", new ErrorCategory(plugin, "Postgres Program Limit Exceeded"));
67+
ERROR_CODE_TO_ERROR_CATEGORY.put("55", new ErrorCategory(plugin, "Object Not in Prerequisite State"));
68+
ERROR_CODE_TO_ERROR_CATEGORY.put("57", new ErrorCategory(plugin, "Operator Intervention"));
69+
ERROR_CODE_TO_ERROR_CATEGORY.put("58", new ErrorCategory(plugin, "Postgres Server System Error"));
70+
ERROR_CODE_TO_ERROR_CATEGORY.put("P0", new ErrorCategory(plugin, "PL/pgSQL Error"));
71+
ERROR_CODE_TO_ERROR_CATEGORY.put("XX", new ErrorCategory(plugin, "Postgres Server Internal Error"));
72+
}
73+
74+
@Override
75+
protected String getExternalDocumentationLink() {
76+
return DBUtils.POSTGRES_SUPPORTED_DOC_URL;
77+
}
78+
79+
@Override
80+
protected ErrorType getErrorTypeFromErrorCode(int errorCode, String sqlState) {
81+
if (!Strings.isNullOrEmpty(sqlState) && sqlState.length() >= 2 &&
82+
ERROR_CODE_TO_ERROR_TYPE.containsKey(sqlState.substring(0, 2))) {
83+
return ERROR_CODE_TO_ERROR_TYPE.get(sqlState.substring(0, 2));
84+
}
85+
return ErrorType.UNKNOWN;
86+
}
87+
88+
@Override
89+
protected ErrorCategory getErrorCategoryFromSqlState(String sqlState) {
90+
if (!Strings.isNullOrEmpty(sqlState) && sqlState.length() >= 2 &&
91+
ERROR_CODE_TO_ERROR_CATEGORY.containsKey(sqlState.substring(0, 2))) {
92+
return ERROR_CODE_TO_ERROR_CATEGORY.get(sqlState.substring(0, 2));
93+
}
94+
return new ErrorCategory(ErrorCategory.ErrorCategoryEnum.PLUGIN);
95+
}
96+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ protected LineageRecorder getLineageRecorder(BatchSinkContext context) {
116116
return new LineageRecorder(context, asset);
117117
}
118118

119+
@Override
120+
protected String getErrorDetailsProviderClassName() {
121+
return PostgresErrorDetailsProvider.class.getName();
122+
}
123+
119124
/**
120125
* PostgreSQL action configuration.
121126
*/

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,21 @@ protected SchemaReader getSchemaReader() {
6767
return new PostgresSchemaReader();
6868
}
6969

70+
@Override
71+
protected String getErrorDetailsProviderClassName() {
72+
return PostgresErrorDetailsProvider.class.getName();
73+
}
74+
7075
@Override
7176
protected Class<? extends DBWritable> getDBRecordType() {
7277
return PostgresDBRecord.class;
7378
}
7479

80+
@Override
81+
protected String getExternalDocumentationLink() {
82+
return DBUtils.POSTGRES_SUPPORTED_DOC_URL;
83+
}
84+
7585
@Override
7686
protected LineageRecorder getLineageRecorder(BatchSourceContext context) {
7787
String fqn = DBUtils.constructFQN("postgres",

0 commit comments

Comments
 (0)