1use mz_ore::str::StrExt;
16use mz_repr::{CatalogItemId, RelationDesc, RelationVersionSelector, SqlScalarType};
17use mz_sql_parser::ast::InspectShardStatement;
18use std::time::Duration;
19use uncased::UncasedStr;
20
21use crate::ast::display::AstDisplay;
22use crate::ast::{
23 CloseStatement, DeallocateStatement, DeclareStatement, DiscardStatement, DiscardTarget,
24 ExecuteStatement, FetchOption, FetchOptionName, FetchStatement, Ident, PrepareStatement,
25 ResetVariableStatement, SetVariableStatement, SetVariableTo, ShowVariableStatement,
26};
27use crate::names::{self, Aug};
28use crate::plan::statement::{StatementContext, StatementDesc};
29use crate::plan::{
30 ClosePlan, DeallocatePlan, DeclarePlan, ExecutePlan, ExecuteTimeout, FetchPlan,
31 InspectShardPlan, Params, Plan, PlanError, PreparePlan, ResetVariablePlan, SetVariablePlan,
32 ShowVariablePlan, VariableValue, describe, query,
33};
34use crate::session::vars;
35use crate::session::vars::{SCHEMA_ALIAS, VarInput};
36
37pub fn describe_set_variable(
38 _: &StatementContext,
39 _: SetVariableStatement,
40) -> Result<StatementDesc, PlanError> {
41 Ok(StatementDesc::new(None))
42}
43
44pub fn plan_set_variable(
45 scx: &StatementContext,
46 SetVariableStatement {
47 local,
48 variable,
49 to,
50 }: SetVariableStatement,
51) -> Result<Plan, PlanError> {
52 let value = plan_set_variable_to(to)?;
53 let name = variable.into_string();
54
55 if let VariableValue::Values(values) = &value {
59 vars::check_transaction_isolation_feature_flag(
60 &name,
61 VarInput::SqlSet(values),
62 scx.catalog.system_vars(),
63 )?;
64 }
65
66 Ok(Plan::SetVariable(SetVariablePlan { name, value, local }))
67}
68
69pub fn plan_set_variable_to(to: SetVariableTo) -> Result<VariableValue, PlanError> {
70 match to {
71 SetVariableTo::Default => Ok(VariableValue::Default),
72 SetVariableTo::Values(values) => {
73 let values = values
79 .into_iter()
80 .map(|v| v.into_unquoted_value())
81 .collect();
82 Ok(VariableValue::Values(values))
83 }
84 }
85}
86
87pub fn describe_reset_variable(
88 _: &StatementContext,
89 _: ResetVariableStatement,
90) -> Result<StatementDesc, PlanError> {
91 Ok(StatementDesc::new(None))
92}
93
94pub fn plan_reset_variable(
95 _: &StatementContext,
96 ResetVariableStatement { variable }: ResetVariableStatement,
97) -> Result<Plan, PlanError> {
98 Ok(Plan::ResetVariable(ResetVariablePlan {
99 name: variable.to_string(),
100 }))
101}
102
103pub fn describe_show_variable(
104 _: &StatementContext,
105 ShowVariableStatement { variable, .. }: ShowVariableStatement,
106) -> Result<StatementDesc, PlanError> {
107 let desc = if variable.as_str() == UncasedStr::new("ALL") {
108 RelationDesc::builder()
109 .with_column("name", SqlScalarType::String.nullable(false))
110 .with_column("setting", SqlScalarType::String.nullable(false))
111 .with_column("description", SqlScalarType::String.nullable(false))
112 .finish()
113 } else if variable.as_str() == SCHEMA_ALIAS {
114 RelationDesc::builder()
115 .with_column(variable.as_str(), SqlScalarType::String.nullable(true))
116 .finish()
117 } else {
118 RelationDesc::builder()
119 .with_column(variable.as_str(), SqlScalarType::String.nullable(false))
120 .finish()
121 };
122 Ok(StatementDesc::new(Some(desc)))
123}
124
125pub fn plan_show_variable(
126 _: &StatementContext,
127 ShowVariableStatement { variable }: ShowVariableStatement,
128) -> Result<Plan, PlanError> {
129 if variable.as_str() == UncasedStr::new("ALL") {
130 Ok(Plan::ShowAllVariables)
131 } else {
132 Ok(Plan::ShowVariable(ShowVariablePlan {
133 name: variable.to_string(),
134 }))
135 }
136}
137
138pub fn describe_inspect_shard(
139 _: &StatementContext,
140 InspectShardStatement { .. }: InspectShardStatement,
141) -> Result<StatementDesc, PlanError> {
142 let desc = RelationDesc::builder()
143 .with_column("state", SqlScalarType::Jsonb.nullable(false))
144 .finish();
145 Ok(StatementDesc::new(Some(desc)))
146}
147
148pub fn plan_inspect_shard(
149 scx: &StatementContext,
150 InspectShardStatement { id }: InspectShardStatement,
151) -> Result<Plan, PlanError> {
152 let id: CatalogItemId = id.parse().map_err(|_| sql_err!("invalid shard id"))?;
153 let gid = scx
155 .catalog
156 .try_get_item(&id)
157 .ok_or_else(|| sql_err!("item doesn't exist"))?
158 .at_version(RelationVersionSelector::Latest)
159 .global_id();
160 Ok(Plan::InspectShard(InspectShardPlan { id: gid }))
161}
162
163pub fn describe_discard(
164 _: &StatementContext,
165 _: DiscardStatement,
166) -> Result<StatementDesc, PlanError> {
167 Ok(StatementDesc::new(None))
168}
169
170pub fn plan_discard(
171 _: &StatementContext,
172 DiscardStatement { target }: DiscardStatement,
173) -> Result<Plan, PlanError> {
174 match target {
175 DiscardTarget::All => Ok(Plan::DiscardAll),
176 DiscardTarget::Temp => Ok(Plan::DiscardTemp),
177 DiscardTarget::Sequences => bail_unsupported!("DISCARD SEQUENCES"),
178 DiscardTarget::Plans => bail_unsupported!("DISCARD PLANS"),
179 }
180}
181
182pub fn describe_declare(
183 scx: &StatementContext,
184 DeclareStatement { stmt, .. }: DeclareStatement<Aug>,
185 param_types_in: &[Option<SqlScalarType>],
186) -> Result<StatementDesc, PlanError> {
187 let (stmt_resolved, _) = names::resolve(scx.catalog, *stmt)?;
188 let desc = describe(scx.pcx()?, scx.catalog, stmt_resolved, param_types_in)?;
191 for (i, ty) in desc.param_types.into_iter().enumerate() {
194 scx.param_types.borrow_mut().insert(i + 1, ty);
195 }
196 Ok(StatementDesc::new(None))
197}
198
199fn statement_or_portal_name(name: Ident) -> String {
205 name.into_string()
206}
207
208pub fn plan_declare(
209 _: &StatementContext,
210 DeclareStatement { name, stmt, sql }: DeclareStatement<Aug>,
211 params: &Params,
212) -> Result<Plan, PlanError> {
213 Ok(Plan::Declare(DeclarePlan {
214 name: statement_or_portal_name(name),
215 stmt: *stmt,
216 sql,
217 params: params.clone(),
218 }))
219}
220
221pub fn describe_fetch(
222 scx: &StatementContext,
223 FetchStatement {
224 name,
225 count: _,
226 options: _,
227 }: FetchStatement<Aug>,
228) -> Result<StatementDesc, PlanError> {
229 let name = statement_or_portal_name(name);
230 if let Some(mut desc) = scx.catalog.get_portal_desc_unverified(&name).cloned() {
231 desc.param_types = Vec::new();
234 Ok(desc)
235 } else {
236 Err(PlanError::UnknownCursor(name))
237 }
238}
239
240generate_extracted_config!(FetchOption, (Timeout, Duration));
241
242pub fn plan_fetch(
243 _: &StatementContext,
244 FetchStatement {
245 name,
246 count,
247 options,
248 }: FetchStatement<Aug>,
249) -> Result<Plan, PlanError> {
250 let FetchOptionExtracted { timeout, .. } = options.try_into()?;
251 let timeout = match timeout {
252 Some(timeout) => {
253 const DAY: Duration = Duration::from_secs(60 * 60 * 24);
257 if timeout > DAY {
258 sql_bail!("timeout out of range: {}s", timeout.as_secs_f64());
259 }
260 ExecuteTimeout::Seconds(timeout.as_secs_f64())
261 }
262 None => ExecuteTimeout::WaitOnce,
264 };
265 Ok(Plan::Fetch(FetchPlan {
266 name: statement_or_portal_name(name),
267 count,
268 timeout,
269 }))
270}
271
272pub fn describe_close(_: &StatementContext, _: CloseStatement) -> Result<StatementDesc, PlanError> {
273 Ok(StatementDesc::new(None))
274}
275
276pub fn plan_close(
277 _: &StatementContext,
278 CloseStatement { name }: CloseStatement,
279) -> Result<Plan, PlanError> {
280 Ok(Plan::Close(ClosePlan {
281 name: statement_or_portal_name(name),
282 }))
283}
284
285pub fn describe_prepare(
286 _: &StatementContext,
287 _: PrepareStatement<Aug>,
288) -> Result<StatementDesc, PlanError> {
289 Ok(StatementDesc::new(None))
290}
291
292pub fn plan_prepare(
293 scx: &StatementContext,
294 PrepareStatement { name, stmt, sql }: PrepareStatement<Aug>,
295) -> Result<Plan, PlanError> {
296 let param_types = [];
298 let (stmt_resolved, _) = names::resolve(scx.catalog, *stmt.clone())?;
299 let desc = describe(scx.pcx()?, scx.catalog, stmt_resolved, ¶m_types)?;
300 Ok(Plan::Prepare(PreparePlan {
301 name: statement_or_portal_name(name),
302 stmt: *stmt,
303 desc,
304 sql,
305 }))
306}
307
308pub fn describe_execute(
309 scx: &StatementContext,
310 stmt: ExecuteStatement<Aug>,
311) -> Result<StatementDesc, PlanError> {
312 Ok(plan_execute_desc(scx, stmt)?.0.clone())
318}
319
320pub fn plan_execute(
321 scx: &StatementContext,
322 stmt: ExecuteStatement<Aug>,
323) -> Result<Plan, PlanError> {
324 Ok(plan_execute_desc(scx, stmt)?.1)
325}
326
327fn plan_execute_desc<'a>(
328 scx: &'a StatementContext,
329 ExecuteStatement { name, params }: ExecuteStatement<Aug>,
330) -> Result<(&'a StatementDesc, Plan), PlanError> {
331 let name = statement_or_portal_name(name);
332 let desc = match scx.catalog.get_prepared_statement_desc(&name) {
333 Some(desc) => desc,
334 None => sql_bail!("unknown prepared statement {}", name.quoted()),
336 };
337 Ok((
338 desc,
339 Plan::Execute(ExecutePlan {
340 name,
341 params: query::plan_params(scx, params, desc)?,
342 }),
343 ))
344}
345
346pub fn describe_deallocate(
347 _: &StatementContext,
348 _: DeallocateStatement,
349) -> Result<StatementDesc, PlanError> {
350 Ok(StatementDesc::new(None))
351}
352
353pub fn plan_deallocate(
354 _: &StatementContext,
355 DeallocateStatement { name }: DeallocateStatement,
356) -> Result<Plan, PlanError> {
357 Ok(Plan::Deallocate(DeallocatePlan {
358 name: name.map(statement_or_portal_name),
359 }))
360}