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 = "
138(SELECT
139CASE
140 WHEN $1 IS NULL THEN NULL
141-- Handle OID-like input, if available via {2}
142 WHEN {2} AND pg_catalog.substring($1, 1, 1) BETWEEN '0' AND '9' THEN
143 $1::pg_catalog.oid::pg_catalog.{0}
144 ELSE (
145 -- String case; look up that the item exists
146 SELECT o.oid
147 FROM mz_unsafe.mz_error_if_null(
148 (
149 -- We need to ensure a distinct here in the case of e.g. functions,
150 -- where multiple items share a GlobalId.
151 SELECT DISTINCT id AS name_id
152 FROM mz_internal.mz_resolve_object_name('{0}', $1)
153 ),
154 -- TODO: Support the correct error code for does not exist (42883).
155 '{1} \"' || $1 || '\" does not exist'
156 ) AS i (name_id),
157 -- Lateral lets us error separately from DNE case
158 LATERAL (
159 SELECT
160 CASE
161 -- Handle too many OIDs
162 WHEN mz_catalog.list_length(mz_catalog.list_agg(oid)) > 1 THEN
163 mz_unsafe.mz_error_if_null(
164 NULL::pg_catalog.{0},
165 'more than one {1} named \"' || $1 || '\"'
166 )
167 -- Resolve object name's OID if we know there is only one
168 ELSE
169 CAST(mz_catalog.list_agg(oid)[1] AS pg_catalog.{0})
170 END
171 FROM mz_catalog.mz_objects
172 WHERE id = name_id
173 GROUP BY id
174 ) AS o (oid)
175 )
176END)";
177
178static STRING_TO_REGCLASS_EXPLICIT: LazyLock<String> = LazyLock::new(|| {
179 SimpleCurlyFormat
180 .format(STRING_REG_CAST_TEMPLATE, ["regclass", "relation", "false"])
181 .unwrap()
182 .to_string()
183});
184
185static STRING_TO_REGCLASS_COERCED: LazyLock<String> = LazyLock::new(|| {
186 SimpleCurlyFormat
187 .format(STRING_REG_CAST_TEMPLATE, ["regclass", "relation", "true"])
188 .unwrap()
189 .to_string()
190});
191
192static STRING_TO_REGPROC: LazyLock<String> = LazyLock::new(|| {
193 SimpleCurlyFormat
194 .format(STRING_REG_CAST_TEMPLATE, ["regproc", "function", "true"])
195 .unwrap()
196 .to_string()
197});
198
199static STRING_TO_REGTYPE: LazyLock<String> = LazyLock::new(|| {
200 SimpleCurlyFormat
201 .format(STRING_REG_CAST_TEMPLATE, ["regtype", "type", "true"])
202 .unwrap()
203 .to_string()
204});
205
206const REG_STRING_CAST_TEMPLATE: &str = "(
207SELECT
208 COALESCE(mz_internal.mz_global_id_to_name(o.id), CAST($1 AS pg_catalog.oid)::pg_catalog.text)
209 AS text
210FROM
211 (
212 SELECT
213 (
214 SELECT DISTINCT id
215 FROM
216 mz_catalog.mz_objects AS o
217 JOIN
218 mz_internal.mz_object_oid_alias AS a
219 ON o.type = a.object_type
220 WHERE
221 oid = CAST($1 AS pg_catalog.oid)
222 AND
223 a.oid_alias = '{0}'
224 )
225 )
226 AS o
227)";
228
229static REGCLASS_TO_STRING: LazyLock<String> = LazyLock::new(|| {
230 SimpleCurlyFormat
231 .format(REG_STRING_CAST_TEMPLATE, ["regclass"])
232 .unwrap()
233 .to_string()
234});
235
236static REGPROC_TO_STRING: LazyLock<String> = LazyLock::new(|| {
237 SimpleCurlyFormat
238 .format(REG_STRING_CAST_TEMPLATE, ["regproc"])
239 .unwrap()
240 .to_string()
241});
242
243static REGTYPE_TO_STRING: LazyLock<String> = LazyLock::new(|| {
244 SimpleCurlyFormat
245 .format(REG_STRING_CAST_TEMPLATE, ["regtype"])
246 .unwrap()
247 .to_string()
248});
249
250#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
256pub enum CastContext {
257 Implicit,
261 Assignment,
265 Explicit,
269 Coerced,
275}
276
277struct CastImpl {
279 template: CastTemplate,
280 context: CastContext,
281}
282
283macro_rules! casts(
284 {
285 $(
286 $from_to:expr => $cast_context:ident: $cast_template:expr
287 ),+
288 } => {{
289 let mut m = BTreeMap::new();
290 $(
291 m.insert($from_to, CastImpl {
292 template: $cast_template.into(),
293 context: CastContext::$cast_context,
294 });
295 )+
296 m
297 }};
298);
299
300static VALID_CASTS: LazyLock<BTreeMap<(SqlScalarBaseType, SqlScalarBaseType), CastImpl>> =
301 LazyLock::new(|| {
302 use SqlScalarBaseType::*;
303 use UnaryFunc::*;
304
305 casts! {
306 (Bool, Int32) => Explicit: CastBoolToInt32(func::CastBoolToInt32),
308 (Bool, Int64) => Explicit: CastBoolToInt64(func::CastBoolToInt64),
309 (Bool, String) => Assignment: CastBoolToString(func::CastBoolToString),
310
311 (Int16, Int32) => Implicit: CastInt16ToInt32(func::CastInt16ToInt32),
313 (Int16, Int64) => Implicit: CastInt16ToInt64(func::CastInt16ToInt64),
314 (Int16, UInt16) => Assignment: CastInt16ToUint16(func::CastInt16ToUint16),
315 (Int16, UInt32) => Assignment: CastInt16ToUint32(func::CastInt16ToUint32),
316 (Int16, UInt64) => Assignment: CastInt16ToUint64(func::CastInt16ToUint64),
317 (Int16, Float32) => Implicit: CastInt16ToFloat32(func::CastInt16ToFloat32),
318 (Int16, Float64) => Implicit: CastInt16ToFloat64(func::CastInt16ToFloat64),
319 (Int16, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
320 let s = to_type.unwrap_numeric_max_scale();
321 let f = CastInt16ToNumeric(func::CastInt16ToNumeric(s));
322 Some(move |e: HirScalarExpr| e.call_unary(f))
323 }),
324 (Int16, Oid) => Implicit: [
325 CastInt16ToInt32(func::CastInt16ToInt32),
326 CastInt32ToOid(func::CastInt32ToOid),
327 ],
328 (Int16, RegClass) => Implicit: [
329 CastInt16ToInt32(func::CastInt16ToInt32),
330 CastInt32ToOid(func::CastInt32ToOid),
331 CastOidToRegClass(func::CastOidToRegClass),
332 ],
333 (Int16, RegProc) => Implicit: [
334 CastInt16ToInt32(func::CastInt16ToInt32),
335 CastInt32ToOid(func::CastInt32ToOid),
336 CastOidToRegProc(func::CastOidToRegProc),
337 ],
338 (Int16, RegType) => Implicit: [
339 CastInt16ToInt32(func::CastInt16ToInt32),
340 CastInt32ToOid(func::CastInt32ToOid),
341 CastOidToRegType(func::CastOidToRegType),
342 ],
343 (Int16, String) => Assignment: CastInt16ToString(func::CastInt16ToString),
344
345 (Int32, Bool) => Explicit: CastInt32ToBool(func::CastInt32ToBool),
347 (Int32, Oid) => Implicit: CastInt32ToOid(func::CastInt32ToOid),
348 (Int32, RegClass) => Implicit: [
349 CastInt32ToOid(func::CastInt32ToOid),
350 CastOidToRegClass(func::CastOidToRegClass),
351 ],
352 (Int32, RegProc) => Implicit: [
353 CastInt32ToOid(func::CastInt32ToOid),
354 CastOidToRegProc(func::CastOidToRegProc),
355 ],
356 (Int32, RegType) => Implicit: [
357 CastInt32ToOid(func::CastInt32ToOid),
358 CastOidToRegType(func::CastOidToRegType),
359 ],
360 (Int32, PgLegacyChar) => Explicit:
361 CastInt32ToPgLegacyChar(func::CastInt32ToPgLegacyChar),
362 (Int32, Int16) => Assignment: CastInt32ToInt16(func::CastInt32ToInt16),
363 (Int32, Int64) => Implicit: CastInt32ToInt64(func::CastInt32ToInt64),
364 (Int32, UInt16) => Assignment: CastInt32ToUint16(func::CastInt32ToUint16),
365 (Int32, UInt32) => Assignment: CastInt32ToUint32(func::CastInt32ToUint32),
366 (Int32, UInt64) => Assignment: CastInt32ToUint64(func::CastInt32ToUint64),
367 (Int32, Float32) => Implicit: CastInt32ToFloat32(func::CastInt32ToFloat32),
368 (Int32, Float64) => Implicit: CastInt32ToFloat64(func::CastInt32ToFloat64),
369 (Int32, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
370 let s = to_type.unwrap_numeric_max_scale();
371 let f = CastInt32ToNumeric(func::CastInt32ToNumeric(s));
372 Some(move |e: HirScalarExpr| e.call_unary(f))
373 }),
374 (Int32, String) => Assignment: CastInt32ToString(func::CastInt32ToString),
375
376 (Int64, Bool) => Explicit: CastInt64ToBool(func::CastInt64ToBool),
378 (Int64, Int16) => Assignment: CastInt64ToInt16(func::CastInt64ToInt16),
379 (Int64, Int32) => Assignment: CastInt64ToInt32(func::CastInt64ToInt32),
380 (Int64, UInt16) => Assignment: CastInt64ToUint16(func::CastInt64ToUint16),
381 (Int64, UInt32) => Assignment: CastInt64ToUint32(func::CastInt64ToUint32),
382 (Int64, UInt64) => Assignment: CastInt64ToUint64(func::CastInt64ToUint64),
383 (Int64, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
384 let s = to_type.unwrap_numeric_max_scale();
385 let f = CastInt64ToNumeric(func::CastInt64ToNumeric(s));
386 Some(move |e: HirScalarExpr| e.call_unary(f))
387 }),
388 (Int64, Float32) => Implicit: CastInt64ToFloat32(func::CastInt64ToFloat32),
389 (Int64, Float64) => Implicit: CastInt64ToFloat64(func::CastInt64ToFloat64),
390 (Int64, Oid) => Implicit: CastInt64ToOid(func::CastInt64ToOid),
391 (Int64, RegClass) => Implicit: [
392 CastInt64ToOid(func::CastInt64ToOid),
393 CastOidToRegClass(func::CastOidToRegClass),
394 ],
395 (Int64, RegProc) => Implicit: [
396 CastInt64ToOid(func::CastInt64ToOid),
397 CastOidToRegProc(func::CastOidToRegProc),
398 ],
399 (Int64, RegType) => Implicit: [
400 CastInt64ToOid(func::CastInt64ToOid),
401 CastOidToRegType(func::CastOidToRegType),
402 ],
403 (Int64, String) => Assignment: CastInt64ToString(func::CastInt64ToString),
404
405 (UInt16, UInt32) => Implicit: CastUint16ToUint32(func::CastUint16ToUint32),
407 (UInt16, UInt64) => Implicit: CastUint16ToUint64(func::CastUint16ToUint64),
408 (UInt16, Int16) => Assignment: CastUint16ToInt16(func::CastUint16ToInt16),
409 (UInt16, Int32) => Implicit: CastUint16ToInt32(func::CastUint16ToInt32),
410 (UInt16, Int64) => Implicit: CastUint16ToInt64(func::CastUint16ToInt64),
411 (UInt16, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
412 let s = to_type.unwrap_numeric_max_scale();
413 let f = CastUint16ToNumeric(func::CastUint16ToNumeric(s));
414 Some(move |e: HirScalarExpr| e.call_unary(f))
415 }),
416 (UInt16, Float32) => Implicit: CastUint16ToFloat32(func::CastUint16ToFloat32),
417 (UInt16, Float64) => Implicit: CastUint16ToFloat64(func::CastUint16ToFloat64),
418 (UInt16, String) => Assignment: CastUint16ToString(func::CastUint16ToString),
419
420 (UInt32, UInt16) => Assignment: CastUint32ToUint16(func::CastUint32ToUint16),
422 (UInt32, UInt64) => Implicit: CastUint32ToUint64(func::CastUint32ToUint64),
423 (UInt32, Int16) => Assignment: CastUint32ToInt16(func::CastUint32ToInt16),
424 (UInt32, Int32) => Assignment: CastUint32ToInt32(func::CastUint32ToInt32),
425 (UInt32, Int64) => Implicit: CastUint32ToInt64(func::CastUint32ToInt64),
426 (UInt32, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
427 let s = to_type.unwrap_numeric_max_scale();
428 let f = CastUint32ToNumeric(func::CastUint32ToNumeric(s));
429 Some(move |e: HirScalarExpr| e.call_unary(f))
430 }),
431 (UInt32, Float32) => Implicit: CastUint32ToFloat32(func::CastUint32ToFloat32),
432 (UInt32, Float64) => Implicit: CastUint32ToFloat64(func::CastUint32ToFloat64),
433 (UInt32, String) => Assignment: CastUint32ToString(func::CastUint32ToString),
434
435 (UInt64, UInt16) => Assignment: CastUint64ToUint16(func::CastUint64ToUint16),
437 (UInt64, UInt32) => Assignment: CastUint64ToUint32(func::CastUint64ToUint32),
438 (UInt64, Int16) => Assignment: CastUint64ToInt16(func::CastUint64ToInt16),
439 (UInt64, Int32) => Assignment: CastUint64ToInt32(func::CastUint64ToInt32),
440 (UInt64, Int64) => Assignment: CastUint64ToInt64(func::CastUint64ToInt64),
441 (UInt64, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
442 let s = to_type.unwrap_numeric_max_scale();
443 let f = CastUint64ToNumeric(func::CastUint64ToNumeric(s));
444 Some(move |e: HirScalarExpr| e.call_unary(f))
445 }),
446 (UInt64, Float32) => Implicit: CastUint64ToFloat32(func::CastUint64ToFloat32),
447 (UInt64, Float64) => Implicit: CastUint64ToFloat64(func::CastUint64ToFloat64),
448 (UInt64, String) => Assignment: CastUint64ToString(func::CastUint64ToString),
449
450 (MzTimestamp, String) => Assignment:
452 CastMzTimestampToString(func::CastMzTimestampToString),
453 (MzTimestamp, Timestamp) => Assignment:
454 CastMzTimestampToTimestamp(func::CastMzTimestampToTimestamp),
455 (MzTimestamp, TimestampTz) => Assignment:
456 CastMzTimestampToTimestampTz(
457 func::CastMzTimestampToTimestampTz,
458 ),
459 (String, MzTimestamp) => Assignment:
460 CastStringToMzTimestamp(func::CastStringToMzTimestamp),
461 (UInt64, MzTimestamp) => Implicit:
462 CastUint64ToMzTimestamp(func::CastUint64ToMzTimestamp),
463 (UInt32, MzTimestamp) => Implicit:
464 CastUint32ToMzTimestamp(func::CastUint32ToMzTimestamp),
465 (Int64, MzTimestamp) => Implicit:
466 CastInt64ToMzTimestamp(func::CastInt64ToMzTimestamp),
467 (Int32, MzTimestamp) => Implicit:
468 CastInt32ToMzTimestamp(func::CastInt32ToMzTimestamp),
469 (Numeric, MzTimestamp) => Implicit:
470 CastNumericToMzTimestamp(func::CastNumericToMzTimestamp),
471 (Timestamp, MzTimestamp) => Implicit:
472 CastTimestampToMzTimestamp(func::CastTimestampToMzTimestamp),
473 (TimestampTz, MzTimestamp) => Implicit:
474 CastTimestampTzToMzTimestamp(
475 func::CastTimestampTzToMzTimestamp,
476 ),
477 (Date, MzTimestamp) => Implicit:
478 CastDateToMzTimestamp(func::CastDateToMzTimestamp),
479
480 (Oid, Int32) => Assignment: CastOidToInt32(func::CastOidToInt32),
482 (Oid, Int64) => Assignment: CastOidToInt32(func::CastOidToInt32),
483 (Oid, String) => Explicit: CastOidToString(func::CastOidToString),
484 (Oid, RegClass) => Implicit: CastOidToRegClass(func::CastOidToRegClass),
485 (Oid, RegProc) => Implicit: CastOidToRegProc(func::CastOidToRegProc),
486 (Oid, RegType) => Implicit: CastOidToRegType(func::CastOidToRegType),
487
488 (RegClass, Oid) => Implicit: CastRegClassToOid(func::CastRegClassToOid),
490 (RegClass, String) => Explicit: sql_impl_cast(®CLASS_TO_STRING),
491
492 (RegProc, Oid) => Implicit: CastRegProcToOid(func::CastRegProcToOid),
494 (RegProc, String) => Explicit: sql_impl_cast(®PROC_TO_STRING),
495
496 (RegType, Oid) => Implicit: CastRegTypeToOid(func::CastRegTypeToOid),
498 (RegType, String) => Explicit: sql_impl_cast(®TYPE_TO_STRING),
499
500 (Float32, Int16) => Assignment: CastFloat32ToInt16(func::CastFloat32ToInt16),
502 (Float32, Int32) => Assignment: CastFloat32ToInt32(func::CastFloat32ToInt32),
503 (Float32, Int64) => Assignment: CastFloat32ToInt64(func::CastFloat32ToInt64),
504 (Float32, UInt16) => Assignment: CastFloat32ToUint16(func::CastFloat32ToUint16),
505 (Float32, UInt32) => Assignment: CastFloat32ToUint32(func::CastFloat32ToUint32),
506 (Float32, UInt64) => Assignment: CastFloat32ToUint64(func::CastFloat32ToUint64),
507 (Float32, Float64) => Implicit: CastFloat32ToFloat64(func::CastFloat32ToFloat64),
508 (Float32, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
509 let s = to_type.unwrap_numeric_max_scale();
510 let f = CastFloat32ToNumeric(func::CastFloat32ToNumeric(s));
511 Some(move |e: HirScalarExpr| e.call_unary(f))
512 }),
513 (Float32, String) => Assignment: CastFloat32ToString(func::CastFloat32ToString),
514
515 (Float64, Int16) => Assignment: CastFloat64ToInt16(func::CastFloat64ToInt16),
517 (Float64, Int32) => Assignment: CastFloat64ToInt32(func::CastFloat64ToInt32),
518 (Float64, Int64) => Assignment: CastFloat64ToInt64(func::CastFloat64ToInt64),
519 (Float64, UInt16) => Assignment: CastFloat64ToUint16(func::CastFloat64ToUint16),
520 (Float64, UInt32) => Assignment: CastFloat64ToUint32(func::CastFloat64ToUint32),
521 (Float64, UInt64) => Assignment: CastFloat64ToUint64(func::CastFloat64ToUint64),
522 (Float64, Float32) => Assignment: CastFloat64ToFloat32(func::CastFloat64ToFloat32),
523 (Float64, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
524 let s = to_type.unwrap_numeric_max_scale();
525 let f = CastFloat64ToNumeric(func::CastFloat64ToNumeric(s));
526 Some(move |e: HirScalarExpr| e.call_unary(f))
527 }),
528 (Float64, String) => Assignment: CastFloat64ToString(func::CastFloat64ToString),
529
530 (Date, Timestamp) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
532 let p = to_type.unwrap_timestamp_precision();
533 let f = CastDateToTimestamp(func::CastDateToTimestamp(p));
534 Some(move |e: HirScalarExpr| e.call_unary(f))
535 }),
536 (Date, TimestampTz) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
537 let p = to_type.unwrap_timestamp_precision();
538 let f = CastDateToTimestampTz(func::CastDateToTimestampTz(p));
539 Some(move |e: HirScalarExpr| e.call_unary(f))
540 }),
541 (Date, String) => Assignment: CastDateToString(func::CastDateToString),
542
543 (Time, Interval) => Implicit: CastTimeToInterval(func::CastTimeToInterval),
545 (Time, String) => Assignment: CastTimeToString(func::CastTimeToString),
546
547 (Timestamp, Date) => Assignment: CastTimestampToDate(func::CastTimestampToDate),
549 (Timestamp, TimestampTz) => Implicit: CastTemplate::new(
550 |_ecx, _ccx, from_type, to_type|
551 {
552 let from = from_type.unwrap_timestamp_precision();
553 let to = to_type.unwrap_timestamp_precision();
554 let f = CastTimestampToTimestampTz(
555 func::CastTimestampToTimestampTz { from, to },
556 );
557 Some(move |e: HirScalarExpr| e.call_unary(f))
558 }),
559 (Timestamp, Timestamp) => Assignment: CastTemplate::new(
560 |_ecx, _ccx, from_type, to_type|
561 {
562 let from = from_type.unwrap_timestamp_precision();
563 let to = to_type.unwrap_timestamp_precision();
564 let f = AdjustTimestampPrecision(
565 func::AdjustTimestampPrecision { from, to },
566 );
567 Some(move |e: HirScalarExpr| e.call_unary(f))
568 }),
569 (Timestamp, Time) => Assignment: CastTimestampToTime(func::CastTimestampToTime),
570 (Timestamp, String) => Assignment: CastTimestampToString(func::CastTimestampToString),
571
572 (TimestampTz, Date) => Assignment: CastTimestampTzToDate(func::CastTimestampTzToDate),
574 (TimestampTz, Timestamp) => Assignment: CastTemplate::new(
575 |_ecx, _ccx, from_type, to_type|
576 {
577 let from = from_type.unwrap_timestamp_precision();
578 let to = to_type.unwrap_timestamp_precision();
579 let f = CastTimestampTzToTimestamp(
580 func::CastTimestampTzToTimestamp { from, to },
581 );
582 Some(move |e: HirScalarExpr| e.call_unary(f))
583 }),
584 (TimestampTz, TimestampTz) => Assignment: CastTemplate::new(
585 |_ecx, _ccx, from_type, to_type|
586 {
587 let from = from_type.unwrap_timestamp_precision();
588 let to = to_type.unwrap_timestamp_precision();
589 let f = AdjustTimestampTzPrecision(
590 func::AdjustTimestampTzPrecision { from, to },
591 );
592 Some(move |e: HirScalarExpr| e.call_unary(f))
593 }),
594 (TimestampTz, Time) => Assignment:
595 CastTimestampTzToTime(func::CastTimestampTzToTime),
596 (TimestampTz, String) => Assignment:
597 CastTimestampTzToString(func::CastTimestampTzToString),
598
599 (Interval, Time) => Assignment: CastIntervalToTime(func::CastIntervalToTime),
601 (Interval, String) => Assignment: CastIntervalToString(func::CastIntervalToString),
602
603 (Bytes, String) => Assignment: CastBytesToString(func::CastBytesToString),
605
606 (String, Bool) => Explicit: CastStringToBool(func::CastStringToBool),
608 (String, Int16) => Explicit: CastStringToInt16(func::CastStringToInt16),
609 (String, Int32) => Explicit: CastStringToInt32(func::CastStringToInt32),
610 (String, Int64) => Explicit: CastStringToInt64(func::CastStringToInt64),
611 (String, UInt16) => Explicit: CastStringToUint16(func::CastStringToUint16),
612 (String, UInt32) => Explicit: CastStringToUint32(func::CastStringToUint32),
613 (String, UInt64) => Explicit: CastStringToUint64(func::CastStringToUint64),
614 (String, Oid) => Explicit: CastStringToOid(func::CastStringToOid),
615
616 (String, RegClass) => Explicit: sql_impl_cast_per_context(
625 &[
626 (CastContext::Explicit, &STRING_TO_REGCLASS_EXPLICIT),
627 (CastContext::Coerced, &STRING_TO_REGCLASS_COERCED)
628 ]
629 ),
630 (String, RegProc) => Explicit: sql_impl_cast(&STRING_TO_REGPROC),
631 (String, RegType) => Explicit: sql_impl_cast(&STRING_TO_REGTYPE),
632
633 (String, Float32) => Explicit: CastStringToFloat32(func::CastStringToFloat32),
634 (String, Float64) => Explicit: CastStringToFloat64(func::CastStringToFloat64),
635 (String, Numeric) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
636 let s = to_type.unwrap_numeric_max_scale();
637 let f = CastStringToNumeric(func::CastStringToNumeric(s));
638 Some(move |e: HirScalarExpr| e.call_unary(f))
639 }),
640 (String, Date) => Explicit: CastStringToDate(func::CastStringToDate),
641 (String, Time) => Explicit: CastStringToTime(func::CastStringToTime),
642 (String, Timestamp) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
643 let p = to_type.unwrap_timestamp_precision();
644 let f = CastStringToTimestamp(func::CastStringToTimestamp(p));
645 Some(move |e: HirScalarExpr| e.call_unary(f))
646 }),
647 (String, TimestampTz) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
648 let p = to_type.unwrap_timestamp_precision();
649 let f = CastStringToTimestampTz(
650 func::CastStringToTimestampTz(p),
651 );
652 Some(move |e: HirScalarExpr| e.call_unary(f))
653 }),
654 (String, Interval) => Explicit: CastStringToInterval(func::CastStringToInterval),
655 (String, Bytes) => Explicit: CastStringToBytes(func::CastStringToBytes),
656 (String, Jsonb) => Explicit: CastStringToJsonb(func::CastStringToJsonb),
657 (String, Uuid) => Explicit: CastStringToUuid(func::CastStringToUuid),
658 (String, Array) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
659 let return_ty = to_type.clone();
660 let to_el_type = to_type.unwrap_array_element_type();
661 let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_el_type)?;
662 Some(|e: HirScalarExpr| {
663 e.call_unary(UnaryFunc::CastStringToArray(
664 func::CastStringToArray {
665 return_ty,
666 cast_expr: Box::new(cast_expr),
667 },
668 ))
669 })
670 }),
671 (String, List) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
672 let return_ty = to_type.clone();
673 let to_el_type = to_type.unwrap_list_element_type();
674 let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_el_type)?;
675 Some(|e: HirScalarExpr| {
676 e.call_unary(UnaryFunc::CastStringToList(
677 func::CastStringToList {
678 return_ty,
679 cast_expr: Box::new(cast_expr),
680 },
681 ))
682 })
683 }),
684 (String, Map) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
685 let return_ty = to_type.clone();
686 let to_val_type = to_type.unwrap_map_value_type();
687 let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_val_type)?;
688 Some(|e: HirScalarExpr| {
689 e.call_unary(UnaryFunc::CastStringToMap(
690 func::CastStringToMap {
691 return_ty,
692 cast_expr: Box::new(cast_expr),
693 },
694 ))
695 })
696 }),
697 (String, Range) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
698 let return_ty = to_type.clone();
699 let to_el_type = to_type.unwrap_range_element_type();
700 let cast_expr = plan_hypothetical_cast(ecx, ccx, from_type, to_el_type)?;
701 Some(|e: HirScalarExpr| {
702 e.call_unary(UnaryFunc::CastStringToRange(
703 func::CastStringToRange {
704 return_ty,
705 cast_expr: Box::new(cast_expr),
706 },
707 ))
708 })
709 }),
710 (String, Int2Vector) => Explicit: CastStringToInt2Vector(func::CastStringToInt2Vector),
711 (String, Char) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
712 let length = to_type.unwrap_char_length();
713 let fail_on_len = ccx != CastContext::Explicit;
714 let f = CastStringToChar(func::CastStringToChar {
715 length, fail_on_len,
716 });
717 Some(move |e: HirScalarExpr| e.call_unary(f))
718 }),
719 (String, VarChar) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
720 let length = to_type.unwrap_varchar_max_length();
721 let fail_on_len = ccx != CastContext::Explicit;
722 let f = CastStringToVarChar(func::CastStringToVarChar {
723 length, fail_on_len,
724 });
725 Some(move |e: HirScalarExpr| e.call_unary(f))
726 }),
727 (String, PgLegacyChar) => Assignment:
728 CastStringToPgLegacyChar(func::CastStringToPgLegacyChar),
729 (Char, String) => Implicit: CastCharToString(func::CastCharToString),
731 (Char, Char) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
732 let length = to_type.unwrap_char_length();
733 let fail_on_len = ccx != CastContext::Explicit;
734 let f = CastStringToChar(func::CastStringToChar {
735 length, fail_on_len,
736 });
737 Some(move |e: HirScalarExpr| e.call_unary(f))
738 }),
739 (Char, VarChar) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
740 let length = to_type.unwrap_varchar_max_length();
741 let fail_on_len = ccx != CastContext::Explicit;
742 let f = CastStringToVarChar(func::CastStringToVarChar {
743 length, fail_on_len,
744 });
745 Some(move |e: HirScalarExpr| e.call_unary(f))
746 }),
747 (Char, PgLegacyChar) => Assignment:
748 CastStringToPgLegacyChar(func::CastStringToPgLegacyChar),
749
750 (VarChar, String) => Implicit: CastVarCharToString(func::CastVarCharToString),
752 (VarChar, Char) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
753 let length = to_type.unwrap_char_length();
754 let fail_on_len = ccx != CastContext::Explicit;
755 let f = CastStringToChar(func::CastStringToChar {
756 length, fail_on_len,
757 });
758 Some(move |e: HirScalarExpr| e.call_unary(f))
759 }),
760 (VarChar, VarChar) => Implicit: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
761 let length = to_type.unwrap_varchar_max_length();
762 let fail_on_len = ccx != CastContext::Explicit;
763 let f = CastStringToVarChar(func::CastStringToVarChar {
764 length, fail_on_len,
765 });
766 Some(move |e: HirScalarExpr| e.call_unary(f))
767 }),
768 (VarChar, PgLegacyChar) => Assignment:
769 CastStringToPgLegacyChar(func::CastStringToPgLegacyChar),
770
771 (PgLegacyChar, String) => Implicit:
773 CastPgLegacyCharToString(func::CastPgLegacyCharToString),
774 (PgLegacyChar, Char) => Assignment:
775 CastPgLegacyCharToChar(func::CastPgLegacyCharToChar),
776 (PgLegacyChar, VarChar) => Assignment:
777 CastPgLegacyCharToVarChar(func::CastPgLegacyCharToVarChar),
778 (PgLegacyChar, Int32) => Explicit:
779 CastPgLegacyCharToInt32(func::CastPgLegacyCharToInt32),
780
781 (PgLegacyName, String) => Implicit: CastVarCharToString(func::CastVarCharToString),
786 (PgLegacyName, Char) => Assignment: CastTemplate::new(|_ecx, ccx, _from_type, to_type| {
787 let length = to_type.unwrap_char_length();
788 let fail_on_len = ccx != CastContext::Explicit;
789 let f = CastStringToChar(func::CastStringToChar {
790 length, fail_on_len,
791 });
792 Some(move |e: HirScalarExpr| e.call_unary(f))
793 }),
794 (PgLegacyName, VarChar) => Assignment: CastTemplate::new(
795 |_ecx, ccx, _from_type, to_type|
796 {
797 let length = to_type.unwrap_varchar_max_length();
798 let fail_on_len = ccx != CastContext::Explicit;
799 let f = CastStringToVarChar(func::CastStringToVarChar {
800 length, fail_on_len,
801 });
802 Some(move |e: HirScalarExpr| e.call_unary(f))
803 }),
804 (String, PgLegacyName) => Implicit:
805 CastStringToPgLegacyName(func::CastStringToPgLegacyName),
806 (Char, PgLegacyName) => Implicit:
807 CastStringToPgLegacyName(func::CastStringToPgLegacyName),
808 (VarChar, PgLegacyName) => Implicit:
809 CastStringToPgLegacyName(func::CastStringToPgLegacyName),
810
811 (Record, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
813 let ty = from_type.clone();
814 Some(|e: HirScalarExpr| {
815 e.call_unary(CastRecordToString(
816 func::CastRecordToString { ty },
817 ))
818 })
819 }),
820 (Record, Record) => Implicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
821 let from_fields = from_type.unwrap_record_element_type();
822 let to_fields = to_type.unwrap_record_element_type();
823 if from_fields.len() != to_fields.len() {
824 return None;
825 }
826
827 if let (
828 l @ SqlScalarType::Record {
829 custom_id: Some(..), ..
830 },
831 r,
832 ) = (from_type, to_type)
833 {
834 if ccx == CastContext::Implicit && l != r {
837 return None;
838 }
839 }
840
841 let cast_exprs = from_fields
842 .iter()
843 .zip_eq(to_fields)
844 .map(|(f, t)| plan_hypothetical_cast(ecx, ccx, f, t))
845 .collect::<Option<Box<_>>>()?;
846 let to = to_type.clone();
847 Some(|e: HirScalarExpr| {
848 e.call_unary(CastRecord1ToRecord2(
849 func::CastRecord1ToRecord2 {
850 return_ty: to,
851 cast_exprs,
852 },
853 ))
854 })
855 }),
856
857 (Array, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
859 let ty = from_type.clone();
860 Some(|e: HirScalarExpr| {
861 e.call_unary(CastArrayToString(
862 func::CastArrayToString { ty },
863 ))
864 })
865 }),
866 (Array, List) => Explicit: CastArrayToListOneDim(func::CastArrayToListOneDim),
867 (Array, Array) => Explicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
868 let inner_from_type = from_type.unwrap_array_element_type();
869 let inner_to_type = to_type.unwrap_array_element_type();
870 let cast_expr = plan_hypothetical_cast(
871 ecx, ccx, inner_from_type, inner_to_type,
872 )?;
873 let return_ty = to_type.clone();
874
875 Some(move |e: HirScalarExpr| {
876 e.call_unary(CastArrayToArray(func::CastArrayToArray {
877 return_ty,
878 cast_expr: Box::new(cast_expr),
879 }))
880 })
881 }),
882
883 (Int2Vector, Array) => Implicit: CastTemplate::new(|ecx, ccx, _from_type, to_type| {
885 let inner_to_type = to_type.unwrap_array_element_type();
886 let element_cast = if inner_to_type != &SqlScalarType::Int16 {
890 let cast_expr = plan_hypothetical_cast(
891 ecx, ccx, &SqlScalarType::Int16, inner_to_type
892 )?;
893 Some((to_type.clone(), cast_expr))
894 } else {
895 None
896 };
897 Some(move |e: HirScalarExpr| {
898 let arr = e.call_unary(
899 UnaryFunc::CastInt2VectorToArray(func::CastInt2VectorToArray)
900 );
901 match element_cast {
902 Some((return_ty, cast_expr)) => {
903 arr.call_unary(CastArrayToArray(
904 func::CastArrayToArray { return_ty, cast_expr: Box::new(cast_expr) }
905 ))
906 }
907 None => arr,
908 }
909 })
910 }),
911 (Int2Vector, String) => Explicit: CastInt2VectorToString(func::CastInt2VectorToString),
912
913 (List, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
915 let ty = from_type.clone();
916 Some(|e: HirScalarExpr| {
917 e.call_unary(CastListToString(
918 func::CastListToString { ty },
919 ))
920 })
921 }),
922 (List, List) => Implicit: CastTemplate::new(|ecx, ccx, from_type, to_type| {
923
924 if let (
925 l @ SqlScalarType::List {
926 custom_id: Some(..), ..
927 },
928 r,
929 ) = (from_type, to_type)
930 {
931 if ccx == CastContext::Implicit && !l.base_eq(r) {
934 return None;
935 }
936 }
937
938 let return_ty = to_type.clone();
939 let from_el_type = from_type.unwrap_list_element_type();
940 let to_el_type = to_type.unwrap_list_element_type();
941 let cast_expr = plan_hypothetical_cast(
942 ecx, ccx, from_el_type, to_el_type,
943 )?;
944 Some(|e: HirScalarExpr| {
945 e.call_unary(UnaryFunc::CastList1ToList2(
946 func::CastList1ToList2 {
947 return_ty,
948 cast_expr: Box::new(cast_expr),
949 },
950 ))
951 })
952 }),
953
954 (Map, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
956 let ty = from_type.clone();
957 Some(|e: HirScalarExpr| e.call_unary(CastMapToString(func::CastMapToString { ty })))
958 }),
959
960 (Jsonb, Bool) => Explicit: CastJsonbToBool(func::CastJsonbToBool),
962 (Jsonb, Int16) => Explicit: CastJsonbToInt16(func::CastJsonbToInt16),
963 (Jsonb, Int32) => Explicit: CastJsonbToInt32(func::CastJsonbToInt32),
964 (Jsonb, Int64) => Explicit: CastJsonbToInt64(func::CastJsonbToInt64),
965 (Jsonb, Float32) => Explicit: CastJsonbToFloat32(func::CastJsonbToFloat32),
966 (Jsonb, Float64) => Explicit: CastJsonbToFloat64(func::CastJsonbToFloat64),
967 (Jsonb, Numeric) => Explicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
968 let s = to_type.unwrap_numeric_max_scale();
969 let f = CastJsonbToNumeric(func::CastJsonbToNumeric(s));
970 Some(move |e: HirScalarExpr| e.call_unary(f))
971 }),
972 (Jsonb, String) => Assignment: CastJsonbToString(func::CastJsonbToString),
973
974 (Uuid, String) => Assignment: CastUuidToString(func::CastUuidToString),
976
977 (Numeric, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| {
979 let scale = to_type.unwrap_numeric_max_scale();
980 Some(move |e: HirScalarExpr| match scale {
981 None => e,
982 Some(scale) => e.call_unary(
983 UnaryFunc::AdjustNumericScale(
984 func::AdjustNumericScale(scale),
985 ),
986 ),
987 })
988 }),
989 (Numeric, Float32) => Implicit: CastNumericToFloat32(func::CastNumericToFloat32),
990 (Numeric, Float64) => Implicit: CastNumericToFloat64(func::CastNumericToFloat64),
991 (Numeric, Int16) => Assignment: CastNumericToInt16(func::CastNumericToInt16),
992 (Numeric, Int32) => Assignment: CastNumericToInt32(func::CastNumericToInt32),
993 (Numeric, Int64) => Assignment: CastNumericToInt64(func::CastNumericToInt64),
994 (Numeric, UInt16) => Assignment: CastNumericToUint16(func::CastNumericToUint16),
995 (Numeric, UInt32) => Assignment: CastNumericToUint32(func::CastNumericToUint32),
996 (Numeric, UInt64) => Assignment: CastNumericToUint64(func::CastNumericToUint64),
997 (Numeric, String) => Assignment: CastNumericToString(func::CastNumericToString),
998
999 (Range, String) => Assignment: CastTemplate::new(|_ecx, _ccx, from_type, _to_type| {
1001 let ty = from_type.clone();
1002 Some(|e: HirScalarExpr| {
1003 e.call_unary(CastRangeToString(
1004 func::CastRangeToString { ty },
1005 ))
1006 })
1007 }),
1008
1009 (MzAclItem, String) => Explicit: sql_impl_cast("(
1011 SELECT
1012 (CASE
1013 WHEN grantee_role_id = 'p' THEN ''
1014 ELSE COALESCE(grantee_role.name, grantee_role_id)
1015 END)
1016 || '='
1017 || mz_internal.mz_aclitem_privileges($1)
1018 || '/'
1019 || COALESCE(grantor_role.name, grantor_role_id)
1020 FROM
1021 (SELECT mz_internal.mz_aclitem_grantee($1) AS grantee_role_id),
1022 (SELECT mz_internal.mz_aclitem_grantor($1) AS grantor_role_id)
1023 LEFT JOIN mz_catalog.mz_roles AS grantee_role ON grantee_role_id = grantee_role.id
1024 LEFT JOIN mz_catalog.mz_roles AS grantor_role ON grantor_role_id = grantor_role.id
1025 )"),
1026 (MzAclItem, AclItem) => Explicit: sql_impl_cast("(
1027 SELECT makeaclitem(
1028 (CASE mz_internal.mz_aclitem_grantee($1)
1029 WHEN 'p' THEN 0
1030 ELSE (SELECT oid FROM mz_catalog.mz_roles
1031 WHERE id = mz_internal.mz_aclitem_grantee($1))
1032 END),
1033 (SELECT oid FROM mz_catalog.mz_roles
1034 WHERE id = mz_internal.mz_aclitem_grantor($1)),
1035 (SELECT array_to_string(
1036 mz_internal.mz_format_privileges(
1037 mz_internal.mz_aclitem_privileges($1)
1038 ), ',')),
1039 -- GRANT OPTION isn't implemented so we hardcode false.
1040 false
1041 )
1042 )"),
1043
1044 (AclItem, String) => Explicit: sql_impl_cast("(
1046 SELECT
1047 (CASE grantee_oid
1048 WHEN 0 THEN ''
1049 ELSE COALESCE(grantee_role.name, grantee_oid::text)
1050 END)
1051 || '='
1052 || mz_internal.aclitem_privileges($1)
1053 || '/'
1054 || COALESCE(grantor_role.name, grantor_oid::text)
1055 FROM
1056 (SELECT mz_internal.aclitem_grantee($1) AS grantee_oid),
1057 (SELECT mz_internal.aclitem_grantor($1) AS grantor_oid)
1058 LEFT JOIN mz_catalog.mz_roles AS grantee_role ON grantee_oid = grantee_role.oid
1059 LEFT JOIN mz_catalog.mz_roles AS grantor_role ON grantor_oid = grantor_role.oid
1060 )"),
1061 (AclItem, MzAclItem) => Explicit: sql_impl_cast("(
1062 SELECT mz_internal.make_mz_aclitem(
1063 (CASE mz_internal.aclitem_grantee($1)
1064 WHEN 0 THEN 'p'
1065 ELSE (SELECT id FROM mz_catalog.mz_roles
1066 WHERE oid = mz_internal.aclitem_grantee($1))
1067 END),
1068 (SELECT id FROM mz_catalog.mz_roles
1069 WHERE oid = mz_internal.aclitem_grantor($1)),
1070 (SELECT array_to_string(
1071 mz_internal.mz_format_privileges(
1072 mz_internal.aclitem_privileges($1)
1073 ), ','))
1074 )
1075 )")
1076 }
1077 });
1078
1079#[derive(Debug)]
1081pub enum CastError {
1082 InvalidCast {
1084 ccx: CastContext,
1085 from: String,
1086 to: String,
1087 },
1088 UnsupportedRangeElementType { element_type_name: String },
1090}
1091
1092impl CastError {
1093 pub fn into_plan_error(self, name: String) -> PlanError {
1095 match self {
1096 CastError::InvalidCast { ccx, from, to } => PlanError::InvalidCast {
1097 name,
1098 ccx,
1099 from,
1100 to,
1101 },
1102 CastError::UnsupportedRangeElementType { element_type_name } => {
1103 PlanError::UnsupportedRangeElementType { element_type_name }
1104 }
1105 }
1106 }
1107}
1108
1109fn get_cast(
1116 ecx: &ExprContext,
1117 ccx: CastContext,
1118 from: &SqlScalarType,
1119 to: &SqlScalarType,
1120) -> Result<Cast, CastError> {
1121 use CastContext::*;
1122
1123 if from == to || (ccx == Implicit && from.base_eq(to)) {
1124 return Ok(Box::new(|expr| expr));
1125 }
1126
1127 if let SqlScalarType::Range { element_type } = to {
1129 validate_range_element_type(ecx, element_type)?;
1130 }
1131
1132 let imp = match VALID_CASTS.get(&(from.into(), to.into())) {
1133 Some(imp) => imp,
1134 None => {
1135 return Err(CastError::InvalidCast {
1136 ccx,
1137 from: ecx.humanize_scalar_type(from, false),
1138 to: ecx.humanize_scalar_type(to, false),
1139 });
1140 }
1141 };
1142 let template = if ccx >= imp.context {
1143 Some(&imp.template)
1144 } else {
1145 None
1146 };
1147 match template.and_then(|template| (template.0)(ecx, ccx, from, to)) {
1148 Some(cast) => Ok(cast),
1149 None => Err(CastError::InvalidCast {
1150 ccx,
1151 from: ecx.humanize_scalar_type(from, false),
1152 to: ecx.humanize_scalar_type(to, false),
1153 }),
1154 }
1155}
1156
1157pub fn to_string(ecx: &ExprContext, expr: HirScalarExpr) -> HirScalarExpr {
1161 plan_cast(ecx, CastContext::Explicit, expr, &SqlScalarType::String)
1162 .expect("cast known to exist")
1163}
1164
1165pub fn to_jsonb(ecx: &ExprContext, expr: HirScalarExpr) -> HirScalarExpr {
1176 use SqlScalarType::*;
1177
1178 match ecx.scalar_type(&expr) {
1179 Bool | Jsonb | Numeric { .. } => {
1180 expr.call_unary(UnaryFunc::CastJsonbableToJsonb(func::CastJsonbableToJsonb))
1181 }
1182 Int16 | Int32 | Int64 | UInt16 | UInt32 | UInt64 | Float32 | Float64 => plan_cast(
1183 ecx,
1184 CastContext::Explicit,
1185 expr,
1186 &Numeric { max_scale: None },
1187 )
1188 .expect("cast known to exist")
1189 .call_unary(UnaryFunc::CastJsonbableToJsonb(func::CastJsonbableToJsonb)),
1190 Record { fields, .. } => {
1191 let mut exprs = vec![];
1192 for (i, (name, _ty)) in fields.iter().enumerate() {
1193 exprs.push(HirScalarExpr::literal(
1194 Datum::String(name),
1195 SqlScalarType::String,
1196 ));
1197 exprs.push(to_jsonb(
1198 ecx,
1199 expr.clone()
1200 .call_unary(UnaryFunc::RecordGet(func::RecordGet(i))),
1201 ));
1202 }
1203 HirScalarExpr::call_variadic(JsonbBuildObject, exprs)
1204 }
1205 ref ty @ List {
1206 ref element_type, ..
1207 }
1208 | ref ty @ Array(ref element_type) => {
1209 let qcx = QueryContext::root(ecx.qcx.scx, ecx.qcx.lifetime);
1212 let ecx = ExprContext {
1213 qcx: &qcx,
1214 name: "to_jsonb",
1215 scope: &Scope::empty(),
1216 relation_type: &SqlRelationType::new(vec![element_type.clone().nullable(true)]),
1217 allow_aggregates: false,
1218 allow_subqueries: false,
1219 allow_parameters: false,
1220 allow_windows: false,
1221 };
1222
1223 let cast_element = to_jsonb(&ecx, HirScalarExpr::column(0));
1226 let cast_element = cast_element
1227 .lower_uncorrelated(ecx.catalog().system_vars())
1228 .expect("to_jsonb does not produce correlated expressions on uncorrelated input");
1229
1230 let func = match ty {
1234 List { .. } => UnaryFunc::CastListToJsonb(CastListToJsonb {
1235 cast_element: Box::new(cast_element),
1236 }),
1237 Array { .. } => UnaryFunc::CastArrayToJsonb(CastArrayToJsonb {
1238 cast_element: Box::new(cast_element),
1239 }),
1240 _ => unreachable!("validated above"),
1241 };
1242
1243 expr.call_unary(func)
1244 }
1245 Date
1246 | Time
1247 | Timestamp { .. }
1248 | TimestampTz { .. }
1249 | Interval
1250 | PgLegacyChar
1251 | PgLegacyName
1252 | Bytes
1253 | String
1254 | Char { .. }
1255 | VarChar { .. }
1256 | Uuid
1257 | Oid
1258 | Map { .. }
1259 | RegProc
1260 | RegType
1261 | RegClass
1262 | Int2Vector
1263 | MzTimestamp
1264 | Range { .. }
1265 | MzAclItem
1266 | AclItem => to_string(ecx, expr)
1267 .call_unary(UnaryFunc::CastJsonbableToJsonb(func::CastJsonbableToJsonb)),
1268 }
1269}
1270
1271pub fn guess_best_common_type(
1280 ecx: &ExprContext,
1281 types: &[CoercibleScalarType],
1282) -> Result<SqlScalarType, PlanError> {
1283 if let Some(CoercibleScalarType::Record(field_tys)) = types.first() {
1293 if types
1294 .iter()
1295 .all(|t| matches!(t, CoercibleScalarType::Record(fts) if field_tys.len() == fts.len()))
1296 {
1297 let mut fields = vec![];
1298 for i in 0..field_tys.len() {
1299 let name = ColumnName::from(format!("f{}", fields.len() + 1));
1300 let mut guesses = vec![];
1301 let mut nullable = false;
1302 for ty in types {
1303 let field_ty = match ty {
1304 CoercibleScalarType::Record(fts) => fts[i].clone(),
1305 _ => unreachable!(),
1306 };
1307 if field_ty.nullable() {
1308 nullable = true;
1309 }
1310 guesses.push(field_ty.scalar_type());
1311 }
1312 let guess = guess_best_common_type(ecx, &guesses)?;
1313 fields.push((name, guess.nullable(nullable)));
1314 }
1315 return Ok(SqlScalarType::Record {
1316 fields: fields.into(),
1317 custom_id: None,
1318 });
1319 }
1320 }
1321
1322 let mut types: Vec<_> = types.into_iter().filter_map(|v| v.as_coerced()).collect();
1324
1325 let contains_int = types.iter().any(|t| {
1327 matches!(
1328 t,
1329 SqlScalarType::Int16 | SqlScalarType::Int32 | SqlScalarType::Int64
1330 )
1331 });
1332
1333 for t in types.iter_mut() {
1334 if contains_int
1335 && matches!(
1336 t,
1337 SqlScalarType::UInt16 | SqlScalarType::UInt32 | SqlScalarType::UInt64
1338 )
1339 {
1340 *t = t.near_match().expect("unsigned ints have near matches")
1341 }
1342 }
1343
1344 let mut types = types.iter();
1345
1346 let mut candidate = match types.next() {
1347 None => return Ok(SqlScalarType::String),
1349 Some(t) => t,
1351 };
1352
1353 let preferred_type = TypeCategory::from_type(candidate).preferred_type();
1354
1355 for typ in types {
1356 if TypeCategory::from_type(candidate) != TypeCategory::from_type(typ) {
1357 sql_bail!(
1359 "{} types {} and {} cannot be matched",
1360 ecx.name,
1361 ecx.humanize_scalar_type(candidate, false),
1362 ecx.humanize_scalar_type(typ, false),
1363 );
1364 };
1365
1366 if preferred_type.as_ref() != Some(candidate)
1368 && can_cast(ecx, CastContext::Implicit, candidate, typ)
1369 && !can_cast(ecx, CastContext::Implicit, typ, candidate)
1370 {
1371 candidate = typ;
1376 }
1377 }
1378 Ok(candidate.without_modifiers())
1379}
1380
1381pub fn plan_coerce<'a>(
1382 ecx: &'a ExprContext,
1383 e: CoercibleScalarExpr,
1384 coerce_to: &SqlScalarType,
1385) -> Result<HirScalarExpr, PlanError> {
1386 use CoercibleScalarExpr::*;
1387
1388 Ok(match e {
1389 Coerced(e) => e,
1390
1391 LiteralNull => HirScalarExpr::literal_null(coerce_to.clone()),
1392
1393 LiteralString(s) => {
1394 let lit = HirScalarExpr::literal(Datum::String(&s), SqlScalarType::String);
1395 let coerce_to_base = &coerce_to.without_modifiers();
1400 plan_cast(ecx, CastContext::Coerced, lit, coerce_to_base)?
1401 }
1402
1403 LiteralRecord(exprs) => {
1404 let arity = exprs.len();
1405 let coercions = match coerce_to {
1406 SqlScalarType::Record { fields, .. } if fields.len() == arity => fields
1407 .iter()
1408 .map(|(_name, ty)| &ty.scalar_type)
1409 .cloned()
1410 .collect(),
1411 _ => vec![SqlScalarType::String; exprs.len()],
1412 };
1413 let mut out = vec![];
1414 for (e, coerce_to) in exprs.into_iter().zip_eq(coercions) {
1415 out.push(plan_coerce(ecx, e, &coerce_to)?);
1416 }
1417 HirScalarExpr::call_variadic(
1418 RecordCreate {
1419 field_names: (0..arity)
1420 .map(|i| ColumnName::from(format!("f{}", i + 1)))
1421 .collect(),
1422 },
1423 out,
1424 )
1425 }
1426
1427 Parameter(n) => {
1428 let prev = ecx.param_types().borrow_mut().insert(n, coerce_to.clone());
1429 if let Some(prev) = prev {
1430 if prev != *coerce_to {
1431 sql_bail!(
1432 "there are contradicting constraints for \
1433 the type of parameter ${}: \
1434 should be both {} and {}",
1435 n,
1436 ecx.humanize_scalar_type(&prev, false),
1437 ecx.humanize_scalar_type(coerce_to, false),
1438 );
1439 }
1440 }
1441 HirScalarExpr::parameter(n)
1442 }
1443 })
1444}
1445
1446fn validate_range_element_type(
1450 ecx: &ExprContext,
1451 element_type: &SqlScalarType,
1452) -> Result<(), CastError> {
1453 let allowed = matches!(
1454 element_type,
1455 SqlScalarType::Int32
1456 | SqlScalarType::Int64
1457 | SqlScalarType::Date
1458 | SqlScalarType::Numeric { .. }
1459 | SqlScalarType::Timestamp { .. }
1460 | SqlScalarType::TimestampTz { .. }
1461 );
1462 if allowed {
1463 Ok(())
1464 } else {
1465 Err(CastError::UnsupportedRangeElementType {
1466 element_type_name: ecx.humanize_scalar_type(element_type, false),
1467 })
1468 }
1469}
1470
1471pub fn plan_hypothetical_cast(
1478 ecx: &ExprContext,
1479 ccx: CastContext,
1480 from: &SqlScalarType,
1481 to: &SqlScalarType,
1482) -> Option<mz_expr::MirScalarExpr> {
1483 let mut scx = ecx.qcx.scx.clone();
1486 scx.param_types = RefCell::new(BTreeMap::new());
1487 let qcx = QueryContext::root(&scx, ecx.qcx.lifetime);
1488 let relation_type = SqlRelationType {
1489 column_types: vec![SqlColumnType {
1490 nullable: true,
1491 scalar_type: from.clone(),
1492 }],
1493 keys: vec![vec![0]],
1494 };
1495 let ecx = ExprContext {
1496 qcx: &qcx,
1497 name: "plan_hypothetical_cast",
1498 scope: &Scope::empty(),
1499 relation_type: &relation_type,
1500 allow_aggregates: false,
1501 allow_subqueries: true,
1502 allow_parameters: true,
1503 allow_windows: false,
1504 };
1505
1506 let col_expr = HirScalarExpr::column(0);
1507
1508 plan_cast(&ecx, ccx, col_expr, to)
1511 .ok()?
1512 .lower_uncorrelated(ecx.catalog().system_vars())
1514 .ok()
1515}
1516
1517pub fn plan_cast(
1527 ecx: &ExprContext,
1528 ccx: CastContext,
1529 expr: HirScalarExpr,
1530 to: &SqlScalarType,
1531) -> Result<HirScalarExpr, PlanError> {
1532 let from = ecx.scalar_type(&expr);
1533
1534 let cast_inner = |from, to, expr| {
1537 get_cast(ecx, ccx, from, to)
1538 .map(|cast| cast(expr))
1539 .map_err(|e| e.into_plan_error(ecx.name.into()))
1540 };
1541
1542 let from_category = TypeCategory::from_type(&from);
1549 let to_category = TypeCategory::from_type(to);
1550 if from_category == TypeCategory::String && to_category != TypeCategory::String {
1551 cast_inner(&SqlScalarType::String, to, expr)
1554 } else if from_category != TypeCategory::String && to_category == TypeCategory::String {
1555 let expr = cast_inner(&from, &SqlScalarType::String, expr)?;
1558 cast_inner(&SqlScalarType::String, to, expr)
1559 } else {
1560 cast_inner(&from, to, expr)
1562 }
1563}
1564
1565pub fn can_cast(
1567 ecx: &ExprContext,
1568 ccx: CastContext,
1569 cast_from: &SqlScalarType,
1570 cast_to: &SqlScalarType,
1571) -> bool {
1572 get_cast(ecx, ccx, cast_from, cast_to).is_ok()
1573}