From 5ded16c5d0830b4b84830e3e17bc63dd099492aa Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Apr 2007 15:01:04 +0500 Subject: [PATCH 1/5] Bug#27069 set with identical elements are created(additional fix) issue an error in strict mode if enum|set column has duplicates members in 'create table' mysql-test/r/strict.result: test case mysql-test/t/strict.test: test case sql/sql_table.cc: issue an error in strict mode if enum|set has duplicates members --- mysql-test/r/strict.result | 5 +++++ mysql-test/t/strict.test | 9 +++++++++ sql/sql_table.cc | 27 +++++++++++++++++++-------- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/strict.result b/mysql-test/r/strict.result index 636a00a4343..f9d84df5d9f 100644 --- a/mysql-test/r/strict.result +++ b/mysql-test/r/strict.result @@ -1386,4 +1386,9 @@ ERROR 01000: Data truncated for column 'a' at row 1 insert into t1 values ('2E3x'); ERROR 01000: Data truncated for column 'a' at row 1 drop table t1; +set sql_mode='traditional'; +create table t1 (f1 set('a','a')); +ERROR HY000: Column 'f1' has duplicated value 'a' in SET +create table t1 (f1 enum('a','a')); +ERROR HY000: Column 'f1' has duplicated value 'a' in ENUM End of 5.0 tests diff --git a/mysql-test/t/strict.test b/mysql-test/t/strict.test index 5e4d956527b..1792c0fccbc 100644 --- a/mysql-test/t/strict.test +++ b/mysql-test/t/strict.test @@ -1249,4 +1249,13 @@ insert into t1 values ('2000a'); insert into t1 values ('2E3x'); drop table t1; +# +# Bug#27069 set with identical elements are created +# +set sql_mode='traditional'; +--error 1291 +create table t1 (f1 set('a','a')); +--error 1291 +create table t1 (f1 enum('a','a')); + --echo End of 5.0 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 607fc4c5040..f498d33191b 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -414,10 +414,11 @@ static int sort_keys(KEY *a, KEY *b) which has some duplicates on its right RETURN VALUES - void + 0 ok + 1 Error */ -void check_duplicates_in_interval(const char *set_or_name, +bool check_duplicates_in_interval(const char *set_or_name, const char *name, TYPELIB *typelib, CHARSET_INFO *cs, unsigned int *dup_val_count) { @@ -433,6 +434,13 @@ void check_duplicates_in_interval(const char *set_or_name, tmp.count--; if (find_type2(&tmp, (const char*)*cur_value, *cur_length, cs)) { + if ((current_thd->variables.sql_mode & + (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES))) + { + my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0), + name,*cur_value,set_or_name); + return 1; + } push_warning_printf(current_thd,MYSQL_ERROR::WARN_LEVEL_NOTE, ER_DUPLICATED_VALUE_IN_TYPE, ER(ER_DUPLICATED_VALUE_IN_TYPE), @@ -440,6 +448,7 @@ void check_duplicates_in_interval(const char *set_or_name, (*dup_val_count)++; } } + return 0; } @@ -575,9 +584,10 @@ int prepare_create_field(create_field *sql_field, if (sql_field->charset->state & MY_CS_BINSORT) sql_field->pack_flag|=FIELDFLAG_BINARY; sql_field->unireg_check=Field::INTERVAL_FIELD; - check_duplicates_in_interval("ENUM",sql_field->field_name, - sql_field->interval, - sql_field->charset, &dup_val_count); + if (check_duplicates_in_interval("ENUM",sql_field->field_name, + sql_field->interval, + sql_field->charset, &dup_val_count)) + DBUG_RETURN(1); break; case FIELD_TYPE_SET: sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) | @@ -585,9 +595,10 @@ int prepare_create_field(create_field *sql_field, if (sql_field->charset->state & MY_CS_BINSORT) sql_field->pack_flag|=FIELDFLAG_BINARY; sql_field->unireg_check=Field::BIT_FIELD; - check_duplicates_in_interval("SET",sql_field->field_name, - sql_field->interval, - sql_field->charset, &dup_val_count); + if (check_duplicates_in_interval("SET",sql_field->field_name, + sql_field->interval, + sql_field->charset, &dup_val_count)) + DBUG_RETURN(1); /* Check that count of unique members is not more then 64 */ if (sql_field->interval->count - dup_val_count > sizeof(longlong)*8) { From 041767e12319c1f4e72a862408f87e97bc6bd587 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Apr 2007 16:55:48 +0300 Subject: [PATCH 2/5] Bug #27659: The optimizer transforms DISTINCT into a GROUP BY when possible. It does that by constructing the same structure (a list of ORDER instances) the parser makes when parsing GROUP BY. While doing that it also eliminates duplicates. But if a duplicate is found it doesn't advance the pointer to ref_pointer array, so the next (and subsequent) ORDER structures point to the wrong element in the SELECT list. Fixed by advancing the pointer in ref_pointer_array even in the case of a duplicate. mysql-test/r/distinct.result: Bug #27659: test case mysql-test/t/distinct.test: Bug #27659: test case sql/sql_select.cc: Bug #27659: use correct ref_pointer_array element --- mysql-test/r/distinct.result | 14 ++++++++++++++ mysql-test/t/distinct.test | 13 +++++++++++++ sql/sql_select.cc | 5 ++--- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 3508a83a810..190e8595126 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -668,3 +668,17 @@ NULL 3 4 DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES(1,1),(1,2),(1,3); +SELECT DISTINCT a, b FROM t1; +a b +1 1 +1 2 +1 3 +SELECT DISTINCT a, a, b FROM t1; +a a b +1 1 1 +1 1 2 +1 1 3 +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/t/distinct.test b/mysql-test/t/distinct.test index 476e4ce7735..7310f98cd16 100644 --- a/mysql-test/t/distinct.test +++ b/mysql-test/t/distinct.test @@ -540,3 +540,16 @@ EXPLAIN SELECT a FROM t1 GROUP BY a; SELECT a FROM t1 GROUP BY a; DROP TABLE t1; + +# +#Bug #27659: SELECT DISTINCT returns incorrect result set when field is +#repeated +# +# +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES(1,1),(1,2),(1,3); +SELECT DISTINCT a, b FROM t1; +SELECT DISTINCT a, a, b FROM t1; +DROP TABLE t1; + +--echo End of 5.0 tests diff --git a/sql/sql_select.cc b/sql/sql_select.cc index d65ecb6fa3b..79ae4ade8ab 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13539,9 +13539,7 @@ create_distinct_group(THD *thd, Item **ref_pointer_array, ORDER *ord_iter; for (ord_iter= group; ord_iter; ord_iter= ord_iter->next) if ((*ord_iter->item)->eq(item, 1)) - break; - if (ord_iter) - continue; + goto next_item; ORDER *ord=(ORDER*) thd->calloc(sizeof(ORDER)); if (!ord) @@ -13556,6 +13554,7 @@ create_distinct_group(THD *thd, Item **ref_pointer_array, *prev=ord; prev= &ord->next; } +next_item: ref_pointer_array++; } *prev=0; From 8e72b760aa0a407f68bf37df37d31caa382d2f82 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 10 Apr 2007 19:08:08 +0300 Subject: [PATCH 3/5] Bug #19372: Added a test case. The problem was fixed by the fix for bug #17379. The problem was that because of some conditions the optimizer always preferred range or full index scan access methods to lookup access methods even when the latter were much cheaper. mysql-test/r/select.result: Bug #19372: test case. The problem was fixed by the patch for bug #17379 mysql-test/t/select.test: Bug #19372: test case. The problem was fixed by the patch for bug #17379 --- mysql-test/r/select.result | 9 +++++++++ mysql-test/t/select.test | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result index b501d547e0a..bfe0b9d19df 100644 --- a/mysql-test/r/select.result +++ b/mysql-test/r/select.result @@ -3986,4 +3986,13 @@ t2.access_id IN (1,4) AND t.access_id IS NULL AND t2.faq_id in (265); faq_id 265 DROP TABLE t1,t2; +CREATE TABLE t1 (a INT, b INT, KEY inx (b,a)); +INSERT INTO t1 VALUES (1,1), (1,2), (1,3), (1,4), (1,5), (1, 6), (1,7); +EXPLAIN SELECT COUNT(*) FROM t1 f1 INNER JOIN t1 f2 +ON ( f1.b=f2.b AND f1.a Date: Wed, 11 Apr 2007 11:41:12 -0700 Subject: [PATCH 4/5] Fixed bug #27484: a crash when incompatible row expressions with nested rows are used as arguments of the IN predicate. Added a function to check compatibility of row expressions. Made sure that this function to be called for Item_func_in objects by fix_length_and_dec(). mysql-test/r/row.result: Added a test case for bug #27484. mysql-test/t/row.test: Added a test case for bug #27484. --- mysql-test/r/row.result | 18 ++++++++++++ mysql-test/t/row.test | 25 ++++++++++++++++ sql/item_cmpfunc.cc | 65 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 104 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result index 76d6fa13766..1c1c4809f36 100644 --- a/mysql-test/r/row.result +++ b/mysql-test/r/row.result @@ -170,3 +170,21 @@ ROW(2,10) <=> ROW(3,4) SELECT ROW(NULL,10) <=> ROW(3,NULL); ROW(NULL,10) <=> ROW(3,NULL) 0 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,1)); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,1),ROW(1,ROW(2,3))); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,ROW(2,2,2))); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(1,ROW(2,3,4)) IN (ROW(1,ROW(2,3,4)),ROW(1,ROW(2,2))); +ERROR 21000: Operand should contain 3 column(s) +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),(SELECT 1,1)); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),(SELECT 1,1),ROW(1,ROW(2,4))); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(1,ROW(2,3)) IN ((SELECT 1,1),ROW(1,ROW(2,3))); +ERROR 21000: Operand should contain 2 column(s) +SELECT ROW(2,1) IN (ROW(21,2),ROW(ROW(1,1,3),0)); +ERROR 21000: Operand should contain 1 column(s) +SELECT ROW(2,1) IN (ROW(ROW(1,1,3),0),ROW(21,2)); +ERROR 21000: Operand should contain 1 column(s) diff --git a/mysql-test/t/row.test b/mysql-test/t/row.test index d8d9a244134..6c66d45b942 100644 --- a/mysql-test/t/row.test +++ b/mysql-test/t/row.test @@ -83,4 +83,29 @@ drop table t1; SELECT ROW(2,10) <=> ROW(3,4); SELECT ROW(NULL,10) <=> ROW(3,NULL); +# +# Bug #27484: nested row expressions in IN predicate +# + +--error 1241 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,1)); +--error 1241 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,1),ROW(1,ROW(2,3))); +--error 1241 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),ROW(1,ROW(2,2,2))); +--error 1241 +SELECT ROW(1,ROW(2,3,4)) IN (ROW(1,ROW(2,3,4)),ROW(1,ROW(2,2))); + +--error 1241 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),(SELECT 1,1)); +--error 1241 +SELECT ROW(1,ROW(2,3)) IN (ROW(1,ROW(2,3)),(SELECT 1,1),ROW(1,ROW(2,4))); +--error 1241 +SELECT ROW(1,ROW(2,3)) IN ((SELECT 1,1),ROW(1,ROW(2,3))); + +--error 1241 +SELECT ROW(2,1) IN (ROW(21,2),ROW(ROW(1,1,3),0)); +--error 1241 +SELECT ROW(2,1) IN (ROW(ROW(1,1,3),0),ROW(21,2)); + # End of 4.1 tests diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 4d54dfc2b39..ce3096da778 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -61,6 +61,42 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) } +/* + Compare row signature of two expressions + + SYNOPSIS: + cmp_row_type() + item1 the first expression + item2 the second expression + + DESCRIPTION + The function checks that two expressions have compatible row signatures + i.e. that the number of columns they return are the same and that if they + are both row expressions then each component from the first expression has + a row signature compatible with the signature of the corresponding component + of the second expression. + + RETURN VALUES + 1 type incompatibility has been detected + 0 otherwise +*/ + +static int cmp_row_type(Item* item1, Item* item2) +{ + uint n= item1->cols(); + if (item2->check_cols(n)) + return 1; + for (uint i=0; iel(i)->check_cols(item1->el(i)->cols()) || + (item1->el(i)->result_type() == ROW_RESULT && + cmp_row_type(item1->el(i), item2->el(i)))) + return 1; + } + return 0; +} + + /* Aggregates result types from the array of items. @@ -75,14 +111,32 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) This function aggregates result types from the array of items. Found type supposed to be used later for comparison of values of these items. Aggregation itself is performed by the item_cmp_type() function. + The function also checks compatibility of row signatures for the + submitted items (see the spec for the cmp_row_type function). + + RETURN VALUES + 1 type incompatibility has been detected + 0 otherwise */ -static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems) +static int agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems) { uint i; type[0]= items[0]->result_type(); for (i= 1 ; i < nitems ; i++) + { type[0]= item_cmp_type(type[0], items[i]->result_type()); + /* + When aggregating types of two row expressions we have to check + that they have the same cardinality and that each component + of the first row expression has a compatible row signature with + the signature of the corresponding component of the second row + expression. + */ + if (type[0] == ROW_RESULT && cmp_row_type(items[0], items[i])) + return 1; // error found: invalid usage of rows + } + return 0; } static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, @@ -984,7 +1038,8 @@ void Item_func_between::fix_length_and_dec() */ if (!args[0] || !args[1] || !args[2]) return; - agg_cmp_type(thd, &cmp_type, args, 3); + if ( agg_cmp_type(thd, &cmp_type, args, 3)) + return; if (cmp_type == STRING_RESULT && agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV)) return; @@ -1532,7 +1587,8 @@ void Item_func_case::fix_length_and_dec() for (nagg= 0; nagg < ncases/2 ; nagg++) agg[nagg+1]= args[nagg*2]; nagg++; - agg_cmp_type(current_thd, &cmp_type, agg, nagg); + if (agg_cmp_type(current_thd, &cmp_type, agg, nagg)) + return; if ((cmp_type == STRING_RESULT) && agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV)) return; @@ -2013,7 +2069,8 @@ void Item_func_in::fix_length_and_dec() uint const_itm= 1; THD *thd= current_thd; - agg_cmp_type(thd, &cmp_type, args, arg_count); + if (agg_cmp_type(thd, &cmp_type, args, arg_count)) + return; if (cmp_type == STRING_RESULT && agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV)) From 8d40fa58edab227caa66c3977a7efe3f0fc5876f Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 11 Apr 2007 12:45:27 -0700 Subject: [PATCH 5/5] Post-merge fix. --- mysql-test/r/row.result | 6 ++++++ sql/item_cmpfunc.cc | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/row.result b/mysql-test/r/row.result index 3a8ab6b8346..bb9e2109f0f 100644 --- a/mysql-test/r/row.result +++ b/mysql-test/r/row.result @@ -193,6 +193,12 @@ SELECT ROW(2,1) IN (ROW(21,2),ROW(ROW(1,1,3),0)); ERROR 21000: Operand should contain 1 column(s) SELECT ROW(2,1) IN (ROW(ROW(1,1,3),0),ROW(21,2)); ERROR 21000: Operand should contain 1 column(s) +SELECT ROW(1,1,1) = ROW(1,1,1) as `1`, ROW(1,1,1) = ROW(1,2,1) as `0`, ROW(1,NULL,1) = ROW(2,2,1) as `0`, ROW(1,NULL,1) = ROW(1,2,2) as `0`, ROW(1,NULL,1) = ROW(1,2,1) as `null` ; +1 0 0 0 null +1 0 0 0 NULL +select row(NULL,1)=(2,0); +row(NULL,1)=(2,0) +0 CREATE TABLE t1 (a int, b int, PRIMARY KEY (a,b)); INSERT INTO t1 VALUES (1,1), (2,1), (3,1), (1,2), (3,2), (3,3); EXPLAIN SELECT * FROM t1 WHERE a=3 AND b=2; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 071762419fc..f9844f6d36e 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -95,9 +95,9 @@ static int cmp_row_type(Item* item1, Item* item2) return 1; for (uint i=0; iel(i)->check_cols(item1->el(i)->cols()) || - (item1->el(i)->result_type() == ROW_RESULT && - cmp_row_type(item1->el(i), item2->el(i)))) + if (item2->element_index(i)->check_cols(item1->element_index(i)->cols()) || + (item1->element_index(i)->result_type() == ROW_RESULT && + cmp_row_type(item1->element_index(i), item2->element_index(i)))) return 1; } return 0;