-
Notifications
You must be signed in to change notification settings - Fork 462
feat(bigquery): support query_results_format and Arrow in QueryRequest and QueryResponse #16444
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
base: main
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ | |
|
|
||
| #include "google/cloud/bigquery/v2/minimal/internal/job_response.h" | ||
| #include "google/cloud/bigquery/v2/minimal/internal/json_utils.h" | ||
| #include "google/cloud/internal/base64_transforms.h" | ||
| #include "google/cloud/internal/debug_string.h" | ||
| #include "google/cloud/internal/make_status.h" | ||
| #include "absl/strings/str_cat.h" | ||
|
|
@@ -192,6 +193,60 @@ std::string CancelJobResponse::DebugString(absl::string_view name, | |
| .Build(); | ||
| } | ||
|
|
||
| std::string ArrowSchema::DebugString(absl::string_view name, | ||
| TracingOptions const& options, | ||
| int indent) const { | ||
| return internal::DebugFormatter(name, options, indent) | ||
| .StringField("serialized_schema", serialized_schema) | ||
| .Build(); | ||
| } | ||
|
|
||
| std::string ArrowRecordBatch::DebugString(absl::string_view name, | ||
| TracingOptions const& options, | ||
| int indent) const { | ||
| return internal::DebugFormatter(name, options, indent) | ||
| .StringField("serialized_record_batch", serialized_record_batch) | ||
| .Field("row_count", row_count) | ||
| .Build(); | ||
| } | ||
|
|
||
| void to_json(nlohmann::json& j, ArrowSchema const& a) { | ||
| j = nlohmann::json{ | ||
| {"serializedSchema", internal::UrlsafeBase64Encode(a.serialized_schema)}}; | ||
| } | ||
|
|
||
| void from_json(nlohmann::json const& j, ArrowSchema& a) { | ||
| if (j.contains("serializedSchema") && j["serializedSchema"].is_string()) { | ||
| std::string b64 = j["serializedSchema"].get<std::string>(); | ||
| auto bytes = internal::UrlsafeBase64Decode(b64); | ||
| if (bytes.ok()) { | ||
| a.serialized_schema.assign(reinterpret_cast<char const*>(bytes->data()), | ||
| bytes->size()); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void to_json(nlohmann::json& j, ArrowRecordBatch const& a) { | ||
| j = nlohmann::json{{"serializedRecordBatch", | ||
| internal::UrlsafeBase64Encode(a.serialized_record_batch)}, | ||
| {"rowCount", std::to_string(a.row_count)}}; | ||
| } | ||
|
|
||
| void from_json(nlohmann::json const& j, ArrowRecordBatch& a) { | ||
| if (j.contains("serializedRecordBatch") && | ||
| j["serializedRecordBatch"].is_string()) { | ||
| std::string b64 = j["serializedRecordBatch"].get<std::string>(); | ||
| auto bytes = internal::UrlsafeBase64Decode(b64); | ||
| if (bytes.ok()) { | ||
| a.serialized_record_batch.assign( | ||
| reinterpret_cast<char const*>(bytes->data()), bytes->size()); | ||
| } | ||
| } | ||
| if (j.contains("rowCount")) { | ||
| a.row_count = GetNumberFromJson(j, "rowCount"); | ||
| } | ||
| } | ||
|
Comment on lines
+235
to
+248
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. Similarly, if void from_json(nlohmann::json const& j, ArrowRecordBatch& a) {
if (j.contains("serializedRecordBatch") &&
j["serializedRecordBatch"].is_string()) {
std::string b64 = j["serializedRecordBatch"].get<std::string>();
auto bytes = internal::UrlsafeBase64Decode(b64);
if (bytes.ok()) {
a.serialized_record_batch.assign(
reinterpret_cast<char const*>(bytes->data()), bytes->size());
}
}
if (j.contains("rowCount")) {
a.row_count = GetNumberFromJson(j, "rowCount");
}
}References
Contributor
Author
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. Fixed in c41e2c5: Added an explicit |
||
|
|
||
| std::string PostQueryResults::DebugString(absl::string_view name, | ||
| TracingOptions const& options, | ||
| int indent) const { | ||
|
|
@@ -209,6 +264,9 @@ std::string PostQueryResults::DebugString(absl::string_view name, | |
| .SubMessage("job_reference", job_reference) | ||
| .SubMessage("session_info", session_info) | ||
| .SubMessage("dml_stats", dml_stats) | ||
| .SubMessage("arrow_schema", arrow_schema) | ||
| .SubMessage("arrow_record_batch", arrow_record_batch) | ||
| .Field("page_row_count", page_row_count) | ||
| .Build(); | ||
| } | ||
|
|
||
|
|
@@ -262,6 +320,11 @@ StatusOr<QueryResponse> QueryResponse::BuildFromHttpResponse( | |
|
|
||
| SafeGetTo(query_results.session_info, *json, "sessionInfo"); | ||
| SafeGetTo(query_results.dml_stats, *json, "dmlStats"); | ||
| SafeGetTo(query_results.arrow_schema, *json, "arrowSchema"); | ||
| SafeGetTo(query_results.arrow_record_batch, *json, "arrowRecordBatch"); | ||
| if (json->contains("pageRowCount")) { | ||
| query_results.page_row_count = GetNumberFromJson(*json, "pageRowCount"); | ||
| } | ||
|
|
||
| QueryResponse response; | ||
| response.http_response = http_response; | ||
|
|
@@ -299,6 +362,15 @@ void to_json(nlohmann::json& j, PostQueryResults const& q) { | |
| {"errors", q.errors}, | ||
| {"sessionInfo", q.session_info}, | ||
| {"dmlStats", q.dml_stats}}; | ||
| if (!q.arrow_schema.serialized_schema.empty()) { | ||
| j["arrowSchema"] = q.arrow_schema; | ||
| } | ||
| if (!q.arrow_record_batch.serialized_record_batch.empty()) { | ||
| j["arrowRecordBatch"] = q.arrow_record_batch; | ||
| } | ||
| if (q.page_row_count > 0) { | ||
| j["pageRowCount"] = std::to_string(q.page_row_count); | ||
| } | ||
| } | ||
|
|
||
| void from_json(nlohmann::json const& j, PostQueryResults& q) { | ||
|
|
@@ -315,6 +387,11 @@ void from_json(nlohmann::json const& j, PostQueryResults& q) { | |
| SafeGetTo(q.errors, j, "errors"); | ||
| SafeGetTo(q.session_info, j, "sessionInfo"); | ||
| SafeGetTo(q.dml_stats, j, "dmlStats"); | ||
| SafeGetTo(q.arrow_schema, j, "arrowSchema"); | ||
| SafeGetTo(q.arrow_record_batch, j, "arrowRecordBatch"); | ||
| if (j.contains("pageRowCount")) { | ||
| q.page_row_count = GetNumberFromJson(j, "pageRowCount"); | ||
| } | ||
| } | ||
|
|
||
| void to_json(nlohmann::json& j, GetQueryResults const& q) { | ||
|
|
@@ -330,6 +407,15 @@ void to_json(nlohmann::json& j, GetQueryResults const& q) { | |
| {"jobReference", q.job_reference}, | ||
| {"rows", q.rows}, | ||
| {"errors", q.errors}}; | ||
| if (!q.arrow_schema.serialized_schema.empty()) { | ||
| j["arrowSchema"] = q.arrow_schema; | ||
| } | ||
| if (!q.arrow_record_batch.serialized_record_batch.empty()) { | ||
| j["arrowRecordBatch"] = q.arrow_record_batch; | ||
| } | ||
| if (q.page_row_count > 0) { | ||
| j["pageRowCount"] = std::to_string(q.page_row_count); | ||
| } | ||
| } | ||
| void from_json(nlohmann::json const& j, GetQueryResults& q) { | ||
| SafeGetTo(q.kind, j, "kind"); | ||
|
|
@@ -344,6 +430,11 @@ void from_json(nlohmann::json const& j, GetQueryResults& q) { | |
| SafeGetTo(q.job_reference, j, "jobReference"); | ||
| SafeGetTo(q.rows, j, "rows"); | ||
| SafeGetTo(q.errors, j, "errors"); | ||
| SafeGetTo(q.arrow_schema, j, "arrowSchema"); | ||
| SafeGetTo(q.arrow_record_batch, j, "arrowRecordBatch"); | ||
| if (j.contains("pageRowCount")) { | ||
| q.page_row_count = GetNumberFromJson(j, "pageRowCount"); | ||
| } | ||
| } | ||
|
|
||
| std::string GetQueryResults::DebugString(absl::string_view name, | ||
|
|
@@ -362,6 +453,9 @@ std::string GetQueryResults::DebugString(absl::string_view name, | |
| .Field("errors", errors) | ||
| .SubMessage("schema", schema) | ||
| .SubMessage("job_reference", job_reference) | ||
| .SubMessage("arrow_schema", arrow_schema) | ||
| .SubMessage("arrow_record_batch", arrow_record_batch) | ||
| .Field("page_row_count", page_row_count) | ||
| .Build(); | ||
| } | ||
|
|
||
|
|
@@ -413,6 +507,12 @@ GetQueryResultsResponse::BuildFromHttpResponse( | |
| } | ||
| } | ||
|
|
||
| SafeGetTo(get_query_results.arrow_schema, *json, "arrowSchema"); | ||
| SafeGetTo(get_query_results.arrow_record_batch, *json, "arrowRecordBatch"); | ||
| if (json->contains("pageRowCount")) { | ||
| get_query_results.page_row_count = GetNumberFromJson(*json, "pageRowCount"); | ||
| } | ||
|
|
||
| GetQueryResultsResponse response; | ||
| response.http_response = http_response; | ||
| response.get_query_results = get_query_results; | ||
|
|
||
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.
If
UrlsafeBase64Decodefails, falling back to assigning the raw base64 stringb64toserialized_schemais incorrect and violates the "Demand Explosive Correctness" principle. We should not silently swallow the decoding error and populate the field with invalid (undecoded) data. If decoding fails, we should avoid populating the field with the raw base64 string, as this will cause downstream parsing errors. Additionally, prefer explicit.ok()checks on the returnedStatusOrobject.References
ok()checks, even if they seem redundant based on the current implementation of a framework, as the framework's contract may change in the future.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.
Fixed in c41e2c5: Added an explicit
bytes.ok()check and removed the fallback that assigned the raw base64 string toserialized_schemaon decode failure.