Skip to content

Commit 6cd6646

Browse files
feat: support more PostgreSQL error codes (GoogleCloudPlatform#4030)
* build(deps): bump com.google.cloud:libraries-bom from 26.72.0 to 26.73.0 Bumps [com.google.cloud:libraries-bom](https://github.com/googleapis/java-cloud-bom) from 26.72.0 to 26.73.0. - [Release notes](https://github.com/googleapis/java-cloud-bom/releases) - [Changelog](https://github.com/googleapis/java-cloud-bom/blob/main/release-please-config.json) - [Commits](googleapis/java-cloud-bom@v26.72.0...v26.73.0) --- updated-dependencies: - dependency-name: com.google.cloud:libraries-bom dependency-version: 26.73.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> * chore: use PostgreSQL error code Use the PostgreSQL error code that is supplied by Spanner to set the SQLState of a PGException. --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Knut Olav Løite <koloite@gmail.com>
1 parent d720921 commit 6cd6646

33 files changed

Lines changed: 173 additions & 69 deletions

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
<dependency>
8686
<groupId>com.google.cloud</groupId>
8787
<artifactId>libraries-bom</artifactId>
88-
<version>26.72.0</version>
88+
<version>26.73.0</version>
8989
<type>pom</type>
9090
<scope>import</scope>
9191
</dependency>

src/main/java/com/google/cloud/spanner/pgadapter/ConnectionHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,8 @@ public void registerAutoDescribedStatement(String sql, Future<DescribeResult> de
821821
public void closeStatement(String statementName) {
822822
if (!hasStatement(statementName)) {
823823
throw PGExceptionFactory.newPGException(
824-
"prepared statement " + statementName + " does not exist");
824+
"prepared statement " + statementName + " does not exist",
825+
SQLState.InvalidSqlStatementName);
825826
}
826827
this.statementsMap.remove(statementName);
827828
}

src/main/java/com/google/cloud/spanner/pgadapter/error/PGExceptionFactory.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.google.api.core.InternalApi;
2020
import com.google.cloud.spanner.ErrorCode;
2121
import com.google.cloud.spanner.SpannerException;
22+
import com.google.common.base.Strings;
2223
import io.grpc.StatusRuntimeException;
2324
import java.util.regex.Pattern;
2425

@@ -109,19 +110,22 @@ public static PGException toPGException(SpannerException spannerException) {
109110
.setSQLState(SQLState.SerializationFailure)
110111
.build();
111112
}
112-
if ((spannerException.getErrorCode() == ErrorCode.NOT_FOUND
113+
if (Strings.isNullOrEmpty(spannerException.getPostgreSQLErrorCode())
114+
&& (spannerException.getErrorCode() == ErrorCode.NOT_FOUND
113115
|| spannerException.getErrorCode() == ErrorCode.INVALID_ARGUMENT)
114116
&& COLUMN_NOT_FOUND_PATTERN.matcher(spannerException.getMessage()).find()) {
115117
return PGException.newBuilder(extractMessage(spannerException))
116118
.setSQLState(SQLState.UndefinedColumn)
117119
.build();
118-
} else if ((spannerException.getErrorCode() == ErrorCode.NOT_FOUND
120+
} else if (Strings.isNullOrEmpty(spannerException.getPostgreSQLErrorCode())
121+
&& (spannerException.getErrorCode() == ErrorCode.NOT_FOUND
119122
|| spannerException.getErrorCode() == ErrorCode.INVALID_ARGUMENT)
120123
&& RELATION_NOT_FOUND_PATTERN.matcher(spannerException.getMessage()).find()) {
121124
return PGException.newBuilder(extractMessage(spannerException))
122125
.setSQLState(SQLState.UndefinedTable)
123126
.build();
124-
} else if (spannerException.getErrorCode() == ErrorCode.ALREADY_EXISTS
127+
} else if (Strings.isNullOrEmpty(spannerException.getPostgreSQLErrorCode())
128+
&& spannerException.getErrorCode() == ErrorCode.ALREADY_EXISTS
125129
&& (PK_VIOLATION_PATTERN.matcher(spannerException.getMessage()).find()
126130
|| PK_VIOLATION_PATTERN_EMULATOR.matcher(spannerException.getMessage()).find()
127131
|| UNIQUE_INDEX_VIOLATION_PATTERN.matcher(spannerException.getMessage()).find()
@@ -131,7 +135,8 @@ public static PGException toPGException(SpannerException spannerException) {
131135
return PGException.newBuilder(extractMessage(spannerException))
132136
.setSQLState(SQLState.UniqueViolation)
133137
.build();
134-
} else if (spannerException.getErrorCode() == ErrorCode.FAILED_PRECONDITION
138+
} else if (Strings.isNullOrEmpty(spannerException.getPostgreSQLErrorCode())
139+
&& spannerException.getErrorCode() == ErrorCode.FAILED_PRECONDITION
135140
&& (FOREIGN_KEY_VIOLATION_PATTERN_EMULATOR.matcher(spannerException.getMessage()).find()
136141
|| FOREIGN_KEY_VIOLATION_PATTERN.matcher(spannerException.getMessage()).find())) {
137142
return PGException.newBuilder(extractMessage(spannerException))
@@ -156,7 +161,7 @@ public static PGException toPGException(SpannerException spannerException) {
156161
} else if (spannerException.getErrorCode() == ErrorCode.DEADLINE_EXCEEDED) {
157162
return newQueryCancelledDueToTimeoutException(spannerException);
158163
}
159-
return newPGException(extractMessage(spannerException));
164+
return newPGException(extractMessage(spannerException), getSQLStateOrDefault(spannerException));
160165
}
161166

162167
/** Converts the given {@link Exception} to a {@link PGException}. */
@@ -206,4 +211,9 @@ static String extractMessage(SpannerException spannerException) {
206211
}
207212
return result;
208213
}
214+
215+
static SQLState getSQLStateOrDefault(SpannerException spannerException) {
216+
SQLState state = SQLState.getSQLState(spannerException.getPostgreSQLErrorCode());
217+
return state == null ? SQLState.RaiseException : state;
218+
}
209219
}

src/main/java/com/google/cloud/spanner/pgadapter/error/SQLState.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414

1515
package com.google.cloud.spanner.pgadapter.error;
1616

17+
import com.google.cloud.spanner.AbstractLazyInitializer;
18+
import com.google.common.collect.ImmutableMap;
1719
import java.nio.charset.StandardCharsets;
20+
import java.util.Map;
21+
import javax.annotation.Nullable;
1822

1923
public enum SQLState {
2024
Success("00000"),
@@ -221,6 +225,30 @@ public enum SQLState {
221225
InvalidTableDefinition("42P16"),
222226
InvalidObjectDefinition("42P17");
223227

228+
private static final AbstractLazyInitializer<Map<String, SQLState>> SQL_STATES =
229+
new AbstractLazyInitializer<Map<String, SQLState>>() {
230+
@Override
231+
protected Map<String, SQLState> initialize() {
232+
ImmutableMap.Builder<String, SQLState> builder = ImmutableMap.builder();
233+
for (SQLState state : SQLState.values()) {
234+
builder.put(state.code, state);
235+
}
236+
return builder.build();
237+
}
238+
};
239+
240+
/** Returns the SQLState object with the given code, or null if no such SQLState is found. */
241+
public static @Nullable SQLState getSQLState(@Nullable String code) {
242+
if (code == null) {
243+
return null;
244+
}
245+
try {
246+
return SQL_STATES.get().get(code);
247+
} catch (Exception ignore) {
248+
return null;
249+
}
250+
}
251+
224252
private final String code;
225253

226254
SQLState(String code) {

src/main/java/com/google/cloud/spanner/pgadapter/parsers/BinaryParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.cloud.spanner.Value;
2323
import com.google.cloud.spanner.pgadapter.ProxyServer.DataFormat;
2424
import com.google.cloud.spanner.pgadapter.error.PGExceptionFactory;
25+
import com.google.cloud.spanner.pgadapter.error.SQLState;
2526
import com.google.cloud.spanner.pgadapter.session.SessionState;
2627
import com.google.common.collect.ImmutableMap;
2728
import com.google.common.io.CharSource;
@@ -57,7 +58,8 @@ public class BinaryParser extends Parser<ByteArray> {
5758
break;
5859
} catch (Exception exception) {
5960
throw PGExceptionFactory.newPGException(
60-
"Invalid binary value: " + new String(item, StandardCharsets.UTF_8));
61+
"Invalid binary value: " + new String(item, StandardCharsets.UTF_8),
62+
SQLState.SyntaxError);
6163
}
6264
case BINARY:
6365
this.item = toByteArray(item);

src/main/java/com/google/cloud/spanner/pgadapter/parsers/BooleanParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.cloud.spanner.Value;
2222
import com.google.cloud.spanner.pgadapter.ProxyServer.DataFormat;
2323
import com.google.cloud.spanner.pgadapter.error.PGExceptionFactory;
24+
import com.google.cloud.spanner.pgadapter.error.SQLState;
2425
import com.google.common.collect.ImmutableMap;
2526
import com.google.common.collect.ImmutableSet;
2627
import java.nio.charset.StandardCharsets;
@@ -94,7 +95,8 @@ public static boolean toBoolean(String value) {
9495
} else if (FALSE_VALUES.contains(value)) {
9596
return false;
9697
} else {
97-
throw PGExceptionFactory.newPGException(value + " is not a valid boolean value");
98+
throw PGExceptionFactory.newPGException(
99+
value + " is not a valid boolean value", SQLState.SyntaxError);
98100
}
99101
}
100102

src/main/java/com/google/cloud/spanner/pgadapter/parsers/DateParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.cloud.spanner.Value;
2424
import com.google.cloud.spanner.pgadapter.ProxyServer.DataFormat;
2525
import com.google.cloud.spanner.pgadapter.error.PGExceptionFactory;
26+
import com.google.cloud.spanner.pgadapter.error.SQLState;
2627
import com.google.cloud.spanner.pgadapter.session.SessionState;
2728
import com.google.common.collect.ImmutableMap;
2829
import java.io.DataOutputStream;
@@ -53,7 +54,8 @@ public class DateParser extends Parser<Date> {
5354
if (stringValue.length() >= 10) {
5455
this.item = Date.parseDate(stringValue.substring(0, 10));
5556
} else {
56-
throw PGExceptionFactory.newPGException("Invalid date value: " + stringValue);
57+
throw PGExceptionFactory.newPGException(
58+
"Invalid date value: " + stringValue, SQLState.SyntaxError);
5759
}
5860
break;
5961
case BINARY:

src/main/java/com/google/cloud/spanner/pgadapter/parsers/DoubleParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.cloud.spanner.Value;
2222
import com.google.cloud.spanner.pgadapter.ProxyServer.DataFormat;
2323
import com.google.cloud.spanner.pgadapter.error.PGExceptionFactory;
24+
import com.google.cloud.spanner.pgadapter.error.SQLState;
2425
import com.google.common.collect.ImmutableMap;
2526
import java.nio.charset.StandardCharsets;
2627
import javax.annotation.Nonnull;
@@ -46,7 +47,8 @@ public class DoubleParser extends Parser<Double> {
4647
try {
4748
this.item = Double.valueOf(stringValue);
4849
} catch (Exception exception) {
49-
throw PGExceptionFactory.newPGException("Invalid float8 value: " + stringValue);
50+
throw PGExceptionFactory.newPGException(
51+
"Invalid float8 value: " + stringValue, SQLState.SyntaxError);
5052
}
5153
break;
5254
case BINARY:

src/main/java/com/google/cloud/spanner/pgadapter/parsers/FloatParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.google.cloud.spanner.Value;
2121
import com.google.cloud.spanner.pgadapter.ProxyServer.DataFormat;
2222
import com.google.cloud.spanner.pgadapter.error.PGExceptionFactory;
23+
import com.google.cloud.spanner.pgadapter.error.SQLState;
2324
import com.google.common.collect.ImmutableMap;
2425
import java.nio.charset.StandardCharsets;
2526
import javax.annotation.Nonnull;
@@ -44,7 +45,8 @@ public class FloatParser extends Parser<Float> {
4445
try {
4546
this.item = Float.valueOf(stringValue);
4647
} catch (Exception exception) {
47-
throw PGExceptionFactory.newPGException("Invalid float4 value: " + stringValue);
48+
throw PGExceptionFactory.newPGException(
49+
"Invalid float4 value: " + stringValue, SQLState.SyntaxError);
4850
}
4951
break;
5052
case BINARY:

src/main/java/com/google/cloud/spanner/pgadapter/parsers/IntegerParser.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import com.google.cloud.spanner.ResultSet;
1818
import com.google.cloud.spanner.Value;
1919
import com.google.cloud.spanner.pgadapter.error.PGExceptionFactory;
20+
import com.google.cloud.spanner.pgadapter.error.SQLState;
2021
import com.google.common.collect.ImmutableMap;
2122
import java.math.BigDecimal;
2223
import java.math.RoundingMode;
@@ -42,7 +43,8 @@ class IntegerParser extends Parser<Integer> {
4243
this.item =
4344
new BigDecimal(stringValue).setScale(0, RoundingMode.HALF_UP).intValueExact();
4445
} catch (Exception exception) {
45-
throw PGExceptionFactory.newPGException("Invalid int4 value: " + stringValue);
46+
throw PGExceptionFactory.newPGException(
47+
"Invalid int4 value: " + stringValue, SQLState.SyntaxError);
4648
}
4749
break;
4850
case BINARY:

0 commit comments

Comments
 (0)