Skip to content

Commit 9aa596f

Browse files
Implement UUID_TIMESTAMP() function that extracts timestamp from UUIDv1 and UUIDv7 values
1 parent 4a01157 commit 9aa596f

File tree

5 files changed

+213
-1
lines changed

5 files changed

+213
-1
lines changed

plugin/type_uuid/item_uuidfunc.cc

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
#define MYSQL_SERVER
1717
#include "mariadb.h"
1818
#include "item_uuidfunc.h"
19+
#include <myisampack.h>
20+
21+
// 100-nanosecond intervals between 1582-10-15 and 1970-01-01
22+
#define UUID_TIME_OFFSET ((ulonglong) 141427 * 24 * 60 * 60 * 1000 * 1000 * 10)
1923

2024
String *Item_func_sys_guid::val_str(String *str)
2125
{
@@ -29,3 +33,53 @@ String *Item_func_sys_guid::val_str(String *str)
2933
my_uuid2str(buf, const_cast<char*>(str->ptr()), 0);
3034
return str;
3135
}
36+
37+
38+
bool Item_func_uuid_timestamp::fix_length_and_dec(THD *thd)
39+
{
40+
Type_std_attributes::set(
41+
Type_temporal_attributes_not_fixed_dec(MAX_DATETIME_WIDTH,
42+
TIME_SECOND_PART_DIGITS, false),
43+
DTCollation_numeric());
44+
set_maybe_null();
45+
return FALSE;
46+
}
47+
48+
49+
bool Item_func_uuid_timestamp::val_native(THD *thd, Native *to)
50+
{
51+
Type_handler_uuid_new::Fbt_null uuid(args[0]);
52+
if (uuid.is_null())
53+
return (null_value= true);
54+
55+
const uchar *buf= (const uchar *) uuid.to_lex_cstring().str;
56+
uint version= buf[6] >> 4;
57+
58+
my_time_t seconds;
59+
ulong microseconds;
60+
61+
if (version == 7)
62+
{
63+
ulonglong unix_ts_ms= mi_uint6korr(buf);
64+
seconds= unix_ts_ms / 1000;
65+
microseconds= (unix_ts_ms % 1000) * 1000;
66+
}
67+
else if (version == 1)
68+
{
69+
ulonglong uuid_ts= ((ulonglong)(mi_uint2korr(buf + 6) & 0x0FFF) << 48) |
70+
((ulonglong) mi_uint2korr(buf + 4) << 32) |
71+
(ulonglong) mi_uint4korr(buf);
72+
73+
if (uuid_ts < UUID_TIME_OFFSET)
74+
return (null_value= true);
75+
76+
ulonglong unix_us= (uuid_ts - UUID_TIME_OFFSET) / 10;
77+
seconds= unix_us / 1000000;
78+
microseconds= unix_us % 1000000;
79+
}
80+
else
81+
return (null_value= true);
82+
83+
return null_value= Timestamp(Timeval(seconds, microseconds)).
84+
to_native(to, TIME_SECOND_PART_DIGITS);
85+
}

plugin/type_uuid/item_uuidfunc.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919

