fix: pass through native DataFusion optimizer options

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
This commit is contained in:
discord9
2026-10-10 11:40:45 +08:00
parent 66c28b5f5b
commit ac12a626ab
4 changed files with 42 additions and 30 deletions
+2 -2
View File
@@ -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 <option>` 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 <option>` 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.
+7 -1
View File
@@ -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()
+1 -1
View File
@@ -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()
+32 -26
View File
@@ -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<String> {
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<Option<(String, String)>, Error> {
let key_lower = key.to_ascii_lowercase();
@@ -87,9 +72,15 @@ pub fn parse_query_option(key: &str, value: &str) -> Result<Option<(String, Stri
}
}
} else {
let normalized = value.to_ascii_lowercase();
let mut options = datafusion_common::config::ConfigOptions::default();
if let Err(error) = options.set(canonical, &normalized) {
let set_result = options.set(&canonical, value).or_else(|error| {
if value.eq_ignore_ascii_case("true") || value.eq_ignore_ascii_case("false") {
options.set(&canonical, &value.to_ascii_lowercase())
} else {
Err(error)
}
});
if let Err(error) = set_result {
return InvalidConfigValueSnafu {
name: key,
value,
@@ -97,7 +88,22 @@ pub fn parse_query_option(key: &str, value: &str) -> Result<Option<(String, Stri
}
.fail();
}
normalized
match options
.entries()
.into_iter()
.find(|entry| entry.key == canonical)
.and_then(|entry| entry.value)
{
Some(value) => value,
None => {
return InvalidConfigValueSnafu {
name: key,
value,
hint: "No matching DataFusion configuration entry",
}
.fail();
}
}
};
Ok(Some((canonical.to_string(), normalized)))
Ok(Some((canonical, normalized)))
}