-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlib.rs
More file actions
104 lines (96 loc) · 3.96 KB
/
Copy pathlib.rs
File metadata and controls
104 lines (96 loc) · 3.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
//! SQL front end: parse + plan (via DataFusion) → the canonical, unresolved
//! shape, built directly (issue #179) → [`resolve_root`].
//!
//! Emits [`UnresolvedQueryExpr`](asap_types::pre_asap::UnresolvedQueryExpr) itself — the
//! canonical `QueryExpr`, generic over an unresolved
//! [`ColumnRef`](asap_types::pre_asap::ColumnRef) — directly, rather than a
//! separate per-language relational tree; `resolve_root` runs the
//! [`Binder`](asap_types::pre_asap::Binder) for positional name resolution.
//! Depends on DataFusion only — never on the PromQL parser.
pub mod error;
pub mod sql;
use asap_types::pre_asap::resolve_root;
use asap_types::pre_asap::QueryExpr;
use asap_types::types::AccuracyTarget;
use asap_types::workload::{QueryLanguage, QueryWorkload, SqlDialect};
pub use error::SqlError;
pub use sql::{SqlCatalog, SqlLowerer};
/// Lower a single SQL query string to the canonical, resolved `QueryExpr`,
/// parsed as `SqlDialect::DataFusionSQL`.
///
/// The `catalog` supplies table schemas (used both to plan the SQL with
/// DataFusion and to carry positional column identity into the resolved
/// tree). `accuracy` is threaded onto every approximate intent as it's built.
pub async fn lower_sql(
query: &str,
catalog: &SqlCatalog,
accuracy: AccuracyTarget,
) -> Result<QueryExpr, SqlError> {
lower_sql_dialect(query, catalog, SqlDialect::DataFusionSQL, accuracy).await
}
/// Lower a single SQL query string under an explicit [`SqlDialect`].
///
/// `ClickhouseSQL` parses via sqlparser's vendored `ClickHouseDialect`
/// (array-lambda syntax, `arr[-1]` indexing). It also teaches DataFusion's
/// planner the ClickHouse-only builtin functions listed in
/// `asap_sql_function_catalog::CLICKHOUSE_BUILTINS` (`uniqExact`, `countIf`)
/// — every other ClickHouse-only builtin still fails to plan.
/// `ElasticSQL` has no vendored parser and always returns `UnsupportedDialect`.
pub async fn lower_sql_dialect(
query: &str,
catalog: &SqlCatalog,
dialect: SqlDialect,
accuracy: AccuracyTarget,
) -> Result<QueryExpr, SqlError> {
let unresolved = SqlLowerer::with_dialect(catalog, dialect)
.lower(query, &accuracy)
.await?;
let resolved = resolve_root(&unresolved)?;
// Binding resolves names; schema inference also checks result types such
// as temporal subtraction, whose duration unit the IR cannot represent.
resolved
.output_schema()
.map_err(|error| SqlError::InvalidExpression(error.to_string()))?;
Ok(resolved)
}
/// Lower every SQL batch entry in `workload` to a `QueryExpr`.
///
/// One `Result` per entry — errors are per-query, not fatal for the batch.
/// Returns `WrongLanguage` for every entry if the workload is not SQL, and
/// `UnsupportedDialect` for `ElasticSQL` (no vendored parser).
pub async fn lower_sql_batch(
workload: &QueryWorkload,
catalog: &SqlCatalog,
) -> Vec<Result<QueryExpr, SqlError>> {
let entries = match &workload.query_batch {
Some(e) if !e.is_empty() => e,
_ => return vec![],
};
// `DataFusion` is a legacy alias for `SQL(DataFusionSQL)`; accept both.
if !matches!(
workload.language,
QueryLanguage::SQL(_) | QueryLanguage::DataFusion
) {
let lang = format!("{:?}", workload.language);
return entries
.iter()
.map(|_| Err(SqlError::WrongLanguage(lang.clone())))
.collect();
}
let dialect = match &workload.language {
QueryLanguage::SQL(d) => d.clone(),
_ => SqlDialect::DataFusionSQL,
};
if matches!(dialect, SqlDialect::ElasticSQL) {
return entries
.iter()
.map(|_| Err(SqlError::UnsupportedDialect("ElasticSQL".into())))
.collect();
}
let mut results = Vec::with_capacity(entries.len());
for entry in entries {
let accuracy = entry.requirements.accuracy.target();
results.push(lower_sql_dialect(&entry.query.0, catalog, dialect.clone(), accuracy).await);
}
results
}