mz_sql/plan/
typeconv.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//! Maintains a catalog of valid casts between [`mz_repr::ScalarType`]s, as well as
11//! other cast-related functions.
12
13use std::cell::RefCell;
14use std::collections::BTreeMap;
15use std::sync::LazyLock;
16
17use dynfmt::{Format, SimpleCurlyFormat};
18use itertools::Itertools;
19use mz_expr::func::{CastArrayToJsonb, CastListToJsonb};
20use mz_expr::{VariadicFunc, func};
21use mz_ore::assert_none;
22use mz_repr::{ColumnName, ColumnType, Datum, RelationType, ScalarBaseType, ScalarType};
23
24use crate::catalog::TypeCategory;
25use crate::plan::error::PlanError;
26use crate::plan::hir::{
27    AbstractColumnType, CoercibleScalarExpr, CoercibleScalarType, HirScalarExpr, UnaryFunc,
28};
29use crate::plan::query::{ExprContext, QueryContext};
30use crate::plan::scope::Scope;
31
32/// Like func::sql_impl_func, but for casts.
33fn sql_impl_cast(expr: &'static str) -> CastTemplate {
34    let invoke = crate::func::sql_impl(expr);
35    CastTemplate::new(move |ecx, _ccx, from_type, _to_type| {
36        // Oddly, this needs to be able to gracefully fail so we can detect unmet dependencies.
37        let mut out = invoke(ecx.qcx, vec![from_type.clone()]).ok()?;
38        Some(move |e| {
39            out.splice_parameters(&[e], 0);
40            out
41        })
42    })
43}
44
45fn sql_impl_cast_per_context(casts: &[(CastContext, &'static str)]) -> CastTemplate {
46    let casts: BTreeMap<CastContext, _> = casts
47        .iter()
48        .map(|(ccx, expr)| (ccx.clone(), crate::func::sql_impl(expr)))
49        .collect();
50    CastTemplate::new(move |ecx, ccx, from_type, _to_type| {
51        let invoke = &casts[&ccx];
52        let r = invoke(ecx.qcx, vec![from_type.clone()]);
53        let mut out = r.ok()?;
54        Some(move |e| {
55            out.splice_parameters(&[e], 0);
56            out
57        })
58    })
59}
60
61/// A cast is a function that takes a `ScalarExpr` to another `ScalarExpr`.
62type Cast = Box<dyn FnOnce(HirScalarExpr) -> HirScalarExpr>;
63
64/// A cast template is a function that produces a `Cast` given a concrete input
65/// and output type. A template can return `None` to indicate that it is
66/// incapable of producing a cast for the specified types.
67///
68/// Cast templates are used to share code for similar casts, where the input or
69/// output type is of one "category" of type. For example, a single cast
70/// template handles converting from strings to any list type. Without cast
71/// templates, we'd have to enumerate every possible list -> list conversion,
72/// which is impractical.
73struct CastTemplate(
74    Box<dyn Fn(&ExprContext, CastContext, &ScalarType, &ScalarType) -> Option<Cast> + Send + Sync>,
75);
76
77impl CastTemplate {
78    fn new<T, C>(t: T) -> CastTemplate
79    where
80        T: Fn(&ExprContext, CastContext, &ScalarType, &ScalarType) -> Option<C>
81            + Send
82            + Sync
83            + 'static,
84        C: FnOnce(HirScalarExpr) -> HirScalarExpr + 'static,
85    {
86        CastTemplate(Box::new(move |ecx, ccx, from_ty, to_ty| {
87            Some(Box::new(t(ecx, ccx, from_ty, to_ty)?))
88        }))
89    }
90}
91
92impl From<UnaryFunc> for CastTemplate {
93    fn from(u: UnaryFunc) -> CastTemplate {
94        CastTemplate::new(move |_ecx, _ccx, _from, _to| {
95            let u = u.clone();
96            Some(move |expr: HirScalarExpr| expr.call_unary(u))
97        })
98    }
99}
100
101impl<const N: usize> From<[UnaryFunc; N]> for CastTemplate {
102    fn from(funcs: [UnaryFunc; N]) -> CastTemplate {
103        CastTemplate::new(move |_ecx, _ccx, _from, _to| {
104            let funcs = funcs.clone();
105            Some(move |mut expr: HirScalarExpr| {
106                for func in funcs {
107                    expr = expr.call_unary(func.clone());
108                }
109                expr
110            })
111        })
112    }
113}
114
115/// STRING to REG*
116///
117/// A reg* type represents a specific type of object by oid.
118///
119/// Casting from a string to a reg*:
120/// - Accepts a string that looks like an OID and converts the value to the
121///   specified reg* type. This is available in all cases except explicitly
122///   casting text values to regclass (e.g. `SELECT '2'::text::regclass`)
123/// - Resolves non-OID-appearing strings to objects. If this string resolves to
124///   more than one OID (e.g. functions), it errors.
125///
126/// The below code provides a template to accomplish this for various reg*
127/// types. Arguments in order are:
128/// - 0: type catalog name this is casting to
129/// - 1: the category of this reg for the error message
130/// - 2: Whether or not to permit passing through numeric values as OIDs
131const STRING_REG_CAST_TEMPLATE: &str = "
132(SELECT
133CASE
134    WHEN $1 IS NULL THEN NULL
135-- Handle OID-like input, if available via {2}
136    WHEN {2} AND pg_catalog.substring($1, 1, 1) BETWEEN '0' AND '9' THEN
137        $1::pg_catalog.oid::pg_catalog.{0}
138    ELSE (
139    -- String case; look up that the item exists
140        SELECT o.oid
141        FROM mz_unsafe.mz_error_if_null(
142            (
143                -- We need to ensure a distinct here in the case of e.g. functions,
144                -- where multiple items share a GlobalId.
145                SELECT DISTINCT id AS name_id
146                FROM mz_internal.mz_resolve_object_name('{0}', $1)
147            ),
148            -- TODO: Support the correct error code for does not exist (42883).
149            '{1} \"' || $1 || '\" does not exist'
150        ) AS i (name_id),
151        -- Lateral lets us error separately from DNE case
152        LATERAL (
153            SELECT
154                CASE
155            -- Handle too many OIDs
156                WHEN mz_catalog.list_length(mz_catalog.list_agg(oid)) > 1 THEN
157                    mz_unsafe.mz_error_if_null(
158                        NULL::pg_catalog.{0},
159                        'more than one {1} named \"' || $1 || '\"'
160                    )
161            -- Resolve object name's OID if we know there is only one
162                ELSE
163                    CAST(mz_catalog.list_agg(oid)[1] AS pg_catalog.{0})
164                END
165            FROM mz_catalog.mz_objects
166            WHERE id = name_id
167            GROUP BY id
168        ) AS o (oid)
169    )
170END)";
171
172static STRING_TO_REGCLASS_EXPLICIT: LazyLock<String> = LazyLock::new(|| {
173    SimpleCurlyFormat
174        .format(STRING_REG_CAST_TEMPLATE, ["regclass", "relation", "false"])
175        .unwrap()
176        .to_string()
177});
178
179static STRING_TO_REGCLASS_COERCED: LazyLock<String> = LazyLock::new(|| {
180    SimpleCurlyFormat
181        .format(STRING_REG_CAST_TEMPLATE, ["regclass", "relation", "true"])
182        .unwrap()
183        .to_string()
184});
185
186static STRING_TO_REGPROC: LazyLock<String> = LazyLock::new(|| {
187    SimpleCurlyFormat
188        .format(STRING_REG_CAST_TEMPLATE, ["regproc", "function", "true"])
189        .unwrap()
190        .to_string()
191});
192
193static STRING_TO_REGTYPE: LazyLock<String> = LazyLock::new(|| {
194    SimpleCurlyFormat
195        .format(STRING_REG_CAST_TEMPLATE, ["regtype", "type", "true"])
196        .unwrap()
197        .to_string()
198});
199
200const REG_STRING_CAST_TEMPLATE: &str = "(
201SELECT
202    COALESCE(mz_internal.mz_global_id_to_name(o.id), CAST($1 AS pg_catalog.oid)::pg_catalog.text)
203    AS text
204FROM
205  (
206        SELECT
207          (
208            SELECT DISTINCT id
209            FROM
210              mz_catalog.mz_objects AS o
211                JOIN
212                  mz_internal.mz_object_oid_alias AS a
213                  ON o.type = a.object_type
214            WHERE
215              oid = CAST($1 AS pg_catalog.oid)
216                AND
217              a.oid_alias = '{0}'
218          )
219      )
220      AS o
221)";
222
223static REGCLASS_TO_STRING: LazyLock<String> = LazyLock::new(|| {
224    SimpleCurlyFormat
225        .format(REG_STRING_CAST_TEMPLATE, ["regclass"])
226        .unwrap()
227        .to_string()
228});
229
230static REGPROC_TO_STRING: LazyLock<String> = LazyLock::new(|| {
231    SimpleCurlyFormat
232        .format(REG_STRING_CAST_TEMPLATE, ["regproc"])
233        .unwrap()
234        .to_string()
235});
236
237static REGTYPE_TO_STRING: LazyLock<String> = LazyLock::new(|| {
238    SimpleCurlyFormat
239        .format(REG_STRING_CAST_TEMPLATE, ["regtype"])
240        .unwrap()
241        .to_string()
242});
243
244/// Describes the context of a cast.
245///
246/// n.b. this type derived `Ord, PartialOrd` and the ordering of these values
247/// has semantics meaning; casts are only permitted when the caller's cast
248/// context is geq the ccx we store, which is the minimum required context.
249#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
250pub enum CastContext {
251    /// Implicit casts are "no-brainer" casts that apply automatically in
252    /// expressions. They are typically lossless, such as `ScalarType::Int32` to
253    /// `ScalarType::Int64`.
254    Implicit,
255    /// Assignment casts are "reasonable" casts that make sense to apply
256    /// automatically in `INSERT` statements, but are surprising enough that
257    /// they don't apply implicitly in expressions.
258    Assignment,
259    /// Explicit casts are casts that are possible but may be surprising, like
260    /// casting `ScalarType::Json` to `ScalarType::Int32`, and therefore they do
261    /// not happen unless explicitly requested by the user with a cast operator.
262    Explicit,
263    /// Coerced casts permit different behavior when a type is coerced from a
264    /// string literal vs. a value of type `pg_catalog::text`.
265    ///
266    /// The only call site that should pass this value in to this module is
267    /// string coercion.
268    Coerced,
269}
270
271/// The implementation of a cast.
272struct CastImpl {
273    template: CastTemplate,
274    context: CastContext,
275}
276
277macro_rules! casts(
278    {
279        $(
280            $from_to:expr => $cast_context:ident: $cast_template:expr
281        ),+
282    } => {{
283        let mut m = BTreeMap::new();
284        $(
285            m.insert($from_to, CastImpl {
286                template: $cast_template.into(),
287                context: CastContext::$cast_context,
288            });
289        )+
290        m
291    }};
292);
293
294static VALID_CASTS: LazyLock<BTreeMap<(ScalarBaseType, ScalarBaseType), CastImpl>> = LazyLock::new(
295    || {
296        use ScalarBaseType::*;
297        use UnaryFunc::*;
298
299        casts! {
300            // BOOL
301            (Bool, Int32) => Explicit: CastBoolToInt32(func::CastBoolToInt32),
302            (Bool, Int64) => Explicit: CastBoolToInt64(func::CastBoolToInt64),
303            (Bool, String) => Assignment: CastBoolToString(func::CastBoolToString),
304
305            //INT16
306            (Int16, Int32) => Implicit: CastInt16ToInt32(func::CastInt16ToInt32),
307            (Int16, Int64) => Implicit: CastInt16ToInt64(func::CastInt16ToInt64),
308            (Int16, UInt16) => Assignment: CastInt16ToUint16(func::CastInt16ToUint16),
309            (Int16, UInt32) => Assignment: CastInt16ToUint32(func::CastInt16ToUint32),
310            (Int16, UInt64) => Assignment: CastInt16ToUint64(func::CastInt16ToUint64),
311            (Int16, Float32) => Implicit: CastInt16ToFloat32(func::CastInt16ToFloat32),
312            (Int16, Float64) => Implicit: CastInt16ToFloat64(func::CastInt16ToFloat64),
313            (Int16, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
314                let s = to_type.unwrap_numeric_max_scale();
315                Some(move |e: HirScalarExpr| e.call_unary(CastInt16ToNumeric(func::CastInt16ToNumeric(s))))
316            }),
317            (Int16, Oid) => Implicit: [
318                CastInt16ToInt32(func::CastInt16ToInt32),
319                CastInt32ToOid(func::CastInt32ToOid),
320            ],
321            (Int16, RegClass) => Implicit: [
322                CastInt16ToInt32(func::CastInt16ToInt32),
323                CastInt32ToOid(func::CastInt32ToOid),
324                CastOidToRegClass(func::CastOidToRegClass),
325            ],
326            (Int16, RegProc) => Implicit: [
327                CastInt16ToInt32(func::CastInt16ToInt32),
328                CastInt32ToOid(func::CastInt32ToOid),
329                CastOidToRegProc(func::CastOidToRegProc),
330            ],
331            (Int16, RegType) => Implicit: [
332                CastInt16ToInt32(func::CastInt16ToInt32),
333                CastInt32ToOid(func::CastInt32ToOid),
334                CastOidToRegType(func::CastOidToRegType),
335            ],
336            (Int16, String) => Assignment: CastInt16ToString(func::CastInt16ToString),
337
338            //INT32
339            (Int32, Bool) => Explicit: CastInt32ToBool(func::CastInt32ToBool),
340            (Int32, Oid) => Implicit: CastInt32ToOid(func::CastInt32ToOid),
341            (Int32, RegClass) => Implicit: [
342                CastInt32ToOid(func::CastInt32ToOid),
343                CastOidToRegClass(func::CastOidToRegClass),
344            ],
345            (Int32, RegProc) => Implicit: [
346                CastInt32ToOid(func::CastInt32ToOid),
347                CastOidToRegProc(func::CastOidToRegProc),
348            ],
349            (Int32, RegType) => Implicit: [
350                CastInt32ToOid(func::CastInt32ToOid),
351                CastOidToRegType(func::CastOidToRegType),
352            ],
353            (Int32, PgLegacyChar) => Explicit: CastInt32ToPgLegacyChar(func::CastInt32ToPgLegacyChar),
354            (Int32, Int16) => Assignment: CastInt32ToInt16(func::CastInt32ToInt16),
355            (Int32, Int64) => Implicit: CastInt32ToInt64(func::CastInt32ToInt64),
356            (Int32, UInt16) => Assignment: CastInt32ToUint16(func::CastInt32ToUint16),
357            (Int32, UInt32) => Assignment: CastInt32ToUint32(func::CastInt32ToUint32),
358            (Int32, UInt64) => Assignment: CastInt32ToUint64(func::CastInt32ToUint64),
359            (Int32, Float32) => Implicit: CastInt32ToFloat32(func::CastInt32ToFloat32),
360            (Int32, Float64) => Implicit: CastInt32ToFloat64(func::CastInt32ToFloat64),
361            (Int32, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
362                let s = to_type.unwrap_numeric_max_scale();
363                Some(move |e: HirScalarExpr| e.call_unary(CastInt32ToNumeric(func::CastInt32ToNumeric(s))))
364            }),
365            (Int32, String) => Assignment: CastInt32ToString(func::CastInt32ToString),
366
367            // INT64
368            (Int64, Bool) => Explicit: CastInt64ToBool(func::CastInt64ToBool),
369            (Int64, Int16) => Assignment: CastInt64ToInt16(func::CastInt64ToInt16),
370            (Int64, Int32) => Assignment: CastInt64ToInt32(func::CastInt64ToInt32),
371            (Int64, UInt16) => Assignment: CastInt64ToUint16(func::CastInt64ToUint16),
372            (Int64, UInt32) => Assignment: CastInt64ToUint32(func::CastInt64ToUint32),
373            (Int64, UInt64) => Assignment: CastInt64ToUint64(func::CastInt64ToUint64),
374            (Int64, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
375                let s = to_type.unwrap_numeric_max_scale();
376                Some(move |e: HirScalarExpr| e.call_unary(CastInt64ToNumeric(func::CastInt64ToNumeric(s))))
377            }),
378            (Int64, Float32) => Implicit: CastInt64ToFloat32(func::CastInt64ToFloat32),
379            (Int64, Float64) => Implicit: CastInt64ToFloat64(func::CastInt64ToFloat64),
380            (Int64, Oid) => Implicit: CastInt64ToOid(func::CastInt64ToOid),
381            (Int64, RegClass) => Implicit: [
382                CastInt64ToOid(func::CastInt64ToOid),
383                CastOidToRegClass(func::CastOidToRegClass),
384            ],
385            (Int64, RegProc) => Implicit: [
386                CastInt64ToOid(func::CastInt64ToOid),
387                CastOidToRegProc(func::CastOidToRegProc),
388            ],
389            (Int64, RegType) => Implicit: [
390                CastInt64ToOid(func::CastInt64ToOid),
391                CastOidToRegType(func::CastOidToRegType),
392            ],
393            (Int64, String) => Assignment: CastInt64ToString(func::CastInt64ToString),
394
395            // UINT16
396            (UInt16, UInt32) => Implicit: CastUint16ToUint32(func::CastUint16ToUint32),
397            (UInt16, UInt64) => Implicit: CastUint16ToUint64(func::CastUint16ToUint64),
398            (UInt16, Int16) => Assignment: CastUint16ToInt16(func::CastUint16ToInt16),
399            (UInt16, Int32) => Implicit: CastUint16ToInt32(func::CastUint16ToInt32),
400            (UInt16, Int64) => Implicit: CastUint16ToInt64(func::CastUint16ToInt64),
401            (UInt16, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
402                let s = to_type.unwrap_numeric_max_scale();
403                Some(move |e: HirScalarExpr| e.call_unary(CastUint16ToNumeric(func::CastUint16ToNumeric(s))))
404            }),
405            (UInt16, Float32) => Implicit: CastUint16ToFloat32(func::CastUint16ToFloat32),
406            (UInt16, Float64) => Implicit: CastUint16ToFloat64(func::CastUint16ToFloat64),
407            (UInt16, String) => Assignment: CastUint16ToString(func::CastUint16ToString),
408
409            // UINT32
410            (UInt32, UInt16) => Assignment: CastUint32ToUint16(func::CastUint32ToUint16),
411            (UInt32, UInt64) => Implicit: CastUint32ToUint64(func::CastUint32ToUint64),
412            (UInt32, Int16) => Assignment: CastUint32ToInt16(func::CastUint32ToInt16),
413            (UInt32, Int32) => Assignment: CastUint32ToInt32(func::CastUint32ToInt32),
414            (UInt32, Int64) => Implicit: CastUint32ToInt64(func::CastUint32ToInt64),
415            (UInt32, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
416                let s = to_type.unwrap_numeric_max_scale();
417                Some(move |e: HirScalarExpr| e.call_unary(CastUint32ToNumeric(func::CastUint32ToNumeric(s))))
418            }),
419            (UInt32, Float32) => Implicit: CastUint32ToFloat32(func::CastUint32ToFloat32),
420            (UInt32, Float64) => Implicit: CastUint32ToFloat64(func::CastUint32ToFloat64),
421            (UInt32, String) => Assignment: CastUint32ToString(func::CastUint32ToString),
422
423            // UINT64
424            (UInt64, UInt16) => Assignment: CastUint64ToUint16(func::CastUint64ToUint16),
425            (UInt64, UInt32) => Assignment: CastUint64ToUint32(func::CastUint64ToUint32),
426            (UInt64, Int16) => Assignment: CastUint64ToInt16(func::CastUint64ToInt16),
427            (UInt64, Int32) => Assignment: CastUint64ToInt32(func::CastUint64ToInt32),
428            (UInt64, Int64) => Assignment: CastUint64ToInt64(func::CastUint64ToInt64),
429            (UInt64, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
430                let s = to_type.unwrap_numeric_max_scale();
431                Some(move |e: HirScalarExpr| e.call_unary(CastUint64ToNumeric(func::CastUint64ToNumeric(s))))
432            }),
433            (UInt64, Float32) => Implicit: CastUint64ToFloat32(func::CastUint64ToFloat32),
434            (UInt64, Float64) => Implicit: CastUint64ToFloat64(func::CastUint64ToFloat64),
435            (UInt64, String) => Assignment: CastUint64ToString(func::CastUint64ToString),
436
437            // MZ_TIMESTAMP
438            (MzTimestamp, String) => Assignment: CastMzTimestampToString(func::CastMzTimestampToString),
439            (MzTimestamp, Timestamp) => Assignment: CastMzTimestampToTimestamp(func::CastMzTimestampToTimestamp),
440            (MzTimestamp, TimestampTz) => Assignment: CastMzTimestampToTimestampTz(func::CastMzTimestampToTimestampTz),
441            (String, MzTimestamp) => Assignment: CastStringToMzTimestamp(func::CastStringToMzTimestamp),
442            (UInt64, MzTimestamp) => Implicit: CastUint64ToMzTimestamp(func::CastUint64ToMzTimestamp),
443            (UInt32, MzTimestamp) => Implicit: CastUint32ToMzTimestamp(func::CastUint32ToMzTimestamp),
444            (Int64, MzTimestamp) => Implicit: CastInt64ToMzTimestamp(func::CastInt64ToMzTimestamp),
445            (Int32, MzTimestamp) => Implicit: CastInt32ToMzTimestamp(func::CastInt32ToMzTimestamp),
446            (Numeric, MzTimestamp) => Implicit: CastNumericToMzTimestamp(func::CastNumericToMzTimestamp),
447            (Timestamp, MzTimestamp) => Implicit: CastTimestampToMzTimestamp(func::CastTimestampToMzTimestamp),
448            (TimestampTz, MzTimestamp) => Implicit: CastTimestampTzToMzTimestamp(func::CastTimestampTzToMzTimestamp),
449            (Date, MzTimestamp) => Implicit: CastDateToMzTimestamp(func::CastDateToMzTimestamp),
450
451            // OID
452            (Oid, Int32) => Assignment: CastOidToInt32(func::CastOidToInt32),
453            (Oid, Int64) => Assignment: CastOidToInt32(func::CastOidToInt32),
454            (Oid, String) => Explicit: CastOidToString(func::CastOidToString),
455            (Oid, RegClass) => Implicit: CastOidToRegClass(func::CastOidToRegClass),
456            (Oid, RegProc) => Implicit: CastOidToRegProc(func::CastOidToRegProc),
457            (Oid, RegType) => Implicit: CastOidToRegType(func::CastOidToRegType),
458
459            // REGCLASS
460            (RegClass, Oid) => Implicit: CastRegClassToOid(func::CastRegClassToOid),
461            (RegClass, String) => Explicit: sql_impl_cast(&REGCLASS_TO_STRING),
462
463            // REGPROC
464            (RegProc, Oid) => Implicit: CastRegProcToOid(func::CastRegProcToOid),
465            (RegProc, String) => Explicit: sql_impl_cast(&REGPROC_TO_STRING),
466
467            // REGTYPE
468            (RegType, Oid) => Implicit: CastRegTypeToOid(func::CastRegTypeToOid),
469            (RegType, String) => Explicit: sql_impl_cast(&REGTYPE_TO_STRING),
470
471            // FLOAT32
472            (Float32, Int16) => Assignment: CastFloat32ToInt16(func::CastFloat32ToInt16),
473            (Float32, Int32) => Assignment: CastFloat32ToInt32(func::CastFloat32ToInt32),
474            (Float32, Int64) => Assignment: CastFloat32ToInt64(func::CastFloat32ToInt64),
475            (Float32, UInt16) => Assignment: CastFloat32ToUint16(func::CastFloat32ToUint16),
476            (Float32, UInt32) => Assignment: CastFloat32ToUint32(func::CastFloat32ToUint32),
477            (Float32, UInt64) => Assignment: CastFloat32ToUint64(func::CastFloat32ToUint64),
478            (Float32, Float64) => Implicit: CastFloat32ToFloat64(func::CastFloat32ToFloat64),
479            (Float32, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
480                let s = to_type.unwrap_numeric_max_scale();
481                Some(move |e: HirScalarExpr| e.call_unary(CastFloat32ToNumeric(func::CastFloat32ToNumeric(s))))
482            }),
483            (Float32, String) => Assignment: CastFloat32ToString(func::CastFloat32ToString),
484
485            // FLOAT64
486            (Float64, Int16) => Assignment: CastFloat64ToInt16(func::CastFloat64ToInt16),
487            (Float64, Int32) => Assignment: CastFloat64ToInt32(func::CastFloat64ToInt32),
488            (Float64, Int64) => Assignment: CastFloat64ToInt64(func::CastFloat64ToInt64),
489            (Float64, UInt16) => Assignment: CastFloat64ToUint16(func::CastFloat64ToUint16),
490            (Float64, UInt32) => Assignment: CastFloat64ToUint32(func::CastFloat64ToUint32),
491            (Float64, UInt64) => Assignment: CastFloat64ToUint64(func::CastFloat64ToUint64),
492            (Float64, Float32) => Assignment: CastFloat64ToFloat32(func::CastFloat64ToFloat32),
493            (Float64, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
494                let s = to_type.unwrap_numeric_max_scale();
495                Some(move |e: HirScalarExpr| e.call_unary(CastFloat64ToNumeric(func::CastFloat64ToNumeric(s))))
496            }),
497            (Float64, String) => Assignment: CastFloat64ToString(func::CastFloat64ToString),
498
499            // DATE
500            (Date, Timestamp) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
501                let p = to_type.unwrap_timestamp_precision();
502                Some(move |e: HirScalarExpr| e.call_unary(CastDateToTimestamp(func::CastDateToTimestamp(p))))
503            }),
504            (Date, TimestampTz) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
505                let p = to_type.unwrap_timestamp_precision();
506                Some(move |e: HirScalarExpr| e.call_unary(CastDateToTimestampTz(func::CastDateToTimestampTz(p))))
507            }),
508            (Date, String) => Assignment: CastDateToString(func::CastDateToString),
509
510            // TIME
511            (Time, Interval) => Implicit: CastTimeToInterval(func::CastTimeToInterval),
512            (Time, String) => Assignment: CastTimeToString(func::CastTimeToString),
513
514            // TIMESTAMP
515            (Timestamp, Date) => Assignment: CastTimestampToDate(func::CastTimestampToDate),
516            (Timestamp, TimestampTz) => Implicit: CastTemplate::new(|_ecx, _ccx, from_type, to_type| {
517                let from = from_type.unwrap_timestamp_precision();
518                let to = to_type.unwrap_timestamp_precision();
519                Some(move |e: HirScalarExpr| e.call_unary(CastTimestampToTimestampTz(func::CastTimestampToTimestampTz{from, to})))
520            }),
521            (Timestamp, Timestamp) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, to_type| {
522                let from = from_type.unwrap_timestamp_precision();
523                let to = to_type.unwrap_timestamp_precision();
524                Some(move |e: HirScalarExpr| e.call_unary(AdjustTimestampPrecision(func::AdjustTimestampPrecision{from, to})))
525            }),
526            (Timestamp, Time) => Assignment: CastTimestampToTime(func::CastTimestampToTime),
527            (Timestamp, String) => Assignment: CastTimestampToString(func::CastTimestampToString),
528
529            // TIMESTAMPTZ
530            (TimestampTz, Date) => Assignment: CastTimestampTzToDate(func::CastTimestampTzToDate),
531            (TimestampTz, Timestamp) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, to_type| {
532                let from = from_type.unwrap_timestamp_precision();
533                let to = to_type.unwrap_timestamp_precision();
534                Some(move |e: HirScalarExpr| e.call_unary(CastTimestampTzToTimestamp(func::CastTimestampTzToTimestamp{from, to})))
535            }),
536            (TimestampTz, TimestampTz) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, to_type| {
537                let from = from_type.unwrap_timestamp_precision();
538                let to = to_type.unwrap_timestamp_precision();
539                Some(move |e: HirScalarExpr| e.call_unary(AdjustTimestampTzPrecision(func::AdjustTimestampTzPrecision{from, to})))
540            }),
541            (TimestampTz, Time) => Assignment: CastTimestampTzToTime(func::CastTimestampTzToTime),
542            (TimestampTz, String) => Assignment: CastTimestampTzToString(func::CastTimestampTzToString),
543
544            // INTERVAL
545            (Interval, Time) => Assignment: CastIntervalToTime(func::CastIntervalToTime),
546            (Interval, String) => Assignment: CastIntervalToString(func::CastIntervalToString),
547
548            // BYTES
549            (Bytes, String) => Assignment: CastBytesToString(func::CastBytesToString),
550
551            // STRING
552            (String, Bool) => Explicit: CastStringToBool(func::CastStringToBool),
553            (String, Int16) => Explicit: CastStringToInt16(func::CastStringToInt16),
554            (String, Int32) => Explicit: CastStringToInt32(func::CastStringToInt32),
555            (String, Int64) => Explicit: CastStringToInt64(func::CastStringToInt64),
556            (String, UInt16) => Explicit: CastStringToUint16(func::CastStringToUint16),
557            (String, UInt32) => Explicit: CastStringToUint32(func::CastStringToUint32),
558            (String, UInt64) => Explicit: CastStringToUint64(func::CastStringToUint64),
559            (String, Oid) => Explicit: CastStringToOid(func::CastStringToOid),
560
561            // STRING to REG*
562            // A reg* type represents a specific type of object by oid.
563            // Converting from string to reg* does a lookup of the object name
564            // in the corresponding mz_catalog table and expects exactly one object to match it.
565            // You can also specify (in postgres) a string that's a valid
566            // int4 and it'll happily cast it (without verifying that the int4 matches
567            // an object oid).
568            // TODO: Support the correct error code for does not exist (42883).
569            (String, RegClass) => Explicit: sql_impl_cast_per_context(
570                &[
571                    (CastContext::Explicit, &STRING_TO_REGCLASS_EXPLICIT),
572                    (CastContext::Coerced, &STRING_TO_REGCLASS_COERCED)
573                ]
574            ),
575            (String, RegProc) => Explicit: sql_impl_cast(&STRING_TO_REGPROC),
576            (String, RegType) => Explicit: sql_impl_cast(&STRING_TO_REGTYPE),
577
578            (String, Float32) => Explicit: CastStringToFloat32(func::CastStringToFloat32),
579            (String, Float64) => Explicit: CastStringToFloat64(func::CastStringToFloat64),
580            (String, Numeric) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
581                let s = to_type.unwrap_numeric_max_scale();
582                Some(move |e: HirScalarExpr| e.call_unary(CastStringToNumeric(func::CastStringToNumeric(s))))
583            }),
584            (String, Date) => Explicit: CastStringToDate(func::CastStringToDate),
585            (String, Time) => Explicit: CastStringToTime(func::CastStringToTime),
586            (String, Timestamp) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
587                let p = to_type.unwrap_timestamp_precision();
588                Some(move |e: HirScalarExpr| e.call_unary(CastStringToTimestamp(func::CastStringToTimestamp(p))))
589            }),
590            (String, TimestampTz) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
591                let p = to_type.unwrap_timestamp_precision();
592                Some(move |e: HirScalarExpr| e.call_unary(CastStringToTimestampTz(func::CastStringToTimestampTz(p))))
593            }),
594            (String, Interval) => Explicit: CastStringToInterval(func::CastStringToInterval),
595            (String, Bytes) => Explicit: CastStringToBytes(func::CastStringToBytes),
596            (String, Jsonb) => Explicit: CastStringToJsonb(func::CastStringToJsonb),
597            (String, Uuid) => Explicit: CastStringToUuid(func::CastStringToUuid),
598            (String, Array) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
599                let return_ty = to_type.clone();
600                let to_el_type = to_type.unwrap_array_element_type();
601                let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_el_type)?;
602                Some(|e: HirScalarExpr| e.call_unary(UnaryFunc::CastStringToArray(func::CastStringToArray {
603                    return_ty,
604                    cast_expr: Box::new(cast_expr),
605                })))
606            }),
607            (String, List) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
608                let return_ty = to_type.clone();
609                let to_el_type = to_type.unwrap_list_element_type();
610                let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_el_type)?;
611                Some(|e: HirScalarExpr| e.call_unary(UnaryFunc::CastStringToList(func::CastStringToList {
612                    return_ty,
613                    cast_expr: Box::new(cast_expr),
614                })))
615            }),
616            (String, Map) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
617                let return_ty = to_type.clone();
618                let to_val_type = to_type.unwrap_map_value_type();
619                let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_val_type)?;
620                Some(|e: HirScalarExpr| e.call_unary(UnaryFunc::CastStringToMap(func::CastStringToMap {
621                    return_ty,
622                    cast_expr: Box::new(cast_expr),
623                })))
624            }),
625            (String, Range) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
626                let return_ty = to_type.clone();
627                let to_el_type = to_type.unwrap_range_element_type();
628                let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_el_type)?;
629                Some(|e: HirScalarExpr| e.call_unary(UnaryFunc::CastStringToRange(func::CastStringToRange {
630                    return_ty,
631                    cast_expr: Box::new(cast_expr),
632                })))
633            }),
634            (String, Int2Vector) => Explicit: CastStringToInt2Vector(func::CastStringToInt2Vector),
635            (String, Char) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
636                let length = to_type.unwrap_char_length();
637                Some(move |e: HirScalarExpr| e.call_unary(CastStringToChar(func::CastStringToChar {length, fail_on_len: ccx != CastContext::Explicit})))
638            }),
639            (String, VarChar) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
640                let length = to_type.unwrap_varchar_max_length();
641                Some(move |e: HirScalarExpr| e.call_unary(CastStringToVarChar(func::CastStringToVarChar {length, fail_on_len: ccx != CastContext::Explicit})))
642            }),
643            (String, PgLegacyChar) => Assignment: CastStringToPgLegacyChar(func::CastStringToPgLegacyChar),
644            // CHAR
645            (Char, String) => Implicit: CastCharToString(func::CastCharToString),
646            (Char, Char) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
647                let length = to_type.unwrap_char_length();
648                Some(move |e: HirScalarExpr| e.call_unary(CastStringToChar(func::CastStringToChar {length, fail_on_len: ccx != CastContext::Explicit})))
649            }),
650            (Char, VarChar) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
651                let length = to_type.unwrap_varchar_max_length();
652                Some(move |e: HirScalarExpr| e.call_unary(CastStringToVarChar(func::CastStringToVarChar {length, fail_on_len: ccx != CastContext::Explicit})))
653            }),
654            (Char, PgLegacyChar) => Assignment: CastStringToPgLegacyChar(func::CastStringToPgLegacyChar),
655
656            // VARCHAR
657            (VarChar, String) => Implicit: CastVarCharToString(func::CastVarCharToString),
658            (VarChar, Char) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
659                let length = to_type.unwrap_char_length();
660                Some(move |e: HirScalarExpr| e.call_unary(CastStringToChar(func::CastStringToChar {length, fail_on_len: ccx != CastContext::Explicit})))
661            }),
662            (VarChar, VarChar) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
663                let length = to_type.unwrap_varchar_max_length();
664                Some(move |e: HirScalarExpr| e.call_unary(CastStringToVarChar(func::CastStringToVarChar {length, fail_on_len: ccx != CastContext::Explicit})))
665            }),
666            (VarChar, PgLegacyChar) => Assignment: CastStringToPgLegacyChar(func::CastStringToPgLegacyChar),
667
668            // PG LEGACY CHAR
669            (PgLegacyChar, String) => Implicit: CastPgLegacyCharToString(func::CastPgLegacyCharToString),
670            (PgLegacyChar, Char) => Assignment: CastPgLegacyCharToChar(func::CastPgLegacyCharToChar),
671            (PgLegacyChar, VarChar) => Assignment: CastPgLegacyCharToVarChar(func::CastPgLegacyCharToVarChar),
672            (PgLegacyChar, Int32) => Explicit: CastPgLegacyCharToInt32(func::CastPgLegacyCharToInt32),
673
674            // PG LEGACY NAME
675            // Under the hood VarChars and Name's are just Strings, so we can re-use existing methods
676            // on Strings and VarChars instead of defining new ones.
677            (PgLegacyName, String) => Implicit: CastVarCharToString(func::CastVarCharToString),
678            (PgLegacyName, Char) => Assignment: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
679                let length = to_type.unwrap_char_length();
680                Some(move |e: HirScalarExpr| e.call_unary(CastStringToChar(func::CastStringToChar {length, fail_on_len: ccx != CastContext::Explicit})))
681            }),
682            (PgLegacyName, VarChar) => Assignment: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
683                let length = to_type.unwrap_varchar_max_length();
684                Some(move |e: HirScalarExpr| e.call_unary(CastStringToVarChar(func::CastStringToVarChar {length, fail_on_len: ccx != CastContext::Explicit})))
685            }),
686            (String, PgLegacyName) => Implicit: CastStringToPgLegacyName(func::CastStringToPgLegacyName),
687            (Char, PgLegacyName) => Implicit: CastStringToPgLegacyName(func::CastStringToPgLegacyName),
688            (VarChar, PgLegacyName) => Implicit: CastStringToPgLegacyName(func::CastStringToPgLegacyName),
689
690            // RECORD
691            (Record, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
692                let ty = from_type.clone();
693                Some(|e: HirScalarExpr| e.call_unary(CastRecordToString(func::CastRecordToString { ty })))
694            }),
695            (Record, Record) => Implicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
696                if from_type.unwrap_record_element_type().len() != to_type.unwrap_record_element_type().len() {
697                    return None;
698                }
699
700                if let (l @ ScalarType::Record {custom_id: Some(..), ..}, r) = (from_type, to_type) {
701                    // Changing `from`'s custom_id requires at least Assignment context
702                    if ccx == CastContext::Implicit && l != r {
703                        return None;
704                    }
705                }
706
707                let cast_exprs = from_type.unwrap_record_element_type()
708                    .iter()
709                    .zip_eq(to_type.unwrap_record_element_type())
710                    .map(|(f, t)| plan_hypothetical_cast(ecx, ccx, f, t))
711                    .collect::<Option<Box<_>>>()?;
712                let to = to_type.clone();
713                Some(|e: HirScalarExpr| e.call_unary(CastRecord1ToRecord2(func::CastRecord1ToRecord2 { return_ty: to, cast_exprs })))
714            }),
715
716            // ARRAY
717            (Array, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
718                let ty = from_type.clone();
719                Some(|e: HirScalarExpr| e.call_unary(CastArrayToString(func::CastArrayToString { ty })))
720            }),
721            (Array, List) => Explicit: CastArrayToListOneDim(func::CastArrayToListOneDim),
722            (Array, Array) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
723                let inner_from_type = from_type.unwrap_array_element_type();
724                let inner_to_type = to_type.unwrap_array_element_type();
725                let cast_expr = plan_hypothetical_cast(ecx, ccx, inner_from_type, inner_to_type)?;
726                let return_ty = to_type.clone();
727
728                Some(move |e: HirScalarExpr| e.call_unary(CastArrayToArray(func::CastArrayToArray { return_ty, cast_expr: Box::new(cast_expr) })))
729            }),
730
731            // INT2VECTOR
732            (Int2Vector, Array) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, _to_type| {
733                Some(|e: HirScalarExpr| e.call_unary(UnaryFunc::CastInt2VectorToArray(func::CastInt2VectorToArray)))
734            }),
735            (Int2Vector, String) => Explicit: CastInt2VectorToString(func::CastInt2VectorToString),
736
737            // LIST
738            (List, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
739                let ty = from_type.clone();
740                Some(|e: HirScalarExpr| e.call_unary(CastListToString(func::CastListToString { ty })))
741            }),
742            (List, List) => Implicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
743
744                if let (l @ ScalarType::List {custom_id: Some(..), ..}, r) = (from_type, to_type) {
745                    // Changing `from`'s custom_id requires at least Assignment context
746                    if ccx == CastContext::Implicit && !l.base_eq(r) {
747                        return None;
748                    }
749                }
750
751                let return_ty = to_type.clone();
752                let from_el_type = from_type.unwrap_list_element_type();
753                let to_el_type = to_type.unwrap_list_element_type();
754                let cast_expr = plan_hypothetical_cast(ecx, ccx, from_el_type, to_el_type)?;
755                Some(|e: HirScalarExpr| e.call_unary(UnaryFunc::CastList1ToList2(func::CastList1ToList2 {
756                    return_ty,
757                    cast_expr: Box::new(cast_expr),
758                })))
759            }),
760
761            // MAP
762            (Map, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
763                let ty = from_type.clone();
764                Some(|e: HirScalarExpr| e.call_unary(CastMapToString(func::CastMapToString { ty })))
765            }),
766
767            // JSONB
768            (Jsonb, Bool) => Explicit: CastJsonbToBool(func::CastJsonbToBool),
769            (Jsonb, Int16) => Explicit: CastJsonbToInt16(func::CastJsonbToInt16),
770            (Jsonb, Int32) => Explicit: CastJsonbToInt32(func::CastJsonbToInt32),
771            (Jsonb, Int64) => Explicit: CastJsonbToInt64(func::CastJsonbToInt64),
772            (Jsonb, Float32) => Explicit: CastJsonbToFloat32(func::CastJsonbToFloat32),
773            (Jsonb, Float64) => Explicit: CastJsonbToFloat64(func::CastJsonbToFloat64),
774            (Jsonb, Numeric) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
775                let s = to_type.unwrap_numeric_max_scale();
776                Some(move |e: HirScalarExpr| e.call_unary(CastJsonbToNumeric(func::CastJsonbToNumeric(s))))
777            }),
778            (Jsonb, String) => Assignment: CastJsonbToString(func::CastJsonbToString),
779
780            // UUID
781            (Uuid, String) => Assignment: CastUuidToString(func::CastUuidToString),
782
783            // Numeric
784            (Numeric, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
785                let scale = to_type.unwrap_numeric_max_scale();
786                Some(move |e: HirScalarExpr| match scale {
787                    None => e,
788                    Some(scale) => e.call_unary(UnaryFunc::AdjustNumericScale(func::AdjustNumericScale(scale))),
789                })
790            }),
791            (Numeric, Float32) => Implicit: CastNumericToFloat32(func::CastNumericToFloat32),
792            (Numeric, Float64) => Implicit: CastNumericToFloat64(func::CastNumericToFloat64),
793            (Numeric, Int16) => Assignment: CastNumericToInt16(func::CastNumericToInt16),
794            (Numeric, Int32) => Assignment: CastNumericToInt32(func::CastNumericToInt32),
795            (Numeric, Int64) => Assignment: CastNumericToInt64(func::CastNumericToInt64),
796            (Numeric, UInt16) => Assignment: CastNumericToUint16(func::CastNumericToUint16),
797            (Numeric, UInt32) => Assignment: CastNumericToUint32(func::CastNumericToUint32),
798            (Numeric, UInt64) => Assignment: CastNumericToUint64(func::CastNumericToUint64),
799            (Numeric, String) => Assignment: CastNumericToString(func::CastNumericToString),
800
801            // Range
802            (Range, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
803                let ty = from_type.clone();
804                Some(|e: HirScalarExpr| e.call_unary(CastRangeToString(func::CastRangeToString { ty })))
805            }),
806
807            // MzAclItem
808            (MzAclItem, String) => Explicit: sql_impl_cast("(
809                SELECT
810                    (CASE
811                        WHEN grantee_role_id = 'p' THEN ''
812                        ELSE COALESCE(grantee_role.name, grantee_role_id)
813                    END)
814                    || '='
815                    || mz_internal.mz_aclitem_privileges($1)
816                    || '/'
817                    || COALESCE(grantor_role.name, grantor_role_id)
818                FROM
819                    (SELECT mz_internal.mz_aclitem_grantee($1) AS grantee_role_id),
820                    (SELECT mz_internal.mz_aclitem_grantor($1) AS grantor_role_id)
821                LEFT JOIN mz_catalog.mz_roles AS grantee_role ON grantee_role_id = grantee_role.id
822                LEFT JOIN mz_catalog.mz_roles AS grantor_role ON grantor_role_id = grantor_role.id
823            )"),
824            (MzAclItem, AclItem) => Explicit: sql_impl_cast("(
825                SELECT makeaclitem(
826                    (CASE mz_internal.mz_aclitem_grantee($1)
827                        WHEN 'p' THEN 0
828                        ELSE (SELECT oid FROM mz_catalog.mz_roles WHERE id = mz_internal.mz_aclitem_grantee($1))
829                    END),
830                    (SELECT oid FROM mz_catalog.mz_roles WHERE id = mz_internal.mz_aclitem_grantor($1)),
831                    (SELECT array_to_string(mz_internal.mz_format_privileges(mz_internal.mz_aclitem_privileges($1)), ',')),
832                    -- GRANT OPTION isn't implemented so we hardcode false.
833                    false
834                )
835            )"),
836
837            // AclItem
838            (AclItem, String) => Explicit: sql_impl_cast("(
839                SELECT
840                    (CASE grantee_oid
841                        WHEN 0 THEN ''
842                        ELSE COALESCE(grantee_role.name, grantee_oid::text)
843                    END)
844                    || '='
845                    || mz_internal.aclitem_privileges($1)
846                    || '/'
847                    || COALESCE(grantor_role.name, grantor_oid::text)
848                FROM
849                    (SELECT mz_internal.aclitem_grantee($1) AS grantee_oid),
850                    (SELECT mz_internal.aclitem_grantor($1) AS grantor_oid)
851                LEFT JOIN mz_catalog.mz_roles AS grantee_role ON grantee_oid = grantee_role.oid
852                LEFT JOIN mz_catalog.mz_roles AS grantor_role ON grantor_oid = grantor_role.oid
853            )"),
854            (AclItem, MzAclItem) => Explicit: sql_impl_cast("(
855                SELECT mz_internal.make_mz_aclitem(
856                    (CASE mz_internal.aclitem_grantee($1)
857                        WHEN 0 THEN 'p'
858                        ELSE (SELECT id FROM mz_catalog.mz_roles WHERE oid = mz_internal.aclitem_grantee($1))
859                    END),
860                    (SELECT id FROM mz_catalog.mz_roles WHERE oid = mz_internal.aclitem_grantor($1)),
861                    (SELECT array_to_string(mz_internal.mz_format_privileges(mz_internal.aclitem_privileges($1)), ','))
862                )
863            )")
864        }
865    },
866);
867
868/// Get casts directly between two [`ScalarType`]s, with control over the
869/// allowed [`CastContext`].
870fn get_cast(
871    ecx: &ExprContext,
872    ccx: CastContext,
873    from: &ScalarType,
874    to: &ScalarType,
875) -> Option<Cast> {
876    use CastContext::*;
877
878    if from == to || (ccx == Implicit && from.base_eq(to)) {
879        return Some(Box::new(|expr| expr));
880    }
881
882    let imp = VALID_CASTS.get(&(from.into(), to.into()))?;
883    let template = if ccx >= imp.context {
884        Some(&imp.template)
885    } else {
886        None
887    };
888    template.and_then(|template| (template.0)(ecx, ccx, from, to))
889}
890
891/// Converts an expression to `ScalarType::String`.
892///
893/// All types are convertible to string, so this never fails.
894pub fn to_string(ecx: &ExprContext, expr: HirScalarExpr) -> HirScalarExpr {
895    plan_cast(ecx, CastContext::Explicit, expr, &ScalarType::String).expect("cast known to exist")
896}
897
898/// Converts an expression to `ScalarType::Jsonb`.
899///
900/// The rules are as follows:
901///   * `ScalarType::Boolean`s become JSON booleans.
902///   * All numeric types are converted to `Float64`s, then become JSON numbers.
903///   * Records are converted to a JSON object where the record's field names
904///     are the keys of the object, and the record's fields are recursively
905///     converted to JSON by `to_jsonb`.
906///   * Other types are converted to strings by their usual cast function an
907//      become JSON strings.
908pub fn to_jsonb(ecx: &ExprContext, expr: HirScalarExpr) -> HirScalarExpr {
909    use ScalarType::*;
910
911    match ecx.scalar_type(&expr) {
912        Bool | Jsonb | Numeric { .. } => {
913            expr.call_unary(UnaryFunc::CastJsonbableToJsonb(func::CastJsonbableToJsonb))
914        }
915        Int16 | Int32 | Float32 | Float64 => plan_cast(
916            ecx,
917            CastContext::Explicit,
918            expr,
919            &Numeric { max_scale: None },
920        )
921        .expect("cast known to exist")
922        .call_unary(UnaryFunc::CastJsonbableToJsonb(func::CastJsonbableToJsonb)),
923        Record { fields, .. } => {
924            let mut exprs = vec![];
925            for (i, (name, _ty)) in fields.iter().enumerate() {
926                exprs.push(HirScalarExpr::literal(
927                    Datum::String(name.as_str()),
928                    ScalarType::String,
929                ));
930                exprs.push(to_jsonb(
931                    ecx,
932                    expr.clone()
933                        .call_unary(UnaryFunc::RecordGet(func::RecordGet(i))),
934                ));
935            }
936            HirScalarExpr::call_variadic(VariadicFunc::JsonbBuildObject, exprs)
937        }
938        ref ty @ List {
939            ref element_type, ..
940        }
941        | ref ty @ Array(ref element_type) => {
942            // Construct a new expression context with one column whose type
943            // is the container's element type.
944            let qcx = QueryContext::root(ecx.qcx.scx, ecx.qcx.lifetime);
945            let ecx = ExprContext {
946                qcx: &qcx,
947                name: "to_jsonb",
948                scope: &Scope::empty(),
949                relation_type: &RelationType::new(vec![element_type.clone().nullable(true)]),
950                allow_aggregates: false,
951                allow_subqueries: false,
952                allow_parameters: false,
953                allow_windows: false,
954            };
955
956            // Create an element-casting expression by calling `to_jsonb` on
957            // an expression that references the first column in a row.
958            let cast_element = to_jsonb(&ecx, HirScalarExpr::column(0));
959            let cast_element = cast_element
960                .lower_uncorrelated()
961                .expect("to_jsonb does not produce correlated expressions on uncorrelated input");
962
963            // The `Cast{Array|List}ToJsonb` functions take the element-casting
964            // expression as an argument and evaluate the expression against
965            // each element of the container at runtime.
966            let func = match ty {
967                List { .. } => UnaryFunc::CastListToJsonb(CastListToJsonb {
968                    cast_element: Box::new(cast_element),
969                }),
970                Array { .. } => UnaryFunc::CastArrayToJsonb(CastArrayToJsonb {
971                    cast_element: Box::new(cast_element),
972                }),
973                _ => unreachable!("validated above"),
974            };
975
976            expr.call_unary(func)
977        }
978        _ => to_string(ecx, expr)
979            .call_unary(UnaryFunc::CastJsonbableToJsonb(func::CastJsonbableToJsonb)),
980    }
981}
982
983/// Guesses the most-common type among a set of [`ScalarType`]s that all members
984/// can be cast to. Returns `None` if a common type cannot be deduced.
985///
986/// Note that this function implements the type-determination components of
987/// Postgres' ["`UNION`, `CASE`, and Related Constructs"][union-type-conv] type
988/// conversion.
989///
990/// [union-type-conv]: https://www.postgresql.org/docs/12/typeconv-union-case.html
991pub fn guess_best_common_type(
992    ecx: &ExprContext,
993    types: &[CoercibleScalarType],
994) -> Result<ScalarType, PlanError> {
995    // This function is a translation of `select_common_type` in PostgreSQL with
996    // the addition of our near match logic, which supports Materialize
997    // non-linear type promotions.
998    // https://github.com/postgres/postgres/blob/d1b307eef/src/backend/parser/parse_coerce.c#L1288-L1308
999
1000    // If every type is a literal record with the same number of fields, the
1001    // best common type is a record with that number of fields. We recursively
1002    // guess the best type for each field.
1003    if let Some(CoercibleScalarType::Record(field_tys)) = types.first() {
1004        if types
1005            .iter()
1006            .all(|t| matches!(t, CoercibleScalarType::Record(fts) if field_tys.len() == fts.len()))
1007        {
1008            let mut fields = vec![];
1009            for i in 0..field_tys.len() {
1010                let name = ColumnName::from(format!("f{}", fields.len() + 1));
1011                let mut guesses = vec![];
1012                let mut nullable = false;
1013                for ty in types {
1014                    let field_ty = match ty {
1015                        CoercibleScalarType::Record(fts) => fts[i].clone(),
1016                        _ => unreachable!(),
1017                    };
1018                    if field_ty.nullable() {
1019                        nullable = true;
1020                    }
1021                    guesses.push(field_ty.scalar_type());
1022                }
1023                let guess = guess_best_common_type(ecx, &guesses)?;
1024                fields.push((name, guess.nullable(nullable)));
1025            }
1026            return Ok(ScalarType::Record {
1027                fields: fields.into(),
1028                custom_id: None,
1029            });
1030        }
1031    }
1032
1033    // Remove unknown types, and collect them.
1034    let mut types: Vec<_> = types.into_iter().filter_map(|v| v.as_coerced()).collect();
1035
1036    // In the case of mixed ints and uints, replace uints with their near match
1037    let contains_int = types
1038        .iter()
1039        .any(|t| matches!(t, ScalarType::Int16 | ScalarType::Int32 | ScalarType::Int64));
1040
1041    for t in types.iter_mut() {
1042        if contains_int
1043            && matches!(
1044                t,
1045                ScalarType::UInt16 | ScalarType::UInt32 | ScalarType::UInt64
1046            )
1047        {
1048            *t = t.near_match().expect("unsigned ints have near matches")
1049        }
1050    }
1051
1052    let mut types = types.iter();
1053
1054    let mut candidate = match types.next() {
1055        // If no known types, fall back to `String`.
1056        None => return Ok(ScalarType::String),
1057        // Start by guessing the first type.
1058        Some(t) => t,
1059    };
1060
1061    let preferred_type = TypeCategory::from_type(candidate).preferred_type();
1062
1063    for typ in types {
1064        if TypeCategory::from_type(candidate) != TypeCategory::from_type(typ) {
1065            // The next type is in a different category; give up.
1066            sql_bail!(
1067                "{} types {} and {} cannot be matched",
1068                ecx.name,
1069                ecx.humanize_scalar_type(candidate, false),
1070                ecx.humanize_scalar_type(typ, false),
1071            );
1072        };
1073
1074        // If this type is the preferred type, make it the candidate.
1075        if preferred_type.as_ref() != Some(candidate)
1076            && can_cast(ecx, CastContext::Implicit, candidate, typ)
1077            && !can_cast(ecx, CastContext::Implicit, typ, candidate)
1078        {
1079            // The current candidate is not the preferred type for its category
1080            // and the next type is implicitly convertible to the current
1081            // candidate, but not vice-versa, so take the next type as the new
1082            // candidate.
1083            candidate = typ;
1084        }
1085    }
1086    Ok(candidate.without_modifiers())
1087}
1088
1089pub fn plan_coerce<'a>(
1090    ecx: &'a ExprContext,
1091    e: CoercibleScalarExpr,
1092    coerce_to: &ScalarType,
1093) -> Result<HirScalarExpr, PlanError> {
1094    use CoercibleScalarExpr::*;
1095
1096    Ok(match e {
1097        Coerced(e) => e,
1098
1099        LiteralNull => HirScalarExpr::literal_null(coerce_to.clone()),
1100
1101        LiteralString(s) => {
1102            let lit = HirScalarExpr::literal(Datum::String(&s), ScalarType::String);
1103            // Per PostgreSQL, string literal explicitly casts to the base type.
1104            // The caller is responsible for applying any desired modifiers
1105            // (with either implicit or explicit semantics) via a separate call
1106            // to `plan_cast`.
1107            let coerce_to_base = &coerce_to.without_modifiers();
1108            plan_cast(ecx, CastContext::Coerced, lit, coerce_to_base)?
1109        }
1110
1111        LiteralRecord(exprs) => {
1112            let arity = exprs.len();
1113            let coercions = match coerce_to {
1114                ScalarType::Record { fields, .. } if fields.len() == arity => fields
1115                    .iter()
1116                    .map(|(_name, ty)| &ty.scalar_type)
1117                    .cloned()
1118                    .collect(),
1119                _ => vec![ScalarType::String; exprs.len()],
1120            };
1121            let mut out = vec![];
1122            for (e, coerce_to) in exprs.into_iter().zip(coercions) {
1123                out.push(plan_coerce(ecx, e, &coerce_to)?);
1124            }
1125            HirScalarExpr::call_variadic(
1126                VariadicFunc::RecordCreate {
1127                    field_names: (0..arity)
1128                        .map(|i| ColumnName::from(format!("f{}", i + 1)))
1129                        .collect(),
1130                },
1131                out,
1132            )
1133        }
1134
1135        Parameter(n) => {
1136            let prev = ecx.param_types().borrow_mut().insert(n, coerce_to.clone());
1137            assert_none!(prev);
1138            HirScalarExpr::parameter(n)
1139        }
1140    })
1141}
1142
1143/// Similar to `plan_cast`, but for situations where you only know the type of
1144/// the input expression (`from`) and not the expression itself. The returned
1145/// expression refers to the first column of some imaginary row, where the first
1146/// column is assumed to have type `from`.
1147///
1148/// If casting from `from` to `to` is not possible, returns `None`.
1149pub fn plan_hypothetical_cast(
1150    ecx: &ExprContext,
1151    ccx: CastContext,
1152    from: &ScalarType,
1153    to: &ScalarType,
1154) -> Option<mz_expr::MirScalarExpr> {
1155    // Reconstruct an expression context where the expression is evaluated on
1156    // the "first column" of some imaginary row.
1157    let mut scx = ecx.qcx.scx.clone();
1158    scx.param_types = RefCell::new(BTreeMap::new());
1159    let qcx = QueryContext::root(&scx, ecx.qcx.lifetime);
1160    let relation_type = RelationType {
1161        column_types: vec![ColumnType {
1162            nullable: true,
1163            scalar_type: from.clone(),
1164        }],
1165        keys: vec![vec![0]],
1166    };
1167    let ecx = ExprContext {
1168        qcx: &qcx,
1169        name: "plan_hypothetical_cast",
1170        scope: &Scope::empty(),
1171        relation_type: &relation_type,
1172        allow_aggregates: false,
1173        allow_subqueries: true,
1174        allow_parameters: true,
1175        allow_windows: false,
1176    };
1177
1178    let col_expr = HirScalarExpr::column(0);
1179
1180    // Determine the `ScalarExpr` required to cast our column to the target
1181    // component type.
1182    plan_cast(&ecx, ccx, col_expr, to)
1183        .ok()?
1184        // TODO(jkosh44) Support casts that have correlated implementations.
1185        .lower_uncorrelated()
1186        .ok()
1187}
1188
1189/// Plans a cast between [`ScalarType`]s, specifying which types of casts are
1190/// permitted using [`CastContext`].
1191///
1192/// # Errors
1193///
1194/// If a cast between the `ScalarExpr`'s base type and the specified type is:
1195/// - Not possible, e.g. `Bytes` to `Interval`
1196/// - Not permitted, e.g. implicitly casting from `Float64` to `Float32`.
1197/// - Not implemented yet
1198pub fn plan_cast(
1199    ecx: &ExprContext,
1200    ccx: CastContext,
1201    expr: HirScalarExpr,
1202    to: &ScalarType,
1203) -> Result<HirScalarExpr, PlanError> {
1204    let from = ecx.scalar_type(&expr);
1205
1206    // Close over `ccx`, `from`, and `to` to simplify error messages in the
1207    // face of intermediate expressions.
1208    let cast_inner = |from, to, expr| match get_cast(ecx, ccx, from, to) {
1209        Some(cast) => Ok(cast(expr)),
1210        None => Err(PlanError::InvalidCast {
1211            name: ecx.name.into(),
1212            ccx,
1213            from: ecx.humanize_scalar_type(from, false),
1214            to: ecx.humanize_scalar_type(to, false),
1215        }),
1216    };
1217
1218    // Get cast which might include parameter rewrites + generating intermediate
1219    // expressions.
1220    //
1221    // String-like types get special handling to match PostgreSQL.
1222    // See: https://github.com/postgres/postgres/blob/6b04abdfc/src/backend/parser/parse_coerce.c#L3205-L3223
1223    let from_category = TypeCategory::from_type(&from);
1224    let to_category = TypeCategory::from_type(to);
1225    if from_category == TypeCategory::String && to_category != TypeCategory::String {
1226        // Converting from stringlike to something non-stringlike. Handle as if
1227        // `from` were a `ScalarType::String.
1228        cast_inner(&ScalarType::String, to, expr)
1229    } else if from_category != TypeCategory::String && to_category == TypeCategory::String {
1230        // Converting from non-stringlike to something stringlike. Convert to a
1231        // `ScalarType::String` and then to the desired type.
1232        let expr = cast_inner(&from, &ScalarType::String, expr)?;
1233        cast_inner(&ScalarType::String, to, expr)
1234    } else {
1235        // Standard cast.
1236        cast_inner(&from, to, expr)
1237    }
1238}
1239
1240/// Reports whether it is possible to perform a cast from the specified types.
1241pub fn can_cast(
1242    ecx: &ExprContext,
1243    ccx: CastContext,
1244    cast_from: &ScalarType,
1245    cast_to: &ScalarType,
1246) -> bool {
1247    get_cast(ecx, ccx, cast_from, cast_to).is_some()
1248}