From 262bf70e03a719fd1c6b49b113cff1edfdb569aa Mon Sep 17 00:00:00 2001 From: diegomarquezp Date: Fri, 17 Oct 2025 19:57:45 +0000 Subject: [PATCH 1/5] feat(bigtable): add support for Prepared and Bound query --- google/cloud/bigtable/CMakeLists.txt | 3 + .../bigtable/bigtable_client_unit_tests.bzl | 1 + .../bigtable/google_cloud_cpp_bigtable.bzl | 2 + google/cloud/bigtable/query.cc | 65 +++++++++++ google/cloud/bigtable/query.h | 110 ++++++++++++++++++ google/cloud/bigtable/query_test.cc | 101 ++++++++++++++++ google/cloud/bigtable/sql_statement.h | 1 - 7 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 google/cloud/bigtable/query.cc create mode 100644 google/cloud/bigtable/query.h create mode 100644 google/cloud/bigtable/query_test.cc diff --git a/google/cloud/bigtable/CMakeLists.txt b/google/cloud/bigtable/CMakeLists.txt index a47b8fc2f6853..baa973a655140 100644 --- a/google/cloud/bigtable/CMakeLists.txt +++ b/google/cloud/bigtable/CMakeLists.txt @@ -236,6 +236,8 @@ add_library( options.h polling_policy.cc polling_policy.h + query.cc + query.h query_row.cc query_row.h read_modify_write_rule.h @@ -495,6 +497,7 @@ if (BUILD_TESTING) mutations_test.cc polling_policy_test.cc query_row_test.cc + query_test.cc read_modify_write_rule_test.cc row_range_test.cc row_reader_test.cc diff --git a/google/cloud/bigtable/bigtable_client_unit_tests.bzl b/google/cloud/bigtable/bigtable_client_unit_tests.bzl index 5864c9b6628ce..85fc5bcbb3b5b 100644 --- a/google/cloud/bigtable/bigtable_client_unit_tests.bzl +++ b/google/cloud/bigtable/bigtable_client_unit_tests.bzl @@ -79,6 +79,7 @@ bigtable_client_unit_tests = [ "mutations_test.cc", "polling_policy_test.cc", "query_row_test.cc", + "query_test.cc", "read_modify_write_rule_test.cc", "row_range_test.cc", "row_reader_test.cc", diff --git a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl index aec931b96bf9b..89041d56943d7 100644 --- a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl +++ b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl @@ -121,6 +121,7 @@ google_cloud_cpp_bigtable_hdrs = [ "mutations.h", "options.h", "polling_policy.h", + "query.h", "query_row.h", "read_modify_write_rule.h", "resource_names.h", @@ -227,6 +228,7 @@ google_cloud_cpp_bigtable_srcs = [ "mutation_batcher.cc", "mutations.cc", "polling_policy.cc", + "query.cc", "query_row.cc", "resource_names.cc", "row_range.cc", diff --git a/google/cloud/bigtable/query.cc b/google/cloud/bigtable/query.cc new file mode 100644 index 0000000000000..efd0b7f5529a3 --- /dev/null +++ b/google/cloud/bigtable/query.cc @@ -0,0 +1,65 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "google/cloud/bigtable/query.h" +#include "google/cloud/bigtable/sql_statement.h" + +namespace google { +namespace cloud { +namespace bigtable { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN + +std::string const& BoundQuery::prepared_query() const { + return query_plan_->prepared_query(); +} + +google::bigtable::v2::ResultSetMetadata const& BoundQuery::metadata() const { + return query_plan_->metadata(); +} + +std::unordered_map const& BoundQuery::parameters() const { + return parameters_; +} + +InstanceResource const& BoundQuery::instance() const { return instance_; } + +google::bigtable::v2::ExecuteQueryRequest BoundQuery::ToRequestProto() { + google::bigtable::v2::ExecuteQueryRequest result; + *result.mutable_prepared_query() = query_plan_->prepared_query(); + *result.mutable_instance_name() = instance_.FullName(); + *result.mutable_prepared_query() = query_plan_->prepared_query(); + + google::protobuf::Map parameters; + for (auto const& kv : parameters_) { + parameters[kv.first] = + bigtable_internal::ValueInternals::ToProto(kv.second).second; + } + *result.mutable_params() = parameters; + return result; +} + +BoundQuery PreparedQuery::BindParameters( + std::unordered_map params) const { + return BoundQuery(instance_, query_plan_, std::move(params)); +} + +InstanceResource const& PreparedQuery::instance() const { return instance_; } +SqlStatement const& PreparedQuery::sql_statement() const { + return sql_statement_; +} + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google diff --git a/google/cloud/bigtable/query.h b/google/cloud/bigtable/query.h new file mode 100644 index 0000000000000..8046020049260 --- /dev/null +++ b/google/cloud/bigtable/query.h @@ -0,0 +1,110 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_QUERY_H +#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_QUERY_H + +#include "google/cloud/bigtable/instance_resource.h" +#include "google/cloud/bigtable/internal/query_plan.h" +#include "google/cloud/bigtable/sql_statement.h" +#include "google/cloud/bigtable/value.h" +#include "google/cloud/bigtable/version.h" +#include "google/cloud/completion_queue.h" +#include +#include +#include + +namespace google { +namespace cloud { +namespace bigtable { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN + +/** + * Move only type representing a PreparedQuery with parameter values. + * Created by calling PreparedQuery::BindParameters. + */ +class BoundQuery { + public: + // Copy and move. + BoundQuery(BoundQuery const&) = delete; + BoundQuery(BoundQuery&&) = default; + BoundQuery& operator=(BoundQuery const&) = delete; + BoundQuery& operator=(BoundQuery&&) = default; + + // Accessors + std::string const& prepared_query() const; + google::bigtable::v2::ResultSetMetadata const& metadata() const; + std::unordered_map const& parameters() const; + InstanceResource const& instance() const; + + google::bigtable::v2::ExecuteQueryRequest ToRequestProto(); + + private: + friend class PreparedQuery; + BoundQuery(InstanceResource instance, + std::shared_ptr query_plan, + std::unordered_map parameters) + : instance_(std::move(instance)), + query_plan_(std::move(query_plan)), + parameters_(std::move(parameters)) {} + + InstanceResource instance_; + // Copy of the query_plan_ contained by the PreparedQuery that created + // this BoundQuery. + std::shared_ptr query_plan_; + std::unordered_map parameters_; +}; + +// Represents a long-lived query execution plan. +// Query plans can expire and are refreshed as a background task. +class PreparedQuery { + public: + // Creates an instance of BoundQuery using the query plan ID from the + // response. + BoundQuery BindParameters( + std::unordered_map params) const; + + // Accessors + InstanceResource const& instance() const; + SqlStatement const& sql_statement() const; + + // While we work on the Bigtable GoogleSQL functionality, we will keep this + // constructor as public, but this will be converted to private as + // originally intended once other classes that orchestrate PreparedQuery + // are implemented. + PreparedQuery(CompletionQueue cq, InstanceResource instance, + SqlStatement sql_statement, + google::bigtable::v2::PrepareQueryResponse response) + : instance_(std::move(instance)), + sql_statement_(std::move(sql_statement)) { + *response.mutable_prepared_query() = sql_statement_.sql(); + + // For now, the refresh function has no effect, and we simply return a new + // prepared query response. + query_plan_ = bigtable_internal::QueryPlan::Create( + std::move(cq), std::move(response), + [] { return google::bigtable::v2::PrepareQueryResponse{}; }); + } + + private: + InstanceResource instance_; + SqlStatement sql_statement_; + std::shared_ptr query_plan_; +}; + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google +#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_QUERY_H diff --git a/google/cloud/bigtable/query_test.cc b/google/cloud/bigtable/query_test.cc new file mode 100644 index 0000000000000..53d14805ad960 --- /dev/null +++ b/google/cloud/bigtable/query_test.cc @@ -0,0 +1,101 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may +// obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "google/cloud/bigtable/query.h" +#include "google/cloud/bigtable/value.h" +#include "google/cloud/testing_util/status_matchers.h" +#include + +namespace google { +namespace cloud { +namespace bigtable { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN +namespace { +using ::google::bigtable::v2::PrepareQueryResponse; + +class BasicInputs { + public: + CompletionQueue cq; + Project p = Project("dummy-project"); + InstanceResource instance = InstanceResource(p, "dummy-instance"); + std::string statement_contents = + "SELECT * FROM my_table WHERE col1 = @val1 and col2 = @val2;"; + SqlStatement sql_statement = SqlStatement(statement_contents); + PrepareQueryResponse response; + std::unordered_map parameters = {{"val1", Value(true)}, + {"val2", Value(2.0)}}; +}; + +TEST(PreparedQuery, DefaultConstructor) { + auto inputs = BasicInputs(); + PreparedQuery q(inputs.cq, inputs.instance, inputs.sql_statement, + inputs.response); + EXPECT_EQ(inputs.instance.FullName(), q.instance().FullName()); + EXPECT_EQ(inputs.statement_contents, q.sql_statement().sql()); +} + +TEST(BoundQuery, FromPreparedQuery) { + auto inputs = BasicInputs(); + auto response = PrepareQueryResponse(); + + // The following variables are only meant to confirm the metadata is correctly + // passed down to the BoundQuery. + auto metadata = std::make_unique(); + auto schema = std::make_unique(); + auto column = google::bigtable::v2::ColumnMetadata(); + *column.mutable_name() = "col1"; + schema->mutable_columns()->Add(std::move(column)); + metadata->set_allocated_proto_schema(schema.release()); + response.set_allocated_metadata(metadata.release()); + + PreparedQuery pq(inputs.cq, inputs.instance, inputs.sql_statement, response); + auto bq = pq.BindParameters(inputs.parameters); + EXPECT_EQ(inputs.instance.FullName(), bq.instance().FullName()); + EXPECT_EQ(inputs.statement_contents, bq.prepared_query()); + EXPECT_EQ(inputs.parameters, bq.parameters()); + EXPECT_TRUE(bq.metadata().has_proto_schema()); + EXPECT_EQ(1, bq.metadata().proto_schema().columns_size()); + EXPECT_EQ("col1", bq.metadata().proto_schema().columns()[0].name()); +} + +TEST(BoundQuery, ToRequestProto) { + auto inputs = BasicInputs(); + PreparedQuery pq(inputs.cq, inputs.instance, inputs.sql_statement, + inputs.response); + auto bq = pq.BindParameters(inputs.parameters); + google::bigtable::v2::ExecuteQueryRequest proto = bq.ToRequestProto(); + EXPECT_EQ(inputs.instance.FullName(), proto.instance_name()); + EXPECT_EQ(inputs.statement_contents, proto.prepared_query()); + + // Test param contents. + EXPECT_EQ(inputs.parameters.size(), proto.mutable_params()->size()); + + // The first parameter is a boolean. + EXPECT_TRUE(proto.params().contains("val1")); + auto val1 = proto.params().find("val1")->second; + EXPECT_TRUE(val1.has_bool_value()); + EXPECT_EQ(true, val1.bool_value()); + + // The second parameter is a double. + EXPECT_TRUE(proto.params().contains("val2")); + auto val2 = proto.params().find("val2")->second; + EXPECT_TRUE(val2.has_float_value()); + EXPECT_EQ(2.0, val2.float_value()); +} +} // namespace +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google diff --git a/google/cloud/bigtable/sql_statement.h b/google/cloud/bigtable/sql_statement.h index ff5d4568630e3..0b184cddaeb79 100644 --- a/google/cloud/bigtable/sql_statement.h +++ b/google/cloud/bigtable/sql_statement.h @@ -1,4 +1,3 @@ - // Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); From d0bc36a0813522a31458d55f0ac193fee25fa1b0 Mon Sep 17 00:00:00 2001 From: diegomarquezp Date: Wed, 22 Oct 2025 21:25:27 +0000 Subject: [PATCH 2/5] chore: decompose BasicInputs for readability --- google/cloud/bigtable/query_test.cc | 72 ++++++++++++++++------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/google/cloud/bigtable/query_test.cc b/google/cloud/bigtable/query_test.cc index 53d14805ad960..277adc3ded265 100644 --- a/google/cloud/bigtable/query_test.cc +++ b/google/cloud/bigtable/query_test.cc @@ -2,8 +2,7 @@ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. -// You may -// obtain a copy of the License at +// You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // @@ -25,30 +24,29 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN namespace { using ::google::bigtable::v2::PrepareQueryResponse; -class BasicInputs { - public: +TEST(PreparedQuery, DefaultConstructor) { CompletionQueue cq; - Project p = Project("dummy-project"); - InstanceResource instance = InstanceResource(p, "dummy-instance"); - std::string statement_contents = - "SELECT * FROM my_table WHERE col1 = @val1 and col2 = @val2;"; - SqlStatement sql_statement = SqlStatement(statement_contents); + Project p("dummy-project"); + InstanceResource instance(p, "dummy-instance"); + std::string statement_contents( + "SELECT * FROM my_table WHERE col1 = @val1 and col2 = @val2;"); + SqlStatement sql_statement(statement_contents); PrepareQueryResponse response; - std::unordered_map parameters = {{"val1", Value(true)}, - {"val2", Value(2.0)}}; -}; - -TEST(PreparedQuery, DefaultConstructor) { - auto inputs = BasicInputs(); - PreparedQuery q(inputs.cq, inputs.instance, inputs.sql_statement, - inputs.response); - EXPECT_EQ(inputs.instance.FullName(), q.instance().FullName()); - EXPECT_EQ(inputs.statement_contents, q.sql_statement().sql()); + PreparedQuery q(cq, instance, sql_statement, response); + EXPECT_EQ(instance.FullName(), q.instance().FullName()); + EXPECT_EQ(statement_contents, q.sql_statement().sql()); } TEST(BoundQuery, FromPreparedQuery) { - auto inputs = BasicInputs(); - auto response = PrepareQueryResponse(); + CompletionQueue cq; + Project p("dummy-project"); + InstanceResource instance(p, "dummy-instance"); + std::string statement_contents( + "SELECT * FROM my_table WHERE col1 = @val1 and col2 = @val2;"); + SqlStatement sql_statement(statement_contents); + PrepareQueryResponse response; + std::unordered_map parameters = {{"val1", Value(true)}, + {"val2", Value(2.0)}}; // The following variables are only meant to confirm the metadata is correctly // passed down to the BoundQuery. @@ -60,27 +58,35 @@ TEST(BoundQuery, FromPreparedQuery) { metadata->set_allocated_proto_schema(schema.release()); response.set_allocated_metadata(metadata.release()); - PreparedQuery pq(inputs.cq, inputs.instance, inputs.sql_statement, response); - auto bq = pq.BindParameters(inputs.parameters); - EXPECT_EQ(inputs.instance.FullName(), bq.instance().FullName()); - EXPECT_EQ(inputs.statement_contents, bq.prepared_query()); - EXPECT_EQ(inputs.parameters, bq.parameters()); + PreparedQuery pq(cq, instance, sql_statement, response); + auto bq = pq.BindParameters(parameters); + EXPECT_EQ(instance.FullName(), bq.instance().FullName()); + EXPECT_EQ(statement_contents, bq.prepared_query()); + EXPECT_EQ(parameters, bq.parameters()); EXPECT_TRUE(bq.metadata().has_proto_schema()); EXPECT_EQ(1, bq.metadata().proto_schema().columns_size()); EXPECT_EQ("col1", bq.metadata().proto_schema().columns()[0].name()); } TEST(BoundQuery, ToRequestProto) { - auto inputs = BasicInputs(); - PreparedQuery pq(inputs.cq, inputs.instance, inputs.sql_statement, - inputs.response); - auto bq = pq.BindParameters(inputs.parameters); + CompletionQueue cq; + Project p("dummy-project"); + InstanceResource instance(p, "dummy-instance"); + std::string statement_contents( + "SELECT * FROM my_table WHERE col1 = @val1 and col2 = @val2;"); + SqlStatement sql_statement(statement_contents); + PrepareQueryResponse response; + std::unordered_map parameters = {{"val1", Value(true)}, + {"val2", Value(2.0)}}; + + PreparedQuery pq(cq, instance, sql_statement, response); + auto bq = pq.BindParameters(parameters); google::bigtable::v2::ExecuteQueryRequest proto = bq.ToRequestProto(); - EXPECT_EQ(inputs.instance.FullName(), proto.instance_name()); - EXPECT_EQ(inputs.statement_contents, proto.prepared_query()); + EXPECT_EQ(instance.FullName(), proto.instance_name()); + EXPECT_EQ(statement_contents, proto.prepared_query()); // Test param contents. - EXPECT_EQ(inputs.parameters.size(), proto.mutable_params()->size()); + EXPECT_EQ(parameters.size(), proto.mutable_params()->size()); // The first parameter is a boolean. EXPECT_TRUE(proto.params().contains("val1")); From df1873aab2115e326b464cc109d93d60ba02e21d Mon Sep 17 00:00:00 2001 From: diegomarquezp Date: Wed, 22 Oct 2025 21:51:46 +0000 Subject: [PATCH 3/5] chore: separate into respective files --- google/cloud/bigtable/CMakeLists.txt | 5 +- .../bigtable/bigtable_client_unit_tests.bzl | 3 +- .../bigtable/{query.cc => bound_query.cc} | 13 +--- google/cloud/bigtable/bound_query.h | 72 +++++++++++++++++++ .../{query_test.cc => bound_query_test.cc} | 15 +--- .../bigtable/google_cloud_cpp_bigtable.bzl | 5 +- google/cloud/bigtable/prepared_query.cc | 36 ++++++++++ .../bigtable/{query.h => prepared_query.h} | 44 ++---------- google/cloud/bigtable/prepared_query_test.cc | 44 ++++++++++++ 9 files changed, 168 insertions(+), 69 deletions(-) rename google/cloud/bigtable/{query.cc => bound_query.cc} (80%) create mode 100644 google/cloud/bigtable/bound_query.h rename google/cloud/bigtable/{query_test.cc => bound_query_test.cc} (87%) create mode 100644 google/cloud/bigtable/prepared_query.cc rename google/cloud/bigtable/{query.h => prepared_query.h} (63%) create mode 100644 google/cloud/bigtable/prepared_query_test.cc diff --git a/google/cloud/bigtable/CMakeLists.txt b/google/cloud/bigtable/CMakeLists.txt index baa973a655140..1bfc2e77de730 100644 --- a/google/cloud/bigtable/CMakeLists.txt +++ b/google/cloud/bigtable/CMakeLists.txt @@ -109,6 +109,8 @@ add_library( app_profile_config.cc app_profile_config.h async_row_reader.h + bound_query.cc + bound_query.h bytes.cc bytes.h cell.h @@ -236,8 +238,9 @@ add_library( options.h polling_policy.cc polling_policy.h + prepared_query.cc + prepared_query.h query.cc - query.h query_row.cc query_row.h read_modify_write_rule.h diff --git a/google/cloud/bigtable/bigtable_client_unit_tests.bzl b/google/cloud/bigtable/bigtable_client_unit_tests.bzl index 85fc5bcbb3b5b..7561f03849126 100644 --- a/google/cloud/bigtable/bigtable_client_unit_tests.bzl +++ b/google/cloud/bigtable/bigtable_client_unit_tests.bzl @@ -21,6 +21,7 @@ bigtable_client_unit_tests = [ "app_profile_config_test.cc", "async_read_stream_test.cc", "bigtable_version_test.cc", + "bound_query_test.cc", "bytes_test.cc", "cell_test.cc", "client_options_test.cc", @@ -78,8 +79,8 @@ bigtable_client_unit_tests = [ "mutation_batcher_test.cc", "mutations_test.cc", "polling_policy_test.cc", + "prepared_query_test.cc", "query_row_test.cc", - "query_test.cc", "read_modify_write_rule_test.cc", "row_range_test.cc", "row_reader_test.cc", diff --git a/google/cloud/bigtable/query.cc b/google/cloud/bigtable/bound_query.cc similarity index 80% rename from google/cloud/bigtable/query.cc rename to google/cloud/bigtable/bound_query.cc index efd0b7f5529a3..7c8e517e664c6 100644 --- a/google/cloud/bigtable/query.cc +++ b/google/cloud/bigtable/bound_query.cc @@ -12,8 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "google/cloud/bigtable/query.h" -#include "google/cloud/bigtable/sql_statement.h" +#include "google/cloud/bigtable/bound_query.h" namespace google { namespace cloud { @@ -49,16 +48,6 @@ google::bigtable::v2::ExecuteQueryRequest BoundQuery::ToRequestProto() { return result; } -BoundQuery PreparedQuery::BindParameters( - std::unordered_map params) const { - return BoundQuery(instance_, query_plan_, std::move(params)); -} - -InstanceResource const& PreparedQuery::instance() const { return instance_; } -SqlStatement const& PreparedQuery::sql_statement() const { - return sql_statement_; -} - GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace bigtable } // namespace cloud diff --git a/google/cloud/bigtable/bound_query.h b/google/cloud/bigtable/bound_query.h new file mode 100644 index 0000000000000..7e242179c2d5a --- /dev/null +++ b/google/cloud/bigtable/bound_query.h @@ -0,0 +1,72 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_BOUND_QUERY_H +#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_BOUND_QUERY_H + +#include "google/cloud/bigtable/instance_resource.h" +#include "google/cloud/bigtable/internal/query_plan.h" +#include "google/cloud/bigtable/value.h" +#include "google/cloud/bigtable/version.h" +#include "google/cloud/completion_queue.h" +#include +#include +#include + +namespace google { +namespace cloud { +namespace bigtable { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN + +/** + * Move only type representing a PreparedQuery with parameter values. + * Created by calling PreparedQuery::BindParameters. + */ +class BoundQuery { + public: + // Copy and move. + BoundQuery(BoundQuery const&) = delete; + BoundQuery(BoundQuery&&) = default; + BoundQuery& operator=(BoundQuery const&) = delete; + BoundQuery& operator=(BoundQuery&&) = default; + + // Accessors + std::string const& prepared_query() const; + google::bigtable::v2::ResultSetMetadata const& metadata() const; + std::unordered_map const& parameters() const; + InstanceResource const& instance() const; + + google::bigtable::v2::ExecuteQueryRequest ToRequestProto(); + + private: + friend class PreparedQuery; + BoundQuery(InstanceResource instance, + std::shared_ptr query_plan, + std::unordered_map parameters) + : instance_(std::move(instance)), + query_plan_(std::move(query_plan)), + parameters_(std::move(parameters)) {} + + InstanceResource instance_; + // Copy of the query_plan_ contained by the PreparedQuery that created + // this BoundQuery. + std::shared_ptr query_plan_; + std::unordered_map parameters_; +}; + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google +#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_BOUND_QUERY_H diff --git a/google/cloud/bigtable/query_test.cc b/google/cloud/bigtable/bound_query_test.cc similarity index 87% rename from google/cloud/bigtable/query_test.cc rename to google/cloud/bigtable/bound_query_test.cc index 277adc3ded265..55813cd5d4124 100644 --- a/google/cloud/bigtable/query_test.cc +++ b/google/cloud/bigtable/bound_query_test.cc @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "google/cloud/bigtable/query.h" +#include "google/cloud/bigtable/bound_query.h" #include "google/cloud/bigtable/value.h" #include "google/cloud/testing_util/status_matchers.h" #include @@ -24,19 +24,6 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN namespace { using ::google::bigtable::v2::PrepareQueryResponse; -TEST(PreparedQuery, DefaultConstructor) { - CompletionQueue cq; - Project p("dummy-project"); - InstanceResource instance(p, "dummy-instance"); - std::string statement_contents( - "SELECT * FROM my_table WHERE col1 = @val1 and col2 = @val2;"); - SqlStatement sql_statement(statement_contents); - PrepareQueryResponse response; - PreparedQuery q(cq, instance, sql_statement, response); - EXPECT_EQ(instance.FullName(), q.instance().FullName()); - EXPECT_EQ(statement_contents, q.sql_statement().sql()); -} - TEST(BoundQuery, FromPreparedQuery) { CompletionQueue cq; Project p("dummy-project"); diff --git a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl index 89041d56943d7..5f8178fa2ec3f 100644 --- a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl +++ b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl @@ -48,6 +48,7 @@ google_cloud_cpp_bigtable_hdrs = [ "admin_client.h", "app_profile_config.h", "async_row_reader.h", + "bound_query.h", "bytes.h", "cell.h", "client_options.h", @@ -121,7 +122,7 @@ google_cloud_cpp_bigtable_hdrs = [ "mutations.h", "options.h", "polling_policy.h", - "query.h", + "prepared_query.h", "query_row.h", "read_modify_write_rule.h", "resource_names.h", @@ -174,6 +175,7 @@ google_cloud_cpp_bigtable_srcs = [ "admin/internal/bigtable_table_admin_tracing_stub.cc", "admin_client.cc", "app_profile_config.cc", + "bound_query.cc", "bytes.cc", "client_options.cc", "cluster_config.cc", @@ -228,6 +230,7 @@ google_cloud_cpp_bigtable_srcs = [ "mutation_batcher.cc", "mutations.cc", "polling_policy.cc", + "prepared_query.cc", "query.cc", "query_row.cc", "resource_names.cc", diff --git a/google/cloud/bigtable/prepared_query.cc b/google/cloud/bigtable/prepared_query.cc new file mode 100644 index 0000000000000..fae34f30d7ff1 --- /dev/null +++ b/google/cloud/bigtable/prepared_query.cc @@ -0,0 +1,36 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "google/cloud/bigtable/prepared_query.h" +#include "google/cloud/bigtable/sql_statement.h" + +namespace google { +namespace cloud { +namespace bigtable { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN + +BoundQuery PreparedQuery::BindParameters( + std::unordered_map params) const { + return BoundQuery(instance_, query_plan_, std::move(params)); +} + +InstanceResource const& PreparedQuery::instance() const { return instance_; } +SqlStatement const& PreparedQuery::sql_statement() const { + return sql_statement_; +} + +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google diff --git a/google/cloud/bigtable/query.h b/google/cloud/bigtable/prepared_query.h similarity index 63% rename from google/cloud/bigtable/query.h rename to google/cloud/bigtable/prepared_query.h index 8046020049260..3005caa2411ae 100644 --- a/google/cloud/bigtable/query.h +++ b/google/cloud/bigtable/prepared_query.h @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_QUERY_H -#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_QUERY_H +#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_PREPARED_QUERY_H +#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_PREPARED_QUERY_H +#include "google/cloud/bigtable/bound_query.h" #include "google/cloud/bigtable/instance_resource.h" #include "google/cloud/bigtable/internal/query_plan.h" -#include "google/cloud/bigtable/sql_statement.h" #include "google/cloud/bigtable/value.h" #include "google/cloud/bigtable/version.h" #include "google/cloud/completion_queue.h" @@ -30,42 +30,6 @@ namespace cloud { namespace bigtable { GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -/** - * Move only type representing a PreparedQuery with parameter values. - * Created by calling PreparedQuery::BindParameters. - */ -class BoundQuery { - public: - // Copy and move. - BoundQuery(BoundQuery const&) = delete; - BoundQuery(BoundQuery&&) = default; - BoundQuery& operator=(BoundQuery const&) = delete; - BoundQuery& operator=(BoundQuery&&) = default; - - // Accessors - std::string const& prepared_query() const; - google::bigtable::v2::ResultSetMetadata const& metadata() const; - std::unordered_map const& parameters() const; - InstanceResource const& instance() const; - - google::bigtable::v2::ExecuteQueryRequest ToRequestProto(); - - private: - friend class PreparedQuery; - BoundQuery(InstanceResource instance, - std::shared_ptr query_plan, - std::unordered_map parameters) - : instance_(std::move(instance)), - query_plan_(std::move(query_plan)), - parameters_(std::move(parameters)) {} - - InstanceResource instance_; - // Copy of the query_plan_ contained by the PreparedQuery that created - // this BoundQuery. - std::shared_ptr query_plan_; - std::unordered_map parameters_; -}; - // Represents a long-lived query execution plan. // Query plans can expire and are refreshed as a background task. class PreparedQuery { @@ -107,4 +71,4 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace bigtable } // namespace cloud } // namespace google -#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_QUERY_H +#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_PREPARED_QUERY_H diff --git a/google/cloud/bigtable/prepared_query_test.cc b/google/cloud/bigtable/prepared_query_test.cc new file mode 100644 index 0000000000000..551578576a1c4 --- /dev/null +++ b/google/cloud/bigtable/prepared_query_test.cc @@ -0,0 +1,44 @@ +// Copyright 2025 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "google/cloud/bigtable/query.h" +#include "google/cloud/bigtable/value.h" +#include "google/cloud/testing_util/status_matchers.h" +#include + +namespace google { +namespace cloud { +namespace bigtable { +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN +namespace { +using ::google::bigtable::v2::PrepareQueryResponse; + +TEST(PreparedQuery, DefaultConstructor) { + CompletionQueue cq; + Project p("dummy-project"); + InstanceResource instance(p, "dummy-instance"); + std::string statement_contents( + "SELECT * FROM my_table WHERE col1 = @val1 and col2 = @val2;"); + SqlStatement sql_statement(statement_contents); + PrepareQueryResponse response; + PreparedQuery q(cq, instance, sql_statement, response); + EXPECT_EQ(instance.FullName(), q.instance().FullName()); + EXPECT_EQ(statement_contents, q.sql_statement().sql()); +} + +} // namespace +GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END +} // namespace bigtable +} // namespace cloud +} // namespace google From b11b3a5fd10060cfeda3058b183d15625063f829 Mon Sep 17 00:00:00 2001 From: diegomarquezp Date: Wed, 22 Oct 2025 22:11:28 +0000 Subject: [PATCH 4/5] chore: configure bazel and makefile --- google/cloud/bigtable/CMakeLists.txt | 4 ++-- google/cloud/bigtable/bound_query_test.cc | 2 ++ google/cloud/bigtable/google_cloud_cpp_bigtable.bzl | 1 - google/cloud/bigtable/prepared_query.h | 1 + google/cloud/bigtable/prepared_query_test.cc | 3 ++- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/google/cloud/bigtable/CMakeLists.txt b/google/cloud/bigtable/CMakeLists.txt index 1bfc2e77de730..e43bc7f4973c7 100644 --- a/google/cloud/bigtable/CMakeLists.txt +++ b/google/cloud/bigtable/CMakeLists.txt @@ -240,7 +240,6 @@ add_library( polling_policy.h prepared_query.cc prepared_query.h - query.cc query_row.cc query_row.h read_modify_write_rule.h @@ -442,6 +441,7 @@ if (BUILD_TESTING) app_profile_config_test.cc async_read_stream_test.cc bigtable_version_test.cc + bound_query_test.cc bytes_test.cc cell_test.cc client_options_test.cc @@ -499,8 +499,8 @@ if (BUILD_TESTING) mutation_batcher_test.cc mutations_test.cc polling_policy_test.cc + prepared_query_test.cc query_row_test.cc - query_test.cc read_modify_write_rule_test.cc row_range_test.cc row_reader_test.cc diff --git a/google/cloud/bigtable/bound_query_test.cc b/google/cloud/bigtable/bound_query_test.cc index 55813cd5d4124..8d8303e80ac25 100644 --- a/google/cloud/bigtable/bound_query_test.cc +++ b/google/cloud/bigtable/bound_query_test.cc @@ -13,6 +13,8 @@ // limitations under the License. #include "google/cloud/bigtable/bound_query.h" +#include "google/cloud/bigtable/prepared_query.h" +#include "google/cloud/bigtable/sql_statement.h" #include "google/cloud/bigtable/value.h" #include "google/cloud/testing_util/status_matchers.h" #include diff --git a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl index 5f8178fa2ec3f..a108700cd49cb 100644 --- a/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl +++ b/google/cloud/bigtable/google_cloud_cpp_bigtable.bzl @@ -231,7 +231,6 @@ google_cloud_cpp_bigtable_srcs = [ "mutations.cc", "polling_policy.cc", "prepared_query.cc", - "query.cc", "query_row.cc", "resource_names.cc", "row_range.cc", diff --git a/google/cloud/bigtable/prepared_query.h b/google/cloud/bigtable/prepared_query.h index 3005caa2411ae..b27a53acdef6e 100644 --- a/google/cloud/bigtable/prepared_query.h +++ b/google/cloud/bigtable/prepared_query.h @@ -18,6 +18,7 @@ #include "google/cloud/bigtable/bound_query.h" #include "google/cloud/bigtable/instance_resource.h" #include "google/cloud/bigtable/internal/query_plan.h" +#include "google/cloud/bigtable/sql_statement.h" #include "google/cloud/bigtable/value.h" #include "google/cloud/bigtable/version.h" #include "google/cloud/completion_queue.h" diff --git a/google/cloud/bigtable/prepared_query_test.cc b/google/cloud/bigtable/prepared_query_test.cc index 551578576a1c4..70b5e2e734d49 100644 --- a/google/cloud/bigtable/prepared_query_test.cc +++ b/google/cloud/bigtable/prepared_query_test.cc @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "google/cloud/bigtable/query.h" +#include "google/cloud/bigtable/prepared_query.h" +#include "google/cloud/bigtable/sql_statement.h" #include "google/cloud/bigtable/value.h" #include "google/cloud/testing_util/status_matchers.h" #include From 15935d53eee018910df5b07fb54e787fe76477ea Mon Sep 17 00:00:00 2001 From: diegomarquezp Date: Thu, 23 Oct 2025 15:55:35 +0000 Subject: [PATCH 5/5] chore: fix compilation error --- google/cloud/bigtable/bound_query.cc | 10 ++++++---- google/cloud/bigtable/bound_query.h | 4 ++-- google/cloud/bigtable/bound_query_test.cc | 10 ++++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/google/cloud/bigtable/bound_query.cc b/google/cloud/bigtable/bound_query.cc index 7c8e517e664c6..00a7007d9d2b7 100644 --- a/google/cloud/bigtable/bound_query.cc +++ b/google/cloud/bigtable/bound_query.cc @@ -19,11 +19,11 @@ namespace cloud { namespace bigtable { GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN -std::string const& BoundQuery::prepared_query() const { +StatusOr BoundQuery::prepared_query() const { return query_plan_->prepared_query(); } -google::bigtable::v2::ResultSetMetadata const& BoundQuery::metadata() const { +StatusOr BoundQuery::metadata() const { return query_plan_->metadata(); } @@ -35,9 +35,11 @@ InstanceResource const& BoundQuery::instance() const { return instance_; } google::bigtable::v2::ExecuteQueryRequest BoundQuery::ToRequestProto() { google::bigtable::v2::ExecuteQueryRequest result; - *result.mutable_prepared_query() = query_plan_->prepared_query(); *result.mutable_instance_name() = instance_.FullName(); - *result.mutable_prepared_query() = query_plan_->prepared_query(); + auto prepared_query = query_plan_->prepared_query(); + if (prepared_query.ok()) { + *result.mutable_prepared_query() = query_plan_->prepared_query().value(); + } google::protobuf::Map parameters; for (auto const& kv : parameters_) { diff --git a/google/cloud/bigtable/bound_query.h b/google/cloud/bigtable/bound_query.h index 7e242179c2d5a..9d8ba8a0fdd87 100644 --- a/google/cloud/bigtable/bound_query.h +++ b/google/cloud/bigtable/bound_query.h @@ -42,8 +42,8 @@ class BoundQuery { BoundQuery& operator=(BoundQuery&&) = default; // Accessors - std::string const& prepared_query() const; - google::bigtable::v2::ResultSetMetadata const& metadata() const; + StatusOr prepared_query() const; + StatusOr metadata() const; std::unordered_map const& parameters() const; InstanceResource const& instance() const; diff --git a/google/cloud/bigtable/bound_query_test.cc b/google/cloud/bigtable/bound_query_test.cc index 8d8303e80ac25..0607734708cfb 100644 --- a/google/cloud/bigtable/bound_query_test.cc +++ b/google/cloud/bigtable/bound_query_test.cc @@ -50,11 +50,13 @@ TEST(BoundQuery, FromPreparedQuery) { PreparedQuery pq(cq, instance, sql_statement, response); auto bq = pq.BindParameters(parameters); EXPECT_EQ(instance.FullName(), bq.instance().FullName()); - EXPECT_EQ(statement_contents, bq.prepared_query()); + EXPECT_STATUS_OK(bq.prepared_query()); + EXPECT_EQ(statement_contents, bq.prepared_query().value()); EXPECT_EQ(parameters, bq.parameters()); - EXPECT_TRUE(bq.metadata().has_proto_schema()); - EXPECT_EQ(1, bq.metadata().proto_schema().columns_size()); - EXPECT_EQ("col1", bq.metadata().proto_schema().columns()[0].name()); + EXPECT_STATUS_OK(bq.metadata()); + EXPECT_TRUE(bq.metadata().value().has_proto_schema()); + EXPECT_EQ(1, bq.metadata().value().proto_schema().columns_size()); + EXPECT_EQ("col1", bq.metadata().value().proto_schema().columns()[0].name()); } TEST(BoundQuery, ToRequestProto) {