risingwave_expr_macro/
types.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright 2024 RisingWave Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! This module provides utility functions for SQL data type conversion and manipulation.

//  name        data type   array type          owned type      ref type            primitive
const TYPE_MATRIX: &str = "
    boolean     Boolean     BoolArray           bool            bool                _
    int2        Int16       I16Array            i16             i16                 y
    int4        Int32       I32Array            i32             i32                 y
    int8        Int64       I64Array            i64             i64                 y
    int256      Int256      Int256Array         Int256          Int256Ref<'_>       _
    float4      Float32     F32Array            F32             F32                 y
    float8      Float64     F64Array            F64             F64                 y
    decimal     Decimal     DecimalArray        Decimal         Decimal             y
    serial      Serial      SerialArray         Serial          Serial              y
    date        Date        DateArray           Date            Date                y
    time        Time        TimeArray           Time            Time                y
    timestamp   Timestamp   TimestampArray      Timestamp       Timestamp           y
    timestamptz Timestamptz TimestamptzArray    Timestamptz     Timestamptz         y
    interval    Interval    IntervalArray       Interval        Interval            y
    varchar     Varchar     Utf8Array           Box<str>        &str                _
    bytea       Bytea       BytesArray          Box<[u8]>       &[u8]               _
    jsonb       Jsonb       JsonbArray          JsonbVal        JsonbRef<'_>        _
    anyarray    List        ListArray           ListValue       ListRef<'_>         _
    struct      Struct      StructArray         StructValue     StructRef<'_>       _
    anymap      Map         MapArray            MapValue        MapRef<'_>          _
    any         ???         ArrayImpl           ScalarImpl      ScalarRefImpl<'_>   _
";

/// Maps a data type to its corresponding data type name.
pub fn data_type(ty: &str) -> &str {
    lookup_matrix(ty, 1)
}

/// Maps a data type to its corresponding array type name.
pub fn array_type(ty: &str) -> &str {
    lookup_matrix(ty, 2)
}

/// Maps a data type to its corresponding `Scalar` type name.
pub fn owned_type(ty: &str) -> &str {
    lookup_matrix(ty, 3)
}

/// Maps a data type to its corresponding `ScalarRef` type name.
pub fn ref_type(ty: &str) -> &str {
    lookup_matrix(ty, 4)
}

/// Checks if a data type is primitive.
pub fn is_primitive(ty: &str) -> bool {
    lookup_matrix(ty, 5) == "y"
}

fn lookup_matrix(mut ty: &str, idx: usize) -> &str {
    if ty.ends_with("[]") {
        ty = "anyarray";
    } else if ty.starts_with("struct") {
        ty = "struct";
    } else if ty == "void" {
        // XXX: we don't support void type yet.
        //      replace it with int for now.
        ty = "int4";
    }
    let s = TYPE_MATRIX.trim().lines().find_map(|line| {
        let mut parts = line.split_whitespace();
        if parts.next() == Some(ty) {
            Some(parts.nth(idx - 1).unwrap())
        } else {
            None
        }
    });
    s.unwrap_or_else(|| panic!("failed to lookup type matrix: unknown type: {}", ty))
}

/// Expands a type wildcard string into a list of concrete types.
pub fn expand_type_wildcard(ty: &str) -> Vec<&str> {
    match ty {
        "*" => TYPE_MATRIX
            .trim()
            .lines()
            .map(|l| l.split_whitespace().next().unwrap())
            .filter(|l| *l != "any")
            .collect(),
        "*int" => vec!["int2", "int4", "int8"],
        "*float" => vec!["float4", "float8"],
        _ => vec![ty],
    }
}

/// Computes the minimal compatible type between a pair of data types.
///
/// This function is used to determine the `auto` type.
pub fn min_compatible_type(types: &[impl AsRef<str>]) -> &str {
    if types.len() == 1 {
        return types[0].as_ref();
    }
    assert_eq!(types.len(), 2);
    match (types[0].as_ref(), types[1].as_ref()) {
        (a, b) if a == b => a,

        ("int2", "int2") => "int2",
        ("int2", "int4") => "int4",
        ("int2", "int8") => "int8",

        ("int4", "int2") => "int4",
        ("int4", "int4") => "int4",
        ("int4", "int8") => "int8",

        ("int8", "int2") => "int8",
        ("int8", "int4") => "int8",
        ("int8", "int8") => "int8",

        ("int2", "int256") => "int256",
        ("int4", "int256") => "int256",
        ("int8", "int256") => "int256",
        ("int256", "int2") => "int256",
        ("int256", "int4") => "int256",
        ("int256", "int8") => "int256",
        ("int256", "float8") => "float8",
        ("float8", "int256") => "float8",

        ("float4", "float4") => "float4",
        ("float4", "float8") => "float8",

        ("float8", "float4") => "float8",
        ("float8", "float8") => "float8",

        ("decimal", "decimal") => "decimal",

        ("date", "timestamp") => "timestamp",
        ("timestamp", "date") => "timestamp",
        ("time", "interval") => "interval",
        ("interval", "time") => "interval",

        (a, b) => panic!("unknown minimal compatible type for {a:?} and {b:?}"),
    }
}