Commit b9f19f7e authored by Alexander Barkov's avatar Alexander Barkov Committed by Sergei Golubchik

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.
parent 50bcda01
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
......@@ -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
#
#
# 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;
#
# 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.5 tests
# End of 10.7 tests
#
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 #
......@@ -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 @@ class UUID: public FixedBinTypeStorage<MY_UUID_SIZE, MY_UUID_STRING_LENGTH>
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 @@ class Binary_string: public Sql_alloc
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 @@ class FixedBinTypeBundle
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 @@ class FixedBinTypeBundle
{
*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 @@ class FixedBinTypeBundle
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 @@ class FixedBinTypeBundle
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 @@ class FixedBinTypeBundle
{
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 @@ class FixedBinTypeBundle
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 @@ class FixedBinTypeBundle
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 @@ class FixedBinTypeBundle
}
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 @@ class FixedBinTypeBundle
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 @@ class FixedBinTypeBundle
return false;
}
String *val_str(String *val_buffer, String *) override
bool val_native(Native *to) override
{
DBUG_ASSERT(marked_for_read());
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());
Fbt_null tmp((const char *) ptr, pack_length());
return tmp.to_string(val_buffer) ? NULL : val_buffer;
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 @@ class FixedBinTypeBundle
{
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 @@ class FixedBinTypeBundle
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 @@ class FixedBinTypeBundle
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 @@ class FixedBinTypeStorage
}
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 @@ class FixedBinTypeStorage
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 @@ class FixedBinTypeStorage
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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment