Skip to content

Commit 8a4d073

Browse files
Generate unique LATERAL FLATTEN aliases per query
Replace the hardcoded FLATTEN_DEFAULT_ALIAS ("_unnest") with a per-SelectBuilder counter that generates unique aliases (_unnest_1, _unnest_2, …). This prevents alias collisions when multiple unnests appear in the same query. - Add flatten_alias_counter to SelectBuilder with next/current accessor methods, scoped to one SELECT so subqueries get independent counters - Remove FLATTEN_DEFAULT_ALIAS constant, the dead alias_name() method, and the default alias from FlattenRelationBuilder - All three FLATTEN code paths (placeholder projection, display-name projection, and Unnest handler) now coordinate through the SelectBuilder to ensure SELECT items and FROM clause use the same alias - Use internal_datafusion_err! macro for FLATTEN error handling - Migrate unnest tests from partial .contains() assertions to insta::assert_snapshot! for full SQL verification
1 parent 5f1d805 commit 8a4d073

4 files changed

Lines changed: 326 additions & 186 deletions

File tree

datafusion/sql/src/unparser/ast.rs

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,52 @@ pub struct SelectBuilder {
162162
qualify: Option<ast::Expr>,
163163
value_table_mode: Option<ast::ValueTableMode>,
164164
flavor: Option<SelectFlavor>,
165+
/// Counter for generating unique LATERAL FLATTEN aliases within this SELECT.
166+
flatten_alias_counter: usize,
167+
/// Table aliases that correspond to LATERAL FLATTEN relations.
168+
/// Column references into these aliases must use `VALUE` as the column name.
169+
flatten_table_aliases: Vec<String>,
165170
}
166171

172+
/// Prefix used for auto-generated LATERAL FLATTEN table aliases.
173+
const FLATTEN_ALIAS_PREFIX: &str = "_unnest";
174+
167175
impl SelectBuilder {
176+
/// Generate a unique alias for a LATERAL FLATTEN relation
177+
/// (`_unnest_1`, `_unnest_2`, …). Each call returns a fresh name.
178+
pub fn next_flatten_alias(&mut self) -> String {
179+
self.flatten_alias_counter += 1;
180+
format!("{FLATTEN_ALIAS_PREFIX}_{}", self.flatten_alias_counter)
181+
}
182+
183+
/// Register a table alias as pointing to a LATERAL FLATTEN relation.
184+
pub fn add_flatten_table_alias(&mut self, alias: String) {
185+
self.flatten_table_aliases.push(alias);
186+
}
187+
188+
/// Returns true if no FLATTEN table aliases have been registered.
189+
pub fn flatten_table_aliases_empty(&self) -> bool {
190+
self.flatten_table_aliases.is_empty()
191+
}
192+
193+
/// Returns true if the given table alias refers to a FLATTEN relation.
194+
pub fn is_flatten_table_alias(&self, alias: &str) -> bool {
195+
self.flatten_table_aliases.iter().any(|a| a == alias)
196+
}
197+
198+
/// Returns the most recently generated flatten alias, or `None` if
199+
/// `next_flatten_alias` has not been called yet.
200+
pub fn current_flatten_alias(&self) -> Option<String> {
201+
if self.flatten_alias_counter > 0 {
202+
Some(format!(
203+
"{FLATTEN_ALIAS_PREFIX}_{}",
204+
self.flatten_alias_counter
205+
))
206+
} else {
207+
None
208+
}
209+
}
210+
168211
pub fn distinct(&mut self, value: Option<ast::Distinct>) -> &mut Self {
169212
self.distinct = value;
170213
self
@@ -371,6 +414,8 @@ impl SelectBuilder {
371414
qualify: Default::default(),
372415
value_table_mode: Default::default(),
373416
flavor: Some(SelectFlavor::Standard),
417+
flatten_alias_counter: 0,
418+
flatten_table_aliases: Vec::new(),
374419
}
375420
}
376421
}
@@ -697,10 +742,6 @@ impl Default for UnnestRelationBuilder {
697742
}
698743
}
699744

700-
/// Default table alias for FLATTEN table factors.
701-
/// Snowflake requires an alias to reference output columns (e.g. `_unnest.VALUE`).
702-
pub const FLATTEN_DEFAULT_ALIAS: &str = "_unnest";
703-
704745
/// Builds a `LATERAL FLATTEN(INPUT => expr, OUTER => bool)` table factor
705746
/// for Snowflake-style unnesting.
706747
#[derive(Clone)]
@@ -757,22 +798,9 @@ impl FlattenRelationBuilder {
757798
})
758799
}
759800

760-
/// Returns the alias name for this FLATTEN relation.
761-
/// Used to build qualified column references like `alias.VALUE`.
762-
pub fn alias_name(&self) -> &str {
763-
self.alias
764-
.as_ref()
765-
.map(|a| a.name.value.as_str())
766-
.unwrap_or(FLATTEN_DEFAULT_ALIAS)
767-
}
768-
769801
fn create_empty() -> Self {
770802
Self {
771-
alias: Some(ast::TableAlias {
772-
name: ast::Ident::with_quote('"', FLATTEN_DEFAULT_ALIAS),
773-
columns: vec![],
774-
explicit: true,
775-
}),
803+
alias: None,
776804
input_expr: None,
777805
outer: false,
778806
}

0 commit comments

Comments
 (0)