Skip to content

Commit c5cc46f

Browse files
abarkovvuvova
authored andcommitted
cleanup: MDEV-11339 Implement native UUID4 function
- Moving the class UUIDv1 into a separate file sql_type_uuid_v1.h - Adding a new class UUIDv4, similar to UUIDv1 - Changing the way how my_random_bytes() failures are handled. Instead of raising an error it now raises a note. Reasoning: if we're in the middle of a multi-million row transaction and one UUIDv4 generation fails, it's not a good idea to throw away the entire transaction. Instead, let's generate bytes using a my_rnd() loop. - Adding a new test func_uuid_v4.test to demonstrate that the UUIDv4() returned type is "UUID NOT NULL". - Adding a new test func_uuidv4_debug.test to emulate my_random_bytes() failures - Adding a template Item_func_uuid_vx to share the code between the implementations of UUID() and UUIDv4().
1 parent 2f28827 commit c5cc46f

File tree

10 files changed

+209
-84
lines changed

10 files changed

+209
-84
lines changed

plugin/type_uuid/item_uuidfunc.cc

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2019,2021, MariaDB Corporation
1+
/* Copyright (c) 2019,2024, MariaDB Corporation
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -29,31 +29,3 @@ String *Item_func_sys_guid::val_str(String *str)
2929
my_uuid2str(buf, const_cast<char*>(str->ptr()), 0);
3030
return str;
3131
}
32-
33-
String *Item_func_uuid_v4::val_str(String *str)
34-
{
35-
DBUG_ASSERT(fixed());
36-
str->alloc(MY_UUID_STRING_LENGTH+1);
37-
str->length(MY_UUID_STRING_LENGTH);
38-
str->set_charset(collation.collation);
39-
40-
uchar buf[MY_UUID_SIZE];
41-
if (!my_uuid_v4(buf)) {
42-
my_error(ER_INTERNAL_ERROR, MYF(0),
43-
"Failed to generate a random value for UUIDv4");
44-
}
45-
my_uuid2str(buf, const_cast<char*>(str->ptr()), 1);
46-
return str;
47-
}
48-
49-
bool Item_func_uuid_v4::val_native(THD *, Native *to)
50-
{
51-
DBUG_ASSERT(fixed());
52-
to->alloc(MY_UUID_SIZE);
53-
to->length(MY_UUID_SIZE);
54-
if (!my_uuid_v4((uchar*)to->ptr())) {
55-
my_error(ER_INTERNAL_ERROR, MYF(0),
56-
"Failed to generate a random value for UUIDv4");
57-
}
58-
return 0;
59-
}

plugin/type_uuid/item_uuidfunc.h

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef ITEM_UUIDFUNC_INCLUDED
22
#define ITEM_UUIDFUNC_INCLUDED
33

4-
/* Copyright (c) 2019,2021, MariaDB Corporation
4+
/* Copyright (c) 2019,2024, MariaDB Corporation
55
66
This program is free software; you can redistribute it and/or modify
77
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,8 @@
1818

1919

2020
#include "item.h"
21-
#include "sql_type_uuid.h"
21+
#include "sql_type_uuid_v1.h"
22+
#include "sql_type_uuid_v4.h"
2223

2324
class Item_func_sys_guid: public Item_str_func
2425
{
@@ -49,46 +50,54 @@ class Item_func_sys_guid: public Item_str_func
4950
{ return get_item_copy<Item_func_sys_guid>(thd, this); }
5051
};
5152

52-
class Item_func_uuid: public Type_handler_uuid_new::Item_fbt_func
53+
54+
template<class UUIDvX>
55+
class Item_func_uuid_vx: public Type_handler_uuid_new::Item_fbt_func
5356
{
5457
public:
55-
Item_func_uuid(THD *thd): Item_fbt_func(thd) { }
58+
using Item_fbt_func::Item_fbt_func;
5659
bool const_item() const override { return false; }
5760
table_map used_tables() const override { return RAND_TABLE_BIT; }
5861
bool check_vcol_func_processor(void *arg) override
5962
{
6063
return mark_unsupported_function(func_name(), "()", arg, VCOL_NON_DETERMINISTIC);
6164
}
62-
LEX_CSTRING func_name_cstring() const override
63-
{
64-
static LEX_CSTRING name= {STRING_WITH_LEN("uuid") };
65-
return name;
66-
}
6765
String *val_str(String *str) override
6866
{
6967
DBUG_ASSERT(fixed());
70-
return UUIDv1().to_string(str) ? NULL : str;
68+
return UUIDvX().to_string(str) ? NULL : str;
7169
}
7270
bool val_native(THD *thd, Native *to) override
7371
{
7472
DBUG_ASSERT(fixed());
75-
return UUIDv1::construct_native(to);
73+
return UUIDvX::construct_native(to);
74+
}
75+
};
76+
77+
78+
class Item_func_uuid: public Item_func_uuid_vx<UUIDv1>
79+
{
80+
public:
81+
using Item_func_uuid_vx::Item_func_uuid_vx;
82+
LEX_CSTRING func_name_cstring() const override
83+
{
84+
static LEX_CSTRING name= {STRING_WITH_LEN("uuid") };
85+
return name;
7686
}
7787
Item *do_get_copy(THD *thd) const override
7888
{ return get_item_copy<Item_func_uuid>(thd, this); }
7989
};
8090

81-
class Item_func_uuid_v4: public Item_func_uuid
91+
92+
class Item_func_uuid_v4: public Item_func_uuid_vx<UUIDv4>
8293
{
8394
public:
84-
Item_func_uuid_v4(THD *thd): Item_func_uuid(thd) { }
95+
using Item_func_uuid_vx::Item_func_uuid_vx;
8596
LEX_CSTRING func_name_cstring() const override
8697
{
8798
static LEX_CSTRING name= {STRING_WITH_LEN("uuidv4") };
8899
return name;
89100
}
90-
String *val_str(String *) override;
91-
bool val_native(THD *thd, Native *to) override;
92101
Item *do_get_copy(THD *thd) const override
93102
{ return get_item_copy<Item_func_uuid_v4>(thd, this); }
94103
};
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#
2+
# MDEV-33827 UUID() returns a NULL-able result
3+
#
4+
CREATE TABLE t1 AS SELECT UUIDv4();
5+
SHOW CREATE TABLE t1;
6+
Table Create Table
7+
t1 CREATE TABLE `t1` (
8+
`UUIDv4()` uuid NOT NULL
9+
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci
10+
DROP TABLE t1;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
--echo #
2+
--echo # MDEV-33827 UUID() returns a NULL-able result
3+
--echo #
4+
5+
CREATE TABLE t1 AS SELECT UUIDv4();
6+
SHOW CREATE TABLE t1;
7+
DROP TABLE t1;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
SET debug_dbug="+d,simulate_uuidv4_my_random_bytes_failure";
2+
#
3+
# Start of 11.6 tests
4+
#
5+
#
6+
# MDEV-11339 Support UUID v4 generation
7+
#
8+
CREATE TABLE t1 (
9+
a int primary key not null,
10+
u UUID DEFAULT UUIDv4(),
11+
unique key(u)
12+
);
13+
INSERT INTO t1(a) SELECT seq FROM seq_1_to_16;
14+
Warnings:
15+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
16+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
17+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
18+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
19+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
20+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
21+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
22+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
23+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
24+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
25+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
26+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
27+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
28+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
29+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
30+
Note 1105 UUIDv4 generation failed; using a my_rnd fallback
31+
SELECT COUNT(DISTINCT u) AS distinct_uuid_count FROM t1;
32+
distinct_uuid_count
33+
16
34+
SELECT
35+
u REGEXP '[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}' AS is_correct_version_and_revision,
36+
COUNT(*)
37+
FROM t1 GROUP BY is_correct_version_and_revision;
38+
is_correct_version_and_revision COUNT(*)
39+
1 16
40+
DROP TABLE t1;
41+
#
42+
# End of 11.6 tests
43+
#
44+
SET debug_dbug="";
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--source include/have_debug.inc
2+
3+
SET debug_dbug="+d,simulate_uuidv4_my_random_bytes_failure";
4+
5+
source include/have_sequence.inc;
6+
7+
--echo #
8+
--echo # Start of 11.6 tests
9+
--echo #
10+
11+
--echo #
12+
--echo # MDEV-11339 Support UUID v4 generation
13+
--echo #
14+
15+
CREATE TABLE t1 (
16+
a int primary key not null,
17+
u UUID DEFAULT UUIDv4(),
18+
unique key(u)
19+
);
20+
INSERT INTO t1(a) SELECT seq FROM seq_1_to_16;
21+
SELECT COUNT(DISTINCT u) AS distinct_uuid_count FROM t1;
22+
SELECT
23+
u REGEXP '[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12}' AS is_correct_version_and_revision,
24+
COUNT(*)
25+
FROM t1 GROUP BY is_correct_version_and_revision;
26+
DROP TABLE t1;
27+
28+
--echo #
29+
--echo # End of 11.6 tests
30+
--echo #
31+
32+
SET debug_dbug="";

plugin/type_uuid/plugin.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2019,2021, MariaDB Corporation
1+
/* Copyright (c) 2019,2024, MariaDB Corporation
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -16,7 +16,6 @@
1616
#define MYSQL_SERVER
1717
#include "mariadb.h"
1818
#include "sql_class.h"
19-
#include "sql_type_uuid.h"
2019
#include "item_uuidfunc.h"
2120
#include <mysql/plugin_data_type.h>
2221
#include <mysql/plugin_function.h>

plugin/type_uuid/sql_type_uuid.h

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef SQL_TYPE_UUID_INCLUDED
22
#define SQL_TYPE_UUID_INCLUDED
33

4-
/* Copyright (c) 2019,2021 MariaDB Corporation
4+
/* Copyright (c) 2019,2024 MariaDB Corporation
55
66
This program is free software; you can redistribute it and/or modify
77
it under the terms of the GNU General Public License as published by
@@ -331,23 +331,4 @@ typedef Type_handler_fbt<UUID<1>, Type_collection_uuid> Type_handler_uuid_old;
331331
typedef Type_handler_fbt<UUID<0>, Type_collection_uuid> Type_handler_uuid_new;
332332

333333

334-
class UUIDv1: public Type_handler_uuid_new::Fbt
335-
{
336-
public:
337-
UUIDv1()
338-
{
339-
my_uuid((uchar*) m_buffer);
340-
}
341-
static bool construct_native(Native *to)
342-
{
343-
to->alloc(MY_UUID_SIZE);
344-
to->length(MY_UUID_SIZE);
345-
my_uuid((uchar*)to->ptr());
346-
return 0;
347-
}
348-
};
349-
350-
#include "sql_type_uuid_v4.h"
351-
352-
353334
#endif // SQL_TYPE_UUID_INCLUDED
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#ifndef SQL_TYPE_UUID_V1_INCLUDED
2+
#define SQL_TYPE_UUID_V1_INCLUDED
3+
4+
/* Copyright (c) 2024, MariaDB Corporation
5+
6+
This program is free software; you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation; version 2 of the License.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program; if not, write to the Free Software
17+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
18+
19+
#include "sql_type_uuid.h"
20+
21+
class UUIDv1: public Type_handler_uuid_new::Fbt
22+
{
23+
public:
24+
UUIDv1()
25+
{
26+
my_uuid((uchar*) m_buffer);
27+
}
28+
static bool construct_native(Native *to)
29+
{
30+
to->alloc(MY_UUID_SIZE);
31+
to->length(MY_UUID_SIZE);
32+
my_uuid((uchar*)to->ptr());
33+
return 0;
34+
}
35+
};
36+
37+
#endif // SQL_TYPE_UUID_V1_INCLUDED

plugin/type_uuid/sql_type_uuid_v4.h

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -35,28 +35,62 @@
3535
bits of random data.
3636
*/
3737

