Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
874ee59
Add some initial implementations for POC and proposal.
elizabeth-ilina Oct 5, 2026
916d13f
Merge branch 'master' into feat/bigquery-cost-warnings
elizabeth-ilina Oct 15, 2026
05aa187
feat(sqllab): add raw query cost warning hooks
AlankritVerma01 Oct 18, 2026
987216e
feat(bigquery): estimate SQL Lab usage with execution settings
AlankritVerma01 Oct 18, 2026
7c8c984
feat(postgres): read planner cost for SQL Lab warnings
AlankritVerma01 Oct 18, 2026
a865897
feat(database): validate SQL Lab query cost warning rules
AlankritVerma01 Oct 18, 2026
224979b
feat(database): configure native SQL Lab warning thresholds
AlankritVerma01 Oct 18, 2026
64bad17
feat(sqllab): check advisory query cost warnings
AlankritVerma01 Oct 18, 2026
606c941
feat(database): restore warning units with exact byte validation
AlankritVerma01 Oct 18, 2026
dccac2a
fix(database): remove obsolete expandable height transitions
AlankritVerma01 Oct 18, 2026
c1ac754
feat(sqllab): confirm captured Run requests against cost warnings
AlankritVerma01 Oct 18, 2026
56aa312
fix(sqllab): capture current statement without changing selection
AlankritVerma01 Oct 18, 2026
9dfad9d
feat(sqllab): check explicit history reruns before execution
AlankritVerma01 Oct 18, 2026
215f29f
fix(database): preserve warning-only import settings
AlankritVerma01 Oct 18, 2026
7c2335a
fix(sqllab): align warning responses and generated contracts
AlankritVerma01 Oct 18, 2026
a89b8ac
docs(sqllab): explain warning setup and estimation limits
AlankritVerma01 Oct 18, 2026
25834e3
refactor(sqllab): remove draft warning settings compatibility
AlankritVerma01 Oct 19, 2026
84b72c2
refactor(sqllab): remove unused raw estimate option
AlankritVerma01 Oct 19, 2026
aa98b2a
fix(database): preserve extra replacement semantics for cost warnings
AlankritVerma01 Oct 19, 2026
88b5b42
fix(sqllab): skip cost checks for disabled warning rules
AlankritVerma01 Oct 19, 2026
c35b9d1
chore: merge apache master and regenerate translations
AlankritVerma01 Oct 19, 2026
6294ebb
fix(bigquery): match warning SQL to DBAPI execution formatting
AlankritVerma01 Oct 19, 2026
b9223a7
refactor(database): simplify query cost warning settings updates
AlankritVerma01 Oct 19, 2026
e1159ff
refactor(sqllab): centralize query cost warning metrics
AlankritVerma01 Oct 19, 2026
0a9b431
chore(docker): remove query cost estimation demo flag
AlankritVerma01 Oct 19, 2026
9d8426d
fix(database): preserve complete cost warning validation messages
AlankritVerma01 Oct 19, 2026
aba0a68
test(sqllab): streamline warning tests and cover async confirmation
AlankritVerma01 Oct 19, 2026
03330b9
test(sqllab): consolidate warning validation and lifecycle coverage
AlankritVerma01 Oct 19, 2026
709d78a
chore: merge apache master into query cost warnings
AlankritVerma01 Oct 19, 2026
94833a9
test(sqllab): remove redundant estimate command cases
AlankritVerma01 Oct 19, 2026
08efdd1
fix(sqllab): update warning inputs in a layout effect
AlankritVerma01 Oct 19, 2026
abc8b72
test(sqllab): make warning assertions explicit
AlankritVerma01 Oct 19, 2026
38eff85
test(database): update query cost warning API expectations
AlankritVerma01 Oct 19, 2026
54b3c9b
feat(sqllab): show cost warning threshold in Run tooltip
AlankritVerma01 Oct 19, 2026
95419ce
fix(sqllab): refine query cost warning dialog presentation
AlankritVerma01 Oct 19, 2026
340283f
fix(sqllab): use default warning dialog spacing
AlankritVerma01 Oct 20, 2026
308f4fe
Merge apache/superset master into feat/bigquery-cost-warnings
AlankritVerma01 Oct 20, 2026
4406ba0
fix(sqllab): detect configured SQL mutators in warning checks
AlankritVerma01 Oct 20, 2026
3d3eadb
refactor(sqllab) use shared ConfirmModal for query cost warning
AndreyZIno Oct 20, 2026
d3915f9
chore: retrigger CI
AndreyZIno Oct 20, 2026
abae8db
Merge branch 'master' into feat/bigquery-cost-warnings
AndreyZIno Oct 21, 2026
2bcdbaf
Merge branch 'master' into feat/bigquery-cost-warnings
AndreyZIno Oct 21, 2026
e9ba289
fix(sqllab): read engine spec from execution context and update AutoS…
AndreyZIno Oct 21, 2026
0e2afa9
test(sqllab): cover query cost warning edge cases
AndreyZIno Oct 21, 2026
981649d
refactor(sqllab): remove unreachable cost warning save guard
AndreyZIno Oct 22, 2026
4852aea
Merge branch 'master' into feat/bigquery-cost-warnings
AndreyZIno Oct 22, 2026
8e4cb5d
Merge Apache master into feat/bigquery-cost-warnings
AlankritVerma01 Oct 23, 2026
c01ed6b
fix(build): serialize TypeScript project builds
AlankritVerma01 Oct 24, 2026
ff7ff37
Revert "fix(build): serialize TypeScript project builds"
AlankritVerma01 Oct 24, 2026
66012a7
refactor(sqllab): delegate pre-run warnings to engine checks
AlankritVerma01 Oct 29, 2026
bfec426
feat(database): support opt-in settings for message-only warnings
AlankritVerma01 Oct 29, 2026
1465157
refactor(sqllab): remove unused estimate validation helper
AlankritVerma01 Oct 29, 2026
088b483
docs(sqllab): describe advisory query checks and engine extension
AlankritVerma01 Oct 29, 2026
1d68f28
merge: sync remote query warning branch
AlankritVerma01 Oct 29, 2026
ceceae1
merge: resolve query warning conflicts with Apache master
AlankritVerma01 Oct 29, 2026
3285e10
fix(sqllab): document the query warning response contract
AlankritVerma01 Oct 29, 2026
6d3576e
fix(database): validate warning rules after parsing extra
AlankritVerma01 Oct 29, 2026
6f945d4
test(sqllab): cover configured warning timeout
AlankritVerma01 Oct 29, 2026
eccdecc
test(sqllab): strengthen estimate and limit assertions
AlankritVerma01 Oct 30, 2026
a5ee74e
test(sqllab): cover stale errors and CTAS request fields
AlankritVerma01 Oct 30, 2026
3b2a48f
test(sqllab): exercise warning validation and timeout boundaries
AlankritVerma01 Oct 30, 2026
f690ab3
test(sqllab): await cancelled execution paths before assertions
AlankritVerma01 Oct 30, 2026
14acb78
docs(sqllab): clarify numeric warning prerequisites
AlankritVerma01 Oct 30, 2026
f358821
test(sqllab): consolidate authorization context coverage
AlankritVerma01 Oct 30, 2026
5471397
test(sqllab): isolate mocks and strengthen malformed metadata coverage
AlankritVerma01 Oct 30, 2026
ec2f209
Merge Apache master into query cost warnings
AlankritVerma01 Oct 30, 2026
37be080
docs(sqllab): clarify confirmation for equal lower bounds
AlankritVerma01 Oct 30, 2026
f47aef2
refactor(sqllab): clarify warning flow names and comments
AlankritVerma01 Oct 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 125 additions & 0 deletions docs/docs/using-superset/exploring-data.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,131 @@ to be drawn as zero across the entire day rather than only around the hours that
Lastly, save your chart as Tutorial Resample and add it to the Tutorial Dashboard. Go to the
tutorial dashboard to see the four charts side by side and compare the different outputs.

