From 9aa596f9cc5b8d4603f3aadec861f7e7e7976128 Mon Sep 17 00:00:00 2001 From: Varun Deep Saini Date: Wed, 24 Dec 2025 00:48:37 +0530 Subject: [PATCH 1/8] Implement UUID_TIMESTAMP() function that extracts timestamp from UUIDv1 and UUIDv7 values --- plugin/type_uuid/item_uuidfunc.cc | 54 +++++++++++++++++ plugin/type_uuid/item_uuidfunc.h | 26 ++++++++ .../type_uuid/func_uuid_timestamp.result | 60 +++++++++++++++++++ .../type_uuid/func_uuid_timestamp.test | 40 +++++++++++++ plugin/type_uuid/plugin.cc | 34 ++++++++++- 5 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result create mode 100644 plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test diff --git a/plugin/type_uuid/item_uuidfunc.cc b/plugin/type_uuid/item_uuidfunc.cc index c024cb30e3e5a..1623f4d9993c6 100644 --- a/plugin/type_uuid/item_uuidfunc.cc +++ b/plugin/type_uuid/item_uuidfunc.cc @@ -16,6 +16,10 @@ #define MYSQL_SERVER #include "mariadb.h" #include "item_uuidfunc.h" +#include + +// 100-nanosecond intervals between 1582-10-15 and 1970-01-01 +#define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * 1000 * 1000 * 10) String *Item_func_sys_guid::val_str(String *str) { @@ -29,3 +33,53 @@ String *Item_func_sys_guid::val_str(String *str) my_uuid2str(buf, const_cast(str->ptr()), 0); return str; } + + +bool Item_func_uuid_timestamp::fix_length_and_dec(THD *thd) +{ + Type_std_attributes::set( + Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH, + TIME_SECOND_PART_DIGITS, false), + DTCollation_numeric()); + set_maybe_null(); + return FALSE; +} + + +bool Item_func_uuid_timestamp::val_native(THD *thd, Native *to) +{ + Type_handler_uuid_new::Fbt_null uuid(args[0]); + if (uuid.is_null()) + return (null_value= true); + + const uchar *buf= (const uchar *) uuid.to_lex_cstring().str; + uint version= buf[6] >> 4; + + my_time_t seconds; + ulong microseconds; + + if (version == 7) + { + ulonglong unix_ts_ms= mi_uint6korr(buf); + seconds= unix_ts_ms / 1000; + microseconds= (unix_ts_ms % 1000) * 1000; + } + else if (version == 1) + { + ulonglong uuid_ts= ((ulonglong)(mi_uint2korr(buf + 6) & 0x0FFF) << 48) | + ((ulonglong) mi_uint2korr(buf + 4) << 32) | + (ulonglong) mi_uint4korr(buf); + + if (uuid_ts < UUID_TIME_OFFSET) + return (null_value= true); + + ulonglong unix_us= (uuid_ts - UUID_TIME_OFFSET) / 10; + seconds= unix_us / 1000000; + microseconds= unix_us % 1000000; + } + else + return (null_value= true); + + return null_value= Timestamp(Timeval(seconds, microseconds)). + to_native(to, TIME_SECOND_PART_DIGITS); +} diff --git a/plugin/type_uuid/item_uuidfunc.h b/plugin/type_uuid/item_uuidfunc.h index 5de03746a3ada..59c2d0a5ede7f 100644 --- a/plugin/type_uuid/item_uuidfunc.h +++ b/plugin/type_uuid/item_uuidfunc.h @@ -18,6 +18,7 @@ #include "item.h" +#include "item_timefunc.h" #include "sql_type_uuid_v1.h" #include "sql_type_uuid_v4.h" #include "sql_type_uuid_v7.h" @@ -115,4 +116,29 @@ class Item_func_uuid_v7: public Item_func_uuid_vx Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } }; + + +class Item_func_uuid_timestamp: public Item_timestampfunc +{ + bool check_arguments() const override + { + return args[0]->check_type_can_return_str(func_name_cstring()); + } +public: + Item_func_uuid_timestamp(THD *thd, Item *arg1) + : Item_timestampfunc(thd, arg1) {} + + LEX_CSTRING func_name_cstring() const override + { + static LEX_CSTRING name= {STRING_WITH_LEN("uuid_timestamp") }; + return name; + } + + bool fix_length_and_dec(THD *thd) override; + bool val_native(THD *thd, Native *to) override; + + Item *do_get_copy(THD *thd) const override + { return get_item_copy(thd, this); } +}; + #endif // ITEM_UUIDFUNC_INCLUDED diff --git a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result new file mode 100644 index 0000000000000..06e6df4983962 --- /dev/null +++ b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result @@ -0,0 +1,60 @@ +SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000'); +UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000') +2024-01-17 20:34:37.539000 +SELECT UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000'); +UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000') +2023-06-13 22:35:47.520000 +SELECT UUID_TIMESTAMP('1ee81f00-a8a8-11ee-8000-000000000000') IS NOT NULL AS has_timestamp; +has_timestamp +1 +SET @uuid1 = UUID(); +SELECT UUID_TIMESTAMP(@uuid1) IS NOT NULL AS has_timestamp; +has_timestamp +1 +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent; +timestamp_is_recent +1 +SET @uuid7 = UUID_V7(); +SELECT UUID_TIMESTAMP(@uuid7) IS NOT NULL AS has_timestamp; +has_timestamp +1 +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent; +timestamp_is_recent +1 +SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS no_timestamp_for_v4; +no_timestamp_for_v4 +1 +SELECT UUID_TIMESTAMP('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11') IS NULL AS no_timestamp_for_v4; +no_timestamp_for_v4 +1 +SELECT UUID_TIMESTAMP(NULL); +UUID_TIMESTAMP(NULL) +NULL +SELECT UUID_TIMESTAMP('not-a-valid-uuid'); +UUID_TIMESTAMP('not-a-valid-uuid') +NULL +Warnings: +Warning 1292 Incorrect uuid value: 'not-a-valid-uuid' +SELECT UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID)); +UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID)) +2024-01-17 20:34:37.539000 +CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID()) AS ts; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ts` timestamp(6) NULL DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +DROP TABLE t1; +CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID_V7()) AS ts; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ts` timestamp(6) NULL DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci +DROP TABLE t1; +SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000'); +UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000') +2024-01-17 20:34:37.539000 +SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; +before_unix_epoch +1 diff --git a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test new file mode 100644 index 0000000000000..cec785654fa28 --- /dev/null +++ b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test @@ -0,0 +1,40 @@ +# UUID_TIMESTAMP() function to extract timestamp from UUIDv1 and UUIDv7 + +SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000'); + +SELECT UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000'); + +SELECT UUID_TIMESTAMP('1ee81f00-a8a8-11ee-8000-000000000000') IS NOT NULL AS has_timestamp; + +SET @uuid1 = UUID(); +SELECT UUID_TIMESTAMP(@uuid1) IS NOT NULL AS has_timestamp; + +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent; + +SET @uuid7 = UUID_V7(); +SELECT UUID_TIMESTAMP(@uuid7) IS NOT NULL AS has_timestamp; + +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent; + +SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS no_timestamp_for_v4; + +SELECT UUID_TIMESTAMP('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11') IS NULL AS no_timestamp_for_v4; + +SELECT UUID_TIMESTAMP(NULL); + +SELECT UUID_TIMESTAMP('not-a-valid-uuid'); + +SELECT UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID)); + +CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID()) AS ts; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID_V7()) AS ts; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000'); + +SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; + diff --git a/plugin/type_uuid/plugin.cc b/plugin/type_uuid/plugin.cc index fa15d847d2356..53b598343909d 100644 --- a/plugin/type_uuid/plugin.cc +++ b/plugin/type_uuid/plugin.cc @@ -180,16 +180,33 @@ class Create_func_uuid_v7 : public Create_func_arg0 virtual ~Create_func_uuid_v7() {} }; +class Create_func_uuid_timestamp : public Create_func_arg1 +{ +public: + Item *create_1_arg(THD *thd, Item *arg1) override + { + DBUG_ENTER("Create_func_uuid_timestamp::create_1_arg"); + DBUG_RETURN(new (thd->mem_root) Item_func_uuid_timestamp(thd, arg1)); + } + static Create_func_uuid_timestamp s_singleton; + +protected: + Create_func_uuid_timestamp() {} + virtual ~Create_func_uuid_timestamp() {} +}; + Create_func_uuid Create_func_uuid::s_singleton; Create_func_sys_guid Create_func_sys_guid::s_singleton; Create_func_uuid_v4 Create_func_uuid_v4::s_singleton; Create_func_uuid_v7 Create_func_uuid_v7::s_singleton; +Create_func_uuid_timestamp Create_func_uuid_timestamp::s_singleton; static Plugin_function plugin_descriptor_function_uuid(&Create_func_uuid::s_singleton), plugin_descriptor_function_sys_guid(&Create_func_sys_guid::s_singleton), plugin_descriptor_function_uuid_v4(&Create_func_uuid_v4::s_singleton), - plugin_descriptor_function_uuid_v7(&Create_func_uuid_v7::s_singleton); + plugin_descriptor_function_uuid_v7(&Create_func_uuid_v7::s_singleton), + plugin_descriptor_function_uuid_timestamp(&Create_func_uuid_timestamp::s_singleton); static constexpr Name type_name={STRING_WITH_LEN("uuid")}; @@ -301,5 +318,20 @@ maria_declare_plugin(type_uuid) NULL, // System variables "1.0.1", // String version representation MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/ +}, +{ + MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h) + &plugin_descriptor_function_uuid_timestamp, // pointer to type-specific plugin descriptor + "uuid_timestamp", // plugin name + "Varun Deep Saini", // plugin author + "Function UUID_TIMESTAMP()", // the plugin description + PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h) + 0, // Pointer to plugin initialization function + 0, // Pointer to plugin deinitialization function + 0x0100, // Numeric version 0xAABB means AA.BB version + NULL, // Status variables + NULL, // System variables + "1.0", // String version representation + MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/ } maria_declare_plugin_end; From 557584c18f500ccda45daf73c1b976bd88476b37 Mon Sep 17 00:00:00 2001 From: Varun Deep Saini Date: Thu, 25 Dec 2025 21:16:39 +0530 Subject: [PATCH 2/8] refactoring --- include/my_sys.h | 2 +- mysys/my_uuid.c | 58 ++++++++++++++++++ plugin/type_uuid/item_uuidfunc.cc | 33 ++-------- plugin/type_uuid/item_uuidfunc.h | 5 +- .../type_uuid/func_uuid_timestamp.result | 60 +++++++++---------- .../type_uuid/func_uuid_timestamp.test | 49 +++++++++------ 6 files changed, 123 insertions(+), 84 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index 3fd85988a7619..3816a0d2d9b94 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -1107,7 +1107,7 @@ int my_msync(int, void *, size_t, int); void my_uuid_init(ulong seed1, ulong seed2); void my_uuid(uchar *guid); void my_uuid_end(void); - +my_bool my_uuid_extract_ts(const uchar *uuid, my_time_t *seconds, ulong *usec); static inline void my_uuid2str(const uchar *guid, char *s, int with_separators) { int i; diff --git a/mysys/my_uuid.c b/mysys/my_uuid.c index 7925f80191b77..ac434dce62324 100644 --- a/mysys/my_uuid.c +++ b/mysys/my_uuid.c @@ -224,3 +224,61 @@ void my_uuid_end() mysql_mutex_destroy(&LOCK_uuid_generator); } } + + +/** + Extract Unix timestamp from a UUID (version 1 or 7) + + @param[in] uuid UUID bytes (16 bytes, big-endian) + @param[out] seconds Unix timestamp seconds + @param[out] usec Microseconds part + + @return + @retval 0 Success + @retval 1 UUID version doesn't contain timestamp or timestamp invalid + + UUIDv1 format (RFC 4122): + Bytes 0-3: time_low (32 bits) + Bytes 4-5: time_mid (16 bits) + Bytes 6-7: version (4 bits) + time_hi (12 bits) + Timestamp is 100-nanosecond intervals since 1582-10-15 + + UUIDv7 format (RFC 9562): + Bytes 0-5: Unix timestamp in milliseconds (48 bits, big-endian) + Bytes 6-7: version (4 bits) + sub-millisecond precision (12 bits) +*/ + +my_bool my_uuid_extract_ts(const uchar *uuid, my_time_t *seconds, ulong *usec) +{ + uint version= uuid[6] >> 4; + ulonglong ts; + + if (version == 7) + { + /* UUIDv7: bytes 0-5 are Unix timestamp in milliseconds (big-endian) */ + ts= mi_uint6korr(uuid); + *seconds= ts / 1000; + *usec= (ts % 1000) * 1000; + return 0; + } + + if (version == 1) + { + /* UUIDv1: reconstruct 60-bit timestamp from time_low, time_mid, time_hi */ + ts= ((ulonglong)(mi_uint2korr(uuid + 6) & 0x0FFF) << 48) | + ((ulonglong) mi_uint2korr(uuid + 4) << 32) | + (ulonglong) mi_uint4korr(uuid); + + /* Timestamp before Unix epoch (1970-01-01) */ + if (ts < UUID_TIME_OFFSET) + return 1; + + ts= (ts - UUID_TIME_OFFSET) / 10; /* Convert to microseconds */ + *seconds= ts / 1000000; + *usec= ts % 1000000; + return 0; + } + + /* Other versions (e.g., v4) don't contain timestamps */ + return 1; +} diff --git a/plugin/type_uuid/item_uuidfunc.cc b/plugin/type_uuid/item_uuidfunc.cc index 1623f4d9993c6..8c250d62f976f 100644 --- a/plugin/type_uuid/item_uuidfunc.cc +++ b/plugin/type_uuid/item_uuidfunc.cc @@ -16,10 +16,6 @@ #define MYSQL_SERVER #include "mariadb.h" #include "item_uuidfunc.h" -#include - -// 100-nanosecond intervals between 1582-10-15 and 1970-01-01 -#define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * 1000 * 1000 * 10) String *Item_func_sys_guid::val_str(String *str) { @@ -52,34 +48,13 @@ bool Item_func_uuid_timestamp::val_native(THD *thd, Native *to) if (uuid.is_null()) return (null_value= true); - const uchar *buf= (const uchar *) uuid.to_lex_cstring().str; - uint version= buf[6] >> 4; - my_time_t seconds; - ulong microseconds; - - if (version == 7) - { - ulonglong unix_ts_ms= mi_uint6korr(buf); - seconds= unix_ts_ms / 1000; - microseconds= (unix_ts_ms % 1000) * 1000; - } - else if (version == 1) - { - ulonglong uuid_ts= ((ulonglong)(mi_uint2korr(buf + 6) & 0x0FFF) << 48) | - ((ulonglong) mi_uint2korr(buf + 4) << 32) | - (ulonglong) mi_uint4korr(buf); - - if (uuid_ts < UUID_TIME_OFFSET) - return (null_value= true); + ulong usec; + const uchar *buf= (const uchar *) uuid.to_lex_cstring().str; - ulonglong unix_us= (uuid_ts - UUID_TIME_OFFSET) / 10; - seconds= unix_us / 1000000; - microseconds= unix_us % 1000000; - } - else + if (my_uuid_extract_ts(buf, &seconds, &usec)) return (null_value= true); - return null_value= Timestamp(Timeval(seconds, microseconds)). + return null_value= Timestamp(Timeval(seconds, usec)). to_native(to, TIME_SECOND_PART_DIGITS); } diff --git a/plugin/type_uuid/item_uuidfunc.h b/plugin/type_uuid/item_uuidfunc.h index 59c2d0a5ede7f..98db0cccabf4a 100644 --- a/plugin/type_uuid/item_uuidfunc.h +++ b/plugin/type_uuid/item_uuidfunc.h @@ -129,10 +129,7 @@ class Item_func_uuid_timestamp: public Item_timestampfunc : Item_timestampfunc(thd, arg1) {} LEX_CSTRING func_name_cstring() const override - { - static LEX_CSTRING name= {STRING_WITH_LEN("uuid_timestamp") }; - return name; - } + { return {STRING_WITH_LEN("uuid_timestamp")}; } bool fix_length_and_dec(THD *thd) override; bool val_native(THD *thd, Native *to) override; diff --git a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result index 06e6df4983962..12f7f9c82e2dc 100644 --- a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result +++ b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result @@ -1,35 +1,34 @@ +SET time_zone='+00:00'; SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000'); UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000') -2024-01-17 20:34:37.539000 +2024-01-17 15:04:37.539000 SELECT UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000'); UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000') -2023-06-13 22:35:47.520000 +2023-06-13 17:05:47.520000 SELECT UUID_TIMESTAMP('1ee81f00-a8a8-11ee-8000-000000000000') IS NOT NULL AS has_timestamp; has_timestamp 1 -SET @uuid1 = UUID(); -SELECT UUID_TIMESTAMP(@uuid1) IS NOT NULL AS has_timestamp; -has_timestamp -1 -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent; -timestamp_is_recent +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW()) AS v1_diff_seconds; +v1_diff_seconds +0 +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW()) AS v7_diff_seconds; +v7_diff_seconds +0 +SELECT DATE(UUID_TIMESTAMP(UUID())) = CURDATE() AS v1_date_matches; +v1_date_matches 1 -SET @uuid7 = UUID_V7(); -SELECT UUID_TIMESTAMP(@uuid7) IS NOT NULL AS has_timestamp; -has_timestamp +SELECT DATE(UUID_TIMESTAMP(UUID_V7())) = CURDATE() AS v7_date_matches; +v7_date_matches 1 -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent; -timestamp_is_recent +SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS v4_returns_null; +v4_returns_null 1 -SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS no_timestamp_for_v4; -no_timestamp_for_v4 +SELECT UUID_TIMESTAMP('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11') IS NULL AS v4_string_returns_null; +v4_string_returns_null 1 -SELECT UUID_TIMESTAMP('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11') IS NULL AS no_timestamp_for_v4; -no_timestamp_for_v4 +SELECT UUID_TIMESTAMP(NULL) IS NULL AS null_input; +null_input 1 -SELECT UUID_TIMESTAMP(NULL); -UUID_TIMESTAMP(NULL) -NULL SELECT UUID_TIMESTAMP('not-a-valid-uuid'); UUID_TIMESTAMP('not-a-valid-uuid') NULL @@ -37,7 +36,7 @@ Warnings: Warning 1292 Incorrect uuid value: 'not-a-valid-uuid' SELECT UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID)); UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID)) -2024-01-17 20:34:37.539000 +2024-01-17 15:04:37.539000 CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID()) AS ts; SHOW CREATE TABLE t1; Table Create Table @@ -45,16 +44,15 @@ t1 CREATE TABLE `t1` ( `ts` timestamp(6) NULL DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci DROP TABLE t1; -CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID_V7()) AS ts; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `ts` timestamp(6) NULL DEFAULT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci -DROP TABLE t1; -SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000'); -UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000') -2024-01-17 20:34:37.539000 SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; before_unix_epoch 1 +SELECT UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000'); +UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000') +0000-00-00 00:00:00.000000 +SET @u1= UUID(); +SET @u7= UUID_V7(); +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(@u1), UUID_TIMESTAMP(@u7)) AS diff_seconds; +diff_seconds +0 +SET time_zone=DEFAULT; diff --git a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test index cec785654fa28..28369c1ae69b4 100644 --- a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test +++ b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test @@ -1,40 +1,51 @@ -# UUID_TIMESTAMP() function to extract timestamp from UUIDv1 and UUIDv7 +# MDEV-33710: UUID_TIMESTAMP() extracts timestamp from UUIDv1 and UUIDv7 +# Use UTC for consistent results across timezones +SET time_zone='+00:00'; + +# Test UUIDv7 with known values +# 0x018d17f3e9a3 = 1705522477475 ms SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000'); +# 0x0188b5b88000 = 1686687547520 ms SELECT UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000'); +# Test UUIDv1 with known value SELECT UUID_TIMESTAMP('1ee81f00-a8a8-11ee-8000-000000000000') IS NOT NULL AS has_timestamp; -SET @uuid1 = UUID(); -SELECT UUID_TIMESTAMP(@uuid1) IS NOT NULL AS has_timestamp; - -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent; - -SET @uuid7 = UUID_V7(); -SELECT UUID_TIMESTAMP(@uuid7) IS NOT NULL AS has_timestamp; - -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent; - -SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS no_timestamp_for_v4; +# Test dynamic UUID generation - timestamp should match NOW() +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW()) AS v1_diff_seconds; +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW()) AS v7_diff_seconds; -SELECT UUID_TIMESTAMP('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11') IS NULL AS no_timestamp_for_v4; +# Verify UUID date matches current date +SELECT DATE(UUID_TIMESTAMP(UUID())) = CURDATE() AS v1_date_matches; +SELECT DATE(UUID_TIMESTAMP(UUID_V7())) = CURDATE() AS v7_date_matches; -SELECT UUID_TIMESTAMP(NULL); +# Test UUIDv4 returns NULL (random UUID, no timestamp) +SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS v4_returns_null; +SELECT UUID_TIMESTAMP('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11') IS NULL AS v4_string_returns_null; +# Test NULL and invalid input +SELECT UUID_TIMESTAMP(NULL) IS NULL AS null_input; SELECT UUID_TIMESTAMP('not-a-valid-uuid'); +# Test with native UUID type SELECT UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID)); +# Test return type is TIMESTAMP(6) CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID()) AS ts; SHOW CREATE TABLE t1; DROP TABLE t1; -CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID_V7()) AS ts; -SHOW CREATE TABLE t1; -DROP TABLE t1; +# Edge case: UUIDv1 before Unix epoch returns NULL +SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; -SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000'); +# Edge case: UUIDv7 at Unix epoch (timestamp = 0) +SELECT UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000'); -SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; +# Test UUIDv1 and UUIDv7 generated together have same second +SET @u1= UUID(); +SET @u7= UUID_V7(); +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(@u1), UUID_TIMESTAMP(@u7)) AS diff_seconds; +SET time_zone=DEFAULT; From 676675f9fd13bcae5d1972edb19dd1c1041a14a5 Mon Sep 17 00:00:00 2001 From: Varun Deep Saini Date: Fri, 26 Dec 2025 01:57:14 +0530 Subject: [PATCH 3/8] refactoring --- include/my_sys.h | 2 +- mysys/my_uuid.c | 39 +++++++++++-------- plugin/type_uuid/item_uuidfunc.cc | 20 +++++----- plugin/type_uuid/item_uuidfunc.h | 1 + .../type_uuid/func_uuid_timestamp.result | 22 ++++------- .../type_uuid/func_uuid_timestamp.test | 17 ++++---- 6 files changed, 50 insertions(+), 51 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index 3816a0d2d9b94..b7798c9f64ce3 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -1107,7 +1107,7 @@ int my_msync(int, void *, size_t, int); void my_uuid_init(ulong seed1, ulong seed2); void my_uuid(uchar *guid); void my_uuid_end(void); -my_bool my_uuid_extract_ts(const uchar *uuid, my_time_t *seconds, ulong *usec); +int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec); static inline void my_uuid2str(const uchar *guid, char *s, int with_separators) { int i; diff --git a/mysys/my_uuid.c b/mysys/my_uuid.c index ac434dce62324..f9e1bf93d8181 100644 --- a/mysys/my_uuid.c +++ b/mysys/my_uuid.c @@ -227,30 +227,29 @@ void my_uuid_end() /** - Extract Unix timestamp from a UUID (version 1 or 7) + Extract Unix timestamp from a UUIDv1 or UUIDv7 @param[in] uuid UUID bytes (16 bytes, big-endian) @param[out] seconds Unix timestamp seconds @param[out] usec Microseconds part @return - @retval 0 Success - @retval 1 UUID version doesn't contain timestamp or timestamp invalid + @retval 1 Success + @retval 0 UUID version doesn't contain timestamp or timestamp invalid - UUIDv1 format (RFC 4122): - Bytes 0-3: time_low (32 bits) - Bytes 4-5: time_mid (16 bits) - Bytes 6-7: version (4 bits) + time_hi (12 bits) + UUIDv1 format (RFC 4122, big-endian): + Bytes 0-3: time_low (32 bits, low part of timestamp) + Bytes 4-5: time_mid (16 bits, middle part of timestamp) + Bytes 6-7: version (4 bits) + time_hi (12 bits, high part of timestamp) Timestamp is 100-nanosecond intervals since 1582-10-15 - UUIDv7 format (RFC 9562): - Bytes 0-5: Unix timestamp in milliseconds (48 bits, big-endian) + UUIDv7 format (RFC 9562, big-endian): + Bytes 0-5: Unix timestamp in milliseconds (48 bits) Bytes 6-7: version (4 bits) + sub-millisecond precision (12 bits) */ - -my_bool my_uuid_extract_ts(const uchar *uuid, my_time_t *seconds, ulong *usec) +int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) { - uint version= uuid[6] >> 4; + uint version= (uchar) uuid[6] >> 4; ulonglong ts; if (version == 7) @@ -259,26 +258,32 @@ my_bool my_uuid_extract_ts(const uchar *uuid, my_time_t *seconds, ulong *usec) ts= mi_uint6korr(uuid); *seconds= ts / 1000; *usec= (ts % 1000) * 1000; - return 0; + return 1; } if (version == 1) { - /* UUIDv1: reconstruct 60-bit timestamp from time_low, time_mid, time_hi */ + /* + UUIDv1: reconstruct 60-bit timestamp from three fields: + - time_low (bytes 0-3): bits 0-31 of timestamp + - time_mid (bytes 4-5): bits 32-47 of timestamp + - time_hi (bytes 6-7): bits 48-59 of timestamp (masked, 4 bits are version) + Formula: (time_hi << 48) | (time_mid << 32) | time_low + */ ts= ((ulonglong)(mi_uint2korr(uuid + 6) & 0x0FFF) << 48) | ((ulonglong) mi_uint2korr(uuid + 4) << 32) | (ulonglong) mi_uint4korr(uuid); /* Timestamp before Unix epoch (1970-01-01) */ if (ts < UUID_TIME_OFFSET) - return 1; + return 0; ts= (ts - UUID_TIME_OFFSET) / 10; /* Convert to microseconds */ *seconds= ts / 1000000; *usec= ts % 1000000; - return 0; + return 1; } /* Other versions (e.g., v4) don't contain timestamps */ - return 1; + return 0; } diff --git a/plugin/type_uuid/item_uuidfunc.cc b/plugin/type_uuid/item_uuidfunc.cc index 8c250d62f976f..f55c1ac26de9d 100644 --- a/plugin/type_uuid/item_uuidfunc.cc +++ b/plugin/type_uuid/item_uuidfunc.cc @@ -38,23 +38,23 @@ bool Item_func_uuid_timestamp::fix_length_and_dec(THD *thd) TIME_SECOND_PART_DIGITS, false), DTCollation_numeric()); set_maybe_null(); - return FALSE; + return false; } -bool Item_func_uuid_timestamp::val_native(THD *thd, Native *to) +bool Item_func_uuid_timestamp::get_timestamp(my_time_t *sec, ulong *usec) { Type_handler_uuid_new::Fbt_null uuid(args[0]); if (uuid.is_null()) - return (null_value= true); + return true; + return !my_uuid_extract_ts(uuid.to_lex_cstring().str, sec, usec); +} + +bool Item_func_uuid_timestamp::val_native(THD *thd, Native *to) +{ my_time_t seconds; ulong usec; - const uchar *buf= (const uchar *) uuid.to_lex_cstring().str; - - if (my_uuid_extract_ts(buf, &seconds, &usec)) - return (null_value= true); - - return null_value= Timestamp(Timeval(seconds, usec)). - to_native(to, TIME_SECOND_PART_DIGITS); + return (null_value= get_timestamp(&seconds, &usec)) || + (null_value= Timestamp(seconds, usec).to_native(to, TIME_SECOND_PART_DIGITS)); } diff --git a/plugin/type_uuid/item_uuidfunc.h b/plugin/type_uuid/item_uuidfunc.h index 98db0cccabf4a..a21587ad57ce0 100644 --- a/plugin/type_uuid/item_uuidfunc.h +++ b/plugin/type_uuid/item_uuidfunc.h @@ -124,6 +124,7 @@ class Item_func_uuid_timestamp: public Item_timestampfunc { return args[0]->check_type_can_return_str(func_name_cstring()); } + bool get_timestamp(my_time_t *sec, ulong *usec); public: Item_func_uuid_timestamp(THD *thd, Item *arg1) : Item_timestampfunc(thd, arg1) {} diff --git a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result index 12f7f9c82e2dc..c8edb28436335 100644 --- a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result +++ b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result @@ -8,17 +8,11 @@ UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000') SELECT UUID_TIMESTAMP('1ee81f00-a8a8-11ee-8000-000000000000') IS NOT NULL AS has_timestamp; has_timestamp 1 -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW()) AS v1_diff_seconds; -v1_diff_seconds -0 -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW()) AS v7_diff_seconds; -v7_diff_seconds -0 -SELECT DATE(UUID_TIMESTAMP(UUID())) = CURDATE() AS v1_date_matches; -v1_date_matches -1 -SELECT DATE(UUID_TIMESTAMP(UUID_V7())) = CURDATE() AS v7_date_matches; -v7_date_matches +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW(6)) < 120 AS v1_time_ok; +v1_time_ok +1 +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW(6)) < 120 AS v7_time_ok; +v7_time_ok 1 SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS v4_returns_null; v4_returns_null @@ -52,7 +46,7 @@ UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000') 0000-00-00 00:00:00.000000 SET @u1= UUID(); SET @u7= UUID_V7(); -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(@u1), UUID_TIMESTAMP(@u7)) AS diff_seconds; -diff_seconds -0 +SELECT ABS(TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(@u1), UUID_TIMESTAMP(@u7))) < 120 AS same_timeframe; +same_timeframe +1 SET time_zone=DEFAULT; diff --git a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test index 28369c1ae69b4..b8b5c40d0b136 100644 --- a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test +++ b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test @@ -13,13 +13,12 @@ SELECT UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000'); # Test UUIDv1 with known value SELECT UUID_TIMESTAMP('1ee81f00-a8a8-11ee-8000-000000000000') IS NOT NULL AS has_timestamp; -# Test dynamic UUID generation - timestamp should match NOW() -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW()) AS v1_diff_seconds; -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW()) AS v7_diff_seconds; - -# Verify UUID date matches current date -SELECT DATE(UUID_TIMESTAMP(UUID())) = CURDATE() AS v1_date_matches; -SELECT DATE(UUID_TIMESTAMP(UUID_V7())) = CURDATE() AS v7_date_matches; +# Test dynamic UUID generation +# UUID() and UUID_V7() use my_interval_timer() (real system time), not session +# timestamp, so we cannot use SET timestamp to fix the time. We use a tolerance +# of 120 seconds (same as update_time.test) to handle slow/loaded machines. +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW(6)) < 120 AS v1_time_ok; +SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW(6)) < 120 AS v7_time_ok; # Test UUIDv4 returns NULL (random UUID, no timestamp) SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS v4_returns_null; @@ -43,9 +42,9 @@ SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_ # Edge case: UUIDv7 at Unix epoch (timestamp = 0) SELECT UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000'); -# Test UUIDv1 and UUIDv7 generated together have same second +# Test UUIDv1 and UUIDv7 generated together should be within 2 minutes SET @u1= UUID(); SET @u7= UUID_V7(); -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(@u1), UUID_TIMESTAMP(@u7)) AS diff_seconds; +SELECT ABS(TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(@u1), UUID_TIMESTAMP(@u7))) < 120 AS same_timeframe; SET time_zone=DEFAULT; From 75c06e72580613e9064bb7ed5d5b2e2736ed1f01 Mon Sep 17 00:00:00 2001 From: Varun Deep Saini Date: Fri, 26 Dec 2025 22:37:01 +0530 Subject: [PATCH 4/8] fixed test --- .../type_uuid/func_uuid_timestamp.result | 73 ++++++++++++------ .../type_uuid/func_uuid_timestamp.test | 75 +++++++++++-------- 2 files changed, 92 insertions(+), 56 deletions(-) diff --git a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result index c8edb28436335..3e80e8098d879 100644 --- a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result +++ b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result @@ -1,25 +1,40 @@ SET time_zone='+00:00'; -SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000'); -UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000') -2024-01-17 15:04:37.539000 -SELECT UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000'); -UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000') -2023-06-13 17:05:47.520000 -SELECT UUID_TIMESTAMP('1ee81f00-a8a8-11ee-8000-000000000000') IS NOT NULL AS has_timestamp; -has_timestamp -1 -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW(6)) < 120 AS v1_time_ok; -v1_time_ok -1 -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW(6)) < 120 AS v7_time_ok; -v7_time_ok -1 +# +# UUIDv1 with known timestamps +# +SELECT UUID_TIMESTAMP('63b00000-bfde-11d3-80fe-9f59977b836e'); +UUID_TIMESTAMP('63b00000-bfde-11d3-80fe-9f59977b836e') +2000-01-01 00:00:00.000000 +SELECT UUID_TIMESTAMP('16488880-2b13-11ef-808b-603c7ba5e656'); +UUID_TIMESTAMP('16488880-2b13-11ef-808b-603c7ba5e656') +2024-06-15 12:30:45.000000 +SELECT UUID_TIMESTAMP('d02b2980-e6a4-11f0-8072-39f36896a88f'); +UUID_TIMESTAMP('d02b2980-e6a4-11f0-8072-39f36896a88f') +2025-12-31 23:59:59.000000 +# +# UUIDv7 with known timestamps (ms precision) +# +SELECT UUID_TIMESTAMP('00dc6acf-ac00-737d-9f12-3229a718bf21'); +UUID_TIMESTAMP('00dc6acf-ac00-737d-9f12-3229a718bf21') +2000-01-01 00:00:00.000000 +SELECT UUID_TIMESTAMP('01901be0-f183-7e6c-9601-62a5e4f6e7b8'); +UUID_TIMESTAMP('01901be0-f183-7e6c-9601-62a5e4f6e7b8') +2024-06-15 12:30:45.123000 +SELECT UUID_TIMESTAMP('019b76da-a7ff-7ece-a98f-44624a8d3b0f'); +UUID_TIMESTAMP('019b76da-a7ff-7ece-a98f-44624a8d3b0f') +2025-12-31 23:59:59.999000 +# +# UUIDv4 returns NULL (no timestamp) +# SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS v4_returns_null; v4_returns_null 1 SELECT UUID_TIMESTAMP('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11') IS NULL AS v4_string_returns_null; v4_string_returns_null 1 +# +# NULL and invalid input +# SELECT UUID_TIMESTAMP(NULL) IS NULL AS null_input; null_input 1 @@ -28,25 +43,35 @@ UUID_TIMESTAMP('not-a-valid-uuid') NULL Warnings: Warning 1292 Incorrect uuid value: 'not-a-valid-uuid' -SELECT UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID)); -UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID)) -2024-01-17 15:04:37.539000 -CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID()) AS ts; +# +# Native UUID type +# +SELECT UUID_TIMESTAMP(CAST('01901be0-f183-7e6c-9601-62a5e4f6e7b8' AS UUID)); +UUID_TIMESTAMP(CAST('01901be0-f183-7e6c-9601-62a5e4f6e7b8' AS UUID)) +2024-06-15 12:30:45.123000 +# +# Return type is TIMESTAMP(6) +# +CREATE TABLE t1 AS SELECT UUID_TIMESTAMP('01901be0-f183-7e6c-9601-62a5e4f6e7b8') AS ts; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( `ts` timestamp(6) NULL DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci DROP TABLE t1; +# +# Edge cases +# SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; before_unix_epoch 1 SELECT UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000'); UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000') 0000-00-00 00:00:00.000000 -SET @u1= UUID(); -SET @u7= UUID_V7(); -SELECT ABS(TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(@u1), UUID_TIMESTAMP(@u7))) < 120 AS same_timeframe; -same_timeframe -1 +SELECT UUID_TIMESTAMP('ffffffff-ffff-7fff-8000-000000000000'); +UUID_TIMESTAMP('ffffffff-ffff-7fff-8000-000000000000') +2042-12-13 16:54:30.655000 +SELECT UUID_TIMESTAMP('ffffffff-ffff-1fff-8000-000000000000'); +UUID_TIMESTAMP('ffffffff-ffff-1fff-8000-000000000000') +2105-11-25 16:30:52.684697 SET time_zone=DEFAULT; diff --git a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test index b8b5c40d0b136..4aff76efaacac 100644 --- a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test +++ b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test @@ -1,50 +1,61 @@ # MDEV-33710: UUID_TIMESTAMP() extracts timestamp from UUIDv1 and UUIDv7 -# Use UTC for consistent results across timezones SET time_zone='+00:00'; -# Test UUIDv7 with known values -# 0x018d17f3e9a3 = 1705522477475 ms -SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000'); - -# 0x0188b5b88000 = 1686687547520 ms -SELECT UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000'); - -# Test UUIDv1 with known value -SELECT UUID_TIMESTAMP('1ee81f00-a8a8-11ee-8000-000000000000') IS NOT NULL AS has_timestamp; - -# Test dynamic UUID generation -# UUID() and UUID_V7() use my_interval_timer() (real system time), not session -# timestamp, so we cannot use SET timestamp to fix the time. We use a tolerance -# of 120 seconds (same as update_time.test) to handle slow/loaded machines. -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW(6)) < 120 AS v1_time_ok; -SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW(6)) < 120 AS v7_time_ok; - -# Test UUIDv4 returns NULL (random UUID, no timestamp) +--echo # +--echo # UUIDv1 with known timestamps +--echo # +# 2000-01-01 00:00:00.000000 +SELECT UUID_TIMESTAMP('63b00000-bfde-11d3-80fe-9f59977b836e'); +# 2024-06-15 12:30:45.000000 +SELECT UUID_TIMESTAMP('16488880-2b13-11ef-808b-603c7ba5e656'); +# 2025-12-31 23:59:59.000000 +SELECT UUID_TIMESTAMP('d02b2980-e6a4-11f0-8072-39f36896a88f'); + +--echo # +--echo # UUIDv7 with known timestamps (ms precision) +--echo # +# 2000-01-01 00:00:00.000000 +SELECT UUID_TIMESTAMP('00dc6acf-ac00-737d-9f12-3229a718bf21'); +# 2024-06-15 12:30:45.123000 +SELECT UUID_TIMESTAMP('01901be0-f183-7e6c-9601-62a5e4f6e7b8'); +# 2025-12-31 23:59:59.999000 +SELECT UUID_TIMESTAMP('019b76da-a7ff-7ece-a98f-44624a8d3b0f'); + +--echo # +--echo # UUIDv4 returns NULL (no timestamp) +--echo # SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS v4_returns_null; SELECT UUID_TIMESTAMP('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11') IS NULL AS v4_string_returns_null; -# Test NULL and invalid input +--echo # +--echo # NULL and invalid input +--echo # SELECT UUID_TIMESTAMP(NULL) IS NULL AS null_input; SELECT UUID_TIMESTAMP('not-a-valid-uuid'); -# Test with native UUID type -SELECT UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID)); +--echo # +--echo # Native UUID type +--echo # +SELECT UUID_TIMESTAMP(CAST('01901be0-f183-7e6c-9601-62a5e4f6e7b8' AS UUID)); -# Test return type is TIMESTAMP(6) -CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID()) AS ts; +--echo # +--echo # Return type is TIMESTAMP(6) +--echo # +CREATE TABLE t1 AS SELECT UUID_TIMESTAMP('01901be0-f183-7e6c-9601-62a5e4f6e7b8') AS ts; SHOW CREATE TABLE t1; DROP TABLE t1; -# Edge case: UUIDv1 before Unix epoch returns NULL +--echo # +--echo # Edge cases +--echo # +# UUIDv1 before Unix epoch SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; - -# Edge case: UUIDv7 at Unix epoch (timestamp = 0) +# UUIDv7 at Unix epoch (ts=0) SELECT UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000'); - -# Test UUIDv1 and UUIDv7 generated together should be within 2 minutes -SET @u1= UUID(); -SET @u7= UUID_V7(); -SELECT ABS(TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(@u1), UUID_TIMESTAMP(@u7))) < 120 AS same_timeframe; +# UUIDv7 max 48-bit timestamp +SELECT UUID_TIMESTAMP('ffffffff-ffff-7fff-8000-000000000000'); +# UUIDv1 max timestamp +SELECT UUID_TIMESTAMP('ffffffff-ffff-1fff-8000-000000000000'); SET time_zone=DEFAULT; From 844454769a1dc9f1e7ee734f7a24e1fbfaac89c7 Mon Sep 17 00:00:00 2001 From: Varun Deep Saini Date: Sun, 28 Dec 2025 10:36:16 +0530 Subject: [PATCH 5/8] refactored if to switch --- mysys/my_uuid.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mysys/my_uuid.c b/mysys/my_uuid.c index f9e1bf93d8181..d45ed3ab450cb 100644 --- a/mysys/my_uuid.c +++ b/mysys/my_uuid.c @@ -252,17 +252,16 @@ int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) uint version= (uchar) uuid[6] >> 4; ulonglong ts; - if (version == 7) + switch (version) { + case 7: /* UUIDv7: bytes 0-5 are Unix timestamp in milliseconds (big-endian) */ ts= mi_uint6korr(uuid); *seconds= ts / 1000; *usec= (ts % 1000) * 1000; return 1; - } - if (version == 1) - { + case 1: /* UUIDv1: reconstruct 60-bit timestamp from three fields: - time_low (bytes 0-3): bits 0-31 of timestamp @@ -282,8 +281,9 @@ int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) *seconds= ts / 1000000; *usec= ts % 1000000; return 1; - } - /* Other versions (e.g., v4) don't contain timestamps */ - return 0; + default: + /* Other versions (e.g., v4) don't contain timestamps */ + return 0; + } } From 7515cf8a11b216445cbc0b702ca9f963fcc2d784 Mon Sep 17 00:00:00 2001 From: Varun Deep Saini Date: Sun, 28 Dec 2025 21:51:32 +0530 Subject: [PATCH 6/8] changed return type to bool --- include/my_sys.h | 6 +++++- mysys/my_uuid.c | 15 ++++++++------- plugin/type_uuid/item_uuidfunc.cc | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index b7798c9f64ce3..836d3b7ec3225 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -17,6 +17,10 @@ #ifndef _my_sys_h #define _my_sys_h +#ifndef __cplusplus +#include +#endif + #include #include @@ -1107,7 +1111,7 @@ int my_msync(int, void *, size_t, int); void my_uuid_init(ulong seed1, ulong seed2); void my_uuid(uchar *guid); void my_uuid_end(void); -int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec); +bool my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec); static inline void my_uuid2str(const uchar *guid, char *s, int with_separators) { int i; diff --git a/mysys/my_uuid.c b/mysys/my_uuid.c index d45ed3ab450cb..138bd3184eff4 100644 --- a/mysys/my_uuid.c +++ b/mysys/my_uuid.c @@ -39,6 +39,7 @@ identifier. */ +#include #include "mysys_priv.h" #include #include @@ -234,8 +235,8 @@ void my_uuid_end() @param[out] usec Microseconds part @return - @retval 1 Success - @retval 0 UUID version doesn't contain timestamp or timestamp invalid + @retval false Success + @retval true UUID version doesn't contain timestamp or timestamp invalid UUIDv1 format (RFC 4122, big-endian): Bytes 0-3: time_low (32 bits, low part of timestamp) @@ -247,7 +248,7 @@ void my_uuid_end() Bytes 0-5: Unix timestamp in milliseconds (48 bits) Bytes 6-7: version (4 bits) + sub-millisecond precision (12 bits) */ -int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) +bool my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) { uint version= (uchar) uuid[6] >> 4; ulonglong ts; @@ -259,7 +260,7 @@ int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) ts= mi_uint6korr(uuid); *seconds= ts / 1000; *usec= (ts % 1000) * 1000; - return 1; + return false; case 1: /* @@ -275,15 +276,15 @@ int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) /* Timestamp before Unix epoch (1970-01-01) */ if (ts < UUID_TIME_OFFSET) - return 0; + return true; ts= (ts - UUID_TIME_OFFSET) / 10; /* Convert to microseconds */ *seconds= ts / 1000000; *usec= ts % 1000000; - return 1; + return false; default: /* Other versions (e.g., v4) don't contain timestamps */ - return 0; + return true; } } diff --git a/plugin/type_uuid/item_uuidfunc.cc b/plugin/type_uuid/item_uuidfunc.cc index f55c1ac26de9d..efbc43f857423 100644 --- a/plugin/type_uuid/item_uuidfunc.cc +++ b/plugin/type_uuid/item_uuidfunc.cc @@ -47,7 +47,7 @@ bool Item_func_uuid_timestamp::get_timestamp(my_time_t *sec, ulong *usec) Type_handler_uuid_new::Fbt_null uuid(args[0]); if (uuid.is_null()) return true; - return !my_uuid_extract_ts(uuid.to_lex_cstring().str, sec, usec); + return my_uuid_extract_ts(uuid.to_lex_cstring().str, sec, usec); } From d5dd95d21a066e820f61732c6f3a9a644e0ca9c6 Mon Sep 17 00:00:00 2001 From: Varun Deep Saini Date: Wed, 31 Dec 2025 10:00:35 +0530 Subject: [PATCH 7/8] refactoring Signed-off-by: Varun Deep Saini --- include/my_sys.h | 6 +- mysys/my_uuid.c | 12 +-- .../type_uuid/func_uuid_timestamp.result | 79 +++++++++++-------- .../type_uuid/func_uuid_timestamp.test | 41 +++++----- 4 files changed, 75 insertions(+), 63 deletions(-) diff --git a/include/my_sys.h b/include/my_sys.h index 836d3b7ec3225..b7798c9f64ce3 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -17,10 +17,6 @@ #ifndef _my_sys_h #define _my_sys_h -#ifndef __cplusplus -#include -#endif - #include #include @@ -1111,7 +1107,7 @@ int my_msync(int, void *, size_t, int); void my_uuid_init(ulong seed1, ulong seed2); void my_uuid(uchar *guid); void my_uuid_end(void); -bool my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec); +int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec); static inline void my_uuid2str(const uchar *guid, char *s, int with_separators) { int i; diff --git a/mysys/my_uuid.c b/mysys/my_uuid.c index 138bd3184eff4..22beb0c6449d3 100644 --- a/mysys/my_uuid.c +++ b/mysys/my_uuid.c @@ -235,22 +235,22 @@ void my_uuid_end() @param[out] usec Microseconds part @return - @retval false Success - @retval true UUID version doesn't contain timestamp or timestamp invalid + @retval 0 Success + @retval 1 UUID version doesn't contain timestamp or timestamp invalid - UUIDv1 format (RFC 4122, big-endian): + UUIDv1 format (RFC 9562 Section 5.1, big-endian): Bytes 0-3: time_low (32 bits, low part of timestamp) Bytes 4-5: time_mid (16 bits, middle part of timestamp) Bytes 6-7: version (4 bits) + time_hi (12 bits, high part of timestamp) Timestamp is 100-nanosecond intervals since 1582-10-15 - UUIDv7 format (RFC 9562, big-endian): + UUIDv7 format (RFC 9562 Section 5.7, big-endian): Bytes 0-5: Unix timestamp in milliseconds (48 bits) Bytes 6-7: version (4 bits) + sub-millisecond precision (12 bits) */ -bool my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) +int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) { - uint version= (uchar) uuid[6] >> 4; + char version= uuid[6] >> 4; ulonglong ts; switch (version) diff --git a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result index 3e80e8098d879..e7bc9c16d4557 100644 --- a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result +++ b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.result @@ -2,27 +2,33 @@ SET time_zone='+00:00'; # # UUIDv1 with known timestamps # -SELECT UUID_TIMESTAMP('63b00000-bfde-11d3-80fe-9f59977b836e'); -UUID_TIMESTAMP('63b00000-bfde-11d3-80fe-9f59977b836e') -2000-01-01 00:00:00.000000 -SELECT UUID_TIMESTAMP('16488880-2b13-11ef-808b-603c7ba5e656'); -UUID_TIMESTAMP('16488880-2b13-11ef-808b-603c7ba5e656') -2024-06-15 12:30:45.000000 -SELECT UUID_TIMESTAMP('d02b2980-e6a4-11f0-8072-39f36896a88f'); -UUID_TIMESTAMP('d02b2980-e6a4-11f0-8072-39f36896a88f') -2025-12-31 23:59:59.000000 +SELECT '4bd352dc-e593-11f0-8de9-0242ac120002' AS uuid, +UUID_TIMESTAMP('4bd352dc-e593-11f0-8de9-0242ac120002') AS ts; +uuid ts +4bd352dc-e593-11f0-8de9-0242ac120002 2025-12-30 15:22:04.357910 +SELECT 'bec1046a-e593-11f0-8de9-0242ac120002' AS uuid, +UUID_TIMESTAMP('bec1046a-e593-11f0-8de9-0242ac120002') AS ts; +uuid ts +bec1046a-e593-11f0-8de9-0242ac120002 2025-12-30 15:25:17.175921 +SELECT 'c28c09a0-e593-11f0-8de9-0242ac120002' AS uuid, +UUID_TIMESTAMP('c28c09a0-e593-11f0-8de9-0242ac120002') AS ts; +uuid ts +c28c09a0-e593-11f0-8de9-0242ac120002 2025-12-30 15:25:23.539600 # # UUIDv7 with known timestamps (ms precision) # -SELECT UUID_TIMESTAMP('00dc6acf-ac00-737d-9f12-3229a718bf21'); -UUID_TIMESTAMP('00dc6acf-ac00-737d-9f12-3229a718bf21') -2000-01-01 00:00:00.000000 -SELECT UUID_TIMESTAMP('01901be0-f183-7e6c-9601-62a5e4f6e7b8'); -UUID_TIMESTAMP('01901be0-f183-7e6c-9601-62a5e4f6e7b8') -2024-06-15 12:30:45.123000 -SELECT UUID_TIMESTAMP('019b76da-a7ff-7ece-a98f-44624a8d3b0f'); -UUID_TIMESTAMP('019b76da-a7ff-7ece-a98f-44624a8d3b0f') -2025-12-31 23:59:59.999000 +SELECT '019b6fdd-4937-7bb5-95c7-53363c6df927' AS uuid, +UUID_TIMESTAMP('019b6fdd-4937-7bb5-95c7-53363c6df927') AS ts; +uuid ts +019b6fdd-4937-7bb5-95c7-53363c6df927 2025-12-30 15:25:31.831000 +SELECT '019b6fdd-5f17-7cf2-b034-248b9c207db6' AS uuid, +UUID_TIMESTAMP('019b6fdd-5f17-7cf2-b034-248b9c207db6') AS ts; +uuid ts +019b6fdd-5f17-7cf2-b034-248b9c207db6 2025-12-30 15:25:37.431000 +SELECT '019b6fdd-7327-7a5b-935c-4de00dd0e7c6' AS uuid, +UUID_TIMESTAMP('019b6fdd-7327-7a5b-935c-4de00dd0e7c6') AS ts; +uuid ts +019b6fdd-7327-7a5b-935c-4de00dd0e7c6 2025-12-30 15:25:42.567000 # # UUIDv4 returns NULL (no timestamp) # @@ -46,13 +52,14 @@ Warning 1292 Incorrect uuid value: 'not-a-valid-uuid' # # Native UUID type # -SELECT UUID_TIMESTAMP(CAST('01901be0-f183-7e6c-9601-62a5e4f6e7b8' AS UUID)); -UUID_TIMESTAMP(CAST('01901be0-f183-7e6c-9601-62a5e4f6e7b8' AS UUID)) -2024-06-15 12:30:45.123000 +SELECT '019b6fdd-4937-7bb5-95c7-53363c6df927' AS uuid, +UUID_TIMESTAMP(CAST('019b6fdd-4937-7bb5-95c7-53363c6df927' AS UUID)) AS ts; +uuid ts +019b6fdd-4937-7bb5-95c7-53363c6df927 2025-12-30 15:25:31.831000 # # Return type is TIMESTAMP(6) # -CREATE TABLE t1 AS SELECT UUID_TIMESTAMP('01901be0-f183-7e6c-9601-62a5e4f6e7b8') AS ts; +CREATE TABLE t1 AS SELECT UUID_TIMESTAMP('019b6fdd-4937-7bb5-95c7-53363c6df927') AS ts; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -62,16 +69,20 @@ DROP TABLE t1; # # Edge cases # -SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; -before_unix_epoch -1 -SELECT UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000'); -UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000') -0000-00-00 00:00:00.000000 -SELECT UUID_TIMESTAMP('ffffffff-ffff-7fff-8000-000000000000'); -UUID_TIMESTAMP('ffffffff-ffff-7fff-8000-000000000000') -2042-12-13 16:54:30.655000 -SELECT UUID_TIMESTAMP('ffffffff-ffff-1fff-8000-000000000000'); -UUID_TIMESTAMP('ffffffff-ffff-1fff-8000-000000000000') -2105-11-25 16:30:52.684697 +SELECT '00000000-0000-1000-8000-000000000000' AS uuid, +UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; +uuid before_unix_epoch +00000000-0000-1000-8000-000000000000 1 +SELECT '00000000-0000-7000-8000-000000000000' AS uuid, +UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000') AS ts; +uuid ts +00000000-0000-7000-8000-000000000000 0000-00-00 00:00:00.000000 +SELECT 'ffffffff-ffff-7fff-8000-000000000000' AS uuid, +UUID_TIMESTAMP('ffffffff-ffff-7fff-8000-000000000000') AS ts; +uuid ts +ffffffff-ffff-7fff-8000-000000000000 2042-12-13 16:54:30.655000 +SELECT 'ffffffff-ffff-1fff-8000-000000000000' AS uuid, +UUID_TIMESTAMP('ffffffff-ffff-1fff-8000-000000000000') AS ts; +uuid ts +ffffffff-ffff-1fff-8000-000000000000 2105-11-25 16:30:52.684697 SET time_zone=DEFAULT; diff --git a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test index 4aff76efaacac..86ae7b4b55c53 100644 --- a/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test +++ b/plugin/type_uuid/mysql-test/type_uuid/func_uuid_timestamp.test @@ -5,22 +5,22 @@ SET time_zone='+00:00'; --echo # --echo # UUIDv1 with known timestamps --echo # -# 2000-01-01 00:00:00.000000 -SELECT UUID_TIMESTAMP('63b00000-bfde-11d3-80fe-9f59977b836e'); -# 2024-06-15 12:30:45.000000 -SELECT UUID_TIMESTAMP('16488880-2b13-11ef-808b-603c7ba5e656'); -# 2025-12-31 23:59:59.000000 -SELECT UUID_TIMESTAMP('d02b2980-e6a4-11f0-8072-39f36896a88f'); +SELECT '4bd352dc-e593-11f0-8de9-0242ac120002' AS uuid, + UUID_TIMESTAMP('4bd352dc-e593-11f0-8de9-0242ac120002') AS ts; +SELECT 'bec1046a-e593-11f0-8de9-0242ac120002' AS uuid, + UUID_TIMESTAMP('bec1046a-e593-11f0-8de9-0242ac120002') AS ts; +SELECT 'c28c09a0-e593-11f0-8de9-0242ac120002' AS uuid, + UUID_TIMESTAMP('c28c09a0-e593-11f0-8de9-0242ac120002') AS ts; --echo # --echo # UUIDv7 with known timestamps (ms precision) --echo # -# 2000-01-01 00:00:00.000000 -SELECT UUID_TIMESTAMP('00dc6acf-ac00-737d-9f12-3229a718bf21'); -# 2024-06-15 12:30:45.123000 -SELECT UUID_TIMESTAMP('01901be0-f183-7e6c-9601-62a5e4f6e7b8'); -# 2025-12-31 23:59:59.999000 -SELECT UUID_TIMESTAMP('019b76da-a7ff-7ece-a98f-44624a8d3b0f'); +SELECT '019b6fdd-4937-7bb5-95c7-53363c6df927' AS uuid, + UUID_TIMESTAMP('019b6fdd-4937-7bb5-95c7-53363c6df927') AS ts; +SELECT '019b6fdd-5f17-7cf2-b034-248b9c207db6' AS uuid, + UUID_TIMESTAMP('019b6fdd-5f17-7cf2-b034-248b9c207db6') AS ts; +SELECT '019b6fdd-7327-7a5b-935c-4de00dd0e7c6' AS uuid, + UUID_TIMESTAMP('019b6fdd-7327-7a5b-935c-4de00dd0e7c6') AS ts; --echo # --echo # UUIDv4 returns NULL (no timestamp) @@ -37,12 +37,13 @@ SELECT UUID_TIMESTAMP('not-a-valid-uuid'); --echo # --echo # Native UUID type --echo # -SELECT UUID_TIMESTAMP(CAST('01901be0-f183-7e6c-9601-62a5e4f6e7b8' AS UUID)); +SELECT '019b6fdd-4937-7bb5-95c7-53363c6df927' AS uuid, + UUID_TIMESTAMP(CAST('019b6fdd-4937-7bb5-95c7-53363c6df927' AS UUID)) AS ts; --echo # --echo # Return type is TIMESTAMP(6) --echo # -CREATE TABLE t1 AS SELECT UUID_TIMESTAMP('01901be0-f183-7e6c-9601-62a5e4f6e7b8') AS ts; +CREATE TABLE t1 AS SELECT UUID_TIMESTAMP('019b6fdd-4937-7bb5-95c7-53363c6df927') AS ts; SHOW CREATE TABLE t1; DROP TABLE t1; @@ -50,12 +51,16 @@ DROP TABLE t1; --echo # Edge cases --echo # # UUIDv1 before Unix epoch -SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; +SELECT '00000000-0000-1000-8000-000000000000' AS uuid, + UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch; # UUIDv7 at Unix epoch (ts=0) -SELECT UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000'); +SELECT '00000000-0000-7000-8000-000000000000' AS uuid, + UUID_TIMESTAMP('00000000-0000-7000-8000-000000000000') AS ts; # UUIDv7 max 48-bit timestamp -SELECT UUID_TIMESTAMP('ffffffff-ffff-7fff-8000-000000000000'); +SELECT 'ffffffff-ffff-7fff-8000-000000000000' AS uuid, + UUID_TIMESTAMP('ffffffff-ffff-7fff-8000-000000000000') AS ts; # UUIDv1 max timestamp -SELECT UUID_TIMESTAMP('ffffffff-ffff-1fff-8000-000000000000'); +SELECT 'ffffffff-ffff-1fff-8000-000000000000' AS uuid, + UUID_TIMESTAMP('ffffffff-ffff-1fff-8000-000000000000') AS ts; SET time_zone=DEFAULT; From 879c14c774b7c87f5689d6e43aa7ef36235e0e23 Mon Sep 17 00:00:00 2001 From: Varun Deep Saini Date: Tue, 20 Jan 2026 00:44:58 +0530 Subject: [PATCH 8/8] updated return types Signed-off-by: Varun Deep Saini --- mysys/my_uuid.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/mysys/my_uuid.c b/mysys/my_uuid.c index 22beb0c6449d3..6544c58d9c37d 100644 --- a/mysys/my_uuid.c +++ b/mysys/my_uuid.c @@ -39,7 +39,6 @@ identifier. */ -#include #include "mysys_priv.h" #include #include @@ -241,7 +240,7 @@ void my_uuid_end() UUIDv1 format (RFC 9562 Section 5.1, big-endian): Bytes 0-3: time_low (32 bits, low part of timestamp) Bytes 4-5: time_mid (16 bits, middle part of timestamp) - Bytes 6-7: version (4 bits) + time_hi (12 bits, high part of timestamp) + Bytes 6-7: version (4 bits) + time_high (12 bits, high part of timestamp) Timestamp is 100-nanosecond intervals since 1582-10-15 UUIDv7 format (RFC 9562 Section 5.7, big-endian): @@ -260,15 +259,15 @@ int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) ts= mi_uint6korr(uuid); *seconds= ts / 1000; *usec= (ts % 1000) * 1000; - return false; + return 0; case 1: /* UUIDv1: reconstruct 60-bit timestamp from three fields: - time_low (bytes 0-3): bits 0-31 of timestamp - time_mid (bytes 4-5): bits 32-47 of timestamp - - time_hi (bytes 6-7): bits 48-59 of timestamp (masked, 4 bits are version) - Formula: (time_hi << 48) | (time_mid << 32) | time_low + - time_high (bytes 6-7): bits 48-59 of timestamp (masked, 4 bits are version) + Formula: (time_high << 48) | (time_mid << 32) | time_low */ ts= ((ulonglong)(mi_uint2korr(uuid + 6) & 0x0FFF) << 48) | ((ulonglong) mi_uint2korr(uuid + 4) << 32) | @@ -276,15 +275,15 @@ int my_uuid_extract_ts(const char *uuid, my_time_t *seconds, ulong *usec) /* Timestamp before Unix epoch (1970-01-01) */ if (ts < UUID_TIME_OFFSET) - return true; + return 1; ts= (ts - UUID_TIME_OFFSET) / 10; /* Convert to microseconds */ *seconds= ts / 1000000; *usec= ts % 1000000; - return false; + return 0; default: /* Other versions (e.g., v4) don't contain timestamps */ - return true; + return 1; } }