risingwave_expr_macro/
types.rs

1// Copyright 2025 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! This module provides utility functions for SQL data type conversion and manipulation.
16
17//  name        data type   array type          owned type      ref type            primitive
18const TYPE_MATRIX: &str = "
19    boolean     Boolean     BoolArray           bool            bool                _
20    int2        Int16       I16Array            i16             i16                 y
21    int4        Int32       I32Array            i32             i32                 y
22    int8        Int64       I64Array            i64             i64                 y
23    int256      Int256      Int256Array         Int256          Int256Ref<'_>       _
24    float4      Float32     F32Array            F32             F32                 y
25    float8      Float64     F64Array            F64             F64                 y
26    decimal     Decimal     DecimalArray        Decimal         Decimal             y
27    serial      Serial      SerialArray         Serial          Serial              y
28    date        Date        DateArray           Date            Date                y
29    time        Time        TimeArray           Time            Time                y
30    timestamp   Timestamp   TimestampArray      Timestamp       Timestamp           y
31    timestamptz Timestamptz TimestamptzArray    Timestamptz     Timestamptz         y
32    interval    Interval    IntervalArray       Interval        Interval            y
33    varchar     Varchar     Utf8Array           Box<str>        &str                _
34    bytea       Bytea       BytesArray          Box<[u8]>       &[u8]               _
35    jsonb       Jsonb       JsonbArray          JsonbVal        JsonbRef<'_>        _
36    vector      Vector      VectorArray         VectorVal       VectorRef<'_>       _
37    anyarray    List        ListArray           ListValue       ListRef<'_>         _
38    struct      Struct      StructArray         StructValue     StructRef<'_>       _
39    anymap      Map         MapArray            MapValue        MapRef<'_>          _
40    any         ???         ArrayImpl           ScalarImpl      ScalarRefImpl<'_>   _
41";
42
43/// Maps a data type to its corresponding data type name.
44pub fn data_type(ty: &str) -> &str {
45    lookup_matrix(ty, 1)
46}
47
48/// Maps a data type to its corresponding array type name.
49pub fn array_type(ty: &str) -> &str {
50    lookup_matrix(ty, 2)
51}
52
53/// Maps a data type to its corresponding `Scalar` type name.
54pub fn owned_type(ty: &str) -> &str {
55    lookup_matrix(ty, 3)
56}
57
58/// Maps a data type to its corresponding `ScalarRef` type name.
59pub fn ref_type(ty: &str) -> &str {
60    lookup_matrix(ty, 4)
61}
62
63/// Checks if a data type is primitive.
64pub fn is_primitive(ty: &str) -> bool {
65    lookup_matrix(ty, 5) == "y"
66}
67
68fn lookup_matrix(mut ty: &str, idx: usize) -> &str {
69    if ty.ends_with("[]") {
70        ty = "anyarray";
71    } else if ty.starts_with("struct") {
72        ty = "struct";
73    } else if ty == "void" {
74        // XXX: we don't support void type yet.
75        //      replace it with int for now.
76        ty = "int4";
77    }
78    let s = TYPE_MATRIX.trim().lines().find_map(|line| {
79        let mut parts = line.split_whitespace();
80        if parts.next() == Some(ty) {
81            Some(parts.nth(idx - 1).unwrap())
82        } else {
83            None
84        }
85    });
86    s.unwrap_or_else(|| panic!("failed to lookup type matrix: unknown type: {}", ty))
87}
88
89/// Expands a type wildcard string into a list of concrete types.
90pub fn expand_type_wildcard(ty: &str) -> Vec<&str> {
91    match ty {
92        "*" => TYPE_MATRIX
93            .trim()
94            .lines()
95            .map(|l| l.split_whitespace().next().unwrap())
96            .filter(|l| *l != "any")
97            .collect(),
98        "*int" => vec!["int2", "int4", "int8"],
99        "*float" => vec!["float4", "float8"],
100        _ => vec![ty],
101    }
102}
103
104/// Computes the minimal compatible type between a pair of data types.
105///
106/// This function is used to determine the `auto` type.
107pub fn min_compatible_type(types: &[impl AsRef<str>]) -> &str {
108    if types.len() == 1 {
109        return types[0].as_ref();
110    }
111    assert_eq!(types.len(), 2);
112    match (types[0].as_ref(), types[1].as_ref()) {
113        (a, b) if a == b => a,
114
115        ("int2", "int2") => "int2",
116        ("int2", "int4") => "int4",
117        ("int2", "int8") => "int8",
118
119        ("int4", "int2") => "int4",
120        ("int4", "int4") => "int4",
121        ("int4", "int8") => "int8",
122
123        ("int8", "int2") => "int8",
124        ("int8", "int4") => "int8",
125        ("int8", "int8") => "int8",
126
127        ("int2", "int256") => "int256",
128        ("int4", "int256") => "int256",
129        ("int8", "int256") => "int256",
130        ("int256", "int2") => "int256",
131        ("int256", "int4") => "int256",
132        ("int256", "int8") => "int256",
133        ("int256", "float8") => "float8",
134        ("float8", "int256") => "float8",
135
136        ("float4", "float4") => "float4",
137        ("float4", "float8") => "float8",
138
139        ("float8", "float4") => "float8",
140        ("float8", "float8") => "float8",
141
142        ("decimal", "decimal") => "decimal",
143
144        ("date", "timestamp") => "timestamp",
145        ("timestamp", "date") => "timestamp",
146        ("time", "interval") => "interval",
147        ("interval", "time") => "interval",
148
149        (a, b) => panic!("unknown minimal compatible type for {a:?} and {b:?}"),
150    }
151}