mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-25 17:12:03 +00:00
Merge pull request #62852 from pet74alex/UUIDv7
Add UUIDv7-generating functions
This commit is contained in:
commit
8a7b0c057f
@ -8,7 +8,8 @@ sidebar_label: UUID
|
||||
|
||||
A Universally Unique Identifier (UUID) is a 16-byte value used to identify records. For detailed information about UUIDs, see [Wikipedia](https://en.wikipedia.org/wiki/Universally_unique_identifier).
|
||||
|
||||
While different UUID variants exist (see [here](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis)), ClickHouse does not validate that inserted UUIDs conform to a particular variant. UUIDs are internally treated as a sequence of 16 random bytes with [8-4-4-4-12 representation](https://en.wikipedia.org/wiki/Universally_unique_identifier#Textual_representation) at SQL level.
|
||||
While different UUID variants exist (see [here](https://datatracker.ietf.org/doc/html/draft-ietf-uuidrev-rfc4122bis)), ClickHouse does not validate that inserted UUIDs conform to a particular variant.
|
||||
UUIDs are internally treated as a sequence of 16 random bytes with [8-4-4-4-12 representation](https://en.wikipedia.org/wiki/Universally_unique_identifier#Textual_representation) at SQL level.
|
||||
|
||||
Example UUID value:
|
||||
|
||||
@ -22,6 +23,46 @@ The default UUID is all-zero. It is used, for example, when a new record is inse
|
||||
00000000-0000-0000-0000-000000000000
|
||||
```
|
||||
|
||||
Due to historical reasons, UUIDs are sorted by their second half (which is unintuitive).
|
||||
UUIDs should therefore not be used in an primary key (or sorting key) of a table, or as partition key.
|
||||
|
||||
Example:
|
||||
|
||||
``` sql
|
||||
CREATE TABLE tab (uuid UUID) ENGINE = Memory;
|
||||
INSERT INTO tab SELECT generateUUIDv4() FROM numbers(50);
|
||||
SELECT * FROM tab ORDER BY uuid;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
``` text
|
||||
┌─uuid─────────────────────────────────┐
|
||||
│ 36a0b67c-b74a-4640-803b-e44bb4547e3c │
|
||||
│ 3a00aeb8-2605-4eec-8215-08c0ecb51112 │
|
||||
│ 3fda7c49-282e-421a-85ab-c5684ef1d350 │
|
||||
│ 16ab55a7-45f6-44a8-873c-7a0b44346b3e │
|
||||
│ e3776711-6359-4f22-878d-bf290d052c85 │
|
||||
│ 1be30226-57b2-4739-88ec-5e3d490090f2 │
|
||||
│ f65853a9-4375-4f0e-8b96-906ff622ed3c │
|
||||
│ d5a0c7a6-79c6-4107-8bb8-df85915edcb7 │
|
||||
│ 258e6068-17d1-4a1a-8be3-ed2ceb21815c │
|
||||
│ 04b0f6a9-1f7b-4a42-8bfc-62f37b8a32b8 │
|
||||
│ 9924f0d9-9c16-43a9-8f08-0944ab495aed │
|
||||
│ 6720dc14-4eab-4e3e-8f0c-10c4ae8d2673 │
|
||||
│ 5ddadb52-0452-4f5d-9030-c3f969af93a4 │
|
||||
│ [...] │
|
||||
│ 2dde30e6-59a1-48f8-b260-eb37921185b6 │
|
||||
│ d5402a1b-77b3-4897-b288-29edf5c3ed12 │
|
||||
│ 01843939-3ba7-4fea-b2aa-45f9a6f1e057 │
|
||||
│ 9eceda2f-6946-40e3-b725-16f2709ca41a │
|
||||
│ 03644f74-47ba-4020-b865-be5fd4c8c7ff │
|
||||
│ ce3bc93d-ab19-4c74-b8cc-737cb9212099 │
|
||||
│ b7ad6c91-23d6-4b5e-b8e4-a52297490b56 │
|
||||
│ 06892f64-cc2d-45f3-bf86-f5c5af5768a9 │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Generating UUIDs
|
||||
|
||||
ClickHouse provides the [generateUUIDv4](../../sql-reference/functions/uuid-functions.md) function to generate random UUID version 4 values.
|
||||
|
@ -8,49 +8,267 @@ sidebar_label: UUIDs
|
||||
|
||||
## generateUUIDv4
|
||||
|
||||
Generates the [UUID](../data-types/uuid.md) of [version 4](https://tools.ietf.org/html/rfc4122#section-4.4).
|
||||
Generates a [version 4](https://tools.ietf.org/html/rfc4122#section-4.4) [UUID](../data-types/uuid.md).
|
||||
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
generateUUIDv4([x])
|
||||
generateUUIDv4([expr])
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `x` — [Expression](../../sql-reference/syntax.md#syntax-expressions) resulting in any of the [supported data types](../../sql-reference/data-types/index.md#data_types). The resulting value is discarded, but the expression itself if used for bypassing [common subexpression elimination](../../sql-reference/functions/index.md#common-subexpression-elimination) if the function is called multiple times in one query. Optional parameter.
|
||||
- `expr` — An arbitrary [expression](../../sql-reference/syntax.md#syntax-expressions) used to bypass [common subexpression elimination](../../sql-reference/functions/index.md#common-subexpression-elimination) if the function is called multiple times in a query. The value of the expression has no effect on the returned UUID. Optional.
|
||||
|
||||
**Returned value**
|
||||
|
||||
The UUID type value.
|
||||
A value of type UUIDv4.
|
||||
|
||||
**Usage example**
|
||||
**Example**
|
||||
|
||||
This example demonstrates creating a table with the UUID type column and inserting a value into the table.
|
||||
First, create a table with a column of type UUID, then insert a generated UUIDv4 into the table.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE t_uuid (x UUID) ENGINE=TinyLog
|
||||
CREATE TABLE tab (uuid UUID) ENGINE = Memory;
|
||||
|
||||
INSERT INTO t_uuid SELECT generateUUIDv4()
|
||||
INSERT INTO tab SELECT generateUUIDv4();
|
||||
|
||||
SELECT * FROM t_uuid
|
||||
SELECT * FROM tab;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌────────────────────────────────────x─┐
|
||||
┌─────────────────────────────────uuid─┐
|
||||
│ f4bf890f-f9dc-4332-ad5c-0c18e73f28e9 │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Usage example if it is needed to generate multiple values in one row**
|
||||
**Example with multiple UUIDs generated per row**
|
||||
|
||||
```sql
|
||||
SELECT generateUUIDv4(1), generateUUIDv4(2)
|
||||
SELECT generateUUIDv4(1), generateUUIDv4(2);
|
||||
|
||||
┌─generateUUIDv4(1)────────────────────┬─generateUUIDv4(2)────────────────────┐
|
||||
│ 2d49dc6e-ddce-4cd0-afb8-790956df54c1 │ 8abf8c13-7dea-4fdf-af3e-0e18767770e6 │
|
||||
└──────────────────────────────────────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## generateUUIDv7 {#generateUUIDv7}
|
||||
|
||||
Generates a [version 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04) [UUID](../data-types/uuid.md).
|
||||
|
||||
The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits), a counter (42 bit) to distinguish UUIDs within a millisecond (including a variant field "2", 2 bit), and a random field (32 bits).
|
||||
For any given timestamp (unix_ts_ms), the counter starts at a random value and is incremented by 1 for each new UUID until the timestamp changes.
|
||||
In case the counter overflows, the timestamp field is incremented by 1 and the counter is reset to a random new start value.
|
||||
|
||||
Function `generateUUIDv7` guarantees that the counter field within a timestamp increments monotonically across all function invocations in concurrently running threads and queries.
|
||||
|
||||
```
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms | ver | counter_high_bits |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
|var| counter_low_bits |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| rand_b |
|
||||
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
|
||||
```
|
||||
|
||||
:::note
|
||||
As of April 2024, version 7 UUIDs are in draft status and their layout may change in future.
|
||||
:::
|
||||
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
generateUUIDv7([expr])
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `expr` — An arbitrary [expression](../../sql-reference/syntax.md#syntax-expressions) used to bypass [common subexpression elimination](../../sql-reference/functions/index.md#common-subexpression-elimination) if the function is called multiple times in a query. The value of the expression has no effect on the returned UUID. Optional.
|
||||
|
||||
**Returned value**
|
||||
|
||||
A value of type UUIDv7.
|
||||
|
||||
**Example**
|
||||
|
||||
First, create a table with a column of type UUID, then insert a generated UUIDv7 into the table.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE tab (uuid UUID) ENGINE = Memory;
|
||||
|
||||
INSERT INTO tab SELECT generateUUIDv7();
|
||||
|
||||
SELECT * FROM tab;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─────────────────────────────────uuid─┐
|
||||
│ 018f05af-f4a8-778f-beee-1bedbc95c93b │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Example with multiple UUIDs generated per row**
|
||||
|
||||
```sql
|
||||
SELECT generateUUIDv7(1), generateUUIDv7(2);
|
||||
|
||||
┌─generateUUIDv7(1)────────────────────┬─generateUUIDv7(2)────────────────────┐
|
||||
│ 018f05c9-4ab8-7b86-b64e-c9f03fbd45d1 │ 018f05c9-4ab8-7b86-b64e-c9f12efb7e16 │
|
||||
└──────────────────────────────────────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## generateUUIDv7ThreadMonotonic
|
||||
|
||||
Generates a [UUID](../data-types/uuid.md) of [version 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04).
|
||||
|
||||
The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits), a counter (42 bit) to distinguish UUIDs within a millisecond (including a variant field "2", 2 bit), and a random field (32 bits).
|
||||
For any given timestamp (unix_ts_ms), the counter starts at a random value and is incremented by 1 for each new UUID until the timestamp changes.
|
||||
In case the counter overflows, the timestamp field is incremented by 1 and the counter is reset to a random new start value.
|
||||
|
||||
This function behaves like [generateUUIDv7](#generateUUIDv7) but gives no guarantee on counter monotony across different simultaneous requests.
|
||||
Monotonicity within one timestamp is guaranteed only within the same thread calling this function to generate UUIDs.
|
||||
|
||||
```
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms | ver | counter_high_bits |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
|var| counter_low_bits |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| rand_b |
|
||||
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
|
||||
```
|
||||
|
||||
:::note
|
||||
As of April 2024, version 7 UUIDs are in draft status and their layout may change in future.
|
||||
:::
|
||||
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
generateUUIDv7ThreadMonotonic([expr])
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `expr` — An arbitrary [expression](../../sql-reference/syntax.md#syntax-expressions) used to bypass [common subexpression elimination](../../sql-reference/functions/index.md#common-subexpression-elimination) if the function is called multiple times in a query. The value of the expression has no effect on the returned UUID. Optional.
|
||||
|
||||
**Returned value**
|
||||
|
||||
A value of type UUIDv7.
|
||||
|
||||
**Usage example**
|
||||
|
||||
First, create a table with a column of type UUID, then insert a generated UUIDv7 into the table.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE tab (uuid UUID) ENGINE = Memory;
|
||||
|
||||
INSERT INTO tab SELECT generateUUIDv7ThreadMonotonic();
|
||||
|
||||
SELECT * FROM tab;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─────────────────────────────────uuid─┐
|
||||
│ 018f05e2-e3b2-70cb-b8be-64b09b626d32 │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Example with multiple UUIDs generated per row**
|
||||
|
||||
```sql
|
||||
SELECT generateUUIDv7ThreadMonotonic(1), generateUUIDv7ThreadMonotonic(2);
|
||||
|
||||
┌─generateUUIDv7ThreadMonotonic(1)─────┬─generateUUIDv7ThreadMonotonic(2)─────┐
|
||||
│ 018f05e1-14ee-7bc5-9906-207153b400b1 │ 018f05e1-14ee-7bc5-9906-2072b8e96758 │
|
||||
└──────────────────────────────────────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## generateUUIDv7NonMonotonic
|
||||
|
||||
Generates a [UUID](../data-types/uuid.md) of [version 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04).
|
||||
|
||||
The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits) and a random field (76 bits, including a 2-bit variant field "2").
|
||||
|
||||
This function is the fastest `generateUUIDv7*` function but it gives no monotonicity guarantees within a timestamp.
|
||||
|
||||
```
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms | ver | rand_a |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
|var| rand_b |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| rand_b |
|
||||
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
|
||||
```
|
||||
|
||||
:::note
|
||||
As of April 2024, version 7 UUIDs are in draft status and their layout may change in future.
|
||||
:::
|
||||
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
generateUUIDv7NonMonotonic([expr])
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `expr` — An arbitrary [expression](../../sql-reference/syntax.md#syntax-expressions) used to bypass [common subexpression elimination](../../sql-reference/functions/index.md#common-subexpression-elimination) if the function is called multiple times in a query. The value of the expression has no effect on the returned UUID. Optional.
|
||||
|
||||
**Returned value**
|
||||
|
||||
A value of type UUIDv7.
|
||||
|
||||
**Example**
|
||||
|
||||
First, create a table with a column of type UUID, then insert a generated UUIDv7 into the table.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE tab (uuid UUID) ENGINE = Memory;
|
||||
|
||||
INSERT INTO tab SELECT generateUUIDv7NonMonotonic();
|
||||
|
||||
SELECT * FROM tab;
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─────────────────────────────────uuid─┐
|
||||
│ 018f05af-f4a8-778f-beee-1bedbc95c93b │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Example with multiple UUIDs generated per row**
|
||||
|
||||
```sql
|
||||
SELECT generateUUIDv7NonMonotonic(1), generateUUIDv7NonMonotonic(2);
|
||||
|
||||
┌─generateUUIDv7NonMonotonic(1) ───────┬─generateUUIDv7(2)NonMonotonic────────┐
|
||||
│ 018f05b1-8c2e-7567-a988-48d09606ae8c │ 018f05b1-8c2e-7946-895b-fcd7635da9a0 │
|
||||
└──────────────────────────────────────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## empty
|
||||
|
||||
Checks whether the input UUID is empty.
|
||||
@ -63,15 +281,15 @@ empty(UUID)
|
||||
|
||||
The UUID is considered empty if it contains all zeros (zero UUID).
|
||||
|
||||
The function also works for [arrays](array-functions.md#function-empty) or [strings](string-functions.md#empty).
|
||||
The function also works for [Arrays](array-functions.md#function-empty) and [Strings](string-functions.md#empty).
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `x` — Input UUID. [UUID](../data-types/uuid.md).
|
||||
- `x` — A UUID. [UUID](../data-types/uuid.md).
|
||||
|
||||
**Returned value**
|
||||
|
||||
- Returns `1` for an empty UUID or `0` for a non-empty UUID.
|
||||
- Returns `1` for an empty UUID or `0` for a non-empty UUID.
|
||||
|
||||
Type: [UInt8](../data-types/int-uint.md).
|
||||
|
||||
@ -105,15 +323,15 @@ notEmpty(UUID)
|
||||
|
||||
The UUID is considered empty if it contains all zeros (zero UUID).
|
||||
|
||||
The function also works for [arrays](array-functions.md#function-notempty) or [strings](string-functions.md#notempty).
|
||||
The function also works for [Arrays](array-functions.md#function-notempty) or [Strings](string-functions.md#notempty).
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `x` — Input UUID. [UUID](../data-types/uuid.md).
|
||||
- `x` — A UUID. [UUID](../data-types/uuid.md).
|
||||
|
||||
**Returned value**
|
||||
|
||||
- Returns `1` for a non-empty UUID or `0` for an empty UUID.
|
||||
- Returns `1` for a non-empty UUID or `0` for an empty UUID.
|
||||
|
||||
Type: [UInt8](../data-types/int-uint.md).
|
||||
|
||||
@ -135,12 +353,12 @@ Result:
|
||||
└────────────────────────────┘
|
||||
```
|
||||
|
||||
## toUUID (x)
|
||||
## toUUID
|
||||
|
||||
Converts String type value to UUID type.
|
||||
Converts a value of type String to a UUID.
|
||||
|
||||
``` sql
|
||||
toUUID(String)
|
||||
toUUID(string)
|
||||
```
|
||||
|
||||
**Returned value**
|
||||
@ -153,13 +371,15 @@ The UUID type value.
|
||||
SELECT toUUID('61f0c404-5cb3-11e7-907b-a6006ad3dba0') AS uuid
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─────────────────────────────────uuid─┐
|
||||
│ 61f0c404-5cb3-11e7-907b-a6006ad3dba0 │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## toUUIDOrDefault (x,y)
|
||||
## toUUIDOrDefault
|
||||
|
||||
**Arguments**
|
||||
|
||||
@ -171,7 +391,7 @@ SELECT toUUID('61f0c404-5cb3-11e7-907b-a6006ad3dba0') AS uuid
|
||||
UUID
|
||||
|
||||
``` sql
|
||||
toUUIDOrDefault(String, UUID)
|
||||
toUUIDOrDefault(string, default)
|
||||
```
|
||||
|
||||
**Returned value**
|
||||
@ -185,6 +405,9 @@ This first example returns the first argument converted to a UUID type as it can
|
||||
``` sql
|
||||
SELECT toUUIDOrDefault('61f0c404-5cb3-11e7-907b-a6006ad3dba0', cast('59f0c404-5cb3-11e7-907b-a6006ad3dba0' as UUID));
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─toUUIDOrDefault('61f0c404-5cb3-11e7-907b-a6006ad3dba0', CAST('59f0c404-5cb3-11e7-907b-a6006ad3dba0', 'UUID'))─┐
|
||||
│ 61f0c404-5cb3-11e7-907b-a6006ad3dba0 │
|
||||
@ -197,18 +420,20 @@ This second example returns the second argument (the provided default UUID) as t
|
||||
SELECT toUUIDOrDefault('-----61f0c404-5cb3-11e7-907b-a6006ad3dba0', cast('59f0c404-5cb3-11e7-907b-a6006ad3dba0' as UUID));
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─toUUIDOrDefault('-----61f0c404-5cb3-11e7-907b-a6006ad3dba0', CAST('59f0c404-5cb3-11e7-907b-a6006ad3dba0', 'UUID'))─┐
|
||||
│ 59f0c404-5cb3-11e7-907b-a6006ad3dba0 │
|
||||
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## toUUIDOrNull (x)
|
||||
## toUUIDOrNull
|
||||
|
||||
It takes an argument of type String and tries to parse it into UUID. If failed, returns NULL.
|
||||
Takes an argument of type String and tries to parse it into UUID. If failed, returns NULL.
|
||||
|
||||
``` sql
|
||||
toUUIDOrNull(String)
|
||||
toUUIDOrNull(string)
|
||||
```
|
||||
|
||||
**Returned value**
|
||||
@ -221,18 +446,20 @@ The Nullable(UUID) type value.
|
||||
SELECT toUUIDOrNull('61f0c404-5cb3-11e7-907b-a6006ad3dba0T') AS uuid
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─uuid─┐
|
||||
│ ᴺᵁᴸᴸ │
|
||||
└──────┘
|
||||
```
|
||||
|
||||
## toUUIDOrZero (x)
|
||||
## toUUIDOrZero
|
||||
|
||||
It takes an argument of type String and tries to parse it into UUID. If failed, returns zero UUID.
|
||||
|
||||
``` sql
|
||||
toUUIDOrZero(String)
|
||||
toUUIDOrZero(string)
|
||||
```
|
||||
|
||||
**Returned value**
|
||||
@ -245,6 +472,8 @@ The UUID type value.
|
||||
SELECT toUUIDOrZero('61f0c404-5cb3-11e7-907b-a6006ad3dba0T') AS uuid
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─────────────────────────────────uuid─┐
|
||||
│ 00000000-0000-0000-0000-000000000000 │
|
||||
@ -263,7 +492,7 @@ UUIDStringToNum(string[, variant = 1])
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `string` — String of 36 characters or FixedString(36). [String](../../sql-reference/syntax.md#syntax-string-literal).
|
||||
- `string` — A [String](../../sql-reference/syntax.md#syntax-string-literal) of 36 characters or [FixedString](../../sql-reference/syntax.md#syntax-string-literal)
|
||||
- `variant` — Integer, representing a variant as specified by [RFC4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.1). 1 = `Big-endian` (default), 2 = `Microsoft`.
|
||||
|
||||
**Returned value**
|
||||
@ -278,6 +507,8 @@ SELECT
|
||||
UUIDStringToNum(uuid) AS bytes
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─uuid─────────────────────────────────┬─bytes────────────┐
|
||||
│ 612f3c40-5d3b-217e-707b-6a546a3d7b29 │ a/<@];!~p{jTj={) │
|
||||
@ -290,6 +521,8 @@ SELECT
|
||||
UUIDStringToNum(uuid, 2) AS bytes
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─uuid─────────────────────────────────┬─bytes────────────┐
|
||||
│ 612f3c40-5d3b-217e-707b-6a546a3d7b29 │ @</a;]~!p{jTj={) │
|
||||
@ -323,6 +556,8 @@ SELECT
|
||||
UUIDNumToString(toFixedString(bytes, 16)) AS uuid
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─bytes────────────┬─uuid─────────────────────────────────┐
|
||||
│ a/<@];!~p{jTj={) │ 612f3c40-5d3b-217e-707b-6a546a3d7b29 │
|
||||
@ -335,15 +570,113 @@ SELECT
|
||||
UUIDNumToString(toFixedString(bytes, 16), 2) AS uuid
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─bytes────────────┬─uuid─────────────────────────────────┐
|
||||
│ @</a;]~!p{jTj={) │ 612f3c40-5d3b-217e-707b-6a546a3d7b29 │
|
||||
└──────────────────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## UUIDToNum
|
||||
|
||||
Accepts a [UUID](../../sql-reference/data-types/uuid.md) and returns its binary representation as a [FixedString(16)](../../sql-reference/data-types/fixedstring.md), with its format optionally specified by `variant` (`Big-endian` by default). This function replaces calls to two separate functions `UUIDStringToNum(toString(uuid))` so no intermediate conversion from UUID to string is required to extract bytes from a UUID.
|
||||
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
UUIDToNum(uuid[, variant = 1])
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `uuid` — [UUID](../data-types/uuid.md).
|
||||
- `variant` — Integer, representing a variant as specified by [RFC4122](https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.1). 1 = `Big-endian` (default), 2 = `Microsoft`.
|
||||
|
||||
**Returned value**
|
||||
|
||||
The binary representation of the UUID.
|
||||
|
||||
**Usage examples**
|
||||
|
||||
``` sql
|
||||
SELECT
|
||||
toUUID('612f3c40-5d3b-217e-707b-6a546a3d7b29') AS uuid,
|
||||
UUIDToNum(uuid) AS bytes
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─uuid─────────────────────────────────┬─bytes────────────┐
|
||||
│ 612f3c40-5d3b-217e-707b-6a546a3d7b29 │ a/<@];!~p{jTj={) │
|
||||
└──────────────────────────────────────┴──────────────────┘
|
||||
```
|
||||
|
||||
``` sql
|
||||
SELECT
|
||||
toUUID('612f3c40-5d3b-217e-707b-6a546a3d7b29') AS uuid,
|
||||
UUIDToNum(uuid, 2) AS bytes
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─uuid─────────────────────────────────┬─bytes────────────┐
|
||||
│ 612f3c40-5d3b-217e-707b-6a546a3d7b29 │ @</a;]~!p{jTj={) │
|
||||
└──────────────────────────────────────┴──────────────────┘
|
||||
```
|
||||
|
||||
## UUIDv7ToDateTime
|
||||
|
||||
Returns the timestamp component of a UUID version 7.
|
||||
|
||||
**Syntax**
|
||||
|
||||
``` sql
|
||||
UUIDv7ToDateTime(uuid[, timezone])
|
||||
```
|
||||
|
||||
**Arguments**
|
||||
|
||||
- `uuid` — [UUID](../data-types/uuid.md) of version 7.
|
||||
- `timezone` — [Timezone name](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) for the returned value (optional). [String](../../sql-reference/data-types/string.md).
|
||||
|
||||
**Returned value**
|
||||
|
||||
- Timestamp with milliseconds precision. If the UUID is not a valid version 7 UUID, it returns 1970-01-01 00:00:00.000.
|
||||
|
||||
Type: [DateTime64(3)](/docs/en/sql-reference/data-types/datetime64.md).
|
||||
|
||||
**Usage examples**
|
||||
|
||||
``` sql
|
||||
SELECT UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'))
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'))─┐
|
||||
│ 2024-04-22 15:30:29.048 │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
``` sql
|
||||
SELECT UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'), 'America/New_York')
|
||||
```
|
||||
|
||||
Result:
|
||||
|
||||
```response
|
||||
┌─UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'), 'America/New_York')─┐
|
||||
│ 2024-04-22 08:30:29.048 │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## serverUUID()
|
||||
|
||||
Returns the random and unique UUID, which is generated when the server is first started and stored forever. The result writes to the file `uuid` created in the ClickHouse server directory `/var/lib/clickhouse/`.
|
||||
Returns the random UUID generated during the first start of the ClickHouse server. The UUID is stored in file `uuid` in the ClickHouse server directory (e.g. `/var/lib/clickhouse/`) and retained between server restarts.
|
||||
|
||||
**Syntax**
|
||||
|
||||
@ -353,10 +686,10 @@ serverUUID()
|
||||
|
||||
**Returned value**
|
||||
|
||||
- The UUID of the server.
|
||||
- The UUID of the server.
|
||||
|
||||
Type: [UUID](../data-types/uuid.md).
|
||||
|
||||
## See Also
|
||||
## See also
|
||||
|
||||
- [dictGetUUID](../../sql-reference/functions/ext-dict-functions.md#ext_dict_functions-other)
|
||||
|
@ -51,6 +51,174 @@ SELECT generateUUIDv4(1), generateUUIDv4(2)
|
||||
└──────────────────────────────────────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## generateUUIDv7 {#uuidv7-function-generate}
|
||||
|
||||
Генерирует идентификатор [UUID версии 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). Генерируемый UUID состоит из 48-битной временной метки (Unix time в миллисекундах), маркеров версии 7 и варианта 2, монотонно возрастающего счётчика для данной временной метки и случайных данных в указанной ниже последовательности. Для каждой новой временной метки счётчик стартует с нового случайного значения, а для следующих UUIDv7 он увеличивается на единицу. В случае переполнения счётчика временная метка принудительно увеличивается на 1, и счётчик снова стартует со случайного значения. Монотонность возрастания счётчика для каждой временной метки гарантируется между всеми одновременно работающими функциями `generateUUIDv7`.
|
||||
```
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms | ver | counter_high_bits |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
|var| counter_low_bits |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| rand_b |
|
||||
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
|
||||
```
|
||||
::::note
|
||||
На апрель 2024 года UUIDv7 находится в статусе черновика и его раскладка по битам может в итоге измениться.
|
||||
::::
|
||||
|
||||
**Синтаксис**
|
||||
|
||||
``` sql
|
||||
generateUUIDv7([x])
|
||||
```
|
||||
|
||||
**Аргументы**
|
||||
|
||||
- `x` — [выражение](../syntax.md#syntax-expressions), возвращающее значение одного из [поддерживаемых типов данных](../data-types/index.md#data_types). Значение используется, чтобы избежать [склейки одинаковых выражений](index.md#common-subexpression-elimination), если функция вызывается несколько раз в одном запросе. Необязательный параметр.
|
||||
|
||||
**Возвращаемое значение**
|
||||
|
||||
Значение типа [UUID](../../sql-reference/functions/uuid-functions.md).
|
||||
|
||||
**Пример использования**
|
||||
|
||||
Этот пример демонстрирует, как создать таблицу с UUID-колонкой и добавить в нее сгенерированный UUIDv7.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE t_uuid (x UUID) ENGINE=TinyLog
|
||||
|
||||
INSERT INTO t_uuid SELECT generateUUIDv7WithCounter()
|
||||
|
||||
SELECT * FROM t_uuid
|
||||
```
|
||||
|
||||
``` text
|
||||
┌────────────────────────────────────x─┐
|
||||
│ 018f05c7-56e3-7ac3-93e9-1d93c4218e0e │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Пример использования, для генерации нескольких значений в одной строке**
|
||||
|
||||
```sql
|
||||
SELECT generateUUIDv7(1), generateUUIDv7(2)
|
||||
┌─generateUUIDv7(1)────────────────────┬─generateUUIDv7(2)────────────────────┐
|
||||
│ 018f05c9-4ab8-7b86-b64e-c9f03fbd45d1 │ 018f05c9-4ab8-7b86-b64e-c9f12efb7e16 │
|
||||
└──────────────────────────────────────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## generateUUIDv7ThreadMonotonic {#uuidv7threadmonotonic-function-generate}
|
||||
|
||||
Генерирует идентификатор [UUID версии 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). Генерируемый UUID состоит из 48-битной временной метки (Unix time в миллисекундах), маркеров версии 7 и варианта 2, монотонно возрастающего счётчика для данной временной метки и случайных данных в указанной ниже последовательности. Для каждой новой временной метки счётчик стартует с нового случайного значения, а для следующих UUIDv7 он увеличивается на единицу. В случае переполнения счётчика временная метка принудительно увеличивается на 1, и счётчик снова стартует со случайного значения. Данная функция является ускоренным аналогом функции `generateUUIDv7` за счёт потери гарантии монотонности счётчика при одной и той же метке времени между одновременно исполняемыми разными запросами. Монотонность счётчика гарантируется только в пределах одного треда, исполняющего данную функцию для генерации нескольких UUID.
|
||||
|
||||
**Синтаксис**
|
||||
|
||||
``` sql
|
||||
generateUUIDv7ThreadMonotonic([x])
|
||||
```
|
||||
|
||||
**Аргументы**
|
||||
|
||||
- `x` — [выражение](../syntax.md#syntax-expressions), возвращающее значение одного из [поддерживаемых типов данных](../data-types/index.md#data_types). Значение используется, чтобы избежать [склейки одинаковых выражений](index.md#common-subexpression-elimination), если функция вызывается несколько раз в одном запросе. Необязательный параметр.
|
||||
|
||||
**Возвращаемое значение**
|
||||
|
||||
Значение типа [UUID](../../sql-reference/functions/uuid-functions.md).
|
||||
|
||||
**Пример использования**
|
||||
|
||||
Этот пример демонстрирует, как создать таблицу с UUID-колонкой и добавить в нее сгенерированный UUIDv7.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE t_uuid (x UUID) ENGINE=TinyLog
|
||||
|
||||
INSERT INTO t_uuid SELECT generateUUIDv7ThreadMonotonic()
|
||||
|
||||
SELECT * FROM t_uuid
|
||||
```
|
||||
|
||||
``` text
|
||||
┌────────────────────────────────────x─┐
|
||||
│ 018f05e2-e3b2-70cb-b8be-64b09b626d32 │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Пример использования, для генерации нескольких значений в одной строке**
|
||||
|
||||
```sql
|
||||
SELECT generateUUIDv7ThreadMonotonic(1), generateUUIDv7ThreadMonotonic(7)
|
||||
|
||||
┌─generateUUIDv7ThreadMonotonic(1)─────┬─generateUUIDv7ThreadMonotonic(2)─────┐
|
||||
│ 018f05e1-14ee-7bc5-9906-207153b400b1 │ 018f05e1-14ee-7bc5-9906-2072b8e96758 │
|
||||
└──────────────────────────────────────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## generateUUIDv7NonMonotonic {#uuidv7nonmonotonic-function-generate}
|
||||
|
||||
Генерирует идентификатор [UUID версии 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). Генерируемый UUID состоит из 48-битной временной метки (Unix time в миллисекундах), маркеров версии 7 и варианта 2, и случайных данных в следующей последовательности:
|
||||
```
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms | ver | rand_a |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
|var| rand_b |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| rand_b |
|
||||
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
|
||||
```
|
||||
::::note
|
||||
На апрель 2024 года UUIDv7 находится в статусе черновика и его раскладка по битам может в итоге измениться.
|
||||
::::
|
||||
|
||||
**Синтаксис**
|
||||
|
||||
``` sql
|
||||
generateUUIDv7NonMonotonic([x])
|
||||
```
|
||||
|
||||
**Аргументы**
|
||||
|
||||
- `x` — [выражение](../syntax.md#syntax-expressions), возвращающее значение одного из [поддерживаемых типов данных](../data-types/index.md#data_types). Значение используется, чтобы избежать [склейки одинаковых выражений](index.md#common-subexpression-elimination), если функция вызывается несколько раз в одном запросе. Необязательный параметр.
|
||||
|
||||
**Возвращаемое значение**
|
||||
|
||||
Значение типа [UUID](../../sql-reference/functions/uuid-functions.md).
|
||||
|
||||
**Пример использования**
|
||||
|
||||
Этот пример демонстрирует, как создать таблицу с UUID-колонкой и добавить в нее сгенерированный UUIDv7.
|
||||
|
||||
``` sql
|
||||
CREATE TABLE t_uuid (x UUID) ENGINE=TinyLog
|
||||
|
||||
INSERT INTO t_uuid SELECT generateUUIDv7NonMonotonic()
|
||||
|
||||
SELECT * FROM t_uuid
|
||||
```
|
||||
|
||||
``` text
|
||||
┌────────────────────────────────────x─┐
|
||||
│ 018f05af-f4a8-778f-beee-1bedbc95c93b │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Пример использования, для генерации нескольких значений в одной строке**
|
||||
|
||||
```sql
|
||||
SELECT generateUUIDv7NonMonotonic(1), generateUUIDv7NonMonotonic(7)
|
||||
┌─generateUUIDv7NonMonotonic(1)────────┬─generateUUIDv7NonMonotonic(2)────────┐
|
||||
│ 018f05b1-8c2e-7567-a988-48d09606ae8c │ 018f05b1-8c2e-7946-895b-fcd7635da9a0 │
|
||||
└──────────────────────────────────────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## empty {#empty}
|
||||
|
||||
Проверяет, является ли входной UUID пустым.
|
||||
@ -259,6 +427,84 @@ SELECT
|
||||
└──────────────────┴──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## UUIDToNum {#uuidtonum}
|
||||
|
||||
Принимает UUID и возвращает в виде набора байт в [FixedString(16)](../../sql-reference/functions/uuid-functions.md). Также принимает необязательный второй параметр - вариант представления UUID, по умолчанию 1 - `Big-endian` (2 означает представление в формате `Microsoft`). Данная функция заменяет последовательность из двух отдельных функций `UUIDStringToNum(toString(uuid))`, так что промежуточная конвертация из UUID в String для извлечения набора байт из UUID не требуется.
|
||||
|
||||
``` sql
|
||||
UUIDToNum(UUID[, variant = 1])
|
||||
```
|
||||
|
||||
**Возвращаемое значение**
|
||||
|
||||
FixedString(16)
|
||||
|
||||
**Примеры использования**
|
||||
|
||||
``` sql
|
||||
SELECT
|
||||
toUUID('612f3c40-5d3b-217e-707b-6a546a3d7b29') AS uuid,
|
||||
UUIDToNum(uuid) AS bytes
|
||||
```
|
||||
|
||||
``` text
|
||||
┌─uuid─────────────────────────────────┬─bytes────────────┐
|
||||
│ 612f3c40-5d3b-217e-707b-6a546a3d7b29 │ a/<@];!~p{jTj={) │
|
||||
└──────────────────────────────────────┴──────────────────┘
|
||||
```
|
||||
``` sql
|
||||
SELECT
|
||||
toUUID('612f3c40-5d3b-217e-707b-6a546a3d7b29') AS uuid,
|
||||
UUIDToNum(uuid, 2) AS bytes
|
||||
```
|
||||
|
||||
```text
|
||||
┌─uuid─────────────────────────────────┬─bytes────────────┐
|
||||
│ 612f3c40-5d3b-217e-707b-6a546a3d7b29 │ @</a;]~!p{jTj={) │
|
||||
└──────────────────────────────────────┴──────────────────┘
|
||||
```
|
||||
|
||||
## UUIDv7ToDateTime {#uuidv7todatetime}
|
||||
|
||||
Принимает UUID версии 7 и извлекает из него временную метку.
|
||||
|
||||
``` sql
|
||||
UUIDv7ToDateTime(uuid[, timezone])
|
||||
```
|
||||
|
||||
**Параметры**
|
||||
|
||||
- `uuid` — [UUID](../data-types/uuid.md) версии 7.
|
||||
- `timezone` — [Часовой пояс](../../operations/server-configuration-parameters/settings.md#server_configuration_parameters-timezone) для возвращаемого значения (необязательный параметр). [String](../../sql-reference/data-types/string.md).
|
||||
|
||||
**Возвращаемое значение**
|
||||
|
||||
- Временная метка с миллисекундной точностью (1970-01-01 00:00:00.000 в случае UUID не версии 7).
|
||||
|
||||
Type: [DateTime64(3)](/docs/ru/sql-reference/data-types/datetime64.md).
|
||||
|
||||
**Примеры использования**
|
||||
|
||||
``` sql
|
||||
SELECT UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'))
|
||||
```
|
||||
|
||||
```text
|
||||
┌─UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'))─┐
|
||||
│ 2024-04-22 15:30:29.048 │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
``` sql
|
||||
SELECT UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'), 'America/New_York')
|
||||
```
|
||||
|
||||
```text
|
||||
┌─UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'), 'America/New_York')─┐
|
||||
│ 2024-04-22 08:30:29.048 │
|
||||
└──────────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## serverUUID() {#server-uuid}
|
||||
|
||||
Возвращает случайный и уникальный UUID, который генерируется при первом запуске сервера и сохраняется навсегда. Результат записывается в файл `uuid`, расположенный в каталоге сервера ClickHouse `/var/lib/clickhouse/`.
|
||||
|
@ -1,14 +1,18 @@
|
||||
#include <Columns/ColumnDecimal.h>
|
||||
#include <Columns/ColumnsDateTime.h>
|
||||
#include <Columns/ColumnFixedString.h>
|
||||
#include <Columns/ColumnString.h>
|
||||
#include <Columns/ColumnsNumber.h>
|
||||
#include <Columns/ColumnVector.h>
|
||||
#include <Common/BitHelpers.h>
|
||||
#include <base/hex.h>
|
||||
#include <DataTypes/DataTypeString.h>
|
||||
#include <DataTypes/DataTypeFixedString.h>
|
||||
#include <DataTypes/DataTypeUUID.h>
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/IFunction.h>
|
||||
#include <Functions/FunctionHelpers.h>
|
||||
#include <Functions/extractTimeZoneFromFunctionArguments.h>
|
||||
#include <IO/WriteHelpers.h>
|
||||
#include <Interpreters/Context_fwd.h>
|
||||
#include <Interpreters/castColumn.h>
|
||||
@ -17,11 +21,11 @@
|
||||
|
||||
namespace DB::ErrorCodes
|
||||
{
|
||||
extern const int ARGUMENT_OUT_OF_BOUND;
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
extern const int ARGUMENT_OUT_OF_BOUND;
|
||||
extern const int ILLEGAL_COLUMN;
|
||||
extern const int ILLEGAL_TYPE_OF_ARGUMENT;
|
||||
extern const int LOGICAL_ERROR;
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
}
|
||||
|
||||
namespace
|
||||
@ -32,7 +36,7 @@ enum class Representation
|
||||
LittleEndian
|
||||
};
|
||||
|
||||
std::pair<int, int> determineBinaryStartIndexWithIncrement(const ptrdiff_t num_bytes, const Representation representation)
|
||||
std::pair<int, int> determineBinaryStartIndexWithIncrement(ptrdiff_t num_bytes, Representation representation)
|
||||
{
|
||||
if (representation == Representation::BigEndian)
|
||||
return {0, 1};
|
||||
@ -42,7 +46,7 @@ std::pair<int, int> determineBinaryStartIndexWithIncrement(const ptrdiff_t num_b
|
||||
throw DB::Exception(DB::ErrorCodes::LOGICAL_ERROR, "{} is not handled yet", magic_enum::enum_name(representation));
|
||||
}
|
||||
|
||||
void formatHex(const std::span<const UInt8> src, UInt8 * dst, const Representation representation)
|
||||
void formatHex(const std::span<const UInt8> src, UInt8 * dst, Representation representation)
|
||||
{
|
||||
const auto src_size = std::ssize(src);
|
||||
const auto [src_start_index, src_increment] = determineBinaryStartIndexWithIncrement(src_size, representation);
|
||||
@ -50,7 +54,7 @@ void formatHex(const std::span<const UInt8> src, UInt8 * dst, const Representati
|
||||
writeHexByteLowercase(src[src_pos], dst + dst_pos);
|
||||
}
|
||||
|
||||
void parseHex(const UInt8 * __restrict src, const std::span<UInt8> dst, const Representation representation)
|
||||
void parseHex(const UInt8 * __restrict src, const std::span<UInt8> dst, Representation representation)
|
||||
{
|
||||
const auto dst_size = std::ssize(dst);
|
||||
const auto [dst_start_index, dst_increment] = determineBinaryStartIndexWithIncrement(dst_size, representation);
|
||||
@ -322,10 +326,191 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class FunctionUUIDToNum : public IFunction
|
||||
{
|
||||
public:
|
||||
static constexpr auto name = "UUIDToNum";
|
||||
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionUUIDToNum>(); }
|
||||
|
||||
String getName() const override { return name; }
|
||||
size_t getNumberOfArguments() const override { return 0; }
|
||||
bool useDefaultImplementationForConstants() const override { return true; }
|
||||
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
||||
bool isInjective(const ColumnsWithTypeAndName &) const override { return true; }
|
||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
||||
bool isVariadic() const override { return true; }
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
||||
{
|
||||
checkArgumentCount(arguments, name);
|
||||
|
||||
if (!isUUID(arguments[0]))
|
||||
{
|
||||
throw Exception(
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
||||
"Illegal type {} of first argument of function {}, expected UUID",
|
||||
arguments[0]->getName(),
|
||||
getName());
|
||||
}
|
||||
|
||||
checkFormatArgument(arguments, name);
|
||||
|
||||
return std::make_shared<DataTypeFixedString>(uuid_bytes_length);
|
||||
}
|
||||
|
||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
|
||||
{
|
||||
const ColumnWithTypeAndName & col_type_name = arguments[0];
|
||||
const ColumnPtr & column = col_type_name.column;
|
||||
|
||||
const bool defaultFormat = (parseVariant(arguments) == UUIDSerializer::Variant::Default);
|
||||
|
||||
if (const auto * col_in = checkAndGetColumn<ColumnUUID>(column.get()))
|
||||
{
|
||||
const auto & vec_in = col_in->getData();
|
||||
const UUID * uuids = vec_in.data();
|
||||
const size_t size = vec_in.size();
|
||||
|
||||
auto col_res = ColumnFixedString::create(uuid_bytes_length);
|
||||
|
||||
ColumnString::Chars & vec_res = col_res->getChars();
|
||||
vec_res.resize(size * uuid_bytes_length);
|
||||
|
||||
size_t dst_offset = 0;
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
uint64_t hiBytes = DB::UUIDHelpers::getHighBytes(uuids[i]);
|
||||
uint64_t loBytes = DB::UUIDHelpers::getLowBytes(uuids[i]);
|
||||
unalignedStoreBigEndian<uint64_t>(&vec_res[dst_offset], hiBytes);
|
||||
unalignedStoreBigEndian<uint64_t>(&vec_res[dst_offset + sizeof(hiBytes)], loBytes);
|
||||
if (!defaultFormat)
|
||||
{
|
||||
std::swap(vec_res[dst_offset], vec_res[dst_offset + 3]);
|
||||
std::swap(vec_res[dst_offset + 1], vec_res[dst_offset + 2]);
|
||||
std::swap(vec_res[dst_offset + 4], vec_res[dst_offset + 5]);
|
||||
std::swap(vec_res[dst_offset + 6], vec_res[dst_offset + 7]);
|
||||
}
|
||||
dst_offset += uuid_bytes_length;
|
||||
}
|
||||
|
||||
return col_res;
|
||||
}
|
||||
else
|
||||
throw Exception(
|
||||
ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}", arguments[0].column->getName(), getName());
|
||||
}
|
||||
};
|
||||
|
||||
class FunctionUUIDv7ToDateTime : public IFunction
|
||||
{
|
||||
public:
|
||||
static constexpr auto name = "UUIDv7ToDateTime";
|
||||
static FunctionPtr create(ContextPtr) { return std::make_shared<FunctionUUIDv7ToDateTime>(); }
|
||||
|
||||
static constexpr UInt32 datetime_scale = 3;
|
||||
|
||||
String getName() const override { return name; }
|
||||
size_t getNumberOfArguments() const override { return 0; }
|
||||
bool useDefaultImplementationForConstants() const override { return true; }
|
||||
ColumnNumbers getArgumentsThatAreAlwaysConstant() const override { return {1}; }
|
||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
||||
bool isVariadic() const override { return true; }
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||
{
|
||||
if (arguments.empty() || arguments.size() > 2)
|
||||
throw Exception(
|
||||
ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH, "Wrong number of arguments for function {}: should be 1 or 2", getName());
|
||||
|
||||
if (!checkAndGetDataType<DataTypeUUID>(arguments[0].type.get()))
|
||||
{
|
||||
throw Exception(
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
||||
"Illegal type {} of first argument of function {}, expected UUID",
|
||||
arguments[0].type->getName(),
|
||||
getName());
|
||||
}
|
||||
|
||||
String timezone;
|
||||
if (arguments.size() == 2)
|
||||
{
|
||||
timezone = extractTimeZoneNameFromColumn(arguments[1].column.get(), arguments[1].name);
|
||||
|
||||
if (timezone.empty())
|
||||
throw Exception(
|
||||
ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT,
|
||||
"Function {} supports a 2nd argument (optional) that must be a valid time zone",
|
||||
getName());
|
||||
}
|
||||
|
||||
return std::make_shared<DataTypeDateTime64>(datetime_scale, timezone);
|
||||
}
|
||||
|
||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr &, size_t /*input_rows_count*/) const override
|
||||
{
|
||||
const ColumnWithTypeAndName & col_type_name = arguments[0];
|
||||
const ColumnPtr & column = col_type_name.column;
|
||||
|
||||
if (const auto * col_in = checkAndGetColumn<ColumnUUID>(column.get()))
|
||||
{
|
||||
const auto & vec_in = col_in->getData();
|
||||
const UUID * uuids = vec_in.data();
|
||||
const size_t size = vec_in.size();
|
||||
|
||||
auto col_res = ColumnDateTime64::create(size, datetime_scale);
|
||||
auto & vec_res = col_res->getData();
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
const uint64_t hiBytes = DB::UUIDHelpers::getHighBytes(uuids[i]);
|
||||
const uint64_t ms = ((hiBytes & 0xf000) == 0x7000) ? (hiBytes >> 16) : 0;
|
||||
|
||||
vec_res[i] = DecimalUtils::decimalFromComponents<DateTime64>(ms / intExp10(datetime_scale), ms % intExp10(datetime_scale), datetime_scale);
|
||||
}
|
||||
|
||||
return col_res;
|
||||
}
|
||||
else
|
||||
throw Exception(
|
||||
ErrorCodes::ILLEGAL_COLUMN, "Illegal column {} of argument of function {}", arguments[0].column->getName(), getName());
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_FUNCTION(CodingUUID)
|
||||
{
|
||||
factory.registerFunction<FunctionUUIDNumToString>();
|
||||
factory.registerFunction<FunctionUUIDStringToNum>();
|
||||
factory.registerFunction<FunctionUUIDToNum>(
|
||||
FunctionDocumentation{
|
||||
.description = R"(
|
||||
This function accepts a UUID and returns a FixedString(16) as its binary representation, with its format optionally specified by variant (Big-endian by default).
|
||||
)",
|
||||
.examples{
|
||||
{"uuid",
|
||||
"select toUUID(UUIDNumToString(toFixedString('a/<@];!~p{jTj={)', 16))) as uuid, UUIDToNum(uuid) as uuidNum, "
|
||||
"UUIDToNum(uuid, 2) as uuidMsNum",
|
||||
R"(
|
||||
┌─uuid─────────────────────────────────┬─uuidNum──────────┬─uuidMsNum────────┐
|
||||
│ 612f3c40-5d3b-217e-707b-6a546a3d7b29 │ a/<@];!~p{jTj={) │ @</a];!~p{jTj={) │
|
||||
└──────────────────────────────────────┴──────────────────┴──────────────────┘
|
||||
)"}},
|
||||
.categories{"UUID"}},
|
||||
FunctionFactory::CaseSensitive);
|
||||
|
||||
factory.registerFunction<FunctionUUIDv7ToDateTime>(
|
||||
FunctionDocumentation{
|
||||
.description = R"(
|
||||
This function extracts the timestamp from a UUID and returns it as a DateTime64(3) typed value.
|
||||
The function expects the UUID having version 7 to be provided as the first argument.
|
||||
An optional second argument can be passed to specify a timezone for the timestamp.
|
||||
)",
|
||||
.examples{
|
||||
{"uuid","select UUIDv7ToDateTime(generateUUIDv7())", ""},
|
||||
{"uuid","select generateUUIDv7() as uuid, UUIDv7ToDateTime(uuid), UUIDv7ToDateTime(uuid, 'America/New_York')", ""}},
|
||||
.categories{"UUID"}},
|
||||
FunctionFactory::CaseSensitive);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,15 +1,11 @@
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionsRandom.h>
|
||||
#include <DataTypes/DataTypeUUID.h>
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionHelpers.h>
|
||||
#include <Functions/FunctionsRandom.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace ErrorCodes
|
||||
{
|
||||
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
|
||||
}
|
||||
|
||||
#define DECLARE_SEVERAL_IMPLEMENTATIONS(...) \
|
||||
DECLARE_DEFAULT_CODE (__VA_ARGS__) \
|
||||
DECLARE_AVX2_SPECIFIC_CODE(__VA_ARGS__)
|
||||
@ -21,30 +17,26 @@ class FunctionGenerateUUIDv4 : public IFunction
|
||||
public:
|
||||
static constexpr auto name = "generateUUIDv4";
|
||||
|
||||
String getName() const override
|
||||
{
|
||||
return name;
|
||||
}
|
||||
String getName() const override { return name; }
|
||||
|
||||
size_t getNumberOfArguments() const override { return 0; }
|
||||
|
||||
bool isDeterministic() const override { return false; }
|
||||
bool isDeterministicInScopeOfQuery() const override { return false; }
|
||||
bool useDefaultImplementationForNulls() const override { return false; }
|
||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; }
|
||||
bool isVariadic() const override { return true; }
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override
|
||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||
{
|
||||
if (arguments.size() > 1)
|
||||
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
|
||||
"Number of arguments for function {} doesn't match: passed {}, should be 0 or 1.",
|
||||
getName(), arguments.size());
|
||||
FunctionArgumentDescriptors mandatory_args;
|
||||
FunctionArgumentDescriptors optional_args{
|
||||
{"expr", nullptr, nullptr, "Arbitrary Expression"}
|
||||
};
|
||||
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
|
||||
|
||||
return std::make_shared<DataTypeUUID>();
|
||||
}
|
||||
|
||||
bool isDeterministic() const override { return false; }
|
||||
|
||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName &, const DataTypePtr &, size_t input_rows_count) const override
|
||||
{
|
||||
auto col_res = ColumnVector<UUID>::create();
|
||||
@ -79,10 +71,10 @@ public:
|
||||
selector.registerImplementation<TargetArch::Default,
|
||||
TargetSpecific::Default::FunctionGenerateUUIDv4>();
|
||||
|
||||
#if USE_MULTITARGET_CODE
|
||||
#if USE_MULTITARGET_CODE
|
||||
selector.registerImplementation<TargetArch::AVX2,
|
||||
TargetSpecific::AVX2::FunctionGenerateUUIDv4>();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
|
||||
|
289
src/Functions/generateUUIDv7.cpp
Normal file
289
src/Functions/generateUUIDv7.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
#include <DataTypes/DataTypeUUID.h>
|
||||
#include <Functions/FunctionFactory.h>
|
||||
#include <Functions/FunctionHelpers.h>
|
||||
#include <Functions/FunctionsRandom.h>
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
/* Bit layouts of UUIDv7
|
||||
|
||||
without counter:
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms | ver | rand_a |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
|var| rand_b |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| rand_b |
|
||||
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
|
||||
|
||||
with counter:
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| unix_ts_ms | ver | counter_high_bits |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
|var| counter_low_bits |
|
||||
├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤
|
||||
| rand_b |
|
||||
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
|
||||
*/
|
||||
|
||||
/// bit counts
|
||||
constexpr auto rand_a_bits_count = 12;
|
||||
constexpr auto rand_b_bits_count = 62;
|
||||
constexpr auto rand_b_low_bits_count = 32;
|
||||
constexpr auto counter_high_bits_count = rand_a_bits_count;
|
||||
constexpr auto counter_low_bits_count = 30;
|
||||
constexpr auto bits_in_counter = counter_high_bits_count + counter_low_bits_count;
|
||||
constexpr uint64_t counter_limit = (1ull << bits_in_counter);
|
||||
|
||||
/// bit masks for UUIDv7 components
|
||||
constexpr uint64_t variant_2_mask = (2ull << rand_b_bits_count);
|
||||
constexpr uint64_t rand_a_bits_mask = (1ull << rand_a_bits_count) - 1;
|
||||
constexpr uint64_t rand_b_bits_mask = (1ull << rand_b_bits_count) - 1;
|
||||
constexpr uint64_t rand_b_with_counter_bits_mask = (1ull << rand_b_low_bits_count) - 1;
|
||||
constexpr uint64_t counter_low_bits_mask = (1ull << counter_low_bits_count) - 1;
|
||||
constexpr uint64_t counter_high_bits_mask = rand_a_bits_mask;
|
||||
|
||||
uint64_t getTimestampMillisecond()
|
||||
{
|
||||
timespec tp;
|
||||
clock_gettime(CLOCK_REALTIME, &tp);
|
||||
const uint64_t sec = tp.tv_sec;
|
||||
return sec * 1000 + tp.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
void setTimestampAndVersion(UUID & uuid, uint64_t timestamp)
|
||||
{
|
||||
UUIDHelpers::getHighBytes(uuid) = (UUIDHelpers::getHighBytes(uuid) & rand_a_bits_mask) | (timestamp << 16) | 0x7000;
|
||||
}
|
||||
|
||||
void setVariant(UUID & uuid)
|
||||
{
|
||||
UUIDHelpers::getLowBytes(uuid) = (UUIDHelpers::getLowBytes(uuid) & rand_b_bits_mask) | variant_2_mask;
|
||||
}
|
||||
|
||||
struct FillAllRandomPolicy
|
||||
{
|
||||
static constexpr auto name = "generateUUIDv7NonMonotonic";
|
||||
static constexpr auto doc_description = R"(Generates a UUID of version 7. The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits), and a random field (74 bit, including a 2-bit variant field "2") to distinguish UUIDs within a millisecond. This function is the fastest generateUUIDv7* function but it gives no monotonicity guarantees within a timestamp.)";
|
||||
struct Data
|
||||
{
|
||||
void generate(UUID & uuid, uint64_t ts)
|
||||
{
|
||||
setTimestampAndVersion(uuid, ts);
|
||||
setVariant(uuid);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct CounterFields
|
||||
{
|
||||
uint64_t last_timestamp = 0;
|
||||
uint64_t counter = 0;
|
||||
|
||||
void resetCounter(const UUID & uuid)
|
||||
{
|
||||
const uint64_t counter_low_bits = (UUIDHelpers::getLowBytes(uuid) >> rand_b_low_bits_count) & counter_low_bits_mask;
|
||||
const uint64_t counter_high_bits = UUIDHelpers::getHighBytes(uuid) & counter_high_bits_mask;
|
||||
counter = (counter_high_bits << 30) | counter_low_bits;
|
||||
}
|
||||
|
||||
void incrementCounter(UUID & uuid)
|
||||
{
|
||||
if (++counter == counter_limit) [[unlikely]]
|
||||
{
|
||||
++last_timestamp;
|
||||
resetCounter(uuid);
|
||||
setTimestampAndVersion(uuid, last_timestamp);
|
||||
setVariant(uuid);
|
||||
}
|
||||
else
|
||||
{
|
||||
UUIDHelpers::getHighBytes(uuid) = (last_timestamp << 16) | 0x7000 | (counter >> counter_low_bits_count);
|
||||
UUIDHelpers::getLowBytes(uuid) = (UUIDHelpers::getLowBytes(uuid) & rand_b_with_counter_bits_mask) | variant_2_mask | ((counter & counter_low_bits_mask) << rand_b_low_bits_count);
|
||||
}
|
||||
}
|
||||
|
||||
void generate(UUID & uuid, uint64_t timestamp)
|
||||
{
|
||||
const bool need_to_increment_counter = (last_timestamp == timestamp) || ((last_timestamp > timestamp) & (last_timestamp < timestamp + 10000));
|
||||
if (need_to_increment_counter)
|
||||
{
|
||||
incrementCounter(uuid);
|
||||
}
|
||||
else
|
||||
{
|
||||
last_timestamp = timestamp;
|
||||
resetCounter(uuid);
|
||||
setTimestampAndVersion(uuid, last_timestamp);
|
||||
setVariant(uuid);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct GlobalCounterPolicy
|
||||
{
|
||||
static constexpr auto name = "generateUUIDv7";
|
||||
static constexpr auto doc_description = R"(Generates a UUID of version 7. The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits), a counter (42 bit, including a variant field "2", 2 bit) to distinguish UUIDs within a millisecond, and a random field (32 bits). For any given timestamp (unix_ts_ms), the counter starts at a random value and is incremented by 1 for each new UUID until the timestamp changes. In case the counter overflows, the timestamp field is incremented by 1 and the counter is reset to a random new start value. Function generateUUIDv7 guarantees that the counter field within a timestamp increments monotonically across all function invocations in concurrently running threads and queries.)";
|
||||
|
||||
/// Guarantee counter monotonicity within one timestamp across all threads generating UUIDv7 simultaneously.
|
||||
struct Data
|
||||
{
|
||||
static inline CounterFields fields;
|
||||
static inline SharedMutex mutex; /// works a little bit faster than std::mutex here
|
||||
std::lock_guard<SharedMutex> guard;
|
||||
|
||||
Data()
|
||||
: guard(mutex)
|
||||
{}
|
||||
|
||||
void generate(UUID & uuid, uint64_t timestamp)
|
||||
{
|
||||
fields.generate(uuid, timestamp);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct ThreadLocalCounterPolicy
|
||||
{
|
||||
static constexpr auto name = "generateUUIDv7ThreadMonotonic";
|
||||
static constexpr auto doc_description = R"(Generates a UUID of version 7. The generated UUID contains the current Unix timestamp in milliseconds (48 bits), followed by version "7" (4 bits), a counter (42 bit, including a variant field "2", 2 bit) to distinguish UUIDs within a millisecond, and a random field (32 bits). For any given timestamp (unix_ts_ms), the counter starts at a random value and is incremented by 1 for each new UUID until the timestamp changes. In case the counter overflows, the timestamp field is incremented by 1 and the counter is reset to a random new start value. This function behaves like generateUUIDv7 but gives no guarantee on counter monotony across different simultaneous requests. Monotonicity within one timestamp is guaranteed only within the same thread calling this function to generate UUIDs.)";
|
||||
|
||||
/// Guarantee counter monotonicity within one timestamp within the same thread. Faster than GlobalCounterPolicy if a query uses multiple threads.
|
||||
struct Data
|
||||
{
|
||||
static inline thread_local CounterFields fields;
|
||||
|
||||
void generate(UUID & uuid, uint64_t timestamp)
|
||||
{
|
||||
fields.generate(uuid, timestamp);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#define DECLARE_SEVERAL_IMPLEMENTATIONS(...) \
|
||||
DECLARE_DEFAULT_CODE (__VA_ARGS__) \
|
||||
DECLARE_AVX2_SPECIFIC_CODE(__VA_ARGS__)
|
||||
|
||||
DECLARE_SEVERAL_IMPLEMENTATIONS(
|
||||
|
||||
template <typename FillPolicy>
|
||||
class FunctionGenerateUUIDv7Base : public IFunction, public FillPolicy
|
||||
{
|
||||
public:
|
||||
String getName() const final { return FillPolicy::name; }
|
||||
|
||||
size_t getNumberOfArguments() const final { return 0; }
|
||||
bool isDeterministic() const override { return false; }
|
||||
bool isDeterministicInScopeOfQuery() const final { return false; }
|
||||
bool useDefaultImplementationForNulls() const final { return false; }
|
||||
bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const final { return false; }
|
||||
bool isVariadic() const final { return true; }
|
||||
|
||||
DataTypePtr getReturnTypeImpl(const ColumnsWithTypeAndName & arguments) const override
|
||||
{
|
||||
FunctionArgumentDescriptors mandatory_args;
|
||||
FunctionArgumentDescriptors optional_args{
|
||||
{"expr", nullptr, nullptr, "Arbitrary Expression"}
|
||||
};
|
||||
validateFunctionArgumentTypes(*this, arguments, mandatory_args, optional_args);
|
||||
|
||||
return std::make_shared<DataTypeUUID>();
|
||||
}
|
||||
|
||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName &, const DataTypePtr &, size_t input_rows_count) const override
|
||||
{
|
||||
auto col_res = ColumnVector<UUID>::create();
|
||||
typename ColumnVector<UUID>::Container & vec_to = col_res->getData();
|
||||
|
||||
if (input_rows_count)
|
||||
{
|
||||
vec_to.resize(input_rows_count);
|
||||
|
||||
/// Not all random bytes produced here are required for the UUIDv7 but it's the simplest way to get the required number of them by using RandImpl
|
||||
RandImpl::execute(reinterpret_cast<char *>(vec_to.data()), vec_to.size() * sizeof(UUID));
|
||||
|
||||
/// Note: For performance reasons, clock_gettime is called once per chunk instead of once per UUID. This reduces precision but
|
||||
/// it still complies with the UUID standard.
|
||||
uint64_t timestamp = getTimestampMillisecond();
|
||||
for (UUID & uuid : vec_to)
|
||||
{
|
||||
typename FillPolicy::Data data;
|
||||
data.generate(uuid, timestamp);
|
||||
}
|
||||
}
|
||||
return col_res;
|
||||
}
|
||||
};
|
||||
) // DECLARE_SEVERAL_IMPLEMENTATIONS
|
||||
#undef DECLARE_SEVERAL_IMPLEMENTATIONS
|
||||
|
||||
template <typename FillPolicy>
|
||||
class FunctionGenerateUUIDv7Base : public TargetSpecific::Default::FunctionGenerateUUIDv7Base<FillPolicy>
|
||||
{
|
||||
public:
|
||||
using Self = FunctionGenerateUUIDv7Base<FillPolicy>;
|
||||
using Parent = TargetSpecific::Default::FunctionGenerateUUIDv7Base<FillPolicy>;
|
||||
|
||||
explicit FunctionGenerateUUIDv7Base(ContextPtr context) : selector(context)
|
||||
{
|
||||
selector.registerImplementation<TargetArch::Default, Parent>();
|
||||
|
||||
#if USE_MULTITARGET_CODE
|
||||
using ParentAVX2 = TargetSpecific::AVX2::FunctionGenerateUUIDv7Base<FillPolicy>;
|
||||
selector.registerImplementation<TargetArch::AVX2, ParentAVX2>();
|
||||
#endif
|
||||
}
|
||||
|
||||
ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override
|
||||
{
|
||||
return selector.selectAndExecute(arguments, result_type, input_rows_count);
|
||||
}
|
||||
|
||||
static FunctionPtr create(ContextPtr context)
|
||||
{
|
||||
return std::make_shared<Self>(context);
|
||||
}
|
||||
|
||||
private:
|
||||
ImplementationSelector<IFunction> selector;
|
||||
};
|
||||
|
||||
template<typename FillPolicy>
|
||||
void registerUUIDv7Generator(auto& factory)
|
||||
{
|
||||
static constexpr auto doc_syntax_format = "{}([expression])";
|
||||
static constexpr auto example_format = "SELECT {}()";
|
||||
static constexpr auto multiple_example_format = "SELECT {f}(1), {f}(2)";
|
||||
|
||||
FunctionDocumentation::Description doc_description = FillPolicy::doc_description;
|
||||
FunctionDocumentation::Syntax doc_syntax = fmt::format(doc_syntax_format, FillPolicy::name);
|
||||
FunctionDocumentation::Arguments doc_arguments = {{"expression", "The expression is used to bypass common subexpression elimination if the function is called multiple times in a query but otherwise ignored. Optional."}};
|
||||
FunctionDocumentation::ReturnedValue doc_returned_value = "A value of type UUID version 7.";
|
||||
FunctionDocumentation::Examples doc_examples = {{"uuid", fmt::format(example_format, FillPolicy::name), ""}, {"multiple", fmt::format(multiple_example_format, fmt::arg("f", FillPolicy::name)), ""}};
|
||||
FunctionDocumentation::Categories doc_categories = {"UUID"};
|
||||
|
||||
factory.template registerFunction<FunctionGenerateUUIDv7Base<FillPolicy>>({doc_description, doc_syntax, doc_arguments, doc_returned_value, doc_examples, doc_categories}, FunctionFactory::CaseInsensitive);
|
||||
}
|
||||
|
||||
REGISTER_FUNCTION(GenerateUUIDv7)
|
||||
{
|
||||
registerUUIDv7Generator<GlobalCounterPolicy>(factory);
|
||||
registerUUIDv7Generator<ThreadLocalCounterPolicy>(factory);
|
||||
registerUUIDv7Generator<FillAllRandomPolicy>(factory);
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ using FunctionLocate = FunctionsStringSearch<PositionImpl<NameLocate, PositionCa
|
||||
|
||||
REGISTER_FUNCTION(Locate)
|
||||
{
|
||||
FunctionDocumentation::Description doc_description = "Like function `position` but with arguments `haystack` and `locate` switched. The behavior of this function depends on the ClickHouse version: In versions < v24.3, `locate` was an alias of function `position` and accepted arguments `(haystack, needle[, start_pos])`. In versions >= 24.3,, `locate` is an individual function (for better compatibility with MySQL) and accepts arguments `(needle, haystack[, start_pos])`. The previous behaviorcan be restored using setting `function_locate_has_mysql_compatible_argument_order = false`.";
|
||||
FunctionDocumentation::Description doc_description = "Like function `position` but with arguments `haystack` and `locate` switched. The behavior of this function depends on the ClickHouse version: In versions < v24.3, `locate` was an alias of function `position` and accepted arguments `(haystack, needle[, start_pos])`. In versions >= 24.3,, `locate` is an individual function (for better compatibility with MySQL) and accepts arguments `(needle, haystack[, start_pos])`. The previous behavior can be restored using setting `function_locate_has_mysql_compatible_argument_order = false`.";
|
||||
FunctionDocumentation::Syntax doc_syntax = "location(needle, haystack[, start_pos])";
|
||||
FunctionDocumentation::Arguments doc_arguments = {{"needle", "Substring to be searched (String)"},
|
||||
{"haystack", "String in which the search is performed (String)."},
|
||||
|
5
tests/queries/0_stateless/00396_uuid_v7.reference
Normal file
5
tests/queries/0_stateless/00396_uuid_v7.reference
Normal file
@ -0,0 +1,5 @@
|
||||
-- UUIDToNum --
|
||||
1
|
||||
1
|
||||
-- UUIDv7toDateTime --
|
||||
2024-04-22 08:30:29.048
|
19
tests/queries/0_stateless/00396_uuid_v7.sql
Normal file
19
tests/queries/0_stateless/00396_uuid_v7.sql
Normal file
@ -0,0 +1,19 @@
|
||||
SELECT '-- UUIDToNum --';
|
||||
SELECT UUIDToNum(toUUID('00112233-4455-6677-8899-aabbccddeeff'), 1) = UUIDStringToNum('00112233-4455-6677-8899-aabbccddeeff', 1);
|
||||
SELECT UUIDToNum(toUUID('00112233-4455-6677-8899-aabbccddeeff'), 2) = UUIDStringToNum('00112233-4455-6677-8899-aabbccddeeff', 2);
|
||||
SELECT UUIDToNum(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
|
||||
SELECT UUIDToNum(toUUID('00112233-4455-6677-8899-aabbccddeeff'), 1, 2); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
|
||||
SELECT UUIDToNum(toUUID('00112233-4455-6677-8899-aabbccddeeff'), 3); -- { serverError ARGUMENT_OUT_OF_BOUND }
|
||||
SELECT UUIDToNum('00112233-4455-6677-8899-aabbccddeeff', 1); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
|
||||
SELECT UUIDToNum(toUUID('00112233-4455-6677-8899-aabbccddeeff'), '1'); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
|
||||
SELECT UUIDToNum(toUUID('00112233-4455-6677-8899-aabbccddeeff'), materialize(1)); -- { serverError ILLEGAL_COLUMN }
|
||||
|
||||
SELECT '-- UUIDv7toDateTime --';
|
||||
SELECT UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'), 'America/New_York');
|
||||
SELECT UUIDv7ToDateTime(); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
|
||||
SELECT UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'), 1); -- { serverError ILLEGAL_COLUMN }
|
||||
SELECT UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'), 'America/New_York', 1); -- { serverError NUMBER_OF_ARGUMENTS_DOESNT_MATCH }
|
||||
SELECT UUIDv7ToDateTime('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'); -- { serverError ILLEGAL_TYPE_OF_ARGUMENT }
|
||||
SELECT UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'), 'America/NewYork'); -- { serverError BAD_ARGUMENTS }
|
||||
SELECT UUIDv7ToDateTime(toUUID('018f05c9-4ab8-7b86-b64e-c9f03fbd45d1'), materialize('America/New_York')); -- { serverError ILLEGAL_COLUMN }
|
||||
|
21
tests/queries/0_stateless/02310_uuid_v7.reference
Normal file
21
tests/queries/0_stateless/02310_uuid_v7.reference
Normal file
@ -0,0 +1,21 @@
|
||||
-- generateUUIDv7 --
|
||||
UUID
|
||||
7
|
||||
2
|
||||
0
|
||||
0
|
||||
1
|
||||
-- generateUUIDv7ThreadMonotonic --
|
||||
UUID
|
||||
7
|
||||
2
|
||||
0
|
||||
0
|
||||
1
|
||||
-- generateUUIDv7NonMonotonic --
|
||||
UUID
|
||||
7
|
||||
2
|
||||
0
|
||||
0
|
||||
1
|
23
tests/queries/0_stateless/02310_uuid_v7.sql
Normal file
23
tests/queries/0_stateless/02310_uuid_v7.sql
Normal file
@ -0,0 +1,23 @@
|
||||
SELECT '-- generateUUIDv7 --';
|
||||
SELECT toTypeName(generateUUIDv7());
|
||||
SELECT substring(hex(generateUUIDv7()), 13, 1); -- check version bits
|
||||
SELECT bitAnd(bitShiftRight(toUInt128(generateUUIDv7()), 62), 3); -- check variant bits
|
||||
SELECT generateUUIDv7(1) = generateUUIDv7(2);
|
||||
SELECT generateUUIDv7() = generateUUIDv7(1);
|
||||
SELECT generateUUIDv7(1) = generateUUIDv7(1);
|
||||
|
||||
SELECT '-- generateUUIDv7ThreadMonotonic --';
|
||||
SELECT toTypeName(generateUUIDv7ThreadMonotonic());
|
||||
SELECT substring(hex(generateUUIDv7ThreadMonotonic()), 13, 1); -- check version bits
|
||||
SELECT bitAnd(bitShiftRight(toUInt128(generateUUIDv7ThreadMonotonic()), 62), 3); -- check variant bits
|
||||
SELECT generateUUIDv7ThreadMonotonic(1) = generateUUIDv7ThreadMonotonic(2);
|
||||
SELECT generateUUIDv7ThreadMonotonic() = generateUUIDv7ThreadMonotonic(1);
|
||||
SELECT generateUUIDv7ThreadMonotonic(1) = generateUUIDv7ThreadMonotonic(1);
|
||||
|
||||
SELECT '-- generateUUIDv7NonMonotonic --';
|
||||
SELECT toTypeName(generateUUIDv7NonMonotonic());
|
||||
SELECT substring(hex(generateUUIDv7NonMonotonic()), 13, 1); -- check version bits
|
||||
SELECT bitAnd(bitShiftRight(toUInt128(generateUUIDv7NonMonotonic()), 62), 3); -- check variant bits
|
||||
SELECT generateUUIDv7NonMonotonic(1) = generateUUIDv7NonMonotonic(2);
|
||||
SELECT generateUUIDv7NonMonotonic() = generateUUIDv7NonMonotonic(1);
|
||||
SELECT generateUUIDv7NonMonotonic(1) = generateUUIDv7NonMonotonic(1);
|
@ -563,6 +563,7 @@ MinIO
|
||||
MinMax
|
||||
MindsDB
|
||||
Mongodb
|
||||
Monotonicity
|
||||
MsgPack
|
||||
multiSearchAllPositionsCaseInsensitive
|
||||
multiSearchAllPositionsCaseInsensitiveUTF
|
||||
@ -614,6 +615,7 @@ NetworkSendErrors
|
||||
NetworkSendPackets
|
||||
Noaa
|
||||
NodeJs
|
||||
NonMonotonic
|
||||
NuRaft
|
||||
NumHexagons
|
||||
NumPy
|
||||
@ -922,6 +924,7 @@ TAVG
|
||||
TCPConnection
|
||||
TCPThreads
|
||||
TDigest
|
||||
ThreadMonotonic
|
||||
TINYINT
|
||||
TLSv
|
||||
TMAX
|
||||
@ -1006,7 +1009,9 @@ URLPathHierarchy
|
||||
USearch
|
||||
UUIDNumToString
|
||||
UUIDStringToNum
|
||||
UUIDToNum
|
||||
UUIDs
|
||||
UUIDv
|
||||
UUid
|
||||
Uber
|
||||
Uint
|
||||
@ -1041,6 +1046,8 @@ Wether
|
||||
WikiStat
|
||||
WindowView
|
||||
Winkler
|
||||
WithCounter
|
||||
WithFastCounter
|
||||
WithNames
|
||||
WithNamesAndTypes
|
||||
WordNet
|
||||
@ -1969,6 +1976,7 @@ modularization
|
||||
moduloOrZero
|
||||
moduli
|
||||
mongodb
|
||||
monotonicity
|
||||
monthName
|
||||
mortonDecode
|
||||
mortonEncode
|
||||
@ -2758,6 +2766,7 @@ userspace
|
||||
userver
|
||||
utils
|
||||
uuid
|
||||
uuidv
|
||||
varPop
|
||||
varPopStable
|
||||
varSamp
|
||||
|
Loading…
Reference in New Issue
Block a user