diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 7e1aebac872..edad116028f 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -723,27 +723,6 @@ WHERE hostname LIKE '%aol%' hostname no cache-dtc-af05.proxy.aol.com 1 DROP TABLE t1; -create table t1 (c1 char(3), c2 char(3)); -create table t2 (c3 char(3), c4 char(3)); -insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); -insert into t2 values ('aaa', 'bb1'), ('aaa', 'bb2'); -select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 -group by c2; -c2 -aaa -aaa -Warnings: -Warning 1052 Column 'c2' in group statement is ambiguous -show warnings; -Level Code Message -Warning 1052 Column 'c2' in group statement is ambiguous -select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 -group by t1.c1; -c2 -aaa -show warnings; -Level Code Message -drop table t1, t2; CREATE TABLE t1 (a int, b int); INSERT INTO t1 VALUES (1,2), (1,3); SELECT a, b FROM t1 GROUP BY 'const'; @@ -762,3 +741,13 @@ SELECT dt DIV 1 AS f, id FROM t1 GROUP BY f; f id 20050501123000 1 DROP TABLE t1; +CREATE TABLE t1 (id varchar(20) NOT NULL); +INSERT INTO t1 VALUES ('trans1'), ('trans2'); +CREATE TABLE t2 (id varchar(20) NOT NULL, err_comment blob NOT NULL); +INSERT INTO t2 VALUES ('trans1', 'a problem'); +SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment +FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment; +COUNT(DISTINCT(t1.id)) comment +1 NULL +1 a problem +DROP TABLE t1, t2; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index b178af1bb1c..d7f3b043439 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1726,6 +1726,20 @@ sum(a) drop procedure p1; drop view v1; drop table t1; +CREATE TABLE t1(a char(2) primary key, b char(2)); +CREATE TABLE t2(a char(2), b char(2), index i(a)); +INSERT INTO t1 VALUES ('a','1'), ('b','2'); +INSERT INTO t2 VALUES ('a','5'), ('a','6'), ('b','5'), ('b','6'); +CREATE VIEW v1 AS +SELECT t1.b as c, t2.b as d FROM t1,t2 WHERE t1.a=t2.a; +SELECT d, c FROM v1 ORDER BY d; +d c +5 1 +5 2 +6 1 +6 2 +DROP VIEW v1; +DROP TABLE t1, t2; create table t1 (s1 int); create view v1 as select sum(distinct s1) from t1; select * from v1; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index f0546daf463..be8bdbe892e 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -542,30 +542,6 @@ SELECT hostname, COUNT(DISTINCT user_id) as no FROM t1 DROP TABLE t1; -# -# Bug#11211: Ambiguous column reference in GROUP BY. -# - -create table t1 (c1 char(3), c2 char(3)); -create table t2 (c3 char(3), c4 char(3)); -insert into t1 values ('aaa', 'bb1'), ('aaa', 'bb2'); -insert into t2 values ('aaa', 'bb1'), ('aaa', 'bb2'); - -# query with ambiguous column reference 'c2' ---disable_ps_protocol -select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 -group by c2; -show warnings; ---enable_ps_protocol - -# this query has no ambiguity -select t1.c1 as c2 from t1, t2 where t1.c2 = t2.c4 -group by t1.c1; - -show warnings; - -drop table t1, t2; - # # Test for bug #8614: GROUP BY 'const' with DISTINCT # @@ -589,3 +565,18 @@ INSERT INTO t1 VALUES ( 1, '2005-05-01 12:30:00' ); SELECT dt DIV 1 AS f, id FROM t1 GROUP BY f; DROP TABLE t1; + +# +# Test for bug #11295: GROUP BY a BLOB column with COUNT(DISTINCT column1) +# when the BLOB column takes NULL values +# + +CREATE TABLE t1 (id varchar(20) NOT NULL); +INSERT INTO t1 VALUES ('trans1'), ('trans2'); +CREATE TABLE t2 (id varchar(20) NOT NULL, err_comment blob NOT NULL); +INSERT INTO t2 VALUES ('trans1', 'a problem'); + +SELECT COUNT(DISTINCT(t1.id)), LEFT(err_comment, 256) AS comment + FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY comment; + +DROP TABLE t1, t2; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 23d482254d1..29284540435 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1569,6 +1569,18 @@ drop procedure p1; drop view v1; drop table t1; +# +# Bug#7422 "order by" doesn't work +# +CREATE TABLE t1(a char(2) primary key, b char(2)); +CREATE TABLE t2(a char(2), b char(2), index i(a)); +INSERT INTO t1 VALUES ('a','1'), ('b','2'); +INSERT INTO t2 VALUES ('a','5'), ('a','6'), ('b','5'), ('b','6'); +CREATE VIEW v1 AS + SELECT t1.b as c, t2.b as d FROM t1,t2 WHERE t1.a=t2.a; +SELECT d, c FROM v1 ORDER BY d; +DROP VIEW v1; +DROP TABLE t1, t2; # # using sum(distinct ) & avg(distinct ) in views (BUG#7015) # diff --git a/sql/filesort.cc b/sql/filesort.cc index 30ebd8d59e1..75da43afed5 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -631,7 +631,7 @@ static void make_sortkey(register SORTPARAM *param, *to++=1; /* All item->str() to use some extra byte for end null.. */ String tmp((char*) to,sort_field->length+4,cs); - String *res=item->val_str(&tmp); + String *res= item->str_result(&tmp); if (!res) { if (maybe_null) @@ -673,8 +673,8 @@ static void make_sortkey(register SORTPARAM *param, } case INT_RESULT: { - longlong value=item->val_int(); - if (maybe_null) + longlong value= item->val_int_result(); + if (maybe_null) { *to++=1; /* purecov: inspected */ if (item->null_value) @@ -715,7 +715,7 @@ static void make_sortkey(register SORTPARAM *param, } case DECIMAL_RESULT: { - my_decimal dec_buf, *dec_val= item->val_decimal(&dec_buf); + my_decimal dec_buf, *dec_val= item->val_decimal_result(&dec_buf); if (maybe_null) { if (item->null_value) @@ -733,7 +733,7 @@ static void make_sortkey(register SORTPARAM *param, } case REAL_RESULT: { - double value= item->val_real(); + double value= item->val_result(); if (maybe_null) { if (item->null_value) diff --git a/sql/item.h b/sql/item.h index 6a1490a19d5..de292279e06 100644 --- a/sql/item.h +++ b/sql/item.h @@ -716,10 +716,6 @@ public: void cleanup(); bool remove_dependence_processor(byte * arg); void print(String *str); - - friend bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, - const char *table_name, List_iterator *it, - bool any_privileges, bool allocate_view_names); }; class Item_equal; diff --git a/sql/item_buff.cc b/sql/item_buff.cc index 7e7bbe51657..6652aaafb57 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -60,8 +60,8 @@ bool Cached_item_str::cmp(void) String *res; bool tmp; - res=item->val_str(&tmp_value); - res->length(min(res->length(), value.alloced_length())); + if ((res=item->val_str(&tmp_value))) + res->length(min(res->length(), value.alloced_length())); if (null_value != item->null_value) { if ((null_value= item->null_value)) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 95d94040378..2b185dbc13b 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -894,8 +894,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, List *index_list); bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, - List_iterator *it, bool any_privileges, - bool allocate_view_names); + List_iterator *it, bool any_privileges); bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, TABLE_LIST **leaves, bool select_insert); int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index ee824085df6..fae657a8caf 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -682,6 +682,7 @@ sp_head::execute(THD *thd) cleanup_items(thd->current_arena->free_list); thd->current_arena= old_arena; + state= EXECUTED; done: DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d", diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 7fa14557e57..312bc3b187b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3053,7 +3053,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, } else if (insert_fields(thd,tables,((Item_field*) item)->db_name, ((Item_field*) item)->table_name, &it, - any_privileges, arena != 0)) + any_privileges)) { if (arena) thd->restore_backup_item_arena(arena, &backup); @@ -3306,8 +3306,6 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, any_privileges 0 If we should ensure that we have SELECT privileges for all columns 1 If any privilege is ok - allocate_view_names if true view names will be copied to current Query_arena - memory (made for SP/PS) RETURN 0 ok 'it' is updated to point at last inserted @@ -3317,7 +3315,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, bool insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator *it, - bool any_privileges, bool allocate_view_names) + bool any_privileges) { /* allocate variables on stack to avoid pool alloaction */ Field_iterator_table table_iter; @@ -3508,25 +3506,6 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, field->query_id=thd->query_id; table->used_keys.intersect(field->part_of_key); } - else if (allocate_view_names && - thd->lex->current_select->first_execution) - { - Item_field *item; - if (alias_used) - item= new Item_field(0, - thd->strdup(tables->alias), - thd->strdup(field_name)); - else - item= new Item_field(thd->strdup(tables->view_db.str), - thd->strdup(tables->view_name.str), - thd->strdup(field_name)); - /* - during cleunup() this item will be put in list to replace - expression from VIEW - */ - thd->nocheck_register_item_tree_change(it->ref(), item, - thd->mem_root); - } } /* All fields are used in case if usual tables (in case of view used diff --git a/sql/sql_class.h b/sql/sql_class.h index bcd482c728e..51a18c9f675 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -700,6 +700,8 @@ public: virtual ~Query_arena() {}; inline bool is_stmt_prepare() const { return state == INITIALIZED; } + inline bool is_first_sp_execute() const + { return state == INITIALIZED_FOR_SP; } inline bool is_stmt_prepare_or_first_sp_execute() const { return (int)state < (int)PREPARED; } inline bool is_first_stmt_execute() const { return state == PREPARED; } diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 9356ee04c45..e905f93b860 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -422,7 +422,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, } } - if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0, 0)) + if (insert_fields(thd, tables, tables->db, tables->alias, &it, 0)) goto err0; protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 9ebe10921fd..86539dd8c5e 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -530,7 +530,19 @@ public: query processing end even if we use temporary table */ bool subquery_in_having; - bool first_execution; /* first execution in SP or PS */ + /* + This variable is required to ensure proper work of subqueries and + stored procedures. Generally, one should use the states of + Query_arena to determine if it's a statement prepare or first + execution of a stored procedure. However, in case when there was an + error during the first execution of a stored procedure, the SP body + is not expelled from the SP cache. Therefore, a deeply nested + subquery might be left unoptimized. So we need this per-subquery + variable to inidicate the optimization/execution state of every + subquery. Prepared statements work OK in that regard, as in + case of an error during prepare the PS is not created. + */ + bool first_execution; bool first_cond_optimization; /* do not wrap view fields with Item_ref */ bool no_wrap_view_item;