Skip to content

Commit 8f106cf

Browse files
authored
Merge branch 'main' into feat/duckshop-10k
2 parents eb9e932 + 4e07586 commit 8f106cf

137 files changed

Lines changed: 5179 additions & 1225 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎Cargo.lock‎

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ junction = { version = "2.1.0", default-features = false }
7272
mimalloc = { version = "0.1", default-features = false, features = ["local_dynamic_tls"] }
7373
proc-macro2 = { version = "1", features = ["span-locations"] }
7474
pyo3 = { version = "0.26", features = ["abi3-py312"] }
75-
polyglot-sql = { git = "https://github.com/chio-labs/polyglot.git", rev = "b18dc647e797e480d2faadf3af407077f8e063df", default-features = false, features = [
75+
polyglot-sql = { git = "https://github.com/chio-labs/polyglot.git", rev = "1ef5056c2b315e69bd13023bd90ffe60d94880a3", default-features = false, features = [
7676
"ast-tools",
7777
"builder",
7878
"all-dialects",
7979
"semantic",
8080
"stacker",
8181
] }
82-
polyglot-sql-function-catalogs = { git = "https://github.com/chio-labs/polyglot.git", rev = "b18dc647e797e480d2faadf3af407077f8e063df", default-features = false, features = [
82+
polyglot-sql-function-catalogs = { git = "https://github.com/chio-labs/polyglot.git", rev = "1ef5056c2b315e69bd13023bd90ffe60d94880a3", default-features = false, features = [
8383
"dialect-duckdb",
8484
] }
8585
blake3 = { version = "1", features = ["rayon"] }

‎crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/analysis_cache.rs‎

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//! Per-model analysis cache keys over everything an analysis reads, and stored outcomes.
22
3-
use crate::sql_macros::main::sql_macro_declared_outputs::sql_macro_declared_outputs;
4-
use crate::sql_macros::models::DeclaredOutput;
53
use std::collections::{BTreeSet, HashMap};
64

75
use sha2::{Digest, Sha256};
@@ -171,20 +169,6 @@ impl KeyHasher {
171169
}
172170
self.text(&model.pivot_sql);
173171
self.families(&model.dynamic_families);
174-
let declared: Vec<DeclaredOutput> = sql_macro_declared_outputs(&model.sql_macro_checks);
175-
self.count(declared.len());
176-
for output in &declared {
177-
match &output.cte {
178-
Some(cte) => {
179-
self.flag(true);
180-
self.text(cte);
181-
}
182-
None => self.flag(false),
183-
}
184-
self.text(&output.name);
185-
self.text(&output.returns);
186-
self.count(output.branch);
187-
}
188172
}
189173

190174
fn families(&mut self, families: &[DynamicFamily]) {

‎crates/sqlbuild-analysis/src/assembly/analysis_session/_helpers/cte_facts.rs‎

Lines changed: 37 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ use polyglot_sql::traversal::ExpressionWalk;
88
use serde_json::{Map, Value};
99

1010
use crate::assembly::analysis_session::_helpers::dict_walk::{
11-
PyValue, alias_or_name, arg, children, column_table_name, direct_tables, expression_args,
12-
find_all, is_star, kind, name, name_payload, output_name, parse_one, projected_expression,
13-
py_truthy, python_int, raw_name_payload, set_operation, to_dict, top_level_ctes,
14-
unwrap_annotations, where_clause,
11+
Assertion, PyValue, alias_or_name, arg, children, column_table_name, direct_tables,
12+
expression_args, find_all, is_star, kind, name, name_payload, output_name, parse_one,
13+
projected_expression, py_truthy, python_int, raw_name_payload, set_operation, to_dict,
14+
top_level_ctes, typed_annotation, unwrap_annotations, where_clause,
1515
};
1616
use crate::assembly::analysis_session::_helpers::mappings::ShapeTable;
1717
use crate::assembly::analysis_session::constants::{
@@ -23,7 +23,7 @@ use crate::assembly::analysis_session::constants::{
2323
NULLABLE_NULLABILITY, NULLIF_FUNCTION_NAME, POLYGLOT_TYPE_NAMES, PYTHON_RULE, SAFE_CAST_RULE,
2424
SELECT_AST_KIND, SET_OPERATION_AST_KINDS, STRING_LITERAL_TYPE, SUBSTRING_AST_KIND,
2525
TABLE_AST_KIND, TEXT_TYPE, TIMESTAMP_TYPE_NAME, TIMESTAMP_TZ_TYPE, TRY_CAST_AST_KIND,
26-
TYPE_PASSTHROUGH_AST_KINDS, UNKNOWN_NULLABILITY, VARCHAR_DATA_TYPES, WILDCARD,
26+
TYPE_PASSTHROUGH_AST_KINDS, UNKNOWN_NULLABILITY, UNKNOWN_TYPE, VARCHAR_DATA_TYPES, WILDCARD,
2727
};
2828
use crate::assembly::analysis_session::constants::{
2929
CONFIDENCE_HIGH, CONFIDENCE_MEDIUM, CONFIDENCE_UNKNOWN, TRANSFORM_AGGREGATION, TRANSFORM_CAST,
@@ -35,8 +35,6 @@ use crate::assembly::analysis_session::types::{Pairs, Shapes};
3535
use crate::nullability_rules::main::conditional_result_nullability::conditional_result_nullability;
3636
use crate::nullability_rules::main::first_arg_nullability::first_arg_nullability;
3737
use crate::nullability_rules::main::safe_cast_nullability::safe_cast_nullability;
38-
use crate::sql_macros::main::sql_macro_declared_type::sql_macro_declared_type;
39-
use crate::sql_macros::models::DeclaredOutput;
4038
use crate::type_system::main::normalize_type::normalize_type;
4139
use crate::type_system::models::{NormalizedType, TypeFamily};
4240

@@ -60,8 +58,6 @@ pub(crate) struct RecoveryProfile<'a> {
6058
pub(crate) rules: Option<&'a Pairs>,
6159
/// Runs the adapter's own rules, those with the `python` rule id.
6260
pub(crate) callback: Option<&'a NullabilityCallback>,
63-
/// The model's select items that are one SQL macro call each, typed by its `returns`.
64-
pub(crate) declared: &'a [DeclaredOutput],
6561
}
6662

6763
/// One enrichment's recovery request.
@@ -133,108 +129,6 @@ pub(crate) struct LegacyAnalysis {
133129
pub(crate) lineage: Vec<LineageRow>,
134130
}
135131

136-
/// The model query's output types its SQL macro call items change, given the relation types.
137-
pub(crate) fn declared_output_types(
138-
cleaned_sql: &str,
139-
types: &ShapeTable,
140-
profile: &RecoveryProfile<'_>,
141-
) -> Fact<Vec<(String, String)>> {
142-
let Some(parsed) = parse_one(cleaned_sql, profile.dialect)? else {
143-
return Ok(Vec::new());
144-
};
145-
let facts: Relations = referenced_types(&parsed, types);
146-
let declared: Vec<(String, String)> = Context {
147-
profile,
148-
branches: declared_branches(&parsed),
149-
}
150-
.query_types(&parsed, &facts)?;
151-
let plain: Vec<(String, String)> = Context {
152-
profile,
153-
branches: Vec::new(),
154-
}
155-
.query_types(&parsed, &facts)?;
156-
let main: HashSet<String> = main_output_columns(&parsed, profile.declared);
157-
Ok(declared
158-
.into_iter()
159-
.filter(|(name, data_type)| {
160-
dict_get(&plain, name) != Some(data_type) || main.contains(&casefold(name))
161-
})
162-
.collect())
163-
}
164-
165-
/// Each select of the main query and top-level CTEs by address, with its scope and branch.
166-
fn declared_branches(root: &Expression) -> Vec<Branch> {
167-
let mut branches: Vec<Branch> = Vec::new();
168-
for (cte_name, has_column_aliases, body) in top_level_ctes(root) {
169-
if !has_column_aliases
170-
&& unwrap_annotations(Some(body)).is_some_and(|body| top_level_ctes(body).is_empty())
171-
{
172-
for (branch, select) in set_branches(Some(body)).into_iter().enumerate() {
173-
branches.push((
174-
std::ptr::from_ref(select),
175-
Some(cte_name.to_owned()),
176-
branch,
177-
));
178-
}
179-
}
180-
}
181-
for (branch, select) in set_branches(Some(root)).into_iter().enumerate() {
182-
branches.push((std::ptr::from_ref(select), None, branch));
183-
}
184-
branches
185-
}
186-
187-
/// The folded main-query output columns its SQL macro call items stand in, in any branch.
188-
fn main_output_columns(root: &Expression, declared: &[DeclaredOutput]) -> HashSet<String> {
189-
let selects: Vec<&Expression> = set_branches(Some(root));
190-
let by_name: bool = set_operation(root).is_some_and(|(_, _, by_name)| by_name);
191-
let Some(first) = selects.first() else {
192-
return HashSet::new();
193-
};
194-
let first_names: Vec<&str> = projection_names(first);
195-
let mut columns: HashSet<String> = HashSet::new();
196-
for output in declared.iter().filter(|output| output.cte.is_none()) {
197-
if by_name {
198-
columns.insert(casefold(&output.name));
199-
continue;
200-
}
201-
let Some(select) = selects.get(output.branch) else {
202-
continue;
203-
};
204-
let position: Option<usize> = projection_names(select)
205-
.iter()
206-
.position(|name| name.eq_ignore_ascii_case(&output.name));
207-
if let Some(column) = position.and_then(|position| first_names.get(position)) {
208-
columns.insert(casefold(column));
209-
}
210-
}
211-
columns
212-
}
213-
214-
/// The output name of each of `select`'s projections, in order.
215-
fn projection_names(select: &Expression) -> Vec<&str> {
216-
select
217-
.get_expressions()
218-
.iter()
219-
.map(|projection| output_name(unwrap_annotations(Some(projection))))
220-
.collect()
221-
}
222-
223-
/// The selects of `node`'s set operation, left to right, or `node` itself.
224-
fn set_branches(node: Option<&Expression>) -> Vec<&Expression> {
225-
let Some(node) = unwrap_annotations(node) else {
226-
return Vec::new();
227-
};
228-
match set_operation(node) {
229-
Some((left, right, _)) => {
230-
let mut branches: Vec<&Expression> = set_branches(Some(left));
231-
branches.extend(set_branches(Some(right)));
232-
branches
233-
}
234-
None => vec![node],
235-
}
236-
}
237-
238132
/// Python's legacy analysis of a model the native engine handed back, or why it defers.
239133
pub(crate) fn legacy_analysis(input: &LegacyInput<'_>) -> Fact<LegacyAnalysis> {
240134
let Some(parsed) = parse_one(input.cleaned_sql, input.profile.dialect)? else {
@@ -272,7 +166,6 @@ pub(crate) fn legacy_analysis(input: &LegacyInput<'_>) -> Fact<LegacyAnalysis> {
272166
let unqualified: Option<&(String, String)> = single_resource(&resources);
273167
let context = Context {
274168
profile: &input.profile,
275-
branches: Vec::new(),
276169
};
277170
let (cte_types, cte_nullability) = if input.recover {
278171
(
@@ -543,7 +436,6 @@ fn passthrough_facts(
543436
}
544437
let context = Context {
545438
profile: &input.profile,
546-
branches: Vec::new(),
547439
};
548440
recovery.types = context.passthrough_types(root, &input_types(input))?;
549441
recovery.nullability = context.passthrough_nullability(root, &input_nullability(input))?;
@@ -574,21 +466,24 @@ fn direct_cte_outputs(root: &Expression, cte_names: &HashSet<String>) -> HashSet
574466
outputs
575467
}
576468

577-
/// A select's address, its top-level CTE or `None` for the main query, and its branch.
578-
type Branch = (*const Expression, Option<String>, usize);
579-
580469
/// The profile every resolver reads.
581470
struct Context<'a, 'b> {
582471
profile: &'a RecoveryProfile<'b>,
583-
/// The selects whose SQL macro call items take their declared types.
584-
branches: Vec<Branch>,
585472
}
586473

587474
impl Context<'_, '_> {
588-
/// The model query's output types, through its top-level CTEs.
589-
fn query_types(&self, root: &Expression, facts: &Relations) -> Fact<Vec<(String, String)>> {
475+
/// Python's `_polyglot_cte_passthrough_types_from_parsed`.
476+
fn passthrough_types(
477+
&self,
478+
root: &Expression,
479+
facts: &Relations,
480+
) -> Fact<Vec<(String, String)>> {
481+
let ctes: Vec<(&str, bool, &Expression)> = top_level_ctes(root);
482+
if ctes.is_empty() {
483+
return Ok(Vec::new());
484+
}
590485
let mut relations: Relations = referenced_facts(root, facts);
591-
for (cte_name, has_column_aliases, body) in top_level_ctes(root) {
486+
for (cte_name, has_column_aliases, body) in ctes {
592487
if has_column_aliases {
593488
continue;
594489
}
@@ -604,52 +499,6 @@ impl Context<'_, '_> {
604499
self.direct_select_types(Some(root), &relations)
605500
}
606501

607-
/// Python's `_polyglot_cte_passthrough_types_from_parsed`.
608-
fn passthrough_types(
609-
&self,
610-
root: &Expression,
611-
facts: &Relations,
612-
) -> Fact<Vec<(String, String)>> {
613-
if top_level_ctes(root).is_empty() {
614-
return Ok(Vec::new());
615-
}
616-
self.query_types(root, facts)
617-
}
618-
619-
/// `types` of `select` with each of its SQL macro call items typed by its `returns`.
620-
fn declared_types(
621-
&self,
622-
select: &Expression,
623-
mut types: Vec<(String, String)>,
624-
) -> Vec<(String, String)> {
625-
let address: *const Expression = std::ptr::from_ref(select);
626-
let Some((_, cte, branch)) = self
627-
.branches
628-
.iter()
629-
.find(|(branch_select, _, _)| *branch_select == address)
630-
else {
631-
return types;
632-
};
633-
for output in self.profile.declared {
634-
let key: String = types
635-
.iter()
636-
.map(|(name, _)| name)
637-
.find(|name| name.eq_ignore_ascii_case(&output.name))
638-
.cloned()
639-
.unwrap_or_else(|| output.name.clone());
640-
let inferred: Option<&str> = dict_get(&types, &key).map(String::as_str);
641-
if let Some(declared) = sql_macro_declared_type(
642-
self.profile.declared,
643-
(cte.as_deref(), *branch, &output.name),
644-
inferred,
645-
self.profile.dialect,
646-
) {
647-
types = dict_set(types, &key, declared);
648-
}
649-
}
650-
types
651-
}
652-
653502
/// Python's `_polyglot_select_output_types`.
654503
fn select_output_types(
655504
&self,
@@ -840,7 +689,7 @@ impl Context<'_, '_> {
840689
inferred = dict_set(inferred, output, inferred_type);
841690
}
842691
}
843-
Ok(self.declared_types(select, inferred))
692+
Ok(inferred)
844693
}
845694

846695
/// Python's `_polyglot_direct_expression_type`.
@@ -849,6 +698,24 @@ impl Context<'_, '_> {
849698
expression: Option<&Expression>,
850699
by_alias: &Relations,
851700
) -> Fact<Option<String>> {
701+
if let Some((asserted, inner)) = typed_annotation(expression) {
702+
if let Some(inferred) = self
703+
.expression_type_in(Some(inner), by_alias)?
704+
.filter(|inferred| !upper(inferred).contains(UNKNOWN_TYPE))
705+
{
706+
return Ok(Some(inferred));
707+
}
708+
return match asserted {
709+
Assertion::Fixed(asserted) => {
710+
let target: Value =
711+
serde_json::to_value(asserted).map_err(|error| error.to_string())?;
712+
Ok(target.as_object().and_then(cast_target_type))
713+
}
714+
Assertion::Like(like) => Ok(self
715+
.expression_type_in(Some(like), by_alias)?
716+
.filter(|like| !upper(like).contains(UNKNOWN_TYPE))),
717+
};
718+
}
852719
let expression: Option<&Expression> = unwrap_annotations(expression);
853720
let node_kind: &str = kind(expression);
854721
if let Some(inferred) = self.expression_type(expression)? {
@@ -1070,6 +937,7 @@ impl Context<'_, '_> {
1070937
aliases: &[(String, &'static str)],
1071938
scoped: &NullRelations,
1072939
) -> Fact<&'static str> {
940+
let expression: Option<&Expression> = unwrap_annotations(expression);
1073941
let node_kind: &str = kind(expression);
1074942
match node_kind {
1075943
NULL_AST_KIND => return Ok(NULLABLE_NULLABILITY),
@@ -1101,6 +969,7 @@ impl Context<'_, '_> {
1101969

1102970
/// Python's `_infer_polyglot_shallow_nullability`.
1103971
fn shallow_nullability(&self, expression: Option<&Expression>) -> Fact<&'static str> {
972+
let expression: Option<&Expression> = unwrap_annotations(expression);
1104973
let node_kind: &str = kind(expression);
1105974
match node_kind {
1106975
NULL_AST_KIND => return Ok(NULLABLE_NULLABILITY),

0 commit comments

Comments
 (0)