1use std::fmt;
18
19use itertools::Itertools;
20use mz_repr::{ColumnName, GlobalId};
21use mz_sql_parser::ast::display::AstDisplay;
22use mz_sql_parser::ast::visit_mut::{self, VisitMut};
23use mz_sql_parser::ast::{
24 CreateConnectionStatement, CreateIndexStatement, CreateMaterializedViewStatement,
25 CreateMetricSinkStatement, CreateSecretStatement, CreateSinkStatement, CreateSourceStatement,
26 CreateSubsourceStatement, CreateTableFromSourceStatement, CreateTableStatement,
27 CreateTypeStatement, CreateViewStatement, CreateWebhookSourceStatement, CteBlock, Function,
28 FunctionArgs, Ident, IfExistsBehavior, MutRecBlock, Op, Query, Statement, TableFactor,
29 TableFromSourceColumns, UnresolvedItemName, UnresolvedSchemaName, Value, ViewDefinition,
30};
31
32use crate::names::{Aug, FullItemName, PartialItemName, PartialSchemaName, RawDatabaseSpecifier};
33use crate::plan::error::PlanError;
34use crate::plan::statement::StatementContext;
35
36pub fn ident(ident: Ident) -> String {
38 ident.into_string()
39}
40
41pub fn ident_ref(ident: &Ident) -> &str {
43 ident.as_str()
44}
45
46pub fn column_name(id: Ident) -> ColumnName {
48 ColumnName::from(ident(id))
49}
50
51pub fn unresolved_item_name(mut name: UnresolvedItemName) -> Result<PartialItemName, PlanError> {
53 if name.0.len() < 1 || name.0.len() > 3 {
54 return Err(PlanError::MisqualifiedName(name.to_string()));
55 }
56 let out = PartialItemName {
57 item: ident(
58 name.0
59 .pop()
60 .expect("name checked to have at least one component"),
61 ),
62 schema: name.0.pop().map(ident),
63 database: name.0.pop().map(ident),
64 };
65 assert!(name.0.is_empty());
66 Ok(out)
67}
68
69pub fn unresolved_schema_name(
71 mut name: UnresolvedSchemaName,
72) -> Result<PartialSchemaName, PlanError> {
73 if name.0.len() < 1 || name.0.len() > 2 {
74 return Err(PlanError::MisqualifiedName(name.to_string()));
75 }
76 let out = PartialSchemaName {
77 schema: ident(
78 name.0
79 .pop()
80 .expect("name checked to have at least one component"),
81 ),
82 database: name.0.pop().map(ident),
83 };
84 assert!(name.0.is_empty());
85 Ok(out)
86}
87
88pub fn op(op: &Op) -> Result<&str, PlanError> {
92 if let Some(namespace) = &op.namespace {
93 if namespace.len() != 0
94 && (namespace.len() != 1
95 || namespace[0].as_str() != mz_repr::namespaces::PG_CATALOG_SCHEMA)
96 {
97 sql_bail!(
98 "operator does not exist: {}.{}",
99 namespace.iter().map(|n| n.to_string()).join("."),
100 op.op,
101 )
102 }
103 }
104 Ok(&op.op)
105}
106
107#[derive(Debug, Clone)]
108pub enum SqlValueOrSecret {
109 Value(Value),
110 Secret(GlobalId),
111}
112
113impl fmt::Display for SqlValueOrSecret {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 match self {
116 SqlValueOrSecret::Value(v) => write!(f, "{}", v),
117 SqlValueOrSecret::Secret(id) => write!(f, "{}", id),
118 }
119 }
120}
121
122impl From<SqlValueOrSecret> for Option<Value> {
123 fn from(s: SqlValueOrSecret) -> Self {
124 match s {
125 SqlValueOrSecret::Value(v) => Some(v),
126 SqlValueOrSecret::Secret(_id) => None,
127 }
128 }
129}
130
131pub fn unresolve(name: FullItemName) -> UnresolvedItemName {
135 let mut out = vec![];
137 if let RawDatabaseSpecifier::Name(n) = name.database {
138 out.push(Ident::new_unchecked(n));
139 }
140 out.push(Ident::new_unchecked(name.schema));
141 out.push(Ident::new_unchecked(name.item));
142 UnresolvedItemName(out)
143}
144
145pub fn full_name(mut raw_name: UnresolvedItemName) -> Result<FullItemName, PlanError> {
148 match raw_name.0.len() {
149 3 => Ok(FullItemName {
150 item: ident(raw_name.0.pop().unwrap()),
151 schema: ident(raw_name.0.pop().unwrap()),
152 database: RawDatabaseSpecifier::Name(ident(raw_name.0.pop().unwrap())),
153 }),
154 2 => Ok(FullItemName {
155 item: ident(raw_name.0.pop().unwrap()),
156 schema: ident(raw_name.0.pop().unwrap()),
157 database: RawDatabaseSpecifier::Ambient,
158 }),
159 _ => sql_bail!("unresolved name {} not fully qualified", raw_name),
160 }
161}
162
163pub fn create_statement(
172 scx: &StatementContext,
173 mut stmt: Statement<Aug>,
174) -> Result<String, PlanError> {
175 let allocate_name = |name: &UnresolvedItemName| -> Result<_, PlanError> {
176 Ok(unresolve(
177 scx.allocate_full_name(unresolved_item_name(name.clone())?)?,
178 ))
179 };
180
181 let allocate_temporary_name = |name: &UnresolvedItemName| -> Result<_, PlanError> {
182 Ok(unresolve(scx.allocate_temporary_full_name(
183 unresolved_item_name(name.clone())?,
184 )))
185 };
186
187 struct QueryNormalizer {
188 ctes: Vec<Ident>,
189 err: Option<PlanError>,
190 }
191
192 impl QueryNormalizer {
193 fn new() -> QueryNormalizer {
194 QueryNormalizer {
195 ctes: vec![],
196 err: None,
197 }
198 }
199 }
200
201 impl<'ast> VisitMut<'ast, Aug> for QueryNormalizer {
202 fn visit_query_mut(&mut self, query: &'ast mut Query<Aug>) {
203 let n = self.ctes.len();
204 match &query.ctes {
205 CteBlock::Simple(ctes) => {
206 for cte in ctes.iter() {
207 self.ctes.push(cte.alias.name.clone());
208 }
209 }
210 CteBlock::MutuallyRecursive(MutRecBlock { options: _, ctes }) => {
211 for cte in ctes.iter() {
212 self.ctes.push(cte.name.clone());
213 }
214 }
215 }
216 visit_mut::visit_query_mut(self, query);
217 self.ctes.truncate(n);
218 }
219
220 fn visit_function_mut(&mut self, func: &'ast mut Function<Aug>) {
221 match &mut func.args {
222 FunctionArgs::Star => (),
223 FunctionArgs::Args { args, order_by } => {
224 for arg in args {
225 self.visit_expr_mut(arg);
226 }
227 for expr in order_by {
228 self.visit_order_by_expr_mut(expr);
229 }
230 }
231 }
232 if let Some(over) = &mut func.over {
233 self.visit_window_spec_mut(over);
234 }
235 }
236
237 fn visit_table_factor_mut(&mut self, table_factor: &'ast mut TableFactor<Aug>) {
238 match table_factor {
239 TableFactor::Table { name, alias, .. } => {
240 self.visit_item_name_mut(name);
241 if let Some(alias) = alias {
242 self.visit_table_alias_mut(alias);
243 }
244 }
245 _ => visit_mut::visit_table_factor_mut(self, table_factor),
248 }
249 }
250 }
251
252 match &mut stmt {
263 Statement::CreateSource(CreateSourceStatement {
264 name,
265 in_cluster: _,
266 col_names: _,
267 connection: _,
268 format: _,
269 include_metadata: _,
270 envelope: _,
271 if_not_exists,
272 key_constraint: _,
273 with_options: _,
274 external_references: _,
275 progress_subsource: _,
276 }) => {
277 *name = allocate_name(name)?;
278 *if_not_exists = false;
279 }
280
281 Statement::CreateSubsource(CreateSubsourceStatement {
282 name,
283 columns,
284 constraints: _,
285 of_source: _,
286 if_not_exists,
287 with_options: _,
288 }) => {
289 *name = allocate_name(name)?;
290 let mut normalizer = QueryNormalizer::new();
291 for c in columns {
292 normalizer.visit_column_def_mut(c);
293 }
294 if let Some(err) = normalizer.err {
295 return Err(err);
296 }
297 *if_not_exists = false;
298 }
299
300 Statement::CreateTableFromSource(CreateTableFromSourceStatement {
301 name,
302 columns,
303 constraints: _,
304 external_reference: _,
305 source: _,
306 if_not_exists,
307 format: _,
308 include_metadata: _,
309 envelope: _,
310 with_options: _,
311 }) => {
312 *name = allocate_name(name)?;
313 let mut normalizer = QueryNormalizer::new();
314 if let TableFromSourceColumns::Defined(columns) = columns {
315 for c in columns {
316 normalizer.visit_column_def_mut(c);
317 }
318 }
319 if let Some(err) = normalizer.err {
320 return Err(err);
321 }
322 *if_not_exists = false;
323 }
324
325 Statement::CreateTable(CreateTableStatement {
326 name,
327 columns,
328 constraints: _,
329 if_not_exists,
330 temporary,
331 with_options: _,
332 }) => {
333 *name = if *temporary {
334 allocate_temporary_name(name)?
335 } else {
336 allocate_name(name)?
337 };
338 let mut normalizer = QueryNormalizer::new();
339 for c in columns {
340 normalizer.visit_column_def_mut(c);
341 }
342 if let Some(err) = normalizer.err {
343 return Err(err);
344 }
345 *if_not_exists = false;
346 }
347
348 Statement::CreateWebhookSource(CreateWebhookSourceStatement {
349 name,
350 is_table: _,
351 if_not_exists,
352 include_headers: _,
353 body_format: _,
354 validate_using: _,
355 in_cluster: _,
356 }) => {
357 *name = allocate_name(name)?;
358 *if_not_exists = false;
359 }
360
361 Statement::CreateSink(CreateSinkStatement {
362 name,
363 in_cluster: _,
364 from: _,
365 connection: _,
366 format: _,
367 envelope: _,
368 mode: _,
369 with_options: _,
370 if_not_exists,
371 }) => {
372 if let Some(name) = name {
373 *name = allocate_name(name)?;
374 }
375 *if_not_exists = false;
376 }
377
378 Statement::CreateMetricSink(CreateMetricSinkStatement {
379 name,
380 in_cluster: _,
381 if_not_exists,
382 from: _,
383 with_options: _,
384 }) => {
385 *name = allocate_name(name)?;
386 *if_not_exists = false;
387 }
388
389 Statement::CreateView(CreateViewStatement {
390 temporary,
391 if_exists,
392 definition:
393 ViewDefinition {
394 name,
395 query,
396 columns: _,
397 },
398 }) => {
399 *name = if *temporary {
400 allocate_temporary_name(name)?
401 } else {
402 allocate_name(name)?
403 };
404 {
405 let mut normalizer = QueryNormalizer::new();
406 normalizer.visit_query_mut(query);
407 if let Some(err) = normalizer.err {
408 return Err(err);
409 }
410 }
411 *if_exists = IfExistsBehavior::Error;
412 }
413
414 Statement::CreateMaterializedView(CreateMaterializedViewStatement {
415 if_exists,
416 name,
417 columns: _,
418 replacement_for: _,
419 in_cluster: _,
420 in_cluster_replica: _,
421 query,
422 with_options: _,
423 as_of: _,
424 }) => {
425 *name = allocate_name(name)?;
426 {
427 let mut normalizer = QueryNormalizer::new();
428 normalizer.visit_query_mut(query);
429 if let Some(err) = normalizer.err {
430 return Err(err);
431 }
432 }
433 *if_exists = IfExistsBehavior::Error;
434 }
435
436 Statement::CreateIndex(CreateIndexStatement {
437 name: _,
438 in_cluster: _,
439 on_name: _,
440 key_parts,
441 with_options: _,
442 if_not_exists,
443 }) => {
444 let mut normalizer = QueryNormalizer::new();
445 if let Some(key_parts) = key_parts {
446 for key_part in key_parts {
447 normalizer.visit_expr_mut(key_part);
448 if let Some(err) = normalizer.err {
449 return Err(err);
450 }
451 }
452 }
453 *if_not_exists = false;
454 }
455
456 Statement::CreateType(CreateTypeStatement { name, as_type }) => {
457 *name = allocate_name(name)?;
458 let mut normalizer = QueryNormalizer::new();
459 normalizer.visit_create_type_as_mut(as_type);
460 if let Some(err) = normalizer.err {
461 return Err(err);
462 }
463 }
464 Statement::CreateSecret(CreateSecretStatement {
465 name,
466 if_not_exists,
467 value: _,
468 }) => {
469 *name = allocate_name(name)?;
470 *if_not_exists = false;
471 }
472 Statement::CreateConnection(CreateConnectionStatement {
473 name,
474 connection_type: _,
475 values,
476 with_options,
477 if_not_exists,
478 }) => {
479 *name = allocate_name(name)?;
480 *if_not_exists = false;
481
482 values.sort();
483
484 with_options
487 .retain(|o| o.name != mz_sql_parser::ast::CreateConnectionOptionName::Validate);
488 }
489
490 _ => bail_internal!("unexpected statement type for normalization"),
491 }
492
493 Ok(stmt.to_ast_string_stable())
494}
495
496macro_rules! generate_extracted_config {
521 (
523 $option_ty:ty, [$($processed:tt)*],
524 ($option_name:path, $t:ty), $($tail:tt),*
525 ) => {
526 generate_extracted_config!(
527 $option_ty,
528 [$($processed)* ($option_name, Option::<$t>, None, false)],
529 $($tail),*
530 );
531 };
532 (
534 $option_ty:ty, [$($processed:tt)*],
535 ($option_name:path, $t:ty)
536 ) => {
537 generate_extracted_config!(
538 $option_ty,
539 [$($processed)* ($option_name, Option::<$t>, None, false)]
540 );
541 };
542 (
544 $option_ty:ty, [$($processed:tt)*],
545 ($option_name:path, $t:ty, Default($v:expr)), $($tail:tt),*
546 ) => {
547 generate_extracted_config!(
548 $option_ty,
549 [$($processed)* ($option_name, $t, $v, false)],
550 $($tail),*
551 );
552 };
553 (
555 $option_ty:ty, [$($processed:tt)*],
556 ($option_name:path, $t:ty, Default($v:expr))
557 ) => {
558 generate_extracted_config!(
559 $option_ty,
560 [$($processed)* ($option_name, $t, $v, false)]
561 );
562 };
563 (
565 $option_ty:ty, [$($processed:tt)*],
566 ($option_name:path, $t:ty, AllowMultiple), $($tail:tt),*
567 ) => {
568 generate_extracted_config!(
569 $option_ty,
570 [$($processed)* ($option_name, $t, vec![], true)],
571 $($tail),*
572 );
573 };
574 (
576 $option_ty:ty, [$($processed:tt)*],
577 ($option_name:path, $t:ty, AllowMultiple)
578 ) => {
579 generate_extracted_config!(
580 $option_ty,
581 [$($processed)* ($option_name, $t, vec![], true)]
582 );
583 };
584 ($option_ty:ty, [$(($option_name:path, $t:ty, $v:expr, $allow_multiple:literal))+]) => {
585 paste::paste! {
586 #[derive(Debug)]
587 pub struct [<$option_ty Extracted>] {
588 pub(crate) seen: ::std::collections::BTreeSet::<[<$option_ty Name>]>,
589 $(
590 pub [<$option_name:snake>]: generate_extracted_config!(
591 @ifty $allow_multiple,
592 Vec::<$t>,
593 $t
594 ),
595 )*
596 }
597
598 impl std::default::Default for [<$option_ty Extracted>] {
599 fn default() -> Self {
600 [<$option_ty Extracted>] {
601 seen: ::std::collections::BTreeSet::<[<$option_ty Name>]>::new(),
602 $(
603 [<$option_name:snake>]: <generate_extracted_config!(
604 @ifty $allow_multiple,
605 Vec::<$t>,
606 $t
607 )>::from($v),
608 )*
609 }
610 }
611 }
612
613 impl std::convert::TryFrom<Vec<$option_ty<Aug>>>
614 for [<$option_ty Extracted>]
615 {
616 type Error = $crate::plan::PlanError;
617 fn try_from(
618 v: Vec<$option_ty<Aug>>,
619 ) -> Result<[<$option_ty Extracted>], Self::Error> {
620 use [<$option_ty Name>]::*;
621 let mut extracted = [<$option_ty Extracted>]::default();
622 for option in v {
623 match option.name {
624 $(
625 $option_name => {
626 if !$allow_multiple
627 && !extracted.seen.insert(option.name.clone())
628 {
629 sql_bail!(
630 "{} specified more than once",
631 option.name.to_ast_string_simple(),
632 );
633 }
634 let val: $t = $crate::plan::with_options
635 ::TryFromValue::try_from_value(option.value)
636 .map_err(|e| sql_err!(
637 "invalid {}: {}",
638 option.name.to_ast_string_simple(),
639 e,
640 ))?;
641 generate_extracted_config!(
642 @ifexpr $allow_multiple,
643 extracted.[<$option_name:snake>].push(val),
644 extracted.[<$option_name:snake>] = val
645 );
646 }
647 )*
648 }
649 }
650 Ok(extracted)
651 }
652 }
653
654 impl [<$option_ty Extracted>] {
655 #[allow(unused)]
656 fn into_values(
657 self,
658 catalog: &dyn crate::catalog::SessionCatalog,
659 ) -> Vec<$option_ty<Aug>> {
660 use [<$option_ty Name>]::*;
661 let mut options = Vec::new();
662 $(
663 let value = self.[<$option_name:snake>];
664 let values: Vec<_> = generate_extracted_config!(
665 @ifexpr $allow_multiple,
666 value,
667 Vec::from([value])
668 );
669 for value in values {
670 let maybe_value = <$t as $crate::plan::with_options::TryFromValue<
674 Option<mz_sql_parser::ast::WithOptionValue<$crate::names::Aug>>
675 >>::try_into_value(value, catalog);
676 match maybe_value {
677 Some(value) => {
678 let option = $option_ty {name: $option_name, value};
679 options.push(option);
680 },
681 None => (),
682 }
683 }
684 )*
685 options
686 }
687 }
688 }
689 };
690 ($option_ty:ty, $($h:tt),+) => {
691 generate_extracted_config!{$option_ty, [], $($h),+}
692 };
693 (@ifexpr false, $lhs:expr, $rhs:expr) => {
696 $rhs
697 };
698 (@ifexpr true, $lhs:expr, $rhs:expr) => {
699 $lhs
700 };
701 (@ifty false, $lhs:ty, $rhs:ty) => {
702 $rhs
703 };
704 (@ifty true, $lhs:ty, $rhs:ty) => {
705 $lhs
706 };
707}
708
709pub(crate) use generate_extracted_config;