### SQL Lab query cost warning settings

SQL Lab supports opt-in pre-run warnings for BigQuery and PostgreSQL. It can ask
for confirmation when estimated usage exceeds a connection's threshold or cannot
be assessed reliably. Warnings are off by default. They do not enforce a spending
or resource limit: an analyst can choose to continue, and existing permissions and
native database limits still apply.

To enable warnings:

1. Add `"SQLLAB_QUERY_COST_WARNINGS": True` and `"ESTIMATE_QUERY_COST": True` to the
existing `FEATURE_FLAGS` dictionary in `superset_config.py`, then restart
Superset and refresh SQL Lab.
2. Open **Settings > Database Connections**, edit the connection, and select
**Advanced > SQL Lab**. Expose the connection in SQL Lab if necessary.
3. Select **Enable query cost estimation**, then **Enable pre-run warnings**
and enter a positive threshold. Save the connection. No threshold is chosen
automatically; choose one appropriate for the connection's workload.

The shipped cost checks use one rule per connection in `extra.query_cost_warning`,
containing `enabled`, `metric`, and `threshold`. BigQuery uses `bytes_processed`,
a positive whole number of bytes no greater than 9,007,199,254,740,991. PostgreSQL uses `total_cost`, a
positive number that can include decimals. PostgreSQL planner units are not
runtime, money, or memory. BigQuery estimates describe usage, not a guaranteed
bill. These metrics are not converted into a common unit.

BigQuery thresholds can be entered in Bytes, MB, or GB (decimal units: 1 MB =
1,000,000 bytes and 1 GB = 1,000,000,000 bytes). Changing the unit changes the
display while retaining the saved byte amount. Fractional MB or GB are accepted
only when they represent a positive whole number of bytes in the allowed range;
invalid amounts show validation instead of being rounded. PostgreSQL thresholds
stay in relative planner cost units and have no default amount.

Disabling warnings retains valid saved values. Turning connection estimation off
also retains the rule and makes checking inactive. A broken rule can be replaced
with `{ "enabled": false }` to disable it without retaining invalid fields.

Create, update, and import validate the rule against the resulting connection's
engine.

The warning estimator uses BigQuery dry runs and PostgreSQL `EXPLAIN (FORMAT
JSON)` without `ANALYZE`. It compares raw values on the server. Valid zero
estimates are retained; missing, malformed, unknown, and masked estimates are
unavailable. A BigQuery lower bound must exceed the threshold to establish a
warning; a lower bound at or below it does not establish that usage is within the
threshold. An upper bound can provide a conservative warning. Estimates hidden by
BigQuery row-level security are unavailable.

For BigQuery, a SQL row `LIMIT` does not cap bytes scanned. Use the warehouse's
native controls, such as `maximum_bytes_billed` where supported, for an actual
scan cap. The warning threshold is separate from those controls. Dry-run a small,
bounded query before executing it when verifying a connection's setup.

The existing manual estimate button keeps its formatted display. Warning checks
are advisory and are intended for deliberate SQL Lab runs, not dashboards,
scheduled queries, automatic retries, CTAS/CVAS, or enforced warehouse limits.

API clients can request an advisory check with `POST /api/v1/sqllab/estimate/`, setting
`check_warning` to `true` and passing the selected `sql`, `database_id`, `catalog`,
`schema`, `template_params`, and SQL Lab dropdown `query_limit`. The check applies
the execution row limits, including the extra row fetched to detect truncation.
The result returns `action: proceed` when this check does not need confirmation.
This is not a guarantee that the query is safe in every other way. Otherwise it
returns `action: confirm`, a `warning` or `unavailable` reason, a nonempty message,
and optional plain-text label/value details. For the cost checks, estimates and
thresholds are compared before display formatting. Precise estimates and upper
bounds equal to the threshold do not warn; lower bounds at equality still require
confirmation because usage could exceed the threshold.
BigQuery bounds are displayed as **At least** or **Up to**. Byte counts can exceed JavaScript's safe integer
range, so clients should display the server-provided details without reconverting
them to numbers.

Checking supports one read-only SELECT. Templates, multiple statements, and
custom SQL transformations are unavailable. A known estimation timeout or an
unusable estimate also returns unavailable. Invalid rules, access failures, and
database or network errors remain errors. Omitting `check_warning` preserves the
manual estimator response.

Database API and SQL Lab bootstrap responses include `query_warning_state`:
`unsupported`, `disabled`, `ready`, or `invalid`. Invalid saved settings are not
an opt-out: clients must preserve validation errors. Engine information exposes
`query_warning_supported` separately from the optional numeric
`query_cost_warning_metric`. `SQLLAB_QUERY_COST_WARNINGS` gates all checks;
`ESTIMATE_QUERY_COST` and connection cost estimation are prerequisites of the
numeric threshold check.

When checking is enabled, a deliberate **Run** (including Run selection or its
keyboard shortcut) sends an assessment request before execution. This adds a
delay that depends on the query, database, and network. The check uses the
captured execution request. The current-statement shortcut uses the existing
statement range without changing your selection. While checking,
**Stop** in the Run area (or its keyboard shortcut) prevents that attempt from
executing; it does not forcibly cancel a database dry run. The **Query warning**
popup explains an above-threshold or unavailable estimate and offers **Cancel**
and **Run anyway**. Errors stop the attempt without executing it.

Changing the SQL or selection, connection, catalog, schema, template parameters,
effective limit, asynchronous execution setting, or locally loaded warning
settings cancels a pending attempt. Switching editor tabs does too. Confirming
runs the captured request once. Remote policy changes become visible when
connection metadata is refreshed; the dialog does not detect them in advance.

**Run query in a new tab** from query history uses the same warning flow. The
rerun retains its existing settings: SQL, connection, catalog, and schema come
from the historical query; the limit and template parameters come from the
active editor, and asynchronous execution follows the connection's current
setting. Cancelling leaves the new tab open without executing its query. Repeated
Run clicks while a check or confirmation is pending do not create another attempt.

#### Engine extension point

Only BigQuery and PostgreSQL have production warning checks. An engine spec can
explicitly opt into the shared flow through `get_query_warning_check()`, returning
a check with `validate(rule)`, `is_enabled(database)`, and
`assess(database, catalog, schema, prepared_sql, rule)`, or `None` when unsupported.
The shared settings validation requires a rule object and a strict boolean
`enabled`; the selected check validates its own fields and prerequisites.

Both shipped integrations use `QueryCostThresholdCheck` with their engine-specific
estimation adapters. A future integration can supply a message-only check and its
own settings controls without changing Run or the confirmation dialog. Checks
return the same `proceed` or `confirm` contract, with display details as plain text.
Subclasses must explicitly opt in; inheriting an engine's manual estimator alone
does not establish warning support.

### Stopping chart queries

In Explore, a mouse, touch, pen, or Enter/Space key press that starts on **Stop** will not
Expand Down
6 changes: 6 additions & 0 deletions docs/static/feature-flags.json
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,12 @@
"lifecycle": "testing",
"description": "Temporary rollout / kill-switch gate for soft delete (off = legacy hard delete). An emergency stop, not a clean rollback: flipping ON->OFF resurrects already-soft-deleted rows. Retained through this release as the move-back lever; removed (along with its two gate points \u2014 BaseDAO.delete routing and the do_orm_execute visibility listener) once post-flip confidence is established."
},
{
"name": "SQLLAB_QUERY_COST_WARNINGS",
"default": false,
"lifecycle": "testing",
"description": "Optional advisory warnings before deliberately running SQL in SQL Lab. Requires explicit connection-level opt-in. Numeric checks also require ESTIMATE_QUERY_COST and connection cost estimation."
},
{
"name": "SSH_TUNNELING",
"default": false,
Expand Down
112 changes: 110 additions & 2 deletions docs/static/resources/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -5448,6 +5448,12 @@
"is_managed_externally": {
"type": "boolean"
},
"query_cost_warning": {
"readOnly": true
},
"query_warning_state": {
"readOnly": true
},
"uuid": {
"format": "uuid",
"nullable": true,
Expand Down Expand Up @@ -5547,6 +5553,12 @@
"id": {
"type": "integer"
},
"query_cost_warning": {
"readOnly": true
},
"query_warning_state": {
"readOnly": true
},
"uuid": {
"format": "uuid",
"nullable": true,
Expand Down Expand Up @@ -7852,6 +7864,13 @@
"description": "OAuth2 authentication is enabled on this connection",
"type": "boolean"
},
"query_cost_warning_metric": {
"nullable": true,
"type": "string"
},
"query_warning_supported": {
"type": "boolean"
},
"supports_dynamic_catalog": {
"description": "The database supports multiple catalogs in a single connection",
"type": "boolean"
Expand Down Expand Up @@ -7882,10 +7901,20 @@
"nullable": true,
"type": "string"
},
"check_warning": {
"default": false,
"description": "Run the connection's advisory pre-execution check",
"type": "boolean"
},
"database_id": {
"description": "The database id",
"type": "integer"
},
"query_limit": {
"description": "The SQL Lab dropdown row limit",
"nullable": true,
"type": "integer"
},
"schema": {
"description": "The database schema",
"nullable": true,
Expand Down Expand Up @@ -11879,6 +11908,19 @@
"id": {
"description": "The database id",
"type": "integer"
},
"query_cost_warning": {
"nullable": true,
"type": "object"
},
"query_warning_state": {
"enum": [
"unsupported",
"disabled",
"ready",
"invalid"
],
"type": "string"
}
},
"type": "object"
Expand Down Expand Up @@ -36071,14 +36113,80 @@
"schema": {
"properties": {
"result": {
"type": "object"
"oneOf": [
{
"items": {
"type": "object"
},
"type": "array"
},
{
"properties": {
"action": {
"enum": [
"proceed"
],
"type": "string"
}
},
"required": [
"action"
],
"type": "object"
},
{
"properties": {
"action": {
"enum": [
"confirm"
],
"type": "string"
},
"details": {
"items": {
"properties": {
"label": {
"type": "string"
},
"value": {
"type": "string"
}
},
"required": [
"label",
"value"
],
"type": "object"
},
"type": "array"
},
"message": {
"minLength": 1,
"type": "string"
},
"reason": {
"enum": [
"warning",
"unavailable"
],
"type": "string"
}
},
"required": [
"action",
"reason",
"message"
],
"type": "object"
}
]
}
},
"type": "object"
}
}
},
"description": "Query estimation result"
"description": "Formatted manual estimate, or a warning decision when check_warning is true. The action is proceed when this check does not require confirmation. A confirm action includes a warning or unavailable reason, a nonempty message, and optional plain-text label/value details."
},
"400": {
"$ref": "#/components/responses/400"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export enum FeatureFlag {
EnableTemplateProcessing = 'ENABLE_TEMPLATE_PROCESSING',
EscapeMarkdownHtml = 'ESCAPE_MARKDOWN_HTML',
EstimateQueryCost = 'ESTIMATE_QUERY_COST',
SqlLabQueryCostWarnings = 'SQLLAB_QUERY_COST_WARNINGS',
FabApiKeyEnabled = 'FAB_API_KEY_ENABLED',
FilterBarClosedByDefault = 'FILTERBAR_CLOSED_BY_DEFAULT',
GlobalAsyncQueries = 'GLOBAL_ASYNC_QUERIES',
Expand Down
44 changes: 22 additions & 22 deletions superset-frontend/src/SqlLab/actions/sqlLab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -566,34 +566,31 @@ export function runQuery(
};
}

export function runQueryFromSqlEditor(
/** Build one request for both the warning check and execution after confirmation. */
export function buildSqlEditorQuery(
database: Database | null,
queryEditor: QueryEditor,
defaultQueryLimit: number,
tempTable?: string,
ctas?: boolean,
ctasMethod?: string,
): SqlLabThunkAction {
return function (dispatch: AppDispatch, getState: GetState) {
const qe = getUpToDateQuery(getState(), queryEditor, queryEditor.id);
const query: Query = {
id: nanoid(11),
dbId: qe.dbId,
sql: qe.selectedText || qe.sql,
sqlEditorId: qe.tabViewId ?? qe.id,
sqlEditorImmutableId: qe.immutableId,
tab: qe.name,
catalog: qe.catalog,
schema: qe.schema,
tempTable,
templateParams: qe.templateParams,
queryLimit: qe.queryLimit || defaultQueryLimit,
runAsync: database ? database.allow_run_async : false,
ctas,
ctas_method: ctasMethod,
updateTabState: !qe.selectedText,
};
dispatch(runQuery(query));
): Query {
return {
id: nanoid(11),
dbId: queryEditor.dbId,
sql: queryEditor.selectedText || queryEditor.sql,
sqlEditorId: queryEditor.tabViewId ?? queryEditor.id,
sqlEditorImmutableId: queryEditor.immutableId,
tab: queryEditor.name,
catalog: queryEditor.catalog,
schema: queryEditor.schema,
tempTable,
templateParams: queryEditor.templateParams,
queryLimit: queryEditor.queryLimit || defaultQueryLimit,
runAsync: database ? database.allow_run_async : false,
ctas,
ctas_method: ctasMethod,
updateTabState: !queryEditor.selectedText,
};
}

Expand Down Expand Up @@ -848,9 +845,11 @@ export function addNewQueryEditor(): SqlLabThunkAction<SqlLabAction> {
};
}

/** Clone with existing effective settings and optional deliberate-run intent. */
export function cloneQueryToNewTab(
query: Query,
autorun: boolean,
autorunSource?: QueryEditor['autorunSource'],
): SqlLabThunkAction<SqlLabAction> {
return function (dispatch: AppDispatch, getState: GetState) {
const state = getState();
Expand All @@ -868,6 +867,7 @@ export function cloneQueryToNewTab(
catalog: query.catalog,
schema: query.schema ?? undefined,
autorun,
...(autorunSource && { autorunSource }),
sql: query.sql,
queryLimit: sourceQueryEditor.queryLimit,
templateParams: sourceQueryEditor.templateParams,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const QueryTable = ({
};

const openQueryInNewTab = (query: QueryResponse) => {
dispatch(cloneQueryToNewTab(query, true));
dispatch(cloneQueryToNewTab(query, true, 'history'));
};

const statusAttributes = {
Expand Down
Loading
Loading