Commit 2299e1ec authored by monty@mysql.com's avatar monty@mysql.com

Better handling of ensuring that setup_tables() are not called twice

This fixed a bug in prepared statements when used with outher joins
Fixed a bug in SUM(DISTINCT) when used with prepared statements.
Some safety fixes in test scripts to ensure that previous test failures shouldn't affect other tests
parent e2051361
DROP TABLE IF EXISTS t1, `"t"1`;
DROP TABLE IF EXISTS t1, `"t"1`, t1aa,t2aa;
drop database if exists mysqldump_test_db;
CREATE TABLE t1(a int);
INSERT INTO t1 VALUES (1), (2);
......
drop table if exists t1,t2;
drop table if exists t1aa,t2aa;
drop database if exists mysqltest;
delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
delete from mysql.db where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
......
......@@ -1639,12 +1639,9 @@ yz,yz
drop procedure bug3368|
drop table t3|
drop table if exists t3|
create table t3 (f1 int, f2 int);
insert into t3 values (1,1);
--disable_warnings|
create table t3 (f1 int, f2 int)|
insert into t3 values (1,1)|
drop procedure if exists bug4579_1|
Warnings:
Note 1305 PROCEDURE bug4579_1 does not exist
create procedure bug4579_1 ()
begin
declare sf1 int;
......
drop table if exists t1;
CREATE TABLE t1 (x1 int);
ALTER TABLE t1 CHANGE x1 x2 int;
CREATE TABLE t2 LIKE t1;
......
drop table if exists t1,t1aa,t2aa;
show tables;
Tables_in_db
columns_priv
......
--disable_warnings
DROP TABLE IF EXISTS t1, `"t"1`;
DROP TABLE IF EXISTS t1, `"t"1`, t1aa,t2aa;
drop database if exists mysqldump_test_db;
--enable_warnings
......
......@@ -9,7 +9,7 @@
--disable_warnings
drop table if exists t1,t2,t3,t4;
# The following may be left from older tests
drop table if exists t1_1,t1_2,t9_1,t9_2;
drop table if exists t1_1,t1_2,t9_1,t9_2,t1aa,t2aa;
drop view if exists v1;
--enable_warnings
......
......@@ -4,6 +4,7 @@
--disable_warnings
drop table if exists t1,t2;
drop table if exists t1aa,t2aa;
drop database if exists mysqltest;
delete from mysql.user where user='mysqltest_1' || user='mysqltest_2' || user='mysqltest_3';
......
......@@ -945,10 +945,12 @@ insert into t2 values (append("xxx", "yyy"), mul(4,3), e())|
insert into t2 values (append("a", "b"), mul(2,mul(3,4)), fun(1.7, 4, 6))|
# These don't work yet.
--disable_ps_protocol
select * from t2 where s = append("a", "b")|
select * from t2 where i = mul(4,3) or i = mul(mul(3,4),2)|
select * from t2 where d = e()|
select * from t2|
--enable_ps_protocol
delete from t2|
drop function e|
......@@ -1263,8 +1265,10 @@ end|
call rc()|
select row_count()|
--disable_ps_protocol
update t1 set data=42 where id = "b";
select row_count()|
--enable_ps_protocol
delete from t1|
select row_count()|
delete from t1|
......@@ -2022,8 +2026,8 @@ drop table t3|
--disable_warnings
drop table if exists t3|
--enable_warnings
create table t3 (f1 int, f2 int);
insert into t3 values (1,1);
create table t3 (f1 int, f2 int)|
insert into t3 values (1,1)|
--disable_warnings
drop procedure if exists bug4579_1|
......
......@@ -557,7 +557,7 @@ INSERT IGNORE INTO t1 (col1) values (1/0);
INSERT IGNORE INTO t1 VALUES (+1.9E+309,-1.9E+309);
INSERT IGNORE INTO t1 VALUES ('+2.0E+309','-2.0E+309');
# stupid...
--replace_result -0 0
--replace_result -0 0 1.7976931348623e+308 1.79769313486232e+308
SELECT * FROM t1;
DROP TABLE t1;
......
#
# Test for Bug #2385 CREATE TABLE LIKE lacks locking on source and destination table
# Test for Bug #2385 CREATE TABLE LIKE lacks locking on source and destination
# table
#
--disable_warnings
drop table if exists t1;
--enable_warnings
connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
......
......@@ -2,6 +2,11 @@
# This test must examine integrity of system database "mysql"
#
# First delete some tables maybe left over from previous tests
--disable_warnings
drop table if exists t1,t1aa,t2aa;
--enable_warnings
-- disable_query_log
use mysql;
-- enable_query_log
......
......@@ -303,12 +303,6 @@ Item_sum_sum_distinct::Item_sum_sum_distinct(THD *thd,
}
Item_sum_sum_distinct::~Item_sum_sum_distinct()
{
delete tree;
}
Item *
Item_sum_sum_distinct::copy_or_same(THD *thd)
{
......@@ -356,6 +350,14 @@ void Item_sum_sum_distinct::clear()
tree->reset();
}
void Item_sum_sum_distinct::cleanup()
{
Item_sum_num::cleanup();
delete tree;
tree= 0;
}
bool Item_sum_sum_distinct::add()
{
/* args[0]->val_real() may reset args[0]->null_value */
......
......@@ -167,10 +167,11 @@ class Item_sum_sum_distinct :public Item_sum_num
Item_sum_sum_distinct(THD *thd, Item_sum_sum_distinct *item);
public:
Item_sum_sum_distinct(Item *item_par);
~Item_sum_sum_distinct();
~Item_sum_sum_distinct() {}
bool setup(THD *thd);
void clear();
void cleanup();
bool add();
double val_real();
......
......@@ -248,6 +248,8 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27)
#define SELECT_NO_UNLOCK (1L << 28)
#define OPTION_SCHEMA_TABLE (1L << 29)
/* Flag set if setup_tables already done */
#define OPTION_SETUP_TABLES_DONE (1L << 30)
/* The rest of the file is included in the server only */
#ifndef MYSQL_CLIENT
......@@ -565,7 +567,8 @@ int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields);
bool handle_select(THD *thd, LEX *lex, select_result *result);
bool handle_select(THD *thd, LEX *lex, select_result *result,
ulong setup_tables_done_option);
bool mysql_select(THD *thd, Item ***rref_pointer_array,
TABLE_LIST *tables, uint wild_num, List<Item> &list,
COND *conds, uint og_num, ORDER *order, ORDER *group,
......@@ -578,7 +581,7 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type,
select_result *result);
bool mysql_union(THD *thd, LEX *lex, select_result *result,
SELECT_LEX_UNIT *unit);
SELECT_LEX_UNIT *unit, ulong setup_tables_done_option);
int mysql_handle_derived(LEX *lex, int (*processor)(THD *thd,
LEX *lex,
TABLE_LIST *table));
......
......@@ -2794,10 +2794,6 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds,
TABLE_LIST *first_select_table= (select_insert ?
tables->next_local:
0);
if (!tables || tables->setup_is_done)
DBUG_RETURN(0);
tables->setup_is_done= 1;
if (!(*leaves))
make_leaves_list(leaves, tables);
......
......@@ -1735,12 +1735,6 @@ bool mysql_insert_select_prepare(THD *thd)
&lex->select_lex.where, TRUE))
DBUG_RETURN(TRUE);
/*
setup was done in mysql_prepare_insert_check_table, but we have to mark
first local table
*/
if (first_select_table)
first_select_table->setup_is_done= 1;
/*
exclude first table from leaf tables list, because it belong to
INSERT
......
......@@ -2212,7 +2212,7 @@ mysql_execute_command(THD *thd)
if (!result && !(result= new select_send()))
goto error;
query_cache_store_query(thd, all_tables);
res= handle_select(thd, lex, result);
res= handle_select(thd, lex, result, 0);
if (result != lex->result)
delete result;
}
......@@ -2635,7 +2635,7 @@ mysql_execute_command(THD *thd)
and item_list belong to SELECT
*/
select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
res=handle_select(thd, lex, result);
res= handle_select(thd, lex, result, 0);
select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
delete result;
}
......@@ -3005,7 +3005,7 @@ mysql_execute_command(THD *thd)
and item_list belong to SELECT
*/
lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
res= handle_select(thd, lex, result);
res= handle_select(thd, lex, result, OPTION_SETUP_TABLES_DONE);
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
delete result;
}
......@@ -3092,7 +3092,8 @@ mysql_execute_command(THD *thd)
0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE,
result, unit, select_lex);
delete result;
}
......
......@@ -1106,7 +1106,11 @@ static int mysql_test_select(Prepared_statement *stmt,
thd->used_tables= 0; // Updated by setup_fields
// JOIN::prepare calls
/*
JOIN::prepare calls
It is not SELECT COMMAND for sure, so setup_tables will be called as
usual, and we pass 0 as setup_tables_done_option
*/
if (unit->prepare(thd, 0, 0))
{
goto err_prep;
......@@ -1239,7 +1243,8 @@ static bool mysql_test_set_fields(Prepared_statement *stmt,
*/
static bool select_like_statement_test(Prepared_statement *stmt,
TABLE_LIST *tables,
bool (*specific_prepare)(THD *thd))
bool (*specific_prepare)(THD *thd),
ulong setup_tables_done_option)
{
DBUG_ENTER("select_like_statement_test");
THD *thd= stmt->thd;
......@@ -1258,7 +1263,7 @@ static bool select_like_statement_test(Prepared_statement *stmt,
thd->used_tables= 0; // Updated by setup_fields
// JOIN::prepare calls
if (lex->unit.prepare(thd, 0, 0))
if (lex->unit.prepare(thd, 0, setup_tables_done_option))
{
res= TRUE;
}
......@@ -1298,7 +1303,7 @@ static int mysql_test_create_table(Prepared_statement *stmt)
select_lex->item_list.elements)
{
select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
res= select_like_statement_test(stmt, tables, 0);
res= select_like_statement_test(stmt, tables, 0, 0);
select_lex->resolve_mode= SELECT_LEX::NOMATTER_MODE;
}
......@@ -1333,7 +1338,8 @@ static bool mysql_test_multiupdate(Prepared_statement *stmt,
here we do not pass tables for opening, tables will be opened and locked
by mysql_multi_update_prepare
*/
return select_like_statement_test(stmt, 0, &mysql_multi_update_prepare);
return select_like_statement_test(stmt, 0, &mysql_multi_update_prepare,
OPTION_SETUP_TABLES_DONE);
}
......@@ -1362,7 +1368,8 @@ static int mysql_test_multidelete(Prepared_statement *stmt,
if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter)))
return res;
if ((res= select_like_statement_test(stmt, tables,
&mysql_multi_delete_prepare)))
&mysql_multi_delete_prepare,
OPTION_SETUP_TABLES_DONE)))
return res;
if (!tables->table)
{
......@@ -1415,7 +1422,8 @@ static int mysql_test_insert_select(Prepared_statement *stmt,
and item_list belong to SELECT
*/
lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
res= select_like_statement_test(stmt, tables, &mysql_insert_select_prepare);
res= select_like_statement_test(stmt, tables, &mysql_insert_select_prepare,
OPTION_SETUP_TABLES_DONE);
/* revert changes*/
lex->select_lex.table_list.first= (byte*) first_local_table;
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
......@@ -1770,11 +1778,6 @@ void reset_stmt_for_execute(THD *thd, LEX *lex)
for (order= (ORDER *)sl->order_list.first; order; order= order->next)
order->item= &order->item_ptr;
}
{
TABLE_LIST *tables= (TABLE_LIST *)sl->table_list.first;
if (tables)
tables->setup_is_done= 0;
}
{
SELECT_LEX_UNIT *unit= sl->master_unit();
unit->unclean();
......
......@@ -206,18 +206,24 @@ static void add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab);
This handles SELECT with and without UNION
*/
bool handle_select(THD *thd, LEX *lex, select_result *result)
bool handle_select(THD *thd, LEX *lex, select_result *result,
ulong setup_tables_done_option)
{
bool res;
register SELECT_LEX *select_lex = &lex->select_lex;
DBUG_ENTER("handle_select");
if (select_lex->next_select())
res= mysql_union(thd, lex, result, &lex->unit);
res= mysql_union(thd, lex, result, &lex->unit, setup_tables_done_option);
else
{
SELECT_LEX_UNIT *unit= &lex->unit;
unit->set_limit(unit->global_parameters, select_lex);
/*
'options' of mysql_select will be set in JOIN, as far as JOIN for
every PS/SP execution new, we will not need reset this flag if
setup_tables_done_option changed for next rexecution
*/
res= mysql_select(thd, &select_lex->ref_pointer_array,
(TABLE_LIST*) select_lex->table_list.first,
select_lex->with_wild, select_lex->item_list,
......@@ -228,7 +234,8 @@ bool handle_select(THD *thd, LEX *lex, select_result *result)
(ORDER*) select_lex->group_list.first,
select_lex->having,
(ORDER*) lex->proc_list.first,
select_lex->options | thd->options,
select_lex->options | thd->options |
setup_tables_done_option,
result, unit, select_lex);
}
DBUG_PRINT("info",("res: %d report_error: %d", res,
......@@ -311,8 +318,9 @@ JOIN::prepare(Item ***rref_pointer_array,
/* Check that all tables, fields, conds and order are ok */
if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables,
FALSE, FALSE) ||
if ((!(select_options & OPTION_SETUP_TABLES_DONE) &&
setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables,
FALSE, FALSE)) ||
setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) ||
select_lex->setup_ref_array(thd, og_num) ||
setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
......@@ -1082,7 +1090,6 @@ JOIN::reinit()
/* conds should not be used here, it is added just for safety */
if (tables_list)
{
tables_list->setup_is_done= 0;
if (setup_tables(thd, tables_list, &conds, &select_lex->leaf_tables,
TRUE, FALSE))
DBUG_RETURN(1);
......
......@@ -25,11 +25,12 @@
#include "sql_select.h"
bool mysql_union(THD *thd, LEX *lex, select_result *result,
SELECT_LEX_UNIT *unit)
SELECT_LEX_UNIT *unit, ulong setup_tables_done_option)
{
DBUG_ENTER("mysql_union");
bool res;
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK)))
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK |
setup_tables_done_option)))
res= unit->exec();
if (!res && thd->cursor && thd->cursor->is_open())
{
......@@ -210,6 +211,13 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
JOIN *join= new JOIN(thd_arg, sl->item_list,
sl->options | thd_arg->options | additional_options,
tmp_result);
/*
setup_tables_done_option should be set only for very first SELECT,
because it protect from secont setup_tables call for select-like non
select commands (DELETE/INSERT/...) and they use only very first
SELECT (for union it can be only INSERT ... SELECT).
*/
additional_options&= ~OPTION_SETUP_TABLES_DONE;
if (!join)
goto err;
......
......@@ -771,9 +771,6 @@ bool mysql_multi_update_prepare(THD *thd)
for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global)
tbl->cleanup_items();
/* undone setup_tables() */
table_list->setup_is_done= 0;
if (setup_tables(thd, table_list, &lex->select_lex.where,
&lex->select_lex.leaf_tables, FALSE, FALSE) ||
(lex->select_lex.no_wrap_view_item= 1,
......@@ -842,7 +839,8 @@ bool mysql_multi_update(THD *thd,
total_list,
conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
(ORDER *)NULL,
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK,
options | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK |
OPTION_SETUP_TABLES_DONE,
result, unit, select_lex);
delete result;
thd->abort_on_warning= 0;
......
......@@ -369,7 +369,6 @@ typedef struct st_table_list
/* used in multi-upd/views privilege check */
bool table_in_first_from_clause;
bool skip_temporary; /* this table shouldn't be temporary */
bool setup_is_done; /* setup_tables() is done */
/* TRUE if this merged view contain auto_increment field */
bool contain_auto_increment;
/* FRMTYPE_ERROR if any type is acceptable */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment