Skip to main content

risingwave_common/types/
postgres_type.rs

1// Copyright 2022 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
15use postgres_types::Type as PgType;
16
17use super::DataType;
18
19/// `DataType` information extracted from PostgreSQL `pg_type`
20///
21/// ```sql
22/// select oid, typarray, typname, typinput, typlen from pg_type
23/// where oid in (16, 21, 23, 20, 1700, 700, 701, 1043, 17, 1082, 1114, 1184, 1083, 1186, 3802);
24/// ```
25///
26/// See also:
27/// * <https://www.postgresql.org/docs/15/catalog-pg-type.html>
28/// * <https://github.com/postgres/postgres/blob/REL_15_4/src/include/catalog/pg_type.dat>
29#[macro_export]
30macro_rules! for_all_base_types {
31    ($macro:ident $(, $x:tt)*) => {
32        $macro! {
33            $($x, )*
34            { Boolean     |   16 |     1000 | bool        | boolin         |      1 }
35            { Bytea       |   17 |     1001 | bytea       | byteain        |     -1 }
36            { Int64       |   20 |     1016 | int8        | int8in         |      8 }
37            { Int16       |   21 |     1005 | int2        | int2in         |      2 }
38            { Int32       |   23 |     1007 | int4        | int4in         |      4 }
39            { Float32     |  700 |     1021 | float4      | float4in       |      4 }
40            { Float64     |  701 |     1022 | float8      | float8in       |      8 }
41            { Varchar     | 1043 |     1015 | varchar     | varcharin      |     -1 }
42            { Date        | 1082 |     1182 | date        | date_in        |      4 }
43            { Time        | 1083 |     1183 | time        | time_in        |      8 }
44            { Timestamp   | 1114 |     1115 | timestamp   | timestamp_in   |      8 }
45            { Timestamptz | 1184 |     1185 | timestamptz | timestamptz_in |      8 }
46            { Interval    | 1186 |     1187 | interval    | interval_in    |     16 }
47            { Decimal     | 1700 |     1231 | numeric     | numeric_in     |     -1 }
48            { Jsonb       | 3802 |     3807 | jsonb       | jsonb_in       |     -1 }
49            { Variant     | 1307 |     1308 | variant     | variant_in     |     -1 }
50        }
51    };
52}
53
54#[derive(Debug, thiserror::Error)]
55#[error("Unsupported oid {0}")]
56pub struct UnsupportedOid(i32);
57
58/// Get type information compatible with Postgres type, such as oid, type length.
59impl DataType {
60    /// For a fixed-size type, typlen is the number of bytes in the internal representation of the type.
61    /// But for a variable-length type, typlen is negative.
62    /// -1 indicates a “varlena” type (one that has a length word),
63    /// -2 indicates a null-terminated C string.
64    ///
65    /// <https://www.postgresql.org/docs/15/catalog-pg-type.html#:~:text=of%20the%20type-,typlen,-int2>
66    pub fn type_len(&self) -> i16 {
67        macro_rules! impl_type_len {
68            ($( { $enum:ident | $oid:literal | $oid_array:literal | $name:ident | $input:ident | $len:literal } )*) => {
69                match self {
70                    $(
71                    DataType::$enum => $len,
72                    )*
73                    DataType::Serial => 8,
74                    DataType::Int256 => -1,
75                    DataType::Vector(_) => -1,
76                    DataType::List(_) | DataType::Struct(_) | DataType::Map(_) => -1,
77                }
78            }
79        }
80        for_all_base_types! { impl_type_len }
81    }
82
83    // NOTE:
84    // Refer https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat when add new TypeOid.
85    // Be careful to distinguish oid from array_type_oid.
86    // Such as:
87    //  https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat#L347
88    //  For Numeric(aka Decimal): oid = 1700, array_type_oid = 1231
89    pub fn from_oid(oid: i32) -> Result<Self, UnsupportedOid> {
90        macro_rules! impl_from_oid {
91            ($( { $enum:ident | $oid:literal | $oid_array:literal | $name:ident | $input:ident | $len:literal } )*) => {
92                match oid {
93                    $(
94                    $oid => Ok(DataType::$enum),
95                    )*
96                    $(
97                    $oid_array => Ok(DataType::list(DataType::$enum)),
98                    )*
99                    // workaround to support text in extended mode.
100                    25 => Ok(DataType::Varchar),
101                    1009 => Ok(DataType::Varchar.list()),
102                    _ => Err(UnsupportedOid(oid)),
103                }
104            }
105        }
106        for_all_base_types! { impl_from_oid }
107    }
108
109    /// Refer to [`Self::from_oid`]
110    pub fn to_oid(&self) -> i32 {
111        macro_rules! impl_to_oid {
112            ($( { $enum:ident | $oid:literal | $oid_array:literal | $name:ident | $input:ident | $len:literal } )*) => {
113                match self {
114                    $(
115                    DataType::$enum => $oid,
116                    )*
117                    DataType::List(list) => match list.elem().unnest_list() {
118                        $(
119                            DataType::$enum => $oid_array,
120                        )*
121                        DataType::Int256 => 1302,
122                        DataType::Serial => 1016,
123                        DataType::Struct(_) => 2287, // pseudo-type of array[struct] (see `pg_type.dat`)
124                        DataType::List { .. } => unreachable!("Never reach here!"),
125                        DataType::Map(_) => 1304,
126                        DataType::Vector(_) => 1306,
127                    }
128                    DataType::Serial => 20,
129                    // XXX: what does the oid mean here? Why we don't have from_oid for them?
130                    DataType::Int256 => 1301,
131                    DataType::Map(_) => 1303,
132                    // TODO: Support to give a new oid for custom struct type. #9434
133                    DataType::Struct(_) => 2249,  // pseudo-type of struct (see `pg_type.dat`)
134                    DataType::Vector(_) => 1305,
135                }
136            }
137        }
138        for_all_base_types! { impl_to_oid }
139    }
140
141    pub fn pg_name(&self) -> &'static str {
142        macro_rules! impl_pg_name {
143            ($( { $enum:ident | $oid:literal | $oid_array:literal | $name:ident | $input:ident | $len:literal } )*) => {
144                match self {
145                    $(
146                    DataType::$enum => stringify!($name),
147                    )*
148                    DataType::Struct(_) => "struct",
149                    DataType::List(_) => "list",
150                    DataType::Serial => "serial",
151                    DataType::Int256 => "rw_int256",
152                    DataType::Map(_) => "map",
153                    DataType::Vector(_) => "vector",
154                }
155            }
156        }
157        for_all_base_types! { impl_pg_name }
158    }
159
160    pub fn to_pg_type(&self) -> PgType {
161        let oid = self.to_oid();
162        PgType::from_oid(oid as u32).unwrap()
163    }
164}