risingwave_frontend/binder/
delete.rs1use risingwave_common::acl::AclMode;
16use risingwave_common::catalog::{Schema, TableVersionId};
17use risingwave_pb::user::grant_privilege::PbObject;
18use risingwave_sqlparser::ast::{Expr, ObjectName, SelectItem};
19
20use super::statement::RewriteExprsRecursive;
21use super::{Binder, BoundBaseTable};
22use crate::catalog::TableId;
23use crate::error::{ErrorCode, Result, RwError};
24use crate::expr::ExprImpl;
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 PbObject::TableId(table_catalog.id.table_id),
82 table_catalog.database_id,
83 AclMode::Delete,
84 table_catalog.owner,
85 )?;
86
87 if !returning_items.is_empty() && table_catalog.has_generated_column() {
88 return Err(RwError::from(ErrorCode::BindError(
89 "`RETURNING` clause is not supported for tables with generated columns".to_owned(),
90 )));
91 }
92 let table_id = table_catalog.id;
93 let owner = table_catalog.owner;
94 let table_version_id = table_catalog.version_id().expect("table must be versioned");
95
96 let (returning_list, fields) = self.bind_returning_list(returning_items)?;
97 let returning = !returning_list.is_empty();
98 let delete = BoundDelete {
99 table_id,
100 table_version_id,
101 table_name,
102 owner,
103 table,
104 selection: selection
105 .map(|expr| self.bind_expr(expr)?.enforce_bool_clause("WHERE"))
106 .transpose()?,
107 returning_list,
108 returning_schema: if returning {
109 Some(Schema { fields })
110 } else {
111 None
112 },
113 };
114 Ok(delete)
115 }
116}