diff --git a/docs/how-to/query-options.md b/docs/how-to/query-options.md
index e34c4e16d62..3fdaa55979d 100644
--- a/docs/how-to/query-options.md
+++ b/docs/how-to/query-options.md
@@ -7,9 +7,9 @@ Query options adjust selected behavior for a connection or request; they are not
| `query.parallelism` | `query_parallelism`, `query.parallelism` | Integer `1`–`1024`; server default `0` means automatic CPU-based parallelism. This is not a resource-pool limit. |
| `query.allow_query_fallback` | `query_fallback`, `allow_query_fallback`, `query.allow_query_fallback` (legacy `ALLOW_QUERY_FALLBACK` syntax / `query_fallback` hint also work) | `true` or `false` |
| `query.enable_remote_dynamic_filter_pushdown` | canonical name | `true` or `false` |
-| `datafusion.optimizer.*` | canonical name | Boolean; only `repartition_joins`, `repartition_aggregations`, `repartition_sorts`, `repartition_windows`, `enable_round_robin_repartition`, `prefer_existing_sort`, `prefer_hash_join`, `join_reordering`, `enable_topk_aggregation`, and `enable_dynamic_filter_pushdown` are supported. |
+| `datafusion.optimizer.*` | canonical name | Keys, types, defaults, and validation come from the linked DataFusion version (for example, numeric `max_passes` and Boolean `filter_null_join_keys`). |
-Use `SET query_parallelism = 4` or `SET query.parallelism TO 4`; `SHOW VARIABLES query.parallelism` works in MySQL and PostgreSQL, which also accepts `SHOW query.parallelism`. `SHOW VARIABLES ` reports the effective value. Unspecified options inherit engine settings; defaults are automatic parallelism, fallback `false`, remote dynamic-filter pushdown `true`, and DataFusion optimizer switches `true` except `prefer_existing_sort` (`false`). DataFusion options are an inline Boolean allowlist applied through existing `ConfigOptions`, not arbitrary DataFusion configuration. Invalid values for recognized options and unsupported names are errors; unknown third-party MySQL/PostgreSQL initialization settings retain existing tolerance.
+Use `SET query_parallelism = 4` or `SET query.parallelism TO 4`; `SHOW VARIABLES query.parallelism` works in MySQL and PostgreSQL, which also accepts `SHOW query.parallelism`. `SHOW VARIABLES ` reports the effective value. Unspecified options inherit engine settings; defaults are automatic parallelism, fallback `false`, and remote dynamic-filter pushdown `true`. Invalid values and unsupported names are errors; unknown third-party MySQL/PostgreSQL initialization settings retain existing tolerance.
HTTP `X-Greptime-Hints` (for example, `query.parallelism=4`) and gRPC `x-greptime-hints` request metadata set request options; gRPC hints are not a protobuf `Hints` field. The Rust Flight client offers `Database::sql_with_hint` and `flight_request().with_hints`. Hints override session `SET`, including within a multi-statement HTTP request. SQL `SET` lasts for its connection only; `SET LOCAL` transaction-scoped restoration is not implemented.
diff --git a/src/query/src/query_engine/state.rs b/src/query/src/query_engine/state.rs
index 5be2d312943..6eefc3ec1e6 100644
--- a/src/query/src/query_engine/state.rs
+++ b/src/query/src/query_engine/state.rs
@@ -324,7 +324,13 @@ impl QueryEngineState {
.build()
})?);
let options = query_ctx.extensions();
- for (key, value) in &options {
+ const MASTER: &str = "datafusion.optimizer.enable_dynamic_filter_pushdown";
+ // The master switch cascades to children, so apply explicit child overrides afterward.
+ for (key, value) in options
+ .get_key_value(MASTER)
+ .into_iter()
+ .chain(options.iter().filter(|(key, _)| key.as_str() != MASTER))
+ {
if key.starts_with("datafusion.") {
state
.config_mut()
diff --git a/src/query/src/sql.rs b/src/query/src/sql.rs
index 0c6e278978b..9bd947c33bf 100644
--- a/src/query/src/sql.rs
+++ b/src/query/src/sql.rs
@@ -865,7 +865,7 @@ pub fn show_query_option(
return Ok(None);
};
let context = engine.engine_context(query_ctx.clone())?;
- let value = match canonical {
+ let value = match canonical.as_str() {
"query.allow_query_fallback" => context
.state()
.config_options()
diff --git a/src/session/src/query_options.rs b/src/session/src/query_options.rs
index 1a872fa317e..e632a64aa99 100644
--- a/src/session/src/query_options.rs
+++ b/src/session/src/query_options.rs
@@ -14,37 +14,22 @@
use crate::session_config::{Error, InvalidConfigValueSnafu};
-/// Returns the canonical name for a supported option key.
-pub fn canonical_query_option_name(key: &str) -> Option<&'static str> {
+/// Returns a canonical query option alias or a DataFusion optimizer option name.
+pub fn canonical_query_option_name(key: &str) -> Option {
let key = key.to_ascii_lowercase();
match key.as_str() {
- "query_parallelism" | "query.parallelism" => Some("query.parallelism"),
+ "query_parallelism" | "query.parallelism" => Some("query.parallelism".to_string()),
"query_fallback" | "allow_query_fallback" | "query.allow_query_fallback" => {
- Some("query.allow_query_fallback")
+ Some("query.allow_query_fallback".to_string())
}
"query.enable_remote_dynamic_filter_pushdown" => {
- Some("query.enable_remote_dynamic_filter_pushdown")
+ Some("query.enable_remote_dynamic_filter_pushdown".to_string())
}
- _ => DATAFUSION_OPTIONS
- .iter()
- .find(|name| **name == key)
- .copied(),
+ _ if key.starts_with("datafusion.optimizer.") => Some(key),
+ _ => None,
}
}
-const DATAFUSION_OPTIONS: &[&str] = &[
- "datafusion.optimizer.repartition_joins",
- "datafusion.optimizer.repartition_aggregations",
- "datafusion.optimizer.repartition_sorts",
- "datafusion.optimizer.repartition_windows",
- "datafusion.optimizer.enable_round_robin_repartition",
- "datafusion.optimizer.prefer_existing_sort",
- "datafusion.optimizer.prefer_hash_join",
- "datafusion.optimizer.join_reordering",
- "datafusion.optimizer.enable_topk_aggregation",
- "datafusion.optimizer.enable_dynamic_filter_pushdown",
-];
-
/// Validate a query option, returning its canonical name and normalized value.
pub fn parse_query_option(key: &str, value: &str) -> Result, Error> {
let key_lower = key.to_ascii_lowercase();
@@ -87,9 +72,15 @@ pub fn parse_query_option(key: &str, value: &str) -> Result Result value,
+ None => {
+ return InvalidConfigValueSnafu {
+ name: key,
+ value,
+ hint: "No matching DataFusion configuration entry",
+ }
+ .fail();
+ }
+ }
};
- Ok(Some((canonical.to_string(), normalized)))
+ Ok(Some((canonical, normalized)))
}