Skip to main content

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