Skip to content

Commit ec4f322

Browse files
committed
ask ai to add comments
fuzz test and refactor fmt: cleanup clippy
1 parent 18c8299 commit ec4f322

File tree

3 files changed

+506
-135
lines changed

3 files changed

+506
-135
lines changed

core/translate/alter.rs

Lines changed: 88 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::translate::expr::{walk_expr, walk_expr_mut, WalkControl};
12
use std::sync::Arc;
23
use turso_parser::{
34
ast::{self, TableInternalId},
@@ -9,7 +10,6 @@ use crate::{
910
schema::{Column, ForeignKey, Table, RESERVED_TABLE_PREFIXES},
1011
translate::{
1112
emitter::Resolver,
12-
expr::{walk_expr, WalkControl},
1313
plan::{ColumnUsedMask, OuterQueryReference, TableReferences},
1414
},
1515
util::normalize_ident,
@@ -2511,8 +2511,14 @@ fn rewrite_expr_column_ref(
25112511
)
25122512
}
25132513

2514-
/// Walk an Upsert clause and rewrite table references for table rename.
2515-
/// Handles conflict targets, target WHERE, DO SET expressions, DO WHERE, and chained upserts.
2514+
/// Walk an Upsert clause and rewrite qualified table references for table rename.
2515+
///
2516+
/// Handles ON CONFLICT clauses that may contain table-qualified column references:
2517+
/// - Conflict targets: Expressions in `ON CONFLICT(expr, ...)` that may reference the table
2518+
/// - Target WHERE: The optional `WHERE` clause after conflict targets
2519+
/// - DO UPDATE SET: Expressions in `SET col = expr` assignments (e.g., `val = t1.val || 'x'`)
2520+
/// - DO UPDATE WHERE: The optional `WHERE` clause of the DO UPDATE
2521+
/// - Chained upserts: Recursively handles multiple ON CONFLICT clauses
25162522
pub fn walk_upsert_for_table_rename(
25172523
upsert: &mut ast::Upsert,
25182524
old_table_norm: &str,
@@ -2555,135 +2561,76 @@ pub fn walk_upsert_for_table_rename(
25552561
changed
25562562
}
25572563

2564+
/// Rewrite qualified table references in an expression tree for table rename.
2565+
///
2566+
/// Handles table-qualified column references in trigger expressions:
2567+
/// - Qualified column refs (e.g., `t1.col`): Rewrites to `"t1_new".col`
2568+
/// - Doubly-qualified (e.g., `main.t1.col`): Rewrites to `main."t1_new".col`
2569+
/// - InTable expression (e.g., `x IN t1`): Rewrites to `x IN "t1_new"`
2570+
/// - Subqueries and nested expressions: Recursively walks all child expressions
2571+
///
2572+
/// `old_table_norm`: Normalized (lowercase) name of the table being renamed.
2573+
/// `new_table_name`: New name for the table (will be double-quoted in output).
2574+
///
2575+
/// This function uses `walk_expr_mut` from `expr.rs` to traverse all expression
2576+
/// variants automatically, including WINDOW clauses and frame bounds. Only the
2577+
/// special cases (table-qualified names) are handled in the callback.
25582578
pub fn rewrite_expr_table_refs_for_rename(
25592579
expr: &mut Box<ast::Expr>,
25602580
old_table_norm: &str,
25612581
new_table_name: &str,
25622582
) -> bool {
25632583
let mut changed = false;
25642584

2565-
match expr.as_mut() {
2566-
ast::Expr::Qualified(ref mut tbl_name, _) => {
2567-
if normalize_ident(tbl_name.as_str()) == old_table_norm {
2568-
*tbl_name = ast::Name::from_string(format!("\"{new_table_name}\""));
2569-
changed = true;
2570-
}
2571-
}
2572-
2573-
ast::Expr::DoublyQualified(_, ref mut tbl_name, _) => {
2574-
if normalize_ident(tbl_name.as_str()) == old_table_norm {
2575-
*tbl_name = ast::Name::from_string(format!("\"{new_table_name}\""));
2576-
changed = true;
2577-
}
2578-
}
2579-
ast::Expr::Between {
2580-
lhs, start, end, ..
2581-
} => {
2582-
changed |= rewrite_expr_table_refs_for_rename(lhs, old_table_norm, new_table_name);
2583-
changed |= rewrite_expr_table_refs_for_rename(start, old_table_norm, new_table_name);
2584-
changed |= rewrite_expr_table_refs_for_rename(end, old_table_norm, new_table_name);
2585-
}
2586-
ast::Expr::Binary(lhs, _, rhs) => {
2587-
changed |= rewrite_expr_table_refs_for_rename(lhs, old_table_norm, new_table_name);
2588-
changed |= rewrite_expr_table_refs_for_rename(rhs, old_table_norm, new_table_name);
2589-
}
2590-
ast::Expr::Case {
2591-
base,
2592-
when_then_pairs,
2593-
else_expr,
2594-
..
2595-
} => {
2596-
if let Some(b) = base {
2597-
changed |= rewrite_expr_table_refs_for_rename(b, old_table_norm, new_table_name);
2598-
}
2599-
for (when_expr, then_expr) in when_then_pairs {
2600-
changed |=
2601-
rewrite_expr_table_refs_for_rename(when_expr, old_table_norm, new_table_name);
2602-
changed |=
2603-
rewrite_expr_table_refs_for_rename(then_expr, old_table_norm, new_table_name);
2585+
// Use walk_expr_mut to traverse ALL expression types automatically.
2586+
// This handles WINDOW clauses, frame bounds, and all other nested expressions.
2587+
let _ = walk_expr_mut(expr, &mut |e: &mut ast::Expr| -> Result<WalkControl> {
2588+
match e {
2589+
// Handle table-qualified column references: tbl.col -> "new_tbl".col
2590+
ast::Expr::Qualified(ref mut tbl_name, _) => {
2591+
if normalize_ident(tbl_name.as_str()) == old_table_norm {
2592+
*tbl_name = ast::Name::from_string(format!("\"{new_table_name}\""));
2593+
changed = true;
2594+
}
26042595
}
2605-
if let Some(else_e) = else_expr {
2606-
changed |=
2607-
rewrite_expr_table_refs_for_rename(else_e, old_table_norm, new_table_name);
2596+
// Handle doubly-qualified references: db.tbl.col -> db."new_tbl".col
2597+
ast::Expr::DoublyQualified(_, ref mut tbl_name, _) => {
2598+
if normalize_ident(tbl_name.as_str()) == old_table_norm {
2599+
*tbl_name = ast::Name::from_string(format!("\"{new_table_name}\""));
2600+
changed = true;
2601+
}
26082602
}
2609-
}
2610-
ast::Expr::Cast { expr: inner, .. } => {
2611-
changed |= rewrite_expr_table_refs_for_rename(inner, old_table_norm, new_table_name);
2612-
}
2613-
ast::Expr::Collate(inner, _) => {
2614-
changed |= rewrite_expr_table_refs_for_rename(inner, old_table_norm, new_table_name);
2615-
}
2616-
ast::Expr::FunctionCall {
2617-
args, filter_over, ..
2618-
} => {
2619-
for arg in args {
2620-
changed |= rewrite_expr_table_refs_for_rename(arg, old_table_norm, new_table_name);
2603+
// Handle `x IN tbl` - the table reference is not a sub-expression
2604+
ast::Expr::InTable { rhs, .. } => {
2605+
if normalize_ident(rhs.name.as_str()) == old_table_norm {
2606+
rhs.name = ast::Name::from_string(format!("\"{new_table_name}\""));
2607+
changed = true;
2608+
}
26212609
}
2622-
if let Some(ref mut filter_expr) = filter_over.filter_clause {
2610+
// Handle subqueries - walk_expr_mut doesn't descend into SELECT statements
2611+
ast::Expr::InSelect { rhs, .. } => {
26232612
changed |=
2624-
rewrite_expr_table_refs_for_rename(filter_expr, old_table_norm, new_table_name);
2613+
rewrite_select_table_refs_for_rename(rhs, old_table_norm, new_table_name);
26252614
}
2626-
}
2627-
ast::Expr::FunctionCallStar { filter_over, .. } => {
2628-
if let Some(ref mut filter_expr) = filter_over.filter_clause {
2615+
ast::Expr::Subquery(select) | ast::Expr::Exists(select) => {
26292616
changed |=
2630-
rewrite_expr_table_refs_for_rename(filter_expr, old_table_norm, new_table_name);
2631-
}
2632-
}
2633-
ast::Expr::InList { lhs, rhs, .. } => {
2634-
changed |= rewrite_expr_table_refs_for_rename(lhs, old_table_norm, new_table_name);
2635-
for item in rhs {
2636-
changed |= rewrite_expr_table_refs_for_rename(item, old_table_norm, new_table_name);
2637-
}
2638-
}
2639-
ast::Expr::InSelect { lhs, rhs, .. } => {
2640-
changed |= rewrite_expr_table_refs_for_rename(lhs, old_table_norm, new_table_name);
2641-
changed |= rewrite_select_table_refs_for_rename(rhs, old_table_norm, new_table_name);
2642-
}
2643-
ast::Expr::InTable { lhs, rhs, .. } => {
2644-
changed |= rewrite_expr_table_refs_for_rename(lhs, old_table_norm, new_table_name);
2645-
if normalize_ident(rhs.name.as_str()) == old_table_norm {
2646-
rhs.name = ast::Name::from_string(format!("\"{new_table_name}\""));
2647-
changed = true;
2617+
rewrite_select_table_refs_for_rename(select, old_table_norm, new_table_name);
26482618
}
2619+
_ => {}
26492620
}
2650-
ast::Expr::IsNull(inner) | ast::Expr::NotNull(inner) => {
2651-
changed |= rewrite_expr_table_refs_for_rename(inner, old_table_norm, new_table_name);
2652-
}
2653-
ast::Expr::Like {
2654-
lhs, rhs, escape, ..
2655-
} => {
2656-
changed |= rewrite_expr_table_refs_for_rename(lhs, old_table_norm, new_table_name);
2657-
changed |= rewrite_expr_table_refs_for_rename(rhs, old_table_norm, new_table_name);
2658-
if let Some(ref mut esc) = escape {
2659-
changed |= rewrite_expr_table_refs_for_rename(esc, old_table_norm, new_table_name);
2660-
}
2661-
}
2662-
ast::Expr::Parenthesized(inner) => {
2663-
for e in inner {
2664-
changed |= rewrite_expr_table_refs_for_rename(e, old_table_norm, new_table_name);
2665-
}
2666-
}
2667-
ast::Expr::Subquery(select) | ast::Expr::Exists(select) => {
2668-
changed |= rewrite_select_table_refs_for_rename(select, old_table_norm, new_table_name);
2669-
}
2670-
ast::Expr::Unary(_, inner) => {
2671-
changed |= rewrite_expr_table_refs_for_rename(inner, old_table_norm, new_table_name);
2672-
}
2673-
ast::Expr::Id(_)
2674-
| ast::Expr::Literal(_)
2675-
| ast::Expr::Name(_)
2676-
| ast::Expr::Variable(_)
2677-
| ast::Expr::Raise(_, _)
2678-
| ast::Expr::Register(_)
2679-
| ast::Expr::Column { .. }
2680-
| ast::Expr::RowId { .. }
2681-
| ast::Expr::SubqueryResult { .. } => {}
2682-
}
2621+
Ok(WalkControl::Continue)
2622+
});
26832623

26842624
changed
26852625
}
26862626

2627+
/// Rewrite table references in a SELECT statement for table rename.
2628+
///
2629+
/// Handles the complete SELECT structure used in trigger commands:
2630+
/// - WITH clause (CTEs): Recursively rewrites CTE subqueries
2631+
/// - SELECT body: Main query and UNION/EXCEPT/INTERSECT compounds
2632+
/// - ORDER BY: Expressions in ORDER BY clause that may contain table refs
2633+
/// - LIMIT/OFFSET: Expressions in LIMIT and OFFSET clauses
26872634
pub fn rewrite_select_table_refs_for_rename(
26882635
select: &mut ast::Select,
26892636
old_table_norm: &str,
@@ -2723,6 +2670,11 @@ pub fn rewrite_select_table_refs_for_rename(
27232670
changed
27242671
}
27252672

2673+
/// Rewrite table references in a SelectBody (main SELECT and compound queries).
2674+
///
2675+
/// Handles:
2676+
/// - Main SELECT: The primary `OneSelect` (SELECT or VALUES terms)
2677+
/// - Compound queries: Recursively walks chained UNION, EXCEPT, or INTERSECT SELECTs
27262678
fn rewrite_select_body_table_refs_for_rename(
27272679
body: &mut ast::SelectBody,
27282680
old_table_norm: &str,
@@ -2744,6 +2696,14 @@ fn rewrite_select_body_table_refs_for_rename(
27442696
changed
27452697
}
27462698

2699+
/// Rewrite table references in a OneSelect (single SELECT or VALUES clause).
2700+
///
2701+
/// Handles:
2702+
/// - Result columns: Including table-qualified stars like `t1.*` → `"t1_new".*`
2703+
/// - FROM clause: Table references and subqueries in the FROM
2704+
/// - WHERE clause: Expressions that may reference the renamed table
2705+
/// - GROUP BY/HAVING: Grouping and filter expressions
2706+
/// - VALUES clause: All value expressions in VALUES(...) rows
27472707
fn rewrite_one_select_table_refs_for_rename(
27482708
one_select: &mut ast::OneSelect,
27492709
old_table_norm: &str,
@@ -2769,12 +2729,13 @@ fn rewrite_one_select_table_refs_for_rename(
27692729
);
27702730
}
27712731
ast::ResultColumn::TableStar(ref mut name) => {
2732+
// Handle `t1.*` -> `"t1_new".*`
27722733
if normalize_ident(name.as_str()) == old_table_norm {
27732734
*name = ast::Name::from_string(format!("\"{new_table_name}\""));
27742735
changed = true;
27752736
}
27762737
}
2777-
ast::ResultColumn::Star => {}
2738+
ast::ResultColumn::Star => {} // `*` has no table qualifier
27782739
}
27792740
}
27802741

@@ -2815,6 +2776,12 @@ fn rewrite_one_select_table_refs_for_rename(
28152776
changed
28162777
}
28172778

2779+
/// Rewrite table references in a FROM clause including JOINs.
2780+
///
2781+
/// Handles:
2782+
/// - Main table entry: The primary table/subquery in the FROM
2783+
/// - JOIN tables: All joined tables referenced in the clause
2784+
/// - ON conditions: Expressions in JOIN ON clauses that may contain table refs
28182785
fn rewrite_from_clause_table_refs_for_rename(
28192786
from: &mut ast::FromClause,
28202787
old_table_norm: &str,
@@ -2842,6 +2809,13 @@ fn rewrite_from_clause_table_refs_for_rename(
28422809
changed
28432810
}
28442811

2812+
/// Rewrite table references in a SelectTable entry.
2813+
///
2814+
/// Handles different table source types:
2815+
/// - Table: Direct table reference `FROM t1` → `FROM "t1_new"`
2816+
/// - TableCall: Table-valued function `FROM func(args)` - walks arguments
2817+
/// - Select: Subquery `FROM (SELECT ...)` - recursively rewrites
2818+
/// - Sub: Subquery with FROM clause (derived table)
28452819
fn rewrite_select_table_entry_refs_for_rename(
28462820
select_table: &mut Box<ast::SelectTable>,
28472821
old_table_norm: &str,

0 commit comments

Comments
 (0)