mz_sql/
lib.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10//! SQL-dataflow translation.
11//!
12//! There are two main parts of the SQL–dataflow translation process:
13//!
14//!   * **Purification** eliminates any external state from a SQL AST. It is an
15//!     asynchronous process that may make network calls to external services.
16//!     The input and output of purification is a SQL AST.
17//!
18//!   * **Planning** converts a purified AST to a [`Plan`], which describes an
19//!     action that the system should take to effect the results of the query.
20//!     Planning is a fast, pure function that always produces the same plan for
21//!     a given input.
22//!
23//! # Details
24//!
25//! The purification step is, to our knowledge, unique to Materialize. In other
26//! SQL databases, there is no concept of purifying a statement before planning
27//! it. The reason for this difference is that in Materialize SQL statements can
28//! depend on external state: local files, Confluent Schema Registries, etc.
29//!
30//! Presently only `CREATE SOURCE` statements can depend on external state,
31//! though this could change in the future. Consider, for example:
32//!
33//! ```sql
34//! CREATE SOURCE ... FORMAT AVRO USING CONFLUENT SCHEMA REGISTRY 'http://csr:8081'
35//! ```
36//!
37//! The shape of the created source is dependent on the Avro schema that is
38//! stored in the schema registry running at `csr:8081`.
39//!
40//! This is problematic, because we need planning to be a pure function of its
41//! input. Why?
42//!
43//!   * Planning locks the catalog while it operates. Therefore it needs to be
44//!     fast, because only one SQL query can be planned at a time. Depending on
45//!     external state while holding a lock on the catalog would be seriously
46//!     detrimental to the latency of other queries running on the system.
47//!
48//!   * The catalog persists SQL ASTs across restarts of Materialize. If those
49//!     ASTs depend on external state, then changes to that external state could
50//!     corrupt Materialize's catalog.
51//!
52//! Purification is the escape hatch. It is a transformation from SQL AST to SQL
53//! AST that "inlines" any external state. For example, we purify the schema
54//! above by fetching the schema from the schema registry and inlining it.
55//!
56//! ```sql
57//! CREATE SOURCE ... FORMAT AVRO USING SCHEMA '{"name": "foo", "fields": [...]}'
58//! ```
59//!
60//! Importantly, purification cannot hold its reference to the catalog across an
61//! await point. That means it can run in its own Tokio task so that it does not
62//! block any other SQL commands on the server.
63//!
64//! [`Plan`]: crate::plan::Plan
65
66#![warn(missing_debug_implementations)]
67
68macro_rules! bail_unsupported {
69    ($feature:expr) => {
70        return Err(crate::plan::error::PlanError::Unsupported {
71            feature: $feature.to_string(),
72            discussion_no: None,
73        }
74        .into())
75    };
76    ($discussion_no:expr, $feature:expr) => {
77        return Err(crate::plan::error::PlanError::Unsupported {
78            feature: $feature.to_string(),
79            discussion_no: Some($discussion_no),
80        }
81        .into())
82    };
83}
84
85macro_rules! bail_never_supported {
86    ($feature:expr, $docs:expr, $details:expr) => {
87        return Err(crate::plan::error::PlanError::NeverSupported {
88            feature: $feature.to_string(),
89            documentation_link: Some($docs.to_string()),
90            details: Some($details.to_string()),
91        }
92        .into())
93    };
94    ($feature:expr, $docs:expr) => {
95        return Err(crate::plan::error::PlanError::NeverSupported {
96            feature: $feature.to_string(),
97            documentation_link: Some($docs.to_string()),
98            details: None,
99        }
100        .into())
101    };
102    ($feature:expr) => {
103        return Err(crate::plan::error::PlanError::NeverSupported {
104            feature: $feature.to_string(),
105            documentation_link: None,
106            details: None,
107        }
108        .into())
109    };
110}
111
112// TODO(benesch): delete these macros once we use structured errors everywhere.
113macro_rules! sql_bail {
114    ($($e:expr),* $(,)?) => {
115        return Err(sql_err!($($e),*))
116    }
117}
118macro_rules! sql_err {
119    ($($e:expr),* $(,)?) => {
120        crate::plan::error::PlanError::Unstructured(format!($($e),*))
121    }
122}
123
124pub const DEFAULT_SCHEMA: &str = "public";
125
126/// The number of concurrent requests we allow at once for webhook sources.
127pub const WEBHOOK_CONCURRENCY_LIMIT: usize = 500;
128
129pub mod ast;
130pub mod catalog;
131pub mod func;
132pub mod kafka_util;
133pub mod names;
134#[macro_use]
135pub mod normalize;
136pub mod optimizer_metrics;
137pub mod parse;
138pub mod plan;
139pub mod pure;
140pub mod rbac;
141pub mod session;