databend_common_ast/ast/statements/
procedure.rs

1// Copyright 2021 Datafuse 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 std::fmt::Display;
16use std::fmt::Formatter;
17
18use derive_visitor::Drive;
19use derive_visitor::DriveMut;
20
21use crate::ast::write_comma_separated_list;
22use crate::ast::CreateOption;
23use crate::ast::Expr;
24use crate::ast::TypeName;
25
26#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
27pub struct ExecuteImmediateStmt {
28    pub script: String,
29}
30
31impl Display for ExecuteImmediateStmt {
32    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
33        write!(f, "EXECUTE IMMEDIATE $$\n{}\n$$", self.script)?;
34        Ok(())
35    }
36}
37
38#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
39pub struct ProcedureType {
40    pub name: Option<String>,
41    pub data_type: TypeName,
42}
43
44impl Display for ProcedureType {
45    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
46        if let Some(name) = &self.name {
47            write!(f, "{} {}", name, self.data_type)
48        } else {
49            write!(f, "{}", self.data_type)
50        }
51    }
52}
53
54#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
55pub enum ProcedureLanguage {
56    SQL,
57}
58
59impl Display for ProcedureLanguage {
60    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61        match self {
62            ProcedureLanguage::SQL => write!(f, "LANGUAGE SQL "),
63        }
64    }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, Drive, DriveMut)]
68pub struct ProcedureIdentity {
69    pub name: String,
70    pub args_type: String,
71}
72
73impl Display for ProcedureIdentity {
74    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
75        write!(f, "{}({})", &self.name, &self.args_type,)
76    }
77}
78
79#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
80pub struct CreateProcedureStmt {
81    pub create_option: CreateOption,
82    pub name: ProcedureIdentity,
83    pub language: ProcedureLanguage,
84    // TODO(eason): Now args is alwarys none, but maybe we also need to consider arg name?
85    pub args: Option<Vec<ProcedureType>>,
86    pub return_type: Vec<ProcedureType>,
87    pub comment: Option<String>,
88    pub script: String,
89}
90
91impl Display for CreateProcedureStmt {
92    // CREATE [ OR REPLACE ] PROCEDURE <name> ()
93    // RETURNS { <result_data_type> }[ NOT NULL ]
94    // LANGUAGE SQL
95    // [ COMMENT = '<string_literal>' ] AS <procedure_definition>
96    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
97        write!(f, "CREATE")?;
98        if let CreateOption::CreateOrReplace = self.create_option {
99            write!(f, " OR REPLACE")?;
100        }
101        write!(f, " PROCEDURE")?;
102        if let CreateOption::CreateIfNotExists = self.create_option {
103            write!(f, " IF NOT EXISTS")?;
104        }
105        write!(f, " {}", self.name.name)?;
106        if let Some(args) = &self.args {
107            if args.is_empty() {
108                write!(f, "()")?;
109            } else {
110                write!(f, "(")?;
111                write_comma_separated_list(f, args.clone())?;
112                write!(f, ")")?;
113            }
114        } else {
115            write!(f, "()")?;
116        }
117        if self.return_type.len() == 1 {
118            if let Some(name) = &self.return_type[0].name {
119                write!(
120                    f,
121                    " RETURNS TABLE({} {})",
122                    name, self.return_type[0].data_type
123                )?;
124            } else {
125                write!(f, " RETURNS {}", self.return_type[0].data_type)?;
126            }
127        } else {
128            write!(f, " RETURNS TABLE(")?;
129            write_comma_separated_list(f, self.return_type.clone())?;
130            write!(f, ")")?;
131        }
132
133        write!(f, " {}", self.language)?;
134        if let Some(comment) = &self.comment {
135            write!(f, " COMMENT='{}'", comment)?;
136        }
137        write!(f, " AS $$\n{}\n$$", self.script)?;
138        Ok(())
139    }
140}
141
142#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
143pub struct DropProcedureStmt {
144    pub if_exists: bool,
145    pub name: ProcedureIdentity,
146}
147
148impl Display for DropProcedureStmt {
149    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
150        write!(f, "DROP PROCEDURE ")?;
151        if self.if_exists {
152            write!(f, "IF EXISTS ")?;
153        }
154        write!(f, "{}", self.name)?;
155
156        Ok(())
157    }
158}
159#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
160pub struct DescProcedureStmt {
161    pub name: ProcedureIdentity,
162}
163
164impl Display for DescProcedureStmt {
165    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
166        write!(f, "DESCRIBE PROCEDURE {}", self.name)?;
167        Ok(())
168    }
169}
170
171#[derive(Debug, Clone, PartialEq, Drive, DriveMut)]
172pub struct CallProcedureStmt {
173    pub name: String,
174    pub args: Vec<Expr>,
175}
176
177impl Display for CallProcedureStmt {
178    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
179        let CallProcedureStmt { name, args } = self;
180        write!(f, "CALL PROCEDURE {}(", name)?;
181        write_comma_separated_list(f, args)?;
182        write!(f, ")")?;
183        Ok(())
184    }
185}