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