From d5068deebcb449a68db497ba9c6d8e70963b59f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 3 Apr 2024 12:26:50 +0300 Subject: [PATCH] MDEV-30732 : wsrep_store_key_val_for_row() may invoke memcpy() on nullptr Problem was that row_mysql_read_blob_ref can return NULL in case when blob datatype is used in a key and its real value is NULL. This NULL pointer is then used in memcpy function in wsrep_store_key_val_for_row. However, memcpy is defined so that argument 2 must not be NULL. Fixed by adding conditions before memcpy functions so that argument 2 is always non NULL. Additional fixes after review - Removed unnecessary copying key data from one buffer to another. Use original key data buffer as input and temporary buffer as output. Extra output buffer is needed because strnxfrm might expand input buffer contents. - Removed unnecessary initialization of variables and move declaration where first time needed. - Removed unnecessary intitialization of temporary buffer because we already keep track actual filled length. - Remove unneccessary extra call to charset->strnxfrm --- mysql-test/suite/galera/r/MDEV-30732.result | 627 ++++++++++++++++++++ mysql-test/suite/galera/t/MDEV-30732.test | 371 ++++++++++++ storage/innobase/handler/ha_innodb.cc | 212 +++---- storage/innobase/include/ha_prototypes.h | 9 +- storage/innobase/rem/rem0rec.cc | 14 +- 5 files changed, 1107 insertions(+), 126 deletions(-) create mode 100644 mysql-test/suite/galera/r/MDEV-30732.result create mode 100644 mysql-test/suite/galera/t/MDEV-30732.test diff --git a/mysql-test/suite/galera/r/MDEV-30732.result b/mysql-test/suite/galera/r/MDEV-30732.result new file mode 100644 index 0000000000000..e2ca79d3fda6e --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-30732.result @@ -0,0 +1,627 @@ +connection node_2; +connection node_1; +SET GLOBAL sql_mode=0; +SET sql_mode=DEFAULT; +CREATE TABLE t (c INT,c2 BLOB NOT NULL,KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +SELECT * from t; +c c2 +1 +1 +1 +1 +1 +DROP TABLE t; +CREATE TABLE t (c INT,c2 BLOB NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT,c2 BLOB NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT,c2 VARCHAR(270) NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT,c2 VARCHAR(270) NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT,c2 CHAR(80) NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +SELECT * from t; +c c2 +1 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT,c2 CHAR(80) NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +SELECT * from t; +c c2 +1 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT,c2 TEXT NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT,c2 TEXT NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 BLOB NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 BLOB NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 VARCHAR(270) NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 VARCHAR(270) NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 CHAR(80) NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +SELECT * from t; +c c2 +1 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 CHAR(80) NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +SELECT * from t; +c c2 +1 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 TEXT NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 TEXT NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +SET GLOBAL sql_mode=0; +SET sql_mode=DEFAULT; +CREATE TABLE t (c INT,c2 BLOB,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT,c2 BLOB NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 BLOB,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 NULL +3 NULL +4 NULL +5 NULL +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 BLOB NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT,c2 VARCHAR(270),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT,c2 VARCHAR(270) NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 VARCHAR(270),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 NULL +3 NULL +4 NULL +5 NULL +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 VARCHAR(270) NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT,c2 CHAR(80),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT,c2 CHAR(80) NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 CHAR(80),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 NULL +3 NULL +4 NULL +5 NULL +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 CHAR(80) NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +CREATE TABLE t (c INT,c2 TEXT,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT,c2 TEXT NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 TEXT,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 NULL +3 NULL +4 NULL +5 NULL +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 TEXT NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +Warnings: +Warning 1364 Field 'c2' doesn't have a default value +UPDATE t SET c2=NULL WHERE c = 1; +Warnings: +Warning 1048 Column 'c2' cannot be null +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 +3 +4 +5 +DROP TABLE t; +SET GLOBAL sql_mode=DEFAULT; +CREATE TABLE t (c INT,c2 BLOB,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT,c2 VARCHAR(270),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT,c2 CHAR(80),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT,c2 TEXT,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 BLOB,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 NULL +3 NULL +4 NULL +5 NULL +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 VARCHAR(270),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 NULL +3 NULL +4 NULL +5 NULL +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 CHAR(80),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 NULL +3 NULL +4 NULL +5 NULL +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 TEXT,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +c c2 +2 NULL +3 NULL +4 NULL +5 NULL +DROP TABLE t; diff --git a/mysql-test/suite/galera/t/MDEV-30732.test b/mysql-test/suite/galera/t/MDEV-30732.test new file mode 100644 index 0000000000000..68525cb02dc0b --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-30732.test @@ -0,0 +1,371 @@ +--source include/galera_cluster.inc + +# +# MDEV-30732 : wsrep_store_key_val_for_row() may invoke memcpy() on nullptr +# original test case +# +SET GLOBAL sql_mode=0; +SET sql_mode=DEFAULT; +CREATE TABLE t (c INT,c2 BLOB NOT NULL,KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +SELECT * from t; +DROP TABLE t; +# +# Additional test cases +# +CREATE TABLE t (c INT,c2 BLOB NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 BLOB NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 VARCHAR(270) NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 VARCHAR(270) NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 CHAR(80) NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 CHAR(80) NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 TEXT NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 TEXT NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; + +CREATE TABLE t (c INT PRIMARY KEY,c2 BLOB NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 BLOB NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 VARCHAR(270) NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 VARCHAR(270) NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 CHAR(80) NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 CHAR(80) NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 TEXT NOT NULL,UNIQUE KEY k2 (c2 (1),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; +CREATE TABLE t (c INT PRIMARY KEY,c2 TEXT NOT NULL,KEY k2 (c, c2 (1))) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * from t; +DROP TABLE t; + +SET GLOBAL sql_mode=0; +SET sql_mode=DEFAULT; +CREATE TABLE t (c INT,c2 BLOB,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 BLOB NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 BLOB,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 BLOB NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 VARCHAR(270),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 VARCHAR(270) NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 VARCHAR(270),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 VARCHAR(270) NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 CHAR(80),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 CHAR(80) NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 CHAR(80),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 CHAR(80) NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="" WHERE c=1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 TEXT,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 TEXT NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 TEXT,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 TEXT NOT NULL,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; + +SET GLOBAL sql_mode=DEFAULT; + +CREATE TABLE t (c INT,c2 BLOB,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 VARCHAR(270),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 CHAR(80),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT,c2 TEXT,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(1),(1),(1),(1); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; + +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 BLOB,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 VARCHAR(270),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 CHAR(80),KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; +CREATE TABLE t (c INT NOT NULL PRIMARY KEY,c2 TEXT,KEY k2 (c2 (6),c)) DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT; +INSERT INTO t (c) VALUES (1),(2),(3),(4),(5); +UPDATE t SET c2=NULL WHERE c = 1; +UPDATE t SET c2="TESTtest" WHERE c = 1; +UPDATE t SET c2="BUGbug" WHERE c2 = "TESTtest"; +DELETE FROM t WHERE c2="BUGbug"; +SELECT * FROM t; +DROP TABLE t; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ada50c1b409d7..00ac0223a3c6a 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6220,25 +6220,22 @@ ha_innobase::close() /* The following accessor functions should really be inside MySQL code! */ #ifdef WITH_WSREP -ulint -wsrep_innobase_mysql_sort( - /* out: str contains sort string */ +size_t +wsrep_normalize_string( int mysql_type, /* in: MySQL type */ uint charset_number, /* in: number of the charset */ - unsigned char* str, /* in: data field */ - ulint str_length, /* in: data field length, + const unsigned char* str, /* in: input data field */ + unsigned char* out_str, /* out: normalized string */ + size_t str_length, /* in: data field length, not UNIV_SQL_NULL */ - ulint buf_length) /* in: total str buffer length */ + size_t buf_length) /* in: total str buffer length */ { - CHARSET_INFO* charset; - enum_field_types mysql_tp; - ulint ret_length = str_length; + size_t ret_length= str_length; + const enum_field_types mysql_tp= (enum_field_types)mysql_type; DBUG_ASSERT(str_length != UNIV_SQL_NULL); - mysql_tp = (enum_field_types) mysql_type; - switch (mysql_tp) { case MYSQL_TYPE_BIT: @@ -6250,8 +6247,7 @@ wsrep_innobase_mysql_sort( case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_VARCHAR: { - uchar tmp_str[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; - ulint tmp_length = REC_VERSION_56_MAX_INDEX_COL_LEN; + CHARSET_INFO* charset; /* Use the charset number to pick the right charset struct for the comparison. Since the MySQL function get_charset may be @@ -6266,36 +6262,26 @@ wsrep_innobase_mysql_sort( charset = get_charset(charset_number, MYF(MY_WME)); if (charset == NULL) { - sql_print_error("InnoDB needs charset %lu for doing " - "a comparison, but MariaDB cannot " - "find that charset.", - (ulong) charset_number); + sql_print_error("InnoDB needs charset %lu for doing " + "a comparison, but MariaDB cannot " + "find that charset.", + (ulong) charset_number); ut_a(0); } } - ut_a(str_length <= tmp_length); - memcpy(tmp_str, str, str_length); - - tmp_length = charset->strnxfrm(str, str_length, - uint(str_length), tmp_str, - tmp_length, 0); - DBUG_ASSERT(tmp_length <= str_length); if (wsrep_protocol_version < 3) { - tmp_length = charset->strnxfrm( - str, str_length, - uint(str_length), tmp_str, tmp_length, 0); - DBUG_ASSERT(tmp_length <= str_length); + ret_length = charset->strnxfrm( + out_str, str_length, + uint(str_length), str, buf_length, 0); } else { /* strnxfrm will expand the destination string, - protocols < 3 truncated the sorted sring - protocols >= 3 gets full sorted sring + protocols < 3 truncated the normalized string + protocols >= 3 gets full normalized string */ - tmp_length = charset->strnxfrm( - str, buf_length, - uint(str_length), tmp_str, str_length, 0); - DBUG_ASSERT(tmp_length <= buf_length); - ret_length = tmp_length; + ret_length = charset->strnxfrm( + out_str, buf_length, + uint(str_length), str, str_length, 0); } break; @@ -6665,8 +6651,6 @@ wsrep_store_key_val_for_row( KEY_PART_INFO* key_part = key_info->key_part; KEY_PART_INFO* end = key_part + key_info->user_defined_key_parts; char* buff_start = buff; - enum_field_types mysql_type; - Field* field; ulint buff_space = buff_len; DBUG_ENTER("wsrep_store_key_val_for_row"); @@ -6675,8 +6659,8 @@ wsrep_store_key_val_for_row( *key_is_null = true; for (; key_part != end; key_part++) { - uchar sorted[REC_VERSION_56_MAX_INDEX_COL_LEN] = {'\0'}; - bool part_is_null = false; + uchar normalized[REC_VERSION_56_MAX_INDEX_COL_LEN+1]; + bool part_is_null= false; if (key_part->null_bit) { if (buff_space > 0) { @@ -6696,23 +6680,15 @@ wsrep_store_key_val_for_row( } if (!part_is_null) *key_is_null = false; - field = key_part->field; - mysql_type = field->type(); + const Field* field= key_part->field; + const enum_field_types mysql_type= field->type(); if (mysql_type == MYSQL_TYPE_VARCHAR) { /* >= 5.0.3 true VARCHAR */ - ulint lenlen; - ulint len; - const byte* data; - ulint key_len; - ulint true_len; - const CHARSET_INFO* cs; - int error=0; - - key_len = key_part->length; + const size_t key_len= key_part->length; if (part_is_null) { - true_len = key_len + 2; + size_t true_len= key_len + 2; if (true_len > buff_space) { fprintf (stderr, "WSREP: key truncated: %s\n", @@ -6723,27 +6699,28 @@ wsrep_store_key_val_for_row( buff_space -= true_len; continue; } - cs = field->charset(); + const CHARSET_INFO* cs = field->charset(); - lenlen = (ulint) + ulint lenlen = (ulint) (((Field_varstring*)field)->length_bytes); - data = row_mysql_read_true_varchar(&len, + size_t len; + const byte* data = row_mysql_read_true_varchar(&len, (byte*) (record + (ulint)get_field_offset(table, field)), lenlen); - true_len = len; + size_t true_len= len; /* For multi byte character sets we need to calculate the true length of the key */ if (len > 0 && cs->mbmaxlen > 1) { - true_len = (ulint) my_well_formed_length(cs, + int error; + true_len= my_well_formed_length(cs, (const char *) data, (const char *) data + len, - (uint) (key_len / - cs->mbmaxlen), + (key_len / cs->mbmaxlen), &error); } @@ -6752,16 +6729,21 @@ wsrep_store_key_val_for_row( if (true_len > key_len) { true_len = key_len; } - /* cannot exceed max column lenght either, we may need to truncate + /* cannot exceed max column length either, we may need to truncate the stored value: */ - if (true_len > sizeof(sorted)) { - true_len = sizeof(sorted); + if (true_len >= sizeof(normalized)) { + true_len = sizeof(normalized) - 1; + } + + /* Normalize string if is not empty string */ + if (true_len) { + ut_ad(data); + true_len= wsrep_normalize_string( + mysql_type, cs->number, data, + normalized, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); } - memcpy(sorted, data, true_len); - true_len = wsrep_innobase_mysql_sort( - mysql_type, cs->number, sorted, true_len, - REC_VERSION_56_MAX_INDEX_COL_LEN); if (wsrep_protocol_version > 1) { /* Note that we always reserve the maximum possible length of the true VARCHAR in the key value, though @@ -6774,7 +6756,7 @@ wsrep_store_key_val_for_row( wsrep_thd_query(thd)); true_len = buff_space; } - memcpy(buff, sorted, true_len); + memcpy(buff, normalized, true_len); buff += true_len; buff_space -= true_len; } else { @@ -6788,19 +6770,11 @@ wsrep_store_key_val_for_row( as BLOB data in innodb. */ || mysql_type == MYSQL_TYPE_GEOMETRY) { - const CHARSET_INFO* cs; - ulint key_len; - ulint true_len; - int error=0; - ulint blob_len; - const byte* blob_data; - + const size_t key_len= key_part->length; ut_a(key_part->key_part_flag & HA_PART_KEY_SEG); - key_len = key_part->length; - if (part_is_null) { - true_len = key_len + 2; + size_t true_len= key_len + 2; if (true_len > buff_space) { fprintf (stderr, "WSREP: key truncated: %s\n", @@ -6813,14 +6787,15 @@ wsrep_store_key_val_for_row( continue; } - cs = field->charset(); + const CHARSET_INFO* cs= field->charset(); - blob_data = row_mysql_read_blob_ref(&blob_len, + size_t blob_len; + const byte* blob_data = row_mysql_read_blob_ref(&blob_len, (byte*) (record + (ulint)get_field_offset(table, field)), (ulint) field->pack_length()); - true_len = blob_len; + size_t true_len= blob_len; ut_a(get_field_offset(table, field) == key_part->offset); @@ -6829,12 +6804,13 @@ wsrep_store_key_val_for_row( the true length of the key */ if (blob_len > 0 && cs->mbmaxlen > 1) { - true_len = (ulint) my_well_formed_length(cs, + int error; + + true_len= my_well_formed_length(cs, (const char *) blob_data, (const char *) blob_data + blob_len, - (uint) (key_len / - cs->mbmaxlen), + (key_len / cs->mbmaxlen), &error); } @@ -6846,11 +6822,16 @@ wsrep_store_key_val_for_row( true_len = key_len; } - memcpy(sorted, blob_data, true_len); - true_len = wsrep_innobase_mysql_sort( - mysql_type, cs->number, sorted, true_len, - REC_VERSION_56_MAX_INDEX_COL_LEN); - + /* Normalize string if it is not empty string. + When true_len == 0 blob_data is not always + nullptr it may be empty string i.e. "" */ + if (true_len) { + ut_ad(blob_data); + true_len= wsrep_normalize_string( + mysql_type, cs->number, blob_data, + normalized, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + } /* Note that we always reserve the maximum possible length of the BLOB prefix in the key value. */ @@ -6866,24 +6847,15 @@ wsrep_store_key_val_for_row( } else { buff += key_len; } - memcpy(buff, sorted, true_len); + memcpy(buff, normalized, true_len); } else { /* Here we handle all other data types except the true VARCHAR, BLOB and TEXT. Note that the column value we store may be also in a column prefix index. */ - const CHARSET_INFO* cs = NULL; - ulint true_len; - ulint key_len; - const uchar* src_start; - int error=0; - enum_field_types real_type; - - key_len = key_part->length; - if (part_is_null) { - true_len = key_len; + size_t true_len= key_part->length; if (true_len > buff_space) { fprintf (stderr, "WSREP: key truncated: %s\n", @@ -6896,9 +6868,9 @@ wsrep_store_key_val_for_row( continue; } - src_start = record + key_part->offset; - real_type = field->real_type(); - true_len = key_len; + const uchar* src_start= record + key_part->offset; + const enum_field_types real_type= field->real_type(); + size_t true_len= key_part->length; /* Character set for the field is defined only to fields whose type is string and real field @@ -6910,26 +6882,32 @@ wsrep_store_key_val_for_row( && ( mysql_type == MYSQL_TYPE_VAR_STRING || mysql_type == MYSQL_TYPE_STRING)) { - cs = field->charset(); + const CHARSET_INFO* cs= field->charset(); /* For multi byte character sets we need to calculate the true length of the key */ - if (key_len > 0 && cs->mbmaxlen > 1) { + if (true_len > 0 && cs->mbmaxlen > 1) { + int error; - true_len = (ulint) - my_well_formed_length(cs, + true_len= my_well_formed_length(cs, (const char *)src_start, (const char *)src_start - + key_len, - (uint) (key_len / - cs->mbmaxlen), + + true_len, + (true_len / cs->mbmaxlen), &error); } - memcpy(sorted, src_start, true_len); - true_len = wsrep_innobase_mysql_sort( - mysql_type, cs->number, sorted, true_len, - REC_VERSION_56_MAX_INDEX_COL_LEN); + + /* Normalize string if it is not empty string */ + if (true_len) { + ut_ad(src_start); + true_len= wsrep_normalize_string( + mysql_type, cs->number, + src_start, normalized, true_len, + REC_VERSION_56_MAX_INDEX_COL_LEN); + } else { + ut_ad(src_start == nullptr); + } if (true_len > buff_space) { fprintf (stderr, @@ -6937,9 +6915,15 @@ wsrep_store_key_val_for_row( wsrep_thd_query(thd)); true_len = buff_space; } - memcpy(buff, sorted, true_len); + memcpy(buff, normalized, true_len); } else { - memcpy(buff, src_start, true_len); + /* Copy only if there is data */ + if (true_len) { + ut_ad(src_start); + memcpy(buff, src_start, true_len); + } else { + ut_ad(src_start == nullptr); + } } buff += true_len; buff_space -= true_len; diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 35a93f32ea3d2..34d1c9fb7a71b 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -148,9 +148,12 @@ innobase_basename( const char* path_name); #ifdef WITH_WSREP -ulint wsrep_innobase_mysql_sort(int mysql_type, uint charset_number, - unsigned char* str, ulint str_length, - ulint buf_length); +size_t wsrep_normalize_string(int mysql_type, + uint charset_number, + const unsigned char* str, + unsigned char* out_str, + ulint str_length, + ulint buf_length); #endif /* WITH_WSREP */ /** Get high resolution timestamp for the current query start time. diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index 47be5e447f546..6480c0358ed35 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -2733,11 +2733,10 @@ wsrep_rec_get_foreign_key( *buf++ = 0; key_len++; } - memcpy(buf, data, len); - *buf_len = wsrep_innobase_mysql_sort( + *buf_len = wsrep_normalize_string( (int)(col_f->prtype & DATA_MYSQL_TYPE_MASK), dtype_get_charset_coll(col_f->prtype), - buf, static_cast(len), + data, buf, static_cast(len), static_cast(*buf_len)); } else { /* new protocol */ if (!(col_r->prtype & DATA_NOT_NULL)) { @@ -2766,13 +2765,10 @@ wsrep_rec_get_foreign_key( case DATA_VARMYSQL: case DATA_CHAR: case DATA_MYSQL: - /* Copy the actual data */ - memcpy(buf, data, len); - len = wsrep_innobase_mysql_sort( - (int) - (col_f->prtype & DATA_MYSQL_TYPE_MASK), + len = wsrep_normalize_string( + (int)(col_f->prtype & DATA_MYSQL_TYPE_MASK), dtype_get_charset_coll(col_f->prtype), - buf, len, *buf_len); + data, buf, len, *buf_len); break; case DATA_BLOB: case DATA_BINARY: