Skip to content

Commit 960eda3

Browse files
google-genai-botcopybara-github
authored andcommitted
feat: Add dry_run functionality to BigQuery execute_sql tool
PiperOrigin-RevId: 814854520
1 parent 0b84d3e commit 960eda3

File tree

3 files changed

+295
-25
lines changed

3 files changed

+295
-25
lines changed

contributing/samples/bigquery/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ distributed via the `google.adk.tools.bigquery` module. These tools include:
2323

2424
1. `execute_sql`
2525

26-
Runs a SQL query in BigQuery.
26+
Runs or dry-runs a SQL query in BigQuery.
2727

2828
1. `ask_data_insights`
2929

src/google/adk/tools/bigquery/query_tool.py

Lines changed: 139 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ def execute_sql(
3737
credentials: Credentials,
3838
settings: BigQueryToolConfig,
3939
tool_context: ToolContext,
40+
dry_run: bool = False,
4041
) -> dict:
4142
"""Run a BigQuery or BigQuery ML SQL query in the project and return the result.
4243
@@ -47,12 +48,17 @@ def execute_sql(
4748
credentials (Credentials): The credentials to use for the request.
4849
settings (BigQueryToolConfig): The settings for the tool.
4950
tool_context (ToolContext): The context for the tool.
51+
dry_run (bool, default False): If True, the query will not be executed.
52+
Instead, the query will be validated and information about the query
53+
will be returned. Defaults to False.
5054
5155
Returns:
52-
dict: Dictionary representing the result of the query.
53-
If the result contains the key "result_is_likely_truncated" with
54-
value True, it means that there may be additional rows matching the
55-
query not returned in the result.
56+
dict: If `dry_run` is False, dictionary representing the result of the
57+
query. If the result contains the key "result_is_likely_truncated"
58+
with value True, it means that there may be additional rows matching
59+
the query not returned in the result.
60+
If `dry_run` is True, dictionary with "dry_run_info" field
61+
containing query information returned by BigQuery.
5662
5763
Examples:
5864
Fetch data or insights from a table:
@@ -77,6 +83,39 @@ def execute_sql(
7783
}
7884
]
7985
}
86+
87+
Validate a query and estimate costs without executing it:
88+
89+
>>> execute_sql(
90+
... "my_project",
91+
... "SELECT island FROM "
92+
... "bigquery-public-data.ml_datasets.penguins",
93+
... dry_run=True
94+
... )
95+
{
96+
"status": "SUCCESS",
97+
"dry_run_info": {
98+
"configuration": {
99+
"dryRun": True,
100+
"jobType": "QUERY",
101+
"query": {
102+
"destinationTable": {
103+
"datasetId": "_...",
104+
"projectId": "my_project",
105+
"tableId": "anon..."
106+
},
107+
"priority": "INTERACTIVE",
108+
"query": "SELECT island FROM bigquery-public-data.ml_datasets.penguins",
109+
"useLegacySql": False,
110+
"writeDisposition": "WRITE_TRUNCATE"
111+
}
112+
},
113+
"jobReference": {
114+
"location": "US",
115+
"projectId": "my_project"
116+
}
117+
}
118+
}
80119
"""
81120
try:
82121
# Validate compute project if applicable
@@ -167,6 +206,18 @@ def execute_sql(
167206
}
168207

