Hi Sergei! Actually I implemented optimization on where with update and delete , with minimal changes on optimizer. Also now we can use optimization in joins, select including subquery etc. I haven't written much test case, but I will write it soon. Please review it. Regards sachin On Wed, Sep 7, 2016 at 11:06 PM, Sachin Setia <sachinsetia1001@gmail.com> wrote:
Hi Sergei!
This code is about adding new long unique key, This is a section of code from mysql_prepare_create_table, The main problem is can we make this code more shorter ? And the reason for this code is that we need to add Alter_info::ALTER_ADD_CHECK_CONSTRAINT , only if there is unique key on long columns
Query statements can be like this
alter table t1 add unique key a; // here a is blob
or
alter table t1 add b blob unique; alter table t1 add c varchar(1000) unique;
This is code
{ Key *key; while ((key=key_it++)) // Add new keys { if (key->type == Key::FOREIGN_KEY && ((Foreign_key *)key)->validate(new_create_list)) goto err;
from here ==> if (key->type == Key::UNIQUE) { List_iterator_fast<Key_part_spec> li(key->columns); Key_part_spec *column; uint total_length= 0; Field **f, *field; Create_field *cf; bool is_hash_key= false; while ((column= li++)) { if (column->length > table->file->max_key_part_length()) { is_hash_key= true; break; } else if (!column->length) { for (f= table->field; f && (field= *f); f++) { if (!my_strcasecmp(system_charset_info, field->field_name, column->field_name.str)) { if (field->max_display_length() > table->file->max_key_part_length()) { is_hash_key= true; goto exit; } total_length+= field->max_display_length(); } } /* Suppose query is like alter table t1 add column a blob unique; alter table t2 add column a blob,add column c blob, add unique key(a,b); In this case we have to add ALTER_ADD_CHECK_CONSTRAINT_FLAG We cant simply add ALTER_ADD_CHECK_CONSTRAINT flag because it is expensive. And there is no other way of doing this type of check. */ field_it.rewind(); while((cf= field_it++)) { if (!my_strcasecmp(system_charset_info, cf->field_name, column->field_name.str)) { if (cf->sql_type == MYSQL_TYPE_TINY_BLOB || cf->sql_type == MYSQL_TYPE_MEDIUM_BLOB || cf->sql_type == MYSQL_TYPE_LONG_BLOB || cf->sql_type == MYSQL_TYPE_BLOB) { is_hash_key= true; break; } if ((cf->sql_type == MYSQL_TYPE_VARCHAR || cf->sql_type == MYSQL_TYPE_VAR_STRING) && cf->length > table->file->max_key_part_length()) { is_hash_key= true; break; } total_length+= cf->length; } } } } exit: if (is_hash_key || total_length > table->file->max_key_length()) { alter_info->flags |= Alter_info::ALTER_ADD_CHECK_CONSTRAINT; alter_info->flags |= Alter_info::ALTER_ADD_COLUMN; } } new_key_list.push_back(key, thd->mem_root); if (key->name.str && !my_strcasecmp(system_charset_info, key->name.str, primary_key_name)) { my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str); goto err; } } }
On Wed, Aug 31, 2016 at 8:49 PM, sachin setiya <sachinsetia1001@gmail.com> wrote:
Hi Sergei!
On 08/24/2016 11:05 PM, Sergei Golubchik wrote:
Hi, Sachin!
On Aug 13, Sachin Setia wrote:
Hello Sergei! Please review commit 71f9069 onward i have changed mysql_prepare_alter_table func.
Okay, here it is. Up to the 03e29c6 (this is one after 71f9069).
Short summary - this all looks pretty good. There're issues, but as a whole - great work!
diff --git a/include/my_base.h b/include/my_base.h index 1317639..d03ca0f 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -241,6 +241,19 @@ enum ha_base_keytype { HA_KEYTYPE_BIT=19 };
+/* Add some constant related to unique long hash column like length hash string etc*/ + +#define HA_HASH_KEY_LENGTH_WITHOUT_NULL 8 +#define HA_HASH_FIELD_LENGTH 8 +#define HA_HASH_KEY_LENGTH_WITH_NULL 9 +#define HA_HASH_STR_HEAD "hash(`" //used in mysql_prepare_create_table +#define HA_HASH_STR_HEAD_LEN strlen(HA_HASH_STR_HEAD_LEN) +#define HA_HASH_STR "hash" +#define HA_HASH_STR_LEN strlen(HA_HASH_STR) +#define HA_HASH_STR_INDEX "HASH_INDEX" +#define HA_HASH_STR_INDEX_LEN strlen(HA_HASH_STR_INDEX) +#define HA_DB_ROW_HASH_STR "DB_ROW_HASH_"
no need to put all these constants into the very global my_base.h. better to define them in sql_show.cc or sql_table.cc (depending on where they're used)
Actually first three are needed in files like opt_range.cc. I moved this to table.h
+ #define HA_MAX_KEYTYPE 31 /* Must be log2-1 */
/* diff --git a/mysql-test/r/features.result b/mysql-test/r/features.result index 52650d1..e050efb 100644 --- a/mysql-test/r/features.result +++ b/mysql-test/r/features.result @@ -7,6 +7,7 @@ Feature_delay_key_write 0 Feature_dynamic_columns 0 Feature_fulltext 0 Feature_gis 0 +Feature_hidden_column 0
Great! Please, add also a test where it's not 0. I mean, in your hidden_field.test you can add
FLUSH STATUS;
at the beginning of the file and SHOW STATUS LIKE 'Feature_hidden_column'; somewhere later. This will show that Feature_hidden_column is incremented accordingly.
Done.
Feature_locale 0 Feature_subquery 0 Feature_timezone 0 diff --git a/mysql-test/r/hidden_field.result b/mysql-test/r/hidden_field.result new file mode 100644 index 0000000..09a2c21 --- /dev/null +++ b/mysql-test/r/hidden_field.result @@ -0,0 +1,367 @@ +create table h_1(abc int primary key, xyz int hidden); +desc h_1; +Field Type Null Key Default Extra +abc int(11) NO PRI NULL +xyz int(11) YES NULL HIDDEN +show create table h_1; +Table Create Table +h_1 CREATE TABLE `h_1` ( + `abc` int(11) NOT NULL, + `xyz` int(11) HIDDEN DEFAULT NULL, + PRIMARY KEY (`abc`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table h_1; +create table h_2(a1 int hidden); +ERROR 42000: A table must have at least 1 column +create table h_3(a1 blob,hidden(a1)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'hidden(a1))' at line 1 +create table h_4(a1 int primary key hidden ,a2 int unique hidden , a3 blob,a4 +int not null hidden unique); +ERROR HY000: Hidden column 'a1' either allow null values or it must have default value +create table h_5(abc int not null hidden); +ERROR HY000: Hidden column 'abc' either allow null values or it must have default value +create table t1(a int hidden, b int); +insert into t1 values(1); +insert into t1(a) values(1); +insert into t1(b) values(1);
better insert 1,2,3 not 1,1,1 so that in SELECT you could unambigously see what INSERT has added what row
Changed.
+insert into t1(a,b) values(5,5); +select * from t1; +b +1 +NULL +1 +5 +select a,b from t1; +a b +NULL 1 +1 NULL +NULL 1 +5 5 +delete from t1; +insert into t1 values(1),(2),(3),(4); +select * from t1; +b +1 +2 +3 +4 +select a from t1; +a +NULL +NULL +NULL +NULL +drop table t1; +create table t1(a int , b int hidden , c int hidden auto_increment unique, d blob , e int unique, f int); +desc t1; +Field Type Null Key Default Extra +a int(11) YES NULL +b int(11) YES NULL HIDDEN +c int(11) NO PRI NULL auto_increment , HIDDEN
why a space before the comma?
Okay Reverted.
+d blob YES NULL +e int(11) YES UNI NULL +f int(11) YES NULL +insert into t1 values(1,'d blob',1,1),(1,'d blob',11,1),(1,'d blob',2,1),(1,'d blob',3,1),(1,'d blob',41,1); +select * from t1; +a d e f +1 d blob 1 1 +1 d blob 11 1 +1 d blob 2 1 +1 d blob 3 1 +1 d blob 41 1 +drop table t1; +create table sdsdsd(a int , b int, hidden(a,b)); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'hidden(a,b))' at line 1 +create table t1(a int,abc int as (a mod 3) virtual hidden); +desc t1; +Field Type Null Key Default Extra +a int(11) YES NULL +abc int(11) YES NULL VIRTUAL , HIDDEN +insert into t1 values(1,default); +ERROR 21S01: Column count doesn't match value count at row 1 +insert into t1 values(1),(22),(233); +select * from t1; +a +1 +22 +233 +select a,abc from t1; +a abc +1 1 +22 1 +233 2 +drop table t1; +create table t1(abc int primary key hidden auto_increment, a int); +desc t1; +Field Type Null Key Default Extra +abc int(11) NO PRI NULL auto_increment , HIDDEN +a int(11) YES NULL +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `abc` int(11) NOT NULL HIDDEN AUTO_INCREMENT, + `a` int(11) DEFAULT NULL, + PRIMARY KEY (`abc`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 values(1); +insert into t1 values(2); +insert into t1 values(3); +select * from t1; +a +1 +2 +3 +select abc,a from t1; +abc a +1 1 +2 2 +3 3 +delete from t1; +insert into t1 values(1),(2),(3),(4),(6); +select abc,a from t1; +abc a +4 1 +5 2 +6 3 +7 4 +8 6 +drop table t1; +create table t1(abc int); +alter table t1 change abc ss int hidden; +ERROR 42000: A table must have at least 1 column +alter table t1 add column xyz int; +alter table t1 modify column abc int ; +desc t1; +Field Type Null Key Default Extra +abc int(11) YES NULL +xyz int(11) YES NULL +insert into t1 values(22); +ERROR 21S01: Column count doesn't match value count at row 1 +alter table t1 modify column abc int hidden;
please, add also tests for making hidden fields visible again. I think that
alter table t1 modify column abc int;
will do the job
Okay, Added.
+desc t1; +Field Type Null Key Default Extra +abc int(11) YES NULL HIDDEN +xyz int(11) YES NULL +insert into t1 values(12); +drop table t1; +some test on copy table structure with table data; +table with hidden fields and unique keys; +create table t1(a int , b int hidden , c int hidden auto_increment unique, d blob , e int unique, f int); +desc t1; +Field Type Null Key Default Extra +a int(11) YES NULL +b int(11) YES NULL HIDDEN +c int(11) NO PRI NULL auto_increment , HIDDEN +d blob YES NULL +e int(11) YES UNI NULL +f int(11) YES NULL +insert into t1 values(1,'d blob',1,1),(1,'d blob',11,1),(1,'d blob',2,1),(1,'d blob',3,1),(1,'d blob',41,1); +select * from t1; +a d e f +1 d blob 1 1 +1 d blob 11 1 +1 d blob 2 1 +1 d blob 3 1 +1 d blob 41 1 +select a,b,c,d,e,f from t1; +a b c d e f +1 NULL 1 d blob 1 1 +1 NULL 2 d blob 11 1 +1 NULL 3 d blob 2 1 +1 NULL 4 d blob 3 1 +1 NULL 5 d blob 41 1 +this wont copy hidden fields and keys; +create table t2 as select * from t1; +desc t2; +Field Type Null Key Default Extra +a int(11) YES NULL +d blob YES NULL +e int(11) YES NULL +f int(11) YES NULL +select * from t2; +a d e f +1 d blob 1 1 +1 d blob 11 1 +1 d blob 2 1 +1 d blob 3 1 +1 d blob 41 1 +select a,b,c,d,e,f from t2; +ERROR 42S22: Unknown column 'b' in 'field list' +drop table t2; +now this will copy hidden fields +create table t2 as select a,b,c,d,e,f from t1; +desc t2; +Field Type Null Key Default Extra +a int(11) YES NULL +b int(11) YES NULL HIDDEN +c int(11) NO 0 HIDDEN +d blob YES NULL +e int(11) YES NULL +f int(11) YES NULL +select * from t2; +a d e f +1 d blob 1 1 +1 d blob 11 1 +1 d blob 2 1 +1 d blob 3 1 +1 d blob 41 1 +select a,b,c,d,e,f from t2; +a b c d e f +1 NULL 1 d blob 1 1 +1 NULL 2 d blob 11 1 +1 NULL 3 d blob 2 1 +1 NULL 4 d blob 3 1 +1 NULL 5 d blob 41 1 +drop table t2,t1; +some test related to copy of data from one table to another; +create table t1(a int , b int hidden , c int hidden auto_increment unique, d blob , e int unique, f int); +insert into t1 values(1,'d blob',1,1),(1,'d blob',11,1),(1,'d blob',2,1),(1,'d blob',3,1),(1,'d blob',41,1); +select a,b,c,d,e,f from t1; +a b c d e f +1 NULL 1 d blob 1 1 +1 NULL 2 d blob 11 1 +1 NULL 3 d blob 2 1 +1 NULL 4 d blob 3 1 +1 NULL 5 d blob 41 1 +create table t2(a int , b int hidden , c int hidden , d blob , e int unique, f int); +insert into t2 select * from t1; +select a,b,c,d,e,f from t2; +a b c d e f +1 NULL NULL d blob 1 1 +1 NULL NULL d blob 11 1 +1 NULL NULL d blob 2 1 +1 NULL NULL d blob 3 1 +1 NULL NULL d blob 41 1 +truncate t2; +insert into t2 (a,b,c,d,e,f) select a,b,c,d,e,f from t1; +select a,b,c,d,e,f from t2; +a b c d e f +1 NULL 1 d blob 1 1 +1 NULL 2 d blob 11 1 +1 NULL 3 d blob 2 1 +1 NULL 4 d blob 3 1 +1 NULL 5 d blob 41 1 +truncate t2; +drop table t1,t2; +some test related to creating view on table with hidden column; +create table t1(a int , b int hidden , c int hidden auto_increment unique, d blob , e int unique, f int); +insert into t1 values(1,'d blob',1,1),(1,'d blob',11,1),(1,'d blob',2,1),(1,'d blob',3,1),(1,'d blob',41,1); +create view v as select * from t1; +desc v; +Field Type Null Key Default Extra +a int(11) YES NULL +d blob YES NULL +e int(11) YES NULL +f int(11) YES NULL +select * from v; +a d e f +1 d blob 1 1 +1 d blob 11 1 +1 d blob 2 1 +1 d blob 3 1 +1 d blob 41 1 +v does not have hidden column; +select a,b,c,d,e,f from v; +ERROR 42S22: Unknown column 'b' in 'field list' +insert into v values(1,21,32,4); +select * from v; +a d e f +1 d blob 1 1 +1 d blob 11 1 +1 d blob 2 1 +1 d blob 3 1 +1 d blob 41 1 +1 21 32 4 +insert into v(a,b,c,d,e,f) values(1,12,3,4,5,6); +ERROR 42S22: Unknown column 'b' in 'field list' +drop view v; +create view v as select a,b,c,d,e,f from t1; +desc v; +Field Type Null Key Default Extra +a int(11) YES NULL +b int(11) YES NULL HIDDEN +c int(11) NO 0 HIDDEN +d blob YES NULL +e int(11) YES NULL +f int(11) YES NULL +select * from v; +a b c d e f +1 NULL 1 d blob 1 1 +1 NULL 2 d blob 11 1 +1 NULL 3 d blob 2 1 +1 NULL 4 d blob 3 1 +1 NULL 5 d blob 41 1 +1 NULL 6 21 32 4 +v does have hidden column; +select a,b,c,d,e,f from v; +a b c d e f +1 NULL 1 d blob 1 1 +1 NULL 2 d blob 11 1 +1 NULL 3 d blob 2 1 +1 NULL 4 d blob 3 1 +1 NULL 5 d blob 41 1 +1 NULL 6 21 32 4 +insert into v values(1,26,33,4,45,66); +select a,b,c,d,e,f from v; +a b c d e f +1 NULL 1 d blob 1 1 +1 NULL 2 d blob 11 1 +1 NULL 3 d blob 2 1 +1 NULL 4 d blob 3 1 +1 NULL 5 d blob 41 1 +1 NULL 6 21 32 4 +1 26 33 4 45 66 +insert into v(a,b,c,d,e,f) values(1,32,31,41,5,6); +select a,b,c,d,e,f from v; +a b c d e f +1 NULL 1 d blob 1 1 +1 NULL 2 d blob 11 1 +1 NULL 3 d blob 2 1 +1 NULL 4 d blob 3 1 +1 NULL 5 d blob 41 1 +1 NULL 6 21 32 4 +1 26 33 4 45 66 +1 32 31 41 5 6 +drop view v; +drop table t1; +now hidden column in where and some join query i think no use of this test but anyway; +create table t1 (a int unique , b int hidden unique, c int unique hidden); +insert into t1(a,b,c) values(1,1,1); +insert into t1(a,b,c) values(2,2,2); +insert into t1(a,b,c) values(3,3,3); +insert into t1(a,b,c) values(4,4,4); +insert into t1(a,b,c) values(21,21,26); +insert into t1(a,b,c) values(31,31,35); +insert into t1(a,b,c) values(41,41,45); +insert into t1(a,b,c) values(22,22,24); +insert into t1(a,b,c) values(32,32,33); +insert into t1(a,b,c) values(42,42,43); +explain select * from t1 where b=3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const b b 5 const 1 +select * from t1 where b=3; +a +3 +explain select * from t1 where c=3; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const c c 5 const 1 +select * from t1 where c=3; +a +3 +create table t2 as select a,b,c from t1; +desc t2; +Field Type Null Key Default Extra +a int(11) YES NULL +b int(11) YES NULL HIDDEN +c int(11) YES NULL HIDDEN +explain select * from t1,t2 where t1.b = t2.c and t1.c = t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 10 +1 SIMPLE t1 ALL b,c NULL NULL NULL 10 Using where; Using join buffer (flat, BNL join) +select * from t1,t2 where t1.b = t2.c and t1.c = t2.b; +a a +1 1 +2 2 +3 3 +4 4 +drop table t1,t2; diff --git a/mysql-test/r/long_unique_where.result b/mysql-test/r/long_unique_where.result new file mode 100644 index 0000000..e9bd416 --- /dev/null +++ b/mysql-test/r/long_unique_where.result @@ -0,0 +1,340 @@ +create table t1(abc blob unique); +insert into t1 values(1),(2),(3),(4),(5),(11),(12),(31),(14),(15),(NULL) +,(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL), +(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL), +(NULL),(NULL),(NULL),(NULL),(NULL); +insert into t1 value(1); +ERROR 23000: Duplicate entry '1' for key 'abc' +explain select * from t1 where abc=31; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const abc abc 9 const 1 +select * from t1 where abc=31; +abc +31 +# in case of null we do not use any optimization +explain select * from t1 where abc is NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 36 Using where +select * from t1 where abc is NULL limit 1; +abc +NULL +#range query
please clarify it here, for example, like
#range query (index not used, because it's a hash)
Copied , :).
+explain select * from t1 where abc >1 limit 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 36 Using where +select * from t1 where abc >1 limit 1; +abc +2 +explain select * from t1 where abc >1 and abc <4; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 36 Using where +select * from t1 where abc >1 and abc <4; +abc +2 +3 +explain select * from t1 where abc =15 or abc <4 ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 36 Using where +select * from t1 where abc =15 or abc <4 ; +abc +1 +2 +3 +15 +drop table t1; +create table t1(abc blob unique, xyz int ); +insert into t1 values(1,1),(2,1),(3,3),(4,1),(5,6),(NULL,3),(NULL,1), +(NULL,NULL),(11,11),(12,11),(31,31), +(14,1),(15,61),(NULL,32),(NULL,12),(NULL,NULL); +insert into t1 value(1,NULL); +ERROR 23000: Duplicate entry '1' for key 'abc' +explain select * from t1 where abc=15; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const abc abc 9 const 1 +select * from t1 where abc= 15; +abc xyz +15 61 +explain select * from t1 where abc=15 and xyz =61; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const abc abc 9 const 1 +select * from t1 where abc= 15 and 61;
type in the where clause
Changed.
+abc xyz +15 61 +# now xyz has different value
what do you mean by that?
echo # now xyz has a value which is not present in table; Added.
+explain select * from t1 where abc=1000; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +select * from t1 where abc= 1000; +abc xyz +explain select * from t1 where abc=14 and xyz =56; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +select * from t1 where abc=14 and xyz =56; +abc xyz +#range query +explain select * from t1 where abc >5 limit 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 16 Using where +select * from t1 where abc >5 limit 1; +abc xyz +11 11 +explain select * from t1 where abc=5 and xyz <56; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const abc abc 9 const 1 +select * from t1 where abc=5 and xyz <56; +abc xyz +5 6 +explain select * from t1 where abc>=5 and xyz <56; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 16 Using where +select * from t1 where abc>=5 and xyz <56; +abc xyz +5 6 +11 11 +12 11 +31 31 +14 1 +explain select * from t1 where abc>5 and xyz =56; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 16 Using where +select * from t1 where abc>5 and xyz =56; +abc xyz +drop table t1; +create table t1(abc blob unique, xyz blob unique ); +insert into t1 values(1,1),(2,11),(3,31),(4,12),(5,63),(NULL,2),(NULL,NULL), +(91,19),(92,119),(93,391),(94,192),(95,693); +insert into t1 value(1,NULL); +ERROR 23000: Duplicate entry '1' for key 'abc' +explain select * from t1 where abc=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const abc abc 9 const 1 +select * from t1 where abc=1; +abc xyz +1 1 +explain select * from t1 where xyz=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const xyz xyz 9 const 1 +select * from t1 where xyz=1; +abc xyz +1 1 +explain select * from t1 where abc=5 and xyz=63; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const abc abc 9 const 1 +select * from t1 where abc=5 and xyz=63; +abc xyz +5 63 +explain select * from t1 where xyz=63 and abc=5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const abc abc 9 const 1 +select * from t1 where xyz=63 and abc=5; +abc xyz +5 63 +explain select * from t1 where xyz=63 or abc=5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where +select * from t1 where xyz=63 or abc=5; +abc xyz +5 63 +# now the first one does not exist +explain select * from t1 where abc=51 and xyz=63; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +select * from t1 where abc=51 and xyz=63; +abc xyz +# now the second one does not exist +explain select * from t1 where abc=5 and xyz=613; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +select * from t1 where abc=5 and xyz=613; +abc xyz +explain select * from t1 where abc is NULL; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where +select * from t1 where abc is NULL; +abc xyz +NULL 2 +NULL NULL +explain select * from t1 where abc is NULL and xyz=2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const xyz xyz 9 const 1 +select * from t1 where abc is NULL and xyz=2; +abc xyz +NULL 2 +#range conditions +explain select * from t1 where abc>11 limit 5; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where +select * from t1 where abc>11 limit 5; +abc xyz +91 19 +92 119 +93 391 +94 192 +95 693 +explain select * from t1 where xyz<11; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where +select * from t1 where xyz<11; +abc xyz +1 1 +NULL 2 +explain select * from t1 where abc>=51 and xyz<=63; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where +select * from t1 where abc>=51 and xyz<=63; +abc xyz +91 19 +explain select * from t1 where abc>5 and xyz<613; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where +select * from t1 where abc>5 and xyz<613; +abc xyz +91 19 +92 119 +93 391 +94 192 +explain select * from t1 where abc=5 and xyz>1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const abc abc 9 const 1 +select * from t1 where abc=5 and xyz>1; +abc xyz +5 63 +explain select * from t1 where abc<55 and xyz=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const xyz xyz 9 const 1 +select * from t1 where abc<55 and xyz=1; +abc xyz +1 1 +explain select * from t1 where abc<=55 or xyz>=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 12 Using where +select * from t1 where abc<=55 and xyz>=1; +abc xyz +1 1 +2 11 +3 31 +4 12 +5 63 +drop table t1; +#now the unique (a,b,c..........) +#let us do more hard test by using unique(a,b,c,d) key first +create table t1 (a blob , b blob , c blob , d blob ,unique(a,b,c,d), +unique(a,b,c) ,unique (b,c,d));
hmm, better do not use redundant keys. it works now, but tenchnically we can implement the optimization where the server will internally remove "unique(a,b,c,d)" - will store it in the frm, but won't tell the engine about it - because unique(a,b,c) guarantees that (a,b,c,d) is *always* unique.
so, if we add this optimization someday your test case will no longer test what it was supposed to.
Okay , Changed.
+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, + UNIQUE KEY `a_b_c_d`(`a`,`b`,`c`,`d`), + UNIQUE KEY `a_b_c`(`a`,`b`,`c`), + UNIQUE KEY `b_c_d`(`b`,`c`,`d`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +insert into t1 values(1,1,1,1),(2,1,2,1),(1,3,3,1),(4,1,4,1),(1,5,1,5), +(6,1,6,1),(1,7,1,7),(8,1,1,8),(1,9,9,1),(2,2,2,2),(4,4,4,4),(5,5,5,5),(6,6,6,6), +(126,216,603,640),(603,460,660,706),(806,609,609,605),(62,62,22,33),(64,65,66,76), +(16,26,63,64),(63,46,66,76),(86,69,69,65),(622,622,622,633),(644,655,666,776); +select * from t1 limit 3; +a b c d +1 1 1 1 +2 1 2 1 +1 3 3 1 +#simple where +#key (a,b,c) +explain select * from t1 where a=1 and b=1 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const a_b_c a_b_c 9 const 1 +select * from t1 where a=1 and b=1 and c=1; +a b c d +1 1 1 1 +explain select * from t1 where a=1 and b=4444 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +select * from t1 where a=1 and b=4444 and c=1; +a b c d +#incomplete key +explain select * from t1 where a=1 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 23 Using where +select * from t1 where a=1 and c=1; +a b c d +1 1 1 1 +1 5 1 5 +1 7 1 7 +explain select * from t1 where a=1 and b=4444 ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 23 Using where +select * from t1 where a=1 and b=4444 ; +a b c d +explain select * from t1 where b=1 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 23 Using where +select * from t1 where b=1 and c=1; +a b c d +1 1 1 1 +8 1 1 8 +#key (b,c,d) +explain select * from t1 where d=1 and b=1 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const b_c_d b_c_d 9 const 1 +select * from t1 where d=1 and b=1 and c=1; +a b c d +1 1 1 1 +explain select * from t1 where d=1 and b=4444 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +select * from t1 where d=1 and b=4444 and c=1; +a b c d +#incomplete key +explain select * from t1 where d=1 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 23 Using where +select * from t1 where d=1 and c=1; +a b c d +1 1 1 1 +explain select * from t1 where d=1 and b=4444 ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 23 Using where +select * from t1 where d=1 and b=4444 ; +a b c d +explain select * from t1 where b=1 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 23 Using where +select * from t1 where b=1 and c=1; +a b c d +1 1 1 1 +8 1 1 8 +#key (a,b,c,d) +explain select * from t1 where a=1 and d=1 and b=1 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 const a_b_c_d a_b_c_d 9 const 1 +select * from t1 where a=1 and d=1 and b=1 and c=1; +a b c d +1 1 1 1 +explain select * from t1 where a=1 and d=1 and b=4444 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +select * from t1 where a=1 and d=1 and b=4444 and c=1; +a b c d +#incomplete key +explain select * from t1 where a=1 and d=1 and c=1 ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 23 Using where +select * from t1 where a=1 and d=1 and c=1 ; +a b c d +1 1 1 1 +explain select * from t1 where d=1 and b=4444 and a=1 ; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 23 Using where +select * from t1 where d=1 and b=4444 and a=1 ; +a b c d +explain select * from t1 where a=1 and c=1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 23 Using where +select * from t1 where a=1 and c=1; +a b c d +1 1 1 1 +1 5 1 5 +1 7 1 7 +drop table t1; diff --git a/mysql-test/r/long_uniques.result b/mysql-test/r/long_uniques.result new file mode 100644 index 0000000..e410fc1 --- /dev/null +++ b/mysql-test/r/long_uniques.result @@ -0,0 +1,1163 @@ +#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 +#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;
for these statements, use "query_vertical" prefix, like
query_vertical show keys from t1;
it works better when the result has only few (best: one) row
Added.
+Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 a 1 a A 0 NULL NULL YES HASH_INDEX
here, notice that your index is shown as "non-unique"
Corrected.
+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 +def test t1 a 1 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob UNI select,insert,update,references +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 1 test a 1 a 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 +# table select we should not be able to see db_row_hash_column;
"not able to see db_row_hash_1 column"
Changed, Sorry.
+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 'sachi' for key 'a' +insert into t1 values(123456789034567891); +ERROR 23000: Duplicate entry '12345' for key 'a' +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 'mmmmm' 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); +#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`) +) 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`) +) 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 `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `a`(`a`) +) 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 1 clm 1 clm_changed A 0 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
you can use myisamchk to see *actually created* indexes in MYI file. examples are in myisam.test, but in short, it's something like
let datadir=`select @@datadir`; replace_result $datadir DATADIR; exec $MYISAMCHK -d $datadir/test/t1
the first command needs to be done only once, in the beginning of the file, usually. The other pair you do whenever you want to examine the table, like, where you do "desc t1" or "show keys".
Done.
+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 1 a 1 a A 0 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 ('Ä');
good!
+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','ff','fdf','gfgfgfg','hghgr'),('maria','db','frter','dasd','utyuty'), +(123456789034567891,3534534534534,53453453453456,64565464564564,45435345345345), +(123456789034567890,435345345345,657567567567,78967657567567,657567567567567676); +Warnings: +Warning 1366 Incorrect integer value: 'ff' for column 'b' at row 5 +Warning 1366 Incorrect integer value: 'db' for column 'b' at row 6 +Warning 1264 Out of range value for column 'b' at row 7 +Warning 1264 Out of range value for column 'b' at row 8
did you really need to insert invalid values in this test?
No, I did not see Warning.
+#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 1 a 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 c 1 c A 0 NULL NULL YES HASH_INDEX +t1 1 d 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 e 1 e A 0 NULL NULL YES HASH_INDEX +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 +def test t1 a 1 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob UNI select,insert,update,references +def test t1 b 2 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references +def test t1 c 3 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob UNI select,insert,update,references +def test t1 d 4 NULL YES text 65535 65535 NULL NULL NULL latin1 latin1_swedish_ci text UNI select,insert,update,references +def test t1 e 5 NULL YES varchar 3000 3000 NULL NULL NULL latin1 latin1_swedish_ci varchar(3000) UNI select,insert,update,references +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 1 test a 1 a A 0 NULL NULL YES HASH_INDEX +def test t1 1 test c 1 c A 0 NULL NULL YES HASH_INDEX +def test t1 1 test d 1 d A 0 NULL NULL YES HASH_INDEX +def test t1 1 test e 1 e 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 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_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 0 fdf gfgfgfg hghgr +maria 0 frter dasd utyuty +123456789034567891 2147483647 53453453453456 64565464564564 45435345345345 +123456789034567890 2147483647 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 'sachi' for key 'a' +insert into t1 values(1234567890345671890,4353453453451,6575675675617,789676575675617,657567567567567676); +ERROR 23000: Duplicate entry '65756' 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 0 fdf gfgfgfg hghgr +maria 0 frter dasd utyuty +123456789034567891 2147483647 53453453453456 64565464564564 45435345345345 +123456789034567890 2147483647 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',401)); +insert into t1 values(repeat('m',4000*11),10,repeat('s',4000*11),repeat('s',4000*11),repeat('s',400)); +ERROR 23000: Duplicate entry 'sssss' for key 'e'
400 characters (that you insert into 'e') - that looks a bit too short for varchar(3000). Why wouldn't you insert, say, 2990 characters? 400 is something that even b-tree can handle, I suspect.
Changed.
+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`), + UNIQUE KEY `c`(`c`), + UNIQUE KEY `d`(`d`), + 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`), + UNIQUE KEY `c`(`c`), + UNIQUE KEY `d`(`d`), + 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 `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`), + UNIQUE KEY `a`(`a`), + UNIQUE KEY `c`(`c`), + UNIQUE KEY `d`(`d`), + UNIQUE KEY `e`(`e`) +) 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; +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 `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`), + 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 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 1 d 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 e 1 e A 0 NULL NULL YES HASH_INDEX +#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 `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`), + UNIQUE KEY `d`(`d`), + UNIQUE KEY `e`(`e`), + 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 db_row_hash_2 1 db_row_hash_2 A NULL NULL NULL YES BTREE +t1 1 d 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 e 1 e A 0 NULL NULL YES HASH_INDEX +t1 1 a 1 a A 0 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 `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`), + UNIQUE KEY `e` (`e`), + UNIQUE KEY `a` (`a`), + UNIQUE KEY `d`(`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 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 e 1 e A NULL NULL NULL YES BTREE +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 d 1 d A 0 NULL NULL YES HASH_INDEX +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 `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`), + UNIQUE KEY `e` (`e`), + UNIQUE KEY `a` (`a`), + UNIQUE KEY `d`(`d`), + 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 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 e 1 e A NULL NULL NULL YES BTREE +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 d 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 clm1 1 clm_changed1 A 0 NULL NULL YES HASH_INDEX +t1 1 clm2 1 clm_changed2 A 0 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 `db_row_hash_1` (`db_row_hash_1`), + UNIQUE KEY `db_row_hash_2` (`db_row_hash_2`), + UNIQUE KEY `e` (`e`), + UNIQUE KEY `a` (`a`), + UNIQUE KEY `d`(`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 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 e 1 e A NULL NULL NULL YES BTREE +t1 0 a 1 a A NULL NULL NULL YES BTREE +t1 1 d 1 d A 0 NULL NULL YES HASH_INDEX
test also
alter table ... add unique key (blob_column)
in three different variants: 1. there were no duplicates in blob_column, key added successfully, 2. there were duplicates, alter table failed. 3. there were duplicates, ALTER IGNORE TABLE... succeeds
Already added in later commit.
+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(a,b,c,d,e,f),unique(d,e,f,g,h),unique(a,b,c,d,e,f,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'); +#table structure; +desc t1; +Field Type Null Key Default Extra +a blob YES MUL NULL +b int(11) YES NULL +c varchar(2000) YES MUL NULL +d text YES MUL 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_b_c`(`a`,`b`,`c`), + UNIQUE KEY `c_d_e`(`c`,`d`,`e`), + UNIQUE KEY `e_f_g_h`(`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f`(`a`,`b`,`c`,`d`,`e`,`f`), + UNIQUE KEY `d_e_f_g_h`(`d`,`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f_g_h`(`a`,`b`,`c`,`d`,`e`,`f`,`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 1 a_b_c 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 1 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 2 d A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 3 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 1 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 2 f A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 3 g A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 4 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 7 g A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 8 h A 0 NULL NULL YES HASH_INDEX +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 +def test t1 a 1 NULL YES blob 65535 65535 NULL NULL NULL NULL NULL blob MUL select,insert,update,references +def test t1 b 2 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references +def test t1 c 3 NULL YES varchar 2000 2000 NULL NULL NULL latin1 latin1_swedish_ci varchar(2000) MUL select,insert,update,references +def test t1 d 4 NULL YES text 65535 65535 NULL NULL NULL latin1 latin1_swedish_ci text MUL select,insert,update,references +def test t1 e 5 NULL YES varchar 3000 3000 NULL NULL NULL latin1 latin1_swedish_ci varchar(3000) MUL select,insert,update,references +def test t1 f 6 NULL YES longblob 4294967295 4294967295 NULL NULL NULL NULL NULL longblob select,insert,update,references +def test t1 g 7 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references +def test t1 h 8 NULL YES text 65535 65535 NULL NULL NULL latin1 latin1_swedish_ci text select,insert,update,references +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 1 test a_b_c 1 a A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c 2 b A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c 3 c A 0 NULL NULL YES HASH_INDEX +def test t1 1 test c_d_e 1 c A 0 NULL NULL YES HASH_INDEX +def test t1 1 test c_d_e 2 d A 0 NULL NULL YES HASH_INDEX +def test t1 1 test c_d_e 3 e A 0 NULL NULL YES HASH_INDEX +def test t1 1 test e_f_g_h 1 e A 0 NULL NULL YES HASH_INDEX +def test t1 1 test e_f_g_h 2 f A 0 NULL NULL YES HASH_INDEX +def test t1 1 test e_f_g_h 3 g A 0 NULL NULL YES HASH_INDEX +def test t1 1 test e_f_g_h 4 h A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f 1 a A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f 2 b A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f 3 c A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f 4 d A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f 5 e A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f 6 f A 0 NULL NULL YES HASH_INDEX +def test t1 1 test d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +def test t1 1 test d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +def test t1 1 test d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +def test t1 1 test d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +def test t1 1 test d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f_g_h 1 a A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f_g_h 2 b A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f_g_h 3 c A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f_g_h 4 d A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f_g_h 5 e A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f_g_h 6 f A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f_g_h 7 g A 0 NULL NULL YES HASH_INDEX +def test t1 1 test a_b_c_d_e_f_g_h 8 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_b_c def test t1 a 1 NULL NULL NULL NULL +def test a_b_c def test t1 b 2 NULL NULL NULL NULL +def test a_b_c def test t1 c 3 NULL NULL NULL NULL +def test c_d_e def test t1 c 1 NULL NULL NULL NULL +def test c_d_e def test t1 d 2 NULL NULL NULL NULL +def test c_d_e def test t1 e 3 NULL NULL NULL NULL +def test e_f_g_h def test t1 e 1 NULL NULL NULL NULL +def test e_f_g_h def test t1 f 2 NULL NULL NULL NULL +def test e_f_g_h def test t1 g 3 NULL NULL NULL NULL +def test e_f_g_h def test t1 h 4 NULL NULL NULL NULL +def test a_b_c_d_e_f def test t1 a 1 NULL NULL NULL NULL +def test a_b_c_d_e_f def test t1 b 2 NULL NULL NULL NULL +def test a_b_c_d_e_f def test t1 c 3 NULL NULL NULL NULL +def test a_b_c_d_e_f def test t1 d 4 NULL NULL NULL NULL +def test a_b_c_d_e_f def test t1 e 5 NULL NULL NULL NULL +def test a_b_c_d_e_f def test t1 f 6 NULL NULL NULL NULL +def test d_e_f_g_h def test t1 d 1 NULL NULL NULL NULL +def test d_e_f_g_h def test t1 e 2 NULL NULL NULL NULL +def test d_e_f_g_h def test t1 f 3 NULL NULL NULL NULL +def test d_e_f_g_h def test t1 g 4 NULL NULL NULL NULL +def test d_e_f_g_h def test t1 h 5 NULL NULL NULL NULL +def test a_b_c_d_e_f_g_h def test t1 a 1 NULL NULL NULL NULL +def test a_b_c_d_e_f_g_h def test t1 b 2 NULL NULL NULL NULL +def test a_b_c_d_e_f_g_h def test t1 c 3 NULL NULL NULL NULL +def test a_b_c_d_e_f_g_h def test t1 d 4 NULL NULL NULL NULL +def test a_b_c_d_e_f_g_h def test t1 e 5 NULL NULL NULL NULL +def test a_b_c_d_e_f_g_h def test t1 f 6 NULL NULL NULL NULL +def test a_b_c_d_e_f_g_h def test t1 g 7 NULL NULL NULL NULL +def test a_b_c_d_e_f_g_h def test t1 h 8 NULL NULL NULL NULL +# table select we should not be able to see db_row_hash_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 +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_b_c' +insert into t1 values(0,0,1,1,1,0,0,0); +ERROR 23000: Duplicate entry '1-1-1' for key 'c_d_e' +insert into t1 values(0,0,0,0,1,1,1,1); +ERROR 23000: Duplicate entry '1-1-1-1' for key 'e_f_g_h' +insert into t1 values(1,1,1,1,1,0,0,0); +ERROR 23000: Duplicate entry '1-1-1' for key 'a_b_c' +insert into t1 values(0,0,0,0,1,1,1,1); +ERROR 23000: Duplicate entry '1-1-1-1' for key 'e_f_g_h' +insert into t1 values(1,1,1,1,1,1,1,1); +ERROR 23000: Duplicate entry '1-1-1' for key 'a_b_c' +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_b_c`(`a`,`b`,`c`), + UNIQUE KEY `c_d_e`(`c`,`d`,`e`), + UNIQUE KEY `e_f_g_h`(`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f`(`a`,`b`,`c`,`d`,`e`,`f`), + UNIQUE KEY `d_e_f_g_h`(`d`,`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f_g_h`(`a`,`b`,`c`,`d`,`e`,`f`,`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_b_c`(`a`,`b`,`c`), + UNIQUE KEY `c_d_e`(`c`,`d`,`e`), + UNIQUE KEY `e_f_g_h`(`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f`(`a`,`b`,`c`,`d`,`e`,`f`), + UNIQUE KEY `d_e_f_g_h`(`d`,`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f_g_h`(`a`,`b`,`c`,`d`,`e`,`f`,`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 1 a_b_c 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 1 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 2 d A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 3 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 1 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 2 f A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 3 g A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 4 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 7 g A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 8 h A 0 NULL 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_b_c`(`a`,`b`,`c`), + UNIQUE KEY `c_d_e`(`c`,`d`,`e`), + UNIQUE KEY `e_f_g_h`(`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f`(`a`,`b`,`c`,`d`,`e`,`f`), + UNIQUE KEY `d_e_f_g_h`(`d`,`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f_g_h`(`a`,`b`,`c`,`d`,`e`,`f`,`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 1 a_b_c 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 1 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 2 d A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 3 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 1 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 2 f A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 3 g A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 4 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 7 g A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 8 h A 0 NULL 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 `a_b_c`(`aa`,`bb`,`c`), + UNIQUE KEY `c_d_e`(`c`,`dd`,`e`), + UNIQUE KEY `e_f_g_h`(`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f`(`aa`,`bb`,`c`,`dd`,`e`,`f`), + UNIQUE KEY `d_e_f_g_h`(`dd`,`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f_g_h`(`aa`,`bb`,`c`,`dd`,`e`,`f`,`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 1 a_b_c 1 aa A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 2 bb A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 1 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 2 dd A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 3 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 1 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 2 f A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 3 g A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 4 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 1 aa A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 2 bb A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 4 dd A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 1 dd A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 1 aa A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 2 bb A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 4 dd A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 7 g A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 8 h A 0 NULL 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 `a_b_c`(`a`,`b`,`c`), + UNIQUE KEY `c_d_e`(`c`,`d`,`e`), + UNIQUE KEY `e_f_g_h`(`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f`(`a`,`b`,`c`,`d`,`e`,`f`), + UNIQUE KEY `d_e_f_g_h`(`d`,`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f_g_h`(`a`,`b`,`c`,`d`,`e`,`f`,`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 1 a_b_c 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 1 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 2 d A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 3 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 1 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 2 f A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 3 g A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 4 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 7 g A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 8 h A 0 NULL 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 int , modify column b int , modify column c int; +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'maria' +Warning 1292 Truncated incorrect INTEGER value: 'maria' +Warning 1292 Truncated incorrect INTEGER value: 'mariadb' +Warning 1292 Truncated incorrect INTEGER value: 'mariadb' +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL, + `c` int(11) 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_b_c` (`a`,`b`,`c`), + UNIQUE KEY `c_d_e`(`c`,`d`,`e`), + UNIQUE KEY `e_f_g_h`(`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f`(`a`,`b`,`c`,`d`,`e`,`f`), + UNIQUE KEY `d_e_f_g_h`(`d`,`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f_g_h`(`a`,`b`,`c`,`d`,`e`,`f`,`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_b_c 1 a A NULL NULL NULL YES BTREE +t1 0 a_b_c 2 b A NULL NULL NULL YES BTREE +t1 0 a_b_c 3 c A NULL NULL NULL YES BTREE +t1 1 c_d_e 1 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 2 d A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 3 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 1 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 2 f A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 3 g A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 4 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 7 g A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 8 h A 0 NULL 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 `a_b_c`(`a`,`b`,`c`), + UNIQUE KEY `c_d_e`(`c`,`d`,`e`), + UNIQUE KEY `e_f_g_h`(`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f`(`a`,`b`,`c`,`d`,`e`,`f`), + UNIQUE KEY `d_e_f_g_h`(`d`,`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f_g_h`(`a`,`b`,`c`,`d`,`e`,`f`,`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 1 a_b_c 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 1 c A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 2 d A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 3 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 1 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 2 f A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 3 g A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 4 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 1 a A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 2 b A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 3 c A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 4 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 5 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 6 f A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 7 g A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 8 h A 0 NULL NULL YES HASH_INDEX +#try to delete blob column in unique; +truncate table t1; +alter table t1 drop column a, drop column b, drop column c; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `d` blob DEFAULT NULL, + `e` varchar(3000) DEFAULT NULL, + `f` longblob DEFAULT NULL, + `g` int(11) DEFAULT NULL, + `h` text DEFAULT NULL, + UNIQUE KEY `c_d_e`(`d`,`e`), + UNIQUE KEY `e_f_g_h`(`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f`(`d`,`e`,`f`), + UNIQUE KEY `d_e_f_g_h`(`d`,`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f_g_h`(`d`,`e`,`f`,`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 1 c_d_e 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 c_d_e 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 1 e A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 2 f A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 3 g A 0 NULL NULL YES HASH_INDEX +t1 1 e_f_g_h 4 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +#now try to delete keys; +alter table t1 drop key c_d_e, drop key e_f_g_h; +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `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_b_c_d_e_f`(`d`,`e`,`f`), + UNIQUE KEY `d_e_f_g_h`(`d`,`e`,`f`,`g`,`h`), + UNIQUE KEY `a_b_c_d_e_f_g_h`(`d`,`e`,`f`,`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 1 a_b_c_d_e_f 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 1 d A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 2 e A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 3 f A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 4 g A 0 NULL NULL YES HASH_INDEX +t1 1 a_b_c_d_e_f_g_h 5 h A 0 NULL NULL YES HASH_INDEX +drop table t1; diff --git a/mysql-test/t/hidden_field.test b/mysql-test/t/hidden_field.test new file mode 100644 index 0000000..8f3b452 --- /dev/null +++ b/mysql-test/t/hidden_field.test @@ -0,0 +1,152 @@ +create table h_1(abc int primary key, xyz int hidden); +desc h_1; +show create table h_1; +drop table h_1; +--error ER_TABLE_MUST_HAVE_COLUMNS +create table h_2(a1 int hidden); +--error ER_PARSE_ERROR +create table h_3(a1 blob,hidden(a1)); +--error ER_HIDDEN_NOT_NULL_WOUT_DEFAULT +create table h_4(a1 int primary key hidden ,a2 int unique hidden , a3 blob,a4 +int not null hidden unique); +--error ER_HIDDEN_NOT_NULL_WOUT_DEFAULT +create table h_5(abc int not null hidden); +create table t1(a int hidden, b int); +#should automatically add null +insert into t1 values(1); +insert into t1(a) values(1); +insert into t1(b) values(1); +insert into t1(a,b) values(5,5); +select * from t1; +select a,b from t1; +delete from t1; +insert into t1 values(1),(2),(3),(4); +select * from t1; +select a from t1; +drop table t1; +#echo more complex case of hidden +create table t1(a int , b int hidden , c int hidden auto_increment unique, d blob , e int unique, f int); +desc t1; +insert into t1 values(1,'d blob',1,1),(1,'d blob',11,1),(1,'d blob',2,1),(1,'d blob',3,1),(1,'d blob',41,1); +select * from t1; +drop table t1; +--error ER_PARSE_ERROR +create table sdsdsd(a int , b int, hidden(a,b)); +create table t1(a int,abc int as (a mod 3) virtual hidden); +desc t1; +--error ER_WRONG_VALUE_COUNT_ON_ROW +insert into t1 values(1,default); +insert into t1 values(1),(22),(233); +select * from t1; +select a,abc from t1; +drop table t1; +create table t1(abc int primary key hidden auto_increment, a int); +desc t1; +show create table t1; +insert into t1 values(1); +insert into t1 values(2); +insert into t1 values(3); +select * from t1; +select abc,a from t1; +delete from t1; +insert into t1 values(1),(2),(3),(4),(6); +select abc,a from t1; +drop table t1; +create table t1(abc int); +--error ER_TABLE_MUST_HAVE_COLUMNS +alter table t1 change abc ss int hidden; +alter table t1 add column xyz int; +alter table t1 modify column abc int ; +desc t1; +--error ER_WRONG_VALUE_COUNT_ON_ROW +insert into t1 values(22); +alter table t1 modify column abc int hidden; +desc t1; +insert into t1 values(12); +drop table t1; + +--echo some test on copy table structure with table data;
in echo's start the message from #-sign to make it better visible in a result
Changed.
+ +--echo table with hidden fields and unique keys; + +create table t1(a int , b int hidden , c int hidden auto_increment unique, d blob , e int unique, f int); +desc t1; +insert into t1 values(1,'d blob',1,1),(1,'d blob',11,1),(1,'d blob',2,1),(1,'d blob',3,1),(1,'d blob',41,1); +select * from t1; +select a,b,c,d,e,f from t1; +--echo this wont copy hidden fields and keys; +create table t2 as select * from t1; +desc t2; +select * from t2; +--error ER_BAD_FIELD_ERROR +select a,b,c,d,e,f from t2; +drop table t2; +--echo now this will copy hidden fields +create table t2 as select a,b,c,d,e,f from t1; +desc t2; +select * from t2; +select a,b,c,d,e,f from t2; +drop table t2,t1; + +--echo some test related to copy of data from one table to another; +create table t1(a int , b int hidden , c int hidden auto_increment unique, d blob , e int unique, f int); +insert into t1 values(1,'d blob',1,1),(1,'d blob',11,1),(1,'d blob',2,1),(1,'d blob',3,1),(1,'d blob',41,1); +select a,b,c,d,e,f from t1; +create table t2(a int , b int hidden , c int hidden , d blob , e int unique, f int); +insert into t2 select * from t1; +select a,b,c,d,e,f from t2; +truncate t2; +insert into t2 (a,b,c,d,e,f) select a,b,c,d,e,f from t1; +select a,b,c,d,e,f from t2; +truncate t2; +drop table t1,t2; + +--echo some test related to creating view on table with hidden column; +create table t1(a int , b int hidden , c int hidden auto_increment unique, d blob , e int unique, f int); +insert into t1 values(1,'d blob',1,1),(1,'d blob',11,1),(1,'d blob',2,1),(1,'d blob',3,1),(1,'d blob',41,1); +create view v as select * from t1; +desc v; +select * from v; +--echo v does not have hidden column; +--error ER_BAD_FIELD_ERROR +select a,b,c,d,e,f from v; +insert into v values(1,21,32,4); +select * from v; +--error ER_BAD_FIELD_ERROR +insert into v(a,b,c,d,e,f) values(1,12,3,4,5,6); +drop view v; + +create view v as select a,b,c,d,e,f from t1; +desc v; +select * from v; +--echo v does have hidden column; +select a,b,c,d,e,f from v; +insert into v values(1,26,33,4,45,66); +select a,b,c,d,e,f from v; +insert into v(a,b,c,d,e,f) values(1,32,31,41,5,6); +select a,b,c,d,e,f from v; +drop view v; +drop table t1; + +--echo now hidden column in where and some join query i think no use of this test but anyway; +create table t1 (a int unique , b int hidden unique, c int unique hidden); +insert into t1(a,b,c) values(1,1,1); +insert into t1(a,b,c) values(2,2,2); +insert into t1(a,b,c) values(3,3,3); +insert into t1(a,b,c) values(4,4,4); +insert into t1(a,b,c) values(21,21,26); +insert into t1(a,b,c) values(31,31,35); +insert into t1(a,b,c) values(41,41,45); +insert into t1(a,b,c) values(22,22,24); +insert into t1(a,b,c) values(32,32,33); +insert into t1(a,b,c) values(42,42,43); +explain select * from t1 where b=3; +select * from t1 where b=3; +explain select * from t1 where c=3; +select * from t1 where c=3; + +create table t2 as select a,b,c from t1; +desc t2; +explain select * from t1,t2 where t1.b = t2.c and t1.c = t2.b; +select * from t1,t2 where t1.b = t2.c and t1.c = t2.b; +drop table t1,t2; diff --git a/mysql-test/t/long_uniques.test b/mysql-test/t/long_uniques.test new file mode 100644 index 0000000..8777aaa --- /dev/null +++ b/mysql-test/t/long_uniques.test @@ -0,0 +1,294 @@
please add also a test case for innodb. In a separate file, long_uniques_innodb.test in particular, test this case:
connection con1; start transaction; insert ('bbbb') connection con2; start transaction; insert ('bbbb')
see? insert the conflicting value in two simultaneously running transactions. try that in different transaction isolation levels. normally the second transaction should *not* see the first 'bbbb' because the first transaction is not committed yet. But InnoDB next-key locks should guarantee that the second transaction will wait for the first.
TODO
+--echo #Structure of tests +--echo #First we will check all option for +--echo #table containing single unique column +--echo #table containing keys like unique(a,b,c,d) etc +--echo #then table containing 2 blob unique etc + +--echo #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); + +--echo #table structure; +desc t1; +show create table t1; +show keys from t1; +select * from information_schema.columns where table_schema = 'test' and table_name = 't1'; +select * from information_schema.statistics where table_schema = 'test' and table_name = 't1'; +select * from information_schema.key_column_usage where table_schema= 'test' and table_name= 't1'; +--echo # table select we should not be able to see db_row_hash_column; +select * from t1; +--error ER_BAD_FIELD_ERROR +select db_row_hash_1 from t1; +--echo #duplicate entry test; +--error ER_DUP_ENTRY +insert into t1 values(2); +--error ER_DUP_ENTRY +insert into t1 values('sachin'); +--error ER_DUP_ENTRY +insert into t1 values(123456789034567891); +select * from t1; +insert into t1 values(11),(22),(33); +--error ER_DUP_ENTRY +insert into t1 values(12),(22); +select * from t1; +insert into t1 values(repeat('s',4000*10)),(repeat('s',4001*10)); +--error ER_DUP_ENTRY +insert into t1 values(repeat('m',4000*10)),(repeat('m',4000*10)); +insert into t1 values(repeat('m',4001)),(repeat('m',4002)); +truncate table t1; +insert into t1 values(1),(2),(3),(4),(5),(8),(7); + +--echo #now some alter commands; +alter table t1 add column b int; +desc t1; +show create table t1; +--error ER_DUP_ENTRY +insert into t1 values(1,2); +--error ER_DUP_ENTRY +insert into t1 values(2,2); +--error ER_BAD_FIELD_ERROR +select db_row_hash_1 from t1; +--echo #now try to change db_row_hash_1 column; +--error ER_CANT_DROP_FIELD_OR_KEY +alter table t1 drop column db_row_hash_1; +--error ER_CANT_DROP_FIELD_OR_KEY +alter table t1 add column d int , add column e int , drop column db_row_hash_1; +--error ER_BAD_FIELD_ERROR +alter table t1 modify column db_row_hash_1 int ; +--error ER_BAD_FIELD_ERROR +alter table t1 add column a int , add column b int, modify column db_row_hash_1 int ; +--error ER_BAD_FIELD_ERROR +alter table t1 change column db_row_hash_1 dsds int; +--error ER_BAD_FIELD_ERROR +alter table t1 add column asd int, change column db_row_hash_1 dsds int; +alter table t1 drop column b , add column c int; +show create table t1; + +--echo #now add some column with name db_row_hash; +alter table t1 add column db_row_hash_1 int unique; +show create table t1; +--error ER_DUP_ENTRY +insert into t1 values(45,1,55),(46,1,55); +alter table t1 add column db_row_hash_2 int, add column db_row_hash_3 int; +desc t1; +--echo #this should also drop the unique index ; +alter table t1 drop column a; +show create table t1; +show keys from t1; +--echo #add column with unique index on blob ; +alter table t1 add column a blob unique; +show create table t1; +--echo # try to change the blob unique column name; +--echo #this will change index to b tree; +alter table t1 modify column a int ; +show create table t1; +show keys from t1; +alter table t1 add column clm blob unique; +--echo #try changing the name ; +alter table t1 change column clm clm_changed blob; +show create table t1; +show keys from t1; +--echo #now drop the unique key; +alter table t1 drop key clm; +show create table t1; +show keys from t1; +drop table t1; + +create table t1 (a TEXT CHARSET latin1 COLLATE latin1_german2_ci unique); +desc t1; +show keys from t1; + insert into t1 values ('ae'); +--error ER_DUP_ENTRY + insert into t1 values ('AE'); + insert into t1 values ('Ä'); +drop table t1; + +--echo #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','ff','fdf','gfgfgfg','hghgr'),('maria','db','frter','dasd','utyuty'), +(123456789034567891,3534534534534,53453453453456,64565464564564,45435345345345), +(123456789034567890,435345345345,657567567567,78967657567567,657567567567567676); + +--echo #table structure; +desc t1; +show create table t1; +show keys from t1; +select * from information_schema.columns where table_schema = 'test' and table_name = 't1'; +select * from information_schema.statistics where table_schema = 'test' and table_name = 't1'; +select * from information_schema.key_column_usage where table_schema= 'test' and table_name= 't1'; +--echo #table select we should not be able to see db_row_hash_column; +select * from t1; +--error ER_BAD_FIELD_ERROR +select db_row_hash_1 from t1; +--error ER_BAD_FIELD_ERROR +select db_row_hash_2 from t1; +--error ER_BAD_FIELD_ERROR +select db_row_hash_3 from t1; +--echo #duplicate entry test; +--error ER_DUP_ENTRY +insert into t1 values(21,2,3,42,51); +--error ER_DUP_ENTRY +insert into t1 values('sachin',null,null,null,null); +--error ER_DUP_ENTRY +insert into t1 values(1234567890345671890,4353453453451,6575675675617,789676575675617,657567567567567676); +select * from t1; +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',401)); +--error ER_DUP_ENTRY +insert into t1 values(repeat('m',4000*11),10,repeat('s',4000*11),repeat('s',4000*11),repeat('s',400)); +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); + +--echo #now some alter commands; +alter table t1 add column f int; +desc t1; +show create table t1; +--echo #unique key should not break; +--error ER_DUP_ENTRY +insert into t1 values(1,2,3,4,5,6); +--error ER_BAD_FIELD_ERROR +select db_row_hash_1 , db_row_hash_2, db_row_hash_3 from t1; +--echo #now try to change db_row_hash_1 column; +--error ER_CANT_DROP_FIELD_OR_KEY +alter table t1 drop column db_row_hash_1, drop column db_row_hash_2, drop column db_row_hash_3; +--error ER_CANT_DROP_FIELD_OR_KEY +alter table t1 add column dg int , add column ef int , drop column db_row_hash_1; +--error ER_BAD_FIELD_ERROR +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 ER_BAD_FIELD_ERROR +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 ER_BAD_FIELD_ERROR +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 ER_BAD_FIELD_ERROR +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; +alter table t1 drop column b , add column g int; +show create table t1; + +--echo #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; + +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; +--echo #this show now break anything; +--error ER_DUP_ENTRY +insert into t1 values(1,2,3,4,5,6,23,5,6); +--echo #this should also drop the unique index; +alter table t1 drop column a, drop column c; +show create table t1; +show keys from t1; +--echo #add column with unique index on blob; +alter table t1 add column a blob unique; +show create table t1; +show keys from t1; +--echo #try to change the blob unique column name; +--echo #this will change index to b tree; +alter table t1 modify column a int , modify column e int; +show create table t1; +show keys from t1; +alter table t1 add column clm1 blob unique,add column clm2 blob unique; +--echo #try changing the name; +alter table t1 change column clm1 clm_changed1 blob, change column clm2 clm_changed2 blob; +show create table t1; +show keys from t1; +--echo #now drop the unique key; +alter table t1 drop key clm1, drop key clm2; +show create table t1; +show keys from t1; +drop table t1; + +--echo #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(a,b,c,d,e,f),unique(d,e,f,g,h),unique(a,b,c,d,e,f,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'); + +--echo #table structure; +desc t1; +show create table t1; +show keys from t1; +select * from information_schema.columns where table_schema = 'test' and table_name = 't1'; +select * from information_schema.statistics where table_schema = 'test' and table_name = 't1'; +select * from information_schema.key_column_usage where table_schema= 'test' and table_name= 't1'; +--echo # table select we should not be able to see db_row_hash_column; +select * from t1; +--error ER_BAD_FIELD_ERROR +select db_row_hash_1 from t1; +--error ER_BAD_FIELD_ERROR +select db_row_hash_2 from t1; +--error ER_BAD_FIELD_ERROR +select db_row_hash_3 from t1; +--echo #duplicate entry test; +--echo #duplicate keys entry; +--error ER_DUP_ENTRY +insert into t1 values(1,1,1,0,0,0,0,0); +--error ER_DUP_ENTRY +insert into t1 values(0,0,1,1,1,0,0,0); +--error ER_DUP_ENTRY +insert into t1 values(0,0,0,0,1,1,1,1); +--error ER_DUP_ENTRY +insert into t1 values(1,1,1,1,1,0,0,0); +--error ER_DUP_ENTRY +insert into t1 values(0,0,0,0,1,1,1,1); +--error ER_DUP_ENTRY +insert into t1 values(1,1,1,1,1,1,1,1); +--error ER_BAD_FIELD_ERROR +select db_row_hash_1,db_row_hash_2,db_row_hash_3,db_row_hash_4,db_row_hash_5 from t1; +--error ER_CANT_DROP_FIELD_OR_KEY +alter table t1 drop column db_row_hash_1, drop column db_row_hash_2, drop column db_row_hash_3; +--error ER_CANT_DROP_FIELD_OR_KEY +alter table t1 add column dg int , add column ef int , drop column db_row_hash_1; +--error ER_BAD_FIELD_ERROR +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 ER_BAD_FIELD_ERROR +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 ER_BAD_FIELD_ERROR +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 ER_BAD_FIELD_ERROR +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; + +show create table t1; +--echo # 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; +show keys from t1; +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; +show keys from t1; + +--echo #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; +show keys from t1; +alter table t1 change column aa a blob , change column bb b blob , change column dd d blob; +show create table t1; +show keys from t1; + +--echo #now we will change the data type to int and varchar limit so that we no longer require hash_index; +--echo #on key a_b_c; +alter table t1 modify column a int , modify column b int , modify column c int; +show create table t1; +show keys from t1; +--echo #change it back; +alter table t1 modify column a blob , modify column b blob , modify column c blob; +show create table t1; +show keys from t1; + +--echo #try to delete blob column in unique; +truncate table t1; +alter table t1 drop column a, drop column b, drop column c; +show create table t1; +show keys from t1; +--echo #now try to delete keys; +alter table t1 drop key c_d_e, drop key e_f_g_h; +show create table t1; +show keys from t1; +drop table t1; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 8dfa519..9d5b4f5 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7214,3 +7214,5 @@ ER_CALCULATING_DEFAULT_VALUE eng "Got an error when calculating default value for %`s" ER_EXPRESSION_REFERS_TO_UNINIT_FIELD 01000 eng "Expression for field %`-.64s is refering to uninitialized field %`s" +ER_HIDDEN_NOT_NULL_WOUT_DEFAULT + eng "Hidden column '%s' either allow null values or it must have default value"
"... should either allow null values ..." or "... should either be nullable ..."
Done.
diff --git a/sql/table.h b/sql/table.h index 651fab7..9d2b279 100644 --- a/sql/table.h +++ b/sql/table.h @@ -330,7 +330,28 @@ enum enum_vcol_update_mode VCOL_UPDATE_ALL };
+/* Field visibility enums */
+enum field_visible_type{ + NOT_HIDDEN=0, + USER_DEFINED_HIDDEN, + MEDIUM_HIDDEN, + FULL_HIDDEN
this could use some comments. Or better names. NOT_HIDDEN is very clear. USER_DEFINED_HIDDEN is kind of ok too. But MEDIUM_HIDDEN is not - what does that mean? Please, either add a comment, like // pseudo-columns (like ROWID). Can be queried explicitly in SELECT, otherwise hidden from anything or rename MEDIUM_HIDDEN to something self-explanatory (may be, PSEUDO_COLUMN_HIDDEN?). FULL_HIDDEN is ok, although FULLY_HIDDEN or COMPLETELY_HIDDEN is a bit easier to read, I'd think.
+}; + +int rem_field_from_hash_col_str(LEX_STRING *hash_lex, const char *field_name);
confus way to abbr words. plz rena to smth lik
remove_field_from_hash_index
or, may be
remove_field_from_hash_index_def remove_field_from_hash_index_sql
by the way, this function isn't used anywhere. Forgot to remove it?
Removed.
+ +int change_field_from_hash_col_str(LEX_STRING *hash_lex, + const char *old_name, char *new_name);
1. notice many <Tab> characters on the previous line that indent that line way too much. 2. this function doesn't seem to be used either
Removed.
+ +int find_field_name_in_hash(char * hash_str, const char *field_name, + int hash_str_length);
again, many <Tab>s on the previous line. Prefer spaces, please.
+ +int find_field_index_in_hash(LEX_STRING * hash_lex, const char * field_name);
name's pretty bad, compared to find_field_name_in_hash. better rename the previous function to find_field_pos_in_hash_str or something like that.
+ +int fields_in_hash_str(LEX_STRING *hash_lex); + +Field * field_ptr_in_hash_str(LEX_STRING * hash_str, TABLE *table, int index); /** Category of table found in the table share. */ @@ -1031,6 +1052,19 @@ struct TABLE Field **field; /* Pointer to fields */
uchar *record[2]; /* Pointer to records */ + uchar *check_unique_buf; /* Pointer to record with same hash */
better comment: /* record buf to resolve hash collisions for long UNIQUE constraints */
Changed.
+ handler *update_handler; /* Handler used in case of update */
I don't think you need to store it in the TABLE. You can either pass it as an argument to ha_update_row() or invoke check_duplicate_long_entries() before ha_update_row() not from it.
+ /* + In the case of write row for long unique we are unable of find + Whick key is voilated because we in case of duplicate 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 + */ + int dupp_key; + /* If dupp != -1 then this string + store message which should be printed */ + char *err_message;
I wonder whether you need it. You can issue an error (with my_error()) directly from check_duplicate_long_entries(), no need to store the error till later. If you issue an error early, you'll simply skip handler::print_keydup_error() later.
This wont work because there can be statements like alter ignore table t1 add unique key(a); Anyway I have removed err_message from table class but dupp_key is still there. I need this here uint handler::get_dup_key(int error) { DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK); DBUG_ENTER("handler::get_dup_key"); table->file->errkey = (uint) -1; if (table->dupp_key != -1) DBUG_RETURN(table->dupp_key);
uchar *write_row_record; /* Used as optimisation in THD::write_row */ uchar *insert_values; /* used by INSERT ... UPDATE */ diff --git a/sql/field.h b/sql/field.h index 05e0615..35a7006 100644 --- a/sql/field.h +++ b/sql/field.h @@ -998,9 +1001,9 @@ class Field: public Value_source virtual int cmp(const uchar *,const uchar *)=0; virtual int cmp_binary(const uchar *a,const uchar *b, uint32 max_length=~0L) { return memcmp(a,b,pack_length()); } - virtual int cmp_offset(uint row_offset) + virtual int cmp_offset(long row_offset)
1. why is that? because old offset was unsigned?
Yes
2. better use my_ptrdiff_t type here
Changed.
{ return cmp(ptr,ptr+row_offset); } - virtual int cmp_binary_offset(uint row_offset) + virtual int cmp_binary_offset(long row_offset) { return cmp_binary(ptr, ptr+row_offset); }; virtual int key_cmp(const uchar *a,const uchar *b) { return cmp(a, b); } diff --git a/sql/sql_select.h b/sql/sql_select.h index 92ba74f..dd55d94 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1818,6 +1825,27 @@ class store_key_field: public store_key When the implementation of this function will be replaced for a proper full version this statement probably should be removed. */ + if (is_hash) + { + Field *f= copy_field.from_field; + String str;
Normally in these cases you should use StringBuffer<MAX_FIELD_WIDTH> instead of String. It will allocate a char[MAX_FIELD_WIDTH] buffer on the stack so the following val_str() will not need to call malloc if the value is shorter than MAX_FIELD_WIDTH.
But in this particular case, you're doing long unique, probably for blobs, so here the result will typically be larger than MAX_FIELD_WIDTH, and this StringBuffer optimization will not actually help.
+ f->val_str(&str); + if (f->is_null()) + { + *(copy_field.to_ptr-1)= 1; //set it null
why do you write to copy_field.to_ptr directly? store_key methods don't do that anywhere else
Okay, I will change It. But I think in newer version I do not require this code. So I will change it later on.
+ null_key= true;
where you reset null_key and copy_field.ptr[-1] back to 0?
+ dbug_tmp_restore_column_map(table->write_set, old_map); + return STORE_KEY_OK; + } + CHARSET_INFO* cs= str.charset(); + uchar l[4]; + int4store(l,str.length()); + cs->coll->hash_sort(cs, l, sizeof(l), &nr1, &nr2);
cs= &my_charset_bin; for hash_sort() above, cs= str.charset(); for hash_sort() below.
+ cs->coll->hash_sort(cs, (uchar *)str.ptr(), str.length(), &nr1, &nr2); + int8store(copy_field.to_ptr, nr1); + dbug_tmp_restore_column_map(table->write_set, old_map); + return STORE_KEY_OK;
I suppose you don't need to calculate hashes if null_key is already true for this row (if it's a multi-column key and one of the previous columns was NULL)
btw, could you add a test case for that? a test case where f->is_null() is true? like, add assert(0); under that if() and try to create a test case that will cause it to crash.
+ } bzero(copy_field.to_ptr,copy_field.to_length);
copy_field.do_copy(©_field); @@ -1860,6 +1889,26 @@ class store_key_item :public store_key table->write_set); int res= FALSE;
+ if (is_hash) + { + String *str= item->val_str(); + if (item->null_value) + { + *(to_field->ptr - 1)= 1; + null_key= true; + dbug_tmp_restore_column_map(table->write_set, old_map); + return STORE_KEY_OK; + } + CHARSET_INFO *cs= str->charset(); + uchar l[4]; + int4store(l,str->length()); + cs->coll->hash_sort(cs,l,sizeof(l), &nr1, &nr2); + cs->coll->hash_sort(cs, (uchar *)str->ptr(), str->length(), &nr1, &nr2); + int8store(to_field->ptr, nr1); + //no idea what it does
remove this comment, please :) and if you're curious what it does, you can always comment dbug_tmp_use_all_columns() and dbug_tmp_restore_column_map() in this function out and run the test suite in debug build, you'll see how it will crash :) or you can ask, that works too...
Okay
+ dbug_tmp_restore_column_map(table->write_set, old_map); + return STORE_KEY_OK; + } /* It looks like the next statement is needed only for a simplified hash function over key values used now in BNLH join. @@ -2271,4 +2320,11 @@ class Pushdown_query: public Sql_alloc bool test_if_order_compatible(SQL_I_List<ORDER> &a, SQL_I_List<ORDER> &b); int test_if_group_changed(List<Cached_item> &list); int create_sort_index(THD *thd, JOIN *join, JOIN_TAB *tab, Filesort *fsort); +/* + It compares the record with same hash to key if + record is equal then return 0 else fetches next + record with same hash and so on if some error + then returns error +*/
better put this comment where a function is defined, in sql_select.cc
+int compare_hash_and_fetch_next(JOIN_TAB *join); #endif /* SQL_SELECT_INCLUDED */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index fa8f143..eb1769b 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -8394,6 +8394,7 @@ SHOW_VAR status_vars[]= { {"Feature_dynamic_columns", (char*) offsetof(STATUS_VAR, feature_dynamic_columns), SHOW_LONG_STATUS}, {"Feature_fulltext", (char*) offsetof(STATUS_VAR, feature_fulltext), SHOW_LONG_STATUS}, {"Feature_gis", (char*) offsetof(STATUS_VAR, feature_gis), SHOW_LONG_STATUS}, + {"Feature_hidden_column", (char*) offsetof(STATUS_VAR, feature_hidden_column), SHOW_LONG_STATUS},
I feel that Feature_hidden_columns (plural) would look better here.
I know we aren't consistent, there's Feature_dynamic_columns (plural) but Feature_subquery, Feature_timezone (singular), so there is no rule here, unfortunately.
Done
{"Feature_locale", (char*) offsetof(STATUS_VAR, feature_locale), SHOW_LONG_STATUS}, {"Feature_subquery", (char*) offsetof(STATUS_VAR, feature_subquery), SHOW_LONG_STATUS}, {"Feature_timezone", (char*) offsetof(STATUS_VAR, feature_timezone), SHOW_LONG_STATUS}, diff --git a/sql/field.cc b/sql/field.cc index c684e6a..8c17b76 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -7671,7 +7672,6 @@ uint32 Field_varstring::data_length() { return length_bytes == 1 ? (uint32) *ptr : uint2korr(ptr); } -
restore the empty line, please
/* Functions to create a packed row. Here the number of length bytes are depending on the given max_length diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 8bb12ce..45e6cce 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -3899,6 +3899,25 @@ bool subselect_uniquesubquery_engine::copy_ref_key(bool skip_constants) */ DBUG_RETURN(true); } + if ((*copy)->is_hash) + { + if (!(*copy)->null_key && *(copy+1)) + { + (*(copy+1))->nr1= (*copy)->nr1; + (*(copy+1))->nr2= (*copy)->nr2;
I don't get it, why *(copy+1) ?
Supoose a key is like unique(a,b,c) then I need to transfer nr1,nr2 from one copy var to another copy var. That is why I am doing this.
+ } + else + break; + } + } + //reset nr1 and nr2 + for (store_key **copy=tab->ref.key_copy ; *copy ; copy++) + { + if ((*copy)->is_hash) + { + (*copy)->nr1= 1; + (*copy)->nr2= 4; + } } DBUG_RETURN(false); } diff --git a/sql/item_func.cc b/sql/item_func.cc index 7f8c89c..3c71e8c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1839,6 +1839,40 @@ void Item_func_int_div::fix_length_and_dec() }
+longlong Item_func_hash::val_int() +{ + unsigned_flag= true; + ulong nr1= 1,nr2= 4; + CHARSET_INFO *cs; + for(uint i= 0;i<arg_count;i++) + { + String * str = args[i]->val_str(); + if(args[i]->null_value) + { + null_value= 1; + return 0; + } + cs= str->charset(); + uchar l[4]; + int4store(l, str->length()); + cs->coll->hash_sort(cs, l, sizeof(l), &nr1, &nr2); + cs->coll->hash_sort(cs, (uchar *)str->ptr(), str->length(), &nr1, &nr2);
that's the third time I see these sequence of lines (and there's one more below). Why not to put it in a reusable function? like
calc_hash_for_unique(&nr1, &nr2, str) { 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); }
Done.
+ } + null_value= 0; + //for testing purpose + //nr1=12;
remove that, please ^^^
Removed.
+ return (longlong)nr1; +} + + +void Item_func_hash::fix_length_and_dec() +{ + maybe_null= 1; + decimals= 0; + max_length= 8; +} + + longlong Item_func_mod::int_op() { DBUG_ASSERT(fixed == 1); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 9d7e735..61022e6 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6191,6 +6192,11 @@ vcol_attribute: lex->alter_info.flags|= Alter_info::ALTER_ADD_INDEX; } | COMMENT_SYM TEXT_STRING_sys { Lex->last_field->comment= $2; } + | HIDDEN_SYM + { + LEX *lex =Lex; + lex->last_field->field_visibility=USER_DEFINED_HIDDEN; + }
Please, make HIDDEN keyword non-reserved. For that it should be added to the keyword_sp rule. And add a test case for it, like
--echo # HIDDEN is not reserved create table t1 (hidden int); drop table t1;
Done.
;
parse_vcol_expr: @@ -9482,6 +9476,12 @@ function_call_keyword: if ($$ == NULL) MYSQL_YYABORT; } + |HASH_SYM '(' expr_list ')'
You've added it to function_call_keyword rule, but it should have been added to the function_call_conflict rule. See comments before these both rules.
Done.
+ { + $$= new (thd->mem_root)Item_func_hash(thd,*$3); + if($$==NULL) + MYSQL_YYABORT; + } | INSERT '(' expr ',' expr ',' expr ',' expr ')' { $$= new (thd->mem_root) Item_func_insert(thd, $3, $5, $7, $9); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 8028779..41f5a55 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -198,6 +198,17 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, TABLE *table= table_list->table; DBUG_ENTER("check_insert_fields");
+ List_iterator<Item> i_iter(values);
1. you don't use i_iter here 2. I'd move the loop into a separate function or a method of TABLE:
uint num_of_hiddens_fields() { for (...) }
see below
+ int num_of_hiddens_fields= 0; + if (!fields.elements) + { + Field ** f= table->field, *field; + for (; f && (field= *f); f++) + { + if (field->field_visibility != NOT_HIDDEN) + num_of_hiddens_fields++; + } + } if (!table_list->single_table_updatable()) { my_error(ER_NON_INSERTABLE_TABLE, MYF(0), table_list->alias, "INSERT"); @@ -212,7 +223,7 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, table_list->view_db.str, table_list->view_name.str); DBUG_RETURN(-1); } - if (values.elements != table->s->fields) + if (values.elements+num_of_hiddens_fields != table->s->fields)
then this if() becomes:
if (values.elements + num_of_hiddens_fields() != table->s->fields)
in fact, you can have a function that counts *visible* fields, then this if() becomes simply
if (values.elements != table->not_hidden_fields())
{ my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), 1L); DBUG_RETURN(-1); @@ -1485,7 +1497,28 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, update_values, false, &map); select_lex->no_wrap_view_item= FALSE; } - + /* + Reason for this condition + suppose this + create table t1 (a int , b int , c int hidden , d int); + create view v as select a,b,c,d from t1; + now query like this fails + insert into v values(1,1,1) + because in insert_view_fields we copy all the fields + whether they are hidden or not we can not do the change + there because there we have only fields name so we need + to manually setup fields as insert_view_fields is called + by only mysql_prepare_insert_check_table function and + mysql_prepare_insert_check_table is called by only by this + function so it is safe to do here + + NOT YET IMPLEMENTED + if (insert_into_view && !is_field_specified_for_view + && fields.elements) + { + Item *ii= fields.pop(); + } + **/
1. I didn't understand the comment, couldn't parse it. Could you, please add some punctuation to it? :) 2. I believe you have a test case for it, and it works. Does it mean that the whole commented block is obsolete and should be removed? If yes, don't forget to remove is_field_specified_for_view declaration.
No It does not work. I will try to solve this. Actually the main problem is suppose create table t1(a int , b int , c int hidden, d int); create view v as select a,b,c,d from t1; then query like insert into t1 values(1,1,1); fails. The problem is desc v shows it is hidden. But it is not setting default values for field c
/* Restore the current context. */ ctx_state.restore_state(context, table_list); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index d59b8b7..dfe83e7 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -729,7 +729,17 @@ int mysql_update(THD *thd, */ can_compare_record= records_are_comparable(table); explain->tracker.on_scan_init(); - + for (uint i= 0; i < table->s->keys; i++) + { + if (table->key_info[i].flags & HA_UNIQUE_HASH) + { + if (!table->update_handler)
Can table->update_handler be possibly not NULL here?
No it cant be. Changed.
+ table->update_handler= table->file->clone(table->s->normalized_path.str, + &table->mem_root);
Note that you create this new handler on the table's memroot! This is wrong, as I've explained in an earlier review, memroot can only be freed as a whole, so by repeating UPDATE statements, you will allocate more and more memory in the table's memroot for update_handler's. You need to allocate it in the thd's memroot, because update_handler's has a life time of only one statement.
+ table->update_handler->ha_external_lock(current_thd, F_RDLCK); + break; + } + } while (!(error=info.read_record(&info)) && !thd->killed) { explain->tracker.on_record_read(); @@ -1912,6 +1929,19 @@ multi_update::initialize_tables(JOIN *join)
if (ignore) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); + + for (uint i= 0; i < table->s->keys; i++) + { + if (table->key_info[i].flags & HA_UNIQUE_HASH) + { + if (!table->update_handler) + table->update_handler= table->file->clone(table->s->normalized_path.str, + &table->mem_root); + table->update_handler->ha_external_lock(current_thd, F_RDLCK); + break; + } + }
same code as in mysql_update(), right? better move it to a small function. For example,
handler *create_update_handler(THD *thd, TABLE *table) { handler *update_handler= 0; for (uint i= 0; i < table->s->keys; i++) { if (table->key_info[i].flags & HA_UNIQUE_HASH) { update_handler= table->file->clone(table->s->normalized_path.str, &table->mem_root); update_handler->ha_external_lock(thd, F_RDLCK); return update_handler; } } return NULL; }
+ if (table == main_table) // First table in join { if (safe_update_on_fly(thd, join->join_tab, table_ref, all_tables)) @@ -2039,6 +2069,13 @@ multi_update::~multi_update() for (table= update_tables ; table; table= table->next_local) { table->table->no_keyread= table->table->no_cache= 0; + if (table->table->update_handler) + { + table->table->update_handler->ha_external_lock(current_thd, F_UNLCK); + table->table->update_handler->ha_close(); + delete table->table->update_handler; + table->table->update_handler= NULL; + }
same here:
void delete_update_handler(THD *thd, handler *h) { if (h) { h->ha_external_lock(thd, F_UNLCK); h->ha_close(); delete h; } }
by the way, try to avoid current_thd, if possible. it is farily expensive on some platforms.
Done
if (ignore) table->table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); } diff --git a/sql/unireg.cc b/sql/unireg.cc index 19d03d2..d502b68 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -89,6 +89,26 @@ static uchar *extra2_write(uchar *pos, enum extra2_frm_value_type type, return extra2_write(pos, type, reinterpret_cast<LEX_STRING *>(str)); }
+static uchar *extra2_write_field_visibility_hash_info(uchar *pos,
please, rename to extra2_write_additional_field_properties or something like that.
Done.
+ int number_of_fields,List_iterator<Create_field> * it) +{ + *pos++=EXTRA2_FIELD_FLAGS; + /* + always 2 first for field visibility + second for is this column represent long unique hash + */ + size_t len = 2*number_of_fields; + pos= extra2_write_len(pos,len); + Create_field *cf; + while((cf=(*it)++)) + { + *pos++=cf->field_visibility; + *pos++=cf->is_long_column_hash;
you can do one byte per field, field_visibility is only two bits, is_long_column_hash is one bit.
Okay , I tried this , but I am not sure if it is rigth or not.
+ } + return pos; +} + + /** Create a frm (table definition) file
@@ -121,6 +141,22 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, uchar *frm_ptr, *pos; LEX_CUSTRING frm= {0,0}; DBUG_ENTER("build_frm_image"); + List_iterator<Create_field> it(create_fields); + Create_field *field; + bool is_hidden_fields_present= false;
please, rename to "have_additional_field_properties"
Okay.
+ /* + Loop througt the iterator to find whether we have any field whose + visibility_type != NOT_HIDDEN + */
Please remove the comment above. Remember, a comment needs to say *why* you are doing something, it should not say *what* you are doing. In this case your comment merely says what the loop below is doing, the comment is in English, the loop in C++, but otherwise they say exactly the same thing. If you rename the variable (as I suggested above) this loop will be completely clear without any comments anyway.
+ while ((field=it++)) + { + if (field->field_visibility != NOT_HIDDEN) + { + is_hidden_fields_present= true; + break; + } + } + it.rewind();
/* If fixed row records, we need one bit to check for deleted rows */ if (!(create_info->table_options & HA_OPTION_PACK_RECORD)) @@ -265,7 +303,9 @@ LEX_CUSTRING build_frm_image(THD *thd, const char *table, pos+= gis_field_options_image(pos, create_fields); } #endif /*HAVE_SPATIAL*/ - + if (is_hidden_fields_present) + pos=extra2_write_field_visibility_hash_info(pos,create_fields.elements,&it); + it.rewind();
you can rewind from inside extra2_write_field_visibility_hash_info. seems logical - it moves the iterator, it should restore it
Okay
int4store(pos, filepos); // end of the extra2 segment pos+= 4;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 3481bf1..ce63a88 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -5287,6 +5287,8 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
if (field_ptr && *field_ptr) { + if ((*field_ptr)->field_visibility == FULL_HIDDEN) + DBUG_RETURN((Field*) 0);
good. please add a test case for that, with a subquery and an outer reference, as I wrote earlier.
Added , but there are some bugs,
*cached_field_index_ptr= field_ptr - table->field; field= *field_ptr; } @@ -7351,6 +7353,10 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
for (; !field_iterator.end_of_fields(); field_iterator.next()) { + /* Field can be null here details in test case*/
"details in test case" is not very helpful. in what case can field be 0 here?
Yes it can be Test case create table t1 (empnum smallint, grp int); create table t2 (empnum int, name char(5)); insert into t1 values(1,1); insert into t2 values(1,'bob'); create view v1 as select * from t2 inner join t1 using (empnum); select * from v1;
+ if ((field= field_iterator.field()) && + field->field_visibility != NOT_HIDDEN) + continue; Item *item;
if (!(item= field_iterator.create_item(thd))) @@ -7986,6 +7992,42 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values, only one row. */ table->auto_increment_field_not_null= FALSE; + Field **f; + List_iterator<Item> i_iter(values); + uint field_count= 0; + for (f= ptr; f && (field= *f); f++) + field_count++; + /* + This if is required in query like + suppose table + create table t1 (a int , b int hidden , c int , d int hidden ); + and query is + create table t2 as select a,b,c,d from t1; + in this case field count will be equal to values.elements + */ + if (field_count != values.elements) + { + Name_resolution_context *context= & thd->lex->select_lex.context; + for (f= ptr; f && (field= *f); f++) + { + if (field->field_visibility!=NOT_HIDDEN) + { + if (f == ptr) + { + values.push_front(new (thd->mem_root) + Item_default_value(thd,context),thd->mem_root); + i_iter.rewind(); + i_iter++; + } + else + i_iter.after(new (thd->mem_root) Item_default_value(thd,context)); + } + else + i_iter++; + } + f= ptr; + i_iter.rewind(); + }
I don't understand what this is doing and why. Could you explain, please?
Actually comment is obsolute , so I removed It , It basically enter the deafult values in hidden fields For example Create table t1 (a int , b int hidden); insert into t1 value(1); here field_count is 2 but values count is 1 so I have to artifically enter default value.
while ((field = *ptr++) && ! thd->is_error()) { /* Ensure that all fields are from the same table */ diff --git a/sql/handler.cc b/sql/handler.cc index 3fbd1b3..99e043b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -5875,6 +5883,132 @@ int handler::ha_reset() DBUG_RETURN(reset()); }
+/** @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(c,d)) + 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 c_d 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
Sorry, I didn't understand this comment. Could you rephrase it? btw, there are no columns 'c' and 'd' in your table example.
also, please, explain all function parameters here (use @param).
+ @returns 0 if no duplicate else returns error + */ +int check_duplicate_long_entries(TABLE *table, handler *h, uchar *new_rec, + int key) +{ + Field *hash_field; + int result; + table->dupp_key= -1; + for (uint i= 0; i < table->s->keys; i++) + { + if (key != -1) + i= key; + if (table->key_info[i].flags & HA_UNIQUE_HASH) + {
you invoke check_duplicate_long_entries() only in two places. one is in check_duplicate_long_entries_update(), inside the loop that checks for (table->key_info[i].flags & HA_UNIQUE_HASH). So I really don't see why you need to repeat this loop and the check here. The second invocation is in ha_write_row(), where key==-1 and you need a loop, indeed. So, the logical thing to do would be to have a function (let's call if F()) which is the content of this if() and always takes a valid key number as an argument. Then check_duplicate_long_entries() would do:
for (uint i= 0; i < table->s->keys; i++) { if (table->key_info[i].flags & HA_UNIQUE_HASH) F(table, h, new_rec, i); }
and check_duplicate_long_entries_update() would invoke F() directly.
also, note that if a function is only used in one file - like this your check_duplicate_long_entries(), it should be declared static.
+ hash_field= table->key_info[i].key_part->field; + DBUG_ASSERT(table->key_info[i].key_length == HA_HASH_KEY_LENGTH_WITH_NULL); + uchar ptr[HA_HASH_KEY_LENGTH_WITH_NULL]; + + if (hash_field->is_null()) + continue; + + key_copy(ptr, new_rec, &table->key_info[i], + table->key_info[i].key_length, false); + + if (!table->check_unique_buf) + table->check_unique_buf= (uchar *)alloc_root(&table->mem_root, + table->s->reclength*sizeof(uchar)); + + result= h->ha_index_read_idx_map(table->check_unique_buf, + i, ptr, HA_WHOLE_KEY, HA_READ_KEY_EXACT); + if (!result) + { + Item_func_or_sum * temp= static_cast<Item_func_or_sum *>(hash_field-> + vcol_info->expr_item); + Item_args * t_item= static_cast<Item_args *>(temp); + uint arg_count= t_item->argument_count(); + Item ** arguments= t_item->arguments(); + int diff= table->check_unique_buf-new_rec; + Field * t_field; + + for (uint j=0; j < arg_count; j++) + {
Add DBUG_ASSERT(arguments[j]->type() == FIELD_ITEM);
+ t_field= static_cast<Item_field *>(arguments[j])->field; + if(t_field->cmp_binary_offset(diff)) + continue; + } + table->dupp_key= i; + if (!table->err_message) + { + table->err_message= (char *) alloc_root(&table->mem_root, + MAX_KEY_LENGTH); + } + StringBuffer<MAX_KEY_LENGTH> str; + str.length(0); + for(uint i= 0; i < arg_count; i++) + { + t_field= ((Item_field *)arguments[i])->field; + if (str.length()) + str.append('-'); + field_unpack(&str, t_field, new_rec, 5,//since blob can be to long + false);
truncation is a great idea. Two comments: 1. make this 5 a defined constant. Like
#define MAX_BLOB_LEN_FOR_ERRMSG 5
2. perhaps 5 is too short? dunno. 3. indicate the truncation. Like
if (t_field->pack_length() > MAX_BLOB_LEN_FOR_ERRMSG) str.append(STRING_WITH_LEN("..."));
TODO
+ } + memcpy(table->err_message,str.ptr(),str.length()); + return HA_ERR_FOUND_DUPP_KEY; + } + } + if (key != -1) + break; + } + return 0; +} + +/** @brief + check whether updated records breaks the + unique constraint on long columns. + @returns 0 if no duplicate else returns error + */ +int check_duplicate_long_entries_update(TABLE *table, handler *h, uchar *new_rec) +{ + Field **f, *field; + LEX_STRING *ls; + int error; + /* + 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].flags & HA_UNIQUE_HASH) + { + ls= &table->key_info[i].key_part->field->vcol_info->expr_str; + for (f= table->field; f && (field= *f); f++) + { + if (find_field_name_in_hash(ls->str, (char *)field->field_name, ls->length) != -1)
ok, I'm confused. Why are you doing that? For INSERT you take the HASH Item and iterate its argument array. That's fine, I get it. For UPDATE you get the vcol expression as a *string* (!!!) and extract column names from there by looking at commas (???). What was that?
+ { + /* Compare fields if they are different then check for duplicates*/ + if(field->cmp_binary_offset(reclength)) + { + if((error= check_duplicate_long_entries(table, table->update_handler, + new_rec, i))) + return error; + /* + break beacuse check_duplicate_long_entries will + take care of remaning fields + */ + break; + } + } + } + } + } + return 0; +}
int handler::ha_write_row(uchar *buf) { @@ -5921,6 +6057,8 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
note that mysql_update can use ha_bulk_update_row() instead of ha_update_row() for some storage engine. I don't think bulk update can work with your code at all, so you need to make sure will_batch is always false if long unique indexes are used (this is easy). See sql_update.cc
And there's bulk insert too, start_bulk_insert(), that you probably need to disable as well.
TODO
mark_trx_read_write(); increment_statistics(&SSV::ha_update_count);
+ if ((error= check_duplicate_long_entries_update(table, table->file, new_data))) + return error; TABLE_IO_WAIT(tracker, m_psi, PSI_TABLE_UPDATE_ROW, active_index, 0, { error= update_row(old_data, new_data);})
diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 30c65e6..a55cccd 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1972,6 +1976,25 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, } append_create_options(thd, packet, field->option_list, check_options, hton->field_options); + //TODO need a better logic to find wheter to put comma or not + int i=1; + bool is_comma_needed=false; + if (*(ptr+i)!=NULL) + { + is_comma_needed=true; + while((*(ptr+i))->field_visibility==MEDIUM_HIDDEN || + (*(ptr+i))->field_visibility==FULL_HIDDEN) + { + i++; + if(!*(ptr+i)) + { + is_comma_needed =false; + break; + } + } + } + if(is_comma_needed) + packet->append(STRING_WITH_LEN(",\n"));
What was wrong with the old logic? Print the comma before every visible column, excluding the first one. You only need to replace the "first one" condition, like
- if (ptr != table->field) + if (not_the_first_field) packet->append(STRING_WITH_LEN(",\n")); + not_the_first_field= true;
Changed.
}
key_info= table->key_info; @@ -1986,6 +2009,19 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, for (uint i=0 ; i < share->keys ; i++,key_info++) { KEY_PART_INFO *key_part= key_info->key_part; + if (key_info->flags & HA_UNIQUE_HASH) + { + char * column_names= key_part->field->vcol_info-> + expr_str.str + HA_HASH_STR_LEN; + int length= key_part->field->vcol_info->expr_str.length; + length-= HA_HASH_STR_LEN; + packet->append(STRING_WITH_LEN(",\n")); + packet->append(STRING_WITH_LEN(" UNIQUE KEY `")); + packet->append(key_info->name, strlen(key_info->name)); + packet->append(STRING_WITH_LEN("`")); + packet->append(column_names, length);
No, I'm afraid you cannot do that. You need to generate the column list by iterating arguments and printing them. Add this test case to your long_uniques.test:
create table t1 (a int, b int, c blob, d blob, unique(a,b), unique(c,d)); set sql_quote_show_create=0; show create table t1; set sql_quote_show_create=default; show create table t1; set sql_mode=ansi_quotes; show create table t1; set sql_mode=default;
(you don't need create table as above, of course, you can use any existing table in the test file).
Changed, Now it uses old logic.
+ continue; + } bool found_primary=0; packet->append(STRING_WITH_LEN(",\n "));
@@ -5411,6 +5447,10 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables,
for (; (field= *ptr) ; ptr++) { + if(field->field_visibility == FULL_HIDDEN || + field->field_visibility == MEDIUM_HIDDEN) + continue; + /* For now we will only show UNI or MUL for TODO */
what do you mean by this comment?
It says I have to setup MUL and UNI for desc table having blob unique columns.
uchar *pos; char tmp[MAX_FIELD_WIDTH]; String type(tmp,sizeof(tmp), system_charset_info); @@ -5465,20 +5505,48 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, pos=(uchar*) ((field->flags & PRI_KEY_FLAG) ? "PRI" : (field->flags & UNIQUE_KEY_FLAG) ? "UNI" : (field->flags & MULTIPLE_KEY_FLAG) ? "MUL":""); + KEY *key= show_table->key_info; + for (int i=0; i<show_table->s->keys; i++, key++) + { + if (key->flags & HA_UNIQUE_HASH) + { + LEX_STRING * ls= &key->key_part->field->vcol_info->expr_str; + int position= find_field_index_in_hash(ls, field->field_name); + int fields= fields_in_hash_str(ls); + //this is for single hash(`abc`) + if (position == 0 && fields == 1) + { + pos= (uchar *) "UNI"; + } + //this is for hash(`abc`,`xyzs`) + if (position == 0 && fields > 1) + { + pos=(uchar *) "MUL"; + } + } + }
really? why wouldn't you set UNIQUE_KEY_FLAG or MULTIPLE_KEY_FLAG instead so that the old code would just work for your new keys?
Done.
table->field[16]->store((const char*) pos, strlen((const char*) pos), cs); - + StringBuffer<256> buf; if (field->unireg_check == Field::NEXT_NUMBER) - table->field[17]->store(STRING_WITH_LEN("auto_increment"), cs); + buf.set(STRING_WITH_LEN("auto_increment"),cs); if (print_on_update_clause(field, &type, true)) - table->field[17]->store(type.ptr(), type.length(), cs); + buf.set(type.ptr(), type.length(),cs); if (field->vcol_info) { if (field->vcol_info->stored_in_db) - table->field[17]->store(STRING_WITH_LEN("PERSISTENT"), cs); + buf.set(STRING_WITH_LEN("PERSISTENT"), cs); else - table->field[17]->store(STRING_WITH_LEN("VIRTUAL"), cs); + buf.set(STRING_WITH_LEN("VIRTUAL"), cs); + } + /*hidden can coexist with auto_increment and virtual */ + if(field->field_visibility==USER_DEFINED_HIDDEN) + { + if (buf.length()) + buf.append(STRING_WITH_LEN(" , "));
no space before the comma
Changed.
+ buf.append(STRING_WITH_LEN("HIDDEN"),cs); } + table->field[17]->store(buf.ptr(), buf.length(), cs); table->field[19]->store(field->comment.str, field->comment.length, cs); if (schema_table_store_record(thd, table)) DBUG_RETURN(1); @@ -6030,6 +6098,89 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond) DBUG_RETURN(res); }
+static int print_get_schema_stat_keypart(THD *thd, TABLE_LIST *tables, + TABLE *table,TABLE *show_table, + LEX_STRING *db_name, + LEX_STRING *table_name, + KEY * key_info,KEY_PART_INFO + *key_part,Field * field ,int i,int j)
1. lots of tabs above that mess up the indentation. 2. Function comment, please. 3. i and j are *really* lousy argument names, please rename.
Removed this whole function.
+{ + CHARSET_INFO *cs= system_charset_info; + const char *str; + restore_record(table, s->default_values); + table->field[0]->store(STRING_WITH_LEN("def"), cs); + table->field[1]->store(db_name->str, db_name->length, cs); + table->field[2]->store(table_name->str, table_name->length, cs); + table->field[3]->store((longlong) ((key_info->flags & + HA_NOSAME) ? 0 : 1), TRUE); + table->field[4]->store(db_name->str, db_name->length, cs); + table->field[5]->store(key_info->name, strlen(key_info->name), cs); + table->field[6]->store((longlong) (j+1), TRUE); + str=field ? field->field_name :"?unknown field?"; + table->field[7]->store(str, strlen(str), cs); + if (show_table->file) + { + if (show_table->file->index_flags(i, j, 0) & HA_READ_ORDER) + { + table->field[8]->store(((key_part->key_part_flag & + HA_REVERSE_SORT) ? + "D" : "A"), 1, cs); + table->field[8]->set_notnull(); + } + KEY *key=show_table->key_info+i; + if (key->rec_per_key[j]) + { + ha_rows records= (ha_rows) ((double) show_table->stat_records() / + key->actual_rec_per_key(j)); + table->field[9]->store((longlong) records, TRUE); + table->field[9]->set_notnull(); + } + /* + In the case of long unique hash as we try + to calc key->rec_per_key[j] it will give zero + so cardinality will be set to null we do not want + this so + */
why not? if you don't know the cardinality - set it to NULL. but, in fact, it shouldn't be zero, why is it?
+ if (key_info->flags & HA_UNIQUE_HASH) + { + table->field[9]->store(0, TRUE); + table->field[9]->set_notnull(); + } + if (key_info->flags & HA_UNIQUE_HASH) + table->field[13]->store(HA_HASH_STR_INDEX,HA_HASH_STR_INDEX_LEN , cs);
I don't think you need to define that string, just put it here like
table->field[13]->store(STRING_WITH_LEN("HASH_INDEX") , cs);
+ else + { + str= show_table->file->index_type(i); + table->field[13]->store(str, strlen(str), cs); + } + } + if (!(key_info->flags & HA_FULLTEXT) && + (key_part->field && + key_part->length != + show_table->s->field[key_part->fieldnr-1]->key_length())) + { + table->field[10]->store((longlong) key_part->length / + key_part->field->charset()->mbmaxlen, TRUE); + table->field[10]->set_notnull(); + } + uint flags= key_part->field ? key_part->field->flags : 0; + const char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES"); + table->field[12]->store(pos, strlen(pos), cs); + if (!show_table->s->keys_in_use.is_set(i)) + table->field[14]->store(STRING_WITH_LEN("disabled"), cs); + else + table->field[14]->store("", 0, cs); + table->field[14]->set_notnull(); + DBUG_ASSERT(MY_TEST(key_info->flags & HA_USES_COMMENT) == + (key_info->comment.length > 0)); + if (key_info->flags & HA_USES_COMMENT) + table->field[15]->store(key_info->comment.str, + key_info->comment.length, cs); + if (schema_table_store_record(thd, table)) + return 1; + return 0; +} +
static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, @@ -6066,67 +6217,34 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, HA_STATUS_TIME); set_statistics_for_table(thd, show_table); } for (uint i=0 ; i < show_table->s->keys ; i++, key_info++) { KEY_PART_INFO *key_part= key_info->key_part; - const char *str; for (uint j=0 ; j < key_info->user_defined_key_parts; j++, key_part++) { - restore_record(table, s->default_values); - table->field[0]->store(STRING_WITH_LEN("def"), cs); - table->field[1]->store(db_name->str, db_name->length, cs); - table->field[2]->store(table_name->str, table_name->length, cs); - table->field[3]->store((longlong) ((key_info->flags & - HA_NOSAME) ? 0 : 1), TRUE); - table->field[4]->store(db_name->str, db_name->length, cs); - table->field[5]->store(key_info->name, strlen(key_info->name), cs); - table->field[6]->store((longlong) (j+1), TRUE); - str=(key_part->field ? key_part->field->field_name : - "?unknown field?"); - table->field[7]->store(str, strlen(str), cs); - if (show_table->file) + + if (key_info->flags & HA_UNIQUE_HASH && key_info->key_part->field) { - if (show_table->file->index_flags(i, j, 0) & HA_READ_ORDER) + LEX_STRING *ls = &key_info->key_part->field->vcol_info->expr_str; + int total_fields= fields_in_hash_str(ls); + int counter= 0; + Field *fld; + while (counter < total_fields) { - table->field[8]->store(((key_part->key_part_flag & - HA_REVERSE_SORT) ? - "D" : "A"), 1, cs); - table->field[8]->set_notnull(); - } - KEY *key=show_table->key_info+i; - if (key->rec_per_key[j]) - { - ha_rows records= (ha_rows) ((double) show_table->stat_records() / - key->actual_rec_per_key(j)); - table->field[9]->store((longlong) records, TRUE); - table->field[9]->set_notnull(); + fld= field_ptr_in_hash_str(ls, show_table, counter);
parsing strings, again? don't do that, please.
+ if(print_get_schema_stat_keypart(thd, tables, table, + show_table, db_name, + table_name, key_info, + key_part, fld, i, counter)) + DBUG_RETURN(1); + counter++; } - str= show_table->file->index_type(i); - table->field[13]->store(str, strlen(str), cs); - } - if (!(key_info->flags & HA_FULLTEXT) && - (key_part->field && - key_part->length != - show_table->s->field[key_part->fieldnr-1]->key_length())) - { - table->field[10]->store((longlong) key_part->length / - key_part->field->charset()->mbmaxlen, TRUE); - table->field[10]->set_notnull(); + + continue; } - uint flags= key_part->field ? key_part->field->flags : 0; - const char *pos=(char*) ((flags & NOT_NULL_FLAG) ? "" : "YES"); - table->field[12]->store(pos, strlen(pos), cs); - if (!show_table->s->keys_in_use.is_set(i)) - table->field[14]->store(STRING_WITH_LEN("disabled"), cs); - else - table->field[14]->store("", 0, cs); - table->field[14]->set_notnull(); - DBUG_ASSERT(MY_TEST(key_info->flags & HA_USES_COMMENT) == - (key_info->comment.length > 0)); - if (key_info->flags & HA_USES_COMMENT) - table->field[15]->store(key_info->comment.str, - key_info->comment.length, cs); - if (schema_table_store_record(thd, table)) + + if(print_get_schema_stat_keypart(thd, tables,table,show_table,db_name, + table_name,key_info,key_part,key_part->field,i,j)) DBUG_RETURN(1); } } @@ -6134,7 +6252,6 @@ static int get_schema_stat_record(THD *thd, TABLE_LIST *tables, DBUG_RETURN(res); }
-
add the empty line back, please
static int get_schema_views_record(THD *thd, TABLE_LIST *tables, TABLE *table, bool res, LEX_STRING *db_name, diff --git a/sql/table.cc b/sql/table.cc index 640ab82..5d5be01 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -685,7 +685,7 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, uint keys, KEY *keyinfo, uint new_frm_ver, uint &ext_key_parts, TABLE_SHARE *share, uint len, - KEY *first_keyinfo, char* &keynames) + KEY *first_keyinfo, char* &keynames,const uchar *key_ex_flags)
this new argument seems to be unused
Reverted, was used in previous versions.
{ uint i, j, n_length; KEY_PART_INFO *key_part= NULL; @@ -738,7 +738,6 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, keyinfo->algorithm= HA_KEY_ALG_UNDEF; strpos+=4; } -
don't delete empty lines, please, restore them all
if (i == 0) { ext_key_parts+= (share->use_ext_keys ? first_keyinfo->user_defined_key_parts*(keys-1) : 0); @@ -801,7 +799,8 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end, keyinfo->ext_key_parts= keyinfo->user_defined_key_parts; keyinfo->ext_key_flags= keyinfo->flags; keyinfo->ext_key_part_map= 0; - if (share->use_ext_keys && i && !(keyinfo->flags & HA_NOSAME)) + if (share->use_ext_keys && i && !(keyinfo->flags & HA_NOSAME) + )
revert
{ for (j= 0; j < first_key_parts && keyinfo->ext_key_parts < MAX_REF_PARTS; @@ -989,6 +988,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, const uchar *frm_image_end = frm_image + frm_length; uchar *record, *null_flags, *null_pos, *mysql57_vcol_null_pos; const uchar *disk_buff, *strpos; + const uchar * field_properties=NULL,*key_ex_flags=NULL;
this key_ex_flags is not used for anything
ulong pos, record_offset; ulong rec_buff_length; handler *handler_file= 0; @@ -1056,7 +1056,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if (length < 256) goto err; } - if (extra2 + length > e2end) + if ( extra2 + length > e2end)
revert
goto err; switch (type) { case EXTRA2_TABLEDEF_VERSION: @@ -1101,6 +1101,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, } #endif /*HAVE_SPATIAL*/ break; + case EXTRA2_FIELD_FLAGS: + field_properties = extra2;
imagine in some later MariaDB version we'll need more flags. there may be more than two bytes per column. so here you can check the length and fail with an error (no assert!) if it's not num_of_fields*2.
Added.
+ break; default: /* abort frm parsing if it's an unknown but important extra2 value */ if (type >= EXTRA2_ENGINE_IMPORTANT) @@ -1795,6 +1797,16 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, reg_field->field_index= i; reg_field->comment=comment; reg_field->vcol_info= vcol_info; + if(field_properties!=NULL) + { + reg_field->field_visibility=static_cast<field_visible_type>(*field_properties++); + reg_field->is_long_column_hash=static_cast<bool>(*field_properties++);
why did you need a cast here? was there compiler warning?
Changed.
+ } + /* + We will add status variable only when we find a user defined hidden column
"increment". or, better, remove this comment completely, it's obvious anyway
Removed
+ */ + if (reg_field->field_visibility == USER_DEFINED_HIDDEN) + status_var_increment(thd->status_var.feature_hidden_column); if (field_type == MYSQL_TYPE_BIT && !f_bit_as_char(pack_flag)) { null_bits_are_used= 1; @@ -2004,13 +2016,27 @@ 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(); + /* + Add HA_UNIQUE_HASH flag if keyinfo has only one field + and field has is_long_column_hash flag on + */ + if (keyinfo->user_defined_key_parts == 1 && + field->is_long_column_hash) + { + keyinfo->flags|= HA_UNIQUE_HASH; + keyinfo->ext_key_flags|= HA_UNIQUE_HASH;
why do you set it in ext_key_flags?
It was used in optimizer. Anyway new version does not use this code.
+ } if (field->null_ptr) { key_part->null_offset=(uint) ((uchar*) field->null_ptr - share->default_values); key_part->null_bit= field->null_bit; key_part->store_length+=HA_KEY_NULL_LENGTH; - keyinfo->flags|=HA_NULL_PART_KEY; + if (keyinfo->flags & HA_UNIQUE_HASH && + !(keyinfo->flags & HA_NULL_PART_KEY)) + {} + else + keyinfo->flags|=HA_NULL_PART_KEY;
1. why not simply
if (!(keyinfo->flags & HA_UNIQUE_HASH)) keyinfo->flags|=HA_NULL_PART_KEY;
Actually this was more complex. If keyinfo does not have HA_NULL_PART_KEY flag for HA_UNIQUE_HASH , then this means Key can not be null. But removed this in newer version.
2. this needs a comment
keyinfo->key_length+= HA_KEY_NULL_LENGTH; } if (field->type() == MYSQL_TYPE_BLOB || @@ -2124,6 +2149,11 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write, if ((keyinfo->flags & HA_NOSAME) || (ha_option & HA_ANY_INDEX_MAY_BE_UNIQUE)) set_if_bigger(share->max_unique_length,keyinfo->key_length); + if (keyinfo->flags & HA_UNIQUE_HASH) + { + keyinfo->ext_key_parts= 1; + keyinfo->ext_key_part_map= 0; + }
why?
This is a create_key_info code. if (share->use_ext_keys && i && !(keyinfo->flags &HA_NOSAME)) { for (j= 0; j < first_key_parts && keyinfo->ext_key_parts < MAX_REF_PARTS; j++) { uint key_parts= keyinfo->user_defined_key_parts; KEY_PART_INFO* curr_key_part= keyinfo->key_part; KEY_PART_INFO* curr_key_part_end= curr_key_part+key_parts; for ( ; curr_key_part < curr_key_part_end; curr_key_part++) { if (curr_key_part->fieldnr == first_key_part[j].fieldnr) break; } if (curr_key_part == curr_key_part_end) { *key_part++= first_key_part[j]; *rec_per_key++= 0; keyinfo->ext_key_parts++; keyinfo->ext_key_part_map|= 1 << j; } } if (j == first_key_parts) keyinfo->ext_key_flags= keyinfo->flags | HA_EXT_NOSAME; hash key_info does not have HA_NOSAME flag so, its keyinfo->ext_key_parts is added. But we do not want this. Anyway removed this in new version. Now HA_UNIQUE_HASH key also have HA_NOSAME flag.
} if (primary_key < MAX_KEY && (share->keys_in_use.is_set(primary_key))) @@ -7808,3 +7842,193 @@ double KEY::actual_rec_per_key(uint i) return (is_statistics_from_stat_tables ? read_stats->get_avg_frequency(i) : (double) rec_per_key[i]); } + +/* + find out that whether field name exists in hash_str + return index of hash_str if found other wise returns + -1 +*/ +int find_field_name_in_hash(char * hash_str, const char * field_name, + int hash_str_length)
ok, all these manipulations with the expression *string* should be removed. Column names might contain commas, column names might contain backticks - you don't handle that. And you should not, really, don't use vcol_info->expr_str, use vcol_info->expr_item instead.
Removed. Now I use expr_item.
+{ + + int j= 0, i= 0; + for (i= 0; i < hash_str_length; i++) + { + while (*(hash_str+i) == *(field_name+j)) + { + i++; + j++; + if(*(field_name+j)=='\0' &&*(hash_str+i)=='`') + goto done; + } + j=0; + } + return -1; + done: + return i; +} + +/* + find out the field positoin in hash_str() + position starts from 0 + else return -1; +*/ +int find_field_index_in_hash(LEX_STRING *hash_lex, const char * field_name) +{ + char *hash_str= hash_lex->str; + int hash_str_length= hash_lex->length; + int field_name_position= find_field_name_in_hash(hash_str, field_name, hash_str_length); + if (field_name_position == -1) + return -1; + int index= 0; + for (int i= 0; i < field_name_position; i++) + { + if (hash_str[i] == ',') + index++; + } + return index; +} + +/* + find total number of field in hash_str +*/ +int fields_in_hash_str(LEX_STRING * hash_lex) +{ + int hash_str_length= hash_lex->length; + char *hash_str= hash_lex->str; + int num_of_fields= 1; + for (int i= 0; i<hash_str_length; i++) + { + if (hash_str[i] == ',' && hash_str[i-1] == '`' + && hash_str[i+1] == '`' ) + num_of_fields++; + } + return num_of_fields; +} + +/* + return fields ptr given by hash_str index + for example + hash(`abc`,`xyz`) + index 1 will return pointer to xyz field +*/ +Field * field_ptr_in_hash_str(LEX_STRING * hash_str, TABLE *table, int index) +{ + char field_name[100]; // 100 is enough i think + int temp_index= 0; + char *str= hash_str->str; + int i= strlen("hash"), j; + Field **f, *field; + while (i < hash_str->length) + { + if (str[i] == ',') + temp_index++; + if (temp_index >= index) + break; + i++; + } + i+= 2; // now i point to first character of field name + for (j= 0; str[i+j] != '`'; j++) + field_name[j]= str[i+j]; + field_name[j]= '\0'; + for (f= table->field; f && (field= *f); f++) + { + if (!my_strcasecmp(system_charset_info, field->field_name, field_name)) + break; + } + return field; +} + +/* + Remove field name from db_row_hash_* column vcol info str + For example + + hash(`abc`,`xyz`) + remove "abc" will return + 0 and hash_str will be set hash(`xyz`) and length will be set + + hash(`xyz`) + remove "xyz" will return + 0 and hash_str will be set NULL and length will be 0 + hash(`xyz`) + remove "xyzff" will return + 1 no change to hash_str and length + TODO a better and less complex logic +*/ +int rem_field_from_hash_col_str(LEX_STRING * hash_lex, const char * field_name) +{ + /* first of all find field_name in hash_str*/ + char * temp= hash_lex->str; + const char * t_field= field_name; + int i= find_field_name_in_hash(temp, field_name, hash_lex->length); + if ( i != -1) + { + /* + We found the field location + First of all we need to find the + , position and there can be three + situations + 1. two , not a problem remove any one + 2. one , remove this + 3 no , return + */ + // see if there is , before field name + int j= strlen(field_name); + if (*(temp + i -j-2) == ',') + { + hash_lex->length= hash_lex->length- j-2-1;//-2 for two '`' and -1 for ',' + memmove(temp+i-j-2, temp+i+1, hash_lex->length); + return 0; + } + if (*(temp+i+1) == ',') + { + hash_lex->length= hash_lex->length-j-2-1;//-2 for two '`' and -1 for ',' + memmove(temp+i-j-1, temp+i+2, hash_lex->length); + return 0; + } + if (*(temp+i+1) == ')') + { + hash_lex->length= 0; + hash_lex->str= NULL; + return 0; + } + } + return 1; +} +/* returns 1 if old_name not found in hash_lex 0 other wise*/ +int change_field_from_hash_col_str(LEX_STRING * hash_lex, const char * old_name, + char * new_name) +{ + /* first of all find field_name in hash_lex*/ + char * temp= hash_lex->str; + const char * t_field= old_name; + int i= find_field_name_in_hash(temp, old_name, hash_lex->length); + if (i != -1) + { + int len= hash_lex->length-strlen(old_name) + strlen(new_name); + int num= 0; + char temp_arr[len]; + int s_c_position= i - strlen(old_name);//here it represent the posotion of + //'`' before old f_name + for (int index= 0; index < len; index++) + { + if (index >= s_c_position && index < s_c_position+strlen(new_name)) + { + temp_arr[index]= new_name[index-s_c_position]; + continue; + } + if (index >= s_c_position+strlen(new_name)) + { + temp_arr[index]= temp[i+num]; + num++; + continue; + } + temp_arr[index]= temp[index]; + } + strcpy(hash_lex->str, temp_arr); + hash_lex->length= len; + return 0; + } + return 1; +} diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5cc7798..921cf18 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc
this is impressive :) but to send you something sooner, I'm going to skip your optimizer changes now, I'll send the review of the original project (long UNIQUE constraint) first, then I'll finish the review of the optimizer part.
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index e745fe8..ed8aa8f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3186,6 +3186,177 @@ static void check_duplicate_key(THD *thd, } }
+/* + Add hidden level 3 hash field to table in case of long + unique column + Returns 0 on success + else 1 +*/ + +int add_hash_field(THD * thd, Alter_info *alter_info, Key *current_key, + KEY *current_key_info, KEY *key_info, CHARSET_INFO *cs)
should be declared static
Done.
+{ + int num= 1; + List_iterator<Key> key_iter(alter_info->key_list); + List_iterator<Key_part_spec> key_part_iter(current_key->columns); + List_iterator<Create_field> it(alter_info->create_list); + Create_field *dup_field, * sql_field; + Key_part_spec *temp_colms; + + Create_field *cf= new (thd->mem_root) Create_field(); + cf->flags|= UNSIGNED_FLAG; + cf->length= cf->char_length= HA_HASH_FIELD_LENGTH; + cf->charset= NULL; + cf->decimals= 0; + char *temp_name= (char *)thd->alloc(30); + strcpy(temp_name, HA_DB_ROW_HASH_STR); + char num_holder[10]; //10 is way more but i think it is ok + sprintf(num_holder, "%d",num); + strcat(temp_name, num_holder);
1. my_snprintf, not sprintf. for just one number - strtol 2. "%u" not "%d" 3. with sprintf, you don't need strcat:
my_snprintf(temp_name, sizeof(temp_name), "DB_ROW_HASH_%u", num);
Okay , Changed.
+ /* + Check for collusions + */ + while ((dup_field= it++)) + { + if (!my_strcasecmp(system_charset_info, temp_name, dup_field->field_name)) + { + temp_name[12]= '\0'; //now temp_name='DB_ROW_HASH_' + num++; + sprintf(num_holder, "%d",num); + strcat(temp_name, num_holder); + it.rewind(); + } + } + it.rewind(); + cf->field_name= temp_name; + cf->sql_type= MYSQL_TYPE_LONGLONG; + /* hash column should be atmost hidden */
should be "fully hidden"
Changed
+ cf->field_visibility= FULL_HIDDEN; + cf->is_long_column_hash= true; + /* add the virtual colmn info */ + Virtual_column_info *v= new (thd->mem_root) Virtual_column_info(); + char * hash_exp= (char *)thd->alloc(1024); + char * key_name= (char *)thd->alloc(252); + strcpy(hash_exp, HA_HASH_STR_HEAD); + temp_colms= key_part_iter++; + strcat(hash_exp, temp_colms->field_name.str); + strcpy(key_name, temp_colms->field_name.str); + strcat(hash_exp, "`"); + while ((temp_colms= key_part_iter++)) + { + while ((sql_field= it++) && + my_strcasecmp(system_charset_info, + temp_colms->field_name.str, sql_field->field_name)) + {} + it.rewind(); + /* + There should be only one key for db_row_hash_* column + we need to give user a error when the accidently query + like + + create table t1(abc blob unique, unique(db_row_hash_1)); + alter table t2 add column abc blob unique,add unique key(db_row_hash_1); + + for this we will iterate through the key_list and + find if and key_part has the same name as of temp_name + */ + if (!sql_field || sql_field->is_long_column_hash) + { + my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), temp_name); + return 1; + }
hmm, are you sure this check is needed? you've just added a column, there can be no existing key that refers to it, can it?
Or, may be, you added a column before the code that checks whether a key is valid? In that case, that code will still fail with ER_KEY_COLUMN_DOES_NOT_EXITS, because your column is fully hidden.
Either way, your check looks redundant.
Removed this whole part.
+ /* + This test for wrong query like + create table t1(a blob ,unique(a,a)); + */ + if (find_field_name_in_hash(hash_exp, + temp_colms->field_name.str, strlen(hash_exp))!=-1) + { + my_error(ER_DUP_FIELDNAME, MYF(0), temp_colms->field_name.str); + return 1; + } + /* If any field can be null add flag */ + if (!sql_field->flags & NOT_NULL_FLAG) + current_key_info->flags|= HA_NULL_PART_KEY; + strcat(hash_exp, (const char * )","); + strcat(key_name, "_"); + strcat(hash_exp, "`"); + strcat(hash_exp, temp_colms->field_name.str); + strcat(key_name, temp_colms->field_name.str); + strcat(hash_exp, "`");
1. hash_exp is generated incorrectly, you forgot that a column name itself can contain backticks. There are quoting functions in sql_show.cc and as my_snprintf("%`s")
Changed.
2. do you really need to create a true virtual column here, with the hash expression and store it in the frm? you can store the key as a normal key (with actual blobs, not uint for the hash value), and generate the vcol in init_from_binary_frm_image().
This is a big change. Took me 3-4 days , But anyway done.
+ } + strcat(hash_exp, (const char * )")"); + v->expr_str.str= hash_exp; + v->expr_str.length= strlen(hash_exp); + v->expr_item= NULL; + v->set_stored_in_db_flag(true); + cf->vcol_info= v; + cf->charset= cs; + cf->create_length_to_internal_length(); + cf->length= cf->char_length= cf->pack_length; + prepare_create_field(cf, NULL, 0); + if (!current_key_info->flags & HA_NULL_PART_KEY) + { + cf->pack_flag^= FIELDFLAG_MAYBE_NULL; + cf->flags^= NOT_NULL_FLAG; + } + alter_info->create_list.push_front(cf,thd->mem_root); + /* Update row offset because field is added in first position */ + int offset=0; + it.rewind(); + while ((dup_field= it++)) + { + dup_field->offset= offset; + if (dup_field->stored_in_db()) + offset+= dup_field->pack_length; + } + it.rewind(); + while ((dup_field= it++)) + { + if (!dup_field->stored_in_db()) + { + dup_field->offset= offset; + offset+= dup_field->pack_length; + } + } + if(current_key->name.length==0) + { + current_key_info->name= key_name; + current_key_info->name_length= strlen(key_name); + key_name= make_unique_key_name(thd, key_name, + key_info, current_key_info); + } + else + current_key_info->name= current_key->name.str; + if (check_if_keyname_exists(current_key_info->name, key_info, + current_key_info)) + { + my_error(ER_DUP_KEYNAME, MYF(0), key_name); + return 1; + } + current_key->type= Key::MULTIPLE; + current_key_info->key_length= cf->pack_length; //length of mysql long column + current_key_info->user_defined_key_parts= 1; + current_key_info->flags= 0; + current_key_info->key_part->fieldnr= 0; + current_key_info->key_part->offset= 0; + current_key_info->key_part->key_type= cf->pack_flag; + current_key_info->key_part->length= cf->pack_length; + /* As key is added in front so update update keyinfo field ref and offset*/ + KEY * t_key = key_info; + KEY_PART_INFO *t_key_part; + while (t_key != current_key_info) + { + t_key_part= t_key->key_part; + for (int i= 0; i < t_key->user_defined_key_parts; i++,t_key_part++) + { + t_key_part->fieldnr+= 1; + t_key_part->offset+= cf->pack_length; + } + t_key++; + } + return 0; +}
/* Preparation for table creation @@ -3283,7 +3454,13 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, /* Fix for prepare statement */ thd->change_item_tree(&sql_field->default_value->expr_item, item); } - + if (sql_field->field_visibility == USER_DEFINED_HIDDEN && + sql_field->flags & NOT_NULL_FLAG && + sql_field->flags & NO_DEFAULT_VALUE_FLAG) + { + my_error(ER_HIDDEN_NOT_NULL_WOUT_DEFAULT, MYF(0), sql_field->field_name);
say "WITHOUT", this "WOUT" looks weird
Changed, I thought short form will work.
+ DBUG_RETURN(TRUE); + } if (sql_field->sql_type == MYSQL_TYPE_SET || sql_field->sql_type == MYSQL_TYPE_ENUM) { @@ -3884,10 +4070,24 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, if (f_is_geom(sql_field->pack_flag) && sql_field->geom_type == Field::GEOM_POINT) 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 (!column->length) + { + if (key->type == Key::PRIMARY) + { //todo change error message
agree, ER_TOO_LONG_KEY would be better here
Changed
+ my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->field_name.str); + DBUG_RETURN(TRUE); + } + if (!add_hash_field(thd, alter_info, key, key_info, + *key_info_buffer, create_info->default_table_charset)) + { + key_part_info= key_info->key_part; + key_part_info++; + null_fields++; + key_length= HA_HASH_KEY_LENGTH_WITHOUT_NULL; + break; + } + else + DBUG_RETURN(TRUE); } } #ifdef HAVE_SPATIAL @@ -3974,9 +4174,9 @@ 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); - } + my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length); + DBUG_RETURN(TRUE);
why don't you call add_hash_field() here? if this place is now impossible, add a DBUG_ASSERT(0) there or remove the if() completely and replace it with an assert. I mean:
if (condition) { something; } else { something else; }
becomes
DBUG_ASSERT(condition); something;
+ } } } // Catch invalid use of partial keys @@ -4021,8 +4221,23 @@ 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) + { + my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length); + DBUG_RETURN(TRUE); + } + //todo we does not respect length given by user in calculating hash
oh. that's a bug. good that you have a comment about it, there're more urgent issues that this one, but it should be fixed eventually
//TODO
+ if(!add_hash_field(thd, alter_info, key, key_info, + *key_info_buffer, create_info->default_table_charset)) + { + key_part_info= key_info->key_part; + key_part_info++; + null_fields++; + key_length= HA_HASH_KEY_LENGTH_WITHOUT_NULL; + break; + } + else + DBUG_RETURN(TRUE); } } key_part_info->length= (uint16) key_part_length; @@ -7502,6 +7717,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, */ for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++) { + if (field->field_visibility == FULL_HIDDEN) + continue;
ok, so you recreate DB_ROW_HASH_xxx columns every time
Yes, BTW I changed this If condition to this one if (field->is_long_unique_hash) continue;
Alter_drop *drop; if (field->type() == MYSQL_TYPE_VARCHAR) create_info->varchar= TRUE; @@ -7818,7 +8057,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
if (key_info->flags & HA_SPATIAL) key_type= Key::SPATIAL; - else if (key_info->flags & HA_NOSAME) + else if (key_info->flags & HA_NOSAME || key_info->flags & HA_UNIQUE_HASH) { if (! my_strcasecmp(system_charset_info, key_name, primary_key_name)) key_type= Key::PRIMARY;
huh? I thought your HA_UNIQUE_HASH indexes cannot be Key::PRIMARY
Sorry , I did not see this.
Regards, Sergei Chief Architect MariaDB and security@mariadb.org