Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for PostgreSQL dialect #739

Merged
merged 8 commits into from
Feb 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions clirr-ignored-differences.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- see http://www.mojohaus.org/clirr-maven-plugin/examples/ignored-differences.html -->
<differences>
<difference>
<differenceType>7012</differenceType>
<className>com/google/cloud/spanner/jdbc/CloudSpannerJdbcConnection</className>
<method>com.google.cloud.spanner.Dialect getDialect()</method>
</difference>
</differences>
13 changes: 6 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
<site.installationModule>google-cloud-spanner-jdbc</site.installationModule>
<junit.version>4.13.2</junit.version>
<findbugs.version>3.0.2</findbugs.version>
<threeten.version>1.4.4</threeten.version>
<truth.version>1.1.3</truth.version>
<mockito.version>4.3.1</mockito.version>
<hamcrest.version>2.2</hamcrest.version>
Expand All @@ -63,7 +62,7 @@
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner-bom</artifactId>
<version>6.18.0</version>
<version>6.19.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down Expand Up @@ -103,6 +102,10 @@
<groupId>com.google.api.grpc</groupId>
<artifactId>proto-google-common-protos</artifactId>
</dependency>
<dependency>
<groupId>com.google.api</groupId>
<artifactId>gax</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner</artifactId>
Expand All @@ -120,10 +123,6 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.threeten</groupId>
<artifactId>threetenbp</artifactId>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
Expand Down Expand Up @@ -234,7 +233,7 @@
com.google.cloud.spanner.GceTestEnvConfig
</spanner.testenv.config.class>
<spanner.testenv.instance>
projects/gcloud-devel/instances/spanner-testing
projects/gcloud-devel/instances/spanner-testing-east1
</spanner.testenv.instance>
</systemPropertyVariables>
<forkedProcessTimeoutInSeconds>2400</forkedProcessTimeoutInSeconds>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package com.google.cloud.spanner.jdbc;

import com.google.cloud.spanner.Dialect;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.connection.AbstractStatementParser;
import com.google.cloud.spanner.connection.ConnectionOptions;
import com.google.common.annotations.VisibleForTesting;
import com.google.rpc.Code;
Expand Down Expand Up @@ -51,6 +54,7 @@ abstract class AbstractJdbcConnection extends AbstractJdbcWrapper
private final ConnectionOptions options;
private final com.google.cloud.spanner.connection.Connection spanner;
private final Properties clientInfo;
private AbstractStatementParser parser;

private SQLWarning firstWarning = null;
private SQLWarning lastWarning = null;
Expand All @@ -76,6 +80,22 @@ ConnectionOptions getConnectionOptions() {
return options;
}

@Override
public Dialect getDialect() {
return spanner.getDialect();
}

protected AbstractStatementParser getParser() throws SQLException {
if (parser == null) {
try {
parser = AbstractStatementParser.getInstance(spanner.getDialect());
} catch (SpannerException e) {
throw JdbcSqlExceptionFactory.of(e);
}
}
return parser;
}

