From a8131a5cee3534432bbacab63909ad005543a646 Mon Sep 17 00:00:00 2001 From: Joseph Koshakow Date: Wed, 24 Aug 2022 16:18:13 -0400 Subject: [PATCH] sql: Add unsigned int types (#14304) This commit adds 16-bit, 32-bit, and 64-bit unsigned integer types to Materialize. In addition it also adds various casts to and from the unsigned int types. The binary format of these types is big endian, which is the same as every other numeric type. These types have separate OIDs from the signed integer types so psql and other drivers don't confuse these for signed integers. No arithmetic operators are added for unsigned integers in this commit. Those can be added in a follow up commit. Works towards resolving #7629 --- doc/user/content/sql/functions/cast.md | 206 +++-- doc/user/content/sql/types/_index.md | 6 +- doc/user/content/sql/types/integer.md | 2 + doc/user/content/sql/types/uint.md | 103 +++ src/adapter/src/catalog.rs | 6 + src/adapter/src/catalog/builtin.rs | 72 ++ src/adapter/src/coord/timestamp_selection.rs | 3 + src/expr/src/scalar.proto | 48 ++ src/expr/src/scalar/func.rs | 195 ++++- src/expr/src/scalar/func/impls.rs | 6 + src/expr/src/scalar/func/impls/float32.rs | 36 + src/expr/src/scalar/func/impls/float64.rs | 36 + src/expr/src/scalar/func/impls/int16.rs | 24 + src/expr/src/scalar/func/impls/int32.rs | 24 + src/expr/src/scalar/func/impls/int64.rs | 24 + src/expr/src/scalar/func/impls/numeric.rs | 31 + src/expr/src/scalar/func/impls/oid.rs | 2 +- src/expr/src/scalar/func/impls/string.rs | 21 + src/expr/src/scalar/func/impls/uint16.rs | 105 +++ src/expr/src/scalar/func/impls/uint32.rs | 105 +++ src/expr/src/scalar/func/impls/uint64.rs | 104 +++ src/expr/src/scalar/mod.rs | 12 + src/interchange/src/avro/encode.rs | 5 +- src/interchange/src/json.rs | 19 +- src/pgrepr/src/oid.rs | 6 + src/pgrepr/src/types.rs | 84 ++ src/pgrepr/src/value.rs | 57 +- src/repr/src/relation_and_scalar.proto | 3 + src/repr/src/row.proto | 2 + src/repr/src/row.rs | 22 + src/repr/src/row/encoding.rs | 8 + src/repr/src/scalar.rs | 60 +- src/repr/src/strconv.rs | 51 +- src/sql/src/catalog.rs | 3 + src/sql/src/func.rs | 9 + src/sql/src/plan/query.rs | 3 + src/sql/src/plan/typeconv.rs | 61 ++ test/pgtest/binary.pt | 196 +++++ test/sqllogictest/unsigned_int.slt | 765 +++++++++++++++++++ test/testdrive/types.td | 18 + 40 files changed, 2451 insertions(+), 92 deletions(-) create mode 100644 doc/user/content/sql/types/uint.md create mode 100644 src/expr/src/scalar/func/impls/uint16.rs create mode 100644 src/expr/src/scalar/func/impls/uint32.rs create mode 100644 src/expr/src/scalar/func/impls/uint64.rs create mode 100644 test/sqllogictest/unsigned_int.slt diff --git a/doc/user/content/sql/functions/cast.md b/doc/user/content/sql/functions/cast.md index a92a166c0538..44d01d66dae5 100644 --- a/doc/user/content/sql/functions/cast.md +++ b/doc/user/content/sql/functions/cast.md @@ -41,84 +41,134 @@ Cast context | Definition | Strictness Casts allowed in less strict contexts are also allowed in stricter contexts. That is, implicit casts also occur by assignment, and both implicit casts and casts by assignment can be explicitly invoked. -Source type | Return type | Cast context -------------|-------------|---------- -[`array`](../../types/array/)1 | [`text`](../../types/text/) | Assignment -[`bigint`](../../types/integer/) | [`bool`](../../types/boolean/) | Explicit -[`bigint`](../../types/integer/) | [`int`](../../types/integer/) | Assignment -[`bigint`](../../types/integer/) | [`float`](../../types/float/) | Implicit -[`bigint`](../../types/integer/) | [`numeric`](../../types/numeric/) | Implicit -[`bigint`](../../types/integer/) | [`real`](../../types/real/) | Implicit -[`bigint`](../../types/integer/) |[`text`](../../types/text/) | Assignment -[`bool`](../../types/boolean/) | [`int`](../../types/integer/) | Explicit -[`bool`](../../types/boolean/) |[`text`](../../types/text/) | Assignment -[`bytea`](../../types/bytea/) |[`text`](../../types/text/)| Assignment -[`date`](../../types/date/) |[`text`](../../types/text/) | Assignment -[`date`](../../types/date/) | [`timestamp`](../../types/timestamp/) | Implicit -[`date`](../../types/date/) | [`timestamptz`](../../types/timestamp/) | Implicit -[`float`](../../types/float/)| [`bigint`](../../types/integer/) | Assignment -[`float`](../../types/float/)| [`int`](../../types/integer/) | Assignment -[`float`](../../types/float/)| [`numeric`](../../types/numeric/)2 | Assignment -[`float`](../../types/float/)| [`real`](../../types/real/) | Assignment -[`float`](../../types/float/)|[`text`](../../types/text/) | Assignment -[`int`](../../types/integer/) | [`bigint`](../../types/integer/) | Implicit -[`int`](../../types/integer/) | [`bool`](../../types/boolean/) | Explicit -[`int`](../../types/integer/) | [`float`](../../types/float/) | Implicit -[`int`](../../types/integer/) | [`numeric`](../../types/numeric/) | Implicit -[`int`](../../types/integer/) | [`oid`](../../types/oid/) | Implicit -[`int`](../../types/integer/) | [`real`](../../types/real/) | Implicit -[`int`](../../types/integer/) |[`text`](../../types/text/) | Assignment -[`interval`](../../types/interval/) |[`text`](../../types/text/) | Assignment -[`interval`](../../types/interval/) | [`time`](../../types/time/) | Assignment -[`jsonb`](../../types/jsonb/) | [`bigint`](../../types/integer/) | Explicit -[`jsonb`](../../types/jsonb/) |[`bool`](../../types/boolean/) | Explicit -[`jsonb`](../../types/jsonb/) | [`float`](../../types/float/) | Explicit -[`jsonb`](../../types/jsonb/) | [`int`](../../types/integer/) | Explicit -[`jsonb`](../../types/jsonb/) | [`real`](../../types/real/) | Explicit -[`jsonb`](../../types/jsonb/) | [`numeric`](../../types/numeric/) | Explicit -[`jsonb`](../../types/jsonb/) |[`text`](../../types/text/) | Assignment -[`list`](../../types/list/)1 | [`list`](../../types/list/) | Implicit -[`list`](../../types/list/)1 |[`text`](../../types/text/) | Assignment -[`map`](../../types/map/) | [`text`](../../types/text/) | Assignment -[`numeric`](../../types/numeric/) | [`bigint`](../../types/integer/) | Assignment -[`numeric`](../../types/numeric/) | [`float`](../../types/float/) | Implicit -[`numeric`](../../types/numeric/) | [`int`](../../types/integer/) | Assignment -[`numeric`](../../types/numeric/) | [`real`](../../types/real/) | Implicit -[`numeric`](../../types/numeric/) |[`text`](../../types/text/) | Assignment -[`oid`](../../types/oid/) | [`int`](../../types/integer/) | Assignment -[`oid`](../../types/oid/) | [`text`](../../types/text/) | Explicit -[`real`](../../types/real/) | [`bigint`](../../types/integer/) | Assignment -[`real`](../../types/real/) | [`float`](../../types/float/) | Implicit -[`real`](../../types/real/) | [`int`](../../types/integer/) | Assignment -[`real`](../../types/real/) | [`numeric`](../../types/numeric/) | Assignment -[`real`](../../types/real/) | [`text`](../../types/text/) | Assignment -[`record`](../../types/record/) |[`text`](../../types/text/) | Assignment -[`text`](../../types/text/) | [`bigint`](../../types/integer/) | Explicit -[`text`](../../types/text/) |[`bool`](../../types/boolean/) | Explicit -[`text`](../../types/text/) | [`bytea`](../../types/bytea/) | Explicit -[`text`](../../types/text/) | [`date`](../../types/date/) | Explicit -[`text`](../../types/text/) | [`float`](../../types/float/) | Explicit -[`text`](../../types/text/) | [`int`](../../types/integer/) | Explicit -[`text`](../../types/text/) | [`interval`](../../types/interval/) | Explicit -[`text`](../../types/text/) | [`jsonb`](../../types/jsonb/) | Explicit -[`text`](../../types/text/) | [`list`](../../types/list/) | Explicit -[`text`](../../types/text/) | [`map`](../../types/map/) | Explicit -[`text`](../../types/text/) | [`numeric`](../../types/numeric/) | Explicit -[`text`](../../types/text/) | [`oid`](../../types/oid/) | Explicit -[`text`](../../types/text/) | [`real`](../../types/real/) | Explicit -[`text`](../../types/text/) | [`time`](../../types/time/) | Explicit -[`text`](../../types/text/) | [`timestamp`](../../types/timestamp/) | Explicit -[`text`](../../types/text/) | [`timestamptz`](../../types/timestamp/) | Explicit -[`text`](../../types/text/) | [`uuid`](../../types/uuid/) | Explicit -[`time`](../../types/time/) | [`interval`](../../types/interval/) | Implicit -[`time`](../../types/time/) |[`text`](../../types/text/) | Assignment -[`timestamp`](../../types/timestamp/) | [`date`](../../types/date/) | Assignment -[`timestamp`](../../types/timestamp/) |[`text`](../../types/text/) | Assignment -[`timestamp`](../../types/timestamp/) | [`timestamptz`](../../types/timestamp/) | Implicit -[`timestamptz`](../../types/timestamp/) | [`date`](../../types/date/) | Assignment -[`timestamptz`](../../types/timestamp/) |[`text`](../../types/text/) | Assignment -[`timestamptz`](../../types/timestamp/) | [`timestamp`](../../types/timestamp/) | Assignment -[`uuid`](../../types/uuid/) | [`text`](../../types/text/) | Assignment +Source type | Return type | Cast context +-------------------------------------------|-----------------------------------------------|---------- +[`array`](../../types/array/)1 | [`text`](../../types/text/) | Assignment +[`bigint`](../../types/integer/) | [`bool`](../../types/boolean/) | Explicit +[`bigint`](../../types/integer/) | [`int`](../../types/integer/) | Assignment +[`bigint`](../../types/integer/) | [`float`](../../types/float/) | Implicit +[`bigint`](../../types/integer/) | [`numeric`](../../types/numeric/) | Implicit +[`bigint`](../../types/integer/) | [`real`](../../types/real/) | Implicit +[`bigint`](../../types/integer/) | [`text`](../../types/text/) | Assignment +[`bigint`](../../types/integer/) | [`uint2`](../../types/uint/) | Assignment +[`bigint`](../../types/integer/) | [`uint4`](../../types/uint/) | Assignment +[`bigint`](../../types/integer/) | [`uint8`](../../types/uint/) | Assignment +[`bool`](../../types/boolean/) | [`int`](../../types/integer/) | Explicit +[`bool`](../../types/boolean/) | [`text`](../../types/text/) | Assignment +[`bytea`](../../types/bytea/) | [`text`](../../types/text/) | Assignment +[`date`](../../types/date/) | [`text`](../../types/text/) | Assignment +[`date`](../../types/date/) | [`timestamp`](../../types/timestamp/) | Implicit +[`date`](../../types/date/) | [`timestamptz`](../../types/timestamp/) | Implicit +[`float`](../../types/float/) | [`bigint`](../../types/integer/) | Assignment +[`float`](../../types/float/) | [`int`](../../types/integer/) | Assignment +[`float`](../../types/float/) | [`numeric`](../../types/numeric/)2 | Assignment +[`float`](../../types/float/) | [`real`](../../types/real/) | Assignment +[`float`](../../types/float/) | [`text`](../../types/text/) | Assignment +[`float`](../../types/float/) | [`uint2`](../../types/uint/) | Assignment +[`float`](../../types/float/) | [`uint4`](../../types/uint/) | Assignment +[`float`](../../types/float/) | [`uint8`](../../types/uint/) | Assignment +[`int`](../../types/integer/) | [`bigint`](../../types/integer/) | Implicit +[`int`](../../types/integer/) | [`bool`](../../types/boolean/) | Explicit +[`int`](../../types/integer/) | [`float`](../../types/float/) | Implicit +[`int`](../../types/integer/) | [`numeric`](../../types/numeric/) | Implicit +[`int`](../../types/integer/) | [`oid`](../../types/oid/) | Implicit +[`int`](../../types/integer/) | [`real`](../../types/real/) | Implicit +[`int`](../../types/integer/) | [`text`](../../types/text/) | Assignment +[`int`](../../types/integer/) | [`uint2`](../../types/uint/) | Assignment +[`int`](../../types/integer/) | [`uint4`](../../types/uint/) | Assignment +[`int`](../../types/integer/) | [`uint8`](../../types/uint/) | Assignment +[`interval`](../../types/interval/) | [`text`](../../types/text/) | Assignment +[`interval`](../../types/interval/) | [`time`](../../types/time/) | Assignment +[`jsonb`](../../types/jsonb/) | [`bigint`](../../types/integer/) | Explicit +[`jsonb`](../../types/jsonb/) | [`bool`](../../types/boolean/) | Explicit +[`jsonb`](../../types/jsonb/) | [`float`](../../types/float/) | Explicit +[`jsonb`](../../types/jsonb/) | [`int`](../../types/integer/) | Explicit +[`jsonb`](../../types/jsonb/) | [`real`](../../types/real/) | Explicit +[`jsonb`](../../types/jsonb/) | [`numeric`](../../types/numeric/) | Explicit +[`jsonb`](../../types/jsonb/) | [`text`](../../types/text/) | Assignment +[`list`](../../types/list/)1 | [`list`](../../types/list/) | Implicit +[`list`](../../types/list/)1 | [`text`](../../types/text/) | Assignment +[`map`](../../types/map/) | [`text`](../../types/text/) | Assignment +[`numeric`](../../types/numeric/) | [`bigint`](../../types/integer/) | Assignment +[`numeric`](../../types/numeric/) | [`float`](../../types/float/) | Implicit +[`numeric`](../../types/numeric/) | [`int`](../../types/integer/) | Assignment +[`numeric`](../../types/numeric/) | [`real`](../../types/real/) | Implicit +[`numeric`](../../types/numeric/) | [`text`](../../types/text/) | Assignment +[`numeric`](../../types/numeric/) | [`uint2`](../../types/uint/) | Assignment +[`numeric`](../../types/numeric/) | [`uint4`](../../types/uint/) | Assignment +[`numeric`](../../types/numeric/) | [`uint8`](../../types/uint/) | Assignment +[`oid`](../../types/oid/) | [`int`](../../types/integer/) | Assignment +[`oid`](../../types/oid/) | [`text`](../../types/text/) | Explicit +[`real`](../../types/real/) | [`bigint`](../../types/integer/) | Assignment +[`real`](../../types/real/) | [`float`](../../types/float/) | Implicit +[`real`](../../types/real/) | [`int`](../../types/integer/) | Assignment +[`real`](../../types/real/) | [`numeric`](../../types/numeric/) | Assignment +[`real`](../../types/real/) | [`text`](../../types/text/) | Assignment +[`real`](../../types/real/) | [`uint2`](../../types/uint/) | Assignment +[`real`](../../types/real/) | [`uint4`](../../types/uint/) | Assignment +[`real`](../../types/real/) | [`uint8`](../../types/uint/) | Assignment +[`record`](../../types/record/) | [`text`](../../types/text/) | Assignment +[`smallint`](../../types/integer/) | [`bigint`](../../types/integer/) | Implicit +[`smallint`](../../types/integer/) | [`float`](../../types/float/) | Implicit +[`smallint`](../../types/integer/) | [`int`](../../types/integer/) | Implicit +[`smallint`](../../types/integer/) | [`numeric`](../../types/numeric/) | Implicit +[`smallint`](../../types/integer/) | [`oid`](../../types/oid/) | Implicit +[`smallint`](../../types/integer/) | [`real`](../../types/real/) | Implicit +[`smallint`](../../types/integer/) | [`text`](../../types/text/) | Assignment +[`smallint`](../../types/integer/) | [`uint2`](../../types/uint/) | Assignment +[`smallint`](../../types/integer/) | [`uint4`](../../types/uint/) | Assignment +[`smallint`](../../types/integer/) | [`uint8`](../../types/uint/) | Assignment +[`text`](../../types/text/) | [`bigint`](../../types/integer/) | Explicit +[`text`](../../types/text/) | [`bool`](../../types/boolean/) | Explicit +[`text`](../../types/text/) | [`bytea`](../../types/bytea/) | Explicit +[`text`](../../types/text/) | [`date`](../../types/date/) | Explicit +[`text`](../../types/text/) | [`float`](../../types/float/) | Explicit +[`text`](../../types/text/) | [`int`](../../types/integer/) | Explicit +[`text`](../../types/text/) | [`interval`](../../types/interval/) | Explicit +[`text`](../../types/text/) | [`jsonb`](../../types/jsonb/) | Explicit +[`text`](../../types/text/) | [`list`](../../types/list/) | Explicit +[`text`](../../types/text/) | [`map`](../../types/map/) | Explicit +[`text`](../../types/text/) | [`numeric`](../../types/numeric/) | Explicit +[`text`](../../types/text/) | [`oid`](../../types/oid/) | Explicit +[`text`](../../types/text/) | [`real`](../../types/real/) | Explicit +[`text`](../../types/text/) | [`time`](../../types/time/) | Explicit +[`text`](../../types/text/) | [`timestamp`](../../types/timestamp/) | Explicit +[`text`](../../types/text/) | [`timestamptz`](../../types/timestamp/) | Explicit +[`text`](../../types/text/) | [`uint2`](../../types/uint/) | Explicit +[`text`](../../types/text/) | [`uint4`](../../types/uint/) | Assignment +[`text`](../../types/text/) | [`uint8`](../../types/uint/) | Assignment +[`text`](../../types/text/) | [`uuid`](../../types/uuid/) | Explicit +[`time`](../../types/time/) | [`interval`](../../types/interval/) | Implicit +[`time`](../../types/time/) | [`text`](../../types/text/) | Assignment +[`timestamp`](../../types/timestamp/) | [`date`](../../types/date/) | Assignment +[`timestamp`](../../types/timestamp/) | [`text`](../../types/text/) | Assignment +[`timestamp`](../../types/timestamp/) | [`timestamptz`](../../types/timestamp/) | Implicit +[`timestamptz`](../../types/timestamp/) | [`date`](../../types/date/) | Assignment +[`timestamptz`](../../types/timestamp/) | [`text`](../../types/text/) | Assignment +[`timestamptz`](../../types/timestamp/) | [`timestamp`](../../types/timestamp/) | Assignment +[`uint2`](../../types/uint/) | [`bigint`](../../types/integer/) | Implicit +[`uint2`](../../types/uint/) | [`float`](../../types/float/) | Implicit +[`uint2`](../../types/uint/) | [`int`](../../types/integer/) | Implicit +[`uint2`](../../types/uint/) | [`numeric`](../../types/numeric/) | Implicit +[`uint2`](../../types/uint/) | [`real`](../../types/real/) | Implicit +[`uint2`](../../types/uint/) | [`text`](../../types/text/) | Assignment +[`uint2`](../../types/uint/) | [`uint4`](../../types/uint/) | Implicit +[`uint2`](../../types/uint/) | [`uint8`](../../types/uint/) | Implicit +[`uint4`](../../types/uint) | [`bigint`](../../types/integer/) | Implicit +[`uint4`](../../types/uint) | [`float`](../../types/float/) | Implicit +[`uint4`](../../types/uint) | [`int`](../../types/integer/) | Assignment +[`uint4`](../../types/uint) | [`numeric`](../../types/numeric/) | Implicit +[`uint4`](../../types/uint) | [`real`](../../types/real/) | Implicit +[`uint4`](../../types/uint) | [`text`](../../types/text/) | Assignment +[`uint4`](../../types/uint) | [`uint2`](../../types/uint/) | Assignment +[`uint4`](../../types/uint) | [`uint8`](../../types/uint/) | Implicit +[`uint8`](../../types/uint/) | [`bigint`](../../types/integer/) | Assignment +[`uint8`](../../types/uint/) | [`float`](../../types/float/) | Implicit +[`uint8`](../../types/uint/) | [`int`](../../types/integer/) | Assignment +[`uint8`](../../types/uint/) | [`real`](../../types/real/) | Implicit +[`uint8`](../../types/uint/) | [`uint2`](../../types/uint/) | Assignment +[`uint8`](../../types/uint/) | [`uint4`](../../types/uint/) | Assignment +[`uuid`](../../types/uuid/) | [`text`](../../types/text/) | Assignment 1 [`Arrays`](../../types/array/) and [`lists`](../../types/list) are composite types subject to special constraints. See their respective type documentation for details. diff --git a/doc/user/content/sql/types/_index.md b/doc/user/content/sql/types/_index.md index e9c9d8fef0dd..bf754bdb29a6 100644 --- a/doc/user/content/sql/types/_index.md +++ b/doc/user/content/sql/types/_index.md @@ -18,7 +18,7 @@ Materialize's type system consists of two classes of types: ## Built-in types Type | Aliases | Use | Size (bytes) | Catalog name | Syntax ------|---------|-----|--------------|----------------|----- +-----|-------|-----|--------------|----------------|----- [`bigint`](integer) | `int8` | Large signed integer | 8 | Named | `123` [`boolean`](boolean) | `bool` | State of `TRUE` or `FALSE` | 1 | Named | `TRUE`, `FALSE` [`bytea`](bytea) | `bytea` | Unicode string | Variable | Named | `'\xDEADBEEF'` or `'\\000'` @@ -33,8 +33,12 @@ Type | Aliases | Use | Size (bytes) | Catalog name | Syntax [`oid`](oid) | | PostgreSQL object identifier | 4 | Named | `123` [`real`](float) | `float4` | Single precision floating-point number | 4 | Named | `1.23` [`record`](record) | | Tuple with arbitrary contents | Variable | Unnameable | `ROW($expr, ...)` +[`smallint`](integer) | `int2` | Small signed integer | 2 | Named | `123` [`text`](text) | `string` | Unicode string | Variable | Named | `'foo'` [`time`](time) | | Time without date | 4 | Named | `TIME '01:23:45'` +[`uint2`](uint) | | Small unsigned integer | 2 | Named | `123` +[`uint4`](uint) | `uint` | Unsigned integer | 4 | Named | `123` +[`uint8`](uint) | | Large unsigned integer | 8 | Named | `123` [`timestamp`](timestamp) | | Date and time | 8 | Named | `TIMESTAMP '2007-02-01 15:04:05'` [`timestamp with time zone`](timestamp) | `timestamp with time zone` | Date and time with timezone | 8 | Named | `TIMESTAMPTZ '2007-02-01 15:04:05+06'` [Arrays](array) (`[]`) | | Multidimensional array | Variable | Named | `ARRAY[...]` diff --git a/doc/user/content/sql/types/integer.md b/doc/user/content/sql/types/integer.md index 1ee59f391275..793e04f653ed 100644 --- a/doc/user/content/sql/types/integer.md +++ b/doc/user/content/sql/types/integer.md @@ -72,6 +72,7 @@ To | Required context [`oid`](../oid) | Implicit [`real`/`double precision`](../float) | Implicit [`text`](../text) | Assignment +[`uint2`/`uint4`/`uint8`](../uint) | Depends on specific cast #### To `integer` or `bigint` @@ -85,6 +86,7 @@ From | Required context [`numeric`](../numeric) | Assignment [`real`/`double precision`](../float) | Assignment [`text`](../text) | Explicit +[`uint2`/`uint4`/`uint8`](../uint) | Depends on specific cast ## Examples diff --git a/doc/user/content/sql/types/uint.md b/doc/user/content/sql/types/uint.md new file mode 100644 index 000000000000..aed74fb918db --- /dev/null +++ b/doc/user/content/sql/types/uint.md @@ -0,0 +1,103 @@ +--- +title: "Unsigned Integer types" +description: "Express unsigned integers" +menu: + main: + parent: 'sql-types' +aliases: + - /sql/types/uint2 + - /sql/types/uint4 + - /sql/types/uint8 +--- + +## `uint2` info + +Detail | Info +-------|------ +**Size** | 2 bytes +**Catalog name** | `mz_catalog.uint2` +**OID** | 16,460 +**Range** | [0, 65,535] + +## `uint4` info + +Detail | Info +-------|------ +**Size** | 4 bytes +**Catalog name** | `mz_catalog.uint4` +**OID** | 16,462 +**Range** | [0, 4,294,967,295] + +## `uint8` info + +Detail | Info +-------|------ +**Size** | 8 bytes +**Catalog name** | `mz_catalog.uint8` +**OID** | 14,464 +**Range** | [0, 18,446,744,073,709,551,615] + +## Details + +### Valid casts + +For details about casting, including contexts, see [Functions: +Cast](../../functions/cast). + +#### Between unsigned integer types + +From | To | Required context +--------|---------|-------- +`uint2` | `uint4` | Implicit +`uint2` | `uint8` | Implicit +`uint4` | `uint2` | Assignment +`uint4` | `uint8` | Implicit +`uint8` | `uint2` | Assignment +`uint8` | `uint4` | Assignment + +#### From unsigned integer types + +You can cast unsigned integer types to: + +To | Required context +---|-------- +[`numeric`](../numeric) | Implicit +[`real`/`double precision`](../float) | Implicit +[`text`](../text) | Assignment +[`smallint`/`integer`/`bigint`](../integer) | Depends on specific cast + +#### To `uint4` or `uint8` + +You can cast the following types to unsigned integer types: + +From | Required context +---|-------- +[`boolean`](../boolean) (`integer` only) | Explicit +[`jsonb`](../jsonb) | Explicit +[`oid`](../oid) (`integer` and `bigint` only) | Assignment +[`numeric`](../numeric) | Assignment +[`real`/`double precision`](../float) | Assignment +[`text`](../text) | Explicit +[`smallint`/`integer`/`bigint`](../integer) | Depends on specific cast + +## Examples + +```sql +SELECT 123::uint4 AS int_v; +``` +```nofmt + int_v +------- + 123 +``` + +
+ +```sql +SELECT 1.23::uint4 AS int_v; +``` +```nofmt + int_v +------- + 1 +``` diff --git a/src/adapter/src/catalog.rs b/src/adapter/src/catalog.rs index 610ec2fb93ce..1dc7b927675b 100644 --- a/src/adapter/src/catalog.rs +++ b/src/adapter/src/catalog.rs @@ -2271,6 +2271,9 @@ impl Catalog { CatalogType::Int16 => CatalogType::Int16, CatalogType::Int32 => CatalogType::Int32, CatalogType::Int64 => CatalogType::Int64, + CatalogType::UInt16 => CatalogType::UInt16, + CatalogType::UInt32 => CatalogType::UInt32, + CatalogType::UInt64 => CatalogType::UInt64, CatalogType::Interval => CatalogType::Interval, CatalogType::Jsonb => CatalogType::Jsonb, CatalogType::Numeric => CatalogType::Numeric, @@ -4553,6 +4556,9 @@ impl ExprHumanizer for ConnCatalog<'_> { .join(",") ), PgLegacyChar => "\"char\"".into(), + UInt16 => "uint2".into(), + UInt32 => "uint4".into(), + UInt64 => "uint8".into(), ty => { let pgrepr_type = mz_pgrepr::Type::from(ty); let pg_catalog_schema = diff --git a/src/adapter/src/catalog/builtin.rs b/src/adapter/src/catalog/builtin.rs index 9cc96caa13ec..3b28e83b8292 100644 --- a/src/adapter/src/catalog/builtin.rs +++ b/src/adapter/src/catalog/builtin.rs @@ -837,6 +837,72 @@ pub const TYPE_ANYCOMPATIBLEMAP: BuiltinType = BuiltinType { }, }; +pub const TYPE_UINT2: BuiltinType = BuiltinType { + name: "uint2", + schema: MZ_CATALOG_SCHEMA, + oid: mz_pgrepr::oid::TYPE_UINT2_OID, + details: CatalogTypeDetails { + typ: CatalogType::UInt16, + array_id: None, + }, +}; + +pub const TYPE_UINT2_ARRAY: BuiltinType = BuiltinType { + name: "_uint2", + schema: MZ_CATALOG_SCHEMA, + oid: mz_pgrepr::oid::TYPE_UINT2_ARRAY_OID, + details: CatalogTypeDetails { + typ: CatalogType::Array { + element_reference: TYPE_UINT2.name, + }, + array_id: None, + }, +}; + +pub const TYPE_UINT4: BuiltinType = BuiltinType { + name: "uint4", + schema: MZ_CATALOG_SCHEMA, + oid: mz_pgrepr::oid::TYPE_UINT4_OID, + details: CatalogTypeDetails { + typ: CatalogType::UInt32, + array_id: None, + }, +}; + +pub const TYPE_UINT4_ARRAY: BuiltinType = BuiltinType { + name: "_uint4", + schema: MZ_CATALOG_SCHEMA, + oid: mz_pgrepr::oid::TYPE_UINT4_ARRAY_OID, + details: CatalogTypeDetails { + typ: CatalogType::Array { + element_reference: TYPE_UINT4.name, + }, + array_id: None, + }, +}; + +pub const TYPE_UINT8: BuiltinType = BuiltinType { + name: "uint8", + schema: MZ_CATALOG_SCHEMA, + oid: mz_pgrepr::oid::TYPE_UINT8_OID, + details: CatalogTypeDetails { + typ: CatalogType::UInt64, + array_id: None, + }, +}; + +pub const TYPE_UINT8_ARRAY: BuiltinType = BuiltinType { + name: "_uint8", + schema: MZ_CATALOG_SCHEMA, + oid: mz_pgrepr::oid::TYPE_UINT8_ARRAY_OID, + details: CatalogTypeDetails { + typ: CatalogType::Array { + element_reference: TYPE_UINT8.name, + }, + array_id: None, + }, +}; + pub const MZ_DATAFLOW_OPERATORS: BuiltinLog = BuiltinLog { name: "mz_dataflow_operators", schema: MZ_CATALOG_SCHEMA, @@ -2146,6 +2212,12 @@ pub static BUILTINS_STATIC: Lazy>> = Lazy::new(|| { Builtin::Type(&TYPE_ANYCOMPATIBLENONARRAY), Builtin::Type(&TYPE_ANYCOMPATIBLELIST), Builtin::Type(&TYPE_ANYCOMPATIBLEMAP), + Builtin::Type(&TYPE_UINT2), + Builtin::Type(&TYPE_UINT2_ARRAY), + Builtin::Type(&TYPE_UINT4), + Builtin::Type(&TYPE_UINT4_ARRAY), + Builtin::Type(&TYPE_UINT8), + Builtin::Type(&TYPE_UINT8_ARRAY), ]; for (schema, funcs) in &[ (PG_CATALOG_SCHEMA, &*mz_sql::func::PG_CATALOG_BUILTINS), diff --git a/src/adapter/src/coord/timestamp_selection.rs b/src/adapter/src/coord/timestamp_selection.rs index de208b6206c0..a65c59ffab30 100644 --- a/src/adapter/src/coord/timestamp_selection.rs +++ b/src/adapter/src/coord/timestamp_selection.rs @@ -73,6 +73,9 @@ impl Coordinator { ScalarType::Int16 => evaled.unwrap_int16().try_into()?, ScalarType::Int32 => evaled.unwrap_int32().try_into()?, ScalarType::Int64 => evaled.unwrap_int64().try_into()?, + ScalarType::UInt16 => evaled.unwrap_uint16().into(), + ScalarType::UInt32 => evaled.unwrap_uint32().into(), + ScalarType::UInt64 => evaled.unwrap_uint64(), ScalarType::TimestampTz => { evaled.unwrap_timestamptz().timestamp_millis().try_into()? } diff --git a/src/expr/src/scalar.proto b/src/expr/src/scalar.proto index 5b16c7a9b7b3..0bc2476c7207 100644 --- a/src/expr/src/scalar.proto +++ b/src/expr/src/scalar.proto @@ -337,6 +337,51 @@ message ProtoUnaryFunc { google.protobuf.Empty trunc_float32 = 216; google.protobuf.Empty trunc_float64 = 217; google.protobuf.Empty trunc_numeric = 218; + google.protobuf.Empty cast_int16_to_uint16 = 219; + google.protobuf.Empty cast_int16_to_uint32 = 220; + google.protobuf.Empty cast_int16_to_uint64 = 221; + google.protobuf.Empty cast_int32_to_uint16 = 222; + google.protobuf.Empty cast_int32_to_uint32 = 223; + google.protobuf.Empty cast_int32_to_uint64 = 224; + google.protobuf.Empty cast_int64_to_uint16 = 225; + google.protobuf.Empty cast_int64_to_uint32 = 226; + google.protobuf.Empty cast_int64_to_uint64 = 227; + google.protobuf.Empty cast_numeric_to_uint16 = 228; + google.protobuf.Empty cast_numeric_to_uint32 = 229; + google.protobuf.Empty cast_numeric_to_uint64 = 230; + google.protobuf.Empty cast_float32_to_uint16 = 231; + google.protobuf.Empty cast_float32_to_uint32 = 232; + google.protobuf.Empty cast_float32_to_uint64 = 233; + google.protobuf.Empty cast_float64_to_uint16 = 234; + google.protobuf.Empty cast_float64_to_uint32 = 235; + google.protobuf.Empty cast_float64_to_uint64 = 236; + google.protobuf.Empty cast_string_to_uint16 = 237; + google.protobuf.Empty cast_string_to_uint32 = 238; + google.protobuf.Empty cast_string_to_uint64 = 239; + google.protobuf.Empty cast_uint16_to_float32 = 240; + google.protobuf.Empty cast_uint16_to_float64 = 241; + google.protobuf.Empty cast_uint16_to_int32 = 242; + google.protobuf.Empty cast_uint16_to_uint32 = 243; + google.protobuf.Empty cast_uint16_to_int64 = 244; + google.protobuf.Empty cast_uint16_to_uint64 = 245; + google.protobuf.Empty cast_uint16_to_string = 246; + mz_repr.adt.numeric.ProtoOptionalNumericMaxScale cast_uint16_to_numeric = 247; + google.protobuf.Empty cast_uint32_to_float32 = 248; + google.protobuf.Empty cast_uint32_to_float64 = 249; + google.protobuf.Empty cast_uint32_to_uint16 = 250; + google.protobuf.Empty cast_uint32_to_int32 = 251; + google.protobuf.Empty cast_uint32_to_int64 = 252; + google.protobuf.Empty cast_uint32_to_uint64 = 253; + google.protobuf.Empty cast_uint32_to_string = 254; + mz_repr.adt.numeric.ProtoOptionalNumericMaxScale cast_uint32_to_numeric = 255; + google.protobuf.Empty cast_uint64_to_float32 = 256; + google.protobuf.Empty cast_uint64_to_float64 = 257; + google.protobuf.Empty cast_uint64_to_uint16 = 258; + google.protobuf.Empty cast_uint64_to_int32 = 259; + google.protobuf.Empty cast_uint64_to_uint32 = 260; + google.protobuf.Empty cast_uint64_to_int64 = 261; + google.protobuf.Empty cast_uint64_to_string = 262; + mz_repr.adt.numeric.ProtoOptionalNumericMaxScale cast_uint64_to_numeric = 263; } } @@ -621,5 +666,8 @@ message ProtoEvalError { ProtoIncompatibleArrayDimensions incompatible_array_dimensions = 52; string type_from_oid = 53; ProtoIndexOutOfRange index_out_of_range = 54; + google.protobuf.Empty uint16_out_of_range = 55; + google.protobuf.Empty uint32_out_of_range = 56; + google.protobuf.Empty uint64_out_of_range = 57; } } diff --git a/src/expr/src/scalar/func.rs b/src/expr/src/scalar/func.rs index e9134fc948eb..312d39afbe48 100644 --- a/src/expr/src/scalar/func.rs +++ b/src/expr/src/scalar/func.rs @@ -3266,6 +3266,9 @@ derive_unary!( CastInt16ToFloat64, CastInt16ToInt32, CastInt16ToInt64, + CastInt16ToUint16, + CastInt16ToUint32, + CastInt16ToUint64, CastInt16ToString, CastInt2VectorToArray, CastInt32ToBool, @@ -3275,6 +3278,9 @@ derive_unary!( CastInt32ToPgLegacyChar, CastInt32ToInt16, CastInt32ToInt64, + CastInt32ToUint16, + CastInt32ToUint32, + CastInt32ToUint64, CastInt32ToString, CastOidToInt32, CastOidToInt64, @@ -3287,6 +3293,9 @@ derive_unary!( CastRegTypeToOid, CastInt64ToInt16, CastInt64ToInt32, + CastInt64ToUint16, + CastInt64ToUint32, + CastInt64ToUint64, CastInt16ToNumeric, CastInt32ToNumeric, CastInt64ToBool, @@ -3295,9 +3304,36 @@ derive_unary!( CastInt64ToFloat64, CastInt64ToOid, CastInt64ToString, + CastUint16ToUint32, + CastUint16ToUint64, + CastUint16ToInt32, + CastUint16ToInt64, + CastUint16ToNumeric, + CastUint16ToFloat32, + CastUint16ToFloat64, + CastUint16ToString, + CastUint32ToUint16, + CastUint32ToUint64, + CastUint32ToInt32, + CastUint32ToInt64, + CastUint32ToNumeric, + CastUint32ToFloat32, + CastUint32ToFloat64, + CastUint32ToString, + CastUint64ToUint16, + CastUint64ToUint32, + CastUint64ToInt32, + CastUint64ToInt64, + CastUint64ToNumeric, + CastUint64ToFloat32, + CastUint64ToFloat64, + CastUint64ToString, CastFloat32ToInt16, CastFloat32ToInt32, CastFloat32ToInt64, + CastFloat32ToUint16, + CastFloat32ToUint32, + CastFloat32ToUint64, CastFloat32ToFloat64, CastFloat32ToString, CastFloat32ToNumeric, @@ -3305,6 +3341,9 @@ derive_unary!( CastFloat64ToInt16, CastFloat64ToInt32, CastFloat64ToInt64, + CastFloat64ToUint16, + CastFloat64ToUint32, + CastFloat64ToUint64, CastFloat64ToFloat32, CastFloat64ToString, CastNumericToFloat32, @@ -3312,6 +3351,9 @@ derive_unary!( CastNumericToInt16, CastNumericToInt32, CastNumericToInt64, + CastNumericToUint16, + CastNumericToUint32, + CastNumericToUint64, CastNumericToString, CastStringToBool, CastStringToPgLegacyChar, @@ -3319,6 +3361,9 @@ derive_unary!( CastStringToInt16, CastStringToInt32, CastStringToInt64, + CastStringToUint16, + CastStringToUint32, + CastStringToUint64, CastStringToInt2Vector, CastStringToOid, CastStringToFloat32, @@ -3513,6 +3558,9 @@ impl Arbitrary for UnaryFunc { CastInt16ToFloat64::arbitrary().prop_map_into(), CastInt16ToInt32::arbitrary().prop_map_into(), CastInt16ToInt64::arbitrary().prop_map_into(), + CastInt16ToUint16::arbitrary().prop_map_into(), + CastInt16ToUint32::arbitrary().prop_map_into(), + CastInt16ToUint64::arbitrary().prop_map_into(), CastInt16ToString::arbitrary().prop_map_into(), CastInt2VectorToArray::arbitrary().prop_map_into(), CastInt32ToBool::arbitrary().prop_map_into(), @@ -3522,6 +3570,9 @@ impl Arbitrary for UnaryFunc { CastInt32ToPgLegacyChar::arbitrary().prop_map_into(), CastInt32ToInt16::arbitrary().prop_map_into(), CastInt32ToInt64::arbitrary().prop_map_into(), + CastInt32ToUint16::arbitrary().prop_map_into(), + CastInt32ToUint32::arbitrary().prop_map_into(), + CastInt32ToUint64::arbitrary().prop_map_into(), CastInt32ToString::arbitrary().prop_map_into(), CastOidToInt32::arbitrary().prop_map_into(), CastOidToInt64::arbitrary().prop_map_into(), @@ -3534,6 +3585,9 @@ impl Arbitrary for UnaryFunc { CastRegTypeToOid::arbitrary().prop_map_into(), CastInt64ToInt16::arbitrary().prop_map_into(), CastInt64ToInt32::arbitrary().prop_map_into(), + CastInt64ToUint16::arbitrary().prop_map_into(), + CastInt64ToUint32::arbitrary().prop_map_into(), + CastInt64ToUint64::arbitrary().prop_map_into(), any::>() .prop_map(|i| UnaryFunc::CastInt16ToNumeric(CastInt16ToNumeric(i))), any::>() @@ -3545,9 +3599,39 @@ impl Arbitrary for UnaryFunc { CastInt64ToFloat64::arbitrary().prop_map_into(), CastInt64ToOid::arbitrary().prop_map_into(), CastInt64ToString::arbitrary().prop_map_into(), + CastUint16ToUint32::arbitrary().prop_map_into(), + CastUint16ToUint64::arbitrary().prop_map_into(), + CastUint16ToInt32::arbitrary().prop_map_into(), + CastUint16ToInt64::arbitrary().prop_map_into(), + any::>() + .prop_map(|i| UnaryFunc::CastUint16ToNumeric(CastUint16ToNumeric(i))), + CastUint16ToFloat32::arbitrary().prop_map_into(), + CastUint16ToFloat64::arbitrary().prop_map_into(), + CastUint16ToString::arbitrary().prop_map_into(), + CastUint32ToUint16::arbitrary().prop_map_into(), + CastUint32ToUint64::arbitrary().prop_map_into(), + CastUint32ToInt32::arbitrary().prop_map_into(), + CastUint32ToInt64::arbitrary().prop_map_into(), + any::>() + .prop_map(|i| UnaryFunc::CastUint32ToNumeric(CastUint32ToNumeric(i))), + CastUint32ToFloat32::arbitrary().prop_map_into(), + CastUint32ToFloat64::arbitrary().prop_map_into(), + CastUint32ToString::arbitrary().prop_map_into(), + CastUint64ToUint16::arbitrary().prop_map_into(), + CastUint64ToUint32::arbitrary().prop_map_into(), + CastUint64ToInt32::arbitrary().prop_map_into(), + CastUint64ToInt64::arbitrary().prop_map_into(), + any::>() + .prop_map(|i| UnaryFunc::CastUint64ToNumeric(CastUint64ToNumeric(i))), + CastUint64ToFloat32::arbitrary().prop_map_into(), + CastUint64ToFloat64::arbitrary().prop_map_into(), + CastUint64ToString::arbitrary().prop_map_into(), CastFloat32ToInt16::arbitrary().prop_map_into(), CastFloat32ToInt32::arbitrary().prop_map_into(), CastFloat32ToInt64::arbitrary().prop_map_into(), + CastFloat32ToUint16::arbitrary().prop_map_into(), + CastFloat32ToUint32::arbitrary().prop_map_into(), + CastFloat32ToUint64::arbitrary().prop_map_into(), CastFloat32ToFloat64::arbitrary().prop_map_into(), CastFloat32ToString::arbitrary().prop_map_into(), any::>() @@ -3557,6 +3641,9 @@ impl Arbitrary for UnaryFunc { CastFloat64ToInt16::arbitrary().prop_map_into(), CastFloat64ToInt32::arbitrary().prop_map_into(), CastFloat64ToInt64::arbitrary().prop_map_into(), + CastFloat64ToUint16::arbitrary().prop_map_into(), + CastFloat64ToUint32::arbitrary().prop_map_into(), + CastFloat64ToUint64::arbitrary().prop_map_into(), CastFloat64ToFloat32::arbitrary().prop_map_into(), CastFloat64ToString::arbitrary().prop_map_into(), CastNumericToFloat32::arbitrary().prop_map_into(), @@ -3564,6 +3651,9 @@ impl Arbitrary for UnaryFunc { CastNumericToInt16::arbitrary().prop_map_into(), CastNumericToInt32::arbitrary().prop_map_into(), CastNumericToInt64::arbitrary().prop_map_into(), + CastNumericToUint16::arbitrary().prop_map_into(), + CastNumericToUint32::arbitrary().prop_map_into(), + CastNumericToUint64::arbitrary().prop_map_into(), CastNumericToString::arbitrary().prop_map_into(), CastStringToBool::arbitrary().prop_map_into(), CastStringToPgLegacyChar::arbitrary().prop_map_into(), @@ -3571,6 +3661,9 @@ impl Arbitrary for UnaryFunc { CastStringToInt16::arbitrary().prop_map_into(), CastStringToInt32::arbitrary().prop_map_into(), CastStringToInt64::arbitrary().prop_map_into(), + CastStringToUint16::arbitrary().prop_map_into(), + CastStringToUint32::arbitrary().prop_map_into(), + CastStringToUint64::arbitrary().prop_map_into(), CastStringToInt2Vector::arbitrary().prop_map_into(), CastStringToOid::arbitrary().prop_map_into(), CastStringToFloat32::arbitrary().prop_map_into(), @@ -3775,6 +3868,9 @@ impl RustType for UnaryFunc { UnaryFunc::CastInt16ToFloat64(_) => CastInt16ToFloat64(()), UnaryFunc::CastInt16ToInt32(_) => CastInt16ToInt32(()), UnaryFunc::CastInt16ToInt64(_) => CastInt16ToInt64(()), + UnaryFunc::CastInt16ToUint16(_) => CastInt16ToUint16(()), + UnaryFunc::CastInt16ToUint32(_) => CastInt16ToUint32(()), + UnaryFunc::CastInt16ToUint64(_) => CastInt16ToUint64(()), UnaryFunc::CastInt16ToString(_) => CastInt16ToString(()), UnaryFunc::CastInt2VectorToArray(_) => CastInt2VectorToArray(()), UnaryFunc::CastInt32ToBool(_) => CastInt32ToBool(()), @@ -3784,6 +3880,9 @@ impl RustType for UnaryFunc { UnaryFunc::CastInt32ToPgLegacyChar(_) => CastInt32ToPgLegacyChar(()), UnaryFunc::CastInt32ToInt16(_) => CastInt32ToInt16(()), UnaryFunc::CastInt32ToInt64(_) => CastInt32ToInt64(()), + UnaryFunc::CastInt32ToUint16(_) => CastInt32ToUint16(()), + UnaryFunc::CastInt32ToUint32(_) => CastInt32ToUint32(()), + UnaryFunc::CastInt32ToUint64(_) => CastInt32ToUint64(()), UnaryFunc::CastInt32ToString(_) => CastInt32ToString(()), UnaryFunc::CastOidToInt32(_) => CastOidToInt32(()), UnaryFunc::CastOidToInt64(_) => CastOidToInt64(()), @@ -3796,6 +3895,9 @@ impl RustType for UnaryFunc { UnaryFunc::CastRegTypeToOid(_) => CastRegTypeToOid(()), UnaryFunc::CastInt64ToInt16(_) => CastInt64ToInt16(()), UnaryFunc::CastInt64ToInt32(_) => CastInt64ToInt32(()), + UnaryFunc::CastInt64ToUint16(_) => CastInt64ToUint16(()), + UnaryFunc::CastInt64ToUint32(_) => CastInt64ToUint32(()), + UnaryFunc::CastInt64ToUint64(_) => CastInt64ToUint64(()), UnaryFunc::CastInt16ToNumeric(func) => CastInt16ToNumeric(func.0.into_proto()), UnaryFunc::CastInt32ToNumeric(func) => CastInt32ToNumeric(func.0.into_proto()), UnaryFunc::CastInt64ToBool(_) => CastInt64ToBool(()), @@ -3804,9 +3906,36 @@ impl RustType for UnaryFunc { UnaryFunc::CastInt64ToFloat64(_) => CastInt64ToFloat64(()), UnaryFunc::CastInt64ToOid(_) => CastInt64ToOid(()), UnaryFunc::CastInt64ToString(_) => CastInt64ToString(()), + UnaryFunc::CastUint16ToUint32(_) => CastUint16ToUint32(()), + UnaryFunc::CastUint16ToUint64(_) => CastUint16ToUint64(()), + UnaryFunc::CastUint16ToInt32(_) => CastUint16ToInt32(()), + UnaryFunc::CastUint16ToInt64(_) => CastUint16ToInt64(()), + UnaryFunc::CastUint16ToNumeric(func) => CastUint16ToNumeric(func.0.into_proto()), + UnaryFunc::CastUint16ToFloat32(_) => CastUint16ToFloat32(()), + UnaryFunc::CastUint16ToFloat64(_) => CastUint16ToFloat64(()), + UnaryFunc::CastUint16ToString(_) => CastUint16ToString(()), + UnaryFunc::CastUint32ToUint16(_) => CastUint32ToUint16(()), + UnaryFunc::CastUint32ToUint64(_) => CastUint32ToUint64(()), + UnaryFunc::CastUint32ToInt32(_) => CastUint32ToInt32(()), + UnaryFunc::CastUint32ToInt64(_) => CastUint32ToInt64(()), + UnaryFunc::CastUint32ToNumeric(func) => CastUint32ToNumeric(func.0.into_proto()), + UnaryFunc::CastUint32ToFloat32(_) => CastUint32ToFloat32(()), + UnaryFunc::CastUint32ToFloat64(_) => CastUint32ToFloat64(()), + UnaryFunc::CastUint32ToString(_) => CastUint32ToString(()), + UnaryFunc::CastUint64ToUint16(_) => CastUint64ToUint16(()), + UnaryFunc::CastUint64ToUint32(_) => CastUint64ToUint32(()), + UnaryFunc::CastUint64ToInt32(_) => CastUint64ToInt32(()), + UnaryFunc::CastUint64ToInt64(_) => CastUint64ToInt64(()), + UnaryFunc::CastUint64ToNumeric(func) => CastUint64ToNumeric(func.0.into_proto()), + UnaryFunc::CastUint64ToFloat32(_) => CastUint64ToFloat32(()), + UnaryFunc::CastUint64ToFloat64(_) => CastUint64ToFloat64(()), + UnaryFunc::CastUint64ToString(_) => CastUint64ToString(()), UnaryFunc::CastFloat32ToInt16(_) => CastFloat32ToInt16(()), UnaryFunc::CastFloat32ToInt32(_) => CastFloat32ToInt32(()), UnaryFunc::CastFloat32ToInt64(_) => CastFloat32ToInt64(()), + UnaryFunc::CastFloat32ToUint16(_) => CastFloat32ToUint16(()), + UnaryFunc::CastFloat32ToUint32(_) => CastFloat32ToUint32(()), + UnaryFunc::CastFloat32ToUint64(_) => CastFloat32ToUint64(()), UnaryFunc::CastFloat32ToFloat64(_) => CastFloat32ToFloat64(()), UnaryFunc::CastFloat32ToString(_) => CastFloat32ToString(()), UnaryFunc::CastFloat32ToNumeric(func) => CastFloat32ToNumeric(func.0.into_proto()), @@ -3814,6 +3943,9 @@ impl RustType for UnaryFunc { UnaryFunc::CastFloat64ToInt16(_) => CastFloat64ToInt16(()), UnaryFunc::CastFloat64ToInt32(_) => CastFloat64ToInt32(()), UnaryFunc::CastFloat64ToInt64(_) => CastFloat64ToInt64(()), + UnaryFunc::CastFloat64ToUint16(_) => CastFloat64ToUint16(()), + UnaryFunc::CastFloat64ToUint32(_) => CastFloat64ToUint32(()), + UnaryFunc::CastFloat64ToUint64(_) => CastFloat64ToUint64(()), UnaryFunc::CastFloat64ToFloat32(_) => CastFloat64ToFloat32(()), UnaryFunc::CastFloat64ToString(_) => CastFloat64ToString(()), UnaryFunc::CastNumericToFloat32(_) => CastNumericToFloat32(()), @@ -3821,6 +3953,9 @@ impl RustType for UnaryFunc { UnaryFunc::CastNumericToInt16(_) => CastNumericToInt16(()), UnaryFunc::CastNumericToInt32(_) => CastNumericToInt32(()), UnaryFunc::CastNumericToInt64(_) => CastNumericToInt64(()), + UnaryFunc::CastNumericToUint16(_) => CastNumericToUint16(()), + UnaryFunc::CastNumericToUint32(_) => CastNumericToUint32(()), + UnaryFunc::CastNumericToUint64(_) => CastNumericToUint64(()), UnaryFunc::CastNumericToString(_) => CastNumericToString(()), UnaryFunc::CastStringToBool(_) => CastStringToBool(()), UnaryFunc::CastStringToPgLegacyChar(_) => CastStringToPgLegacyChar(()), @@ -3828,6 +3963,9 @@ impl RustType for UnaryFunc { UnaryFunc::CastStringToInt16(_) => CastStringToInt16(()), UnaryFunc::CastStringToInt32(_) => CastStringToInt32(()), UnaryFunc::CastStringToInt64(_) => CastStringToInt64(()), + UnaryFunc::CastStringToUint16(_) => CastStringToUint16(()), + UnaryFunc::CastStringToUint32(_) => CastStringToUint32(()), + UnaryFunc::CastStringToUint64(_) => CastStringToUint64(()), UnaryFunc::CastStringToInt2Vector(_) => CastStringToInt2Vector(()), UnaryFunc::CastStringToOid(_) => CastStringToOid(()), UnaryFunc::CastStringToFloat32(_) => CastStringToFloat32(()), @@ -4037,6 +4175,9 @@ impl RustType for UnaryFunc { CastInt16ToFloat64(()) => Ok(impls::CastInt16ToFloat64.into()), CastInt16ToInt32(()) => Ok(impls::CastInt16ToInt32.into()), CastInt16ToInt64(()) => Ok(impls::CastInt16ToInt64.into()), + CastInt16ToUint16(()) => Ok(impls::CastInt16ToUint16.into()), + CastInt16ToUint32(()) => Ok(impls::CastInt16ToUint32.into()), + CastInt16ToUint64(()) => Ok(impls::CastInt16ToUint64.into()), CastInt16ToString(()) => Ok(impls::CastInt16ToString.into()), CastInt2VectorToArray(()) => Ok(impls::CastInt2VectorToArray.into()), CastInt32ToBool(()) => Ok(impls::CastInt32ToBool.into()), @@ -4046,6 +4187,9 @@ impl RustType for UnaryFunc { CastInt32ToPgLegacyChar(()) => Ok(impls::CastInt32ToPgLegacyChar.into()), CastInt32ToInt16(()) => Ok(impls::CastInt32ToInt16.into()), CastInt32ToInt64(()) => Ok(impls::CastInt32ToInt64.into()), + CastInt32ToUint16(()) => Ok(impls::CastInt32ToUint16.into()), + CastInt32ToUint32(()) => Ok(impls::CastInt32ToUint32.into()), + CastInt32ToUint64(()) => Ok(impls::CastInt32ToUint64.into()), CastInt32ToString(()) => Ok(impls::CastInt32ToString.into()), CastOidToInt32(()) => Ok(impls::CastOidToInt32.into()), CastOidToInt64(()) => Ok(impls::CastOidToInt64.into()), @@ -4058,6 +4202,9 @@ impl RustType for UnaryFunc { CastRegTypeToOid(()) => Ok(impls::CastRegTypeToOid.into()), CastInt64ToInt16(()) => Ok(impls::CastInt64ToInt16.into()), CastInt64ToInt32(()) => Ok(impls::CastInt64ToInt32.into()), + CastInt64ToUint16(()) => Ok(impls::CastInt64ToUint16.into()), + CastInt64ToUint32(()) => Ok(impls::CastInt64ToUint32.into()), + CastInt64ToUint64(()) => Ok(impls::CastInt64ToUint64.into()), CastInt16ToNumeric(max_scale) => { Ok(impls::CastInt16ToNumeric(max_scale.into_rust()?).into()) } @@ -4072,9 +4219,42 @@ impl RustType for UnaryFunc { CastInt64ToFloat64(()) => Ok(impls::CastInt64ToFloat64.into()), CastInt64ToOid(()) => Ok(impls::CastInt64ToOid.into()), CastInt64ToString(()) => Ok(impls::CastInt64ToString.into()), + CastUint16ToUint32(()) => Ok(impls::CastUint16ToUint32.into()), + CastUint16ToUint64(()) => Ok(impls::CastUint16ToUint64.into()), + CastUint16ToInt32(()) => Ok(impls::CastUint16ToInt32.into()), + CastUint16ToInt64(()) => Ok(impls::CastUint16ToInt64.into()), + CastUint16ToNumeric(max_scale) => { + Ok(impls::CastUint16ToNumeric(max_scale.into_rust()?).into()) + } + CastUint16ToFloat32(()) => Ok(impls::CastUint16ToFloat32.into()), + CastUint16ToFloat64(()) => Ok(impls::CastUint16ToFloat64.into()), + CastUint16ToString(()) => Ok(impls::CastUint16ToString.into()), + CastUint32ToUint16(()) => Ok(impls::CastUint32ToUint16.into()), + CastUint32ToUint64(()) => Ok(impls::CastUint32ToUint64.into()), + CastUint32ToInt32(()) => Ok(impls::CastUint32ToInt32.into()), + CastUint32ToInt64(()) => Ok(impls::CastUint32ToInt64.into()), + CastUint32ToNumeric(max_scale) => { + Ok(impls::CastUint32ToNumeric(max_scale.into_rust()?).into()) + } + CastUint32ToFloat32(()) => Ok(impls::CastUint32ToFloat32.into()), + CastUint32ToFloat64(()) => Ok(impls::CastUint32ToFloat64.into()), + CastUint32ToString(()) => Ok(impls::CastUint32ToString.into()), + CastUint64ToUint16(()) => Ok(impls::CastUint64ToUint16.into()), + CastUint64ToUint32(()) => Ok(impls::CastUint64ToUint32.into()), + CastUint64ToInt32(()) => Ok(impls::CastUint64ToInt32.into()), + CastUint64ToInt64(()) => Ok(impls::CastUint64ToInt64.into()), + CastUint64ToNumeric(max_scale) => { + Ok(impls::CastUint64ToNumeric(max_scale.into_rust()?).into()) + } + CastUint64ToFloat32(()) => Ok(impls::CastUint64ToFloat32.into()), + CastUint64ToFloat64(()) => Ok(impls::CastUint64ToFloat64.into()), + CastUint64ToString(()) => Ok(impls::CastUint64ToString.into()), CastFloat32ToInt16(()) => Ok(impls::CastFloat32ToInt16.into()), CastFloat32ToInt32(()) => Ok(impls::CastFloat32ToInt32.into()), CastFloat32ToInt64(()) => Ok(impls::CastFloat32ToInt64.into()), + CastFloat32ToUint16(()) => Ok(impls::CastFloat32ToUint16.into()), + CastFloat32ToUint32(()) => Ok(impls::CastFloat32ToUint32.into()), + CastFloat32ToUint64(()) => Ok(impls::CastFloat32ToUint64.into()), CastFloat32ToFloat64(()) => Ok(impls::CastFloat32ToFloat64.into()), CastFloat32ToString(()) => Ok(impls::CastFloat32ToString.into()), CastFloat32ToNumeric(max_scale) => { @@ -4086,6 +4266,9 @@ impl RustType for UnaryFunc { CastFloat64ToInt16(()) => Ok(impls::CastFloat64ToInt16.into()), CastFloat64ToInt32(()) => Ok(impls::CastFloat64ToInt32.into()), CastFloat64ToInt64(()) => Ok(impls::CastFloat64ToInt64.into()), + CastFloat64ToUint16(()) => Ok(impls::CastFloat64ToUint16.into()), + CastFloat64ToUint32(()) => Ok(impls::CastFloat64ToUint32.into()), + CastFloat64ToUint64(()) => Ok(impls::CastFloat64ToUint64.into()), CastFloat64ToFloat32(()) => Ok(impls::CastFloat64ToFloat32.into()), CastFloat64ToString(()) => Ok(impls::CastFloat64ToString.into()), CastNumericToFloat32(()) => Ok(impls::CastNumericToFloat32.into()), @@ -4093,6 +4276,9 @@ impl RustType for UnaryFunc { CastNumericToInt16(()) => Ok(impls::CastNumericToInt16.into()), CastNumericToInt32(()) => Ok(impls::CastNumericToInt32.into()), CastNumericToInt64(()) => Ok(impls::CastNumericToInt64.into()), + CastNumericToUint16(()) => Ok(impls::CastNumericToUint16.into()), + CastNumericToUint32(()) => Ok(impls::CastNumericToUint32.into()), + CastNumericToUint64(()) => Ok(impls::CastNumericToUint64.into()), CastNumericToString(()) => Ok(impls::CastNumericToString.into()), CastStringToBool(()) => Ok(impls::CastStringToBool.into()), CastStringToPgLegacyChar(()) => Ok(impls::CastStringToPgLegacyChar.into()), @@ -4100,6 +4286,9 @@ impl RustType for UnaryFunc { CastStringToInt16(()) => Ok(impls::CastStringToInt16.into()), CastStringToInt32(()) => Ok(impls::CastStringToInt32.into()), CastStringToInt64(()) => Ok(impls::CastStringToInt64.into()), + CastStringToUint16(()) => Ok(impls::CastStringToUint16.into()), + CastStringToUint32(()) => Ok(impls::CastStringToUint32.into()), + CastStringToUint64(()) => Ok(impls::CastStringToUint64.into()), CastStringToInt2Vector(()) => Ok(impls::CastStringToInt2Vector.into()), CastStringToOid(()) => Ok(impls::CastStringToOid.into()), CastStringToFloat32(()) => Ok(impls::CastStringToFloat32.into()), @@ -4850,7 +5039,11 @@ where Int16 => Ok(strconv::format_int16(buf, d.unwrap_int16())), Int32 => Ok(strconv::format_int32(buf, d.unwrap_int32())), Int64 => Ok(strconv::format_int64(buf, d.unwrap_int64())), - Oid | RegClass | RegProc | RegType => Ok(strconv::format_oid(buf, d.unwrap_uint32())), + UInt16 => Ok(strconv::format_uint16(buf, d.unwrap_uint16())), + UInt32 | Oid | RegClass | RegProc | RegType => { + Ok(strconv::format_uint32(buf, d.unwrap_uint32())) + } + UInt64 => Ok(strconv::format_uint64(buf, d.unwrap_uint64())), Float32 => Ok(strconv::format_float32(buf, d.unwrap_float32())), Float64 => Ok(strconv::format_float64(buf, d.unwrap_float64())), Numeric { .. } => Ok(strconv::format_numeric(buf, &d.unwrap_numeric())), diff --git a/src/expr/src/scalar/func/impls.rs b/src/expr/src/scalar/func/impls.rs index 092d5917a706..74a1ddd63bfb 100644 --- a/src/expr/src/scalar/func/impls.rs +++ b/src/expr/src/scalar/func/impls.rs @@ -31,6 +31,9 @@ mod regproc; mod string; mod time; mod timestamp; +mod uint16; +mod uint32; +mod uint64; mod uuid; mod varchar; @@ -59,4 +62,7 @@ pub use regproc::*; pub use string::*; pub use time::*; pub use timestamp::*; +pub use uint16::*; +pub use uint32::*; +pub use uint64::*; pub use varchar::*; diff --git a/src/expr/src/scalar/func/impls/float32.rs b/src/expr/src/scalar/func/impls/float32.rs index 4bd4782e1518..6d56fc5d48bc 100644 --- a/src/expr/src/scalar/func/impls/float32.rs +++ b/src/expr/src/scalar/func/impls/float32.rs @@ -126,6 +126,42 @@ sqlfunc!( } ); +sqlfunc!( + #[sqlname = "real_to_uint2"] + fn cast_float32_to_uint16(a: f32) -> Result { + let f = round_float32(a); + if (f >= 0.0) && (f <= (u16::MAX as f32)) { + Ok(f as u16) + } else { + Err(EvalError::UInt16OutOfRange) + } + } +); + +sqlfunc!( + #[sqlname = "real_to_uint4"] + fn cast_float32_to_uint32(a: f32) -> Result { + let f = round_float32(a); + if (f >= 0.0) && (f <= (u32::MAX as f32)) { + Ok(f as u32) + } else { + Err(EvalError::UInt32OutOfRange) + } + } +); + +sqlfunc!( + #[sqlname = "real_to_uint8"] + fn cast_float32_to_uint64(a: f32) -> Result { + let f = round_float32(a); + if (f >= 0.0) && (f <= (u64::MAX as f32)) { + Ok(f as u64) + } else { + Err(EvalError::UInt64OutOfRange) + } + } +); + #[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)] pub struct CastFloat32ToNumeric(pub Option); diff --git a/src/expr/src/scalar/func/impls/float64.rs b/src/expr/src/scalar/func/impls/float64.rs index d48c93ee513a..796a36e32652 100644 --- a/src/expr/src/scalar/func/impls/float64.rs +++ b/src/expr/src/scalar/func/impls/float64.rs @@ -134,6 +134,42 @@ sqlfunc!( } ); +sqlfunc!( + #[sqlname = "double_to_uint2"] + fn cast_float64_to_uint16(a: f64) -> Result { + let f = round_float64(a); + if (f >= 0.0) && (f <= (u16::MAX as f64)) { + Ok(f as u16) + } else { + Err(EvalError::UInt16OutOfRange) + } + } +); + +sqlfunc!( + #[sqlname = "double_to_uint4"] + fn cast_float64_to_uint32(a: f64) -> Result { + let f = round_float64(a); + if (f >= 0.0) && (f <= (u32::MAX as f64)) { + Ok(f as u32) + } else { + Err(EvalError::UInt32OutOfRange) + } + } +); + +sqlfunc!( + #[sqlname = "double_to_uint8"] + fn cast_float64_to_uint64(a: f64) -> Result { + let f = round_float64(a); + if (f >= 0.0) && (f <= (u64::MAX as f64)) { + Ok(f as u64) + } else { + Err(EvalError::UInt64OutOfRange) + } + } +); + #[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)] pub struct CastFloat64ToNumeric(pub Option); diff --git a/src/expr/src/scalar/func/impls/int16.rs b/src/expr/src/scalar/func/impls/int16.rs index f82823d29636..45b44bd41608 100644 --- a/src/expr/src/scalar/func/impls/int16.rs +++ b/src/expr/src/scalar/func/impls/int16.rs @@ -81,6 +81,30 @@ sqlfunc!( } ); +sqlfunc!( + #[sqlname = "smallint_to_uint2"] + #[preserves_uniqueness = true] + fn cast_int16_to_uint16(a: i16) -> Result { + u16::try_from(a).or(Err(EvalError::UInt16OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "smallint_to_uint4"] + #[preserves_uniqueness = true] + fn cast_int16_to_uint32(a: i16) -> Result { + u32::try_from(a).or(Err(EvalError::UInt32OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "smallint_to_uint8"] + #[preserves_uniqueness = true] + fn cast_int16_to_uint64(a: i16) -> Result { + u64::try_from(a).or(Err(EvalError::UInt64OutOfRange)) + } +); + #[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)] pub struct CastInt16ToNumeric(pub Option); diff --git a/src/expr/src/scalar/func/impls/int32.rs b/src/expr/src/scalar/func/impls/int32.rs index bc7c2c42aeb9..e3e7adabde36 100644 --- a/src/expr/src/scalar/func/impls/int32.rs +++ b/src/expr/src/scalar/func/impls/int32.rs @@ -88,6 +88,30 @@ sqlfunc!( } ); +sqlfunc!( + #[sqlname = "integer_to_uint2"] + #[preserves_uniqueness = true] + fn cast_int32_to_uint16(a: i32) -> Result { + u16::try_from(a).or(Err(EvalError::UInt16OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "integer_to_uint4"] + #[preserves_uniqueness = true] + fn cast_int32_to_uint32(a: i32) -> Result { + u32::try_from(a).or(Err(EvalError::UInt32OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "integer_to_uint8"] + #[preserves_uniqueness = true] + fn cast_int32_to_uint64(a: i32) -> Result { + u64::try_from(a).or(Err(EvalError::UInt64OutOfRange)) + } +); + #[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)] pub struct CastInt32ToNumeric(pub Option); diff --git a/src/expr/src/scalar/func/impls/int64.rs b/src/expr/src/scalar/func/impls/int64.rs index c8c54371fa44..26ca8d1cfc38 100644 --- a/src/expr/src/scalar/func/impls/int64.rs +++ b/src/expr/src/scalar/func/impls/int64.rs @@ -75,6 +75,30 @@ sqlfunc!( } ); +sqlfunc!( + #[sqlname = "bigint_to_uint2"] + #[preserves_uniqueness = true] + fn cast_int64_to_uint16(a: i64) -> Result { + u16::try_from(a).or(Err(EvalError::UInt16OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "bigint_to_uint4"] + #[preserves_uniqueness = true] + fn cast_int64_to_uint32(a: i64) -> Result { + u32::try_from(a).or(Err(EvalError::UInt32OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "bigint_to_uint8"] + #[preserves_uniqueness = true] + fn cast_int64_to_uint64(a: i64) -> Result { + u64::try_from(a).or(Err(EvalError::UInt64OutOfRange)) + } +); + #[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)] pub struct CastInt64ToNumeric(pub Option); diff --git a/src/expr/src/scalar/func/impls/numeric.rs b/src/expr/src/scalar/func/impls/numeric.rs index 540f6396c6f3..361947c8e973 100644 --- a/src/expr/src/scalar/func/impls/numeric.rs +++ b/src/expr/src/scalar/func/impls/numeric.rs @@ -229,6 +229,37 @@ sqlfunc!( } ); +sqlfunc!( + #[sqlname = "numeric_to_uint2"] + fn cast_numeric_to_uint16(mut a: Numeric) -> Result { + let mut cx = numeric::cx_datum(); + cx.round(&mut a); + cx.clear_status(); + let u = cx.try_into_u32(a).or(Err(EvalError::UInt16OutOfRange))?; + u16::try_from(u).or(Err(EvalError::UInt16OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "numeric_to_uint4"] + fn cast_numeric_to_uint32(mut a: Numeric) -> Result { + let mut cx = numeric::cx_datum(); + cx.round(&mut a); + cx.clear_status(); + cx.try_into_u32(a).or(Err(EvalError::UInt32OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "numeric_to_uint8"] + fn cast_numeric_to_uint64(mut a: Numeric) -> Result { + let mut cx = numeric::cx_datum(); + cx.round(&mut a); + cx.clear_status(); + cx.try_into_u64(a).or(Err(EvalError::UInt64OutOfRange)) + } +); + #[derive( Arbitrary, Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect, )] diff --git a/src/expr/src/scalar/func/impls/oid.rs b/src/expr/src/scalar/func/impls/oid.rs index 6b3483f0a9bf..2593bc1d0f1d 100644 --- a/src/expr/src/scalar/func/impls/oid.rs +++ b/src/expr/src/scalar/func/impls/oid.rs @@ -16,7 +16,7 @@ sqlfunc!( #[preserves_uniqueness = true] fn cast_oid_to_string(a: Oid) -> String { let mut buf = String::new(); - strconv::format_oid(&mut buf, a.0); + strconv::format_uint32(&mut buf, a.0); buf } ); diff --git a/src/expr/src/scalar/func/impls/string.rs b/src/expr/src/scalar/func/impls/string.rs index ffee61375b0d..94a8fc6f06b3 100644 --- a/src/expr/src/scalar/func/impls/string.rs +++ b/src/expr/src/scalar/func/impls/string.rs @@ -98,6 +98,27 @@ sqlfunc!( } ); +sqlfunc!( + #[sqlname = "text_to_uint2"] + fn cast_string_to_uint16(a: &'a str) -> Result { + strconv::parse_uint16(a).err_into() + } +); + +sqlfunc!( + #[sqlname = "text_to_uint4"] + fn cast_string_to_uint32(a: &'a str) -> Result { + strconv::parse_uint32(a).err_into() + } +); + +sqlfunc!( + #[sqlname = "text_to_uint8"] + fn cast_string_to_uint64(a: &'a str) -> Result { + strconv::parse_uint64(a).err_into() + } +); + #[derive( Arbitrary, Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect, )] diff --git a/src/expr/src/scalar/func/impls/uint16.rs b/src/expr/src/scalar/func/impls/uint16.rs new file mode 100644 index 000000000000..592a7bbf026a --- /dev/null +++ b/src/expr/src/scalar/func/impls/uint16.rs @@ -0,0 +1,105 @@ +// Copyright Materialize, Inc. and contributors. All rights reserved. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0. + +use std::fmt; + +use serde::{Deserialize, Serialize}; + +use mz_lowertest::MzReflect; +use mz_repr::adt::numeric::{self, Numeric, NumericMaxScale}; +use mz_repr::{strconv, ColumnType, ScalarType}; + +use crate::scalar::func::EagerUnaryFunc; +use crate::EvalError; + +sqlfunc!( + #[sqlname = "uint2_to_real"] + #[preserves_uniqueness = true] + fn cast_uint16_to_float32(a: u16) -> f32 { + f32::from(a) + } +); + +sqlfunc!( + #[sqlname = "uint2_to_double"] + #[preserves_uniqueness = true] + fn cast_uint16_to_float64(a: u16) -> f64 { + f64::from(a) + } +); + +sqlfunc!( + #[sqlname = "uint2_to_integer"] + #[preserves_uniqueness = true] + fn cast_uint16_to_int32(a: u16) -> i32 { + i32::from(a) + } +); + +sqlfunc!( + #[sqlname = "uint2_to_uint4"] + #[preserves_uniqueness = true] + fn cast_uint16_to_uint32(a: u16) -> u32 { + u32::from(a) + } +); + +sqlfunc!( + #[sqlname = "uint2_to_bigint"] + #[preserves_uniqueness = true] + fn cast_uint16_to_int64(a: u16) -> i64 { + i64::from(a) + } +); + +sqlfunc!( + #[sqlname = "uint2_to_uint8"] + #[preserves_uniqueness = true] + fn cast_uint16_to_uint64(a: u16) -> u64 { + u64::from(a) + } +); + +sqlfunc!( + #[sqlname = "uint2_to_text"] + #[preserves_uniqueness = true] + fn cast_uint16_to_string(a: u16) -> String { + let mut buf = String::new(); + strconv::format_uint16(&mut buf, a); + buf + } +); + +#[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)] +pub struct CastUint16ToNumeric(pub Option); + +impl<'a> EagerUnaryFunc<'a> for CastUint16ToNumeric { + type Input = u16; + type Output = Result; + + fn call(&self, a: u16) -> Result { + let mut a = Numeric::from(i32::from(a)); + if let Some(scale) = self.0 { + if numeric::rescale(&mut a, scale.into_u8()).is_err() { + return Err(EvalError::NumericFieldOverflow); + } + } + Ok(a) + } + + fn output_type(&self, input: ColumnType) -> ColumnType { + ScalarType::Numeric { max_scale: self.0 }.nullable(input.nullable) + } +} + +impl fmt::Display for CastUint16ToNumeric { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("uint2_to_numeric") + } +} diff --git a/src/expr/src/scalar/func/impls/uint32.rs b/src/expr/src/scalar/func/impls/uint32.rs new file mode 100644 index 000000000000..38c8b9960766 --- /dev/null +++ b/src/expr/src/scalar/func/impls/uint32.rs @@ -0,0 +1,105 @@ +// Copyright Materialize, Inc. and contributors. All rights reserved. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0. + +use std::fmt; + +use serde::{Deserialize, Serialize}; + +use mz_lowertest::MzReflect; +use mz_repr::adt::numeric::{self, Numeric, NumericMaxScale}; +use mz_repr::{strconv, ColumnType, ScalarType}; + +use crate::scalar::func::EagerUnaryFunc; +use crate::EvalError; + +sqlfunc!( + #[sqlname = "uint4_to_real"] + fn cast_uint32_to_float32(a: u32) -> f32 { + a as f32 + } +); + +sqlfunc!( + #[sqlname = "uint4_to_double"] + #[preserves_uniqueness = true] + fn cast_uint32_to_float64(a: u32) -> f64 { + f64::from(a) + } +); + +sqlfunc!( + #[sqlname = "uint4_to_uint2"] + #[preserves_uniqueness = true] + fn cast_uint32_to_uint16(a: u32) -> Result { + u16::try_from(a).or(Err(EvalError::UInt16OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "uint4_to_integer"] + #[preserves_uniqueness = true] + fn cast_uint32_to_int32(a: u32) -> Result { + i32::try_from(a).or(Err(EvalError::Int32OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "uint4_to_bigint"] + #[preserves_uniqueness = true] + fn cast_uint32_to_int64(a: u32) -> i64 { + i64::from(a) + } +); + +sqlfunc!( + #[sqlname = "uint4_to_uint8"] + #[preserves_uniqueness = true] + fn cast_uint32_to_uint64(a: u32) -> u64 { + u64::from(a) + } +); + +sqlfunc!( + #[sqlname = "uint4_to_text"] + #[preserves_uniqueness = true] + fn cast_uint32_to_string(a: u32) -> String { + let mut buf = String::new(); + strconv::format_uint32(&mut buf, a); + buf + } +); + +#[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)] +pub struct CastUint32ToNumeric(pub Option); + +impl<'a> EagerUnaryFunc<'a> for CastUint32ToNumeric { + type Input = u32; + type Output = Result; + + fn call(&self, a: u32) -> Result { + let mut a = Numeric::from(a); + if let Some(scale) = self.0 { + if numeric::rescale(&mut a, scale.into_u8()).is_err() { + return Err(EvalError::NumericFieldOverflow); + } + } + // Besides `rescale`, cast is infallible. + Ok(a) + } + + fn output_type(&self, input: ColumnType) -> ColumnType { + ScalarType::Numeric { max_scale: self.0 }.nullable(input.nullable) + } +} + +impl fmt::Display for CastUint32ToNumeric { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("uint4_to_numeric") + } +} diff --git a/src/expr/src/scalar/func/impls/uint64.rs b/src/expr/src/scalar/func/impls/uint64.rs new file mode 100644 index 000000000000..765c8ba1a054 --- /dev/null +++ b/src/expr/src/scalar/func/impls/uint64.rs @@ -0,0 +1,104 @@ +// Copyright Materialize, Inc. and contributors. All rights reserved. +// +// Use of this software is governed by the Business Source License +// included in the LICENSE file. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0. + +use std::fmt; + +use serde::{Deserialize, Serialize}; + +use mz_lowertest::MzReflect; +use mz_repr::adt::numeric::{self, Numeric, NumericMaxScale}; +use mz_repr::{strconv, ColumnType, ScalarType}; + +use crate::scalar::func::EagerUnaryFunc; +use crate::EvalError; + +sqlfunc!( + #[sqlname = "uint8_to_real"] + fn cast_uint64_to_float32(a: u64) -> f32 { + a as f32 + } +); + +sqlfunc!( + #[sqlname = "uint8_to_double"] + fn cast_uint64_to_float64(a: u64) -> f64 { + a as f64 + } +); + +sqlfunc!( + #[sqlname = "uint8_to_uint2"] + #[preserves_uniqueness = true] + fn cast_uint64_to_uint16(a: u64) -> Result { + u16::try_from(a).or(Err(EvalError::UInt16OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "uint8_to_integer"] + #[preserves_uniqueness = true] + fn cast_uint64_to_int32(a: u64) -> Result { + i32::try_from(a).or(Err(EvalError::Int32OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "uint8_to_uint4"] + #[preserves_uniqueness = true] + fn cast_uint64_to_uint32(a: u64) -> Result { + u32::try_from(a).or(Err(EvalError::UInt32OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "uint8_to_bigint"] + #[preserves_uniqueness = true] + fn cast_uint64_to_int64(a: u64) -> Result { + i64::try_from(a).or(Err(EvalError::Int64OutOfRange)) + } +); + +sqlfunc!( + #[sqlname = "uint8_to_text"] + #[preserves_uniqueness = true] + fn cast_uint64_to_string(a: u64) -> String { + let mut buf = String::new(); + strconv::format_uint64(&mut buf, a); + buf + } +); + +#[derive(Ord, PartialOrd, Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, MzReflect)] +pub struct CastUint64ToNumeric(pub Option); + +impl<'a> EagerUnaryFunc<'a> for CastUint64ToNumeric { + type Input = u64; + type Output = Result; + + fn call(&self, a: u64) -> Result { + let mut a = Numeric::from(a); + if let Some(scale) = self.0 { + if numeric::rescale(&mut a, scale.into_u8()).is_err() { + return Err(EvalError::NumericFieldOverflow); + } + } + // Besides `rescale`, cast is infallible. + Ok(a) + } + + fn output_type(&self, input: ColumnType) -> ColumnType { + ScalarType::Numeric { max_scale: self.0 }.nullable(input.nullable) + } +} + +impl fmt::Display for CastUint64ToNumeric { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("bigint_to_numeric") + } +} diff --git a/src/expr/src/scalar/mod.rs b/src/expr/src/scalar/mod.rs index 3ccb37c93b01..a61c1325b50e 100644 --- a/src/expr/src/scalar/mod.rs +++ b/src/expr/src/scalar/mod.rs @@ -1620,6 +1620,9 @@ pub enum EvalError { Int16OutOfRange, Int32OutOfRange, Int64OutOfRange, + UInt16OutOfRange, + UInt32OutOfRange, + UInt64OutOfRange, OidOutOfRange, IntervalOutOfRange, TimestampOutOfRange, @@ -1707,6 +1710,9 @@ impl fmt::Display for EvalError { EvalError::Int16OutOfRange => f.write_str("smallint out of range"), EvalError::Int32OutOfRange => f.write_str("integer out of range"), EvalError::Int64OutOfRange => f.write_str("bigint out of range"), + EvalError::UInt16OutOfRange => f.write_str("uint2 out of range"), + EvalError::UInt32OutOfRange => f.write_str("uint4 out of range"), + EvalError::UInt64OutOfRange => f.write_str("uint8 out of range"), EvalError::OidOutOfRange => f.write_str("OID out of range"), EvalError::IntervalOutOfRange => f.write_str("interval out of range"), EvalError::TimestampOutOfRange => f.write_str("timestamp out of range"), @@ -1909,6 +1915,9 @@ impl RustType for EvalError { EvalError::Int16OutOfRange => Int16OutOfRange(()), EvalError::Int32OutOfRange => Int32OutOfRange(()), EvalError::Int64OutOfRange => Int64OutOfRange(()), + EvalError::UInt16OutOfRange => Uint16OutOfRange(()), + EvalError::UInt32OutOfRange => Uint32OutOfRange(()), + EvalError::UInt64OutOfRange => Uint64OutOfRange(()), EvalError::OidOutOfRange => OidOutOfRange(()), EvalError::IntervalOutOfRange => IntervalOutOfRange(()), EvalError::TimestampOutOfRange => TimestampOutOfRange(()), @@ -2011,6 +2020,9 @@ impl RustType for EvalError { Int16OutOfRange(()) => Ok(EvalError::Int16OutOfRange), Int32OutOfRange(()) => Ok(EvalError::Int32OutOfRange), Int64OutOfRange(()) => Ok(EvalError::Int64OutOfRange), + Uint16OutOfRange(()) => Ok(EvalError::UInt16OutOfRange), + Uint32OutOfRange(()) => Ok(EvalError::UInt32OutOfRange), + Uint64OutOfRange(()) => Ok(EvalError::UInt64OutOfRange), OidOutOfRange(()) => Ok(EvalError::OidOutOfRange), IntervalOutOfRange(()) => Ok(EvalError::IntervalOutOfRange), TimestampOutOfRange(()) => Ok(EvalError::TimestampOutOfRange), diff --git a/src/interchange/src/avro/encode.rs b/src/interchange/src/avro/encode.rs index 886180d7853e..423d524dd73c 100644 --- a/src/interchange/src/avro/encode.rs +++ b/src/interchange/src/avro/encode.rs @@ -279,13 +279,16 @@ impl<'a> mz_avro::types::ToAvro for TypedDatum<'a> { } ScalarType::Int16 => Value::Int(i32::from(datum.unwrap_int16())), ScalarType::Int32 => Value::Int(datum.unwrap_int32()), + ScalarType::Int64 => Value::Long(datum.unwrap_int64()), + ScalarType::UInt16 => Value::Fixed(2, datum.unwrap_uint16().to_le_bytes().into()), + ScalarType::UInt32 => Value::Fixed(4, datum.unwrap_uint32().to_le_bytes().into()), + ScalarType::UInt64 => Value::Fixed(8, datum.unwrap_uint64().to_le_bytes().into()), ScalarType::Oid | ScalarType::RegClass | ScalarType::RegProc | ScalarType::RegType => { Value::Fixed(4, datum.unwrap_uint32().to_le_bytes().into()) } - ScalarType::Int64 => Value::Long(datum.unwrap_int64()), ScalarType::Float32 => Value::Float(datum.unwrap_float32()), ScalarType::Float64 => Value::Double(datum.unwrap_float64()), ScalarType::Numeric { max_scale } => { diff --git a/src/interchange/src/json.rs b/src/interchange/src/json.rs index 851bed8e029c..21366865fb18 100644 --- a/src/interchange/src/json.rs +++ b/src/interchange/src/json.rs @@ -124,12 +124,15 @@ impl ToJson for TypedDatum<'_> { ScalarType::Int16 => json!(datum.unwrap_int16()), ScalarType::Int32 => json!(datum.unwrap_int32()), ScalarType::Int64 => json!(datum.unwrap_int64()), - ScalarType::Oid + ScalarType::UInt16 => json!(datum.unwrap_uint16()), + ScalarType::UInt32 + | ScalarType::Oid | ScalarType::RegClass | ScalarType::RegProc | ScalarType::RegType => { json!(datum.unwrap_uint32()) } + ScalarType::UInt64 => json!(datum.unwrap_uint64()), ScalarType::Float32 => json!(datum.unwrap_float32()), ScalarType::Float64 => json!(datum.unwrap_float64()), ScalarType::Numeric { .. } => { @@ -237,12 +240,24 @@ fn build_row_schema_field String>( json!("int") } ScalarType::Int64 => json!("long"), - ScalarType::Oid | ScalarType::RegClass | ScalarType::RegProc | ScalarType::RegType => { + ScalarType::UInt16 => json!({ + "type": "fixed", + "size": 2, + }), + ScalarType::UInt32 + | ScalarType::Oid + | ScalarType::RegClass + | ScalarType::RegProc + | ScalarType::RegType => { json!({ "type": "fixed", "size": 4, }) } + ScalarType::UInt64 => json!({ + "type": "fixed", + "size": 8, + }), ScalarType::Float32 => json!("float"), ScalarType::Float64 => json!("double"), ScalarType::Date => json!({ diff --git a/src/pgrepr/src/oid.rs b/src/pgrepr/src/oid.rs index e5fcb4123006..fdb4ae45d856 100644 --- a/src/pgrepr/src/oid.rs +++ b/src/pgrepr/src/oid.rs @@ -101,3 +101,9 @@ pub const FUNC_MAP_LENGTH_OID: u32 = 16_456; pub const FUNC_MZ_PANIC_OID: u32 = 16_457; pub const FUNC_MZ_VERSION_NUM_OID: u32 = 16_458; pub const FUNC_TRUNC_F32_OID: u32 = 16_459; +pub const TYPE_UINT2_OID: u32 = 16_460; +pub const TYPE_UINT2_ARRAY_OID: u32 = 16_461; +pub const TYPE_UINT4_OID: u32 = 16_462; +pub const TYPE_UINT4_ARRAY_OID: u32 = 16_463; +pub const TYPE_UINT8_OID: u32 = 16_464; +pub const TYPE_UINT8_ARRAY_OID: u32 = 16_465; diff --git a/src/pgrepr/src/types.rs b/src/pgrepr/src/types.rs index 5566c0722ac6..d6412a8b9719 100644 --- a/src/pgrepr/src/types.rs +++ b/src/pgrepr/src/types.rs @@ -67,6 +67,12 @@ pub enum Type { Int4, /// An 8-byte signed integer. Int8, + /// A 2-byte unsigned integer. This does not exist in PostgreSQL. + UInt2, + /// A 4-byte unsigned integer. This does not exist in PostgreSQL. + UInt4, + /// An 8-byte unsigned integer. This does not exist in PostgreSQL. + UInt8, /// A time interval. Interval { /// Optional constraints on the type. @@ -376,6 +382,66 @@ pub static ANYCOMPATIBLEMAP: Lazy = Lazy::new(|| { ) }); +/// An anonymous [`Type::UInt2`], akin to [`postgres_types::Type::INT2`]. +pub static UINT2: Lazy = Lazy::new(|| { + postgres_types::Type::new( + "uint2".to_owned(), + oid::TYPE_UINT2_OID, + postgres_types::Kind::Pseudo, + "mz_catalog".to_owned(), + ) +}); + +/// An anonymous [`Type::UInt4`], akin to [`postgres_types::Type::INT4`]. +pub static UINT4: Lazy = Lazy::new(|| { + postgres_types::Type::new( + "uint4".to_owned(), + oid::TYPE_UINT4_OID, + postgres_types::Kind::Pseudo, + "mz_catalog".to_owned(), + ) +}); + +/// An anonymous [`Type::UInt8`], akin to [`postgres_types::Type::INT8`]. +pub static UINT8: Lazy = Lazy::new(|| { + postgres_types::Type::new( + "uint8".to_owned(), + oid::TYPE_UINT8_OID, + postgres_types::Kind::Pseudo, + "mz_catalog".to_owned(), + ) +}); + +/// An anonymous [`Type::Array`], akin to [`postgres_types::Type::INT2_ARRAY`]. +pub static UINT2_ARRAY: Lazy = Lazy::new(|| { + postgres_types::Type::new( + "uint2_array".to_owned(), + oid::TYPE_UINT2_ARRAY_OID, + postgres_types::Kind::Pseudo, + "mz_catalog".to_owned(), + ) +}); + +/// An anonymous [`Type::Array`], akin to [`postgres_types::Type::INT4_ARRAY`]. +pub static UINT4_ARRAY: Lazy = Lazy::new(|| { + postgres_types::Type::new( + "uint4_array".to_owned(), + oid::TYPE_UINT4_ARRAY_OID, + postgres_types::Kind::Pseudo, + "mz_catalog".to_owned(), + ) +}); + +/// An anonymous [`Type::Array`], akin to [`postgres_types::Type::INT8_ARRAY`]. +pub static UINT8_ARRAY: Lazy = Lazy::new(|| { + postgres_types::Type::new( + "uint8_array".to_owned(), + oid::TYPE_UINT8_ARRAY_OID, + postgres_types::Kind::Pseudo, + "mz_catalog".to_owned(), + ) +}); + impl Type { /// Returns the type corresponding to the provided OID, if the OID is known. pub fn from_oid(oid: u32) -> Result { @@ -521,6 +587,9 @@ impl Type { Type::Int2 => &postgres_types::Type::INT2_ARRAY, Type::Int4 => &postgres_types::Type::INT4_ARRAY, Type::Int8 => &postgres_types::Type::INT8_ARRAY, + Type::UInt2 => &UINT2_ARRAY, + Type::UInt4 => &UINT4_ARRAY, + Type::UInt8 => &UINT8_ARRAY, Type::Interval { .. } => &postgres_types::Type::INTERVAL_ARRAY, Type::Json => &postgres_types::Type::JSON_ARRAY, Type::Jsonb => &postgres_types::Type::JSONB_ARRAY, @@ -551,6 +620,9 @@ impl Type { Type::Int2 => &postgres_types::Type::INT2, Type::Int4 => &postgres_types::Type::INT4, Type::Int8 => &postgres_types::Type::INT8, + Type::UInt2 => &UINT2, + Type::UInt4 => &UINT4, + Type::UInt8 => &UINT8, Type::Interval { .. } => &postgres_types::Type::INTERVAL, Type::Json => &postgres_types::Type::JSON, Type::Jsonb => &postgres_types::Type::JSONB, @@ -667,6 +739,9 @@ impl Type { | Type::Int2 | Type::Int4 | Type::Int8 + | Type::UInt2 + | Type::UInt4 + | Type::UInt8 | Type::Interval { constraints: None } | Type::Json | Type::Jsonb @@ -703,6 +778,9 @@ impl Type { Type::Int2 => 2, Type::Int4 => 4, Type::Int8 => 8, + Type::UInt2 => 2, + Type::UInt4 => 4, + Type::UInt8 => 8, Type::Interval { .. } => 16, Type::Json => -1, Type::Jsonb => -1, @@ -767,6 +845,9 @@ impl TryFrom<&Type> for ScalarType { Type::Int2 => Ok(ScalarType::Int16), Type::Int4 => Ok(ScalarType::Int32), Type::Int8 => Ok(ScalarType::Int64), + Type::UInt2 => Ok(ScalarType::UInt16), + Type::UInt4 => Ok(ScalarType::UInt32), + Type::UInt8 => Ok(ScalarType::UInt64), Type::Interval { .. } => Ok(ScalarType::Interval), Type::Json => Err(TypeConversionError::UnsupportedType(Type::Json)), Type::Jsonb => Ok(ScalarType::Jsonb), @@ -942,6 +1023,9 @@ impl From<&ScalarType> for Type { ScalarType::Int16 => Type::Int2, ScalarType::Int32 => Type::Int4, ScalarType::Int64 => Type::Int8, + ScalarType::UInt16 => Type::UInt2, + ScalarType::UInt32 => Type::UInt4, + ScalarType::UInt64 => Type::UInt8, ScalarType::Interval => Type::Interval { constraints: None }, ScalarType::Jsonb => Type::Jsonb, ScalarType::List { element_type, .. } => { diff --git a/src/pgrepr/src/value.rs b/src/pgrepr/src/value.rs index 87bd4ddccb15..2822be88c4d4 100644 --- a/src/pgrepr/src/value.rs +++ b/src/pgrepr/src/value.rs @@ -12,7 +12,7 @@ use std::error::Error; use std::io; use std::str; -use bytes::{BufMut, BytesMut}; +use bytes::{Buf, BufMut, BytesMut}; use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime, Utc}; use postgres_types::{FromSql, IsNull, ToSql, Type as PgType}; use uuid::Uuid; @@ -58,6 +58,12 @@ pub enum Value { Int4(i32), /// An 8-byte signed integer. Int8(i64), + /// A 2-byte unsigned integer. + UInt2(u16), + /// A 4-byte unsigned integer. + UInt4(u32), + /// An 8-byte unsigned integer. + UInt8(u64), /// A time interval. Interval(Interval), /// A binary JSON blob. @@ -107,10 +113,13 @@ impl Value { (Datum::Int32(i), ScalarType::Int32) => Some(Value::Int4(i)), (Datum::Int64(i), ScalarType::Int64) => Some(Value::Int8(i)), (Datum::UInt8(c), ScalarType::PgLegacyChar) => Some(Value::Char(c)), + (Datum::UInt16(u), ScalarType::UInt16) => Some(Value::UInt2(u)), (Datum::UInt32(oid), ScalarType::Oid) => Some(Value::Oid(oid)), (Datum::UInt32(oid), ScalarType::RegClass) => Some(Value::Oid(oid)), (Datum::UInt32(oid), ScalarType::RegProc) => Some(Value::Oid(oid)), (Datum::UInt32(oid), ScalarType::RegType) => Some(Value::Oid(oid)), + (Datum::UInt32(u), ScalarType::UInt32) => Some(Value::UInt4(u)), + (Datum::UInt64(u), ScalarType::UInt64) => Some(Value::UInt8(u)), (Datum::Float32(f), ScalarType::Float32) => Some(Value::Float4(*f)), (Datum::Float64(f), ScalarType::Float64) => Some(Value::Float8(*f)), (Datum::Numeric(d), ScalarType::Numeric { .. }) => Some(Value::Numeric(Numeric(d))), @@ -197,6 +206,9 @@ impl Value { Value::Int2(i) => Datum::Int16(i), Value::Int4(i) => Datum::Int32(i), Value::Int8(i) => Datum::Int64(i), + Value::UInt2(u) => Datum::UInt16(u), + Value::UInt4(u) => Datum::UInt32(u), + Value::UInt8(u) => Datum::UInt64(u), Value::Jsonb(js) => buf.push_unary_row(js.0.into_row()), Value::List(elems) => { let elem_pg_type = match typ { @@ -287,6 +299,9 @@ impl Value { Value::Int2(i) => strconv::format_int16(buf, *i), Value::Int4(i) => strconv::format_int32(buf, *i), Value::Int8(i) => strconv::format_int64(buf, *i), + Value::UInt2(u) => strconv::format_uint16(buf, *u), + Value::UInt4(u) => strconv::format_uint32(buf, *u), + Value::UInt8(u) => strconv::format_uint64(buf, *u), Value::Interval(iv) => strconv::format_interval(buf, iv.0), Value::Float4(f) => strconv::format_float32(buf, *f), Value::Float8(f) => strconv::format_float64(buf, *f), @@ -301,7 +316,7 @@ impl Value { Some(elem) => Ok(elem.encode_text(buf.nonnull_buffer())), }) .expect("provided closure never fails"), - Value::Oid(oid) => strconv::format_oid(buf, *oid), + Value::Oid(oid) => strconv::format_uint32(buf, *oid), Value::Record(elems) => strconv::format_record(buf, elems, |buf, elem| match elem { None => Ok::<_, ()>(buf.write_null()), Some(elem) => Ok(elem.encode_text(buf.nonnull_buffer())), @@ -352,6 +367,18 @@ impl Value { Value::Int2(i) => i.to_sql(&PgType::INT2, buf), Value::Int4(i) => i.to_sql(&PgType::INT4, buf), Value::Int8(i) => i.to_sql(&PgType::INT8, buf), + Value::UInt2(u) => { + buf.put_u16(*u); + Ok(IsNull::No) + } + Value::UInt4(u) => { + buf.put_u32(*u); + Ok(IsNull::No) + } + Value::UInt8(u) => { + buf.put_u64(*u); + Ok(IsNull::No) + } Value::Interval(iv) => iv.to_sql(&PgType::INTERVAL, buf), Value::Jsonb(js) => js.to_sql(&PgType::JSONB, buf), Value::List(_) => { @@ -454,6 +481,9 @@ impl Value { Type::Int2 => Value::Int2(strconv::parse_int16(s)?), Type::Int4 => Value::Int4(strconv::parse_int32(s)?), Type::Int8 => Value::Int8(strconv::parse_int64(s)?), + Type::UInt2 => Value::UInt2(strconv::parse_uint16(s)?), + Type::UInt4 => Value::UInt4(strconv::parse_uint32(s)?), + Type::UInt8 => Value::UInt8(strconv::parse_uint64(s)?), Type::Interval { .. } => Value::Interval(Interval(strconv::parse_interval(s)?)), Type::Json => return Err("input of json types is not implemented".into()), Type::Jsonb => Value::Jsonb(Jsonb(strconv::parse_jsonb(s)?)), @@ -488,7 +518,7 @@ impl Value { /// Deserializes a value of type `ty` from `raw` using the [binary encoding /// format](Format::Binary). - pub fn decode_binary(ty: &Type, raw: &[u8]) -> Result> { + pub fn decode_binary(ty: &Type, mut raw: &[u8]) -> Result> { match ty { Type::Array(_) => Err("input of array types is not implemented".into()), Type::Int2Vector => Err("input of int2vector types is not implemented".into()), @@ -502,6 +532,27 @@ impl Value { Type::Int2 => i16::from_sql(ty.inner(), raw).map(Value::Int2), Type::Int4 => i32::from_sql(ty.inner(), raw).map(Value::Int4), Type::Int8 => i64::from_sql(ty.inner(), raw).map(Value::Int8), + Type::UInt2 => { + let v = raw.get_u16(); + if !raw.is_empty() { + return Err("invalid buffer size".into()); + } + Ok(Value::UInt2(v)) + } + Type::UInt4 => { + let v = raw.get_u32(); + if !raw.is_empty() { + return Err("invalid buffer size".into()); + } + Ok(Value::UInt4(v)) + } + Type::UInt8 => { + let v = raw.get_u64(); + if !raw.is_empty() { + return Err("invalid buffer size".into()); + } + Ok(Value::UInt8(v)) + } Type::Interval { .. } => Interval::from_sql(ty.inner(), raw).map(Value::Interval), Type::Json => return Err("input of json types is not implemented".into()), Type::Jsonb => Jsonb::from_sql(ty.inner(), raw).map(Value::Jsonb), diff --git a/src/repr/src/relation_and_scalar.proto b/src/repr/src/relation_and_scalar.proto index 0e11380a7b79..6e6cb024d6ce 100644 --- a/src/repr/src/relation_and_scalar.proto +++ b/src/repr/src/relation_and_scalar.proto @@ -106,5 +106,8 @@ message ProtoScalarType { google.protobuf.Empty RegType = 26; google.protobuf.Empty RegClass = 27; google.protobuf.Empty Int2Vector = 28; + google.protobuf.Empty UInt16 = 29; + google.protobuf.Empty UInt32 = 30; + google.protobuf.Empty UInt64 = 31; } } diff --git a/src/repr/src/row.proto b/src/repr/src/row.proto index 868d8c02fae9..31d10c61f6fc 100644 --- a/src/repr/src/row.proto +++ b/src/repr/src/row.proto @@ -58,6 +58,8 @@ message ProtoDatum { bytes uuid = 25; uint32 uint32 = 26; uint32 uint8 = 27; + uint32 uint16 = 28; + uint64 uint64 = 29; } } diff --git a/src/repr/src/row.rs b/src/repr/src/row.rs index 0d2491b18a30..009551713e84 100644 --- a/src/repr/src/row.rs +++ b/src/repr/src/row.rs @@ -268,6 +268,8 @@ impl<'a> Serialize for DatumMap<'a> { map.end() } } + +// All new tags MUST be added to the end of the enum. #[derive(Debug, Clone, Copy, PartialEq, Eq, IntoPrimitive, TryFromPrimitive)] #[repr(u8)] enum Tag { @@ -301,6 +303,8 @@ enum Tag { JsonNull, Dummy, Numeric, + UInt16, + UInt64, } // -------------------------------------------------------------------------------- @@ -405,10 +409,18 @@ unsafe fn read_datum<'a>(data: &'a [u8], offset: &mut usize) -> Datum<'a> { let i = u8::from_le_bytes(read_byte_array(data, offset)); Datum::UInt8(i) } + Tag::UInt16 => { + let i = u16::from_le_bytes(read_byte_array(data, offset)); + Datum::UInt16(i) + } Tag::UInt32 => { let i = u32::from_le_bytes(read_byte_array(data, offset)); Datum::UInt32(i) } + Tag::UInt64 => { + let i = u64::from_le_bytes(read_byte_array(data, offset)); + Datum::UInt64(i) + } Tag::Float32 => { let f = f32::from_bits(u32::from_le_bytes(read_byte_array(data, offset))); Datum::Float32(OrderedFloat::from(f)) @@ -573,10 +585,18 @@ where data.push(Tag::UInt8.into()); data.extend_from_slice(&i.to_le_bytes()); } + Datum::UInt16(i) => { + data.push(Tag::UInt16.into()); + data.extend_from_slice(&i.to_le_bytes()); + } Datum::UInt32(i) => { data.push(Tag::UInt32.into()); data.extend_from_slice(&i.to_le_bytes()); } + Datum::UInt64(i) => { + data.push(Tag::UInt64.into()); + data.extend_from_slice(&i.to_le_bytes()); + } Datum::Float32(f) => { data.push(Tag::Float32.into()); data.extend_from_slice(&f.to_bits().to_le_bytes()); @@ -726,7 +746,9 @@ pub fn datum_size(datum: &Datum) -> usize { Datum::Int32(_) => 1 + size_of::(), Datum::Int64(_) => 1 + size_of::(), Datum::UInt8(_) => 1 + size_of::(), + Datum::UInt16(_) => 1 + size_of::(), Datum::UInt32(_) => 1 + size_of::(), + Datum::UInt64(_) => 1 + size_of::(), Datum::Float32(_) => 1 + size_of::(), Datum::Float64(_) => 1 + size_of::(), Datum::Date(_) => 1 + 8, diff --git a/src/repr/src/row/encoding.rs b/src/repr/src/row/encoding.rs index a24f5cb5c2af..c377d21c3763 100644 --- a/src/repr/src/row/encoding.rs +++ b/src/repr/src/row/encoding.rs @@ -69,7 +69,9 @@ impl<'a> From> for ProtoDatum { Datum::Int16(x) => DatumType::Int16(x.into()), Datum::Int32(x) => DatumType::Int32(x), Datum::UInt8(x) => DatumType::Uint8(x.into()), + Datum::UInt16(x) => DatumType::Uint16(x.into()), Datum::UInt32(x) => DatumType::Uint32(x), + Datum::UInt64(x) => DatumType::Uint64(x), Datum::Int64(x) => DatumType::Int64(x), Datum::Float32(x) => DatumType::Float32(x.into_inner()), Datum::Float64(x) => DatumType::Float64(x.into_inner()), @@ -173,7 +175,13 @@ impl RowPacker<'_> { .map_err(|_| format!("uint8 field stored with out of range value: {}", *x))?; self.push(Datum::UInt8(x)) } + Some(DatumType::Uint16(x)) => { + let x = u16::try_from(*x) + .map_err(|_| format!("uint16 field stored with out of range value: {}", *x))?; + self.push(Datum::UInt16(x)) + } Some(DatumType::Uint32(x)) => self.push(Datum::UInt32(*x)), + Some(DatumType::Uint64(x)) => self.push(Datum::UInt64(*x)), Some(DatumType::Float32(x)) => self.push(Datum::Float32((*x).into())), Some(DatumType::Float64(x)) => self.push(Datum::Float64((*x).into())), Some(DatumType::Bytes(x)) => self.push(Datum::Bytes(x)), diff --git a/src/repr/src/scalar.rs b/src/repr/src/scalar.rs index 7ee023d22932..547828aca668 100644 --- a/src/repr/src/scalar.rs +++ b/src/repr/src/scalar.rs @@ -60,8 +60,12 @@ pub enum Datum<'a> { Int64(i64), /// An 8-bit unsigned integer. UInt8(u8), + /// An 16-bit unsigned integer. + UInt16(u16), /// A 32-bit unsigned integer. UInt32(u32), + /// A 64-bit unsigned integer. + UInt64(u64), /// A 32-bit floating point number. Float32(OrderedFloat), /// A 64-bit floating point number. @@ -142,7 +146,9 @@ impl<'a> Serialize for Datum<'a> { Int32(i) => serializer.serialize_i32(*i), Int64(i) => serializer.serialize_i64(*i), UInt8(u) => serializer.serialize_u8(*u), + UInt16(u) => serializer.serialize_u16(*u), UInt32(u) => serializer.serialize_u32(*u), + UInt64(u) => serializer.serialize_u64(*u), Float32(f) => serializer.serialize_f32(**f), Float64(f) => serializer.serialize_f64(**f), Date(d) => d.serialize(serializer), @@ -372,7 +378,7 @@ impl<'a> Datum<'a> { } } - /// Unwraps the 8-bit integer value within this datum. + /// Unwraps the 8-bit unsigned integer value within this datum. /// /// # Panics /// @@ -385,7 +391,20 @@ impl<'a> Datum<'a> { } } - /// Unwraps the 64-bit integer value within this datum. + /// Unwraps the 16-bit unsigned integer value within this datum. + /// + /// # Panics + /// + /// Panics if the datum is not [`Datum::UInt16`]. + #[track_caller] + pub fn unwrap_uint16(&self) -> u16 { + match self { + Datum::UInt16(u) => *u, + _ => panic!("Datum::unwrap_uint16 called on {:?}", self), + } + } + + /// Unwraps the 32-bit unsigned integer value within this datum. /// /// # Panics /// @@ -398,6 +417,19 @@ impl<'a> Datum<'a> { } } + /// Unwraps the 64-bit unsigned integer value within this datum. + /// + /// # Panics + /// + /// Panics if the datum is not [`Datum::UInt64`]. + #[track_caller] + pub fn unwrap_uint64(&self) -> u64 { + match self { + Datum::UInt64(u) => *u, + _ => panic!("Datum::unwrap_uint64 called on {:?}", self), + } + } + #[track_caller] pub fn unwrap_ordered_float32(&self) -> OrderedFloat { match self { @@ -632,11 +664,16 @@ impl<'a> Datum<'a> { (Datum::Int64(_), _) => false, (Datum::UInt8(_), ScalarType::PgLegacyChar) => true, (Datum::UInt8(_), _) => false, + (Datum::UInt16(_), ScalarType::UInt16) => true, + (Datum::UInt16(_), _) => false, (Datum::UInt32(_), ScalarType::Oid) => true, (Datum::UInt32(_), ScalarType::RegClass) => true, (Datum::UInt32(_), ScalarType::RegProc) => true, (Datum::UInt32(_), ScalarType::RegType) => true, + (Datum::UInt32(_), ScalarType::UInt32) => true, (Datum::UInt32(_), _) => false, + (Datum::UInt64(_), ScalarType::UInt64) => true, + (Datum::UInt64(_), _) => false, (Datum::Float32(_), ScalarType::Float32) => true, (Datum::Float32(_), _) => false, (Datum::Float64(_), ScalarType::Float64) => true, @@ -863,7 +900,9 @@ impl fmt::Display for Datum<'_> { Datum::Int32(num) => write!(f, "{}", num), Datum::Int64(num) => write!(f, "{}", num), Datum::UInt8(num) => write!(f, "{}", num), + Datum::UInt16(num) => write!(f, "{}", num), Datum::UInt32(num) => write!(f, "{}", num), + Datum::UInt64(num) => write!(f, "{}", num), Datum::Float32(num) => write!(f, "{}", num), Datum::Float64(num) => write!(f, "{}", num), Datum::Date(d) => write!(f, "{}", d), @@ -930,7 +969,9 @@ impl From<&Datum<'_>> for serde_json::Value { Datum::Int32(n) => serde_json::Value::Number(serde_json::Number::from(*n)), Datum::Int64(n) => serde_json::Value::Number(serde_json::Number::from(*n)), Datum::UInt8(n) => serde_json::Value::Number(serde_json::Number::from(*n)), + Datum::UInt16(n) => serde_json::Value::Number(serde_json::Number::from(*n)), Datum::UInt32(n) => serde_json::Value::Number(serde_json::Number::from(*n)), + Datum::UInt64(n) => serde_json::Value::Number(serde_json::Number::from(*n)), Datum::Float32(n) => float_to_json(n.into_inner() as f64), Datum::Float64(n) => float_to_json(n.into_inner()), Datum::Numeric(d) => { @@ -988,6 +1029,12 @@ pub enum ScalarType { Int32, /// The type of [`Datum::Int64`]. Int64, + /// The type of [`Datum::UInt16`]. + UInt16, + /// The type of [`Datum::UInt32`]. + UInt32, + /// The type of [`Datum::UInt64`]. + UInt64, /// The type of [`Datum::Float32`]. Float32, /// The type of [`Datum::Float64`]. @@ -1120,6 +1167,9 @@ impl RustType for ScalarType { ScalarType::Int16 => Int16(()), ScalarType::Int32 => Int32(()), ScalarType::Int64 => Int64(()), + ScalarType::UInt16 => UInt16(()), + ScalarType::UInt32 => UInt32(()), + ScalarType::UInt64 => UInt64(()), ScalarType::Float32 => Float32(()), ScalarType::Float64 => Float64(()), ScalarType::Date => Date(()), @@ -1181,6 +1231,9 @@ impl RustType for ScalarType { Int16(()) => Ok(ScalarType::Int16), Int32(()) => Ok(ScalarType::Int32), Int64(()) => Ok(ScalarType::Int64), + UInt16(()) => Ok(ScalarType::UInt16), + UInt32(()) => Ok(ScalarType::UInt32), + UInt64(()) => Ok(ScalarType::UInt64), Float32(()) => Ok(ScalarType::Float32), Float64(()) => Ok(ScalarType::Float64), Date(()) => Ok(ScalarType::Date), @@ -1335,6 +1388,9 @@ impl_datum_type_copy!(f64, Float64); impl_datum_type_copy!(i16, Int16); impl_datum_type_copy!(i32, Int32); impl_datum_type_copy!(i64, Int64); +impl_datum_type_copy!(u16, UInt16); +impl_datum_type_copy!(u32, UInt32); +impl_datum_type_copy!(u64, UInt64); impl_datum_type_copy!(Interval, Interval); impl_datum_type_copy!(NaiveDate, Date); impl_datum_type_copy!(NaiveTime, Time); diff --git a/src/repr/src/strconv.rs b/src/repr/src/strconv.rs index f805ba8a9a96..f66c34335477 100644 --- a/src/repr/src/strconv.rs +++ b/src/repr/src/strconv.rs @@ -158,12 +158,57 @@ where Nestable::Yes } -/// Writes an OID to `buf`. -pub fn format_oid(buf: &mut F, oid: u32) -> Nestable +/// Parses an [`u16`] from `s`. +/// +/// Valid values are whatever the [`std::str::FromStr`] implementation on `u16` accepts, +/// plus leading and trailing whitespace. +pub fn parse_uint16(s: &str) -> Result { + s.trim() + .parse() + .map_err(|e| ParseError::invalid_input_syntax("uint2", s).with_details(e)) +} + +/// Writes an `u16` to `buf`. +pub fn format_uint16(buf: &mut F, u: u16) -> Nestable +where + F: FormatBuffer, +{ + write!(buf, "{}", u); + Nestable::Yes +} + +/// Parses an [`u32`] from `s`. +/// +/// Valid values are whatever the [`std::str::FromStr`] implementation on `u32` accepts, +/// plus leading and trailing whitespace. +pub fn parse_uint32(s: &str) -> Result { + s.trim() + .parse() + .map_err(|e| ParseError::invalid_input_syntax("uint4", s).with_details(e)) +} + +/// Writes an `u32` to `buf`. +pub fn format_uint32(buf: &mut F, u: u32) -> Nestable +where + F: FormatBuffer, +{ + write!(buf, "{}", u); + Nestable::Yes +} + +/// Parses an `u64` from `s`. +pub fn parse_uint64(s: &str) -> Result { + s.trim() + .parse() + .map_err(|e| ParseError::invalid_input_syntax("uint8", s).with_details(e)) +} + +/// Writes an `u64` to `buf`. +pub fn format_uint64(buf: &mut F, u: u64) -> Nestable where F: FormatBuffer, { - write!(buf, "{}", oid); + write!(buf, "{}", u); Nestable::Yes } diff --git a/src/sql/src/catalog.rs b/src/sql/src/catalog.rs index 2e56cc9c4daa..165865465dfb 100644 --- a/src/sql/src/catalog.rs +++ b/src/sql/src/catalog.rs @@ -432,6 +432,9 @@ pub enum CatalogType { Int16, Int32, Int64, + UInt16, + UInt32, + UInt64, Interval, Jsonb, List { diff --git a/src/sql/src/func.rs b/src/sql/src/func.rs index 097f32e986dc..2085b646646b 100644 --- a/src/sql/src/func.rs +++ b/src/sql/src/func.rs @@ -81,6 +81,9 @@ impl TypeCategory { | ScalarType::Int16 | ScalarType::Int32 | ScalarType::Int64 + | ScalarType::UInt16 + | ScalarType::UInt32 + | ScalarType::UInt64 | ScalarType::Oid | ScalarType::RegClass | ScalarType::RegProc @@ -141,6 +144,9 @@ impl TypeCategory { | CatalogType::Int16 | CatalogType::Int32 | CatalogType::Int64 + | CatalogType::UInt16 + | CatalogType::UInt32 + | CatalogType::UInt64 | CatalogType::Oid | CatalogType::RegClass | CatalogType::RegProc @@ -814,6 +820,9 @@ impl From for ParamType { Int16 => ScalarType::Int16, Int32 => ScalarType::Int32, Int64 => ScalarType::Int64, + UInt16 => ScalarType::UInt16, + UInt32 => ScalarType::UInt32, + UInt64 => ScalarType::UInt64, Float32 => ScalarType::Float32, Float64 => ScalarType::Float64, Numeric => ScalarType::Numeric { max_scale: None }, diff --git a/src/sql/src/plan/query.rs b/src/sql/src/plan/query.rs index 46f99f04d6b0..7fd37e47e76c 100644 --- a/src/sql/src/plan/query.rs +++ b/src/sql/src/plan/query.rs @@ -4683,6 +4683,9 @@ fn scalar_type_from_catalog( CatalogType::Int16 => Ok(ScalarType::Int16), CatalogType::Int32 => Ok(ScalarType::Int32), CatalogType::Int64 => Ok(ScalarType::Int64), + CatalogType::UInt16 => Ok(ScalarType::UInt16), + CatalogType::UInt32 => Ok(ScalarType::UInt32), + CatalogType::UInt64 => Ok(ScalarType::UInt64), CatalogType::Interval => Ok(ScalarType::Interval), CatalogType::Jsonb => Ok(ScalarType::Jsonb), CatalogType::Oid => Ok(ScalarType::Oid), diff --git a/src/sql/src/plan/typeconv.rs b/src/sql/src/plan/typeconv.rs index 3b40c753b7b5..717cdffc4c6c 100644 --- a/src/sql/src/plan/typeconv.rs +++ b/src/sql/src/plan/typeconv.rs @@ -145,6 +145,9 @@ static VALID_CASTS: Lazy> = //INT16 (Int16, Int32) => Implicit: CastInt16ToInt32(func::CastInt16ToInt32), (Int16, Int64) => Implicit: CastInt16ToInt64(func::CastInt16ToInt64), + (Int16, UInt16) => Assignment: CastInt16ToUint16(func::CastInt16ToUint16), + (Int16, UInt32) => Assignment: CastInt16ToUint32(func::CastInt16ToUint32), + (Int16, UInt64) => Assignment: CastInt16ToUint64(func::CastInt16ToUint64), (Int16, Float32) => Implicit: CastInt16ToFloat32(func::CastInt16ToFloat32), (Int16, Float64) => Implicit: CastInt16ToFloat64(func::CastInt16ToFloat64), (Int16, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| { @@ -190,6 +193,9 @@ static VALID_CASTS: Lazy> = (Int32, PgLegacyChar) => Explicit: CastInt32ToPgLegacyChar(func::CastInt32ToPgLegacyChar), (Int32, Int16) => Assignment: CastInt32ToInt16(func::CastInt32ToInt16), (Int32, Int64) => Implicit: CastInt32ToInt64(func::CastInt32ToInt64), + (Int32, UInt16) => Assignment: CastInt32ToUint16(func::CastInt32ToUint16), + (Int32, UInt32) => Assignment: CastInt32ToUint32(func::CastInt32ToUint32), + (Int32, UInt64) => Assignment: CastInt32ToUint64(func::CastInt32ToUint64), (Int32, Float32) => Implicit: CastInt32ToFloat32(func::CastInt32ToFloat32), (Int32, Float64) => Implicit: CastInt32ToFloat64(func::CastInt32ToFloat64), (Int32, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| { @@ -202,6 +208,9 @@ static VALID_CASTS: Lazy> = (Int64, Bool) => Explicit: CastInt64ToBool(func::CastInt64ToBool), (Int64, Int16) => Assignment: CastInt64ToInt16(func::CastInt64ToInt16), (Int64, Int32) => Assignment: CastInt64ToInt32(func::CastInt64ToInt32), + (Int64, UInt16) => Assignment: CastInt64ToUint16(func::CastInt64ToUint16), + (Int64, UInt32) => Assignment: CastInt64ToUint32(func::CastInt64ToUint32), + (Int64, UInt64) => Assignment: CastInt64ToUint64(func::CastInt64ToUint64), (Int64, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| { let s = to_type.unwrap_numeric_max_scale(); Some(move |e: HirScalarExpr| e.call_unary(CastInt64ToNumeric(func::CastInt64ToNumeric(s)))) @@ -223,6 +232,46 @@ static VALID_CASTS: Lazy> = ], (Int64, String) => Assignment: CastInt64ToString(func::CastInt64ToString), + // UINT16 + (UInt16, UInt32) => Implicit: CastUint16ToUint32(func::CastUint16ToUint32), + (UInt16, UInt64) => Implicit: CastUint16ToUint64(func::CastUint16ToUint64), + (UInt16, Int32) => Implicit: CastUint16ToInt32(func::CastUint16ToInt32), + (UInt16, Int64) => Implicit: CastUint16ToInt64(func::CastUint16ToInt64), + (UInt16, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| { + let s = to_type.unwrap_numeric_max_scale(); + Some(move |e: HirScalarExpr| e.call_unary(CastUint16ToNumeric(func::CastUint16ToNumeric(s)))) + }), + (UInt16, Float32) => Implicit: CastUint16ToFloat32(func::CastUint16ToFloat32), + (UInt16, Float64) => Implicit: CastUint16ToFloat64(func::CastUint16ToFloat64), + (UInt16, String) => Assignment: CastUint16ToString(func::CastUint16ToString), + + // UINT32 + (UInt32, UInt16) => Assignment: CastUint32ToUint16(func::CastUint32ToUint16), + (UInt32, UInt64) => Implicit: CastUint32ToUint64(func::CastUint32ToUint64), + (UInt32, Int32) => Assignment: CastUint32ToInt32(func::CastUint32ToInt32), + (UInt32, Int64) => Implicit: CastUint32ToInt64(func::CastUint32ToInt64), + (UInt32, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| { + let s = to_type.unwrap_numeric_max_scale(); + Some(move |e: HirScalarExpr| e.call_unary(CastUint32ToNumeric(func::CastUint32ToNumeric(s)))) + }), + (UInt32, Float32) => Implicit: CastUint32ToFloat32(func::CastUint32ToFloat32), + (UInt32, Float64) => Implicit: CastUint32ToFloat64(func::CastUint32ToFloat64), + (UInt32, String) => Assignment: CastUint32ToString(func::CastUint32ToString), + + // UINT64 + (UInt64, UInt16) => Assignment: CastUint64ToUint16(func::CastUint64ToUint16), + (UInt64, UInt32) => Assignment: CastUint64ToUint32(func::CastUint64ToUint32), + (UInt64, Int32) => Assignment: CastUint64ToInt32(func::CastUint64ToInt32), + (UInt64, Int64) => Assignment: CastUint64ToInt64(func::CastUint64ToInt64), + (UInt64, Numeric) => Implicit: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| { + let s = to_type.unwrap_numeric_max_scale(); + Some(move |e: HirScalarExpr| e.call_unary(CastUint64ToNumeric(func::CastUint64ToNumeric(s)))) + }), + (UInt64, Float32) => Implicit: CastUint64ToFloat32(func::CastUint64ToFloat32), + (UInt64, Float64) => Implicit: CastUint64ToFloat64(func::CastUint64ToFloat64), + (UInt64, String) => Assignment: CastUint64ToString(func::CastUint64ToString), + + // OID (Oid, Int32) => Assignment: CastOidToInt32(func::CastOidToInt32), (Oid, Int64) => Assignment: CastOidToInt32(func::CastOidToInt32), @@ -265,6 +314,9 @@ static VALID_CASTS: Lazy> = (Float32, Int16) => Assignment: CastFloat32ToInt16(func::CastFloat32ToInt16), (Float32, Int32) => Assignment: CastFloat32ToInt32(func::CastFloat32ToInt32), (Float32, Int64) => Assignment: CastFloat32ToInt64(func::CastFloat32ToInt64), + (Float32, UInt16) => Assignment: CastFloat32ToUint16(func::CastFloat32ToUint16), + (Float32, UInt32) => Assignment: CastFloat32ToUint32(func::CastFloat32ToUint32), + (Float32, UInt64) => Assignment: CastFloat32ToUint64(func::CastFloat32ToUint64), (Float32, Float64) => Implicit: CastFloat32ToFloat64(func::CastFloat32ToFloat64), (Float32, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| { let s = to_type.unwrap_numeric_max_scale(); @@ -276,6 +328,9 @@ static VALID_CASTS: Lazy> = (Float64, Int16) => Assignment: CastFloat64ToInt16(func::CastFloat64ToInt16), (Float64, Int32) => Assignment: CastFloat64ToInt32(func::CastFloat64ToInt32), (Float64, Int64) => Assignment: CastFloat64ToInt64(func::CastFloat64ToInt64), + (Float64, UInt16) => Assignment: CastFloat64ToUint16(func::CastFloat64ToUint16), + (Float64, UInt32) => Assignment: CastFloat64ToUint32(func::CastFloat64ToUint32), + (Float64, UInt64) => Assignment: CastFloat64ToUint64(func::CastFloat64ToUint64), (Float64, Float32) => Assignment: CastFloat64ToFloat32(func::CastFloat64ToFloat32), (Float64, Numeric) => Assignment: CastTemplate::new(|_ecx, _ccx, _from_type, to_type| { let s = to_type.unwrap_numeric_max_scale(); @@ -316,6 +371,9 @@ static VALID_CASTS: Lazy> = (String, Int16) => Explicit: CastStringToInt16(func::CastStringToInt16), (String, Int32) => Explicit: CastStringToInt32(func::CastStringToInt32), (String, Int64) => Explicit: CastStringToInt64(func::CastStringToInt64), + (String, UInt16) => Explicit: CastStringToUint16(func::CastStringToUint16), + (String, UInt32) => Explicit: CastStringToUint32(func::CastStringToUint32), + (String, UInt64) => Explicit: CastStringToUint64(func::CastStringToUint64), (String, Oid) => Explicit: CastStringToOid(func::CastStringToOid), // STRING to REG* @@ -555,6 +613,9 @@ static VALID_CASTS: Lazy> = (Numeric, Int16) => Assignment: CastNumericToInt16(func::CastNumericToInt16), (Numeric, Int32) => Assignment: CastNumericToInt32(func::CastNumericToInt32), (Numeric, Int64) => Assignment: CastNumericToInt64(func::CastNumericToInt64), + (Numeric, UInt16) => Assignment: CastNumericToUint16(func::CastNumericToUint16), + (Numeric, UInt32) => Assignment: CastNumericToUint32(func::CastNumericToUint32), + (Numeric, UInt64) => Assignment: CastNumericToUint64(func::CastNumericToUint64), (Numeric, String) => Assignment: CastNumericToString(func::CastNumericToString) } }); diff --git a/test/pgtest/binary.pt b/test/pgtest/binary.pt index 30be385da23c..4d12c948f0b3 100644 --- a/test/pgtest/binary.pt +++ b/test/pgtest/binary.pt @@ -1,5 +1,7 @@ # Test binary encodings +# Intervals + send Parse {"query": "SELECT INTERVAL '2147483647 days 2147483647 hours 59 minutes 59.999999 seconds'"} Bind {"result_formats": [1]} @@ -95,3 +97,197 @@ BindComplete DataRow {"fields":["[148, 182, 46, 0, 0, 0, 0, 1, 128, 0, 0, 1, 0, 0, 0, 0]"]} CommandComplete {"tag":"SELECT 1"} ReadyForQuery {"status":"I"} + +# Integers + +send +Parse {"query": "SELECT 42::int2"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["\u0000*"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT 42::uint2"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["\u0000*"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT -32768::int2"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["[128, 0]"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT 32768::uint2"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["[128, 0]"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT 42::int4"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["\u0000\u0000\u0000*"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT 42::uint4"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["\u0000\u0000\u0000*"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT -2147483648::int4"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["[128, 0, 0, 0]"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT 2147483648::uint4"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["[128, 0, 0, 0]"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT 42::int8"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["\u0000\u0000\u0000\u0000\u0000\u0000\u0000*"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT 42::uint8"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["\u0000\u0000\u0000\u0000\u0000\u0000\u0000*"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT -9223372036854775808::int8"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["[128, 0, 0, 0, 0, 0, 0, 0]"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} + +send +Parse {"query": "SELECT 9223372036854775808::uint8"} +Bind {"result_formats": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +ParseComplete +BindComplete +DataRow {"fields":["[128, 0, 0, 0, 0, 0, 0, 0]"]} +CommandComplete {"tag":"SELECT 1"} +ReadyForQuery {"status":"I"} diff --git a/test/sqllogictest/unsigned_int.slt b/test/sqllogictest/unsigned_int.slt new file mode 100644 index 000000000000..f5aebb4854cb --- /dev/null +++ b/test/sqllogictest/unsigned_int.slt @@ -0,0 +1,765 @@ +# Copyright Materialize, Inc. and contributors. All rights reserved. +# +# Use of this software is governed by the Business Source License +# included in the LICENSE file at the root of this repository. +# +# As of the Change Date specified in that file, in accordance with +# the Business Source License, use of this software will be governed +# by the Apache License, Version 2.0. + +# This comment was copied from map.slt +# The unsigned types have an uncommon OID. If tokio-postres (the driver +# used +# by sqllogictest) encounters an OID it doesn't recognize (uint2, +# uint4, or uint8 in +# this case), then it queries pg_type (a wrapper around mz_types) for +# information about it. Our unsigned types currently don't have entries +# in +# mz_types, so that query fails and tokio-postgres is unable to execute +# queries with unsigned types. As a workaround until unsigned types +# are reflected in pg_type, +# we just convert everything to `numeric`. + +query I +SELECT 42::uint2::numeric +---- +42 + +query I +SELECT 32768::uint2::numeric +---- +32768 + +query T +SELECT pg_typeof(42::uint2) +---- +uint2 + +query error uint2 out of range +SELECT -666::uint2::numeric + +query error uint2 out of range +SELECT 65536::uint2::numeric + +query I +SELECT 42::uint4::numeric +---- +42 + +query I +SELECT 65536::uint4::numeric +---- +65536 + +query I +SELECT 2147483648::uint4::numeric +---- +2147483648 + +query T +SELECT pg_typeof(42::uint4) +---- +uint4 + +query error uint4 out of range +SELECT -666::uint4::numeric + +query error uint4 out of range +SELECT 4294967296::uint4::numeric + +query I +SELECT 42::uint8::numeric +---- +42 + +query I +SELECT 65536::uint8::numeric +---- +65536 + +query I +SELECT 4294967296::uint8::numeric +---- +4294967296 + +query I +SELECT 9223372036854775808::uint8::numeric +---- +9223372036854775808 + +query T +SELECT pg_typeof(42::uint8) +---- +uint8 + +query error uint8 out of range +SELECT -666::uint8::numeric + +query error uint8 out of range +SELECT 18446744073709551616::uint8::numeric + +statement ok +CREATE TABLE t2 (a uint2) + +statement ok +INSERT INTO t2 VALUES (13) + +statement ok +INSERT INTO t2 VALUES (32768) + +statement error uint2 out of range +INSERT INTO t2 VALUES (65536) + +statement error uint2 out of range +INSERT INTO t2 VALUES (-13) + +query I rowsort +SELECT CAST(a AS numeric) from t2 +---- +13 +32768 + +statement ok +CREATE TABLE t4 (a uint4) + +statement ok +INSERT INTO t4 VALUES (13), (65536), (2147483648) + +statement error uint4 out of range +INSERT INTO t4 VALUES (4294967296) + +statement error uint4 out of range +INSERT INTO t4 VALUES (-13) + +query I rowsort +SELECT CAST(a AS numeric) FROM t4 +---- +13 +2147483648 +65536 + +statement ok +CREATE TABLE t8 (a uint8) + +statement ok +INSERT INTO t8 VALUES (13), (65536), (4294967296), (9223372036854775808) + +statement error uint8 out of range +INSERT INTO t8 VALUES (18446744073709551616) + +statement error uint8 out of range +INSERT INTO t8 VALUES (-13) + +query I rowsort +SELECT CAST(a AS numeric) FROM t8 +---- +13 +4294967296 +65536 +9223372036854775808 + + +# Test casts to/from unsigned integers + +# From int2 + +query I +SELECT 21::int2::uint2::numeric +---- +21 + +query error uint2 out of range +SELECT -21::int2::uint2::numeric + +query I +SELECT 47::int2::uint4::numeric +---- +47 + +query error uint4 out of range +SELECT -47::int2::uint4::numeric + +query I +SELECT 99::int2::uint8::numeric +---- +99 + +query error uint8 out of range +SELECT -99::int2::uint8::numeric + +# From int4 + +query I +SELECT 21::int4::uint2::numeric +---- +21 + +query error uint2 out of range +SELECT -21::int4::uint2::numeric + +query error uint2 out of range +SELECT 65536::int4::uint2::numeric + +query I +SELECT 47::int4::uint4::numeric +---- +47 + +query I +SELECT 65536::int4::uint4::numeric +---- +65536 + +query error uint4 out of range +SELECT -47::int4::uint4::numeric + +query I +SELECT 99::int4::uint8::numeric +---- +99 + +query I +SELECT 65536::int4::uint8::numeric +---- +65536 + +query error uint8 out of range +SELECT -99::int4::uint8::numeric + +# From int8 + +query I +SELECT 21::int8::uint2::numeric +---- +21 + +query error uint2 out of range +SELECT -21::int8::uint2::numeric + +query error uint2 out of range +SELECT 65536::int8::uint2::numeric + +query I +SELECT 47::int8::uint4::numeric +---- +47 + +query I +SELECT 65536::int8::uint4::numeric +---- +65536 + +query error uint4 out of range +SELECT -47::int8::uint4::numeric + +query error uint4 out of range +SELECT 4294967296::int8::uint4::numeric + +query I +SELECT 99::int8::uint8::numeric +---- +99 + +query I +SELECT 65536::int8::uint8::numeric +---- +65536 + +query I +SELECT 4294967296::int8::uint8::numeric +---- +4294967296 + +query error uint8 out of range +SELECT -99::int8::uint8::numeric + +# From numeric + +query I +SELECT 12.0::numeric::uint2::numeric +---- +12 + +query I +SELECT 12.4::numeric::uint2::numeric +---- +12 + +query I +SELECT 12.6::numeric::uint2::numeric +---- +13 + +query error uint2 out of range +SELECT -12.0::numeric::uint2::numeric + +query error uint2 out of range +SELECT 65536.0::numeric::uint2::numeric + +query I +SELECT 65535.4::numeric::uint2::numeric +---- +65535 + +query error uint2 out of range +SELECT 65535.5::numeric::uint2::numeric + +query I +SELECT 12.0::numeric::uint4::numeric +---- +12 + +query I +SELECT 12.4::numeric::uint4::numeric +---- +12 + +query I +SELECT 12.6::numeric::uint4::numeric +---- +13 + +query I +SELECT 65536.0::numeric::uint4::numeric +---- +65536 + +query error uint4 out of range +SELECT -12.0::numeric::uint4::numeric + +query error uint4 out of range +SELECT 4294967296::numeric::uint4::numeric + +query I +SELECT 4294967295.4::numeric::uint4::numeric +---- +4294967295 + +query error uint4 out of range +SELECT 4294967295.5::numeric::uint4::numeric + +query I +SELECT 12.0::numeric::uint8::numeric +---- +12 + +query I +SELECT 12.4::numeric::uint8::numeric +---- +12 + +query I +SELECT 12.6::numeric::uint8::numeric +---- +13 + +query I +SELECT 65536.0::numeric::uint8::numeric +---- +65536 + +query I +SELECT 4294967296.0::numeric::uint8::numeric +---- +4294967296 + +query error uint8 out of range +SELECT -12.0::numeric::uint8::numeric + +query error uint8 out of range +SELECT 18446744073709551616::numeric::uint8::numeric + +query I +SELECT 18446744073709551615.4::numeric::uint8::numeric +---- +18446744073709551615 + +query error uint8 out of range +SELECT 18446744073709551615.5::numeric::uint8::numeric + +# From float32 + +query I +SELECT 12.0::float::uint2::numeric +---- +12 + +query I +SELECT 12.4::float::uint2::numeric +---- +12 + +query I +SELECT 12.6::float::uint2::numeric +---- +13 + +query error uint2 out of range +SELECT -12.0::float::uint2::numeric + +query error uint2 out of range +SELECT 65536.0::float::uint2::numeric + +query I +SELECT 65535.4::float::uint2::numeric +---- +65535 + +query error uint2 out of range +SELECT 65535.5::float::uint2::numeric + +query I +SELECT 12.0::float::uint4::numeric +---- +12 + +query I +SELECT 12.4::float::uint4::numeric +---- +12 + +query I +SELECT 12.6::float::uint4::numeric +---- +13 + +query I +SELECT 65536.0::float::uint4::numeric +---- +65536 + +query error uint4 out of range +SELECT -12.0::float::uint4::numeric + +query error uint4 out of range +SELECT 4294967296::float::uint4::numeric + +query I +SELECT 4294967295.4::float::uint4::numeric +---- +4294967295 + +query error uint4 out of range +SELECT 4294967295.5::float::uint4::numeric + +query I +SELECT 12.0::float::uint8::numeric +---- +12 + +query I +SELECT 12.4::float::uint8::numeric +---- +12 + +query I +SELECT 12.6::float::uint8::numeric +---- +13 + +query I +SELECT 65536.0::float::uint8::numeric +---- +65536 + +query I +SELECT 4294967296.0::float::uint8::numeric +---- +4294967296 + +query error uint8 out of range +SELECT -12.0::float::uint8::numeric + +query error uint8 out of range +SELECT 18446744073709553665::float::uint8::numeric + +query I +SELECT 18446744073709553664.0::float::uint8::numeric +---- +18446744073709551615 + +query error uint8 out of range +SELECT 18446744073709553664.5::float::uint8::numeric + +# From float64 + +query I +SELECT 12.0::double::uint2::numeric +---- +12 + +query I +SELECT 12.4::double::uint2::numeric +---- +12 + +query I +SELECT 12.6::double::uint2::numeric +---- +13 + +query error uint2 out of range +SELECT -12.0::double::uint2::numeric + +query error uint2 out of range +SELECT 65536.0::double::uint2::numeric + +query I +SELECT 65535.4::double::uint2::numeric +---- +65535 + +query error uint2 out of range +SELECT 65535.5::double::uint2::numeric + +query I +SELECT 12.0::double::uint4::numeric +---- +12 + +query I +SELECT 12.4::double::uint4::numeric +---- +12 + +query I +SELECT 12.6::double::uint4::numeric +---- +13 + +query I +SELECT 65536.0::double::uint4::numeric +---- +65536 + +query error uint4 out of range +SELECT -12.0::double::uint4::numeric + +query error uint4 out of range +SELECT 4294967296::double::uint4::numeric + +query I +SELECT 4294967295.4::double::uint4::numeric +---- +4294967295 + +query error uint4 out of range +SELECT 4294967295.5::double::uint4::numeric + +query I +SELECT 12.0::double::uint8::numeric +---- +12 + +query I +SELECT 12.4::double::uint8::numeric +---- +12 + +query I +SELECT 12.6::double::uint8::numeric +---- +13 + +query I +SELECT 65536.0::double::uint8::numeric +---- +65536 + +query I +SELECT 4294967296.0::double::uint8::numeric +---- +4294967296 + +query error uint8 out of range +SELECT -12.0::double::uint8::numeric + +query error uint8 out of range +SELECT 18446744073709553665::double::uint8::numeric + +query I +SELECT 18446744073709553664.0::double::uint8::numeric +---- +18446744073709551615 + +query error uint8 out of range +SELECT 18446744073709553664.5::double::uint8::numeric + +# From text + +query I +SELECT '44'::uint2::numeric +---- +44 + +query error invalid input syntax for type uint2: invalid digit found in string: "-44" +SELECT '-44'::uint2::numeric + +query error invalid input syntax for type uint2: number too large to fit in target type: "65536" +SELECT '65536'::uint2::numeric + +query I +SELECT '44'::uint4::numeric +---- +44 + +query error invalid input syntax for type uint4: invalid digit found in string: "-44" +SELECT '-44'::uint4::numeric + +query error invalid input syntax for type uint4: number too large to fit in target type: "4294967296" +SELECT '4294967296'::uint4::numeric + +query I +SELECT '44'::uint8::numeric +---- +44 + +query error invalid input syntax for type uint8: invalid digit found in string: "-44" +SELECT '-44'::uint8::numeric + +query error invalid input syntax for type uint8: number too large to fit in target type: "18446744073709551616" +SELECT '18446744073709551616'::uint8::numeric + +# From uint2 + +query I +SELECT 124::uint2::uint4::numeric +---- +124 + +query I +SELECT 124::uint2::uint8::numeric +---- +124 + +query I +SELECT 124::uint2::int4 +---- +124 + +query I +SELECT 124::uint2::int8 +---- +124 + +query I +SELECT 124::uint2::numeric +---- +124 + +query I +SELECT 124::uint2::real +---- +124 + +query I +SELECT 124::uint2::double +---- +124 + +query T +SELECT 124::uint2::text +---- +124 + +# From uint4 + +query I +SELECT 6789::uint4::uint2::numeric +---- +6789 + +query error uint2 out of range +SELECT 65536::uint4::uint2::numeric + +query I +SELECT 6789::uint4::uint8::numeric +---- +6789 + +query I +SELECT 6789::uint4::int4 +---- +6789 + +query error integer out of range +SELECT 2147483648::uint4::int4 + +query I +SELECT 6789::uint4::int8 +---- +6789 + +query I +SELECT 6789::uint4::numeric +---- +6789 + +query I +SELECT 6789::uint4::real +---- +6789 + +query I +SELECT 6789::uint4::double +---- +6789 + +query T +SELECT 6789::uint4::text +---- +6789 + +# From uint8 + +query I +SELECT 15445::uint8::uint2::numeric +---- +15445 + +query error uint2 out of range +SELECT 65536::uint8::uint2::numeric + +query I +SELECT 15445::uint8::uint4::numeric +---- +15445 + +query error uint4 out of range +SELECT 4294967296::uint8::uint4::numeric + +query I +SELECT 15445::uint8::int4 +---- +15445 + +query error integer out of range +SELECT 2147483648::uint8::int4 + +query I +SELECT 15445::uint8::int8 +---- +15445 + +query error bigint out of range +SELECT 9223372036854775808::uint8::int8 + +query I +SELECT 15445::uint8::numeric +---- +15445 + +query I +SELECT 15445::uint8::real +---- +15445 + +query I +SELECT 15445::uint8::double +---- +15445 + +query T +SELECT 15445::uint8::text +---- +15445 diff --git a/test/testdrive/types.td b/test/testdrive/types.td index b4a43cb61463..6d4eab2dbfa0 100644 --- a/test/testdrive/types.td +++ b/test/testdrive/types.td @@ -28,6 +28,9 @@ _int2 _int2vector _int4 _int8 +_uint2 +_uint4 +_uint8 _interval _jsonb _numeric @@ -62,6 +65,9 @@ int2 int2vector int4 int8 +uint2 +uint4 +uint8 interval jsonb list @@ -93,6 +99,9 @@ _int2 system _int2vector system _int4 system _int8 system +_uint2 system +_uint4 system +_uint8 system _interval system _jsonb system _numeric system @@ -127,6 +136,9 @@ int2 system int2vector system int4 system int8 system +uint2 system +uint4 system +uint8 system interval system jsonb system list system @@ -174,6 +186,12 @@ ALTER SYSTEM SET max_tables = 10000 > CREATE TABLE int8_t (a int8); > CREATE TABLE bigint_t (a bigint); +> CREATE TABLE uint2_t (a uint2); + +> CREATE TABLE uint4_t (a uint4); + +> CREATE TABLE uint8_t (a uint8); + > CREATE TABLE interval_t (a interval); > CREATE TABLE jsonb_t (a jsonb);