Repository: googleapis/java-spanner-jdbc
Pull request #1250 (2023-06-02 19:35:18)

build(deps): update dependency com.google.cloud:google-cloud-shared-config to v1.5.6
[![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Change | Age | Adoption | Passing | Confidence |
|---|---|---|---|---|---|
| [com.google.cloud:google-cloud-shared-config](https://togithub.com/googleapis/java-shared-config) | `1.5.5` -> `1.5.6` | [![age](https://badges.renovateapi.com/packages/maven/com.google.cloud:google-cloud-shared-config/1.5.6/age-slim)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://badges.renovateapi.com/packages/maven/com.google.cloud:google-cloud-shared-config/1.5.6/adoption-slim)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://badges.renovateapi.com/packages/maven/com.google.cloud:google-cloud-shared-config/1.5.6/compatibility-slim/1.5.5)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://badges.renovateapi.com/packages/maven/com.google.cloud:google-cloud-shared-config/1.5.6/confidence-slim/1.5.5)](https://docs.renovatebot.com/merge-confidence/) |

---

### Release Notes

<details>
<summary>googleapis/java-shared-config</summary>

### [`v1.5.6`](https://togithub.com/googleapis/java-shared-config/blob/HEAD/CHANGELOG.md#&#8203;156-httpsgithubcomgoogleapisjava-shared-configcomparev155v156-2023-06-02)

[Compare Source](https://togithub.com/googleapis/java-shared-config/compare/v1.5.5...v1.5.6)

##### Bug Fixes

-   Add junit-vintage dep to avoid skipping post-compilation native tests ([#&#8203;586](https://togithub.com/googleapis/java-shared-config/issues/586)) ([f6e6f69](https://togithub.com/googleapis/java-shared-config/commit/f6e6f690d58e2a86db721926049b0132310724bf))
-   **java:** Skip fixing poms for special modules ([#&#8203;1744](https://togithub.com/googleapis/java-shared-config/issues/1744)) ([#&#8203;556](https://togithub.com/googleapis/java-shared-config/issues/556)) ([cc433c2](https://togithub.com/googleapis/java-shared-config/commit/cc433c246f1b6edbc093e6af37aced652d884a65))
-   Remove java-trace checks ([#&#8203;612](https://togithub.com/googleapis/java-shared-config/issues/612)) ([cfcdba8](https://togithub.com/googleapis/java-shared-config/commit/cfcdba834f27b6bb03460cd09f076068f67a892b))

##### Dependencies

-   Update dependency com.google.auto.service:auto-service-annotations to v1.1.0 ([#&#8203;610](https://togithub.com/googleapis/java-shared-config/issues/610)) ([aeefcbe](https://togithub.com/googleapis/java-shared-config/commit/aeefcbec212dc102bd15027984895a4ba51d045f))
-   Update dependency com.puppycrawl.tools:checkstyle to v10.10.0 ([#&#8203;598](https://togithub.com/googleapis/java-shared-config/issues/598)) ([29309c3](https://togithub.com/googleapis/java-shared-config/commit/29309c36cb6ffe2aea221d3cc8cde036441d21b1))
-   Update dependency com.puppycrawl.tools:checkstyle to v10.11.0 ([#&#8203;602](https://togithub.com/googleapis/java-shared-config/issues/602)) ([61b9c5f](https://togithub.com/googleapis/java-shared-config/commit/61b9c5f04422bc8edf8a249e3dfb7290bd188a8d))
-   Update dependency com.puppycrawl.tools:checkstyle to v10.12.0 ([#&#8203;614](https://togithub.com/googleapis/java-shared-config/issues/614)) ([8559d0d](https://togithub.com/googleapis/java-shared-config/commit/8559d0dc634e238ee640d68439839f50a938ce76))
-   Update dependency com.puppycrawl.tools:checkstyle to v10.6.0 ([#&#8203;554](https://togithub.com/googleapis/java-shared-config/issues/554)) ([44a77b0](https://togithub.com/googleapis/java-shared-config/commit/44a77b0faf5b4f3f9208117ccab0a3717d059efd))
-   Update dependency com.puppycrawl.tools:checkstyle to v10.7.0 ([#&#8203;563](https://togithub.com/googleapis/java-shared-config/issues/563)) ([5c51e07](https://togithub.com/googleapis/java-shared-config/commit/5c51e07af8e37019d462211d47307155c630adb9))
-   Update dependency com.puppycrawl.tools:checkstyle to v10.8.1 ([#&#8203;573](https://togithub.com/googleapis/java-shared-config/issues/573)) ([e5c6e54](https://togithub.com/googleapis/java-shared-config/commit/e5c6e5406488c0a204ef2afcbe8582176fa373e4))
-   Update dependency com.puppycrawl.tools:checkstyle to v10.9.2 ([#&#8203;579](https://togithub.com/googleapis/java-shared-config/issues/579)) ([a67a7c8](https://togithub.com/googleapis/java-shared-config/commit/a67a7c8d05bab4c8dbeaf5b5874170084e75abb7))
-   Update dependency com.puppycrawl.tools:checkstyle to v10.9.3 ([#&#8203;582](https://togithub.com/googleapis/java-shared-config/issues/582)) ([c87ff96](https://togithub.com/googleapis/java-shared-config/commit/c87ff962304efd82e2f79458976c627d1ff622d8))
-   Update dependency org.graalvm.buildtools:native-maven-plugin to v0.9.21 ([#&#8203;593](https://togithub.com/googleapis/java-shared-config/issues/593)) ([12ac165](https://togithub.com/googleapis/java-shared-config/commit/12ac165f36b6b5257f7928f8a2c21ae936af3794))
-   Update dependency org.graalvm.buildtools:native-maven-plugin to v0.9.22 ([#&#8203;603](https://togithub.com/googleapis/java-shared-config/issues/603)) ([9ea7833](https://togithub.com/googleapis/java-shared-config/commit/9ea783312cc9e136f8bdb6f4dae5591221e42773))
-   Update dependency org.junit.vintage:junit-vintage-engine to v5.9.2 ([#&#8203;560](https://togithub.com/googleapis/java-shared-config/issues/560)) ([60a80bd](https://togithub.com/googleapis/java-shared-config/commit/60a80bd272dd7483db8e4a5773125a9c57b9899e))
-   Update dependency org.junit.vintage:junit-vintage-engine to v5.9.3 ([#&#8203;597](https://togithub.com/googleapis/java-shared-config/issues/597)) ([61064b9](https://togithub.com/googleapis/java-shared-config/commit/61064b9c767c528139b025e3d629d12fc64d7809))
-   Update doclet version to 1.9.0 ([#&#8203;611](https://togithub.com/googleapis/java-shared-config/issues/611)) ([cd8c762](https://togithub.com/googleapis/java-shared-config/commit/cd8c76208ab3d10ab451545a180474c6270368d3))
-   Update graalvm native-image dependencies to v0.9.19 ([#&#8203;550](https://togithub.com/googleapis/java-shared-config/issues/550)) ([3313229](https://togithub.com/googleapis/java-shared-config/commit/3313229155be704b50e499379936e16598a348a6))
-   Update graalvm native-image dependencies to v0.9.20 ([#&#8203;568](https://togithub.com/googleapis/java-shared-config/issues/568)) ([79d7b4b](https://togithub.com/googleapis/java-shared-config/commit/79d7b4be908cc9e24a48d89eeb97b0c6155493d1))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View repository job log [here](https://app.renovatebot.com/dashboard#github/googleapis/java-spanner-jdbc).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNS4xMDUuMiIsInVwZGF0ZWRJblZlciI6IjM1LjEwNS4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->



Patch:
diff --git a/pom.xml b/pom.xml
index 64082e8..923ec36 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,7 +14,7 @@
   <parent>
     <groupId>com.google.cloud</groupId>
     <artifactId>google-cloud-shared-config</artifactId>
-    <version>1.5.5</version>
+    <version>1.5.6</version>
   </parent>
   <developers>
     <developer>
@@ -69,7 +69,7 @@
       <dependency>
         <groupId>com.google.cloud</groupId>
         <artifactId>google-cloud-shared-dependencies</artifactId>
-        <version>3.10.1</version>
+        <version>3.11.0</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
@@ -393,7 +393,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-project-info-reports-plugin</artifactId>
-        <version>3.4.4</version>
+        <version>3.4.5</version>
         <reportSets>
           <reportSet>
             <reports>
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 847f54d..cd1c50a 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 @@ abstract class AbstractJdbcPreparedStatement extends JdbcStatement implements Pr
   @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 3ce105a..5fb4177 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.Type;
 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 @@ class JdbcParameterStore {
   }
 
   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 @@ class JdbcParameterStore {
         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 @@ class JdbcParameterStore {
    */
   private Builder setNullValue(ValueBinder<Builder> 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 @@ class JdbcParameterStore {
         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()));
     }
   }
 }


Test patch:
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 b4c33a8..8f21e68 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.assertEquals;
 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.Type.StructField;
 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.MalformedURLException;
 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 class JdbcPreparedStatementTest {
       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 class JdbcPreparedStatementTest {
       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 class JdbcPreparedStatementTest {
     }
   }
 
-  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 class JdbcPreparedStatementTest {
       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 9da17d7..d3607d8 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.ErrorCode;
 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.Connection;
 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 class JdbcPreparedStatementWithMockedServerTest {
       }
     }
   }
+
+  @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 ea7c236..7e2481a 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 @@ public class ITJdbcDatabaseMetaDataTest extends ITAbstractJdbcTest {
           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 @@ public class ITJdbcDatabaseMetaDataTest extends ITAbstractJdbcTest {
           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 bbd3712..ff0bff7 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 @@ public class ITJdbcPgDatabaseMetaDataTest extends ITAbstractJdbcTest {
           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 @@ public class ITJdbcPgDatabaseMetaDataTest extends ITAbstractJdbcTest {
   private static final List<Table> 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 c1d8416..2864559 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 class ITJdbcPreparedStatementTest extends ITAbstractJdbcTest {
     }
   }
 
+  @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<String> 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 24579b2..153dd77 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<INT64>,
+    ColFloat64Array     ARRAY<FLOAT64>,
+    ColBoolArray		ARRAY<BOOL>,
+    ColStringArray	    ARRAY<STRING(100)>,
+    ColBytesArray		ARRAY<BYTES(100)>,
+    ColDateArray		ARRAY<DATE>,
+    ColTimestampArray	ARRAY<TIMESTAMP>,
+    ColNumericArray	    ARRAY<NUMERIC>,
+    ColJsonArray		ARRAY<JSON>,
+) 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 aaba70c..6aa8e84 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<INT64>,
+    ColFloat64Array     ARRAY<FLOAT64>,
+    ColBoolArray		ARRAY<BOOL>,
+    ColStringArray	    ARRAY<STRING(100)>,
+    ColBytesArray		ARRAY<BYTES(100)>,
+    ColDateArray		ARRAY<DATE>,
+    ColTimestampArray	ARRAY<TIMESTAMP>,
+    ColNumericArray	    ARRAY<NUMERIC>,
+    ColJsonArray		ARRAY<JSON>,
+) 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 438d2d5..c77968b 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,