@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return checkClosedAndThrowUnsupported(CALLABLE_STATEMENTS_UNSUPPORTED);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@
abstract class AbstractJdbcPreparedStatement extends JdbcStatement implements PreparedStatement {
private static final String METHOD_NOT_ON_PREPARED_STATEMENT =
"This method may not be called on a PreparedStatement";
private final JdbcParameterStore parameters = new JdbcParameterStore();
private final JdbcParameterStore parameters;

AbstractJdbcPreparedStatement(JdbcConnection connection) {
AbstractJdbcPreparedStatement(JdbcConnection connection) throws SQLException {
super(connection);
parameters = new JdbcParameterStore(connection.getDialect());
}

JdbcParameterStore getParameters() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.cloud.spanner.Options.QueryOption;
import com.google.cloud.spanner.ReadContext.QueryAnalyzeMode;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.connection.AbstractStatementParser;
import com.google.cloud.spanner.connection.Connection;
import com.google.cloud.spanner.connection.StatementResult;
import com.google.cloud.spanner.connection.StatementResult.ClientSideStatementType;
Expand All @@ -35,14 +36,16 @@
abstract class AbstractJdbcStatement extends AbstractJdbcWrapper implements Statement {
private static final String CURSORS_NOT_SUPPORTED = "Cursors are not supported";
private static final String ONLY_FETCH_FORWARD_SUPPORTED = "Only fetch_forward is supported";
final AbstractStatementParser parser;
private boolean closed;
private boolean closeOnCompletion;
private boolean poolable;
private final JdbcConnection connection;
private int queryTimeout;

AbstractJdbcStatement(JdbcConnection connection) {
AbstractJdbcStatement(JdbcConnection connection) throws SQLException {
this.connection = connection;
this.parser = connection.getParser();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ static int extractColumnType(Type type) {
if (type.equals(Type.float64())) return Types.DOUBLE;
if (type.equals(Type.int64())) return Types.BIGINT;
if (type.equals(Type.numeric())) return Types.NUMERIC;
if (type.equals(Type.pgNumeric())) return Types.NUMERIC;
if (type.equals(Type.string())) return Types.NVARCHAR;
if (type.equals(Type.json())) return Types.NVARCHAR;
if (type.equals(Type.timestamp())) return Types.TIMESTAMP;
Expand Down Expand Up @@ -106,6 +107,7 @@ static String getClassName(Type type) {
if (type == Type.float64()) return Double.class.getName();
if (type == Type.int64()) return Long.class.getName();
if (type == Type.numeric()) return BigDecimal.class.getName();
if (type == Type.pgNumeric()) return BigDecimal.class.getName();
if (type == Type.string()) return String.class.getName();
if (type == Type.json()) return String.class.getName();
if (type == Type.timestamp()) return Timestamp.class.getName();
Expand All @@ -116,6 +118,7 @@ static String getClassName(Type type) {
if (type.getArrayElementType() == Type.float64()) return Double[].class.getName();
if (type.getArrayElementType() == Type.int64()) return Long[].class.getName();
if (type.getArrayElementType() == Type.numeric()) return BigDecimal[].class.getName();
if (type.getArrayElementType() == Type.pgNumeric()) return BigDecimal[].class.getName();
if (type.getArrayElementType() == Type.string()) return String[].class.getName();
if (type.getArrayElementType() == Type.json()) return String[].class.getName();
if (type.getArrayElementType() == Type.timestamp()) return Timestamp[].class.getName();
Expand Down Expand Up @@ -145,6 +148,16 @@ static byte checkedCastToByte(BigDecimal val) throws SQLException {
}
}

/** Cast value and throw {@link SQLException} if out-of-range. */
static byte checkedCastToByte(BigInteger val) throws SQLException {
try {
return val.byteValueExact();
} catch (ArithmeticException e) {
throw JdbcSqlExceptionFactory.of(
String.format(OUT_OF_RANGE_MSG, "byte", val), com.google.rpc.Code.OUT_OF_RANGE);
}
}

/** Cast value and throw {@link SQLException} if out-of-range. */
static short checkedCastToShort(long val) throws SQLException {
if (val > Short.MAX_VALUE || val < Short.MIN_VALUE) {
Expand All @@ -164,6 +177,16 @@ static short checkedCastToShort(BigDecimal val) throws SQLException {
}
}

/** Cast value and throw {@link SQLException} if out-of-range. */
static short checkedCastToShort(BigInteger val) throws SQLException {
try {
return val.shortValueExact();
} catch (ArithmeticException e) {
throw JdbcSqlExceptionFactory.of(
String.format(OUT_OF_RANGE_MSG, "short", val), com.google.rpc.Code.OUT_OF_RANGE);
}
}

/** Cast value and throw {@link SQLException} if out-of-range. */
static int checkedCastToInt(long val) throws SQLException {
if (val > Integer.MAX_VALUE || val < Integer.MIN_VALUE) {
Expand All @@ -183,6 +206,16 @@ static int checkedCastToInt(BigDecimal val) throws SQLException {
}
}

/** Cast value and throw {@link SQLException} if out-of-range. */
static int checkedCastToInt(BigInteger val) throws SQLException {
try {
return val.intValueExact();
} catch (ArithmeticException e) {
throw JdbcSqlExceptionFactory.of(
String.format(OUT_OF_RANGE_MSG, "int", val), com.google.rpc.Code.OUT_OF_RANGE);
}
}

/** Cast value and throw {@link SQLException} if out-of-range. */
static float checkedCastToFloat(double val) throws SQLException {
if (val > Float.MAX_VALUE || val < -Float.MAX_VALUE) {
Expand Down Expand Up @@ -226,6 +259,16 @@ static long checkedCastToLong(BigDecimal val) throws SQLException {
}
}

/** Cast value and throw {@link SQLException} if out-of-range. */
static long checkedCastToLong(BigInteger val) throws SQLException {
try {
return val.longValueExact();
} catch (ArithmeticException e) {
throw JdbcSqlExceptionFactory.of(
String.format(OUT_OF_RANGE_MSG, "long", val), com.google.rpc.Code.OUT_OF_RANGE);
}
}

/**
* Parses the given string value as a double. Throws {@link SQLException} if the string is not a
* valid double value.
Expand All @@ -240,6 +283,20 @@ static double parseDouble(String val) throws SQLException {
}
}

/**
* Parses the given string value as a float. Throws {@link SQLException} if the string is not a
* valid float value.
*/
static float parseFloat(String val) throws SQLException {
Preconditions.checkNotNull(val);
try {
return Float.parseFloat(val);
} catch (NumberFormatException e) {
throw JdbcSqlExceptionFactory.of(
String.format("%s is not a valid number", val), com.google.rpc.Code.INVALID_ARGUMENT, e);
}
}

/**
* Parses the given string value as a {@link Date} value. Throws {@link SQLException} if the
* string is not a valid {@link Date} value.
Expand Down Expand Up @@ -332,6 +389,20 @@ static Timestamp parseTimestamp(String val, Calendar cal) throws SQLException {
}
}

/**
* Parses the given string value as a {@link BigDecimal} value. Throws {@link SQLException} if the
* string is not a valid {@link BigDecimal} value.
*/
static BigDecimal parseBigDecimal(String val) throws SQLException {
Preconditions.checkNotNull(val);
try {
return new BigDecimal(val);
} catch (NumberFormatException e) {
throw JdbcSqlExceptionFactory.of(
String.format("%s is not a valid number", val), com.google.rpc.Code.INVALID_ARGUMENT, e);
}
}

/** Should return true if this object has been closed */
public abstract boolean isClosed();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.cloud.spanner.AbortedException;
import com.google.cloud.spanner.CommitResponse;
import com.google.cloud.spanner.CommitStats;
import com.google.cloud.spanner.Dialect;
import com.google.cloud.spanner.Mutation;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.TimestampBound;
Expand Down Expand Up @@ -321,6 +322,11 @@ default String getStatementTag() throws SQLException {
*/
String getConnectionUrl();

/** @return The {@link Dialect} that is used by this connection. */
default Dialect getDialect() {
return Dialect.GOOGLE_STANDARD_SQL;
}

/**
* @see
* com.google.cloud.spanner.connection.Connection#addTransactionRetryListener(com.google.cloud.spanner.connection.TransactionRetryListener)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import com.google.cloud.spanner.TimestampBound;
import com.google.cloud.spanner.connection.AutocommitDmlMode;
import com.google.cloud.spanner.connection.ConnectionOptions;
import com.google.cloud.spanner.connection.StatementParser;
import com.google.cloud.spanner.connection.TransactionMode;
import com.google.common.collect.Iterators;
import java.sql.Array;
Expand Down Expand Up @@ -72,8 +71,8 @@ public JdbcPreparedStatement prepareStatement(String sql) throws SQLException {
@Override
public String nativeSQL(String sql) throws SQLException {
checkClosed();
return JdbcParameterStore.convertPositionalParametersToNamedParameters(
StatementParser.removeCommentsAndTrim(sql))
return getParser()
.convertPositionalParametersToNamedParameters('?', getParser().removeCommentsAndTrim(sql))
.sqlWithNamedParameters;
}

Expand Down
26 changes: 26 additions & 0 deletions src/main/java/com/google/cloud/spanner/jdbc/JdbcDataType.java
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,32 @@ public Type getSpannerType() {
return Type.numeric();
}
},
PG_NUMERIC {
@Override
public int getSqlType() {
return Types.NUMERIC;
}

@Override
public Class<BigDecimal> getJavaClass() {
return BigDecimal.class;
}

@Override
public Code getCode() {
return Code.PG_NUMERIC;
}

@Override
public List<BigDecimal> getArrayElements(ResultSet rs, int columnIndex) {
return rs.getValue(columnIndex).getNumericArray();
}

@Override
public Type getSpannerType() {
return Type.pgNumeric();
}
},
STRING {
@Override
public int getSqlType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package com.google.cloud.spanner.jdbc;

import com.google.cloud.spanner.jdbc.JdbcParameterStore.ParametersInfo;
import com.google.cloud.spanner.connection.AbstractStatementParser.ParametersInfo;
import java.math.BigDecimal;
import java.sql.Date;
import java.sql.ParameterMetaData;
Expand Down
Loading