Skip to content
/ server Public
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions plugin/type_uuid/item_uuidfunc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#define MYSQL_SERVER
#include "mariadb.h"
#include "item_uuidfunc.h"
#include <string>
#include <cctype>

String *Item_func_sys_guid::val_str(String *str)
{
Expand All @@ -29,3 +31,65 @@ String *Item_func_sys_guid::val_str(String *str)
my_uuid2str(buf, const_cast<char*>(str->ptr()), 0);
return str;
}

static bool is_valid_uuid_format_any(const std::string &str)
{
if (str.size() != 36) {
return false;
}
if (str[8] != '-' || str[13] != '-' || str[18] != '-' || str[23] != '-') {
return false;
}
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] == '-') {
continue;
}
if (!isxdigit(str[i])) {
return false;
}
}
return true;
}

int return_uuid_version(const std::string &str)
{
if (!is_valid_uuid_format_any(str)) {
return -1;
}
if (!isxdigit(str[14])) {
return -1;
}
// Currently the only supported versions are below 8, as per RFC 4122.
// If the version is above 7, it's either not a valid UUID or it's a
//future version that we don't support, so we return -1 in that case as well.
if (str[14] == '8' || str[14] == '9' ) {
return -1;
}
return (str[14] <= '9')
? (str[14] - '0')
: (static_cast<char>(std::tolower(static_cast<unsigned char>(str[14]))) - 'a' + 10);
}

longlong Item_func_uuid_version::val_int()
{
String in_tmp;
String *uuid_arg = args[0]->val_str(&in_tmp);
if (!uuid_arg) {
null_value = true;
return 0;
}

std::string in_str(uuid_arg->ptr(), uuid_arg->length());
int version = return_uuid_version(in_str);
if (version < 0) {
my_printf_error(ER_TRUNCATED_WRONG_VALUE,
"Incorrect uuid value: '%-.128s'",
MYF(0),
in_str.c_str());
null_value = true;
return 0;
}

null_value = false;
return version;
}
33 changes: 33 additions & 0 deletions plugin/type_uuid/item_uuidfunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,4 +115,37 @@ class Item_func_uuid_v7: public Item_func_uuid_vx<UUIDv7>
Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_uuid_v7>(thd, this); }
};

class Item_func_uuid_version : public Item_int_func
{
public:
Item_func_uuid_version(THD *thd, Item *arg1)
: Item_int_func(thd, arg1) {}

LEX_CSTRING func_name_cstring() const override
{
static LEX_CSTRING name = {STRING_WITH_LEN("uuid_version") };
return name;
}

longlong val_int() override;
const Type_handler *type_handler() const override
{
if (unsigned_flag) {
return &type_handler_ulong;
}
return &type_handler_slong;
}
bool fix_length_and_dec(THD *thd) override
{
decimals = 0;
max_length = 1;
set_maybe_null();
unsigned_flag = 1;
return FALSE;
}

Item *shallow_copy(THD *thd) const override
{ return get_item_copy<Item_func_uuid_version>(thd, this); }
};
#endif // ITEM_UUIDFUNC_INCLUDED
86 changes: 86 additions & 0 deletions plugin/type_uuid/mysql-test/type_uuid/func_uuid_version.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#
# Start of 13.0 test
#
#
# MDEV-38983 Adding UUID_VERSION()
#
#
# UUIDv1
#
SELECT UUID_VERSION(uuid()) AS version;
version
1
#
# UUIDv4
#
SELECT UUID_VERSION(uuid_v4()) AS version;
version
4
#
# UUIDv7
#
SELECT UUID_VERSION(uuid_v7()) AS version;
version
7
#
# UUIDv5
#
SELECT UUID_VERSION("3e1f44c0-1c3d-535d-ac3f-5218a74bf2df") AS version;
version
5
#
# not valid with text
#
SELECT UUID_VERSION("lefred") AS version;
ERROR 22007: Incorrect uuid value: 'lefred'
#
# not valid with wrong uuid (version 8)
#
SELECT UUID_VERSION("AF39A01C-E29D-8C4C-8072-60CEB26A82F1") AS version;
ERROR 22007: Incorrect uuid value: 'AF39A01C-E29D-8C4C-8072-60CEB26A82F1'
#
# not valid with wrong uuid (version 9)
#
SELECT UUID_VERSION("AF39A01C-E29D-8C4C-8072-60CEB26A82F1") AS version;
ERROR 22007: Incorrect uuid value: 'AF39A01C-E29D-8C4C-8072-60CEB26A82F1'
#
# no argument
#
SELECT UUID_VERSION() AS version;
ERROR 42000: Incorrect parameter count in the call to native function 'UUID_VERSION'
#
# multiple arguments
#
SELECT UUID_VERSION(uuid(), 1) AS version;
ERROR 42000: Incorrect parameter count in the call to native function 'UUID_VERSION'
#
# use it in check constraint to force uuid_v1
#
CREATE TABLE t1 (uuid CHAR(36) PRIMARY KEY CHECK(uuid_version(uuid) = 1));
INSERT INTO t1 VALUES(UUID());
INSERT INTO t1 VALUES(UUID_v4());
ERROR 23000: CONSTRAINT `t1.uuid` failed for `test`.`t1`
INSERT INTO t1 VALUES(UUID_v7());
ERROR 23000: CONSTRAINT `t1.uuid` failed for `test`.`t1`
DROP TABLE t1;
#
# use it in check constraint to force uuid_v4
#
CREATE TABLE t1 (uuid CHAR(36) PRIMARY KEY CHECK(uuid_version(uuid) = 4));
INSERT INTO t1 VALUES(UUID());
ERROR 23000: CONSTRAINT `t1.uuid` failed for `test`.`t1`
INSERT INTO t1 VALUES(UUID_v4());
INSERT INTO t1 VALUES(UUID_v7());
ERROR 23000: CONSTRAINT `t1.uuid` failed for `test`.`t1`
DROP TABLE t1;
#
# use it in check constraint to force uuid_v7
#
CREATE TABLE t1 (uuid CHAR(36) PRIMARY KEY CHECK(uuid_version(uuid) = 7));
INSERT INTO t1 VALUES(UUID());
ERROR 23000: CONSTRAINT `t1.uuid` failed for `test`.`t1`
INSERT INTO t1 VALUES(UUID_v4());
ERROR 23000: CONSTRAINT `t1.uuid` failed for `test`.`t1`
INSERT INTO t1 VALUES(UUID_v7());
DROP TABLE t1;
End of 13.0 test
95 changes: 95 additions & 0 deletions plugin/type_uuid/mysql-test/type_uuid/func_uuid_version.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
--echo #
--echo # Start of 13.0 test
--echo #

