risingwave_frontend/binder/
delete.rs1use risingwave_common::acl::AclMode;
16use risingwave_common::catalog::{Schema, TableVersionId};
17use risingwave_sqlparser::ast::{Expr, ObjectName, SelectItem};
18
19use super::statement::RewriteExprsRecursive;
20use super::{Binder, BoundBaseTable};
21use crate::catalog::TableId;
22use crate::error::{ErrorCode, Result, RwError};
23use crate::expr::ExprImpl;
24use crate::handler::privilege::ObjectCheckItem;
25use crate::user::UserId;
26
27#[derive(Debug, Clone)]
28pub struct BoundDelete {
29 pub table_id: TableId,
31
32 pub table_version_id: TableVersionId,
34
35 pub table_name: String,
37
38 pub owner: UserId,
40
41 pub table: BoundBaseTable,
43
44 pub selection: Option<ExprImpl>,
45
46 pub returning_list: Vec<ExprImpl>,
50
51 pub returning_schema: Option<Schema>,
52}
53
54impl RewriteExprsRecursive for BoundDelete {
55 fn rewrite_exprs_recursive(&mut self, rewriter: &mut impl crate::expr::ExprRewriter) {
56 self.selection =
57 std::mem::take(&mut self.selection).map(|expr| rewriter.rewrite_expr(expr));
58
59 let new_returning_list = std::mem::take(&mut self.returning_list)
60 .into_iter()
61 .map(|expr| rewriter.rewrite_expr(expr))
62 .collect::<Vec<_>>();
63 self.returning_list = new_returning_list;
64 }
65}
66
67impl Binder {
68 pub(super) fn bind_delete(
69 &mut self,
70 name: ObjectName,
71 selection: Option<Expr>,
72 returning_items: Vec<SelectItem>,
73 ) -> Result<BoundDelete> {
74 let (schema_name, table_name) = Self::resolve_schema_qualified_name(&self.db_name, &name)?;
75 let schema_name = schema_name.as_deref();
76 let table = self.bind_table(schema_name, &table_name)?;
77
78 let table_catalog = &table.table_catalog;
79 Self::check_for_dml(table_catalog, false)?;
80 self.check_privilege(
81 ObjectCheckItem::new(
82 table_catalog.owner,
83 AclMode::Delete,
84 table_name.clone(),
85 table_catalog.id,
86 ),
87 table_catalog.database_id,
88 )?;
89
90 if !returning_items.is_empty() && table_catalog.has_generated_column() {
91 return Err(RwError::from(ErrorCode::BindError(
92 "`RETURNING` clause is not supported for tables with generated columns".to_owned(),
93 )));
94 }
95 let table_id = table_catalog.id;
96 let owner = table_catalog.owner;
97 let table_version_id = table_catalog.version_id().expect("table must be versioned");
98
99 let (returning_list, fields) = self.bind_returning_list(returning_items)?;
100 let returning = !returning_list.is_empty();
101 let delete = BoundDelete {
102 table_id,
103 table_version_id,
104 table_name,
105 owner,
106 table,
107 selection: selection
108 .map(|expr| self.bind_expr(&expr)?.enforce_bool_clause("WHERE"))
109 .transpose()?,
110 returning_list,
111 returning_schema: if returning {
112 Some(Schema { fields })
113 } else {
114 None
115 },
116 };
117 Ok(delete)
118 }
119}