169208
# Finally execute the query and fetch the result
209+
if dry_run:
210+
job_config_kwargs = {"dry_run": True}
211+
if bq_connection_properties:
212+
job_config_kwargs["connection_properties"] = bq_connection_properties
213+
job_config = bigquery.QueryJobConfig(**job_config_kwargs)
214+
dry_run_job = bq_client.query(
215+
query,
216+
project=project_id,
217+
job_config=job_config,
218+
)
219+
return {"status": "SUCCESS", "dry_run_info": dry_run_job.to_api_repr()}
220+
170221
job_config = (
171222
bigquery.QueryJobConfig(connection_properties=bq_connection_properties)
172223
if bq_connection_properties
@@ -214,12 +265,17 @@ def _execute_sql_write_mode(*args, **kwargs) -> dict:
214265
credentials (Credentials): The credentials to use for the request.
215266
settings (BigQueryToolConfig): The settings for the tool.
216267
tool_context (ToolContext): The context for the tool.
268+
dry_run (bool, default False): If True, the query will not be executed.
269+
Instead, the query will be validated and information about the query
270+
will be returned. Defaults to False.
217271
218272
Returns:
219-
dict: Dictionary representing the result of the query.
220-
If the result contains the key "result_is_likely_truncated" with
221-
value True, it means that there may be additional rows matching the
222-
query not returned in the result.
273+
dict: If `dry_run` is False, dictionary representing the result of the
274+
query. If the result contains the key "result_is_likely_truncated"
275+
with value True, it means that there may be additional rows matching
276+
the query not returned in the result.
277+
If `dry_run` is True, dictionary with "dry_run_info" field
278+
containing query information returned by BigQuery.
223279
224280
Examples:
225281
Fetch data or insights from a table:
@@ -245,6 +301,39 @@ def _execute_sql_write_mode(*args, **kwargs) -> dict:
245301
]
246302
}
247303
304+
Validate a query and estimate costs without executing it:
305+
306+
>>> execute_sql(
307+
... "my_project",
308+
... "SELECT island FROM "
309+
... "bigquery-public-data.ml_datasets.penguins",
310+
... dry_run=True
311+
... )
312+
{
313+
"status": "SUCCESS",
314+
"dry_run_info": {
315+
"configuration": {
316+
"dryRun": True,
317+
"jobType": "QUERY",
318+
"query": {
319+
"destinationTable": {
320+
"datasetId": "_...",
321+
"projectId": "my_project",
322+
"tableId": "anon..."
323+
},
324+
"priority": "INTERACTIVE",
325+
"query": "SELECT island FROM bigquery-public-data.ml_datasets.penguins",
326+
"useLegacySql": False,
327+
"writeDisposition": "WRITE_TRUNCATE"
328+
}
329+
},
330+
"jobReference": {
331+
"location": "US",
332+
"projectId": "my_project"
333+
}
334+
}
335+
}
336+
248337
Create a table with schema prescribed:
249338
250339
>>> execute_sql("my_project",
@@ -396,12 +485,17 @@ def _execute_sql_protected_write_mode(*args, **kwargs) -> dict:
396485
credentials (Credentials): The credentials to use for the request.
397486
settings (BigQueryToolConfig): The settings for the tool.
398487
tool_context (ToolContext): The context for the tool.
488+
dry_run (bool, default False): If True, the query will not be executed.
489+
Instead, the query will be validated and information about the query
490+
will be returned. Defaults to False.
399491
400492
Returns:
401-
dict: Dictionary representing the result of the query.
402-
If the result contains the key "result_is_likely_truncated" with
403-
value True, it means that there may be additional rows matching the
404-
query not returned in the result.
493+
dict: If `dry_run` is False, dictionary representing the result of the
494+
query. If the result contains the key "result_is_likely_truncated"
495+
with value True, it means that there may be additional rows matching
496+
the query not returned in the result.
497+
If `dry_run` is True, dictionary with "dry_run_info" field
498+
containing query information returned by BigQuery.
405499
406500
Examples:
407501
Fetch data or insights from a table:
@@ -427,6 +521,39 @@ def _execute_sql_protected_write_mode(*args, **kwargs) -> dict:
427521
]
428522
}
429523
524+
Validate a query and estimate costs without executing it:
525+
526+
>>> execute_sql(
527+
... "my_project",
528+
... "SELECT island FROM "
529+
... "bigquery-public-data.ml_datasets.penguins",
530+
... dry_run=True
531+
... )
532+
{
533+
"status": "SUCCESS",
534+
"dry_run_info": {
535+
"configuration": {
536+
"dryRun": True,
537+
"jobType": "QUERY",
538+
"query": {
539+
"destinationTable": {
540+
"datasetId": "_...",
541+
"projectId": "my_project",
542+
"tableId": "anon..."
543+
},
544+
"priority": "INTERACTIVE",
545+
"query": "SELECT island FROM bigquery-public-data.ml_datasets.penguins",
546+
"useLegacySql": False,
547+
"writeDisposition": "WRITE_TRUNCATE"
548+
}
549+
},
550+
"jobReference": {
551+
"location": "US",
552+
"projectId": "my_project"
553+
}
554+
}
555+
}
556+
430557
Create a temporary table with schema prescribed:
431558
432559
>>> execute_sql("my_project",

0 commit comments

Comments
 (0)