Re: [Maria-developers] bb2db687a05: 26 aug (MDEV-371 Unique indexes for blobs)
Hi, Sachin! Could you please explain what you store in the frm file and how you modify keyinfo/keypart structures in memory? Needs to be tested with partitioned tables. Particularly with MDEV-14005. Tests were great and thourough, good job. It'd be useful to have at least some tests for innodb too, though. See other comments below. On Oct 08, Sachin Setiya wrote:
diff --git a/mysql-test/main/long_unique.result b/mysql-test/main/long_unique.result new file mode 100644 index 00000000000..1a06c230c72 --- /dev/null +++ b/mysql-test/main/long_unique.result @@ -0,0 +1,1391 @@ +#Structure of tests +#First we will check all option for +#table containing single unique column +#table containing keys like unique(a,b,c,d) etc +#then table containing 2 blob unique etc +set @allowed_packet= @@max_allowed_packet; +#table with single long blob column; +create table t1(a blob unique); +insert into t1 values(1),(2),(3),(56),('sachin'),('maria'),(123456789034567891),(null),(null),(123456789034567890); +#table structure; +desc t1; +Field Type Null Key Default Extra +a blob YES UNI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + UNIQUE KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table t1 +Non_unique 0 +Key_name a +Seq_in_index 1 +Column_name a +Collation A +Cardinality NULL +Sub_part NULL +Packed NULL +Null YES +Index_type HASH_INDEX
I'm not sure about it. One cannot write UNIQUE (a) USING HASH_INDEX in CREATE TABLE, right? May be just report HASH here? (and fix the parser to behave accordingly)
+Comment +Index_comment + +MyISAM file: DATADIR/test/t1 +Record format: Packed +Character set: latin1_swedish_ci (8) +Data records: 10 Deleted blocks: 0 +Recordlength: 20 + +table description: +Key Start Len Index Type +1 12 8 multip. ulonglong NULL
good idea
+select * from information_schema.columns where table_schema = 'test' and table_name = 't1'; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE DATETIME_PRECISION CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT IS_GENERATED GENERATION_EXPRESSION +def test t1 a 1 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob UNI select,insert,update,references NEVER NULL +select * from information_schema.statistics where table_schema = 'test' and table_name = 't1'; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT +def test t1 0 test a 1 a A NULL NULL NULL YES HASH_INDEX +select * from information_schema.key_column_usage where table_schema= 'test' and table_name= 't1'; +CONSTRAINT_CATALOG def +CONSTRAINT_SCHEMA test +CONSTRAINT_NAME a +TABLE_CATALOG def +TABLE_SCHEMA test +TABLE_NAME t1 +COLUMN_NAME a +ORDINAL_POSITION 1 +POSITION_IN_UNIQUE_CONSTRAINT NULL +REFERENCED_TABLE_SCHEMA NULL +REFERENCED_TABLE_NAME NULL +REFERENCED_COLUMN_NAME NULL +# table select we should not be able to see db_row_hash_column; +select * from t1; +a +1 +2 +3 +56 +sachin +maria +123456789034567891 +NULL +NULL +123456789034567890 +select db_row_hash_1 from t1; +ERROR 42S22: Unknown column 'db_row_hash_1' in 'field list' +#duplicate entry test; +insert into t1 values(2); +ERROR 23000: Duplicate entry '2' for key 'a' +insert into t1 values('sachin'); +ERROR 23000: Duplicate entry 'sachin' for key 'a' +insert into t1 values(123456789034567891); +ERROR 23000: Duplicate entry '123456789034567891' for key 'a'
looks great :)
+select * from t1; +a +1 +2 +3 +56 +sachin +maria +123456789034567891 +NULL +NULL +123456789034567890 +insert into t1 values(11),(22),(33); +insert into t1 values(12),(22); +ERROR 23000: Duplicate entry '22' for key 'a' +select * from t1; +a +1 +2 +3 +56 +sachin +maria +123456789034567891 +NULL +NULL +123456789034567890 +11 +22 +33 +12 +insert into t1 values(repeat('s',4000*10)),(repeat('s',4001*10)); +insert into t1 values(repeat('m',4000*10)),(repeat('m',4000*10)); +ERROR 23000: Duplicate entry 'mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm' for key 'a' +insert into t1 values(repeat('m',4001)),(repeat('m',4002)); +truncate table t1; +insert into t1 values(1),(2),(3),(4),(5),(8),(7); + +MyISAM file: DATADIR/test/t1 +Record format: Packed +Character set: latin1_swedish_ci (8) +Data records: 7 Deleted blocks: 0 +Recordlength: 20 + +table description: +Key Start Len Index Type +1 12 8 multip. ulonglong NULL +#now some alter commands; +alter table t1 add column b int; +desc t1; +Field Type Null Key Default Extra +a blob YES UNI NULL +b int(11) YES NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` int(11) DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535))
I think there shouldn't be (65535) here
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 values(1,2); +ERROR 23000: Duplicate entry '1' for key 'a' +insert into t1 values(2,2); +ERROR 23000: Duplicate entry '2' for key 'a' +select db_row_hash_1 from t1; +ERROR 42S22: Unknown column 'db_row_hash_1' in 'field list' +#now try to change db_row_hash_1 column; +alter table t1 drop column db_row_hash_1; +ERROR 42000: Can't DROP COLUMN `db_row_hash_1`; check that it exists +alter table t1 add column d int , add column e int , drop column db_row_hash_1; +ERROR 42000: Can't DROP COLUMN `db_row_hash_1`; check that it exists +alter table t1 modify column db_row_hash_1 int ; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 add column a int , add column b int, modify column db_row_hash_1 int ; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 change column db_row_hash_1 dsds int; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 add column asd int, change column db_row_hash_1 dsds int; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 drop column b , add column c int; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `c` int(11) DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +#now add some column with name db_row_hash; +alter table t1 add column db_row_hash_1 int unique; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `c` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535)), + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 values(45,1,55),(46,1,55); +ERROR 23000: Duplicate entry '55' for key 'db_row_hash_1' +alter table t1 add column db_row_hash_2 int, add column db_row_hash_3 int; +desc t1; +Field Type Null Key Default Extra +a blob YES UNI NULL +c int(11) YES NULL +db_row_hash_1 int(11) YES UNI NULL +db_row_hash_2 int(11) YES NULL +db_row_hash_3 int(11) YES NULL +#this should also drop the unique index ; +alter table t1 drop column a; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_3` int(11) DEFAULT NULL, + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE +#add column with unique index on blob ; +alter table t1 add column a blob unique; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_3` int(11) DEFAULT NULL, + `a` blob DEFAULT NULL, + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +# try to change the blob unique column name; +#this will change index to b tree; +alter table t1 modify column a int ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_3` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL, + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE +t1 0 a 1 a A NULL NULL NULL YES BTREE +alter table t1 add column clm blob unique; +#try changing the name ; +alter table t1 change column clm clm_changed blob; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_3` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL, + `clm_changed` blob DEFAULT NULL, + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `a` (`a`), + UNIQUE KEY `clm` (`clm_changed`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 0 clm 1 clm_changed A NULL NULL NULL YES HASH_INDEX +#now drop the unique key; +alter table t1 drop key clm; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_3` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL, + `clm_changed` blob DEFAULT NULL, + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE +t1 0 a 1 a A NULL NULL NULL YES BTREE +drop table t1; +create table t1 (a TEXT CHARSET latin1 COLLATE latin1_german2_ci unique); +desc t1; +Field Type Null Key Default Extra +a text YES UNI NULL +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES HASH_INDEX +insert into t1 values ('ae'); +insert into t1 values ('AE'); +ERROR 23000: Duplicate entry 'AE' for key 'a' +insert into t1 values ('Ä');
this should've failed, shouldn't it?
+drop table t1; +create table t1 (a int primary key, b blob unique); +desc t1; +Field Type Null Key Default Extra +a int(11) NO PRI NULL +b blob YES UNI NULL +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 a A 0 NULL NULL BTREE +t1 0 b 1 b A NULL NULL NULL YES HASH_INDEX +insert into t1 values(1,1),(2,2),(3,3); +insert into t1 values(1,1); +ERROR 23000: Duplicate entry '1' for key 'b' +insert into t1 values(7,1); +ERROR 23000: Duplicate entry '1' for key 'b' +drop table t1; +#table with multiple long blob column and varchar text column ; +create table t1(a blob unique, b int , c blob unique , d text unique , e varchar(3000) unique); +insert into t1 values(1,2,3,4,5),(2,11,22,33,44),(3111,222,333,444,555),(5611,2222,3333,4444,5555), +('sachin',341,'fdf','gfgfgfg','hghgr'),('maria',345,'frter','dasd','utyuty'), +(123456789034567891,353534,53453453453456,64565464564564,45435345345345), +(123456789034567890,43545,657567567567,78967657567567,657567567567567676); +#table structure; +desc t1; +Field Type Null Key Default Extra +a blob YES UNI NULL +b int(11) YES NULL +c blob YES UNI NULL +d text YES UNI NULL +e varchar(3000) YES UNI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` blob DEFAULT NULL, + `d` text DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + UNIQUE KEY `a` (`a`), + UNIQUE KEY `c` (`c`), + UNIQUE KEY `d` (`d`), + UNIQUE KEY `e` (`e`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES HASH_INDEX +t1 0 c 1 c A NULL NULL NULL YES HASH_INDEX +t1 0 d 1 d A NULL NULL NULL YES HASH_INDEX +t1 0 e 1 e A NULL NULL NULL YES HASH_INDEX + +MyISAM file: DATADIR/test/t1 +Record format: Packed +Character set: latin1_swedish_ci (8) +Data records: 8 Deleted blocks: 0 +Recordlength: 3072 + +table description: +Key Start Len Index Type +1 3063 8 multip. ulonglong NULL +2 3055 8 multip. ulonglong NULL +3 3047 8 multip. ulonglong NULL +4 3039 8 multip. ulonglong prefix NULL
why "prefix" here? how is it different from others?
+select * from information_schema.columns where table_schema = 'test' and table_name = 't1'; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE DATETIME_PRECISION CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT IS_GENERATED GENERATION_EXPRESSION +def test t1 a 1 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob UNI select,insert,update,references NEVER NULL +def test t1 b 2 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL +def test t1 c 3 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob UNI select,insert,update,references NEVER NULL +def test t1 d 4 NULL YES text 65535 65535 NULL NULL NULL latin1 latin1_swedish_ci text UNI select,insert,update,references NEVER NULL +def test t1 e 5 NULL YES varchar 3000 3000 NULL NULL NULL latin1 latin1_swedish_ci varchar(3000) UNI select,insert,update,references NEVER NULL +select * from information_schema.statistics where table_schema = 'test' and table_name = 't1'; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT +def test t1 0 test a 1 a A NULL NULL NULL YES HASH_INDEX +def test t1 0 test c 1 c A NULL NULL NULL YES HASH_INDEX +def test t1 0 test d 1 d A NULL NULL NULL YES HASH_INDEX +def test t1 0 test e 1 e A NULL NULL NULL YES HASH_INDEX +select * from information_schema.key_column_usage where table_schema= 'test' and table_name= 't1'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION POSITION_IN_UNIQUE_CONSTRAINT REFERENCED_TABLE_SCHEMA REFERENCED_TABLE_NAME REFERENCED_COLUMN_NAME +def test a def test t1 a 1 NULL NULL NULL NULL +def test c def test t1 c 1 NULL NULL NULL NULL +def test d def test t1 d 1 NULL NULL NULL NULL +def test e def test t1 e 1 NULL NULL NULL NULL +#table select we should not be able to see db_row_hash_1 column; +select * from t1; +a b c d e +1 2 3 4 5 +2 11 22 33 44 +3111 222 333 444 555 +5611 2222 3333 4444 5555 +sachin 341 fdf gfgfgfg hghgr +maria 345 frter dasd utyuty +123456789034567891 353534 53453453453456 64565464564564 45435345345345 +123456789034567890 43545 657567567567 78967657567567 657567567567567676 +select db_row_hash_1 from t1; +ERROR 42S22: Unknown column 'db_row_hash_1' in 'field list' +select db_row_hash_2 from t1; +ERROR 42S22: Unknown column 'db_row_hash_2' in 'field list' +select db_row_hash_3 from t1; +ERROR 42S22: Unknown column 'db_row_hash_3' in 'field list' +#duplicate entry test; +insert into t1 values(21,2,3,42,51); +ERROR 23000: Duplicate entry '3' for key 'c' +insert into t1 values('sachin',null,null,null,null); +ERROR 23000: Duplicate entry 'sachin' for key 'a' +insert into t1 values(1234567890345671890,4353451,6575675675617,789676575675617,657567567567567676); +ERROR 23000: Duplicate entry '657567567567567676' for key 'e' +select * from t1; +a b c d e +1 2 3 4 5 +2 11 22 33 44 +3111 222 333 444 555 +5611 2222 3333 4444 5555 +sachin 341 fdf gfgfgfg hghgr +maria 345 frter dasd utyuty +123456789034567891 353534 53453453453456 64565464564564 45435345345345 +123456789034567890 43545 657567567567 78967657567567 657567567567567676 +insert into t1 values(repeat('s',4000*10),100,repeat('s',4000*10),repeat('s',4000*10), +repeat('s',400)),(repeat('s',4001*10),1000,repeat('s',4001*10),repeat('s',4001*10), +repeat('s',2995)); +insert into t1 values(repeat('m',4000*11),10,repeat('s',4000*11),repeat('s',4000*11),repeat('s',2995)); +ERROR 23000: Duplicate entry 'ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss' for key 'e' +truncate table t1; +insert into t1 values(1,2,3,4,5),(2,11,22,33,44),(3111,222,333,444,555),(5611,2222,3333,4444,5555); +#now some alter commands; +alter table t1 add column f int; +desc t1; +Field Type Null Key Default Extra +a blob YES UNI NULL +b int(11) YES NULL +c blob YES UNI NULL +d text YES UNI NULL +e varchar(3000) YES UNI NULL +f int(11) YES NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` blob DEFAULT NULL, + `d` text DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` int(11) DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535)), + UNIQUE KEY `c` (`c`(65535)), + UNIQUE KEY `d` (`d`(65535)), + UNIQUE KEY `e` (`e`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +#unique key should not break; +insert into t1 values(1,2,3,4,5,6); +ERROR 23000: Duplicate entry '1' for key 'a' +select db_row_hash_1 , db_row_hash_2, db_row_hash_3 from t1; +ERROR 42S22: Unknown column 'db_row_hash_1' in 'field list' +#now try to change db_row_hash_1 column; +alter table t1 drop column db_row_hash_1, drop column db_row_hash_2, drop column db_row_hash_3; +ERROR 42000: Can't DROP COLUMN `db_row_hash_1`; check that it exists +alter table t1 add column dg int , add column ef int , drop column db_row_hash_1; +ERROR 42000: Can't DROP COLUMN `db_row_hash_1`; check that it exists +alter table t1 modify column db_row_hash_1 int , modify column db_row_hash_2 int, modify column db_row_hash_3 int; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 add column ar int , add column rb int, modify column db_row_hash_1 int , modify column db_row_hash_3 int; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 change column db_row_hash_1 dsds int , change column db_row_hash_2 dfdf int , change column db_row_hash_3 gdfg int ; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 add column asd int, drop column a, change column db_row_hash_1 dsds int, change db_row_hash_3 fdfdfd int; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 drop column b , add column g int; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `c` blob DEFAULT NULL, + `d` text DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` int(11) DEFAULT NULL, + `g` int(11) DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535)), + UNIQUE KEY `c` (`c`(65535)), + UNIQUE KEY `d` (`d`(65535)), + UNIQUE KEY `e` (`e`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +#now add some column with name db_row_hash; +alter table t1 add column db_row_hash_1 int unique; +alter table t1 add column db_row_hash_2 int unique; +alter table t1 add column db_row_hash_3 int unique; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `c` blob DEFAULT NULL, + `d` text DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` int(11) DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_3` int(11) DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535)), + UNIQUE KEY `c` (`c`(65535)), + UNIQUE KEY `d` (`d`(65535)), + UNIQUE KEY `e` (`e`), + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`), + UNIQUE KEY `db_row_hash_3` (`db_row_hash_3`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +alter table t1 add column db_row_hash_7 int, add column db_row_hash_5 int , add column db_row_hash_4 int ; +alter table t1 drop column db_row_hash_7,drop column db_row_hash_3, drop column db_row_hash_4; +desc t1; +Field Type Null Key Default Extra +a blob YES UNI NULL +c blob YES UNI NULL +d text YES UNI NULL +e varchar(3000) YES UNI NULL +f int(11) YES NULL +g int(11) YES NULL +db_row_hash_1 int(11) YES UNI NULL +db_row_hash_2 int(11) YES UNI NULL +db_row_hash_5 int(11) YES NULL +#this show now break anything;
"this should not" ?
+insert into t1 values(1,2,3,4,5,6,23,5,6); +ERROR 23000: Duplicate entry '1' for key 'a' +#this should also drop the unique index; +alter table t1 drop column a, drop column c; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `d` text DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` int(11) DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_5` int(11) DEFAULT NULL, + UNIQUE KEY `d` (`d`(65535)), + UNIQUE KEY `e` (`e`), + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 d 1 d A NULL 65535 NULL YES HASH_INDEX +t1 0 e 1 e A NULL NULL NULL YES HASH_INDEX +t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE +t1 0 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE +#add column with unique index on blob; +alter table t1 add column a blob unique; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `d` text DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` int(11) DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_5` int(11) DEFAULT NULL, + `a` blob DEFAULT NULL, + UNIQUE KEY `d` (`d`(65535)), + UNIQUE KEY `e` (`e`), + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`), + UNIQUE KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 d 1 d A NULL 65535 NULL YES HASH_INDEX +t1 0 e 1 e A NULL NULL NULL YES HASH_INDEX +t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE +t1 0 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE +t1 0 a 1 a A NULL NULL NULL YES HASH_INDEX +#try to change the blob unique column name; +#this will change index to b tree; +alter table t1 modify column a int , modify column e int; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `d` text DEFAULT NULL, + `e` int(11) DEFAULT NULL, + `f` int(11) DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_5` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL, + UNIQUE KEY `d` (`d`(65535)), + UNIQUE KEY `e` (`e`), + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`), + UNIQUE KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 d 1 d A NULL 65535 NULL YES HASH_INDEX +t1 0 e 1 e A NULL NULL NULL YES BTREE +t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE +t1 0 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE +t1 0 a 1 a A NULL NULL NULL YES BTREE +alter table t1 add column clm1 blob unique,add column clm2 blob unique; +#try changing the name; +alter table t1 change column clm1 clm_changed1 blob, change column clm2 clm_changed2 blob; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `d` text DEFAULT NULL, + `e` int(11) DEFAULT NULL, + `f` int(11) DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_5` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL, + `clm_changed1` blob DEFAULT NULL, + `clm_changed2` blob DEFAULT NULL, + UNIQUE KEY `d` (`d`(65535)), + UNIQUE KEY `e` (`e`), + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`), + UNIQUE KEY `a` (`a`), + UNIQUE KEY `clm1` (`clm_changed1`), + UNIQUE KEY `clm2` (`clm_changed2`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 d 1 d A NULL 65535 NULL YES HASH_INDEX +t1 0 e 1 e A NULL NULL NULL YES BTREE +t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE +t1 0 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 0 clm1 1 clm_changed1 A NULL NULL NULL YES HASH_INDEX +t1 0 clm2 1 clm_changed2 A NULL NULL NULL YES HASH_INDEX +#now drop the unique key; +alter table t1 drop key clm1, drop key clm2; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `d` text DEFAULT NULL, + `e` int(11) DEFAULT NULL, + `f` int(11) DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + `db_row_hash_5` int(11) DEFAULT NULL, + `a` int(11) DEFAULT NULL, + `clm_changed1` blob DEFAULT NULL, + `clm_changed2` blob DEFAULT NULL, + UNIQUE KEY `d` (`d`(65535)), + UNIQUE KEY `e` (`e`), + UNIQUE KEY `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`), + UNIQUE KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 d 1 d A NULL 65535 NULL YES HASH_INDEX +t1 0 e 1 e A NULL NULL NULL YES BTREE +t1 0 db_row_hash_1 1 db_row_hash_1 A NULL NULL NULL YES BTREE +t1 0 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE +t1 0 a 1 a A NULL NULL NULL YES BTREE +drop table t1; +#now the table with key on multiple columns; the ultimate test; +create table t1(a blob, b int , c varchar(2000) , d text , e varchar(3000) , f longblob , g int , h text , +unique(a,b,c), unique(c,d,e),unique(e,f,g,h), unique(b,d,g,h)); +insert into t1 values(1,1,1,1,1,1,1,1),(2,2,2,2,2,2,2,2),(3,3,3,3,3,3,3,3),(4,4,4,4,4,4,4,4),(5,5,5,5,5,5,5,5), +('maria',6,'maria','maria','maria','maria',6,'maria'),('mariadb',7,'mariadb','mariadb','mariadb','mariadb',8,'mariadb') +,(null,null,null,null,null,null,null,null),(null,null,null,null,null,null,null,null); +#table structure; +desc t1; +Field Type Null Key Default Extra +a blob YES MUL NULL +b int(11) YES MUL NULL +c varchar(2000) YES MUL NULL +d text YES NULL +e varchar(3000) YES MUL NULL +f longblob YES NULL +g int(11) YES NULL +h text YES NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` varchar(2000) DEFAULT NULL, + `d` text DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + UNIQUE KEY `a` (`a`,`b`,`c`), + UNIQUE KEY `c` (`c`,`d`,`e`), + UNIQUE KEY `e` (`e`,`f`,`g`,`h`), + UNIQUE KEY `b` (`b`,`d`,`g`,`h`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES HASH_INDEX +t1 0 a 2 b A NULL NULL NULL YES HASH_INDEX +t1 0 a 3 c A NULL NULL NULL YES HASH_INDEX +t1 0 c 1 c A NULL NULL NULL YES HASH_INDEX +t1 0 c 2 d A 0 NULL NULL YES HASH_INDEX +t1 0 c 3 e A 0 NULL NULL YES HASH_INDEX +t1 0 e 1 e A 0 NULL NULL YES HASH_INDEX +t1 0 e 2 f A 0 NULL NULL YES HASH_INDEX +t1 0 e 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 e 4 h A 0 NULL NULL YES HASH_INDEX +t1 0 b 1 b A 0 NULL NULL YES HASH_INDEX +t1 0 b 2 d A 0 NULL NULL YES HASH_INDEX +t1 0 b 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 b 4 h A 0 NULL NULL YES HASH_INDEX + +MyISAM file: DATADIR/test/t1 +Record format: Packed +Character set: latin1_swedish_ci (8) +Data records: 9 Deleted blocks: 0 +Recordlength: 5092 + +table description: +Key Start Len Index Type +1 5081 8 multip. ulonglong prefix NULL +2 5073 8 multip. ulonglong prefix NULL +3 5065 8 multip. ulonglong prefix NULL +4 5057 8 multip. ulonglong NULL +select * from information_schema.columns where table_schema = 'test' and table_name = 't1'; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE DATETIME_PRECISION CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT IS_GENERATED GENERATION_EXPRESSION +def test t1 a 1 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob MUL select,insert,update,references NEVER NULL +def test t1 b 2 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) MUL select,insert,update,references NEVER NULL +def test t1 c 3 NULL YES varchar 2000 2000 NULL NULL NULL latin1 latin1_swedish_ci varchar(2000) MUL select,insert,update,references NEVER NULL +def test t1 d 4 NULL YES text 65535 65535 NULL NULL NULL latin1 latin1_swedish_ci text select,insert,update,references NEVER NULL +def test t1 e 5 NULL YES varchar 3000 3000 NULL NULL NULL latin1 latin1_swedish_ci varchar(3000) MUL select,insert,update,references NEVER NULL +def test t1 f 6 NULL YES longblob 4294967295 4294967295 NULL NULL NULL NULL NULL longblob select,insert,update,references NEVER NULL +def test t1 g 7 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL +def test t1 h 8 NULL YES text 65535 65535 NULL NULL NULL latin1 latin1_swedish_ci text select,insert,update,references NEVER NULL +select * from information_schema.statistics where table_schema = 'test' and table_name = 't1'; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT +def test t1 0 test a 1 a A NULL NULL NULL YES HASH_INDEX +def test t1 0 test a 2 b A NULL NULL NULL YES HASH_INDEX +def test t1 0 test a 3 c A NULL NULL NULL YES HASH_INDEX +def test t1 0 test c 1 c A NULL NULL NULL YES HASH_INDEX +def test t1 0 test c 2 d A 0 NULL NULL YES HASH_INDEX +def test t1 0 test c 3 e A 0 NULL NULL YES HASH_INDEX +def test t1 0 test e 1 e A 0 NULL NULL YES HASH_INDEX +def test t1 0 test e 2 f A 0 NULL NULL YES HASH_INDEX +def test t1 0 test e 3 g A 0 NULL NULL YES HASH_INDEX +def test t1 0 test e 4 h A 0 NULL NULL YES HASH_INDEX +def test t1 0 test b 1 b A 0 NULL NULL YES HASH_INDEX +def test t1 0 test b 2 d A 0 NULL NULL YES HASH_INDEX +def test t1 0 test b 3 g A 0 NULL NULL YES HASH_INDEX +def test t1 0 test b 4 h A 0 NULL NULL YES HASH_INDEX +select * from information_schema.key_column_usage where table_schema= 'test' and table_name= 't1'; +CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION POSITION_IN_UNIQUE_CONSTRAINT REFERENCED_TABLE_SCHEMA REFERENCED_TABLE_NAME REFERENCED_COLUMN_NAME +def test a def test t1 a 1 NULL NULL NULL NULL +def test a def test t1 b 2 NULL NULL NULL NULL +def test a def test t1 c 3 NULL NULL NULL NULL +def test c def test t1 c 1 NULL NULL NULL NULL +def test c def test t1 d 2 NULL NULL NULL NULL +def test c def test t1 e 3 NULL NULL NULL NULL +def test e def test t1 e 1 NULL NULL NULL NULL +def test e def test t1 f 2 NULL NULL NULL NULL +def test e def test t1 g 3 NULL NULL NULL NULL +def test e def test t1 h 4 NULL NULL NULL NULL +def test b def test t1 b 1 NULL NULL NULL NULL +def test b def test t1 d 2 NULL NULL NULL NULL +def test b def test t1 g 3 NULL NULL NULL NULL +def test b def test t1 h 4 NULL NULL NULL NULL +# table select we should not be able to see db_row_hash_1 column; +select * from t1; +a b c d e f g h +1 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 +3 3 3 3 3 3 3 3 +4 4 4 4 4 4 4 4 +5 5 5 5 5 5 5 5 +maria 6 maria maria maria maria 6 maria +mariadb 7 mariadb mariadb mariadb mariadb 8 mariadb +NULL NULL NULL NULL NULL NULL NULL NULL +NULL NULL NULL NULL NULL NULL NULL NULL +select db_row_hash_1 from t1; +ERROR 42S22: Unknown column 'db_row_hash_1' in 'field list' +select db_row_hash_2 from t1; +ERROR 42S22: Unknown column 'db_row_hash_2' in 'field list' +select db_row_hash_3 from t1; +ERROR 42S22: Unknown column 'db_row_hash_3' in 'field list' +#duplicate entry test; +#duplicate keys entry; +insert into t1 values(1,1,1,0,0,0,0,0); +ERROR 23000: Duplicate entry '1-1-1' for key 'a' +insert into t1 values(0,0,1,1,1,0,0,0); +ERROR 23000: Duplicate entry '1-1-1' for key 'c' +insert into t1 values(0,0,0,0,1,1,1,1); +ERROR 23000: Duplicate entry '1-1-1-1' for key 'e' +insert into t1 values(1,1,1,1,1,0,0,0); +ERROR 23000: Duplicate entry '1-1-1' for key 'a' +insert into t1 values(0,0,0,0,1,1,1,1); +ERROR 23000: Duplicate entry '1-1-1-1' for key 'e' +insert into t1 values(1,1,1,1,1,1,1,1); +ERROR 23000: Duplicate entry '1-1-1' for key 'a' +select db_row_hash_1,db_row_hash_2,db_row_hash_3,db_row_hash_4,db_row_hash_5 from t1; +ERROR 42S22: Unknown column 'db_row_hash_1' in 'field list' +alter table t1 drop column db_row_hash_1, drop column db_row_hash_2, drop column db_row_hash_3; +ERROR 42000: Can't DROP COLUMN `db_row_hash_1`; check that it exists +alter table t1 add column dg int , add column ef int , drop column db_row_hash_1; +ERROR 42000: Can't DROP COLUMN `db_row_hash_1`; check that it exists +alter table t1 modify column db_row_hash_1 int , modify column db_row_hash_2 int, modify column db_row_hash_3 int; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 add column ar int , add column rb int, modify column db_row_hash_1 int , modify column db_row_hash_3 int; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 change column db_row_hash_1 dsds int , change column db_row_hash_2 dfdf int , change column db_row_hash_3 gdfg int ; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +alter table t1 add column asd int, drop column a, change column db_row_hash_1 dsds int, change db_row_hash_3 fdfdfd int; +ERROR 42S22: Unknown column 'db_row_hash_1' in 't1' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` varchar(2000) DEFAULT NULL, + `d` text DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + UNIQUE KEY `a` (`a`,`b`,`c`), + UNIQUE KEY `c` (`c`,`d`,`e`), + UNIQUE KEY `e` (`e`,`f`,`g`,`h`), + UNIQUE KEY `b` (`b`,`d`,`g`,`h`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +# add column named db_row_hash_*; +alter table t1 add column db_row_hash_7 int , add column db_row_hash_5 int, +add column db_row_hash_1 int, add column db_row_hash_2 int; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` varchar(2000) DEFAULT NULL, + `d` text DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + `db_row_hash_7` int(11) DEFAULT NULL, + `db_row_hash_5` int(11) DEFAULT NULL, + `db_row_hash_1` int(11) DEFAULT NULL, + `db_row_hash_2` int(11) DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535),`b`,`c`), + UNIQUE KEY `c` (`c`,`d`(65535),`e`), + UNIQUE KEY `e` (`e`,`f`,`g`,`h`(65535)), + UNIQUE KEY `b` (`b`,`d`(65535),`g`,`h`(65535)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL 65535 NULL YES HASH_INDEX +t1 0 a 2 b A NULL NULL NULL YES HASH_INDEX +t1 0 a 3 c A NULL NULL NULL YES HASH_INDEX +t1 0 c 1 c A NULL NULL NULL YES HASH_INDEX +t1 0 c 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 c 3 e A 0 NULL NULL YES HASH_INDEX +t1 0 e 1 e A 0 NULL NULL YES HASH_INDEX +t1 0 e 2 f A 0 NULL NULL YES HASH_INDEX +t1 0 e 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 e 4 h A 0 65535 NULL YES HASH_INDEX +t1 0 b 1 b A 0 NULL NULL YES HASH_INDEX +t1 0 b 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 b 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 b 4 h A 0 65535 NULL YES HASH_INDEX +alter table t1 drop column db_row_hash_7 , drop column db_row_hash_5 , +drop column db_row_hash_1, drop column db_row_hash_2 ; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` varchar(2000) DEFAULT NULL, + `d` text DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535),`b`,`c`), + UNIQUE KEY `c` (`c`,`d`(65535),`e`), + UNIQUE KEY `e` (`e`,`f`,`g`,`h`(65535)), + UNIQUE KEY `b` (`b`,`d`(65535),`g`,`h`(65535)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL 65535 NULL YES HASH_INDEX +t1 0 a 2 b A NULL NULL NULL YES HASH_INDEX +t1 0 a 3 c A NULL NULL NULL YES HASH_INDEX +t1 0 c 1 c A NULL NULL NULL YES HASH_INDEX +t1 0 c 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 c 3 e A 0 NULL NULL YES HASH_INDEX +t1 0 e 1 e A 0 NULL NULL YES HASH_INDEX +t1 0 e 2 f A 0 NULL NULL YES HASH_INDEX +t1 0 e 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 e 4 h A 0 65535 NULL YES HASH_INDEX +t1 0 b 1 b A 0 NULL NULL YES HASH_INDEX +t1 0 b 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 b 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 b 4 h A 0 65535 NULL YES HASH_INDEX +#try to change column names; +alter table t1 change column a aa blob , change column b bb blob , change column d dd blob; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `aa` blob DEFAULT NULL, + `bb` blob DEFAULT NULL, + `c` varchar(2000) DEFAULT NULL, + `dd` blob DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + UNIQUE KEY `e` (`e`,`f`,`g`,`h`(65535)), + UNIQUE KEY `a` (`aa`(65535),`bb`,`c`), + UNIQUE KEY `c` (`c`,`dd`(65535),`e`), + UNIQUE KEY `b` (`bb`,`dd`(65535),`g`,`h`(65535)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 e 1 e A NULL NULL NULL YES HASH_INDEX +t1 0 e 2 f A NULL NULL NULL YES HASH_INDEX +t1 0 e 3 g A NULL NULL NULL YES HASH_INDEX +t1 0 e 4 h A NULL 65535 NULL YES HASH_INDEX +t1 0 a 1 aa A 0 65535 NULL YES HASH_INDEX +t1 0 a 2 bb A 0 NULL NULL YES HASH_INDEX +t1 0 a 3 c A 0 NULL NULL YES HASH_INDEX +t1 0 c 1 c A 0 NULL NULL YES HASH_INDEX +t1 0 c 2 dd A 0 65535 NULL YES HASH_INDEX +t1 0 c 3 e A 0 NULL NULL YES HASH_INDEX +t1 0 b 1 bb A 0 NULL NULL YES HASH_INDEX +t1 0 b 2 dd A 0 65535 NULL YES HASH_INDEX +t1 0 b 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 b 4 h A 0 65535 NULL YES HASH_INDEX +alter table t1 change column aa a blob , change column bb b blob , change column dd d blob; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` blob DEFAULT NULL, + `c` varchar(2000) DEFAULT NULL, + `d` blob DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + UNIQUE KEY `e` (`e`,`f`,`g`,`h`(65535)), + UNIQUE KEY `a` (`a`(65535),`b`,`c`), + UNIQUE KEY `c` (`c`,`d`(65535),`e`), + UNIQUE KEY `b` (`b`,`d`(65535),`g`,`h`(65535)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 e 1 e A NULL NULL NULL YES HASH_INDEX +t1 0 e 2 f A NULL NULL NULL YES HASH_INDEX +t1 0 e 3 g A NULL NULL NULL YES HASH_INDEX +t1 0 e 4 h A NULL 65535 NULL YES HASH_INDEX +t1 0 a 1 a A 0 65535 NULL YES HASH_INDEX +t1 0 a 2 b A 0 NULL NULL YES HASH_INDEX +t1 0 a 3 c A 0 NULL NULL YES HASH_INDEX +t1 0 c 1 c A 0 NULL NULL YES HASH_INDEX +t1 0 c 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 c 3 e A 0 NULL NULL YES HASH_INDEX +t1 0 b 1 b A 0 NULL NULL YES HASH_INDEX +t1 0 b 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 b 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 b 4 h A 0 65535 NULL YES HASH_INDEX +#now we will change the data type to int and varchar limit so that we no longer require hash_index; +#on key a_b_c; +alter table t1 modify column a varchar(20) , modify column b varchar(20) , modify column c varchar(20); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(20) DEFAULT NULL, + `b` varchar(20) DEFAULT NULL, + `c` varchar(20) DEFAULT NULL, + `d` blob DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + UNIQUE KEY `e` (`e`,`f`,`g`,`h`(65535)), + UNIQUE KEY `a` (`a`,`b`,`c`), + UNIQUE KEY `c` (`c`,`d`(65535),`e`), + UNIQUE KEY `b` (`b`,`d`(65535),`g`,`h`(65535)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 e 1 e A NULL NULL NULL YES HASH_INDEX +t1 0 e 2 f A NULL NULL NULL YES HASH_INDEX +t1 0 e 3 g A NULL NULL NULL YES HASH_INDEX +t1 0 e 4 h A NULL 65535 NULL YES HASH_INDEX +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 0 a 2 b A NULL NULL NULL YES BTREE +t1 0 a 3 c A 0 NULL NULL YES BTREE +t1 0 c 1 c A 0 NULL NULL YES HASH_INDEX +t1 0 c 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 c 3 e A 0 NULL NULL YES HASH_INDEX +t1 0 b 1 b A 0 NULL NULL YES HASH_INDEX +t1 0 b 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 b 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 b 4 h A 0 65535 NULL YES HASH_INDEX +#change it back; +alter table t1 modify column a blob , modify column b blob , modify column c blob; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` blob DEFAULT NULL, + `c` blob DEFAULT NULL, + `d` blob DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + UNIQUE KEY `e` (`e`,`f`,`g`,`h`(65535)), + UNIQUE KEY `a` (`a`,`b`,`c`), + UNIQUE KEY `c` (`c`,`d`(65535),`e`), + UNIQUE KEY `b` (`b`,`d`(65535),`g`,`h`(65535)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 e 1 e A NULL NULL NULL YES HASH_INDEX +t1 0 e 2 f A NULL NULL NULL YES HASH_INDEX +t1 0 e 3 g A NULL NULL NULL YES HASH_INDEX +t1 0 e 4 h A NULL 65535 NULL YES HASH_INDEX +t1 0 a 1 a A 0 NULL NULL YES HASH_INDEX +t1 0 a 2 b A 0 NULL NULL YES HASH_INDEX +t1 0 a 3 c A 0 NULL NULL YES HASH_INDEX +t1 0 c 1 c A 0 NULL NULL YES HASH_INDEX +t1 0 c 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 c 3 e A 0 NULL NULL YES HASH_INDEX +t1 0 b 1 b A 0 NULL NULL YES HASH_INDEX +t1 0 b 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 b 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 b 4 h A 0 65535 NULL YES HASH_INDEX +#try to delete blob column in unique; +truncate table t1; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` blob DEFAULT NULL, + `c` blob DEFAULT NULL, + `d` blob DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + UNIQUE KEY `e` (`e`,`f`,`g`,`h`(65535)), + UNIQUE KEY `a` (`a`,`b`,`c`), + UNIQUE KEY `c` (`c`,`d`(65535),`e`), + UNIQUE KEY `b` (`b`,`d`(65535),`g`,`h`(65535)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 e 1 e A NULL NULL NULL YES HASH_INDEX +t1 0 e 2 f A NULL NULL NULL YES HASH_INDEX +t1 0 e 3 g A NULL NULL NULL YES HASH_INDEX +t1 0 e 4 h A NULL 65535 NULL YES HASH_INDEX +t1 0 a 1 a A 0 NULL NULL YES HASH_INDEX +t1 0 a 2 b A 0 NULL NULL YES HASH_INDEX +t1 0 a 3 c A 0 NULL NULL YES HASH_INDEX +t1 0 c 1 c A 0 NULL NULL YES HASH_INDEX +t1 0 c 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 c 3 e A 0 NULL NULL YES HASH_INDEX +t1 0 b 1 b A 0 NULL NULL YES HASH_INDEX +t1 0 b 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 b 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 b 4 h A 0 65535 NULL YES HASH_INDEX +#now try to delete keys; +alter table t1 drop key c, drop key e; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` blob DEFAULT NULL, + `c` blob DEFAULT NULL, + `d` blob DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535),`b`(65535),`c`(65535)), + UNIQUE KEY `b` (`b`(65535),`d`(65535),`g`,`h`(65535)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL 65535 NULL YES HASH_INDEX +t1 0 a 2 b A NULL 65535 NULL YES HASH_INDEX +t1 0 a 3 c A 0 65535 NULL YES HASH_INDEX +t1 0 b 1 b A 0 65535 NULL YES HASH_INDEX +t1 0 b 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 b 3 g A 0 NULL NULL YES HASH_INDEX +t1 0 b 4 h A 0 65535 NULL YES HASH_INDEX +drop table t1; +#now alter table containing some data basically some tests with ignore; +create table t1 (a blob); +insert into t1 values(1),(2),(3); +#normal alter table; +alter table t1 add unique key(a); +alter table t1 drop key a; +truncate table t1; +insert into t1 values(1),(1),(2),(2),(3); +alter table t1 add unique key(a); +ERROR 23000: Duplicate entry '1' for key 'a' +alter ignore table t1 add unique key(a); +select * from t1; +a +1 +2 +3 +insert into t1 values(1); +ERROR 23000: Duplicate entry '1' for key 'a' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL 65535 NULL YES HASH_INDEX +drop table t1; +#Now with multiple keys; +create table t1(a blob , b blob, c blob , d blob , e int); +insert into t1 values (1,1,1,1,1); +insert into t1 values (1,1,1,1,1); +insert into t1 values (2,1,1,1,1); +insert into t1 values (2,2,2,2,2); +insert into t1 values (3,3,4,4,4); +insert into t1 values (4,4,4,4,4); +alter table t1 add unique key(a,c), add unique key(b,d), add unique key(e); +ERROR 23000: Duplicate entry '1-1' for key 'a' +alter ignore table t1 add unique key(a,c), add unique key(b,d), add unique key(e); +select * from t1; +a b c d e +1 1 1 1 1 +2 2 2 2 2 +3 3 4 4 4 +insert into t1 values (1,12,1,13,14); +ERROR 23000: Duplicate entry '1-1' for key 'a' +insert into t1 values (12,1,14,1,14); +ERROR 23000: Duplicate entry '1-1' for key 'b' +insert into t1 values (13,12,13,14,4); +ERROR 23000: Duplicate entry '4' for key 'e' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + `b` blob DEFAULT NULL, + `c` blob DEFAULT NULL, + `d` blob DEFAULT NULL, + `e` int(11) DEFAULT NULL, + UNIQUE KEY `a` (`a`(65535),`c`(65535)), + UNIQUE KEY `b` (`b`(65535),`d`(65535)), + UNIQUE KEY `e` (`e`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL 65535 NULL YES HASH_INDEX +t1 0 a 2 c A NULL 65535 NULL YES HASH_INDEX +t1 0 b 1 b A NULL 65535 NULL YES HASH_INDEX +t1 0 b 2 d A 0 65535 NULL YES HASH_INDEX +t1 0 e 1 e A 0 NULL NULL YES BTREE +drop table t1; +#visibility of db_row_hash +create table t1 (a blob unique , b blob unique); +desc t1; +Field Type Null Key Default Extra +a blob YES UNI NULL +b blob YES UNI NULL +insert into t1 values(1,19); +insert into t1 values(2,29); +insert into t1 values(3,39); +insert into t1 values(4,49); +create table t2 (DB_ROW_HASH_1 int, DB_ROW_HASH_2 int); +insert into t2 values(11,1); +insert into t2 values(22,2); +insert into t2 values(33,3); +insert into t2 values(44,4); +select * from t1; +a b +1 19 +2 29 +3 39 +4 49 +select * from t2; +DB_ROW_HASH_1 DB_ROW_HASH_2 +11 1 +22 2 +33 3 +44 4 +select DB_ROW_HASH_1, DB_ROW_HASH_2 from t1; +ERROR 42S22: Unknown column 'DB_ROW_HASH_1' in 'field list' +#bug +select DB_ROW_HASH_1, DB_ROW_HASH_2 from t1,t2; +DB_ROW_HASH_1 DB_ROW_HASH_2 +11 1 +11 1 +11 1 +11 1 +22 2 +22 2 +22 2 +22 2 +33 3 +33 3 +33 3 +33 3 +44 4 +44 4 +44 4 +44 4 +select * from t1 where DB_ROW_HASH_1 in (select DB_ROW_HASH_1 from t2); +ERROR 42S22: Unknown column 'DB_ROW_HASH_1' in 'IN/ALL/ANY subquery' +select DB_ROW_HASH_1, DB_ROW_HASH_2 from t1,t2 where DB_ROW_HASH_1 in (select DB_ROW_HASH_1 from t2); +DB_ROW_HASH_1 DB_ROW_HASH_2 +11 1 +22 2 +33 3 +44 4 +11 1 +22 2 +33 3 +44 4 +11 1 +22 2 +33 3 +44 4 +11 1 +22 2 +33 3 +44 4 +select * from t2 where DB_ROW_HASH_1 in (select DB_ROW_HASH_1 from t1); +DB_ROW_HASH_1 DB_ROW_HASH_2 +11 1 +22 2 +33 3 +44 4 +select DB_ROW_HASH_1 from t1,t2 where t1.DB_ROW_HASH_1 = t2.DB_ROW_HASH_2; +ERROR 42S22: Unknown column 't1.DB_ROW_HASH_1' in 'where clause' +select DB_ROW_HASH_1 from t1 inner join t2 on t1.a = t2.DB_ROW_HASH_2; +DB_ROW_HASH_1 +11 +22 +33 +44 +drop table t1,t2; +#very long blob entry; +SET @@GLOBAL.max_allowed_packet=67108864; +connect 'newcon', localhost, root,,; +connection newcon; +show variables like 'max_allowed_packet'; +Variable_name Value +max_allowed_packet 67108864 +create table t1(a longblob unique, b longblob , c longblob , unique(b,c)); +desc t1; +Field Type Null Key Default Extra +a longblob YES UNI NULL +b longblob YES MUL NULL +c longblob YES NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` longblob DEFAULT NULL, + `b` longblob DEFAULT NULL, + `c` longblob DEFAULT NULL, + UNIQUE KEY `a` (`a`), + UNIQUE KEY `b` (`b`,`c`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL NULL NULL YES HASH_INDEX +t1 0 b 1 b A NULL NULL NULL YES HASH_INDEX +t1 0 b 2 c A 0 NULL NULL YES HASH_INDEX +insert into t1 values(concat(repeat('sachin',10000000),'1'),concat(repeat('sachin',10000000),'1'), +concat(repeat('sachin',10000000),'1')); +insert into t1 values(concat(repeat('sachin',10000000),'2'),concat(repeat('sachin',10000000),'2'), +concat(repeat('sachin',10000000),'1')); +insert into t1 values(concat(repeat('sachin',10000000),'2'),concat(repeat('sachin',10000000),'2'), +concat(repeat('sachin',10000000),'4')); +ERROR 23000: Duplicate entry 'sachinsachinsachinsachinsachinsachinsachinsachinsachinsachinsach' for key 'a' +insert into t1 values(concat(repeat('sachin',10000000),'3'),concat(repeat('sachin',10000000),'1'), +concat(repeat('sachin',10000000),'1')); +ERROR 23000: Duplicate entry 'sachinsachinsachinsachinsachinsachinsachinsachinsachinsachinsach' for key 'b' +drop table t1; +#long key unique with different key length +create table t1(a blob, unique(a(3000))); +desc t1; +Field Type Null Key Default Extra +a blob YES UNI NULL +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL 3000 NULL YES HASH_INDEX +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob DEFAULT NULL, + UNIQUE KEY `a` (`a`(3000)) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 value(concat(repeat('s',3000),'1')); +insert into t1 value(concat(repeat('s',3000),'2')); +ERROR 23000: Duplicate entry 'ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss' for key 'a' +insert into t1 value(concat(repeat('a',3000),'2')); +drop table t1; +create table t1(a varchar(4000), b longblob , c varchar(5000), d longblob, +unique(a(3500), b(1000000)), unique(c(4500), d(10000000))); +desc t1; +Field Type Null Key Default Extra +a varchar(4000) YES MUL NULL +b longblob YES NULL +c varchar(5000) YES MUL NULL +d longblob YES NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` varchar(4000) DEFAULT NULL, + `b` longblob DEFAULT NULL, + `c` varchar(5000) DEFAULT NULL, + `d` longblob DEFAULT NULL, + UNIQUE KEY `a` (`a`(3500),`b`), + UNIQUE KEY `c` (`c`(4500),`d`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +show keys from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 a 1 a A NULL 3500 NULL YES HASH_INDEX +t1 0 a 2 b A NULL NULL NULL YES HASH_INDEX +t1 0 c 1 c A 0 4500 NULL YES HASH_INDEX +t1 0 c 2 d A 0 NULL NULL YES HASH_INDEX +drop table t1; +disconnect newcon; +connection default; +SET @@GLOBAL.max_allowed_packet=4194304; +#ext bug +create table t1(a int primary key, b blob unique, c int, d blob , index(c)); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) NOT NULL, + `b` blob DEFAULT NULL, + `c` int(11) DEFAULT NULL, + `d` blob DEFAULT NULL, + PRIMARY KEY (`a`), + UNIQUE KEY `b` (`b`), + KEY `c` (`c`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 values(1,23,1,33); +insert into t1 values(2,23,1,33); +ERROR 23000: Duplicate entry '23' for key 'b' +drop table t1; +create table t2 (a blob unique , c int , index(c)); +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` blob DEFAULT NULL, + `c` int(11) DEFAULT NULL, + UNIQUE KEY `a` (`a`), + KEY `c` (`c`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t2 values(1,1); +insert into t2 values(2,1); +drop table t2; +#not null test //todo solve warnings +create table t1(a blob unique not null); +desc t1; +Field Type Null Key Default Extra +a blob NO PRI NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob NOT NULL, + UNIQUE KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 values(1); +insert into t1 values(3); +insert into t1 values(1); +ERROR 23000: Duplicate entry '1' for key 'a' +drop table t1; +create table t1(a int primary key, b blob unique , c blob unique not null); +insert into t1 values(1,1,1); +insert into t1 values(2,1,2); +ERROR 23000: Duplicate entry '1' for key 'b' +insert into t1 values(3,3,1); +ERROR 23000: Duplicate entry '1' for key 'c' +drop table t1; +create table t1 (a blob unique not null, b blob not null, c blob not null, unique(b,c)); +desc t1; +Field Type Null Key Default Extra +a blob NO PRI NULL +b blob NO MUL NULL +c blob NO NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` blob NOT NULL, + `b` blob NOT NULL, + `c` blob NOT NULL, + UNIQUE KEY `a` (`a`), + UNIQUE KEY `b` (`b`,`c`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 values (1, 2, 3); +insert into t1 values (2, 1, 3); +insert into t1 values (2, 1, 3); +ERROR 23000: Duplicate entry '2' for key 'a' +drop table t1; +set @@GLOBAL.max_allowed_packet= @allowed_packet; diff --git a/sql/field.h b/sql/field.h index b6f28808e2e..13eea28fe8a 100644 --- a/sql/field.h +++ b/sql/field.h @@ -539,6 +539,7 @@ class Virtual_column_info: public Sql_alloc Item *expr; LEX_CSTRING name; /* Name of constraint */ uint flags; + LEX_CSTRING hash_expr;
It is not a good idea to put your hash-unique-constraint specific data into a common Virtual_column_info. Luckily, you don't need it. Just like "current_timestamp()" expression is generated on the fly as needed in parse_vcol_defs(), you can generate the hash expression there too, no need to do it in TABLE_SHARE::init_from_binary_frm_image(). So, just remove hash_expr.
Virtual_column_info() : vcol_type((enum_vcol_info_type)VCOL_TYPE_NONE), @@ -681,7 +688,7 @@ class Field: public Value_source GEOM_MULTIPOINT = 4, GEOM_MULTILINESTRING = 5, GEOM_MULTIPOLYGON = 6, GEOM_GEOMETRYCOLLECTION = 7 }; - enum imagetype { itRAW, itMBR}; + enum imagetype { itRAW, itMBR, itHASH};
itHASH isn't used anywhere in your patch :)
utype unireg_check; uint32 field_length; // Length of field diff --git a/sql/field.cc b/sql/field.cc index dc854826ed6..f75f52141e3 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -9822,7 +9822,7 @@ int Field_bit::key_cmp(const uchar *str, uint length) }
-int Field_bit::cmp_offset(uint row_offset) +int Field_bit::cmp_offset(long row_offset)
may be my_ptrdiff_t ?
{ if (bit_len) { diff --git a/sql/item_func.h b/sql/item_func.h index 3b6cb4ceeac..0391de0c5ad 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -803,6 +803,19 @@ class Item_long_func: public Item_int_func };
+class Item_func_hash: public Item_int_func +{ +public: + Item_func_hash(THD *thd, List<Item> &item): Item_int_func(thd, item) + {} + longlong val_int(); + void fix_length_and_dec(); + const Type_handler *type_handler() const { return &type_handler_long; } + Item *get_copy(THD *thd) + { return get_item_copy<Item_func_hash>(thd, this); } + const char *func_name() const { return "HASH"; }
is it a user visible function? Can one write SELECT HASH(a) FROM t1 ? looks like yes, so 1. please add tests for it 2. we need to document what hash function, exactly, is used. 3. May be better to call it MARIADB_HASH? to highlight its internal-use nature and a home-baked hash function? And to reduce a chance for a collision with user defined functions. 4. An even better approach would be not to create any user visible function at all. Currently unpack_vcol_info_from_frm() calls the parser and then initializes vcol_info and calls fix_fields. If you split it in two you can do `new Item_func_hash` manually and skip the first part of unpack_vcol_info_from_frm(). And you won't need HASH to be user-visible. As a minor optimization, the same can be done for "current_timestamp()"
+}; + class Item_longlong_func: public Item_int_func { public: diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 4923c628bf9..c620ea23165 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2300,7 +2300,7 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, */ packet->append(STRING_WITH_LEN("PRIMARY KEY")); } - else if (key_info->flags & HA_NOSAME) + else if (key_info->flags & HA_NOSAME || key_info->flags & HA_LONG_UNIQUE_HASH)
Is it needed? As far as I can see, you always set HA_NOSAME whenever you set HA_LONG_UNIQUE_HASH.
packet->append(STRING_WITH_LEN("UNIQUE KEY ")); else if (key_info->flags & HA_FULLTEXT) packet->append(STRING_WITH_LEN("FULLTEXT KEY ")); diff --git a/include/my_base.h b/include/my_base.h index c36072c0bfa..ba17f8d80dc 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -290,6 +291,11 @@ enum ha_base_keytype { #define HA_KEY_HAS_PART_KEY_SEG 65536 /* Internal Flag Can be calcaluted */ #define HA_INVISIBLE_KEY 2<<18 +/* + Some more flags for keys these are not stored in + frm it is calculated on the fly in init_from_binary_frm_image +*/
1. I don't think you need to make the same comment more verbose every time you repeat it :) Just say, like #define HA_INVISIBLE_KEY 2<<18 /* this is calculated too */ #define HA_LONG_UNIQUE_HASH 2<<19 /* this is calculated too */ 2. Do you need a separate flag for that, just HA_INVISIBLE_KEY isn't enough?
+#define HA_LONG_UNIQUE_HASH 2<<19 /* Automatic bits in key-flag */
#define HA_SPACE_PACK_USED 4 /* Test for if SPACE_PACK used */ @@ -317,6 +323,13 @@ enum ha_base_keytype { #define HA_BIT_PART 1024 #define HA_CAN_MEMCMP 2048 /* internal, never stored in frm */
+/* + Used for key parts whole length is greater then > file->max_key_part_length + Only used for HA_LONG_UNIQUE_HASH keys +*/ //TODO a better name ?? +#define HA_HASH_KEY_PART_FLAG 4096 +/* Field need to be frees externally */ +#define HA_FIELD_EX_FREED 8192
Okay, this is a weird name, agree. But it is not used anywere, so there's an easy solution :)
/* optionbits for database */ #define HA_OPTION_PACK_RECORD 1U #define HA_OPTION_PACK_KEYS 2U diff --git a/sql/table.h b/sql/table.h index 785fd9f3427..9ed7fcd7beb 100644 --- a/sql/table.h +++ b/sql/table.h @@ -346,9 +346,39 @@ enum field_visibility_t { INVISIBLE_FULL };
-#define INVISIBLE_MAX_BITS 3 +#define INVISIBLE_MAX_BITS 3 +/* We will store the info into 3rd bit if field is hash field */ +#define HASH_FIELD_MASK 15 +#define HASH_FIELD_MASK_SHIFT 4 +#define HA_HASH_FIELD_LENGTH 8 +#define HA_HASH_KEY_LENGTH_WITHOUT_NULL 8 +#define HA_HASH_KEY_LENGTH_WITH_NULL 9 +//TODO is this correct ? how about size of char ptr on 32/16 bit machine?
I don't understand that, sorry
+#define HA_HASH_KEY_PART_LENGTH 4 + 8 // 4 for length , 8 for portable size of char ptr
you almost always should use parentheses in macro expressions
+const LEX_CSTRING ha_hash_str {STRING_WITH_LEN("HASH")};
??? you create a copy of ha_hash_str symbol in every .o file that included table.h?
+ +int find_field_pos_in_hash(Item *hash_item, const char * field_name); + +int fields_in_hash_str(Item *hash_item); + +Field * field_ptr_in_hash_str(Item *hash_item, int index); + +int get_key_part_length(KEY *keyinfo, int index); + +void calc_hash_for_unique(ulong &nr1, ulong &nr2, String *str); + +void create_update_handler(THD *thd, TABLE *table); + +void delete_update_handler(THD *thd, TABLE *table); + +void setup_table_hash(TABLE *table); + +void re_setup_table(TABLE *table); + +int get_hash_key(THD *thd, TABLE *table, handler *h, uint key_index, uchar *rec_buf, + uchar *key_buff); /** Category of table found in the table share. */ @@ -1094,6 +1124,17 @@ struct TABLE THD *in_use; /* Which thread uses this */
uchar *record[3]; /* Pointer to records */ + /* record buf to resolve hash collisions for long UNIQUE constraints */ + uchar *check_unique_buf; + handler *update_handler; /* Handler used in case of update */ + /* + In the case of write row for long unique we are unable of find + Whick key is voilated. Because we in case of duplicate hash we never reach + handler write_row function. So print_error will always print that + key 0 is voilated. We store which key is voilated in this variable + by default this should be initialized to -1
typos :) "unable to find", "which", "violated"
+ */ + int dupp_hash_key; uchar *write_row_record; /* Used as optimisation in THD::write_row */ uchar *insert_values; /* used by INSERT ... UPDATE */ @@ -2898,6 +2939,7 @@ void append_unescaped(String *res, const char *pos, size_t length); void prepare_frm_header(THD *thd, uint reclength, uchar *fileinfo, HA_CREATE_INFO *create_info, uint keys, KEY *key_info); const char *fn_frm_ext(const char *name); +void calc_hash_for_unique(ulong &nr1, ulong &nr2, String *str);
you have this prototype twice in table.h
/* Check that the integer is in the internal */ static inline int set_zone(int nr,int min_zone,int max_zone) diff --git a/sql/table.cc b/sql/table.cc index 73b1a6bd9b2..8cd4db2844d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -747,7 +748,13 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, if (i == 0) { ext_key_parts+= (share->use_ext_keys ? first_keyinfo->user_defined_key_parts*(keys-1) : 0); + /* + Some keys can be HA_LONG_UNIQUE_HASH , but we do not know at this point , + how many ?, but will always be less than or equal to total num of + keys. Each HA_LONG_UNIQUE_HASH key require one extra key_part in which + it stored hash. On safe side we will allocate memory for each key. + */ - n_length=keys * sizeof(KEY) + ext_key_parts * sizeof(KEY_PART_INFO); + n_length=keys * sizeof(KEY) + (ext_key_parts +keys) * sizeof(KEY_PART_INFO);
Hmm, why wouldn't you store the number of HA_KEY_ALG_LONG_HASH keys in EXTRA2_LONG_UNIQUES ? Then you'll know it here.
if (!(keyinfo= (KEY*) alloc_root(&share->mem_root, n_length + len))) return 1; @@ -798,6 +805,14 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, } key_part->store_length=key_part->length; } + if (keyinfo->algorithm == HA_KEY_ALG_LONG_HASH) + { + keyinfo->flags|= HA_LONG_UNIQUE_HASH | HA_NOSAME; + keyinfo->key_length= 0; + share->ext_key_parts++; + // This empty key_part for storing Hash + key_part++; + }
so, you write keyinfo's for HA_LONG_UNIQUE_HASH keys into the frm? why don't you write keysegs for them? I mean, it is not very logical. I'd thought you won't write either keyinfos or keysegs. Or, okay, you could write both. But only keyinfos and no keysegs? That's strange
/* Add primary key to end of extended keys for non unique keys for @@ -1143,13 +1159,21 @@ bool parse_vcol_defs(THD *thd, MEM_ROOT *mem_root, TABLE *table, pos+= expr_length; }
- /* Now, initialize CURRENT_TIMESTAMP fields */ + /* Now, initialize CURRENT_TIMESTAMP and UNIQUE_INDEX_HASH_FIELD fields */ for (field_ptr= table->field; *field_ptr; field_ptr++) { Field *field= *field_ptr; - if (field->has_default_now_unireg_check()) + if (field->vcol_info && (length = field->vcol_info->hash_expr.length)) { expr_str.length(parse_vcol_keyword.length); + expr_str.append((char*)field->vcol_info->hash_expr.str, length); + vcol= unpack_vcol_info_from_frm(thd, mem_root, table, &expr_str, + &(field->vcol_info), error_reported);
see above about not going through the parser for hash keys.
+ *(vfield_ptr++)= *field_ptr; + + } + if (field->has_default_now_unireg_check()) + { expr_str.append(STRING_WITH_LEN("current_timestamp(")); expr_str.append_ulonglong(field->decimals()); expr_str.append(')'); @@ -2106,7 +2132,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, uchar flags= *extra2_field_flags++; if (flags & VERS_OPTIMIZED_UPDATE) reg_field->flags|= VERS_UPDATE_UNVERSIONED_FLAG; - + if (flags & EXTRA2_LONG_UNIQUE_HASH_FIELD) + reg_field->flags|= LONG_UNIQUE_HASH_FIELD;
so, you write LONG_UNIQUE_HASH_FIELD fields to frm too. Why?
reg_field->invisible= f_visibility(flags); } if (reg_field->invisible == INVISIBLE_USER) @@ -2350,6 +2438,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, key_part= keyinfo->key_part; uint key_parts= share->use_ext_keys ? keyinfo->ext_key_parts : keyinfo->user_defined_key_parts; + if (keyinfo->flags & HA_LONG_UNIQUE_HASH) + key_parts++;
key_parts++ ? Doesn't your HA_LONG_UNIQUE_HASH key have only one part, always?
for (i=0; i < key_parts; key_part++, i++) { Field *field; @@ -2363,7 +2453,16 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
field= key_part->field= share->field[key_part->fieldnr-1]; key_part->type= field->key_type(); + if (keyinfo->flags & HA_LONG_UNIQUE_HASH + &&(key_part->length > handler_file->max_key_part_length() + || key_part->length == 0))
1. fix the spacing and the indentation here, please 2. what should happen if HA_LONG_UNIQUE_HASH flag is set, but the key_part->length is small ?
+ { + key_part->key_part_flag= HA_HASH_KEY_PART_FLAG; + key_part->store_length= HA_HASH_KEY_PART_LENGTH; + } + /* Invisible Full is currently used by long uniques */ - if (field->invisible > INVISIBLE_USER && !field->vers_sys_field()) + if ((field->invisible == INVISIBLE_USER || + field->invisible == INVISIBLE_SYSTEM )&& !field->vers_sys_field())
why is this change?
keyinfo->flags |= HA_INVISIBLE_KEY; if (field->null_ptr) { @@ -2428,7 +2527,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, field->part_of_sortkey= share->keys_in_use; } } - if (field->key_length() != key_part->length) + if (field->key_length() != key_part->length && + !(keyinfo->flags & HA_LONG_UNIQUE_HASH))
why is that?
{ #ifndef TO_BE_DELETED_ON_PRODUCTION if (field->type() == MYSQL_TYPE_NEWDECIMAL) @@ -2470,7 +2570,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (!(key_part->key_part_flag & (HA_BLOB_PART | HA_VAR_LENGTH_PART | HA_BIT_PART)) && key_part->type != HA_KEYTYPE_FLOAT && - key_part->type == HA_KEYTYPE_DOUBLE) + key_part->type == HA_KEYTYPE_DOUBLE && + !(keyinfo->flags & HA_LONG_UNIQUE_HASH))
why is that?
key_part->key_part_flag|= HA_CAN_MEMCMP; } keyinfo->usable_key_parts= usable_parts; // Filesort @@ -8346,6 +8454,377 @@ double KEY::actual_rec_per_key(uint i) }
+/* + find out the field positoin in hash_str() + position starts from 0 + else return -1; +*/ +int find_field_pos_in_hash(Item *hash_item, const char * field_name) +{ + Item_func_or_sum * temp= static_cast<Item_func_or_sum *>(hash_item); + Item_args * t_item= static_cast<Item_args *>(temp); + uint arg_count= t_item->argument_count(); + Item ** arguments= t_item->arguments(); + Field * t_field; + + for (uint j=0; j < arg_count; j++) + { + DBUG_ASSERT(arguments[j]->type() == Item::FIELD_ITEM || + arguments[j]->type() == Item::FUNC_ITEM); + if (arguments[j]->type() == Item::FIELD_ITEM) + { + t_field= static_cast<Item_field *>(arguments[j])->field; + } + else + { + Item_func_left *fnc= static_cast<Item_func_left *>(arguments[j]); + t_field= static_cast<Item_field *>(fnc->arguments()[0])->field; + } + if (!my_strcasecmp(system_charset_info, t_field->field_name.str, field_name)) + return j; + } + return -1; +} + +/* + find total number of field in hash_str +*/ +int fields_in_hash_str(Item * hash_item)
can be static
+{ + Item_func_or_sum * temp= static_cast<Item_func_or_sum *>(hash_item); + Item_args * t_item= static_cast<Item_args *>(temp); + return t_item->argument_count(); +} + +/* + Returns fields ptr given by hash_str index + Index starts from 0 +*/ +Field * field_ptr_in_hash_str(Item *hash_item, int index) +{ + Item_func_or_sum * temp= static_cast<Item_func_or_sum *>(hash_item); + Item_args * t_item= static_cast<Item_args *>(temp); + return static_cast<Item_field *>(t_item->arguments()[index])->field; +} + +//NO longer Needed
remove it, then :)
+int get_key_part_length(KEY *keyinfo, int index) +{ + DBUG_ASSERT(keyinfo->flags & HA_LONG_UNIQUE_HASH); + TABLE *tbl= keyinfo->table; + Item *h_item= keyinfo->key_part->field->vcol_info->expr; + Field *fld= field_ptr_in_hash_str(h_item, index); + if (!index) + return fld->pack_length()+HA_HASH_KEY_LENGTH_WITH_NULL+1; + return fld->pack_length()+1; +} +/** + @brief clone of current handler. + Creates a clone of handler used in update for + unique hash key. + @param thd Thread Object + @param table Table Object + @return handler object +*/ +void create_update_handler(THD *thd, TABLE *table)
better, clone_handler_for_update
+{ + handler *update_handler= NULL; + for (uint i= 0; i < table->s->keys; i++)
indentation
+ { + if (table->key_info[i].flags & HA_LONG_UNIQUE_HASH) + { + update_handler= table->file->clone(table->s->normalized_path.str, + thd->mem_root); + update_handler->ha_external_lock(thd, F_RDLCK); + table->update_handler= update_handler;
why do you store it in TABLE? you can just keep it in a local variable in mysql_update, you don't need it outside of mysql_update anyway. (and multi-update) also, you shouldn't need to scan all table keys here. use some flag or property in TABLE_SCHEMA to check quickly whether the table has these lock unique keys.
+ return; + } + } + return; +} + +/** + @brief Deletes update handler object + @param thd Thread Object + @param table Table Object +*/ +void delete_update_handler(THD *thd, TABLE *table) +{ + if (table->update_handler) + { + table->update_handler->ha_external_lock(thd, F_UNLCK); + table->update_handler->ha_close(); + delete table->update_handler; + table->update_handler= NULL; + } +} +/** + @brief This function makes table object with + long unique keys ready for storage engine. + It makes key_part of HA_LONG_UNIQUE_HASH point to + hash key_part. + @param table Table object + */ +void setup_table_hash(TABLE *table)
this and other functions could be methods in TABLE
+{ + /* + Extra parts of long unique key which are used only at server level + for example in key unique(a, b, c) //a b c are blob + extra_key_part_hash is 3 + */ + uint extra_key_part_hash= 0; + uint hash_parts= 0; + KEY *s_keyinfo= table->s->key_info; + KEY *keyinfo= table->key_info; + /* + Sometime s_keyinfo or key_info can be null. So + two different loop for keyinfo and s_keyinfo + reference test case:- main.subselect_sj2
how they could be null here?
+ */ + + if (keyinfo) + { + for (uint i= 0; i < table->s->keys; i++, keyinfo++) + { + if (keyinfo->flags & HA_LONG_UNIQUE_HASH) + { + DBUG_ASSERT(keyinfo->user_defined_key_parts == + keyinfo->ext_key_parts); + keyinfo->flags&= ~(HA_NOSAME | HA_LONG_UNIQUE_HASH); + keyinfo->algorithm= HA_KEY_ALG_UNDEF; + extra_key_part_hash+= keyinfo->ext_key_parts; + hash_parts++; + keyinfo->key_part= keyinfo->key_part+ keyinfo->ext_key_parts; + keyinfo->user_defined_key_parts= keyinfo->usable_key_parts= + keyinfo->ext_key_parts= 1; + keyinfo->key_length= keyinfo->key_part->store_length; + } + } + table->s->key_parts-= extra_key_part_hash; + table->s->key_parts+= hash_parts; + table->s->ext_key_parts-= extra_key_part_hash;
I don't understand what you're doing here. Could you add a comment, explaning the resulting structure of keys and keysegs and what's where?
+ } + if (s_keyinfo) + { + for (uint i= 0; i < table->s->keys; i++, s_keyinfo++) + { + if (s_keyinfo->flags & HA_LONG_UNIQUE_HASH) + { + DBUG_ASSERT(s_keyinfo->user_defined_key_parts == + s_keyinfo->ext_key_parts); + s_keyinfo->flags&= ~(HA_NOSAME | HA_LONG_UNIQUE_HASH); + s_keyinfo->algorithm= HA_KEY_ALG_BTREE; + extra_key_part_hash+= s_keyinfo->ext_key_parts; + s_keyinfo->key_part= s_keyinfo->key_part+ s_keyinfo->ext_key_parts; + s_keyinfo->user_defined_key_parts= s_keyinfo->usable_key_parts= + s_keyinfo->ext_key_parts= 1; + s_keyinfo->key_length= s_keyinfo->key_part->store_length; + } + } + if (!keyinfo) + { + table->s->key_parts-= extra_key_part_hash; + table->s->key_parts+= hash_parts; + table->s->ext_key_parts-= extra_key_part_hash; + } + } +} + +/** + @brief Revert the effect of setup_table_hash + @param table Table Object + */ +void re_setup_table(TABLE *table) +{ + //extra key parts excluding hash , which needs to be added in keyparts + uint extra_key_parts_ex_hash= 0; + uint extra_hash_parts= 0; // this var for share->extra_hash_parts + KEY *s_keyinfo= table->s->key_info; + KEY *keyinfo= table->key_info; + /* + Sometime s_keyinfo can be null so + two different loop for keyinfo and s_keyinfo + ref test case:- main.subselect_sj2 + */ + if (keyinfo) + { + for (uint i= 0; i < table->s->keys; i++, keyinfo++) + { + if (keyinfo->user_defined_key_parts == 1 && + keyinfo->key_part->field->flags & LONG_UNIQUE_HASH_FIELD) + { + keyinfo->flags|= (HA_NOSAME | HA_LONG_UNIQUE_HASH); + keyinfo->algorithm= HA_KEY_ALG_LONG_HASH; + /* Sometimes it can happen, that we does not parsed hash_str. + Like when this function is called in ha_create. So we will + Use field from table->field rather then share->field*/ + Item *h_item= table->field[keyinfo->key_part->fieldnr - 1]-> + vcol_info->expr; + uint hash_parts= fields_in_hash_str(h_item); + keyinfo->key_part= keyinfo->key_part- hash_parts; + keyinfo->user_defined_key_parts= keyinfo->usable_key_parts= + keyinfo->ext_key_parts= hash_parts; + extra_key_parts_ex_hash+= hash_parts; + extra_hash_parts++; + keyinfo->key_length= -1; + } + } + table->s->key_parts-= extra_hash_parts; + table->s->key_parts+= extra_key_parts_ex_hash; + table->s->ext_key_parts+= extra_key_parts_ex_hash + extra_hash_parts; + } + if (s_keyinfo) + { + for (uint i= 0; i < table->s->keys; i++, s_keyinfo++) + { + if (s_keyinfo->user_defined_key_parts == 1 && + s_keyinfo->key_part->field->flags & LONG_UNIQUE_HASH_FIELD) + { + s_keyinfo->flags|= (HA_NOSAME | HA_LONG_UNIQUE_HASH); + s_keyinfo->algorithm= HA_KEY_ALG_LONG_HASH; + extra_hash_parts++; + /* Sometimes it can happen, that we does not parsed hash_str. + Like when this function is called in ha_create. So we will + Use field from table->field rather then share->field*/ + Item *h_item= table->field[s_keyinfo->key_part->fieldnr - 1]-> + vcol_info->expr; + uint hash_parts= fields_in_hash_str(h_item); + s_keyinfo->key_part= s_keyinfo->key_part- hash_parts; + s_keyinfo->user_defined_key_parts= s_keyinfo->usable_key_parts= + s_keyinfo->ext_key_parts= hash_parts; + extra_key_parts_ex_hash+= hash_parts; + s_keyinfo->key_length= -1; + } + } + if (!keyinfo) + { + table->s->key_parts-= extra_hash_parts; + table->s->key_parts+= extra_key_parts_ex_hash; + table->s->ext_key_parts+= extra_key_parts_ex_hash + extra_hash_parts; + } + } +} + +/** + @brief set_hash + @param table + @param key_index + @param key_buff + +int get_hash_key(THD *thd,TABLE *table, handler *h, uint key_index, + uchar * rec_buff, uchar *key_buff)
unused?
+{ + KEY *keyinfo= &table->key_info[key_index]; + DBUG_ASSERT(keyinfo->flags & HA_LONG_UNIQUE_HASH); + KEY_PART_INFO *temp_key_part= table->key_info[key_index].key_part; + Field *fld[keyinfo->user_defined_key_parts]; + Field *t_field; + uchar hash_buff[9]; + ulong nr1= 1, nr2= 4; + String *str1, temp1; + String *str2, temp2; + bool is_null= false; + bool is_same= true; + bool is_index_inited= h->inited; + /* difference between field->ptr and start of rec_buff * + long diff = rec_buff- table->record[0]; + int result= 0; + for (uint i=0; i < keyinfo->user_defined_key_parts; i++, temp_key_part++) + { + uint maybe_null= MY_TEST(temp_key_part->null_bit); + fld[i]= temp_key_part->field->new_key_field(thd->mem_root, table, + key_buff + maybe_null, 12, + maybe_null?key_buff:0, 1, + temp_key_part->key_part_flag + & HA_HASH_KEY_PART_FLAG); + if (fld[i]->is_real_null()) + { + is_null= true; + break; + } + str1= fld[i]->val_str(&temp1); + calc_hash_for_unique(nr1, nr2, str1); + key_buff+= temp_key_part->store_length; + } + if (is_null && !(keyinfo->flags & HA_NULL_PART_KEY)) + return HA_ERR_KEY_NOT_FOUND; + if (keyinfo->flags & HA_NULL_PART_KEY) + { + hash_buff[0]= is_null; + int8store(hash_buff + 1, nr1); + } + else + int8store(hash_buff, nr1); + if (!is_index_inited) + result= h->ha_index_init(key_index, 0); + if (result) + return result; + + setup_table_hash(table); + result= h->ha_index_read_map(rec_buff, hash_buff, HA_WHOLE_KEY, + HA_READ_KEY_EXACT); + re_setup_table(table); + if (!result) + { + for (uint i=0; i < keyinfo->user_defined_key_parts; i++) + { + t_field= keyinfo->key_part[i].field; + t_field->move_field(t_field->ptr+diff, + t_field->null_ptr+diff, t_field->null_bit); + } + do + { + re_setup_table(table); + is_same= true; + for (uint i=0; i < keyinfo->user_defined_key_parts; i++) + { + t_field= keyinfo->key_part[i].field; + if (fld[i]->is_real_null() && t_field->is_real_null()) + continue; + if (!fld[i]->is_real_null() && !t_field->is_real_null()) + { + str1= t_field->val_str(&temp1); + str2= fld[i]->val_str(&temp2); + if (my_strcasecmp(str1->charset(), str1->c_ptr_safe(), + str2->c_ptr_safe())) + { + is_same= false; + break; + } + } + else + { + is_same= false; + break; + } + } + setup_table_hash(table); + } + while (!is_same && !(result= h->ha_index_next_same(rec_buff, hash_buff, + keyinfo->key_length))); + for (uint i=0; i < keyinfo->user_defined_key_parts; i++) + { + t_field= keyinfo->key_part[i].field; + t_field->move_field(t_field->ptr-diff, + t_field->null_ptr-diff, t_field->null_bit); + } + } + if (!is_index_inited) + h->ha_index_end(); + re_setup_table(table); + for (uint i=0; i < keyinfo->user_defined_key_parts; i++) + { + if (keyinfo->key_part[i].key_part_flag & HA_FIELD_EX_FREED) + { + Field_blob *blb= static_cast<Field_blob *>(fld[i]); + uchar * addr; + blb->get_ptr(&addr); + my_free(addr); + } + } + return result; +} +*/ LEX_CSTRING *fk_option_name(enum_fk_option opt) { static LEX_CSTRING names[]= @@ -8814,3 +9293,15 @@ bool TABLE::export_structure(THD *thd, Row_definition_list *defs) } return false; } + +void calc_hash_for_unique(ulong &nr1, ulong &nr2, String *str) +{ + CHARSET_INFO *cs; + uchar l[4]; + int4store(l, str->length()); + cs= &my_charset_bin; + cs->coll->hash_sort(cs, l, sizeof(l), &nr1, &nr2); + cs= str->charset(); + cs->coll->hash_sort(cs, (uchar *)str->ptr(), str->length(), &nr1, &nr2); + sql_print_information("setiya %lu, %s", nr1, str->ptr());
really? :)
+} diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4ac8b102d79..f42687c0377 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3343,6 +3343,87 @@ mysql_add_invisible_index(THD *thd, List<Key> *key_list, key_list->push_back(key, thd->mem_root); return key; } +/** + Add hidden level 3 hash field to table in case of long
s/hidden level 3/fully invisible/
+ unique column + @param thd Thread Context. + @param create_list List of table fields. + @param cs Field Charset + @param key_info Whole Keys buffer + @param key_index Index of current key
1. instead of key_info and key_index, you can just take a key_info of the current key here (that is key_info + key_index). 2. what is the "current key"? Is it the unique key over blobs that you create a hash field for? please clarify the comment.
+*/ + +static void add_hash_field(THD * thd, List<Create_field> *create_list, + CHARSET_INFO *cs, KEY *key_info, int key_index) +{ + List_iterator<Create_field> it(*create_list); + Create_field *dup_field, *cf= new (thd->mem_root) Create_field(); + cf->flags|= UNSIGNED_FLAG | LONG_UNIQUE_HASH_FIELD; + cf->charset= cs; + cf->decimals= 0; + cf->length= cf->char_length= cf->pack_length= HA_HASH_FIELD_LENGTH; + cf->invisible= INVISIBLE_FULL; + cf->pack_flag|= FIELDFLAG_MAYBE_NULL; + uint num= 1; + char *temp_name= (char *)thd->alloc(30); + my_snprintf(temp_name, 30, "DB_ROW_HASH_%u", num);
please, give names for 30 and for the whole my_snprintf - macros, functions, whatever. And better use a LEX_STRING for it, for example: #define LONG_HASH_FIELD_NAME_LENGTH 30 static inline make_long_hash_field_name(LEX_STRING buf, uint num) { buf->length= my_snprintf(buf->str, LONG_HASH_FIELD_NAME_LENGTH, "DB_ROW_HASH_%u", num); }
+ /* + Check for collusions
collisions :)
+ */ + while ((dup_field= it++)) + { + if (!my_strcasecmp(system_charset_info, temp_name, dup_field->field_name.str)) + { + num++; + my_snprintf(temp_name, 30, "DB_ROW_HASH_%u", num); + it.rewind(); + } + } + it.rewind(); + cf->field_name.str= temp_name; + cf->field_name.length= strlen(temp_name);
you won't need strlen here, if you use LEX_STRING above
+ cf->set_handler(&type_handler_longlong); + /* + We have added db_row_hash field in starting of + fields array , So we have to change key_part + field index + for (int i= 0; i <= key_index; i++, key_info++) + { + KEY_PART_INFO *info= key_info->key_part; + for (uint j= 0; j < key_info->user_defined_key_parts; j++, info++) + { + info->fieldnr+= 1; + info->offset+= HA_HASH_FIELD_LENGTH; + } + }*/
Forgot to remove it?
+ key_info[key_index].flags|= HA_NOSAME; + key_info[key_index].algorithm= HA_KEY_ALG_LONG_HASH; + it.rewind(); + uint record_offset= 0; + while ((dup_field= it++)) + { + dup_field->offset= record_offset; + if (dup_field->stored_in_db()) + record_offset+= dup_field->pack_length;
Why do you change all field offsets? You only need to put your field last, that's all. Like while ((dup_field= it++)) set_if_bigger(record_offset, dup_field->offset + dup_field->pack_length)
+ } + cf->offset= record_offset; + /* + it.rewind(); + while ((sql_field= it++)) + { + if (!sql_field->stored_in_db()) + { + sql_field->offset= record_offset; + record_offset+= sql_field->pack_length; + } + }
why is that?
+ */ + /* hash column should be fully hidden */ + //prepare_create_field(cf, NULL, 0);
Forgot to remove it?
+ create_list->push_back(cf,thd->mem_root); +} + + /* Preparation for table creation
@@ -3868,6 +3951,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, }
cols2.rewind(); + key_part_info->fieldnr= field; + key_part_info->offset= (uint16) sql_field->offset;
why did you need to move that?
if (key->type == Key::FULLTEXT) { if ((sql_field->real_field_type() != MYSQL_TYPE_STRING && @@ -3922,8 +4007,19 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, column->length= MAX_LEN_GEOM_POINT_FIELD; if (!column->length) { - my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.str); - DBUG_RETURN(TRUE); + if (key->type == Key::PRIMARY) + { + my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.str); + DBUG_RETURN(TRUE); + } + else if (!is_hash_field_added) + { + add_hash_field(thd, &alter_info->create_list, + create_info->default_table_charset, + *key_info_buffer, key_number); + column->length= 0;
why column->length= 0 ?
+ is_hash_field_added= true; + } } } #ifdef HAVE_SPATIAL @@ -4062,11 +4159,29 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, } else { - my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length); - DBUG_RETURN(TRUE); - } + if(key->type == Key::UNIQUE) + { + if (!is_hash_field_added) + { + add_hash_field(thd, &alter_info->create_list, + create_info->default_table_charset, + *key_info_buffer, key_number); + is_hash_field_added= true;
instead of is_hash_field_added and many add_hash_field() here and there, I'd rather rename the variable to hash_field_needed. And only do hash_field_needed= true. And at the end if (hash_field_needed) add_hash_field(...)
+ } + } + else + { + my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length);
any test cases for this error?
+ DBUG_RETURN(TRUE); + } + } } - key_part_info->length= (uint16) key_part_length; + /* We can not store key_part_length more then 2^16 - 1 in frm + So we will simply make it zero */
Not really. If someone explicitly asks for a long prefix, it should be an error. Like CREATE TABLE (a blob, UNIQUE (a(65537)); -- this is an error
+ if (is_hash_field_added && key_part_length > (2<<16) - 1) + key_part_info->length= 0; + else + key_part_info->length= (uint16) key_part_length; /* Use packed keys for long strings on the first column */ if (!((*db_options) & HA_OPTION_NO_PACK_KEYS) && !((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) && @@ -4122,12 +4237,37 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, if (key->type == Key::UNIQUE && !(key_info->flags & HA_NULL_PART_KEY)) unique_key=1; key_info->key_length=(uint16) key_length; - if (key_length > max_key_length && key->type != Key::FULLTEXT) + if (key_length > max_key_length && key->type != Key::FULLTEXT && + !is_hash_field_added) { my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length); DBUG_RETURN(TRUE); }
+ if (is_hash_field_added) + { + if (key_info->flags & HA_NULL_PART_KEY) + null_fields++; + else + { + uint elements= alter_info->create_list.elements; + Create_field *hash_fld= static_cast<Create_field *>(alter_info-> + create_list.elem(elements -1 )); + hash_fld->flags|= NOT_NULL_FLAG; + hash_fld->pack_flag&= ~FIELDFLAG_MAYBE_NULL; + /* + Althought we do not need default value anywhere in code , but if we create + table with non null long columns , then at the time of insert we get warning. + So default value is used so solve this warning. + Virtual_column_info *default_value= new (thd->mem_root) Virtual_column_info(); + char * def_str= (char *)alloc_root(thd->mem_root, 2); + strncpy(def_str, "0", 1); + default_value->expr_str.str= def_str; + default_value->expr_str.length= 1; + default_value->expr_item= new (thd->mem_root) Item_int(thd,0); + hash_fld->default_value= default_value; */ + }
Forgot to remove it?
+ } if (validate_comment_length(thd, &key->key_create_info.comment, INDEX_COMMENT_MAXLEN, ER_TOO_LONG_INDEX_COMMENT, @@ -8328,6 +8468,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, enum Key::Keytype key_type; LEX_CSTRING tmp_name; bzero((char*) &key_create_info, sizeof(key_create_info)); + if (key_info->flags & HA_LONG_UNIQUE_HASH) + { + key_info->flags&= ~(HA_LONG_UNIQUE_HASH); + key_info->algorithm= HA_KEY_ALG_UNDEF; + }
Why?
key_create_info.algorithm= key_info->algorithm; /* We copy block size directly as some engines, like Area, sets this diff --git a/sql/handler.cc b/sql/handler.cc index b77b2a3fa2c..cda53dfdc87 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6179,6 +6185,185 @@ int handler::ha_reset() DBUG_RETURN(reset()); }
+static int check_duplicate_long_entry_key(TABLE *table, handler *h, uchar *new_rec, + uint key_no) +{ + Field *hash_field; + int result, error= 0; + if (!(table->key_info[key_no].user_defined_key_parts == 1 + && table->key_info[key_no].key_part->field->flags & LONG_UNIQUE_HASH_FIELD )) + return 0;
What if LONG_UNIQUE_HASH_FIELD is set but user_defined_key_parts != 1?
+ hash_field= table->key_info[key_no].key_part->field; + DBUG_ASSERT((table->key_info[key_no].flags & HA_NULL_PART_KEY && + table->key_info[key_no].key_length == HA_HASH_KEY_LENGTH_WITH_NULL) + || table->key_info[key_no].key_length == HA_HASH_KEY_LENGTH_WITHOUT_NULL); + uchar ptr[HA_HASH_KEY_LENGTH_WITH_NULL]; + + if (hash_field->is_real_null()) + return 0; + + key_copy(ptr, new_rec, &table->key_info[key_no], + table->key_info[key_no].key_length, false);
good, use existing function, no need to reinvent the wheel
+ + if (!table->check_unique_buf) + table->check_unique_buf= (uchar *)alloc_root(&table->mem_root, + table->s->reclength*sizeof(uchar)); + + result= h->ha_index_init(key_no, 0); + if (result) + return result; + result= h->ha_index_read_map(table->check_unique_buf, + ptr, HA_WHOLE_KEY, HA_READ_KEY_EXACT); + if (!result) + { + bool is_same; + do + { + Item_func_or_sum * temp= static_cast<Item_func_or_sum *>(hash_field-> + vcol_info->expr); + Item_args * t_item= static_cast<Item_args *>(temp); + uint arg_count= t_item->argument_count(); + Item ** arguments= t_item->arguments(); + long diff= table->check_unique_buf - new_rec; + Field * t_field; + is_same= true; + for (uint j=0; j < arg_count; j++) + { + DBUG_ASSERT(arguments[j]->type() == Item::FIELD_ITEM || + // this one for left(fld_name,length) + arguments[j]->type() == Item::FUNC_ITEM); + if (arguments[j]->type() == Item::FIELD_ITEM) + { + t_field= static_cast<Item_field *>(arguments[j])->field; + if (t_field->cmp_offset(diff)) + is_same= false; + } + else + { + Item_func_left *fnc= static_cast<Item_func_left *>(arguments[j]); + DBUG_ASSERT(!my_strcasecmp(system_charset_info, "left", fnc->func_name())); + //item_data= fnc->val_str(&tmp1); + DBUG_ASSERT(fnc->arguments()[0]->type() == Item::FIELD_ITEM); + t_field= static_cast<Item_field *>(fnc->arguments()[0])->field; + // field_data= t_field->val_str(&tmp2); + // if (my_strnncoll(t_field->charset(),(const uchar *)item_data->ptr(), + // item_data->length(), + // (const uchar *)field_data.ptr(), + // item_data->length())) + // return 0; + uint length= fnc->arguments()[1]->val_int(); + if (t_field->cmp_max(t_field->ptr, t_field->ptr + diff, length)) + is_same= false; + } + }
you don't need all that code, use key_cmp() or key_cmp_if_same() from key.cc
+ } + while (!is_same && !(result= table->file->ha_index_next_same(table->check_unique_buf, + ptr, table->key_info[key_no].key_length))); + if (is_same) + { + table->dupp_hash_key= key_no; + error= HA_ERR_FOUND_DUPP_KEY; + goto exit; + } + else + goto exit; + } + if (result == HA_ERR_LOCK_WAIT_TIMEOUT) + { + table->dupp_hash_key= key_no; + //TODO check if this is the only case + error= HA_ERR_FOUND_DUPP_KEY;
Why?
+ } + exit: + h->ha_index_end(); + return error; +} +/** @brief + check whether inserted/updated records breaks the + unique constraint on long columns. + In the case of update we just need to check the specic key + reason for that is consider case + create table t1(a blob , b blob , x blob , y blob ,unique(a,b) + ,unique(x,y)) + and update statement like this + update t1 set a=23+a; in this case if we try to scan for + whole keys in table then index scan on x_y will return 0 + because data is same so in the case of update we take + key as a parameter in normal insert key should be -1 + @returns 0 if no duplicate else returns error + */ +static int check_duplicate_long_entries(TABLE *table, handler *h, uchar *new_rec) +{ + table->dupp_hash_key= -1; + int result; + for (uint i= 0; i < table->s->keys; i++) + { + if ((result= check_duplicate_long_entry_key(table, h, new_rec, i))) + return result; + } + return 0; +} + +/** @brief + check whether updated records breaks the + unique constraint on long columns. + @returns 0 if no duplicate else returns error + */ +static int check_duplicate_long_entries_update(TABLE *table, handler *h, uchar *new_rec) +{ + Field **f, *field; + Item *h_item; + int error= 0; + bool is_update_handler_null= false; + /* + Here we are comparing whether new record and old record are same + with respect to fields in hash_str + */ + long reclength= table->record[1]-table->record[0]; + for (uint i= 0; i < table->s->keys; i++) + { + if (table->key_info[i].user_defined_key_parts == 1 && + table->key_info[i].key_part->field->flags & LONG_UNIQUE_HASH_FIELD) + { + /* + Currently mysql_update is pacthed so that it will automatically set the + Update handler and then free it but ha_update_row is used in many function ( + like in case of reinsert) Instead of patching them all here we check is + update_handler is null then set it And then set it null again + */ + if (!table->update_handler) + { + create_update_handler(current_thd, table); + is_update_handler_null= true; + } + h_item= table->key_info[i].key_part->field->vcol_info->expr; + for (f= table->field; f && (field= *f); f++) + { + if ( find_field_pos_in_hash(h_item, field->field_name.str) != -1) + { + /* Compare fields if they are different then check for duplicates*/ + if(field->cmp_binary_offset(reclength)) + { + if((error= check_duplicate_long_entry_key(table, table->update_handler, + new_rec, i))) + goto exit; + /* + break beacuse check_duplicate_long_entrie_key will + take care of remaning fields + */ + break; + } + } + } + } + } + exit: + if (is_update_handler_null) + { + delete_update_handler(current_thd, table); + } + return error; +}
int handler::ha_write_row(uchar *buf) { @@ -6189,14 +6374,21 @@ int handler::ha_write_row(uchar *buf) DBUG_ENTER("handler::ha_write_row"); DEBUG_SYNC_C("ha_write_row_start");
+ setup_table_hash(table);
No-no. You cannot modify table structure back and forth for *every inserted row*. It's ok to do it once, when a table is opened. But not for every row,
MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str); mark_trx_read_write(); increment_statistics(&SSV::ha_write_count);
+ if ((error= check_duplicate_long_entries(table, table->file, buf))) + { + re_setup_table(table); + DBUG_RETURN(error); + } TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_WRITE_ROW, MAX_KEY, 0, { error= write_row(buf); })
MYSQL_INSERT_ROW_DONE(error); + re_setup_table(table); if (likely(!error) && !row_already_logged) { rows_changed++;
Regards, Sergei Chief Architect MariaDB and security@mariadb.org
participants (1)
-
Sergei Golubchik