2020
#include "item.h"
21+
#include "item_timefunc.h"
2122
#include "sql_type_uuid_v1.h"
2223
#include "sql_type_uuid_v4.h"
2324
#include "sql_type_uuid_v7.h"
@@ -115,4 +116,29 @@ class Item_func_uuid_v7: public Item_func_uuid_vx<UUIDv7>
115116
Item *do_get_copy(THD *thd) const override
116117
{ return get_item_copy<Item_func_uuid_v7>(thd, this); }
117118
};
119+
120+
121+
class Item_func_uuid_timestamp: public Item_timestampfunc
122+
{
123+
bool check_arguments() const override
124+
{
125+
return args[0]->check_type_can_return_str(func_name_cstring());
126+
}
127+
public:
128+
Item_func_uuid_timestamp(THD *thd, Item *arg1)
129+
: Item_timestampfunc(thd, arg1) {}
130+
131+
LEX_CSTRING func_name_cstring() const override
132+
{
133+
static LEX_CSTRING name= {STRING_WITH_LEN("uuid_timestamp") };
134+
return name;
135+
}
136+
137+
bool fix_length_and_dec(THD *thd) override;
138+
bool val_native(THD *thd, Native *to) override;
139+
140+
Item *do_get_copy(THD *thd) const override
141+
{ return get_item_copy<Item_func_uuid_timestamp>(thd, this); }
142+
};
143+
118144
#endif // ITEM_UUIDFUNC_INCLUDED
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000');
2+
UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000')
3+
2024-01-17 20:34:37.539000
4+
SELECT UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000');
5+
UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000')
6+
2023-06-13 22:35:47.520000
7+
SELECT UUID_TIMESTAMP('1ee81f00-a8a8-11ee-8000-000000000000') IS NOT NULL AS has_timestamp;
8+
has_timestamp
9+
1
10+
SET @uuid1 = UUID();
11+
SELECT UUID_TIMESTAMP(@uuid1) IS NOT NULL AS has_timestamp;
12+
has_timestamp
13+
1
14+
SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent;
15+
timestamp_is_recent
16+
1
17+
SET @uuid7 = UUID_V7();
18+
SELECT UUID_TIMESTAMP(@uuid7) IS NOT NULL AS has_timestamp;
19+
has_timestamp
20+
1
21+
SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent;
22+
timestamp_is_recent
23+
1
24+
SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS no_timestamp_for_v4;
25+
no_timestamp_for_v4
26+
1
27+
SELECT UUID_TIMESTAMP('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11') IS NULL AS no_timestamp_for_v4;
28+
no_timestamp_for_v4
29+
1
30+
SELECT UUID_TIMESTAMP(NULL);
31+
UUID_TIMESTAMP(NULL)
32+
NULL
33+
SELECT UUID_TIMESTAMP('not-a-valid-uuid');
34+
UUID_TIMESTAMP('not-a-valid-uuid')
35+
NULL
36+
Warnings:
37+
Warning 1292 Incorrect uuid value: 'not-a-valid-uuid'
38+
SELECT UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID));
39+
UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID))
40+
2024-01-17 20:34:37.539000
41+
CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID()) AS ts;
42+
SHOW CREATE TABLE t1;
43+
Table Create Table
44+
t1 CREATE TABLE `t1` (
45+
`ts` timestamp(6) NULL DEFAULT NULL
46+
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
47+
DROP TABLE t1;
48+
CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID_V7()) AS ts;
49+
SHOW CREATE TABLE t1;
50+
Table Create Table
51+
t1 CREATE TABLE `t1` (
52+
`ts` timestamp(6) NULL DEFAULT NULL
53+
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
54+
DROP TABLE t1;
55+
SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000');
56+
UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000')
57+
2024-01-17 20:34:37.539000
58+
SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch;
59+
before_unix_epoch
60+
1
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# UUID_TIMESTAMP() function to extract timestamp from UUIDv1 and UUIDv7
2+
3+
SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000');
4+
5+
SELECT UUID_TIMESTAMP('0188b5b8-8000-7000-8000-000000000000');
6+
7+
SELECT UUID_TIMESTAMP('1ee81f00-a8a8-11ee-8000-000000000000') IS NOT NULL AS has_timestamp;
8+
9+
SET @uuid1 = UUID();
10+
SELECT UUID_TIMESTAMP(@uuid1) IS NOT NULL AS has_timestamp;
11+
12+
SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent;
13+
14+
SET @uuid7 = UUID_V7();
15+
SELECT UUID_TIMESTAMP(@uuid7) IS NOT NULL AS has_timestamp;
16+
17+
SELECT TIMESTAMPDIFF(SECOND, UUID_TIMESTAMP(UUID_V7()), NOW()) BETWEEN -5 AND 5 AS timestamp_is_recent;
18+
19+
SELECT UUID_TIMESTAMP(UUID_V4()) IS NULL AS no_timestamp_for_v4;
20+
21+
SELECT UUID_TIMESTAMP('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11') IS NULL AS no_timestamp_for_v4;
22+
23+
SELECT UUID_TIMESTAMP(NULL);
24+
25+
SELECT UUID_TIMESTAMP('not-a-valid-uuid');
26+
27+
SELECT UUID_TIMESTAMP(CAST('018d17f3-e9a3-7000-8000-000000000000' AS UUID));
28+
29+
CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID()) AS ts;
30+
SHOW CREATE TABLE t1;
31+
DROP TABLE t1;
32+
33+
CREATE TABLE t1 AS SELECT UUID_TIMESTAMP(UUID_V7()) AS ts;
34+
SHOW CREATE TABLE t1;
35+
DROP TABLE t1;
36+
37+
SELECT UUID_TIMESTAMP('018d17f3-e9a3-7000-8000-000000000000');
38+
39+
SELECT UUID_TIMESTAMP('00000000-0000-1000-8000-000000000000') IS NULL AS before_unix_epoch;
40+

