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