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