spanner-jdbc icon indicating copy to clipboard operation
spanner-jdbc copied to clipboard

Bulk delete fails when schema has DATE column

Open O1O1O1O opened this issue 6 years ago • 1 comments

For a table with this schema:

CREATE TABLE geo_views (
	city STRING(MAX) NOT NULL,
	client_id INT64 NOT NULL,
	date DATE NOT NULL,
	domain STRING(MAX) NOT NULL,
	url STRING(MAX) NOT NULL,
	pageviews INT64 NOT NULL,
) PRIMARY KEY (client_id, domain, date DESC, city, url)

if I try this query:

    NamedDB('spanner) autoCommit { implicit session =>
      sql"DELETE FROM ${SQLSyntax.createUnsafely(geoViews.tableName)} WHERE client_id > $TEST_ID_BASE".update.apply()
    }

I get this exception:

Exception in thread "Google Cloud Spanner JDBC Transaction Thread-0" java.lang.AssertionError: Illegal key part: class nl.topicus.jdbc.shaded.com.google.cloud.Date
	at nl.topicus.jdbc.shaded.com.google.cloud.spanner.Key.toProto(Key.java:287)
	at nl.topicus.jdbc.shaded.com.google.cloud.spanner.KeySet.appendToProto(KeySet.java:204)
	at nl.topicus.jdbc.shaded.com.google.cloud.spanner.Mutation.toProto(Mutation.java:381)
	at nl.topicus.jdbc.shaded.com.google.cloud.spanner.SpannerImpl$TransactionContextImpl.commit(SpannerImpl.java:1394)
	at nl.topicus.jdbc.shaded.com.google.cloud.spanner.SpannerImpl$TransactionRunnerImpl.runInternal(SpannerImpl.java:1299)
	at nl.topicus.jdbc.shaded.com.google.cloud.spanner.SpannerImpl$TransactionRunnerImpl.run(SpannerImpl.java:1242)
	at nl.topicus.jdbc.shaded.com.google.cloud.spanner.SessionPool$PooledSession$1.run(SessionPool.java:398)
	at nl.topicus.jdbc.transaction.TransactionThread.run(TransactionThread.java:115)

It looks like the toProto code in the shaded com.google.cloud.spanner.Key code is missing a case for the Date type.

From: https://github.com/googleapis/google-cloud-java/blob/master/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/Key.java#L285

  ListValue toProto() {
    ListValue.Builder builder = ListValue.newBuilder();
    for (Object part : parts) {
      if (part == null) {
        builder.addValues(NULL_PROTO);
      } else if (part instanceof Boolean) {
        builder.addValuesBuilder().setBoolValue((Boolean) part);
      } else if (part instanceof Long) {
        builder.addValuesBuilder().setStringValue(part.toString());
      } else if (part instanceof Double) {
        builder.addValuesBuilder().setNumberValue((Double) part);
      } else if (part instanceof String) {
        builder.addValuesBuilder().setStringValue((String) part);
      } else if (part instanceof ByteArray) {
        builder.addValuesBuilder().setStringValue(((ByteArray) part).toBase64());
      } else if (part instanceof Timestamp) {
        builder.addValuesBuilder().setStringValue(((Timestamp) part).toString());
      } else {
        throw new AssertionError("Illegal key part: " + part.getClass());
      }
    }
    return builder.build();
  }

I know that isn't your code but maybe there is a workaround. Either way just wanted to report it here in case people are hitting the problem and Googling for an answer. I've created an issue on the Google Spanner client.

I have tried with and without AllowExtendedMode=true and removing the query parameter in the WHERE condition by making it a constant in the query and it still fails. The only solution was to remove the WHERE condition completely.

O1O1O1O avatar Feb 07 '19 19:02 O1O1O1O

Google has fixed this issue with https://github.com/googleapis/google-cloud-java/pull/4473

O1O1O1O avatar Feb 08 '19 23:02 O1O1O1O