mirror of
https://github.com/MariaDB/server.git
synced 2025-08-17 06:42:17 +03:00
MDEV-26664 Store UUIDs in a more efficient manner
UUID values llllllll-mmmm-Vhhh-vsss-nnnnnnnnnnnn are now stored as nnnnnnnnnnnn-vsss-Vhhh-mmmm-llllllll inside the record: - the groups (segments separated by dash) are reordered right-to-left. - the bytes inside the groups are not reordered (stored as before, in big-endian format). This provides a better sorting order: the earlier UUID was generated, the higher it appears in the ORDER BY output. Also, this change enables a good key prefix compression, because the constant part is now in the beginning, while the non-constant part (the timestamp) is in the end.
This commit is contained in:
committed by
Sergei Golubchik
parent
50bcda010f
commit
b9f19f7eae
BIN
plugin/type_uuid/mysql-test/type_uuid/std_data/t1nopackkey.frm
Normal file
BIN
plugin/type_uuid/mysql-test/type_uuid/std_data/t1nopackkey.frm
Normal file
Binary file not shown.
BIN
plugin/type_uuid/mysql-test/type_uuid/std_data/t1packkey.frm
Normal file
BIN
plugin/type_uuid/mysql-test/type_uuid/std_data/t1packkey.frm
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -138,6 +138,50 @@ SELECT * FROM t1 WHERE a IN ('::', 10);
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # ORDER BY
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a UUID);
|
||||
DELIMITER $$;
|
||||
FOR i IN 0..15
|
||||
DO
|
||||
INSERT INTO t1 VALUES (REPLACE('XX000000-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00XX0000-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('0000XX00-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('000000XX-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-XX00-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-00XX-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-XX00-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-00XX-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-XX00-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-00XX-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-XX0000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-00XX00000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-0000XX000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-000000XX0000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-00000000XX00','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-0000000000XX','XX',LPAD(HEX(i),2,'0')));
|
||||
END FOR;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
--echo #
|
||||
--echo # Logical ORDER BY
|
||||
--echo #
|
||||
SELECT * FROM t1 ORDER BY a;
|
||||
SELECT COALESCE(NULL, a) FROM t1 ORDER BY a;
|
||||
|
||||
--echo #
|
||||
--echo # Lexicographical ORDER BY
|
||||
--echo #
|
||||
|
||||
SELECT * FROM t1 ORDER BY CAST(a AS BINARY(16));
|
||||
SELECT * FROM t1 ORDER BY CAST(COALESCE(NULL,a) AS BINARY(16));
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # cmp_item_uuid: IN for non-constants
|
||||
--echo #
|
||||
|
@@ -66,3 +66,43 @@ SELECT * FROM t1 WHERE a=CAST('00000000-0000-0000-0000-0000000000ff' AS UUID);
|
||||
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=CAST('00000000-0000-0000-0000-0000000000ff' AS UUID);
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
CREATE OR REPLACE TABLE t1 (a UUID,KEY(a));
|
||||
SHOW CREATE TABLE t1;
|
||||
BEGIN;
|
||||
DELIMITER $$;
|
||||
FOR i IN 0..255
|
||||
DO
|
||||
INSERT INTO t1 VALUES (REPLACE('XX000000-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00XX0000-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('0000XX00-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('000000XX-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-XX00-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-00XX-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-XX00-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-00XX-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-XX00-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-00XX-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-XX0000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-00XX00000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-0000XX000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-000000XX0000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-00000000XX00','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-0000000000XX','XX',LPAD(HEX(i),2,'0')));
|
||||
END FOR;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
COMMIT;
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='ff000000-0000-0000-0000-000000000000';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00ff0000-0000-0000-0000-000000000000';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='0000ff00-0000-0000-0000-000000000000';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='000000ff-0000-0000-0000-000000000000';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-ff00-0000-0000-000000000000';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-00ff-0000-0000-000000000000';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-ff00-0000-000000000000';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-00ff-0000-000000000000';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-ff00-000000000000';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-00ff-000000000000';
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-0000-ff0000000000';
|
||||
DROP TABLE t1;
|
||||
|
@@ -115,6 +115,69 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = UUID'00000000-0000-0000-0000-0000000000ff'
|
||||
DROP TABLE t1;
|
||||
CREATE OR REPLACE TABLE t1 (a UUID,KEY(a));
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` uuid DEFAULT NULL,
|
||||
KEY `a` (`a`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
BEGIN;
|
||||
FOR i IN 0..255
|
||||
DO
|
||||
INSERT INTO t1 VALUES (REPLACE('XX000000-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00XX0000-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('0000XX00-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('000000XX-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-XX00-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-00XX-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-XX00-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-00XX-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-XX00-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-00XX-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-XX0000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-00XX00000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-0000XX000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-000000XX0000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-00000000XX00','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-0000000000XX','XX',LPAD(HEX(i),2,'0')));
|
||||
END FOR;
|
||||
$$
|
||||
COMMIT;
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='ff000000-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00ff0000-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='0000ff00-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='000000ff-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-ff00-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-00ff-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-ff00-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-00ff-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-ff00-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-00ff-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-0000-ff0000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# End of 10.5 tests
|
||||
#
|
||||
|
@@ -25,7 +25,7 @@ a
|
||||
00000000-0000-0000-0000-0000000000ff
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-0000-0000000000ff';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
1 SIMPLE t1 ref a a 17 const 4 Using where
|
||||
SELECT * FROM t1 WHERE a='garbage';
|
||||
a
|
||||
Warnings:
|
||||
@@ -66,7 +66,7 @@ EXPLAIN SELECT * FROM t1 WHERE a IN
|
||||
'00000000-0000-0000-0000-0000000000f0'
|
||||
);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range a a 17 NULL 6 Using where
|
||||
1 SIMPLE t1 range a a 17 NULL 12 Using where
|
||||
SELECT * FROM t1 WHERE a IN
|
||||
(
|
||||
'00000000-0000-0000-0000-000000000080',
|
||||
@@ -85,7 +85,7 @@ EXPLAIN SELECT * FROM t1 WHERE a IN
|
||||
'garbage'
|
||||
);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range a a 17 NULL 4 Using where
|
||||
1 SIMPLE t1 range a a 17 NULL 8 Using where
|
||||
Warnings:
|
||||
Warning 1292 Incorrect uuid value: 'garbage'
|
||||
SELECT * FROM t1 WHERE a BETWEEN
|
||||
@@ -178,10 +178,73 @@ a
|
||||
00000000-0000-0000-0000-0000000000ff
|
||||
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=CAST('00000000-0000-0000-0000-0000000000ff' AS UUID);
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 100.00 Using where
|
||||
1 SIMPLE t1 ref a a 17 const 4 100.00 Using where
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = UUID'00000000-0000-0000-0000-0000000000ff'
|
||||
DROP TABLE t1;
|
||||
CREATE OR REPLACE TABLE t1 (a UUID,KEY(a));
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` uuid DEFAULT NULL,
|
||||
KEY `a` (`a`)
|
||||
) ENGINE=MEMORY DEFAULT CHARSET=latin1
|
||||
BEGIN;
|
||||
FOR i IN 0..255
|
||||
DO
|
||||
INSERT INTO t1 VALUES (REPLACE('XX000000-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00XX0000-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('0000XX00-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('000000XX-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-XX00-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-00XX-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-XX00-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-00XX-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-XX00-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-00XX-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-XX0000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-00XX00000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-0000XX000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-000000XX0000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-00000000XX00','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-0000000000XX','XX',LPAD(HEX(i),2,'0')));
|
||||
END FOR;
|
||||
$$
|
||||
COMMIT;
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='ff000000-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00ff0000-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='0000ff00-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='000000ff-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-ff00-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-00ff-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-ff00-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-00ff-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-ff00-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-00ff-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-0000-ff0000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 2 Using where
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# End of 10.5 tests
|
||||
#
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Start of 10.5 tests
|
||||
# Start of 10.7 tests
|
||||
#
|
||||
#
|
||||
# MDEV-4958 Adding datatype UUID
|
||||
@@ -41,7 +41,7 @@ a
|
||||
00000000-0000-0000-0000-0000000000ff
|
||||
EXPLAIN SELECT * FROM t1 WHERE a>='00000000-0000-0000-0000-0000000000fe';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range a a 17 NULL 2 Using where; Using index
|
||||
1 SIMPLE t1 range a a 17 NULL 3 Using where; Using index
|
||||
SELECT * FROM t1 WHERE a>='garbage';
|
||||
a
|
||||
EXPLAIN SELECT * FROM t1 WHERE a>='garbage';
|
||||
@@ -64,7 +64,7 @@ EXPLAIN SELECT * FROM t1 WHERE a IN
|
||||
'00000000-0000-0000-0000-0000000000f0'
|
||||
);
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 range a a 17 NULL 3 Using where; Using index
|
||||
1 SIMPLE t1 range a a 17 NULL 4 Using where; Using index
|
||||
SELECT * FROM t1 WHERE a IN
|
||||
(
|
||||
'00000000-0000-0000-0000-000000000080',
|
||||
@@ -115,6 +115,123 @@ id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = UUID'00000000-0000-0000-0000-0000000000ff'
|
||||
DROP TABLE t1;
|
||||
CREATE OR REPLACE TABLE t1 (a UUID,KEY(a));
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` uuid DEFAULT NULL,
|
||||
KEY `a` (`a`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
BEGIN;
|
||||
FOR i IN 0..255
|
||||
DO
|
||||
INSERT INTO t1 VALUES (REPLACE('XX000000-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00XX0000-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('0000XX00-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('000000XX-0000-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-XX00-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-00XX-0000-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-XX00-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-00XX-0000-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-XX00-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-00XX-000000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-XX0000000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-00XX00000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-0000XX000000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-000000XX0000','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-00000000XX00','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t1 VALUES (REPLACE('00000000-0000-0000-0000-0000000000XX','XX',LPAD(HEX(i),2,'0')));
|
||||
END FOR;
|
||||
$$
|
||||
COMMIT;
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='ff000000-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00ff0000-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='0000ff00-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='000000ff-0000-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-ff00-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-00ff-0000-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-ff00-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-00ff-0000-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-ff00-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-00ff-000000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
EXPLAIN SELECT * FROM t1 WHERE a='00000000-0000-0000-0000-ff0000000000';
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref a a 17 const 1 Using where; Using index
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# End of 10.5 tests
|
||||
# Testing index prefix compression
|
||||
#
|
||||
CREATE PROCEDURE test_pack_key()
|
||||
BEGIN
|
||||
SHOW CREATE TABLE t1;
|
||||
FOR i IN 0..0x1FFF
|
||||
DO
|
||||
INSERT INTO t1 VALUES (UUID());
|
||||
END FOR;
|
||||
SELECT
|
||||
CASE
|
||||
WHEN INDEX_LENGTH/DATA_LENGTH < 0.7 THEN 'PACKED'
|
||||
WHEN INDEX_LENGTH/DATA_LENGTH > 1.2 THEN 'NOT PACKED'
|
||||
ELSE CONCAT('UNKNOWN ', INDEX_LENGTH/DATA_LENGTH)
|
||||
END AS PackKey
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
|
||||
END;
|
||||
$$
|
||||
"------------------ CREATE TABLE"
|
||||
CREATE TABLE t1 (a UUID, KEY(a));
|
||||
CALL test_pack_key();
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` uuid DEFAULT NULL,
|
||||
KEY `a` (`a`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
PackKey
|
||||
PACKED
|
||||
DROP TABLE t1;
|
||||
"------------------ t1packkey.frm"
|
||||
TRUNCATE TABLE t1;
|
||||
CALL test_pack_key();
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` uuid DEFAULT NULL,
|
||||
KEY `a` (`a`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
PackKey
|
||||
PACKED
|
||||
DROP TABLE t1;
|
||||
"------------------ t1nopackkey.frm"
|
||||
TRUNCATE TABLE t1;
|
||||
CALL test_pack_key();
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` uuid DEFAULT NULL,
|
||||
KEY `a` (`a`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
PackKey
|
||||
NOT PACKED
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE test_pack_key;
|
||||
#
|
||||
# End of 10.7 tests
|
||||
#
|
||||
|
@@ -1,5 +1,7 @@
|
||||
let $MYSQLD_DATADIR= `select @@datadir`;
|
||||
|
||||
--echo #
|
||||
--echo # Start of 10.5 tests
|
||||
--echo # Start of 10.7 tests
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
@@ -10,7 +12,50 @@
|
||||
SET default_storage_engine=MyISAM;
|
||||
--source type_uuid_engines.inc
|
||||
|
||||
--echo #
|
||||
--echo # Testing index prefix compression
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE test_pack_key()
|
||||
BEGIN
|
||||
SHOW CREATE TABLE t1;
|
||||
FOR i IN 0..0x1FFF
|
||||
DO
|
||||
INSERT INTO t1 VALUES (UUID());
|
||||
END FOR;
|
||||
SELECT
|
||||
CASE
|
||||
WHEN INDEX_LENGTH/DATA_LENGTH < 0.7 THEN 'PACKED'
|
||||
WHEN INDEX_LENGTH/DATA_LENGTH > 1.2 THEN 'NOT PACKED'
|
||||
ELSE CONCAT('UNKNOWN ', INDEX_LENGTH/DATA_LENGTH)
|
||||
END AS PackKey
|
||||
FROM INFORMATION_SCHEMA.TABLES
|
||||
WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1';
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
--echo "------------------ CREATE TABLE"
|
||||
CREATE TABLE t1 (a UUID, KEY(a));
|
||||
CALL test_pack_key();
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo "------------------ t1packkey.frm"
|
||||
--copy_file $MTR_SUITE_DIR/std_data/t1packkey.frm $MYSQLD_DATADIR/test/t1.frm
|
||||
TRUNCATE TABLE t1;
|
||||
CALL test_pack_key();
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo "------------------ t1nopackkey.frm"
|
||||
--copy_file $MTR_SUITE_DIR/std_data/t1nopackkey.frm $MYSQLD_DATADIR/test/t1.frm
|
||||
TRUNCATE TABLE t1;
|
||||
CALL test_pack_key();
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
DROP PROCEDURE test_pack_key;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.5 tests
|
||||
--echo # End of 10.7 tests
|
||||
--echo #
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -30,3 +30,75 @@ INSERT INTO t1 VALUES ('ffff0000-0000-0000-0000-00000000ffff');
|
||||
SELECT * FROM t1 PARTITION (p00);
|
||||
SELECT * FROM t1 PARTITION (pFF);
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
CREATE TABLE t0 (a UUID);
|
||||
DELIMITER $$;
|
||||
FOR i IN 0..255
|
||||
DO
|
||||
INSERT INTO t0 VALUES (REPLACE('XXfd306d-307f-11ec-8d10-d20bbc909b57','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t0 VALUES (REPLACE('9cfd306d-XX7f-12ec-8d10-d20bbc909b57','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t0 VALUES (REPLACE('9cfd306d-307f-13XX-8d10-d20bbc909b57','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t0 VALUES (REPLACE('9cfd306d-307f-14ec-8dXX-d20bbc909b57','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t0 VALUES (REPLACE('9cfd306d-307f-15ec-8d10-XX0bbc909b57','XX',LPAD(HEX(i),2,'0')));
|
||||
INSERT INTO t0 VALUES (REPLACE('9cfd306d-307f-16ec-8d10-d20bbc909bXX','XX',LPAD(HEX(i),2,'0')));
|
||||
END FOR;
|
||||
$$
|
||||
--echo # Test that UUID and BINARY(16) implement the same distribution by key
|
||||
CREATE PROCEDURE test_partition_by_key_uuid_vs_binary(parts INT)
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE REPLACE('CREATE TABLE t1 (a UUID) PARTITION BY KEY (a) PARTITIONS 7','7',parts);
|
||||
EXECUTE IMMEDIATE REPLACE('CREATE TABLE t2 (a BINARY(16)) PARTITION BY KEY (a) PARTITIONS 7','7',parts);
|
||||
INSERT INTO t1 SELECT * FROM t0;
|
||||
INSERT INTO t2 SELECT * FROM t0;
|
||||
FOR i IN 0..(parts-1)
|
||||
DO
|
||||
BEGIN
|
||||
DECLARE query_template TEXT DEFAULT 'SELECT a_p0, COUNT(*) FROM ('
|
||||
'SELECT a AS a_p0 FROM t1 PARTITION(p0) '
|
||||
'UNION ALL '
|
||||
'SELECT CAST(a AS UUID) AS a_p0 FROM t2 PARTITION(p0)) td '
|
||||
'GROUP BY a_p0';
|
||||
DECLARE query TEXT DEFAULT REPLACE(query_template,'p0',CONCAT('p',i));
|
||||
SELECT query;
|
||||
EXECUTE IMMEDIATE query;
|
||||
END;
|
||||
END FOR;
|
||||
DROP TABLE t1,t2;
|
||||
END;
|
||||
$$
|
||||
--echo # Display statistics how records are distributed between partitions
|
||||
CREATE PROCEDURE test_partition_by_key_pstat(parts INT)
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE REPLACE('CREATE TABLE t1 (a UUID) PARTITION BY KEY (a) PARTITIONS 7','7',parts);
|
||||
CREATE TABLE t1_pstat (pname VARCHAR(32), pcount int);
|
||||
INSERT INTO t1 SELECT * FROM t0;
|
||||
FOR i IN 0..(parts-1)
|
||||
DO
|
||||
BEGIN
|
||||
DECLARE query_template TEXT DEFAULT 'INSERT INTO t1_pstat VALUES (''p0'',(SELECT COUNT(*) FROM t1 PARTITION (p0)))';
|
||||
EXECUTE IMMEDIATE REPLACE(query_template,'p0',CONCAT('p',i));
|
||||
END;
|
||||
END FOR;
|
||||
SELECT * FROM t1_pstat ORDER BY CAST(SUBSTR(pname,2,100) AS UNSIGNED);
|
||||
DROP TABLE t1,t1_pstat;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL test_partition_by_key_uuid_vs_binary(7);
|
||||
CALL test_partition_by_key_pstat(7);
|
||||
CALL test_partition_by_key_pstat(4);
|
||||
CALL test_partition_by_key_pstat(5);
|
||||
CALL test_partition_by_key_pstat(6);
|
||||
CALL test_partition_by_key_pstat(8);
|
||||
CALL test_partition_by_key_pstat(9);
|
||||
CALL test_partition_by_key_pstat(10);
|
||||
CALL test_partition_by_key_pstat(11);
|
||||
CALL test_partition_by_key_pstat(12);
|
||||
CALL test_partition_by_key_pstat(13);
|
||||
CALL test_partition_by_key_pstat(14);
|
||||
CALL test_partition_by_key_pstat(15);
|
||||
CALL test_partition_by_key_pstat(16);
|
||||
DROP PROCEDURE test_partition_by_key_uuid_vs_binary;
|
||||
DROP PROCEDURE test_partition_by_key_pstat;
|
||||
DROP TABLE t0;
|
||||
|
@@ -24,8 +24,162 @@ public:
|
||||
bool ascii_to_fbt(const char *str, size_t str_length);
|
||||
size_t to_string(char *dst, size_t dstsize) const;
|
||||
static const Name &default_value();
|
||||
|
||||
/*
|
||||
Binary (in-memory) UUIDv1 representation:
|
||||
|
||||
llllllll-mmmm-Vhhh-vsss-nnnnnnnnnnnn
|
||||
|
||||
Binary sortable (in-record) representation:
|
||||
|
||||
nnnnnnnnnnnn-vsss-Vhhh-mmmm-llllllll
|
||||
|
||||
Sign Section Bits Bytes Pos PosBinSortable
|
||||
------------- ------- ---- ----- --- --------------
|
||||
llllllll time low 32 4 0 12
|
||||
mmmm time mid 16 2 4 10
|
||||
Vhhh version and time hi 16 2 6 8
|
||||
vsss variant and clock seq 16 2 8 6
|
||||
nnnnnnnnnnnn node ID 48 6 10 0
|
||||
*/
|
||||
|
||||
class Segment
|
||||
{
|
||||
size_t m_memory_pos;
|
||||
size_t m_record_pos;
|
||||
size_t m_length;
|
||||
public:
|
||||
constexpr Segment(size_t memory_pos, size_t record_pos, size_t length)
|
||||
:m_memory_pos(memory_pos), m_record_pos(record_pos), m_length(length)
|
||||
{ }
|
||||
void memory_to_record(char *to, const char *from) const
|
||||
{
|
||||
memcpy(to + m_record_pos, from + m_memory_pos, m_length);
|
||||
}
|
||||
void record_to_memory(char *to, const char * from) const
|
||||
{
|
||||
memcpy(to + m_memory_pos, from + m_record_pos, m_length);
|
||||
}
|
||||
int cmp_memory(const char *a, const char *b) const
|
||||
{
|
||||
return memcmp(a + m_memory_pos, b + m_memory_pos, m_length);
|
||||
}
|
||||
void hash_record(const uchar *ptr, ulong *nr, ulong *nr2) const
|
||||
{
|
||||
my_charset_bin.hash_sort(ptr + m_record_pos, m_length, nr, nr2);
|
||||
}
|
||||
};
|
||||
|
||||
static const Segment & segment(uint i)
|
||||
{
|
||||
static Segment segments[]=
|
||||
{
|
||||
{0, 12, 4}, // llllllll
|
||||
{4, 10, 2}, // mmmm
|
||||
{6, 8, 2}, // Vhhh
|
||||
{8, 6, 2}, // vsss
|
||||
{10, 0, 6} // nnnnnnnnnnnn
|
||||
};
|
||||
return segments[i];
|
||||
}
|
||||
|
||||
// Convert the in-memory representation to the in-record representation
|
||||
static void memory_to_record(char *to, const char *from)
|
||||
{
|
||||
segment(0).memory_to_record(to, from);
|
||||
segment(1).memory_to_record(to, from);
|
||||
segment(2).memory_to_record(to, from);
|
||||
segment(3).memory_to_record(to, from);
|
||||
segment(4).memory_to_record(to, from);
|
||||
}
|
||||
|
||||
// Convert the in-record representation to the in-memory representation
|
||||
static void record_to_memory(char *to, const char *from)
|
||||
{
|
||||
segment(0).record_to_memory(to, from);
|
||||
segment(1).record_to_memory(to, from);
|
||||
segment(2).record_to_memory(to, from);
|
||||
segment(3).record_to_memory(to, from);
|
||||
segment(4).record_to_memory(to, from);
|
||||
}
|
||||
|
||||
/*
|
||||
Calculate a hash of the in-record representation.
|
||||
Used in Field_uuid::hash(), e.g. for KEY partitioning. This
|
||||
makes partition distribution for UUID and BINARY(16) equal,
|
||||
so for example:
|
||||
|
||||
CREATE OR REPLACE TABLE t1 (c1 UUID) PARTITION BY KEY(c1) PARTITIONS 5;
|
||||
INSERT INTO t1 (c1) VALUES (UUID());
|
||||
|
||||
and
|
||||
|
||||
CREATE OR REPLACE TABLE t1 (c1 BINARY(16)) PARTITION BY KEY(c1) PARTITIONS 5;
|
||||
INSERT INTO t1 (c1) VALUES (UUID());
|
||||
|
||||
put values into the same partition.
|
||||
*/
|
||||
static void hash_record(const uchar *ptr, ulong *nr, ulong *nr2)
|
||||
{
|
||||
segment(0).hash_record(ptr, nr, nr2);
|
||||
segment(1).hash_record(ptr, nr, nr2);
|
||||
segment(2).hash_record(ptr, nr, nr2);
|
||||
segment(3).hash_record(ptr, nr, nr2);
|
||||
segment(4).hash_record(ptr, nr, nr2);
|
||||
}
|
||||
|
||||
// Compare two in-memory values
|
||||
static int cmp(const LEX_CSTRING &a, const LEX_CSTRING &b)
|
||||
{
|
||||
DBUG_ASSERT(a.length == binary_length());
|
||||
DBUG_ASSERT(b.length == binary_length());
|
||||
int res;
|
||||
if ((res= segment(4).cmp_memory(a.str, b.str)) ||
|
||||
(res= segment(3).cmp_memory(a.str, b.str)) ||
|
||||
(res= segment(2).cmp_memory(a.str, b.str)) ||
|
||||
(res= segment(1).cmp_memory(a.str, b.str)) ||
|
||||
(res= segment(0).cmp_memory(a.str, b.str)))
|
||||
return res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ulong KEY_pack_flags(uint column_nr)
|
||||
{
|
||||
return HA_PACK_KEY;
|
||||
}
|
||||
|
||||
/*
|
||||
Convert in-record representation to binlog representation.
|
||||
We tranfer UUID values in binlog by compressing in-memory representation.
|
||||
This makes replication between UUID and BINARY(16) simpler:
|
||||
|
||||
Transferring by compressing the in-record representation would require
|
||||
extending the binary log format to put the extact data type name into
|
||||
the column metadata.
|
||||
*/
|
||||
static uchar *pack(uchar *to, const uchar *from, uint max_length)
|
||||
{
|
||||
uchar buf[binary_length()];
|
||||
record_to_memory((char *) buf, (const char *) from);
|
||||
return StringPack(&my_charset_bin, binary_length()).
|
||||
pack(to, buf, max_length);
|
||||
}
|
||||
|
||||
// Convert binlog representation to in-record representation
|
||||
static const uchar *unpack(uchar *to,
|
||||
const uchar *from, const uchar *from_end,
|
||||
uint param_data)
|
||||
{
|
||||
uchar buf[binary_length()];
|
||||
const uchar *rc= StringPack(&my_charset_bin, binary_length()).
|
||||
unpack(buf, from, from_end, param_data);
|
||||
memory_to_record((char *) to, (const char *) buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#include "sql_type_fixedbin.h"
|
||||
typedef FixedBinTypeBundle<UUID> UUIDBundle;
|
||||
|
||||
|
@@ -484,6 +484,11 @@ public:
|
||||
if (str.Alloced_length)
|
||||
Alloced_length= (uint32) (str.Alloced_length - offset);
|
||||
}
|
||||
LEX_CSTRING to_lex_cstring() const
|
||||
{
|
||||
LEX_CSTRING tmp= {Ptr, str_length};
|
||||
return tmp;
|
||||
}
|
||||
inline LEX_CSTRING *get_value(LEX_CSTRING *res)
|
||||
{
|
||||
res->str= Ptr;
|
||||
|
@@ -111,6 +111,12 @@ public:
|
||||
return fbt;
|
||||
}
|
||||
|
||||
static Fbt record_to_memory(const char *ptr)
|
||||
{
|
||||
Fbt fbt;
|
||||
FbtImpl::record_to_memory(fbt.m_buffer, ptr);
|
||||
return fbt;
|
||||
}
|
||||
/*
|
||||
Check at Item's fix_fields() time if "item" can return a nullable value
|
||||
on conversion to Fbt, or conversion produces a NOT NULL Fbt value.
|
||||
@@ -132,10 +138,10 @@ public:
|
||||
{
|
||||
*error= make_from_item(item, warn);
|
||||
}
|
||||
void to_binary(char *str, size_t str_size) const
|
||||
void to_record(char *str, size_t str_size) const
|
||||
{
|
||||
DBUG_ASSERT(str_size >= sizeof(m_buffer));
|
||||
memcpy(str, m_buffer, sizeof(m_buffer));
|
||||
FbtImpl::memory_to_record(str, m_buffer);
|
||||
}
|
||||
bool to_binary(String *to) const
|
||||
{
|
||||
@@ -154,18 +160,13 @@ public:
|
||||
FbtImpl::max_char_length()+1));
|
||||
return false;
|
||||
}
|
||||
int cmp(const char *str, size_t length) const
|
||||
{
|
||||
DBUG_ASSERT(length == sizeof(m_buffer));
|
||||
return memcmp(m_buffer, str, length);
|
||||
}
|
||||
int cmp(const Binary_string &other) const
|
||||
{
|
||||
return cmp(other.ptr(), other.length());
|
||||
return FbtImpl::cmp(FbtImpl::to_lex_cstring(), other.to_lex_cstring());
|
||||
}
|
||||
int cmp(const Fbt &other) const
|
||||
{
|
||||
return memcmp(m_buffer, other.m_buffer, sizeof(m_buffer));
|
||||
return FbtImpl::cmp(FbtImpl::to_lex_cstring(), other.to_lex_cstring());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -191,9 +192,9 @@ public:
|
||||
DBUG_ASSERT(!is_null());
|
||||
return *this;
|
||||
}
|
||||
void to_binary(char *str, size_t str_size) const
|
||||
void to_record(char *str, size_t str_size) const
|
||||
{
|
||||
to_fbt().to_binary(str, str_size);
|
||||
to_fbt().to_record(str, str_size);
|
||||
}
|
||||
bool to_binary(String *to) const
|
||||
{
|
||||
@@ -257,6 +258,10 @@ public:
|
||||
{
|
||||
return FbtImpl::default_value();
|
||||
}
|
||||
ulong KEY_pack_flags(uint column_nr) const override
|
||||
{
|
||||
return FbtImpl::KEY_pack_flags(column_nr);
|
||||
}
|
||||
protocol_send_type_t protocol_send_type() const override
|
||||
{
|
||||
return PROTOCOL_SEND_STRING;
|
||||
@@ -480,7 +485,7 @@ public:
|
||||
DBUG_ASSERT(!item->null_value);
|
||||
DBUG_ASSERT(FbtImpl::binary_length() == tmp.length());
|
||||
DBUG_ASSERT(FbtImpl::binary_length() == sort_field->length);
|
||||
memcpy(to, tmp.ptr(), tmp.length());
|
||||
FbtImpl::memory_to_record((char*) to, tmp.ptr());
|
||||
}
|
||||
uint make_packed_sort_key_part(uchar *to, Item *item,
|
||||
const SORT_FIELD_ATTR *sort_field,
|
||||
@@ -501,7 +506,7 @@ public:
|
||||
DBUG_ASSERT(!item->null_value);
|
||||
DBUG_ASSERT(FbtImpl::binary_length() == tmp.length());
|
||||
DBUG_ASSERT(FbtImpl::binary_length() == sort_field->length);
|
||||
memcpy(to, tmp.ptr(), tmp.length());
|
||||
FbtImpl::memory_to_record((char*) to, tmp.ptr());
|
||||
return tmp.length();
|
||||
}
|
||||
void sort_length(THD *thd, const Type_std_attributes *item,
|
||||
@@ -700,9 +705,7 @@ public:
|
||||
}
|
||||
int cmp_native(const Native &a, const Native &b) const override
|
||||
{
|
||||
DBUG_ASSERT(a.length() == FbtImpl::binary_length());
|
||||
DBUG_ASSERT(b.length() == FbtImpl::binary_length());
|
||||
return memcmp(a.ptr(), b.ptr(), FbtImpl::binary_length());
|
||||
return FbtImpl::cmp(a.to_lex_cstring(), b.to_lex_cstring());
|
||||
}
|
||||
bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override
|
||||
{
|
||||
@@ -1107,7 +1110,7 @@ public:
|
||||
if (fbt.is_null())
|
||||
return maybe_null() ? set_null_with_warn(err)
|
||||
: set_min_value_with_warn(err);
|
||||
fbt.to_binary((char *) ptr, FbtImpl::binary_length());
|
||||
fbt.to_record((char *) ptr, FbtImpl::binary_length());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1184,11 +1187,27 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
String *val_str(String *val_buffer, String *) override
|
||||
bool val_native(Native *to) override
|
||||
{
|
||||
DBUG_ASSERT(marked_for_read());
|
||||
Fbt_null tmp((const char *) ptr, pack_length());
|
||||
return tmp.to_string(val_buffer) ? NULL : val_buffer;
|
||||
DBUG_ASSERT(!is_null());
|
||||
if (to->alloc(FbtImpl::binary_length()))
|
||||
return true;
|
||||
to->length(FbtImpl::binary_length());
|
||||
FbtImpl::record_to_memory((char*) to->ptr(), (const char*) ptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
Fbt to_fbt() const
|
||||
{
|
||||
DBUG_ASSERT(marked_for_read());
|
||||
DBUG_ASSERT(!is_null());
|
||||
return Fbt::record_to_memory((const char*) ptr);
|
||||
}
|
||||
|
||||
String *val_str(String *val_buffer, String *) override
|
||||
{
|
||||
return to_fbt().to_string(val_buffer) ? NULL : val_buffer;
|
||||
}
|
||||
|
||||
my_decimal *val_decimal(my_decimal *to) override
|
||||
@@ -1227,7 +1246,7 @@ public:
|
||||
{
|
||||
DBUG_ASSERT(marked_for_write_or_computed());
|
||||
DBUG_ASSERT(value.length() == FbtImpl::binary_length());
|
||||
memcpy(ptr, value.ptr(), value.length());
|
||||
FbtImpl::memory_to_record((char*) ptr, value.ptr());
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1409,6 +1428,13 @@ public:
|
||||
item->type_handler() == type_handler());
|
||||
return true;
|
||||
}
|
||||
void hash(ulong *nr, ulong *nr2)
|
||||
{
|
||||
if (is_null())
|
||||
*nr^= (*nr << 1) | 1;
|
||||
else
|
||||
FbtImpl::hash_record(ptr, nr, nr2);
|
||||
}
|
||||
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *prm, KEY_PART *key_part,
|
||||
const Item_bool_func *cond,
|
||||
scalar_comparison_op op, Item *value) override
|
||||
@@ -1450,13 +1476,13 @@ public:
|
||||
uchar *pack(uchar *to, const uchar *from, uint max_length) override
|
||||
{
|
||||
DBUG_PRINT("debug", ("Packing field '%s'", field_name.str));
|
||||
return StringPack(&my_charset_bin, FbtImpl::binary_length()).pack(to, from, max_length);
|
||||
return FbtImpl::pack(to, from, max_length);
|
||||
}
|
||||
|
||||
const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
|
||||
uint param_data) override
|
||||
{
|
||||
return StringPack(&my_charset_bin, FbtImpl::binary_length()).unpack(to, from, from_end, param_data);
|
||||
return FbtImpl::unpack(to, from, from_end, param_data);
|
||||
}
|
||||
|
||||
uint max_packed_col_length(uint max_length) override
|
||||
|
@@ -21,6 +21,38 @@
|
||||
format and their own (variable size) canonical string representation.
|
||||
|
||||
Examples are INET6 and UUID types.
|
||||
|
||||
The MariaDB server uses three binary representations of a data type:
|
||||
|
||||
1. In-memory binary representation (user visible)
|
||||
This representation:
|
||||
- can be used in INSERT..VALUES (X'AABBCC')
|
||||
- can be used in WHERE conditions: WHERE c1=X'AABBCC'
|
||||
- is returned by CAST(x AS BINARY(N))
|
||||
- is returned by Field::val_native() and Item::val_native()
|
||||
|
||||
2. In-record binary representation (user invisible)
|
||||
This representation:
|
||||
- is used in records (is pointed by Field::ptr)
|
||||
- must be comparable by memcmp()
|
||||
|
||||
3. Binlog binary (row) representation
|
||||
Usually, for string data types the binlog representation
|
||||
is based on the in-record representation with trailing byte compression:
|
||||
- trailing space compression for text string data types
|
||||
- trailing zero compression for binary string data types
|
||||
|
||||
We have to have separate in-memory and in-record representations
|
||||
because we use HA_KEYTYPE_BINARY for indexing. The engine API
|
||||
does not have a way to pass a comparison function as a parameter.
|
||||
|
||||
The default implementation below assumes that:
|
||||
- the in-memory and in-record representations are equal
|
||||
- the binlog representation is compatible with BINARY(N)
|
||||
This is OK for simple data types, like INET6.
|
||||
|
||||
Data type implementations that need different representations
|
||||
can override the default implementation (like e.g. UUID does).
|
||||
*/
|
||||
|
||||
/***********************************************************************/
|
||||
@@ -29,6 +61,7 @@ template<size_t NATIVE_LEN, size_t MAX_CHAR_LEN>
|
||||
class FixedBinTypeStorage
|
||||
{
|
||||
protected:
|
||||
// The buffer that stores the in-memory binary representation
|
||||
char m_buffer[NATIVE_LEN];
|
||||
|
||||
// Non-initializing constructor
|
||||
@@ -42,7 +75,7 @@ protected:
|
||||
}
|
||||
public:
|
||||
|
||||
// Initialize from binary representation
|
||||
// Initialize from the in-memory binary representation
|
||||
FixedBinTypeStorage(const char *str, size_t length)
|
||||
{
|
||||
if (length != binary_length())
|
||||
@@ -51,9 +84,49 @@ public:
|
||||
memcpy(&m_buffer, str, sizeof(m_buffer));
|
||||
}
|
||||
|
||||
// Return the buffer with the in-memory representation
|
||||
Lex_cstring to_lex_cstring() const
|
||||
{
|
||||
return Lex_cstring(m_buffer, sizeof(m_buffer));
|
||||
}
|
||||
|
||||
static constexpr uint binary_length() { return NATIVE_LEN; }
|
||||
static constexpr uint max_char_length() { return MAX_CHAR_LEN; }
|
||||
|
||||
// Compare the in-memory binary representations of two values
|
||||
static int cmp(const LEX_CSTRING &a, const LEX_CSTRING &b)
|
||||
{
|
||||
DBUG_ASSERT(a.length == binary_length());
|
||||
DBUG_ASSERT(b.length == binary_length());
|
||||
return memcmp(a.str, b.str, b.length);
|
||||
}
|
||||
|
||||
/*
|
||||
Convert from the in-memory to the in-record representation.
|
||||
Used in Field::store_native().
|
||||
*/
|
||||
static void memory_to_record(char *to, const char *from)
|
||||
{
|
||||
memcpy(to, from, NATIVE_LEN);
|
||||
}
|
||||
/*
|
||||
Convert from the in-record to the in-memory representation
|
||||
Used in Field::val_native().
|
||||
*/
|
||||
static void record_to_memory(char *to, const char *from)
|
||||
{
|
||||
memcpy(to, from, NATIVE_LEN);
|
||||
}
|
||||
|
||||
/*
|
||||
Hash the in-record representation
|
||||
Used in Field::hash().
|
||||
*/
|
||||
static void hash_record(const uchar *ptr, ulong *nr, ulong *nr2)
|
||||
{
|
||||
my_charset_bin.hash_sort(ptr, binary_length(), nr, nr2);
|
||||
}
|
||||
|
||||
static bool only_zero_bytes(const char *ptr, size_t length)
|
||||
{
|
||||
for (uint i= 0 ; i < length; i++)
|
||||
@@ -64,5 +137,37 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
static ulong KEY_pack_flags(uint column_nr)
|
||||
{
|
||||
/*
|
||||
Return zero by default. A particular data type can override
|
||||
this method return some flags, e.g. HA_PACK_KEY to enable
|
||||
key prefix compression.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Convert from the in-record to the binlog representation.
|
||||
Used in Field::pack(), and in filesort to store the addon fields.
|
||||
By default, do what BINARY(N) does.
|
||||
*/
|
||||
static uchar *pack(uchar *to, const uchar *from, uint max_length)
|
||||
{
|
||||
return StringPack(&my_charset_bin, binary_length()).pack(to, from, max_length);
|
||||
}
|
||||
|
||||
/*
|
||||
Convert from the in-binary-log to the in-record representation.
|
||||
Used in Field::unpack().
|
||||
By default, do what BINARY(N) does.
|
||||
*/
|
||||
static const uchar *unpack(uchar *to, const uchar *from, const uchar *from_end,
|
||||
uint param_data)
|
||||
{
|
||||
return StringPack(&my_charset_bin, binary_length()).unpack(to, from, from_end,
|
||||
param_data);
|
||||
}
|
||||
|
||||
};
|
||||
#endif /* SQL_TYPE_FIXEDBIN_STORAGE */
|
||||
|
Reference in New Issue
Block a user