GPU Coverage Report
This page defines every column, JSON field and code that
algeon_explain_coverage and EXPLAIN GPU return. It is a lookup reference.
The calls themselves, how to read a result and what the report does not
guarantee are covered in GPU Coverage Validation.
Columns
The UDTF and Flight SQL return the same Arrow schema.
physical_rootis the authoritative pre-native root captured by the retained optimizer diagnostics, and it is null when no native optimizer diagnostic exists.post_native_plan_rootis the completed executable plan's root.- A candidate row's
outcomeisselected,not_supportedornot_selected_by_cost. The summary row'soutcomeisaccepted_replaced,retained_datafusionorrejected_before_execution. - When planning produces no executable plan, the summary
gpu_fragmentsandcpu_boundariescells are null. They are never reported as zero in that case. - A rejected summary adds
detail, the rejection text, todetail_json. - Validation accepts one query statement only. Empty input, multiple
statements, non-query statements, and direct or view-indirect recursive calls
to
algeon_explain_coveragereturn a structured terminal result.
What blocked a candidate
reason_code says which contract a candidate missed. The blocking column and
the blocking object in detail_json and in each coverage_json candidate
outcome say which part of the query missed it. The object has a stable kind,
the one-line text, and structured fields for that kind:
- An
aggregate_functiondefect is the function itself,DISTINCT,ORDER BY, aFILTERthat differs between stages, an argument count, a partial stage, grouping sets, or a partitioned input. - A
window_functiondefect is the function, a missingORDER BY, a frame, or a non-constant offset or default. - An
expressionsubject includes the type it produced where that type is the cause. expressionholds the rejected expression in SQL form without column indexes, cut at 160 characters.
The text and the type names can quote the query's own SQL and identifiers.
EXPLAIN GPU returns them to the session that ran the statement, and the
disclosure model keeps them out of
operational logs.
Final disposition and GPU path
The final disposition is derived by walking the executable final physical plan. Whether an optimizer attempted a native rewrite does not decide it, and neither does a single candidate outcome. One report can hold selected and not-supported candidates while the completed plan stays mixed.
GPU fragments and explicit GPU islands are counted together for native.
rejected is the planning outcome when no executable plan exists and has no
final disposition. It is projected as gpu_path=rejected with null fragment
and boundary cells, carries the phase, reason_code and detail in
coverage_json, and repeats the code and text in the summary row.
Terminal source-resolution failures, an unsupported required GPU island, and a
failed final-plan requirement are planning errors. An ordinary relational
capability miss is no error. The unsupported operator stays on DataFusion, and
when DataFusion CPU execution is allowed each supported subtree below it runs
as a native fragment if its DataFusion parent keeps its input contracts. The
final disposition is mixed when a fragment is kept and datafusion
otherwise.
Rejected summary row
The fields a rejected row shares with the execution status are described in Rejections in EXPLAIN GPU. The remaining rules:
- A failure with an Algeon identity reports its
x-algeon-error-codeasreason_code. - A DataFusion error without one is classified as the Flight SQL boundary
classifies it, for example
sql_parseorfield_not_found. detailnames the caller's field or column where the error does.- For a failure whose raw text the server withholds,
detailis the static internal-failure message. A masked error stays masked in the report. - When the status message names a blocking plan element, it ends with
; EXPLAIN GPU lists every blocking candidate, anddetailends before that clause. detailcan quote the query's own SQL and identifiers; it reaches the session that ran the statement and stays out of operational logs.
Under native_required, SELECT APPROX_PERCENTILE_CONT(x, 0.5) FROM t returns
GPU execution does not support aggregate function approx_percentile_cont as
detail. Its not_supported candidate row repeats the subject in blocking
as aggregate function approx_percentile_cont.
Candidate outcomes
coverage_json.candidate_outcomes retains relational candidate-selection
diagnostics from the native optimizer. Each entry has one of these outcome
values:
- A fragment its parent could not keep has reason
native_fragment_parent_contract_unsupported. The fragment would change the input schema, boundedness, ordering, distribution or co-partitioning the parent relies on. - Two preference rules apply whenever DataFusion CPU execution is allowed. The
first matches a plan that reads no column data, because every source is a
literal with no columns or no rows and no GPU algorithm runs (reason
native_no_column_data_not_selected_by_cost). - The second matches a plan whose every node is a literal source; native
execution would only copy host rows to the device and back (reason
native_host_literal_passthrough_not_selected_by_cost). - Otherwise an enabled cost threshold matched. A subtree whose candidate the cost model declines stays on DataFusion whole.
Every candidate carries its stable candidate_family, and every non-selected
candidate carries remedy_code, remedy_kind and remedy in both its table
row and coverage_json. These fields are independent of final_disposition.
The final plan can be native beside candidate diagnostics when another selected
candidate covers the executable path. A not_supported or
not_selected_by_cost outcome keeps that candidate's operators on DataFusion
inside an executable plan, and the statement is not rejected.
Remedies for plan shapes
- When the extra partitions come from the setting,
SET datafusion.execution.target_partitions = 1makes DataFusion plan one sort, a single-stage aggregate, and a limit over one partition, all of which lower natively. The Flight SQL server already sets one partition under thenative_requiredexecution mode. - Each branch of a
UNION ALLis a partition at any setting. An aggregate that reads a union directly, or through the probe side of a join, keeps its partial and final stages attarget_partitions = 1, and a sort over such a union keeps the merge of its sorted partitions. - DataFusion does not merge the stages of a grouping set aggregate (
ROLLUP,CUBE,GROUPING SETS). - A single-stage aggregate fails native validation when, for example, an
aggregate function has no native kernel or a
MEDIANsits next to a standard deviation. - A sort key fails native validation on the single sort DataFusion plans at one
partition for
ORDER BY random(). After the setting, that query reportsunsupported_expressionfor the key. - A union on the collected side of a join is merged into one partition, and the setting still removes the stages or the merge there.
Validation context
Validation clones the caller's SessionState. If that state has an Algeon
native optimizer rule, the clone receives an isolated copy of the exact
optimizer configuration after the cloned DataFusion options are applied. Its
completed-plan requirements are copied too. Validation does not install a
diagnostic policy and does not plan a second time under another configuration.
coverage_json.validated_under records:
Revalidate after catalog, view, table or configuration changes. The fingerprints do not claim that source metadata or table contents are unchanged.
Runtime caveats
Rust surface
The SQL UDTF and the Rust API use the same validation primitive,
validate_query. The API is async because source planning can perform I/O
against the sources. It never executes the returned plan or performs GPU
admission.
Rust API
use algeon_datafusion::{
gpu_coverage::{QueryGpuPlanningOutcome, validate_query},
planner::FinalPlanDisposition,
};
let coverage = validate_query(&ctx, "SELECT count(*) FROM lineitem").await?;
match &coverage.planning_outcome {
QueryGpuPlanningOutcome::Planned(plan) => match plan.disposition() {
FinalPlanDisposition::Native => {}
FinalPlanDisposition::DataFusion | FinalPlanDisposition::Mixed => {
for outcome in &coverage.candidate_outcomes {
eprintln!(
"{} reason_code={} reason_kind={} category={} detail={}",
outcome.selection.as_str(),
outcome.reason_code.as_deref().unwrap_or("absent"),
outcome.reason_kind.map_or("absent", |kind| kind.as_str()),
outcome.category.as_deref().unwrap_or("absent"),
outcome.detail,
);
if let Some(remedy) = outcome.remedy {
eprintln!("{} {}: {}", remedy.code, remedy.kind.as_str(), remedy.guidance);
}
if let Some(blocking) = &outcome.blocking {
eprintln!("blocked by {}: {}", blocking.kind(), blocking.text());
}
}
}
},
QueryGpuPlanningOutcome::Rejected(rejection) => {
eprintln!("{} {}: {}", rejection.phase.as_str(), rejection.reason_code, rejection.detail);
}
}
println!("{}", coverage.to_json());
A rejection has two texts. detail is the client-safe message described under
Rejected statements.
For a failure whose raw text a server withholds, such as an Arrow, Parquet or
I/O error raised while planning, it is the static internal-failure message. That
message points at GetQueryStats and a query id, which an embedded session
does not have. trusted_diagnostic holds the source-chain text of the same
failure for the process that planned it, including foreign error messages and
local paths. A rejection that only the validator makes repeats detail there.
to_json, the EXPLAIN GPU rows and the Flight status never carry
trusted_diagnostic. A caller that forwards a rejection to a client forwards
detail.