--echo #
--echo # MDEV-38983 Adding UUID_VERSION()
--echo #

--echo #
--echo # UUIDv1
--echo #
SELECT UUID_VERSION(uuid()) AS version;

--echo #
--echo # UUIDv4
--echo #
SELECT UUID_VERSION(uuid_v4()) AS version;

--echo #
--echo # UUIDv7
--echo #
SELECT UUID_VERSION(uuid_v7()) AS version;

--echo #
--echo # UUIDv5
--echo #
SELECT UUID_VERSION("3e1f44c0-1c3d-535d-ac3f-5218a74bf2df") AS version;

--echo #
--echo # not valid with text
--echo #
--error ER_TRUNCATED_WRONG_VALUE
SELECT UUID_VERSION("lefred") AS version;

--echo #
--echo # not valid with wrong uuid (version 8)
--echo #
--error ER_TRUNCATED_WRONG_VALUE
SELECT UUID_VERSION("AF39A01C-E29D-8C4C-8072-60CEB26A82F1") AS version;

--echo #
--echo # not valid with wrong uuid (version 9)
--echo #
--error ER_TRUNCATED_WRONG_VALUE
SELECT UUID_VERSION("AF39A01C-E29D-8C4C-8072-60CEB26A82F1") AS version;

--echo #
--echo # no argument
--echo #
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
SELECT UUID_VERSION() AS version;

--echo #
--echo # multiple arguments
--echo #
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
SELECT UUID_VERSION(uuid(), 1) AS version;

--echo #
--echo # use it in check constraint to force uuid_v1
--echo #

CREATE TABLE t1 (uuid CHAR(36) PRIMARY KEY CHECK(uuid_version(uuid) = 1));
INSERT INTO t1 VALUES(UUID());
--error ER_CONSTRAINT_FAILED
INSERT INTO t1 VALUES(UUID_v4());
--error ER_CONSTRAINT_FAILED
INSERT INTO t1 VALUES(UUID_v7());
DROP TABLE t1;

--echo #
--echo # use it in check constraint to force uuid_v4
--echo #

CREATE TABLE t1 (uuid CHAR(36) PRIMARY KEY CHECK(uuid_version(uuid) = 4));
--error ER_CONSTRAINT_FAILED
INSERT INTO t1 VALUES(UUID());
INSERT INTO t1 VALUES(UUID_v4());
--error ER_CONSTRAINT_FAILED
INSERT INTO t1 VALUES(UUID_v7());
DROP TABLE t1;

--echo #
--echo # use it in check constraint to force uuid_v7
--echo #

CREATE TABLE t1 (uuid CHAR(36) PRIMARY KEY CHECK(uuid_version(uuid) = 7));
--error ER_CONSTRAINT_FAILED
INSERT INTO t1 VALUES(UUID());
--error ER_CONSTRAINT_FAILED
INSERT INTO t1 VALUES(UUID_v4());
INSERT INTO t1 VALUES(UUID_v7());
DROP TABLE t1;

--echo End of 13.0 test
34 changes: 33 additions & 1 deletion plugin/type_uuid/plugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -180,16 +180,33 @@ class Create_func_uuid_v7 : public Create_func_arg0
virtual ~Create_func_uuid_v7() {}
};

class Create_func_uuid_version : public Create_func_arg1
{
public:
Item *create_1_arg(THD *thd, Item *arg1) override
{
DBUG_ENTER("Create_func_uuid_version::create_1_arg");
DBUG_RETURN(new (thd->mem_root) Item_func_uuid_version(thd, arg1));
}
static Create_func_uuid_version s_singleton;

protected:
Create_func_uuid_version() {}
virtual ~Create_func_uuid_version() {}
};

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_version Create_func_uuid_version::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_version(&Create_func_uuid_version::s_singleton);

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

Expand Down Expand Up @@ -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_version, // pointer to type-specific plugin descriptor
"uuid_version", // plugin name
"lefred", // plugin author
"Function UUID_VERSION()", // the plugin description
PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sigh, not your fault, but we should fix the fact that "GPL" isn't a license.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really know what to use there then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave it for now, it needs to be addressed at a higher level.

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_BETA // Maturity(see include/mysql/plugin.h)*/
}
maria_declare_plugin_end;
Loading