1use std::cell::RefCell;
14use std::collections::BTreeMap;
15use std::sync::LazyLock;
16
17use dynfmt::{Format, SimpleCurlyFormat};
18use itertools::Itertools;
19use mz_expr::func;
20use mz_expr::func::variadic::{JsonbBuildObject, RecordCreate};
21use mz_expr::func::{CastArrayToJsonb, CastListToJsonb};
22use mz_repr::{
23 ColumnName, Datum, SqlColumnType, SqlRelationType, SqlScalarBaseType, SqlScalarType,
24};
25
26use crate::catalog::TypeCategory;
27use crate::plan::error::PlanError;
28use crate::plan::hir::{
29 AbstractColumnType, CoercibleScalarExpr, CoercibleScalarType, HirScalarExpr, UnaryFunc,
30};
31use crate::plan::query::{ExprContext, QueryContext};
32use crate::plan::scope::Scope;
33
34fn sql_impl_cast(expr: &'static str) -> CastTemplate {
36 let invoke = crate::func::sql_impl(expr);
37 CastTemplate::new(move |ecx, _ccx, from_type, _to_type| {
38 let mut out = invoke(ecx, vec![from_type.clone()]).ok()?;
40 Some(move |e| {
41 out.splice_parameters(&[e], 0);
42 out
43 })
44 })
45}
46
47fn sql_impl_cast_per_context(casts: &[(CastContext, &'static str)]) -> CastTemplate {
48 let casts: BTreeMap<CastContext, _> = casts
49 .iter()
50 .map(|(ccx, expr)| (ccx.clone(), crate::func::sql_impl(expr)))
51 .collect();
52 CastTemplate::new(move |ecx, ccx, from_type, _to_type| {
53 let invoke = &casts[&ccx];
54 let r = invoke(ecx, vec![from_type.clone()]);
55 let mut out = r.ok()?;
56 Some(move |e| {
57 out.splice_parameters(&[e], 0);
58 out
59 })
60 })
61}
62
63type Cast = Box<dyn FnOnce(HirScalarExpr) -> HirScalarExpr>;
65
66struct CastTemplate(
76 Box<
77 dyn Fn(&ExprContext, CastContext, &SqlScalarType, &SqlScalarType) -> Option<Cast>
78 + Send
79 + Sync,
80 >,
81);
82
83impl CastTemplate {
84 fn new<T, C>(t: T) -> CastTemplate
85 where
86 T: Fn(&ExprContext, CastContext, &SqlScalarType, &SqlScalarType) -> Option<C>
87 + Send
88 + Sync
89 + 'static,
90 C: FnOnce(HirScalarExpr) -> HirScalarExpr + 'static,
91 {
92 CastTemplate(Box::new(move |ecx, ccx, from_ty, to_ty| {
93 Some(Box::new(t(ecx, ccx, from_ty, to_ty)?))
94 }))
95 }
96}
97
98impl From<UnaryFunc> for CastTemplate {
99 fn from(u: UnaryFunc) -> CastTemplate {
100 CastTemplate::new(move |_ecx, _ccx, _from, _to| {
101 let u = u.clone();
102 Some(move |expr: HirScalarExpr| expr.call_unary(u))
103 })
104 }
105}
106
107impl<const N: usize> From<[UnaryFunc; N]> for CastTemplate {
108 fn from(funcs: [UnaryFunc; N]) -> CastTemplate {
109 CastTemplate::new(move |_ecx, _ccx, _from, _to| {
110 let funcs = funcs.clone();
111 Some(move |mut expr: HirScalarExpr| {
112 for func in funcs {
113 expr = expr.call_unary(func.clone());
114 }
115 expr
116 })
117 })
118 }
119}
120
121const STRING_REG_CAST_TEMPLATE: &str = "
140(SELECT
141CASE
142 WHEN $1 IS NULL THEN NULL
143-- Handle the absent reference, which the reg* text output spells `-`. PostgreSQL's
144-- `parseDashOrOid` accepts it for every reg* type, including text to regclass.
145 WHEN $1 = '-' THEN 0::pg_catalog.oid::pg_catalog.{0}
146-- Handle OID-like input, if available via {2}
147 WHEN {2} AND pg_catalog.substring($1, 1, 1) BETWEEN '0' AND '9' THEN
148 $1::pg_catalog.oid::pg_catalog.{0}
149 ELSE (
150 -- String case; look up that the item exists
151 SELECT o.oid
152 FROM mz_unsafe.mz_error_if_null(
153 (
154 -- We need to ensure a distinct here in the case of e.g. functions,
155 -- where multiple items share a GlobalId.
156 SELECT DISTINCT id AS name_id
157 FROM mz_internal.mz_resolve_object_name('{0}', $1)
158 ),
159 -- TODO: Support the correct error code for does not exist (42883).
160 '{1} \"' || $1 || '\" does not exist'
161 ) AS i (name_id),
162 -- Lateral lets us error separately from DNE case
163 LATERAL (
164 SELECT
165 CASE
166 -- Handle too many OIDs
167 WHEN mz_catalog.list_length(mz_catalog.list_agg(oid)) > 1 THEN
168 mz_unsafe.mz_error_if_null(
169 NULL::pg_catalog.{0},
170 'more than one {1} named \"' || $1 || '\"'
171 )
172 -- Resolve object name's OID if we know there is only one
173 ELSE
174 CAST(mz_catalog.list_agg(oid)[1] AS pg_catalog.{0})
175 END
176 FROM mz_catalog.mz_objects
177 WHERE id = name_id
178 GROUP BY id
179 ) AS o (oid)
180 )
181END)";
182
183static STRING_TO_REGCLASS_EXPLICIT: LazyLock<String> = LazyLock::new(|| {
184 SimpleCurlyFormat
185 .format(STRING_REG_CAST_TEMPLATE, ["regclass", "relation", "false"])
186 .unwrap()
187 .to_string()
188});
189
190static STRING_TO_REGCLASS_COERCED: LazyLock<String> = LazyLock::new(|| {
191 SimpleCurlyFormat
192 .format(STRING_REG_CAST_TEMPLATE, ["regclass", "relation", "true"])
193 .unwrap()
194 .to_string()
195});
196
197static STRING_TO_REGPROC: LazyLock<String> = LazyLock::new(|| {
198 SimpleCurlyFormat
199 .format(STRING_REG_CAST_TEMPLATE, ["regproc", "function", "true"])
200 .unwrap()
201 .to_string()
202});
203
204static STRING_TO_REGTYPE: LazyLock<String> = LazyLock::new(|| {
205 SimpleCurlyFormat
206 .format(STRING_REG_CAST_TEMPLATE, ["regtype", "type", "true"])
207 .unwrap()
208 .to_string()
209});
210
211const REG_STRING_CAST_TEMPLATE: &str = "(
215SELECT
216 CASE
217 WHEN CAST($1 AS pg_catalog.oid) = 0::pg_catalog.oid THEN '-'
218 ELSE
219 COALESCE(mz_internal.mz_global_id_to_name(o.id), CAST($1 AS pg_catalog.oid)::pg_catalog.text)
220 END
221 AS text
222FROM
223 (
224 SELECT
225 (
226 SELECT DISTINCT id
227 FROM
228 mz_catalog.mz_objects AS o
229 JOIN
230 mz_internal.mz_object_oid_alias AS a
231 ON o.type = a.object_type
232 WHERE
233 oid = CAST($1 AS pg_catalog.oid)
234 AND
235 a.oid_alias = '{0}'
236 )
237 )
238 AS o
239)";
240
241static REGCLASS_TO_STRING: LazyLock<String> = LazyLock::new(|| {
242 SimpleCurlyFormat
243 .format(REG_STRING_CAST_TEMPLATE, ["regclass"])
244 .unwrap()
245 .to_string()
246});
247
248static REGPROC_TO_STRING: LazyLock<String> = LazyLock::new(|| {
249 SimpleCurlyFormat
250 .format(REG_STRING_CAST_TEMPLATE, ["regproc"])
251 .unwrap()
252 .to_string()
253});
254
255static REGTYPE_TO_STRING: LazyLock<String> = LazyLock::new(|| {
256 SimpleCurlyFormat
257 .format(REG_STRING_CAST_TEMPLATE, ["regtype"])
258 .unwrap()
259 .to_string()
260});
261
262#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
268pub enum CastContext {
269 Implicit,
273 Assignment,
277 Explicit,
281 Coerced,
287}
288
289struct CastImpl {
291 template: CastTemplate,
292 context: CastContext,
293}
294
295macro_rules! casts(
296 {
297 $(
298 $from_to:expr => $cast_context:ident: $cast_template:expr
299 ),+
300 } => {{
301 let mut m = BTreeMap::new();
302 $(
303 m.insert($from_to, CastImpl {
304 template: $cast_template.into(),
305 context: CastContext::$cast_context,
306 });
307 )+
308 m
309 }};
310);
311
312static VALID_CASTS: LazyLock<BTreeMap<(SqlScalarBaseType, SqlScalarBaseType), CastImpl>> =
313 LazyLock::new(|| {
314 use SqlScalarBaseType::*;
315 use UnaryFunc::*;
316
317 casts! {
318 (Bool, Int32) => Explicit: CastBoolToInt32(func::CastBoolToInt32),
320 (Bool, Int64) => Explicit: CastBoolToInt64(func::CastBoolToInt64),
321 (Bool, String) => Assignment: CastBoolToString(func::CastBoolToString),
322
323 (Int16, Int32) => Implicit: CastInt16ToInt32(func::CastInt16ToInt32),
325 (Int16, Int64) => Implicit: CastInt16ToInt64(func::CastInt16ToInt64),
326 (Int16, UInt16) => Assignment: CastInt16ToUint16(func::CastInt16ToUint16),
327 (Int16, UInt32) => Assignment: CastInt16ToUint32(func::CastInt16ToUint32),
328 (Int16, UInt64) => Assignment: CastInt16ToUint64(func::CastInt16ToUint64),
329 (Int16, Float32) => Implicit: CastInt16ToFloat32(func::CastInt16ToFloat32),
330 (Int16, Float64) => Implicit: CastInt16ToFloat64(func::CastInt16ToFloat64),
331 (Int16, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
332 let s = to_type.unwrap_numeric_max_scale();
333 let f = CastInt16ToNumeric(func::CastInt16ToNumeric(s));
334 Some(move |e: HirScalarExpr| e.call_unary(f))
335 }),
336 (Int16, Oid) => Implicit: [
337 CastInt16ToInt32(func::CastInt16ToInt32),
338 CastInt32ToOid(func::CastInt32ToOid),
339 ],
340 (Int16, RegClass) => Implicit: [
341 CastInt16ToInt32(func::CastInt16ToInt32),
342 CastInt32ToOid(func::CastInt32ToOid),
343 CastOidToRegClass(func::CastOidToRegClass),
344 ],
345 (Int16, RegProc) => Implicit: [
346 CastInt16ToInt32(func::CastInt16ToInt32),
347 CastInt32ToOid(func::CastInt32ToOid),
348 CastOidToRegProc(func::CastOidToRegProc),
349 ],
350 (Int16, RegType) => Implicit: [
351 CastInt16ToInt32(func::CastInt16ToInt32),
352 CastInt32ToOid(func::CastInt32ToOid),
353 CastOidToRegType(func::CastOidToRegType),
354 ],
355 (Int16, String) => Assignment: CastInt16ToString(func::CastInt16ToString),
356
357 (Int32, Bool) => Explicit: CastInt32ToBool(func::CastInt32ToBool),
359 (Int32, Oid) => Implicit: CastInt32ToOid(func::CastInt32ToOid),
360 (Int32, RegClass) => Implicit: [
361 CastInt32ToOid(func::CastInt32ToOid),
362 CastOidToRegClass(func::CastOidToRegClass),
363 ],
364 (Int32, RegProc) => Implicit: [
365 CastInt32ToOid(func::CastInt32ToOid),
366 CastOidToRegProc(func::CastOidToRegProc),
367 ],
368 (Int32, RegType) => Implicit: [
369 CastInt32ToOid(func::CastInt32ToOid),
370 CastOidToRegType(func::CastOidToRegType),
371 ],
372 (Int32, PgLegacyChar) => Explicit:
373 CastInt32ToPgLegacyChar(func::CastInt32ToPgLegacyChar),
374 (Int32, Int16) => Assignment: CastInt32ToInt16(func::CastInt32ToInt16),
375 (Int32, Int64) => Implicit: CastInt32ToInt64(func::CastInt32ToInt64),
376 (Int32, UInt16) => Assignment: CastInt32ToUint16(func::CastInt32ToUint16),
377 (Int32, UInt32) => Assignment: CastInt32ToUint32(func::CastInt32ToUint32),
378 (Int32, UInt64) => Assignment: CastInt32ToUint64(func::CastInt32ToUint64),
379 (Int32, Float32) => Implicit: CastInt32ToFloat32(func::CastInt32ToFloat32),
380 (Int32, Float64) => Implicit: CastInt32ToFloat64(func::CastInt32ToFloat64),
381 (Int32, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
382 let s = to_type.unwrap_numeric_max_scale();
383 let f = CastInt32ToNumeric(func::CastInt32ToNumeric(s));
384 Some(move |e: HirScalarExpr| e.call_unary(f))
385 }),
386 (Int32, String) => Assignment: CastInt32ToString(func::CastInt32ToString),
387
388 (Int64, Bool) => Explicit: CastInt64ToBool(func::CastInt64ToBool),
390 (Int64, Int16) => Assignment: CastInt64ToInt16(func::CastInt64ToInt16),
391 (Int64, Int32) => Assignment: CastInt64ToInt32(func::CastInt64ToInt32),
392 (Int64, UInt16) => Assignment: CastInt64ToUint16(func::CastInt64ToUint16),
393 (Int64, UInt32) => Assignment: CastInt64ToUint32(func::CastInt64ToUint32),
394 (Int64, UInt64) => Assignment: CastInt64ToUint64(func::CastInt64ToUint64),
395 (Int64, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
396 let s = to_type.unwrap_numeric_max_scale();
397 let f = CastInt64ToNumeric(func::CastInt64ToNumeric(s));
398 Some(move |e: HirScalarExpr| e.call_unary(f))
399 }),
400 (Int64, Float32) => Implicit: CastInt64ToFloat32(func::CastInt64ToFloat32),
401 (Int64, Float64) => Implicit: CastInt64ToFloat64(func::CastInt64ToFloat64),
402 (Int64, Oid) => Implicit: CastInt64ToOid(func::CastInt64ToOid),
403 (Int64, RegClass) => Implicit: [
404 CastInt64ToOid(func::CastInt64ToOid),
405 CastOidToRegClass(func::CastOidToRegClass),
406 ],
407 (Int64, RegProc) => Implicit: [
408 CastInt64ToOid(func::CastInt64ToOid),
409 CastOidToRegProc(func::CastOidToRegProc),
410 ],
411 (Int64, RegType) => Implicit: [
412 CastInt64ToOid(func::CastInt64ToOid),
413 CastOidToRegType(func::CastOidToRegType),
414 ],
415 (Int64, String) => Assignment: CastInt64ToString(func::CastInt64ToString),
416
417 (UInt16, UInt32) => Implicit: CastUint16ToUint32(func::CastUint16ToUint32),
419 (UInt16, UInt64) => Implicit: CastUint16ToUint64(func::CastUint16ToUint64),
420 (UInt16, Int16) => Assignment: CastUint16ToInt16(func::CastUint16ToInt16),
421 (UInt16, Int32) => Implicit: CastUint16ToInt32(func::CastUint16ToInt32),
422 (UInt16, Int64) => Implicit: CastUint16ToInt64(func::CastUint16ToInt64),
423 (UInt16, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
424 let s = to_type.unwrap_numeric_max_scale();
425 let f = CastUint16ToNumeric(func::CastUint16ToNumeric(s));
426 Some(move |e: HirScalarExpr| e.call_unary(f))
427 }),
428 (UInt16, Float32) => Implicit: CastUint16ToFloat32(func::CastUint16ToFloat32),
429 (UInt16, Float64) => Implicit: CastUint16ToFloat64(func::CastUint16ToFloat64),
430 (UInt16, String) => Assignment: CastUint16ToString(func::CastUint16ToString),
431
432 (UInt32, UInt16) => Assignment: CastUint32ToUint16(func::CastUint32ToUint16),
434 (UInt32, UInt64) => Implicit: CastUint32ToUint64(func::CastUint32ToUint64),
435 (UInt32, Int16) => Assignment: CastUint32ToInt16(func::CastUint32ToInt16),
436 (UInt32, Int32) => Assignment: CastUint32ToInt32(func::CastUint32ToInt32),
437 (UInt32, Int64) => Implicit: CastUint32ToInt64(func::CastUint32ToInt64),
438 (UInt32, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
439 let s = to_type.unwrap_numeric_max_scale();
440 let f = CastUint32ToNumeric(func::CastUint32ToNumeric(s));
441 Some(move |e: HirScalarExpr| e.call_unary(f))
442 }),
443 (UInt32, Float32) => Implicit: CastUint32ToFloat32(func::CastUint32ToFloat32),
444 (UInt32, Float64) => Implicit: CastUint32ToFloat64(func::CastUint32ToFloat64),
445 (UInt32, String) => Assignment: CastUint32ToString(func::CastUint32ToString),
446
447 (UInt64, UInt16) => Assignment: CastUint64ToUint16(func::CastUint64ToUint16),
449 (UInt64, UInt32) => Assignment: CastUint64ToUint32(func::CastUint64ToUint32),
450 (UInt64, Int16) => Assignment: CastUint64ToInt16(func::CastUint64ToInt16),
451 (UInt64, Int32) => Assignment: CastUint64ToInt32(func::CastUint64ToInt32),
452 (UInt64, Int64) => Assignment: CastUint64ToInt64(func::CastUint64ToInt64),
453 (UInt64, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
454 let s = to_type.unwrap_numeric_max_scale();
455 let f = CastUint64ToNumeric(func::CastUint64ToNumeric(s));
456 Some(move |e: HirScalarExpr| e.call_unary(f))
457 }),
458 (UInt64, Float32) => Implicit: CastUint64ToFloat32(func::CastUint64ToFloat32),
459 (UInt64, Float64) => Implicit: CastUint64ToFloat64(func::CastUint64ToFloat64),
460 (UInt64, String) => Assignment: CastUint64ToString(func::CastUint64ToString),
461
462 (MzTimestamp, String) => Assignment:
464 CastMzTimestampToString(func::CastMzTimestampToString),
465 (MzTimestamp, Timestamp) => Assignment:
466 CastMzTimestampToTimestamp(func::CastMzTimestampToTimestamp),
467 (MzTimestamp, TimestampTz) => Assignment:
468 CastMzTimestampToTimestampTz(
469 func::CastMzTimestampToTimestampTz,
470 ),
471 (String, MzTimestamp) => Assignment:
472 CastStringToMzTimestamp(func::CastStringToMzTimestamp),
473 (UInt64, MzTimestamp) => Implicit:
474 CastUint64ToMzTimestamp(func::CastUint64ToMzTimestamp),
475 (UInt32, MzTimestamp) => Implicit:
476 CastUint32ToMzTimestamp(func::CastUint32ToMzTimestamp),
477 (Int64, MzTimestamp) => Implicit:
478 CastInt64ToMzTimestamp(func::CastInt64ToMzTimestamp),
479 (Int32, MzTimestamp) => Implicit:
480 CastInt32ToMzTimestamp(func::CastInt32ToMzTimestamp),
481 (Numeric, MzTimestamp) => Implicit:
482 CastNumericToMzTimestamp(func::CastNumericToMzTimestamp),
483 (Timestamp, MzTimestamp) => Implicit:
484 CastTimestampToMzTimestamp(func::CastTimestampToMzTimestamp),
485 (TimestampTz, MzTimestamp) => Implicit:
486 CastTimestampTzToMzTimestamp(
487 func::CastTimestampTzToMzTimestamp,
488 ),
489 (Date, MzTimestamp) => Implicit:
490 CastDateToMzTimestamp(func::CastDateToMzTimestamp),
491
492 (Oid, Int32) => Assignment: CastOidToInt32(func::CastOidToInt32),
494 (Oid, Int64) => Assignment: CastOidToInt64(func::CastOidToInt64),
495 (Oid, String) => Explicit: CastOidToString(func::CastOidToString),
496 (Oid, RegClass) => Implicit: CastOidToRegClass(func::CastOidToRegClass),
497 (Oid, RegProc) => Implicit: CastOidToRegProc(func::CastOidToRegProc),
498 (Oid, RegType) => Implicit: CastOidToRegType(func::CastOidToRegType),
499
500 (RegClass, Oid) => Implicit: CastRegClassToOid(func::CastRegClassToOid),
502 (RegClass, String) => Explicit: sql_impl_cast(®CLASS_TO_STRING),
503
504 (RegProc, Oid) => Implicit: CastRegProcToOid(func::CastRegProcToOid),
506 (RegProc, String) => Explicit: sql_impl_cast(®PROC_TO_STRING),
507
508 (RegType, Oid) => Implicit: CastRegTypeToOid(func::CastRegTypeToOid),
510 (RegType, String) => Explicit: sql_impl_cast(®TYPE_TO_STRING),
511
512 (Float32, Int16) => Assignment: CastFloat32ToInt16(func::CastFloat32ToInt16),
514 (Float32, Int32) => Assignment: CastFloat32ToInt32(func::CastFloat32ToInt32),
515 (Float32, Int64) => Assignment: CastFloat32ToInt64(func::CastFloat32ToInt64),
516 (Float32, UInt16) => Assignment: CastFloat32ToUint16(func::CastFloat32ToUint16),
517 (Float32, UInt32) => Assignment: CastFloat32ToUint32(func::CastFloat32ToUint32),
518 (Float32, UInt64) => Assignment: CastFloat32ToUint64(func::CastFloat32ToUint64),
519 (Float32, Float64) => Implicit: CastFloat32ToFloat64(func::CastFloat32ToFloat64),
520 (Float32, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
521 let s = to_type.unwrap_numeric_max_scale();
522 let f = CastFloat32ToNumeric(func::CastFloat32ToNumeric(s));
523 Some(move |e: HirScalarExpr| e.call_unary(f))
524 }),
525 (Float32, String) => Assignment: CastFloat32ToString(func::CastFloat32ToString),
526
527 (Float64, Int16) => Assignment: CastFloat64ToInt16(func::CastFloat64ToInt16),
529 (Float64, Int32) => Assignment: CastFloat64ToInt32(func::CastFloat64ToInt32),
530 (Float64, Int64) => Assignment: CastFloat64ToInt64(func::CastFloat64ToInt64),
531 (Float64, UInt16) => Assignment: CastFloat64ToUint16(func::CastFloat64ToUint16),
532 (Float64, UInt32) => Assignment: CastFloat64ToUint32(func::CastFloat64ToUint32),
533 (Float64, UInt64) => Assignment: CastFloat64ToUint64(func::CastFloat64ToUint64),
534 (Float64, Float32) => Assignment: CastFloat64ToFloat32(func::CastFloat64ToFloat32),
535 (Float64, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
536 let s = to_type.unwrap_numeric_max_scale();
537 let f = CastFloat64ToNumeric(func::CastFloat64ToNumeric(s));
538 Some(move |e: HirScalarExpr| e.call_unary(f))
539 }),
540 (Float64, String) => Assignment: CastFloat64ToString(func::CastFloat64ToString),
541
542 (Date, Timestamp) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
544 let p = to_type.unwrap_timestamp_precision();
545 let f = CastDateToTimestamp(func::CastDateToTimestamp(p));
546 Some(move |e: HirScalarExpr| e.call_unary(f))
547 }),
548 (Date, TimestampTz) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
549 let p = to_type.unwrap_timestamp_precision();
550 let f = CastDateToTimestampTz(func::CastDateToTimestampTz(p));
551 Some(move |e: HirScalarExpr| e.call_unary(f))
552 }),
553 (Date, String) => Assignment: CastDateToString(func::CastDateToString),
554
555 (Time, Interval) => Implicit: CastTimeToInterval(func::CastTimeToInterval),
557 (Time, String) => Assignment: CastTimeToString(func::CastTimeToString),
558
559 (Timestamp, Date) => Assignment: CastTimestampToDate(func::CastTimestampToDate),
561 (Timestamp, TimestampTz) => Implicit: CastTemplate::new(
562 |_ecx, _ccx, from_type, to_type|
563 {
564 let from = from_type.unwrap_timestamp_precision();
565 let to = to_type.unwrap_timestamp_precision();
566 let f = CastTimestampToTimestampTz(
567 func::CastTimestampToTimestampTz { from, to },
568 );
569 Some(move |e: HirScalarExpr| e.call_unary(f))
570 }),
571 (Timestamp, Timestamp) => Assignment: CastTemplate::new(
572 |_ecx, _ccx, from_type, to_type|
573 {
574 let from = from_type.unwrap_timestamp_precision();
575 let to = to_type.unwrap_timestamp_precision();
576 let f = AdjustTimestampPrecision(
577 func::AdjustTimestampPrecision { from, to },
578 );
579 Some(move |e: HirScalarExpr| e.call_unary(f))
580 }),
581 (Timestamp, Time) => Assignment: CastTimestampToTime(func::CastTimestampToTime),
582 (Timestamp, String) => Assignment: CastTimestampToString(func::CastTimestampToString),
583
584 (TimestampTz, Date) => Assignment: CastTimestampTzToDate(func::CastTimestampTzToDate),
586 (TimestampTz, Timestamp) => Assignment: CastTemplate::new(
587 |_ecx, _ccx, from_type, to_type|
588 {
589 let from = from_type.unwrap_timestamp_precision();
590 let to = to_type.unwrap_timestamp_precision();
591 let f = CastTimestampTzToTimestamp(
592 func::CastTimestampTzToTimestamp { from, to },
593 );
594 Some(move |e: HirScalarExpr| e.call_unary(f))
595 }),
596 (TimestampTz, TimestampTz) => Assignment: CastTemplate::new(
597 |_ecx, _ccx, from_type, to_type|
598 {
599 let from = from_type.unwrap_timestamp_precision();
600 let to = to_type.unwrap_timestamp_precision();
601 let f = AdjustTimestampTzPrecision(
602 func::AdjustTimestampTzPrecision { from, to },
603 );
604 Some(move |e: HirScalarExpr| e.call_unary(f))
605 }),
606 (TimestampTz, Time) => Assignment:
607 CastTimestampTzToTime(func::CastTimestampTzToTime),
608 (TimestampTz, String) => Assignment:
609 CastTimestampTzToString(func::CastTimestampTzToString),
610
611 (Interval, Time) => Assignment: CastIntervalToTime(func::CastIntervalToTime),
613 (Interval, String) => Assignment: CastIntervalToString(func::CastIntervalToString),
614
615 (Bytes, String) => Assignment: CastBytesToString(func::CastBytesToString),
617
618 (String, Bool) => Explicit: CastStringToBool(func::CastStringToBool),
620 (String, Int16) => Explicit: CastStringToInt16(func::CastStringToInt16),
621 (String, Int32) => Explicit: CastStringToInt32(func::CastStringToInt32),
622 (String, Int64) => Explicit: CastStringToInt64(func::CastStringToInt64),
623 (String, UInt16) => Explicit: CastStringToUint16(func::CastStringToUint16),
624 (String, UInt32) => Explicit: CastStringToUint32(func::CastStringToUint32),
625 (String, UInt64) => Explicit: CastStringToUint64(func::CastStringToUint64),
626 (String, Oid) => Explicit: CastStringToOid(func::CastStringToOid),
627
628 (String, RegClass) => Explicit: sql_impl_cast_per_context(
637 &[
638 (CastContext::Explicit, &STRING_TO_REGCLASS_EXPLICIT),
639 (CastContext::Coerced, &STRING_TO_REGCLASS_COERCED)
640 ]
641 ),
642 (String, RegProc) => Explicit: sql_impl_cast(&STRING_TO_REGPROC),
643 (String, RegType) => Explicit: sql_impl_cast(&STRING_TO_REGTYPE),
644
645 (String, Float32) => Explicit: CastStringToFloat32(func::CastStringToFloat32),
646 (String, Float64) => Explicit: CastStringToFloat64(func::CastStringToFloat64),
647 (String, Numeric) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
648 let s = to_type.unwrap_numeric_max_scale();
649 let f = CastStringToNumeric(func::CastStringToNumeric(s));
650 Some(move |e: HirScalarExpr| e.call_unary(f))
651 }),
652 (String, Date) => Explicit: CastStringToDate(func::CastStringToDate),
653 (String, Time) => Explicit: CastStringToTime(func::CastStringToTime),
654 (String, Timestamp) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
655 let p = to_type.unwrap_timestamp_precision();
656 let f = CastStringToTimestamp(func::CastStringToTimestamp(p));
657 Some(move |e: HirScalarExpr| e.call_unary(f))
658 }),
659 (String, TimestampTz) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
660 let p = to_type.unwrap_timestamp_precision();
661 let f = CastStringToTimestampTz(
662 func::CastStringToTimestampTz(p),
663 );
664 Some(move |e: HirScalarExpr| e.call_unary(f))
665 }),
666 (String, Interval) => Explicit: CastStringToInterval(func::CastStringToInterval),
667 (String, Bytes) => Explicit: CastStringToBytes(func::CastStringToBytes),
668 (String, Jsonb) => Explicit: CastStringToJsonb(func::CastStringToJsonb),
669 (String, Uuid) => Explicit: CastStringToUuid(func::CastStringToUuid),
670 (String, Array) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
671 let return_ty = to_type.clone();
672 let to_el_type = to_type.unwrap_array_element_type();
673 let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_el_type)?;
674 Some(|e: HirScalarExpr| {
675 e.call_unary(UnaryFunc::CastStringToArray(
676 func::CastStringToArray {
677 return_ty,
678 cast_expr: Box::new(cast_expr),
679 },
680 ))
681 })
682 }),
683 (String, List) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
684 let return_ty = to_type.clone();
685 let to_el_type = to_type.unwrap_list_element_type();
686 let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_el_type)?;
687 Some(|e: HirScalarExpr| {
688 e.call_unary(UnaryFunc::CastStringToList(
689 func::CastStringToList {
690 return_ty,
691 cast_expr: Box::new(cast_expr),
692 },
693 ))
694 })
695 }),
696 (String, Map) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
697 let return_ty = to_type.clone();
698 let to_val_type = to_type.unwrap_map_value_type();
699 let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_val_type)?;
700 Some(|e: HirScalarExpr| {
701 e.call_unary(UnaryFunc::CastStringToMap(
702 func::CastStringToMap {
703 return_ty,
704 cast_expr: Box::new(cast_expr),
705 },
706 ))
707 })
708 }),
709 (String, Range) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
710 let return_ty = to_type.clone();
711 let to_el_type = to_type.unwrap_range_element_type();
712 let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_el_type)?;
713 Some(|e: HirScalarExpr| {
714 e.call_unary(UnaryFunc::CastStringToRange(
715 func::CastStringToRange {
716 return_ty,
717 cast_expr: Box::new(cast_expr),
718 },
719 ))
720 })
721 }),
722 (String, Int2Vector) => Explicit: CastStringToInt2Vector(func::CastStringToInt2Vector),
723 (String, Char) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
724 let length = to_type.unwrap_char_length();
725 let fail_on_len = ccx != CastContext::Explicit;
726 let f = CastStringToChar(func::CastStringToChar {
727 length, fail_on_len,
728 });
729 Some(move |e: HirScalarExpr| e.call_unary(f))
730 }),
731 (String, VarChar) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
732 let length = to_type.unwrap_varchar_max_length();
733 let fail_on_len = ccx != CastContext::Explicit;
734 let f = CastStringToVarChar(func::CastStringToVarChar {
735 length, fail_on_len,
736 });
737 Some(move |e: HirScalarExpr| e.call_unary(f))
738 }),
739 (String, PgLegacyChar) => Assignment:
740 CastStringToPgLegacyChar(func::CastStringToPgLegacyChar),
741 (Char, String) => Implicit: CastCharToString(func::CastCharToString),
743 (Char, Char) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
744 let length = to_type.unwrap_char_length();
745 let fail_on_len = ccx != CastContext::Explicit;
746 let f = CastStringToChar(func::CastStringToChar {
747 length, fail_on_len,
748 });
749 Some(move |e: HirScalarExpr| e.call_unary(f))
750 }),
751 (Char, VarChar) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
752 let length = to_type.unwrap_varchar_max_length();
753 let fail_on_len = ccx != CastContext::Explicit;
754 let f = CastStringToVarChar(func::CastStringToVarChar {
755 length, fail_on_len,
756 });
757 Some(move |e: HirScalarExpr| e.call_unary(f))
758 }),
759 (Char, PgLegacyChar) => Assignment:
760 CastStringToPgLegacyChar(func::CastStringToPgLegacyChar),
761
762 (VarChar, String) => Implicit: CastVarCharToString(func::CastVarCharToString),
764 (VarChar, Char) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
765 let length = to_type.unwrap_char_length();
766 let fail_on_len = ccx != CastContext::Explicit;
767 let f = CastStringToChar(func::CastStringToChar {
768 length, fail_on_len,
769 });
770 Some(move |e: HirScalarExpr| e.call_unary(f))
771 }),
772 (VarChar, VarChar) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
773 let length = to_type.unwrap_varchar_max_length();
774 let fail_on_len = ccx != CastContext::Explicit;
775 let f = CastStringToVarChar(func::CastStringToVarChar {
776 length, fail_on_len,
777 });
778 Some(move |e: HirScalarExpr| e.call_unary(f))
779 }),
780 (VarChar, PgLegacyChar) => Assignment:
781 CastStringToPgLegacyChar(func::CastStringToPgLegacyChar),
782
783 (PgLegacyChar, String) => Implicit:
785 CastPgLegacyCharToString(func::CastPgLegacyCharToString),
786 (PgLegacyChar, Char) => Assignment:
787 CastPgLegacyCharToChar(func::CastPgLegacyCharToChar),
788 (PgLegacyChar, VarChar) => Assignment:
789 CastPgLegacyCharToVarChar(func::CastPgLegacyCharToVarChar),
790 (PgLegacyChar, Int32) => Explicit:
791 CastPgLegacyCharToInt32(func::CastPgLegacyCharToInt32),
792
793 (PgLegacyName, String) => Implicit: CastVarCharToString(func::CastVarCharToString),
798 (PgLegacyName, Char) => Assignment: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
799 let length = to_type.unwrap_char_length();
800 let fail_on_len = ccx != CastContext::Explicit;
801 let f = CastStringToChar(func::CastStringToChar {
802 length, fail_on_len,
803 });
804 Some(move |e: HirScalarExpr| e.call_unary(f))
805 }),
806 (PgLegacyName, VarChar) => Assignment: CastTemplate::new(
807 |_ecx, ccx, _from_type, to_type|
808 {
809 let length = to_type.unwrap_varchar_max_length();
810 let fail_on_len = ccx != CastContext::Explicit;
811 let f = CastStringToVarChar(func::CastStringToVarChar {
812 length, fail_on_len,
813 });
814 Some(move |e: HirScalarExpr| e.call_unary(f))
815 }),
816 (String, PgLegacyName) => Implicit:
817 CastStringToPgLegacyName(func::CastStringToPgLegacyName),
818 (Char, PgLegacyName) => Implicit:
819 CastStringToPgLegacyName(func::CastStringToPgLegacyName),
820 (VarChar, PgLegacyName) => Implicit:
821 CastStringToPgLegacyName(func::CastStringToPgLegacyName),
822
823 (Record, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
825 let ty = from_type.clone();
826 Some(|e: HirScalarExpr| {
827 e.call_unary(CastRecordToString(
828 func::CastRecordToString { ty },
829 ))
830 })
831 }),
832 (Record, Record) => Implicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
833 let from_fields = from_type.unwrap_record_element_type();
834 let to_fields = to_type.unwrap_record_element_type();
835 if from_fields.len() != to_fields.len() {
836 return None;
837 }
838
839 if let (
840 l @ SqlScalarType::Record {
841 custom_id: Some(..), ..
842 },
843 r,
844 ) = (from_type, to_type)
845 {
846 if ccx == CastContext::Implicit && l != r {
849 return None;
850 }
851 }
852
853 let cast_exprs = from_fields
854 .iter()
855 .zip_eq(to_fields)
856 .map(|(f, t)| plan_hypothetical_cast(ecx, ccx, f, t))
857 .collect::<Option<Box<_>>>()?;
858 let to = to_type.clone();
859 Some(|e: HirScalarExpr| {
860 e.call_unary(CastRecord1ToRecord2(
861 func::CastRecord1ToRecord2 {
862 return_ty: to,
863 cast_exprs,
864 },
865 ))
866 })
867 }),
868
869 (Array, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
871 let ty = from_type.clone();
872 Some(|e: HirScalarExpr| {
873 e.call_unary(CastArrayToString(
874 func::CastArrayToString { ty },
875 ))
876 })
877 }),
878 (Array, List) => Explicit: CastArrayToListOneDim(func::CastArrayToListOneDim),
879 (Array, Array) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
880 let inner_from_type = from_type.unwrap_array_element_type();
881 let inner_to_type = to_type.unwrap_array_element_type();
882 let cast_expr = plan_hypothetical_cast(
883 ecx, ccx, inner_from_type, inner_to_type,
884 )?;
885 let return_ty = to_type.clone();
886
887 Some(move |e: HirScalarExpr| {
888 e.call_unary(CastArrayToArray(func::CastArrayToArray {
889 return_ty,
890 cast_expr: Box::new(cast_expr),
891 }))
892 })
893 }),
894
895 (Int2Vector, Array) => Implicit: CastTemplate::new(|ecx, ccx, _from_type, to_type| {
897 let inner_to_type = to_type.unwrap_array_element_type();
898 let element_cast = if inner_to_type != &SqlScalarType::Int16 {
902 let cast_expr = plan_hypothetical_cast(
903 ecx, ccx, &SqlScalarType::Int16, inner_to_type
904 )?;
905 Some((to_type.clone(), cast_expr))
906 } else {
907 None
908 };
909 Some(move |e: HirScalarExpr| {
910 let arr = e.call_unary(
911 UnaryFunc::CastInt2VectorToArray(func::CastInt2VectorToArray)
912 );
913 match element_cast {
914 Some((return_ty, cast_expr)) => {
915 arr.call_unary(CastArrayToArray(
916 func::CastArrayToArray { return_ty, cast_expr: Box::new(cast_expr) }
917 ))
918 }
919 None => arr,
920 }
921 })
922 }),
923 (Int2Vector, String) => Explicit: CastInt2VectorToString(func::CastInt2VectorToString),
924
925 (List, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
927 let ty = from_type.clone();
928 Some(|e: HirScalarExpr| {
929 e.call_unary(CastListToString(
930 func::CastListToString { ty },
931 ))
932 })
933 }),
934 (List, List) => Implicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
935
936 if let (
937 l @ SqlScalarType::List {
938 custom_id: Some(..), ..
939 },
940 r,
941 ) = (from_type, to_type)
942 {
943 if ccx == CastContext::Implicit && !l.base_eq(r) {
946 return None;
947 }
948 }
949
950 let return_ty = to_type.clone();
951 let from_el_type = from_type.unwrap_list_element_type();
952 let to_el_type = to_type.unwrap_list_element_type();
953 let cast_expr = plan_hypothetical_cast(
954 ecx, ccx, from_el_type, to_el_type,
955 )?;
956 Some(|e: HirScalarExpr| {
957 e.call_unary(UnaryFunc::CastList1ToList2(
958 func::CastList1ToList2 {
959 return_ty,
960 cast_expr: Box::new(cast_expr),
961 },
962 ))
963 })
964 }),
965
966 (Map, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
968 let ty = from_type.clone();
969 Some(|e: HirScalarExpr| e.call_unary(CastMapToString(func::CastMapToString { ty })))
970 }),
971
972 (Jsonb, Bool) => Explicit: CastJsonbToBool(func::CastJsonbToBool),
974 (Jsonb, Int16) => Explicit: CastJsonbToInt16(func::CastJsonbToInt16),
975 (Jsonb, Int32) => Explicit: CastJsonbToInt32(func::CastJsonbToInt32),
976 (Jsonb, Int64) => Explicit: CastJsonbToInt64(func::CastJsonbToInt64),
977 (Jsonb, Float32) => Explicit: CastJsonbToFloat32(func::CastJsonbToFloat32),
978 (Jsonb, Float64) => Explicit: CastJsonbToFloat64(func::CastJsonbToFloat64),
979 (Jsonb, Numeric) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
980 let s = to_type.unwrap_numeric_max_scale();
981 let f = CastJsonbToNumeric(func::CastJsonbToNumeric(s));
982 Some(move |e: HirScalarExpr| e.call_unary(f))
983 }),
984 (Jsonb, String) => Assignment: CastJsonbToString(func::CastJsonbToString),
985
986 (Uuid, String) => Assignment: CastUuidToString(func::CastUuidToString),
988
989 (Numeric, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
991 let scale = to_type.unwrap_numeric_max_scale();
992 Some(move |e: HirScalarExpr| match scale {
993 None => e,
994 Some(scale) => e.call_unary(
995 UnaryFunc::AdjustNumericScale(
996 func::AdjustNumericScale(scale),
997 ),
998 ),
999 })
1000 }),
1001 (Numeric, Float32) => Implicit: CastNumericToFloat32(func::CastNumericToFloat32),
1002 (Numeric, Float64) => Implicit: CastNumericToFloat64(func::CastNumericToFloat64),
1003 (Numeric, Int16) => Assignment: CastNumericToInt16(func::CastNumericToInt16),
1004 (Numeric, Int32) => Assignment: CastNumericToInt32(func::CastNumericToInt32),
1005 (Numeric, Int64) => Assignment: CastNumericToInt64(func::CastNumericToInt64),
1006 (Numeric, UInt16) => Assignment: CastNumericToUint16(func::CastNumericToUint16),
1007 (Numeric, UInt32) => Assignment: CastNumericToUint32(func::CastNumericToUint32),
1008 (Numeric, UInt64) => Assignment: CastNumericToUint64(func::CastNumericToUint64),
1009 (Numeric, String) => Assignment: CastNumericToString(func::CastNumericToString),
1010
1011 (Range, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
1013 let ty = from_type.clone();
1014 Some(|e: HirScalarExpr| {
1015 e.call_unary(CastRangeToString(
1016 func::CastRangeToString { ty },
1017 ))
1018 })
1019 }),
1020
1021 (MzAclItem, String) => Explicit: sql_impl_cast("(
1023 SELECT
1024 (CASE
1025 WHEN grantee_role_id = 'p' THEN ''
1026 ELSE COALESCE(grantee_role.name, grantee_role_id)
1027 END)
1028 || '='
1029 || mz_internal.mz_aclitem_privileges($1)
1030 || '/'
1031 || COALESCE(grantor_role.name, grantor_role_id)
1032 FROM
1033 (SELECT mz_internal.mz_aclitem_grantee($1) AS grantee_role_id),
1034 (SELECT mz_internal.mz_aclitem_grantor($1) AS grantor_role_id)
1035 LEFT JOIN mz_catalog.mz_roles AS grantee_role ON grantee_role_id = grantee_role.id
1036 LEFT JOIN mz_catalog.mz_roles AS grantor_role ON grantor_role_id = grantor_role.id
1037 )"),
1038 (MzAclItem, AclItem) => Explicit: sql_impl_cast("(
1039 SELECT makeaclitem(
1040 (CASE mz_internal.mz_aclitem_grantee($1)
1041 WHEN 'p' THEN 0
1042 ELSE (SELECT oid FROM mz_catalog.mz_roles
1043 WHERE id = mz_internal.mz_aclitem_grantee($1))
1044 END),
1045 (SELECT oid FROM mz_catalog.mz_roles
1046 WHERE id = mz_internal.mz_aclitem_grantor($1)),
1047 (SELECT array_to_string(
1048 mz_internal.mz_format_privileges(
1049 mz_internal.mz_aclitem_privileges($1)
1050 ), ',')),
1051 -- GRANT OPTION isn't implemented so we hardcode false.
1052 false
1053 )
1054 )"),
1055
1056 (AclItem, String) => Explicit: sql_impl_cast("(
1058 SELECT
1059 (CASE grantee_oid
1060 WHEN 0 THEN ''
1061 ELSE COALESCE(grantee_role.name, grantee_oid::text)
1062 END)
1063 || '='
1064 || mz_internal.aclitem_privileges($1)
1065 || '/'
1066 || COALESCE(grantor_role.name, grantor_oid::text)
1067 FROM
1068 (SELECT mz_internal.aclitem_grantee($1) AS grantee_oid),
1069 (SELECT mz_internal.aclitem_grantor($1) AS grantor_oid)
1070 LEFT JOIN mz_catalog.mz_roles AS grantee_role ON grantee_oid = grantee_role.oid
1071 LEFT JOIN mz_catalog.mz_roles AS grantor_role ON grantor_oid = grantor_role.oid
1072 )"),
1073 (AclItem, MzAclItem) => Explicit: sql_impl_cast("(
1074 SELECT mz_internal.make_mz_aclitem(
1075 (CASE mz_internal.aclitem_grantee($1)
1076 WHEN 0 THEN 'p'
1077 ELSE (SELECT id FROM mz_catalog.mz_roles
1078 WHERE oid = mz_internal.aclitem_grantee($1))
1079 END),
1080 (SELECT id FROM mz_catalog.mz_roles
1081 WHERE oid = mz_internal.aclitem_grantor($1)),
1082 (SELECT array_to_string(
1083 mz_internal.mz_format_privileges(
1084 mz_internal.aclitem_privileges($1)
1085 ), ','))
1086 )
1087 )")
1088 }
1089 });
1090
1091#[derive(Debug)]
1093pub enum CastError {
1094 InvalidCast {
1096 ccx: CastContext,
1097 from: String,
1098 to: String,
1099 },
1100 UnsupportedRangeElementType { element_type_name: String },
1102}
1103
1104impl CastError {
1105 pub fn into_plan_error(self, name: String) -> PlanError {
1107 match self {
1108 CastError::InvalidCast { ccx, from, to } => PlanError::InvalidCast {
1109 name,
1110 ccx,
1111 from,
1112 to,
1113 },
1114 CastError::UnsupportedRangeElementType { element_type_name } => {
1115 PlanError::UnsupportedRangeElementType { element_type_name }
1116 }
1117 }
1118 }
1119}
1120
1121fn get_cast(
1128 ecx: &ExprContext,
1129 ccx: CastContext,
1130 from: &SqlScalarType,
1131 to: &SqlScalarType,
1132) -> Result<Cast, CastError> {
1133 use CastContext::*;
1134
1135 if from == to || (ccx == Implicit && from.base_eq(to)) {
1136 return Ok(Box::new(|expr| expr));
1137 }
1138
1139 if let SqlScalarType::Range { element_type } = to {
1141 validate_range_element_type(ecx, element_type)?;
1142 }
1143
1144 let imp = match VALID_CASTS.get(&(from.into(), to.into())) {
1145 Some(imp) => imp,
1146 None => {
1147 return Err(CastError::InvalidCast {
1148 ccx,
1149 from: ecx.humanize_sql_scalar_type(from, false),
1150 to: ecx.humanize_sql_scalar_type(to, false),
1151 });
1152 }
1153 };
1154 let template = if ccx >= imp.context {
1155 Some(&imp.template)
1156 } else {
1157 None
1158 };
1159 match template.and_then(|template| (template.0)(ecx, ccx, from, to)) {
1160 Some(cast) => Ok(cast),
1161 None => Err(CastError::InvalidCast {
1162 ccx,
1163 from: ecx.humanize_sql_scalar_type(from, false),
1164 to: ecx.humanize_sql_scalar_type(to, false),
1165 }),
1166 }
1167}
1168
1169pub fn to_string(ecx: &ExprContext, expr: HirScalarExpr) -> Result<HirScalarExpr, PlanError> {
1177 plan_cast(ecx, CastContext::Explicit, expr, &SqlScalarType::String)
1178}
1179
1180pub fn to_jsonb(ecx: &ExprContext, expr: HirScalarExpr) -> Result<HirScalarExpr, PlanError> {
1192 use SqlScalarType::*;
1193
1194 Ok(match ecx.scalar_type(&expr) {
1195 Bool | Jsonb | Numeric { .. } => {
1196 expr.call_unary(UnaryFunc::CastJsonbableToJsonb(func::CastJsonbableToJsonb))
1197 }
1198 Int16 | Int32 | Int64 | UInt16 | UInt32 | UInt64 | Float32 | Float64 => plan_cast(
1199 ecx,
1200 CastContext::Explicit,
1201 expr,
1202 &Numeric { max_scale: None },
1203 )
1204 .expect("cast known to exist")
1205 .call_unary(UnaryFunc::CastJsonbableToJsonb(func::CastJsonbableToJsonb)),
1206 Record { fields, .. } => {
1207 let mut exprs = vec![];
1208 for (i, (name, _ty)) in fields.iter().enumerate() {
1209 exprs.push(HirScalarExpr::literal(
1210 Datum::String(name),
1211 SqlScalarType::String,
1212 ));
1213 exprs.push(to_jsonb(
1214 ecx,
1215 expr.clone()
1216 .call_unary(UnaryFunc::RecordGet(func::RecordGet(i))),
1217 )?);
1218 }
1219 HirScalarExpr::call_variadic(JsonbBuildObject, exprs)
1220 }
1221 ref ty @ List {
1222 ref element_type, ..
1223 }
1224 | ref ty @ Array(ref element_type) => {
1225 let qcx = QueryContext::root(ecx.qcx.scx, ecx.qcx.lifetime);
1228 let ecx = ExprContext {
1229 qcx: &qcx,
1230 name: "to_jsonb",
1231 scope: &Scope::empty(),
1232 relation_type: &SqlRelationType::new(vec![element_type.clone().nullable(true)]),
1233 allow_aggregates: false,
1234 allow_subqueries: false,
1235 allow_parameters: false,
1236 allow_windows: false,
1237 };
1238
1239 let cast_element = to_jsonb(&ecx, HirScalarExpr::column(0))?;
1242 let cast_element = cast_element
1243 .lower_uncorrelated(ecx.catalog().system_vars())
1244 .expect("to_jsonb does not produce correlated expressions on uncorrelated input");
1245
1246 let func = match ty {
1250 List { .. } => UnaryFunc::CastListToJsonb(CastListToJsonb {
1251 cast_element: Box::new(cast_element),
1252 }),
1253 Array { .. } => UnaryFunc::CastArrayToJsonb(CastArrayToJsonb {
1254 cast_element: Box::new(cast_element),
1255 }),
1256 _ => unreachable!("validated above"),
1257 };
1258
1259 expr.call_unary(func)
1260 }
1261 Date
1262 | Time
1263 | Timestamp { .. }
1264 | TimestampTz { .. }
1265 | Interval
1266 | PgLegacyChar
1267 | PgLegacyName
1268 | Bytes
1269 | String
1270 | Char { .. }
1271 | VarChar { .. }
1272 | Uuid
1273 | Oid
1274 | Map { .. }
1275 | RegProc
1276 | RegType
1277 | RegClass
1278 | Int2Vector
1279 | MzTimestamp
1280 | Range { .. }
1281 | MzAclItem
1282 | AclItem => to_string(ecx, expr)?
1283 .call_unary(UnaryFunc::CastJsonbableToJsonb(func::CastJsonbableToJsonb)),
1284 })
1285}
1286
1287pub fn guess_best_common_type(
1296 ecx: &ExprContext,
1297 types: &[CoercibleScalarType],
1298) -> Result<SqlScalarType, PlanError> {
1299 if let Some(CoercibleScalarType::Record(field_tys)) = types.first() {
1309 if types
1310 .iter()
1311 .all(|t| matches!(t, CoercibleScalarType::Record(fts) if field_tys.len() == fts.len()))
1312 {
1313 let mut fields = vec![];
1314 for i in 0..field_tys.len() {
1315 let name = ColumnName::from(format!("f{}", fields.len() + 1));
1316 let mut guesses = vec![];
1317 let mut nullable = false;
1318 for ty in types {
1319 let field_ty = match ty {
1320 CoercibleScalarType::Record(fts) => fts[i].clone(),
1321 _ => unreachable!(),
1322 };
1323 if field_ty.nullable() {
1324 nullable = true;
1325 }
1326 guesses.push(field_ty.scalar_type());
1327 }
1328 let guess = guess_best_common_type(ecx, &guesses)?;
1329 fields.push((name, guess.nullable(nullable)));
1330 }
1331 return Ok(SqlScalarType::Record {
1332 fields: fields.into(),
1333 custom_id: None,
1334 });
1335 }
1336 }
1337
1338 let mut types: Vec<_> = types.into_iter().filter_map(|v| v.as_coerced()).collect();
1340
1341 let contains_int = types.iter().any(|t| {
1343 matches!(
1344 t,
1345 SqlScalarType::Int16 | SqlScalarType::Int32 | SqlScalarType::Int64
1346 )
1347 });
1348
1349 for t in types.iter_mut() {
1350 if contains_int
1351 && matches!(
1352 t,
1353 SqlScalarType::UInt16 | SqlScalarType::UInt32 | SqlScalarType::UInt64
1354 )
1355 {
1356 *t = t.near_match().expect("unsigned ints have near matches")
1357 }
1358 }
1359
1360 let mut types = types.iter();
1361
1362 let mut candidate = match types.next() {
1363 None => return Ok(SqlScalarType::String),
1365 Some(t) => t,
1367 };
1368
1369 let preferred_type = TypeCategory::from_type(candidate).preferred_type();
1370
1371 for typ in types {
1372 if TypeCategory::from_type(candidate) != TypeCategory::from_type(typ) {
1373 sql_bail!(
1375 "{} types {} and {} cannot be matched",
1376 ecx.name,
1377 ecx.humanize_sql_scalar_type(candidate, false),
1378 ecx.humanize_sql_scalar_type(typ, false),
1379 );
1380 };
1381
1382 if preferred_type.as_ref() != Some(candidate)
1384 && can_cast(ecx, CastContext::Implicit, candidate, typ)
1385 && !can_cast(ecx, CastContext::Implicit, typ, candidate)
1386 {
1387 candidate = typ;
1392 }
1393 }
1394 Ok(candidate.without_modifiers())
1395}
1396
1397pub fn plan_coerce<'a>(
1398 ecx: &'a ExprContext,
1399 e: CoercibleScalarExpr,
1400 coerce_to: &SqlScalarType,
1401) -> Result<HirScalarExpr, PlanError> {
1402 use CoercibleScalarExpr::*;
1403
1404 Ok(match e {
1405 Coerced(e) => e,
1406
1407 LiteralNull => HirScalarExpr::literal_null(coerce_to.clone()),
1408
1409 LiteralString(s) => {
1410 let lit = HirScalarExpr::literal(Datum::String(&s), SqlScalarType::String);
1411 let coerce_to_base = &coerce_to.without_modifiers();
1416 plan_cast(ecx, CastContext::Coerced, lit, coerce_to_base)?
1417 }
1418
1419 LiteralRecord(exprs) => {
1420 let arity = exprs.len();
1421 let coercions = match coerce_to {
1422 SqlScalarType::Record { fields, .. } if fields.len() == arity => fields
1423 .iter()
1424 .map(|(_name, ty)| &ty.scalar_type)
1425 .cloned()
1426 .collect(),
1427 _ => vec![SqlScalarType::String; exprs.len()],
1428 };
1429 let mut out = vec![];
1430 for (e, coerce_to) in exprs.into_iter().zip_eq(coercions) {
1431 out.push(plan_coerce(ecx, e, &coerce_to)?);
1432 }
1433 HirScalarExpr::call_variadic(
1434 RecordCreate {
1435 field_names: (0..arity)
1436 .map(|i| ColumnName::from(format!("f{}", i + 1)))
1437 .collect(),
1438 },
1439 out,
1440 )
1441 }
1442
1443 Parameter(n) => {
1444 let prev = ecx.param_types().borrow_mut().insert(n, coerce_to.clone());
1445 if let Some(prev) = prev {
1446 if prev != *coerce_to {
1447 sql_bail!(
1448 "there are contradicting constraints for \
1449 the type of parameter ${}: \
1450 should be both {} and {}",
1451 n,
1452 ecx.humanize_sql_scalar_type(&prev, false),
1453 ecx.humanize_sql_scalar_type(coerce_to, false),
1454 );
1455 }
1456 }
1457 HirScalarExpr::parameter(n)
1458 }
1459 })
1460}
1461
1462fn validate_range_element_type(
1466 ecx: &ExprContext,
1467 element_type: &SqlScalarType,
1468) -> Result<(), CastError> {
1469 let allowed = matches!(
1470 element_type,
1471 SqlScalarType::Int32
1472 | SqlScalarType::Int64
1473 | SqlScalarType::Date
1474 | SqlScalarType::Numeric { .. }
1475 | SqlScalarType::Timestamp { .. }
1476 | SqlScalarType::TimestampTz { .. }
1477 );
1478 if allowed {
1479 Ok(())
1480 } else {
1481 Err(CastError::UnsupportedRangeElementType {
1482 element_type_name: ecx.humanize_sql_scalar_type(element_type, false),
1483 })
1484 }
1485}
1486
1487pub fn plan_hypothetical_cast(
1494 ecx: &ExprContext,
1495 ccx: CastContext,
1496 from: &SqlScalarType,
1497 to: &SqlScalarType,
1498) -> Option<mz_expr::MirScalarExpr> {
1499 let mut scx = ecx.qcx.scx.clone();
1502 scx.param_types = RefCell::new(BTreeMap::new());
1503 let qcx = QueryContext::root(&scx, ecx.qcx.lifetime);
1504 let relation_type = SqlRelationType {
1505 column_types: vec![SqlColumnType {
1506 nullable: true,
1507 scalar_type: from.clone(),
1508 }],
1509 keys: vec![vec![0]],
1510 };
1511 let ecx = ExprContext {
1512 qcx: &qcx,
1513 name: "plan_hypothetical_cast",
1514 scope: &Scope::empty(),
1515 relation_type: &relation_type,
1516 allow_aggregates: false,
1517 allow_subqueries: true,
1518 allow_parameters: true,
1519 allow_windows: false,
1520 };
1521
1522 let col_expr = HirScalarExpr::column(0);
1523
1524 plan_cast(&ecx, ccx, col_expr, to)
1527 .ok()?
1528 .lower_uncorrelated(ecx.catalog().system_vars())
1530 .ok()
1531}
1532
1533pub fn plan_cast(
1543 ecx: &ExprContext,
1544 ccx: CastContext,
1545 expr: HirScalarExpr,
1546 to: &SqlScalarType,
1547) -> Result<HirScalarExpr, PlanError> {
1548 let from = ecx.scalar_type(&expr);
1549
1550 let cast_inner = |from, to, expr| {
1553 get_cast(ecx, ccx, from, to)
1554 .map(|cast| cast(expr))
1555 .map_err(|e| e.into_plan_error(ecx.name.into()))
1556 };
1557
1558 let from_category = TypeCategory::from_type(&from);
1565 let to_category = TypeCategory::from_type(to);
1566 if from_category == TypeCategory::String && to_category != TypeCategory::String {
1567 cast_inner(&SqlScalarType::String, to, expr)
1570 } else if from_category != TypeCategory::String && to_category == TypeCategory::String {
1571 let expr = cast_inner(&from, &SqlScalarType::String, expr)?;
1574 cast_inner(&SqlScalarType::String, to, expr)
1575 } else {
1576 cast_inner(&from, to, expr)
1578 }
1579}
1580
1581pub fn can_cast(
1583 ecx: &ExprContext,
1584 ccx: CastContext,
1585 cast_from: &SqlScalarType,
1586 cast_to: &SqlScalarType,
1587) -> bool {
1588 get_cast(ecx, ccx, cast_from, cast_to).is_ok()
1589}