1use crate::dialects::transform_recursive;
9use crate::dialects::DialectType;
10use crate::expressions::{
11 Alias, BinaryOp, Column, Expression, Identifier, Join, LateralView, Literal, Over, Paren,
12 Select, TableRef, VarArgFunc, With,
13};
14use crate::resolver::{Resolver, ResolverError};
15use crate::schema::{normalize_name, Schema};
16use crate::scope::{build_scope, traverse_scope, Scope};
17use std::cell::RefCell;
18use std::collections::{HashMap, HashSet};
19use thiserror::Error;
20
21#[derive(Debug, Error, Clone)]
23pub enum QualifyColumnsError {
24 #[error("Unknown table: {0}")]
25 UnknownTable(String),
26
27 #[error("Unknown column: {0}")]
28 UnknownColumn(String),
29
30 #[error("Ambiguous column: {0}")]
31 AmbiguousColumn(String),
32
33 #[error("Cannot automatically join: {0}")]
34 CannotAutoJoin(String),
35
36 #[error("Unknown output column: {0}")]
37 UnknownOutputColumn(String),
38
39 #[error("Column could not be resolved: {column}{for_table}")]
40 ColumnNotResolved { column: String, for_table: String },
41
42 #[error("Resolver error: {0}")]
43 ResolverError(#[from] ResolverError),
44}
45
46pub type QualifyColumnsResult<T> = Result<T, QualifyColumnsError>;
48
49#[derive(Debug, Clone, Default)]
51pub struct QualifyColumnsOptions {
52 pub expand_alias_refs: bool,
54 pub expand_stars: bool,
56 pub infer_schema: Option<bool>,
58 pub allow_partial_qualification: bool,
60 pub dialect: Option<DialectType>,
62}
63
64impl QualifyColumnsOptions {
65 pub fn new() -> Self {
67 Self {
68 expand_alias_refs: true,
69 expand_stars: true,
70 infer_schema: None,
71 allow_partial_qualification: false,
72 dialect: None,
73 }
74 }
75
76 pub fn with_expand_alias_refs(mut self, expand: bool) -> Self {
78 self.expand_alias_refs = expand;
79 self
80 }
81
82 pub fn with_expand_stars(mut self, expand: bool) -> Self {
84 self.expand_stars = expand;
85 self
86 }
87
88 pub fn with_dialect(mut self, dialect: DialectType) -> Self {
90 self.dialect = Some(dialect);
91 self
92 }
93
94 pub fn with_allow_partial(mut self, allow: bool) -> Self {
96 self.allow_partial_qualification = allow;
97 self
98 }
99}
100
101pub fn qualify_columns(
116 expression: Expression,
117 schema: &dyn Schema,
118 options: &QualifyColumnsOptions,
119) -> QualifyColumnsResult<Expression> {
120 let infer_schema = options.infer_schema.unwrap_or(schema.is_empty());
121 let dialect = options.dialect.or_else(|| schema.dialect());
122 let first_error: RefCell<Option<QualifyColumnsError>> = RefCell::new(None);
123
124 let transformed = transform_recursive(expression, &|node| {
125 if first_error.borrow().is_some() {
126 return Ok(node);
127 }
128
129 match node {
130 Expression::Select(mut select) => {
131 if let Some(with) = &mut select.with {
132 pushdown_cte_alias_columns_with(with);
133 }
134
135 let scope_expr = Expression::Select(select.clone());
136 let scope = build_scope(&scope_expr);
137 let mut resolver = Resolver::new(&scope, schema, infer_schema);
138
139 let column_tables = if first_error.borrow().is_none() {
141 match expand_using(&mut select, &scope, &mut resolver) {
142 Ok(ct) => ct,
143 Err(err) => {
144 *first_error.borrow_mut() = Some(err);
145 HashMap::new()
146 }
147 }
148 } else {
149 HashMap::new()
150 };
151
152 if first_error.borrow().is_none() {
154 if let Err(err) = qualify_columns_in_scope(
155 &mut select,
156 &scope,
157 &mut resolver,
158 options.allow_partial_qualification,
159 ) {
160 *first_error.borrow_mut() = Some(err);
161 }
162 }
163
164 if first_error.borrow().is_none() && options.expand_alias_refs {
166 if let Err(err) = expand_alias_refs(&mut select, &mut resolver, dialect) {
167 *first_error.borrow_mut() = Some(err);
168 }
169 }
170
171 if first_error.borrow().is_none() && options.expand_stars {
173 if let Err(err) =
174 expand_stars(&mut select, &scope, &mut resolver, &column_tables)
175 {
176 *first_error.borrow_mut() = Some(err);
177 }
178 }
179
180 if first_error.borrow().is_none() {
182 if let Err(err) = qualify_outputs_select(&mut select) {
183 *first_error.borrow_mut() = Some(err);
184 }
185 }
186
187 if first_error.borrow().is_none() {
189 if let Err(err) = expand_group_by(&mut select, dialect) {
190 *first_error.borrow_mut() = Some(err);
191 }
192 }
193
194 Ok(Expression::Select(select))
195 }
196 _ => Ok(node),
197 }
198 })
199 .map_err(|err| QualifyColumnsError::CannotAutoJoin(err.to_string()))?;
200
201 if let Some(err) = first_error.into_inner() {
202 return Err(err);
203 }
204
205 Ok(transformed)
206}
207
208pub fn validate_qualify_columns(expression: &Expression) -> QualifyColumnsResult<()> {
213 let mut all_unqualified = Vec::new();
214
215 for scope in traverse_scope(expression) {
216 if let Expression::Select(_) = &scope.expression {
217 let unqualified = get_unqualified_columns(&scope);
219
220 let external = get_external_columns(&scope);
222 if !external.is_empty() && !is_correlated_subquery(&scope) {
223 let first = &external[0];
224 let for_table = if first.table.is_some() {
225 format!(" for table: '{}'", first.table.as_ref().unwrap())
226 } else {
227 String::new()
228 };
229 return Err(QualifyColumnsError::ColumnNotResolved {
230 column: first.name.clone(),
231 for_table,
232 });
233 }
234
235 all_unqualified.extend(unqualified);
236 }
237 }
238
239 if !all_unqualified.is_empty() {
240 let first = &all_unqualified[0];
241 return Err(QualifyColumnsError::AmbiguousColumn(first.name.clone()));
242 }
243
244 Ok(())
245}
246
247fn get_source_name(expr: &Expression) -> Option<String> {
249 match expr {
250 Expression::Table(t) => Some(
251 t.alias
252 .as_ref()
253 .map(|a| a.name.clone())
254 .unwrap_or_else(|| t.name.name.clone()),
255 ),
256 Expression::Subquery(sq) => sq.alias.as_ref().map(|a| a.name.clone()),
257 _ => None,
258 }
259}
260
261fn get_ordered_source_names(select: &Select) -> Vec<String> {
264 let mut ordered = Vec::new();
265 if let Some(from) = &select.from {
266 for expr in &from.expressions {
267 if let Some(name) = get_source_name(expr) {
268 ordered.push(name);
269 }
270 }
271 }
272 for join in &select.joins {
273 if let Some(name) = get_source_name(&join.this) {
274 ordered.push(name);
275 }
276 }
277 ordered
278}
279
280fn make_coalesce(column_name: &str, tables: &[String]) -> Expression {
282 let args: Vec<Expression> = tables
283 .iter()
284 .map(|t| Expression::qualified_column(t.as_str(), column_name))
285 .collect();
286 Expression::Coalesce(Box::new(VarArgFunc {
287 expressions: args,
288 original_name: None,
289 inferred_type: None,
290 }))
291}
292
293fn expand_using(
299 select: &mut Select,
300 _scope: &Scope,
301 resolver: &mut Resolver,
302) -> QualifyColumnsResult<HashMap<String, Vec<String>>> {
303 let mut columns: HashMap<String, String> = HashMap::new();
305
306 let mut column_tables: HashMap<String, Vec<String>> = HashMap::new();
308
309 let join_names: HashSet<String> = select
311 .joins
312 .iter()
313 .filter_map(|j| get_source_name(&j.this))
314 .collect();
315
316 let all_ordered = get_ordered_source_names(select);
317 let mut ordered: Vec<String> = all_ordered
318 .iter()
319 .filter(|name| !join_names.contains(name.as_str()))
320 .cloned()
321 .collect();
322
323 if join_names.is_empty() {
324 return Ok(column_tables);
325 }
326
327 fn update_source_columns(
329 source_name: &str,
330 columns: &mut HashMap<String, String>,
331 resolver: &mut Resolver,
332 ) {
333 if let Ok(source_cols) = resolver.get_source_columns(source_name) {
334 for col_name in source_cols {
335 columns
336 .entry(col_name)
337 .or_insert_with(|| source_name.to_string());
338 }
339 }
340 }
341
342 for source_name in &ordered {
344 update_source_columns(source_name, &mut columns, resolver);
345 }
346
347 for i in 0..select.joins.len() {
348 let source_table = ordered.last().cloned().unwrap_or_default();
350 if !source_table.is_empty() {
351 update_source_columns(&source_table, &mut columns, resolver);
352 }
353
354 let join_table = get_source_name(&select.joins[i].this).unwrap_or_default();
356 ordered.push(join_table.clone());
357
358 if select.joins[i].using.is_empty() {
360 continue;
361 }
362
363 let _join_columns: Vec<String> =
364 resolver.get_source_columns(&join_table).unwrap_or_default();
365
366 let using_identifiers: Vec<String> = select.joins[i]
367 .using
368 .iter()
369 .map(|id| id.name.clone())
370 .collect();
371
372 let using_count = using_identifiers.len();
373 let is_semi_or_anti = matches!(
374 select.joins[i].kind,
375 crate::expressions::JoinKind::Semi
376 | crate::expressions::JoinKind::Anti
377 | crate::expressions::JoinKind::LeftSemi
378 | crate::expressions::JoinKind::LeftAnti
379 | crate::expressions::JoinKind::RightSemi
380 | crate::expressions::JoinKind::RightAnti
381 );
382
383 let mut conditions: Vec<Expression> = Vec::new();
384
385 for identifier in &using_identifiers {
386 let table = columns
387 .get(identifier)
388 .cloned()
389 .unwrap_or_else(|| source_table.clone());
390
391 let lhs = if i == 0 || using_count == 1 {
393 Expression::qualified_column(table.as_str(), identifier.as_str())
395 } else {
396 let coalesce_cols: Vec<String> = ordered[..ordered.len() - 1]
399 .iter()
400 .filter(|t| {
401 resolver
402 .get_source_columns(t)
403 .unwrap_or_default()
404 .contains(identifier)
405 })
406 .cloned()
407 .collect();
408
409 if coalesce_cols.len() > 1 {
410 make_coalesce(identifier, &coalesce_cols)
411 } else {
412 Expression::qualified_column(table.as_str(), identifier.as_str())
413 }
414 };
415
416 let rhs = Expression::qualified_column(join_table.as_str(), identifier.as_str());
418
419 conditions.push(Expression::Eq(Box::new(BinaryOp::new(lhs, rhs))));
420
421 if !is_semi_or_anti {
423 let tables = column_tables
424 .entry(identifier.clone())
425 .or_insert_with(Vec::new);
426 if !tables.contains(&table) {
427 tables.push(table.clone());
428 }
429 if !tables.contains(&join_table) {
430 tables.push(join_table.clone());
431 }
432 }
433 }
434
435 let on_condition = conditions
437 .into_iter()
438 .reduce(|acc, cond| Expression::And(Box::new(BinaryOp::new(acc, cond))))
439 .expect("at least one USING column");
440
441 select.joins[i].on = Some(on_condition);
443 select.joins[i].using = vec![];
444 }
445
446 if !column_tables.is_empty() {
448 let mut new_expressions = Vec::with_capacity(select.expressions.len());
450 for expr in &select.expressions {
451 match expr {
452 Expression::Column(col)
453 if col.table.is_none() && column_tables.contains_key(&col.name.name) =>
454 {
455 let tables = &column_tables[&col.name.name];
456 let coalesce = make_coalesce(&col.name.name, tables);
457 new_expressions.push(Expression::Alias(Box::new(Alias {
459 this: coalesce,
460 alias: Identifier::new(&col.name.name),
461 column_aliases: vec![],
462 alias_explicit_as: false,
463 alias_keyword: None,
464 pre_alias_comments: vec![],
465 trailing_comments: vec![],
466 inferred_type: None,
467 })));
468 }
469 _ => {
470 let mut rewritten = expr.clone();
471 rewrite_using_columns_in_expression(&mut rewritten, &column_tables);
472 new_expressions.push(rewritten);
473 }
474 }
475 }
476 select.expressions = new_expressions;
477
478 if let Some(where_clause) = &mut select.where_clause {
480 rewrite_using_columns_in_expression(&mut where_clause.this, &column_tables);
481 }
482
483 if let Some(group_by) = &mut select.group_by {
485 for expr in &mut group_by.expressions {
486 rewrite_using_columns_in_expression(expr, &column_tables);
487 }
488 }
489
490 if let Some(having) = &mut select.having {
492 rewrite_using_columns_in_expression(&mut having.this, &column_tables);
493 }
494
495 if let Some(qualify) = &mut select.qualify {
497 rewrite_using_columns_in_expression(&mut qualify.this, &column_tables);
498 }
499
500 if let Some(order_by) = &mut select.order_by {
502 for ordered in &mut order_by.expressions {
503 rewrite_using_columns_in_expression(&mut ordered.this, &column_tables);
504 }
505 }
506 }
507
508 Ok(column_tables)
509}
510
511fn rewrite_using_columns_in_expression(
513 expr: &mut Expression,
514 column_tables: &HashMap<String, Vec<String>>,
515) {
516 let transformed = transform_recursive(expr.clone(), &|node| match node {
517 Expression::Column(col)
518 if col.table.is_none() && column_tables.contains_key(&col.name.name) =>
519 {
520 let tables = &column_tables[&col.name.name];
521 Ok(make_coalesce(&col.name.name, tables))
522 }
523 other => Ok(other),
524 });
525
526 if let Ok(next) = transformed {
527 *expr = next;
528 }
529}
530
531fn qualify_columns_in_scope(
533 select: &mut Select,
534 scope: &Scope,
535 resolver: &mut Resolver,
536 allow_partial: bool,
537) -> QualifyColumnsResult<()> {
538 for expr in &mut select.expressions {
539 qualify_columns_in_expression(expr, scope, resolver, allow_partial)?;
540 }
541 if let Some(where_clause) = &mut select.where_clause {
542 qualify_columns_in_expression(&mut where_clause.this, scope, resolver, allow_partial)?;
543 }
544 if let Some(group_by) = &mut select.group_by {
545 for expr in &mut group_by.expressions {
546 qualify_columns_in_expression(expr, scope, resolver, allow_partial)?;
547 }
548 }
549 if let Some(having) = &mut select.having {
550 qualify_columns_in_expression(&mut having.this, scope, resolver, allow_partial)?;
551 }
552 if let Some(qualify) = &mut select.qualify {
553 qualify_columns_in_expression(&mut qualify.this, scope, resolver, allow_partial)?;
554 }
555 if let Some(order_by) = &mut select.order_by {
556 for ordered in &mut order_by.expressions {
557 qualify_columns_in_expression(&mut ordered.this, scope, resolver, allow_partial)?;
558 }
559 }
560 for join in &mut select.joins {
561 qualify_columns_in_expression(&mut join.this, scope, resolver, allow_partial)?;
562 if let Some(on) = &mut join.on {
563 qualify_columns_in_expression(on, scope, resolver, allow_partial)?;
564 }
565 }
566 Ok(())
567}
568
569fn expand_alias_refs(
576 select: &mut Select,
577 _resolver: &mut Resolver,
578 _dialect: Option<DialectType>,
579) -> QualifyColumnsResult<()> {
580 let mut alias_to_expression: HashMap<String, (Expression, usize)> = HashMap::new();
581
582 for (i, expr) in select.expressions.iter_mut().enumerate() {
583 replace_alias_refs_in_expression(expr, &alias_to_expression, false);
584 if let Expression::Alias(alias) = expr {
585 alias_to_expression.insert(alias.alias.name.clone(), (alias.this.clone(), i + 1));
586 }
587 }
588
589 if let Some(where_clause) = &mut select.where_clause {
590 replace_alias_refs_in_expression(&mut where_clause.this, &alias_to_expression, false);
591 }
592 if let Some(group_by) = &mut select.group_by {
593 for expr in &mut group_by.expressions {
594 replace_alias_refs_in_expression(expr, &alias_to_expression, true);
595 }
596 }
597 if let Some(having) = &mut select.having {
598 replace_alias_refs_in_expression(&mut having.this, &alias_to_expression, false);
599 }
600 if let Some(qualify) = &mut select.qualify {
601 replace_alias_refs_in_expression(&mut qualify.this, &alias_to_expression, false);
602 }
603 if let Some(order_by) = &mut select.order_by {
604 for ordered in &mut order_by.expressions {
605 replace_alias_refs_in_expression(&mut ordered.this, &alias_to_expression, false);
606 }
607 }
608
609 Ok(())
610}
611
612fn expand_group_by(select: &mut Select, _dialect: Option<DialectType>) -> QualifyColumnsResult<()> {
619 let projections = select.expressions.clone();
620
621 if let Some(group_by) = &mut select.group_by {
622 for group_expr in &mut group_by.expressions {
623 if let Some(index) = positional_reference(group_expr) {
624 let replacement = select_expression_at_position(&projections, index)?;
625 *group_expr = replacement;
626 }
627 }
628 }
629 Ok(())
630}
631
632fn expand_stars(
642 select: &mut Select,
643 _scope: &Scope,
644 resolver: &mut Resolver,
645 column_tables: &HashMap<String, Vec<String>>,
646) -> QualifyColumnsResult<()> {
647 let mut new_selections: Vec<Expression> = Vec::new();
648 let mut has_star = false;
649 let mut coalesced_columns: HashSet<String> = HashSet::new();
650
651 let ordered_sources = get_ordered_source_names(select);
653
654 for expr in &select.expressions {
655 match expr {
656 Expression::Star(_) => {
657 has_star = true;
658 for source_name in &ordered_sources {
659 if let Ok(columns) = resolver.get_source_columns(source_name) {
660 if columns.contains(&"*".to_string()) || columns.is_empty() {
661 return Ok(());
662 }
663 for col_name in &columns {
664 if coalesced_columns.contains(col_name) {
665 continue;
667 }
668 if let Some(tables) = column_tables.get(col_name) {
669 if tables.contains(source_name) {
670 coalesced_columns.insert(col_name.clone());
672 let coalesce = make_coalesce(col_name, tables);
673 new_selections.push(Expression::Alias(Box::new(Alias {
674 this: coalesce,
675 alias: Identifier::new(col_name),
676 column_aliases: vec![],
677 alias_explicit_as: false,
678 alias_keyword: None,
679 pre_alias_comments: vec![],
680 trailing_comments: vec![],
681 inferred_type: None,
682 })));
683 continue;
684 }
685 }
686 new_selections
687 .push(create_qualified_column(col_name, Some(source_name)));
688 }
689 }
690 }
691 }
692 Expression::Column(col) if is_star_column(col) => {
693 has_star = true;
694 if let Some(table) = &col.table {
695 let table_name = &table.name;
696 if !ordered_sources.contains(table_name) {
697 return Err(QualifyColumnsError::UnknownTable(table_name.clone()));
698 }
699 if let Ok(columns) = resolver.get_source_columns(table_name) {
700 if columns.contains(&"*".to_string()) || columns.is_empty() {
701 return Ok(());
702 }
703 for col_name in &columns {
704 if coalesced_columns.contains(col_name) {
705 continue;
706 }
707 if let Some(tables) = column_tables.get(col_name) {
708 if tables.contains(table_name) {
709 coalesced_columns.insert(col_name.clone());
710 let coalesce = make_coalesce(col_name, tables);
711 new_selections.push(Expression::Alias(Box::new(Alias {
712 this: coalesce,
713 alias: Identifier::new(col_name),
714 column_aliases: vec![],
715 alias_explicit_as: false,
716 alias_keyword: None,
717 pre_alias_comments: vec![],
718 trailing_comments: vec![],
719 inferred_type: None,
720 })));
721 continue;
722 }
723 }
724 new_selections
725 .push(create_qualified_column(col_name, Some(table_name)));
726 }
727 }
728 }
729 }
730 _ => new_selections.push(expr.clone()),
731 }
732 }
733
734 if has_star {
735 select.expressions = new_selections;
736 }
737
738 Ok(())
739}
740
741pub fn qualify_outputs(scope: &Scope) -> QualifyColumnsResult<()> {
748 if let Expression::Select(mut select) = scope.expression.clone() {
749 qualify_outputs_select(&mut select)?;
750 }
751 Ok(())
752}
753
754fn qualify_outputs_select(select: &mut Select) -> QualifyColumnsResult<()> {
755 let mut new_selections: Vec<Expression> = Vec::new();
756
757 for (i, expr) in select.expressions.iter().enumerate() {
758 match expr {
759 Expression::Alias(_) => new_selections.push(expr.clone()),
760 Expression::Column(col) => {
761 new_selections.push(create_alias(expr.clone(), &col.name.name));
762 }
763 Expression::Star(_) => new_selections.push(expr.clone()),
764 _ => {
765 let alias_name = get_output_name(expr).unwrap_or_else(|| format!("_col_{}", i));
766 new_selections.push(create_alias(expr.clone(), &alias_name));
767 }
768 }
769 }
770
771 select.expressions = new_selections;
772 Ok(())
773}
774
775fn qualify_columns_in_expression(
776 expr: &mut Expression,
777 scope: &Scope,
778 resolver: &mut Resolver,
779 allow_partial: bool,
780) -> QualifyColumnsResult<()> {
781 let first_error: RefCell<Option<QualifyColumnsError>> = RefCell::new(None);
782 let resolver_cell: RefCell<&mut Resolver> = RefCell::new(resolver);
783
784 let transformed = transform_recursive(expr.clone(), &|node| {
785 if first_error.borrow().is_some() {
786 return Ok(node);
787 }
788
789 match node {
790 Expression::Column(mut col) => {
791 if let Err(err) = qualify_single_column(
792 &mut col,
793 scope,
794 &mut resolver_cell.borrow_mut(),
795 allow_partial,
796 ) {
797 *first_error.borrow_mut() = Some(err);
798 }
799 Ok(Expression::Column(col))
800 }
801 _ => Ok(node),
802 }
803 })
804 .map_err(|err| QualifyColumnsError::CannotAutoJoin(err.to_string()))?;
805
806 if let Some(err) = first_error.into_inner() {
807 return Err(err);
808 }
809
810 *expr = transformed;
811 Ok(())
812}
813
814fn qualify_single_column(
815 col: &mut Column,
816 scope: &Scope,
817 resolver: &mut Resolver,
818 allow_partial: bool,
819) -> QualifyColumnsResult<()> {
820 if is_star_column(col) {
821 return Ok(());
822 }
823
824 if let Some(table) = &col.table {
825 let table_name = &table.name;
826 if !scope.sources.contains_key(table_name) {
827 if resolver.table_exists_in_schema(table_name) {
831 return Ok(());
832 }
833 return Err(QualifyColumnsError::UnknownTable(table_name.clone()));
834 }
835
836 if let Ok(source_columns) = resolver.get_source_columns(table_name) {
837 let normalized_column_name = normalize_column_name(&col.name.name, resolver.dialect);
838 if !allow_partial
839 && !source_columns.is_empty()
840 && !source_columns.iter().any(|column| {
841 normalize_column_name(column, resolver.dialect) == normalized_column_name
842 })
843 && !source_columns.contains(&"*".to_string())
844 {
845 return Err(QualifyColumnsError::UnknownColumn(col.name.name.clone()));
846 }
847 }
848 return Ok(());
849 }
850
851 if let Some(table_name) = resolver.get_table(&col.name.name) {
852 col.table = Some(Identifier::new(table_name));
853 return Ok(());
854 }
855
856 if let Some(outer_table) = resolver.find_column_in_outer_schema_tables(&col.name.name) {
859 col.table = Some(Identifier::new(outer_table));
860 return Ok(());
861 }
862
863 if !allow_partial {
864 return Err(QualifyColumnsError::UnknownColumn(col.name.name.clone()));
865 }
866
867 Ok(())
868}
869
870fn normalize_column_name(name: &str, dialect: Option<DialectType>) -> String {
871 normalize_name(name, dialect, false, true)
872}
873
874fn replace_alias_refs_in_expression(
875 expr: &mut Expression,
876 alias_to_expression: &HashMap<String, (Expression, usize)>,
877 literal_index: bool,
878) {
879 let transformed = transform_recursive(expr.clone(), &|node| match node {
880 Expression::Column(col) if col.table.is_none() => {
881 if let Some((alias_expr, index)) = alias_to_expression.get(&col.name.name) {
882 if literal_index && matches!(alias_expr, Expression::Literal(_)) {
883 return Ok(Expression::number(*index as i64));
884 }
885 return Ok(Expression::Paren(Box::new(Paren {
886 this: alias_expr.clone(),
887 trailing_comments: vec![],
888 })));
889 }
890 Ok(Expression::Column(col))
891 }
892 other => Ok(other),
893 });
894
895 if let Ok(next) = transformed {
896 *expr = next;
897 }
898}
899
900fn positional_reference(expr: &Expression) -> Option<usize> {
901 match expr {
902 Expression::Literal(lit) if matches!(lit.as_ref(), Literal::Number(_)) => {
903 let Literal::Number(value) = lit.as_ref() else {
904 unreachable!()
905 };
906 value.parse::<usize>().ok()
907 }
908 _ => None,
909 }
910}
911
912fn select_expression_at_position(
913 projections: &[Expression],
914 index: usize,
915) -> QualifyColumnsResult<Expression> {
916 if index == 0 || index > projections.len() {
917 return Err(QualifyColumnsError::UnknownOutputColumn(index.to_string()));
918 }
919
920 let projection = projections[index - 1].clone();
921 Ok(match projection {
922 Expression::Alias(alias) => alias.this.clone(),
923 other => other,
924 })
925}
926
927fn get_reserved_words(dialect: Option<DialectType>) -> HashSet<&'static str> {
930 let mut words: HashSet<&'static str> = [
932 "ADD",
934 "ALL",
935 "ALTER",
936 "AND",
937 "ANY",
938 "AS",
939 "ASC",
940 "BETWEEN",
941 "BY",
942 "CASE",
943 "CAST",
944 "CHECK",
945 "COLUMN",
946 "CONSTRAINT",
947 "CREATE",
948 "CROSS",
949 "CURRENT",
950 "CURRENT_DATE",
951 "CURRENT_TIME",
952 "CURRENT_TIMESTAMP",
953 "CURRENT_USER",
954 "DATABASE",
955 "DEFAULT",
956 "DELETE",
957 "DESC",
958 "DISTINCT",
959 "DROP",
960 "ELSE",
961 "END",
962 "ESCAPE",
963 "EXCEPT",
964 "EXISTS",
965 "FALSE",
966 "FETCH",
967 "FOR",
968 "FOREIGN",
969 "FROM",
970 "FULL",
971 "GRANT",
972 "GROUP",
973 "HAVING",
974 "IF",
975 "IN",
976 "INDEX",
977 "INNER",
978 "INSERT",
979 "INTERSECT",
980 "INTO",
981 "IS",
982 "JOIN",
983 "KEY",
984 "LEFT",
985 "LIKE",
986 "LIMIT",
987 "NATURAL",
988 "NOT",
989 "NULL",
990 "OFFSET",
991 "ON",
992 "OR",
993 "ORDER",
994 "OUTER",
995 "PRIMARY",
996 "REFERENCES",
997 "REPLACE",
998 "RETURNING",
999 "RIGHT",
1000 "ROLLBACK",
1001 "ROW",
1002 "ROWS",
1003 "SELECT",
1004 "SESSION_USER",
1005 "SET",
1006 "SOME",
1007 "TABLE",
1008 "THEN",
1009 "TO",
1010 "TRUE",
1011 "TRUNCATE",
1012 "UNION",
1013 "UNIQUE",
1014 "UPDATE",
1015 "USING",
1016 "VALUES",
1017 "VIEW",
1018 "WHEN",
1019 "WHERE",
1020 "WINDOW",
1021 "WITH",
1022 ]
1023 .iter()
1024 .copied()
1025 .collect();
1026
1027 match dialect {
1029 Some(DialectType::MySQL) => {
1030 words.extend(
1031 [
1032 "ANALYZE",
1033 "BOTH",
1034 "CHANGE",
1035 "CONDITION",
1036 "DATABASES",
1037 "DAY_HOUR",
1038 "DAY_MICROSECOND",
1039 "DAY_MINUTE",
1040 "DAY_SECOND",
1041 "DELAYED",
1042 "DETERMINISTIC",
1043 "DIV",
1044 "DUAL",
1045 "EACH",
1046 "ELSEIF",
1047 "ENCLOSED",
1048 "EXPLAIN",
1049 "FLOAT4",
1050 "FLOAT8",
1051 "FORCE",
1052 "HOUR_MICROSECOND",
1053 "HOUR_MINUTE",
1054 "HOUR_SECOND",
1055 "IGNORE",
1056 "INFILE",
1057 "INT1",
1058 "INT2",
1059 "INT3",
1060 "INT4",
1061 "INT8",
1062 "ITERATE",
1063 "KEYS",
1064 "KILL",
1065 "LEADING",
1066 "LEAVE",
1067 "LINES",
1068 "LOAD",
1069 "LOCK",
1070 "LONG",
1071 "LONGBLOB",
1072 "LONGTEXT",
1073 "LOOP",
1074 "LOW_PRIORITY",
1075 "MATCH",
1076 "MEDIUMBLOB",
1077 "MEDIUMINT",
1078 "MEDIUMTEXT",
1079 "MINUTE_MICROSECOND",
1080 "MINUTE_SECOND",
1081 "MOD",
1082 "MODIFIES",
1083 "NO_WRITE_TO_BINLOG",
1084 "OPTIMIZE",
1085 "OPTIONALLY",
1086 "OUT",
1087 "OUTFILE",
1088 "PURGE",
1089 "READS",
1090 "REGEXP",
1091 "RELEASE",
1092 "RENAME",
1093 "REPEAT",
1094 "REQUIRE",
1095 "RESIGNAL",
1096 "RETURN",
1097 "REVOKE",
1098 "RLIKE",
1099 "SCHEMA",
1100 "SCHEMAS",
1101 "SECOND_MICROSECOND",
1102 "SENSITIVE",
1103 "SEPARATOR",
1104 "SHOW",
1105 "SIGNAL",
1106 "SPATIAL",
1107 "SQL",
1108 "SQLEXCEPTION",
1109 "SQLSTATE",
1110 "SQLWARNING",
1111 "SQL_BIG_RESULT",
1112 "SQL_CALC_FOUND_ROWS",
1113 "SQL_SMALL_RESULT",
1114 "SSL",
1115 "STARTING",
1116 "STRAIGHT_JOIN",
1117 "TERMINATED",
1118 "TINYBLOB",
1119 "TINYINT",
1120 "TINYTEXT",
1121 "TRAILING",
1122 "TRIGGER",
1123 "UNDO",
1124 "UNLOCK",
1125 "UNSIGNED",
1126 "USAGE",
1127 "UTC_DATE",
1128 "UTC_TIME",
1129 "UTC_TIMESTAMP",
1130 "VARBINARY",
1131 "VARCHARACTER",
1132 "WHILE",
1133 "WRITE",
1134 "XOR",
1135 "YEAR_MONTH",
1136 "ZEROFILL",
1137 ]
1138 .iter()
1139 .copied(),
1140 );
1141 }
1142 Some(DialectType::PostgreSQL) | Some(DialectType::CockroachDB) => {
1143 words.extend(
1144 [
1145 "ANALYSE",
1146 "ANALYZE",
1147 "ARRAY",
1148 "AUTHORIZATION",
1149 "BINARY",
1150 "BOTH",
1151 "COLLATE",
1152 "CONCURRENTLY",
1153 "DO",
1154 "FREEZE",
1155 "ILIKE",
1156 "INITIALLY",
1157 "ISNULL",
1158 "LATERAL",
1159 "LEADING",
1160 "LOCALTIME",
1161 "LOCALTIMESTAMP",
1162 "NOTNULL",
1163 "ONLY",
1164 "OVERLAPS",
1165 "PLACING",
1166 "SIMILAR",
1167 "SYMMETRIC",
1168 "TABLESAMPLE",
1169 "TRAILING",
1170 "VARIADIC",
1171 "VERBOSE",
1172 ]
1173 .iter()
1174 .copied(),
1175 );
1176 }
1177 Some(DialectType::BigQuery) => {
1178 words.extend(
1179 [
1180 "ASSERT_ROWS_MODIFIED",
1181 "COLLATE",
1182 "CONTAINS",
1183 "CUBE",
1184 "DEFINE",
1185 "ENUM",
1186 "EXTRACT",
1187 "FOLLOWING",
1188 "GROUPING",
1189 "GROUPS",
1190 "HASH",
1191 "IGNORE",
1192 "LATERAL",
1193 "LOOKUP",
1194 "MERGE",
1195 "NEW",
1196 "NO",
1197 "NULLS",
1198 "OF",
1199 "OVER",
1200 "PARTITION",
1201 "PRECEDING",
1202 "PROTO",
1203 "RANGE",
1204 "RECURSIVE",
1205 "RESPECT",
1206 "ROLLUP",
1207 "STRUCT",
1208 "TABLESAMPLE",
1209 "TREAT",
1210 "UNBOUNDED",
1211 "WITHIN",
1212 ]
1213 .iter()
1214 .copied(),
1215 );
1216 }
1217 Some(DialectType::Snowflake) => {
1218 words.extend(
1219 [
1220 "ACCOUNT",
1221 "BOTH",
1222 "CONNECT",
1223 "FOLLOWING",
1224 "ILIKE",
1225 "INCREMENT",
1226 "ISSUE",
1227 "LATERAL",
1228 "LEADING",
1229 "LOCALTIME",
1230 "LOCALTIMESTAMP",
1231 "MINUS",
1232 "QUALIFY",
1233 "REGEXP",
1234 "RLIKE",
1235 "SOME",
1236 "START",
1237 "TABLESAMPLE",
1238 "TOP",
1239 "TRAILING",
1240 "TRY_CAST",
1241 ]
1242 .iter()
1243 .copied(),
1244 );
1245 }
1246 Some(DialectType::TSQL) | Some(DialectType::Fabric) => {
1247 words.extend(
1248 [
1249 "BACKUP",
1250 "BREAK",
1251 "BROWSE",
1252 "BULK",
1253 "CASCADE",
1254 "CHECKPOINT",
1255 "CLOSE",
1256 "CLUSTERED",
1257 "COALESCE",
1258 "COMPUTE",
1259 "CONTAINS",
1260 "CONTAINSTABLE",
1261 "CONTINUE",
1262 "CONVERT",
1263 "DBCC",
1264 "DEALLOCATE",
1265 "DENY",
1266 "DISK",
1267 "DISTRIBUTED",
1268 "DUMP",
1269 "ERRLVL",
1270 "EXEC",
1271 "EXECUTE",
1272 "EXIT",
1273 "EXTERNAL",
1274 "FILE",
1275 "FILLFACTOR",
1276 "FREETEXT",
1277 "FREETEXTTABLE",
1278 "FUNCTION",
1279 "GOTO",
1280 "HOLDLOCK",
1281 "IDENTITY",
1282 "IDENTITYCOL",
1283 "IDENTITY_INSERT",
1284 "KILL",
1285 "LINENO",
1286 "MERGE",
1287 "NONCLUSTERED",
1288 "NULLIF",
1289 "OF",
1290 "OFF",
1291 "OFFSETS",
1292 "OPEN",
1293 "OPENDATASOURCE",
1294 "OPENQUERY",
1295 "OPENROWSET",
1296 "OPENXML",
1297 "OVER",
1298 "PERCENT",
1299 "PIVOT",
1300 "PLAN",
1301 "PRINT",
1302 "PROC",
1303 "PROCEDURE",
1304 "PUBLIC",
1305 "RAISERROR",
1306 "READ",
1307 "READTEXT",
1308 "RECONFIGURE",
1309 "REPLICATION",
1310 "RESTORE",
1311 "RESTRICT",
1312 "REVERT",
1313 "ROWCOUNT",
1314 "ROWGUIDCOL",
1315 "RULE",
1316 "SAVE",
1317 "SECURITYAUDIT",
1318 "SEMANTICKEYPHRASETABLE",
1319 "SEMANTICSIMILARITYDETAILSTABLE",
1320 "SEMANTICSIMILARITYTABLE",
1321 "SETUSER",
1322 "SHUTDOWN",
1323 "STATISTICS",
1324 "SYSTEM_USER",
1325 "TEXTSIZE",
1326 "TOP",
1327 "TRAN",
1328 "TRANSACTION",
1329 "TRIGGER",
1330 "TSEQUAL",
1331 "UNPIVOT",
1332 "UPDATETEXT",
1333 "WAITFOR",
1334 "WRITETEXT",
1335 ]
1336 .iter()
1337 .copied(),
1338 );
1339 }
1340 Some(DialectType::ClickHouse) => {
1341 words.extend(
1342 [
1343 "ANTI",
1344 "ARRAY",
1345 "ASOF",
1346 "FINAL",
1347 "FORMAT",
1348 "GLOBAL",
1349 "INF",
1350 "KILL",
1351 "MATERIALIZED",
1352 "NAN",
1353 "PREWHERE",
1354 "SAMPLE",
1355 "SEMI",
1356 "SETTINGS",
1357 "TOP",
1358 ]
1359 .iter()
1360 .copied(),
1361 );
1362 }
1363 Some(DialectType::DuckDB) => {
1364 words.extend(
1365 [
1366 "ANALYSE",
1367 "ANALYZE",
1368 "ARRAY",
1369 "BOTH",
1370 "LATERAL",
1371 "LEADING",
1372 "LOCALTIME",
1373 "LOCALTIMESTAMP",
1374 "PLACING",
1375 "QUALIFY",
1376 "SIMILAR",
1377 "TABLESAMPLE",
1378 "TRAILING",
1379 ]
1380 .iter()
1381 .copied(),
1382 );
1383 }
1384 Some(DialectType::Hive) | Some(DialectType::Spark) | Some(DialectType::Databricks) => {
1385 words.extend(
1386 [
1387 "BOTH",
1388 "CLUSTER",
1389 "DISTRIBUTE",
1390 "EXCHANGE",
1391 "EXTENDED",
1392 "FUNCTION",
1393 "LATERAL",
1394 "LEADING",
1395 "MACRO",
1396 "OVER",
1397 "PARTITION",
1398 "PERCENT",
1399 "RANGE",
1400 "READS",
1401 "REDUCE",
1402 "REGEXP",
1403 "REVOKE",
1404 "RLIKE",
1405 "ROLLUP",
1406 "SEMI",
1407 "SORT",
1408 "TABLESAMPLE",
1409 "TRAILING",
1410 "TRANSFORM",
1411 "UNBOUNDED",
1412 "UNIQUEJOIN",
1413 ]
1414 .iter()
1415 .copied(),
1416 );
1417 }
1418 Some(DialectType::Trino) | Some(DialectType::Presto) | Some(DialectType::Athena) => {
1419 words.extend(
1420 [
1421 "CUBE",
1422 "DEALLOCATE",
1423 "DESCRIBE",
1424 "EXECUTE",
1425 "EXTRACT",
1426 "GROUPING",
1427 "LATERAL",
1428 "LOCALTIME",
1429 "LOCALTIMESTAMP",
1430 "NORMALIZE",
1431 "PREPARE",
1432 "ROLLUP",
1433 "SOME",
1434 "TABLESAMPLE",
1435 "UESCAPE",
1436 "UNNEST",
1437 ]
1438 .iter()
1439 .copied(),
1440 );
1441 }
1442 Some(DialectType::Oracle) => {
1443 words.extend(
1444 [
1445 "ACCESS",
1446 "AUDIT",
1447 "CLUSTER",
1448 "COMMENT",
1449 "COMPRESS",
1450 "CONNECT",
1451 "EXCLUSIVE",
1452 "FILE",
1453 "IDENTIFIED",
1454 "IMMEDIATE",
1455 "INCREMENT",
1456 "INITIAL",
1457 "LEVEL",
1458 "LOCK",
1459 "LONG",
1460 "MAXEXTENTS",
1461 "MINUS",
1462 "MODE",
1463 "NOAUDIT",
1464 "NOCOMPRESS",
1465 "NOWAIT",
1466 "NUMBER",
1467 "OF",
1468 "OFFLINE",
1469 "ONLINE",
1470 "PCTFREE",
1471 "PRIOR",
1472 "RAW",
1473 "RENAME",
1474 "RESOURCE",
1475 "REVOKE",
1476 "SHARE",
1477 "SIZE",
1478 "START",
1479 "SUCCESSFUL",
1480 "SYNONYM",
1481 "SYSDATE",
1482 "TRIGGER",
1483 "UID",
1484 "VALIDATE",
1485 "VARCHAR2",
1486 "WHENEVER",
1487 ]
1488 .iter()
1489 .copied(),
1490 );
1491 }
1492 Some(DialectType::Redshift) => {
1493 words.extend(
1494 [
1495 "AZ64",
1496 "BZIP2",
1497 "DELTA",
1498 "DELTA32K",
1499 "DISTSTYLE",
1500 "ENCODE",
1501 "GZIP",
1502 "ILIKE",
1503 "LIMIT",
1504 "LUNS",
1505 "LZO",
1506 "LZOP",
1507 "MOSTLY13",
1508 "MOSTLY32",
1509 "MOSTLY8",
1510 "RAW",
1511 "SIMILAR",
1512 "SNAPSHOT",
1513 "SORTKEY",
1514 "SYSDATE",
1515 "TOP",
1516 "ZSTD",
1517 ]
1518 .iter()
1519 .copied(),
1520 );
1521 }
1522 _ => {
1523 words.extend(
1525 [
1526 "ANALYZE",
1527 "ARRAY",
1528 "BOTH",
1529 "CUBE",
1530 "GROUPING",
1531 "LATERAL",
1532 "LEADING",
1533 "LOCALTIME",
1534 "LOCALTIMESTAMP",
1535 "OVER",
1536 "PARTITION",
1537 "QUALIFY",
1538 "RANGE",
1539 "ROLLUP",
1540 "SIMILAR",
1541 "SOME",
1542 "TABLESAMPLE",
1543 "TRAILING",
1544 ]
1545 .iter()
1546 .copied(),
1547 );
1548 }
1549 }
1550
1551 words
1552}
1553
1554fn needs_quoting(name: &str, reserved_words: &HashSet<&str>) -> bool {
1562 if name.is_empty() {
1563 return false;
1564 }
1565
1566 if name.as_bytes()[0].is_ascii_digit() {
1568 return true;
1569 }
1570
1571 if !name.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_') {
1573 return true;
1574 }
1575
1576 let upper = name.to_uppercase();
1578 reserved_words.contains(upper.as_str())
1579}
1580
1581fn maybe_quote(id: &mut Identifier, reserved_words: &HashSet<&str>) {
1583 if id.quoted || id.name.is_empty() || id.name == "*" {
1586 return;
1587 }
1588 if needs_quoting(&id.name, reserved_words) {
1589 id.quoted = true;
1590 }
1591}
1592
1593fn quote_identifiers_recursive(expr: &mut Expression, reserved_words: &HashSet<&str>) {
1595 match expr {
1596 Expression::Identifier(id) => {
1598 maybe_quote(id, reserved_words);
1599 }
1600
1601 Expression::Column(col) => {
1602 maybe_quote(&mut col.name, reserved_words);
1603 if let Some(ref mut table) = col.table {
1604 maybe_quote(table, reserved_words);
1605 }
1606 }
1607
1608 Expression::Table(table_ref) => {
1609 maybe_quote(&mut table_ref.name, reserved_words);
1610 if let Some(ref mut schema) = table_ref.schema {
1611 maybe_quote(schema, reserved_words);
1612 }
1613 if let Some(ref mut catalog) = table_ref.catalog {
1614 maybe_quote(catalog, reserved_words);
1615 }
1616 if let Some(ref mut alias) = table_ref.alias {
1617 maybe_quote(alias, reserved_words);
1618 }
1619 for ca in &mut table_ref.column_aliases {
1620 maybe_quote(ca, reserved_words);
1621 }
1622 for p in &mut table_ref.partitions {
1623 maybe_quote(p, reserved_words);
1624 }
1625 for h in &mut table_ref.hints {
1627 quote_identifiers_recursive(h, reserved_words);
1628 }
1629 if let Some(ref mut ver) = table_ref.version {
1630 quote_identifiers_recursive(&mut ver.this, reserved_words);
1631 if let Some(ref mut e) = ver.expression {
1632 quote_identifiers_recursive(e, reserved_words);
1633 }
1634 }
1635 }
1636
1637 Expression::Star(star) => {
1638 if let Some(ref mut table) = star.table {
1639 maybe_quote(table, reserved_words);
1640 }
1641 if let Some(ref mut except_ids) = star.except {
1642 for id in except_ids {
1643 maybe_quote(id, reserved_words);
1644 }
1645 }
1646 if let Some(ref mut replace_aliases) = star.replace {
1647 for alias in replace_aliases {
1648 maybe_quote(&mut alias.alias, reserved_words);
1649 quote_identifiers_recursive(&mut alias.this, reserved_words);
1650 }
1651 }
1652 if let Some(ref mut rename_pairs) = star.rename {
1653 for (from, to) in rename_pairs {
1654 maybe_quote(from, reserved_words);
1655 maybe_quote(to, reserved_words);
1656 }
1657 }
1658 }
1659
1660 Expression::Alias(alias) => {
1662 maybe_quote(&mut alias.alias, reserved_words);
1663 for ca in &mut alias.column_aliases {
1664 maybe_quote(ca, reserved_words);
1665 }
1666 quote_identifiers_recursive(&mut alias.this, reserved_words);
1667 }
1668
1669 Expression::Select(select) => {
1671 for e in &mut select.expressions {
1672 quote_identifiers_recursive(e, reserved_words);
1673 }
1674 if let Some(ref mut from) = select.from {
1675 for e in &mut from.expressions {
1676 quote_identifiers_recursive(e, reserved_words);
1677 }
1678 }
1679 for join in &mut select.joins {
1680 quote_join(join, reserved_words);
1681 }
1682 for lv in &mut select.lateral_views {
1683 quote_lateral_view(lv, reserved_words);
1684 }
1685 if let Some(ref mut prewhere) = select.prewhere {
1686 quote_identifiers_recursive(prewhere, reserved_words);
1687 }
1688 if let Some(ref mut wh) = select.where_clause {
1689 quote_identifiers_recursive(&mut wh.this, reserved_words);
1690 }
1691 if let Some(ref mut gb) = select.group_by {
1692 for e in &mut gb.expressions {
1693 quote_identifiers_recursive(e, reserved_words);
1694 }
1695 }
1696 if let Some(ref mut hv) = select.having {
1697 quote_identifiers_recursive(&mut hv.this, reserved_words);
1698 }
1699 if let Some(ref mut q) = select.qualify {
1700 quote_identifiers_recursive(&mut q.this, reserved_words);
1701 }
1702 if let Some(ref mut ob) = select.order_by {
1703 for o in &mut ob.expressions {
1704 quote_identifiers_recursive(&mut o.this, reserved_words);
1705 }
1706 }
1707 if let Some(ref mut lim) = select.limit {
1708 quote_identifiers_recursive(&mut lim.this, reserved_words);
1709 }
1710 if let Some(ref mut off) = select.offset {
1711 quote_identifiers_recursive(&mut off.this, reserved_words);
1712 }
1713 if let Some(ref mut with) = select.with {
1714 quote_with(with, reserved_words);
1715 }
1716 if let Some(ref mut windows) = select.windows {
1717 for nw in windows {
1718 maybe_quote(&mut nw.name, reserved_words);
1719 quote_over(&mut nw.spec, reserved_words);
1720 }
1721 }
1722 if let Some(ref mut distinct_on) = select.distinct_on {
1723 for e in distinct_on {
1724 quote_identifiers_recursive(e, reserved_words);
1725 }
1726 }
1727 if let Some(ref mut limit_by) = select.limit_by {
1728 for e in limit_by {
1729 quote_identifiers_recursive(e, reserved_words);
1730 }
1731 }
1732 if let Some(ref mut settings) = select.settings {
1733 for e in settings {
1734 quote_identifiers_recursive(e, reserved_words);
1735 }
1736 }
1737 if let Some(ref mut format) = select.format {
1738 quote_identifiers_recursive(format, reserved_words);
1739 }
1740 }
1741
1742 Expression::Union(u) => {
1744 quote_identifiers_recursive(&mut u.left, reserved_words);
1745 quote_identifiers_recursive(&mut u.right, reserved_words);
1746 if let Some(ref mut with) = u.with {
1747 quote_with(with, reserved_words);
1748 }
1749 if let Some(ref mut ob) = u.order_by {
1750 for o in &mut ob.expressions {
1751 quote_identifiers_recursive(&mut o.this, reserved_words);
1752 }
1753 }
1754 if let Some(ref mut lim) = u.limit {
1755 quote_identifiers_recursive(lim, reserved_words);
1756 }
1757 if let Some(ref mut off) = u.offset {
1758 quote_identifiers_recursive(off, reserved_words);
1759 }
1760 }
1761 Expression::Intersect(i) => {
1762 quote_identifiers_recursive(&mut i.left, reserved_words);
1763 quote_identifiers_recursive(&mut i.right, reserved_words);
1764 if let Some(ref mut with) = i.with {
1765 quote_with(with, reserved_words);
1766 }
1767 if let Some(ref mut ob) = i.order_by {
1768 for o in &mut ob.expressions {
1769 quote_identifiers_recursive(&mut o.this, reserved_words);
1770 }
1771 }
1772 }
1773 Expression::Except(e) => {
1774 quote_identifiers_recursive(&mut e.left, reserved_words);
1775 quote_identifiers_recursive(&mut e.right, reserved_words);
1776 if let Some(ref mut with) = e.with {
1777 quote_with(with, reserved_words);
1778 }
1779 if let Some(ref mut ob) = e.order_by {
1780 for o in &mut ob.expressions {
1781 quote_identifiers_recursive(&mut o.this, reserved_words);
1782 }
1783 }
1784 }
1785
1786 Expression::Subquery(sq) => {
1788 quote_identifiers_recursive(&mut sq.this, reserved_words);
1789 if let Some(ref mut alias) = sq.alias {
1790 maybe_quote(alias, reserved_words);
1791 }
1792 for ca in &mut sq.column_aliases {
1793 maybe_quote(ca, reserved_words);
1794 }
1795 if let Some(ref mut ob) = sq.order_by {
1796 for o in &mut ob.expressions {
1797 quote_identifiers_recursive(&mut o.this, reserved_words);
1798 }
1799 }
1800 }
1801
1802 Expression::Insert(ins) => {
1804 quote_table_ref(&mut ins.table, reserved_words);
1805 for c in &mut ins.columns {
1806 maybe_quote(c, reserved_words);
1807 }
1808 for row in &mut ins.values {
1809 for e in row {
1810 quote_identifiers_recursive(e, reserved_words);
1811 }
1812 }
1813 if let Some(ref mut q) = ins.query {
1814 quote_identifiers_recursive(q, reserved_words);
1815 }
1816 for (id, val) in &mut ins.partition {
1817 maybe_quote(id, reserved_words);
1818 if let Some(ref mut v) = val {
1819 quote_identifiers_recursive(v, reserved_words);
1820 }
1821 }
1822 for e in &mut ins.returning {
1823 quote_identifiers_recursive(e, reserved_words);
1824 }
1825 if let Some(ref mut on_conflict) = ins.on_conflict {
1826 quote_identifiers_recursive(on_conflict, reserved_words);
1827 }
1828 if let Some(ref mut with) = ins.with {
1829 quote_with(with, reserved_words);
1830 }
1831 if let Some(ref mut alias) = ins.alias {
1832 maybe_quote(alias, reserved_words);
1833 }
1834 if let Some(ref mut src_alias) = ins.source_alias {
1835 maybe_quote(src_alias, reserved_words);
1836 }
1837 }
1838
1839 Expression::Update(upd) => {
1840 quote_table_ref(&mut upd.table, reserved_words);
1841 for tr in &mut upd.extra_tables {
1842 quote_table_ref(tr, reserved_words);
1843 }
1844 for join in &mut upd.table_joins {
1845 quote_join(join, reserved_words);
1846 }
1847 for (id, val) in &mut upd.set {
1848 maybe_quote(id, reserved_words);
1849 quote_identifiers_recursive(val, reserved_words);
1850 }
1851 if let Some(ref mut from) = upd.from_clause {
1852 for e in &mut from.expressions {
1853 quote_identifiers_recursive(e, reserved_words);
1854 }
1855 }
1856 for join in &mut upd.from_joins {
1857 quote_join(join, reserved_words);
1858 }
1859 if let Some(ref mut wh) = upd.where_clause {
1860 quote_identifiers_recursive(&mut wh.this, reserved_words);
1861 }
1862 for e in &mut upd.returning {
1863 quote_identifiers_recursive(e, reserved_words);
1864 }
1865 if let Some(ref mut with) = upd.with {
1866 quote_with(with, reserved_words);
1867 }
1868 }
1869
1870 Expression::Delete(del) => {
1871 quote_table_ref(&mut del.table, reserved_words);
1872 if let Some(ref mut alias) = del.alias {
1873 maybe_quote(alias, reserved_words);
1874 }
1875 for tr in &mut del.using {
1876 quote_table_ref(tr, reserved_words);
1877 }
1878 if let Some(ref mut wh) = del.where_clause {
1879 quote_identifiers_recursive(&mut wh.this, reserved_words);
1880 }
1881 if let Some(ref mut with) = del.with {
1882 quote_with(with, reserved_words);
1883 }
1884 }
1885
1886 Expression::And(bin)
1888 | Expression::Or(bin)
1889 | Expression::Eq(bin)
1890 | Expression::Neq(bin)
1891 | Expression::Lt(bin)
1892 | Expression::Lte(bin)
1893 | Expression::Gt(bin)
1894 | Expression::Gte(bin)
1895 | Expression::Add(bin)
1896 | Expression::Sub(bin)
1897 | Expression::Mul(bin)
1898 | Expression::Div(bin)
1899 | Expression::Mod(bin)
1900 | Expression::BitwiseAnd(bin)
1901 | Expression::BitwiseOr(bin)
1902 | Expression::BitwiseXor(bin)
1903 | Expression::Concat(bin)
1904 | Expression::Adjacent(bin)
1905 | Expression::TsMatch(bin)
1906 | Expression::PropertyEQ(bin)
1907 | Expression::ArrayContainsAll(bin)
1908 | Expression::ArrayContainedBy(bin)
1909 | Expression::ArrayOverlaps(bin)
1910 | Expression::JSONBContainsAllTopKeys(bin)
1911 | Expression::JSONBContainsAnyTopKeys(bin)
1912 | Expression::JSONBDeleteAtPath(bin)
1913 | Expression::ExtendsLeft(bin)
1914 | Expression::ExtendsRight(bin)
1915 | Expression::Is(bin)
1916 | Expression::NullSafeEq(bin)
1917 | Expression::NullSafeNeq(bin)
1918 | Expression::Glob(bin)
1919 | Expression::Match(bin)
1920 | Expression::MemberOf(bin)
1921 | Expression::BitwiseLeftShift(bin)
1922 | Expression::BitwiseRightShift(bin) => {
1923 quote_identifiers_recursive(&mut bin.left, reserved_words);
1924 quote_identifiers_recursive(&mut bin.right, reserved_words);
1925 }
1926
1927 Expression::Like(like) | Expression::ILike(like) => {
1929 quote_identifiers_recursive(&mut like.left, reserved_words);
1930 quote_identifiers_recursive(&mut like.right, reserved_words);
1931 if let Some(ref mut esc) = like.escape {
1932 quote_identifiers_recursive(esc, reserved_words);
1933 }
1934 }
1935
1936 Expression::Not(un) | Expression::Neg(un) | Expression::BitwiseNot(un) => {
1938 quote_identifiers_recursive(&mut un.this, reserved_words);
1939 }
1940
1941 Expression::In(in_expr) => {
1943 quote_identifiers_recursive(&mut in_expr.this, reserved_words);
1944 for e in &mut in_expr.expressions {
1945 quote_identifiers_recursive(e, reserved_words);
1946 }
1947 if let Some(ref mut q) = in_expr.query {
1948 quote_identifiers_recursive(q, reserved_words);
1949 }
1950 if let Some(ref mut un) = in_expr.unnest {
1951 quote_identifiers_recursive(un, reserved_words);
1952 }
1953 }
1954
1955 Expression::Between(bw) => {
1956 quote_identifiers_recursive(&mut bw.this, reserved_words);
1957 quote_identifiers_recursive(&mut bw.low, reserved_words);
1958 quote_identifiers_recursive(&mut bw.high, reserved_words);
1959 }
1960
1961 Expression::IsNull(is_null) => {
1962 quote_identifiers_recursive(&mut is_null.this, reserved_words);
1963 }
1964
1965 Expression::IsTrue(is_tf) | Expression::IsFalse(is_tf) => {
1966 quote_identifiers_recursive(&mut is_tf.this, reserved_words);
1967 }
1968
1969 Expression::Exists(ex) => {
1970 quote_identifiers_recursive(&mut ex.this, reserved_words);
1971 }
1972
1973 Expression::Function(func) => {
1975 for arg in &mut func.args {
1976 quote_identifiers_recursive(arg, reserved_words);
1977 }
1978 }
1979
1980 Expression::AggregateFunction(agg) => {
1981 for arg in &mut agg.args {
1982 quote_identifiers_recursive(arg, reserved_words);
1983 }
1984 if let Some(ref mut filter) = agg.filter {
1985 quote_identifiers_recursive(filter, reserved_words);
1986 }
1987 for o in &mut agg.order_by {
1988 quote_identifiers_recursive(&mut o.this, reserved_words);
1989 }
1990 }
1991
1992 Expression::WindowFunction(wf) => {
1993 quote_identifiers_recursive(&mut wf.this, reserved_words);
1994 quote_over(&mut wf.over, reserved_words);
1995 }
1996
1997 Expression::Case(case) => {
1999 if let Some(ref mut operand) = case.operand {
2000 quote_identifiers_recursive(operand, reserved_words);
2001 }
2002 for (when, then) in &mut case.whens {
2003 quote_identifiers_recursive(when, reserved_words);
2004 quote_identifiers_recursive(then, reserved_words);
2005 }
2006 if let Some(ref mut else_) = case.else_ {
2007 quote_identifiers_recursive(else_, reserved_words);
2008 }
2009 }
2010
2011 Expression::Cast(cast) | Expression::TryCast(cast) | Expression::SafeCast(cast) => {
2013 quote_identifiers_recursive(&mut cast.this, reserved_words);
2014 if let Some(ref mut fmt) = cast.format {
2015 quote_identifiers_recursive(fmt, reserved_words);
2016 }
2017 }
2018
2019 Expression::Paren(paren) => {
2021 quote_identifiers_recursive(&mut paren.this, reserved_words);
2022 }
2023
2024 Expression::Annotated(ann) => {
2025 quote_identifiers_recursive(&mut ann.this, reserved_words);
2026 }
2027
2028 Expression::With(with) => {
2030 quote_with(with, reserved_words);
2031 }
2032
2033 Expression::Cte(cte) => {
2034 maybe_quote(&mut cte.alias, reserved_words);
2035 for c in &mut cte.columns {
2036 maybe_quote(c, reserved_words);
2037 }
2038 quote_identifiers_recursive(&mut cte.this, reserved_words);
2039 }
2040
2041 Expression::From(from) => {
2043 for e in &mut from.expressions {
2044 quote_identifiers_recursive(e, reserved_words);
2045 }
2046 }
2047
2048 Expression::Join(join) => {
2049 quote_join(join, reserved_words);
2050 }
2051
2052 Expression::JoinedTable(jt) => {
2053 quote_identifiers_recursive(&mut jt.left, reserved_words);
2054 for join in &mut jt.joins {
2055 quote_join(join, reserved_words);
2056 }
2057 if let Some(ref mut alias) = jt.alias {
2058 maybe_quote(alias, reserved_words);
2059 }
2060 }
2061
2062 Expression::Where(wh) => {
2063 quote_identifiers_recursive(&mut wh.this, reserved_words);
2064 }
2065
2066 Expression::GroupBy(gb) => {
2067 for e in &mut gb.expressions {
2068 quote_identifiers_recursive(e, reserved_words);
2069 }
2070 }
2071
2072 Expression::Having(hv) => {
2073 quote_identifiers_recursive(&mut hv.this, reserved_words);
2074 }
2075
2076 Expression::OrderBy(ob) => {
2077 for o in &mut ob.expressions {
2078 quote_identifiers_recursive(&mut o.this, reserved_words);
2079 }
2080 }
2081
2082 Expression::Ordered(ord) => {
2083 quote_identifiers_recursive(&mut ord.this, reserved_words);
2084 }
2085
2086 Expression::Limit(lim) => {
2087 quote_identifiers_recursive(&mut lim.this, reserved_words);
2088 }
2089
2090 Expression::Offset(off) => {
2091 quote_identifiers_recursive(&mut off.this, reserved_words);
2092 }
2093
2094 Expression::Qualify(q) => {
2095 quote_identifiers_recursive(&mut q.this, reserved_words);
2096 }
2097
2098 Expression::Window(ws) => {
2099 for e in &mut ws.partition_by {
2100 quote_identifiers_recursive(e, reserved_words);
2101 }
2102 for o in &mut ws.order_by {
2103 quote_identifiers_recursive(&mut o.this, reserved_words);
2104 }
2105 }
2106
2107 Expression::Over(over) => {
2108 quote_over(over, reserved_words);
2109 }
2110
2111 Expression::WithinGroup(wg) => {
2112 quote_identifiers_recursive(&mut wg.this, reserved_words);
2113 for o in &mut wg.order_by {
2114 quote_identifiers_recursive(&mut o.this, reserved_words);
2115 }
2116 }
2117
2118 Expression::Pivot(piv) => {
2120 quote_identifiers_recursive(&mut piv.this, reserved_words);
2121 for e in &mut piv.expressions {
2122 quote_identifiers_recursive(e, reserved_words);
2123 }
2124 for f in &mut piv.fields {
2125 quote_identifiers_recursive(f, reserved_words);
2126 }
2127 if let Some(ref mut alias) = piv.alias {
2128 maybe_quote(alias, reserved_words);
2129 }
2130 }
2131
2132 Expression::Unpivot(unpiv) => {
2133 quote_identifiers_recursive(&mut unpiv.this, reserved_words);
2134 maybe_quote(&mut unpiv.value_column, reserved_words);
2135 maybe_quote(&mut unpiv.name_column, reserved_words);
2136 for e in &mut unpiv.columns {
2137 quote_identifiers_recursive(e, reserved_words);
2138 }
2139 if let Some(ref mut alias) = unpiv.alias {
2140 maybe_quote(alias, reserved_words);
2141 }
2142 }
2143
2144 Expression::Values(vals) => {
2146 for tuple in &mut vals.expressions {
2147 for e in &mut tuple.expressions {
2148 quote_identifiers_recursive(e, reserved_words);
2149 }
2150 }
2151 if let Some(ref mut alias) = vals.alias {
2152 maybe_quote(alias, reserved_words);
2153 }
2154 for ca in &mut vals.column_aliases {
2155 maybe_quote(ca, reserved_words);
2156 }
2157 }
2158
2159 Expression::Array(arr) => {
2161 for e in &mut arr.expressions {
2162 quote_identifiers_recursive(e, reserved_words);
2163 }
2164 }
2165
2166 Expression::Struct(st) => {
2167 for (_name, e) in &mut st.fields {
2168 quote_identifiers_recursive(e, reserved_words);
2169 }
2170 }
2171
2172 Expression::Tuple(tup) => {
2173 for e in &mut tup.expressions {
2174 quote_identifiers_recursive(e, reserved_words);
2175 }
2176 }
2177
2178 Expression::Subscript(sub) => {
2180 quote_identifiers_recursive(&mut sub.this, reserved_words);
2181 quote_identifiers_recursive(&mut sub.index, reserved_words);
2182 }
2183
2184 Expression::Dot(dot) => {
2185 quote_identifiers_recursive(&mut dot.this, reserved_words);
2186 maybe_quote(&mut dot.field, reserved_words);
2187 }
2188
2189 Expression::ScopeResolution(sr) => {
2190 if let Some(ref mut this) = sr.this {
2191 quote_identifiers_recursive(this, reserved_words);
2192 }
2193 quote_identifiers_recursive(&mut sr.expression, reserved_words);
2194 }
2195
2196 Expression::Lateral(lat) => {
2198 quote_identifiers_recursive(&mut lat.this, reserved_words);
2199 }
2201
2202 Expression::DPipe(dpipe) => {
2204 quote_identifiers_recursive(&mut dpipe.this, reserved_words);
2205 quote_identifiers_recursive(&mut dpipe.expression, reserved_words);
2206 }
2207
2208 Expression::Merge(merge) => {
2210 quote_identifiers_recursive(&mut merge.this, reserved_words);
2211 quote_identifiers_recursive(&mut merge.using, reserved_words);
2212 if let Some(ref mut on) = merge.on {
2213 quote_identifiers_recursive(on, reserved_words);
2214 }
2215 if let Some(ref mut whens) = merge.whens {
2216 quote_identifiers_recursive(whens, reserved_words);
2217 }
2218 if let Some(ref mut with) = merge.with_ {
2219 quote_identifiers_recursive(with, reserved_words);
2220 }
2221 if let Some(ref mut ret) = merge.returning {
2222 quote_identifiers_recursive(ret, reserved_words);
2223 }
2224 }
2225
2226 Expression::LateralView(lv) => {
2228 quote_lateral_view(lv, reserved_words);
2229 }
2230
2231 Expression::Anonymous(anon) => {
2233 quote_identifiers_recursive(&mut anon.this, reserved_words);
2234 for e in &mut anon.expressions {
2235 quote_identifiers_recursive(e, reserved_words);
2236 }
2237 }
2238
2239 Expression::Filter(filter) => {
2241 quote_identifiers_recursive(&mut filter.this, reserved_words);
2242 quote_identifiers_recursive(&mut filter.expression, reserved_words);
2243 }
2244
2245 Expression::Returning(ret) => {
2247 for e in &mut ret.expressions {
2248 quote_identifiers_recursive(e, reserved_words);
2249 }
2250 }
2251
2252 Expression::BracedWildcard(inner) => {
2254 quote_identifiers_recursive(inner, reserved_words);
2255 }
2256
2257 Expression::ReturnStmt(inner) => {
2259 quote_identifiers_recursive(inner, reserved_words);
2260 }
2261
2262 Expression::Literal(_)
2264 | Expression::Boolean(_)
2265 | Expression::Null(_)
2266 | Expression::DataType(_)
2267 | Expression::Raw(_)
2268 | Expression::Placeholder(_)
2269 | Expression::CurrentDate(_)
2270 | Expression::CurrentTime(_)
2271 | Expression::CurrentTimestamp(_)
2272 | Expression::CurrentTimestampLTZ(_)
2273 | Expression::SessionUser(_)
2274 | Expression::RowNumber(_)
2275 | Expression::Rank(_)
2276 | Expression::DenseRank(_)
2277 | Expression::PercentRank(_)
2278 | Expression::CumeDist(_)
2279 | Expression::Random(_)
2280 | Expression::Pi(_)
2281 | Expression::JSONPathRoot(_) => {
2282 }
2284
2285 _ => {}
2289 }
2290}
2291
2292fn quote_join(join: &mut Join, reserved_words: &HashSet<&str>) {
2294 quote_identifiers_recursive(&mut join.this, reserved_words);
2295 if let Some(ref mut on) = join.on {
2296 quote_identifiers_recursive(on, reserved_words);
2297 }
2298 for id in &mut join.using {
2299 maybe_quote(id, reserved_words);
2300 }
2301 if let Some(ref mut mc) = join.match_condition {
2302 quote_identifiers_recursive(mc, reserved_words);
2303 }
2304 for piv in &mut join.pivots {
2305 quote_identifiers_recursive(piv, reserved_words);
2306 }
2307}
2308
2309fn quote_with(with: &mut With, reserved_words: &HashSet<&str>) {
2311 for cte in &mut with.ctes {
2312 maybe_quote(&mut cte.alias, reserved_words);
2313 for c in &mut cte.columns {
2314 maybe_quote(c, reserved_words);
2315 }
2316 for k in &mut cte.key_expressions {
2317 maybe_quote(k, reserved_words);
2318 }
2319 quote_identifiers_recursive(&mut cte.this, reserved_words);
2320 }
2321}
2322
2323fn quote_over(over: &mut Over, reserved_words: &HashSet<&str>) {
2325 if let Some(ref mut wn) = over.window_name {
2326 maybe_quote(wn, reserved_words);
2327 }
2328 for e in &mut over.partition_by {
2329 quote_identifiers_recursive(e, reserved_words);
2330 }
2331 for o in &mut over.order_by {
2332 quote_identifiers_recursive(&mut o.this, reserved_words);
2333 }
2334 if let Some(ref mut alias) = over.alias {
2335 maybe_quote(alias, reserved_words);
2336 }
2337}
2338
2339fn quote_table_ref(table_ref: &mut TableRef, reserved_words: &HashSet<&str>) {
2341 maybe_quote(&mut table_ref.name, reserved_words);
2342 if let Some(ref mut schema) = table_ref.schema {
2343 maybe_quote(schema, reserved_words);
2344 }
2345 if let Some(ref mut catalog) = table_ref.catalog {
2346 maybe_quote(catalog, reserved_words);
2347 }
2348 if let Some(ref mut alias) = table_ref.alias {
2349 maybe_quote(alias, reserved_words);
2350 }
2351 for ca in &mut table_ref.column_aliases {
2352 maybe_quote(ca, reserved_words);
2353 }
2354 for p in &mut table_ref.partitions {
2355 maybe_quote(p, reserved_words);
2356 }
2357 for h in &mut table_ref.hints {
2358 quote_identifiers_recursive(h, reserved_words);
2359 }
2360}
2361
2362fn quote_lateral_view(lv: &mut LateralView, reserved_words: &HashSet<&str>) {
2364 quote_identifiers_recursive(&mut lv.this, reserved_words);
2365 if let Some(ref mut ta) = lv.table_alias {
2366 maybe_quote(ta, reserved_words);
2367 }
2368 for ca in &mut lv.column_aliases {
2369 maybe_quote(ca, reserved_words);
2370 }
2371}
2372
2373pub fn quote_identifiers(expression: Expression, dialect: Option<DialectType>) -> Expression {
2384 let reserved_words = get_reserved_words(dialect);
2385 let mut result = expression;
2386 quote_identifiers_recursive(&mut result, &reserved_words);
2387 result
2388}
2389
2390pub fn pushdown_cte_alias_columns(_scope: &Scope) {
2395 }
2398
2399fn pushdown_cte_alias_columns_with(with: &mut With) {
2400 for cte in &mut with.ctes {
2401 if cte.columns.is_empty() {
2402 continue;
2403 }
2404
2405 if let Expression::Select(select) = &mut cte.this {
2406 let mut next_expressions = Vec::with_capacity(select.expressions.len());
2407
2408 for (i, projection) in select.expressions.iter().enumerate() {
2409 let Some(alias_name) = cte.columns.get(i) else {
2410 next_expressions.push(projection.clone());
2411 continue;
2412 };
2413
2414 match projection {
2415 Expression::Alias(existing) => {
2416 let mut aliased = existing.clone();
2417 aliased.alias = alias_name.clone();
2418 next_expressions.push(Expression::Alias(aliased));
2419 }
2420 _ => {
2421 next_expressions.push(create_alias(projection.clone(), &alias_name.name));
2422 }
2423 }
2424 }
2425
2426 select.expressions = next_expressions;
2427 }
2428 }
2429}
2430
2431fn get_scope_columns(scope: &Scope) -> Vec<ColumnRef> {
2437 let mut columns = Vec::new();
2438 collect_columns(&scope.expression, &mut columns);
2439 columns
2440}
2441
2442#[derive(Debug, Clone)]
2444struct ColumnRef {
2445 table: Option<String>,
2446 name: String,
2447}
2448
2449fn collect_columns(expr: &Expression, columns: &mut Vec<ColumnRef>) {
2451 match expr {
2452 Expression::Column(col) => {
2453 columns.push(ColumnRef {
2454 table: col.table.as_ref().map(|t| t.name.clone()),
2455 name: col.name.name.clone(),
2456 });
2457 }
2458 Expression::Select(select) => {
2459 for e in &select.expressions {
2460 collect_columns(e, columns);
2461 }
2462 if let Some(from) = &select.from {
2463 for e in &from.expressions {
2464 collect_columns(e, columns);
2465 }
2466 }
2467 if let Some(where_clause) = &select.where_clause {
2468 collect_columns(&where_clause.this, columns);
2469 }
2470 if let Some(group_by) = &select.group_by {
2471 for e in &group_by.expressions {
2472 collect_columns(e, columns);
2473 }
2474 }
2475 if let Some(having) = &select.having {
2476 collect_columns(&having.this, columns);
2477 }
2478 if let Some(order_by) = &select.order_by {
2479 for o in &order_by.expressions {
2480 collect_columns(&o.this, columns);
2481 }
2482 }
2483 for join in &select.joins {
2484 collect_columns(&join.this, columns);
2485 if let Some(on) = &join.on {
2486 collect_columns(on, columns);
2487 }
2488 }
2489 }
2490 Expression::Alias(alias) => {
2491 collect_columns(&alias.this, columns);
2492 }
2493 Expression::Function(func) => {
2494 for arg in &func.args {
2495 collect_columns(arg, columns);
2496 }
2497 }
2498 Expression::AggregateFunction(agg) => {
2499 for arg in &agg.args {
2500 collect_columns(arg, columns);
2501 }
2502 }
2503 Expression::And(bin)
2504 | Expression::Or(bin)
2505 | Expression::Eq(bin)
2506 | Expression::Neq(bin)
2507 | Expression::Lt(bin)
2508 | Expression::Lte(bin)
2509 | Expression::Gt(bin)
2510 | Expression::Gte(bin)
2511 | Expression::Add(bin)
2512 | Expression::Sub(bin)
2513 | Expression::Mul(bin)
2514 | Expression::Div(bin) => {
2515 collect_columns(&bin.left, columns);
2516 collect_columns(&bin.right, columns);
2517 }
2518 Expression::Not(unary) | Expression::Neg(unary) => {
2519 collect_columns(&unary.this, columns);
2520 }
2521 Expression::Paren(paren) => {
2522 collect_columns(&paren.this, columns);
2523 }
2524 Expression::Case(case) => {
2525 if let Some(operand) = &case.operand {
2526 collect_columns(operand, columns);
2527 }
2528 for (when, then) in &case.whens {
2529 collect_columns(when, columns);
2530 collect_columns(then, columns);
2531 }
2532 if let Some(else_) = &case.else_ {
2533 collect_columns(else_, columns);
2534 }
2535 }
2536 Expression::Cast(cast) => {
2537 collect_columns(&cast.this, columns);
2538 }
2539 Expression::In(in_expr) => {
2540 collect_columns(&in_expr.this, columns);
2541 for e in &in_expr.expressions {
2542 collect_columns(e, columns);
2543 }
2544 if let Some(query) = &in_expr.query {
2545 collect_columns(query, columns);
2546 }
2547 }
2548 Expression::Between(between) => {
2549 collect_columns(&between.this, columns);
2550 collect_columns(&between.low, columns);
2551 collect_columns(&between.high, columns);
2552 }
2553 Expression::Subquery(subquery) => {
2554 collect_columns(&subquery.this, columns);
2555 }
2556 _ => {}
2557 }
2558}
2559
2560fn get_unqualified_columns(scope: &Scope) -> Vec<ColumnRef> {
2562 get_scope_columns(scope)
2563 .into_iter()
2564 .filter(|c| c.table.is_none())
2565 .collect()
2566}
2567
2568fn get_external_columns(scope: &Scope) -> Vec<ColumnRef> {
2570 let source_names: HashSet<_> = scope.sources.keys().cloned().collect();
2571
2572 get_scope_columns(scope)
2573 .into_iter()
2574 .filter(|c| {
2575 if let Some(table) = &c.table {
2576 !source_names.contains(table)
2577 } else {
2578 false
2579 }
2580 })
2581 .collect()
2582}
2583
2584fn is_correlated_subquery(scope: &Scope) -> bool {
2586 scope.can_be_correlated && !get_external_columns(scope).is_empty()
2587}
2588
2589fn is_star_column(col: &Column) -> bool {
2591 col.name.name == "*"
2592}
2593
2594fn create_qualified_column(name: &str, table: Option<&str>) -> Expression {
2596 Expression::boxed_column(Column {
2597 name: Identifier::new(name),
2598 table: table.map(Identifier::new),
2599 join_mark: false,
2600 trailing_comments: vec![],
2601 span: None,
2602 inferred_type: None,
2603 })
2604}
2605
2606fn create_alias(expr: Expression, alias_name: &str) -> Expression {
2608 Expression::Alias(Box::new(Alias {
2609 this: expr,
2610 alias: Identifier::new(alias_name),
2611 column_aliases: vec![],
2612 alias_explicit_as: false,
2613 alias_keyword: None,
2614 pre_alias_comments: vec![],
2615 trailing_comments: vec![],
2616 inferred_type: None,
2617 }))
2618}
2619
2620fn get_output_name(expr: &Expression) -> Option<String> {
2622 match expr {
2623 Expression::Column(col) => Some(col.name.name.clone()),
2624 Expression::Alias(alias) => Some(alias.alias.name.clone()),
2625 Expression::Identifier(id) => Some(id.name.clone()),
2626 _ => None,
2627 }
2628}
2629
2630#[cfg(test)]
2631mod tests {
2632 use super::*;
2633 use crate::expressions::DataType;
2634 use crate::generator::Generator;
2635 use crate::parser::Parser;
2636 use crate::scope::build_scope;
2637 use crate::{MappingSchema, Schema};
2638
2639 fn gen(expr: &Expression) -> String {
2640 Generator::new().generate(expr).unwrap()
2641 }
2642
2643 fn parse(sql: &str) -> Expression {
2644 Parser::parse_sql(sql).expect("Failed to parse")[0].clone()
2645 }
2646
2647 #[test]
2648 fn test_qualify_columns_options() {
2649 let options = QualifyColumnsOptions::new()
2650 .with_expand_alias_refs(true)
2651 .with_expand_stars(false)
2652 .with_dialect(DialectType::PostgreSQL)
2653 .with_allow_partial(true);
2654
2655 assert!(options.expand_alias_refs);
2656 assert!(!options.expand_stars);
2657 assert_eq!(options.dialect, Some(DialectType::PostgreSQL));
2658 assert!(options.allow_partial_qualification);
2659 }
2660
2661 #[test]
2662 fn test_get_scope_columns() {
2663 let expr = parse("SELECT a, b FROM t WHERE c = 1");
2664 let scope = build_scope(&expr);
2665 let columns = get_scope_columns(&scope);
2666
2667 assert!(columns.iter().any(|c| c.name == "a"));
2668 assert!(columns.iter().any(|c| c.name == "b"));
2669 assert!(columns.iter().any(|c| c.name == "c"));
2670 }
2671
2672 #[test]
2673 fn test_get_unqualified_columns() {
2674 let expr = parse("SELECT t.a, b FROM t");
2675 let scope = build_scope(&expr);
2676 let unqualified = get_unqualified_columns(&scope);
2677
2678 assert!(unqualified.iter().any(|c| c.name == "b"));
2680 assert!(!unqualified.iter().any(|c| c.name == "a"));
2681 }
2682
2683 #[test]
2684 fn test_is_star_column() {
2685 let col = Column {
2686 name: Identifier::new("*"),
2687 table: Some(Identifier::new("t")),
2688 join_mark: false,
2689 trailing_comments: vec![],
2690 span: None,
2691 inferred_type: None,
2692 };
2693 assert!(is_star_column(&col));
2694
2695 let col2 = Column {
2696 name: Identifier::new("id"),
2697 table: None,
2698 join_mark: false,
2699 trailing_comments: vec![],
2700 span: None,
2701 inferred_type: None,
2702 };
2703 assert!(!is_star_column(&col2));
2704 }
2705
2706 #[test]
2707 fn test_create_qualified_column() {
2708 let expr = create_qualified_column("id", Some("users"));
2709 let sql = gen(&expr);
2710 assert!(sql.contains("users"));
2711 assert!(sql.contains("id"));
2712 }
2713
2714 #[test]
2715 fn test_create_alias() {
2716 let col = Expression::boxed_column(Column {
2717 name: Identifier::new("value"),
2718 table: None,
2719 join_mark: false,
2720 trailing_comments: vec![],
2721 span: None,
2722 inferred_type: None,
2723 });
2724 let aliased = create_alias(col, "total");
2725 let sql = gen(&aliased);
2726 assert!(sql.contains("AS") || sql.contains("total"));
2727 }
2728
2729 #[test]
2730 fn test_validate_qualify_columns_success() {
2731 let expr = parse("SELECT t.a, t.b FROM t");
2733 let result = validate_qualify_columns(&expr);
2734 let _ = result;
2737 }
2738
2739 #[test]
2740 fn test_collect_columns_nested() {
2741 let expr = parse("SELECT a + b, c FROM t WHERE d > 0 GROUP BY e HAVING f = 1");
2742 let mut columns = Vec::new();
2743 collect_columns(&expr, &mut columns);
2744
2745 let names: Vec<_> = columns.iter().map(|c| c.name.as_str()).collect();
2746 assert!(names.contains(&"a"));
2747 assert!(names.contains(&"b"));
2748 assert!(names.contains(&"c"));
2749 assert!(names.contains(&"d"));
2750 assert!(names.contains(&"e"));
2751 assert!(names.contains(&"f"));
2752 }
2753
2754 #[test]
2755 fn test_collect_columns_in_case() {
2756 let expr = parse("SELECT CASE WHEN a = 1 THEN b ELSE c END FROM t");
2757 let mut columns = Vec::new();
2758 collect_columns(&expr, &mut columns);
2759
2760 let names: Vec<_> = columns.iter().map(|c| c.name.as_str()).collect();
2761 assert!(names.contains(&"a"));
2762 assert!(names.contains(&"b"));
2763 assert!(names.contains(&"c"));
2764 }
2765
2766 #[test]
2767 fn test_collect_columns_in_subquery() {
2768 let expr = parse("SELECT a FROM t WHERE b IN (SELECT c FROM s)");
2769 let mut columns = Vec::new();
2770 collect_columns(&expr, &mut columns);
2771
2772 let names: Vec<_> = columns.iter().map(|c| c.name.as_str()).collect();
2773 assert!(names.contains(&"a"));
2774 assert!(names.contains(&"b"));
2775 assert!(names.contains(&"c"));
2776 }
2777
2778 #[test]
2779 fn test_qualify_outputs_basic() {
2780 let expr = parse("SELECT a, b + c FROM t");
2781 let scope = build_scope(&expr);
2782 let result = qualify_outputs(&scope);
2783 assert!(result.is_ok());
2784 }
2785
2786 #[test]
2787 fn test_qualify_columns_expands_star_with_schema() {
2788 let expr = parse("SELECT * FROM users");
2789
2790 let mut schema = MappingSchema::new();
2791 schema
2792 .add_table(
2793 "users",
2794 &[
2795 (
2796 "id".to_string(),
2797 DataType::Int {
2798 length: None,
2799 integer_spelling: false,
2800 },
2801 ),
2802 ("name".to_string(), DataType::Text),
2803 ("email".to_string(), DataType::Text),
2804 ],
2805 None,
2806 )
2807 .expect("schema setup");
2808
2809 let result =
2810 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
2811 let sql = gen(&result);
2812
2813 assert!(!sql.contains("SELECT *"));
2814 assert!(sql.contains("users.id"));
2815 assert!(sql.contains("users.name"));
2816 assert!(sql.contains("users.email"));
2817 }
2818
2819 #[test]
2820 fn test_qualify_columns_expands_group_by_positions() {
2821 let expr = parse("SELECT a, b FROM t GROUP BY 1, 2");
2822
2823 let mut schema = MappingSchema::new();
2824 schema
2825 .add_table(
2826 "t",
2827 &[
2828 (
2829 "a".to_string(),
2830 DataType::Int {
2831 length: None,
2832 integer_spelling: false,
2833 },
2834 ),
2835 (
2836 "b".to_string(),
2837 DataType::Int {
2838 length: None,
2839 integer_spelling: false,
2840 },
2841 ),
2842 ],
2843 None,
2844 )
2845 .expect("schema setup");
2846
2847 let result =
2848 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
2849 let sql = gen(&result);
2850
2851 assert!(!sql.contains("GROUP BY 1"));
2852 assert!(!sql.contains("GROUP BY 2"));
2853 assert!(sql.contains("GROUP BY"));
2854 assert!(sql.contains("t.a"));
2855 assert!(sql.contains("t.b"));
2856 }
2857
2858 #[test]
2863 fn test_expand_using_simple() {
2864 let expr = parse("SELECT x.b FROM x JOIN y USING (b)");
2866
2867 let mut schema = MappingSchema::new();
2868 schema
2869 .add_table(
2870 "x",
2871 &[
2872 ("a".to_string(), DataType::BigInt { length: None }),
2873 ("b".to_string(), DataType::BigInt { length: None }),
2874 ],
2875 None,
2876 )
2877 .expect("schema setup");
2878 schema
2879 .add_table(
2880 "y",
2881 &[
2882 ("b".to_string(), DataType::BigInt { length: None }),
2883 ("c".to_string(), DataType::BigInt { length: None }),
2884 ],
2885 None,
2886 )
2887 .expect("schema setup");
2888
2889 let result =
2890 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
2891 let sql = gen(&result);
2892
2893 assert!(
2895 !sql.contains("USING"),
2896 "USING should be replaced with ON: {sql}"
2897 );
2898 assert!(
2899 sql.contains("ON x.b = y.b"),
2900 "ON condition should be x.b = y.b: {sql}"
2901 );
2902 assert!(sql.contains("SELECT x.b"), "SELECT should keep x.b: {sql}");
2904 }
2905
2906 #[test]
2907 fn test_expand_using_unqualified_coalesce() {
2908 let expr = parse("SELECT b FROM x JOIN y USING(b)");
2910
2911 let mut schema = MappingSchema::new();
2912 schema
2913 .add_table(
2914 "x",
2915 &[
2916 ("a".to_string(), DataType::BigInt { length: None }),
2917 ("b".to_string(), DataType::BigInt { length: None }),
2918 ],
2919 None,
2920 )
2921 .expect("schema setup");
2922 schema
2923 .add_table(
2924 "y",
2925 &[
2926 ("b".to_string(), DataType::BigInt { length: None }),
2927 ("c".to_string(), DataType::BigInt { length: None }),
2928 ],
2929 None,
2930 )
2931 .expect("schema setup");
2932
2933 let result =
2934 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
2935 let sql = gen(&result);
2936
2937 assert!(
2938 sql.contains("COALESCE(x.b, y.b)"),
2939 "Unqualified USING column should become COALESCE: {sql}"
2940 );
2941 assert!(
2942 sql.contains("AS b"),
2943 "COALESCE should be aliased as 'b': {sql}"
2944 );
2945 assert!(
2946 sql.contains("ON x.b = y.b"),
2947 "ON condition should be generated: {sql}"
2948 );
2949 }
2950
2951 #[test]
2952 fn test_expand_using_with_where() {
2953 let expr = parse("SELECT b FROM x JOIN y USING(b) WHERE b = 1");
2955
2956 let mut schema = MappingSchema::new();
2957 schema
2958 .add_table(
2959 "x",
2960 &[("b".to_string(), DataType::BigInt { length: None })],
2961 None,
2962 )
2963 .expect("schema setup");
2964 schema
2965 .add_table(
2966 "y",
2967 &[("b".to_string(), DataType::BigInt { length: None })],
2968 None,
2969 )
2970 .expect("schema setup");
2971
2972 let result =
2973 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
2974 let sql = gen(&result);
2975
2976 assert!(
2977 sql.contains("WHERE COALESCE(x.b, y.b)"),
2978 "WHERE should use COALESCE for USING column: {sql}"
2979 );
2980 }
2981
2982 #[test]
2983 fn test_expand_using_multi_join() {
2984 let expr = parse("SELECT b FROM x JOIN y USING(b) JOIN z USING(b)");
2986
2987 let mut schema = MappingSchema::new();
2988 for table in &["x", "y", "z"] {
2989 schema
2990 .add_table(
2991 table,
2992 &[("b".to_string(), DataType::BigInt { length: None })],
2993 None,
2994 )
2995 .expect("schema setup");
2996 }
2997
2998 let result =
2999 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3000 let sql = gen(&result);
3001
3002 assert!(
3004 sql.contains("COALESCE(x.b, y.b, z.b)"),
3005 "Should have 3-table COALESCE: {sql}"
3006 );
3007 assert!(
3009 sql.contains("ON x.b = y.b"),
3010 "First join ON condition: {sql}"
3011 );
3012 }
3013
3014 #[test]
3015 fn test_expand_using_multi_column() {
3016 let expr = parse("SELECT b, c FROM y JOIN z USING(b, c)");
3018
3019 let mut schema = MappingSchema::new();
3020 schema
3021 .add_table(
3022 "y",
3023 &[
3024 ("b".to_string(), DataType::BigInt { length: None }),
3025 ("c".to_string(), DataType::BigInt { length: None }),
3026 ],
3027 None,
3028 )
3029 .expect("schema setup");
3030 schema
3031 .add_table(
3032 "z",
3033 &[
3034 ("b".to_string(), DataType::BigInt { length: None }),
3035 ("c".to_string(), DataType::BigInt { length: None }),
3036 ],
3037 None,
3038 )
3039 .expect("schema setup");
3040
3041 let result =
3042 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3043 let sql = gen(&result);
3044
3045 assert!(
3046 sql.contains("COALESCE(y.b, z.b)"),
3047 "column 'b' should get COALESCE: {sql}"
3048 );
3049 assert!(
3050 sql.contains("COALESCE(y.c, z.c)"),
3051 "column 'c' should get COALESCE: {sql}"
3052 );
3053 assert!(
3055 sql.contains("y.b = z.b") && sql.contains("y.c = z.c"),
3056 "ON should have both equality conditions: {sql}"
3057 );
3058 }
3059
3060 #[test]
3061 fn test_expand_using_star() {
3062 let expr = parse("SELECT * FROM x JOIN y USING(b)");
3064
3065 let mut schema = MappingSchema::new();
3066 schema
3067 .add_table(
3068 "x",
3069 &[
3070 ("a".to_string(), DataType::BigInt { length: None }),
3071 ("b".to_string(), DataType::BigInt { length: None }),
3072 ],
3073 None,
3074 )
3075 .expect("schema setup");
3076 schema
3077 .add_table(
3078 "y",
3079 &[
3080 ("b".to_string(), DataType::BigInt { length: None }),
3081 ("c".to_string(), DataType::BigInt { length: None }),
3082 ],
3083 None,
3084 )
3085 .expect("schema setup");
3086
3087 let result =
3088 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3089 let sql = gen(&result);
3090
3091 assert!(
3093 sql.contains("COALESCE(x.b, y.b) AS b"),
3094 "USING column should be COALESCE in star expansion: {sql}"
3095 );
3096 assert!(sql.contains("x.a"), "non-USING column a from x: {sql}");
3098 assert!(sql.contains("y.c"), "non-USING column c from y: {sql}");
3099 let coalesce_count = sql.matches("COALESCE").count();
3101 assert_eq!(
3102 coalesce_count, 1,
3103 "b should appear only once as COALESCE: {sql}"
3104 );
3105 }
3106
3107 #[test]
3108 fn test_expand_using_table_star() {
3109 let expr = parse("SELECT x.* FROM x JOIN y USING(b)");
3111
3112 let mut schema = MappingSchema::new();
3113 schema
3114 .add_table(
3115 "x",
3116 &[
3117 ("a".to_string(), DataType::BigInt { length: None }),
3118 ("b".to_string(), DataType::BigInt { length: None }),
3119 ],
3120 None,
3121 )
3122 .expect("schema setup");
3123 schema
3124 .add_table(
3125 "y",
3126 &[
3127 ("b".to_string(), DataType::BigInt { length: None }),
3128 ("c".to_string(), DataType::BigInt { length: None }),
3129 ],
3130 None,
3131 )
3132 .expect("schema setup");
3133
3134 let result =
3135 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3136 let sql = gen(&result);
3137
3138 assert!(
3140 sql.contains("COALESCE(x.b, y.b)"),
3141 "USING column from x.* should become COALESCE: {sql}"
3142 );
3143 assert!(sql.contains("x.a"), "non-USING column a: {sql}");
3144 }
3145
3146 #[test]
3147 fn test_qualify_columns_qualified_table_name() {
3148 let expr = parse("SELECT a FROM raw.t1");
3149
3150 let mut schema = MappingSchema::new();
3151 schema
3152 .add_table(
3153 "raw.t1",
3154 &[("a".to_string(), DataType::BigInt { length: None })],
3155 None,
3156 )
3157 .expect("schema setup");
3158
3159 let result =
3160 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3161 let sql = gen(&result);
3162
3163 assert!(
3164 sql.contains("t1.a"),
3165 "column should be qualified with table name: {sql}"
3166 );
3167
3168 let expr = parse("SELECT MAX(a) FROM raw.t1");
3170 let result =
3171 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3172 let sql = gen(&result);
3173 assert!(
3174 sql.contains("t1.a"),
3175 "column in function should be qualified with table name: {sql}"
3176 );
3177
3178 let expr = parse("SELECT ABS(a) FROM raw.t1");
3180 let result =
3181 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3182 let sql = gen(&result);
3183 assert!(
3184 sql.contains("t1.a"),
3185 "column in function should be qualified with table name: {sql}"
3186 );
3187 }
3188
3189 #[test]
3190 fn test_qualify_columns_count_star() {
3191 let expr = parse("SELECT COUNT(*) FROM t1");
3193
3194 let mut schema = MappingSchema::new();
3195 schema
3196 .add_table(
3197 "t1",
3198 &[("id".to_string(), DataType::BigInt { length: None })],
3199 None,
3200 )
3201 .expect("schema setup");
3202
3203 let result =
3204 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3205 let sql = gen(&result);
3206
3207 assert!(
3208 sql.contains("COUNT(*)"),
3209 "COUNT(*) should be preserved: {sql}"
3210 );
3211 }
3212
3213 #[test]
3214 fn test_qualify_columns_correlated_scalar_subquery() {
3215 let expr =
3216 parse("SELECT id, (SELECT AVG(val) FROM t2 WHERE t2.id = t1.id) AS avg_val FROM t1");
3217
3218 let mut schema = MappingSchema::new();
3219 schema
3220 .add_table(
3221 "t1",
3222 &[("id".to_string(), DataType::BigInt { length: None })],
3223 None,
3224 )
3225 .expect("schema setup");
3226 schema
3227 .add_table(
3228 "t2",
3229 &[
3230 ("id".to_string(), DataType::BigInt { length: None }),
3231 ("val".to_string(), DataType::BigInt { length: None }),
3232 ],
3233 None,
3234 )
3235 .expect("schema setup");
3236
3237 let result =
3238 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3239 let sql = gen(&result);
3240
3241 assert!(
3242 sql.contains("t1.id"),
3243 "outer column should be qualified: {sql}"
3244 );
3245 assert!(
3246 sql.contains("t2.id"),
3247 "inner column should be qualified: {sql}"
3248 );
3249 }
3250
3251 #[test]
3252 fn test_qualify_columns_correlated_scalar_subquery_unqualified() {
3253 let expr =
3254 parse("SELECT t1_id, (SELECT AVG(val) FROM t2 WHERE t2_id = t1_id) AS avg_val FROM t1");
3255
3256 let mut schema = MappingSchema::new();
3257 schema
3258 .add_table(
3259 "t1",
3260 &[("t1_id".to_string(), DataType::BigInt { length: None })],
3261 None,
3262 )
3263 .expect("schema setup");
3264 schema
3265 .add_table(
3266 "t2",
3267 &[
3268 ("t2_id".to_string(), DataType::BigInt { length: None }),
3269 ("val".to_string(), DataType::BigInt { length: None }),
3270 ],
3271 None,
3272 )
3273 .expect("schema setup");
3274
3275 let result =
3276 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3277 let sql = gen(&result);
3278
3279 assert!(
3280 sql.contains("t1.t1_id"),
3281 "outer column should be qualified: {sql}"
3282 );
3283 assert!(
3284 sql.contains("t2.t2_id"),
3285 "inner column should be qualified: {sql}"
3286 );
3287 assert!(
3289 sql.contains("= t1.t1_id"),
3290 "correlated column should be qualified: {sql}"
3291 );
3292 }
3293
3294 #[test]
3295 fn test_qualify_columns_correlated_exists_subquery() {
3296 let expr = parse(
3297 "SELECT o_orderpriority FROM orders \
3298 WHERE EXISTS (SELECT * FROM lineitem WHERE l_orderkey = o_orderkey)",
3299 );
3300
3301 let mut schema = MappingSchema::new();
3302 schema
3303 .add_table(
3304 "orders",
3305 &[
3306 ("o_orderpriority".to_string(), DataType::Text),
3307 ("o_orderkey".to_string(), DataType::BigInt { length: None }),
3308 ],
3309 None,
3310 )
3311 .expect("schema setup");
3312 schema
3313 .add_table(
3314 "lineitem",
3315 &[("l_orderkey".to_string(), DataType::BigInt { length: None })],
3316 None,
3317 )
3318 .expect("schema setup");
3319
3320 let result =
3321 qualify_columns(expr, &schema, &QualifyColumnsOptions::new()).expect("qualify");
3322 let sql = gen(&result);
3323
3324 assert!(
3325 sql.contains("orders.o_orderpriority"),
3326 "outer column should be qualified: {sql}"
3327 );
3328 assert!(
3329 sql.contains("lineitem.l_orderkey"),
3330 "inner column should be qualified: {sql}"
3331 );
3332 assert!(
3333 sql.contains("orders.o_orderkey"),
3334 "correlated outer column should be qualified: {sql}"
3335 );
3336 }
3337
3338 #[test]
3339 fn test_qualify_columns_rejects_unknown_table() {
3340 let expr = parse("SELECT id FROM t1 WHERE nonexistent.col = 1");
3341
3342 let mut schema = MappingSchema::new();
3343 schema
3344 .add_table(
3345 "t1",
3346 &[("id".to_string(), DataType::BigInt { length: None })],
3347 None,
3348 )
3349 .expect("schema setup");
3350
3351 let result = qualify_columns(expr, &schema, &QualifyColumnsOptions::new());
3352 assert!(
3353 result.is_err(),
3354 "should reject reference to table not in scope or schema"
3355 );
3356 }
3357
3358 #[test]
3363 fn test_needs_quoting_reserved_word() {
3364 let reserved = get_reserved_words(None);
3365 assert!(needs_quoting("select", &reserved));
3366 assert!(needs_quoting("SELECT", &reserved));
3367 assert!(needs_quoting("from", &reserved));
3368 assert!(needs_quoting("WHERE", &reserved));
3369 assert!(needs_quoting("join", &reserved));
3370 assert!(needs_quoting("table", &reserved));
3371 }
3372
3373 #[test]
3374 fn test_needs_quoting_normal_identifiers() {
3375 let reserved = get_reserved_words(None);
3376 assert!(!needs_quoting("foo", &reserved));
3377 assert!(!needs_quoting("my_column", &reserved));
3378 assert!(!needs_quoting("col1", &reserved));
3379 assert!(!needs_quoting("A", &reserved));
3380 assert!(!needs_quoting("_hidden", &reserved));
3381 }
3382
3383 #[test]
3384 fn test_needs_quoting_special_characters() {
3385 let reserved = get_reserved_words(None);
3386 assert!(needs_quoting("my column", &reserved)); assert!(needs_quoting("my-column", &reserved)); assert!(needs_quoting("my.column", &reserved)); assert!(needs_quoting("col@name", &reserved)); assert!(needs_quoting("col#name", &reserved)); }
3392
3393 #[test]
3394 fn test_needs_quoting_starts_with_digit() {
3395 let reserved = get_reserved_words(None);
3396 assert!(needs_quoting("1col", &reserved));
3397 assert!(needs_quoting("123", &reserved));
3398 assert!(needs_quoting("0_start", &reserved));
3399 }
3400
3401 #[test]
3402 fn test_needs_quoting_empty() {
3403 let reserved = get_reserved_words(None);
3404 assert!(!needs_quoting("", &reserved));
3405 }
3406
3407 #[test]
3408 fn test_maybe_quote_sets_quoted_flag() {
3409 let reserved = get_reserved_words(None);
3410 let mut id = Identifier::new("select");
3411 assert!(!id.quoted);
3412 maybe_quote(&mut id, &reserved);
3413 assert!(id.quoted);
3414 }
3415
3416 #[test]
3417 fn test_maybe_quote_skips_already_quoted() {
3418 let reserved = get_reserved_words(None);
3419 let mut id = Identifier::quoted("myname");
3420 assert!(id.quoted);
3421 maybe_quote(&mut id, &reserved);
3422 assert!(id.quoted); assert_eq!(id.name, "myname"); }
3425
3426 #[test]
3427 fn test_maybe_quote_skips_star() {
3428 let reserved = get_reserved_words(None);
3429 let mut id = Identifier::new("*");
3430 maybe_quote(&mut id, &reserved);
3431 assert!(!id.quoted); }
3433
3434 #[test]
3435 fn test_maybe_quote_skips_normal() {
3436 let reserved = get_reserved_words(None);
3437 let mut id = Identifier::new("normal_col");
3438 maybe_quote(&mut id, &reserved);
3439 assert!(!id.quoted);
3440 }
3441
3442 #[test]
3443 fn test_quote_identifiers_column_with_reserved_name() {
3444 let expr = Expression::boxed_column(Column {
3446 name: Identifier::new("select"),
3447 table: None,
3448 join_mark: false,
3449 trailing_comments: vec![],
3450 span: None,
3451 inferred_type: None,
3452 });
3453 let result = quote_identifiers(expr, None);
3454 if let Expression::Column(col) = &result {
3455 assert!(col.name.quoted, "Column named 'select' should be quoted");
3456 } else {
3457 panic!("Expected Column expression");
3458 }
3459 }
3460
3461 #[test]
3462 fn test_quote_identifiers_column_with_special_chars() {
3463 let expr = Expression::boxed_column(Column {
3464 name: Identifier::new("my column"),
3465 table: None,
3466 join_mark: false,
3467 trailing_comments: vec![],
3468 span: None,
3469 inferred_type: None,
3470 });
3471 let result = quote_identifiers(expr, None);
3472 if let Expression::Column(col) = &result {
3473 assert!(col.name.quoted, "Column with space should be quoted");
3474 } else {
3475 panic!("Expected Column expression");
3476 }
3477 }
3478
3479 #[test]
3480 fn test_quote_identifiers_preserves_normal_column() {
3481 let expr = Expression::boxed_column(Column {
3482 name: Identifier::new("normal_col"),
3483 table: Some(Identifier::new("my_table")),
3484 join_mark: false,
3485 trailing_comments: vec![],
3486 span: None,
3487 inferred_type: None,
3488 });
3489 let result = quote_identifiers(expr, None);
3490 if let Expression::Column(col) = &result {
3491 assert!(!col.name.quoted, "Normal column should not be quoted");
3492 assert!(
3493 !col.table.as_ref().unwrap().quoted,
3494 "Normal table should not be quoted"
3495 );
3496 } else {
3497 panic!("Expected Column expression");
3498 }
3499 }
3500
3501 #[test]
3502 fn test_quote_identifiers_table_ref_reserved() {
3503 let expr = Expression::Table(Box::new(TableRef::new("select")));
3504 let result = quote_identifiers(expr, None);
3505 if let Expression::Table(tr) = &result {
3506 assert!(tr.name.quoted, "Table named 'select' should be quoted");
3507 } else {
3508 panic!("Expected Table expression");
3509 }
3510 }
3511
3512 #[test]
3513 fn test_quote_identifiers_table_ref_schema_and_alias() {
3514 let mut tr = TableRef::new("my_table");
3515 tr.schema = Some(Identifier::new("from"));
3516 tr.alias = Some(Identifier::new("t"));
3517 let expr = Expression::Table(Box::new(tr));
3518 let result = quote_identifiers(expr, None);
3519 if let Expression::Table(tr) = &result {
3520 assert!(!tr.name.quoted, "Normal table name should not be quoted");
3521 assert!(
3522 tr.schema.as_ref().unwrap().quoted,
3523 "Schema named 'from' should be quoted"
3524 );
3525 assert!(
3526 !tr.alias.as_ref().unwrap().quoted,
3527 "Normal alias should not be quoted"
3528 );
3529 } else {
3530 panic!("Expected Table expression");
3531 }
3532 }
3533
3534 #[test]
3535 fn test_quote_identifiers_identifier_node() {
3536 let expr = Expression::Identifier(Identifier::new("order"));
3537 let result = quote_identifiers(expr, None);
3538 if let Expression::Identifier(id) = &result {
3539 assert!(id.quoted, "Identifier named 'order' should be quoted");
3540 } else {
3541 panic!("Expected Identifier expression");
3542 }
3543 }
3544
3545 #[test]
3546 fn test_quote_identifiers_alias() {
3547 let inner = Expression::boxed_column(Column {
3548 name: Identifier::new("val"),
3549 table: None,
3550 join_mark: false,
3551 trailing_comments: vec![],
3552 span: None,
3553 inferred_type: None,
3554 });
3555 let expr = Expression::Alias(Box::new(Alias {
3556 this: inner,
3557 alias: Identifier::new("select"),
3558 column_aliases: vec![Identifier::new("from")],
3559 alias_explicit_as: false,
3560 alias_keyword: None,
3561 pre_alias_comments: vec![],
3562 trailing_comments: vec![],
3563 inferred_type: None,
3564 }));
3565 let result = quote_identifiers(expr, None);
3566 if let Expression::Alias(alias) = &result {
3567 assert!(alias.alias.quoted, "Alias named 'select' should be quoted");
3568 assert!(
3569 alias.column_aliases[0].quoted,
3570 "Column alias named 'from' should be quoted"
3571 );
3572 if let Expression::Column(col) = &alias.this {
3574 assert!(!col.name.quoted);
3575 }
3576 } else {
3577 panic!("Expected Alias expression");
3578 }
3579 }
3580
3581 #[test]
3582 fn test_quote_identifiers_select_recursive() {
3583 let expr = parse("SELECT a, b FROM t WHERE c = 1");
3585 let result = quote_identifiers(expr, None);
3586 let sql = gen(&result);
3588 assert!(sql.contains("a"));
3590 assert!(sql.contains("b"));
3591 assert!(sql.contains("t"));
3592 }
3593
3594 #[test]
3595 fn test_quote_identifiers_digit_start() {
3596 let expr = Expression::boxed_column(Column {
3597 name: Identifier::new("1col"),
3598 table: None,
3599 join_mark: false,
3600 trailing_comments: vec![],
3601 span: None,
3602 inferred_type: None,
3603 });
3604 let result = quote_identifiers(expr, None);
3605 if let Expression::Column(col) = &result {
3606 assert!(
3607 col.name.quoted,
3608 "Column starting with digit should be quoted"
3609 );
3610 } else {
3611 panic!("Expected Column expression");
3612 }
3613 }
3614
3615 #[test]
3616 fn test_quote_identifiers_with_mysql_dialect() {
3617 let reserved = get_reserved_words(Some(DialectType::MySQL));
3618 assert!(needs_quoting("KILL", &reserved));
3620 assert!(needs_quoting("FORCE", &reserved));
3622 }
3623
3624 #[test]
3625 fn test_quote_identifiers_with_postgresql_dialect() {
3626 let reserved = get_reserved_words(Some(DialectType::PostgreSQL));
3627 assert!(needs_quoting("ILIKE", &reserved));
3629 assert!(needs_quoting("VERBOSE", &reserved));
3631 }
3632
3633 #[test]
3634 fn test_quote_identifiers_with_bigquery_dialect() {
3635 let reserved = get_reserved_words(Some(DialectType::BigQuery));
3636 assert!(needs_quoting("STRUCT", &reserved));
3638 assert!(needs_quoting("PROTO", &reserved));
3640 }
3641
3642 #[test]
3643 fn test_quote_identifiers_case_insensitive_reserved() {
3644 let reserved = get_reserved_words(None);
3645 assert!(needs_quoting("Select", &reserved));
3646 assert!(needs_quoting("sElEcT", &reserved));
3647 assert!(needs_quoting("FROM", &reserved));
3648 assert!(needs_quoting("from", &reserved));
3649 }
3650
3651 #[test]
3652 fn test_quote_identifiers_join_using() {
3653 let mut join = crate::expressions::Join {
3655 this: Expression::Table(Box::new(TableRef::new("other"))),
3656 on: None,
3657 using: vec![Identifier::new("key"), Identifier::new("value")],
3658 kind: crate::expressions::JoinKind::Inner,
3659 use_inner_keyword: false,
3660 use_outer_keyword: false,
3661 deferred_condition: false,
3662 join_hint: None,
3663 match_condition: None,
3664 pivots: vec![],
3665 comments: vec![],
3666 nesting_group: 0,
3667 directed: false,
3668 };
3669 let reserved = get_reserved_words(None);
3670 quote_join(&mut join, &reserved);
3671 assert!(
3673 join.using[0].quoted,
3674 "USING identifier 'key' should be quoted"
3675 );
3676 assert!(
3677 !join.using[1].quoted,
3678 "USING identifier 'value' should not be quoted"
3679 );
3680 }
3681
3682 #[test]
3683 fn test_quote_identifiers_cte() {
3684 let mut cte = crate::expressions::Cte {
3686 alias: Identifier::new("select"),
3687 this: Expression::boxed_column(Column {
3688 name: Identifier::new("x"),
3689 table: None,
3690 join_mark: false,
3691 trailing_comments: vec![],
3692 span: None,
3693 inferred_type: None,
3694 }),
3695 columns: vec![Identifier::new("from"), Identifier::new("normal")],
3696 materialized: None,
3697 key_expressions: vec![],
3698 alias_first: false,
3699 comments: Vec::new(),
3700 };
3701 let reserved = get_reserved_words(None);
3702 maybe_quote(&mut cte.alias, &reserved);
3703 for c in &mut cte.columns {
3704 maybe_quote(c, &reserved);
3705 }
3706 assert!(cte.alias.quoted, "CTE alias 'select' should be quoted");
3707 assert!(cte.columns[0].quoted, "CTE column 'from' should be quoted");
3708 assert!(
3709 !cte.columns[1].quoted,
3710 "CTE column 'normal' should not be quoted"
3711 );
3712 }
3713
3714 #[test]
3715 fn test_quote_identifiers_binary_ops_recurse() {
3716 let expr = Expression::Add(Box::new(crate::expressions::BinaryOp::new(
3719 Expression::boxed_column(Column {
3720 name: Identifier::new("select"),
3721 table: None,
3722 join_mark: false,
3723 trailing_comments: vec![],
3724 span: None,
3725 inferred_type: None,
3726 }),
3727 Expression::boxed_column(Column {
3728 name: Identifier::new("normal"),
3729 table: None,
3730 join_mark: false,
3731 trailing_comments: vec![],
3732 span: None,
3733 inferred_type: None,
3734 }),
3735 )));
3736 let result = quote_identifiers(expr, None);
3737 if let Expression::Add(bin) = &result {
3738 if let Expression::Column(left) = &bin.left {
3739 assert!(
3740 left.name.quoted,
3741 "'select' column should be quoted in binary op"
3742 );
3743 }
3744 if let Expression::Column(right) = &bin.right {
3745 assert!(!right.name.quoted, "'normal' column should not be quoted");
3746 }
3747 } else {
3748 panic!("Expected Add expression");
3749 }
3750 }
3751
3752 #[test]
3753 fn test_quote_identifiers_already_quoted_preserved() {
3754 let expr = Expression::boxed_column(Column {
3756 name: Identifier::quoted("normal_name"),
3757 table: None,
3758 join_mark: false,
3759 trailing_comments: vec![],
3760 span: None,
3761 inferred_type: None,
3762 });
3763 let result = quote_identifiers(expr, None);
3764 if let Expression::Column(col) = &result {
3765 assert!(
3766 col.name.quoted,
3767 "Already-quoted identifier should remain quoted"
3768 );
3769 } else {
3770 panic!("Expected Column expression");
3771 }
3772 }
3773
3774 #[test]
3775 fn test_quote_identifiers_full_parsed_query() {
3776 let mut select = crate::expressions::Select::new();
3779 select.expressions.push(Expression::boxed_column(Column {
3780 name: Identifier::new("order"),
3781 table: Some(Identifier::new("t")),
3782 join_mark: false,
3783 trailing_comments: vec![],
3784 span: None,
3785 inferred_type: None,
3786 }));
3787 select.from = Some(crate::expressions::From {
3788 expressions: vec![Expression::Table(Box::new(TableRef::new("t")))],
3789 });
3790 let expr = Expression::Select(Box::new(select));
3791
3792 let result = quote_identifiers(expr, None);
3793 if let Expression::Select(sel) = &result {
3794 if let Expression::Column(col) = &sel.expressions[0] {
3795 assert!(col.name.quoted, "Column named 'order' should be quoted");
3796 assert!(
3797 !col.table.as_ref().unwrap().quoted,
3798 "Table 't' should not be quoted"
3799 );
3800 } else {
3801 panic!("Expected Column in SELECT list");
3802 }
3803 } else {
3804 panic!("Expected Select expression");
3805 }
3806 }
3807
3808 #[test]
3809 fn test_get_reserved_words_all_dialects() {
3810 let dialects = [
3812 None,
3813 Some(DialectType::Generic),
3814 Some(DialectType::MySQL),
3815 Some(DialectType::PostgreSQL),
3816 Some(DialectType::BigQuery),
3817 Some(DialectType::Snowflake),
3818 Some(DialectType::TSQL),
3819 Some(DialectType::ClickHouse),
3820 Some(DialectType::DuckDB),
3821 Some(DialectType::Hive),
3822 Some(DialectType::Spark),
3823 Some(DialectType::Trino),
3824 Some(DialectType::Oracle),
3825 Some(DialectType::Redshift),
3826 ];
3827 for dialect in &dialects {
3828 let words = get_reserved_words(*dialect);
3829 assert!(
3831 words.contains("SELECT"),
3832 "All dialects should have SELECT as reserved"
3833 );
3834 assert!(
3835 words.contains("FROM"),
3836 "All dialects should have FROM as reserved"
3837 );
3838 }
3839 }
3840}