summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormatthias@three.local.lan <>2004-12-14 12:24:59 +0100
committermatthias@three.local.lan <>2004-12-14 12:24:59 +0100
commit621daba7b659bfdf0fe5e8b1754606e1ac116f6f (patch)
treebddd3849df4d89a28106f9b2ceaa154ae66cfba9
parente69c8e76f9fa620aa62ffcac2643bfdadc021fac (diff)
parent94b3e06dd6dc258602b571c8b9803fce443c638d (diff)
downloadmariadb-git-621daba7b659bfdf0fe5e8b1754606e1ac116f6f.tar.gz
Merge mleich@bk-internal.mysql.com:/home/bk/mysql-4.1
into three.local.lan:/home/matthias/Arbeit/mysql-4.1/src
-rw-r--r--Makefile.am6
-rw-r--r--innobase/dict/dict0load.c16
-rw-r--r--mysql-test/mysql-test-run.sh2
-rw-r--r--mysql-test/r/group_by.result12
-rw-r--r--mysql-test/r/insert_select.result.es7
-rw-r--r--mysql-test/t/group_by.test9
-rw-r--r--sql/item.cc29
-rw-r--r--sql/item.h31
-rw-r--r--sql/item_cmpfunc.cc7
-rw-r--r--sql/item_func.cc5
-rw-r--r--sql/item_row.cc1
-rw-r--r--sql/item_strfunc.cc1
-rw-r--r--sql/item_strfunc.h3
-rw-r--r--sql/item_subselect.cc3
-rw-r--r--sql/item_sum.cc4
-rw-r--r--sql/log_event.cc7
-rw-r--r--sql/mysqld.cc3
-rw-r--r--sql/set_var.cc6
-rw-r--r--sql/sql_base.cc6
-rw-r--r--sql/sql_handler.cc6
-rw-r--r--sql/sql_help.cc3
-rw-r--r--sql/sql_prepare.cc23
-rw-r--r--sql/sql_select.cc3
-rw-r--r--tests/client_test.c51
24 files changed, 212 insertions, 32 deletions
diff --git a/Makefile.am b/Makefile.am
index b00b3747294..c1ae9217e8b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -100,8 +100,4 @@ tags:
# Test installation
test:
- cd mysql-test
- ./mysql-test-run
- ./mysql-test-run --ps-protocol
-
-
+ cd mysql-test; ./mysql-test-run && ./mysql-test-run --ps-protocol
diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c
index 8fc6eb9141e..7890ebd2b47 100644
--- a/innobase/dict/dict0load.c
+++ b/innobase/dict/dict0load.c
@@ -765,6 +765,22 @@ dict_load_table(
return(NULL);
}
+#if MYSQL_VERSION_ID < 50300
+ /* Starting from MySQL 5.0.3, the high-order bit of MIX_LEN is the
+ "compact format" flag. */
+ field = rec_get_nth_field(rec, 7, &len);
+ if (mach_read_from_1(field) & 0x80) {
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+ mem_heap_free(heap);
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: table %s is in the new compact format\n"
+ "InnoDB: of MySQL 5.0.3 or later\n", name);
+ return(NULL);
+ }
+#endif /* MYSQL_VERSION_ID < 50300 */
+
ut_a(0 == ut_strcmp("SPACE",
dict_field_get_col(
dict_index_get_nth_field(
diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh
index 5a7ede0cba8..426b8b486be 100644
--- a/mysql-test/mysql-test-run.sh
+++ b/mysql-test/mysql-test-run.sh
@@ -947,7 +947,7 @@ start_ndbcluster()
else
NDBCLUSTER_EXTRA_OPTS="--small"
fi
- ./ndb/ndbcluster $NDBCLUSTER_OPTS $NDBCLUSTER_EXTRA_OPTS --diskless --initial || exit 1
+ ./ndb/ndbcluster $NDBCLUSTER_OPTS $NDBCLUSTER_EXTRA_OPTS --initial || exit 1
NDB_CONNECTSTRING="host=localhost:$NDBCLUSTER_PORT"
else
NDB_CONNECTSTRING="$USE_RUNNING_NDBCLUSTER"
diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result
index 022b8eff7e8..f92b3ea4f4d 100644
--- a/mysql-test/r/group_by.result
+++ b/mysql-test/r/group_by.result
@@ -638,3 +638,15 @@ alias
1,2
1
drop table t1;
+create table t1 (a int);
+insert into t1 values(null);
+select min(a) is null from t1;
+min(a) is null
+1
+select min(a) is null or null from t1;
+min(a) is null or null
+1
+select 1 and min(a) is null from t1;
+1 and min(a) is null
+1
+drop table t1;
diff --git a/mysql-test/r/insert_select.result.es b/mysql-test/r/insert_select.result.es
index 3955c0534f2..9e11402733d 100644
--- a/mysql-test/r/insert_select.result.es
+++ b/mysql-test/r/insert_select.result.es
@@ -78,6 +78,13 @@ a
1
2
drop table t1, t2;
+create table t1(a int);
+insert into t1 values(1),(1);
+reset master;
+create table t2(unique(a)) select a from t1;
+ERROR 23000: Duplicate entry '1' for key 1
+show binlog events;
+drop table t1;
create table t1 (a int not null);
create table t2 (a int not null);
insert into t1 values (1);
diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test
index 59983594c32..c0447b06303 100644
--- a/mysql-test/t/group_by.test
+++ b/mysql-test/t/group_by.test
@@ -465,3 +465,12 @@ select group_concat( distinct col1 ) as alias from t1
drop table t1;
+
+#Test for BUG#6976: Aggregate functions have incorrect NULL-ness
+create table t1 (a int);
+insert into t1 values(null);
+select min(a) is null from t1;
+select min(a) is null or null from t1;
+select 1 and min(a) is null from t1;
+drop table t1;
+
diff --git a/sql/item.cc b/sql/item.cc
index 9ed8b39dece..92a15694e89 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -1488,7 +1488,14 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
"forward reference in item list");
return -1;
}
-
+ /*
+ Here, a subset of actions performed by Item_ref::set_properties
+ is not enough. So we pass ptr to NULL into Item_[direct]_ref
+ constructor, so no initialization is performed, and call
+ fix_fields() below.
+ */
+ Item *save= last->ref_pointer_array[counter];
+ last->ref_pointer_array[counter]= NULL;
Item_ref *rf= (place == IN_HAVING ?
new Item_ref(last->ref_pointer_array + counter,
(char *)table_name,
@@ -1499,6 +1506,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if (!rf)
return 1;
thd->change_item_tree(ref, rf);
+ last->ref_pointer_array[counter]= save;
/*
rf is Item_ref => never substitute other items (in this case)
during fix_fields() => we can use rf after fix_fields()
@@ -2221,19 +2229,24 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
"forward reference in item list"));
return 1;
}
+
+ set_properties();
+
+ if (ref && (*ref)->check_cols(1))
+ return 1;
+ return 0;
+}
+
+void Item_ref::set_properties()
+{
max_length= (*ref)->max_length;
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
collation.set((*ref)->collation);
with_sum_func= (*ref)->with_sum_func;
fixed= 1;
-
- if (ref && (*ref)->check_cols(1))
- return 1;
- return 0;
}
-
void Item_ref::print(String *str)
{
if (ref && *ref)
@@ -2279,7 +2292,7 @@ bool Item_default_value::fix_fields(THD *thd,
fixed= 1;
return 0;
}
- if (arg->fix_fields(thd, table_list, &arg))
+ if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
return 1;
if (arg->type() == REF_ITEM)
@@ -2326,7 +2339,7 @@ bool Item_insert_value::fix_fields(THD *thd,
Item **items)
{
DBUG_ASSERT(fixed == 0);
- if (arg->fix_fields(thd, table_list, &arg))
+ if (!arg->fixed && arg->fix_fields(thd, table_list, &arg))
return 1;
if (arg->type() == REF_ITEM)
diff --git a/sql/item.h b/sql/item.h
index 7a288473533..71b92cd1efc 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -827,14 +827,36 @@ public:
class Item_ref :public Item_ident
{
+protected:
+ void set_properties();
public:
Field *result_field; /* Save result here */
Item **ref;
Item_ref(const char *db_par, const char *table_name_par,
const char *field_name_par)
:Item_ident(db_par, table_name_par, field_name_par), ref(0) {}
+ /*
+ This constructor is used in two scenarios:
+ A) *item = NULL
+ No initialization is performed, fix_fields() call will be necessary.
+
+ B) *item points to an Item this Item_ref will refer to. This is
+ used for GROUP BY. fix_fields() will not be called in this case,
+ so we call set_properties to make this item "fixed". set_properties
+ performs a subset of action Item_ref::fix_fields does, and this subset
+ is enough for Item_ref's used in GROUP BY.
+
+ TODO we probably fix a superset of problems like in BUG#6658. Check this
+ with Bar, and if we have a more broader set of problems like this.
+ */
Item_ref(Item **item, const char *table_name_par, const char *field_name_par)
- :Item_ident(NullS, table_name_par, field_name_par), ref(item) {}
+ :Item_ident(NullS, table_name_par, field_name_par), ref(item)
+ {
+ DBUG_ASSERT(item);
+ if (*item)
+ set_properties();
+ }
+
/* Constructor need to process subselect with temporary tables (see Item) */
Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), ref(item->ref) {}
enum Type type() const { return REF_ITEM; }
@@ -842,29 +864,34 @@ public:
{ return ref && (*ref)->eq(item, binary_cmp); }
double val()
{
+ DBUG_ASSERT(fixed);
double tmp=(*ref)->val_result();
null_value=(*ref)->null_value;
return tmp;
}
longlong val_int()
{
+ DBUG_ASSERT(fixed);
longlong tmp=(*ref)->val_int_result();
null_value=(*ref)->null_value;
return tmp;
}
String *val_str(String* tmp)
{
+ DBUG_ASSERT(fixed);
tmp=(*ref)->str_result(tmp);
null_value=(*ref)->null_value;
return tmp;
}
bool is_null()
{
+ DBUG_ASSERT(fixed);
(void) (*ref)->val_int_result();
return (*ref)->null_value;
}
bool get_date(TIME *ltime,uint fuzzydate)
{
+ DBUG_ASSERT(fixed);
return (null_value=(*ref)->get_date_result(ltime,fuzzydate));
}
bool send(Protocol *prot, String *tmp){ return (*ref)->send(prot, tmp); }
@@ -902,6 +929,7 @@ public:
:Item_ref(item, table_name_par, field_name_par) {}
/* Constructor need to process subselect with temporary tables (see Item) */
Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {}
+
double val()
{
double tmp=(*ref)->val();
@@ -933,6 +961,7 @@ public:
class Item_in_subselect;
+
class Item_ref_null_helper: public Item_ref
{
protected:
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 88083878053..a135f08ae45 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2022,6 +2022,7 @@ void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array,
{
Item **ref= li.ref();
uint el= fields.elements;
+ ref_pointer_array[el]= item;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name);
fields.push_front(item);
ref_pointer_array[el]= item;
@@ -2373,8 +2374,10 @@ bool
Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- if (args[0]->fix_fields(thd, tables, args) || args[0]->check_cols(1) ||
- args[1]->fix_fields(thd,tables, args + 1) || args[1]->check_cols(1))
+ if ((!args[0]->fixed &&
+ args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) ||
+ (!args[1]->fixed &&
+ args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1))
return 1; /* purecov: inspected */
with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func;
max_length= 1;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 98b204d1809..2d939f47716 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -349,8 +349,8 @@ void Item_func::split_sum_func(THD *thd, Item **ref_pointer_array,
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
uint el= fields.elements;
+ ref_pointer_array[el]= item;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name);
- new_item->collation.set(item->collation);
fields.push_front(item);
ref_pointer_array[el]= item;
thd->change_item_tree(arg, new_item);
@@ -1663,7 +1663,8 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
arg != arg_end ;
arg++,i++)
{
- if ((*arg)->fix_fields(thd, tables, arg))
+ if (!(*arg)->fixed &&
+ (*arg)->fix_fields(thd, tables, arg))
DBUG_RETURN(1);
// we can't assign 'item' before, because fix_fields() can change arg
Item *item= *arg;
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 289efe45300..4e4957b980e 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -95,6 +95,7 @@ void Item_row::split_sum_func(THD *thd, Item **ref_pointer_array,
else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM)
{
uint el= fields.elements;
+ ref_pointer_array[el]=*arg;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, (*arg)->name);
fields.push_front(*arg);
ref_pointer_array[el]= *arg;
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index aaeeb9d8bb8..e1b063cd5e0 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1748,6 +1748,7 @@ void Item_func_make_set::split_sum_func(THD *thd, Item **ref_pointer_array,
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
uint el= fields.elements;
+ ref_pointer_array[el]=item;
Item *new_item= new Item_ref(ref_pointer_array + el, 0, item->name);
fields.push_front(item);
ref_pointer_array[el]= item;
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 8efe60bbd89..698536a61c7 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -397,7 +397,8 @@ public:
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
DBUG_ASSERT(fixed == 0);
- return (item->fix_fields(thd, tlist, &item) ||
+ return (!item->fixed &&
+ item->fix_fields(thd, tlist, &item) ||
item->check_cols(1) ||
Item_func::fix_fields(thd, tlist, ref));
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index ffa3b072801..1d0f46fd196 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -766,7 +766,8 @@ Item_in_subselect::single_value_transformer(JOIN *join,
// left expression belong to outer select
SELECT_LEX *current= thd->lex->current_select, *up;
thd->lex->current_select= up= current->return_after_parsing();
- if (left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
+ if (!left_expr->fixed &&
+ left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
{
thd->lex->current_select= current;
goto err;
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 66d4fba205c..029a1fd6c48 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1918,7 +1918,9 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
for (i=0 ; i < arg_count ; i++)
{
- if (args[i]->fix_fields(thd, tables, args + i) || args[i]->check_cols(1))
+ if ((!args[i]->fixed &&
+ args[i]->fix_fields(thd, tables, args + i)) ||
+ args[i]->check_cols(1))
return 1;
if (i < arg_count_field)
maybe_null|= args[i]->maybe_null;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 7a4d14d101a..087e58a7bad 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1416,7 +1416,9 @@ Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex,
List<Item> &fields_arg,
enum enum_duplicates handle_dup,
bool using_trans)
- :Log_event(thd_arg, 0, using_trans), thread_id(thd_arg->thread_id),
+ :Log_event(thd_arg, !thd_arg->tmp_table_used ?
+ 0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans),
+ thread_id(thd_arg->thread_id),
slave_proxy_id(thd_arg->variables.pseudo_thread_id),
num_fields(0),fields(0),
field_lens(0),field_block_len(0),
@@ -1606,6 +1608,9 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db,
commented ? "# " : "",
db);
+ if (flags & LOG_EVENT_THREAD_SPECIFIC_F)
+ fprintf(file,"%sSET @@session.pseudo_thread_id=%lu;\n",
+ commented ? "# " : "", (ulong)thread_id);
fprintf(file, "%sLOAD DATA ",
commented ? "# " : "");
if (check_fname_outside_temp_buf())
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 9343c79c9f0..e39c902444e 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4757,7 +4757,8 @@ replicating a LOAD DATA INFILE command.",
(gptr*) &delayed_queue_size, (gptr*) &delayed_queue_size, 0, GET_ULONG,
REQUIRED_ARG, DELAYED_QUEUE_SIZE, 1, ~0L, 0, 1, 0},
{"expire_logs_days", OPT_EXPIRE_LOGS_DAYS,
- "Binary logs will be rotated after expire-log-days days ",
+ "If non-zero, binary logs will be purged after expire_logs_days "
+ "days; possible purges happen at startup and at binary log rotation.",
(gptr*) &expire_logs_days,
(gptr*) &expire_logs_days, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 99, 0, 1, 0},
diff --git a/sql/set_var.cc b/sql/set_var.cc
index b7f410c207d..d10ea3e11c1 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2799,7 +2799,8 @@ int set_var::check(THD *thd)
return 0;
}
- if (value->fix_fields(thd, 0, &value) || value->check_cols(1))
+ if ((!value->fixed &&
+ value->fix_fields(thd, 0, &value)) || value->check_cols(1))
return -1;
if (var->check_update_type(value->result_type()))
{
@@ -2834,7 +2835,8 @@ int set_var::light_check(THD *thd)
if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL))
return 1;
- if (value && (value->fix_fields(thd, 0, &value) || value->check_cols(1)))
+ if (value && ((!value->fixed && value->fix_fields(thd, 0, &value)) ||
+ value->check_cols(1)))
return -1;
return 0;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 05b11646cd7..5c71049e565 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2684,7 +2684,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
thd->restore_backup_item_arena(arena, &backup);
if (*conds && !(*conds)->fixed)
{
- if ((*conds)->fix_fields(thd, tables, conds))
+ if (!(*conds)->fixed &&
+ (*conds)->fix_fields(thd, tables, conds))
DBUG_RETURN(1);
}
}
@@ -2696,7 +2697,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
thd->restore_backup_item_arena(arena, &backup);
if (table->on_expr && !table->on_expr->fixed)
{
- if (table->on_expr->fix_fields(thd, tables, &table->on_expr))
+ if (!table->on_expr->fixed &&
+ table->on_expr->fix_fields(thd, tables, &table->on_expr))
DBUG_RETURN(1);
}
}
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index f98bb0a9131..f250a00eca1 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -429,7 +429,8 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
tables->table=table;
- if (cond && (cond->fix_fields(thd, tables, &cond) || cond->check_cols(1)))
+ if (cond && ((!cond->fixed &&
+ cond->fix_fields(thd, tables, &cond)) || cond->check_cols(1)))
goto err0;
table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it
@@ -516,7 +517,8 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
for (key_len=0 ; (item=it_ke++) ; key_part++)
{
// 'item' can be changed by fix_fields() call
- if (item->fix_fields(thd, tables, it_ke.ref()) ||
+ if ((!item->fixed &&
+ item->fix_fields(thd, tables, it_ke.ref())) ||
(item= *it_ke.ref())->check_cols(1))
goto err;
if (item->used_tables() & ~RAND_TABLE_BIT)
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 04ecbbd43b9..0e0d32a922d 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -557,7 +557,8 @@ int send_variant_2_list(MEM_ROOT *mem_root, Protocol *protocol,
SQL_SELECT *prepare_simple_select(THD *thd, Item *cond, TABLE_LIST *tables,
TABLE *table, int *error)
{
- cond->fix_fields(thd, tables, &cond); // can never fail
+ if (!cond->fixed)
+ cond->fix_fields(thd, tables, &cond); // can never fail
SQL_SELECT *res= make_select(table,0,0,cond,error);
if (*error || (res && res->check_quick(thd, 0, HA_POS_ERROR)))
{
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index f4a96d751cd..6d2ddf03b50 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1514,6 +1514,27 @@ static bool init_param_array(Prepared_statement *stmt)
}
+/* Init statement before execution */
+
+static void cleanup_stmt_for_execute(Prepared_statement *stmt)
+{
+ THD *thd= stmt->thd;
+ LEX *lex= stmt->lex;
+ SELECT_LEX *sl= lex->all_selects_list;
+
+ for (; sl; sl= sl->next_select_in_list())
+ {
+ for (TABLE_LIST *tables= (TABLE_LIST*) sl->table_list.first;
+ tables;
+ tables= tables->next)
+ {
+ if (tables->table)
+ tables->table->insert_values= 0;
+ }
+ }
+}
+
+
/*
Given a query string with parameter markers, create a Prepared Statement
from it and send PS info back to the client.
@@ -1614,6 +1635,7 @@ int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
if (!error)
error= send_prepare_results(stmt, test(name));
+ cleanup_stmt_for_execute(stmt);
/* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */
if (!(specialflag & SPECIAL_NO_PRIOR))
@@ -1904,6 +1926,7 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
reset_stmt_params(stmt);
close_thread_tables(thd); // to close derived tables
thd->set_statement(&thd->stmt_backup);
+ cleanup_stmt_for_execute(stmt);
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index f2499966815..2d701e668cf 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -8904,7 +8904,8 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab)
if (thd->is_fatal_error)
DBUG_RETURN(TRUE);
- cond->fix_fields(thd,(TABLE_LIST *) 0, (Item**)&cond);
+ if (!cond->fixed)
+ cond->fix_fields(thd,(TABLE_LIST *) 0, (Item**)&cond);
if (join_tab->select)
{
error=(int) cond->add(join_tab->select->cond);
diff --git a/tests/client_test.c b/tests/client_test.c
index 75ce242900a..b0bf40799da 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -1026,6 +1026,56 @@ static void test_tran_innodb()
}
+/* Test for BUG#7242 */
+
+static void test_prepare_insert_update()
+{
+ MYSQL_STMT *stmt;
+ int rc;
+ int i;
+ const char *testcase[]= {
+ "CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B))",
+ "INSERT t1 VALUES (1,2,10), (3,4,20)",
+ "INSERT t1 VALUES (5,6,30), (7,4,40), (8,9,60) ON DUPLICATE KEY UPDATE c=c+100",
+ "SELECT * FROM t1",
+ "INSERT t1 SET a=5 ON DUPLICATE KEY UPDATE b=0",
+ "SELECT * FROM t1",
+ "INSERT t1 VALUES (2,1,11), (7,4,40) ON DUPLICATE KEY UPDATE c=c+VALUES(a)",
+ NULL};
+ const char **cur_query;
+
+ myheader("test_prepare_insert_update");
+
+ for (cur_query= testcase; *cur_query; cur_query++)
+ {
+ printf("\nRunning query: %s", *cur_query);
+ strmov(query, *cur_query);
+ stmt= mysql_simple_prepare(mysql, query);
+ check_stmt(stmt);
+
+ verify_param_count(stmt, 0);
+ rc= mysql_stmt_execute(stmt);
+
+ check_execute(stmt, rc);
+ /* try the last query several times */
+ if (!cur_query[1])
+ {
+ for (i=0; i < 3;i++)
+ {
+ printf("\nExecuting last statement again");
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ }
+ }
+ mysql_stmt_close(stmt);
+ }
+
+ rc= mysql_commit(mysql);
+ myquery(rc);
+}
+
/* Test simple prepares of all DML statements */
static void test_prepare_simple()
@@ -11513,6 +11563,7 @@ and you are welcome to modify and redistribute it under the GPL license\n");
static struct my_tests_st my_tests[]= {
{ "client_query", client_query },
+ { "test_prepare_insert_update", test_prepare_insert_update},
#if NOT_YET_WORKING
{ "test_drop_temp", test_drop_temp },
#endif