From f5d6707687b0d40390000d6a8b54dc67d163270d Mon Sep 17 00:00:00 2001 From: anweshadas Date: Tue, 7 Jul 2026 02:19:24 +0000 Subject: [PATCH 1/5] feat(bigtable): add view_parameters support to BoundStatement --- .../data/v2/models/sql/BoundStatement.java | 38 +++++++++++++++++-- .../v2/models/sql/BoundStatementTest.java | 23 +++++++++++ .../testproxy/BoundStatementDeserializer.java | 1 + 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java index 82c1084afd7e..52b503c908b0 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java @@ -58,10 +58,15 @@ public class BoundStatement { private final PreparedStatementImpl preparedStatement; private final Map params; + private final Map viewParameters; - private BoundStatement(PreparedStatementImpl preparedStatement, Map params) { + private BoundStatement( + PreparedStatementImpl preparedStatement, + Map params, + Map viewParameters) { this.preparedStatement = preparedStatement; this.params = params; + this.viewParameters = viewParameters; } /** @@ -78,6 +83,7 @@ public static class Builder { private final PreparedStatementImpl preparedStatement; private final Map> paramTypes; private final Map params; + private final Map viewParameters; /** * Creates a builder from a {@link PreparedStatement} @@ -90,6 +96,7 @@ public Builder(PreparedStatementImpl preparedStatement, Map> this.preparedStatement = preparedStatement; this.paramTypes = paramTypes; this.params = new HashMap<>(); + this.viewParameters = new HashMap<>(); } /** Builds a {@link BoundStatement} from the builder */ @@ -101,7 +108,31 @@ public BoundStatement build() { "Attempting to build BoundStatement without binding parameter: " + paramName); } } - return new BoundStatement(preparedStatement, ImmutableMap.copyOf(params)); + return new BoundStatement( + preparedStatement, + ImmutableMap.copyOf(params), + ImmutableMap.copyOf(viewParameters)); + } + + /** + * Sets a view parameter with the name {@code name} and the Value {@code value}. + */ + public Builder setViewParameter(String name, Value value) { + Preconditions.checkNotNull(name, "name cannot be null"); + Preconditions.checkNotNull(value, "value cannot be null"); + viewParameters.put(name, value); + return this; + } + + /** + * Sets view parameters from a map. + */ + public Builder setViewParameters(Map viewParameters) { + Preconditions.checkNotNull(viewParameters, "viewParameters cannot be null"); + for (Map.Entry entry : viewParameters.entrySet()) { + setViewParameter(entry.getKey(), entry.getValue()); + } + return this; } /** @@ -372,7 +403,8 @@ public ExecuteQueryRequest toProto( requestContext.getProjectId(), requestContext.getInstanceId())) .setAppProfileId(requestContext.getAppProfileId()) .setPreparedQuery(preparedQuery) - .putAllParams(params); + .putAllParams(params) + .putAllViewParameters(viewParameters); if (resumeToken != null) { requestBuilder.setResumeToken(resumeToken); diff --git a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java index 71f46610a203..7d6425b5fb1c 100644 --- a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java +++ b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java @@ -869,4 +869,27 @@ public void builderValidatesAllParamsAreSet() { assertThat(e.getMessage()) .contains("Attempting to build BoundStatement without binding parameter: bytesParam"); } + + @Test + public void statementWithViewParameters() { + Value stringVal = Value.newBuilder().setType(stringType()).setStringValue("alice").build(); + Value intVal = Value.newBuilder().setType(int64Type()).setIntValue(42).build(); + HashMap viewParams = new HashMap<>(); + viewParams.put("user_id", stringVal); + viewParams.put("age", intVal); + + BoundStatement s = boundStatementBuilder() + .setViewParameters(viewParams) + .build(); + + assertThat(s.toProto(EXPECTED_PREPARED_QUERY, REQUEST_CONTEXT, NO_RESUME_TOKEN)) + .isEqualTo( + ExecuteQueryRequest.newBuilder() + .setPreparedQuery(EXPECTED_PREPARED_QUERY) + .setInstanceName(EXPECTED_INSTANCE_NAME) + .setAppProfileId(EXPECTED_APP_PROFILE) + .putViewParameters("user_id", stringVal) + .putViewParameters("age", intVal) + .build()); + } } diff --git a/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java b/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java index 43da147274f7..56b40d0d5957 100644 --- a/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java +++ b/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java @@ -128,6 +128,7 @@ static BoundStatement toBoundStatement( throw new IllegalArgumentException("Unexpected query param type in param: " + value); } } + boundStatementBuilder.setViewParameters(request.getRequest().getViewParametersMap()); return boundStatementBuilder.build(); } From cdcd5444637e717db72f6cef9e29a56618b7faca Mon Sep 17 00:00:00 2001 From: anweshadas Date: Tue, 7 Jul 2026 18:29:48 +0000 Subject: [PATCH 2/5] fix(bigtable): address PR review comments and formatting lint rules --- .../data/v2/models/sql/BoundStatement.java | 12 +++------- .../v2/models/sql/BoundStatementTest.java | 23 +++++++++++++++---- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java index 52b503c908b0..bf57cba90443 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java @@ -109,14 +109,10 @@ public BoundStatement build() { } } return new BoundStatement( - preparedStatement, - ImmutableMap.copyOf(params), - ImmutableMap.copyOf(viewParameters)); + preparedStatement, ImmutableMap.copyOf(params), ImmutableMap.copyOf(viewParameters)); } - /** - * Sets a view parameter with the name {@code name} and the Value {@code value}. - */ + /** Sets a view parameter with the name {@code name} and the Value {@code value} */ public Builder setViewParameter(String name, Value value) { Preconditions.checkNotNull(name, "name cannot be null"); Preconditions.checkNotNull(value, "value cannot be null"); @@ -124,9 +120,7 @@ public Builder setViewParameter(String name, Value value) { return this; } - /** - * Sets view parameters from a map. - */ + /** Sets view parameters from a map */ public Builder setViewParameters(Map viewParameters) { Preconditions.checkNotNull(viewParameters, "viewParameters cannot be null"); for (Map.Entry entry : viewParameters.entrySet()) { diff --git a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java index 7d6425b5fb1c..cb240dc33477 100644 --- a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java +++ b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java @@ -53,6 +53,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.Map; import javax.annotation.Nullable; import org.junit.Test; import org.junit.runner.RunWith; @@ -874,13 +875,11 @@ public void builderValidatesAllParamsAreSet() { public void statementWithViewParameters() { Value stringVal = Value.newBuilder().setType(stringType()).setStringValue("alice").build(); Value intVal = Value.newBuilder().setType(int64Type()).setIntValue(42).build(); - HashMap viewParams = new HashMap<>(); + Map viewParams = new HashMap<>(); viewParams.put("user_id", stringVal); viewParams.put("age", intVal); - BoundStatement s = boundStatementBuilder() - .setViewParameters(viewParams) - .build(); + BoundStatement s = boundStatementBuilder().setViewParameters(viewParams).build(); assertThat(s.toProto(EXPECTED_PREPARED_QUERY, REQUEST_CONTEXT, NO_RESUME_TOKEN)) .isEqualTo( @@ -892,4 +891,20 @@ public void statementWithViewParameters() { .putViewParameters("age", intVal) .build()); } + + @Test + public void statementWithSingleViewParameter() { + Value stringVal = Value.newBuilder().setType(stringType()).setStringValue("alice").build(); + + BoundStatement s = boundStatementBuilder().setViewParameter("user_id", stringVal).build(); + + assertThat(s.toProto(EXPECTED_PREPARED_QUERY, REQUEST_CONTEXT, NO_RESUME_TOKEN)) + .isEqualTo( + ExecuteQueryRequest.newBuilder() + .setPreparedQuery(EXPECTED_PREPARED_QUERY) + .setInstanceName(EXPECTED_INSTANCE_NAME) + .setAppProfileId(EXPECTED_APP_PROFILE) + .putViewParameters("user_id", stringVal) + .build()); + } } From 29ced7a5c9d6606021135bb43a53a056b075a044 Mon Sep 17 00:00:00 2001 From: anweshadas Date: Tue, 7 Jul 2026 18:39:36 +0000 Subject: [PATCH 3/5] feat(bigtable): enforce String types for view_parameters in BoundStatement --- .../data/v2/models/sql/BoundStatement.java | 10 +++--- .../v2/models/sql/BoundStatementTest.java | 34 +++++++++++++------ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java index bf57cba90443..311a247d5721 100644 --- a/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java +++ b/java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatement.java @@ -112,18 +112,18 @@ public BoundStatement build() { preparedStatement, ImmutableMap.copyOf(params), ImmutableMap.copyOf(viewParameters)); } - /** Sets a view parameter with the name {@code name} and the Value {@code value} */ - public Builder setViewParameter(String name, Value value) { + /** Sets a view parameter with the name {@code name} and the String value {@code value} */ + public Builder setViewParameter(String name, String value) { Preconditions.checkNotNull(name, "name cannot be null"); Preconditions.checkNotNull(value, "value cannot be null"); - viewParameters.put(name, value); + viewParameters.put(name, stringParamOf(value)); return this; } /** Sets view parameters from a map */ - public Builder setViewParameters(Map viewParameters) { + public Builder setViewParameters(Map viewParameters) { Preconditions.checkNotNull(viewParameters, "viewParameters cannot be null"); - for (Map.Entry entry : viewParameters.entrySet()) { + for (Map.Entry entry : viewParameters.entrySet()) { setViewParameter(entry.getKey(), entry.getValue()); } return this; diff --git a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java index cb240dc33477..891aacabc9da 100644 --- a/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java +++ b/java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/sql/BoundStatementTest.java @@ -873,11 +873,9 @@ public void builderValidatesAllParamsAreSet() { @Test public void statementWithViewParameters() { - Value stringVal = Value.newBuilder().setType(stringType()).setStringValue("alice").build(); - Value intVal = Value.newBuilder().setType(int64Type()).setIntValue(42).build(); - Map viewParams = new HashMap<>(); - viewParams.put("user_id", stringVal); - viewParams.put("age", intVal); + Map viewParams = new HashMap<>(); + viewParams.put("user_id", "alice"); + viewParams.put("role", "admin"); BoundStatement s = boundStatementBuilder().setViewParameters(viewParams).build(); @@ -887,16 +885,18 @@ public void statementWithViewParameters() { .setPreparedQuery(EXPECTED_PREPARED_QUERY) .setInstanceName(EXPECTED_INSTANCE_NAME) .setAppProfileId(EXPECTED_APP_PROFILE) - .putViewParameters("user_id", stringVal) - .putViewParameters("age", intVal) + .putViewParameters( + "user_id", + Value.newBuilder().setType(stringType()).setStringValue("alice").build()) + .putViewParameters( + "role", + Value.newBuilder().setType(stringType()).setStringValue("admin").build()) .build()); } @Test public void statementWithSingleViewParameter() { - Value stringVal = Value.newBuilder().setType(stringType()).setStringValue("alice").build(); - - BoundStatement s = boundStatementBuilder().setViewParameter("user_id", stringVal).build(); + BoundStatement s = boundStatementBuilder().setViewParameter("user_id", "alice").build(); assertThat(s.toProto(EXPECTED_PREPARED_QUERY, REQUEST_CONTEXT, NO_RESUME_TOKEN)) .isEqualTo( @@ -904,7 +904,19 @@ public void statementWithSingleViewParameter() { .setPreparedQuery(EXPECTED_PREPARED_QUERY) .setInstanceName(EXPECTED_INSTANCE_NAME) .setAppProfileId(EXPECTED_APP_PROFILE) - .putViewParameters("user_id", stringVal) + .putViewParameters( + "user_id", + Value.newBuilder().setType(stringType()).setStringValue("alice").build()) .build()); } + + @Test + public void statementWithNullViewParameter() { + assertThrows( + NullPointerException.class, () -> boundStatementBuilder().setViewParameter(null, "alice")); + assertThrows( + NullPointerException.class, + () -> boundStatementBuilder().setViewParameter("user_id", null)); + assertThrows(NullPointerException.class, () -> boundStatementBuilder().setViewParameters(null)); + } } From 4c5db2254387016b8f61ea965a057bd42dff653c Mon Sep 17 00:00:00 2001 From: anweshadas Date: Tue, 7 Jul 2026 19:18:31 +0000 Subject: [PATCH 4/5] fix(bigtable): update test-proxy BoundStatementDeserializer for String view_parameters --- .../testproxy/BoundStatementDeserializer.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java b/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java index 56b40d0d5957..a4db3eda4aea 100644 --- a/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java +++ b/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java @@ -128,7 +128,16 @@ static BoundStatement toBoundStatement( throw new IllegalArgumentException("Unexpected query param type in param: " + value); } } - boundStatementBuilder.setViewParameters(request.getRequest().getViewParametersMap()); + for (Map.Entry entry : request.getRequest().getViewParametersMap().entrySet()) { + Value value = entry.getValue(); + if (value.getKindCase().equals(KindCase.STRING_VALUE)) { + boundStatementBuilder.setViewParameter(entry.getKey(), value.getStringValue()); + } else if (value.getKindCase().equals(KindCase.KIND_NOT_SET)) { + boundStatementBuilder.setViewParameter(entry.getKey(), null); + } else { + throw new IllegalArgumentException("Unexpected view parameter value: " + value); + } + } return boundStatementBuilder.build(); } From 93f98fc4f7d9594b1e551839f0de0d072e114469 Mon Sep 17 00:00:00 2001 From: anweshadas Date: Tue, 7 Jul 2026 19:27:46 +0000 Subject: [PATCH 5/5] fix(bigtable): enforce strict string requirement in BoundStatementDeserializer --- .../bigtable/testproxy/BoundStatementDeserializer.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java b/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java index a4db3eda4aea..3cbece85f3e7 100644 --- a/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java +++ b/java-bigtable/test-proxy/src/main/java/com/google/cloud/bigtable/testproxy/BoundStatementDeserializer.java @@ -132,10 +132,12 @@ static BoundStatement toBoundStatement( Value value = entry.getValue(); if (value.getKindCase().equals(KindCase.STRING_VALUE)) { boundStatementBuilder.setViewParameter(entry.getKey(), value.getStringValue()); - } else if (value.getKindCase().equals(KindCase.KIND_NOT_SET)) { - boundStatementBuilder.setViewParameter(entry.getKey(), null); } else { - throw new IllegalArgumentException("Unexpected view parameter value: " + value); + throw new IllegalArgumentException( + "View parameter '" + + entry.getKey() + + "' must be a String, got: " + + value.getKindCase()); } } return boundStatementBuilder.build();