plugin/type_uuid/plugin.cc

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,16 +180,33 @@ class Create_func_uuid_v7 : public Create_func_arg0
180180
virtual ~Create_func_uuid_v7() {}
181181
};
182182

183+
class Create_func_uuid_timestamp : public Create_func_arg1
184+
{
185+
public:
186+
Item *create_1_arg(THD *thd, Item *arg1) override
187+
{
188+
DBUG_ENTER("Create_func_uuid_timestamp::create_1_arg");
189+
DBUG_RETURN(new (thd->mem_root) Item_func_uuid_timestamp(thd, arg1));
190+
}
191+
static Create_func_uuid_timestamp s_singleton;
192+
193+
protected:
194+
Create_func_uuid_timestamp() {}
195+
virtual ~Create_func_uuid_timestamp() {}
196+
};
197+
183198
Create_func_uuid Create_func_uuid::s_singleton;
184199
Create_func_sys_guid Create_func_sys_guid::s_singleton;
185200
Create_func_uuid_v4 Create_func_uuid_v4::s_singleton;
186201
Create_func_uuid_v7 Create_func_uuid_v7::s_singleton;
202+
Create_func_uuid_timestamp Create_func_uuid_timestamp::s_singleton;
187203

188204
static Plugin_function
189205
plugin_descriptor_function_uuid(&Create_func_uuid::s_singleton),
190206
plugin_descriptor_function_sys_guid(&Create_func_sys_guid::s_singleton),
191207
plugin_descriptor_function_uuid_v4(&Create_func_uuid_v4::s_singleton),
192-
plugin_descriptor_function_uuid_v7(&Create_func_uuid_v7::s_singleton);
208+
plugin_descriptor_function_uuid_v7(&Create_func_uuid_v7::s_singleton),
209+
plugin_descriptor_function_uuid_timestamp(&Create_func_uuid_timestamp::s_singleton);
193210

194211
static constexpr Name type_name={STRING_WITH_LEN("uuid")};
195212

@@ -301,5 +318,20 @@ maria_declare_plugin(type_uuid)
301318
NULL, // System variables
302319
"1.0.1", // String version representation
303320
MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
321+
},
322+
{
323+
MariaDB_FUNCTION_PLUGIN, // the plugin type (see include/mysql/plugin.h)
324+
&plugin_descriptor_function_uuid_timestamp, // pointer to type-specific plugin descriptor
325+
"uuid_timestamp", // plugin name
326+
"Varun Deep Saini", // plugin author
327+
"Function UUID_TIMESTAMP()", // the plugin description
328+
PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
329+
0, // Pointer to plugin initialization function
330+
0, // Pointer to plugin deinitialization function
331+
0x0100, // Numeric version 0xAABB means AA.BB version
332+
NULL, // Status variables
333+
NULL, // System variables
334+
"1.0", // String version representation
335+
MariaDB_PLUGIN_MATURITY_STABLE// Maturity(see include/mysql/plugin.h)*/
304336
}
305337
maria_declare_plugin_end;

0 commit comments

Comments
 (0)