From 1eb4d02f1dfeb3d0de7f7a838fee7318a582d631 Mon Sep 17 00:00:00 2001 From: Gabor Gevay Date: Mon, 17 Mar 2025 14:14:57 +0100 Subject: [PATCH 1/4] parser: Rename to_ast_string to to_ast_string_simple --- .../src/catalog/builtin_table_updates.rs | 20 +++++------ src/environmentd/src/http/sql.rs | 4 +-- src/sql-parser/src/ast/display.rs | 6 ++-- src/sql-parser/src/lib.rs | 4 +-- src/sql-pretty/src/doc.rs | 15 ++++---- src/sql/src/names.rs | 6 ++-- src/sql/src/normalize.rs | 4 +-- src/sql/src/plan/error.rs | 2 +- src/sql/src/plan/statement/acl.rs | 10 +++--- src/sql/src/plan/statement/ddl.rs | 34 +++++++++++-------- src/sql/src/pure.rs | 2 +- src/sql/src/pure/error.rs | 2 +- src/sql/src/pure/mysql.rs | 9 +++-- src/sql/src/pure/postgres.rs | 7 ++-- src/storage/src/source/postgres.rs | 2 +- .../src/source/postgres/replication.rs | 2 +- src/storage/src/source/postgres/snapshot.rs | 10 +++--- 17 files changed, 77 insertions(+), 62 deletions(-) diff --git a/src/adapter/src/catalog/builtin_table_updates.rs b/src/adapter/src/catalog/builtin_table_updates.rs index 9dcfd4a24c151..ab8cbfacbbc94 100644 --- a/src/adapter/src/catalog/builtin_table_updates.rs +++ b/src/adapter/src/catalog/builtin_table_updates.rs @@ -559,8 +559,8 @@ impl CatalogState { // information is redundant because each // Postgres connection connects to only one // database. - let schema_name = external_reference[1].to_ast_string(); - let table_name = external_reference[2].to_ast_string(); + let schema_name = external_reference[1].to_ast_string_simple(); + let table_name = external_reference[2].to_ast_string_simple(); self.pack_postgres_source_tables_update( id, @@ -571,8 +571,8 @@ impl CatalogState { } "mysql" => { mz_ore::soft_assert_eq_no_log!(external_reference.len(), 2); - let schema_name = external_reference[0].to_ast_string(); - let table_name = external_reference[1].to_ast_string(); + let schema_name = external_reference[0].to_ast_string_simple(); + let table_name = external_reference[1].to_ast_string_simple(); self.pack_mysql_source_tables_update( id, @@ -586,7 +586,7 @@ impl CatalogState { "load-generator" => vec![], "kafka" => { mz_ore::soft_assert_eq_no_log!(external_reference.len(), 1); - let topic = external_reference[0].to_ast_string(); + let topic = external_reference[0].to_ast_string_simple(); let envelope = data_source.envelope(); let (key_format, value_format) = data_source.formats(); @@ -674,8 +674,8 @@ impl CatalogState { // information is redundant because each // Postgres connection connects to only one // database. - let schema_name = external_reference[1].to_ast_string(); - let table_name = external_reference[2].to_ast_string(); + let schema_name = external_reference[1].to_ast_string_simple(); + let table_name = external_reference[2].to_ast_string_simple(); self.pack_postgres_source_tables_update( id, @@ -686,8 +686,8 @@ impl CatalogState { } "mysql" => { mz_ore::soft_assert_eq_no_log!(external_reference.len(), 2); - let schema_name = external_reference[0].to_ast_string(); - let table_name = external_reference[1].to_ast_string(); + let schema_name = external_reference[0].to_ast_string_simple(); + let table_name = external_reference[1].to_ast_string_simple(); self.pack_mysql_source_tables_update( id, @@ -1606,7 +1606,7 @@ impl CatalogState { let key_sql = key_sqls .get(i) .expect("missing sql information for index key") - .to_ast_string(); + .to_ast_string_simple(); let (field_number, expression) = match key { MirScalarExpr::Column(col) => { (Datum::UInt64(u64::cast_from(*col + 1)), Datum::Null) diff --git a/src/environmentd/src/http/sql.rs b/src/environmentd/src/http/sql.rs index 145c9b0f0fea5..6f1f0c987e24a 100644 --- a/src/environmentd/src/http/sql.rs +++ b/src/environmentd/src/http/sql.rs @@ -1173,7 +1173,7 @@ async fn execute_request( } }) { - return Err(Error::Unsupported(stmt.to_ast_string())); + return Err(Error::Unsupported(stmt.to_ast_string_simple())); } Ok(()) } @@ -1284,7 +1284,7 @@ async fn execute_stmt( let message = anyhow!( "request supplied {actual} parameters, \ but {statement} requires {expected}", - statement = stmt.to_ast_string(), + statement = stmt.to_ast_string_simple(), actual = raw_params.len(), expected = param_types.len() ); diff --git a/src/sql-parser/src/ast/display.rs b/src/sql-parser/src/ast/display.rs index d205588246b75..78f2d515c1a55 100644 --- a/src/sql-parser/src/ast/display.rs +++ b/src/sql-parser/src/ast/display.rs @@ -154,7 +154,7 @@ pub trait AstDisplay { where W: fmt::Write; - fn to_ast_string(&self) -> String { + fn to_ast_string_simple(&self) -> String { let mut buf = String::new(); let mut f = AstFormatter::new(&mut buf, FormatMode::Simple); self.fmt(&mut f); @@ -321,7 +321,7 @@ impl<'a> AstDisplay for EscapeSingleQuoteString<'a> { impl<'a> fmt::Display for EscapeSingleQuoteString<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&self.to_ast_string()) + f.write_str(&self.to_ast_string_simple()) } } @@ -341,7 +341,7 @@ impl<'a> AstDisplay for EscapedStringLiteral<'a> { impl<'a> fmt::Display for EscapedStringLiteral<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(&self.to_ast_string()) + f.write_str(&self.to_ast_string_simple()) } } diff --git a/src/sql-parser/src/lib.rs b/src/sql-parser/src/lib.rs index dc90d4ef154d3..e60179fa92be7 100644 --- a/src/sql-parser/src/lib.rs +++ b/src/sql-parser/src/lib.rs @@ -72,7 +72,7 @@ pub fn datadriven_testcase(tc: &datadriven::TestCase) -> String { match parser::parse_statements(input) { Ok(s) => { let stmt = s.into_element().ast; - for printed in [stmt.to_ast_string(), stmt.to_ast_string_stable()] { + for printed in [stmt.to_ast_string_simple(), stmt.to_ast_string_stable()] { let mut parsed = match parser::parse_statements(&printed) { Ok(parsed) => parsed.into_element().ast, Err(err) => panic!("reparse failed: {}: {}\n", stmt, err), @@ -121,7 +121,7 @@ pub fn datadriven_testcase(tc: &datadriven::TestCase) -> String { let input = tc.input.trim(); match parser::parse_expr(input) { Ok(s) => { - for printed in [s.to_ast_string(), s.to_ast_string_stable()] { + for printed in [s.to_ast_string_simple(), s.to_ast_string_stable()] { match parser::parse_expr(&printed) { Ok(parsed) => { // TODO: We always coerce the double colon operator into a Cast expr instead diff --git a/src/sql-pretty/src/doc.rs b/src/sql-pretty/src/doc.rs index 1d6308b799aa7..439dad9b41a85 100644 --- a/src/sql-pretty/src/doc.rs +++ b/src/sql-pretty/src/doc.rs @@ -26,14 +26,14 @@ pub(crate) fn doc_display<'a, T: AstDisplay>(v: &T, _debug: &str) -> RcDoc<'a, ( "UNKNOWN PRETTY TYPE in {}: {}, {}", _debug, std::any::type_name::(), - v.to_ast_string() + v.to_ast_string_simple() ); doc_display_pass(v) } // Use when the AstDisplay trait is what we want. fn doc_display_pass<'a, T: AstDisplay>(v: &T) -> RcDoc<'a, ()> { - RcDoc::text(v.to_ast_string()) + RcDoc::text(v.to_ast_string_simple()) } pub(crate) fn doc_create_source(v: &CreateSourceStatement) -> RcDoc { @@ -251,7 +251,7 @@ pub(crate) fn doc_create_materialized_view( if let Some(cluster) = &v.in_cluster { docs.push(RcDoc::text(format!( "IN CLUSTER {}", - cluster.to_ast_string() + cluster.to_ast_string_simple() ))); } if !v.with_options.is_empty() { @@ -281,7 +281,7 @@ fn doc_view_definition(v: &ViewDefinition) -> RcDoc { pub(crate) fn doc_insert(v: &InsertStatement) -> RcDoc { let mut first = vec![RcDoc::text(format!( "INSERT INTO {}", - v.table_name.to_ast_string() + v.table_name.to_ast_string_simple() ))]; if !v.columns.is_empty() { first.push(bracket( @@ -597,7 +597,10 @@ pub fn doc_expr(v: &Expr) -> RcDoc { } Expr::Cast { expr, data_type } => { let doc = doc_expr(expr); - RcDoc::concat([doc, RcDoc::text(format!("::{}", data_type.to_ast_string()))]) + RcDoc::concat([ + doc, + RcDoc::text(format!("::{}", data_type.to_ast_string_simple())), + ]) } Expr::Nested(ast) => bracket("(", doc_expr(ast), ")"), Expr::Function(fun) => doc_function(fun), @@ -713,7 +716,7 @@ fn doc_function(v: &Function) -> RcDoc { } let name = format!( "{}({}", - v.name.to_ast_string(), + v.name.to_ast_string_simple(), if v.distinct { "DISTINCT " } else { "" } ); bracket(name, comma_separate(doc_expr, args), ")") diff --git a/src/sql/src/names.rs b/src/sql/src/names.rs index 1401f83872040..dfff544402057 100644 --- a/src/sql/src/names.rs +++ b/src/sql/src/names.rs @@ -524,7 +524,7 @@ impl AstDisplay for ResolvedItemName { impl std::fmt::Display for ResolvedItemName { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str(self.to_ast_string().as_str()) + f.write_str(self.to_ast_string_simple().as_str()) } } @@ -547,7 +547,7 @@ impl AstDisplay for ResolvedColumnReference { impl std::fmt::Display for ResolvedColumnReference { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.write_str(self.to_ast_string().as_str()) + f.write_str(self.to_ast_string_simple().as_str()) } } @@ -794,7 +794,7 @@ impl ResolvedDataType { impl fmt::Display for ResolvedDataType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.to_ast_string().as_str()) + f.write_str(self.to_ast_string_simple().as_str()) } } diff --git a/src/sql/src/normalize.rs b/src/sql/src/normalize.rs index 2013e9d220261..250b47077da60 100644 --- a/src/sql/src/normalize.rs +++ b/src/sql/src/normalize.rs @@ -606,10 +606,10 @@ macro_rules! generate_extracted_config { $( $option_name => { if !$allow_multiple && !extracted.seen.insert(option.name.clone()) { - sql_bail!("{} specified more than once", option.name.to_ast_string()); + sql_bail!("{} specified more than once", option.name.to_ast_string_simple()); } let val: $t = $crate::plan::with_options::TryFromValue::try_from_value(option.value) - .map_err(|e| sql_err!("invalid {}: {}", option.name.to_ast_string(), e))?; + .map_err(|e| sql_err!("invalid {}: {}", option.name.to_ast_string_simple(), e))?; generate_extracted_config!( @ifexpr $allow_multiple, extracted.[<$option_name:snake>].push(val), diff --git a/src/sql/src/plan/error.rs b/src/sql/src/plan/error.rs index 2fd2ffb64b211..3bb81cc9fe606 100644 --- a/src/sql/src/plan/error.rs +++ b/src/sql/src/plan/error.rs @@ -650,7 +650,7 @@ impl fmt::Display for PlanError { write!(f, "cannot drop {object_type} {object_name}{reason}") } Self::InvalidOptionValue { option_name, err } => write!(f, "invalid {} option value: {}", option_name, err), - Self::UnexpectedDuplicateReference { name } => write!(f, "unexpected multiple references to {}", name.to_ast_string()), + Self::UnexpectedDuplicateReference { name } => write!(f, "unexpected multiple references to {}", name.to_ast_string_simple()), Self::RecursiveTypeMismatch(name, declared, inferred) => { let declared = separated(", ", declared); let inferred = separated(", ", inferred); diff --git a/src/sql/src/plan/statement/acl.rs b/src/sql/src/plan/statement/acl.rs index 1886cba0c7359..c0fef9fedfef1 100644 --- a/src/sql/src/plan/statement/acl.rs +++ b/src/sql/src/plan/statement/acl.rs @@ -119,7 +119,7 @@ fn plan_alter_cluster_owner( })), None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type: ObjectType::Cluster, }); Ok(Plan::AlterNoop(AlterNoopPlan { @@ -143,7 +143,7 @@ fn plan_alter_database_owner( })), None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type: ObjectType::Database, }); @@ -178,7 +178,7 @@ fn plan_alter_schema_owner( } None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type: ObjectType::Schema, }); @@ -231,7 +231,7 @@ fn plan_alter_item_owner( } None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type, }); @@ -254,7 +254,7 @@ fn plan_alter_network_policy_owner( })), None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type: ObjectType::NetworkPolicy, }); diff --git a/src/sql/src/plan/statement/ddl.rs b/src/sql/src/plan/statement/ddl.rs index 94c879873d565..969a07e98aeba 100644 --- a/src/sql/src/plan/statement/ddl.rs +++ b/src/sql/src/plan/statement/ddl.rs @@ -3484,9 +3484,9 @@ impl std::convert::TryFrom>> for CsrConfigOptionExtract })); } let option_name = option.name.clone(); - let option_name_str = option_name.to_ast_string(); + let option_name_str = option_name.to_ast_string_simple(); let better_error = |e: PlanError| PlanError::InvalidOptionValue { - option_name: option_name.to_ast_string(), + option_name: option_name.to_ast_string_simple(), err: e.into(), }; let to_compatibility_level = |val: Option>| { @@ -5200,7 +5200,7 @@ pub fn plan_drop_objects( match id { Some(id) => referenced_ids.push(id), None => scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type, }), } @@ -5851,7 +5851,7 @@ pub fn plan_alter_cluster( Some(entry) => entry, None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type: ObjectType::Cluster, }); @@ -6157,7 +6157,7 @@ pub fn plan_alter_item_set_cluster( } None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type, }); @@ -6219,7 +6219,7 @@ pub fn plan_alter_schema_rename( let Some((db_spec, schema_spec)) = resolve_schema(scx, name.clone(), if_exists)? else { let object_type = ObjectType::Schema; scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type, }); return Ok(Plan::AlterNoop(AlterNoopPlan { object_type })); @@ -6350,7 +6350,7 @@ pub fn plan_alter_item_rename( } None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type, }); @@ -6374,7 +6374,7 @@ pub fn plan_alter_cluster_rename( })), None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type, }); @@ -6441,7 +6441,7 @@ pub fn plan_alter_cluster_replica_rename( } None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type, }); @@ -6586,7 +6586,7 @@ fn alter_retain_history( } None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type, }); @@ -6677,7 +6677,10 @@ pub fn plan_alter_connection( if !with_options.is_empty() { sql_bail!( "ALTER CONNECTION...ROTATE KEYS does not support WITH ({})", - with_options.iter().map(|o| o.to_ast_string()).join(", ") + with_options + .iter() + .map(|o| o.to_ast_string_simple()) + .join(", ") ); } @@ -6951,7 +6954,7 @@ pub fn plan_alter_source( // planned directly. sql_bail!( "Cannot modify the {} of a SOURCE.", - option.name.to_ast_string() + option.name.to_ast_string_simple() ); } AlterSourceAction::ResetOptions(reset) => { @@ -6969,7 +6972,10 @@ pub fn plan_alter_source( None, ); } - sql_bail!("Cannot modify the {} of a SOURCE.", option.to_ast_string()); + sql_bail!( + "Cannot modify the {} of a SOURCE.", + option.to_ast_string_simple() + ); } AlterSourceAction::DropSubsources { .. } => { sql_bail!("ALTER SOURCE...DROP SUBSOURCE no longer supported; use DROP SOURCE") @@ -7092,7 +7098,7 @@ pub fn plan_alter_table_add_column( } None => { scx.catalog.add_notice(PlanNotice::ObjectDoesNotExist { - name: name.to_ast_string(), + name: name.to_ast_string_simple(), object_type, }); return Ok(Plan::AlterNoop(AlterNoopPlan { object_type })); diff --git a/src/sql/src/pure.rs b/src/sql/src/pure.rs index 0e9b90d839669..0d99f30dc31da 100644 --- a/src/sql/src/pure.rs +++ b/src/sql/src/pure.rs @@ -439,7 +439,7 @@ async fn purify_create_sink( { sql_bail!( "CREATE SINK...WITH ({}..) is not allowed", - op.name.to_ast_string(), + op.name.to_ast_string_simple(), ) } diff --git a/src/sql/src/pure/error.rs b/src/sql/src/pure/error.rs index 9acaa9b3b3551..c6e36102e575f 100644 --- a/src/sql/src/pure/error.rs +++ b/src/sql/src/pure/error.rs @@ -135,7 +135,7 @@ impl PgSourcePurificationError { /// Logical errors detectable during purification for a KAFKA SOURCE. #[derive(Debug, Clone, thiserror::Error)] pub enum KafkaSourcePurificationError { - #[error("{} is only valid for multi-output sources", .0.to_ast_string())] + #[error("{} is only valid for multi-output sources", .0.to_ast_string_simple())] ReferencedSubsources(ExternalReferences), #[error("KAFKA CONNECTION without TOPIC")] ConnectionMissingTopic, diff --git a/src/sql/src/pure/mysql.rs b/src/sql/src/pure/mysql.rs index c3b7890da13a4..6de5b5d321d94 100644 --- a/src/sql/src/pure/mysql.rs +++ b/src/sql/src/pure/mysql.rs @@ -234,13 +234,13 @@ pub(super) fn map_column_refs<'a>( .insert(name.0[2].as_str()); if !new { return Err(PlanError::InvalidOptionValue { - option_name: option_type.to_ast_string(), + option_name: option_type.to_ast_string_simple(), err: Box::new(PlanError::UnexpectedDuplicateReference { name: name.clone() }), }); } } else { return Err(PlanError::InvalidOptionValue { - option_name: option_type.to_ast_string(), + option_name: option_type.to_ast_string_simple(), err: Box::new(PlanError::UnderqualifiedColumnName(name.to_string())), }); } @@ -379,7 +379,10 @@ pub(super) async fn purify_source_exports( if requested_exports.is_empty() { sql_bail!( "MySQL source must ingest at least one table, but {} matched none", - requested_references.as_ref().unwrap().to_ast_string() + requested_references + .as_ref() + .unwrap() + .to_ast_string_simple() ); } diff --git a/src/sql/src/pure/postgres.rs b/src/sql/src/pure/postgres.rs index 3d7d35bc3ff9f..8b4224f2638a3 100644 --- a/src/sql/src/pure/postgres.rs +++ b/src/sql/src/pure/postgres.rs @@ -244,7 +244,7 @@ pub(super) fn generate_source_export_statement_values( let mut full_name = purified_export.external_reference.0.clone(); full_name.push(name); unsupported_cols.push(( - UnresolvedItemName(full_name).to_ast_string(), + UnresolvedItemName(full_name).to_ast_string_simple(), mz_repr::adt::system::Oid(c.type_oid), )); continue; @@ -374,7 +374,10 @@ pub(super) async fn purify_source_exports( if requested_exports.is_empty() { sql_bail!( "[internal error]: Postgres reference {} did not match any tables", - requested_references.as_ref().unwrap().to_ast_string() + requested_references + .as_ref() + .unwrap() + .to_ast_string_simple() ); } diff --git a/src/storage/src/source/postgres.rs b/src/storage/src/source/postgres.rs index 26073f81230b4..38213160bf5a7 100644 --- a/src/storage/src/source/postgres.rs +++ b/src/storage/src/source/postgres.rs @@ -374,7 +374,7 @@ impl From for DataflowError { async fn ensure_replication_slot(client: &Client, slot: &str) -> Result<(), TransientError> { // Note: Using unchecked here is okay because we're using it in a SQL query. - let slot = Ident::new_unchecked(slot).to_ast_string(); + let slot = Ident::new_unchecked(slot).to_ast_string_simple(); let query = format!("CREATE_REPLICATION_SLOT {slot} LOGICAL \"pgoutput\" NOEXPORT_SNAPSHOT"); match simple_query_opt(client, &query).await { Ok(_) => Ok(()), diff --git a/src/storage/src/source/postgres/replication.rs b/src/storage/src/source/postgres/replication.rs index 5ac4b51cbe8c0..ccb7152f993df 100644 --- a/src/storage/src/source/postgres/replication.rs +++ b/src/storage/src/source/postgres/replication.rs @@ -700,7 +700,7 @@ async fn raw_stream<'a>( let lsn = PgLsn::from(resume_lsn.offset); let query = format!( r#"START_REPLICATION SLOT "{}" LOGICAL {} ("proto_version" '1', "publication_names" '{}')"#, - Ident::new_unchecked(slot).to_ast_string(), + Ident::new_unchecked(slot).to_ast_string_simple(), lsn, publication, ); diff --git a/src/storage/src/source/postgres/snapshot.rs b/src/storage/src/source/postgres/snapshot.rs index e5171b8d0a3ed..5536b42702bcd 100644 --- a/src/storage/src/source/postgres/snapshot.rs +++ b/src/storage/src/source/postgres/snapshot.rs @@ -404,8 +404,8 @@ pub(crate) fn render>( ( format!( "{}.{}", - Ident::new_unchecked(desc.namespace.clone()).to_ast_string(), - Ident::new_unchecked(desc.name.clone()).to_ast_string() + Ident::new_unchecked(desc.namespace.clone()).to_ast_string_simple(), + Ident::new_unchecked(desc.name.clone()).to_ast_string_simple() ), desc.oid.clone(), outputs.len(), @@ -473,8 +473,8 @@ pub(crate) fn render>( // emulate's PG's rules for name formatting. let query = format!( "COPY {}.{} TO STDOUT (FORMAT TEXT, DELIMITER '\t')", - Ident::new_unchecked(namespace).to_ast_string(), - Ident::new_unchecked(table).to_ast_string(), + Ident::new_unchecked(namespace).to_ast_string_simple(), + Ident::new_unchecked(table).to_ast_string_simple(), ); let mut stream = pin!(client.copy_out_simple(&query).await?); @@ -623,7 +623,7 @@ async fn export_snapshot_inner( .await?; // Note: Using unchecked here is okay because we're using it in a SQL query. - let slot = Ident::new_unchecked(slot).to_ast_string(); + let slot = Ident::new_unchecked(slot).to_ast_string_simple(); let temporary_str = if temporary { " TEMPORARY" } else { "" }; let query = format!("CREATE_REPLICATION_SLOT {slot}{temporary_str} LOGICAL \"pgoutput\" USE_SNAPSHOT"); From f42e9f233fc01b817c899d67b4d55866c201af0c Mon Sep 17 00:00:00 2001 From: Gabor Gevay Date: Mon, 17 Mar 2025 14:48:13 +0100 Subject: [PATCH 2/4] Pretty-print in `SHOW CREATE` and in `SHOW REDACTED CREATE` --- Cargo.lock | 1 + .../tests/adapter/test_constraints.py | 3 +- .../checks/all_checks/create_table.py | 9 - .../materialize/checks/all_checks/debezium.py | 8 +- .../checks/all_checks/json_source.py | 4 +- .../checks/all_checks/kafka_formats.py | 6 +- .../checks/all_checks/materialized_views.py | 29 - .../checks/all_checks/mysql_cdc.py | 1 + .../checks/all_checks/null_value.py | 10 +- .../checks/all_checks/rename_view.py | 4 +- .../checks/all_checks/retain_history.py | 6 - .../checks/all_checks/text_bytea_types.py | 8 +- .../materialize/checks/all_checks/top_k.py | 20 +- .../materialize/checks/all_checks/webhook.py | 8 +- misc/wasm/src/sql-pretty-wasm/src/lib.rs | 4 +- src/expr/src/scalar/func.rs | 15 +- src/lsp-server/src/backend.rs | 14 +- src/sql-parser/src/ast/display.rs | 16 +- src/sql-pretty/src/doc.rs | 429 +++++---- src/sql-pretty/src/lib.rs | 61 +- src/sql-pretty/src/util.rs | 6 +- src/sql-pretty/tests/parser.rs | 48 +- src/sql/BUILD.bazel | 3 + src/sql/Cargo.toml | 1 + src/sql/src/func.rs | 2 +- src/sql/src/plan/statement/show.rs | 19 +- .../check-from-v0.111.0-kafka-sink.td | 11 +- .../check-from-v0.131.0-alter-table.td | 2 +- .../legacy-upgrade/check-from-v0.27.0-json.td | 2 +- .../check-from-v0.27.0-special-functions.td | 2 +- .../check-from-v0.27.0-subquery.td | 2 +- .../create-in-v0.111.0-kafka-sink.td | 6 - .../10-create-connection.td | 2 +- test/mysql-cdc-old-syntax/30-text-columns.td | 2 +- .../35-exclude-columns.td | 2 +- test/mysql-cdc-old-syntax/alter-source.td | 12 +- test/mysql-cdc/10-create-connection.td | 2 +- test/mysql-cdc/30-text-columns.td | 2 +- test/mysql-cdc/35-exclude-columns.td | 2 +- test/mysql-cdc/alter-source.td | 14 +- test/mysql-cdc/create-alter-iam-connection.td | 2 +- test/pg-cdc-old-syntax/alter-source.td | 10 +- test/pg-cdc/alter-source.td | 10 +- test/pg-cdc/pg-cdc.td | 2 +- test/sqllogictest/alter-table.slt | 10 +- test/sqllogictest/alter.slt | 22 +- .../cockroach/case_sensitive_names.slt | 4 +- test/sqllogictest/id.slt | 6 +- test/sqllogictest/joins.slt | 2 +- test/sqllogictest/materialized_views.slt | 26 +- test/sqllogictest/operator.slt | 10 +- test/sqllogictest/pg_catalog_matviews.slt | 22 +- test/sqllogictest/pg_catalog_views.slt | 2 +- test/sqllogictest/privilege_checks.slt | 8 +- test/sqllogictest/redacted.slt | 20 +- test/sqllogictest/rename.slt | 60 +- test/sqllogictest/slt.slt | 44 + .../connection-alter.td | 15 - .../connection-create-drop.td | 5 - .../createdrop.td | 5 - .../testdrive-old-kafka-src-syntax/indexes.td | 5 - .../load-generator.td | 9 - .../materializations.td | 5 - test/testdrive-old-kafka-src-syntax/rename.td | 900 ------------------ test/testdrive-old-kafka-src-syntax/tables.td | 5 - test/testdrive/catalog.td | 2 +- test/testdrive/connection-alter.td | 6 +- test/testdrive/connection-create-drop.td | 2 +- test/testdrive/createdrop.td | 2 +- test/testdrive/indexes.td | 2 +- .../kafka-avro-sinks-doc-comments.td | 2 +- test/testdrive/load-generator.td | 6 +- test/testdrive/materializations.td | 2 +- test/testdrive/rename.td | 51 +- test/testdrive/tables.td | 2 +- test/testdrive/webhook.td | 4 +- test/yugabyte-cdc/yugabyte-cdc.td | 2 +- 77 files changed, 663 insertions(+), 1427 deletions(-) delete mode 100644 test/testdrive-old-kafka-src-syntax/rename.td diff --git a/Cargo.lock b/Cargo.lock index 8558511c8d3c6..155950fc121ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6974,6 +6974,7 @@ dependencies = [ "mz-secrets", "mz-sql-lexer", "mz-sql-parser", + "mz-sql-pretty", "mz-ssh-util", "mz-storage-types", "mz-tracing", diff --git a/misc/dbt-materialize/tests/adapter/test_constraints.py b/misc/dbt-materialize/tests/adapter/test_constraints.py index fae5fe003ce85..f5f1500574914 100644 --- a/misc/dbt-materialize/tests/adapter/test_constraints.py +++ b/misc/dbt-materialize/tests/adapter/test_constraints.py @@ -133,8 +133,7 @@ def test_ddl_enforcement(self, project): fetch="one", ) assert ( - 'ASSERT NOT NULL = "a", ASSERT NOT NULL = "b"' - in nullability_assertions_ddl[1] + "ASSERT NOT NULL = a, ASSERT NOT NULL = b" in nullability_assertions_ddl[1] ) diff --git a/misc/python/materialize/checks/all_checks/create_table.py b/misc/python/materialize/checks/all_checks/create_table.py index 92b034cd51961..1daa5805f5f31 100644 --- a/misc/python/materialize/checks/all_checks/create_table.py +++ b/misc/python/materialize/checks/all_checks/create_table.py @@ -60,9 +60,6 @@ def validate(self) -> Testdrive: > SELECT * FROM create_table_view2; 2 - > SHOW CREATE TABLE create_table1; - materialize.public.create_table1 "CREATE TABLE \\"materialize\\".\\"public\\".\\"create_table1\\" (\\"f1\\" \\"pg_catalog\\".\\"int4\\", \\"f2\\" \\"pg_catalog\\".\\"int4\\" NOT NULL DEFAULT 1234)" - ! INSERT INTO create_table1 (f2) VALUES (NULL); contains: null value in column @@ -72,9 +69,6 @@ def validate(self) -> Testdrive: > DELETE FROM create_table1 WHERE f1 = 999; - > SHOW CREATE TABLE create_table2; - materialize.public.create_table2 "CREATE TABLE \\"materialize\\".\\"public\\".\\"create_table2\\" (\\"f1\\" \\"pg_catalog\\".\\"int4\\", \\"f2\\" \\"pg_catalog\\".\\"int4\\" NOT NULL DEFAULT 1234)" - ! INSERT INTO create_table2 (f2) VALUES (NULL); contains: null value in column @@ -84,9 +78,6 @@ def validate(self) -> Testdrive: > DELETE FROM create_table2 WHERE f1 = 999; - > SHOW CREATE TABLE create_table3; - materialize.public.create_table3 "CREATE TABLE \\"materialize\\".\\"public\\".\\"create_table3\\" (\\"f1\\" \\"pg_catalog\\".\\"int4\\", \\"f2\\" \\"pg_catalog\\".\\"int4\\" NOT NULL DEFAULT 1234)" - ! INSERT INTO create_table3 (f2) VALUES (NULL); contains: null value in column diff --git a/misc/python/materialize/checks/all_checks/debezium.py b/misc/python/materialize/checks/all_checks/debezium.py index 8f89d1524f26a..bbeb30161d4d0 100644 --- a/misc/python/materialize/checks/all_checks/debezium.py +++ b/misc/python/materialize/checks/all_checks/debezium.py @@ -149,15 +149,15 @@ def validate(self) -> Testdrive: F 2 16000 """ + ( - """ + r""" $ set-regex match="FORMAT .*? ENVELOPE DEBEZIUM " replacement="" > SHOW CREATE SOURCE debezium_source1; - materialize.public.debezium_source1 "CREATE SOURCE \\"materialize\\".\\"public\\".\\"debezium_source1\\" IN CLUSTER \\"quickstart\\" FROM KAFKA CONNECTION \\"materialize\\".\\"public\\".\\"kafka_conn\\" (TOPIC = 'postgres.public.debezium_table') EXPOSE PROGRESS AS \\"materialize\\".\\"public\\".\\"debezium_source1_progress\\"" + materialize.public.debezium_source1 "CREATE SOURCE materialize.public.debezium_source1\nIN CLUSTER quickstart\nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'postgres.public.debezium_table')\nEXPOSE PROGRESS AS materialize.public.debezium_source1_progress;" > SHOW CREATE SOURCE debezium_source2; - materialize.public.debezium_source2 "CREATE SOURCE \\"materialize\\".\\"public\\".\\"debezium_source2\\" IN CLUSTER \\"quickstart\\" FROM KAFKA CONNECTION \\"materialize\\".\\"public\\".\\"kafka_conn\\" (TOPIC = 'postgres.public.debezium_table') EXPOSE PROGRESS AS \\"materialize\\".\\"public\\".\\"debezium_source2_progress\\"" + materialize.public.debezium_source2 "CREATE SOURCE materialize.public.debezium_source2\nIN CLUSTER quickstart\nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'postgres.public.debezium_table')\nEXPOSE PROGRESS AS materialize.public.debezium_source2_progress;" > SHOW CREATE SOURCE debezium_source3; - materialize.public.debezium_source3 "CREATE SOURCE \\"materialize\\".\\"public\\".\\"debezium_source3\\" IN CLUSTER \\"quickstart\\" FROM KAFKA CONNECTION \\"materialize\\".\\"public\\".\\"kafka_conn\\" (TOPIC = 'postgres.public.debezium_table') EXPOSE PROGRESS AS \\"materialize\\".\\"public\\".\\"debezium_source3_progress\\"" + materialize.public.debezium_source3 "CREATE SOURCE materialize.public.debezium_source3\nIN CLUSTER quickstart\nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'postgres.public.debezium_table')\nEXPOSE PROGRESS AS materialize.public.debezium_source3_progress;" """ if not self.is_running_as_cloudtest() else "" diff --git a/misc/python/materialize/checks/all_checks/json_source.py b/misc/python/materialize/checks/all_checks/json_source.py index 54789a5bff1c0..37b9c24a73db7 100644 --- a/misc/python/materialize/checks/all_checks/json_source.py +++ b/misc/python/materialize/checks/all_checks/json_source.py @@ -81,9 +81,9 @@ def validate(self) -> Testdrive: "\\"object\\"" "{\\"a\\":\\"b\\",\\"c\\":\\"d\\"}" "\\"str\\"" "\\"hello\\"" """ - + """ + + r""" > SHOW CREATE SOURCE format_jsonb_src; - materialize.public.format_jsonb_src "CREATE SOURCE \\"materialize\\".\\"public\\".\\"format_jsonb_src\\" IN CLUSTER \\"single_replica_cluster\\" FROM KAFKA CONNECTION \\"materialize\\".\\"public\\".\\"kafka_conn\\" (TOPIC = 'testdrive-format-json-${testdrive.seed}') EXPOSE PROGRESS AS \\"materialize\\".\\"public\\".\\"format_jsonb_src_progress\\"" + materialize.public.format_jsonb_src "CREATE SOURCE materialize.public.format_jsonb_src\nIN CLUSTER single_replica_cluster\nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'testdrive-format-json-${testdrive.seed}')\nEXPOSE PROGRESS AS materialize.public.format_jsonb_src_progress;" """ ) ) diff --git a/misc/python/materialize/checks/all_checks/kafka_formats.py b/misc/python/materialize/checks/all_checks/kafka_formats.py index f20e387e26d68..7e76b4b59dfa2 100644 --- a/misc/python/materialize/checks/all_checks/kafka_formats.py +++ b/misc/python/materialize/checks/all_checks/kafka_formats.py @@ -173,7 +173,7 @@ def manipulate(self) -> list[Testdrive]: def validate(self) -> Testdrive: return Testdrive( dedent( - """ + r""" > SELECT COUNT(*) FROM format_bytes1 3 @@ -217,10 +217,10 @@ def validate(self) -> Testdrive: key2A key2B value2A value2B key3A key3B value3A value3B - $ set-regex match=testdrive-format-bytes-\\d+ replacement= + $ set-regex match=testdrive-format-bytes-\d+ replacement= > SHOW CREATE SOURCE format_bytes1_src; - materialize.public.format_bytes1_src "CREATE SOURCE \\"materialize\\".\\"public\\".\\"format_bytes1_src\\" IN CLUSTER \\"kafka_formats\\" FROM KAFKA CONNECTION \\"materialize\\".\\"public\\".\\"kafka_conn\\" (TOPIC = '') EXPOSE PROGRESS AS \\"materialize\\".\\"public\\".\\"format_bytes1_src_progress\\"" + materialize.public.format_bytes1_src "CREATE SOURCE materialize.public.format_bytes1_src\nIN CLUSTER kafka_formats\nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = '')\nEXPOSE PROGRESS AS materialize.public.format_bytes1_src_progress;" """ ) ) diff --git a/misc/python/materialize/checks/all_checks/materialized_views.py b/misc/python/materialize/checks/all_checks/materialized_views.py index e533d8e1e3120..a9befc5579547 100644 --- a/misc/python/materialize/checks/all_checks/materialized_views.py +++ b/misc/python/materialize/checks/all_checks/materialized_views.py @@ -287,35 +287,6 @@ def validate(self) -> Testdrive: 2 3 - $ set-regex match=\\d{13} replacement= - - > SHOW CREATE MATERIALIZED VIEW refresh_view_2s_1 - "materialize.public.refresh_view_2s_1" "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"refresh_view_2s_1\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = EVERY '2 seconds' ALIGNED TO ::\\"mz_catalog\\".\\"mz_timestamp\\") AS SELECT DISTINCT (\\"x\\") FROM \\"materialize\\".\\"public\\".\\"refresh_table\\"" - - > SHOW CREATE MATERIALIZED VIEW refresh_view_2s_2 - "materialize.public.refresh_view_2s_2" "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"refresh_view_2s_2\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = EVERY '2 seconds' ALIGNED TO ::\\"mz_catalog\\".\\"mz_timestamp\\") AS SELECT DISTINCT (\\"x\\") FROM \\"materialize\\".\\"public\\".\\"refresh_table\\"" - - > SHOW CREATE MATERIALIZED VIEW refresh_view_2s_3 - "materialize.public.refresh_view_2s_3" "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"refresh_view_2s_3\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = EVERY '2 seconds' ALIGNED TO ::\\"mz_catalog\\".\\"mz_timestamp\\") AS SELECT DISTINCT (\\"x\\") FROM \\"materialize\\".\\"public\\".\\"refresh_table\\"" - - > SHOW CREATE MATERIALIZED VIEW refresh_view_at_1 - "materialize.public.refresh_view_at_1" "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"refresh_view_at_1\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = AT ::\\"mz_catalog\\".\\"mz_timestamp\\"::\\"pg_catalog\\".\\"text\\"::\\"pg_catalog\\".\\"int8\\") AS SELECT DISTINCT (\\"x\\") FROM \\"materialize\\".\\"public\\".\\"refresh_table\\"" - - > SHOW CREATE MATERIALIZED VIEW refresh_view_at_2 - "materialize.public.refresh_view_at_2" "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"refresh_view_at_2\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = AT ::\\"mz_catalog\\".\\"mz_timestamp\\"::\\"pg_catalog\\".\\"text\\"::\\"pg_catalog\\".\\"int8\\") AS SELECT DISTINCT (\\"x\\") FROM \\"materialize\\".\\"public\\".\\"refresh_table\\"" - - > SHOW CREATE MATERIALIZED VIEW refresh_view_at_3 - "materialize.public.refresh_view_at_3" "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"refresh_view_at_3\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = AT ::\\"mz_catalog\\".\\"mz_timestamp\\"::\\"pg_catalog\\".\\"text\\"::\\"pg_catalog\\".\\"int8\\") AS SELECT DISTINCT (\\"x\\") FROM \\"materialize\\".\\"public\\".\\"refresh_table\\"" - - > SHOW CREATE MATERIALIZED VIEW refresh_view_late_1 - "materialize.public.refresh_view_late_1" "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"refresh_view_late_1\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = AT ::\\"mz_catalog\\".\\"mz_timestamp\\"::\\"pg_catalog\\".\\"text\\"::\\"pg_catalog\\".\\"int8\\" + 86400000) AS SELECT DISTINCT (\\"x\\") FROM \\"materialize\\".\\"public\\".\\"refresh_table\\"" - - > SHOW CREATE MATERIALIZED VIEW refresh_view_late_2 - "materialize.public.refresh_view_late_2" "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"refresh_view_late_2\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = AT ::\\"mz_catalog\\".\\"mz_timestamp\\"::\\"pg_catalog\\".\\"text\\"::\\"pg_catalog\\".\\"int8\\" + 86400000) AS SELECT DISTINCT (\\"x\\") FROM \\"materialize\\".\\"public\\".\\"refresh_table\\"" - - > SHOW CREATE MATERIALIZED VIEW refresh_view_late_3 - "materialize.public.refresh_view_late_3" "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"refresh_view_late_3\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = AT ::\\"mz_catalog\\".\\"mz_timestamp\\"::\\"pg_catalog\\".\\"text\\"::\\"pg_catalog\\".\\"int8\\" + 86400000) AS SELECT DISTINCT (\\"x\\") FROM \\"materialize\\".\\"public\\".\\"refresh_table\\"" - $ set-regex match=(s\\d+|\\d{13}|[ ]{12}0|u\\d{1,3}|\\(\\d+-\\d\\d-\\d\\d\\s\\d\\d:\\d\\d:\\d\\d\\.\\d\\d\\d\\)|\\(\\d+\\)) replacement=<> >[version<13900] EXPLAIN TIMESTAMP FOR SELECT * FROM refresh_view_late_1 diff --git a/misc/python/materialize/checks/all_checks/mysql_cdc.py b/misc/python/materialize/checks/all_checks/mysql_cdc.py index c0ac05a1bcb72..cfa02f586c2b2 100644 --- a/misc/python/materialize/checks/all_checks/mysql_cdc.py +++ b/misc/python/materialize/checks/all_checks/mysql_cdc.py @@ -214,6 +214,7 @@ def validate(self) -> Testdrive: H 200 {self.expects} # TODO: Figure out the quoting here -- it returns "f4" when done using the SQL shell + # (Might have changed again with https://github.com/MaterializeInc/materialize/pull/31933) # > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \\((.*?)\\)')[1] FROM (SHOW CREATE SOURCE mysql_source_tableA{self.suffix}); # "\"f4\"" diff --git a/misc/python/materialize/checks/all_checks/null_value.py b/misc/python/materialize/checks/all_checks/null_value.py index 05c72ca14db5b..3da22d2249c9f 100644 --- a/misc/python/materialize/checks/all_checks/null_value.py +++ b/misc/python/materialize/checks/all_checks/null_value.py @@ -51,10 +51,7 @@ def manipulate(self) -> list[Testdrive]: def validate(self) -> Testdrive: return Testdrive( dedent( - f""" - > SHOW CREATE VIEW null_value_view1; - materialize.public.null_value_view1 "CREATE VIEW \\"materialize\\".\\"public\\".\\"null_value_view1\\" AS SELECT \\"f1\\", \\"f2\\", NULL FROM \\"materialize\\".\\"public\\".\\"null_value_table\\" WHERE \\"f1\\" IS NULL OR \\"f1\\" IS NOT NULL OR \\"f1\\" = NULL" - + """ > SELECT * FROM null_value_view1; @@ -69,9 +66,6 @@ def validate(self) -> Testdrive: - > SHOW CREATE MATERIALIZED VIEW null_value_view2; - materialize.public.null_value_view2 "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"null_value_view2\\" IN CLUSTER \\"{self._default_cluster()}\\" WITH (REFRESH = ON COMMIT) AS SELECT \\"f1\\", \\"f2\\", NULL FROM \\"materialize\\".\\"public\\".\\"null_value_table\\" WHERE \\"f1\\" IS NULL OR \\"f1\\" IS NOT NULL OR \\"f1\\" = NULL" - > SELECT * FROM null_value_view2; @@ -85,8 +79,6 @@ def validate(self) -> Testdrive: - - """ ) ) diff --git a/misc/python/materialize/checks/all_checks/rename_view.py b/misc/python/materialize/checks/all_checks/rename_view.py index 0a4c0d73c51f8..3c9984d8faed0 100644 --- a/misc/python/materialize/checks/all_checks/rename_view.py +++ b/misc/python/materialize/checks/all_checks/rename_view.py @@ -47,9 +47,9 @@ def manipulate(self) -> list[Testdrive]: def validate(self) -> Testdrive: return Testdrive( dedent( - """ + r""" > SHOW CREATE VIEW rename_view_viewB3; - materialize.public.rename_view_viewb3 "CREATE VIEW \\"materialize\\".\\"public\\".\\"rename_view_viewb3\\" AS SELECT \\"f2\\" FROM \\"materialize\\".\\"public\\".\\"rename_view_viewa3\\" WHERE \\"f2\\" > 0" + materialize.public.rename_view_viewb3 "CREATE VIEW\n materialize.public.rename_view_viewb3\n AS SELECT f2 FROM materialize.public.rename_view_viewa3 WHERE f2 > 0;" > SELECT * FROM rename_view_viewA3; 1 diff --git a/misc/python/materialize/checks/all_checks/retain_history.py b/misc/python/materialize/checks/all_checks/retain_history.py index cc509ea0e2a24..ace76c2461dff 100644 --- a/misc/python/materialize/checks/all_checks/retain_history.py +++ b/misc/python/materialize/checks/all_checks/retain_history.py @@ -234,12 +234,6 @@ def validate(self) -> Testdrive: definition_validations = f""" > SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW retain_history_mv1); "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"retain_history_mv1\\" IN CLUSTER \\"quickstart\\" WITH (RETAIN HISTORY = FOR '{RETAIN_HISTORY_DURATION}', REFRESH = ON COMMIT) AS SELECT * FROM \\"materialize\\".\\"public\\".\\"retain_history_table\\"" - - > SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW retain_history_mv2); - "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"retain_history_mv2\\" IN CLUSTER \\"quickstart\\" WITH (RETAIN HISTORY = FOR '{RETAIN_HISTORY_DURATION}', REFRESH = ON COMMIT) AS SELECT * FROM \\"materialize\\".\\"public\\".\\"retain_history_table\\"" - - > SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW retain_history_mv3); - "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"retain_history_mv3\\" IN CLUSTER \\"quickstart\\" WITH (RETAIN HISTORY = FOR '{RETAIN_HISTORY_DURATION}', REFRESH = ON COMMIT) AS SELECT * FROM \\"materialize\\".\\"public\\".\\"retain_history_mv2\\"" """ other_validations = """ diff --git a/misc/python/materialize/checks/all_checks/text_bytea_types.py b/misc/python/materialize/checks/all_checks/text_bytea_types.py index 59cb3ffff8b67..3a4950c5287b6 100644 --- a/misc/python/materialize/checks/all_checks/text_bytea_types.py +++ b/misc/python/materialize/checks/all_checks/text_bytea_types.py @@ -49,10 +49,7 @@ def manipulate(self) -> list[Testdrive]: def validate(self) -> Testdrive: return Testdrive( dedent( - f""" - > SHOW CREATE MATERIALIZED VIEW string_bytea_types_view1; - materialize.public.string_bytea_types_view1 "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"string_bytea_types_view1\\" IN CLUSTER \\"{self._default_cluster()}\\" WITH (REFRESH = ON COMMIT) AS SELECT \\"text_col\\", \\"bytea_col\\", 'това'::\\"pg_catalog\\".\\"text\\", '\\\\xAAAA'::\\"pg_catalog\\".\\"bytea\\" FROM \\"materialize\\".\\"public\\".\\"text_bytea_types_table\\" WHERE \\"text_col\\" >= ''::\\"pg_catalog\\".\\"text\\" AND \\"bytea_col\\" >= ''::\\"pg_catalog\\".\\"bytea\\"" - + """ > SELECT text_col, text, LENGTH(bytea_col), LENGTH(bytea) FROM string_bytea_types_view1; aaaa това 2 2 aaaa това 2 2 @@ -61,9 +58,6 @@ def validate(self) -> Testdrive: "това е" това 10 2 "това е" това 10 2 - > SHOW CREATE VIEW string_bytea_types_view2; - materialize.public.string_bytea_types_view2 "CREATE VIEW \\"materialize\\".\\"public\\".\\"string_bytea_types_view2\\" AS SELECT \\"text_col\\", \\"bytea_col\\", 'това'::\\"pg_catalog\\".\\"text\\", '\\\\xAAAA'::\\"pg_catalog\\".\\"bytea\\" FROM \\"materialize\\".\\"public\\".\\"text_bytea_types_table\\" WHERE \\"text_col\\" >= ''::\\"pg_catalog\\".\\"text\\" AND \\"bytea_col\\" >= ''::\\"pg_catalog\\".\\"bytea\\"" - > SELECT text_col, text, LENGTH(bytea_col), LENGTH(bytea) FROM string_bytea_types_view2; aaaa това 2 2 aaaa това 2 2 diff --git a/misc/python/materialize/checks/all_checks/top_k.py b/misc/python/materialize/checks/all_checks/top_k.py index 5e4e0c6642597..79b6b0c5dfb71 100644 --- a/misc/python/materialize/checks/all_checks/top_k.py +++ b/misc/python/materialize/checks/all_checks/top_k.py @@ -68,17 +68,11 @@ def manipulate(self) -> list[Testdrive]: def validate(self) -> Testdrive: return Testdrive( dedent( - f""" - > SHOW CREATE MATERIALIZED VIEW basic_topk_view1; - materialize.public.basic_topk_view1 "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"basic_topk_view1\\" IN CLUSTER \\"{self._default_cluster()}\\" WITH (REFRESH = ON COMMIT) AS SELECT \\"f1\\", \\"pg_catalog\\".\\"count\\"(\\"f1\\") FROM \\"materialize\\".\\"public\\".\\"basic_topk_table\\" GROUP BY \\"f1\\" ORDER BY \\"f1\\" DESC NULLS LAST LIMIT 2" - + """ > SELECT * FROM basic_topk_view1; 2 32 3 48 - > SHOW CREATE MATERIALIZED VIEW basic_topk_view2; - materialize.public.basic_topk_view2 "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"basic_topk_view2\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = ON COMMIT) AS SELECT \\"f1\\", \\"pg_catalog\\".\\"count\\"(\\"f1\\") FROM \\"materialize\\".\\"public\\".\\"basic_topk_table\\" GROUP BY \\"f1\\" ORDER BY \\"f1\\" ASC NULLS FIRST LIMIT 2" - > SELECT * FROM basic_topk_view2; 1 16 0 @@ -149,16 +143,10 @@ def validate(self) -> Testdrive: return Testdrive( dedent( """ - > SHOW CREATE MATERIALIZED VIEW monotonic_topk_view1; - materialize.public.monotonic_topk_view1 "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"monotonic_topk_view1\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = ON COMMIT) AS SELECT \\"f1\\", \\"pg_catalog\\".\\"count\\"(\\"f1\\") FROM \\"materialize\\".\\"public\\".\\"monotonic_topk_source\\" GROUP BY \\"f1\\" ORDER BY \\"f1\\" DESC NULLS LAST LIMIT 2" - > SELECT * FROM monotonic_topk_view1; E 5 D 4 - > SHOW CREATE MATERIALIZED VIEW monotonic_topk_view2; - materialize.public.monotonic_topk_view2 "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"monotonic_topk_view2\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = ON COMMIT) AS SELECT \\"f1\\", \\"pg_catalog\\".\\"count\\"(\\"f1\\") FROM \\"materialize\\".\\"public\\".\\"monotonic_topk_source\\" GROUP BY \\"f1\\" ORDER BY \\"f1\\" ASC NULLS FIRST LIMIT 2" - > SELECT * FROM monotonic_topk_view2; A 1 B 2 @@ -213,15 +201,9 @@ def validate(self) -> Testdrive: return Testdrive( dedent( """ - > SHOW CREATE MATERIALIZED VIEW monotonic_top1_view1; - materialize.public.monotonic_top1_view1 "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"monotonic_top1_view1\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = ON COMMIT) AS SELECT \\"f1\\", \\"pg_catalog\\".\\"count\\"(\\"f1\\") FROM \\"materialize\\".\\"public\\".\\"monotonic_top1_source\\" GROUP BY \\"f1\\" ORDER BY \\"f1\\" DESC NULLS LAST LIMIT 1" - > SELECT * FROM monotonic_top1_view1; D 5 - > SHOW CREATE MATERIALIZED VIEW monotonic_top1_view2; - materialize.public.monotonic_top1_view2 "CREATE MATERIALIZED VIEW \\"materialize\\".\\"public\\".\\"monotonic_top1_view2\\" IN CLUSTER \\"quickstart\\" WITH (REFRESH = ON COMMIT) AS SELECT \\"f1\\", \\"pg_catalog\\".\\"count\\"(\\"f1\\") FROM \\"materialize\\".\\"public\\".\\"monotonic_top1_source\\" GROUP BY \\"f1\\" ORDER BY \\"f1\\" ASC NULLS FIRST LIMIT 1" - > SELECT * FROM monotonic_top1_view2; A 1 """ diff --git a/misc/python/materialize/checks/all_checks/webhook.py b/misc/python/materialize/checks/all_checks/webhook.py index 623096dfdb54b..d1cd05ca7a8a1 100644 --- a/misc/python/materialize/checks/all_checks/webhook.py +++ b/misc/python/materialize/checks/all_checks/webhook.py @@ -111,13 +111,13 @@ def validate(self) -> Testdrive: \\\\x01\\x02\\x03\\x04 > SHOW CREATE SOURCE webhook_text - materialize.public.webhook_text "CREATE SOURCE \\"materialize\\".\\"public\\".\\"webhook_text\\" IN CLUSTER \\"webhook_cluster\\" FROM WEBHOOK BODY FORMAT TEXT" + materialize.public.webhook_text "CREATE SOURCE materialize.public.webhook_text IN CLUSTER webhook_cluster FROM WEBHOOK BODY FORMAT TEXT;" > SHOW CREATE SOURCE webhook_json - materialize.public.webhook_json "CREATE SOURCE \\"materialize\\".\\"public\\".\\"webhook_json\\" IN CLUSTER \\"webhook_cluster\\" FROM WEBHOOK BODY FORMAT JSON INCLUDE HEADERS" + materialize.public.webhook_json "CREATE SOURCE materialize.public.webhook_json IN CLUSTER webhook_cluster FROM WEBHOOK BODY FORMAT JSON INCLUDE HEADERS;" > SHOW CREATE SOURCE webhook_bytes - materialize.public.webhook_bytes "CREATE SOURCE \\"materialize\\".\\"public\\".\\"webhook_bytes\\" IN CLUSTER \\"webhook_cluster\\" FROM WEBHOOK BODY FORMAT BYTES" + materialize.public.webhook_bytes "CREATE SOURCE materialize.public.webhook_bytes IN CLUSTER webhook_cluster FROM WEBHOOK BODY FORMAT BYTES;" """ ) ) @@ -165,7 +165,7 @@ def validate(self) -> Testdrive: threeeeeee > SHOW CREATE TABLE webhook_table_text - materialize.public.webhook_table_text "CREATE TABLE \\"materialize\\".\\"public\\".\\"webhook_table_text\\" FROM WEBHOOK BODY FORMAT TEXT" + materialize.public.webhook_table_text "CREATE TABLE materialize.public.webhook_table_text FROM WEBHOOK BODY FORMAT TEXT;" """ ) ) diff --git a/misc/wasm/src/sql-pretty-wasm/src/lib.rs b/misc/wasm/src/sql-pretty-wasm/src/lib.rs index 3eb5e4a469db4..8d69335cfd4f9 100644 --- a/misc/wasm/src/sql-pretty-wasm/src/lib.rs +++ b/misc/wasm/src/sql-pretty-wasm/src/lib.rs @@ -29,7 +29,7 @@ static ALLOCATOR: LockedAllocator = /// SQL query is not parseable. #[wasm_bindgen(js_name = prettyStr)] pub fn pretty_str(query: &str, width: usize) -> Result { - mz_sql_pretty::pretty_str(query, width).map_err(|e| JsError::new(&e.to_string())) + mz_sql_pretty::pretty_str_simple(query, width).map_err(|e| JsError::new(&e.to_string())) } /// Pretty prints many SQL queries. @@ -38,7 +38,7 @@ pub fn pretty_str(query: &str, width: usize) -> Result { /// error if any SQL query is not parseable. #[wasm_bindgen(js_name = prettyStrs)] pub fn pretty_strs(queries: &str, width: usize) -> Result, JsError> { - Ok(mz_sql_pretty::pretty_strs(queries, width) + Ok(mz_sql_pretty::pretty_strs_simple(queries, width) .map_err(|e| JsError::new(&e.to_string()))? .into_iter() .collect()) diff --git a/src/expr/src/scalar/func.rs b/src/expr/src/scalar/func.rs index bdf7cfdd1e4a6..914a2e0e39074 100644 --- a/src/expr/src/scalar/func.rs +++ b/src/expr/src/scalar/func.rs @@ -47,10 +47,12 @@ use mz_repr::adt::mz_acl_item::{AclItem, AclMode, MzAclItem}; use mz_repr::adt::numeric::{self, DecimalLike, Numeric, NumericMaxScale}; use mz_repr::adt::range::{self, Range, RangeBound, RangeOps}; use mz_repr::adt::regex::{any_regex, Regex}; +use mz_repr::adt::system::Oid; use mz_repr::adt::timestamp::{CheckedTimestamp, TimestampLike}; use mz_repr::role_id::RoleId; use mz_repr::{strconv, ColumnName, ColumnType, Datum, DatumType, Row, RowArena, ScalarType}; -use mz_sql_pretty::pretty_str; +use mz_sql_parser::ast::display::FormatMode; +use mz_sql_pretty::{pretty_str, PrettyConfig}; use num::traits::CheckedNeg; use proptest::prelude::*; use proptest::strategy::*; @@ -73,7 +75,6 @@ pub(crate) mod format; pub(crate) mod impls; pub use impls::*; -use mz_repr::adt::system::Oid; /// The maximum size of a newly allocated string. Chosen to be the smallest number to keep our tests /// passing without changing. 100MiB is probably higher than what we want, but it's better than no @@ -2165,8 +2166,14 @@ fn pretty_sql<'a>( let width = width.unwrap_int32(); let width = usize::try_from(width).map_err(|_| EvalError::PrettyError("invalid width".into()))?; - let pretty = - pretty_str(sql, width).map_err(|e| EvalError::PrettyError(e.to_string().into()))?; + let pretty = pretty_str( + sql, + PrettyConfig { + width, + format_mode: FormatMode::Simple, + }, + ) + .map_err(|e| EvalError::PrettyError(e.to_string().into()))?; let pretty = temp_storage.push_string(pretty); Ok(Datum::String(pretty)) } diff --git a/src/lsp-server/src/backend.rs b/src/lsp-server/src/backend.rs index 81c406d008f66..4033ac5e9a5b8 100644 --- a/src/lsp-server/src/backend.rs +++ b/src/lsp-server/src/backend.rs @@ -20,8 +20,10 @@ use ::serde::Deserialize; use mz_ore::collections::HashMap; use mz_sql_lexer::keywords::Keyword; use mz_sql_lexer::lexer::{self, Token}; +use mz_sql_parser::ast::display::FormatMode; use mz_sql_parser::ast::{statement_kind_label_value, Raw, Statement}; use mz_sql_parser::parser::parse_statements; +use mz_sql_pretty::PrettyConfig; use regex::Regex; use ropey::Rope; use serde::Serialize; @@ -36,7 +38,7 @@ use crate::{PKG_NAME, PKG_VERSION}; /// Default formatting width to use in the [LanguageServer::formatting] implementation. pub const DEFAULT_FORMATTING_WIDTH: usize = 100; -/// This is a re-implemention of [mz_sql_parser::parser::StatementParseResult] +/// This is a re-implementation of [mz_sql_parser::parser::StatementParseResult] /// but replacing the sql code with a rope. #[derive(Debug)] pub struct ParseResult { @@ -483,7 +485,15 @@ impl LanguageServer for Backend { let pretty = parse_result .asts .iter() - .map(|ast| mz_sql_pretty::to_pretty(ast, *width)) + .map(|ast| { + mz_sql_pretty::to_pretty( + ast, + PrettyConfig { + width: *width, + format_mode: FormatMode::Simple, + }, + ) + }) .collect::>() .join("\n"); let rope = &parse_result.rope; diff --git a/src/sql-parser/src/ast/display.rs b/src/sql-parser/src/ast/display.rs index 78f2d515c1a55..3e4a7537a9c61 100644 --- a/src/sql-parser/src/ast/display.rs +++ b/src/sql-parser/src/ast/display.rs @@ -155,22 +155,20 @@ pub trait AstDisplay { W: fmt::Write; fn to_ast_string_simple(&self) -> String { - let mut buf = String::new(); - let mut f = AstFormatter::new(&mut buf, FormatMode::Simple); - self.fmt(&mut f); - buf + self.to_ast_string(FormatMode::Simple) } fn to_ast_string_stable(&self) -> String { - let mut buf = String::new(); - let mut f = AstFormatter::new(&mut buf, FormatMode::Stable); - self.fmt(&mut f); - buf + self.to_ast_string(FormatMode::Stable) } fn to_ast_string_redacted(&self) -> String { + self.to_ast_string(FormatMode::SimpleRedacted) + } + + fn to_ast_string(&self, format_mode: FormatMode) -> String { let mut buf = String::new(); - let mut f = AstFormatter::new(&mut buf, FormatMode::SimpleRedacted); + let mut f = AstFormatter::new(&mut buf, format_mode); self.fmt(&mut f); buf } diff --git a/src/sql-pretty/src/doc.rs b/src/sql-pretty/src/doc.rs index 439dad9b41a85..bc55dd58cc9b7 100644 --- a/src/sql-pretty/src/doc.rs +++ b/src/sql-pretty/src/doc.rs @@ -17,10 +17,14 @@ use crate::util::{ bracket, bracket_doc, comma_separate, comma_separated, intersperse_line_nest, nest, nest_comma_separate, nest_title, title_comma_separate, }; -use crate::TAB; +use crate::{PrettyConfig, TAB}; // Use when we don't know what to do. -pub(crate) fn doc_display<'a, T: AstDisplay>(v: &T, _debug: &str) -> RcDoc<'a, ()> { +pub(crate) fn doc_display<'a, T: AstDisplay>( + v: &T, + config: PrettyConfig, + _debug: &str, +) -> RcDoc<'a, ()> { #[cfg(test)] eprintln!( "UNKNOWN PRETTY TYPE in {}: {}, {}", @@ -28,15 +32,24 @@ pub(crate) fn doc_display<'a, T: AstDisplay>(v: &T, _debug: &str) -> RcDoc<'a, ( std::any::type_name::(), v.to_ast_string_simple() ); - doc_display_pass(v) + doc_display_pass(v, config) } // Use when the AstDisplay trait is what we want. -fn doc_display_pass<'a, T: AstDisplay>(v: &T) -> RcDoc<'a, ()> { - RcDoc::text(v.to_ast_string_simple()) +fn doc_display_pass<'a, T: AstDisplay>(v: &T, config: PrettyConfig) -> RcDoc<'a, ()> { + RcDoc::text(v.to_ast_string(config.format_mode)) } -pub(crate) fn doc_create_source(v: &CreateSourceStatement) -> RcDoc { +fn doc_display_pass_mapper( + config: PrettyConfig, +) -> impl for<'b> FnMut(&'b T) -> RcDoc<'b, ()> { + move |v| doc_display_pass(v, config) +} + +pub(crate) fn doc_create_source( + v: &CreateSourceStatement, + config: PrettyConfig, +) -> RcDoc { let mut docs = Vec::new(); let title = format!( "CREATE SOURCE{}", @@ -46,148 +59,151 @@ pub(crate) fn doc_create_source(v: &CreateSourceStatement) -> RcD "" } ); - let mut doc = doc_display_pass(&v.name); + let mut doc = doc_display_pass(&v.name, config); let mut names = Vec::new(); - names.extend(v.col_names.iter().map(doc_display_pass)); - names.extend(v.key_constraint.iter().map(doc_display_pass)); + names.extend(v.col_names.iter().map(doc_display_pass_mapper(config))); + names.extend(v.key_constraint.iter().map(doc_display_pass_mapper(config))); if !names.is_empty() { doc = nest(doc, bracket("(", comma_separated(names), ")")); } docs.push(nest_title(title, doc)); if let Some(cluster) = &v.in_cluster { - docs.push(nest_title("IN CLUSTER", doc_display_pass(cluster))); + docs.push(nest_title("IN CLUSTER", doc_display_pass(cluster, config))); } - docs.push(nest_title("FROM", doc_display_pass(&v.connection))); + docs.push(nest_title("FROM", doc_display_pass(&v.connection, config))); if let Some(format) = &v.format { - docs.push(doc_format_specifier(format)); + docs.push(doc_format_specifier(format, config)); } if !v.include_metadata.is_empty() { docs.push(nest_title( "INCLUDE", - comma_separate(doc_display_pass, &v.include_metadata), + comma_separate(doc_display_pass_mapper(config), &v.include_metadata), )); } if let Some(envelope) = &v.envelope { - docs.push(nest_title("ENVELOPE", doc_display_pass(envelope))); + docs.push(nest_title("ENVELOPE", doc_display_pass(envelope, config))); } if let Some(references) = &v.external_references { - docs.push(doc_external_references(references)); + docs.push(doc_external_references(references, config)); } if let Some(progress) = &v.progress_subsource { - docs.push(nest_title("EXPOSE PROGRESS AS", doc_display_pass(progress))); + docs.push(nest_title( + "EXPOSE PROGRESS AS", + doc_display_pass(progress, config), + )); } if !v.with_options.is_empty() { docs.push(bracket( "WITH (", - comma_separate(doc_display_pass, &v.with_options), + comma_separate(doc_display_pass_mapper(config), &v.with_options), ")", )); } RcDoc::intersperse(docs, Doc::line()).group() } -fn doc_format_specifier(v: &FormatSpecifier) -> RcDoc { +fn doc_format_specifier(v: &FormatSpecifier, config: PrettyConfig) -> RcDoc { match v { - FormatSpecifier::Bare(format) => nest_title("FORMAT", doc_display_pass(format)), + FormatSpecifier::Bare(format) => nest_title("FORMAT", doc_display_pass(format, config)), FormatSpecifier::KeyValue { key, value } => { let docs = vec![ - nest_title("KEY FORMAT", doc_display_pass(key)), - nest_title("VALUE FORMAT", doc_display_pass(value)), + nest_title("KEY FORMAT", doc_display_pass(key, config)), + nest_title("VALUE FORMAT", doc_display_pass(value, config)), ]; RcDoc::intersperse(docs, Doc::line()).group() } } } -fn doc_external_references(v: &ExternalReferences) -> RcDoc { +fn doc_external_references(v: &ExternalReferences, config: PrettyConfig) -> RcDoc { match v { ExternalReferences::SubsetTables(subsources) => bracket( "FOR TABLES (", - comma_separate(doc_display_pass, subsources), + comma_separate(doc_display_pass_mapper(config), subsources), ")", ), ExternalReferences::SubsetSchemas(schemas) => bracket( "FOR SCHEMAS (", - comma_separate(doc_display_pass, schemas), + comma_separate(doc_display_pass_mapper(config), schemas), ")", ), ExternalReferences::All => RcDoc::text("FOR ALL TABLES"), } } -pub(crate) fn doc_copy(v: &CopyStatement) -> RcDoc { +pub(crate) fn doc_copy(v: &CopyStatement, config: PrettyConfig) -> RcDoc { let relation = match &v.relation { CopyRelation::Named { name, columns } => { - let mut relation = doc_display_pass(name); + let mut relation = doc_display_pass(name, config); if !columns.is_empty() { relation = bracket_doc( nest(relation, RcDoc::text("(")), - comma_separate(doc_display_pass, columns), + comma_separate(doc_display_pass_mapper(config), columns), RcDoc::text(")"), RcDoc::line_(), ); } RcDoc::concat([RcDoc::text("COPY "), relation]) } - CopyRelation::Select(query) => bracket("COPY (", doc_select_statement(query), ")"), - CopyRelation::Subscribe(query) => bracket("COPY (", doc_subscribe(query), ")"), + CopyRelation::Select(query) => bracket("COPY (", doc_select_statement(query, config), ")"), + CopyRelation::Subscribe(query) => bracket("COPY (", doc_subscribe(query, config), ")"), }; let mut docs = vec![ relation, RcDoc::concat([ - doc_display_pass(&v.direction), + doc_display_pass(&v.direction, config), RcDoc::text(" "), - doc_display_pass(&v.target), + doc_display_pass(&v.target, config), ]), ]; if !v.options.is_empty() { docs.push(bracket( "WITH (", - comma_separate(doc_display_pass, &v.options), + comma_separate(doc_display_pass_mapper(config), &v.options), ")", )); } RcDoc::intersperse(docs, Doc::line()).group() } -pub(crate) fn doc_subscribe(v: &SubscribeStatement) -> RcDoc { +pub(crate) fn doc_subscribe(v: &SubscribeStatement, config: PrettyConfig) -> RcDoc { let doc = match &v.relation { - SubscribeRelation::Name(name) => nest_title("SUBSCRIBE", doc_display_pass(name)), - SubscribeRelation::Query(query) => bracket("SUBSCRIBE (", doc_query(query), ")"), + SubscribeRelation::Name(name) => nest_title("SUBSCRIBE", doc_display_pass(name, config)), + SubscribeRelation::Query(query) => bracket("SUBSCRIBE (", doc_query(query, config), ")"), }; let mut docs = vec![doc]; if !v.options.is_empty() { docs.push(bracket( "WITH (", - comma_separate(doc_display_pass, &v.options), + comma_separate(doc_display_pass_mapper(config), &v.options), ")", )); } if let Some(as_of) = &v.as_of { - docs.push(doc_as_of(as_of)); + docs.push(doc_as_of(as_of, config)); } if let Some(up_to) = &v.up_to { - docs.push(nest_title("UP TO", doc_expr(up_to))); + docs.push(nest_title("UP TO", doc_expr(up_to, config))); } match &v.output { SubscribeOutput::Diffs => {} SubscribeOutput::WithinTimestampOrderBy { order_by } => { docs.push(nest_title( "WITHIN TIMESTAMP ORDER BY ", - comma_separate(doc_order_by_expr, order_by), + comma_separate(doc_order_by_expr_mapper(config), order_by), )); } SubscribeOutput::EnvelopeUpsert { key_columns } => { docs.push(bracket( "ENVELOPE UPSERT (KEY (", - comma_separate(doc_display_pass, key_columns), + comma_separate(doc_display_pass_mapper(config), key_columns), "))", )); } SubscribeOutput::EnvelopeDebezium { key_columns } => { docs.push(bracket( "ENVELOPE DEBEZIUM (KEY (", - comma_separate(doc_display_pass, key_columns), + comma_separate(doc_display_pass_mapper(config), key_columns), "))", )); } @@ -195,15 +211,18 @@ pub(crate) fn doc_subscribe(v: &SubscribeStatement) -> RcDoc { RcDoc::intersperse(docs, Doc::line()).group() } -fn doc_as_of(v: &AsOf) -> RcDoc { +fn doc_as_of(v: &AsOf, config: PrettyConfig) -> RcDoc { let (title, expr) = match v { AsOf::At(expr) => ("AS OF", expr), AsOf::AtLeast(expr) => ("AS OF AT LEAST", expr), }; - nest_title(title, doc_expr(expr)) + nest_title(title, doc_expr(expr, config)) } -pub(crate) fn doc_create_view(v: &CreateViewStatement) -> RcDoc { +pub(crate) fn doc_create_view( + v: &CreateViewStatement, + config: PrettyConfig, +) -> RcDoc { let mut docs = vec![]; docs.push(RcDoc::text(format!( "CREATE{}{} VIEW{}", @@ -219,12 +238,13 @@ pub(crate) fn doc_create_view(v: &CreateViewStatement) -> RcDoc { "" }, ))); - docs.push(doc_view_definition(&v.definition)); + docs.push(doc_view_definition(&v.definition, config)); intersperse_line_nest(docs) } pub(crate) fn doc_create_materialized_view( v: &CreateMaterializedViewStatement, + config: PrettyConfig, ) -> RcDoc { let mut docs = vec![]; docs.push(RcDoc::text(format!( @@ -244,7 +264,7 @@ pub(crate) fn doc_create_materialized_view( if !v.columns.is_empty() { docs.push(bracket( "(", - comma_separate(doc_display_pass, &v.columns), + comma_separate(doc_display_pass_mapper(config), &v.columns), ")", )); } @@ -257,28 +277,28 @@ pub(crate) fn doc_create_materialized_view( if !v.with_options.is_empty() { docs.push(bracket( "WITH (", - comma_separate(doc_display_pass, &v.with_options), + comma_separate(doc_display_pass_mapper(config), &v.with_options), ")", )); } - docs.push(nest_title("AS", doc_query(&v.query))); + docs.push(nest_title("AS", doc_query(&v.query, config))); intersperse_line_nest(docs) } -fn doc_view_definition(v: &ViewDefinition) -> RcDoc { +fn doc_view_definition(v: &ViewDefinition, config: PrettyConfig) -> RcDoc { let mut docs = vec![RcDoc::text(v.name.to_string())]; if !v.columns.is_empty() { docs.push(bracket( "(", - comma_separate(doc_display_pass, &v.columns), + comma_separate(doc_display_pass_mapper(config), &v.columns), ")", )); } - docs.push(nest_title("AS", doc_query(&v.query))); + docs.push(nest_title("AS", doc_query(&v.query, config))); RcDoc::intersperse(docs, Doc::line()).group() } -pub(crate) fn doc_insert(v: &InsertStatement) -> RcDoc { +pub(crate) fn doc_insert(v: &InsertStatement, config: PrettyConfig) -> RcDoc { let mut first = vec![RcDoc::text(format!( "INSERT INTO {}", v.table_name.to_ast_string_simple() @@ -286,38 +306,44 @@ pub(crate) fn doc_insert(v: &InsertStatement) -> RcDoc { if !v.columns.is_empty() { first.push(bracket( "(", - comma_separate(doc_display_pass, &v.columns), + comma_separate(doc_display_pass_mapper(config), &v.columns), ")", )); } let sources = match &v.source { - InsertSource::Query(query) => doc_query(query), - _ => doc_display(&v.source, "insert source"), + InsertSource::Query(query) => doc_query(query, config), + _ => doc_display(&v.source, config, "insert source"), }; let mut doc = intersperse_line_nest([intersperse_line_nest(first), sources]); if !v.returning.is_empty() { doc = nest( doc, - nest_title("RETURNING", comma_separate(doc_select_item, &v.returning)), + nest_title( + "RETURNING", + comma_separate(doc_display_pass_mapper(config), &v.returning), + ), ) } doc } -pub(crate) fn doc_select_statement(v: &SelectStatement) -> RcDoc { - let mut doc = doc_query(&v.query); +pub(crate) fn doc_select_statement( + v: &SelectStatement, + config: PrettyConfig, +) -> RcDoc { + let mut doc = doc_query(&v.query, config); if let Some(as_of) = &v.as_of { - doc = intersperse_line_nest([doc, doc_as_of(as_of)]); + doc = intersperse_line_nest([doc, doc_as_of(as_of, config)]); } doc.group() } -fn doc_order_by(v: &[OrderByExpr]) -> RcDoc { - title_comma_separate("ORDER BY", doc_order_by_expr, v) +fn doc_order_by(v: &[OrderByExpr], config: PrettyConfig) -> RcDoc { + title_comma_separate("ORDER BY", doc_order_by_expr_mapper(config), v) } -fn doc_order_by_expr(v: &OrderByExpr) -> RcDoc { - let doc = doc_expr(&v.expr); +fn doc_order_by_expr(v: &OrderByExpr, config: PrettyConfig) -> RcDoc { + let doc = doc_expr(&v.expr, config); let doc = match v.asc { Some(true) => nest(doc, RcDoc::text("ASC")), Some(false) => nest(doc, RcDoc::text("DESC")), @@ -330,33 +356,48 @@ fn doc_order_by_expr(v: &OrderByExpr) -> RcDoc { } } -fn doc_query(v: &Query) -> RcDoc { +fn doc_order_by_expr_mapper( + config: PrettyConfig, +) -> impl for<'b> FnMut(&'b OrderByExpr) -> RcDoc<'b, ()> { + move |v| doc_order_by_expr(v, config) +} + +fn doc_query(v: &Query, config: PrettyConfig) -> RcDoc { let mut docs = vec![]; if !v.ctes.is_empty() { match &v.ctes { - CteBlock::Simple(ctes) => docs.push(title_comma_separate("WITH", doc_cte, ctes)), + CteBlock::Simple(ctes) => { + docs.push(title_comma_separate("WITH", doc_cte_mapper(config), ctes)) + } CteBlock::MutuallyRecursive(mutrec) => { let mut doc = RcDoc::text("WITH MUTUALLY RECURSIVE"); if !mutrec.options.is_empty() { doc = nest( doc, - bracket("(", comma_separate(doc_display_pass, &mutrec.options), ")"), + bracket( + "(", + comma_separate(doc_display_pass_mapper(config), &mutrec.options), + ")", + ), ); } docs.push(nest( doc, - comma_separate(doc_mutually_recursive, &mutrec.ctes), + comma_separate(doc_mutually_recursive_mapper(config), &mutrec.ctes), )); } } } - docs.push(doc_set_expr(&v.body)); + docs.push(doc_set_expr(&v.body, config)); if !v.order_by.is_empty() { - docs.push(doc_order_by(&v.order_by)); + docs.push(doc_order_by(&v.order_by, config)); } let offset = if let Some(offset) = &v.offset { - vec![RcDoc::concat([nest_title("OFFSET", doc_expr(offset))])] + vec![RcDoc::concat([nest_title( + "OFFSET", + doc_expr(offset, config), + )])] } else { vec![] }; @@ -366,11 +407,11 @@ fn doc_query(v: &Query) -> RcDoc { docs.extend(offset); docs.push(RcDoc::concat([ RcDoc::text("FETCH FIRST "), - doc_expr(&limit.quantity), + doc_expr(&limit.quantity, config), RcDoc::text(" ROWS WITH TIES"), ])); } else { - docs.push(nest_title("LIMIT", doc_expr(&limit.quantity))); + docs.push(nest_title("LIMIT", doc_expr(&limit.quantity, config))); docs.extend(offset); } } else { @@ -380,34 +421,46 @@ fn doc_query(v: &Query) -> RcDoc { RcDoc::intersperse(docs, Doc::line()).group() } -fn doc_cte(v: &Cte) -> RcDoc { +fn doc_cte(v: &Cte, config: PrettyConfig) -> RcDoc { RcDoc::concat([ RcDoc::text(format!("{} AS", v.alias)), RcDoc::line(), - bracket("(", doc_query(&v.query), ")"), + bracket("(", doc_query(&v.query, config), ")"), ]) } -fn doc_mutually_recursive(v: &CteMutRec) -> RcDoc { +fn doc_cte_mapper( + config: PrettyConfig, +) -> impl for<'b> FnMut(&'b Cte) -> RcDoc<'b, ()> { + move |v| doc_cte(v, config) +} + +fn doc_mutually_recursive(v: &CteMutRec, config: PrettyConfig) -> RcDoc { let mut docs = Vec::new(); if !v.columns.is_empty() { docs.push(bracket( "(", - comma_separate(doc_display_pass, &v.columns), + comma_separate(doc_display_pass_mapper(config), &v.columns), ")", )); } - docs.push(bracket("AS (", doc_query(&v.query), ")")); + docs.push(bracket("AS (", doc_query(&v.query, config), ")")); nest( - doc_display_pass(&v.name), + doc_display_pass(&v.name, config), RcDoc::intersperse(docs, Doc::line()).group(), ) } -fn doc_set_expr(v: &SetExpr) -> RcDoc { +fn doc_mutually_recursive_mapper( + config: PrettyConfig, +) -> impl for<'b> FnMut(&'b CteMutRec) -> RcDoc<'b, ()> { + move |v| doc_mutually_recursive(v, config) +} + +fn doc_set_expr(v: &SetExpr, config: PrettyConfig) -> RcDoc { match v { - SetExpr::Select(v) => doc_select(v), - SetExpr::Query(v) => bracket("(", doc_query(v), ")"), + SetExpr::Select(v) => doc_select(v, config), + SetExpr::Query(v) => bracket("(", doc_query(v, config), ")"), SetExpr::SetOperation { op, all, @@ -416,64 +469,78 @@ fn doc_set_expr(v: &SetExpr) -> RcDoc { } => { let all_str = if *all { " ALL" } else { "" }; RcDoc::concat([ - doc_set_expr(left), + doc_set_expr(left, config), RcDoc::line(), RcDoc::concat([ RcDoc::text(format!("{}{}", op, all_str)), RcDoc::line(), - doc_set_expr(right), + doc_set_expr(right, config), ]) .nest(TAB) .group(), ]) } - SetExpr::Values(v) => doc_values(v), - SetExpr::Show(v) => doc_display(v, "SHOW"), - SetExpr::Table(v) => nest(RcDoc::text("TABLE"), doc_display_pass(v)), + SetExpr::Values(v) => doc_values(v, config), + SetExpr::Show(v) => doc_display(v, config, "SHOW"), + SetExpr::Table(v) => nest(RcDoc::text("TABLE"), doc_display_pass(v, config)), } .group() } -fn doc_values(v: &Values) -> RcDoc { +fn doc_values(v: &Values, config: PrettyConfig) -> RcDoc { let rows = v.0.iter() - .map(|row| bracket("(", comma_separate(doc_expr, row), ")")); + .map(|row| bracket("(", comma_separate(doc_expr_mapper(config), row), ")")); RcDoc::concat([RcDoc::text("VALUES"), RcDoc::line(), comma_separated(rows)]) .nest(TAB) .group() } -fn doc_table_with_joins(v: &TableWithJoins) -> RcDoc { - let mut docs = vec![doc_table_factor(&v.relation)]; +fn doc_table_with_joins(v: &TableWithJoins, config: PrettyConfig) -> RcDoc { + let mut docs = vec![doc_table_factor(&v.relation, config)]; for j in &v.joins { - docs.push(doc_join(j)); + docs.push(doc_join(j, config)); } intersperse_line_nest(docs) } -fn doc_join(v: &Join) -> RcDoc { +fn doc_table_with_joins_mapper( + config: PrettyConfig, +) -> impl for<'b> FnMut(&'b TableWithJoins) -> RcDoc<'b, ()> { + move |v| doc_table_with_joins(v, config) +} + +fn doc_join(v: &Join, config: PrettyConfig) -> RcDoc { let (constraint, name) = match &v.join_operator { JoinOperator::Inner(constraint) => (constraint, "JOIN"), JoinOperator::FullOuter(constraint) => (constraint, "FULL JOIN"), JoinOperator::LeftOuter(constraint) => (constraint, "LEFT JOIN"), JoinOperator::RightOuter(constraint) => (constraint, "RIGHT JOIN"), - _ => return doc_display(v, "join operator"), + _ => return doc_display(v, config, "join operator"), }; let constraint = match constraint { - JoinConstraint::On(expr) => nest_title("ON", doc_expr(expr)), + JoinConstraint::On(expr) => nest_title("ON", doc_expr(expr, config)), JoinConstraint::Using { columns, alias } => { - let mut doc = bracket("USING(", comma_separate(doc_display_pass, columns), ")"); + let mut doc = bracket( + "USING(", + comma_separate(doc_display_pass_mapper(config), columns), + ")", + ); if let Some(alias) = alias { - doc = nest(doc, nest_title("AS", doc_display_pass(alias))); + doc = nest(doc, nest_title("AS", doc_display_pass(alias, config))); } doc } - _ => return doc_display(v, "join constrant"), + _ => return doc_display(v, config, "join constraint"), }; - intersperse_line_nest([RcDoc::text(name), doc_table_factor(&v.relation), constraint]) + intersperse_line_nest([ + RcDoc::text(name), + doc_table_factor(&v.relation, config), + constraint, + ]) } -fn doc_table_factor(v: &TableFactor) -> RcDoc { +fn doc_table_factor(v: &TableFactor, config: PrettyConfig) -> RcDoc { match v { TableFactor::Derived { lateral, @@ -481,97 +548,119 @@ fn doc_table_factor(v: &TableFactor) -> RcDoc { alias, } => { let prefix = if *lateral { "LATERAL (" } else { "(" }; - let mut docs = vec![bracket(prefix, doc_query(subquery), ")")]; + let mut docs = vec![bracket(prefix, doc_query(subquery, config), ")")]; if let Some(alias) = alias { docs.push(RcDoc::text(format!("AS {}", alias))); } intersperse_line_nest(docs) } TableFactor::NestedJoin { join, alias } => { - let mut doc = bracket("(", doc_table_with_joins(join), ")"); + let mut doc = bracket("(", doc_table_with_joins(join, config), ")"); if let Some(alias) = alias { doc = nest(doc, RcDoc::text(format!("AS {}", alias))); } doc } TableFactor::Table { name, alias } => { - let mut doc = doc_display_pass(name); + let mut doc = doc_display_pass(name, config); if let Some(alias) = alias { doc = nest(doc, RcDoc::text(format!("AS {}", alias))); } doc } - _ => doc_display(v, "table factor variant"), + _ => doc_display(v, config, "table factor variant"), } } -fn doc_distinct(v: &Distinct) -> RcDoc { +fn doc_distinct(v: &Distinct, config: PrettyConfig) -> RcDoc { match v { Distinct::EntireRow => RcDoc::text("DISTINCT"), - Distinct::On(cols) => bracket("DISTINCT ON (", comma_separate(doc_expr, cols), ")"), + Distinct::On(cols) => bracket( + "DISTINCT ON (", + comma_separate(doc_expr_mapper(config), cols), + ")", + ), } } -fn doc_select(v: &Select) -> RcDoc { +fn doc_select(v: &Select, config: PrettyConfig) -> RcDoc { let mut docs = vec![]; let mut select = RcDoc::text("SELECT"); if let Some(distinct) = &v.distinct { - select = nest(select, doc_distinct(distinct)); + select = nest(select, doc_distinct(distinct, config)); } - docs.push(nest_comma_separate(select, doc_select_item, &v.projection)); + docs.push(nest_comma_separate( + select, + doc_select_item_mapper(config), + &v.projection, + )); if !v.from.is_empty() { - docs.push(title_comma_separate("FROM", doc_table_with_joins, &v.from)); + docs.push(title_comma_separate( + "FROM", + doc_table_with_joins_mapper(config), + &v.from, + )); } if let Some(selection) = &v.selection { - docs.push(nest_title("WHERE", doc_expr(selection))); + docs.push(nest_title("WHERE", doc_expr(selection, config))); } if !v.group_by.is_empty() { - docs.push(title_comma_separate("GROUP BY", doc_expr, &v.group_by)); + docs.push(title_comma_separate( + "GROUP BY", + doc_expr_mapper(config), + &v.group_by, + )); } if let Some(having) = &v.having { - docs.push(nest_title("HAVING", doc_expr(having))); + docs.push(nest_title("HAVING", doc_expr(having, config))); } if let Some(qualify) = &v.qualify { - docs.push(nest_title("QUALIFY", doc_expr(qualify))); + docs.push(nest_title("QUALIFY", doc_expr(qualify, config))); } if !v.options.is_empty() { docs.push(bracket( "OPTIONS (", - comma_separate(doc_display_pass, &v.options), + comma_separate(doc_display_pass_mapper(config), &v.options), ")", )); } RcDoc::intersperse(docs, Doc::line()).group() } -fn doc_select_item(v: &SelectItem) -> RcDoc { +fn doc_select_item(v: &SelectItem, config: PrettyConfig) -> RcDoc { match v { SelectItem::Expr { expr, alias } => { - let mut doc = doc_expr(expr); + let mut doc = doc_expr(expr, config); if let Some(alias) = alias { doc = nest( doc, - RcDoc::concat([RcDoc::text("AS "), doc_display_pass(alias)]), + RcDoc::concat([RcDoc::text("AS "), doc_display_pass(alias, config)]), ); } doc } - SelectItem::Wildcard => doc_display_pass(v), + SelectItem::Wildcard => doc_display_pass(v, config), } } -pub fn doc_expr(v: &Expr) -> RcDoc { +fn doc_select_item_mapper( + config: PrettyConfig, +) -> impl for<'b> FnMut(&'b SelectItem) -> RcDoc<'b, ()> { + move |v| doc_select_item(v, config) +} + +pub fn doc_expr(v: &Expr, config: PrettyConfig) -> RcDoc { match v { Expr::Op { op, expr1, expr2 } => { if let Some(expr2) = expr2 { RcDoc::concat([ - doc_expr(expr1), + doc_expr(expr1, config), RcDoc::line(), RcDoc::text(format!("{} ", op)), - doc_expr(expr2).nest(TAB), + doc_expr(expr2, config).nest(TAB), ]) } else { - RcDoc::concat([RcDoc::text(format!("{} ", op)), doc_expr(expr1)]) + RcDoc::concat([RcDoc::text(format!("{} ", op)), doc_expr(expr1, config)]) } } Expr::Case { @@ -582,58 +671,60 @@ pub fn doc_expr(v: &Expr) -> RcDoc { } => { let mut docs = Vec::new(); if let Some(operand) = operand { - docs.push(doc_expr(operand)); + docs.push(doc_expr(operand, config)); } for (c, r) in conditions.iter().zip(results) { - let when = nest_title("WHEN", doc_expr(c)); - let then = nest_title("THEN", doc_expr(r)); + let when = nest_title("WHEN", doc_expr(c, config)); + let then = nest_title("THEN", doc_expr(r, config)); docs.push(nest(when, then)); } if let Some(else_result) = else_result { - docs.push(nest_title("ELSE", doc_expr(else_result))); + docs.push(nest_title("ELSE", doc_expr(else_result, config))); } let doc = intersperse_line_nest(docs); bracket_doc(RcDoc::text("CASE"), doc, RcDoc::text("END"), RcDoc::line()) } Expr::Cast { expr, data_type } => { - let doc = doc_expr(expr); + let doc = doc_expr(expr, config); RcDoc::concat([ doc, RcDoc::text(format!("::{}", data_type.to_ast_string_simple())), ]) } - Expr::Nested(ast) => bracket("(", doc_expr(ast), ")"), - Expr::Function(fun) => doc_function(fun), - Expr::Subquery(ast) => bracket("(", doc_query(ast), ")"), + Expr::Nested(ast) => bracket("(", doc_expr(ast, config), ")"), + Expr::Function(fun) => doc_function(fun, config), + Expr::Subquery(ast) => bracket("(", doc_query(ast, config), ")"), Expr::Identifier(_) | Expr::Value(_) | Expr::QualifiedWildcard(_) | Expr::WildcardAccess(_) - | Expr::FieldAccess { .. } => doc_display_pass(v), + | Expr::FieldAccess { .. } => doc_display_pass(v, config), Expr::And { left, right } => bracket_doc( - doc_expr(left), + doc_expr(left, config), RcDoc::text("AND"), - doc_expr(right), + doc_expr(right, config), RcDoc::line(), ), Expr::Or { left, right } => bracket_doc( - doc_expr(left), + doc_expr(left, config), RcDoc::text("OR"), - doc_expr(right), + doc_expr(right, config), RcDoc::line(), ), - Expr::Exists(s) => bracket("EXISTS (", doc_query(s), ")"), + Expr::Exists(s) => bracket("EXISTS (", doc_query(s, config), ")"), Expr::IsExpr { expr, negated, construct, } => bracket_doc( - doc_expr(expr), + doc_expr(expr, config), RcDoc::text(if *negated { "IS NOT" } else { "IS" }), - doc_display_pass(construct), + doc_display_pass(construct, config), RcDoc::line(), ), - Expr::Not { expr } => RcDoc::concat([RcDoc::text("NOT"), RcDoc::line(), doc_expr(expr)]), + Expr::Not { expr } => { + RcDoc::concat([RcDoc::text("NOT"), RcDoc::line(), doc_expr(expr, config)]) + } Expr::Between { expr, negated, @@ -641,10 +732,14 @@ pub fn doc_expr(v: &Expr) -> RcDoc { high, } => RcDoc::intersperse( [ - doc_expr(expr), + doc_expr(expr, config), RcDoc::text(if *negated { "NOT BETWEEN" } else { "BETWEEN" }), RcDoc::intersperse( - [doc_expr(low), RcDoc::text("AND"), doc_expr(high)], + [ + doc_expr(low, config), + RcDoc::text("AND"), + doc_expr(high, config), + ], RcDoc::line(), ) .group(), @@ -657,9 +752,9 @@ pub fn doc_expr(v: &Expr) -> RcDoc { negated, } => RcDoc::intersperse( [ - doc_expr(expr), + doc_expr(expr, config), RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }), - doc_query(subquery), + doc_query(subquery, config), RcDoc::text(")"), ], RcDoc::line(), @@ -670,41 +765,53 @@ pub fn doc_expr(v: &Expr) -> RcDoc { negated, } => RcDoc::intersperse( [ - doc_expr(expr), + doc_expr(expr, config), RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }), - comma_separate(doc_expr, list), + comma_separate(doc_expr_mapper(config), list), RcDoc::text(")"), ], RcDoc::line(), ), - Expr::Row { exprs } => bracket("ROW(", comma_separate(doc_expr, exprs), ")"), + Expr::Row { exprs } => bracket("ROW(", comma_separate(doc_expr_mapper(config), exprs), ")"), Expr::NullIf { l_expr, r_expr } => bracket( "NULLIF (", - comma_separate(doc_expr, [&**l_expr, &**r_expr]), + comma_separate(doc_expr_mapper(config), [&**l_expr, &**r_expr]), ")", ), - Expr::HomogenizingFunction { function, exprs } => { - bracket(format!("{function}("), comma_separate(doc_expr, exprs), ")") - } - Expr::ArraySubquery(s) => bracket("ARRAY(", doc_query(s), ")"), - Expr::ListSubquery(s) => bracket("LIST(", doc_query(s), ")"), - Expr::Array(exprs) => bracket("ARRAY[", comma_separate(doc_expr, exprs), "]"), - Expr::List(exprs) => bracket("LIST[", comma_separate(doc_expr, exprs), "]"), - _ => doc_display(v, "expr variant"), + Expr::HomogenizingFunction { function, exprs } => bracket( + format!("{function}("), + comma_separate(doc_expr_mapper(config), exprs), + ")", + ), + Expr::ArraySubquery(s) => bracket("ARRAY(", doc_query(s, config), ")"), + Expr::ListSubquery(s) => bracket("LIST(", doc_query(s, config), ")"), + Expr::Array(exprs) => bracket( + "ARRAY[", + comma_separate(doc_expr_mapper(config), exprs), + "]", + ), + Expr::List(exprs) => bracket("LIST[", comma_separate(doc_expr_mapper(config), exprs), "]"), + _ => doc_display(v, config, "expr variant"), } .group() } -fn doc_function(v: &Function) -> RcDoc { +fn doc_expr_mapper( + config: PrettyConfig, +) -> impl for<'b> FnMut(&'b Expr) -> RcDoc<'b, ()> { + move |v| doc_expr(v, config) +} + +fn doc_function(v: &Function, config: PrettyConfig) -> RcDoc { match &v.args { - FunctionArgs::Star => doc_display_pass(v), + FunctionArgs::Star => doc_display_pass(v, config), FunctionArgs::Args { args, order_by } => { if args.is_empty() { // Nullary, don't allow newline between parens, so just delegate. - return doc_display_pass(v); + return doc_display_pass(v, config); } if v.filter.is_some() || v.over.is_some() || !order_by.is_empty() { - return doc_display(v, "function filter or over or order by"); + return doc_display(v, config, "function filter or over or order by"); } let special = match v.name.to_ast_string_stable().as_str() { r#""extract""# if v.args.len() == Some(2) => true, @@ -712,14 +819,14 @@ fn doc_function(v: &Function) -> RcDoc { _ => false, }; if special { - return doc_display(v, "special function"); + return doc_display(v, config, "special function"); } let name = format!( "{}({}", v.name.to_ast_string_simple(), if v.distinct { "DISTINCT " } else { "" } ); - bracket(name, comma_separate(doc_expr, args), ")") + bracket(name, comma_separate(doc_expr_mapper(config), args), ")") } } } diff --git a/src/sql-pretty/src/lib.rs b/src/sql-pretty/src/lib.rs index 60c9c298dcb34..1d3c00c88ac78 100644 --- a/src/sql-pretty/src/lib.rs +++ b/src/sql-pretty/src/lib.rs @@ -10,6 +10,7 @@ mod doc; mod util; +use mz_sql_parser::ast::display::FormatMode; use mz_sql_parser::ast::*; use mz_sql_parser::parser::{parse_statements, ParserStatementError}; use pretty::RcDoc; @@ -22,39 +23,69 @@ use crate::doc::{ pub use crate::doc::doc_expr; +pub const DEFAULT_WIDTH: usize = 100; + const TAB: isize = 4; -fn to_doc(v: &Statement) -> RcDoc { +fn to_doc(v: &Statement, config: PrettyConfig) -> RcDoc { match v { - Statement::Select(v) => doc_select_statement(v), - Statement::Insert(v) => doc_insert(v), - Statement::CreateView(v) => doc_create_view(v), - Statement::CreateMaterializedView(v) => doc_create_materialized_view(v), - Statement::Copy(v) => doc_copy(v), - Statement::Subscribe(v) => doc_subscribe(v), - Statement::CreateSource(v) => doc_create_source(v), - _ => doc_display(v, "statement"), + Statement::Select(v) => doc_select_statement(v, config), + Statement::Insert(v) => doc_insert(v, config), + Statement::CreateView(v) => doc_create_view(v, config), + Statement::CreateMaterializedView(v) => doc_create_materialized_view(v, config), + Statement::Copy(v) => doc_copy(v, config), + Statement::Subscribe(v) => doc_subscribe(v, config), + Statement::CreateSource(v) => doc_create_source(v, config), + _ => doc_display(v, config, "statement"), } } +#[derive(Clone, Copy)] +pub struct PrettyConfig { + pub width: usize, + pub format_mode: FormatMode, +} + /// Pretty prints a statement at a width. -pub fn to_pretty(stmt: &Statement, width: usize) -> String { - format!("{};", to_doc(stmt).pretty(width)) +pub fn to_pretty(stmt: &Statement, config: PrettyConfig) -> String { + format!("{};", to_doc(stmt, config).pretty(config.width)) } /// Parses `str` into SQL statements and pretty prints them. -pub fn pretty_strs(str: &str, width: usize) -> Result, Error> { +pub fn pretty_strs(str: &str, config: PrettyConfig) -> Result, Error> { let stmts = parse_statements(str)?; - Ok(stmts.iter().map(|s| to_pretty(&s.ast, width)).collect()) + Ok(stmts.iter().map(|s| to_pretty(&s.ast, config)).collect()) } /// Parses `str` into a single SQL statement and pretty prints it. -pub fn pretty_str(str: &str, width: usize) -> Result { +pub fn pretty_str(str: &str, config: PrettyConfig) -> Result { let stmts = parse_statements(str)?; if stmts.len() != 1 { return Err(Error::ExpectedOne); } - Ok(to_pretty(&stmts[0].ast, width)) + Ok(to_pretty(&stmts[0].ast, config)) +} + +/// Parses `str` into SQL statements and pretty prints them in `Simple` mode. +pub fn pretty_strs_simple(str: &str, width: usize) -> Result, Error> { + pretty_strs( + str, + PrettyConfig { + width, + format_mode: FormatMode::Simple, + }, + ) +} + +/// Parses `str` into a single SQL statement and pretty prints it in `Simple` mode. +pub fn pretty_str_simple(str: &str, width: usize) -> Result { + pretty_str( + str, + PrettyConfig { + width, + format_mode: FormatMode::Simple, + }, + ) } #[derive(Error, Debug)] diff --git a/src/sql-pretty/src/util.rs b/src/sql-pretty/src/util.rs index cda422fc9234b..a953c077d3627 100644 --- a/src/sql-pretty/src/util.rs +++ b/src/sql-pretty/src/util.rs @@ -33,7 +33,7 @@ where pub(crate) fn title_comma_separate<'a, F, T, S>(title: S, f: F, v: &'a [T]) -> RcDoc<'a, ()> where - F: Fn(&'a T) -> RcDoc<'a>, + F: FnMut(&'a T) -> RcDoc<'a>, S: Into, { let title = RcDoc::text(title.into()); @@ -50,7 +50,7 @@ pub(crate) fn nest_comma_separate<'a, F, T: 'a, I>( v: I, ) -> RcDoc<'a, ()> where - F: Fn(&'a T) -> RcDoc<'a>, + F: FnMut(&'a T) -> RcDoc<'a>, I: IntoIterator, { nest(title, comma_separate(f, v)) @@ -58,7 +58,7 @@ where pub(crate) fn comma_separate<'a, F, T: 'a, I>(f: F, v: I) -> RcDoc<'a, ()> where - F: Fn(&'a T) -> RcDoc<'a>, + F: FnMut(&'a T) -> RcDoc<'a>, I: IntoIterator, { let docs = v.into_iter().map(f); diff --git a/src/sql-pretty/tests/parser.rs b/src/sql-pretty/tests/parser.rs index 01ab8aef9d313..c08d04f3c9f0d 100644 --- a/src/sql-pretty/tests/parser.rs +++ b/src/sql-pretty/tests/parser.rs @@ -8,10 +8,10 @@ // by the Apache License, Version 2.0. use datadriven::walk; -use mz_sql_parser::ast::display::AstDisplay; +use mz_sql_parser::ast::display::{AstDisplay, FormatMode}; use mz_sql_parser::datadriven_testcase; use mz_sql_parser::parser::{parse_expr, parse_statements}; -use mz_sql_pretty::{doc_expr, to_pretty}; +use mz_sql_pretty::{doc_expr, to_pretty, PrettyConfig}; // Use the parser's datadriven tests to get a comprehensive set of SQL statements. Assert they all // generate identical ASTs when pretty printed. Output the same output as the parser so datadriven @@ -41,10 +41,30 @@ fn verify_pretty_expr(expr: &str) { }; for n in &[1, 40, 1000000] { let n = *n; - let pretty1 = format!("{}", doc_expr(&original).pretty(n)); + let pretty1 = format!( + "{}", + doc_expr( + &original, + PrettyConfig { + width: n, + format_mode: FormatMode::Simple + } + ) + .pretty(n) + ); let prettied = parse_expr(&pretty1) .unwrap_or_else(|_| panic!("could not parse: {pretty1}, original: {expr}")); - let pretty2 = format!("{}", doc_expr(&prettied).pretty(n)); + let pretty2 = format!( + "{}", + doc_expr( + &prettied, + PrettyConfig { + width: n, + format_mode: FormatMode::Simple + } + ) + .pretty(n) + ); assert_eq!(pretty1, pretty2); assert_eq!( original.to_ast_string_stable(), @@ -62,15 +82,27 @@ fn verify_pretty_statement(stmt: &str) { }, Err(_) => return, }; - for n in &[1, 40, 1000000] { - let n = *n; - let pretty1 = to_pretty(&original.ast, n); + for width in &[1, 40, 1000000] { + let width = *width; + let pretty1 = to_pretty( + &original.ast, + PrettyConfig { + width, + format_mode: FormatMode::Simple, + }, + ); let prettied = parse_statements(&pretty1) .unwrap_or_else(|_| panic!("could not parse: {pretty1}, original: {stmt}")) .into_iter() .next() .unwrap(); - let pretty2 = to_pretty(&prettied.ast, n); + let pretty2 = to_pretty( + &prettied.ast, + PrettyConfig { + width, + format_mode: FormatMode::Simple, + }, + ); assert_eq!(pretty1, pretty2); assert_eq!( original.ast.to_ast_string_stable(), diff --git a/src/sql/BUILD.bazel b/src/sql/BUILD.bazel index 7d64064acddd0..72c98898ad429 100644 --- a/src/sql/BUILD.bazel +++ b/src/sql/BUILD.bazel @@ -58,6 +58,7 @@ rust_library( "//src/secrets:mz_secrets", "//src/sql-lexer:mz_sql_lexer", "//src/sql-parser:mz_sql_parser", + "//src/sql-pretty:mz_sql_pretty", "//src/ssh-util:mz_ssh_util", "//src/storage-types:mz_storage_types", "//src/tracing:mz_tracing", @@ -121,6 +122,7 @@ rust_test( "//src/secrets:mz_secrets", "//src/sql-lexer:mz_sql_lexer", "//src/sql-parser:mz_sql_parser", + "//src/sql-pretty:mz_sql_pretty", "//src/ssh-util:mz_ssh_util", "//src/storage-types:mz_storage_types", "//src/tracing:mz_tracing", @@ -163,6 +165,7 @@ rust_doc_test( "//src/secrets:mz_secrets", "//src/sql-lexer:mz_sql_lexer", "//src/sql-parser:mz_sql_parser", + "//src/sql-pretty:mz_sql_pretty", "//src/ssh-util:mz_ssh_util", "//src/storage-types:mz_storage_types", "//src/tracing:mz_tracing", diff --git a/src/sql/Cargo.toml b/src/sql/Cargo.toml index 6279e14e34dbf..2ecc58c6d136e 100644 --- a/src/sql/Cargo.toml +++ b/src/sql/Cargo.toml @@ -58,6 +58,7 @@ mz-repr = { path = "../repr", features = ["tracing"] } mz-rocksdb-types = { path = "../rocksdb-types" } mz-secrets = { path = "../secrets" } mz-sql-parser = { path = "../sql-parser" } +mz-sql-pretty = { path = "../sql-pretty" } mz-sql-lexer = { path = "../sql-lexer" } mz-ssh-util = { path = "../ssh-util" } mz-storage-types = { path = "../storage-types" } diff --git a/src/sql/src/func.rs b/src/sql/src/func.rs index f3c78d0c8ff99..401e97652e275 100644 --- a/src/sql/src/func.rs +++ b/src/sql/src/func.rs @@ -3838,7 +3838,7 @@ pub static MZ_CATALOG_BUILTINS: LazyLock> = LazyLoc "pretty_sql" => Scalar { params!(String, Int32) => BinaryFunc::PrettySql => String, oid::FUNC_PRETTY_SQL; params!(String) => Operation::unary(|_ecx, s| { - let width = HirScalarExpr::literal(Datum::Int32(100), ScalarType::Int32); + let width = HirScalarExpr::literal(Datum::Int32(mz_sql_pretty::DEFAULT_WIDTH.try_into().expect("must fit")), ScalarType::Int32); Ok(s.call_binary(width, BinaryFunc::PrettySql)) }) => String, oid::FUNC_PRETTY_SQL_NOWIDTH; }, diff --git a/src/sql/src/plan/statement/show.rs b/src/sql/src/plan/statement/show.rs index 00dce3f717113..10420aa3146b5 100644 --- a/src/sql/src/plan/statement/show.rs +++ b/src/sql/src/plan/statement/show.rs @@ -19,12 +19,13 @@ use std::fmt::Write; use mz_ore::assert_none; use mz_ore::collections::CollectionExt; use mz_repr::{CatalogItemId, Datum, RelationDesc, Row, ScalarType}; -use mz_sql_parser::ast::display::AstDisplay; +use mz_sql_parser::ast::display::{AstDisplay, FormatMode}; use mz_sql_parser::ast::{ CreateSubsourceOptionName, ExternalReferenceExport, ExternalReferences, ObjectType, ShowCreateClusterStatement, ShowCreateConnectionStatement, ShowCreateMaterializedViewStatement, ShowObjectType, SystemObjectType, UnresolvedItemName, WithOptionValue, }; +use mz_sql_pretty::PrettyConfig; use query::QueryContext; use crate::ast::visit_mut::VisitMut; @@ -1182,9 +1183,15 @@ fn humanize_sql_for_show_create( _ => (), } - if redacted { - Ok(resolved.to_ast_string_redacted()) - } else { - Ok(resolved.to_ast_string_stable()) - } + Ok(mz_sql_pretty::to_pretty( + &resolved, + PrettyConfig { + width: mz_sql_pretty::DEFAULT_WIDTH, + format_mode: if redacted { + FormatMode::SimpleRedacted + } else { + FormatMode::Simple + }, + }, + )) } diff --git a/test/legacy-upgrade/check-from-v0.111.0-kafka-sink.td b/test/legacy-upgrade/check-from-v0.111.0-kafka-sink.td index f045d83ab47af..6035ddc849ffc 100644 --- a/test/legacy-upgrade/check-from-v0.111.0-kafka-sink.td +++ b/test/legacy-upgrade/check-from-v0.111.0-kafka-sink.td @@ -7,17 +7,14 @@ # the Business Source License, use of this software will be governed # by the Apache License, Version 2.0. -$ set-from-sql var=expected-compression-implicit-create-sql -SELECT sql FROM expected_compression_implicit_create_sql - > SHOW CREATE SINK compression_implicit; -"materialize.public.compression_implicit" ${expected-compression-implicit-create-sql} +materialize.public.compression_implicit "CREATE SINK materialize.public.compression_implicit IN CLUSTER quickstart FROM materialize.public.kafka_sink_from INTO KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'kafka-sink') FORMAT JSON ENVELOPE DEBEZIUM;" > SHOW CREATE SINK compression_none_explicit; -"materialize.public.compression_none_explicit" "CREATE SINK \"materialize\".\"public\".\"compression_none_explicit\" IN CLUSTER \"quickstart\" FROM \"materialize\".\"public\".\"kafka_sink_from\" INTO KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'kafka-sink', COMPRESSION TYPE = 'none') FORMAT JSON ENVELOPE DEBEZIUM" +"materialize.public.compression_none_explicit" "CREATE SINK materialize.public.compression_none_explicit IN CLUSTER quickstart FROM materialize.public.kafka_sink_from INTO KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'kafka-sink', COMPRESSION TYPE = 'none') FORMAT JSON ENVELOPE DEBEZIUM;" > SHOW CREATE SINK compression_lz4_explicit; -"materialize.public.compression_lz4_explicit" "CREATE SINK \"materialize\".\"public\".\"compression_lz4_explicit\" IN CLUSTER \"quickstart\" FROM \"materialize\".\"public\".\"kafka_sink_from\" INTO KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'kafka-sink', COMPRESSION TYPE = 'lz4') FORMAT JSON ENVELOPE DEBEZIUM" +"materialize.public.compression_lz4_explicit" "CREATE SINK materialize.public.compression_lz4_explicit IN CLUSTER quickstart FROM materialize.public.kafka_sink_from INTO KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'kafka-sink', COMPRESSION TYPE = 'lz4') FORMAT JSON ENVELOPE DEBEZIUM;" > SHOW CREATE SINK compression_gzip_explicit; -"materialize.public.compression_gzip_explicit" "CREATE SINK \"materialize\".\"public\".\"compression_gzip_explicit\" IN CLUSTER \"quickstart\" FROM \"materialize\".\"public\".\"kafka_sink_from\" INTO KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'kafka-sink', COMPRESSION TYPE = 'gzip') FORMAT JSON ENVELOPE DEBEZIUM" +"materialize.public.compression_gzip_explicit" "CREATE SINK materialize.public.compression_gzip_explicit IN CLUSTER quickstart FROM materialize.public.kafka_sink_from INTO KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'kafka-sink', COMPRESSION TYPE = 'gzip') FORMAT JSON ENVELOPE DEBEZIUM;" diff --git a/test/legacy-upgrade/check-from-v0.131.0-alter-table.td b/test/legacy-upgrade/check-from-v0.131.0-alter-table.td index 5995ffebe3f81..64a40ebbef346 100644 --- a/test/legacy-upgrade/check-from-v0.131.0-alter-table.td +++ b/test/legacy-upgrade/check-from-v0.131.0-alter-table.td @@ -8,7 +8,7 @@ # by the Apache License, Version 2.0. > SHOW CREATE TABLE alter_table_t1; -"materialize.public.alter_table_t1" "CREATE TABLE \"materialize\".\"public\".\"alter_table_t1\" (\"a\" \"pg_catalog\".\"int4\", \"b\" \"pg_catalog\".\"text\" VERSION ADDED 1, \"c\" \"pg_catalog\".\"int8\" VERSION ADDED 2)" +materialize.public.alter_table_t1 "CREATE TABLE materialize.public.alter_table_t1 (a pg_catalog.int4, b pg_catalog.text VERSION ADDED 1, c pg_catalog.int8 VERSION ADDED 2);" > SELECT * FROM alter_table_t1 ORDER BY a DESC; diff --git a/test/legacy-upgrade/check-from-v0.27.0-json.td b/test/legacy-upgrade/check-from-v0.27.0-json.td index 39f48fbe9b1ff..6f5157bb9d4fe 100644 --- a/test/legacy-upgrade/check-from-v0.27.0-json.td +++ b/test/legacy-upgrade/check-from-v0.27.0-json.td @@ -8,4 +8,4 @@ # by the Apache License, Version 2.0. > SHOW CREATE MATERIALIZED VIEW json_view; -"materialize.public.json_view" "CREATE MATERIALIZED VIEW \"materialize\".\"public\".\"json_view\" IN CLUSTER \"json_compute_cluster\" WITH (REFRESH = ON COMMIT) AS SELECT \"a\" -> 1 AS \"c1\", \"a\" ->> 'b' AS \"c2\", \"a\" #> '{b,1}' AS \"c3\", \"a\" #>> '{b, 1}' AS \"c4\", \"a\" - 'b' AS \"c5\", \"a\" @> '{b, 1}' AS \"c6\", \"a\" <@ '{b, 1}'::\"pg_catalog\".\"jsonb\" AS \"c7\", \"a\" ? 'b' AS \"c8\" FROM \"materialize\".\"public\".\"json_table\"" +materialize.public.json_view "CREATE MATERIALIZED VIEW materialize.public.json_view\n IN CLUSTER json_compute_cluster\n WITH (REFRESH = ON COMMIT)\n AS\n SELECT\n a -> 1 AS c1,\n a ->> 'b' AS c2,\n a #> '{b,1}' AS c3,\n a #>> '{b, 1}' AS c4,\n a - 'b' AS c5,\n a @> '{b, 1}' AS c6,\n a <@ '{b, 1}'::pg_catalog.jsonb AS c7,\n a ? 'b' AS c8\n FROM materialize.public.json_table;" diff --git a/test/legacy-upgrade/check-from-v0.27.0-special-functions.td b/test/legacy-upgrade/check-from-v0.27.0-special-functions.td index 556d2b52def10..b48de1ec91f52 100644 --- a/test/legacy-upgrade/check-from-v0.27.0-special-functions.td +++ b/test/legacy-upgrade/check-from-v0.27.0-special-functions.td @@ -14,4 +14,4 @@ # > SHOW CREATE MATERIALIZED VIEW special_functions_view; -"materialize.public.special_functions_view" "CREATE MATERIALIZED VIEW \"materialize\".\"public\".\"special_functions_view\" IN CLUSTER \"${arg.created-cluster}\" WITH (REFRESH = ON COMMIT) AS SELECT * FROM \"materialize\".\"public\".\"special_functions\" WHERE \"mz_catalog\".\"mz_now\"() > \"f1\"" +materialize.public.special_functions_view "CREATE MATERIALIZED VIEW materialize.public.special_functions_view\n IN CLUSTER ${arg.created-cluster}\n WITH (REFRESH = ON COMMIT)\n AS SELECT * FROM materialize.public.special_functions WHERE mz_catalog.mz_now() > f1;" diff --git a/test/legacy-upgrade/check-from-v0.27.0-subquery.td b/test/legacy-upgrade/check-from-v0.27.0-subquery.td index d823f85f422c6..b7280e2eb6413 100644 --- a/test/legacy-upgrade/check-from-v0.27.0-subquery.td +++ b/test/legacy-upgrade/check-from-v0.27.0-subquery.td @@ -11,4 +11,4 @@ # CREATE a view containing subqueries/derived tables of various types > SHOW CREATE MATERIALIZED VIEW subquery_view; -"materialize.public.subquery_view" "CREATE MATERIALIZED VIEW \"materialize\".\"public\".\"subquery_view\" IN CLUSTER \"${arg.created-cluster}\" WITH (REFRESH = ON COMMIT) AS SELECT (SELECT 1) FROM (SELECT 2) AS \"derived\" WHERE 2 NOT IN (SELECT 3) AND NOT EXISTS (SELECT 4) AND 5 >= ALL (SELECT 6) AND 7 < ANY (SELECT 8)" +materialize.public.subquery_view "CREATE MATERIALIZED VIEW materialize.public.subquery_view\n IN CLUSTER quickstart\n WITH (REFRESH = ON COMMIT)\n AS\n SELECT (SELECT 1)\n FROM (SELECT 2) AS derived\n WHERE\n 2 NOT IN ( SELECT 3 ) AND NOT EXISTS (SELECT 4) AND 5 >= ALL (SELECT 6)\n AND\n 7 < ANY (SELECT 8);" diff --git a/test/legacy-upgrade/create-in-v0.111.0-kafka-sink.td b/test/legacy-upgrade/create-in-v0.111.0-kafka-sink.td index 0338642652c15..63f0b8a02bd53 100644 --- a/test/legacy-upgrade/create-in-v0.111.0-kafka-sink.td +++ b/test/legacy-upgrade/create-in-v0.111.0-kafka-sink.td @@ -19,12 +19,6 @@ FORMAT JSON ENVELOPE DEBEZIUM -> CREATE TABLE expected_compression_implicit_create_sql (sql text) ->[version<11200] INSERT INTO expected_compression_implicit_create_sql - VALUES ('CREATE SINK "materialize"."public"."compression_implicit" IN CLUSTER "quickstart" FROM "materialize"."public"."kafka_sink_from" INTO KAFKA CONNECTION "materialize"."public"."kafka_conn" (TOPIC = ''kafka-sink'', COMPRESSION TYPE = ''none'') FORMAT JSON ENVELOPE DEBEZIUM') ->[version>=11200] INSERT INTO expected_compression_implicit_create_sql - VALUES ('CREATE SINK "materialize"."public"."compression_implicit" IN CLUSTER "quickstart" FROM "materialize"."public"."kafka_sink_from" INTO KAFKA CONNECTION "materialize"."public"."kafka_conn" (TOPIC = ''kafka-sink'') FORMAT JSON ENVELOPE DEBEZIUM') - > CREATE SINK compression_none_explicit FROM kafka_sink_from INTO KAFKA CONNECTION kafka_conn (TOPIC 'kafka-sink', COMPRESSION TYPE = 'none') FORMAT JSON diff --git a/test/mysql-cdc-old-syntax/10-create-connection.td b/test/mysql-cdc-old-syntax/10-create-connection.td index 9d5df44cc435a..893ae670bbd78 100644 --- a/test/mysql-cdc-old-syntax/10-create-connection.td +++ b/test/mysql-cdc-old-syntax/10-create-connection.td @@ -44,7 +44,7 @@ mysq mysql > SHOW CREATE CONNECTION mysq name create_sql --------------------------------- -materialize.public.mysq "CREATE CONNECTION \"materialize\".\"public\".\"mysq\" TO MYSQL (HOST = \"mysql\", PASSWORD = SECRET \"materialize\".\"public\".\"mysqlpass\", USER = \"root\")" +materialize.public.mysq "CREATE CONNECTION materialize.public.mysq TO MYSQL (HOST = mysql, PASSWORD = SECRET materialize.public.mysqlpass, USER = root);" # # Error checking diff --git a/test/mysql-cdc-old-syntax/30-text-columns.td b/test/mysql-cdc-old-syntax/30-text-columns.td index ba4cdf823806c..b40947e2b2332 100644 --- a/test/mysql-cdc-old-syntax/30-text-columns.td +++ b/test/mysql-cdc-old-syntax/30-text-columns.td @@ -89,7 +89,7 @@ INSERT INTO t1 SELECT * FROM t1; "0000-00-00 00:00:00.0000" > SHOW CREATE SOURCE t1; -materialize.public.t1 "CREATE SUBSOURCE \"materialize\".\"public\".\"t1\" (\"f1\" \"pg_catalog\".\"text\", \"f2\" \"pg_catalog\".\"text\", \"f3\" \"pg_catalog\".\"text\", \"f4\" \"pg_catalog\".\"text\", \"f5\" \"pg_catalog\".\"text\", \"f6\" \"pg_catalog\".\"text\", \"f7\" \"pg_catalog\".\"text\", \"f8\" \"pg_catalog\".\"text\", \"f9\" \"pg_catalog\".\"text\") OF SOURCE \"materialize\".\"public\".\"da\" WITH (EXTERNAL REFERENCE = \"public\".\"t1\", TEXT COLUMNS = (\"f1\", \"f2\", \"f3\", \"f4\", \"f5\", \"f6\", \"f7\", \"f8\", \"f9\"))" +materialize.public.t1 "CREATE SUBSOURCE materialize.public.t1 (f1 pg_catalog.text, f2 pg_catalog.text, f3 pg_catalog.text, f4 pg_catalog.text, f5 pg_catalog.text, f6 pg_catalog.text, f7 pg_catalog.text, f8 pg_catalog.text, f9 pg_catalog.text) OF SOURCE materialize.public.da WITH (EXTERNAL REFERENCE = public.t1, TEXT COLUMNS = (f1, f2, f3, f4, f5, f6, f7, f8, f9));" > DROP SOURCE da CASCADE; diff --git a/test/mysql-cdc-old-syntax/35-exclude-columns.td b/test/mysql-cdc-old-syntax/35-exclude-columns.td index 6f13bfb961127..39f7ea4e6e225 100644 --- a/test/mysql-cdc-old-syntax/35-exclude-columns.td +++ b/test/mysql-cdc-old-syntax/35-exclude-columns.td @@ -62,7 +62,7 @@ INSERT INTO t1 SELECT * FROM t1; "test" > SHOW CREATE SOURCE t1; -materialize.public.t1 "CREATE SUBSOURCE \"materialize\".\"public\".\"t1\" (\"f1\" \"pg_catalog\".\"int4\", \"f4\" \"pg_catalog\".\"varchar\"(64)) OF SOURCE \"materialize\".\"public\".\"da\" WITH (EXTERNAL REFERENCE = \"public\".\"t1\", EXCLUDE COLUMNS = (\"f2\", \"f3\"))" +materialize.public.t1 "CREATE SUBSOURCE materialize.public.t1 (f1 pg_catalog.int4, f4 pg_catalog.varchar(64)) OF SOURCE materialize.public.da WITH (EXTERNAL REFERENCE = public.t1, EXCLUDE COLUMNS = (f2, f3));" ! SELECT f2 FROM t1; contains:column "f2" does not exist diff --git a/test/mysql-cdc-old-syntax/alter-source.td b/test/mysql-cdc-old-syntax/alter-source.td index 56e2d2d2dc294..b189e59ac6731 100644 --- a/test/mysql-cdc-old-syntax/alter-source.td +++ b/test/mysql-cdc-old-syntax/alter-source.td @@ -112,12 +112,8 @@ table_e subsource table_f subsource table_g subsource -# Show all tablestodo this should be splittable -> SELECT regexp_match(create_sql, 'FOR TABLES \((.+?)\) EXPOSE')[1] FROM (SHOW CREATE SOURCE mz_source); -"\"public\".\"table_a\" AS \"materialize\".\"public\".\"table_a\", \"public\".\"table_b\" AS \"materialize\".\"public\".\"table_b\", \"public\".\"table_c\" AS \"materialize\".\"public\".\"table_c\", \"public\".\"table_d\" AS \"materialize\".\"public\".\"table_d\", \"public\".\"table_e\" AS \"materialize\".\"public\".\"table_e\", \"public\".\"table_f\" AS \"materialize\".\"public\".\"table_f\", \"public\".\"table_g\" AS \"materialize\".\"public\".\"table_g\"" - > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); -"\"public\".\"table_f\".\"f2\"" +public.table_f.f2 # # Error checking @@ -346,7 +342,7 @@ contains: invalid TEXT COLUMNS option value: unexpected multiple references to p "\"public\".\"table_f\".\"f2\"" > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_f); -"\"f2\"" +f2 # Drop a table, which shuffles the tables' output indexes, then add a table and ensure it can be added. $ mysql-execute name=mysql @@ -363,7 +359,7 @@ INSERT INTO table_f VALUES (3, 'var1'); "\"public\".\"table_f\".\"f2\", \"public\".\"table_i\".\"f2\"" > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); -"\"f2\"" +f2 > SELECT * FROM table_f 1 var0 @@ -419,7 +415,7 @@ contains: invalid EXCLUDE COLUMNS option value: unexpected multiple references t "\"public\".\"table_f\".\"f2\", \"public\".\"table_i\".\"f2\"" > SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); -"\"f2\"" +f2 > SELECT * FROM table_i 1 diff --git a/test/mysql-cdc/10-create-connection.td b/test/mysql-cdc/10-create-connection.td index 9d5df44cc435a..893ae670bbd78 100644 --- a/test/mysql-cdc/10-create-connection.td +++ b/test/mysql-cdc/10-create-connection.td @@ -44,7 +44,7 @@ mysq mysql > SHOW CREATE CONNECTION mysq name create_sql --------------------------------- -materialize.public.mysq "CREATE CONNECTION \"materialize\".\"public\".\"mysq\" TO MYSQL (HOST = \"mysql\", PASSWORD = SECRET \"materialize\".\"public\".\"mysqlpass\", USER = \"root\")" +materialize.public.mysq "CREATE CONNECTION materialize.public.mysq TO MYSQL (HOST = mysql, PASSWORD = SECRET materialize.public.mysqlpass, USER = root);" # # Error checking diff --git a/test/mysql-cdc/30-text-columns.td b/test/mysql-cdc/30-text-columns.td index 4deed2444dde6..d6c617535e138 100644 --- a/test/mysql-cdc/30-text-columns.td +++ b/test/mysql-cdc/30-text-columns.td @@ -90,7 +90,7 @@ INSERT INTO t1 SELECT * FROM t1; $ set-regex match="DETAILS = '[a-f0-9]+'" replacement=
> SHOW CREATE TABLE t1; -materialize.public.t1 "CREATE TABLE \"materialize\".\"public\".\"t1\" (\"f1\" \"pg_catalog\".\"text\", \"f2\" \"pg_catalog\".\"text\", \"f3\" \"pg_catalog\".\"text\", \"f4\" \"pg_catalog\".\"text\", \"f5\" \"pg_catalog\".\"text\", \"f6\" \"pg_catalog\".\"text\", \"f7\" \"pg_catalog\".\"text\", \"f8\" \"pg_catalog\".\"text\", \"f9\" \"pg_catalog\".\"text\") FROM SOURCE \"materialize\".\"public\".\"da\" (REFERENCE = \"public\".\"t1\") WITH (TEXT COLUMNS = (\"f1\", \"f2\", \"f3\", \"f4\", \"f5\", \"f6\", \"f7\", \"f8\", \"f9\"),
)" +materialize.public.t1 "CREATE TABLE materialize.public.t1 (f1 pg_catalog.text, f2 pg_catalog.text, f3 pg_catalog.text, f4 pg_catalog.text, f5 pg_catalog.text, f6 pg_catalog.text, f7 pg_catalog.text, f8 pg_catalog.text, f9 pg_catalog.text) FROM SOURCE materialize.public.da (REFERENCE = public.t1) WITH (TEXT COLUMNS = (f1, f2, f3, f4, f5, f6, f7, f8, f9),
);" > DROP SOURCE da CASCADE; diff --git a/test/mysql-cdc/35-exclude-columns.td b/test/mysql-cdc/35-exclude-columns.td index 1e235f0a11626..7fd8f247ee4c8 100644 --- a/test/mysql-cdc/35-exclude-columns.td +++ b/test/mysql-cdc/35-exclude-columns.td @@ -56,7 +56,7 @@ INSERT INTO t1 SELECT * FROM t1; $ set-regex match="DETAILS = '[a-f0-9]+'" replacement=
> SHOW CREATE TABLE t1; -materialize.public.t1 "CREATE TABLE \"materialize\".\"public\".\"t1\" (\"f1\" \"pg_catalog\".\"int4\", \"f4\" \"pg_catalog\".\"varchar\"(64)) FROM SOURCE \"materialize\".\"public\".\"da\" (REFERENCE = \"public\".\"t1\") WITH (EXCLUDE COLUMNS = (\"f2\", \"f3\"),
)" +materialize.public.t1 "CREATE TABLE materialize.public.t1 (f1 pg_catalog.int4, f4 pg_catalog.varchar(64)) FROM SOURCE materialize.public.da (REFERENCE = public.t1) WITH (EXCLUDE COLUMNS = (f2, f3),
);" ! SELECT f2 FROM t1; contains:column "f2" does not exist diff --git a/test/mysql-cdc/alter-source.td b/test/mysql-cdc/alter-source.td index 076a70f565833..fac2ab4583749 100644 --- a/test/mysql-cdc/alter-source.td +++ b/test/mysql-cdc/alter-source.td @@ -117,10 +117,10 @@ table_g "" $ set-regex match="DETAILS = '[a-f0-9]+'" replacement=
> SHOW CREATE SOURCE mz_source; -materialize.public.mz_source "CREATE SOURCE \"materialize\".\"public\".\"mz_source\" IN CLUSTER \"quickstart\" FROM MYSQL CONNECTION \"materialize\".\"public\".\"mysql_conn\" EXPOSE PROGRESS AS \"materialize\".\"public\".\"mz_source_progress\"" +materialize.public.mz_source "CREATE SOURCE materialize.public.mz_source\nIN CLUSTER quickstart\nFROM MYSQL CONNECTION materialize.public.mysql_conn\nEXPOSE PROGRESS AS materialize.public.mz_source_progress;" > SHOW CREATE TABLE table_a; -materialize.public.table_a "CREATE TABLE \"materialize\".\"public\".\"table_a\" (\"pk\" \"pg_catalog\".\"int4\" NOT NULL, \"f2\" \"pg_catalog\".\"text\", CONSTRAINT \"PRIMARY\" PRIMARY KEY (\"pk\")) FROM SOURCE \"materialize\".\"public\".\"mz_source\" (REFERENCE = \"public\".\"table_a\") WITH (
)" +materialize.public.table_a "CREATE TABLE materialize.public.table_a (pk pg_catalog.int4 NOT NULL, f2 pg_catalog.text, CONSTRAINT \"PRIMARY\" PRIMARY KEY (pk)) FROM SOURCE materialize.public.mz_source (REFERENCE = public.table_a) WITH (
);" # # Error checking @@ -338,7 +338,7 @@ contains: invalid TEXT COLUMNS option value: unexpected multiple references to p 2 var1 > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE table_f); -"\"f2\"" +f2 # Drop a table, which shuffles the tables' output indexes, then add a table and ensure it can be added. $ mysql-execute name=mysql @@ -352,7 +352,7 @@ INSERT INTO table_f VALUES (3, 'var1'); > CREATE TABLE table_i FROM SOURCE mz_source (REFERENCE public.table_i) WITH (TEXT COLUMNS [f2]); > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE table_i); -"\"f2\"" +f2 > SELECT * FROM table_f 1 var0 @@ -376,7 +376,7 @@ contains:TEXT COLUMNS refers to table not currently being added > CREATE TABLE t_f FROM SOURCE mz_source_wo_init_text_cols (REFERENCE public.table_f) WITH (TEXT COLUMNS [f2]); > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE t_f); -"\"f2\"" +f2 # @@ -395,7 +395,7 @@ contains: invalid EXCLUDE COLUMNS option value: unexpected multiple references t > CREATE TABLE table_i FROM SOURCE mz_source (REFERENCE public.table_i) WITH (EXCLUDE COLUMNS [f2]); > SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE table_i); -"\"f2\"" +f2 > SELECT * FROM table_i 1 @@ -421,7 +421,7 @@ contains:EXCLUDE COLUMNS refers to table not currently being added > CREATE TABLE t_f2 FROM SOURCE mz_source_wo_init_exclude_cols (REFERENCE public.table_f) WITH (EXCLUDE COLUMNS [f2]); > SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE t_f2); -"\"f2\"" +f2 # Add a table after having created the source $ mysql-execute name=mysql diff --git a/test/mysql-cdc/create-alter-iam-connection.td b/test/mysql-cdc/create-alter-iam-connection.td index 0e8c6abab187f..359ab0f8a3b5f 100644 --- a/test/mysql-cdc/create-alter-iam-connection.td +++ b/test/mysql-cdc/create-alter-iam-connection.td @@ -26,7 +26,7 @@ aws_conn aws mysql_conn mysql > SHOW CREATE CONNECTION mysql_conn -materialize.public.mysql_conn "CREATE CONNECTION \"materialize\".\"public\".\"mysql_conn\" TO MYSQL (AWS CONNECTION = \"materialize\".\"public\".\"aws_conn\", HOST = \"mysql\", SSL MODE = \"required\", USER = \"root\")" +materialize.public.mysql_conn "CREATE CONNECTION materialize.public.mysql_conn TO MYSQL (AWS CONNECTION = materialize.public.aws_conn, HOST = mysql, SSL MODE = required, USER = root);" ! ALTER CONNECTION mysql_conn SET (PASSWORD SECRET mysqlpass); diff --git a/test/pg-cdc-old-syntax/alter-source.td b/test/pg-cdc-old-syntax/alter-source.td index 1318d9edfd26b..74b83c2e5c458 100644 --- a/test/pg-cdc-old-syntax/alter-source.td +++ b/test/pg-cdc-old-syntax/alter-source.td @@ -129,15 +129,11 @@ table_e subsource table_f subsource table_g subsource -# Show all tablestodo this should be splittable -> SELECT regexp_match(create_sql, 'FOR TABLES \((.+?)\) EXPOSE')[1] FROM (SHOW CREATE SOURCE mz_source); -"\"postgres\".\"public\".\"table_a\" AS \"materialize\".\"public\".\"table_a\", \"postgres\".\"public\".\"table_b\" AS \"materialize\".\"public\".\"table_b\", \"postgres\".\"public\".\"table_c\" AS \"materialize\".\"public\".\"table_c\", \"postgres\".\"public\".\"table_d\" AS \"materialize\".\"public\".\"table_d\", \"postgres\".\"public\".\"table_e\" AS \"materialize\".\"public\".\"table_e\", \"postgres\".\"public\".\"table_f\" AS \"materialize\".\"public\".\"table_f\", \"postgres\".\"public\".\"table_g\" AS \"materialize\".\"public\".\"table_g\"" - > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); -"\"postgres\".\"public\".\"table_f\".\"f2\"" +postgres.public.table_f.f2 > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_f); -"\"f2\"" +f2 # # State checking @@ -363,7 +359,7 @@ INSERT INTO table_f VALUES (3, 'var1'); "\"postgres\".\"public\".\"table_f\".\"f2\", \"postgres\".\"public\".\"table_i\".\"f2\"" > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); -"\"f2\"" +f2 > SELECT * FROM table_f 1 var0 diff --git a/test/pg-cdc/alter-source.td b/test/pg-cdc/alter-source.td index ef3b69b5f8889..92f6c0f3abb6c 100644 --- a/test/pg-cdc/alter-source.td +++ b/test/pg-cdc/alter-source.td @@ -139,10 +139,10 @@ table_g "" $ set-regex match="DETAILS = '[a-f0-9]+'" replacement=
> SHOW CREATE SOURCE mz_source; -materialize.public.mz_source "CREATE SOURCE \"materialize\".\"public\".\"mz_source\" IN CLUSTER \"quickstart\" FROM POSTGRES CONNECTION \"materialize\".\"public\".\"pg\" (PUBLICATION = 'mz_source') EXPOSE PROGRESS AS \"materialize\".\"public\".\"mz_source_progress\"" +materialize.public.mz_source "CREATE SOURCE materialize.public.mz_source\nIN CLUSTER quickstart\nFROM POSTGRES CONNECTION materialize.public.pg (PUBLICATION = 'mz_source')\nEXPOSE PROGRESS AS materialize.public.mz_source_progress;" > SHOW CREATE TABLE table_a; -materialize.public.table_a "CREATE TABLE \"materialize\".\"public\".\"table_a\" (\"pk\" \"pg_catalog\".\"int4\" NOT NULL, \"f2\" \"pg_catalog\".\"text\", CONSTRAINT \"table_a_pkey\" PRIMARY KEY (\"pk\")) FROM SOURCE \"materialize\".\"public\".\"mz_source\" (REFERENCE = \"postgres\".\"public\".\"table_a\") WITH (
)" +materialize.public.table_a "CREATE TABLE materialize.public.table_a (pk pg_catalog.int4 NOT NULL, f2 pg_catalog.text, CONSTRAINT table_a_pkey PRIMARY KEY (pk)) FROM SOURCE materialize.public.mz_source (REFERENCE = postgres.public.table_a) WITH (
);" # # State checking @@ -349,7 +349,7 @@ contains: invalid TEXT COLUMNS option value: unexpected multiple references to p 2 var1 > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE table_f); -"\"f2\"" +f2 # Drop a table that's in the publication, which shuffles the tables' output # indexes, then add a table to the publication and ensure it can be added. @@ -366,7 +366,7 @@ INSERT INTO table_f VALUES (3, 'var1'); > CREATE TABLE table_i FROM SOURCE mz_source (REFERENCE table_i) WITH (TEXT COLUMNS [f2]); > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE table_i); -"\"f2\"" +f2 > SELECT * FROM table_f 1 var0 @@ -393,7 +393,7 @@ contains: invalid TEXT COLUMNS option value: column "table_e.xyz" does not exist > CREATE TABLE t_f FROM SOURCE mz_source_wo_init_text_cols (REFERENCE table_f) WITH (TEXT COLUMNS [f2]); > SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE TABLE t_f); -"\"f2\"" +f2 # add a table after having created the source $ postgres-execute connection=postgres://postgres:postgres@postgres diff --git a/test/pg-cdc/pg-cdc.td b/test/pg-cdc/pg-cdc.td index d4899be0022ff..c61980c145f20 100644 --- a/test/pg-cdc/pg-cdc.td +++ b/test/pg-cdc/pg-cdc.td @@ -739,7 +739,7 @@ var1 $ set-regex match="DETAILS = '[a-f0-9]+'" replacement=
> SHOW CREATE TABLE enum_table -materialize.public.enum_table "CREATE TABLE \"materialize\".\"public\".\"enum_table\" (\"a\" \"pg_catalog\".\"text\") FROM SOURCE \"materialize\".\"public\".\"enum_source\" (REFERENCE = \"postgres\".\"public\".\"enum_table\") WITH (TEXT COLUMNS = (\"a\"),
)" +materialize.public.enum_table "CREATE TABLE materialize.public.enum_table (a pg_catalog.text) FROM SOURCE materialize.public.enum_source (REFERENCE = postgres.public.enum_table) WITH (TEXT COLUMNS = (a),
);" # Test that TEXT COLUMN types can change $ postgres-execute connection=postgres://postgres:postgres@postgres diff --git a/test/sqllogictest/alter-table.slt b/test/sqllogictest/alter-table.slt index 0e25ffb0c0b2d..1b963e322745a 100644 --- a/test/sqllogictest/alter-table.slt +++ b/test/sqllogictest/alter-table.slt @@ -28,13 +28,13 @@ CREATE VIEW v2 AS SELECT * FROM t2; query TT SHOW CREATE VIEW v1 ---- -materialize.public.v1 CREATE␠VIEW␠"materialize"."public"."v1"␠AS␠SELECT␠*␠FROM␠"materialize"."public"."t2" +materialize.public.v1 CREATE␠VIEW␠materialize.public.v1␠AS␠SELECT␠*␠FROM␠materialize.public.t2; # Note: When the feature is off we should not record versions. query TT SHOW CREATE VIEW v2 ---- -materialize.public.v2 CREATE␠VIEW␠"materialize"."public"."v2"␠AS␠SELECT␠*␠FROM␠"materialize"."public"."t2" +materialize.public.v2 CREATE␠VIEW␠materialize.public.v2␠AS␠SELECT␠*␠FROM␠materialize.public.t2; statement ok DROP VIEW v1 CASCADE; @@ -82,12 +82,12 @@ b true text (empty) query TT SHOW CREATE TABLE t1; ---- -materialize.public.t1 CREATE␠TABLE␠"materialize"."public"."t1"␠("a"␠"pg_catalog"."int4"␠NOT␠NULL,␠"b"␠"pg_catalog"."text"␠VERSION␠ADDED␠1) +materialize.public.t1 CREATE␠TABLE␠materialize.public.t1␠(a␠pg_catalog.int4␠NOT␠NULL,␠b␠pg_catalog.text␠VERSION␠ADDED␠1); query TT SHOW CREATE VIEW v1; ---- -materialize.public.v1 CREATE␠VIEW␠"materialize"."public"."v1"␠AS␠SELECT␠*␠FROM␠"materialize"."public"."t1" +materialize.public.v1 CREATE␠VIEW␠materialize.public.v1␠AS␠SELECT␠*␠FROM␠materialize.public.t1; statement ok CREATE VIEW v2 AS SELECT * FROM t1; @@ -145,7 +145,7 @@ ALTER TABLE t1 ADD COLUMN c timestamp; query TT SHOW CREATE TABLE t1; ---- -materialize.public.t1 CREATE␠TABLE␠"materialize"."public"."t1"␠("a"␠"pg_catalog"."int4"␠NOT␠NULL,␠"b"␠"pg_catalog"."text"␠VERSION␠ADDED␠1,␠"c"␠"pg_catalog"."timestamp"␠VERSION␠ADDED␠2) +materialize.public.t1 CREATE␠TABLE␠materialize.public.t1␠(a␠pg_catalog.int4␠NOT␠NULL,␠b␠pg_catalog.text␠VERSION␠ADDED␠1,␠c␠pg_catalog.timestamp␠VERSION␠ADDED␠2); query TTTT SHOW COLUMNS FROM t1; diff --git a/test/sqllogictest/alter.slt b/test/sqllogictest/alter.slt index 5f780a908d8c8..ea07771a8c433 100644 --- a/test/sqllogictest/alter.slt +++ b/test/sqllogictest/alter.slt @@ -106,7 +106,7 @@ CREATE SOURCE s FROM LOAD GENERATOR COUNTER WITH (RETAIN HISTORY FOR '5m') query T SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW mv) ---- -CREATE MATERIALIZED VIEW "materialize"."public"."mv" IN CLUSTER "quickstart" WITH (REFRESH = ON COMMIT) AS SELECT 1 +CREATE MATERIALIZED VIEW materialize.public.mv⏎ IN CLUSTER quickstart⏎ WITH (REFRESH = ON COMMIT)⏎ AS SELECT 1; statement ok ALTER MATERIALIZED VIEW mv SET (RETAIN HISTORY FOR '1m') @@ -114,7 +114,7 @@ ALTER MATERIALIZED VIEW mv SET (RETAIN HISTORY FOR '1m') query T SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW mv) ---- -CREATE MATERIALIZED VIEW "materialize"."public"."mv" IN CLUSTER "quickstart" WITH (REFRESH = ON COMMIT, RETAIN HISTORY = FOR '1m') AS SELECT 1 +CREATE MATERIALIZED VIEW materialize.public.mv⏎ IN CLUSTER quickstart⏎ WITH (REFRESH = ON COMMIT, RETAIN HISTORY = FOR '1m')⏎ AS SELECT 1; statement ok ALTER MATERIALIZED VIEW mv RESET (RETAIN HISTORY) @@ -122,7 +122,7 @@ ALTER MATERIALIZED VIEW mv RESET (RETAIN HISTORY) query T SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW mv) ---- -CREATE MATERIALIZED VIEW "materialize"."public"."mv" IN CLUSTER "quickstart" WITH (REFRESH = ON COMMIT) AS SELECT 1 +CREATE MATERIALIZED VIEW materialize.public.mv⏎ IN CLUSTER quickstart⏎ WITH (REFRESH = ON COMMIT)⏎ AS SELECT 1; statement ok CREATE TABLE t (a INT) WITH (RETAIN HISTORY FOR '1000 hours') @@ -130,7 +130,7 @@ CREATE TABLE t (a INT) WITH (RETAIN HISTORY FOR '1000 hours') query T SELECT create_sql FROM (SHOW CREATE TABLE t) ---- -CREATE TABLE "materialize"."public"."t" ("a" "pg_catalog"."int4") WITH (RETAIN HISTORY = FOR '1000 hours') +CREATE TABLE materialize.public.t (a pg_catalog.int4) WITH (RETAIN HISTORY = FOR '1000 hours'); statement ok CREATE INDEX i ON t(a) @@ -141,7 +141,7 @@ ALTER TABLE t SET (RETAIN HISTORY FOR '1m') query T SELECT create_sql FROM (SHOW CREATE TABLE t) ---- -CREATE TABLE "materialize"."public"."t" ("a" "pg_catalog"."int4") WITH (RETAIN HISTORY = FOR '1m') +CREATE TABLE materialize.public.t (a pg_catalog.int4) WITH (RETAIN HISTORY = FOR '1m'); statement ok ALTER TABLE t RESET (RETAIN HISTORY) @@ -149,7 +149,7 @@ ALTER TABLE t RESET (RETAIN HISTORY) query T SELECT create_sql FROM (SHOW CREATE TABLE t) ---- -CREATE TABLE "materialize"."public"."t" ("a" "pg_catalog"."int4") +CREATE TABLE materialize.public.t (a pg_catalog.int4); statement ok ALTER SOURCE s SET (RETAIN HISTORY FOR '1m') @@ -157,7 +157,7 @@ ALTER SOURCE s SET (RETAIN HISTORY FOR '1m') query T SELECT create_sql FROM (SHOW CREATE SOURCE s) ---- -CREATE SOURCE "materialize"."public"."s" IN CLUSTER "quickstart" FROM LOAD GENERATOR COUNTER EXPOSE PROGRESS AS "materialize"."public"."s_progress" WITH (RETAIN HISTORY = FOR '1m') +CREATE SOURCE materialize.public.s⏎IN CLUSTER quickstart⏎FROM LOAD GENERATOR COUNTER⏎EXPOSE PROGRESS AS materialize.public.s_progress⏎WITH (RETAIN HISTORY = FOR '1m'); statement ok ALTER SOURCE s RESET (RETAIN HISTORY) @@ -165,7 +165,7 @@ ALTER SOURCE s RESET (RETAIN HISTORY) query T SELECT create_sql FROM (SHOW CREATE SOURCE s) ---- -CREATE SOURCE "materialize"."public"."s" IN CLUSTER "quickstart" FROM LOAD GENERATOR COUNTER EXPOSE PROGRESS AS "materialize"."public"."s_progress" +CREATE SOURCE materialize.public.s⏎IN CLUSTER quickstart⏎FROM LOAD GENERATOR COUNTER⏎EXPOSE PROGRESS AS materialize.public.s_progress; statement ok ALTER INDEX i SET (RETAIN HISTORY FOR '1m') @@ -173,7 +173,7 @@ ALTER INDEX i SET (RETAIN HISTORY FOR '1m') query T SELECT create_sql FROM (SHOW CREATE INDEX i) ---- -CREATE INDEX "i" IN CLUSTER "quickstart" ON "materialize"."public"."t" ("a") WITH (RETAIN HISTORY = FOR '1m') +CREATE INDEX i IN CLUSTER quickstart ON materialize.public.t (a) WITH (RETAIN HISTORY = FOR '1m'); statement ok ALTER INDEX i SET (RETAIN HISTORY = FOR '1000 hours') @@ -181,7 +181,7 @@ ALTER INDEX i SET (RETAIN HISTORY = FOR '1000 hours') query T SELECT create_sql FROM (SHOW CREATE INDEX i) ---- -CREATE INDEX "i" IN CLUSTER "quickstart" ON "materialize"."public"."t" ("a") WITH (RETAIN HISTORY = FOR '1000 hours') +CREATE INDEX i IN CLUSTER quickstart ON materialize.public.t (a) WITH (RETAIN HISTORY = FOR '1000 hours'); statement ok ALTER INDEX i RESET (RETAIN HISTORY) @@ -189,4 +189,4 @@ ALTER INDEX i RESET (RETAIN HISTORY) query T SELECT create_sql FROM (SHOW CREATE INDEX i) ---- -CREATE INDEX "i" IN CLUSTER "quickstart" ON "materialize"."public"."t" ("a") +CREATE INDEX i IN CLUSTER quickstart ON materialize.public.t (a); diff --git a/test/sqllogictest/cockroach/case_sensitive_names.slt b/test/sqllogictest/cockroach/case_sensitive_names.slt index 5c93d1f291bc2..94d2661c5af27 100644 --- a/test/sqllogictest/cockroach/case_sensitive_names.slt +++ b/test/sqllogictest/cockroach/case_sensitive_names.slt @@ -271,7 +271,7 @@ query TT SHOW CREATE VIEW xv ---- materialize.public.xv -CREATE VIEW "materialize"."public"."xv" AS SELECT "x", "Y" FROM "materialize"."public"."foo" +CREATE VIEW materialize.public.xv AS SELECT x, "Y" FROM materialize.public.foo; query error unknown catalog item 'XV' SHOW CREATE VIEW "XV" @@ -283,7 +283,7 @@ query TT SHOW CREATE VIEW "YV" ---- materialize.public.YV -CREATE VIEW "materialize"."public"."YV" AS SELECT "x", "Y" FROM "materialize"."public"."foo" +CREATE VIEW materialize.public."YV" AS SELECT x, "Y" FROM materialize.public.foo; query error unknown catalog item 'yv' SHOW CREATE VIEW YV diff --git a/test/sqllogictest/id.slt b/test/sqllogictest/id.slt index ee29c67246899..fda1bef4ad68c 100644 --- a/test/sqllogictest/id.slt +++ b/test/sqllogictest/id.slt @@ -72,7 +72,7 @@ query TT SHOW CREATE VIEW foo ---- materialize.public.foo -CREATE VIEW "materialize"."public"."foo" AS SELECT * FROM "materialize"."public"."x" +CREATE VIEW materialize.public.foo AS SELECT * FROM materialize.public.x; statement ok DROP VIEW foo; @@ -84,7 +84,7 @@ query TT SHOW CREATE VIEW foo ---- materialize.public.foo -CREATE VIEW "materialize"."public"."foo" AS SELECT * FROM "materialize"."public"."x" +CREATE VIEW materialize.public.foo AS SELECT * FROM materialize.public.x; # If the name *differs*, fall back to the id version. @@ -98,4 +98,4 @@ query TT SHOW CREATE VIEW foo ---- materialize.public.foo -CREATE VIEW "materialize"."public"."foo" AS SELECT * FROM [u1 AS "materialize"."public"."y"] +CREATE VIEW materialize.public.foo AS SELECT * FROM [u1 AS materialize.public.y]; diff --git a/test/sqllogictest/joins.slt b/test/sqllogictest/joins.slt index 332108ee37aa6..1a0ef778a5464 100644 --- a/test/sqllogictest/joins.slt +++ b/test/sqllogictest/joins.slt @@ -860,7 +860,7 @@ query TT SHOW CREATE VIEW v1; ---- materialize.public.v1 -CREATE VIEW "materialize"."public"."v1" AS SELECT "x".* FROM "materialize"."public"."t1" JOIN "materialize"."public"."t2" USING ("f1") AS "x" WHERE "x"."f1" = 3 +CREATE VIEW⏎ materialize.public.v1⏎ AS⏎ SELECT x.*⏎ FROM materialize.public.t1 JOIN materialize.public.t2 USING(f1) AS x⏎ WHERE x.f1 = 3; mode cockroach diff --git a/test/sqllogictest/materialized_views.slt b/test/sqllogictest/materialized_views.slt index bdce4d73d30b7..257ad72ba9c2e 100644 --- a/test/sqllogictest/materialized_views.slt +++ b/test/sqllogictest/materialized_views.slt @@ -369,15 +369,19 @@ CREATE MATERIALIZED VIEW mv AS SELECT 1 query TT colnames SHOW CREATE MATERIALIZED VIEW mv ---- -name create_sql -materialize.public.mv CREATE␠MATERIALIZED␠VIEW␠"materialize"."public"."mv"␠IN␠CLUSTER␠"quickstart"␠WITH␠(REFRESH␠=␠ON␠COMMIT)␠AS␠SELECT␠1 +name create_sql +materialize.public.mv CREATE␠MATERIALIZED␠VIEW␠materialize.public.mv⏎␠␠␠␠IN␠CLUSTER␠quickstart⏎␠␠␠␠WITH␠(REFRESH␠=␠ON␠COMMIT)⏎␠␠␠␠AS␠SELECT␠1; # Test: SHOW CREATE MATERIALIZED VIEW as mz_support -simple conn=mz_catalog_server,user=mz_support -SHOW CREATE MATERIALIZED VIEW mv +simple multiline,conn=mz_catalog_server,user=mz_support +SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW mv); ---- -materialize.public.mv,CREATE MATERIALIZED VIEW "materialize"."public"."mv" IN CLUSTER "quickstart" WITH (REFRESH = ON COMMIT) AS SELECT 1 +CREATE MATERIALIZED VIEW materialize.public.mv + IN CLUSTER quickstart + WITH (REFRESH = ON COMMIT) + AS SELECT 1; +EOF COMPLETE 1 # Test: SHOW MATERIALIZED VIEWS @@ -1793,3 +1797,15 @@ simple conn=mz_system,user=mz_system ALTER SYSTEM SET enable_explain_pushdown = false ---- COMPLETE 0 + +query T multiline +SELECT regexp_replace(create_sql, 'AT \d+', 'XXX', 'g') FROM (SHOW CREATE MATERIALIZED VIEW mvi3); +---- +CREATE MATERIALIZED VIEW materialize.public.mvi3 + IN CLUSTER quickstart + WITH ( + REFRESH = XXX::mz_catalog.mz_timestamp, + REFRESH = XXX::mz_catalog.mz_timestamp::pg_catalog.text::pg_catalog.int8 + 2000 + ) + AS SELECT DISTINCT 5 * x FROM materialize.public.t3; +EOF diff --git a/test/sqllogictest/operator.slt b/test/sqllogictest/operator.slt index bd3711fce8cfd..2562ec29dc95b 100644 --- a/test/sqllogictest/operator.slt +++ b/test/sqllogictest/operator.slt @@ -118,7 +118,7 @@ query TT SHOW CREATE VIEW PG_ADDER ---- materialize.public.pg_adder -CREATE VIEW "materialize"."public"."pg_adder" AS SELECT 2 OPERATOR(pg_catalog.+) 2 +CREATE VIEW materialize.public.pg_adder AS SELECT 2 OPERATOR(pg_catalog.+) 2; statement ok CREATE VIEW ADDER AS SELECT 2 OPERATOR(+) 2; @@ -127,12 +127,12 @@ query TT SHOW CREATE VIEW ADDER ---- materialize.public.adder -CREATE VIEW "materialize"."public"."adder" AS SELECT 2 OPERATOR(+) 2 +CREATE VIEW materialize.public.adder AS SELECT 2 OPERATOR(+) 2; simple conn=mz_catalog_server,user=mz_support SHOW CREATE VIEW ADDER ---- -materialize.public.adder,CREATE VIEW "materialize"."public"."adder" AS SELECT 2 OPERATOR(+) 2 +materialize.public.adder,CREATE VIEW materialize.public.adder AS SELECT 2 OPERATOR(+) 2; COMPLETE 1 statement ok @@ -142,7 +142,7 @@ query TT SHOW CREATE VIEW MULTIPLIER ---- materialize.public.multiplier -CREATE VIEW "materialize"."public"."multiplier" AS SELECT 2 OPERATOR(*) 2 +CREATE VIEW materialize.public.multiplier AS SELECT 2 OPERATOR(*) 2; statement ok CREATE VIEW PG_MULTIPLIER AS SELECT 2 OPERATOR(pg_catalog.*) 2; @@ -151,7 +151,7 @@ query TT SHOW CREATE VIEW PG_MULTIPLIER ---- materialize.public.pg_multiplier -CREATE VIEW "materialize"."public"."pg_multiplier" AS SELECT 2 OPERATOR(pg_catalog.*) 2 +CREATE VIEW materialize.public.pg_multiplier AS SELECT 2 OPERATOR(pg_catalog.*) 2; query error Expected operator, found number "5." CREATE VIEW INVALID_FIVE AS select 2 OPERATOR(5.*) 2; diff --git a/test/sqllogictest/pg_catalog_matviews.slt b/test/sqllogictest/pg_catalog_matviews.slt index e77529a768090..a82d4f1865b28 100644 --- a/test/sqllogictest/pg_catalog_matviews.slt +++ b/test/sqllogictest/pg_catalog_matviews.slt @@ -34,10 +34,24 @@ query TT SHOW CREATE VIEW pg_matviews ---- pg_catalog.pg_matviews -CREATE VIEW "pg_catalog"."pg_matviews" AS SELECT "s"."name" AS "schemaname", "m"."name" AS "matviewname", "role_owner"."oid" AS "matviewowner", "m"."definition" AS "definition" FROM "mz_catalog"."mz_materialized_views" AS "m" LEFT JOIN "mz_catalog"."mz_schemas" AS "s" ON "s"."id" = "m"."schema_id" LEFT JOIN "mz_catalog"."mz_databases" AS "d" ON "d"."id" = "s"."database_id" JOIN "mz_catalog"."mz_roles" AS "role_owner" ON "role_owner"."id" = "m"."owner_id" WHERE "s"."database_id" IS NULL OR "d"."name" = "pg_catalog"."current_database"() +CREATE VIEW⏎ pg_catalog.pg_matviews⏎ AS⏎ SELECT⏎ s.name AS schemaname,⏎ m.name AS matviewname,⏎ role_owner.oid AS matviewowner,⏎ m.definition AS definition⏎ FROM⏎ mz_catalog.mz_materialized_views AS m⏎ LEFT JOIN mz_catalog.mz_schemas AS s ON s.id = m.schema_id⏎ LEFT JOIN mz_catalog.mz_databases AS d ON d.id = s.database_id⏎ JOIN mz_catalog.mz_roles AS role_owner ON role_owner.id = m.owner_id⏎ WHERE s.database_id IS NULL OR d.name = pg_catalog.current_database(); -simple conn=mz_catalog_server,user=mz_support -SHOW CREATE VIEW pg_matviews +simple multiline,conn=mz_catalog_server,user=mz_support +SELECT create_sql FROM (SHOW CREATE VIEW pg_matviews); ---- -pg_catalog.pg_matviews,CREATE VIEW "pg_catalog"."pg_matviews" AS SELECT "s"."name" AS "schemaname", "m"."name" AS "matviewname", "role_owner"."oid" AS "matviewowner", "m"."definition" AS "definition" FROM "mz_catalog"."mz_materialized_views" AS "m" LEFT JOIN "mz_catalog"."mz_schemas" AS "s" ON "s"."id" = "m"."schema_id" LEFT JOIN "mz_catalog"."mz_databases" AS "d" ON "d"."id" = "s"."database_id" JOIN "mz_catalog"."mz_roles" AS "role_owner" ON "role_owner"."id" = "m"."owner_id" WHERE "s"."database_id" IS NULL OR "d"."name" = "pg_catalog"."current_database"() +CREATE VIEW + pg_catalog.pg_matviews + AS + SELECT + s.name AS schemaname, + m.name AS matviewname, + role_owner.oid AS matviewowner, + m.definition AS definition + FROM + mz_catalog.mz_materialized_views AS m + LEFT JOIN mz_catalog.mz_schemas AS s ON s.id = m.schema_id + LEFT JOIN mz_catalog.mz_databases AS d ON d.id = s.database_id + JOIN mz_catalog.mz_roles AS role_owner ON role_owner.id = m.owner_id + WHERE s.database_id IS NULL OR d.name = pg_catalog.current_database(); +EOF COMPLETE 1 diff --git a/test/sqllogictest/pg_catalog_views.slt b/test/sqllogictest/pg_catalog_views.slt index 88bc5b42968ee..3b81afe902811 100644 --- a/test/sqllogictest/pg_catalog_views.slt +++ b/test/sqllogictest/pg_catalog_views.slt @@ -34,7 +34,7 @@ query TT SHOW CREATE VIEW pg_views ---- pg_catalog.pg_views -CREATE VIEW "pg_catalog"."pg_views" AS SELECT "s"."name" AS "schemaname", "v"."name" AS "viewname", "role_owner"."oid" AS "viewowner", "v"."definition" AS "definition" FROM "mz_catalog"."mz_views" AS "v" LEFT JOIN "mz_catalog"."mz_schemas" AS "s" ON "s"."id" = "v"."schema_id" LEFT JOIN "mz_catalog"."mz_databases" AS "d" ON "d"."id" = "s"."database_id" JOIN "mz_catalog"."mz_roles" AS "role_owner" ON "role_owner"."id" = "v"."owner_id" WHERE "s"."database_id" IS NULL OR "d"."name" = "pg_catalog"."current_database"() +CREATE VIEW⏎ pg_catalog.pg_views⏎ AS⏎ SELECT⏎ s.name AS schemaname,⏎ v.name AS viewname,⏎ role_owner.oid AS viewowner,⏎ v.definition AS definition⏎ FROM⏎ mz_catalog.mz_views AS v⏎ LEFT JOIN mz_catalog.mz_schemas AS s ON s.id = v.schema_id⏎ LEFT JOIN mz_catalog.mz_databases AS d ON d.id = s.database_id⏎ JOIN mz_catalog.mz_roles AS role_owner ON role_owner.id = v.owner_id⏎ WHERE s.database_id IS NULL OR d.name = pg_catalog.current_database(); # test that nothing in the pg_catalog or information_schema schemas use unsinged ints query ITITTITT diff --git a/test/sqllogictest/privilege_checks.slt b/test/sqllogictest/privilege_checks.slt index 0b86b37b65720..d80a3d4b18449 100644 --- a/test/sqllogictest/privilege_checks.slt +++ b/test/sqllogictest/privilege_checks.slt @@ -1393,13 +1393,13 @@ COMPLETE 0 simple conn=joe,user=joe SHOW CREATE TABLE t; ---- -materialize.public.t,CREATE TABLE "materialize"."public"."t" ("a" "pg_catalog"."int4") +materialize.public.t,CREATE TABLE materialize.public.t (a pg_catalog.int4); COMPLETE 1 simple conn=child,user=child SHOW CREATE TABLE t; ---- -materialize.public.t,CREATE TABLE "materialize"."public"."t" ("a" "pg_catalog"."int4") +materialize.public.t,CREATE TABLE materialize.public.t (a pg_catalog.int4); COMPLETE 1 simple conn=mz_system,user=mz_system @@ -1437,13 +1437,13 @@ COMPLETE 0 simple conn=joe,user=joe SHOW CREATE CONNECTION csr_conn; ---- -materialize.public.csr_conn,CREATE CONNECTION "materialize"."public"."csr_conn" TO CONFLUENT SCHEMA REGISTRY (URL = 'https://google.com') +materialize.public.csr_conn,CREATE CONNECTION materialize.public.csr_conn TO CONFLUENT SCHEMA REGISTRY (URL = 'https://google.com'); COMPLETE 1 simple conn=child,user=child SHOW CREATE CONNECTION csr_conn; ---- -materialize.public.csr_conn,CREATE CONNECTION "materialize"."public"."csr_conn" TO CONFLUENT SCHEMA REGISTRY (URL = 'https://google.com') +materialize.public.csr_conn,CREATE CONNECTION materialize.public.csr_conn TO CONFLUENT SCHEMA REGISTRY (URL = 'https://google.com'); COMPLETE 1 simple conn=mz_system,user=mz_system diff --git a/test/sqllogictest/redacted.slt b/test/sqllogictest/redacted.slt index a3541006ff934..64a0f951be16f 100644 --- a/test/sqllogictest/redacted.slt +++ b/test/sqllogictest/redacted.slt @@ -27,7 +27,7 @@ EOF query T multiline SELECT create_sql FROM (SHOW REDACTED CREATE TABLE t); ---- -CREATE TABLE materialize.public.t (i pg_catalog.int4) +CREATE TABLE materialize.public.t (i pg_catalog.int4); EOF statement ok @@ -42,7 +42,7 @@ EOF query T multiline SELECT create_sql FROM (SHOW REDACTED CREATE CONNECTION kafka_conn); ---- -CREATE CONNECTION materialize.public.kafka_conn TO KAFKA (BROKER = 'localhost:9092', SECURITY PROTOCOL = plaintext) +CREATE CONNECTION materialize.public.kafka_conn TO KAFKA (BROKER = 'localhost:9092', SECURITY PROTOCOL = plaintext); EOF query T multiline @@ -74,7 +74,7 @@ EOF query T multiline SELECT create_sql FROM (SHOW REDACTED CREATE TABLE redactable_t); ---- -CREATE TABLE materialize.public.redactable_t (a pg_catalog.int4) WITH (RETAIN HISTORY = FOR '2s', REDACTED = '') +CREATE TABLE materialize.public.redactable_t (a pg_catalog.int4) WITH (RETAIN HISTORY = FOR '2s', REDACTED = ''); EOF query T multiline @@ -101,7 +101,7 @@ EOF query T multiline SELECT create_sql FROM (SHOW REDACTED CREATE INDEX t_idx_i); ---- -CREATE INDEX t_idx_i IN CLUSTER quickstart ON materialize.public.t (i) +CREATE INDEX t_idx_i IN CLUSTER quickstart ON materialize.public.t (i); EOF statement ok @@ -116,7 +116,7 @@ EOF query T multiline SELECT create_sql FROM (SHOW REDACTED CREATE VIEW v); ---- -CREATE VIEW materialize.public.v AS SELECT '' +CREATE VIEW materialize.public.v AS SELECT ''; EOF query T multiline @@ -144,7 +144,10 @@ EOF query T multiline SELECT regexp_replace(create_sql, 'u[0-9]+', 'uX', 'g') FROM (SHOW REDACTED CREATE SOURCE s); ---- -CREATE SOURCE materialize.public.s IN CLUSTER quickstart FROM LOAD GENERATOR COUNTER EXPOSE PROGRESS AS materialize.public.s_progress +CREATE SOURCE materialize.public.s +IN CLUSTER quickstart +FROM LOAD GENERATOR COUNTER +EXPOSE PROGRESS AS materialize.public.s_progress; EOF query T multiline @@ -187,7 +190,10 @@ EOF query T multiline SELECT create_sql FROM (SHOW REDACTED CREATE MATERIALIZED VIEW mv1); ---- -CREATE MATERIALIZED VIEW materialize.public.mv1 IN CLUSTER quickstart WITH (REFRESH = ON COMMIT) AS SELECT i + i + '' FROM materialize.public.t +CREATE MATERIALIZED VIEW materialize.public.mv1 + IN CLUSTER quickstart + WITH (REFRESH = ON COMMIT) + AS SELECT i + i + '' FROM materialize.public.t; EOF query T multiline diff --git a/test/sqllogictest/rename.slt b/test/sqllogictest/rename.slt index 594fdcb8533be..2c42f29f7f704 100644 --- a/test/sqllogictest/rename.slt +++ b/test/sqllogictest/rename.slt @@ -38,7 +38,7 @@ query TT SHOW CREATE TABLE b1.t ---- materialize.b1.t -CREATE TABLE "materialize"."b1"."t" ("x" "pg_catalog"."int4") +CREATE TABLE materialize.b1.t (x pg_catalog.int4); statement ok INSERT INTO b1.t VALUES (1), (2), (3) @@ -87,7 +87,7 @@ query TT SHOW CREATE TABLE b2.t; ---- materialize.b2.t -CREATE TABLE "materialize"."b2"."t" ("x" "pg_catalog"."int4") +CREATE TABLE materialize.b2.t (x pg_catalog.int4); statement ok CREATE SCHEMA friend; @@ -106,7 +106,7 @@ query TT SHOW CREATE VIEW friend.v1; ---- materialize.friend.v1 -CREATE VIEW "materialize"."friend"."v1" AS SELECT "x" FROM "materialize"."b2"."t" +CREATE VIEW materialize.friend.v1 AS SELECT x FROM materialize.b2.t; statement ok ALTER SCHEMA b2 RENAME TO b3; @@ -122,7 +122,7 @@ query TT SHOW CREATE VIEW friend.v1; ---- materialize.friend.v1 -CREATE VIEW "materialize"."friend"."v1" AS SELECT "x" FROM "materialize"."b3"."t" +CREATE VIEW materialize.friend.v1 AS SELECT x FROM materialize.b3.t; statement ok CREATE SCHEMA grand_friend; @@ -147,19 +147,19 @@ query TT SHOW CREATE TABLE b3.t; ---- materialize.b3.t -CREATE TABLE "materialize"."b3"."t" ("x" "pg_catalog"."int4") +CREATE TABLE materialize.b3.t (x pg_catalog.int4); query TT SHOW CREATE VIEW enemy.v1; ---- materialize.enemy.v1 -CREATE VIEW "materialize"."enemy"."v1" AS SELECT "x" FROM "materialize"."b3"."t" +CREATE VIEW materialize.enemy.v1 AS SELECT x FROM materialize.b3.t; query TT SHOW CREATE MATERIALIZED VIEW grand_friend.mv1; ---- materialize.grand_friend.mv1 -CREATE MATERIALIZED VIEW "materialize"."grand_friend"."mv1" IN CLUSTER "quickstart" WITH (REFRESH = ON COMMIT) AS SELECT "x" FROM "materialize"."enemy"."v1" +CREATE MATERIALIZED VIEW materialize.grand_friend.mv1⏎ IN CLUSTER quickstart⏎ WITH (REFRESH = ON COMMIT)⏎ AS SELECT x FROM materialize.enemy.v1; statement ok CREATE TABLE a1.t (y text); @@ -171,7 +171,7 @@ query TT SHOW CREATE TABLE a1.t; ---- materialize.a1.t -CREATE TABLE "materialize"."a1"."t" ("y" "pg_catalog"."text") +CREATE TABLE materialize.a1.t (y pg_catalog.text); statement ok CREATE VIEW enemy.v2 AS (SELECT * FROM a1.t, b3.t); @@ -196,7 +196,7 @@ query TT SHOW CREATE VIEW enemy.v2; ---- materialize.enemy.v2 -CREATE VIEW "materialize"."enemy"."v2" AS SELECT * FROM "materialize"."a1"."t", "materialize"."b3"."t" +CREATE VIEW materialize.enemy.v2 AS SELECT * FROM materialize.a1.t, materialize.b3.t; statement ok CREATE INDEX enemy_v2_idx ON enemy.v2 (y, x); @@ -210,7 +210,7 @@ query TT SHOW CREATE INDEX enemy.enemy_v2_idx ---- materialize.enemy.enemy_v2_idx -CREATE INDEX "enemy_v2_idx" IN CLUSTER "quickstart" ON "materialize"."enemy"."v2" ("y", "x") +CREATE INDEX enemy_v2_idx IN CLUSTER quickstart ON materialize.enemy.v2 (y, x); statement ok ALTER SCHEMA b3 RENAME TO b4; @@ -219,7 +219,7 @@ query TT SHOW CREATE VIEW enemy.v2; ---- materialize.enemy.v2 -CREATE VIEW "materialize"."enemy"."v2" AS SELECT * FROM "materialize"."a1"."t", "materialize"."b4"."t" +CREATE VIEW materialize.enemy.v2 AS SELECT * FROM materialize.a1.t, materialize.b4.t; statement ok ALTER SCHEMA enemy RENAME TO friend_again; @@ -228,13 +228,13 @@ query TT SHOW CREATE VIEW friend_again.v2; ---- materialize.friend_again.v2 -CREATE VIEW "materialize"."friend_again"."v2" AS SELECT * FROM "materialize"."a1"."t", "materialize"."b4"."t" +CREATE VIEW materialize.friend_again.v2 AS SELECT * FROM materialize.a1.t, materialize.b4.t; query TT SHOW CREATE INDEX friend_again.enemy_v2_idx ---- materialize.friend_again.enemy_v2_idx -CREATE INDEX "enemy_v2_idx" IN CLUSTER "quickstart" ON "materialize"."friend_again"."v2" ("y", "x") +CREATE INDEX enemy_v2_idx IN CLUSTER quickstart ON materialize.friend_again.v2 (y, x); statement ok CREATE TABLE grand_friend.t1 (keys text); @@ -287,7 +287,7 @@ query TT SHOW CREATE VIEW c1.v1; ---- materialize.c1.v1 -CREATE VIEW "materialize"."c1"."v1" AS SELECT "y" FROM "materialize"."friend_again"."v2" JOIN "materialize"."grand_friend"."t1" ON "materialize"."friend_again"."v2"."y" = "materialize"."grand_friend"."t1"."keys" UNION ALL SELECT "aux_key" FROM "materialize"."c1"."keys", "materialize"."b4"."t" +CREATE VIEW⏎ materialize.c1.v1⏎ AS⏎ SELECT y⏎ FROM⏎ materialize.friend_again.v2⏎ JOIN⏎ materialize.grand_friend.t1⏎ ON materialize.friend_again.v2.y = materialize.grand_friend.t1.keys⏎ UNION ALL SELECT aux_key FROM materialize.c1.keys, materialize.b4.t; statement ok ALTER SCHEMA c1 RENAME TO c2; @@ -299,7 +299,7 @@ query TT SHOW CREATE VIEW c2.v1; ---- materialize.c2.v1 -CREATE VIEW "materialize"."c2"."v1" AS SELECT "y" FROM "materialize"."friend_again"."v2" JOIN "materialize"."grand_acquaintance"."t1" ON "materialize"."friend_again"."v2"."y" = "materialize"."grand_acquaintance"."t1"."keys" UNION ALL SELECT "aux_key" FROM "materialize"."c2"."keys", "materialize"."b4"."t" +CREATE VIEW⏎ materialize.c2.v1⏎ AS⏎ SELECT y⏎ FROM⏎ materialize.friend_again.v2⏎ JOIN⏎ materialize.grand_acquaintance.t1⏎ ON materialize.friend_again.v2.y = materialize.grand_acquaintance.t1.keys⏎ UNION ALL SELECT aux_key FROM materialize.c2.keys, materialize.b4.t; statement ok CREATE TABLE c2.c2 (ts int); @@ -308,7 +308,7 @@ query TT SHOW CREATE TABLE c2.c2; ---- materialize.c2.c2 -CREATE TABLE "materialize"."c2"."c2" ("ts" "pg_catalog"."int4") +CREATE TABLE materialize.c2.c2 (ts pg_catalog.int4); statement ok ALTER SCHEMA c2 RENAME TO c3; @@ -317,7 +317,7 @@ query TT SHOW CREATE TABLE c3.c2; ---- materialize.c3.c2 -CREATE TABLE "materialize"."c3"."c2" ("ts" "pg_catalog"."int4") +CREATE TABLE materialize.c3.c2 (ts pg_catalog.int4); # Renaming system owned schemas is not allowed. @@ -348,7 +348,7 @@ query TT SHOW CREATE VIEW d.qualified_columns; ---- materialize.d.qualified_columns -CREATE VIEW "materialize"."d"."qualified_columns" AS SELECT "materialize"."d"."values"."x", "materialize"."d"."values"."y", "z" FROM "materialize"."d"."values" +CREATE VIEW⏎ materialize.d.qualified_columns⏎ AS SELECT materialize.d.values.x, materialize.d.values.y, z FROM materialize.d.values; query ITI SELECT * FROM d.qualified_columns; @@ -370,7 +370,7 @@ query TT SHOW CREATE VIEW d_renamed.qualified_columns; ---- materialize.d_renamed.qualified_columns -CREATE VIEW "materialize"."d_renamed"."qualified_columns" AS SELECT "materialize"."d_renamed"."values"."x", "materialize"."d_renamed"."values"."y", "z" FROM "materialize"."d_renamed"."values" +CREATE VIEW⏎ materialize.d_renamed.qualified_columns⏎ AS⏎ SELECT materialize.d_renamed.values.x, materialize.d_renamed.values.y, z⏎ FROM materialize.d_renamed.values; query ITI SELECT * FROM d_renamed.qualified_columns LIMIT 1; @@ -394,7 +394,7 @@ query TT SHOW CREATE VIEW d_renamed."case"; ---- materialize.d_renamed.case -CREATE VIEW "materialize"."d_renamed"."case" ("case") AS SELECT * FROM "materialize"."case"."case" +CREATE VIEW materialize.d_renamed.case (case) AS SELECT * FROM materialize.case.case; statement ok CREATE SCHEMA "CASE"; @@ -419,13 +419,13 @@ query TT SHOW CREATE VIEW "cAsE".case; ---- materialize.cAsE.case -CREATE VIEW "materialize"."cAsE"."case" AS VALUES (1) +CREATE VIEW materialize."cAsE".case AS VALUES (1); query TT SHOW CREATE VIEW d_renamed.case; ---- materialize.d_renamed.case -CREATE VIEW "materialize"."d_renamed"."case" ("case") AS SELECT * FROM "materialize"."cAsE"."case" +CREATE VIEW materialize.d_renamed.case (case) AS SELECT * FROM materialize."cAsE".case; statement ok CREATE SCHEMA j; @@ -446,7 +446,7 @@ query TT SHOW CREATE VIEW j.k.l; ---- j.k.l -CREATE VIEW "j"."k"."l" AS VALUES (101) +CREATE VIEW j.k.l AS VALUES (101); query I SELECT * FROM j.k.l; @@ -460,7 +460,7 @@ query TT SHOW CREATE VIEW j.k.l; ---- j.k.l -CREATE VIEW "j"."k"."l" AS VALUES (101) +CREATE VIEW j.k.l AS VALUES (101); query I SELECT * FROM j.k.l; @@ -561,7 +561,7 @@ query TT SHOW CREATE VIEW c.foo.v1; ---- c.foo.v1 -CREATE VIEW "c"."foo"."v1" AS SELECT "x", "y" FROM "a"."foo"."t1", "b"."foo"."t1" +CREATE VIEW c.foo.v1 AS SELECT x, y FROM a.foo.t1, b.foo.t1; statement ok ALTER SCHEMA b.foo RENAME TO bbb; @@ -570,7 +570,7 @@ query TT SHOW CREATE VIEW c.foo.v1; ---- c.foo.v1 -CREATE VIEW "c"."foo"."v1" AS SELECT "x", "y" FROM "a"."foo"."t1", "b"."bbb"."t1" +CREATE VIEW c.foo.v1 AS SELECT x, y FROM a.foo.t1, b.bbb.t1; statement ok ALTER SCHEMA c.foo RENAME TO ccc; @@ -579,7 +579,7 @@ query TT SHOW CREATE VIEW c.ccc.v1; ---- c.ccc.v1 -CREATE VIEW "c"."ccc"."v1" AS SELECT "x", "y" FROM "a"."foo"."t1", "b"."bbb"."t1" +CREATE VIEW c.ccc.v1 AS SELECT x, y FROM a.foo.t1, b.bbb.t1; # Ambiguously refer to a schema. @@ -605,7 +605,7 @@ query TT SHOW CREATE VIEW d.amb.v1; ---- d.amb.v1 -CREATE VIEW "d"."amb"."v1" AS SELECT "amb"."t1"."x" FROM "materialize"."amb"."t1", "d"."amb"."t1" +CREATE VIEW d.amb.v1 AS SELECT amb.t1.x FROM materialize.amb.t1, d.amb.t1; statement error db error: ERROR: renaming conflict: in d\.amb\.v1, which uses d\.amb, ambiguous reference to schema named amb ALTER SCHEMA d.amb RENAME TO this_rename_will_fail; @@ -646,7 +646,7 @@ query TT SHOW CREATE VIEW temp_view; ---- mz_temp.temp_view -CREATE TEMPORARY VIEW "mz_temp"."temp_view" AS SELECT * FROM "materialize"."public_renamed"."non_temp_base" +CREATE TEMPORARY VIEW mz_temp.temp_view AS SELECT * FROM materialize.public_renamed.non_temp_base; statement ok ALTER TABLE non_temp_base RENAME TO non_temp_table; @@ -655,4 +655,4 @@ query TT SHOW CREATE VIEW temp_view; ---- mz_temp.temp_view -CREATE TEMPORARY VIEW "mz_temp"."temp_view" AS SELECT * FROM "materialize"."public_renamed"."non_temp_table" +CREATE TEMPORARY VIEW mz_temp.temp_view AS SELECT * FROM materialize.public_renamed.non_temp_table; diff --git a/test/sqllogictest/slt.slt b/test/sqllogictest/slt.slt index 4f982d85442f7..025b155a980f9 100644 --- a/test/sqllogictest/slt.slt +++ b/test/sqllogictest/slt.slt @@ -39,6 +39,9 @@ column␠name␠with␠spaces! nospaces space␠again 2 3 +statement ok +CREATE MATERIALIZED VIEW mv1 AS SELECT 1; + mode standard query TT @@ -59,6 +62,27 @@ with newline EOF +query TT +SHOW CREATE MATERIALIZED VIEW mv1; +---- +materialize.public.mv1 +CREATE MATERIALIZED VIEW materialize.public.mv1⏎ IN CLUSTER quickstart⏎ WITH (REFRESH = ON COMMIT)⏎ AS SELECT 1; + +query T +SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW mv1); +---- +CREATE MATERIALIZED VIEW materialize.public.mv1⏎ IN CLUSTER quickstart⏎ WITH (REFRESH = ON COMMIT)⏎ AS SELECT 1; + +simple multiline,conn=mz_catalog_server,user=mz_support +SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW mv1); +---- +CREATE MATERIALIZED VIEW materialize.public.mv1 + IN CLUSTER quickstart + WITH (REFRESH = ON COMMIT) + AS SELECT 1; +EOF +COMPLETE 1 + mode cockroach query TT @@ -76,3 +100,23 @@ result with newline EOF + +query TT +SHOW CREATE MATERIALIZED VIEW mv1; +---- +materialize.public.mv1 CREATE␠MATERIALIZED␠VIEW␠materialize.public.mv1⏎␠␠␠␠IN␠CLUSTER␠quickstart⏎␠␠␠␠WITH␠(REFRESH␠=␠ON␠COMMIT)⏎␠␠␠␠AS␠SELECT␠1; + +query T +SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW mv1); +---- +CREATE MATERIALIZED VIEW materialize.public.mv1⏎ IN CLUSTER quickstart⏎ WITH (REFRESH = ON COMMIT)⏎ AS SELECT 1; + +simple multiline,conn=mz_catalog_server,user=mz_support +SELECT create_sql FROM (SHOW CREATE MATERIALIZED VIEW mv1); +---- +CREATE MATERIALIZED VIEW materialize.public.mv1 + IN CLUSTER quickstart + WITH (REFRESH = ON COMMIT) + AS SELECT 1; +EOF +COMPLETE 1 diff --git a/test/testdrive-old-kafka-src-syntax/connection-alter.td b/test/testdrive-old-kafka-src-syntax/connection-alter.td index 4a4488e5516e7..5416272f4a2d0 100644 --- a/test/testdrive-old-kafka-src-syntax/connection-alter.td +++ b/test/testdrive-old-kafka-src-syntax/connection-alter.td @@ -55,11 +55,6 @@ contains:Failed to resolve hostname > SELECT status = 'stalled' FROM mz_internal.mz_source_statuses WHERE name = 'mz_source'; true -> SHOW CREATE CONNECTION conn -name create_sql ---------------------------------- -materialize.public.conn "CREATE CONNECTION \"materialize\".\"public\".\"conn\" TO KAFKA (BROKER = 'abcd', SECURITY PROTOCOL = \"plaintext\")" - $ kafka-ingest format=bytes topic=connection_test 2,3 @@ -71,18 +66,8 @@ first second 1 2 2 3 -> SHOW CREATE CONNECTION conn -name create_sql ---------------------------------- -materialize.public.conn "CREATE CONNECTION \"materialize\".\"public\".\"conn\" TO KAFKA (BROKER = '${testdrive.kafka-addr}', SECURITY PROTOCOL = \"plaintext\")" - > ALTER CONNECTION conn SET (BROKERS ['${testdrive.kafka-addr}']) -> SHOW CREATE CONNECTION conn -name create_sql ---------------------------------- -materialize.public.conn "CREATE CONNECTION \"materialize\".\"public\".\"conn\" TO KAFKA (BROKERS = ('${testdrive.kafka-addr}'), SECURITY PROTOCOL = \"plaintext\")" - ! ALTER CONNECTION conn DROP (SECURITY PROTOCOL); contains:Broker does not support SSL connections diff --git a/test/testdrive-old-kafka-src-syntax/connection-create-drop.td b/test/testdrive-old-kafka-src-syntax/connection-create-drop.td index c8280aea04e32..8327ad2119925 100644 --- a/test/testdrive-old-kafka-src-syntax/connection-create-drop.td +++ b/test/testdrive-old-kafka-src-syntax/connection-create-drop.td @@ -56,11 +56,6 @@ testconn kafka > SHOW CONNECTIONS testconn kafka "" -> SHOW CREATE CONNECTION testconn -name create_sql ---------------------------------- -materialize.public.testconn "CREATE CONNECTION \"materialize\".\"public\".\"testconn\" TO KAFKA (BROKER = '${testdrive.kafka-addr}', SECURITY PROTOCOL = \"plaintext\")" - > SELECT brokers, sink_progress_topic = '_materialize-progress-' || mz_environment_id() || '-' || id diff --git a/test/testdrive-old-kafka-src-syntax/createdrop.td b/test/testdrive-old-kafka-src-syntax/createdrop.td index 3531d12b524d4..0030e96d8e4a6 100644 --- a/test/testdrive-old-kafka-src-syntax/createdrop.td +++ b/test/testdrive-old-kafka-src-syntax/createdrop.td @@ -190,11 +190,6 @@ contains:unknown catalog item 'nonexistent' # Test CREATE VIEW IF NOT EXISTS > CREATE VIEW IF NOT EXISTS test1 AS SELECT 42 AS a -> SHOW CREATE VIEW test1 -name create_sql --------------------------------------------------------------------------------------------------- -materialize.public.test1 "CREATE VIEW \"materialize\".\"public\".\"test1\" AS SELECT 42 AS \"a\"" - ! CREATE VIEW test1 AS SELECT 43 AS b contains:view "materialize.public.test1" already exists diff --git a/test/testdrive-old-kafka-src-syntax/indexes.td b/test/testdrive-old-kafka-src-syntax/indexes.td index 5660bc008f911..86ada74f7bdf7 100644 --- a/test/testdrive-old-kafka-src-syntax/indexes.td +++ b/test/testdrive-old-kafka-src-syntax/indexes.td @@ -203,11 +203,6 @@ data_view_primary_idx data_view "{b - a,a}" "" > SET CLUSTER TO quickstart -> SHOW CREATE INDEX data_view_primary_idx -name create_sql --------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.data_view_primary_idx "CREATE INDEX \"data_view_primary_idx\" IN CLUSTER \"\" ON \"materialize\".\"public\".\"data_view\" (\"b\" - \"a\", \"a\")" - > CREATE TABLE foo ( a int NOT NULL, b decimal(13, 1), diff --git a/test/testdrive-old-kafka-src-syntax/load-generator.td b/test/testdrive-old-kafka-src-syntax/load-generator.td index 53ba08831bf94..85da6be0f68e7 100644 --- a/test/testdrive-old-kafka-src-syntax/load-generator.td +++ b/test/testdrive-old-kafka-src-syntax/load-generator.td @@ -56,12 +56,6 @@ exact:COUNTER load generators do not support SCALE FACTOR values > CREATE TABLE organizations FROM SOURCE auction_house (REFERENCE organizations); > CREATE TABLE users FROM SOURCE auction_house (REFERENCE users); -> SHOW CREATE SOURCE auction_house -"materialize.public.auction_house" "CREATE SOURCE \"materialize\".\"public\".\"auction_house\" IN CLUSTER \"${arg.single-replica-cluster}\" FROM LOAD GENERATOR AUCTION (AS OF = 300, UP TO = 301) EXPOSE PROGRESS AS \"materialize\".\"public\".\"auction_house_progress\"" - -> SHOW CREATE TABLE accounts -materialize.public.accounts "CREATE TABLE \"materialize\".\"public\".\"accounts\" (\"id\" \"pg_catalog\".\"int8\" NOT NULL, \"org_id\" \"pg_catalog\".\"int8\" NOT NULL, \"balance\" \"pg_catalog\".\"int8\" NOT NULL, UNIQUE (\"id\")) FROM SOURCE \"materialize\".\"public\".\"auction_house\" (REFERENCE = \"mz_load_generators\".\"auction\".\"accounts\") WITH (DETAILS = '1a040a021002')" - > SHOW SOURCES auction_house load-generator ${arg.single-replica-cluster} "" auction_house_progress progress "" @@ -116,9 +110,6 @@ users "" $ set-regex match="DETAILS = '[a-f0-9]+'" replacement=
-> SHOW CREATE TABLE accounts -materialize.public.accounts "CREATE TABLE \"materialize\".\"public\".\"accounts\" (\"id\" \"pg_catalog\".\"int8\" NOT NULL, \"org_id\" \"pg_catalog\".\"int8\" NOT NULL, \"balance\" \"pg_catalog\".\"int8\" NOT NULL, UNIQUE (\"id\")) FROM SOURCE \"materialize\".\"public\".\"auction_house\" (REFERENCE = \"mz_load_generators\".\"auction\".\"accounts\") WITH (
)" - # CLOCK load generator source > CREATE SOURCE clock diff --git a/test/testdrive-old-kafka-src-syntax/materializations.td b/test/testdrive-old-kafka-src-syntax/materializations.td index 8d6df838706f5..9f5e7d0d6182c 100644 --- a/test/testdrive-old-kafka-src-syntax/materializations.td +++ b/test/testdrive-old-kafka-src-syntax/materializations.td @@ -80,11 +80,6 @@ sum false numeric "" > SHOW VIEWS LIKE '%data%' data_view "" -> SHOW CREATE MATERIALIZED VIEW test1 -name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -materialize.public.test1 "CREATE MATERIALIZED VIEW \"materialize\".\"public\".\"test1\" IN CLUSTER \"quickstart\" WITH (REFRESH = ON COMMIT) AS SELECT \"b\", \"pg_catalog\".\"sum\"(\"a\") FROM \"materialize\".\"public\".\"data\" GROUP BY \"b\"" - # Materialized view can be built on a not-materialized view. > CREATE MATERIALIZED VIEW test2 AS SELECT b, 1 + sum(a + 1) FROM data_view GROUP BY b diff --git a/test/testdrive-old-kafka-src-syntax/rename.td b/test/testdrive-old-kafka-src-syntax/rename.td deleted file mode 100644 index f30c33bf7cec1..0000000000000 --- a/test/testdrive-old-kafka-src-syntax/rename.td +++ /dev/null @@ -1,900 +0,0 @@ -# Copyright Materialize, Inc. and contributors. All rights reserved. -# -# Use of this software is governed by the Business Source License -# included in the LICENSE file at the root of this repository. -# -# As of the Change Date specified in that file, in accordance with -# the Business Source License, use of this software will be governed -# by the Apache License, Version 2.0. - -$ set-arg-default default-replica-size=1 -$ set-arg-default single-replica-cluster=quickstart - -$ set-regex match=u\d+|cluster1|quickstart|testdrive_single_replica_cluster replacement= - -$ set writer-schema={ - "name": "row", - "type": "record", - "fields": [ - {"name": "a", "type": "long"}, - {"name": "b", "type": "string"} - ] - } - -$ kafka-create-topic topic=data -$ kafka-ingest topic=data format=avro schema=${writer-schema} -{"a": 1, "b": "dog"} - -# Create library of objects and verify names -> CREATE CONNECTION kafka_conn - TO KAFKA (BROKER '${testdrive.kafka-addr}', SECURITY PROTOCOL PLAINTEXT); - -> CREATE CONNECTION IF NOT EXISTS csr_conn TO CONFLUENT SCHEMA REGISTRY ( - URL '${testdrive.schema-registry-url}' - ); - -> CREATE SOURCE mz_data - IN CLUSTER ${arg.single-replica-cluster} - FROM KAFKA CONNECTION kafka_conn (TOPIC 'testdrive-data-${testdrive.seed}') - FORMAT AVRO USING SCHEMA '${writer-schema}' - -> CREATE DEFAULT INDEX ON mz_data - -> CREATE SINK sink1 - IN CLUSTER ${arg.single-replica-cluster} - FROM mz_data - INTO KAFKA CONNECTION kafka_conn (TOPIC 'testdrive-snk1-${testdrive.seed}') - FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION csr_conn - ENVELOPE DEBEZIUM - -> CREATE VIEW mz_view AS - SELECT * FROM mz_data - -> CREATE DEFAULT INDEX ON mz_view - -> SHOW INDEXES ON mz_view -name on cluster key comment --------------------------------------------------------------------------------------------- -mz_view_primary_idx mz_view {a,b} "" - -> CREATE VIEW dependent_view AS - SELECT * FROM mz_view; - -> CREATE VIEW byzantine_view AS - SELECT mz_data.a, mz_view.b FROM mz_data JOIN mz_view ON mz_data.a = mz_view.a; - -> CREATE VIEW oppositional_view AS - SELECT * FROM mz_view WHERE b = ' - an adversarial string - "materialize"."public"."mz_data" - '; - -> CREATE VIEW public_objects AS - SELECT mz_objects.id, mz_objects.oid, mz_objects.schema_id, mz_objects.name, mz_objects.type - FROM mz_objects - JOIN mz_schemas ON mz_objects.schema_id = mz_schemas.id - WHERE mz_schemas.name = 'public'; - -> SELECT name FROM public_objects WHERE name LIKE 'mz_data%'; -name ------ -mz_data -mz_data_primary_idx -mz_data_progress - -# Test that data can be selected from the source before renaming. -> SELECT * FROM mz_data -a b ------- -1 dog - -! ALTER VIEW mz_data RENAME TO renamed_mz_data; -exact:mz_data is a source not a view - -! ALTER INDEX mz_data RENAME TO renamed_mz_data; -exact:mz_data is a source not an index - -> ALTER SOURCE mz_data RENAME TO renamed_mz_data; - -> SELECT name FROM public_objects WHERE name LIKE 'mz_data%'; -name ------ -mz_data_primary_idx -mz_data_progress - -> SELECT name FROM public_objects WHERE name LIKE 'renamed_mz_data%'; -name ------ -renamed_mz_data - -# Test that data can be selected from the source after renaming. -> SELECT * FROM renamed_mz_data -a b ------- -1 dog - -# Test that data can be selected from the source if it is rematerialized with -# the new name. This previously tripped an assertion that asserted that a source -# descriptor never changed; it is in fact okay for the name of a source to -# change. -> DROP INDEX mz_data_primary_idx -> CREATE DEFAULT INDEX ON renamed_mz_data -> SELECT * FROM renamed_mz_data -a b ------- -1 dog - -> SELECT name FROM public_objects WHERE name LIKE 'mz_view%'; -name ------ -mz_view -mz_view_primary_idx - -! ALTER SOURCE mz_view RENAME TO renamed_mz_view; -exact:mz_view is a view not a source - -! ALTER INDEX mz_view RENAME TO renamed_mz_view; -exact:mz_view is a view not an index - -> ALTER VIEW mz_view RENAME TO renamed_mz_view; - -> SELECT name FROM public_objects WHERE name LIKE 'mz_view%'; -name ------ -mz_view_primary_idx - -> SELECT name FROM public_objects WHERE name LIKE 'renamed_mz_view%'; -name ------ -renamed_mz_view - -> SELECT name FROM public_objects WHERE name LIKE 'mz_view_primary_idx%'; -name ------ -mz_view_primary_idx - -! ALTER VIEW mz_view_primary_idx RENAME TO renamed_index; -exact:mz_view_primary_idx is an index not a view - -! ALTER SOURCE mz_view_primary_idx RENAME TO renamed_index; -exact:mz_view_primary_idx is an index not a source - -> ALTER INDEX mz_view_primary_idx RENAME TO renamed_index; - -> SELECT name FROM public_objects WHERE name LIKE 'mz_view_primary_idx%'; -name ------ - -> SELECT name FROM public_objects WHERE name LIKE 'renamed_index%'; -name ------ -renamed_index - -> SELECT name FROM public_objects WHERE name LIKE 'sink1%'; -name ------ -sink1 - -! ALTER VIEW sink1 RENAME TO renamed_sink; -exact:sink1 is a sink not a view - -> ALTER SINK sink1 RENAME TO renamed_sink - -> SELECT name FROM public_objects WHERE name LIKE 'sink1%'; -name ------ - -> SELECT name FROM public_objects WHERE name LIKE 'renamed_sink%'; -name ------ -renamed_sink - -# Clean up temp view -> DROP VIEW public_objects; - -# Source was successfully renamed -> SHOW SOURCES; -name type cluster comment ------------------------------------------------------------------ -mz_data_progress progress "" -renamed_mz_data kafka "" - -# Sink was successfully renamed -> SHOW SINKS -name type cluster comment ----------------------------------------------------- -renamed_sink kafka "" - -# View was successfully renamed -> SHOW VIEWS -name comment --------------------------- -byzantine_view "" -dependent_view "" -oppositional_view "" -renamed_mz_view "" - -# Item's own `CREATE VIEW` statement updated -> SHOW CREATE VIEW renamed_mz_view -name create_sql ---------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.renamed_mz_view "CREATE VIEW \"materialize\".\"public\".\"renamed_mz_view\" AS SELECT * FROM \"materialize\".\"public\".\"renamed_mz_data\"" - -# Item's indexes are properly re-attributed -> SHOW INDEXES ON renamed_mz_view -name on cluster key comment --------------------------------------------------------------------------------------------- -renamed_index renamed_mz_view {a,b} "" - -> SHOW CREATE INDEX renamed_index -name create_sql ---------------------------------------------------------------------------------------------------------------------- -materialize.public.renamed_index "CREATE INDEX \"renamed_index\" IN CLUSTER \"\" ON \"materialize\".\"public\".\"renamed_mz_view\" (\"a\", \"b\")" - -# Simple dependencies are renamed -> SHOW CREATE VIEW dependent_view -name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.dependent_view "CREATE VIEW \"materialize\".\"public\".\"dependent_view\" AS SELECT * FROM \"materialize\".\"public\".\"renamed_mz_view\"" - -$ skip-if -SELECT mz_version_num() < 13500; - -> SHOW CREATE SINK renamed_sink -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.renamed_sink "CREATE SINK \"materialize\".\"public\".\"renamed_sink\" IN CLUSTER \"\" FROM \"materialize\".\"public\".\"renamed_mz_data\" INTO KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-snk1-${testdrive.seed}') FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION \"materialize\".\"public\".\"csr_conn\" ENVELOPE DEBEZIUM" - -$ skip-end - -# Simple dependencies with both fully qualified and unqualified item references are renamed -> SHOW CREATE VIEW byzantine_view -name create_sql ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.byzantine_view "CREATE VIEW \"materialize\".\"public\".\"byzantine_view\" AS SELECT \"renamed_mz_data\".\"a\", \"renamed_mz_view\".\"b\" FROM \"materialize\".\"public\".\"renamed_mz_data\" JOIN \"materialize\".\"public\".\"renamed_mz_view\" ON \"renamed_mz_data\".\"a\" = \"renamed_mz_view\".\"a\"" - -# Strings containing old item name are not modified -> SHOW CREATE VIEW oppositional_view -name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.oppositional_view "CREATE VIEW \"materialize\".\"public\".\"oppositional_view\" AS SELECT * FROM \"materialize\".\"public\".\"renamed_mz_view\" WHERE \"b\" = '\n an adversarial string\n \"materialize\".\"public\".\"mz_data\"\n '" - -# 🔬 Name collisions - -> ALTER VIEW renamed_mz_view RENAME TO t1 -> CREATE VIEW a AS SELECT 1 AS a -> CREATE VIEW v0 AS SELECT 2 AS b -> CREATE VIEW t2 (a, b, t1_a, t1_b) AS - SELECT * FROM a - JOIN v0 - ON a.a = v0.b - JOIN t1 - ON a.a = t1.a; - -# ❌ Identifiers used in dependent items -! ALTER VIEW t1 RENAME TO b; -contains:renaming conflict -! ALTER VIEW t1 RENAME TO materialize; -contains:renaming conflict -! ALTER VIEW t1 RENAME TO public; -contains:renaming conflict - -# ❌ Identifiers used in own definition -# `materialize.public.a` contains an unqualified reference to `materialize.public.t1.a`. -! ALTER VIEW a RENAME TO anything -contains:renaming conflict -! ALTER VIEW v0 RENAME TO b -contains:renaming conflict - -# ❌ Name used by another item in schema's catalog -! ALTER VIEW t1 RENAME TO a -contains:catalog item 'a' already exists -! ALTER VIEW t1 RENAME TO dependent_view; -contains:catalog item 'dependent_view' already exists - -# 🔬 Aliases - -> CREATE VIEW table_alias_check AS - SELECT t1.a AS b - FROM ( - SELECT a - FROM t1 - ) AS t1; - -# ❌ View name used as alias -! ALTER VIEW t1 RENAME TO anything -contains:renaming conflict - -# 🔬 Unresolvable without scope analysis -# These are example queries whose ambiguity cannot be resolved through -# simple ident analysis; i.e. you need either real or strictly inferred scope -# information to disambiguate references to `db0.scm0.z`. - -> CREATE DATABASE IF NOT EXISTS db0; -> CREATE SCHEMA IF NOT EXISTS db0.scm0; -> CREATE VIEW db0.scm0.z AS SELECT 1 AS a; - -> CREATE SCHEMA IF NOT EXISTS materialize.db0; -> CREATE VIEW materialize.db0.scm0 AS SELECT 1 AS z; - -> CREATE VIEW final_boss_1 AS - SELECT db0.scm0.z, db0.scm0.z.a - FROM db0.scm0.z - JOIN db0.scm0 - ON db0.scm0.z = db0.scm0.z.a; - -# ❌ Item name used as column -! ALTER VIEW db0.scm0.z RENAME TO anything -contains:renaming conflict -# ❌ Item name used as schema -! ALTER VIEW db0.scm0 RENAME TO anything -contains:renaming conflict - -> CREATE SCHEMA IF NOT EXISTS materialize.scm0; -> CREATE VIEW materialize.scm0.z AS SELECT 1 AS a; -> CREATE VIEW materialize.public.scm0 AS SELECT 1 AS z; - -> CREATE VIEW final_boss_2 AS - SELECT scm0.z, scm0.z.a - FROM scm0.z - JOIN scm0 - ON scm0.z = scm0.z.a; - -# ❌ Item name used as column -! ALTER VIEW scm0.z RENAME TO anything -contains:renaming conflict -# ❌ Item name used as schema -! ALTER VIEW scm0 RENAME TO anything -contains:renaming conflict - -# 🔬 DB::DB - -# 🔬🔬 DB::DB - DB-level qualification -> CREATE DATABASE IF NOT EXISTS db1 -> CREATE DATABASE IF NOT EXISTS db2 - -> CREATE SCHEMA IF NOT EXISTS db1.scm1 -> CREATE SCHEMA IF NOT EXISTS db2.scm1 - -> CREATE VIEW db1.scm1.v AS SELECT 1 as a; -> CREATE VIEW db2.scm1.v AS SELECT 2 as b; - -# References to `v` are ambiguous because not all references are sufficiently -# qualified. This won't work until we have database-level qualification. -> CREATE VIEW db1_db2_scm1_min_qual_invalid AS - SELECT * FROM - ( - SELECT v.a FROM db1.scm1.v - ) AS l - JOIN ( - SELECT v.b FROM db2.scm1.v - ) AS r - ON l.a = r.b; - -# ❌ Insufficient qualification -! ALTER VIEW db1.scm1.v rename to anything; -contains:renaming conflict -! ALTER VIEW db2.scm1.v rename to anything; -contains:renaming conflict - -> DROP VIEW db1_db2_scm1_min_qual_invalid - -# References to `v` are ambiguous because not all references are sufficiently -# qualified. -> CREATE VIEW db1_db2_scm1_mix_qual_invalid AS - SELECT * FROM - ( - SELECT db1.scm1.v.a FROM db1.scm1.v - ) AS l - JOIN ( - SELECT scm1.v.b FROM db2.scm1.v - ) AS r - ON l.a = r.b; - -# ❌ Insufficient qualification -! ALTER VIEW db1.scm1.v rename to anything; -contains:renaming conflict -! ALTER VIEW db2.scm1.v rename to anything; -contains:renaming conflict - -> DROP VIEW db1_db2_scm1_mix_qual_invalid - -# Fully qualifying references allows renaming -> CREATE VIEW db1_db2_scm1_valid_qual AS - SELECT * FROM - ( - SELECT db1.scm1.v.a FROM db1.scm1.v - ) AS l - JOIN ( - SELECT db2.scm1.v.b FROM db2.scm1.v - ) AS r - ON l.a = r.b; - -# ✅ Sufficient qualification + new idents -> ALTER VIEW db1.scm1.v RENAME TO v0 -> ALTER VIEW db1.scm1.v0 RENAME TO v1 -> ALTER VIEW db2.scm1.v RENAME TO v2 - -> SHOW CREATE VIEW db1_db2_scm1_valid_qual -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.db1_db2_scm1_valid_qual "CREATE VIEW \"materialize\".\"public\".\"db1_db2_scm1_valid_qual\" AS SELECT * FROM (SELECT \"db1\".\"scm1\".\"v1\".\"a\" FROM \"db1\".\"scm1\".\"v1\") AS \"l\" JOIN (SELECT \"db2\".\"scm1\".\"v2\".\"b\" FROM \"db2\".\"scm1\".\"v2\") AS \"r\" ON \"l\".\"a\" = \"r\".\"b\"" - -> CREATE VIEW "materialize"."public"."db1_db2_scm1_valid_qual_test" AS SELECT * FROM (SELECT "db1"."scm1"."v1"."a" FROM "db1"."scm1"."v1") AS "l" JOIN (SELECT "db2"."scm1"."v2"."b" FROM "db2"."scm1"."v2") AS "r" ON "l"."a" = "r"."b" - -# 🔬🔬 DB::DB - No qualification necessary -# Evaluate ability to handle two database-qualified references. -> CREATE SCHEMA db2.scm2; -> CREATE VIEW db2.scm2.v2 AS - SELECT 1 AS z; - -> CREATE VIEW db_db_qual_diff_s_v AS - SELECT db2.scm2.v2.z - FROM db2.scm2.v2 - JOIN db1.scm1.v1 - ON db2.scm2.v2.z = db1.scm1.v1.a - -# ❌ Identifiers used in dependent items -! ALTER VIEW db2.scm2.v2 RENAME TO db2; -contains:renaming conflict -! ALTER VIEW db2.scm2.v2 RENAME TO scm2; -contains:renaming conflict -! ALTER VIEW db2.scm2.v2 RENAME TO z; -contains:renaming conflict -! ALTER VIEW db2.scm2.v2 RENAME TO scm2; -contains:renaming conflict -! ALTER VIEW db2.scm2.v2 RENAME TO a; -contains:renaming conflict - -# ✅ New idents -> ALTER VIEW db2.scm2.v2 RENAME TO v3; -> ALTER VIEW db1.scm1.v1 RENAME TO v4; - -> SHOW CREATE VIEW db_db_qual_diff_s_v -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.db_db_qual_diff_s_v "CREATE VIEW \"materialize\".\"public\".\"db_db_qual_diff_s_v\" AS SELECT \"db2\".\"scm2\".\"v3\".\"z\" FROM \"db2\".\"scm2\".\"v3\" JOIN \"db1\".\"scm1\".\"v4\" ON \"db2\".\"scm2\".\"v3\".\"z\" = \"db1\".\"scm1\".\"v4\".\"a\"" - -> CREATE VIEW "materialize"."public"."db_db_qual_diff_s_v_test" AS SELECT "db2"."scm2"."v3"."z" FROM "db2"."scm2"."v3" JOIN "db1"."scm1"."v4" ON "db2"."scm2"."v3"."z" = "db1"."scm1"."v4"."a" - -# 🔬 DB::Schema -# Evaluate ability to handle one database-qualified reference and one -# schema-qualified reference. - -> CREATE SCHEMA IF NOT EXISTS scm3 - -> CREATE VIEW scm3.v2 AS - SELECT 1 AS z; - -> CREATE VIEW db_scm_qual AS - SELECT scm3.v2.z, db1.scm1.v4.a - FROM scm3.v2 - JOIN db1.scm1.v4 - ON scm3.v2.z = db1.scm1.v4.a; - -> ALTER VIEW scm3.v2 RENAME TO v3; -> ALTER VIEW db1.scm1.v4 RENAME TO v5; - -> SHOW CREATE VIEW db_scm_qual -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.db_scm_qual "CREATE VIEW \"materialize\".\"public\".\"db_scm_qual\" AS SELECT \"scm3\".\"v3\".\"z\", \"db1\".\"scm1\".\"v5\".\"a\" FROM \"materialize\".\"scm3\".\"v3\" JOIN \"db1\".\"scm1\".\"v5\" ON \"scm3\".\"v3\".\"z\" = \"db1\".\"scm1\".\"v5\".\"a\"" - -> CREATE VIEW "materialize"."public"."db_scm_qual_test" AS SELECT "scm3"."v3"."z", "db1"."scm1"."v5"."a" FROM "materialize"."scm3"."v3" JOIN "db1"."scm1"."v5" ON "scm3"."v3"."z" = "db1"."scm1"."v5"."a" - -# 🔬 DB::View -# Evaluate ability to handle one database-qualified reference and one -# implicitly-qualified reference. - -> CREATE VIEW v1 AS - SELECT 1 AS z; - -> CREATE VIEW db_v_qual AS - SELECT v1.z, db1.scm1.v5.a - FROM v1 - JOIN db1.scm1.v5 - ON v1.z = db1.scm1.v5.a; - -# ❌ Identifiers used in dependent items -! ALTER VIEW v1 RENAME TO z; -contains:renaming conflict -! ALTER VIEW v1 RENAME TO db1; -contains:renaming conflict -! ALTER VIEW v1 RENAME TO scm1; -contains:renaming conflict -! ALTER VIEW v1 RENAME TO v5; -contains:renaming conflict -! ALTER VIEW db1.scm1.v5 RENAME TO v1; -contains:renaming conflict - -# ✅ New idents -> ALTER VIEW v1 RENAME TO v2; -> ALTER VIEW db1.scm1.v5 RENAME TO v6; - -> SHOW CREATE VIEW db_v_qual -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.db_v_qual "CREATE VIEW \"materialize\".\"public\".\"db_v_qual\" AS SELECT \"v2\".\"z\", \"db1\".\"scm1\".\"v6\".\"a\" FROM \"materialize\".\"public\".\"v2\" JOIN \"db1\".\"scm1\".\"v6\" ON \"v2\".\"z\" = \"db1\".\"scm1\".\"v6\".\"a\"" - -> CREATE VIEW "materialize"."public"."db_v_qual_test" AS SELECT "v2"."z", "db1"."scm1"."v6"."a" FROM "materialize"."public"."v2" JOIN "db1"."scm1"."v6" ON "v2"."z" = "db1"."scm1"."v6"."a" - -# 🔬 Schema::Schema - -# 🔬🔬 Require schema-level qualification -> CREATE DATABASE IF NOT EXISTS db1 -> CREATE SCHEMA IF NOT EXISTS db1.scm1 -> CREATE SCHEMA IF NOT EXISTS db1.scm2 - -> CREATE VIEW db1.scm1.v AS SELECT 1 as a; -> CREATE VIEW db1.scm2.v AS SELECT 2 as b; - -# References to `v` are ambiguous because not all references are sufficiently -# qualified. This won't work until we have schema-level qualification. -> CREATE VIEW db1_scm1_scm2_min_qual_invalid AS - SELECT * FROM - ( - SELECT v.a FROM db1.scm1.v - ) AS l - JOIN ( - SELECT v.b FROM db1.scm2.v - ) AS r - ON l.a = r.b; - -# ❌ Insufficient qualification -! ALTER VIEW db1.scm1.v rename to anything; -contains:renaming conflict -! ALTER VIEW db1.scm2.v rename to anything; -contains:renaming conflict - -> DROP VIEW db1_scm1_scm2_min_qual_invalid - -# References to `v` are ambiguous because not all references are sufficiently -# qualified. -> CREATE VIEW db1_scm1_scm2_mix_qual_invalid AS - SELECT * FROM - ( - SELECT db1.scm1.v.a FROM db1.scm1.v - ) AS l - JOIN ( - SELECT v.b FROM db1.scm2.v - ) AS r - ON l.a = r.b; - -# ❌ Insufficient qualification -! ALTER VIEW db1.scm1.v rename to anything; -contains:renaming conflict -! ALTER VIEW db1.scm2.v rename to anything; -contains:renaming conflict - -> DROP VIEW db1_scm1_scm2_mix_qual_invalid - -# Qualifying to the point of differentiation allows renaming -> CREATE VIEW db1_scm1_scm2_valid_qual AS - SELECT * FROM - ( - SELECT scm1.v.a FROM db1.scm1.v - ) AS l - JOIN ( - SELECT scm2.v.b FROM db1.scm2.v - ) AS r - ON l.a = r.b; - -# ✅ Sufficient qualification + new idents -> ALTER VIEW db1.scm1.v RENAME TO v3 -> ALTER VIEW db1.scm1.v3 RENAME TO v4 -> ALTER VIEW db1.scm2.v RENAME TO v5 - -> SHOW CREATE VIEW db1_scm1_scm2_valid_qual -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.db1_scm1_scm2_valid_qual "CREATE VIEW \"materialize\".\"public\".\"db1_scm1_scm2_valid_qual\" AS SELECT * FROM (SELECT \"scm1\".\"v4\".\"a\" FROM \"db1\".\"scm1\".\"v4\") AS \"l\" JOIN (SELECT \"scm2\".\"v5\".\"b\" FROM \"db1\".\"scm2\".\"v5\") AS \"r\" ON \"l\".\"a\" = \"r\".\"b\"" - -> CREATE VIEW "materialize"."public"."db1_scm1_scm2_valid_qual_test" AS SELECT * FROM (SELECT "scm1"."v4"."a" FROM "db1"."scm1"."v4") AS "l" JOIN (SELECT "scm2"."v5"."b" FROM "db1"."scm2"."v5") AS "r" ON "l"."a" = "r"."b" - -# 🔬🔬 No qualification necessary -> CREATE SCHEMA IF NOT EXISTS scm4; -> CREATE SCHEMA IF NOT EXISTS scm5; - -> CREATE VIEW scm4.v1 AS - SELECT 1 AS z; - -> CREATE VIEW scm5.v2 AS - SELECT 1 AS a; - -> CREATE VIEW scm_scm_qual AS - SELECT scm4.v1.z, scm5.v2.a - FROM scm4.v1 - JOIN scm5.v2 - ON scm4.v1.z = scm5.v2.a; - -# ❌ Identifiers used in dependent items -! ALTER VIEW scm4.v1 RENAME TO z; -contains:renaming conflict -! ALTER VIEW scm4.v1 RENAME TO scm5; -contains:renaming conflict -! ALTER VIEW scm4.v1 RENAME TO v2; -contains:renaming conflict -! ALTER VIEW scm4.v1 RENAME TO a; -contains:renaming conflict -! ALTER VIEW scm5.v2 RENAME TO a; -contains:renaming conflict -! ALTER VIEW scm5.v2 RENAME TO v1; -contains:renaming conflict - -# ✅ New idents -> ALTER VIEW scm4.v1 RENAME TO v3; -> ALTER VIEW scm5.v2 RENAME TO v4; - -> SHOW CREATE VIEW scm_scm_qual -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.scm_scm_qual "CREATE VIEW \"materialize\".\"public\".\"scm_scm_qual\" AS SELECT \"scm4\".\"v3\".\"z\", \"scm5\".\"v4\".\"a\" FROM \"materialize\".\"scm4\".\"v3\" JOIN \"materialize\".\"scm5\".\"v4\" ON \"scm4\".\"v3\".\"z\" = \"scm5\".\"v4\".\"a\"" - -> CREATE VIEW "materialize"."public"."scm_scm_qual_test" AS SELECT "scm4"."v3"."z", "scm5"."v4"."a" FROM "materialize"."scm4"."v3" JOIN "materialize"."scm5"."v4" ON "scm4"."v3"."z" = "scm5"."v4"."a" - -# 🔬 Schema::View -# Evaluate ability to handle one schema-qualified reference and one -# implicitly-qualified reference. - -> CREATE VIEW v1 AS - SELECT 1 AS z; - -> CREATE VIEW scm_v_qual AS - SELECT v1.z, scm5.v4.a - FROM v1 - JOIN scm5.v4 - ON v1.z = scm5.v4.a; - -# ❌ Identifiers used in dependent items -! ALTER VIEW v1 RENAME TO z; -contains:renaming conflict -! ALTER VIEW v1 RENAME TO scm5; -contains:renaming conflict -! ALTER VIEW v1 RENAME TO v4; -contains:renaming conflict - -# ✅ New idents -> ALTER VIEW v1 RENAME TO v3; -> ALTER VIEW scm5.v4 RENAME TO v6; - -> SHOW CREATE VIEW scm_v_qual -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.scm_v_qual "CREATE VIEW \"materialize\".\"public\".\"scm_v_qual\" AS SELECT \"v3\".\"z\", \"scm5\".\"v6\".\"a\" FROM \"materialize\".\"public\".\"v3\" JOIN \"materialize\".\"scm5\".\"v6\" ON \"v3\".\"z\" = \"scm5\".\"v6\".\"a\"" - -> CREATE VIEW "materialize"."public"."scm_v_qual_test" AS SELECT "v3"."z", "scm5"."v6"."a" FROM "materialize"."public"."v3" JOIN "materialize"."scm5"."v6" ON "v3"."z" = "scm5"."v6"."a" - -# 🔬 View::View -# Evaluate ability to handle two implicitly-qualified references. - -> CREATE VIEW v4 AS - SELECT 1 AS a - -> CREATE VIEW v_v_qual AS - SELECT v3.z, v4.a - FROM v3 - JOIN v4 - ON v3.z = v4.a - -# ❌ Identifiers used in dependent items -! ALTER VIEW v4 RENAME TO z; -contains:renaming conflict - -# ✅ New idents -> ALTER VIEW v4 RENAME TO v6; -> ALTER VIEW v3 RENAME TO v5; - -> SHOW CREATE VIEW v_v_qual -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.v_v_qual "CREATE VIEW \"materialize\".\"public\".\"v_v_qual\" AS SELECT \"v5\".\"z\", \"v6\".\"a\" FROM \"materialize\".\"public\".\"v5\" JOIN \"materialize\".\"public\".\"v6\" ON \"v5\".\"z\" = \"v6\".\"a\"" - -> CREATE VIEW "materialize"."public"."v_v_qual_test" AS SELECT "v5"."z", "v6"."a" FROM "materialize"."public"."v5" JOIN "materialize"."public"."v6" ON "v5"."z" = "v6"."a" - -# 🔬 Qualified wildcard - -> CREATE VIEW qualified_wildcard AS - SELECT v5.* - FROM v5 - -# ✅ New idents -> ALTER VIEW v5 RENAME TO v7 - -> SHOW CREATE VIEW qualified_wildcard -name create_sql ---------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.qualified_wildcard "CREATE VIEW \"materialize\".\"public\".\"qualified_wildcard\" AS SELECT \"v7\".* FROM \"materialize\".\"public\".\"v7\"" - -> CREATE VIEW "materialize"."public"."qualified_wildcard_test" AS SELECT "v7".* FROM "materialize"."public"."v7" - -# 🔬 WHERE...IN - -> CREATE VIEW where_in_subquery AS - SELECT b FROM t1 WHERE a IN (SELECT a FROM scm5.v6); - -> CREATE VIEW where_in_literal AS - SELECT b FROM t1 WHERE b IN ('v8') - -# ❌ Identifiers used in dependent items -! ALTER VIEW where_in_subquery RENAME TO scm5 -contains:renaming conflict - -# ✅ New idents -> ALTER VIEW where_in_literal RENAME TO v8 -> ALTER VIEW v8 RENAME TO v9 - -> SHOW CREATE VIEW v9 -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.v9 "CREATE VIEW \"materialize\".\"public\".\"v9\" AS SELECT \"b\" FROM \"materialize\".\"public\".\"t1\" WHERE \"b\" IN ('v8')" - -> CREATE VIEW "materialize"."public"."where_in_literal_test" AS SELECT "b" FROM "materialize"."public"."t1" WHERE "b" IN ('v8') - -# 🔬🔬🔬 Spaces - -> CREATE VIEW space AS - SELECT 1 as "has space"; - -> CREATE VIEW "already has space" AS - SELECT 1 as my_space; - -> CREATE VIEW space_dependent AS - SELECT * FROM space - JOIN "already has space" - ON "already has space".my_space = space."has space"; - -# ❌ Identifiers used in own definition -! ALTER VIEW space RENAME TO "has space" -contains:renaming conflict -! ALTER VIEW "already has space" RENAME TO my_space -contains:renaming conflict - -# ✅ New idents -> ALTER VIEW space RENAME TO "now has space" -> ALTER VIEW "already has space" RENAME TO "still has space" - -> SHOW CREATE VIEW space_dependent -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.space_dependent "CREATE VIEW \"materialize\".\"public\".\"space_dependent\" AS SELECT * FROM \"materialize\".\"public\".\"now has space\" JOIN \"materialize\".\"public\".\"still has space\" ON \"still has space\".\"my_space\" = \"now has space\".\"has space\"" - -> CREATE VIEW "materialize"."public"."space_dependent_test" AS SELECT * FROM "materialize"."public"."now has space" JOIN "materialize"."public"."still has space" ON "still has space"."my_space" = "now has space"."has space" - -# 🔬 Keyword - -> CREATE VIEW natural AS - SELECT * FROM t1 NATURAL JOIN t1 AS a; - -# ✅ Keywords are never trapped in a rename -> ALTER VIEW natural RENAME TO unnatural - -> SHOW CREATE VIEW unnatural -name create_sql -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.unnatural "CREATE VIEW \"materialize\".\"public\".\"unnatural\" AS SELECT * FROM \"materialize\".\"public\".\"t1\" NATURAL JOIN \"materialize\".\"public\".\"t1\" AS \"a\"" - -> CREATE VIEW "materialize"."public"."unnatural_test" AS SELECT * FROM "materialize"."public"."t1" NATURAL JOIN "materialize"."public"."t1" AS "a" - -# 🔬 Function names - -> CREATE VIEW func AS - SELECT count(1) - -> CREATE VIEW no_func AS - SELECT 1 AS a; - -> CREATE VIEW func_dependency (a, x_a) AS - SELECT * FROM no_func - JOIN ( - SELECT * FROM no_func - ) AS x - ON no_func.a = x.a; - -# ❌ Identifiers used in dependent items -! ALTER VIEW func RENAME TO count -contains:renaming conflict - -# ✅ Non-colliding function name -> ALTER VIEW no_func RENAME TO count - -> SHOW CREATE VIEW func_dependency -name create_sql ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.func_dependency "CREATE VIEW \"materialize\".\"public\".\"func_dependency\" (\"a\", \"x_a\") AS SELECT * FROM \"materialize\".\"public\".\"count\" JOIN (SELECT * FROM \"materialize\".\"public\".\"count\") AS \"x\" ON \"count\".\"a\" = \"x\".\"a\"" - -> CREATE VIEW "materialize"."public"."func_dependency_test" ("a", "x_a") AS SELECT * FROM count JOIN (SELECT * FROM count) AS x ON count.a = x.a - -> SHOW CREATE VIEW count -name create_sql ---------------------------------------------------------------------------------------- -materialize.public.count "CREATE VIEW \"materialize\".\"public\".\"count\" AS SELECT 1 AS \"a\"" - -> DROP VIEW count CASCADE; - -> CREATE VIEW count AS SELECT 1 - -> CREATE TABLE j (b int) - -> SHOW TABLES -name comment -------------- -j "" - -> ALTER TABLE j RENAME TO renamed_j - -> SHOW TABLES -name comment ------------------- -renamed_j "" - -> SELECT name FROM mz_tables WHERE id like 'u%'; -name ------- -renamed_j - -# Test that after renaming a materialized object it is possible to create -# another object with the original name. This used to fail because the index -# on the original object is not renamed. See database-issues#1585. -> CREATE TABLE t_orig () -> ALTER TABLE t_orig RENAME TO t_dontcare -> CREATE TABLE t_orig () -> CREATE VIEW v_orig AS SELECT 1 -> CREATE DEFAULT INDEX ON v_orig -> ALTER VIEW v_orig RENAME TO v_dontcare -> CREATE VIEW v_orig AS SELECT 1 -> CREATE DEFAULT INDEX ON v_orig - -# Test renaming a schema that contains objects. - -> CREATE SCHEMA to_be_renamed; - -> SET SCHEMA TO to_be_renamed; - -> CREATE SOURCE mz_data - IN CLUSTER ${arg.single-replica-cluster} - FROM KAFKA CONNECTION public.kafka_conn (TOPIC 'testdrive-data-${testdrive.seed}') - FORMAT AVRO USING SCHEMA '${writer-schema}' - -> CREATE DEFAULT INDEX ON mz_data - -> CREATE SINK sink1 - IN CLUSTER ${arg.single-replica-cluster} - FROM mz_data - INTO KAFKA CONNECTION public.kafka_conn (TOPIC 'testdrive-snk1-rename-schema-${testdrive.seed}') - FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION public.csr_conn - ENVELOPE DEBEZIUM - -> SET SCHEMA TO public; - -# Check the initial state of the create_sql. - -> SHOW CREATE SOURCE to_be_renamed.mz_data; -name create_sql ---------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.to_be_renamed.mz_data "CREATE SOURCE \"materialize\".\"to_be_renamed\".\"mz_data\" IN CLUSTER \"\" FROM KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-data-${testdrive.seed}') FORMAT AVRO USING SCHEMA '{ \"name\": \"row\", \"type\": \"record\", \"fields\": [ {\"name\": \"a\", \"type\": \"long\"}, {\"name\": \"b\", \"type\": \"string\"} ] }' EXPOSE PROGRESS AS \"materialize\".\"to_be_renamed\".\"mz_data_progress\"" - -$ skip-if -SELECT mz_version_num() < 13500; - -> SHOW CREATE SINK to_be_renamed.sink1; -name create_sql ---------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.to_be_renamed.sink1 "CREATE SINK \"materialize\".\"to_be_renamed\".\"sink1\" IN CLUSTER \"\" FROM \"materialize\".\"to_be_renamed\".\"mz_data\" INTO KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-snk1-rename-schema-${testdrive.seed}') FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION \"materialize\".\"public\".\"csr_conn\" ENVELOPE DEBEZIUM" -# Make sure the create_sql got updated. - -$ skip-end - -> ALTER SCHEMA to_be_renamed RENAME TO foo_bar; - -> SHOW CREATE SOURCE foo_bar.mz_data; -name create_sql ---------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.foo_bar.mz_data "CREATE SOURCE \"materialize\".\"foo_bar\".\"mz_data\" IN CLUSTER \"\" FROM KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-data-${testdrive.seed}') FORMAT AVRO USING SCHEMA '{ \"name\": \"row\", \"type\": \"record\", \"fields\": [ {\"name\": \"a\", \"type\": \"long\"}, {\"name\": \"b\", \"type\": \"string\"} ] }' EXPOSE PROGRESS AS \"materialize\".\"foo_bar\".\"mz_data_progress\"" - -$ skip-if -SELECT mz_version_num() < 13500; - -> SHOW CREATE SINK foo_bar.sink1; -name create_sql ---------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.foo_bar.sink1 "CREATE SINK \"materialize\".\"foo_bar\".\"sink1\" IN CLUSTER \"\" FROM \"materialize\".\"foo_bar\".\"mz_data\" INTO KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-snk1-rename-schema-${testdrive.seed}') FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION \"materialize\".\"public\".\"csr_conn\" ENVELOPE DEBEZIUM" diff --git a/test/testdrive-old-kafka-src-syntax/tables.td b/test/testdrive-old-kafka-src-syntax/tables.td index a4c17921d03d0..f90b6707dd0ae 100644 --- a/test/testdrive-old-kafka-src-syntax/tables.td +++ b/test/testdrive-old-kafka-src-syntax/tables.td @@ -19,11 +19,6 @@ contains:unknown catalog item 't' > CREATE TABLE t (a int, b text NOT NULL) -> SHOW CREATE TABLE t; -name create_sql ------------------------- -materialize.public.t "CREATE TABLE \"materialize\".\"public\".\"t\" (\"a\" \"pg_catalog\".\"int4\", \"b\" \"pg_catalog\".\"text\" NOT NULL)" - > CREATE TABLE s (a int DEFAULT 1) > DROP TABLE s; diff --git a/test/testdrive/catalog.td b/test/testdrive/catalog.td index 684d564489ab7..fc37265ba30c3 100644 --- a/test/testdrive/catalog.td +++ b/test/testdrive/catalog.td @@ -385,7 +385,7 @@ v1 view "" v2 view "" > SELECT create_sql FROM (SHOW CREATE TABLE tbl) -"CREATE TABLE \"d\".\"public\".\"tbl\" (\"a\" \"pg_catalog\".\"int4\", \"b\" \"pg_catalog\".\"text\")" +"CREATE TABLE d.public.tbl (a pg_catalog.int4, b pg_catalog.text);" ! SHOW COLUMNS FROM pass_secret contains:d.public.pass_secret is a secret and so does not have columns diff --git a/test/testdrive/connection-alter.td b/test/testdrive/connection-alter.td index b6306a1729b38..a5412cba518b1 100644 --- a/test/testdrive/connection-alter.td +++ b/test/testdrive/connection-alter.td @@ -60,7 +60,7 @@ true > SHOW CREATE CONNECTION conn name create_sql --------------------------------- -materialize.public.conn "CREATE CONNECTION \"materialize\".\"public\".\"conn\" TO KAFKA (BROKER = 'abcd', SECURITY PROTOCOL = \"plaintext\")" +materialize.public.conn "CREATE CONNECTION materialize.public.conn TO KAFKA (BROKER = 'abcd', SECURITY PROTOCOL = plaintext);" $ kafka-ingest format=bytes topic=connection_test 2,3 @@ -76,14 +76,14 @@ first second > SHOW CREATE CONNECTION conn name create_sql --------------------------------- -materialize.public.conn "CREATE CONNECTION \"materialize\".\"public\".\"conn\" TO KAFKA (BROKER = '${testdrive.kafka-addr}', SECURITY PROTOCOL = \"plaintext\")" +materialize.public.conn "CREATE CONNECTION materialize.public.conn TO KAFKA (BROKER = '${testdrive.kafka-addr}', SECURITY PROTOCOL = plaintext);" > ALTER CONNECTION conn SET (BROKERS ['${testdrive.kafka-addr}']) > SHOW CREATE CONNECTION conn name create_sql --------------------------------- -materialize.public.conn "CREATE CONNECTION \"materialize\".\"public\".\"conn\" TO KAFKA (BROKERS = ('${testdrive.kafka-addr}'), SECURITY PROTOCOL = \"plaintext\")" +materialize.public.conn "CREATE CONNECTION materialize.public.conn TO KAFKA (BROKERS = ('${testdrive.kafka-addr}'), SECURITY PROTOCOL = plaintext);" ! ALTER CONNECTION conn DROP (SECURITY PROTOCOL); contains:Broker does not support SSL connections diff --git a/test/testdrive/connection-create-drop.td b/test/testdrive/connection-create-drop.td index 15777c36a2862..63573cf3eb56a 100644 --- a/test/testdrive/connection-create-drop.td +++ b/test/testdrive/connection-create-drop.td @@ -59,7 +59,7 @@ testconn kafka "" > SHOW CREATE CONNECTION testconn name create_sql --------------------------------- -materialize.public.testconn "CREATE CONNECTION \"materialize\".\"public\".\"testconn\" TO KAFKA (BROKER = '${testdrive.kafka-addr}', SECURITY PROTOCOL = \"plaintext\")" +materialize.public.testconn "CREATE CONNECTION materialize.public.testconn TO KAFKA (BROKER = '${testdrive.kafka-addr}', SECURITY PROTOCOL = plaintext);" > SELECT brokers, diff --git a/test/testdrive/createdrop.td b/test/testdrive/createdrop.td index 060dd089f8c7f..357aaeea56fe6 100644 --- a/test/testdrive/createdrop.td +++ b/test/testdrive/createdrop.td @@ -195,7 +195,7 @@ contains:unknown catalog item 'nonexistent' > SHOW CREATE VIEW test1 name create_sql -------------------------------------------------------------------------------------------------- -materialize.public.test1 "CREATE VIEW \"materialize\".\"public\".\"test1\" AS SELECT 42 AS \"a\"" +materialize.public.test1 "CREATE VIEW materialize.public.test1 AS SELECT 42 AS a;" ! CREATE VIEW test1 AS SELECT 43 AS b contains:view "materialize.public.test1" already exists diff --git a/test/testdrive/indexes.td b/test/testdrive/indexes.td index 37d3f99b8c6dc..bde76468a764b 100644 --- a/test/testdrive/indexes.td +++ b/test/testdrive/indexes.td @@ -220,7 +220,7 @@ data_view_primary_idx data_view "{b - a,a}" "" > SHOW CREATE INDEX data_view_primary_idx name create_sql -------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.data_view_primary_idx "CREATE INDEX \"data_view_primary_idx\" IN CLUSTER \"\" ON \"materialize\".\"public\".\"data_view\" (\"b\" - \"a\", \"a\")" +materialize.public.data_view_primary_idx "CREATE INDEX data_view_primary_idx IN CLUSTER ON materialize.public.data_view (b - a, a);" > CREATE TABLE foo ( a int NOT NULL, diff --git a/test/testdrive/kafka-avro-sinks-doc-comments.td b/test/testdrive/kafka-avro-sinks-doc-comments.td index 86fa30219b167..fd169db7c963e 100644 --- a/test/testdrive/kafka-avro-sinks-doc-comments.td +++ b/test/testdrive/kafka-avro-sinks-doc-comments.td @@ -52,7 +52,7 @@ $ set-arg-default single-replica-cluster=quickstart > SHOW CREATE SINK sink1; name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.sink1 "CREATE SINK \"materialize\".\"public\".\"sink1\" IN CLUSTER \"sink1_cluster\" FROM \"materialize\".\"public\".\"t\" INTO KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-sink1-${testdrive.seed}') KEY (\"c2\") NOT ENFORCED FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION \"materialize\".\"public\".\"csr_conn\" (DOC ON COLUMN \"materialize\".\"public\".\"t\".\"c1\" = 'doc on t.c1', VALUE DOC ON COLUMN \"materialize\".\"public\".\"t\".\"c2\" = 'value doc on t.c2', KEY DOC ON COLUMN \"materialize\".\"public\".\"t\".\"c2\" = 'key doc on t.c2', DOC ON COLUMN \"materialize\".\"public\".\"t\".\"c4\" = 'doc on t.c4', KEY DOC ON TYPE \"materialize\".\"public\".\"point\" = 'key doc on point', VALUE DOC ON TYPE \"materialize\".\"public\".\"point\" = 'value doc on point', KEY DOC ON TYPE \"materialize\".\"public\".\"t\" = 'key doc on t', VALUE DOC ON COLUMN \"materialize\".\"public\".\"point\".\"y\" = 'value doc on point.y', DOC ON TYPE \"materialize\".\"public\".\"point\" = 'comment on type point', DOC ON COLUMN \"materialize\".\"public\".\"point\".\"x\" = 'comment on column point.x', DOC ON TYPE \"materialize\".\"public\".\"t\" = 'comment on table t with a \\\\ \\', DOC ON COLUMN \"materialize\".\"public\".\"t\".\"c3_map[text=>text]\" = 'comment on column t.c3_map with a ''') ENVELOPE UPSERT" +materialize.public.sink1 "CREATE SINK materialize.public.sink1 IN CLUSTER sink1_cluster FROM materialize.public.t INTO KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'testdrive-sink1-${testdrive.seed}') KEY (c2) NOT ENFORCED FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION materialize.public.csr_conn (DOC ON COLUMN materialize.public.t.c1 = 'doc on t.c1', VALUE DOC ON COLUMN materialize.public.t.c2 = 'value doc on t.c2', KEY DOC ON COLUMN materialize.public.t.c2 = 'key doc on t.c2', DOC ON COLUMN materialize.public.t.c4 = 'doc on t.c4', KEY DOC ON TYPE materialize.public.point = 'key doc on point', VALUE DOC ON TYPE materialize.public.point = 'value doc on point', KEY DOC ON TYPE materialize.public.t = 'key doc on t', VALUE DOC ON COLUMN materialize.public.point.y = 'value doc on point.y', DOC ON TYPE materialize.public.point = 'comment on type point', DOC ON COLUMN materialize.public.point.x = 'comment on column point.x', DOC ON TYPE materialize.public.t = 'comment on table t with a \\\\ \\', DOC ON COLUMN materialize.public.t.\"c3_map[text=>text]\" = 'comment on column t.c3_map with a ''') ENVELOPE UPSERT;" $ unset-regex diff --git a/test/testdrive/load-generator.td b/test/testdrive/load-generator.td index 53ba08831bf94..fe4e82286b0e7 100644 --- a/test/testdrive/load-generator.td +++ b/test/testdrive/load-generator.td @@ -57,10 +57,10 @@ exact:COUNTER load generators do not support SCALE FACTOR values > CREATE TABLE users FROM SOURCE auction_house (REFERENCE users); > SHOW CREATE SOURCE auction_house -"materialize.public.auction_house" "CREATE SOURCE \"materialize\".\"public\".\"auction_house\" IN CLUSTER \"${arg.single-replica-cluster}\" FROM LOAD GENERATOR AUCTION (AS OF = 300, UP TO = 301) EXPOSE PROGRESS AS \"materialize\".\"public\".\"auction_house_progress\"" +"materialize.public.auction_house" "CREATE SOURCE materialize.public.auction_house\nIN CLUSTER ${arg.single-replica-cluster}\nFROM LOAD GENERATOR AUCTION (AS OF = 300, UP TO = 301)\nEXPOSE PROGRESS AS materialize.public.auction_house_progress;" > SHOW CREATE TABLE accounts -materialize.public.accounts "CREATE TABLE \"materialize\".\"public\".\"accounts\" (\"id\" \"pg_catalog\".\"int8\" NOT NULL, \"org_id\" \"pg_catalog\".\"int8\" NOT NULL, \"balance\" \"pg_catalog\".\"int8\" NOT NULL, UNIQUE (\"id\")) FROM SOURCE \"materialize\".\"public\".\"auction_house\" (REFERENCE = \"mz_load_generators\".\"auction\".\"accounts\") WITH (DETAILS = '1a040a021002')" +materialize.public.accounts "CREATE TABLE materialize.public.accounts (id pg_catalog.int8 NOT NULL, org_id pg_catalog.int8 NOT NULL, balance pg_catalog.int8 NOT NULL, UNIQUE (id)) FROM SOURCE materialize.public.auction_house (REFERENCE = mz_load_generators.auction.accounts) WITH (DETAILS = '1a040a021002');" > SHOW SOURCES auction_house load-generator ${arg.single-replica-cluster} "" @@ -117,7 +117,7 @@ users "" $ set-regex match="DETAILS = '[a-f0-9]+'" replacement=
> SHOW CREATE TABLE accounts -materialize.public.accounts "CREATE TABLE \"materialize\".\"public\".\"accounts\" (\"id\" \"pg_catalog\".\"int8\" NOT NULL, \"org_id\" \"pg_catalog\".\"int8\" NOT NULL, \"balance\" \"pg_catalog\".\"int8\" NOT NULL, UNIQUE (\"id\")) FROM SOURCE \"materialize\".\"public\".\"auction_house\" (REFERENCE = \"mz_load_generators\".\"auction\".\"accounts\") WITH (
)" +materialize.public.accounts "CREATE TABLE materialize.public.accounts (id pg_catalog.int8 NOT NULL, org_id pg_catalog.int8 NOT NULL, balance pg_catalog.int8 NOT NULL, UNIQUE (id)) FROM SOURCE materialize.public.auction_house (REFERENCE = mz_load_generators.auction.accounts) WITH (
);" # CLOCK load generator source diff --git a/test/testdrive/materializations.td b/test/testdrive/materializations.td index 3ac2bb28a090c..92d4c3b839ddd 100644 --- a/test/testdrive/materializations.td +++ b/test/testdrive/materializations.td @@ -85,7 +85,7 @@ data_view "" > SHOW CREATE MATERIALIZED VIEW test1 name create_sql ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.test1 "CREATE MATERIALIZED VIEW \"materialize\".\"public\".\"test1\" IN CLUSTER \"quickstart\" WITH (REFRESH = ON COMMIT) AS SELECT \"b\", \"pg_catalog\".\"sum\"(\"a\") FROM \"materialize\".\"public\".\"data_tbl\" GROUP BY \"b\"" +materialize.public.test1 "CREATE MATERIALIZED VIEW materialize.public.test1\n IN CLUSTER quickstart\n WITH (REFRESH = ON COMMIT)\n AS SELECT b, pg_catalog.sum(a) FROM materialize.public.data_tbl GROUP BY b;" # Materialized view can be built on a not-materialized view. > CREATE MATERIALIZED VIEW test2 AS diff --git a/test/testdrive/rename.td b/test/testdrive/rename.td index 4dfc9edcb4c6f..9836a770c4365 100644 --- a/test/testdrive/rename.td +++ b/test/testdrive/rename.td @@ -10,7 +10,7 @@ $ set-arg-default default-replica-size=1 $ set-arg-default single-replica-cluster=quickstart -$ set-regex match=u\d+|cluster1|quickstart|testdrive_single_replica_cluster replacement= +$ set-regex match=u\d+|cluster1|quickstart|testdrive_single_replica_cluster|testdrive-data-\d+ replacement= $ set writer-schema={ "name": "row", @@ -231,7 +231,7 @@ renamed_mz_view "" > SHOW CREATE VIEW renamed_mz_view name create_sql --------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.renamed_mz_view "CREATE VIEW \"materialize\".\"public\".\"renamed_mz_view\" AS SELECT * FROM \"materialize\".\"public\".\"renamed_mz_data_tbl\"" +materialize.public.renamed_mz_view "CREATE VIEW\n materialize.public.renamed_mz_view AS SELECT * FROM materialize.public.renamed_mz_data_tbl;" # Item's indexes are properly re-attributed > SHOW INDEXES ON renamed_mz_view @@ -242,30 +242,30 @@ renamed_index renamed_mz_view {a,b} "" > SHOW CREATE INDEX renamed_index name create_sql --------------------------------------------------------------------------------------------------------------------- -materialize.public.renamed_index "CREATE INDEX \"renamed_index\" IN CLUSTER \"\" ON \"materialize\".\"public\".\"renamed_mz_view\" (\"a\", \"b\")" +materialize.public.renamed_index "CREATE INDEX renamed_index IN CLUSTER ON materialize.public.renamed_mz_view (a, b);" # Simple dependencies are renamed > SHOW CREATE VIEW dependent_view name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------ -materialize.public.dependent_view "CREATE VIEW \"materialize\".\"public\".\"dependent_view\" AS SELECT * FROM \"materialize\".\"public\".\"renamed_mz_view\"" +materialize.public.dependent_view "CREATE VIEW materialize.public.dependent_view AS SELECT * FROM materialize.public.renamed_mz_view;" > SHOW CREATE SINK renamed_sink name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.renamed_sink "CREATE SINK \"materialize\".\"public\".\"renamed_sink\" IN CLUSTER \"\" FROM \"materialize\".\"public\".\"renamed_mz_data_tbl\" INTO KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-snk1-${testdrive.seed}') FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION \"materialize\".\"public\".\"csr_conn\" ENVELOPE DEBEZIUM" +materialize.public.renamed_sink "CREATE SINK materialize.public.renamed_sink IN CLUSTER FROM materialize.public.renamed_mz_data_tbl INTO KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'testdrive-snk1-${testdrive.seed}') FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION materialize.public.csr_conn ENVELOPE DEBEZIUM;" # Simple dependencies with both fully qualified and unqualified item references are renamed > SHOW CREATE VIEW byzantine_view name create_sql --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.byzantine_view "CREATE VIEW \"materialize\".\"public\".\"byzantine_view\" AS SELECT \"renamed_mz_data_tbl\".\"a\", \"renamed_mz_view\".\"b\" FROM \"materialize\".\"public\".\"renamed_mz_data_tbl\" JOIN \"materialize\".\"public\".\"renamed_mz_view\" ON \"renamed_mz_data_tbl\".\"a\" = \"renamed_mz_view\".\"a\"" +materialize.public.byzantine_view "CREATE VIEW\n materialize.public.byzantine_view\n AS\n SELECT renamed_mz_data_tbl.a, renamed_mz_view.b\n FROM\n materialize.public.renamed_mz_data_tbl\n JOIN materialize.public.renamed_mz_view ON renamed_mz_data_tbl.a = renamed_mz_view.a;" # Strings containing old item name are not modified > SHOW CREATE VIEW oppositional_view name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ -materialize.public.oppositional_view "CREATE VIEW \"materialize\".\"public\".\"oppositional_view\" AS SELECT * FROM \"materialize\".\"public\".\"renamed_mz_view\" WHERE \"b\" = '\n an adversarial string\n \"materialize\".\"public\".\"mz_data_tbl\"\n '" +materialize.public.oppositional_view "CREATE VIEW\n materialize.public.oppositional_view\n AS\n SELECT *\n FROM materialize.public.renamed_mz_view\n WHERE b = '\n an adversarial string\n \"materialize\".\"public\".\"mz_data_tbl\"\n ';" # 🔬 Name collisions @@ -426,7 +426,7 @@ contains:renaming conflict > SHOW CREATE VIEW db1_db2_scm1_valid_qual name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.db1_db2_scm1_valid_qual "CREATE VIEW \"materialize\".\"public\".\"db1_db2_scm1_valid_qual\" AS SELECT * FROM (SELECT \"db1\".\"scm1\".\"v1\".\"a\" FROM \"db1\".\"scm1\".\"v1\") AS \"l\" JOIN (SELECT \"db2\".\"scm1\".\"v2\".\"b\" FROM \"db2\".\"scm1\".\"v2\") AS \"r\" ON \"l\".\"a\" = \"r\".\"b\"" +materialize.public.db1_db2_scm1_valid_qual "CREATE VIEW\n materialize.public.db1_db2_scm1_valid_qual\n AS\n SELECT *\n FROM\n (SELECT db1.scm1.v1.a FROM db1.scm1.v1) AS l\n JOIN (SELECT db2.scm1.v2.b FROM db2.scm1.v2) AS r ON l.a = r.b;" > CREATE VIEW "materialize"."public"."db1_db2_scm1_valid_qual_test" AS SELECT * FROM (SELECT "db1"."scm1"."v1"."a" FROM "db1"."scm1"."v1") AS "l" JOIN (SELECT "db2"."scm1"."v2"."b" FROM "db2"."scm1"."v2") AS "r" ON "l"."a" = "r"."b" @@ -461,7 +461,7 @@ contains:renaming conflict > SHOW CREATE VIEW db_db_qual_diff_s_v name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.db_db_qual_diff_s_v "CREATE VIEW \"materialize\".\"public\".\"db_db_qual_diff_s_v\" AS SELECT \"db2\".\"scm2\".\"v3\".\"z\" FROM \"db2\".\"scm2\".\"v3\" JOIN \"db1\".\"scm1\".\"v4\" ON \"db2\".\"scm2\".\"v3\".\"z\" = \"db1\".\"scm1\".\"v4\".\"a\"" +materialize.public.db_db_qual_diff_s_v "CREATE VIEW\n materialize.public.db_db_qual_diff_s_v\n AS SELECT db2.scm2.v3.z FROM db2.scm2.v3 JOIN db1.scm1.v4 ON db2.scm2.v3.z = db1.scm1.v4.a;" > CREATE VIEW "materialize"."public"."db_db_qual_diff_s_v_test" AS SELECT "db2"."scm2"."v3"."z" FROM "db2"."scm2"."v3" JOIN "db1"."scm1"."v4" ON "db2"."scm2"."v3"."z" = "db1"."scm1"."v4"."a" @@ -486,7 +486,7 @@ materialize.public.db_db_qual_diff_s_v "CREATE VIEW \"materialize\".\"public\".\ > SHOW CREATE VIEW db_scm_qual name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.db_scm_qual "CREATE VIEW \"materialize\".\"public\".\"db_scm_qual\" AS SELECT \"scm3\".\"v3\".\"z\", \"db1\".\"scm1\".\"v5\".\"a\" FROM \"materialize\".\"scm3\".\"v3\" JOIN \"db1\".\"scm1\".\"v5\" ON \"scm3\".\"v3\".\"z\" = \"db1\".\"scm1\".\"v5\".\"a\"" +materialize.public.db_scm_qual "CREATE VIEW\n materialize.public.db_scm_qual\n AS\n SELECT scm3.v3.z, db1.scm1.v5.a\n FROM materialize.scm3.v3 JOIN db1.scm1.v5 ON scm3.v3.z = db1.scm1.v5.a;" > CREATE VIEW "materialize"."public"."db_scm_qual_test" AS SELECT "scm3"."v3"."z", "db1"."scm1"."v5"."a" FROM "materialize"."scm3"."v3" JOIN "db1"."scm1"."v5" ON "scm3"."v3"."z" = "db1"."scm1"."v5"."a" @@ -522,7 +522,7 @@ contains:renaming conflict > SHOW CREATE VIEW db_v_qual name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.db_v_qual "CREATE VIEW \"materialize\".\"public\".\"db_v_qual\" AS SELECT \"v2\".\"z\", \"db1\".\"scm1\".\"v6\".\"a\" FROM \"materialize\".\"public\".\"v2\" JOIN \"db1\".\"scm1\".\"v6\" ON \"v2\".\"z\" = \"db1\".\"scm1\".\"v6\".\"a\"" +materialize.public.db_v_qual "CREATE VIEW\n materialize.public.db_v_qual\n AS\n SELECT v2.z, db1.scm1.v6.a\n FROM materialize.public.v2 JOIN db1.scm1.v6 ON v2.z = db1.scm1.v6.a;" > CREATE VIEW "materialize"."public"."db_v_qual_test" AS SELECT "v2"."z", "db1"."scm1"."v6"."a" FROM "materialize"."public"."v2" JOIN "db1"."scm1"."v6" ON "v2"."z" = "db1"."scm1"."v6"."a" @@ -595,7 +595,7 @@ contains:renaming conflict > SHOW CREATE VIEW db1_scm1_scm2_valid_qual name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.db1_scm1_scm2_valid_qual "CREATE VIEW \"materialize\".\"public\".\"db1_scm1_scm2_valid_qual\" AS SELECT * FROM (SELECT \"scm1\".\"v4\".\"a\" FROM \"db1\".\"scm1\".\"v4\") AS \"l\" JOIN (SELECT \"scm2\".\"v5\".\"b\" FROM \"db1\".\"scm2\".\"v5\") AS \"r\" ON \"l\".\"a\" = \"r\".\"b\"" +materialize.public.db1_scm1_scm2_valid_qual "CREATE VIEW\n materialize.public.db1_scm1_scm2_valid_qual\n AS\n SELECT *\n FROM\n (SELECT scm1.v4.a FROM db1.scm1.v4) AS l\n JOIN (SELECT scm2.v5.b FROM db1.scm2.v5) AS r ON l.a = r.b;" > CREATE VIEW "materialize"."public"."db1_scm1_scm2_valid_qual_test" AS SELECT * FROM (SELECT "scm1"."v4"."a" FROM "db1"."scm1"."v4") AS "l" JOIN (SELECT "scm2"."v5"."b" FROM "db1"."scm2"."v5") AS "r" ON "l"."a" = "r"."b" @@ -636,7 +636,7 @@ contains:renaming conflict > SHOW CREATE VIEW scm_scm_qual name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.scm_scm_qual "CREATE VIEW \"materialize\".\"public\".\"scm_scm_qual\" AS SELECT \"scm4\".\"v3\".\"z\", \"scm5\".\"v4\".\"a\" FROM \"materialize\".\"scm4\".\"v3\" JOIN \"materialize\".\"scm5\".\"v4\" ON \"scm4\".\"v3\".\"z\" = \"scm5\".\"v4\".\"a\"" +materialize.public.scm_scm_qual "CREATE VIEW\n materialize.public.scm_scm_qual\n AS\n SELECT scm4.v3.z, scm5.v4.a\n FROM materialize.scm4.v3 JOIN materialize.scm5.v4 ON scm4.v3.z = scm5.v4.a;" > CREATE VIEW "materialize"."public"."scm_scm_qual_test" AS SELECT "scm4"."v3"."z", "scm5"."v4"."a" FROM "materialize"."scm4"."v3" JOIN "materialize"."scm5"."v4" ON "scm4"."v3"."z" = "scm5"."v4"."a" @@ -668,7 +668,7 @@ contains:renaming conflict > SHOW CREATE VIEW scm_v_qual name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.scm_v_qual "CREATE VIEW \"materialize\".\"public\".\"scm_v_qual\" AS SELECT \"v3\".\"z\", \"scm5\".\"v6\".\"a\" FROM \"materialize\".\"public\".\"v3\" JOIN \"materialize\".\"scm5\".\"v6\" ON \"v3\".\"z\" = \"scm5\".\"v6\".\"a\"" +materialize.public.scm_v_qual "CREATE VIEW\n materialize.public.scm_v_qual\n AS\n SELECT v3.z, scm5.v6.a\n FROM materialize.public.v3 JOIN materialize.scm5.v6 ON v3.z = scm5.v6.a;" > CREATE VIEW "materialize"."public"."scm_v_qual_test" AS SELECT "v3"."z", "scm5"."v6"."a" FROM "materialize"."public"."v3" JOIN "materialize"."scm5"."v6" ON "v3"."z" = "scm5"."v6"."a" @@ -695,7 +695,7 @@ contains:renaming conflict > SHOW CREATE VIEW v_v_qual name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.v_v_qual "CREATE VIEW \"materialize\".\"public\".\"v_v_qual\" AS SELECT \"v5\".\"z\", \"v6\".\"a\" FROM \"materialize\".\"public\".\"v5\" JOIN \"materialize\".\"public\".\"v6\" ON \"v5\".\"z\" = \"v6\".\"a\"" +materialize.public.v_v_qual "CREATE VIEW\n materialize.public.v_v_qual\n AS SELECT v5.z, v6.a FROM materialize.public.v5 JOIN materialize.public.v6 ON v5.z = v6.a;" > CREATE VIEW "materialize"."public"."v_v_qual_test" AS SELECT "v5"."z", "v6"."a" FROM "materialize"."public"."v5" JOIN "materialize"."public"."v6" ON "v5"."z" = "v6"."a" @@ -711,7 +711,7 @@ materialize.public.v_v_qual "CREATE VIEW \"materialize\".\"public\".\"v_v_qual\" > SHOW CREATE VIEW qualified_wildcard name create_sql --------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.qualified_wildcard "CREATE VIEW \"materialize\".\"public\".\"qualified_wildcard\" AS SELECT \"v7\".* FROM \"materialize\".\"public\".\"v7\"" +materialize.public.qualified_wildcard "CREATE VIEW materialize.public.qualified_wildcard AS SELECT v7.* FROM materialize.public.v7;" > CREATE VIEW "materialize"."public"."qualified_wildcard_test" AS SELECT "v7".* FROM "materialize"."public"."v7" @@ -734,7 +734,7 @@ contains:renaming conflict > SHOW CREATE VIEW v9 name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.v9 "CREATE VIEW \"materialize\".\"public\".\"v9\" AS SELECT \"b\" FROM \"materialize\".\"public\".\"t1\" WHERE \"b\" IN ('v8')" +materialize.public.v9 "CREATE VIEW materialize.public.v9 AS SELECT b FROM materialize.public.t1 WHERE b IN ( 'v8' );" > CREATE VIEW "materialize"."public"."where_in_literal_test" AS SELECT "b" FROM "materialize"."public"."t1" WHERE "b" IN ('v8') @@ -764,7 +764,7 @@ contains:renaming conflict > SHOW CREATE VIEW space_dependent name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.space_dependent "CREATE VIEW \"materialize\".\"public\".\"space_dependent\" AS SELECT * FROM \"materialize\".\"public\".\"now has space\" JOIN \"materialize\".\"public\".\"still has space\" ON \"still has space\".\"my_space\" = \"now has space\".\"has space\"" +materialize.public.space_dependent "CREATE VIEW\n materialize.public.space_dependent\n AS\n SELECT *\n FROM\n materialize.public.\"now has space\"\n JOIN\n materialize.public.\"still has space\"\n ON \"still has space\".my_space = \"now has space\".\"has space\";" > CREATE VIEW "materialize"."public"."space_dependent_test" AS SELECT * FROM "materialize"."public"."now has space" JOIN "materialize"."public"."still has space" ON "still has space"."my_space" = "now has space"."has space" @@ -779,7 +779,7 @@ materialize.public.space_dependent "CREATE VIEW \"materialize\".\"public\".\"spa > SHOW CREATE VIEW unnatural name create_sql ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.unnatural "CREATE VIEW \"materialize\".\"public\".\"unnatural\" AS SELECT * FROM \"materialize\".\"public\".\"t1\" NATURAL JOIN \"materialize\".\"public\".\"t1\" AS \"a\"" +materialize.public.unnatural "CREATE VIEW\n materialize.public.unnatural\n AS SELECT * FROM materialize.public.t1 NATURAL JOIN materialize.public.t1 AS a;" > CREATE VIEW "materialize"."public"."unnatural_test" AS SELECT * FROM "materialize"."public"."t1" NATURAL JOIN "materialize"."public"."t1" AS "a" @@ -808,14 +808,14 @@ contains:renaming conflict > SHOW CREATE VIEW func_dependency name create_sql --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.public.func_dependency "CREATE VIEW \"materialize\".\"public\".\"func_dependency\" (\"a\", \"x_a\") AS SELECT * FROM \"materialize\".\"public\".\"count\" JOIN (SELECT * FROM \"materialize\".\"public\".\"count\") AS \"x\" ON \"count\".\"a\" = \"x\".\"a\"" +materialize.public.func_dependency "CREATE VIEW\n materialize.public.func_dependency\n (a, x_a)\n AS\n SELECT *\n FROM\n materialize.public.count\n JOIN (SELECT * FROM materialize.public.count) AS x ON count.a = x.a;" > CREATE VIEW "materialize"."public"."func_dependency_test" ("a", "x_a") AS SELECT * FROM count JOIN (SELECT * FROM count) AS x ON count.a = x.a > SHOW CREATE VIEW count name create_sql --------------------------------------------------------------------------------------- -materialize.public.count "CREATE VIEW \"materialize\".\"public\".\"count\" AS SELECT 1 AS \"a\"" +materialize.public.count "CREATE VIEW materialize.public.count AS SELECT 1 AS a;" > DROP VIEW count CASCADE; @@ -884,12 +884,13 @@ renamed_mz_data_tbl > SHOW CREATE SOURCE to_be_renamed.mz_data; name create_sql --------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.to_be_renamed.mz_data "CREATE SOURCE \"materialize\".\"to_be_renamed\".\"mz_data\" IN CLUSTER \"\" FROM KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-data-${testdrive.seed}') EXPOSE PROGRESS AS \"materialize\".\"to_be_renamed\".\"mz_data_progress\"" +materialize.to_be_renamed.mz_data "CREATE SOURCE materialize.to_be_renamed.mz_data\nIN CLUSTER \nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = '')\nEXPOSE PROGRESS AS materialize.to_be_renamed.mz_data_progress;" > SHOW CREATE SINK to_be_renamed.sink1; name create_sql --------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.to_be_renamed.sink1 "CREATE SINK \"materialize\".\"to_be_renamed\".\"sink1\" IN CLUSTER \"\" FROM \"materialize\".\"to_be_renamed\".\"mz_data_tbl\" INTO KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-snk1-rename-schema-${testdrive.seed}') FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION \"materialize\".\"public\".\"csr_conn\" ENVELOPE DEBEZIUM" +materialize.to_be_renamed.sink1 "CREATE SINK materialize.to_be_renamed.sink1 IN CLUSTER FROM materialize.to_be_renamed.mz_data_tbl INTO KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'testdrive-snk1-rename-schema-${testdrive.seed}') FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION materialize.public.csr_conn ENVELOPE DEBEZIUM;" + # Make sure the create_sql got updated. > ALTER SCHEMA to_be_renamed RENAME TO foo_bar; @@ -897,9 +898,9 @@ materialize.to_be_renamed.sink1 "CREATE SINK \"materialize\".\"to_be_renamed\ > SHOW CREATE SOURCE foo_bar.mz_data; name create_sql --------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.foo_bar.mz_data "CREATE SOURCE \"materialize\".\"foo_bar\".\"mz_data\" IN CLUSTER \"\" FROM KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-data-${testdrive.seed}') EXPOSE PROGRESS AS \"materialize\".\"foo_bar\".\"mz_data_progress\"" +materialize.foo_bar.mz_data "CREATE SOURCE materialize.foo_bar.mz_data\nIN CLUSTER \nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = '')\nEXPOSE PROGRESS AS materialize.foo_bar.mz_data_progress;" > SHOW CREATE SINK foo_bar.sink1; name create_sql --------------------------------------------------------------------------------------------------------------------------------------------------- -materialize.foo_bar.sink1 "CREATE SINK \"materialize\".\"foo_bar\".\"sink1\" IN CLUSTER \"\" FROM \"materialize\".\"foo_bar\".\"mz_data_tbl\" INTO KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-snk1-rename-schema-${testdrive.seed}') FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION \"materialize\".\"public\".\"csr_conn\" ENVELOPE DEBEZIUM" +materialize.foo_bar.sink1 "CREATE SINK materialize.foo_bar.sink1 IN CLUSTER FROM materialize.foo_bar.mz_data_tbl INTO KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'testdrive-snk1-rename-schema-${testdrive.seed}') FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY CONNECTION materialize.public.csr_conn ENVELOPE DEBEZIUM;" diff --git a/test/testdrive/tables.td b/test/testdrive/tables.td index ee3cca8630026..bd70cbd6236c0 100644 --- a/test/testdrive/tables.td +++ b/test/testdrive/tables.td @@ -22,7 +22,7 @@ contains:unknown catalog item 't' > SHOW CREATE TABLE t; name create_sql ------------------------ -materialize.public.t "CREATE TABLE \"materialize\".\"public\".\"t\" (\"a\" \"pg_catalog\".\"int4\", \"b\" \"pg_catalog\".\"text\" NOT NULL)" +materialize.public.t "CREATE TABLE materialize.public.t (a pg_catalog.int4, b pg_catalog.text NOT NULL);" > CREATE TABLE s (a int DEFAULT 1) > DROP TABLE s; diff --git a/test/testdrive/webhook.td b/test/testdrive/webhook.td index ef0e2bf2713e5..51a92f74d75fa 100644 --- a/test/testdrive/webhook.td +++ b/test/testdrive/webhook.td @@ -24,7 +24,7 @@ name nullable type comment body false text "" > SHOW CREATE SOURCE webhook_text; -materialize.public.webhook_text "CREATE SOURCE \"materialize\".\"public\".\"webhook_text\" IN CLUSTER \"webhook_cluster\" FROM WEBHOOK BODY FORMAT TEXT" +materialize.public.webhook_text "CREATE SOURCE materialize.public.webhook_text IN CLUSTER webhook_cluster FROM WEBHOOK BODY FORMAT TEXT;" > SELECT name, type FROM mz_objects WHERE name = 'webhook_text'; webhook_text source @@ -556,7 +556,7 @@ aaa_1 aaa_1 > SHOW CREATE TABLE webhook_as_table; -materialize.public.webhook_as_table "CREATE TABLE \"materialize\".\"public\".\"webhook_as_table\" FROM WEBHOOK BODY FORMAT TEXT" +materialize.public.webhook_as_table "CREATE TABLE materialize.public.webhook_as_table FROM WEBHOOK BODY FORMAT TEXT;" > SHOW COLUMNS FROM webhook_as_table; name nullable type comment diff --git a/test/yugabyte-cdc/yugabyte-cdc.td b/test/yugabyte-cdc/yugabyte-cdc.td index 2476dfc7ac2b7..82f66b0511118 100644 --- a/test/yugabyte-cdc/yugabyte-cdc.td +++ b/test/yugabyte-cdc/yugabyte-cdc.td @@ -672,7 +672,7 @@ enum_table subsource cdc_cluster "" 2 var1 > SHOW CREATE SOURCE enum_table -materialize.public.enum_table "CREATE SUBSOURCE \"materialize\".\"public\".\"enum_table\" (\"pk\" \"pg_catalog\".\"int4\" NOT NULL, \"a\" \"pg_catalog\".\"text\", CONSTRAINT \"enum_table_pkey\" PRIMARY KEY (\"pk\")) OF SOURCE \"materialize\".\"public\".\"enum_source\" WITH (EXTERNAL REFERENCE = \"yugabyte\".\"public\".\"enum_table\", TEXT COLUMNS = (\"a\"))" +materialize.public.enum_table "CREATE SUBSOURCE materialize.public.enum_table (pk pg_catalog.int4 NOT NULL, a pg_catalog.text, CONSTRAINT enum_table_pkey PRIMARY KEY (pk)) OF SOURCE materialize.public.enum_source WITH (EXTERNAL REFERENCE = yugabyte.public.enum_table, TEXT COLUMNS = (a));" > SELECT "колона" FROM another_enum_table var2 From 5e6278c54380b55da5f35e44be25306d8868e670 Mon Sep 17 00:00:00 2001 From: Gabor Gevay Date: Mon, 31 Mar 2025 14:50:24 +0200 Subject: [PATCH 3/4] Refactor `sql-pretty`: pass around `PrettyConfig` as `&self`. --- src/sql-pretty/src/doc.rs | 1422 +++++++++++++++----------------- src/sql-pretty/src/lib.rs | 42 +- src/sql-pretty/src/util.rs | 6 +- src/sql-pretty/tests/parser.rs | 18 +- 4 files changed, 720 insertions(+), 768 deletions(-) diff --git a/src/sql-pretty/src/doc.rs b/src/sql-pretty/src/doc.rs index bc55dd58cc9b7..b9956c6baf7c0 100644 --- a/src/sql-pretty/src/doc.rs +++ b/src/sql-pretty/src/doc.rs @@ -17,816 +17,768 @@ use crate::util::{ bracket, bracket_doc, comma_separate, comma_separated, intersperse_line_nest, nest, nest_comma_separate, nest_title, title_comma_separate, }; -use crate::{PrettyConfig, TAB}; - -// Use when we don't know what to do. -pub(crate) fn doc_display<'a, T: AstDisplay>( - v: &T, - config: PrettyConfig, - _debug: &str, -) -> RcDoc<'a, ()> { - #[cfg(test)] - eprintln!( - "UNKNOWN PRETTY TYPE in {}: {}, {}", - _debug, - std::any::type_name::(), - v.to_ast_string_simple() - ); - doc_display_pass(v, config) -} - -// Use when the AstDisplay trait is what we want. -fn doc_display_pass<'a, T: AstDisplay>(v: &T, config: PrettyConfig) -> RcDoc<'a, ()> { - RcDoc::text(v.to_ast_string(config.format_mode)) -} - -fn doc_display_pass_mapper( - config: PrettyConfig, -) -> impl for<'b> FnMut(&'b T) -> RcDoc<'b, ()> { - move |v| doc_display_pass(v, config) -} - -pub(crate) fn doc_create_source( - v: &CreateSourceStatement, - config: PrettyConfig, -) -> RcDoc { - let mut docs = Vec::new(); - let title = format!( - "CREATE SOURCE{}", - if v.if_not_exists { - " IF NOT EXISTS" - } else { - "" - } - ); - let mut doc = doc_display_pass(&v.name, config); - let mut names = Vec::new(); - names.extend(v.col_names.iter().map(doc_display_pass_mapper(config))); - names.extend(v.key_constraint.iter().map(doc_display_pass_mapper(config))); - if !names.is_empty() { - doc = nest(doc, bracket("(", comma_separated(names), ")")); - } - docs.push(nest_title(title, doc)); - if let Some(cluster) = &v.in_cluster { - docs.push(nest_title("IN CLUSTER", doc_display_pass(cluster, config))); - } - docs.push(nest_title("FROM", doc_display_pass(&v.connection, config))); - if let Some(format) = &v.format { - docs.push(doc_format_specifier(format, config)); - } - if !v.include_metadata.is_empty() { - docs.push(nest_title( - "INCLUDE", - comma_separate(doc_display_pass_mapper(config), &v.include_metadata), - )); - } - if let Some(envelope) = &v.envelope { - docs.push(nest_title("ENVELOPE", doc_display_pass(envelope, config))); - } - if let Some(references) = &v.external_references { - docs.push(doc_external_references(references, config)); - } - if let Some(progress) = &v.progress_subsource { - docs.push(nest_title( - "EXPOSE PROGRESS AS", - doc_display_pass(progress, config), - )); - } - if !v.with_options.is_empty() { - docs.push(bracket( - "WITH (", - comma_separate(doc_display_pass_mapper(config), &v.with_options), - ")", - )); - } - RcDoc::intersperse(docs, Doc::line()).group() -} - -fn doc_format_specifier(v: &FormatSpecifier, config: PrettyConfig) -> RcDoc { - match v { - FormatSpecifier::Bare(format) => nest_title("FORMAT", doc_display_pass(format, config)), - FormatSpecifier::KeyValue { key, value } => { - let docs = vec![ - nest_title("KEY FORMAT", doc_display_pass(key, config)), - nest_title("VALUE FORMAT", doc_display_pass(value, config)), - ]; - RcDoc::intersperse(docs, Doc::line()).group() - } - } -} - -fn doc_external_references(v: &ExternalReferences, config: PrettyConfig) -> RcDoc { - match v { - ExternalReferences::SubsetTables(subsources) => bracket( - "FOR TABLES (", - comma_separate(doc_display_pass_mapper(config), subsources), - ")", - ), - ExternalReferences::SubsetSchemas(schemas) => bracket( - "FOR SCHEMAS (", - comma_separate(doc_display_pass_mapper(config), schemas), - ")", - ), - ExternalReferences::All => RcDoc::text("FOR ALL TABLES"), - } -} - -pub(crate) fn doc_copy(v: &CopyStatement, config: PrettyConfig) -> RcDoc { - let relation = match &v.relation { - CopyRelation::Named { name, columns } => { - let mut relation = doc_display_pass(name, config); - if !columns.is_empty() { - relation = bracket_doc( - nest(relation, RcDoc::text("(")), - comma_separate(doc_display_pass_mapper(config), columns), - RcDoc::text(")"), - RcDoc::line_(), - ); +use crate::{Pretty, TAB}; + +impl Pretty { + // Use when we don't know what to do. + pub(crate) fn doc_display<'a, T: AstDisplay>(&self, v: &T, _debug: &str) -> RcDoc<'a, ()> { + #[cfg(test)] + eprintln!( + "UNKNOWN PRETTY TYPE in {}: {}, {}", + _debug, + std::any::type_name::(), + v.to_ast_string_simple() + ); + self.doc_display_pass(v) + } + + // Use when the AstDisplay trait is what we want. + fn doc_display_pass<'a, T: AstDisplay>(&self, v: &T) -> RcDoc<'a, ()> { + RcDoc::text(v.to_ast_string(self.config.format_mode)) + } + + pub(crate) fn doc_create_source<'a, T: AstInfo>( + &'a self, + v: &'a CreateSourceStatement, + ) -> RcDoc<'a> { + let mut docs = Vec::new(); + let title = format!( + "CREATE SOURCE{}", + if v.if_not_exists { + " IF NOT EXISTS" + } else { + "" } - RcDoc::concat([RcDoc::text("COPY "), relation]) + ); + let mut doc = self.doc_display_pass(&v.name); + let mut names = Vec::new(); + names.extend(v.col_names.iter().map(|name| self.doc_display_pass(name))); + names.extend(v.key_constraint.iter().map(|kc| self.doc_display_pass(kc))); + if !names.is_empty() { + doc = nest(doc, bracket("(", comma_separated(names), ")")); } - CopyRelation::Select(query) => bracket("COPY (", doc_select_statement(query, config), ")"), - CopyRelation::Subscribe(query) => bracket("COPY (", doc_subscribe(query, config), ")"), - }; - let mut docs = vec![ - relation, - RcDoc::concat([ - doc_display_pass(&v.direction, config), - RcDoc::text(" "), - doc_display_pass(&v.target, config), - ]), - ]; - if !v.options.is_empty() { - docs.push(bracket( - "WITH (", - comma_separate(doc_display_pass_mapper(config), &v.options), - ")", - )); - } - RcDoc::intersperse(docs, Doc::line()).group() -} - -pub(crate) fn doc_subscribe(v: &SubscribeStatement, config: PrettyConfig) -> RcDoc { - let doc = match &v.relation { - SubscribeRelation::Name(name) => nest_title("SUBSCRIBE", doc_display_pass(name, config)), - SubscribeRelation::Query(query) => bracket("SUBSCRIBE (", doc_query(query, config), ")"), - }; - let mut docs = vec![doc]; - if !v.options.is_empty() { - docs.push(bracket( - "WITH (", - comma_separate(doc_display_pass_mapper(config), &v.options), - ")", - )); - } - if let Some(as_of) = &v.as_of { - docs.push(doc_as_of(as_of, config)); - } - if let Some(up_to) = &v.up_to { - docs.push(nest_title("UP TO", doc_expr(up_to, config))); - } - match &v.output { - SubscribeOutput::Diffs => {} - SubscribeOutput::WithinTimestampOrderBy { order_by } => { + docs.push(nest_title(title, doc)); + if let Some(cluster) = &v.in_cluster { + docs.push(nest_title("IN CLUSTER", self.doc_display_pass(cluster))); + } + docs.push(nest_title("FROM", self.doc_display_pass(&v.connection))); + if let Some(format) = &v.format { + docs.push(self.doc_format_specifier(format)); + } + if !v.include_metadata.is_empty() { docs.push(nest_title( - "WITHIN TIMESTAMP ORDER BY ", - comma_separate(doc_order_by_expr_mapper(config), order_by), + "INCLUDE", + comma_separate(|im| self.doc_display_pass(im), &v.include_metadata), )); } - SubscribeOutput::EnvelopeUpsert { key_columns } => { - docs.push(bracket( - "ENVELOPE UPSERT (KEY (", - comma_separate(doc_display_pass_mapper(config), key_columns), - "))", + if let Some(envelope) = &v.envelope { + docs.push(nest_title("ENVELOPE", self.doc_display_pass(envelope))); + } + if let Some(references) = &v.external_references { + docs.push(self.doc_external_references(references)); + } + if let Some(progress) = &v.progress_subsource { + docs.push(nest_title( + "EXPOSE PROGRESS AS", + self.doc_display_pass(progress), )); } - SubscribeOutput::EnvelopeDebezium { key_columns } => { + if !v.with_options.is_empty() { docs.push(bracket( - "ENVELOPE DEBEZIUM (KEY (", - comma_separate(doc_display_pass_mapper(config), key_columns), - "))", + "WITH (", + comma_separate(|wo| self.doc_display_pass(wo), &v.with_options), + ")", )); } + RcDoc::intersperse(docs, Doc::line()).group() + } + + fn doc_format_specifier(&self, v: &FormatSpecifier) -> RcDoc { + match v { + FormatSpecifier::Bare(format) => nest_title("FORMAT", self.doc_display_pass(format)), + FormatSpecifier::KeyValue { key, value } => { + let docs = vec![ + nest_title("KEY FORMAT", self.doc_display_pass(key)), + nest_title("VALUE FORMAT", self.doc_display_pass(value)), + ]; + RcDoc::intersperse(docs, Doc::line()).group() + } + } } - RcDoc::intersperse(docs, Doc::line()).group() -} -fn doc_as_of(v: &AsOf, config: PrettyConfig) -> RcDoc { - let (title, expr) = match v { - AsOf::At(expr) => ("AS OF", expr), - AsOf::AtLeast(expr) => ("AS OF AT LEAST", expr), - }; - nest_title(title, doc_expr(expr, config)) -} + fn doc_external_references<'a>(&'a self, v: &'a ExternalReferences) -> RcDoc<'a> { + match v { + ExternalReferences::SubsetTables(subsources) => bracket( + "FOR TABLES (", + comma_separate(|s| self.doc_display_pass(s), subsources), + ")", + ), + ExternalReferences::SubsetSchemas(schemas) => bracket( + "FOR SCHEMAS (", + comma_separate(|s| self.doc_display_pass(s), schemas), + ")", + ), + ExternalReferences::All => RcDoc::text("FOR ALL TABLES"), + } + } -pub(crate) fn doc_create_view( - v: &CreateViewStatement, - config: PrettyConfig, -) -> RcDoc { - let mut docs = vec![]; - docs.push(RcDoc::text(format!( - "CREATE{}{} VIEW{}", - if v.if_exists == IfExistsBehavior::Replace { - " OR REPLACE" - } else { - "" - }, - if v.temporary { " TEMPORARY" } else { "" }, - if v.if_exists == IfExistsBehavior::Skip { - " IF NOT EXISTS" - } else { - "" - }, - ))); - docs.push(doc_view_definition(&v.definition, config)); - intersperse_line_nest(docs) -} + pub(crate) fn doc_copy<'a, T: AstInfo>(&'a self, v: &'a CopyStatement) -> RcDoc<'a> { + let relation = match &v.relation { + CopyRelation::Named { name, columns } => { + let mut relation = self.doc_display_pass(name); + if !columns.is_empty() { + relation = bracket_doc( + nest(relation, RcDoc::text("(")), + comma_separate(|c| self.doc_display_pass(c), columns), + RcDoc::text(")"), + RcDoc::line_(), + ); + } + RcDoc::concat([RcDoc::text("COPY "), relation]) + } + CopyRelation::Select(query) => bracket("COPY (", self.doc_select_statement(query), ")"), + CopyRelation::Subscribe(query) => bracket("COPY (", self.doc_subscribe(query), ")"), + }; + let mut docs = vec![ + relation, + RcDoc::concat([ + self.doc_display_pass(&v.direction), + RcDoc::text(" "), + self.doc_display_pass(&v.target), + ]), + ]; + if !v.options.is_empty() { + docs.push(bracket( + "WITH (", + comma_separate(|o| self.doc_display_pass(o), &v.options), + ")", + )); + } + RcDoc::intersperse(docs, Doc::line()).group() + } + + pub(crate) fn doc_subscribe<'a, T: AstInfo>( + &'a self, + v: &'a SubscribeStatement, + ) -> RcDoc<'a> { + let doc = match &v.relation { + SubscribeRelation::Name(name) => nest_title("SUBSCRIBE", self.doc_display_pass(name)), + SubscribeRelation::Query(query) => bracket("SUBSCRIBE (", self.doc_query(query), ")"), + }; + let mut docs = vec![doc]; + if !v.options.is_empty() { + docs.push(bracket( + "WITH (", + comma_separate(|o| self.doc_display_pass(o), &v.options), + ")", + )); + } + if let Some(as_of) = &v.as_of { + docs.push(self.doc_as_of(as_of)); + } + if let Some(up_to) = &v.up_to { + docs.push(nest_title("UP TO", self.doc_expr(up_to))); + } + match &v.output { + SubscribeOutput::Diffs => {} + SubscribeOutput::WithinTimestampOrderBy { order_by } => { + docs.push(nest_title( + "WITHIN TIMESTAMP ORDER BY ", + comma_separate(|o| self.doc_order_by_expr(o), order_by), + )); + } + SubscribeOutput::EnvelopeUpsert { key_columns } => { + docs.push(bracket( + "ENVELOPE UPSERT (KEY (", + comma_separate(|kc| self.doc_display_pass(kc), key_columns), + "))", + )); + } + SubscribeOutput::EnvelopeDebezium { key_columns } => { + docs.push(bracket( + "ENVELOPE DEBEZIUM (KEY (", + comma_separate(|kc| self.doc_display_pass(kc), key_columns), + "))", + )); + } + } + RcDoc::intersperse(docs, Doc::line()).group() + } -pub(crate) fn doc_create_materialized_view( - v: &CreateMaterializedViewStatement, - config: PrettyConfig, -) -> RcDoc { - let mut docs = vec![]; - docs.push(RcDoc::text(format!( - "CREATE{} MATERIALIZED VIEW{} {}", - if v.if_exists == IfExistsBehavior::Replace { - " OR REPLACE" - } else { - "" - }, - if v.if_exists == IfExistsBehavior::Skip { - " IF NOT EXISTS" - } else { - "" - }, - v.name, - ))); - if !v.columns.is_empty() { - docs.push(bracket( - "(", - comma_separate(doc_display_pass_mapper(config), &v.columns), - ")", - )); + fn doc_as_of<'a, T: AstInfo>(&'a self, v: &'a AsOf) -> RcDoc<'a> { + let (title, expr) = match v { + AsOf::At(expr) => ("AS OF", expr), + AsOf::AtLeast(expr) => ("AS OF AT LEAST", expr), + }; + nest_title(title, self.doc_expr(expr)) } - if let Some(cluster) = &v.in_cluster { + + pub(crate) fn doc_create_view<'a, T: AstInfo>( + &'a self, + v: &'a CreateViewStatement, + ) -> RcDoc<'a> { + let mut docs = vec![]; docs.push(RcDoc::text(format!( - "IN CLUSTER {}", - cluster.to_ast_string_simple() + "CREATE{}{} VIEW{}", + if v.if_exists == IfExistsBehavior::Replace { + " OR REPLACE" + } else { + "" + }, + if v.temporary { " TEMPORARY" } else { "" }, + if v.if_exists == IfExistsBehavior::Skip { + " IF NOT EXISTS" + } else { + "" + }, ))); + docs.push(self.doc_view_definition(&v.definition)); + intersperse_line_nest(docs) } - if !v.with_options.is_empty() { - docs.push(bracket( - "WITH (", - comma_separate(doc_display_pass_mapper(config), &v.with_options), - ")", - )); - } - docs.push(nest_title("AS", doc_query(&v.query, config))); - intersperse_line_nest(docs) -} -fn doc_view_definition(v: &ViewDefinition, config: PrettyConfig) -> RcDoc { - let mut docs = vec![RcDoc::text(v.name.to_string())]; - if !v.columns.is_empty() { - docs.push(bracket( - "(", - comma_separate(doc_display_pass_mapper(config), &v.columns), - ")", - )); + pub(crate) fn doc_create_materialized_view<'a, T: AstInfo>( + &'a self, + v: &'a CreateMaterializedViewStatement, + ) -> RcDoc<'a> { + let mut docs = vec![]; + docs.push(RcDoc::text(format!( + "CREATE{} MATERIALIZED VIEW{} {}", + if v.if_exists == IfExistsBehavior::Replace { + " OR REPLACE" + } else { + "" + }, + if v.if_exists == IfExistsBehavior::Skip { + " IF NOT EXISTS" + } else { + "" + }, + v.name, + ))); + if !v.columns.is_empty() { + docs.push(bracket( + "(", + comma_separate(|c| self.doc_display_pass(c), &v.columns), + ")", + )); + } + if let Some(cluster) = &v.in_cluster { + docs.push(RcDoc::text(format!( + "IN CLUSTER {}", + cluster.to_ast_string_simple() + ))); + } + if !v.with_options.is_empty() { + docs.push(bracket( + "WITH (", + comma_separate(|wo| self.doc_display_pass(wo), &v.with_options), + ")", + )); + } + docs.push(nest_title("AS", self.doc_query(&v.query))); + intersperse_line_nest(docs) } - docs.push(nest_title("AS", doc_query(&v.query, config))); - RcDoc::intersperse(docs, Doc::line()).group() -} -pub(crate) fn doc_insert(v: &InsertStatement, config: PrettyConfig) -> RcDoc { - let mut first = vec![RcDoc::text(format!( - "INSERT INTO {}", - v.table_name.to_ast_string_simple() - ))]; - if !v.columns.is_empty() { - first.push(bracket( - "(", - comma_separate(doc_display_pass_mapper(config), &v.columns), - ")", - )); - } - let sources = match &v.source { - InsertSource::Query(query) => doc_query(query, config), - _ => doc_display(&v.source, config, "insert source"), - }; - let mut doc = intersperse_line_nest([intersperse_line_nest(first), sources]); - if !v.returning.is_empty() { - doc = nest( - doc, - nest_title( - "RETURNING", - comma_separate(doc_display_pass_mapper(config), &v.returning), - ), - ) + fn doc_view_definition<'a, T: AstInfo>(&'a self, v: &'a ViewDefinition) -> RcDoc<'a> { + let mut docs = vec![RcDoc::text(v.name.to_string())]; + if !v.columns.is_empty() { + docs.push(bracket( + "(", + comma_separate(|c| self.doc_display_pass(c), &v.columns), + ")", + )); + } + docs.push(nest_title("AS", self.doc_query(&v.query))); + RcDoc::intersperse(docs, Doc::line()).group() + } + + pub(crate) fn doc_insert<'a, T: AstInfo>(&'a self, v: &'a InsertStatement) -> RcDoc<'a> { + let mut first = vec![RcDoc::text(format!( + "INSERT INTO {}", + v.table_name.to_ast_string_simple() + ))]; + if !v.columns.is_empty() { + first.push(bracket( + "(", + comma_separate(|c| self.doc_display_pass(c), &v.columns), + ")", + )); + } + let sources = match &v.source { + InsertSource::Query(query) => self.doc_query(query), + _ => self.doc_display(&v.source, "insert source"), + }; + let mut doc = intersperse_line_nest([intersperse_line_nest(first), sources]); + if !v.returning.is_empty() { + doc = nest( + doc, + nest_title( + "RETURNING", + comma_separate(|r| self.doc_display_pass(r), &v.returning), + ), + ) + } + doc } - doc -} -pub(crate) fn doc_select_statement( - v: &SelectStatement, - config: PrettyConfig, -) -> RcDoc { - let mut doc = doc_query(&v.query, config); - if let Some(as_of) = &v.as_of { - doc = intersperse_line_nest([doc, doc_as_of(as_of, config)]); + pub(crate) fn doc_select_statement<'a, T: AstInfo>( + &'a self, + v: &'a SelectStatement, + ) -> RcDoc<'a> { + let mut doc = self.doc_query(&v.query); + if let Some(as_of) = &v.as_of { + doc = intersperse_line_nest([doc, self.doc_as_of(as_of)]); + } + doc.group() } - doc.group() -} - -fn doc_order_by(v: &[OrderByExpr], config: PrettyConfig) -> RcDoc { - title_comma_separate("ORDER BY", doc_order_by_expr_mapper(config), v) -} -fn doc_order_by_expr(v: &OrderByExpr, config: PrettyConfig) -> RcDoc { - let doc = doc_expr(&v.expr, config); - let doc = match v.asc { - Some(true) => nest(doc, RcDoc::text("ASC")), - Some(false) => nest(doc, RcDoc::text("DESC")), - None => doc, - }; - match v.nulls_last { - Some(true) => nest(doc, RcDoc::text("NULLS LAST")), - Some(false) => nest(doc, RcDoc::text("NULLS FIRST")), - None => doc, + fn doc_order_by<'a, T: AstInfo>(&'a self, v: &'a [OrderByExpr]) -> RcDoc<'a> { + title_comma_separate("ORDER BY", |o| self.doc_order_by_expr(o), v) } -} -fn doc_order_by_expr_mapper( - config: PrettyConfig, -) -> impl for<'b> FnMut(&'b OrderByExpr) -> RcDoc<'b, ()> { - move |v| doc_order_by_expr(v, config) -} + fn doc_order_by_expr<'a, T: AstInfo>(&'a self, v: &'a OrderByExpr) -> RcDoc<'a> { + let doc = self.doc_expr(&v.expr); + let doc = match v.asc { + Some(true) => nest(doc, RcDoc::text("ASC")), + Some(false) => nest(doc, RcDoc::text("DESC")), + None => doc, + }; + match v.nulls_last { + Some(true) => nest(doc, RcDoc::text("NULLS LAST")), + Some(false) => nest(doc, RcDoc::text("NULLS FIRST")), + None => doc, + } + } -fn doc_query(v: &Query, config: PrettyConfig) -> RcDoc { - let mut docs = vec![]; - if !v.ctes.is_empty() { - match &v.ctes { - CteBlock::Simple(ctes) => { - docs.push(title_comma_separate("WITH", doc_cte_mapper(config), ctes)) - } - CteBlock::MutuallyRecursive(mutrec) => { - let mut doc = RcDoc::text("WITH MUTUALLY RECURSIVE"); - if !mutrec.options.is_empty() { - doc = nest( + fn doc_query<'a, T: AstInfo>(&'a self, v: &'a Query) -> RcDoc<'a> { + let mut docs = vec![]; + if !v.ctes.is_empty() { + match &v.ctes { + CteBlock::Simple(ctes) => { + docs.push(title_comma_separate("WITH", |cte| self.doc_cte(cte), ctes)) + } + CteBlock::MutuallyRecursive(mutrec) => { + let mut doc = RcDoc::text("WITH MUTUALLY RECURSIVE"); + if !mutrec.options.is_empty() { + doc = nest( + doc, + bracket( + "(", + comma_separate(|o| self.doc_display_pass(o), &mutrec.options), + ")", + ), + ); + } + docs.push(nest( doc, - bracket( - "(", - comma_separate(doc_display_pass_mapper(config), &mutrec.options), - ")", - ), - ); + comma_separate(|c| self.doc_mutually_recursive(c), &mutrec.ctes), + )); } - docs.push(nest( - doc, - comma_separate(doc_mutually_recursive_mapper(config), &mutrec.ctes), - )); } } - } - docs.push(doc_set_expr(&v.body, config)); - if !v.order_by.is_empty() { - docs.push(doc_order_by(&v.order_by, config)); - } + docs.push(self.doc_set_expr(&v.body)); + if !v.order_by.is_empty() { + docs.push(self.doc_order_by(&v.order_by)); + } - let offset = if let Some(offset) = &v.offset { - vec![RcDoc::concat([nest_title( - "OFFSET", - doc_expr(offset, config), - )])] - } else { - vec![] - }; - - if let Some(limit) = &v.limit { - if limit.with_ties { - docs.extend(offset); - docs.push(RcDoc::concat([ - RcDoc::text("FETCH FIRST "), - doc_expr(&limit.quantity, config), - RcDoc::text(" ROWS WITH TIES"), - ])); + let offset = if let Some(offset) = &v.offset { + vec![RcDoc::concat([nest_title("OFFSET", self.doc_expr(offset))])] + } else { + vec![] + }; + + if let Some(limit) = &v.limit { + if limit.with_ties { + docs.extend(offset); + docs.push(RcDoc::concat([ + RcDoc::text("FETCH FIRST "), + self.doc_expr(&limit.quantity), + RcDoc::text(" ROWS WITH TIES"), + ])); + } else { + docs.push(nest_title("LIMIT", self.doc_expr(&limit.quantity))); + docs.extend(offset); + } } else { - docs.push(nest_title("LIMIT", doc_expr(&limit.quantity, config))); docs.extend(offset); } - } else { - docs.extend(offset); - } - - RcDoc::intersperse(docs, Doc::line()).group() -} - -fn doc_cte(v: &Cte, config: PrettyConfig) -> RcDoc { - RcDoc::concat([ - RcDoc::text(format!("{} AS", v.alias)), - RcDoc::line(), - bracket("(", doc_query(&v.query, config), ")"), - ]) -} -fn doc_cte_mapper( - config: PrettyConfig, -) -> impl for<'b> FnMut(&'b Cte) -> RcDoc<'b, ()> { - move |v| doc_cte(v, config) -} + RcDoc::intersperse(docs, Doc::line()).group() + } -fn doc_mutually_recursive(v: &CteMutRec, config: PrettyConfig) -> RcDoc { - let mut docs = Vec::new(); - if !v.columns.is_empty() { - docs.push(bracket( - "(", - comma_separate(doc_display_pass_mapper(config), &v.columns), - ")", - )); + fn doc_cte<'a, T: AstInfo>(&'a self, v: &'a Cte) -> RcDoc<'a> { + RcDoc::concat([ + RcDoc::text(format!("{} AS", v.alias)), + RcDoc::line(), + bracket("(", self.doc_query(&v.query), ")"), + ]) } - docs.push(bracket("AS (", doc_query(&v.query, config), ")")); - nest( - doc_display_pass(&v.name, config), - RcDoc::intersperse(docs, Doc::line()).group(), - ) -} -fn doc_mutually_recursive_mapper( - config: PrettyConfig, -) -> impl for<'b> FnMut(&'b CteMutRec) -> RcDoc<'b, ()> { - move |v| doc_mutually_recursive(v, config) -} + fn doc_mutually_recursive<'a, T: AstInfo>(&'a self, v: &'a CteMutRec) -> RcDoc<'a> { + let mut docs = Vec::new(); + if !v.columns.is_empty() { + docs.push(bracket( + "(", + comma_separate(|c| self.doc_display_pass(c), &v.columns), + ")", + )); + } + docs.push(bracket("AS (", self.doc_query(&v.query), ")")); + nest( + self.doc_display_pass(&v.name), + RcDoc::intersperse(docs, Doc::line()).group(), + ) + } -fn doc_set_expr(v: &SetExpr, config: PrettyConfig) -> RcDoc { - match v { - SetExpr::Select(v) => doc_select(v, config), - SetExpr::Query(v) => bracket("(", doc_query(v, config), ")"), - SetExpr::SetOperation { - op, - all, - left, - right, - } => { - let all_str = if *all { " ALL" } else { "" }; - RcDoc::concat([ - doc_set_expr(left, config), - RcDoc::line(), + fn doc_set_expr<'a, T: AstInfo>(&'a self, v: &'a SetExpr) -> RcDoc<'a> { + match v { + SetExpr::Select(v) => self.doc_select(v), + SetExpr::Query(v) => bracket("(", self.doc_query(v), ")"), + SetExpr::SetOperation { + op, + all, + left, + right, + } => { + let all_str = if *all { " ALL" } else { "" }; RcDoc::concat([ - RcDoc::text(format!("{}{}", op, all_str)), + self.doc_set_expr(left), RcDoc::line(), - doc_set_expr(right, config), + RcDoc::concat([ + RcDoc::text(format!("{}{}", op, all_str)), + RcDoc::line(), + self.doc_set_expr(right), + ]) + .nest(TAB) + .group(), ]) - .nest(TAB) - .group(), - ]) + } + SetExpr::Values(v) => self.doc_values(v), + SetExpr::Show(v) => self.doc_display(v, "SHOW"), + SetExpr::Table(v) => nest(RcDoc::text("TABLE"), self.doc_display_pass(v)), } - SetExpr::Values(v) => doc_values(v, config), - SetExpr::Show(v) => doc_display(v, config, "SHOW"), - SetExpr::Table(v) => nest(RcDoc::text("TABLE"), doc_display_pass(v, config)), - } - .group() -} - -fn doc_values(v: &Values, config: PrettyConfig) -> RcDoc { - let rows = - v.0.iter() - .map(|row| bracket("(", comma_separate(doc_expr_mapper(config), row), ")")); - RcDoc::concat([RcDoc::text("VALUES"), RcDoc::line(), comma_separated(rows)]) - .nest(TAB) .group() -} - -fn doc_table_with_joins(v: &TableWithJoins, config: PrettyConfig) -> RcDoc { - let mut docs = vec![doc_table_factor(&v.relation, config)]; - for j in &v.joins { - docs.push(doc_join(j, config)); } - intersperse_line_nest(docs) -} -fn doc_table_with_joins_mapper( - config: PrettyConfig, -) -> impl for<'b> FnMut(&'b TableWithJoins) -> RcDoc<'b, ()> { - move |v| doc_table_with_joins(v, config) -} + fn doc_values<'a, T: AstInfo>(&'a self, v: &'a Values) -> RcDoc<'a> { + let rows = + v.0.iter() + .map(|row| bracket("(", comma_separate(|v| self.doc_expr(v), row), ")")); + RcDoc::concat([RcDoc::text("VALUES"), RcDoc::line(), comma_separated(rows)]) + .nest(TAB) + .group() + } -fn doc_join(v: &Join, config: PrettyConfig) -> RcDoc { - let (constraint, name) = match &v.join_operator { - JoinOperator::Inner(constraint) => (constraint, "JOIN"), - JoinOperator::FullOuter(constraint) => (constraint, "FULL JOIN"), - JoinOperator::LeftOuter(constraint) => (constraint, "LEFT JOIN"), - JoinOperator::RightOuter(constraint) => (constraint, "RIGHT JOIN"), - _ => return doc_display(v, config, "join operator"), - }; - let constraint = match constraint { - JoinConstraint::On(expr) => nest_title("ON", doc_expr(expr, config)), - JoinConstraint::Using { columns, alias } => { - let mut doc = bracket( - "USING(", - comma_separate(doc_display_pass_mapper(config), columns), - ")", - ); - if let Some(alias) = alias { - doc = nest(doc, nest_title("AS", doc_display_pass(alias, config))); + fn doc_table_with_joins<'a, T: AstInfo>(&'a self, v: &'a TableWithJoins) -> RcDoc<'a> { + let mut docs = vec![self.doc_table_factor(&v.relation)]; + for j in &v.joins { + docs.push(self.doc_join(j)); + } + intersperse_line_nest(docs) + } + + fn doc_join<'a, T: AstInfo>(&'a self, v: &'a Join) -> RcDoc<'a> { + let (constraint, name) = match &v.join_operator { + JoinOperator::Inner(constraint) => (constraint, "JOIN"), + JoinOperator::FullOuter(constraint) => (constraint, "FULL JOIN"), + JoinOperator::LeftOuter(constraint) => (constraint, "LEFT JOIN"), + JoinOperator::RightOuter(constraint) => (constraint, "RIGHT JOIN"), + _ => return self.doc_display(v, "join operator"), + }; + let constraint = match constraint { + JoinConstraint::On(expr) => nest_title("ON", self.doc_expr(expr)), + JoinConstraint::Using { columns, alias } => { + let mut doc = bracket( + "USING(", + comma_separate(|c| self.doc_display_pass(c), columns), + ")", + ); + if let Some(alias) = alias { + doc = nest(doc, nest_title("AS", self.doc_display_pass(alias))); + } + doc } - doc - } - _ => return doc_display(v, config, "join constraint"), - }; - intersperse_line_nest([ - RcDoc::text(name), - doc_table_factor(&v.relation, config), - constraint, - ]) -} - -fn doc_table_factor(v: &TableFactor, config: PrettyConfig) -> RcDoc { - match v { - TableFactor::Derived { - lateral, - subquery, - alias, - } => { - let prefix = if *lateral { "LATERAL (" } else { "(" }; - let mut docs = vec![bracket(prefix, doc_query(subquery, config), ")")]; - if let Some(alias) = alias { - docs.push(RcDoc::text(format!("AS {}", alias))); + _ => return self.doc_display(v, "join constraint"), + }; + intersperse_line_nest([ + RcDoc::text(name), + self.doc_table_factor(&v.relation), + constraint, + ]) + } + + fn doc_table_factor<'a, T: AstInfo>(&'a self, v: &'a TableFactor) -> RcDoc<'a> { + match v { + TableFactor::Derived { + lateral, + subquery, + alias, + } => { + let prefix = if *lateral { "LATERAL (" } else { "(" }; + let mut docs = vec![bracket(prefix, self.doc_query(subquery), ")")]; + if let Some(alias) = alias { + docs.push(RcDoc::text(format!("AS {}", alias))); + } + intersperse_line_nest(docs) } - intersperse_line_nest(docs) - } - TableFactor::NestedJoin { join, alias } => { - let mut doc = bracket("(", doc_table_with_joins(join, config), ")"); - if let Some(alias) = alias { - doc = nest(doc, RcDoc::text(format!("AS {}", alias))); + TableFactor::NestedJoin { join, alias } => { + let mut doc = bracket("(", self.doc_table_with_joins(join), ")"); + if let Some(alias) = alias { + doc = nest(doc, RcDoc::text(format!("AS {}", alias))); + } + doc } - doc - } - TableFactor::Table { name, alias } => { - let mut doc = doc_display_pass(name, config); - if let Some(alias) = alias { - doc = nest(doc, RcDoc::text(format!("AS {}", alias))); + TableFactor::Table { name, alias } => { + let mut doc = self.doc_display_pass(name); + if let Some(alias) = alias { + doc = nest(doc, RcDoc::text(format!("AS {}", alias))); + } + doc } - doc + _ => self.doc_display(v, "table factor variant"), } - _ => doc_display(v, config, "table factor variant"), } -} -fn doc_distinct(v: &Distinct, config: PrettyConfig) -> RcDoc { - match v { - Distinct::EntireRow => RcDoc::text("DISTINCT"), - Distinct::On(cols) => bracket( - "DISTINCT ON (", - comma_separate(doc_expr_mapper(config), cols), - ")", - ), + fn doc_distinct<'a, T: AstInfo>(&'a self, v: &'a Distinct) -> RcDoc<'a> { + match v { + Distinct::EntireRow => RcDoc::text("DISTINCT"), + Distinct::On(cols) => bracket( + "DISTINCT ON (", + comma_separate(|c| self.doc_expr(c), cols), + ")", + ), + } } -} -fn doc_select(v: &Select, config: PrettyConfig) -> RcDoc { - let mut docs = vec![]; - let mut select = RcDoc::text("SELECT"); - if let Some(distinct) = &v.distinct { - select = nest(select, doc_distinct(distinct, config)); - } - docs.push(nest_comma_separate( - select, - doc_select_item_mapper(config), - &v.projection, - )); - if !v.from.is_empty() { - docs.push(title_comma_separate( - "FROM", - doc_table_with_joins_mapper(config), - &v.from, - )); - } - if let Some(selection) = &v.selection { - docs.push(nest_title("WHERE", doc_expr(selection, config))); - } - if !v.group_by.is_empty() { - docs.push(title_comma_separate( - "GROUP BY", - doc_expr_mapper(config), - &v.group_by, - )); - } - if let Some(having) = &v.having { - docs.push(nest_title("HAVING", doc_expr(having, config))); - } - if let Some(qualify) = &v.qualify { - docs.push(nest_title("QUALIFY", doc_expr(qualify, config))); - } - if !v.options.is_empty() { - docs.push(bracket( - "OPTIONS (", - comma_separate(doc_display_pass_mapper(config), &v.options), - ")", + fn doc_select<'a, T: AstInfo>(&'a self, v: &'a Select) -> RcDoc<'a> { + let mut docs = vec![]; + let mut select = RcDoc::text("SELECT"); + if let Some(distinct) = &v.distinct { + select = nest(select, self.doc_distinct(distinct)); + } + docs.push(nest_comma_separate( + select, + |s| self.doc_select_item(s), + &v.projection, )); + if !v.from.is_empty() { + docs.push(title_comma_separate( + "FROM", + |t| self.doc_table_with_joins(t), + &v.from, + )); + } + if let Some(selection) = &v.selection { + docs.push(nest_title("WHERE", self.doc_expr(selection))); + } + if !v.group_by.is_empty() { + docs.push(title_comma_separate( + "GROUP BY", + |e| self.doc_expr(e), + &v.group_by, + )); + } + if let Some(having) = &v.having { + docs.push(nest_title("HAVING", self.doc_expr(having))); + } + if let Some(qualify) = &v.qualify { + docs.push(nest_title("QUALIFY", self.doc_expr(qualify))); + } + if !v.options.is_empty() { + docs.push(bracket( + "OPTIONS (", + comma_separate(|o| self.doc_display_pass(o), &v.options), + ")", + )); + } + RcDoc::intersperse(docs, Doc::line()).group() } - RcDoc::intersperse(docs, Doc::line()).group() -} -fn doc_select_item(v: &SelectItem, config: PrettyConfig) -> RcDoc { - match v { - SelectItem::Expr { expr, alias } => { - let mut doc = doc_expr(expr, config); - if let Some(alias) = alias { - doc = nest( - doc, - RcDoc::concat([RcDoc::text("AS "), doc_display_pass(alias, config)]), - ); + fn doc_select_item<'a, T: AstInfo>(&'a self, v: &'a SelectItem) -> RcDoc<'a> { + match v { + SelectItem::Expr { expr, alias } => { + let mut doc = self.doc_expr(expr); + if let Some(alias) = alias { + doc = nest( + doc, + RcDoc::concat([RcDoc::text("AS "), self.doc_display_pass(alias)]), + ); + } + doc } - doc + SelectItem::Wildcard => self.doc_display_pass(v), } - SelectItem::Wildcard => doc_display_pass(v, config), } -} -fn doc_select_item_mapper( - config: PrettyConfig, -) -> impl for<'b> FnMut(&'b SelectItem) -> RcDoc<'b, ()> { - move |v| doc_select_item(v, config) -} - -pub fn doc_expr(v: &Expr, config: PrettyConfig) -> RcDoc { - match v { - Expr::Op { op, expr1, expr2 } => { - if let Some(expr2) = expr2 { + pub fn doc_expr<'a, T: AstInfo>(&'a self, v: &'a Expr) -> RcDoc<'a> { + match v { + Expr::Op { op, expr1, expr2 } => { + if let Some(expr2) = expr2 { + RcDoc::concat([ + self.doc_expr(expr1), + RcDoc::line(), + RcDoc::text(format!("{} ", op)), + self.doc_expr(expr2).nest(TAB), + ]) + } else { + RcDoc::concat([RcDoc::text(format!("{} ", op)), self.doc_expr(expr1)]) + } + } + Expr::Case { + operand, + conditions, + results, + else_result, + } => { + let mut docs = Vec::new(); + if let Some(operand) = operand { + docs.push(self.doc_expr(operand)); + } + for (c, r) in conditions.iter().zip(results) { + let when = nest_title("WHEN", self.doc_expr(c)); + let then = nest_title("THEN", self.doc_expr(r)); + docs.push(nest(when, then)); + } + if let Some(else_result) = else_result { + docs.push(nest_title("ELSE", self.doc_expr(else_result))); + } + let doc = intersperse_line_nest(docs); + bracket_doc(RcDoc::text("CASE"), doc, RcDoc::text("END"), RcDoc::line()) + } + Expr::Cast { expr, data_type } => { + let doc = self.doc_expr(expr); RcDoc::concat([ - doc_expr(expr1, config), - RcDoc::line(), - RcDoc::text(format!("{} ", op)), - doc_expr(expr2, config).nest(TAB), + doc, + RcDoc::text(format!("::{}", data_type.to_ast_string_simple())), ]) - } else { - RcDoc::concat([RcDoc::text(format!("{} ", op)), doc_expr(expr1, config)]) } - } - Expr::Case { - operand, - conditions, - results, - else_result, - } => { - let mut docs = Vec::new(); - if let Some(operand) = operand { - docs.push(doc_expr(operand, config)); + Expr::Nested(ast) => bracket("(", self.doc_expr(ast), ")"), + Expr::Function(fun) => self.doc_function(fun), + Expr::Subquery(ast) => bracket("(", self.doc_query(ast), ")"), + Expr::Identifier(_) + | Expr::Value(_) + | Expr::QualifiedWildcard(_) + | Expr::WildcardAccess(_) + | Expr::FieldAccess { .. } => self.doc_display_pass(v), + Expr::And { left, right } => bracket_doc( + self.doc_expr(left), + RcDoc::text("AND"), + self.doc_expr(right), + RcDoc::line(), + ), + Expr::Or { left, right } => bracket_doc( + self.doc_expr(left), + RcDoc::text("OR"), + self.doc_expr(right), + RcDoc::line(), + ), + Expr::Exists(s) => bracket("EXISTS (", self.doc_query(s), ")"), + Expr::IsExpr { + expr, + negated, + construct, + } => bracket_doc( + self.doc_expr(expr), + RcDoc::text(if *negated { "IS NOT" } else { "IS" }), + self.doc_display_pass(construct), + RcDoc::line(), + ), + Expr::Not { expr } => { + RcDoc::concat([RcDoc::text("NOT"), RcDoc::line(), self.doc_expr(expr)]) } - for (c, r) in conditions.iter().zip(results) { - let when = nest_title("WHEN", doc_expr(c, config)); - let then = nest_title("THEN", doc_expr(r, config)); - docs.push(nest(when, then)); + Expr::Between { + expr, + negated, + low, + high, + } => RcDoc::intersperse( + [ + self.doc_expr(expr), + RcDoc::text(if *negated { "NOT BETWEEN" } else { "BETWEEN" }), + RcDoc::intersperse( + [self.doc_expr(low), RcDoc::text("AND"), self.doc_expr(high)], + RcDoc::line(), + ) + .group(), + ], + RcDoc::line(), + ), + Expr::InSubquery { + expr, + subquery, + negated, + } => RcDoc::intersperse( + [ + self.doc_expr(expr), + RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }), + self.doc_query(subquery), + RcDoc::text(")"), + ], + RcDoc::line(), + ), + Expr::InList { + expr, + list, + negated, + } => RcDoc::intersperse( + [ + self.doc_expr(expr), + RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }), + comma_separate(|e| self.doc_expr(e), list), + RcDoc::text(")"), + ], + RcDoc::line(), + ), + Expr::Row { exprs } => { + bracket("ROW(", comma_separate(|e| self.doc_expr(e), exprs), ")") } - if let Some(else_result) = else_result { - docs.push(nest_title("ELSE", doc_expr(else_result, config))); + Expr::NullIf { l_expr, r_expr } => bracket( + "NULLIF (", + comma_separate(|e| self.doc_expr(e), [&**l_expr, &**r_expr]), + ")", + ), + Expr::HomogenizingFunction { function, exprs } => bracket( + format!("{function}("), + comma_separate(|e| self.doc_expr(e), exprs), + ")", + ), + Expr::ArraySubquery(s) => bracket("ARRAY(", self.doc_query(s), ")"), + Expr::ListSubquery(s) => bracket("LIST(", self.doc_query(s), ")"), + Expr::Array(exprs) => { + bracket("ARRAY[", comma_separate(|e| self.doc_expr(e), exprs), "]") } - let doc = intersperse_line_nest(docs); - bracket_doc(RcDoc::text("CASE"), doc, RcDoc::text("END"), RcDoc::line()) + Expr::List(exprs) => bracket("LIST[", comma_separate(|e| self.doc_expr(e), exprs), "]"), + _ => self.doc_display(v, "expr variant"), } - Expr::Cast { expr, data_type } => { - let doc = doc_expr(expr, config); - RcDoc::concat([ - doc, - RcDoc::text(format!("::{}", data_type.to_ast_string_simple())), - ]) - } - Expr::Nested(ast) => bracket("(", doc_expr(ast, config), ")"), - Expr::Function(fun) => doc_function(fun, config), - Expr::Subquery(ast) => bracket("(", doc_query(ast, config), ")"), - Expr::Identifier(_) - | Expr::Value(_) - | Expr::QualifiedWildcard(_) - | Expr::WildcardAccess(_) - | Expr::FieldAccess { .. } => doc_display_pass(v, config), - Expr::And { left, right } => bracket_doc( - doc_expr(left, config), - RcDoc::text("AND"), - doc_expr(right, config), - RcDoc::line(), - ), - Expr::Or { left, right } => bracket_doc( - doc_expr(left, config), - RcDoc::text("OR"), - doc_expr(right, config), - RcDoc::line(), - ), - Expr::Exists(s) => bracket("EXISTS (", doc_query(s, config), ")"), - Expr::IsExpr { - expr, - negated, - construct, - } => bracket_doc( - doc_expr(expr, config), - RcDoc::text(if *negated { "IS NOT" } else { "IS" }), - doc_display_pass(construct, config), - RcDoc::line(), - ), - Expr::Not { expr } => { - RcDoc::concat([RcDoc::text("NOT"), RcDoc::line(), doc_expr(expr, config)]) - } - Expr::Between { - expr, - negated, - low, - high, - } => RcDoc::intersperse( - [ - doc_expr(expr, config), - RcDoc::text(if *negated { "NOT BETWEEN" } else { "BETWEEN" }), - RcDoc::intersperse( - [ - doc_expr(low, config), - RcDoc::text("AND"), - doc_expr(high, config), - ], - RcDoc::line(), - ) - .group(), - ], - RcDoc::line(), - ), - Expr::InSubquery { - expr, - subquery, - negated, - } => RcDoc::intersperse( - [ - doc_expr(expr, config), - RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }), - doc_query(subquery, config), - RcDoc::text(")"), - ], - RcDoc::line(), - ), - Expr::InList { - expr, - list, - negated, - } => RcDoc::intersperse( - [ - doc_expr(expr, config), - RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }), - comma_separate(doc_expr_mapper(config), list), - RcDoc::text(")"), - ], - RcDoc::line(), - ), - Expr::Row { exprs } => bracket("ROW(", comma_separate(doc_expr_mapper(config), exprs), ")"), - Expr::NullIf { l_expr, r_expr } => bracket( - "NULLIF (", - comma_separate(doc_expr_mapper(config), [&**l_expr, &**r_expr]), - ")", - ), - Expr::HomogenizingFunction { function, exprs } => bracket( - format!("{function}("), - comma_separate(doc_expr_mapper(config), exprs), - ")", - ), - Expr::ArraySubquery(s) => bracket("ARRAY(", doc_query(s, config), ")"), - Expr::ListSubquery(s) => bracket("LIST(", doc_query(s, config), ")"), - Expr::Array(exprs) => bracket( - "ARRAY[", - comma_separate(doc_expr_mapper(config), exprs), - "]", - ), - Expr::List(exprs) => bracket("LIST[", comma_separate(doc_expr_mapper(config), exprs), "]"), - _ => doc_display(v, config, "expr variant"), + .group() } - .group() -} -fn doc_expr_mapper( - config: PrettyConfig, -) -> impl for<'b> FnMut(&'b Expr) -> RcDoc<'b, ()> { - move |v| doc_expr(v, config) -} - -fn doc_function(v: &Function, config: PrettyConfig) -> RcDoc { - match &v.args { - FunctionArgs::Star => doc_display_pass(v, config), - FunctionArgs::Args { args, order_by } => { - if args.is_empty() { - // Nullary, don't allow newline between parens, so just delegate. - return doc_display_pass(v, config); - } - if v.filter.is_some() || v.over.is_some() || !order_by.is_empty() { - return doc_display(v, config, "function filter or over or order by"); - } - let special = match v.name.to_ast_string_stable().as_str() { - r#""extract""# if v.args.len() == Some(2) => true, - r#""position""# if v.args.len() == Some(2) => true, - _ => false, - }; - if special { - return doc_display(v, config, "special function"); + fn doc_function<'a, T: AstInfo>(&'a self, v: &'a Function) -> RcDoc<'a> { + match &v.args { + FunctionArgs::Star => self.doc_display_pass(v), + FunctionArgs::Args { args, order_by } => { + if args.is_empty() { + // Nullary, don't allow newline between parens, so just delegate. + return self.doc_display_pass(v); + } + if v.filter.is_some() || v.over.is_some() || !order_by.is_empty() { + return self.doc_display(v, "function filter or over or order by"); + } + let special = match v.name.to_ast_string_stable().as_str() { + r#""extract""# if v.args.len() == Some(2) => true, + r#""position""# if v.args.len() == Some(2) => true, + _ => false, + }; + if special { + return self.doc_display(v, "special function"); + } + let name = format!( + "{}({}", + v.name.to_ast_string_simple(), + if v.distinct { "DISTINCT " } else { "" } + ); + bracket(name, comma_separate(|e| self.doc_expr(e), args), ")") } - let name = format!( - "{}({}", - v.name.to_ast_string_simple(), - if v.distinct { "DISTINCT " } else { "" } - ); - bracket(name, comma_separate(doc_expr_mapper(config), args), ")") } } } diff --git a/src/sql-pretty/src/lib.rs b/src/sql-pretty/src/lib.rs index 1d3c00c88ac78..af3803ba64bad 100644 --- a/src/sql-pretty/src/lib.rs +++ b/src/sql-pretty/src/lib.rs @@ -16,30 +16,10 @@ use mz_sql_parser::parser::{parse_statements, ParserStatementError}; use pretty::RcDoc; use thiserror::Error; -use crate::doc::{ - doc_copy, doc_create_materialized_view, doc_create_source, doc_create_view, doc_display, - doc_insert, doc_select_statement, doc_subscribe, -}; - -pub use crate::doc::doc_expr; - pub const DEFAULT_WIDTH: usize = 100; const TAB: isize = 4; -fn to_doc(v: &Statement, config: PrettyConfig) -> RcDoc { - match v { - Statement::Select(v) => doc_select_statement(v, config), - Statement::Insert(v) => doc_insert(v, config), - Statement::CreateView(v) => doc_create_view(v, config), - Statement::CreateMaterializedView(v) => doc_create_materialized_view(v, config), - Statement::Copy(v) => doc_copy(v, config), - Statement::Subscribe(v) => doc_subscribe(v, config), - Statement::CreateSource(v) => doc_create_source(v, config), - _ => doc_display(v, config, "statement"), - } -} - #[derive(Clone, Copy)] pub struct PrettyConfig { pub width: usize, @@ -48,7 +28,7 @@ pub struct PrettyConfig { /// Pretty prints a statement at a width. pub fn to_pretty(stmt: &Statement, config: PrettyConfig) -> String { - format!("{};", to_doc(stmt, config).pretty(config.width)) + format!("{};", Pretty { config }.to_doc(stmt).pretty(config.width)) } /// Parses `str` into SQL statements and pretty prints them. @@ -95,3 +75,23 @@ pub enum Error { #[error("expected exactly one statement")] ExpectedOne, } + +/// (Public only for tests) +pub struct Pretty { + pub config: PrettyConfig, +} + +impl Pretty { + fn to_doc<'a, T: AstInfo>(&'a self, v: &'a Statement) -> RcDoc<'a> { + match v { + Statement::Select(v) => self.doc_select_statement(v), + Statement::Insert(v) => self.doc_insert(v), + Statement::CreateView(v) => self.doc_create_view(v), + Statement::CreateMaterializedView(v) => self.doc_create_materialized_view(v), + Statement::Copy(v) => self.doc_copy(v), + Statement::Subscribe(v) => self.doc_subscribe(v), + Statement::CreateSource(v) => self.doc_create_source(v), + _ => self.doc_display(v, "statement"), + } + } +} diff --git a/src/sql-pretty/src/util.rs b/src/sql-pretty/src/util.rs index a953c077d3627..cda422fc9234b 100644 --- a/src/sql-pretty/src/util.rs +++ b/src/sql-pretty/src/util.rs @@ -33,7 +33,7 @@ where pub(crate) fn title_comma_separate<'a, F, T, S>(title: S, f: F, v: &'a [T]) -> RcDoc<'a, ()> where - F: FnMut(&'a T) -> RcDoc<'a>, + F: Fn(&'a T) -> RcDoc<'a>, S: Into, { let title = RcDoc::text(title.into()); @@ -50,7 +50,7 @@ pub(crate) fn nest_comma_separate<'a, F, T: 'a, I>( v: I, ) -> RcDoc<'a, ()> where - F: FnMut(&'a T) -> RcDoc<'a>, + F: Fn(&'a T) -> RcDoc<'a>, I: IntoIterator, { nest(title, comma_separate(f, v)) @@ -58,7 +58,7 @@ where pub(crate) fn comma_separate<'a, F, T: 'a, I>(f: F, v: I) -> RcDoc<'a, ()> where - F: FnMut(&'a T) -> RcDoc<'a>, + F: Fn(&'a T) -> RcDoc<'a>, I: IntoIterator, { let docs = v.into_iter().map(f); diff --git a/src/sql-pretty/tests/parser.rs b/src/sql-pretty/tests/parser.rs index c08d04f3c9f0d..e1758d4a40cd2 100644 --- a/src/sql-pretty/tests/parser.rs +++ b/src/sql-pretty/tests/parser.rs @@ -11,7 +11,7 @@ use datadriven::walk; use mz_sql_parser::ast::display::{AstDisplay, FormatMode}; use mz_sql_parser::datadriven_testcase; use mz_sql_parser::parser::{parse_expr, parse_statements}; -use mz_sql_pretty::{doc_expr, to_pretty, PrettyConfig}; +use mz_sql_pretty::{to_pretty, Pretty, PrettyConfig}; // Use the parser's datadriven tests to get a comprehensive set of SQL statements. Assert they all // generate identical ASTs when pretty printed. Output the same output as the parser so datadriven @@ -43,26 +43,26 @@ fn verify_pretty_expr(expr: &str) { let n = *n; let pretty1 = format!( "{}", - doc_expr( - &original, - PrettyConfig { + Pretty { + config: PrettyConfig { width: n, format_mode: FormatMode::Simple } - ) + } + .doc_expr(&original) .pretty(n) ); let prettied = parse_expr(&pretty1) .unwrap_or_else(|_| panic!("could not parse: {pretty1}, original: {expr}")); let pretty2 = format!( "{}", - doc_expr( - &prettied, - PrettyConfig { + Pretty { + config: PrettyConfig { width: n, format_mode: FormatMode::Simple } - ) + } + .doc_expr(&prettied) .pretty(n) ); assert_eq!(pretty1, pretty2); From 2f3f888ac02376657e8579ffc929f35ed704668c Mon Sep 17 00:00:00 2001 From: Gabor Gevay Date: Wed, 26 Mar 2025 12:21:48 +0100 Subject: [PATCH 4/4] Version guards in SHOW CREATE tests --- .../materialize/checks/all_checks/debezium.py | 13 ++++- .../checks/all_checks/json_source.py | 6 +- .../checks/all_checks/kafka_formats.py | 5 +- .../checks/all_checks/rename_view.py | 5 +- .../materialize/checks/all_checks/webhook.py | 22 +++++-- .../10-create-connection.td | 7 ++- test/mysql-cdc-old-syntax/30-text-columns.td | 5 +- .../35-exclude-columns.td | 5 +- test/mysql-cdc-old-syntax/alter-source.td | 57 +++++++++++++------ test/mysql-cdc/10-create-connection.td | 7 ++- test/pg-cdc-old-syntax/alter-source.td | 32 ++++++++--- test/pg-cdc-old-syntax/pg-cdc.td | 5 +- 12 files changed, 130 insertions(+), 39 deletions(-) diff --git a/misc/python/materialize/checks/all_checks/debezium.py b/misc/python/materialize/checks/all_checks/debezium.py index bbeb30161d4d0..a1fee114ffa9f 100644 --- a/misc/python/materialize/checks/all_checks/debezium.py +++ b/misc/python/materialize/checks/all_checks/debezium.py @@ -152,12 +152,19 @@ def validate(self) -> Testdrive: r""" $ set-regex match="FORMAT .*? ENVELOPE DEBEZIUM " replacement="" - > SHOW CREATE SOURCE debezium_source1; + >[version>=14000] SHOW CREATE SOURCE debezium_source1; materialize.public.debezium_source1 "CREATE SOURCE materialize.public.debezium_source1\nIN CLUSTER quickstart\nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'postgres.public.debezium_table')\nEXPOSE PROGRESS AS materialize.public.debezium_source1_progress;" - > SHOW CREATE SOURCE debezium_source2; + >[version>=14000] SHOW CREATE SOURCE debezium_source2; materialize.public.debezium_source2 "CREATE SOURCE materialize.public.debezium_source2\nIN CLUSTER quickstart\nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'postgres.public.debezium_table')\nEXPOSE PROGRESS AS materialize.public.debezium_source2_progress;" - > SHOW CREATE SOURCE debezium_source3; + >[version>=14000] SHOW CREATE SOURCE debezium_source3; materialize.public.debezium_source3 "CREATE SOURCE materialize.public.debezium_source3\nIN CLUSTER quickstart\nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'postgres.public.debezium_table')\nEXPOSE PROGRESS AS materialize.public.debezium_source3_progress;" + + >[version<14000] SHOW CREATE SOURCE debezium_source1; + materialize.public.debezium_source1 "CREATE SOURCE \"materialize\".\"public\".\"debezium_source1\" IN CLUSTER \"quickstart\" FROM KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'postgres.public.debezium_table') EXPOSE PROGRESS AS \"materialize\".\"public\".\"debezium_source1_progress\"" + >[version<14000] SHOW CREATE SOURCE debezium_source2; + materialize.public.debezium_source2 "CREATE SOURCE \"materialize\".\"public\".\"debezium_source2\" IN CLUSTER \"quickstart\" FROM KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'postgres.public.debezium_table') EXPOSE PROGRESS AS \"materialize\".\"public\".\"debezium_source2_progress\"" + >[version<14000] SHOW CREATE SOURCE debezium_source3; + materialize.public.debezium_source3 "CREATE SOURCE \"materialize\".\"public\".\"debezium_source3\" IN CLUSTER \"quickstart\" FROM KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'postgres.public.debezium_table') EXPOSE PROGRESS AS \"materialize\".\"public\".\"debezium_source3_progress\"" """ if not self.is_running_as_cloudtest() else "" diff --git a/misc/python/materialize/checks/all_checks/json_source.py b/misc/python/materialize/checks/all_checks/json_source.py index 37b9c24a73db7..2826d21462e3a 100644 --- a/misc/python/materialize/checks/all_checks/json_source.py +++ b/misc/python/materialize/checks/all_checks/json_source.py @@ -82,8 +82,12 @@ def validate(self) -> Testdrive: "\\"str\\"" "\\"hello\\"" """ + r""" - > SHOW CREATE SOURCE format_jsonb_src; + + >[version>=14000] SHOW CREATE SOURCE format_jsonb_src; materialize.public.format_jsonb_src "CREATE SOURCE materialize.public.format_jsonb_src\nIN CLUSTER single_replica_cluster\nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = 'testdrive-format-json-${testdrive.seed}')\nEXPOSE PROGRESS AS materialize.public.format_jsonb_src_progress;" + + >[version<14000] SHOW CREATE SOURCE format_jsonb_src; + materialize.public.format_jsonb_src "CREATE SOURCE \"materialize\".\"public\".\"format_jsonb_src\" IN CLUSTER \"single_replica_cluster\" FROM KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = 'testdrive-format-json-1') EXPOSE PROGRESS AS \"materialize\".\"public\".\"format_jsonb_src_progress\"" """ ) ) diff --git a/misc/python/materialize/checks/all_checks/kafka_formats.py b/misc/python/materialize/checks/all_checks/kafka_formats.py index 7e76b4b59dfa2..38325502e14d4 100644 --- a/misc/python/materialize/checks/all_checks/kafka_formats.py +++ b/misc/python/materialize/checks/all_checks/kafka_formats.py @@ -219,8 +219,11 @@ def validate(self) -> Testdrive: $ set-regex match=testdrive-format-bytes-\d+ replacement= - > SHOW CREATE SOURCE format_bytes1_src; + >[version>=14000] SHOW CREATE SOURCE format_bytes1_src; materialize.public.format_bytes1_src "CREATE SOURCE materialize.public.format_bytes1_src\nIN CLUSTER kafka_formats\nFROM KAFKA CONNECTION materialize.public.kafka_conn (TOPIC = '')\nEXPOSE PROGRESS AS materialize.public.format_bytes1_src_progress;" + + >[version<14000] SHOW CREATE SOURCE format_bytes1_src; + materialize.public.format_bytes1_src "CREATE SOURCE \"materialize\".\"public\".\"format_bytes1_src\" IN CLUSTER \"kafka_formats\" FROM KAFKA CONNECTION \"materialize\".\"public\".\"kafka_conn\" (TOPIC = '') EXPOSE PROGRESS AS \"materialize\".\"public\".\"format_bytes1_src_progress\"" """ ) ) diff --git a/misc/python/materialize/checks/all_checks/rename_view.py b/misc/python/materialize/checks/all_checks/rename_view.py index 3c9984d8faed0..d6465fe8a7b72 100644 --- a/misc/python/materialize/checks/all_checks/rename_view.py +++ b/misc/python/materialize/checks/all_checks/rename_view.py @@ -48,9 +48,12 @@ def validate(self) -> Testdrive: return Testdrive( dedent( r""" - > SHOW CREATE VIEW rename_view_viewB3; + >[version>=14000] SHOW CREATE VIEW rename_view_viewB3; materialize.public.rename_view_viewb3 "CREATE VIEW\n materialize.public.rename_view_viewb3\n AS SELECT f2 FROM materialize.public.rename_view_viewa3 WHERE f2 > 0;" + >[version<14000] SHOW CREATE VIEW rename_view_viewB3; + materialize.public.rename_view_viewb3 "CREATE VIEW \"materialize\".\"public\".\"rename_view_viewb3\" AS SELECT \"f2\" FROM \"materialize\".\"public\".\"rename_view_viewa3\" WHERE \"f2\" > 0" + > SELECT * FROM rename_view_viewA3; 1 2 diff --git a/misc/python/materialize/checks/all_checks/webhook.py b/misc/python/materialize/checks/all_checks/webhook.py index d1cd05ca7a8a1..73f9bbd87390f 100644 --- a/misc/python/materialize/checks/all_checks/webhook.py +++ b/misc/python/materialize/checks/all_checks/webhook.py @@ -110,14 +110,23 @@ def validate(self) -> Testdrive: \\\\x01 \\\\x01\\x02\\x03\\x04 - > SHOW CREATE SOURCE webhook_text + >[version>=14000] SHOW CREATE SOURCE webhook_text materialize.public.webhook_text "CREATE SOURCE materialize.public.webhook_text IN CLUSTER webhook_cluster FROM WEBHOOK BODY FORMAT TEXT;" - > SHOW CREATE SOURCE webhook_json + >[version>=14000] SHOW CREATE SOURCE webhook_json materialize.public.webhook_json "CREATE SOURCE materialize.public.webhook_json IN CLUSTER webhook_cluster FROM WEBHOOK BODY FORMAT JSON INCLUDE HEADERS;" - > SHOW CREATE SOURCE webhook_bytes + >[version>=14000] SHOW CREATE SOURCE webhook_bytes materialize.public.webhook_bytes "CREATE SOURCE materialize.public.webhook_bytes IN CLUSTER webhook_cluster FROM WEBHOOK BODY FORMAT BYTES;" + + >[version<14000] SHOW CREATE SOURCE webhook_text + materialize.public.webhook_text "CREATE SOURCE \\"materialize\\".\\"public\\".\\"webhook_text\\" IN CLUSTER \\"webhook_cluster\\" FROM WEBHOOK BODY FORMAT TEXT" + + >[version<14000] SHOW CREATE SOURCE webhook_json + materialize.public.webhook_json "CREATE SOURCE \\"materialize\\".\\"public\\".\\"webhook_json\\" IN CLUSTER \\"webhook_cluster\\" FROM WEBHOOK BODY FORMAT JSON INCLUDE HEADERS" + + >[version<14000] SHOW CREATE SOURCE webhook_bytes + materialize.public.webhook_bytes "CREATE SOURCE \\"materialize\\".\\"public\\".\\"webhook_bytes\\" IN CLUSTER \\"webhook_cluster\\" FROM WEBHOOK BODY FORMAT BYTES" """ ) ) @@ -158,14 +167,17 @@ def manipulate(self) -> list[Testdrive]: def validate(self) -> Testdrive: return Testdrive( dedent( - """ + r""" > SELECT * FROM webhook_table_text hello_world anotha_one! threeeeeee - > SHOW CREATE TABLE webhook_table_text + >[version>=14000] SHOW CREATE TABLE webhook_table_text materialize.public.webhook_table_text "CREATE TABLE materialize.public.webhook_table_text FROM WEBHOOK BODY FORMAT TEXT;" + + >[version<14000] SHOW CREATE TABLE webhook_table_text + materialize.public.webhook_table_text "CREATE TABLE \"materialize\".\"public\".\"webhook_table_text\" FROM WEBHOOK BODY FORMAT TEXT" """ ) ) diff --git a/test/mysql-cdc-old-syntax/10-create-connection.td b/test/mysql-cdc-old-syntax/10-create-connection.td index 893ae670bbd78..7bf940ae618d6 100644 --- a/test/mysql-cdc-old-syntax/10-create-connection.td +++ b/test/mysql-cdc-old-syntax/10-create-connection.td @@ -41,11 +41,16 @@ name type ------------------------------ mysq mysql -> SHOW CREATE CONNECTION mysq +>[version>=14000] SHOW CREATE CONNECTION mysq name create_sql --------------------------------- materialize.public.mysq "CREATE CONNECTION materialize.public.mysq TO MYSQL (HOST = mysql, PASSWORD = SECRET materialize.public.mysqlpass, USER = root);" +>[version<14000] SHOW CREATE CONNECTION mysq +name create_sql +--------------------------------- +materialize.public.mysq "CREATE CONNECTION \"materialize\".\"public\".\"mysq\" TO MYSQL (HOST = \"mysql\", PASSWORD = SECRET \"materialize\".\"public\".\"mysqlpass\", USER = \"root\")" + # # Error checking # diff --git a/test/mysql-cdc-old-syntax/30-text-columns.td b/test/mysql-cdc-old-syntax/30-text-columns.td index b40947e2b2332..b1f9632d69ba2 100644 --- a/test/mysql-cdc-old-syntax/30-text-columns.td +++ b/test/mysql-cdc-old-syntax/30-text-columns.td @@ -88,9 +88,12 @@ INSERT INTO t1 SELECT * FROM t1; "0000-00-00 00:00:00.0000" "0000-00-00 00:00:00.0000" -> SHOW CREATE SOURCE t1; +>[version>=14000] SHOW CREATE SOURCE t1; materialize.public.t1 "CREATE SUBSOURCE materialize.public.t1 (f1 pg_catalog.text, f2 pg_catalog.text, f3 pg_catalog.text, f4 pg_catalog.text, f5 pg_catalog.text, f6 pg_catalog.text, f7 pg_catalog.text, f8 pg_catalog.text, f9 pg_catalog.text) OF SOURCE materialize.public.da WITH (EXTERNAL REFERENCE = public.t1, TEXT COLUMNS = (f1, f2, f3, f4, f5, f6, f7, f8, f9));" +>[version<14000] SHOW CREATE SOURCE t1; +materialize.public.t1 "CREATE SUBSOURCE \"materialize\".\"public\".\"t1\" (\"f1\" \"pg_catalog\".\"text\", \"f2\" \"pg_catalog\".\"text\", \"f3\" \"pg_catalog\".\"text\", \"f4\" \"pg_catalog\".\"text\", \"f5\" \"pg_catalog\".\"text\", \"f6\" \"pg_catalog\".\"text\", \"f7\" \"pg_catalog\".\"text\", \"f8\" \"pg_catalog\".\"text\", \"f9\" \"pg_catalog\".\"text\") OF SOURCE \"materialize\".\"public\".\"da\" WITH (EXTERNAL REFERENCE = \"public\".\"t1\", TEXT COLUMNS = (\"f1\", \"f2\", \"f3\", \"f4\", \"f5\", \"f6\", \"f7\", \"f8\", \"f9\"))" + > DROP SOURCE da CASCADE; # diff --git a/test/mysql-cdc-old-syntax/35-exclude-columns.td b/test/mysql-cdc-old-syntax/35-exclude-columns.td index 39f7ea4e6e225..1703bb1dac963 100644 --- a/test/mysql-cdc-old-syntax/35-exclude-columns.td +++ b/test/mysql-cdc-old-syntax/35-exclude-columns.td @@ -61,9 +61,12 @@ INSERT INTO t1 SELECT * FROM t1; "test" "test" -> SHOW CREATE SOURCE t1; +>[version>=14000] SHOW CREATE SOURCE t1; materialize.public.t1 "CREATE SUBSOURCE materialize.public.t1 (f1 pg_catalog.int4, f4 pg_catalog.varchar(64)) OF SOURCE materialize.public.da WITH (EXTERNAL REFERENCE = public.t1, EXCLUDE COLUMNS = (f2, f3));" +>[version<14000] SHOW CREATE SOURCE t1; +materialize.public.t1 "CREATE SUBSOURCE \"materialize\".\"public\".\"t1\" (\"f1\" \"pg_catalog\".\"int4\", \"f4\" \"pg_catalog\".\"varchar\"(64)) OF SOURCE \"materialize\".\"public\".\"da\" WITH (EXTERNAL REFERENCE = \"public\".\"t1\", EXCLUDE COLUMNS = (\"f2\", \"f3\"))" + ! SELECT f2 FROM t1; contains:column "f2" does not exist diff --git a/test/mysql-cdc-old-syntax/alter-source.td b/test/mysql-cdc-old-syntax/alter-source.td index b189e59ac6731..0e1689b32e848 100644 --- a/test/mysql-cdc-old-syntax/alter-source.td +++ b/test/mysql-cdc-old-syntax/alter-source.td @@ -112,9 +112,12 @@ table_e subsource table_f subsource table_g subsource -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); public.table_f.f2 +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +"\"public\".\"table_f\".\"f2\"" + # # Error checking # @@ -204,10 +207,6 @@ contains:cannot drop source "table_e": still depended upon by materialized view mz_source_progress progress table_g subsource -# Show that all table definitions have been updated -> SELECT regexp_match(create_sql, 'FOR TABLES \((.+?)\) EXPOSE') FROM (SHOW CREATE SOURCE mz_source); -"{\"public\".\"table_g\" AS \"materialize\".\"public\".\"table_g\"}" - > SHOW MATERIALIZED VIEWS > DROP SOURCE table_g; @@ -338,11 +337,17 @@ contains: invalid TEXT COLUMNS option value: unexpected multiple references to p 1 var0 2 var1 -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +public.table_f.f2 + +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); "\"public\".\"table_f\".\"f2\"" -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_f); -f2 +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_f); +"f2" + +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_f); +"\"f2\"" # Drop a table, which shuffles the tables' output indexes, then add a table and ensure it can be added. $ mysql-execute name=mysql @@ -355,12 +360,18 @@ INSERT INTO table_f VALUES (3, 'var1'); > ALTER SOURCE mz_source ADD SUBSOURCE public.table_i WITH (TEXT COLUMNS [public.table_i.f2]); -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +"public.table_f.f2, public.table_i.f2" + +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); "\"public\".\"table_f\".\"f2\", \"public\".\"table_i\".\"f2\"" -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); f2 +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); +"\"f2\"" + > SELECT * FROM table_f 1 var0 2 var1 @@ -389,9 +400,11 @@ detail:the following columns are referenced but not added: public.table_f.f2 > ALTER SOURCE mz_source_wo_init_text_cols ADD SUBSOURCE public.table_f AS t_f WITH (TEXT COLUMNS [public.table_f.f2]); -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source_wo_init_text_cols); -"\"public\".\"table_f\".\"f2\"" +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source_wo_init_text_cols); +"public.table_f.f2" +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source_wo_init_text_cols); +"\"public\".\"table_f\".\"f2\"" # # Can add tables with exclude columns @@ -406,17 +419,26 @@ contains: invalid EXCLUDE COLUMNS option value: unexpected multiple references t 2 3 -> SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +>[version>=14000] SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +"public.table_f.f2" + +>[version<14000] SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); "\"public\".\"table_f\".\"f2\"" > ALTER SOURCE mz_source ADD SUBSOURCE public.table_i WITH (EXCLUDE COLUMNS [public.table_i.f2]); -> SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +>[version>=14000] SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +"public.table_f.f2, public.table_i.f2" + +>[version<14000] SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); "\"public\".\"table_f\".\"f2\", \"public\".\"table_i\".\"f2\"" -> SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); +>[version>=14000] SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); f2 +>[version<14000] SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); +"\"f2\"" + > SELECT * FROM table_i 1 2 @@ -444,7 +466,10 @@ detail:the following columns are referenced but not added: public.table_f.f2 > ALTER SOURCE mz_source_wo_init_exclude_cols ADD SUBSOURCE public.table_f AS t_f2 WITH (EXCLUDE COLUMNS [public.table_f.f2]); -> SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source_wo_init_exclude_cols); +>[version>=14000] SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source_wo_init_exclude_cols); +"public.table_f.f2" + +>[version<14000] SELECT regexp_match(create_sql, 'EXCLUDE COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source_wo_init_exclude_cols); "\"public\".\"table_f\".\"f2\"" # Add a table after having created the source diff --git a/test/mysql-cdc/10-create-connection.td b/test/mysql-cdc/10-create-connection.td index 893ae670bbd78..7bf940ae618d6 100644 --- a/test/mysql-cdc/10-create-connection.td +++ b/test/mysql-cdc/10-create-connection.td @@ -41,11 +41,16 @@ name type ------------------------------ mysq mysql -> SHOW CREATE CONNECTION mysq +>[version>=14000] SHOW CREATE CONNECTION mysq name create_sql --------------------------------- materialize.public.mysq "CREATE CONNECTION materialize.public.mysq TO MYSQL (HOST = mysql, PASSWORD = SECRET materialize.public.mysqlpass, USER = root);" +>[version<14000] SHOW CREATE CONNECTION mysq +name create_sql +--------------------------------- +materialize.public.mysq "CREATE CONNECTION \"materialize\".\"public\".\"mysq\" TO MYSQL (HOST = \"mysql\", PASSWORD = SECRET \"materialize\".\"public\".\"mysqlpass\", USER = \"root\")" + # # Error checking # diff --git a/test/pg-cdc-old-syntax/alter-source.td b/test/pg-cdc-old-syntax/alter-source.td index 74b83c2e5c458..15186534188be 100644 --- a/test/pg-cdc-old-syntax/alter-source.td +++ b/test/pg-cdc-old-syntax/alter-source.td @@ -129,11 +129,17 @@ table_e subsource table_f subsource table_g subsource -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); postgres.public.table_f.f2 -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_f); -f2 +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +"\"postgres\".\"public\".\"table_f\".\"f2\"" + +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_f); +"f2" + +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_f); +"\"f2\"" # # State checking @@ -338,7 +344,10 @@ contains: invalid TEXT COLUMNS option value: unexpected multiple references to p 1 var0 2 var1 -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +postgres.public.table_f.f2 + +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); "\"postgres\".\"public\".\"table_f\".\"f2\"" # Drop a table that's in the publication, which shuffles the tables' output @@ -355,12 +364,18 @@ INSERT INTO table_f VALUES (3, 'var1'); > ALTER SOURCE mz_source ADD SUBSOURCE table_i WITH (TEXT COLUMNS [table_i.f2]); -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); +"postgres.public.table_f.f2, postgres.public.table_i.f2" + +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source); "\"postgres\".\"public\".\"table_f\".\"f2\", \"postgres\".\"public\".\"table_i\".\"f2\"" -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); f2 +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE table_i); +"\"f2\"" + > SELECT * FROM table_f 1 var0 2 var1 @@ -391,7 +406,10 @@ detail:the following tables are referenced but not added: public.table_f > ALTER SOURCE mz_source_wo_init_text_cols ADD SUBSOURCE table_f AS t_f WITH (TEXT COLUMNS [table_f.f2]); -> SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source_wo_init_text_cols); +>[version>=14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source_wo_init_text_cols); +postgres.public.table_f.f2 + +>[version<14000] SELECT regexp_match(create_sql, 'TEXT COLUMNS = \((.*?)\)')[1] FROM (SHOW CREATE SOURCE mz_source_wo_init_text_cols); "\"postgres\".\"public\".\"table_f\".\"f2\"" # add a table after having created the source diff --git a/test/pg-cdc-old-syntax/pg-cdc.td b/test/pg-cdc-old-syntax/pg-cdc.td index ea095713c86fb..d6fc4c55189dc 100644 --- a/test/pg-cdc-old-syntax/pg-cdc.td +++ b/test/pg-cdc-old-syntax/pg-cdc.td @@ -800,7 +800,10 @@ enum_table subsource cdc_cluster "" var0 var1 -> SHOW CREATE SOURCE enum_table +>[version>=14000] SHOW CREATE SOURCE enum_table +materialize.public.enum_table "CREATE SUBSOURCE materialize.public.enum_table (a pg_catalog.text) OF SOURCE materialize.public.enum_source WITH (EXTERNAL REFERENCE = postgres.public.enum_table, TEXT COLUMNS = (a));" + +>[version<14000] SHOW CREATE SOURCE enum_table materialize.public.enum_table "CREATE SUBSOURCE \"materialize\".\"public\".\"enum_table\" (\"a\" \"pg_catalog\".\"text\") OF SOURCE \"materialize\".\"public\".\"enum_source\" WITH (EXTERNAL REFERENCE = \"postgres\".\"public\".\"enum_table\", TEXT COLUMNS = (\"a\"))" # Test that TEXT COLUMN types can change