Repository navigation
feat(sqllab): Add optional pre-run query cost warnings - #45313
elizabeth-ilina wants to merge 70 commits into
Conversation
✅ Deploy Preview for superset-docs-preview ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
CodeAnt PR Risk: Medium Risk
Assessed commit: |
This reverts commit c01ed6b. Keep the shared build-system change separate from the query cost warning feature.
| """Validate replacement or retained settings without adding omitted extra.""" | ||
| assert self._model | ||
| serialized_extra = self._properties.get("extra", self._model.extra) or "{}" | ||
| if "query_cost_warning" not in serialized_extra: |
There was a problem hiding this comment.
This gate does a substring test on the raw extra string, so a JSON-escaped key ("\u0071uery_cost_warning") skips it. extra_validator only runs QueryWarningRuleSchema over the parsed value, so an update with threshold: -1 or a metric the engine doesn't support is stored without the engine/threshold validation, and the Run-time check then returns 400 for that connection. Could this test the parsed extra dict for the key instead (parsing first, as normalize_query_cost_warning already does)?
There was a problem hiding this comment.
Hey, thanks for catching this. Fixed by parsing the JSON before checking for the warning setting. Added regression coverage for escaped keys in both submitted and retained settings, including invalid thresholds and unsupported metrics.
| } | ||
| timeout = app.config["SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT"] | ||
| try: | ||
| with utils.timeout( |
There was a problem hiding this comment.
The new utils.timeout(...) wrapper around check.assess isn't covered. test_warning_known_timeout_is_unavailable has the mocked check raise SupersetTimeoutException directly, so it would still pass if this wrapper were removed or ignored SQLLAB_QUERY_COST_ESTIMATE_TIMEOUT, and a slow estimate would then block Run indefinitely. Could a command-level test patch utils.timeout and assert it is entered with the configured seconds, then that the confirm/unavailable result is returned when it raises?
There was a problem hiding this comment.
Thanks, agreed - the previous test only covered handling the exception. Updated it to check that the timeout context is entered with the configured duration, and that a timeout returns confirm/unavailable without calling the estimator.
| {"query": []}, | ||
| {"query": {"totalBytesProcessed": "1"}}, | ||
| {"rowLevelSecurityStatistics": "masked"}, | ||
| {"rowLevelSecurityStatistics": {"rowLevelSecurityApplied": "false"}}, |
There was a problem hiding this comment.
The string-valued rowLevelSecurityApplied case has no totalBytesProcessed or accuracy, so _query_cost_warning_estimate returns an unusable estimate for it even if the boolean check in bigquery.py is removed, and this assertion still passes. A regression there could let a dry run with malformed row-security metadata but a valid byte count return proceed. Could this case also include "totalBytesProcessed": "1" and "totalBytesProcessedAccuracy": "PRECISE" so it fails without the guard?
There was a problem hiding this comment.
Thanks, fixed. The case now includes a valid byte count and PRECISE accuracy, so it specifically tests the row-security guard. I also fixed a few other test issues: mock leakage between tests, cancellation assertions that ran too early, and malformed-response cases that weren't testing the intended guard.
| MagicMock(), | ||
| False, | ||
| ) | ||
| execute._set_query_limit_if_required(sql) |
There was a problem hiding this comment.
These assertions check the prepared SQL limit but not limiting_factor, so they still pass if every assignment is removed from the shared set_query_limit. The only tests that assert those values (sqllab_tests.py) are skipped, so a wrong attribution would change the truncated-result guidance with nothing failing. Could a unit test on set_query_limit assert QUERY for SQL limit 5 / dropdown 100, DROPDOWN for 500 / 100, and QUERY_AND_DROPDOWN for 100 / 100?
There was a problem hiding this comment.
Thanks, added unit coverage for all three cases, asserting both the effective limit and limiting_factor.
SUMMARY
Add optional pre-run query cost warnings to SQL Lab for BigQuery and PostgreSQL. Administrators configure a threshold per connection; users can cancel or continue when an estimate exceeds it or cannot establish whether usage is within it. Warnings are advisory, not enforced spending or resource limits.
Enable
SQLLAB_QUERY_COST_WARNINGSandESTIMATE_QUERY_COST, then open Settings > Database Connections > Edit > Advanced > SQL Lab. Enable query cost estimation and Enable pre-run warnings, enter a positive threshold, and save. Warnings are off by default, with no automatic threshold. Settings useextra.query_cost_warning; no database migration is required.EXPLAIN (FORMAT JSON)withoutANALYZE. Planner units are relative, not money, memory or execution time.A precise estimate or upper bound at or below the threshold proceeds normally. Above-threshold estimates prompt for confirmation, including conservative warnings for upper bounds. A lower bound at or below the threshold is inconclusive and also requires confirmation. Comparisons use raw values; details preserve native units and label bounds as At least or Up to.
The existing
ConfirmModaldisplays Query warning, an explanation, optional details, and Cancel / Run anyway. Missing or unreliable estimates and known timeouts explain why assessment is unavailable. Invalid settings, permission failures, malformed assessment responses and unexpected errors stop the attempt.Run keeps its normal appearance and shortcut tooltip. Enabled checks add an assessment request before execution; latency depends on the query, database and network. Disabled warnings send no assessment request. Manual estimation retains its existing formatted response.
The check uses the captured execution request and effective row limit. Cancel, Stop or relevant input changes invalidate a pending attempt; repeated confirmation submits the captured query once. Stop prevents execution but does not forcibly cancel the database estimate.
The estimate endpoint's
check_warningoption returns a sharedproceed/confirmassessment. Engine checks own settings validation, prerequisites and assessment; Run and the dialog do not interpret database metrics. Both shipped engines use a shared numeric check. A test-only nonnumeric check demonstrates extension without changing the execution workflow. Future settings types may need their own settings UI.Scope includes deliberate SQL Lab runs, selection, current-statement shortcuts, history reruns and asynchronous execution. Dashboards, scheduled queries, retries and CTAS/CVAS are excluded. Templates, multiple statements and custom SQL transformations receive an unavailable-assessment explanation. Existing authorization and native database limits still apply.
BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF
Before: SQL Lab offers manual estimation, but Run does not compare it with a connection threshold.
After: administrators configure a warning rule, and Run asks for confirmation when required.
BigQuery settings
PostgreSQL settings
PostgreSQL warning
BigQuery warning
Unavailable assessment
TESTING INSTRUCTIONS
Automated tests cover settings/import validation, engine adapters, bounds and precision, authorization, SQL preparation, timeouts, malformed responses, stale inputs and single execution after confirmation. The nonnumeric fixture checks the shared extension contract. CI results are available in the PR checks.
The screenshots use real BigQuery dry-run and PostgreSQL EXPLAIN responses through SQL Lab, plus a real unavailable assessment for multiple statements. Each dialog was cancelled; no execution request was submitted during these captures. The displayed thresholds are demonstration values, not defaults.
ADDITIONAL INFORMATION
SQLLAB_QUERY_COST_WARNINGS; the shipped numeric checks also requireESTIMATE_QUERY_COST