-
Notifications
You must be signed in to change notification settings - Fork 388
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(spanner): fix Client::OverlayQueryOptions() to merge correctly #7118
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,9 +19,7 @@ | |
#include "google/cloud/spanner/results.h" | ||
#include "google/cloud/spanner/timestamp.h" | ||
#include "google/cloud/spanner/value.h" | ||
#include "google/cloud/internal/setenv.h" | ||
#include "google/cloud/testing_util/is_proto_equal.h" | ||
#include "google/cloud/testing_util/scoped_environment.h" | ||
#include "google/cloud/testing_util/status_matchers.h" | ||
#include "absl/memory/memory.h" | ||
#include "absl/types/optional.h" | ||
|
@@ -36,6 +34,19 @@ namespace google { | |
namespace cloud { | ||
namespace spanner { | ||
inline namespace SPANNER_CLIENT_NS { | ||
|
||
class OverlayQueryOptionsTester { | ||
public: | ||
static QueryOptions OverlayQueryOptions( | ||
QueryOptions const& preferred, QueryOptions const& fallback, | ||
absl::optional<std::string> const& optimizer_version_env, | ||
absl::optional<std::string> const& optimizer_statistics_package_env) { | ||
return Client::OverlayQueryOptions(preferred, fallback, | ||
optimizer_version_env, | ||
optimizer_statistics_package_env); | ||
} | ||
}; | ||
|
||
namespace { | ||
|
||
namespace spanner_proto = ::google::spanner::v1; | ||
|
@@ -45,12 +56,9 @@ using ::google::cloud::spanner_mocks::MockResultSetSource; | |
using ::google::cloud::testing_util::IsProtoEqual; | ||
using ::google::cloud::testing_util::StatusIs; | ||
using ::google::protobuf::TextFormat; | ||
using ::testing::AnyNumber; | ||
using ::testing::ByMove; | ||
using ::testing::DoAll; | ||
using ::testing::ElementsAre; | ||
using ::testing::Eq; | ||
using ::testing::Field; | ||
using ::testing::HasSubstr; | ||
using ::testing::Return; | ||
using ::testing::SaveArg; | ||
|
@@ -1026,59 +1034,86 @@ TEST(ClientTest, ProfileQueryWithOptionsSuccess) { | |
} | ||
|
||
TEST(ClientTest, QueryOptionsOverlayPrecedence) { | ||
struct Levels { | ||
absl::optional<std::string> env; | ||
absl::optional<std::string> client; | ||
absl::optional<std::string> function; | ||
absl::optional<std::string> expected; | ||
}; | ||
std::vector<Levels> levels = { | ||
{{}, {}, {}, {}}, | ||
{"env", {}, {}, "env"}, | ||
{{}, "client", {}, "client"}, | ||
{{}, {}, "function", "function"}, | ||
{"env", "client", {}, "client"}, | ||
{"env", {}, "function", "function"}, | ||
{{}, "client", "function", "function"}, | ||
{"env", "client", "function", "function"}, | ||
}; | ||
constexpr auto OverlayQueryOptions = // NOLINT(readability-identifier-naming) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am sure you understand the tradeoffs between testing the function that computes the query options vs. verifying the correct query options are sent to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a separate test, |
||
OverlayQueryOptionsTester::OverlayQueryOptions; | ||
|
||
// Check optimizer_version. | ||
{ | ||
QueryOptions preferred; | ||
preferred.set_optimizer_version("preferred"); | ||
QueryOptions fallback; | ||
fallback.set_optimizer_version("fallback"); | ||
absl::optional<std::string> optimizer_version_env = "environment"; | ||
EXPECT_EQ(OverlayQueryOptions(preferred, fallback, optimizer_version_env, | ||
absl::nullopt) | ||
.optimizer_version(), | ||
"preferred"); | ||
preferred.set_optimizer_version(absl::nullopt); | ||
EXPECT_EQ(OverlayQueryOptions(preferred, fallback, optimizer_version_env, | ||
absl::nullopt) | ||
.optimizer_version(), | ||
"fallback"); | ||
fallback.set_optimizer_version(absl::nullopt); | ||
EXPECT_EQ(OverlayQueryOptions(preferred, fallback, optimizer_version_env, | ||
absl::nullopt) | ||
.optimizer_version(), | ||
"environment"); | ||
optimizer_version_env = absl::nullopt; | ||
EXPECT_EQ(OverlayQueryOptions(preferred, fallback, optimizer_version_env, | ||
absl::nullopt) | ||
.optimizer_version(), | ||
absl::nullopt); | ||
} | ||
|
||
auto constexpr kQueryOptionsField = &Connection::SqlParams::query_options; | ||
auto conn = std::make_shared<MockConnection>(); | ||
for (auto const& level : levels) { | ||
google::cloud::testing_util::ScopedEnvironment opt_ver_env( | ||
"SPANNER_OPTIMIZER_VERSION", level.env); | ||
google::cloud::testing_util::ScopedEnvironment opt_stats_env( | ||
"SPANNER_OPTIMIZER_STATISTICS_PACKAGE", level.env); | ||
auto client_qo = QueryOptions() | ||
.set_optimizer_version(level.client) | ||
.set_optimizer_statistics_package(level.client); | ||
Client client(conn, ClientOptions().set_query_options(client_qo)); | ||
auto expected = QueryOptions() | ||
.set_optimizer_version(level.expected) | ||
.set_optimizer_statistics_package(level.expected); | ||
EXPECT_CALL(*conn, ExecuteQuery(Field(kQueryOptionsField, Eq(expected)))) | ||
.Times(AnyNumber()); | ||
|
||
auto const qo = QueryOptions() | ||
.set_optimizer_version(level.function) | ||
.set_optimizer_statistics_package(level.function); | ||
auto const ro = Transaction::ReadOnlyOptions{}; | ||
auto const su = Transaction::SingleUseOptions{ro}; | ||
|
||
// Call all the overloads that accept QueryOptions to ensure they all work. | ||
client.ExecuteQuery(SqlStatement{}, qo); | ||
client.ExecuteQuery(su, SqlStatement{}, qo); | ||
client.ExecuteQuery(Transaction{ro}, SqlStatement{}, qo); | ||
client.ExecuteQuery(QueryPartition{}, qo); | ||
|
||
client.ProfileQuery(SqlStatement{}, qo); | ||
client.ProfileQuery(su, SqlStatement{}, qo); | ||
client.ProfileQuery(Transaction{ro}, SqlStatement{}, qo); | ||
|
||
client.ExecuteDml(Transaction{ro}, SqlStatement{}, qo); | ||
client.ProfileDml(Transaction{ro}, SqlStatement{}, qo); | ||
client.AnalyzeSql(Transaction{ro}, SqlStatement{}, qo); | ||
// Check optimizer_statistics_package. | ||
{ | ||
QueryOptions preferred; | ||
preferred.set_optimizer_statistics_package("preferred"); | ||
QueryOptions fallback; | ||
fallback.set_optimizer_statistics_package("fallback"); | ||
absl::optional<std::string> optimizer_statistics_package_env = | ||
"environment"; | ||
EXPECT_EQ(OverlayQueryOptions(preferred, fallback, absl::nullopt, | ||
optimizer_statistics_package_env) | ||
.optimizer_statistics_package(), | ||
"preferred"); | ||
preferred.set_optimizer_statistics_package(absl::nullopt); | ||
EXPECT_EQ(OverlayQueryOptions(preferred, fallback, absl::nullopt, | ||
optimizer_statistics_package_env) | ||
.optimizer_statistics_package(), | ||
"fallback"); | ||
fallback.set_optimizer_statistics_package(absl::nullopt); | ||
EXPECT_EQ(OverlayQueryOptions(preferred, fallback, absl::nullopt, | ||
optimizer_statistics_package_env) | ||
.optimizer_statistics_package(), | ||
"environment"); | ||
optimizer_statistics_package_env = absl::nullopt; | ||
EXPECT_EQ(OverlayQueryOptions(preferred, fallback, absl::nullopt, | ||
optimizer_statistics_package_env) | ||
.optimizer_statistics_package(), | ||
absl::nullopt); | ||
} | ||
|
||
// Check request_priority. | ||
{ | ||
QueryOptions preferred; | ||
preferred.set_request_priority(RequestPriority::kHigh); | ||
QueryOptions fallback; | ||
fallback.set_request_priority(RequestPriority::kLow); | ||
EXPECT_EQ( | ||
OverlayQueryOptions(preferred, fallback, absl::nullopt, absl::nullopt) | ||
.request_priority(), | ||
RequestPriority::kHigh); | ||
preferred.set_request_priority(absl::nullopt); | ||
EXPECT_EQ( | ||
OverlayQueryOptions(preferred, fallback, absl::nullopt, absl::nullopt) | ||
.request_priority(), | ||
RequestPriority::kLow); | ||
fallback.set_request_priority(absl::nullopt); | ||
EXPECT_EQ( | ||
OverlayQueryOptions(preferred, fallback, absl::nullopt, absl::nullopt) | ||
.request_priority(), | ||
absl::nullopt); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,9 @@ inline namespace SPANNER_CLIENT_NS { | |
* These QueryOptions allow users to configure features about how their SQL | ||
* queries executes on the server. | ||
* | ||
* Note: If you add an attribute here, remember to update the implementation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ugh... that will make it to the public documentation too... Can you add the comment to a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no |
||
* of Client::OverlayQueryOptions(). | ||
* | ||
* @see https://cloud.google.com/spanner/docs/reference/rest/v1/QueryOptions | ||
* @see http://cloud/spanner/docs/query-optimizer/manage-query-optimizer | ||
*/ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, put this static function in the
spanner_internal
namespace and you don't need thefriend
helper, your call.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.