38+
#include "sql_type_uuid.h"
3839
#include "my_rnd.h"
3940

40-
#define UUID_VERSION 0x40
41-
#define UUID_VERSION_MASK 0x0F
42-
#define UUID_VARIANT 0x80
43-
#define UUID_VARIANT_MASK 0x3F
41+
class UUIDv4: public Type_handler_uuid_new::Fbt
42+
{
43+
static constexpr uchar UUID_VERSION() { return 0x40; }
44+
static constexpr uchar UUID_VERSION_MASK() { return 0x0F; }
45+
static constexpr uchar UUID_VARIANT() { return 0x80; }
46+
static constexpr uchar UUID_VARIANT_MASK() { return 0x3F; }
4447

45-
/**
46-
Create a global unique identifier version 4 (uuidv4)
48+
static void inject_version_and_variant(uchar *to)
49+
{
50+
to[6]= ((to[6] & UUID_VERSION_MASK()) | UUID_VERSION());
51+
to[8]= ((to[8] & UUID_VARIANT_MASK()) | UUID_VARIANT());
52+
}
4753

48-
@func my_uuid_v4()
49-
@param to Store uuidv4 here. Must be of size MY_UUID_SIZE (16)
50-
@return 1 in case of success and 0 in case of failure
51-
*/
52-
static inline bool my_uuid_v4(uchar *to)
53-
{
54-
if (my_random_bytes(to, 16) != MY_AES_OK)
55-
return 0;
54+
// Construct using a my_rnd()-based fallback method
55+
static void construct_fallback(char *to)
56+
{
57+
for (uint i= 0; i < 4; i++)
58+
int4store(&to[i * 4], (uint32) (my_rnd(&sql_rand)*0xFFFFFFFF));
59+
}
60+
61+
static void construct(char *to)
62+
{
63+
bool error= my_random_bytes((uchar*) to, 16) != MY_AES_OK;
64+
DBUG_EXECUTE_IF("simulate_uuidv4_my_random_bytes_failure", error= true; );
65+
66+
if (error) // A very unlikely failure happened.
67+
{
68+
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_NOTE,
69+
ER_UNKNOWN_ERROR,
70+
"UUIDv4 generation failed; using a my_rnd fallback");
71+
construct_fallback(to);
72+
}
73+
/*
74+
We have random bytes at to[6] and to[8].
75+
Let's inject proper version and variant to make it good UUIDv4.
76+
*/
77+
inject_version_and_variant((uchar*) to);
78+
}
79+
80+
public:
81+
82+
UUIDv4()
83+
{
84+
construct(m_buffer);
85+
}
86+
static bool construct_native(Native *to)
87+
{
88+
to->alloc(MY_UUID_SIZE);
89+
to->length(MY_UUID_SIZE);
90+
construct((char*)to->ptr());
91+
return 0;
92+
}
5693

57-
to[6]= ((to[6] & UUID_VERSION_MASK) | UUID_VERSION);
58-
to[8]= ((to[8] & UUID_VARIANT_MASK) | UUID_VARIANT);
59-
return 1;
60-
}
94+
};
6195

6296
#endif // SQL_TYPE_UUID_V4_INCLUDED

0 commit comments

Comments
 (0)