diff --git a/docs/en/sql-reference/functions/uuid-functions.md b/docs/en/sql-reference/functions/uuid-functions.md index 07232b9a7cb1..3681f3d76b41 100644 --- a/docs/en/sql-reference/functions/uuid-functions.md +++ b/docs/en/sql-reference/functions/uuid-functions.md @@ -52,11 +52,17 @@ SELECT generateUUIDv4(1), generateUUIDv4(2); └──────────────────────────────────────┴──────────────────────────────────────┘ ``` -## generateUUIDv7 +## generateUUIDv7 {#uuidv7-function-generate} 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). +At any given new timestamp in unix_ts_ms, the counter starts from some random value and then it's being increased by 1 on each new UUID v7 with counter generation until current timestamp changes. +The counter overflow causes unix_ts_ms field increment by 1 and the counter restart from a random value. Counter increment monotony at one timestamp is guaranteed across all `generateUUIDv7` functions running simultaneously. + +:::note +As of April 2024 UUIDv7 is only a draft and the layout may change in future. +::: ``` 0 1 2 3 @@ -64,9 +70,9 @@ The generated UUID contains the current Unix timestamp in milliseconds (48 bits) ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ | unix_ts_ms | ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -| unix_ts_ms | ver | rand_a | +| unix_ts_ms | ver | counter_high_bits | ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -|var| rand_b | +|var| counter_low_bits | ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ | rand_b | └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ @@ -110,40 +116,25 @@ SELECT * FROM tab; SELECT generateUUIDv7(1), generateUUIDv7(2); ┌─generateUUIDv7(1)────────────────────┬─generateUUIDv7(2)────────────────────┐ -│ 018f05b1-8c2e-7567-a988-48d09606ae8c │ 018f05b1-8c2e-7946-895b-fcd7635da9a0 │ +│ 018f05c9-4ab8-7b86-b64e-c9f03fbd45d1 │ 018f05c9-4ab8-7b86-b64e-c9f12efb7e16 │ └──────────────────────────────────────┴──────────────────────────────────────┘ ``` -## generateUUIDv7WithCounter +## generateUUIDv7WithFastCounter 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). -At any given new timestamp in unix_ts_ms, the counter starts from some random value and then it's being increased by 1 on each new UUID v7 with counter generation until current timestamp changes. -The counter overflow causes unix_ts_ms field increment by 1 and the counter restart from a random value. Counter increment monotony at one timestamp is guaranteed across all `generateUUIDv7WithCounter` functions running simultaneously. -``` - 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 | -└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ -``` +This function behaves like [generateUUIDv7](#uuidv7-function-generate) but gives no guarantee on counter monotony across different requests running simultaneously. Counter increment monotony at one timestamp is guaranteed only within one thread calling this function to generate many UUIDs. **Syntax** ``` sql -generateUUIDv7WithCounter([x]) +generateUUIDv7WithFastCounter([x]) ``` **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 expression is used to bypass [common subexpression elimination](../../sql-reference/functions/index.md#common-subexpression-elimination) if the function is called multiple times in a query but otherwise ignored. Optional. +- `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. **Returned value** @@ -156,72 +147,92 @@ First, create a table with a column of type UUID, then insert a generated UUIDv7 ``` sql CREATE TABLE tab (uuid UUID) ENGINE = Memory; -INSERT INTO tab SELECT generateUUIDv7WithCounter(); +INSERT INTO tab SELECT generateUUIDv7WithFastCounter(); SELECT * FROM tab; ``` ```response ┌─────────────────────────────────uuid─┐ -│ 018f05c7-56e3-7ac3-93e9-1d93c4218e0e │ +│ 018f05e2-e3b2-70cb-b8be-64b09b626d32 │ └──────────────────────────────────────┘ ``` **Example where multiple UUIDs are generated per row** ```sql -SELECT generateUUIDv7WithCounter(1), generateUUIDv7WithCounter(2); +SELECT generateUUIDv7WithFastCounter(1), generateUUIDv7WithFastCounter(2); -┌─generateUUIDv7WithCounter(1)─────────┬─generateUUIDv7WithCounter(2)─────────┐ -│ 018f05c9-4ab8-7b86-b64e-c9f03fbd45d1 │ 018f05c9-4ab8-7b86-b64e-c9f12efb7e16 │ +┌─generateUUIDv7WithFastCounter(1)─────┬─generateUUIDv7WithFastCounter(2)─────┐ +│ 018f05e1-14ee-7bc5-9906-207153b400b1 │ 018f05e1-14ee-7bc5-9906-2072b8e96758 │ └──────────────────────────────────────┴──────────────────────────────────────┘ ``` -## generateUUIDv7WithFastCounter + +## generateUUIDv7NonMonotonic Generates a [UUID](../data-types/uuid.md) of [version 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). -This function behaves like `generateUUIDv7WithCounter` but gives no guarantee on counter monotony across different requests running simultaneously. Counter increment monotony at one timestamp is guaranteed only within one thread calling this function to generate many UUIDs. +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 variant field "2", 2 bit). +The monotonicity within one timestamp is not guaranteed at all. This is the fastest version of `generateUUIDv7*` functions family. + +:::note +As of April 2024 UUIDv7 is only a draft and the layout may change in future. +::: + +``` + 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 | +└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ +``` **Syntax** ``` sql -generateUUIDv7WithFastCounter([x]) +generateUUIDv7NonMonotonic([x]) ``` **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. +- `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 expression is used to bypass [common subexpression elimination](../../sql-reference/functions/index.md#common-subexpression-elimination) if the function is called multiple times in a query but otherwise ignored. Optional. **Returned value** A value of type UUIDv7. -**Usage example** +**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 generateUUIDv7WithFastCounter(); +INSERT INTO tab SELECT generateUUIDv7NonMonotonic(); SELECT * FROM tab; ``` ```response ┌─────────────────────────────────uuid─┐ -│ 018f05e2-e3b2-70cb-b8be-64b09b626d32 │ +│ 018f05af-f4a8-778f-beee-1bedbc95c93b │ └──────────────────────────────────────┘ ``` **Example where multiple UUIDs are generated per row** ```sql -SELECT generateUUIDv7WithFastCounter(1), generateUUIDv7WithFastCounter(2); +SELECT generateUUIDv7NonMonotonic(1), generateUUIDv7NonMonotonic(2); -┌─generateUUIDv7WithFastCounter(1)─────┬─generateUUIDv7WithFastCounter(2)─────┐ -│ 018f05e1-14ee-7bc5-9906-207153b400b1 │ 018f05e1-14ee-7bc5-9906-2072b8e96758 │ +┌─generateUUIDv7NonMonotonic(1) ───────┬─generateUUIDv7(2)NonMonotonic────────┐ +│ 018f05b1-8c2e-7567-a988-48d09606ae8c │ 018f05b1-8c2e-7946-895b-fcd7635da9a0 │ └──────────────────────────────────────┴──────────────────────────────────────┘ ``` diff --git a/docs/ru/sql-reference/functions/uuid-functions.md b/docs/ru/sql-reference/functions/uuid-functions.md index 8f41d2ab6f43..f072d9d68633 100644 --- a/docs/ru/sql-reference/functions/uuid-functions.md +++ b/docs/ru/sql-reference/functions/uuid-functions.md @@ -53,21 +53,23 @@ 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, и случайных данных в следующей последовательности: +Генерирует идентификатор [UUID версии 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). Генерируемый UUID состоит из 48-битной временной метки (Unix time в миллисекундах), маркеров версии 7 и варианта 2, монотонно возрастающего счётчика для данной временной метки и случайных данных в указанной ниже последовательности. Для каждой новой временной метки счётчик стартует с нового случайного значения, а для следующих UUIDv7 он увеличивается на единицу. В случае переполнения счётчика временная метка принудительно увеличивается на 1, и счётчик снова стартует со случайного значения. Монотонность возрастания счётчика для каждой временной метки гарантируется между всеми одновременно работающими функциями `generateUUIDv7WithCounter`. +::::note +На апрель 2024 года UUIDv7 находится в статусе черновика и его раскладка по битам может в итоге измениться. +:::: ``` 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 | +| unix_ts_ms | ver | counter_high_bits | ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ -|var| rand_b | +|var| counter_low_bits | ├─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┼─┤ | rand_b | └─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ ``` - **Синтаксис** ``` sql @@ -89,46 +91,34 @@ generateUUIDv7([x]) ``` sql CREATE TABLE t_uuid (x UUID) ENGINE=TinyLog -INSERT INTO t_uuid SELECT generateUUIDv7() +INSERT INTO t_uuid SELECT generateUUIDv7WithCounter() SELECT * FROM t_uuid ``` ``` text ┌────────────────────────────────────x─┐ -│ 018f05af-f4a8-778f-beee-1bedbc95c93b │ +│ 018f05c7-56e3-7ac3-93e9-1d93c4218e0e │ └──────────────────────────────────────┘ ``` **Пример использования, для генерации нескольких значений в одной строке** ```sql -SELECT generateUUIDv7(1), generateUUIDv7(7) +SELECT generateUUIDv7(1), generateUUIDv7(2) ┌─generateUUIDv7(1)────────────────────┬─generateUUIDv7(2)────────────────────┐ -│ 018f05b1-8c2e-7567-a988-48d09606ae8c │ 018f05b1-8c2e-7946-895b-fcd7635da9a0 │ +│ 018f05c9-4ab8-7b86-b64e-c9f03fbd45d1 │ 018f05c9-4ab8-7b86-b64e-c9f12efb7e16 │ └──────────────────────────────────────┴──────────────────────────────────────┘ ``` -## generateUUIDv7WithCounter {#uuidv7withcounter-function-generate} +## generateUUIDv7WithFastCounter {#uuidv7withfastcounter-function-generate} + +Генерирует идентификатор [UUID версии 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). Данная функция является ускоренным аналогом функции `generateUUIDv7WithCounter` за счёт потери гарантии монотонности счётчика при одной и той же метке времени между одновременно исполняемыми разными запросами. Монотонность счётчика гарантируется только в пределах одного треда, исполняющего данную функцию для генерации нескольких UUID. -Генерирует идентификатор [UUID версии 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). Генерируемый UUID состоит из 48-битной временной метки (Unix time в миллисекундах), маркеров версии 7 и варианта 2, монотонно возрастающего счётчика для данной временной метки и случайных данных в указанной ниже последовательности. Для каждой новой временной метки счётчик стартует с нового случайного значения, а для следующих UUIDv7 он увеличивается на единицу. В случае переполнения счётчика временная метка принудительно увеличивается на 1, и счётчик снова стартует со случайного значения. Монотонность возрастания счётчика для каждой временной метки гарантируется между всеми одновременно работающими функциями `generateUUIDv7WithCounter`. -``` - 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 | -└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ -``` **Синтаксис** ``` sql -generateUUIDv7WithCounter([x]) +generateUUIDv7WithFastCounter([x]) ``` **Аргументы** @@ -146,34 +136,50 @@ generateUUIDv7WithCounter([x]) ``` sql CREATE TABLE t_uuid (x UUID) ENGINE=TinyLog -INSERT INTO t_uuid SELECT generateUUIDv7WithCounter() +INSERT INTO t_uuid SELECT generateUUIDv7WithFastCounter() SELECT * FROM t_uuid ``` ``` text ┌────────────────────────────────────x─┐ -│ 018f05c7-56e3-7ac3-93e9-1d93c4218e0e │ +│ 018f05e2-e3b2-70cb-b8be-64b09b626d32 │ └──────────────────────────────────────┘ ``` **Пример использования, для генерации нескольких значений в одной строке** ```sql -SELECT generateUUIDv7WithCounter(1), generateUUIDv7WithCounter(7) -┌─generateUUIDv7WithCounter(1)─────────┬─generateUUIDv7WithCounter(2)─────────┐ -│ 018f05c9-4ab8-7b86-b64e-c9f03fbd45d1 │ 018f05c9-4ab8-7b86-b64e-c9f12efb7e16 │ +SELECT generateUUIDv7WithFastCounter(1), generateUUIDv7WithFastCounter(7) +┌─generateUUIDv7WithFastCounter(1)─────┬─generateUUIDv7WithFastCounter(2)─────┐ +│ 018f05e1-14ee-7bc5-9906-207153b400b1 │ 018f05e1-14ee-7bc5-9906-2072b8e96758 │ └──────────────────────────────────────┴──────────────────────────────────────┘ ``` -## generateUUIDv7WithFastCounter {#uuidv7withfastcounter-function-generate} +## generateUUIDv7NonMonotonic {#uuidv7nonmonotonic-function-generate} -Генерирует идентификатор [UUID версии 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). Данная функция является ускоренным аналогом функции `generateUUIDv7WithCounter` за счёт потери гарантии монотонности счётчика при одной и той же метке времени между одновременно исполняемыми разными запросами. Монотонность счётчика гарантируется только в пределах одного треда, исполняющего данную функцию для генерации нескольких UUID. +Генерирует идентификатор [UUID версии 7](https://datatracker.ietf.org/doc/html/draft-peabody-dispatch-new-uuid-format-04). Генерируемый UUID состоит из 48-битной временной метки (Unix time в миллисекундах), маркеров версии 7 и варианта 2, и случайных данных в следующей последовательности: +::::note +На апрель 2024 года UUIDv7 находится в статусе черновика и его раскладка по битам может в итоге измениться. +:::: +``` + 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 | +└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘ +``` **Синтаксис** ``` sql -generateUUIDv7WithFastCounter([x]) +generateUUIDv7NonMonotonic([x]) ``` **Аргументы** @@ -191,23 +197,23 @@ generateUUIDv7WithFastCounter([x]) ``` sql CREATE TABLE t_uuid (x UUID) ENGINE=TinyLog -INSERT INTO t_uuid SELECT generateUUIDv7WithFastCounter() +INSERT INTO t_uuid SELECT generateUUIDv7NonMonotonic() SELECT * FROM t_uuid ``` ``` text ┌────────────────────────────────────x─┐ -│ 018f05e2-e3b2-70cb-b8be-64b09b626d32 │ +│ 018f05af-f4a8-778f-beee-1bedbc95c93b │ └──────────────────────────────────────┘ ``` **Пример использования, для генерации нескольких значений в одной строке** ```sql -SELECT generateUUIDv7WithFastCounter(1), generateUUIDv7WithFastCounter(7) -┌─generateUUIDv7WithFastCounter(1)─────┬─generateUUIDv7WithFastCounter(2)─────┐ -│ 018f05e1-14ee-7bc5-9906-207153b400b1 │ 018f05e1-14ee-7bc5-9906-2072b8e96758 │ +SELECT generateUUIDv7(1), generateUUIDv7(7) +┌─generateUUIDv7NonMonotonic(1)────────┬─generateUUIDv7NonMonotonic(2)────────┐ +│ 018f05b1-8c2e-7567-a988-48d09606ae8c │ 018f05b1-8c2e-7946-895b-fcd7635da9a0 │ └──────────────────────────────────────┴──────────────────────────────────────┘ ``` diff --git a/src/Functions/FunctionsCodingUUID.cpp b/src/Functions/FunctionsCodingUUID.cpp index 889eec866a88..a6fc9779ae10 100644 --- a/src/Functions/FunctionsCodingUUID.cpp +++ b/src/Functions/FunctionsCodingUUID.cpp @@ -408,7 +408,6 @@ class FunctionUUIDv7ToDateTime : public IFunction String getName() const override { return name; } size_t getNumberOfArguments() const override { return 0; } - bool isInjective(const ColumnsWithTypeAndName &) const override { return true; } bool isSuitableForShortCircuitArgumentsExecution(const DataTypesWithConstInfo & /*arguments*/) const override { return false; } bool isVariadic() const override { return true; } diff --git a/src/Functions/generateUUIDv7.cpp b/src/Functions/generateUUIDv7.cpp index 5da0be2b998e..0b5e1827cc51 100644 --- a/src/Functions/generateUUIDv7.cpp +++ b/src/Functions/generateUUIDv7.cpp @@ -7,21 +7,59 @@ namespace DB namespace ErrorCodes { - extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; +extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH; } namespace { -constexpr auto bits_in_counter = 42; + +/* Bit layouts of the 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); -constexpr uint8_t random_data_offset = 6; -constexpr uint8_t random_data_count = 10; -constexpr uint8_t next_count_random_data_offset = 12; -constexpr uint8_t next_count_random_data_count = 4; -using UUIDAsArray = std::array; +// bit masks for UUIDv7 parts +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 auto counter_high_bits_mask = rand_a_bits_mask; -uint64_t getTimestampMs() +inline uint64_t getTimestampMillisecond() { timespec tp; clock_gettime(CLOCK_REALTIME, &tp); @@ -29,270 +67,200 @@ uint64_t getTimestampMs() return sec * 1000 + tp.tv_nsec / 1000000; } -void fillTimestamp(UUIDAsArray & uuid, uint64_t timestamp) +inline void setTimestamp(UUID & uuid, uint64_t timestamp) { - uuid[0] = (timestamp >> 40) & 0xFF; - uuid[1] = (timestamp >> 32) & 0xFF; - uuid[2] = (timestamp >> 24) & 0xFF; - uuid[3] = (timestamp >> 16) & 0xFF; - uuid[4] = (timestamp >> 8) & 0xFF; - uuid[5] = (timestamp)&0xFF; -} + UUIDHelpers::getHighBytes(uuid) = (UUIDHelpers::getHighBytes(uuid) & rand_a_bits_mask) | ( timestamp << 16) | 0x7000; // version 7 } -#define DECLARE_SEVERAL_IMPLEMENTATIONS(...) \ - DECLARE_DEFAULT_CODE(__VA_ARGS__) \ - DECLARE_AVX2_SPECIFIC_CODE(__VA_ARGS__) - -DECLARE_SEVERAL_IMPLEMENTATIONS( +inline void setVariant(UUID & uuid) +{ + UUIDHelpers::getLowBytes(uuid) = (UUIDHelpers::getLowBytes(uuid) & rand_b_bits_mask) | variant_2_mask; +} -namespace UUIDv7Impl +struct FillAllRandomPolicy { - void store(UUID & new_uuid, UUIDAsArray & uuid) + static constexpr auto name = "generateUUIDv7NonMonotonic"; + static constexpr auto doc_description = "Generates a UUID of version 7 containing the current Unix timestamp in milliseconds (48 bits), followed by version \"7\" (4 bits), and a random field (74 bit) to distinguish UUIDs within a millisecond (including a variant field \"2\", 2 bit). It is the fastest version of generateUUIDv7* functions family."; + struct Data { - uuid[6] = (uuid[6] & 0x0f) | 0x70; // version 7 - uuid[8] = (uuid[8] & 0x3f) | 0x80; // variant 2 + Data() {} - DB::UUIDHelpers::getHighBytes(new_uuid) = unalignedLoadBigEndian(uuid.data()); - DB::UUIDHelpers::getLowBytes(new_uuid) = unalignedLoadBigEndian(uuid.data() + 8); - } + void generate(UUID & uuid, uint64_t ts) + { + setTimestamp(uuid, ts); + setVariant(uuid); + } + }; +}; - struct UUIDv7Base +struct CounterFields +{ + uint64_t timestamp = 0; + uint64_t counter = 0; + + void resetCounter(const UUID& uuid) { - UUIDAsArray & uuid; - explicit UUIDv7Base(UUIDAsArray & u) : uuid(u) { } - }; + const uint64_t counterLowBits = (UUIDHelpers::getLowBytes(uuid) >> rand_b_low_bits_count) & counter_low_bits_mask; + const uint64_t counterHighBits = UUIDHelpers::getHighBytes(uuid) & counter_high_bits_mask; + counter = (counterHighBits << 30) | counterLowBits; + } - struct RandomData + void incrementCounter(UUID& uuid) { - static constexpr auto name = "generateUUIDv7"; - struct Data : UUIDv7Base + if (++counter == counter_limit) [[unlikely]] { - UUIDAsArray uuid_data; - - Data() : UUIDv7Base(uuid_data) { } - - void generate(UUID & new_uuid) - { - fillTimestamp(uuid, getTimestampMs()); - memcpy(uuid.data() + random_data_offset, &new_uuid, random_data_count); - store(new_uuid, uuid); - } - }; - }; + ++timestamp; + resetCounter(uuid); + setTimestamp(uuid, timestamp); + setVariant(uuid); + } + else + { + UUIDHelpers::getHighBytes(uuid) = (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); + } + } - struct CounterDataCommon : UUIDv7Base + void generate(UUID& new_uuid, uint64_t unix_time_ms) { - explicit CounterDataCommon(UUIDAsArray & u) - : UUIDv7Base(u) - {} - - uint64_t getCounter() + const bool need_to_increment_counter = (timestamp == unix_time_ms) || ((timestamp > unix_time_ms) & (timestamp < unix_time_ms + 10000)); + if (need_to_increment_counter) { - uint64_t counter = uuid[6] & 0x0f; - counter = (counter << 8) | uuid[7]; - counter = (counter << 6) | (uuid[8] & 0x3f); - counter = (counter << 8) | uuid[9]; - counter = (counter << 8) | uuid[10]; - counter = (counter << 8) | uuid[11]; - return counter; + incrementCounter(new_uuid); } - - void generate(UUID & newUUID) + else { - uint64_t timestamp = 0; - /// Get timestamp of the previous uuid - for (int i = 0; i != 6; ++i) - timestamp = (timestamp << 8) | uuid[i]; - - const uint64_t unix_time_ms = getTimestampMs(); - // continue incrementing counter when clock slightly goes back or when counter overflow happened during the previous UUID generation - bool need_to_increment_counter = (timestamp == unix_time_ms || timestamp < unix_time_ms + 10000); - uint64_t counter = 0; - if (need_to_increment_counter) - counter = getCounter(); - else - timestamp = unix_time_ms; - - bool counter_incremented = false; - if (need_to_increment_counter) - { - if (++counter == counter_limit) - { - ++timestamp; - // counter bytes will be filled by the random data - } - else - { - uuid[6] = counter >> 38; - uuid[7] = counter >> 30; - uuid[8] = counter >> 24; - uuid[9] = counter >> 16; - uuid[10] = counter >> 8; - uuid[11] = counter; - counter_incremented = true; - } - } + timestamp = unix_time_ms; + resetCounter(new_uuid); + setTimestamp(new_uuid, timestamp); + setVariant(new_uuid); + } + } +}; - fillTimestamp(uuid, timestamp); - // Get the required number of random bytes: 4 in the case of incrementing existing counter, 10 in the case of renewing counter - memcpy( - uuid.data() + (counter_incremented ? next_count_random_data_offset : random_data_offset), - &newUUID, - counter_incremented ? next_count_random_data_count : random_data_count); +struct CounterDataCommon +{ + CounterFields& fields; + explicit CounterDataCommon(CounterFields & f) + : fields(f) + {} - store(newUUID, uuid); - } - }; + void generate(UUID& uuid, uint64_t ts) + { + fields.generate(uuid, ts); + } +}; + +struct ThreadLocalCounter +{ + static constexpr auto name = "generateUUIDv7WithFastCounter"; + static constexpr auto doc_description = "Generates a UUID of version 7 containing 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). Counter increment monotony at one timestamp is guaraneed only within one thread running generateUUIDv7 function."; - struct ThreadLocalCounter + struct Data : CounterDataCommon { - static constexpr auto name = "generateUUIDv7WithFastCounter"; - struct Data : CounterDataCommon + // Implement counter monotony only within one thread so function doesn't require mutexes and doesn't affect performance of the same function running simultenaously on other threads + static inline thread_local CounterFields thread_local_fields; + Data() + : CounterDataCommon(thread_local_fields) { - // Implement counter monotony only within one thread so function doesn't require mutexes and doesn't affect performance of the same function running simultenaously on other threads - static inline thread_local UUIDAsArray uuid_data; - - Data() - : CounterDataCommon(uuid_data) - {} - }; + } }; +}; + +struct GlobalCounter +{ + static constexpr auto name = "generateUUIDv7"; + static constexpr auto doc_description = "Generates a UUID of version 7 containing 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). Counter increment monotony at one timestamp is guaraneed across all generateUUIDv7 functions running simultaneously."; - struct GlobalCounter + struct Data : CounterDataCommon { - static constexpr auto name = "generateUUIDv7WithCounter"; - struct Data : std::lock_guard, CounterDataCommon + // Implement counter monotony within one timestamp across all threads generating UUIDv7 with counter simultaneously + static inline CounterFields static_fields; + static inline SharedMutex mtx; + std::lock_guard guard; // SharedMutex works a little bit faster than std::mutex here + Data() + : CounterDataCommon(static_fields) + , guard(mtx) { - // Implement counter monotony within one timestamp across all threads generating UUIDv7 with counter simultaneously - static inline UUIDAsArray uuid_data; - static inline std::mutex mtx; - - Data() - : std::lock_guard(mtx) - , CounterDataCommon(uuid_data) - {} - }; + } }; +}; } -template -class FunctionGenerateUUIDv7Base : public IFunction, public FillPolicy -{ - public: - using FillPolicy::name; - using FillPolicyData = typename FillPolicy::Data; - - FunctionGenerateUUIDv7Base() = default; - - String getName() const final { return 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 DataTypes & 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()); - - return std::make_shared(); - } - - ColumnPtr executeImpl(const ColumnsWithTypeAndName &, const DataTypePtr &, size_t input_rows_count) const override - { - auto col_res = ColumnVector::create(); - typename ColumnVector::Container & vec_to = col_res->getData(); - - size_t size = input_rows_count; - vec_to.resize(size); - - /// RandImpl is target-dependent and is not the same in different TargetSpecific namespaces. - /// 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(vec_to.data()), vec_to.size() * sizeof(UUID)); - - for (UUID & new_uuid : vec_to) - { - FillPolicyData data; - data.generate(new_uuid); - } - - return col_res; - } - }; - -using FunctionGenerateUUIDv7 = FunctionGenerateUUIDv7Base; -using FunctionGenerateUUIDv7WithCounter = FunctionGenerateUUIDv7Base; -using FunctionGenerateUUIDv7WithFastCounter = FunctionGenerateUUIDv7Base; - -) // DECLARE_SEVERAL_IMPLEMENTATIONS -#undef DECLARE_SEVERAL_IMPLEMENTATIONS +#define DECLARE_SEVERAL_IMPLEMENTATIONS(...) \ +DECLARE_DEFAULT_CODE (__VA_ARGS__) \ +DECLARE_AVX2_SPECIFIC_CODE(__VA_ARGS__) +DECLARE_SEVERAL_IMPLEMENTATIONS( -class FunctionGenerateUUIDv7 : public TargetSpecific::Default::FunctionGenerateUUIDv7 -{ +template +class FunctionGenerateUUIDv7Base : public IFunction, public FillPolicy { public: - explicit FunctionGenerateUUIDv7(ContextPtr context) : selector(context) - { - selector.registerImplementation(); + using FillPolicy::name; + using FillPolicyData = typename FillPolicy::Data; -#if USE_MULTITARGET_CODE - selector.registerImplementation(); -#endif - } + String getName() const final { return name; } - 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(context); } - -private: - ImplementationSelector selector; -}; + 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; } -class FunctionGenerateUUIDv7WithCounter : public TargetSpecific::Default::FunctionGenerateUUIDv7WithCounter -{ -public: - explicit FunctionGenerateUUIDv7WithCounter(ContextPtr context) : selector(context) + DataTypePtr getReturnTypeImpl(const DataTypes & arguments) const override { - selector.registerImplementation(); - -#if USE_MULTITARGET_CODE - selector.registerImplementation(); -#endif + 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()); + + return std::make_shared(); } - ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override + ColumnPtr executeImpl(const ColumnsWithTypeAndName &, const DataTypePtr &, size_t input_rows_count) const override { - return selector.selectAndExecute(arguments, result_type, input_rows_count); - } + auto col_res = ColumnVector::create(); + typename ColumnVector::Container & vec_to = col_res->getData(); - static FunctionPtr create(ContextPtr context) { return std::make_shared(context); } - -private: - ImplementationSelector selector; + size_t size = input_rows_count; + if (size) + { + vec_to.resize(size); + + /// 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(vec_to.data()), vec_to.size() * sizeof(UUID)); + auto ts = getTimestampMillisecond(); + for (UUID & new_uuid : vec_to) + { + FillPolicyData data; + data.generate(new_uuid, ts); + } + } + return col_res; + } }; +) // DECLARE_SEVERAL_IMPLEMENTATIONS +#undef DECLARE_SEVERAL_IMPLEMENTATIONS - -class FunctionGenerateUUIDv7WithFastCounter : public TargetSpecific::Default::FunctionGenerateUUIDv7WithFastCounter +template +class FunctionGenerateUUIDv7Base : public TargetSpecific::Default::FunctionGenerateUUIDv7Base { public: - explicit FunctionGenerateUUIDv7WithFastCounter(ContextPtr context) : selector(context) + using Self = FunctionGenerateUUIDv7Base; + using Parent = TargetSpecific::Default::FunctionGenerateUUIDv7Base; + + explicit FunctionGenerateUUIDv7Base(ContextPtr context) : selector(context) { - selector.registerImplementation(); + selector.registerImplementation(); -#if USE_MULTITARGET_CODE - selector.registerImplementation(); -#endif + #if USE_MULTITARGET_CODE + using ParentAVX2 = TargetSpecific::AVX2::FunctionGenerateUUIDv7Base; + selector.registerImplementation(); + #endif } ColumnPtr executeImpl(const ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, size_t input_rows_count) const override @@ -300,52 +268,35 @@ class FunctionGenerateUUIDv7WithFastCounter : public TargetSpecific::Default::Fu return selector.selectAndExecute(arguments, result_type, input_rows_count); } - static FunctionPtr create(ContextPtr context) { return std::make_shared(context); } + static FunctionPtr create(ContextPtr context) + { + return std::make_shared(context); + } private: ImplementationSelector selector; }; +template +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>({doc_description, doc_syntax, doc_arguments, doc_returned_value, doc_examples, doc_categories}, FunctionFactory::CaseInsensitive); +} REGISTER_FUNCTION(GenerateUUIDv7) { - factory.registerFunction( - FunctionDocumentation{ - .description = R"( -Generates a UUID of version 7 with current Unix time having milliseconds precision followed by random data. -This function takes an optional argument, the value of which is discarded to generate different values in case the function is called multiple times. -The function returns a value of type UUID. -)", - .examples{{"uuid", "SELECT generateUUIDv7()", ""}, {"multiple", "SELECT generateUUIDv7(1), generateUUIDv7(2)", ""}}, - .categories{"UUID"}}, - FunctionFactory::CaseSensitive); - - factory.registerFunction( - FunctionDocumentation{ - .description = R"( -Generates a UUID of version 7 with current Unix time having milliseconds precision, a monotonic counter within the same timestamp starting from the random value, and followed by 4 random bytes. -This function takes an optional argument, the value of which is discarded to generate different values in case the function is called multiple times. -The function returns a value of type UUID. -)", - .examples{ - {"uuid", "SELECT generateUUIDv7WithCounter()", ""}, - {"multiple", "SELECT generateUUIDv7WithCounter(1), generateUUIDv7WithCounter(2)", ""}}, - .categories{"UUID"}}, - FunctionFactory::CaseSensitive); - - factory.registerFunction( - FunctionDocumentation{ - .description = R"( -Generates a UUID of version 7 with current Unix time having milliseconds precision, a monotonic counter within the same timestamp and the same request starting from the random value, and followed by 4 random bytes. -This function takes an optional argument, the value of which is discarded to generate different values in case the function is called multiple times. -This function is a little bit faster version of the function GenerateUUIDv7WithCounter. It doesn't guarantee the counter monotony within the same timestamp across different requests. -The function returns a value of type UUID. -)", - .examples{ - {"uuid", "SELECT generateUUIDv7WithFastCounter()", ""}, - {"multiple", "SELECT generateUUIDv7WithFastCounter(1), generateUUIDv7WithFastCounter(2)", ""}}, - .categories{"UUID"}}, - FunctionFactory::CaseSensitive); + registerUUIDv7Generator(factory); + registerUUIDv7Generator(factory); + registerUUIDv7Generator(factory); } } diff --git a/tests/queries/0_stateless/02310_generate_multi_columns_with_uuid_v7.reference b/tests/queries/0_stateless/02310_generate_multi_columns_with_uuid_v7.reference deleted file mode 100644 index b6d3cdbe300b..000000000000 --- a/tests/queries/0_stateless/02310_generate_multi_columns_with_uuid_v7.reference +++ /dev/null @@ -1,9 +0,0 @@ -0 -0 -1 -0 -0 -1 -0 -0 -1 diff --git a/tests/queries/0_stateless/02310_generate_multi_columns_with_uuid_v7.sql b/tests/queries/0_stateless/02310_generate_multi_columns_with_uuid_v7.sql deleted file mode 100644 index 39e62185099d..000000000000 --- a/tests/queries/0_stateless/02310_generate_multi_columns_with_uuid_v7.sql +++ /dev/null @@ -1,17 +0,0 @@ -SELECT generateUUIDv7(1) = generateUUIDv7(2); - -SELECT generateUUIDv7() = generateUUIDv7(1); - -SELECT generateUUIDv7(1) = generateUUIDv7(1); - -SELECT generateUUIDv7WithCounter(1) = generateUUIDv7WithCounter(2); - -SELECT generateUUIDv7WithCounter() = generateUUIDv7WithCounter(1); - -SELECT generateUUIDv7WithCounter(1) = generateUUIDv7WithCounter(1); - -SELECT generateUUIDv7WithFastCounter(1) = generateUUIDv7WithFastCounter(2); - -SELECT generateUUIDv7WithFastCounter() = generateUUIDv7WithFastCounter(1); - -SELECT generateUUIDv7WithFastCounter(1) = generateUUIDv7WithFastCounter(1); diff --git a/tests/queries/0_stateless/02310_uuid_v7.reference b/tests/queries/0_stateless/02310_uuid_v7.reference new file mode 100644 index 000000000000..149a9018d4e3 --- /dev/null +++ b/tests/queries/0_stateless/02310_uuid_v7.reference @@ -0,0 +1,21 @@ +-- generateUUIDv7 -- +UUID +7 +2 +0 +0 +1 +-- generateUUIDv7WithFastCounter -- +UUID +7 +2 +0 +0 +1 +-- generateUUIDv7NonMonotonic -- +UUID +7 +2 +0 +0 +1 diff --git a/tests/queries/0_stateless/02310_uuid_v7.sql b/tests/queries/0_stateless/02310_uuid_v7.sql new file mode 100644 index 000000000000..6f80cfbd921c --- /dev/null +++ b/tests/queries/0_stateless/02310_uuid_v7.sql @@ -0,0 +1,23 @@ +SELECT '-- generateUUIDv7 --'; +SELECT toTypeName(generateUUIDv7()); +SELECT substring(hex(generateUUIDv7()), 13, 1); -- extract version +SELECT bitAnd(bitShiftRight(toUInt128(generateUUIDv7()), 62), 3); -- extract variant +SELECT generateUUIDv7(1) = generateUUIDv7(2); +SELECT generateUUIDv7() = generateUUIDv7(1); +SELECT generateUUIDv7(1) = generateUUIDv7(1); + +SELECT '-- generateUUIDv7WithFastCounter --'; +SELECT toTypeName(generateUUIDv7WithFastCounter()); +SELECT substring(hex(generateUUIDv7WithFastCounter()), 13, 1); -- extract version +SELECT bitAnd(bitShiftRight(toUInt128(generateUUIDv7WithFastCounter()), 62), 3); -- extract variant +SELECT generateUUIDv7WithFastCounter(1) = generateUUIDv7WithFastCounter(2); +SELECT generateUUIDv7WithFastCounter() = generateUUIDv7WithFastCounter(1); +SELECT generateUUIDv7WithFastCounter(1) = generateUUIDv7WithFastCounter(1); + +SELECT '-- generateUUIDv7NonMonotonic --'; +SELECT toTypeName(generateUUIDv7NonMonotonic()); +SELECT substring(hex(generateUUIDv7NonMonotonic()), 13, 1); -- extract version +SELECT bitAnd(bitShiftRight(toUInt128(generateUUIDv7NonMonotonic()), 62), 3); -- extract variant +SELECT generateUUIDv7NonMonotonic(1) = generateUUIDv7NonMonotonic(2); +SELECT generateUUIDv7NonMonotonic() = generateUUIDv7NonMonotonic(1); +SELECT generateUUIDv7NonMonotonic(1) = generateUUIDv7NonMonotonic(1);