diff --git a/CHANGELOG.md b/CHANGELOG.md
index 57a583fc9..d51198acb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,19 @@
# Changelog
+## [2.11.0](https://github.com/googleapis/java-spanner-jdbc/compare/v2.10.0...v2.11.0) (2023-06-12)
+
+
+### Features
+
+* Support untyped NULL value parameters ([#1224](https://github.com/googleapis/java-spanner-jdbc/issues/1224)) ([80d2b9d](https://github.com/googleapis/java-spanner-jdbc/commit/80d2b9d3e4c3265522bbb20766bff1f164617711))
+
+
+### Dependencies
+
+* Update dependency com.google.cloud:google-cloud-shared-dependencies to v3.11.0 ([#1254](https://github.com/googleapis/java-spanner-jdbc/issues/1254)) ([41f40fc](https://github.com/googleapis/java-spanner-jdbc/commit/41f40fce634cea205d5e5a9c1eb567ecb97ff655))
+* Update dependency com.google.cloud:google-cloud-spanner-bom to v6.42.3 ([#1248](https://github.com/googleapis/java-spanner-jdbc/issues/1248)) ([397d573](https://github.com/googleapis/java-spanner-jdbc/commit/397d5738a8126aaf090d533d0f20efb74a77a788))
+* Update dependency com.google.cloud:google-cloud-spanner-bom to v6.43.0 ([#1255](https://github.com/googleapis/java-spanner-jdbc/issues/1255)) ([ffe36b6](https://github.com/googleapis/java-spanner-jdbc/commit/ffe36b6b2087157c8d895fa348cff614435a4735))
+
## [2.10.0](https://github.com/googleapis/java-spanner-jdbc/compare/v2.9.16...v2.10.0) (2023-05-30)
diff --git a/pom.xml b/pom.xml
index 116956d90..9b0d4aec6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
google-cloud-spanner-jdbc
- 2.10.0
+ 2.11.0
jar
Google Cloud Spanner JDBC
https://github.com/googleapis/java-spanner-jdbc
@@ -14,7 +14,7 @@
com.google.cloud
google-cloud-shared-config
- 1.5.5
+ 1.5.6
@@ -62,14 +62,14 @@
com.google.cloud
google-cloud-spanner-bom
- 6.42.2
+ 6.43.0
pom
import
com.google.cloud
google-cloud-shared-dependencies
- 3.10.1
+ 3.11.0
pom
import
@@ -393,7 +393,7 @@
org.apache.maven.plugins
maven-project-info-reports-plugin
- 3.4.4
+ 3.4.5
diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml
index 7ac31aeb4..42875833f 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -29,7 +29,7 @@
com.google.cloud
google-cloud-spanner-jdbc
- 2.9.16
+ 2.10.0
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index 6cd1705d3..9b0ce3fe4 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -28,7 +28,7 @@
com.google.cloud
google-cloud-spanner-jdbc
- 2.10.0
+ 2.11.0
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index cf10eb51d..06de2d0ec 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -30,7 +30,7 @@
com.google.cloud
libraries-bom
- 26.15.0
+ 26.16.0
pom
import
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/AbstractJdbcPreparedStatement.java b/src/main/java/com/google/cloud/spanner/jdbc/AbstractJdbcPreparedStatement.java
index 847f54d38..cd1c50a73 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/AbstractJdbcPreparedStatement.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/AbstractJdbcPreparedStatement.java
@@ -81,7 +81,8 @@ public void addBatch(String sql) throws SQLException {
@Override
public void setNull(int parameterIndex, int sqlType) throws SQLException {
checkClosed();
- parameters.setParameter(parameterIndex, null, sqlType, null);
+ parameters.setParameter(
+ parameterIndex, /* value = */ null, sqlType, /* scaleOrLength = */ null);
}
@Override
diff --git a/src/main/java/com/google/cloud/spanner/jdbc/JdbcParameterStore.java b/src/main/java/com/google/cloud/spanner/jdbc/JdbcParameterStore.java
index 3ce105aa7..5fb4177fc 100644
--- a/src/main/java/com/google/cloud/spanner/jdbc/JdbcParameterStore.java
+++ b/src/main/java/com/google/cloud/spanner/jdbc/JdbcParameterStore.java
@@ -24,6 +24,7 @@
import com.google.cloud.spanner.Value;
import com.google.cloud.spanner.ValueBinder;
import com.google.common.io.CharStreams;
+import com.google.protobuf.NullValue;
import com.google.rpc.Code;
import java.io.IOException;
import java.io.InputStream;
@@ -231,6 +232,10 @@ void setParameter(
}
private void checkTypeAndValueSupported(Object value, int sqlType) throws SQLException {
+ if (value == null) {
+ // null is always supported, as we will just fall back to an untyped NULL value.
+ return;
+ }
if (!isTypeSupported(sqlType)) {
throw JdbcSqlExceptionFactory.of(
"Type " + sqlType + " is not supported", Code.INVALID_ARGUMENT);
@@ -775,8 +780,13 @@ private Builder setArrayValue(ValueBinder binder, int type, Object valu
case Types.LONGVARBINARY:
case Types.BLOB:
return binder.toBytesArray(null);
+ default:
+ return binder.to(
+ Value.untyped(
+ com.google.protobuf.Value.newBuilder()
+ .setNullValue(NullValue.NULL_VALUE)
+ .build()));
}
- throw JdbcSqlExceptionFactory.unsupported("Unknown/unsupported array base type: " + type);
}
if (boolean[].class.isAssignableFrom(value.getClass())) {
@@ -864,7 +874,9 @@ private List toDoubleList(Number[] input) {
*/
private Builder setNullValue(ValueBinder binder, Integer sqlType) {
if (sqlType == null) {
- return binder.to((String) null);
+ return binder.to(
+ Value.untyped(
+ com.google.protobuf.Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build()));
}
switch (sqlType) {
case Types.BIGINT:
@@ -924,8 +936,14 @@ private Builder setNullValue(ValueBinder binder, Integer sqlType) {
return binder.to((ByteArray) null);
case Types.VARCHAR:
return binder.to((String) null);
+ case JsonType.VENDOR_TYPE_NUMBER:
+ return binder.to(Value.json(null));
+ case PgJsonbType.VENDOR_TYPE_NUMBER:
+ return binder.to(Value.pgJsonb(null));
default:
- throw new IllegalArgumentException("Unsupported sql type for setting to null: " + sqlType);
+ return binder.to(
+ Value.untyped(
+ com.google.protobuf.Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build()));
}
}
}
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/JdbcPreparedStatementTest.java b/src/test/java/com/google/cloud/spanner/jdbc/JdbcPreparedStatementTest.java
index b4c33a802..8f21e68d3 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/JdbcPreparedStatementTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/JdbcPreparedStatementTest.java
@@ -20,7 +20,6 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.mock;
@@ -39,7 +38,6 @@
import com.google.cloud.spanner.Value;
import com.google.cloud.spanner.connection.AbstractStatementParser;
import com.google.cloud.spanner.connection.Connection;
-import com.google.rpc.Code;
import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.math.BigDecimal;
@@ -47,7 +45,6 @@
import java.net.URL;
import java.sql.Date;
import java.sql.JDBCType;
-import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Time;
@@ -197,7 +194,10 @@ public void testParameters() throws SQLException, MalformedURLException {
ps.setObject(35, "TEST");
ps.setObject(36, "TEST", Types.NVARCHAR);
ps.setObject(37, "TEST", Types.NVARCHAR, 20);
+ ps.setRef(38, null);
+ ps.setRowId(39, null);
ps.setShort(40, (short) 1);
+ ps.setSQLXML(41, null);
ps.setString(42, "TEST");
ps.setTime(43, new Time(1000L));
ps.setTime(44, new Time(1000L), Calendar.getInstance(TimeZone.getTimeZone("GMT")));
@@ -211,8 +211,6 @@ public void testParameters() throws SQLException, MalformedURLException {
ps.setObject(52, "{}", JsonType.VENDOR_TYPE_NUMBER);
ps.setObject(53, "{}", PgJsonbType.VENDOR_TYPE_NUMBER);
- testSetUnsupportedTypes(ps);
-
JdbcParameterMetaData pmd = ps.getParameterMetaData();
assertEquals(numberOfParams, pmd.getParameterCount());
assertEquals(JdbcArray.class.getName(), pmd.getParameterClassName(1));
@@ -274,33 +272,9 @@ public void testParameters() throws SQLException, MalformedURLException {
}
}
- private void testSetUnsupportedTypes(PreparedStatement ps) {
- try {
- ps.setRef(38, null);
- fail("missing expected exception");
- } catch (SQLException e) {
- assertTrue(e instanceof JdbcSqlException);
- assertEquals(Code.INVALID_ARGUMENT, ((JdbcSqlException) e).getCode());
- }
- try {
- ps.setRowId(39, null);
- fail("missing expected exception");
- } catch (SQLException e) {
- assertTrue(e instanceof JdbcSqlException);
- assertEquals(Code.INVALID_ARGUMENT, ((JdbcSqlException) e).getCode());
- }
- try {
- ps.setSQLXML(41, null);
- fail("missing expected exception");
- } catch (SQLException e) {
- assertTrue(e instanceof JdbcSqlException);
- assertEquals(Code.INVALID_ARGUMENT, ((JdbcSqlException) e).getCode());
- }
- }
-
@Test
public void testSetNullValues() throws SQLException {
- final int numberOfParameters = 27;
+ final int numberOfParameters = 31;
String sql = generateSqlWithParameters(numberOfParameters);
try (JdbcPreparedStatement ps = new JdbcPreparedStatement(createMockConnection(), sql)) {
int index = 0;
@@ -331,6 +305,10 @@ public void testSetNullValues() throws SQLException {
ps.setNull(++index, Types.BIT);
ps.setNull(++index, Types.VARBINARY);
ps.setNull(++index, Types.VARCHAR);
+ ps.setNull(++index, JsonType.VENDOR_TYPE_NUMBER);
+ ps.setNull(++index, PgJsonbType.VENDOR_TYPE_NUMBER);
+ ps.setNull(++index, Types.OTHER);
+ ps.setNull(++index, Types.NULL);
assertEquals(numberOfParameters, index);
JdbcParameterMetaData pmd = ps.getParameterMetaData();
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/JdbcPreparedStatementWithMockedServerTest.java b/src/test/java/com/google/cloud/spanner/jdbc/JdbcPreparedStatementWithMockedServerTest.java
index 9da17d7db..d3607d842 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/JdbcPreparedStatementWithMockedServerTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/JdbcPreparedStatementWithMockedServerTest.java
@@ -25,6 +25,7 @@
import com.google.cloud.spanner.MockSpannerServiceImpl;
import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
import com.google.cloud.spanner.Statement;
+import com.google.cloud.spanner.Value;
import com.google.cloud.spanner.connection.SpannerPool;
import com.google.cloud.spanner.jdbc.JdbcSqlExceptionFactory.JdbcSqlBatchUpdateException;
import io.grpc.Server;
@@ -36,6 +37,7 @@
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
+import java.sql.Types;
import java.util.Arrays;
import java.util.Collection;
import org.junit.After;
@@ -193,4 +195,69 @@ public void testExecuteBatch_withException() throws SQLException {
}
}
}
+
+ @Test
+ public void testInsertUntypedNullValues() throws SQLException {
+ mockSpanner.putStatementResult(
+ StatementResult.update(
+ Statement.newBuilder(
+ "insert into all_nullable_types (ColInt64, ColFloat64, ColBool, ColString, ColBytes, ColDate, ColTimestamp, ColNumeric, ColJson, ColInt64Array, ColFloat64Array, ColBoolArray, ColStringArray, ColBytesArray, ColDateArray, ColTimestampArray, ColNumericArray, ColJsonArray) "
+ + "values (@p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11, @p12, @p13, @p14, @p15, @p16, @p17, @p18)")
+ .bind("p1")
+ .to((Value) null)
+ .bind("p2")
+ .to((Value) null)
+ .bind("p3")
+ .to((Value) null)
+ .bind("p4")
+ .to((Value) null)
+ .bind("p5")
+ .to((Value) null)
+ .bind("p6")
+ .to((Value) null)
+ .bind("p7")
+ .to((Value) null)
+ .bind("p8")
+ .to((Value) null)
+ .bind("p9")
+ .to((Value) null)
+ .bind("p10")
+ .to((Value) null)
+ .bind("p11")
+ .to((Value) null)
+ .bind("p12")
+ .to((Value) null)
+ .bind("p13")
+ .to((Value) null)
+ .bind("p14")
+ .to((Value) null)
+ .bind("p15")
+ .to((Value) null)
+ .bind("p16")
+ .to((Value) null)
+ .bind("p17")
+ .to((Value) null)
+ .bind("p18")
+ .to((Value) null)
+ .build(),
+ 1L));
+ try (Connection connection = createConnection()) {
+ for (int type : new int[] {Types.OTHER, Types.NULL}) {
+ try (PreparedStatement statement =
+ connection.prepareStatement(
+ "insert into all_nullable_types ("
+ + "ColInt64, ColFloat64, ColBool, ColString, ColBytes, ColDate, ColTimestamp, ColNumeric, ColJson, "
+ + "ColInt64Array, ColFloat64Array, ColBoolArray, ColStringArray, ColBytesArray, ColDateArray, ColTimestampArray, ColNumericArray, ColJsonArray) "
+ + "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) {
+ for (int param = 1;
+ param <= statement.getParameterMetaData().getParameterCount();
+ param++) {
+ statement.setNull(param, type);
+ }
+ assertEquals(1, statement.executeUpdate());
+ }
+ mockSpanner.clearRequests();
+ }
+ }
+ }
}
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcDatabaseMetaDataTest.java b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcDatabaseMetaDataTest.java
index ea7c236a4..7e2481a23 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcDatabaseMetaDataTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcDatabaseMetaDataTest.java
@@ -512,7 +512,8 @@ private IndexInfo(
new IndexInfo("TableWithRef", false, "PRIMARY_KEY", 1, "Id", "A"),
new IndexInfo("TableWithRef", true, "FOREIGN_KEY", 1, "RefFloat", "A"),
new IndexInfo("TableWithRef", true, "FOREIGN_KEY", 2, "RefString", "A"),
- new IndexInfo("TableWithRef", true, "FOREIGN_KEY", 3, "RefDate", "A"));
+ new IndexInfo("TableWithRef", true, "FOREIGN_KEY", 3, "RefDate", "A"),
+ new IndexInfo("all_nullable_types", false, "PRIMARY_KEY", 1, "ColInt64", "A"));
@Test
public void testGetIndexInfo() throws SQLException {
@@ -860,7 +861,8 @@ private Table(String name, String type) {
new Table("SingersView", "VIEW"),
new Table("Songs"),
new Table("TableWithAllColumnTypes"),
- new Table("TableWithRef"));
+ new Table("TableWithRef"),
+ new Table("all_nullable_types"));
@Test
public void testGetTables() throws SQLException {
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPgDatabaseMetaDataTest.java b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPgDatabaseMetaDataTest.java
index bbd37122c..ff0bff7a9 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPgDatabaseMetaDataTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPgDatabaseMetaDataTest.java
@@ -420,6 +420,7 @@ private IndexInfo(
new IndexInfo("albums", false, "PRIMARY_KEY", 1, "singerid", "A"),
new IndexInfo("albums", false, "PRIMARY_KEY", 2, "albumid", "A"),
new IndexInfo("albums", true, "albumsbyalbumtitle", 1, "albumtitle", "A"),
+ new IndexInfo("all_nullable_types", false, "PRIMARY_KEY", 1, "colint64", "A"),
new IndexInfo("concerts", false, "PRIMARY_KEY", 1, "venueid", "A"),
new IndexInfo("concerts", false, "PRIMARY_KEY", 2, "singerid", "A"),
new IndexInfo("concerts", false, "PRIMARY_KEY", 3, "concertdate", "A"),
@@ -790,6 +791,7 @@ private Table(String name, String type) {
private static final List EXPECTED_TABLES =
Arrays.asList(
new Table("albums"),
+ new Table("all_nullable_types"),
new Table("concerts"),
new Table("singers"),
// TODO: Enable when views are supported for PostgreSQL dialect databases.
diff --git a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPreparedStatementTest.java b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPreparedStatementTest.java
index c1d841696..2864559c8 100644
--- a/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPreparedStatementTest.java
+++ b/src/test/java/com/google/cloud/spanner/jdbc/it/ITJdbcPreparedStatementTest.java
@@ -1294,6 +1294,39 @@ public void test12_InsertReturningTestData() throws SQLException {
}
}
+ @Test
+ public void test13_InsertUntypedNullValues() throws SQLException {
+ try (Connection connection = createConnection(env, database)) {
+ try (PreparedStatement preparedStatement =
+ connection.prepareStatement(
+ "insert into all_nullable_types ("
+ + "ColInt64, ColFloat64, ColBool, ColString, ColBytes, ColDate, ColTimestamp, ColNumeric, ColJson, "
+ + "ColInt64Array, ColFloat64Array, ColBoolArray, ColStringArray, ColBytesArray, ColDateArray, ColTimestampArray, ColNumericArray, ColJsonArray) "
+ + "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) {
+ for (int param = 1;
+ param <= preparedStatement.getParameterMetaData().getParameterCount();
+ param++) {
+ preparedStatement.setNull(param, Types.OTHER);
+ }
+ if (getDialect() == Dialect.POSTGRESQL) {
+ // PostgreSQL-dialect databases do not allow NULLs in primary keys.
+ preparedStatement.setLong(1, 1L);
+ }
+ assertEquals(1, preparedStatement.executeUpdate());
+
+ // Verify that calling preparedStatement.setObject(index, null) works.
+ for (int param = 1;
+ param <= preparedStatement.getParameterMetaData().getParameterCount();
+ param++) {
+ preparedStatement.setObject(param, null);
+ }
+ // We need a different primary key value to insert another row.
+ preparedStatement.setLong(1, 2L);
+ assertEquals(1, preparedStatement.executeUpdate());
+ }
+ }
+ }
+
private List readValuesFromFile(String filename) {
StringBuilder builder = new StringBuilder();
try (InputStream stream = ITJdbcPreparedStatementTest.class.getResourceAsStream(filename)) {
diff --git a/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables.sql b/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables.sql
index 24579b272..153dd773d 100644
--- a/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables.sql
+++ b/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables.sql
@@ -97,6 +97,29 @@ CREATE TABLE TableWithAllColumnTypes (
) PRIMARY KEY (ColInt64)
;
+CREATE TABLE all_nullable_types (
+ ColInt64 INT64,
+ ColFloat64 FLOAT64,
+ ColBool BOOL,
+ ColString STRING(100),
+ ColBytes BYTES(100),
+ ColDate DATE,
+ ColTimestamp TIMESTAMP,
+ ColNumeric NUMERIC,
+ ColJson JSON,
+
+ ColInt64Array ARRAY,
+ ColFloat64Array ARRAY,
+ ColBoolArray ARRAY,
+ ColStringArray ARRAY,
+ ColBytesArray ARRAY,
+ ColDateArray ARRAY,
+ ColTimestampArray ARRAY,
+ ColNumericArray ARRAY,
+ ColJsonArray ARRAY,
+) PRIMARY KEY (ColInt64)
+;
+
CREATE TABLE TableWithRef (
Id INT64 NOT NULL,
RefFloat FLOAT64 NOT NULL,
diff --git a/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables_Emulator.sql b/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables_Emulator.sql
index aaba70c19..6aa8e843c 100644
--- a/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables_Emulator.sql
+++ b/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables_Emulator.sql
@@ -92,6 +92,29 @@ CREATE TABLE TableWithAllColumnTypes (
) PRIMARY KEY (ColInt64)
;
+CREATE TABLE all_nullable_types (
+ ColInt64 INT64,
+ ColFloat64 FLOAT64,
+ ColBool BOOL,
+ ColString STRING(100),
+ ColBytes BYTES(100),
+ ColDate DATE,
+ ColTimestamp TIMESTAMP,
+ ColNumeric NUMERIC,
+ ColJson JSON,
+
+ ColInt64Array ARRAY,
+ ColFloat64Array ARRAY,
+ ColBoolArray ARRAY,
+ ColStringArray ARRAY,
+ ColBytesArray ARRAY,
+ ColDateArray ARRAY,
+ ColTimestampArray ARRAY,
+ ColNumericArray ARRAY,
+ ColJsonArray ARRAY,
+) PRIMARY KEY (ColInt64)
+;
+
CREATE TABLE TableWithRef (
Id INT64 NOT NULL,
RefFloat FLOAT64 NOT NULL,
diff --git a/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables_PG.sql b/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables_PG.sql
index 438d2d5df..c77968b45 100644
--- a/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables_PG.sql
+++ b/src/test/resources/com/google/cloud/spanner/jdbc/it/CreateMusicTables_PG.sql
@@ -74,6 +74,27 @@ CREATE TABLE TableWithAllColumnTypes (
ColNumeric NUMERIC NOT NULL,
ColJson VARCHAR NOT NULL
);
+CREATE TABLE all_nullable_types (
+ ColInt64 bigint primary key,
+ ColFloat64 float8,
+ ColBool boolean,
+ ColString varchar(100),
+ ColBytes bytea,
+ ColDate date,
+ ColTimestamp timestamptz,
+ ColNumeric numeric,
+ ColJson jsonb,
+
+ ColInt64Array bigint[],
+ ColFloat64Array float8[],
+ ColBoolArray boolean[],
+ ColStringArray varchar(100)[],
+ ColBytesArray bytea[],
+ ColDateArray date[],
+ ColTimestampArray timestamptz[],
+ ColNumericArray numeric[],
+ ColJsonArray jsonb[]
+);
CREATE TABLE TableWithRef (
Id BIGINT NOT NULL PRIMARY KEY,
diff --git a/versions.txt b/versions.txt
index 363915b72..bee319b9a 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,4 +1,4 @@
# Format:
# module:released-version:current-version
-google-cloud-spanner-jdbc:2.10.0:2.10.0
+google-cloud-spanner-jdbc:2.11.0:2.11.0