Skip to main content

risingwave_meta/controller/
rename.rs

1// Copyright 2023 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use itertools::Itertools;
16use risingwave_pb::expr::expr_node::{self, RexNode};
17use risingwave_pb::expr::{ExprNode, FunctionCall, UserDefinedFunction};
18use risingwave_pb::plan_common::PbColumnDesc;
19use risingwave_sqlparser::ast::{
20    Array, CdcTableInfo, CreateSink, CreateSinkStatement, CreateSourceStatement,
21    CreateSubscriptionStatement, Distinct, Expr, Function, FunctionArg, FunctionArgExpr,
22    FunctionArgList, Ident, ObjectName, Query, SelectItem, SetExpr, Statement, TableAlias,
23    TableFactor, TableWithJoins, Window,
24};
25use risingwave_sqlparser::parser::Parser;
26
27/// `alter_relation_rename` renames a relation to a new name in its `Create` statement, and returns
28/// the updated definition raw sql. Note that the `definition` must be a `Create` statement and the
29/// `new_name` must be a valid identifier, it should be validated before calling this function. To
30/// update all relations that depend on the renamed one, use `alter_relation_rename_refs`.
31pub fn alter_relation_rename(definition: &str, new_name: &str) -> String {
32    // This happens when we try to rename a table that's created by `CREATE TABLE AS`. Remove it
33    // when we support `SHOW CREATE TABLE` for `CREATE TABLE AS`.
34    if definition.is_empty() {
35        tracing::warn!("found empty definition when renaming relation, ignored.");
36        return definition.into();
37    }
38    let ast = Parser::parse_sql(definition).expect("failed to parse relation definition");
39    let mut stmt =
40        Itertools::exactly_one(ast.into_iter()).expect("should contains only one statement");
41
42    match &mut stmt {
43        Statement::CreateTable { name, .. }
44        | Statement::CreateView { name, .. }
45        | Statement::CreateIndex { name, .. }
46        | Statement::CreateSource {
47            stmt: CreateSourceStatement {
48                source_name: name, ..
49            },
50        }
51        | Statement::CreateSubscription {
52            stmt:
53                CreateSubscriptionStatement {
54                    subscription_name: name,
55                    ..
56                },
57        }
58        | Statement::CreateSink {
59            stmt: CreateSinkStatement {
60                sink_name: name, ..
61            },
62        } => replace_table_name(name, new_name),
63        _ => unreachable!(),
64    };
65
66    stmt.to_string()
67}
68
69/// `alter_relation_rename_refs` updates all references of renamed-relation in the definition of
70/// target relation's `Create` statement.
71pub fn alter_relation_rename_refs(definition: &str, from: &str, to: &str) -> String {
72    let ast = Parser::parse_sql(definition).expect("failed to parse relation definition");
73    let mut stmt =
74        Itertools::exactly_one(ast.into_iter()).expect("should contains only one statement");
75
76    match &mut stmt {
77        Statement::CreateTable {
78            query: Some(query), ..
79        }
80        | Statement::CreateView { query, .. }
81        | Statement::Query(query) // Used by view, actually we store a query as the definition of view.
82        | Statement::CreateSink {
83            stmt:
84            CreateSinkStatement {
85                sink_from: CreateSink::AsQuery(query),
86                into_table_name: None,
87                ..
88            },
89        } => {
90            QueryRewriter::rewrite_query(query, from, to);
91        }
92        Statement::CreateIndex { table_name, .. }
93        | Statement::CreateSink {
94            stmt:
95            CreateSinkStatement {
96                sink_from: CreateSink::From(table_name),
97                into_table_name: None,
98                ..
99            },
100        }| Statement::CreateSubscription {
101            stmt:
102            CreateSubscriptionStatement {
103                subscription_from: table_name,
104                ..
105            },
106        } | Statement::CreateTable {
107            cdc_table_info:
108            Some(CdcTableInfo {
109                source_name: table_name,
110                ..
111            }),
112            ..
113        } | Statement::CreateSource {
114            stmt: CreateSourceStatement {
115                cdc_table_info:
116                    Some(CdcTableInfo {
117                        source_name: table_name,
118                        ..
119                    }),
120                ..
121            },
122        } => replace_table_name(table_name, to),
123        Statement::CreateSink {
124            stmt: CreateSinkStatement {
125                sink_from,
126                into_table_name: Some(table_name),
127                ..
128            }
129        } => {
130            let idx = table_name.0.len() - 1;
131            if table_name.0[idx].real_value() == from {
132                table_name.0[idx] = Ident::from_real_value(to);
133            } else {
134                match sink_from {
135                    CreateSink::From(table_name) => replace_table_name(table_name, to),
136                    CreateSink::AsQuery(query) => QueryRewriter::rewrite_query(query, from, to),
137                }
138            }
139        }
140        _ => unreachable!(),
141    };
142    stmt.to_string()
143}
144
145/// Replace the last ident in the `table_name` with the given name, the object name is ensured to be
146/// non-empty. e.g. `schema.table` or `database.schema.table`.
147fn replace_table_name(table_name: &mut ObjectName, to: &str) {
148    let idx = table_name.0.len() - 1;
149    table_name.0[idx] = Ident::from_real_value(to);
150}
151
152/// `QueryRewriter` is a visitor that updates all references of relation named `from` to `to` in the
153/// given query, which is the part of create statement of `relation`.
154struct QueryRewriter<'a> {
155    from: &'a str,
156    to: &'a str,
157}
158
159impl QueryRewriter<'_> {
160    fn rewrite_query(query: &mut Query, from: &str, to: &str) {
161        let rewriter = QueryRewriter { from, to };
162        rewriter.visit_query(query)
163    }
164
165    /// Visit the query and update all references of relation named `from` to `to`.
166    fn visit_query(&self, query: &mut Query) {
167        if let Some(with) = &mut query.with {
168            for cte_table in &mut with.cte_tables {
169                match &mut cte_table.cte_inner {
170                    risingwave_sqlparser::ast::CteInner::Query(query) => self.visit_query(query),
171                    risingwave_sqlparser::ast::CteInner::ChangeLog {
172                        from: name,
173                        key: _key,
174                    } => {
175                        let idx = name.0.len() - 1;
176                        if name.0[idx].real_value() == self.from {
177                            replace_table_name(name, self.to);
178                        }
179                    }
180                }
181            }
182        }
183        self.visit_set_expr(&mut query.body);
184        for expr in &mut query.order_by {
185            self.visit_expr(&mut expr.expr);
186        }
187    }
188
189    /// Visit table factor and update all references of relation named `from` to `to`.
190    /// Rewrite idents(i.e. `schema.table`, `table`) that contains the old name in the
191    /// following pattern:
192    /// 1. `FROM a` to `FROM new_a AS a`
193    /// 2. `FROM a AS b` to `FROM new_a AS b`
194    ///
195    /// So that we DON'T have to:
196    /// 1. rewrite the select and expr part like `schema.table.column`, `table.column`,
197    ///    `alias.column` etc.
198    /// 2. handle the case that the old name is used as alias.
199    /// 3. handle the case that the new name is used as alias.
200    fn visit_table_factor(&self, table_factor: &mut TableFactor) {
201        match table_factor {
202            TableFactor::Table { name, alias, .. } => {
203                let idx = name.0.len() - 1;
204                if name.0[idx].real_value() == self.from {
205                    if alias.is_none() {
206                        *alias = Some(TableAlias {
207                            name: Ident::from_real_value(self.from),
208                            columns: vec![],
209                        });
210                    }
211                    name.0[idx] = Ident::from_real_value(self.to);
212                }
213            }
214            TableFactor::Derived { subquery, .. } => self.visit_query(subquery),
215            TableFactor::TableFunction { args, .. } => {
216                for arg in args {
217                    self.visit_function_arg(arg);
218                }
219            }
220            TableFactor::NestedJoin(table_with_joins) => {
221                self.visit_table_with_joins(table_with_joins);
222            }
223            TableFactor::MatchRecognize { table, .. } => {
224                // Only the input table can reference a relation: the binder rejects subqueries in
225                // both DEFINE and MEASURES (they have no representation in the executor's scalar
226                // expressions), so the remaining clauses contain no rename targets.
227                self.visit_table_factor(table);
228            }
229        }
230    }
231
232    /// Visit table with joins and update all references of relation named `from` to `to`.
233    fn visit_table_with_joins(&self, table_with_joins: &mut TableWithJoins) {
234        self.visit_table_factor(&mut table_with_joins.relation);
235        for join in &mut table_with_joins.joins {
236            self.visit_table_factor(&mut join.relation);
237        }
238    }
239
240    /// Visit query body expression and update all references.
241    fn visit_set_expr(&self, set_expr: &mut SetExpr) {
242        match set_expr {
243            SetExpr::Select(select) => {
244                if let Distinct::DistinctOn(exprs) = &mut select.distinct {
245                    for expr in exprs {
246                        self.visit_expr(expr);
247                    }
248                }
249                for select_item in &mut select.projection {
250                    self.visit_select_item(select_item);
251                }
252                for from_item in &mut select.from {
253                    self.visit_table_with_joins(from_item);
254                }
255                if let Some(where_clause) = &mut select.selection {
256                    self.visit_expr(where_clause);
257                }
258                for expr in &mut select.group_by {
259                    self.visit_expr(expr);
260                }
261                if let Some(having) = &mut select.having {
262                    self.visit_expr(having);
263                }
264                for named_window in &mut select.window {
265                    for expr in &mut named_window.window_spec.partition_by {
266                        self.visit_expr(expr);
267                    }
268                    for expr in &mut named_window.window_spec.order_by {
269                        self.visit_expr(&mut expr.expr);
270                    }
271                }
272            }
273            SetExpr::Query(query) => self.visit_query(query),
274            SetExpr::SetOperation { left, right, .. } => {
275                self.visit_set_expr(left);
276                self.visit_set_expr(right);
277            }
278            SetExpr::Values(_) => {}
279        }
280    }
281
282    /// Visit function arguments and update all references.
283    fn visit_function_arg(&self, function_arg: &mut FunctionArg) {
284        match function_arg {
285            FunctionArg::Unnamed(arg) | FunctionArg::Named { arg, .. } => match arg {
286                FunctionArgExpr::Expr(expr) | FunctionArgExpr::ExprQualifiedWildcard(expr, _) => {
287                    self.visit_expr(expr)
288                }
289                FunctionArgExpr::QualifiedWildcard(_, None) | FunctionArgExpr::Wildcard(None) => {}
290                FunctionArgExpr::QualifiedWildcard(_, Some(exprs))
291                | FunctionArgExpr::Wildcard(Some(exprs)) => {
292                    for expr in exprs {
293                        self.visit_expr(expr);
294                    }
295                }
296                FunctionArgExpr::SecretRef(_) => {}
297            },
298        }
299    }
300
301    fn visit_function_arg_list(&self, arg_list: &mut FunctionArgList) {
302        for arg in &mut arg_list.args {
303            self.visit_function_arg(arg);
304        }
305        for expr in &mut arg_list.order_by {
306            self.visit_expr(&mut expr.expr)
307        }
308    }
309
310    /// Visit function and update all references.
311    fn visit_function(&self, function: &mut Function) {
312        self.visit_function_arg_list(&mut function.arg_list);
313        if let Some(over) = &mut function.over {
314            match over {
315                Window::Spec(window) => {
316                    for expr in &mut window.partition_by {
317                        self.visit_expr(expr);
318                    }
319                    for expr in &mut window.order_by {
320                        self.visit_expr(&mut expr.expr);
321                    }
322                }
323                Window::Name(_) => {
324                    // Named window references don't contain expressions to rewrite
325                }
326            }
327        }
328    }
329
330    /// Visit expression and update all references.
331    fn visit_expr(&self, expr: &mut Expr) {
332        match expr {
333            Expr::FieldIdentifier(expr, ..)
334            | Expr::IsNull(expr)
335            | Expr::IsNotNull(expr)
336            | Expr::IsTrue(expr)
337            | Expr::IsNotTrue(expr)
338            | Expr::IsFalse(expr)
339            | Expr::IsNotFalse(expr)
340            | Expr::IsUnknown(expr)
341            | Expr::IsNotUnknown(expr)
342            | Expr::IsJson { expr, .. }
343            | Expr::InList { expr, .. }
344            | Expr::SomeOp(expr)
345            | Expr::AllOp(expr)
346            | Expr::UnaryOp { expr, .. }
347            | Expr::Cast { expr, .. }
348            | Expr::TryCast { expr, .. }
349            | Expr::AtTimeZone {
350                timestamp: expr, ..
351            }
352            | Expr::Extract { expr, .. }
353            | Expr::Substring { expr, .. }
354            | Expr::Overlay { expr, .. }
355            | Expr::Trim { expr, .. }
356            | Expr::Nested(expr)
357            | Expr::Index { obj: expr, .. }
358            | Expr::ArrayRangeIndex { obj: expr, .. } => self.visit_expr(expr),
359
360            Expr::Position { substring, string } => {
361                self.visit_expr(substring);
362                self.visit_expr(string);
363            }
364
365            Expr::InSubquery { expr, subquery, .. } => {
366                self.visit_expr(expr);
367                self.visit_query(subquery);
368            }
369            Expr::Between {
370                expr, low, high, ..
371            } => {
372                self.visit_expr(expr);
373                self.visit_expr(low);
374                self.visit_expr(high);
375            }
376            Expr::Like {
377                expr, pattern: pat, ..
378            } => {
379                self.visit_expr(expr);
380                self.visit_expr(pat);
381            }
382            Expr::ILike {
383                expr, pattern: pat, ..
384            } => {
385                self.visit_expr(expr);
386                self.visit_expr(pat);
387            }
388            Expr::SimilarTo {
389                expr, pattern: pat, ..
390            } => {
391                self.visit_expr(expr);
392                self.visit_expr(pat);
393            }
394
395            Expr::IsDistinctFrom(expr1, expr2)
396            | Expr::IsNotDistinctFrom(expr1, expr2)
397            | Expr::BinaryOp {
398                left: expr1,
399                right: expr2,
400                ..
401            } => {
402                self.visit_expr(expr1);
403                self.visit_expr(expr2);
404            }
405            Expr::Function(function) => self.visit_function(function),
406            Expr::Exists(query) | Expr::Subquery(query) | Expr::ArraySubquery(query) => {
407                self.visit_query(query)
408            }
409
410            Expr::GroupingSets(exprs_vec) | Expr::Cube(exprs_vec) | Expr::Rollup(exprs_vec) => {
411                for exprs in exprs_vec {
412                    for expr in exprs {
413                        self.visit_expr(expr);
414                    }
415                }
416            }
417
418            Expr::Row(exprs) | Expr::Array(Array { elem: exprs, .. }) => {
419                for expr in exprs {
420                    self.visit_expr(expr);
421                }
422            }
423            Expr::Map { entries } => {
424                for (key, value) in entries {
425                    self.visit_expr(key);
426                    self.visit_expr(value);
427                }
428            }
429
430            Expr::LambdaFunction { body, args: _ } => self.visit_expr(body),
431
432            // No need to visit.
433            Expr::Identifier(_)
434            | Expr::CompoundIdentifier(_)
435            | Expr::Collate { .. }
436            | Expr::Value(_)
437            | Expr::Parameter { .. }
438            | Expr::TypedString { .. }
439            | Expr::Case { .. } => {}
440        }
441    }
442
443    /// Visit select item and update all references.
444    fn visit_select_item(&self, select_item: &mut SelectItem) {
445        match select_item {
446            SelectItem::UnnamedExpr(expr)
447            | SelectItem::ExprQualifiedWildcard(expr, _)
448            | SelectItem::ExprWithAlias { expr, .. } => self.visit_expr(expr),
449            SelectItem::QualifiedWildcard(_, None) | SelectItem::Wildcard(None) => {}
450            SelectItem::QualifiedWildcard(_, Some(exprs)) | SelectItem::Wildcard(Some(exprs)) => {
451                for expr in exprs {
452                    self.visit_expr(expr);
453                }
454            }
455        }
456    }
457}
458
459/// Rewrite the expression in index item after there's a schema change on the primary table.
460// TODO: move this out of `rename.rs`, this has nothing to do with renaming.
461pub struct IndexItemRewriter {
462    pub original_columns: Vec<PbColumnDesc>,
463    pub new_columns: Vec<PbColumnDesc>,
464}
465
466impl IndexItemRewriter {
467    pub fn rewrite_expr(&self, expr: &mut ExprNode) {
468        let rex_node = expr.rex_node.as_mut().unwrap();
469        match rex_node {
470            RexNode::InputRef(idx) => {
471                let old_idx = *idx as usize;
472                let original_column = &self.original_columns[old_idx];
473                let (new_idx, new_column) = self
474                    .new_columns
475                    .iter()
476                    .find_position(|c| c.column_id == original_column.column_id)
477                    .expect("should already checked index referencing column still exists");
478                *idx = new_idx as u32;
479
480                // If there's a type change, we need to wrap it with an internal `CompositeCast` to
481                // maintain the correct return type. It cannot execute and will be eliminated in
482                // the frontend when rebuilding the index items.
483                if new_column.column_type != original_column.column_type {
484                    let old_type = original_column.column_type.clone().unwrap();
485                    let new_type = new_column.column_type.clone().unwrap();
486
487                    assert_eq!(&old_type, expr.return_type.as_ref().unwrap());
488                    expr.return_type = Some(new_type); // update return type of `InputRef`
489
490                    let new_expr_node = ExprNode {
491                        function_type: expr_node::Type::CompositeCast as _,
492                        return_type: Some(old_type),
493                        rex_node: RexNode::FuncCall(FunctionCall {
494                            children: vec![expr.clone()],
495                        })
496                        .into(),
497                    };
498
499                    *expr = new_expr_node;
500                }
501            }
502            RexNode::Constant(_) => {}
503            RexNode::Udf(udf) => self.rewrite_udf(udf),
504            RexNode::FuncCall(function_call) => self.rewrite_function_call(function_call),
505            RexNode::Now(_) | RexNode::SecretRef(_) => {}
506        }
507    }
508
509    fn rewrite_udf(&self, udf: &mut UserDefinedFunction) {
510        udf.children
511            .iter_mut()
512            .for_each(|expr| self.rewrite_expr(expr));
513    }
514
515    fn rewrite_function_call(&self, function_call: &mut FunctionCall) {
516        function_call
517            .children
518            .iter_mut()
519            .for_each(|expr| self.rewrite_expr(expr));
520    }
521}
522
523#[cfg(test)]
524mod tests {
525    use super::*;
526
527    #[test]
528    fn test_alter_table_rename() {
529        let definition = "CREATE TABLE foo (a int, b int)";
530        let new_name = "bar";
531        let expected = "CREATE TABLE bar (a INT, b INT)";
532        let actual = alter_relation_rename(definition, new_name);
533        assert_eq!(expected, actual);
534    }
535
536    #[test]
537    fn test_rename_index_refs() {
538        let definition = "CREATE INDEX idx1 ON foo(v1 DESC, v2)";
539        let from = "foo";
540        let to = "bar";
541        let expected = "CREATE INDEX idx1 ON bar(v1 DESC, v2)";
542        let actual = alter_relation_rename_refs(definition, from, to);
543        assert_eq!(expected, actual);
544    }
545
546    #[test]
547    fn test_rename_sink_refs() {
548        let definition =
549            "CREATE SINK sink_t FROM foo WITH (connector = 'kafka', format = 'append_only')";
550        let from = "foo";
551        let to = "bar";
552        let expected =
553            "CREATE SINK sink_t FROM bar WITH (connector = 'kafka', format = 'append_only')";
554        let actual = alter_relation_rename_refs(definition, from, to);
555        assert_eq!(expected, actual);
556    }
557
558    #[test]
559    fn test_rename_with_alias_refs() {
560        let definition =
561            "CREATE MATERIALIZED VIEW mv1 AS SELECT foo.v1 AS m1v, foo.v2 AS m2v FROM foo";
562        let from = "foo";
563        let to = "bar";
564        let expected =
565            "CREATE MATERIALIZED VIEW mv1 AS SELECT foo.v1 AS m1v, foo.v2 AS m2v FROM bar AS foo";
566        let actual = alter_relation_rename_refs(definition, from, to);
567        assert_eq!(expected, actual);
568
569        let definition = "CREATE MATERIALIZED VIEW mv1 AS SELECT foo.v1 AS m1v, (foo.v2).v3 AS m2v FROM foo WHERE foo.v1 = 1 AND (foo.v2).v3 IS TRUE";
570        let expected = "CREATE MATERIALIZED VIEW mv1 AS SELECT foo.v1 AS m1v, (foo.v2).v3 AS m2v FROM bar AS foo WHERE foo.v1 = 1 AND (foo.v2).v3 IS TRUE";
571        let actual = alter_relation_rename_refs(definition, from, to);
572        assert_eq!(expected, actual);
573
574        let definition = "CREATE MATERIALIZED VIEW mv1 AS SELECT bar.v1 AS m1v, (bar.v2).v3 AS m2v FROM foo AS bar WHERE bar.v1 = 1";
575        let expected = "CREATE MATERIALIZED VIEW mv1 AS SELECT bar.v1 AS m1v, (bar.v2).v3 AS m2v FROM bar AS bar WHERE bar.v1 = 1";
576        let actual = alter_relation_rename_refs(definition, from, to);
577        assert_eq!(expected, actual);
578    }
579
580    #[test]
581    fn test_rename_with_complex_funcs() {
582        let definition = "CREATE MATERIALIZED VIEW mv1 AS SELECT \
583                            agg1(\
584                              foo.v1, func2(foo.v2) \
585                              ORDER BY \
586                              (SELECT foo.v3 FROM foo), \
587                              (SELECT first_value(foo.v4) OVER (PARTITION BY (SELECT foo.v5 FROM foo) ORDER BY (SELECT foo.v6 FROM foo)) FROM foo)\
588                            ) \
589                          FROM foo";
590        let from = "foo";
591        let to = "bar";
592        let expected = "CREATE MATERIALIZED VIEW mv1 AS SELECT \
593                          agg1(\
594                            foo.v1, func2(foo.v2) \
595                            ORDER BY \
596                            (SELECT foo.v3 FROM bar AS foo), \
597                            (SELECT first_value(foo.v4) OVER (PARTITION BY (SELECT foo.v5 FROM bar AS foo) ORDER BY (SELECT foo.v6 FROM bar AS foo)) FROM bar AS foo)\
598                          ) \
599                        FROM bar AS foo";
600        let actual = alter_relation_rename_refs(definition, from, to);
601        assert_eq!(expected, actual);
602    }
603}