From 7b1ec027325870da62d0a6b36eeb04b03bd0f576 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Jun 2005 04:24:21 -0700 Subject: [PATCH 1/4] group_by.result, group_by.test: Added a test case for bug #11295. item_buff.cc: Fixed bug #11295. This a correction for the patch of bug #11088 that takes into account a possible NULL values of the BLOB column. sql/item_buff.cc: Fixed bug #11295. This a correction for the patch of bug #11088 that takes into account a possible NULL values of the BLOB column. mysql-test/t/group_by.test: Added a test case for bug #11295. mysql-test/r/group_by.result: Added a test case for bug #11295. --- mysql-test/r/group_by.result | 10 ++++++++++ mysql-test/t/group_by.test | 15 +++++++++++++++ sql/item_buff.cc | 4 ++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index e279fca2a9d..7f78b8bda9b 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -741,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 err_comment +FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY err_comment; +COUNT(DISTINCT(t1.id)) err_comment +1 NULL +1 a problem +DROP TABLE t1, t2; diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 382580cbd4e..694aa8d7411 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -565,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 err_comment + FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY err_comment; + +DROP TABLE t1, t2; diff --git a/sql/item_buff.cc b/sql/item_buff.cc index f5e77862e1d..8298ce2cfb7 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -51,8 +51,8 @@ bool Item_str_buff::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)) From 8f318ec5a027051318c66ede077c7a43c539be6b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Jun 2005 08:15:49 -0700 Subject: [PATCH 2/4] group_by.result, group_by.test: Correction for the test case of bug #11295 to remove warning. mysql-test/t/group_by.test: Correction for the test case of bug #11295 to remove warning. mysql-test/r/group_by.result: Correction for the test case of bug #11295 to remove warning. --- mysql-test/r/group_by.result | 6 +++--- mysql-test/t/group_by.test | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 0fda8e2b048..edad116028f 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -745,9 +745,9 @@ 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 err_comment -FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY err_comment; -COUNT(DISTINCT(t1.id)) err_comment +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/t/group_by.test b/mysql-test/t/group_by.test index 694aa8d7411..be8bdbe892e 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -576,7 +576,7 @@ 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 err_comment - FROM t1 LEFT JOIN t2 ON t1.id=t2.id GROUP BY err_comment; +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; From c4257ae3cee0b97e60ba11c5c68a94f4d3472f5a Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Jun 2005 20:14:50 +0400 Subject: [PATCH 3/4] Fix bug #7422 "order by" doesn't work Field with wrong buffer was used to make sort key, which results in producing same sort key for all records. sql/filesort.cc: Fix bug#7422 "order by" doesn't work mysql-test/t/view.test: Test case for bug#7422 "order by" doesn't work mysql-test/r/view.result: Test case for bug#7422 "order by" doesn't work --- mysql-test/r/view.result | 14 ++++++++++++++ mysql-test/t/view.test | 12 ++++++++++++ sql/filesort.cc | 10 +++++----- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index 84be086ae37..1c96ceb6439 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1726,3 +1726,17 @@ 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; diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 0477ab0ea20..7d075f10abe 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -1569,3 +1569,15 @@ 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; 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) From 04f6f63dd8bdcb4e0d5e7cc6b2200a87eff037fe Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 21 Jun 2005 21:15:21 +0400 Subject: [PATCH 4/4] A preparatory patch to help adding JOIN::transform() and move one-time query transformations to the PREPARE stage (prepared statements). sql/item.h: Remove an unused friend declaration. sql/mysql_priv.h: Change signature of insert_fields() sql/sp_head.cc: Make is_stmt_prepare_or_first_sp_execute really work: reset SP state to EXECUTED after execution. sql/sql_base.cc: allocate_view_names flag of insert_fields is removed. The purpose of this variable was to amend the case when a view is replaced with a base table between subsequent executions of a prepared statement: in that case the new table theoretically can be used instead of the view. If allocate_view_names was set, all the references to the view expressions were replaced with Item_field's which in turn could have been resolved by their names. But this approach doesn't work for other reasons, so let's not try to help what must be solved by TDC. sql/sql_class.h: Add is_first_sp_execute() helper method. sql/sql_handler.cc: insert_fields signature changed. sql/sql_lex.h: Add a comment for variable 'first_execution'. --- sql/item.h | 4 ---- sql/mysql_priv.h | 3 +-- sql/sp_head.cc | 1 + sql/sql_base.cc | 25 ++----------------------- sql/sql_class.h | 2 ++ sql/sql_handler.cc | 2 +- sql/sql_lex.h | 14 +++++++++++++- 7 files changed, 20 insertions(+), 31 deletions(-) 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/mysql_priv.h b/sql/mysql_priv.h index dad524b4e53..2add9ac9269 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 8f83208f44b..fee3bdfeb5f 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3051,7 +3051,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); @@ -3304,8 +3304,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 @@ -3315,7 +3313,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; @@ -3506,25 +3504,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 bee04303460..dd4b8310e51 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -699,6 +699,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 052873640c6..a9bfb6da926 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;