Skip to main content

mz_expr/scalar/func/
unmaterializable.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// Portions of this file are derived from the PostgreSQL project. The original
11// source code is subject to the terms of the PostgreSQL license, a copy of
12// which can be found in the LICENSE file at the root of this repository.
13
14//! Unmaterializable functions.
15//!
16//! The definitions are placeholders and cannot be evaluated directly.
17//! Evaluation is handled directly within the `mz-adapter` crate.
18
19use std::fmt;
20
21use mz_repr::{ReprColumnType, SqlColumnType, SqlScalarType};
22use serde::{Deserialize, Serialize};
23
24#[derive(
25    Ord,
26    PartialOrd,
27    Clone,
28    Debug,
29    Eq,
30    PartialEq,
31    Serialize,
32    Deserialize,
33    Hash
34)]
35pub enum UnmaterializableFunc {
36    CurrentDatabase,
37    CurrentSchema,
38    CurrentSchemasWithSystem,
39    CurrentSchemasWithoutSystem,
40    CurrentTimestamp,
41    CurrentUser,
42    IsRbacEnabled,
43    MzIsSuperuser,
44    MzNow,
45    MzRoleOidMemberships,
46    MzSessionId,
47    MzSessionRoleMemberships,
48    MzUptime,
49    MzVersion,
50    MzVersionNum,
51    PgBackendPid,
52    PgPostmasterStartTime,
53    SessionUser,
54    Version,
55    ViewableVariables,
56}
57
58impl UnmaterializableFunc {
59    pub fn output_sql_type(&self) -> SqlColumnType {
60        match self {
61            UnmaterializableFunc::CurrentDatabase => SqlScalarType::String.nullable(false),
62            // TODO: The `CurrentSchema` function should return `name`. This is
63            // tricky in Materialize because `name` truncates to 63 characters
64            // but Materialize does not have a limit on identifier length.
65            UnmaterializableFunc::CurrentSchema => SqlScalarType::String.nullable(true),
66            // TODO: The `CurrentSchemas` function should return `name[]`. This
67            // is tricky in Materialize because `name` truncates to 63
68            // characters but Materialize does not have a limit on identifier
69            // length.
70            UnmaterializableFunc::CurrentSchemasWithSystem => {
71                SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false)
72            }
73            UnmaterializableFunc::CurrentSchemasWithoutSystem => {
74                SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false)
75            }
76            UnmaterializableFunc::CurrentTimestamp => {
77                SqlScalarType::TimestampTz { precision: None }.nullable(false)
78            }
79            UnmaterializableFunc::CurrentUser => SqlScalarType::String.nullable(false),
80            UnmaterializableFunc::IsRbacEnabled => SqlScalarType::Bool.nullable(false),
81            UnmaterializableFunc::MzIsSuperuser => SqlScalarType::Bool.nullable(false),
82            UnmaterializableFunc::MzNow => SqlScalarType::MzTimestamp.nullable(false),
83            UnmaterializableFunc::MzRoleOidMemberships => SqlScalarType::Map {
84                value_type: Box::new(SqlScalarType::Array(Box::new(SqlScalarType::String))),
85                custom_id: None,
86            }
87            .nullable(false),
88            UnmaterializableFunc::MzSessionId => SqlScalarType::Uuid.nullable(false),
89            UnmaterializableFunc::MzSessionRoleMemberships => {
90                SqlScalarType::Array(Box::new(SqlScalarType::String)).nullable(false)
91            }
92            UnmaterializableFunc::MzUptime => SqlScalarType::Interval.nullable(true),
93            UnmaterializableFunc::MzVersion => SqlScalarType::String.nullable(false),
94            UnmaterializableFunc::MzVersionNum => SqlScalarType::Int32.nullable(false),
95            UnmaterializableFunc::PgBackendPid => SqlScalarType::Int32.nullable(false),
96            UnmaterializableFunc::PgPostmasterStartTime => {
97                SqlScalarType::TimestampTz { precision: None }.nullable(false)
98            }
99            UnmaterializableFunc::SessionUser => SqlScalarType::String.nullable(false),
100            UnmaterializableFunc::Version => SqlScalarType::String.nullable(false),
101            UnmaterializableFunc::ViewableVariables => SqlScalarType::Map {
102                value_type: Box::new(SqlScalarType::String),
103                custom_id: None,
104            }
105            .nullable(false),
106        }
107    }
108
109    /// Computes the representation type of this unmaterializable function.
110    ///
111    /// This is a wrapper around [`Self::output_sql_type`] that converts the result to a representation type.
112    pub fn output_type(&self) -> ReprColumnType {
113        ReprColumnType::from(&self.output_sql_type())
114    }
115}
116
117impl UnmaterializableFunc {
118    /// Whether this function is relevant to user data product queries when
119    /// `restrict_to_user_objects` is active. Functions that return internal
120    /// system information (version, uptime, role hierarchy, etc.) are excluded
121    /// because they expose system internals outside the scope of data product queries.
122    ///
123    /// No wildcard arm: adding a new variant forces a compile-time decision.
124    pub fn allowed_in_restricted_session(&self) -> bool {
125        match self {
126            // Session identity and time: needed for normal query execution.
127            // MzSessionRoleMemberships returns only the current session's role
128            // chain (not the full system graph), used by mz_show_my_object_privileges
129            // in mz_mcp_data_products.
130            Self::CurrentDatabase
131            | Self::CurrentSchema
132            | Self::CurrentSchemasWithSystem
133            | Self::CurrentSchemasWithoutSystem
134            | Self::CurrentTimestamp
135            | Self::CurrentUser
136            | Self::SessionUser
137            | Self::MzNow
138            | Self::MzSessionId
139            | Self::MzSessionRoleMemberships => true,
140            // Session config inspection
141            Self::IsRbacEnabled | Self::ViewableVariables => true,
142            // Internal system information: not relevant to data product queries
143            Self::MzIsSuperuser
144            | Self::MzRoleOidMemberships
145            | Self::MzUptime
146            | Self::MzVersion
147            | Self::MzVersionNum
148            | Self::PgBackendPid
149            | Self::PgPostmasterStartTime
150            | Self::Version => false,
151        }
152    }
153}
154
155impl fmt::Display for UnmaterializableFunc {
156    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157        match self {
158            UnmaterializableFunc::CurrentDatabase => f.write_str("current_database"),
159            UnmaterializableFunc::CurrentSchema => f.write_str("current_schema"),
160            UnmaterializableFunc::CurrentSchemasWithSystem => f.write_str("current_schemas(true)"),
161            UnmaterializableFunc::CurrentSchemasWithoutSystem => {
162                f.write_str("current_schemas(false)")
163            }
164            UnmaterializableFunc::CurrentTimestamp => f.write_str("current_timestamp"),
165            UnmaterializableFunc::CurrentUser => f.write_str("current_user"),
166            UnmaterializableFunc::IsRbacEnabled => f.write_str("is_rbac_enabled"),
167            UnmaterializableFunc::MzIsSuperuser => f.write_str("mz_is_superuser"),
168            UnmaterializableFunc::MzNow => f.write_str("mz_now"),
169            UnmaterializableFunc::MzRoleOidMemberships => f.write_str("mz_role_oid_memberships"),
170            UnmaterializableFunc::MzSessionId => f.write_str("mz_session_id"),
171            UnmaterializableFunc::MzSessionRoleMemberships => {
172                f.write_str("mz_session_role_memberships")
173            }
174            UnmaterializableFunc::MzUptime => f.write_str("mz_uptime"),
175            UnmaterializableFunc::MzVersion => f.write_str("mz_version"),
176            UnmaterializableFunc::MzVersionNum => f.write_str("mz_version_num"),
177            UnmaterializableFunc::PgBackendPid => f.write_str("pg_backend_pid"),
178            UnmaterializableFunc::PgPostmasterStartTime => f.write_str("pg_postmaster_start_time"),
179            UnmaterializableFunc::SessionUser => f.write_str("session_user"),
180            UnmaterializableFunc::Version => f.write_str("version"),
181            UnmaterializableFunc::ViewableVariables => f.write_str("viewable_variables"),
182        }
183    }
184}