Skip to content

Commit be62a56

Browse files
committed
feat(bigtable): add support for Prepared and Bound query
1 parent a5d8a1d commit be62a56

File tree

7 files changed

+282
-1
lines changed

7 files changed

+282
-1
lines changed

google/cloud/bigtable/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ add_library(
236236
options.h
237237
polling_policy.cc
238238
polling_policy.h
239+
query.cc
240+
query.h
239241
query_row.cc
240242
query_row.h
241243
read_modify_write_rule.h
@@ -495,6 +497,7 @@ if (BUILD_TESTING)
495497
mutations_test.cc
496498
polling_policy_test.cc
497499
query_row_test.cc
500+
query_test.cc
498501
read_modify_write_rule_test.cc
499502
row_range_test.cc
500503
row_reader_test.cc

google/cloud/bigtable/bigtable_client_unit_tests.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ bigtable_client_unit_tests = [
7979
"mutations_test.cc",
8080
"polling_policy_test.cc",
8181
"query_row_test.cc",
82+
"query_test.cc",
8283
"read_modify_write_rule_test.cc",
8384
"row_range_test.cc",
8485
"row_reader_test.cc",

google/cloud/bigtable/google_cloud_cpp_bigtable.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ google_cloud_cpp_bigtable_hdrs = [
121121
"mutations.h",
122122
"options.h",
123123
"polling_policy.h",
124+
"query.h",
124125
"query_row.h",
125126
"read_modify_write_rule.h",
126127
"resource_names.h",
@@ -227,6 +228,7 @@ google_cloud_cpp_bigtable_srcs = [
227228
"mutation_batcher.cc",
228229
"mutations.cc",
229230
"polling_policy.cc",
231+
"query.cc",
230232
"query_row.cc",
231233
"resource_names.cc",
232234
"row_range.cc",

google/cloud/bigtable/query.cc

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "google/cloud/bigtable/query.h"
16+
#include "google/cloud/bigtable/sql_statement.h"
17+
18+
namespace google {
19+
namespace cloud {
20+
namespace bigtable {
21+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
22+
23+
std::string const& BoundQuery::prepared_query() const {
24+
return query_plan_->prepared_query();
25+
}
26+
27+
google::bigtable::v2::ResultSetMetadata const& BoundQuery::metadata() const {
28+
return query_plan_->metadata();
29+
}
30+
31+
std::unordered_map<std::string, Value> const& BoundQuery::parameters() const {
32+
return parameters_;
33+
}
34+
35+
InstanceResource const& BoundQuery::instance() const { return instance_; }
36+
37+
google::bigtable::v2::ExecuteQueryRequest BoundQuery::ToRequestProto() {
38+
google::bigtable::v2::ExecuteQueryRequest result;
39+
*result.mutable_prepared_query() = query_plan_->prepared_query();
40+
*result.mutable_instance_name() = instance_.FullName();
41+
*result.mutable_prepared_query() = query_plan_->prepared_query();
42+
43+
google::protobuf::Map<std::string, google::bigtable::v2::Value> parameters;
44+
for (auto const& kv : parameters_) {
45+
parameters[kv.first] =
46+
bigtable_internal::ValueInternals::ToProto(kv.second).second;
47+
}
48+
*result.mutable_params() = parameters;
49+
return result;
50+
}
51+
52+
BoundQuery PreparedQuery::BindParameters(
53+
std::unordered_map<std::string, Value> params) const {
54+
return BoundQuery(instance_, query_plan_, std::move(params));
55+
}
56+
57+
InstanceResource const& PreparedQuery::instance() const { return instance_; }
58+
SqlStatement const& PreparedQuery::sql_statement() const {
59+
return sql_statement_;
60+
}
61+
62+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
63+
} // namespace bigtable
64+
} // namespace cloud
65+
} // namespace google

google/cloud/bigtable/query.h

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_QUERY_H
16+
#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_QUERY_H
17+
18+
#include "google/cloud/bigtable/instance_resource.h"
19+
#include "google/cloud/bigtable/internal/query_plan.h"
20+
#include "google/cloud/bigtable/sql_statement.h"
21+
#include "google/cloud/bigtable/value.h"
22+
#include "google/cloud/bigtable/version.h"
23+
#include "google/cloud/completion_queue.h"
24+
#include <google/bigtable/v2/bigtable.pb.h>
25+
#include <string>
26+
#include <unordered_map>
27+
28+
namespace google {
29+
namespace cloud {
30+
namespace bigtable {
31+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
32+
33+
/**
34+
* Move only type representing a PreparedQuery with parameter values.
35+
* Created by calling PreparedQuery::BindParameters.
36+
*/
37+
class BoundQuery {
38+
public:
39+
// Copy and move.
40+
BoundQuery(BoundQuery const&) = delete;
41+
BoundQuery(BoundQuery&&) = default;
42+
BoundQuery& operator=(BoundQuery const&) = delete;
43+
BoundQuery& operator=(BoundQuery&&) = default;
44+
45+
// Accessors
46+
std::string const& prepared_query() const;
47+
google::bigtable::v2::ResultSetMetadata const& metadata() const;
48+
std::unordered_map<std::string, Value> const& parameters() const;
49+
InstanceResource const& instance() const;
50+
51+
google::bigtable::v2::ExecuteQueryRequest ToRequestProto();
52+
53+
private:
54+
friend class PreparedQuery;
55+
BoundQuery(InstanceResource instance,
56+
std::shared_ptr<bigtable_internal::QueryPlan> query_plan,
57+
std::unordered_map<std::string, Value> parameters)
58+
: instance_(std::move(instance)),
59+
query_plan_(std::move(query_plan)),
60+
parameters_(std::move(parameters)) {}
61+
62+
InstanceResource instance_;
63+
// Copy of the query_plan_ contained by the PreparedQuery that created
64+
// this BoundQuery.
65+
std::shared_ptr<bigtable_internal::QueryPlan> query_plan_;
66+
std::unordered_map<std::string, Value> parameters_;
67+
};
68+
69+
// Represents a long-lived query execution plan.
70+
// Query plans can expire and are refreshed as a background task.
71+
class PreparedQuery {
72+
public:
73+
// Creates an instance of BoundQuery using the query plan ID from the
74+
// response.
75+
BoundQuery BindParameters(
76+
std::unordered_map<std::string, Value> params) const;
77+
78+
// Accessors
79+
InstanceResource const& instance() const;
80+
SqlStatement const& sql_statement() const;
81+
82+
// While we work on the Bigtable GoogleSQL functionality, we will keep this
83+
// constructor as public, but this will be converted to private as
84+
// originally intended once other classes that orchestrate PreparedQuery
85+
// are implemented.
86+
PreparedQuery(CompletionQueue cq, InstanceResource instance,
87+
SqlStatement sql_statement,
88+
google::bigtable::v2::PrepareQueryResponse response)
89+
: instance_(std::move(instance)),
90+
sql_statement_(std::move(sql_statement)) {
91+
*response.mutable_prepared_query() = sql_statement_.sql();
92+
93+
// For now, the refresh function has no effect, and we simply return a new
94+
// prepared query response.
95+
query_plan_ = bigtable_internal::QueryPlan::Create(
96+
std::move(cq), std::move(response),
97+
[] { return google::bigtable::v2::PrepareQueryResponse{}; });
98+
}
99+
100+
private:
101+
InstanceResource instance_;
102+
SqlStatement sql_statement_;
103+
std::shared_ptr<bigtable_internal::QueryPlan> query_plan_;
104+
};
105+
106+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
107+
} // namespace bigtable
108+
} // namespace cloud
109+
} // namespace google
110+
#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_QUERY_H
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may
6+
// obtain a copy of the License at
7+
//
8+
// https://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
#include "google/cloud/bigtable/query.h"
17+
#include "google/cloud/bigtable/value.h"
18+
#include "google/cloud/testing_util/status_matchers.h"
19+
#include <algorithm>
20+
21+
namespace google {
22+
namespace cloud {
23+
namespace bigtable {
24+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
25+
namespace {
26+
using ::google::bigtable::v2::PrepareQueryResponse;
27+
28+
class BasicInputs {
29+
public:
30+
CompletionQueue cq;
31+
Project p = Project("dummy-project");
32+
InstanceResource instance = InstanceResource(p, "dummy-instance");
33+
std::string statement_contents =
34+
"SELECT * FROM my_table WHERE col1 = @val1 and col2 = @val2;";
35+
SqlStatement sql_statement = SqlStatement(statement_contents);
36+
PrepareQueryResponse response;
37+
std::unordered_map<std::string, Value> parameters = {{"val1", Value(true)},
38+
{"val2", Value(2.0)}};
39+
};
40+
41+
TEST(PreparedQuery, DefaultConstructor) {
42+
auto inputs = BasicInputs();
43+
PreparedQuery q(inputs.cq, inputs.instance, inputs.sql_statement,
44+
inputs.response);
45+
EXPECT_EQ(inputs.instance.FullName(), q.instance().FullName());
46+
EXPECT_EQ(inputs.statement_contents, q.sql_statement().sql());
47+
}
48+
49+
TEST(BoundQuery, FromPreparedQuery) {
50+
auto inputs = BasicInputs();
51+
auto response = PrepareQueryResponse();
52+
53+
// The following variables are only meant to confirm the metadata is correctly
54+
// passed down to the BoundQuery.
55+
auto metadata = std::make_unique<google::bigtable::v2::ResultSetMetadata>();
56+
auto schema = std::make_unique<google::bigtable::v2::ProtoSchema>();
57+
auto column = google::bigtable::v2::ColumnMetadata();
58+
*column.mutable_name() = "col1";
59+
schema->mutable_columns()->Add(std::move(column));
60+
metadata->set_allocated_proto_schema(schema.release());
61+
response.set_allocated_metadata(metadata.release());
62+
63+
PreparedQuery pq(inputs.cq, inputs.instance, inputs.sql_statement, response);
64+
auto bq = pq.BindParameters(inputs.parameters);
65+
EXPECT_EQ(inputs.instance.FullName(), bq.instance().FullName());
66+
EXPECT_EQ(inputs.statement_contents, bq.prepared_query());
67+
EXPECT_EQ(inputs.parameters, bq.parameters());
68+
EXPECT_TRUE(bq.metadata().has_proto_schema());
69+
EXPECT_EQ(1, bq.metadata().proto_schema().columns_size());
70+
EXPECT_EQ("col1", bq.metadata().proto_schema().columns()[0].name());
71+
}
72+
73+
TEST(BoundQuery, ToRequestProto) {
74+
auto inputs = BasicInputs();
75+
PreparedQuery pq(inputs.cq, inputs.instance, inputs.sql_statement,
76+
inputs.response);
77+
auto bq = pq.BindParameters(inputs.parameters);
78+
google::bigtable::v2::ExecuteQueryRequest proto = bq.ToRequestProto();
79+
EXPECT_EQ(inputs.instance.FullName(), proto.instance_name());
80+
EXPECT_EQ(inputs.statement_contents, proto.prepared_query());
81+
82+
// Test param contents.
83+
EXPECT_EQ(inputs.parameters.size(), proto.mutable_params()->size());
84+
85+
// The first parameter is a boolean.
86+
EXPECT_TRUE(proto.params().contains("val1"));
87+
auto val1 = proto.params().find("val1")->second;
88+
EXPECT_TRUE(val1.has_bool_value());
89+
EXPECT_EQ(true, val1.bool_value());
90+
91+
// The second parameter is a double.
92+
EXPECT_TRUE(proto.params().contains("val2"));
93+
auto val2 = proto.params().find("val2")->second;
94+
EXPECT_TRUE(val2.has_float_value());
95+
EXPECT_EQ(2.0, val2.float_value());
96+
}
97+
} // namespace
98+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
99+
} // namespace bigtable
100+
} // namespace cloud
101+
} // namespace google

google/cloud/bigtable/sql_statement.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
// Copyright 2025 Google LLC
32
//
43
// Licensed under the Apache License, Version 2.0 (the "License");

0 commit comments

Comments
 (0)