1use std::cell::RefCell;
15use std::collections::{BTreeMap, BTreeSet};
16use std::sync::{Arc, Mutex};
17
18use mz_repr::namespaces::is_system_schema;
19use mz_repr::{
20 CatalogItemId, ColumnIndex, RelationDesc, RelationVersionSelector, SqlColumnType, SqlScalarType,
21};
22use mz_sql_parser::ast::{
23 ColumnDef, ColumnName, CreateMaterializedViewStatement, RawItemName, ShowStatement,
24 StatementKind, TableConstraint, UnresolvedDatabaseName, UnresolvedSchemaName,
25};
26use mz_storage_types::connections::Connection;
27
28use crate::ast::{Ident, Statement, UnresolvedItemName};
29use crate::catalog::{
30 CatalogCluster, CatalogCollectionItem, CatalogDatabase, CatalogItem, CatalogItemType,
31 CatalogSchema, ObjectType, SessionCatalog, SystemObjectType,
32};
33use crate::names::{
34 self, Aug, DatabaseId, FullItemName, ItemQualifiers, ObjectId, PartialItemName,
35 QualifiedItemName, RawDatabaseSpecifier, ResolvedColumnReference, ResolvedDataType,
36 ResolvedDatabaseSpecifier, ResolvedIds, ResolvedItemName, ResolvedSchemaName, SchemaSpecifier,
37 SystemObjectId,
38};
39use crate::normalize;
40use crate::plan::error::PlanError;
41use crate::plan::{Params, Plan, PlanContext, PlanKind, query};
42use crate::session::vars::FeatureFlag;
43
44mod acl;
45pub(crate) mod ddl;
46mod dml;
47mod raise;
48mod scl;
49pub(crate) mod show;
50mod tcl;
51mod validate;
52
53use crate::session::vars;
54pub(crate) use ddl::PgConfigOptionExtracted;
55use mz_controller_types::ClusterId;
56use mz_pgrepr::oid::{FIRST_MATERIALIZE_OID, FIRST_USER_OID};
57use mz_repr::role_id::RoleId;
58
59#[derive(Debug, Clone, Eq, PartialEq)]
61pub struct StatementDesc {
62 pub relation_desc: Option<RelationDesc>,
65 pub param_types: Vec<SqlScalarType>,
67 pub is_copy: bool,
69}
70
71impl StatementDesc {
72 pub fn new(relation_desc: Option<RelationDesc>) -> Self {
73 StatementDesc {
74 relation_desc,
75 param_types: vec![],
76 is_copy: false,
77 }
78 }
79
80 pub fn arity(&self) -> usize {
83 self.relation_desc
84 .as_ref()
85 .map(|desc| desc.typ().column_types.len())
86 .unwrap_or(0)
87 }
88
89 fn with_params(mut self, param_types: Vec<SqlScalarType>) -> Self {
90 self.param_types = param_types;
91 self
92 }
93
94 fn with_is_copy(mut self) -> Self {
95 self.is_copy = true;
96 self
97 }
98}
99
100pub fn describe(
104 pcx: &PlanContext,
105 catalog: &dyn SessionCatalog,
106 stmt: Statement<Aug>,
107 param_types_in: &[Option<SqlScalarType>],
108) -> Result<StatementDesc, PlanError> {
109 let mut param_types = BTreeMap::new();
110 for (i, ty) in param_types_in.iter().enumerate() {
111 if let Some(ty) = ty {
112 param_types.insert(i + 1, ty.clone());
113 }
114 }
115
116 let scx = StatementContext {
117 pcx: Some(pcx),
118 catalog,
119 param_types: RefCell::new(param_types),
120 ambiguous_columns: RefCell::new(false),
121 sql_impl_resolved_ids: Arc::new(Mutex::new(ResolvedIds::empty())),
122 };
123
124 let desc = match stmt {
125 Statement::AlterCluster(stmt) => ddl::describe_alter_cluster_set_options(&scx, stmt)?,
127 Statement::AlterConnection(stmt) => ddl::describe_alter_connection(&scx, stmt)?,
128 Statement::AlterIndex(stmt) => ddl::describe_alter_index_options(&scx, stmt)?,
129 Statement::AlterMaterializedViewApplyReplacement(stmt) => {
130 ddl::describe_alter_materialized_view_apply_replacement(&scx, stmt)?
131 }
132 Statement::AlterObjectRename(stmt) => ddl::describe_alter_object_rename(&scx, stmt)?,
133 Statement::AlterObjectSwap(stmt) => ddl::describe_alter_object_swap(&scx, stmt)?,
134 Statement::AlterRetainHistory(stmt) => ddl::describe_alter_retain_history(&scx, stmt)?,
135 Statement::AlterRole(stmt) => ddl::describe_alter_role(&scx, stmt)?,
136 Statement::AlterSecret(stmt) => ddl::describe_alter_secret_options(&scx, stmt)?,
137 Statement::AlterSetCluster(stmt) => ddl::describe_alter_set_cluster(&scx, stmt)?,
138 Statement::AlterSink(stmt) => ddl::describe_alter_sink(&scx, stmt)?,
139 Statement::AlterSource(stmt) => ddl::describe_alter_source(&scx, stmt)?,
140 Statement::AlterSystemSet(stmt) => ddl::describe_alter_system_set(&scx, stmt)?,
141 Statement::AlterSystemReset(stmt) => ddl::describe_alter_system_reset(&scx, stmt)?,
142 Statement::AlterSystemResetAll(stmt) => ddl::describe_alter_system_reset_all(&scx, stmt)?,
143 Statement::AlterTableAddColumn(stmt) => ddl::describe_alter_table_add_column(&scx, stmt)?,
144 Statement::AlterNetworkPolicy(stmt) => ddl::describe_alter_network_policy(&scx, stmt)?,
145 Statement::Comment(stmt) => ddl::describe_comment(&scx, stmt)?,
146 Statement::CreateCluster(stmt) => ddl::describe_create_cluster(&scx, stmt)?,
147 Statement::CreateClusterReplica(stmt) => ddl::describe_create_cluster_replica(&scx, stmt)?,
148 Statement::CreateConnection(stmt) => ddl::describe_create_connection(&scx, stmt)?,
149 Statement::CreateDatabase(stmt) => ddl::describe_create_database(&scx, stmt)?,
150 Statement::CreateIndex(stmt) => ddl::describe_create_index(&scx, stmt)?,
151 Statement::CreateRole(stmt) => ddl::describe_create_role(&scx, stmt)?,
152 Statement::CreateSchema(stmt) => ddl::describe_create_schema(&scx, stmt)?,
153 Statement::CreateSecret(stmt) => ddl::describe_create_secret(&scx, stmt)?,
154 Statement::CreateSink(stmt) => ddl::describe_create_sink(&scx, stmt)?,
155 Statement::CreateMetricSink(stmt) => ddl::describe_create_metric_sink(&scx, stmt)?,
156 Statement::CreateWebhookSource(stmt) => ddl::describe_create_webhook_source(&scx, stmt)?,
157 Statement::CreateSource(stmt) => ddl::describe_create_source(&scx, stmt)?,
158 Statement::CreateSubsource(stmt) => ddl::describe_create_subsource(&scx, stmt)?,
159 Statement::CreateTable(stmt) => ddl::describe_create_table(&scx, stmt)?,
160 Statement::CreateTableFromSource(stmt) => {
161 ddl::describe_create_table_from_source(&scx, stmt)?
162 }
163 Statement::CreateType(stmt) => ddl::describe_create_type(&scx, stmt)?,
164 Statement::CreateView(stmt) => ddl::describe_create_view(&scx, stmt)?,
165 Statement::CreateMaterializedView(stmt) => {
166 ddl::describe_create_materialized_view(&scx, stmt)?
167 }
168 Statement::CreateNetworkPolicy(stmt) => ddl::describe_create_network_policy(&scx, stmt)?,
169 Statement::DropObjects(stmt) => ddl::describe_drop_objects(&scx, stmt)?,
170 Statement::DropOwned(stmt) => ddl::describe_drop_owned(&scx, stmt)?,
171
172 Statement::AlterOwner(stmt) => acl::describe_alter_owner(&scx, stmt)?,
174 Statement::GrantRole(stmt) => acl::describe_grant_role(&scx, stmt)?,
175 Statement::RevokeRole(stmt) => acl::describe_revoke_role(&scx, stmt)?,
176 Statement::GrantPrivileges(stmt) => acl::describe_grant_privileges(&scx, stmt)?,
177 Statement::RevokePrivileges(stmt) => acl::describe_revoke_privileges(&scx, stmt)?,
178 Statement::AlterDefaultPrivileges(stmt) => {
179 acl::describe_alter_default_privileges(&scx, stmt)?
180 }
181 Statement::ReassignOwned(stmt) => acl::describe_reassign_owned(&scx, stmt)?,
182
183 Statement::Show(ShowStatement::ShowColumns(stmt)) => {
185 show::show_columns(&scx, stmt)?.describe()?
186 }
187 Statement::Show(ShowStatement::ShowCreateConnection(stmt)) => {
188 show::describe_show_create_connection(&scx, stmt)?
189 }
190 Statement::Show(ShowStatement::ShowCreateCluster(stmt)) => {
191 show::describe_show_create_cluster(&scx, stmt)?
192 }
193 Statement::Show(ShowStatement::ShowCreateIndex(stmt)) => {
194 show::describe_show_create_index(&scx, stmt)?
195 }
196 Statement::Show(ShowStatement::ShowCreateSink(stmt)) => {
197 show::describe_show_create_sink(&scx, stmt)?
198 }
199 Statement::Show(ShowStatement::ShowCreateMetricSink(stmt)) => {
200 show::describe_show_create_metric_sink(&scx, stmt)?
201 }
202 Statement::Show(ShowStatement::ShowCreateSource(stmt)) => {
203 show::describe_show_create_source(&scx, stmt)?
204 }
205 Statement::Show(ShowStatement::ShowCreateTable(stmt)) => {
206 show::describe_show_create_table(&scx, stmt)?
207 }
208 Statement::Show(ShowStatement::ShowCreateView(stmt)) => {
209 show::describe_show_create_view(&scx, stmt)?
210 }
211 Statement::Show(ShowStatement::ShowCreateMaterializedView(stmt)) => {
212 show::describe_show_create_materialized_view(&scx, stmt)?
213 }
214 Statement::Show(ShowStatement::ShowCreateType(stmt)) => {
215 show::describe_show_create_type(&scx, stmt)?
216 }
217 Statement::Show(ShowStatement::ShowObjects(stmt)) => {
218 show::show_objects(&scx, stmt)?.describe()?
219 }
220
221 Statement::Close(stmt) => scl::describe_close(&scx, stmt)?,
223 Statement::Deallocate(stmt) => scl::describe_deallocate(&scx, stmt)?,
224 Statement::Declare(stmt) => scl::describe_declare(&scx, stmt, param_types_in)?,
225 Statement::Discard(stmt) => scl::describe_discard(&scx, stmt)?,
226 Statement::Execute(stmt) => scl::describe_execute(&scx, stmt)?,
227 Statement::Fetch(stmt) => scl::describe_fetch(&scx, stmt)?,
228 Statement::Prepare(stmt) => scl::describe_prepare(&scx, stmt)?,
229 Statement::ResetVariable(stmt) => scl::describe_reset_variable(&scx, stmt)?,
230 Statement::SetVariable(stmt) => scl::describe_set_variable(&scx, stmt)?,
231 Statement::Show(ShowStatement::ShowVariable(stmt)) => {
232 scl::describe_show_variable(&scx, stmt)?
233 }
234
235 Statement::Copy(stmt) => dml::describe_copy(&scx, stmt)?,
237 Statement::Delete(stmt) => dml::describe_delete(&scx, stmt)?,
238 Statement::ExplainPlan(stmt) => dml::describe_explain_plan(&scx, stmt)?,
239 Statement::ExplainPushdown(stmt) => dml::describe_explain_pushdown(&scx, stmt)?,
240 Statement::ExplainAnalyzeObject(stmt) => dml::describe_explain_analyze_object(&scx, stmt)?,
241 Statement::ExplainAnalyzeCluster(stmt) => {
242 dml::describe_explain_analyze_cluster(&scx, stmt)?
243 }
244 Statement::ExplainTimestamp(stmt) => dml::describe_explain_timestamp(&scx, stmt)?,
245 Statement::ExplainSinkSchema(stmt) => dml::describe_explain_schema(&scx, stmt)?,
246 Statement::Insert(stmt) => dml::describe_insert(&scx, stmt)?,
247 Statement::Select(stmt) => dml::describe_select(&scx, stmt)?,
248 Statement::Subscribe(stmt) => dml::describe_subscribe(&scx, stmt)?,
249 Statement::Update(stmt) => dml::describe_update(&scx, stmt)?,
250
251 Statement::Commit(stmt) => tcl::describe_commit(&scx, stmt)?,
253 Statement::Rollback(stmt) => tcl::describe_rollback(&scx, stmt)?,
254 Statement::SetTransaction(stmt) => tcl::describe_set_transaction(&scx, stmt)?,
255 Statement::StartTransaction(stmt) => tcl::describe_start_transaction(&scx, stmt)?,
256
257 Statement::Raise(stmt) => raise::describe_raise(&scx, stmt)?,
259 Statement::Show(ShowStatement::InspectShard(stmt)) => {
260 scl::describe_inspect_shard(&scx, stmt)?
261 }
262 Statement::ValidateConnection(stmt) => validate::describe_validate_connection(&scx, stmt)?,
263 Statement::ExecuteUnitTest(_) => {
264 return Err(PlanError::Unsupported {
265 feature: "EXECUTE UNIT TEST statement".to_string(),
266 discussion_no: None,
267 });
268 }
269 };
270
271 let desc = desc.with_params(scx.finalize_param_types()?);
272 Ok(desc)
273}
274
275#[mz_ore::instrument(level = "debug")]
292pub fn plan(
293 pcx: Option<&PlanContext>,
294 catalog: &dyn SessionCatalog,
295 stmt: Statement<Aug>,
296 params: &Params,
297 resolved_ids: &ResolvedIds,
298) -> Result<(Plan, ResolvedIds), PlanError> {
299 let param_types = params
300 .expected_types
304 .iter()
305 .enumerate()
306 .map(|(i, ty)| (i + 1, ty.clone()))
307 .collect();
308
309 let kind: StatementKind = (&stmt).into();
310 let permitted_plans = Plan::generated_from(&kind);
311
312 let scx = &mut StatementContext {
313 pcx,
314 catalog,
315 param_types: RefCell::new(param_types),
316 ambiguous_columns: RefCell::new(false),
317 sql_impl_resolved_ids: Arc::new(Mutex::new(ResolvedIds::empty())),
318 };
319
320 if resolved_ids
321 .items()
322 .filter_map(|id| catalog.try_get_item(id))
324 .any(|item| {
325 item.func().is_ok()
326 && item.name().qualifiers.schema_spec
327 == SchemaSpecifier::Id(catalog.get_mz_unsafe_schema_id())
328 })
329 {
330 scx.require_feature_flag(&vars::UNSAFE_ENABLE_UNSAFE_FUNCTIONS)?;
331 }
332
333 let plan = match stmt {
334 Statement::AlterCluster(stmt) => ddl::plan_alter_cluster(scx, stmt),
336 Statement::AlterConnection(stmt) => ddl::plan_alter_connection(scx, stmt),
337 Statement::AlterIndex(stmt) => ddl::plan_alter_index_options(scx, stmt),
338 Statement::AlterMaterializedViewApplyReplacement(stmt) => {
339 ddl::plan_alter_materialized_view_apply_replacement(scx, stmt)
340 }
341 Statement::AlterObjectRename(stmt) => ddl::plan_alter_object_rename(scx, stmt),
342 Statement::AlterObjectSwap(stmt) => ddl::plan_alter_object_swap(scx, stmt),
343 Statement::AlterRetainHistory(stmt) => ddl::plan_alter_retain_history(scx, stmt),
344 Statement::AlterRole(stmt) => ddl::plan_alter_role(scx, stmt),
345 Statement::AlterSecret(stmt) => ddl::plan_alter_secret(scx, stmt),
346 Statement::AlterSetCluster(stmt) => ddl::plan_alter_item_set_cluster(scx, stmt),
347 Statement::AlterSink(stmt) => ddl::plan_alter_sink(scx, stmt),
348 Statement::AlterSource(stmt) => ddl::plan_alter_source(scx, stmt),
349 Statement::AlterSystemSet(stmt) => ddl::plan_alter_system_set(scx, stmt),
350 Statement::AlterSystemReset(stmt) => ddl::plan_alter_system_reset(scx, stmt),
351 Statement::AlterSystemResetAll(stmt) => ddl::plan_alter_system_reset_all(scx, stmt),
352 Statement::AlterTableAddColumn(stmt) => ddl::plan_alter_table_add_column(scx, stmt),
353 Statement::AlterNetworkPolicy(stmt) => ddl::plan_alter_network_policy(scx, stmt),
354 Statement::Comment(stmt) => ddl::plan_comment(scx, stmt),
355 Statement::CreateCluster(stmt) => ddl::plan_create_cluster(scx, stmt),
356 Statement::CreateClusterReplica(stmt) => ddl::plan_create_cluster_replica(scx, stmt),
357 Statement::CreateConnection(stmt) => ddl::plan_create_connection(scx, stmt),
358 Statement::CreateDatabase(stmt) => ddl::plan_create_database(scx, stmt),
359 Statement::CreateIndex(stmt) => ddl::plan_create_index(scx, stmt),
360 Statement::CreateRole(stmt) => ddl::plan_create_role(scx, stmt),
361 Statement::CreateSchema(stmt) => ddl::plan_create_schema(scx, stmt),
362 Statement::CreateSecret(stmt) => ddl::plan_create_secret(scx, stmt),
363 Statement::CreateSink(stmt) => ddl::plan_create_sink(scx, stmt),
364 Statement::CreateMetricSink(stmt) => ddl::plan_create_metric_sink(scx, stmt),
365 Statement::CreateWebhookSource(stmt) => ddl::plan_create_webhook_source(scx, stmt),
366 Statement::CreateSource(stmt) => ddl::plan_create_source(scx, stmt),
367 Statement::CreateSubsource(stmt) => ddl::plan_create_subsource(scx, stmt),
368 Statement::CreateTable(stmt) => ddl::plan_create_table(scx, stmt),
369 Statement::CreateTableFromSource(stmt) => ddl::plan_create_table_from_source(scx, stmt),
370 Statement::CreateType(stmt) => ddl::plan_create_type(scx, stmt),
371 Statement::CreateView(stmt) => ddl::plan_create_view(scx, stmt),
372 Statement::CreateMaterializedView(stmt) => ddl::plan_create_materialized_view(scx, stmt),
373 Statement::CreateNetworkPolicy(stmt) => ddl::plan_create_network_policy(scx, stmt),
374 Statement::DropObjects(stmt) => ddl::plan_drop_objects(scx, stmt),
375 Statement::DropOwned(stmt) => ddl::plan_drop_owned(scx, stmt),
376
377 Statement::AlterOwner(stmt) => acl::plan_alter_owner(scx, stmt),
379 Statement::GrantRole(stmt) => acl::plan_grant_role(scx, stmt),
380 Statement::RevokeRole(stmt) => acl::plan_revoke_role(scx, stmt),
381 Statement::GrantPrivileges(stmt) => acl::plan_grant_privileges(scx, stmt),
382 Statement::RevokePrivileges(stmt) => acl::plan_revoke_privileges(scx, stmt),
383 Statement::AlterDefaultPrivileges(stmt) => acl::plan_alter_default_privileges(scx, stmt),
384 Statement::ReassignOwned(stmt) => acl::plan_reassign_owned(scx, stmt),
385
386 Statement::Copy(stmt) => dml::plan_copy(scx, stmt),
388 Statement::Delete(stmt) => dml::plan_delete(scx, stmt, params),
389 Statement::ExplainPlan(stmt) => dml::plan_explain_plan(scx, stmt, params),
390 Statement::ExplainPushdown(stmt) => dml::plan_explain_pushdown(scx, stmt, params),
391 Statement::ExplainAnalyzeObject(stmt) => {
392 dml::plan_explain_analyze_object(scx, stmt, params)
393 }
394 Statement::ExplainAnalyzeCluster(stmt) => {
395 dml::plan_explain_analyze_cluster(scx, stmt, params)
396 }
397 Statement::ExplainTimestamp(stmt) => dml::plan_explain_timestamp(scx, stmt),
398 Statement::ExplainSinkSchema(stmt) => dml::plan_explain_schema(scx, stmt),
399 Statement::Insert(stmt) => dml::plan_insert(scx, stmt, params),
400 Statement::Select(stmt) => dml::plan_select(scx, stmt, params, None),
401 Statement::Subscribe(stmt) => dml::plan_subscribe(scx, stmt, params, None),
402 Statement::Update(stmt) => dml::plan_update(scx, stmt, params),
403
404 Statement::Show(ShowStatement::ShowColumns(stmt)) => show::show_columns(scx, stmt)?.plan(),
406 Statement::Show(ShowStatement::ShowCreateConnection(stmt)) => {
407 show::plan_show_create_connection(scx, stmt).map(Plan::ShowCreate)
408 }
409 Statement::Show(ShowStatement::ShowCreateCluster(stmt)) => {
410 show::plan_show_create_cluster(scx, stmt).map(Plan::ShowCreate)
411 }
412 Statement::Show(ShowStatement::ShowCreateIndex(stmt)) => {
413 show::plan_show_create_index(scx, stmt).map(Plan::ShowCreate)
414 }
415 Statement::Show(ShowStatement::ShowCreateSink(stmt)) => {
416 show::plan_show_create_sink(scx, stmt).map(Plan::ShowCreate)
417 }
418 Statement::Show(ShowStatement::ShowCreateMetricSink(stmt)) => {
419 show::plan_show_create_metric_sink(scx, stmt).map(Plan::ShowCreate)
420 }
421 Statement::Show(ShowStatement::ShowCreateSource(stmt)) => {
422 show::plan_show_create_source(scx, stmt).map(Plan::ShowCreate)
423 }
424 Statement::Show(ShowStatement::ShowCreateTable(stmt)) => {
425 show::plan_show_create_table(scx, stmt).map(Plan::ShowCreate)
426 }
427 Statement::Show(ShowStatement::ShowCreateView(stmt)) => {
428 show::plan_show_create_view(scx, stmt).map(Plan::ShowCreate)
429 }
430 Statement::Show(ShowStatement::ShowCreateMaterializedView(stmt)) => {
431 show::plan_show_create_materialized_view(scx, stmt).map(Plan::ShowCreate)
432 }
433 Statement::Show(ShowStatement::ShowCreateType(stmt)) => {
434 show::plan_show_create_type(scx, stmt).map(Plan::ShowCreate)
435 }
436 Statement::Show(ShowStatement::ShowObjects(stmt)) => show::show_objects(scx, stmt)?.plan(),
437
438 Statement::Close(stmt) => scl::plan_close(scx, stmt),
440 Statement::Deallocate(stmt) => scl::plan_deallocate(scx, stmt),
441 Statement::Declare(stmt) => scl::plan_declare(scx, stmt, params),
442 Statement::Discard(stmt) => scl::plan_discard(scx, stmt),
443 Statement::Execute(stmt) => scl::plan_execute(scx, stmt),
444 Statement::Fetch(stmt) => scl::plan_fetch(scx, stmt),
445 Statement::Prepare(stmt) => scl::plan_prepare(scx, stmt),
446 Statement::ResetVariable(stmt) => scl::plan_reset_variable(scx, stmt),
447 Statement::SetVariable(stmt) => scl::plan_set_variable(scx, stmt),
448 Statement::Show(ShowStatement::ShowVariable(stmt)) => scl::plan_show_variable(scx, stmt),
449
450 Statement::Commit(stmt) => tcl::plan_commit(scx, stmt),
452 Statement::Rollback(stmt) => tcl::plan_rollback(scx, stmt),
453 Statement::SetTransaction(stmt) => tcl::plan_set_transaction(scx, stmt),
454 Statement::StartTransaction(stmt) => tcl::plan_start_transaction(scx, stmt),
455
456 Statement::Raise(stmt) => raise::plan_raise(scx, stmt),
458 Statement::Show(ShowStatement::InspectShard(stmt)) => scl::plan_inspect_shard(scx, stmt),
459 Statement::ValidateConnection(stmt) => validate::plan_validate_connection(scx, stmt),
460 Statement::ExecuteUnitTest(_) => {
461 return Err(PlanError::Unsupported {
462 feature: "EXECUTE UNIT TEST statement".to_string(),
463 discussion_no: None,
464 });
465 }
466 };
467
468 if let Ok(plan) = &plan {
469 mz_ore::soft_assert_no_log!(
470 permitted_plans.contains(&PlanKind::from(plan)),
471 "plan {:?}, permitted plans {:?}",
472 plan,
473 permitted_plans
474 );
475 }
476
477 let sql_impl_ids = scx
483 .sql_impl_resolved_ids
484 .lock()
485 .expect("planning is single-threaded")
486 .clone();
487 plan.map(|p| (p, sql_impl_ids))
488}
489
490pub fn plan_copy_from(
491 pcx: &PlanContext,
492 catalog: &dyn SessionCatalog,
493 target_id: CatalogItemId,
494 target_name: String,
495 columns: Vec<ColumnIndex>,
496 rows: Vec<mz_repr::Row>,
497) -> Result<super::HirRelationExpr, PlanError> {
498 query::plan_copy_from_rows(pcx, catalog, target_id, target_name, columns, rows)
499}
500
501impl PartialEq<ObjectType> for CatalogItemType {
508 fn eq(&self, other: &ObjectType) -> bool {
509 match (self, other) {
510 (CatalogItemType::Source, ObjectType::Source)
511 | (CatalogItemType::Table, ObjectType::Table)
512 | (CatalogItemType::Sink, ObjectType::Sink)
513 | (CatalogItemType::MetricSink, ObjectType::MetricSink)
514 | (CatalogItemType::View, ObjectType::View)
515 | (CatalogItemType::MaterializedView, ObjectType::MaterializedView)
516 | (CatalogItemType::Index, ObjectType::Index)
517 | (CatalogItemType::Type, ObjectType::Type)
518 | (CatalogItemType::Secret, ObjectType::Secret)
519 | (CatalogItemType::Connection, ObjectType::Connection) => true,
520 (_, _) => false,
521 }
522 }
523}
524
525impl PartialEq<CatalogItemType> for ObjectType {
526 fn eq(&self, other: &CatalogItemType) -> bool {
527 other == self
528 }
529}
530
531#[derive(Debug, Clone)]
533pub struct StatementContext<'a> {
534 pcx: Option<&'a PlanContext>,
539 pub catalog: &'a dyn SessionCatalog,
540 pub param_types: RefCell<BTreeMap<usize, SqlScalarType>>,
543 pub ambiguous_columns: RefCell<bool>,
546 pub sql_impl_resolved_ids: Arc<Mutex<ResolvedIds>>,
556}
557
558impl<'a> StatementContext<'a> {
559 pub fn new(
560 pcx: Option<&'a PlanContext>,
561 catalog: &'a dyn SessionCatalog,
562 ) -> StatementContext<'a> {
563 StatementContext {
564 pcx,
565 catalog,
566 param_types: Default::default(),
567 ambiguous_columns: RefCell::new(false),
568 sql_impl_resolved_ids: Arc::new(Mutex::new(ResolvedIds::empty())),
569 }
570 }
571
572 pub fn current_schemas(&self) -> &[(ResolvedDatabaseSpecifier, SchemaSpecifier)] {
574 self.catalog.search_path()
575 }
576
577 pub fn current_schema(&self) -> Option<&(ResolvedDatabaseSpecifier, SchemaSpecifier)> {
580 self.current_schemas().into_iter().next()
581 }
582
583 pub fn pcx(&self) -> Result<&PlanContext, PlanError> {
584 self.pcx.ok_or_else(|| sql_err!("no plan context"))
585 }
586
587 pub(crate) fn record_sql_impl_ids(&self, ids: &ResolvedIds) {
593 self.sql_impl_resolved_ids
594 .lock()
595 .expect("planning is single-threaded")
596 .extend_from(ids);
597 }
598
599 pub fn allocate_full_name(&self, name: PartialItemName) -> Result<FullItemName, PlanError> {
600 let (database, schema): (RawDatabaseSpecifier, String) = match (name.database, name.schema)
601 {
602 (None, None) => {
603 let Some((database, schema)) = self.current_schema() else {
604 return Err(PlanError::InvalidSchemaName);
605 };
606 let schema = self.get_schema(database, schema);
607 let database = match schema.database() {
608 ResolvedDatabaseSpecifier::Ambient => RawDatabaseSpecifier::Ambient,
609 ResolvedDatabaseSpecifier::Id(id) => {
610 RawDatabaseSpecifier::Name(self.catalog.get_database(id).name().to_string())
611 }
612 };
613 (database, schema.name().schema.clone())
614 }
615 (None, Some(schema)) => {
616 if is_system_schema(&schema) {
617 (RawDatabaseSpecifier::Ambient, schema)
618 } else {
619 match self.catalog.active_database_name() {
620 Some(name) => (RawDatabaseSpecifier::Name(name.to_string()), schema),
621 None => {
622 sql_bail!(
623 "no database specified for non-system schema and no active database"
624 )
625 }
626 }
627 }
628 }
629 (Some(_database), None) => {
630 sql_bail!("unreachable: specified the database but no schema")
633 }
634 (Some(database), Some(schema)) => (RawDatabaseSpecifier::Name(database), schema),
635 };
636 let item = name.item;
637 Ok(FullItemName {
638 database,
639 schema,
640 item,
641 })
642 }
643
644 pub fn allocate_qualified_name(
645 &self,
646 name: PartialItemName,
647 ) -> Result<QualifiedItemName, PlanError> {
648 let full_name = self.allocate_full_name(name)?;
649 let database_spec = match full_name.database {
650 RawDatabaseSpecifier::Ambient => ResolvedDatabaseSpecifier::Ambient,
651 RawDatabaseSpecifier::Name(name) => ResolvedDatabaseSpecifier::Id(
652 self.resolve_database(&UnresolvedDatabaseName(Ident::new(name)?))?
653 .id(),
654 ),
655 };
656 let schema_spec = self
657 .resolve_schema_in_database(&database_spec, &Ident::new(full_name.schema)?)?
658 .id()
659 .clone();
660 Ok(QualifiedItemName {
661 qualifiers: ItemQualifiers {
662 database_spec,
663 schema_spec,
664 },
665 item: full_name.item,
666 })
667 }
668
669 pub fn allocate_temporary_full_name(&self, name: PartialItemName) -> FullItemName {
670 FullItemName {
671 database: RawDatabaseSpecifier::Ambient,
672 schema: name
673 .schema
674 .unwrap_or_else(|| mz_repr::namespaces::MZ_TEMP_SCHEMA.to_owned()),
675 item: name.item,
676 }
677 }
678
679 pub fn allocate_temporary_qualified_name(
680 &self,
681 name: PartialItemName,
682 ) -> Result<QualifiedItemName, PlanError> {
683 if let Some(schema_name) = name.schema {
688 if schema_name != mz_repr::namespaces::MZ_TEMP_SCHEMA {
689 return Err(PlanError::InvalidTemporarySchema);
690 }
691 }
692
693 Ok(QualifiedItemName {
694 qualifiers: ItemQualifiers {
695 database_spec: ResolvedDatabaseSpecifier::Ambient,
696 schema_spec: SchemaSpecifier::Temporary,
697 },
698 item: name.item,
699 })
700 }
701
702 pub fn allocate_resolved_item_name(
705 &self,
706 id: CatalogItemId,
707 name: UnresolvedItemName,
708 ) -> Result<ResolvedItemName, PlanError> {
709 let partial = normalize::unresolved_item_name(name)?;
710 let qualified = self.allocate_qualified_name(partial.clone())?;
711 let full_name = self.allocate_full_name(partial)?;
712 Ok(ResolvedItemName::Item {
713 id,
714 qualifiers: qualified.qualifiers,
715 full_name,
716 print_id: true,
717 version: RelationVersionSelector::Latest,
718 })
719 }
720
721 pub fn active_database(&self) -> Option<&DatabaseId> {
722 self.catalog.active_database()
723 }
724
725 pub fn resolve_optional_schema(
726 &self,
727 schema_name: &Option<ResolvedSchemaName>,
728 ) -> Result<SchemaSpecifier, PlanError> {
729 match schema_name {
730 Some(ResolvedSchemaName::Schema { schema_spec, .. }) => Ok(schema_spec.clone()),
731 None => self.resolve_active_schema().map(|spec| spec.clone()),
732 Some(ResolvedSchemaName::Error) => {
733 unreachable!("should have been handled by name resolution")
734 }
735 }
736 }
737
738 pub fn resolve_active_schema(&self) -> Result<&SchemaSpecifier, PlanError> {
739 match self.current_schema() {
740 Some((_db, schema)) => Ok(schema),
741 None => Err(PlanError::InvalidSchemaName),
742 }
743 }
744
745 pub fn get_cluster(&self, id: &ClusterId) -> &dyn CatalogCluster<'_> {
746 self.catalog.get_cluster(*id)
747 }
748
749 pub fn resolve_database(
750 &self,
751 name: &UnresolvedDatabaseName,
752 ) -> Result<&dyn CatalogDatabase, PlanError> {
753 let name = normalize::ident_ref(&name.0);
754 Ok(self.catalog.resolve_database(name)?)
755 }
756
757 pub fn get_database(&self, id: &DatabaseId) -> &dyn CatalogDatabase {
758 self.catalog.get_database(id)
759 }
760
761 pub fn resolve_schema_in_database(
762 &self,
763 database_spec: &ResolvedDatabaseSpecifier,
764 schema: &Ident,
765 ) -> Result<&dyn CatalogSchema, PlanError> {
766 let schema = normalize::ident_ref(schema);
767 Ok(self
768 .catalog
769 .resolve_schema_in_database(database_spec, schema)?)
770 }
771
772 pub fn resolve_schema(
773 &self,
774 name: UnresolvedSchemaName,
775 ) -> Result<&dyn CatalogSchema, PlanError> {
776 let name = normalize::unresolved_schema_name(name)?;
777 Ok(self
778 .catalog
779 .resolve_schema(name.database.as_deref(), &name.schema)?)
780 }
781
782 pub fn get_schema(
783 &self,
784 database_spec: &ResolvedDatabaseSpecifier,
785 schema_spec: &SchemaSpecifier,
786 ) -> &dyn CatalogSchema {
787 self.catalog.get_schema(database_spec, schema_spec)
788 }
789
790 pub fn resolve_item(&self, name: RawItemName) -> Result<&dyn CatalogItem, PlanError> {
791 match name {
792 RawItemName::Name(name) => {
793 let name = normalize::unresolved_item_name(name)?;
794 Ok(self.catalog.resolve_item(&name)?)
795 }
796 RawItemName::Id(id, _, _) => {
797 let gid = id.parse()?;
798 Ok(self.catalog.get_item(&gid))
799 }
800 }
801 }
802
803 pub fn get_item(&self, id: &CatalogItemId) -> &dyn CatalogItem {
804 self.catalog.get_item(id)
805 }
806
807 pub fn get_item_by_resolved_name(
808 &self,
809 name: &ResolvedItemName,
810 ) -> Result<Box<dyn CatalogCollectionItem + '_>, PlanError> {
811 match name {
812 ResolvedItemName::Item { id, version, .. } => {
813 Ok(self.get_item(id).at_version(*version))
814 }
815 ResolvedItemName::Cte { .. } => sql_bail!("non-user item"),
816 ResolvedItemName::Error => unreachable!("should have been caught in name resolution"),
817 }
818 }
819
820 pub fn get_column_by_resolved_name(
821 &self,
822 name: &ColumnName<Aug>,
823 ) -> Result<(Box<dyn CatalogCollectionItem + '_>, usize), PlanError> {
824 match (&name.relation, &name.column) {
825 (
826 ResolvedItemName::Item { id, version, .. },
827 ResolvedColumnReference::Column { index, .. },
828 ) => {
829 let item = self.get_item(id).at_version(*version);
830 Ok((item, *index))
831 }
832 _ => unreachable!(
833 "get_column_by_resolved_name errors should have been caught in name resolution"
834 ),
835 }
836 }
837
838 pub fn resolve_function(
839 &self,
840 name: UnresolvedItemName,
841 ) -> Result<&dyn CatalogItem, PlanError> {
842 let name = normalize::unresolved_item_name(name)?;
843 Ok(self.catalog.resolve_function(&name)?)
844 }
845
846 pub fn resolve_cluster(
847 &self,
848 name: Option<&Ident>,
849 ) -> Result<&dyn CatalogCluster<'_>, PlanError> {
850 let name = name.map(|name| name.as_str());
851 Ok(self.catalog.resolve_cluster(name)?)
852 }
853
854 pub fn resolve_type(&self, mut ty: mz_pgrepr::Type) -> Result<ResolvedDataType, PlanError> {
855 match &mut ty {
861 mz_pgrepr::Type::Interval { constraints } => *constraints = None,
862 mz_pgrepr::Type::Time { precision } => *precision = None,
863 mz_pgrepr::Type::TimeTz { precision } => *precision = None,
864 mz_pgrepr::Type::Timestamp { precision } => *precision = None,
865 mz_pgrepr::Type::TimestampTz { precision } => *precision = None,
866 _ => (),
867 }
868 let mut ty = if ty.oid() >= FIRST_USER_OID {
874 sql_bail!("internal error, unexpected user type: {ty:?} ");
875 } else if ty.oid() < FIRST_MATERIALIZE_OID {
876 format!("pg_catalog.{}", ty)
877 } else {
878 format!("mz_catalog.{}", ty)
880 };
881 if ty == "pg_catalog.json" {
885 ty = "pg_catalog.jsonb".into();
886 }
887 let data_type = mz_sql_parser::parser::parse_data_type(&ty)?;
888 let (data_type, _) = names::resolve(self.catalog, data_type)?;
889 Ok(data_type)
890 }
891
892 pub fn get_object_type(&self, id: &ObjectId) -> ObjectType {
893 self.catalog.get_object_type(id)
894 }
895
896 pub fn get_system_object_type(&self, id: &SystemObjectId) -> SystemObjectType {
897 match id {
898 SystemObjectId::Object(id) => SystemObjectType::Object(self.get_object_type(id)),
899 SystemObjectId::System => SystemObjectType::System,
900 }
901 }
902
903 pub fn require_feature_flag(&self, flag: &'static FeatureFlag) -> Result<(), PlanError> {
905 flag.require(self.catalog.system_vars())?;
906 Ok(())
907 }
908
909 pub fn is_feature_flag_enabled(&self, flag: &'static FeatureFlag) -> bool {
911 self.require_feature_flag(flag).is_ok()
912 }
913
914 pub fn finalize_param_types(self) -> Result<Vec<SqlScalarType>, PlanError> {
915 let param_types = self.param_types.into_inner();
916 let mut out = vec![];
917 for (i, (n, typ)) in param_types.into_iter().enumerate() {
918 if n != i + 1 {
919 sql_bail!("unable to infer type for parameter ${}", i + 1);
920 }
921 out.push(typ);
922 }
923 Ok(out)
924 }
925
926 pub fn humanize_sql_scalar_type(&self, typ: &SqlScalarType, postgres_compat: bool) -> String {
929 self.catalog.humanize_sql_scalar_type(typ, postgres_compat)
930 }
931
932 pub fn humanize_column_type(&self, typ: &SqlColumnType, postgres_compat: bool) -> String {
935 self.catalog.humanize_sql_column_type(typ, postgres_compat)
936 }
937
938 pub fn relation_desc_into_table_defs(
939 &self,
940 desc: &RelationDesc,
941 ) -> Result<(Vec<ColumnDef<Aug>>, Vec<TableConstraint<Aug>>), PlanError> {
942 let mut columns = vec![];
943 let mut null_cols = BTreeSet::new();
944 for (column_name, column_type) in desc.iter() {
945 let name = Ident::new(column_name.as_str().to_owned())?;
946
947 let ty = mz_pgrepr::Type::from(&column_type.scalar_type);
948 let data_type = self.resolve_type(ty)?;
949
950 let options = if !column_type.nullable {
951 null_cols.insert(columns.len());
952 vec![mz_sql_parser::ast::ColumnOptionDef {
953 name: None,
954 option: mz_sql_parser::ast::ColumnOption::NotNull,
955 }]
956 } else {
957 vec![]
958 };
959
960 columns.push(ColumnDef {
961 name,
962 data_type,
963 collation: None,
964 options,
965 });
966 }
967
968 let mut table_constraints = vec![];
969 for key in desc.typ().keys.iter() {
970 let mut col_names = vec![];
971 for col_idx in key {
972 if !null_cols.contains(col_idx) {
973 sql_bail!(
976 "[internal error] key columns must be NOT NULL when generating table constraints"
977 );
978 }
979 col_names.push(columns[*col_idx].name.clone());
980 }
981 table_constraints.push(TableConstraint::Unique {
982 name: None,
983 columns: col_names,
984 is_primary: false,
985 nulls_not_distinct: false,
986 });
987 }
988
989 Ok((columns, table_constraints))
990 }
991
992 pub fn get_owner_id(&self, id: &ObjectId) -> Option<RoleId> {
993 self.catalog.get_owner_id(id)
994 }
995
996 pub fn humanize_resolved_name(
997 &self,
998 name: &ResolvedItemName,
999 ) -> Result<PartialItemName, PlanError> {
1000 let item = self.get_item_by_resolved_name(name)?;
1001 Ok(self.catalog.minimal_qualification(item.name()))
1002 }
1003
1004 pub fn dangerous_resolve_name(&self, name: Vec<&str>) -> ResolvedItemName {
1007 tracing::trace!("dangerous_resolve_name {:?}", name);
1008 let name: Vec<_> = name.into_iter().map(Ident::new_unchecked).collect();
1010 let name = UnresolvedItemName::qualified(&name);
1011 let entry = match self.resolve_item(RawItemName::Name(name.clone())) {
1012 Ok(entry) => entry,
1013 Err(_) => self
1014 .resolve_function(name.clone())
1015 .expect("name referred to an existing object"),
1016 };
1017
1018 let partial = normalize::unresolved_item_name(name).unwrap();
1019 let full_name = self.allocate_full_name(partial).unwrap();
1020
1021 ResolvedItemName::Item {
1022 id: entry.id(),
1023 qualifiers: entry.name().qualifiers.clone(),
1024 full_name,
1025 print_id: true,
1026 version: RelationVersionSelector::Latest,
1027 }
1028 }
1029}
1030
1031pub fn resolve_cluster_for_materialized_view<'a>(
1032 catalog: &'a dyn SessionCatalog,
1033 stmt: &CreateMaterializedViewStatement<Aug>,
1034) -> Result<ClusterId, PlanError> {
1035 Ok(match &stmt.in_cluster {
1036 None => catalog.resolve_cluster(None)?.id(),
1037 Some(in_cluster) => in_cluster.id,
1038 })
1039}
1040
1041#[derive(Debug, Clone, Copy)]
1043pub enum StatementClassification {
1044 ACL,
1045 DDL,
1046 DML,
1047 Other,
1048 SCL,
1049 Show,
1050 TCL,
1051}
1052
1053impl StatementClassification {
1054 pub fn is_ddl(&self) -> bool {
1055 matches!(self, StatementClassification::DDL)
1056 }
1057}
1058
1059impl<T: mz_sql_parser::ast::AstInfo> From<&Statement<T>> for StatementClassification {
1060 fn from(value: &Statement<T>) -> Self {
1061 use StatementClassification::*;
1062
1063 match value {
1064 Statement::AlterCluster(_) => DDL,
1066 Statement::AlterConnection(_) => DDL,
1067 Statement::AlterIndex(_) => DDL,
1068 Statement::AlterMaterializedViewApplyReplacement(_) => DDL,
1069 Statement::AlterObjectRename(_) => DDL,
1070 Statement::AlterObjectSwap(_) => DDL,
1071 Statement::AlterNetworkPolicy(_) => DDL,
1072 Statement::AlterRetainHistory(_) => DDL,
1073 Statement::AlterRole(_) => DDL,
1074 Statement::AlterSecret(_) => DDL,
1075 Statement::AlterSetCluster(_) => DDL,
1076 Statement::AlterSink(_) => DDL,
1077 Statement::AlterSource(_) => DDL,
1078 Statement::AlterSystemSet(_) => DDL,
1079 Statement::AlterSystemReset(_) => DDL,
1080 Statement::AlterSystemResetAll(_) => DDL,
1081 Statement::AlterTableAddColumn(_) => DDL,
1082 Statement::Comment(_) => DDL,
1083 Statement::CreateCluster(_) => DDL,
1084 Statement::CreateClusterReplica(_) => DDL,
1085 Statement::CreateConnection(_) => DDL,
1086 Statement::CreateDatabase(_) => DDL,
1087 Statement::CreateIndex(_) => DDL,
1088 Statement::CreateRole(_) => DDL,
1089 Statement::CreateSchema(_) => DDL,
1090 Statement::CreateSecret(_) => DDL,
1091 Statement::CreateSink(_) => DDL,
1092 Statement::CreateMetricSink(_) => DDL,
1093 Statement::CreateWebhookSource(_) => DDL,
1094 Statement::CreateSource(_) => DDL,
1095 Statement::CreateSubsource(_) => DDL,
1096 Statement::CreateTable(_) => DDL,
1097 Statement::CreateTableFromSource(_) => DDL,
1098 Statement::CreateType(_) => DDL,
1099 Statement::CreateView(_) => DDL,
1100 Statement::CreateMaterializedView(_) => DDL,
1101 Statement::CreateNetworkPolicy(_) => DDL,
1102 Statement::DropObjects(_) => DDL,
1103 Statement::DropOwned(_) => DDL,
1104
1105 Statement::AlterOwner(_) => ACL,
1107 Statement::GrantRole(_) => ACL,
1108 Statement::RevokeRole(_) => ACL,
1109 Statement::GrantPrivileges(_) => ACL,
1110 Statement::RevokePrivileges(_) => ACL,
1111 Statement::AlterDefaultPrivileges(_) => ACL,
1112 Statement::ReassignOwned(_) => ACL,
1113
1114 Statement::Copy(_) => DML,
1116 Statement::Delete(_) => DML,
1117 Statement::ExplainPlan(_) => DML,
1118 Statement::ExplainPushdown(_) => DML,
1119 Statement::ExplainAnalyzeObject(_) => DML,
1120 Statement::ExplainAnalyzeCluster(_) => DML,
1121 Statement::ExplainTimestamp(_) => DML,
1122 Statement::ExplainSinkSchema(_) => DML,
1123 Statement::Insert(_) => DML,
1124 Statement::Select(_) => DML,
1125 Statement::Subscribe(_) => DML,
1126 Statement::Update(_) => DML,
1127
1128 Statement::Show(ShowStatement::ShowColumns(_)) => Show,
1130 Statement::Show(ShowStatement::ShowCreateConnection(_)) => Show,
1131 Statement::Show(ShowStatement::ShowCreateCluster(_)) => Show,
1132 Statement::Show(ShowStatement::ShowCreateIndex(_)) => Show,
1133 Statement::Show(ShowStatement::ShowCreateSink(_)) => Show,
1134 Statement::Show(ShowStatement::ShowCreateMetricSink(_)) => Show,
1135 Statement::Show(ShowStatement::ShowCreateSource(_)) => Show,
1136 Statement::Show(ShowStatement::ShowCreateTable(_)) => Show,
1137 Statement::Show(ShowStatement::ShowCreateView(_)) => Show,
1138 Statement::Show(ShowStatement::ShowCreateMaterializedView(_)) => Show,
1139 Statement::Show(ShowStatement::ShowCreateType(_)) => Show,
1140 Statement::Show(ShowStatement::ShowObjects(_)) => Show,
1141
1142 Statement::Close(_) => SCL,
1144 Statement::Deallocate(_) => SCL,
1145 Statement::Declare(_) => SCL,
1146 Statement::Discard(_) => SCL,
1147 Statement::Execute(_) => SCL,
1148 Statement::Fetch(_) => SCL,
1149 Statement::Prepare(_) => SCL,
1150 Statement::ResetVariable(_) => SCL,
1151 Statement::SetVariable(_) => SCL,
1152 Statement::Show(ShowStatement::ShowVariable(_)) => SCL,
1153
1154 Statement::Commit(_) => TCL,
1156 Statement::Rollback(_) => TCL,
1157 Statement::SetTransaction(_) => TCL,
1158 Statement::StartTransaction(_) => TCL,
1159
1160 Statement::Raise(_) => Other,
1162 Statement::Show(ShowStatement::InspectShard(_)) => Other,
1163 Statement::ValidateConnection(_) => Other,
1164 Statement::ExecuteUnitTest(_) => Other,
1165 }
1166 }
1167}