summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <marty@flipper.bredbandsbolaget.se>2005-06-23 10:58:37 +0200
committerunknown <marty@flipper.bredbandsbolaget.se>2005-06-23 10:58:37 +0200
commited439bc6a2b1b02c65f0a93078488ddd9e8a13fc (patch)
treecb7fd7068d67fac6b8197f74309105291303b970
parent81a7a93f421547640afcdb0ecef1c1717152d27a (diff)
parent9dfb7aab152881736329e66bf1ea1e471753ebe9 (diff)
downloadmariadb-git-ed439bc6a2b1b02c65f0a93078488ddd9e8a13fc.tar.gz
Merge flipper.bredbandsbolaget.se:/home/marty/MySQL/mysql-5.0
into flipper.bredbandsbolaget.se:/home/marty/MySQL/mysql-5.1 sql/ha_federated.cc: Auto merged sql/item.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_yacc.yy: Auto merged BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted
-rw-r--r--BitKeeper/etc/logging_ok1
-rw-r--r--mysql-test/README13
-rw-r--r--mysql-test/lib/mtr_cases.pl8
-rw-r--r--mysql-test/r/insert_select.result15
-rw-r--r--mysql-test/r/insert_update.result2
-rw-r--r--mysql-test/r/rpl_multi_update3.result43
-rw-r--r--mysql-test/t/insert_select.test14
-rw-r--r--mysql-test/t/insert_update.test2
-rw-r--r--mysql-test/t/rpl_multi_update3.test34
-rw-r--r--mysys/my_access.c12
-rw-r--r--sql/ha_federated.cc12
-rw-r--r--sql/item.cc4
-rw-r--r--sql/item.h11
-rw-r--r--sql/sql_base.cc19
-rw-r--r--sql/sql_class.cc43
-rw-r--r--sql/sql_class.h15
-rw-r--r--sql/sql_prepare.cc36
-rw-r--r--sql/sql_select.cc5
-rw-r--r--sql/sql_yacc.yy15
19 files changed, 228 insertions, 76 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index 4c3233817ab..416ab8dbbde 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -140,6 +140,7 @@ magnus@msdesk.mysql.com
magnus@neptunus.(none)
magnus@shellback.(none)
marko@hundin.mysql.fi
+marty@flipper.bredbandsbolaget.se
marty@linux.site
marty@shark.
mats@mysql.com
diff --git a/mysql-test/README b/mysql-test/README
index 65e6186613a..10d64784ed4 100644
--- a/mysql-test/README
+++ b/mysql-test/README
@@ -2,8 +2,17 @@ This directory contains a test suite for mysql daemon. To run
the currently existing test cases, simply execute ./mysql-test-run in
this directory. It will fire up the newly built mysqld and test it.
-If you want to run the test with a running MySQL server use the --external
-option to mysql-test-run.
+If you want to run a test with a running MySQL server use the --extern
+option to mysql-test-run. Please note that in this mode the test suite
+expects user to specify test names to run. Otherwise it falls back to the
+normal "non-extern" behaviour. The reason is that some tests
+could not run with external server. Here is the sample command
+to test "alias" and "analyze" tests on external server:
+
+mysql-test-run --extern alias analyze
+
+To match your setup you might also need to provide --socket, --user and
+other relevant options.
Note that you do not have to have to do make install, and you could
actually have a co-existing MySQL installation - the tests will not
diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl
index 72cbe72bc0a..2babaabc24c 100644
--- a/mysql-test/lib/mtr_cases.pl
+++ b/mysql-test/lib/mtr_cases.pl
@@ -154,6 +154,14 @@ sub collect_one_test_case($$$$$) {
}
}
+ if ( defined mtr_match_prefix($tname,"federated") )
+ {
+ $tinfo->{'slave_num'}= 1; # Default, use one slave
+
+ # FIXME currently we always restart slaves
+ $tinfo->{'slave_restart'}= 1;
+ }
+
# FIXME what about embedded_server + ndbcluster, skip ?!
my $master_opt_file= "$testdir/$tname-master.opt";
diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result
index 11384b0feff..026dae8381a 100644
--- a/mysql-test/r/insert_select.result
+++ b/mysql-test/r/insert_select.result
@@ -634,3 +634,18 @@ ff1 ff2
1 2
2 1
drop table t1, t2;
+create table t1 (a int unique);
+create table t2 (a int, b int);
+insert into t1 values (1),(2);
+insert into t2 values (1,2);
+select * from t1;
+a
+1
+2
+insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b;
+select * from t1;
+a
+2
+3
+drop table t1;
+drop table t2;
diff --git a/mysql-test/r/insert_update.result b/mysql-test/r/insert_update.result
index 6d3aa941c8c..739beea6286 100644
--- a/mysql-test/r/insert_update.result
+++ b/mysql-test/r/insert_update.result
@@ -1,4 +1,4 @@
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1, t2;
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) ON DUPLICATE KEY UPDATE c=c+100;
diff --git a/mysql-test/r/rpl_multi_update3.result b/mysql-test/r/rpl_multi_update3.result
new file mode 100644
index 00000000000..708b230b19f
--- /dev/null
+++ b/mysql-test/r/rpl_multi_update3.result
@@ -0,0 +1,43 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1 (
+a int unsigned not null auto_increment primary key,
+b int unsigned
+) ENGINE=MyISAM;
+CREATE TABLE t2 (
+a int unsigned not null auto_increment primary key,
+b int unsigned
+) ENGINE=MyISAM;
+INSERT INTO t1 VALUES (NULL, 0);
+INSERT INTO t1 SELECT NULL, 0 FROM t1;
+INSERT INTO t2 VALUES (NULL, 0), (NULL,1);
+SELECT * FROM t1 ORDER BY a;
+a b
+1 0
+2 0
+SELECT * FROM t2 ORDER BY a;
+a b
+1 0
+2 1
+UPDATE t2, (SELECT a FROM t1) AS t SET t2.b = t.a+5 ;
+SELECT * FROM t1 ORDER BY a;
+a b
+1 0
+2 0
+SELECT * FROM t2 ORDER BY a;
+a b
+1 6
+2 6
+SELECT * FROM t1 ORDER BY a;
+a b
+1 0
+2 0
+SELECT * FROM t2 ORDER BY a;
+a b
+1 6
+2 6
+drop table t1,t2;
diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test
index 834561ed5f7..a6468c52645 100644
--- a/mysql-test/t/insert_select.test
+++ b/mysql-test/t/insert_select.test
@@ -173,3 +173,17 @@ insert into t1 values (1),(1),(2);
insert into t2(ff1) select f1 from t1 on duplicate key update ff2=ff2+1;
select * from t2;
drop table t1, t2;
+#
+# BUGS #9728 - 'Decreased functionality in "on duplicate key update"'
+# #8147 - 'a column proclaimed ambigous in INSERT ... SELECT .. ON
+# DUPLICATE'
+#
+create table t1 (a int unique);
+create table t2 (a int, b int);
+insert into t1 values (1),(2);
+insert into t2 values (1,2);
+select * from t1;
+insert into t1 select t2.a from t2 on duplicate key update a= a + t2.b;
+select * from t1;
+drop table t1;
+drop table t2;
diff --git a/mysql-test/t/insert_update.test b/mysql-test/t/insert_update.test
index f5857840588..7653fd8dd42 100644
--- a/mysql-test/t/insert_update.test
+++ b/mysql-test/t/insert_update.test
@@ -1,5 +1,5 @@
--disable_warnings
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1, t2;
--enable_warnings
CREATE TABLE t1 (a INT, b INT, c INT, UNIQUE (A), UNIQUE(B));
diff --git a/mysql-test/t/rpl_multi_update3.test b/mysql-test/t/rpl_multi_update3.test
new file mode 100644
index 00000000000..b8c8ed79532
--- /dev/null
+++ b/mysql-test/t/rpl_multi_update3.test
@@ -0,0 +1,34 @@
+# Let's verify that multi-update with a subselect does not cause the slave to crash
+# (BUG#10442)
+
+source include/master-slave.inc;
+
+CREATE TABLE t1 (
+ a int unsigned not null auto_increment primary key,
+ b int unsigned
+) ENGINE=MyISAM;
+
+CREATE TABLE t2 (
+ a int unsigned not null auto_increment primary key,
+ b int unsigned
+) ENGINE=MyISAM;
+
+INSERT INTO t1 VALUES (NULL, 0);
+INSERT INTO t1 SELECT NULL, 0 FROM t1;
+
+INSERT INTO t2 VALUES (NULL, 0), (NULL,1);
+
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+
+UPDATE t2, (SELECT a FROM t1) AS t SET t2.b = t.a+5 ;
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+
+save_master_pos;
+connection slave;
+sync_with_master;
+SELECT * FROM t1 ORDER BY a;
+SELECT * FROM t2 ORDER BY a;
+
+drop table t1,t2;
diff --git a/mysys/my_access.c b/mysys/my_access.c
index 28210bdfc7d..c01031827c0 100644
--- a/mysys/my_access.c
+++ b/mysys/my_access.c
@@ -93,18 +93,20 @@ int check_if_legal_filename(const char *path)
path+= dirname_length(path); /* To start of filename */
if (!(end= strchr(path, FN_EXTCHAR)))
end= strend(path);
- if (path == end || (uint) (path - end) > MAX_RESERVED_NAME_LENGTH)
+ if (path == end || (uint) (end - path) > MAX_RESERVED_NAME_LENGTH)
DBUG_RETURN(0); /* Simplify inner loop */
for (reserved_name= reserved_names; *reserved_name; reserved_name++)
{
const char *name= path;
- while (name != end)
+ const char *current_reserved_name= *reserved_name;
+
+ while (name != end && *current_reserved_name)
{
- if (my_toupper(&my_charset_latin1, *path) !=
- my_toupper(&my_charset_latin1, *name))
+ if (*current_reserved_name != my_toupper(&my_charset_latin1, *name))
break;
- if (name++ == end)
+ current_reserved_name++;
+ if (++name == end)
DBUG_RETURN(1); /* Found wrong path */
}
}
diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc
index 844612e0643..c18ca5d7915 100644
--- a/sql/ha_federated.cc
+++ b/sql/ha_federated.cc
@@ -462,6 +462,12 @@ static int check_foreign_data_source(FEDERATED_SHARE *share)
}
else
{
+ /*
+ Since we do not support transactions at this version, we can let the client
+ API silently reconnect. For future versions, we will need more logic to deal
+ with transactions
+ */
+ mysql->reconnect= 1;
/*
Note: I am not using INORMATION_SCHEMA because this needs to work with < 5.0
if we can connect, then make sure the table exists
@@ -988,6 +994,12 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_CONNECT_TO_MASTER);
}
+ /*
+ Since we do not support transactions at this version, we can let the client
+ API silently reconnect. For future versions, we will need more logic to deal
+ with transactions
+ */
+ mysql->reconnect= 1;
DBUG_RETURN(0);
}
diff --git a/sql/item.cc b/sql/item.cc
index 29d580cad00..ec685982304 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -338,6 +338,7 @@ Item::Item():
place == IN_HAVING)
thd->lex->current_select->select_n_having_items++;
}
+ item_flags= 0;
}
/*
@@ -358,7 +359,8 @@ Item::Item(THD *thd, Item *item):
unsigned_flag(item->unsigned_flag),
with_sum_func(item->with_sum_func),
fixed(item->fixed),
- collation(item->collation)
+ collation(item->collation),
+ item_flags(item->item_flags)
{
next= thd->free_list; // Put in free list
thd->free_list= this;
diff --git a/sql/item.h b/sql/item.h
index c912ad3f0a7..c8180b4932a 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -225,6 +225,11 @@ typedef Item* (Item::*Item_transformer) (byte *arg);
typedef void (*Cond_traverser) (const Item *item, void *arg);
+/*
+ See comments for sql_yacc.yy: insert_update_elem rule
+ */
+#define MY_ITEM_PREFER_1ST_TABLE 1
+
class Item {
Item(const Item &); /* Prevent use of these */
void operator=(Item &);
@@ -272,6 +277,7 @@ public:
my_bool is_autogenerated_name; /* indicate was name of this Item
autogenerated or set by user */
DTCollation collation;
+ uint8 item_flags; /* Flags on how item should be processed */
// alloc & destruct is done as start of select using sql_alloc
Item();
@@ -584,6 +590,11 @@ public:
cleanup();
delete this;
}
+ virtual bool set_flags_processor(byte *args)
+ {
+ this->item_flags|= *((uint8*)args);
+ return false;
+ }
virtual bool is_splocal() { return 0; } /* Needed for error checking */
};
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 312bc3b187b..b112ca971c3 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2628,7 +2628,6 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
uint length=(uint) strlen(name);
char name_buff[NAME_LEN+1];
-
if (item->cached_table)
{
/*
@@ -2695,10 +2694,13 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
db= name_buff;
}
+ bool search_global= item->item_flags & MY_ITEM_PREFER_1ST_TABLE;
if (table_name && table_name[0])
{ /* Qualified field */
- bool found_table=0;
- for (; tables; tables= tables->next_local)
+ bool found_table=0;
+ uint table_idx= 0;
+ for (; tables; tables= search_global?tables->next_global:tables->next_local,
+ table_idx++)
{
/* TODO; Ensure that db and tables->db always points to something ! */
if (!my_strcasecmp(table_alias_charset, tables->alias, table_name) &&
@@ -2734,6 +2736,8 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
return (Field*) 0;
}
found=find;
+ if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE)
+ break;
}
}
}
@@ -2758,9 +2762,10 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
return (Field*) not_found_field;
return (Field*) 0;
}
-
bool allow_rowid= tables && !tables->next_local; // Only one table
- for (; tables ; tables= tables->next_local)
+ uint table_idx= 0;
+ for (; tables ; tables= search_global?tables->next_global:tables->next_local,
+ table_idx++)
{
if (!tables->table && !tables->ancestor)
{
@@ -2795,7 +2800,9 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
my_error(ER_NON_UNIQ_ERROR, MYF(0), name, thd->where);
return (Field*) 0;
}
- found=field;
+ found= field;
+ if (table_idx == 0 && item->item_flags & MY_ITEM_PREFER_1ST_TABLE)
+ break;
}
}
if (found)
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index f54135ea8cb..8abd7cbbe7d 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -156,9 +156,15 @@ bool foreign_key_prefix(Key *a, Key *b)
/****************************************************************************
** Thread specific functions
****************************************************************************/
+/*
+ Pass nominal parameters to Statement constructor only to ensure that
+ the destructor works OK in case of error. The main_mem_root will be
+ re-initialized in init().
+*/
THD::THD()
- :user_time(0), global_read_lock(0), is_fatal_error(0),
+ :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0),
+ user_time(0), global_read_lock(0), is_fatal_error(0),
rand_used(0), time_zone_used(0),
last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0),
in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE),
@@ -1483,9 +1489,10 @@ Query_arena::Type Query_arena::type() const
Statement functions
*/
-Statement::Statement(THD *thd)
- :Query_arena(&main_mem_root, INITIALIZED),
- id(++thd->statement_id_counter),
+Statement::Statement(enum enum_state state_arg, ulong id_arg,
+ ulong alloc_block_size, ulong prealloc_size)
+ :Query_arena(&main_mem_root, state_arg),
+ id(id_arg),
set_query_id(1),
allow_sum_func(0),
lex(&main_lex),
@@ -1494,33 +1501,7 @@ Statement::Statement(THD *thd)
cursor(0)
{
name.str= NULL;
- init_sql_alloc(&main_mem_root,
- thd->variables.query_alloc_block_size,
- thd->variables.query_prealloc_size);
-}
-
-/*
- This constructor is called when Statement is a parent of THD and
- for the backup statement. Some variables are initialized in
- THD::init due to locking problems.
-*/
-
-Statement::Statement()
- :Query_arena(&main_mem_root, CONVENTIONAL_EXECUTION),
- id(0),
- set_query_id(1),
- allow_sum_func(0), /* initialized later */
- lex(&main_lex),
- query(0), /* these two are set */
- query_length(0), /* in alloc_query() */
- cursor(0)
-{
- /*
- This is just to ensure that the destructor works correctly in
- case of an error and the backup statement. The memory root will
- be re-initialized in THD::init.
- */
- init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
+ init_sql_alloc(&main_mem_root, alloc_block_size, prealloc_size);
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 4a4754583df..fbc5e5f85bf 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -817,13 +817,11 @@ public:
public:
- /*
- This constructor is called when statement is a subobject of THD:
- some variables are initialized in THD::init due to locking problems
- */
- Statement();
+ /* This constructor is called for backup statements */
+ Statement() { clear_alloc_root(&main_mem_root); }
- Statement(THD *thd);
+ Statement(enum enum_state state_arg, ulong id_arg,
+ ulong alloc_block_size, ulong prealloc_size);
virtual ~Statement();
/* Assign execution context (note: not all members) of given stmt to self */
@@ -966,11 +964,6 @@ public:
/* all prepared statements and cursors of this connection */
Statement_map stmt_map;
/*
- keeps THD state while it is used for active statement
- Note: we perform special cleanup for it in THD destructor.
- */
- Statement stmt_backup;
- /*
A pointer to the stack frame of handle_one_connection(),
which is called first in the thread for handling a client
*/
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 73bbea79760..eeea493d868 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1706,6 +1706,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
LEX_STRING *name)
{
LEX *lex;
+ Statement stmt_backup;
Prepared_statement *stmt= new Prepared_statement(thd);
bool error;
DBUG_ENTER("mysql_stmt_prepare");
@@ -1739,13 +1740,13 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
DBUG_RETURN(TRUE);
}
- thd->set_n_backup_statement(stmt, &thd->stmt_backup);
- thd->set_n_backup_item_arena(stmt, &thd->stmt_backup);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
+ thd->set_n_backup_item_arena(stmt, &stmt_backup);
if (alloc_query(thd, packet, packet_length))
{
- thd->restore_backup_statement(stmt, &thd->stmt_backup);
- thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
+ thd->restore_backup_statement(stmt, &stmt_backup);
+ thd->restore_backup_item_arena(stmt, &stmt_backup);
/* Statement map deletes statement on erase */
thd->stmt_map.erase(stmt);
DBUG_RETURN(TRUE);
@@ -1770,7 +1771,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
transformation can be reused on execute, we set again thd->mem_root from
stmt->mem_root (see setup_wild for one place where we do that).
*/
- thd->restore_backup_item_arena(stmt, &thd->stmt_backup);
+ thd->restore_backup_item_arena(stmt, &stmt_backup);
if (!error)
error= check_prepared_statement(stmt, test(name));
@@ -1786,7 +1787,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
lex_end(lex);
close_thread_tables(thd);
cleanup_stmt_and_thd_after_use(stmt, thd);
- thd->restore_backup_statement(stmt, &thd->stmt_backup);
+ thd->restore_backup_statement(stmt, &stmt_backup);
thd->current_arena= thd;
if (error)
@@ -1949,6 +1950,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
{
ulong stmt_id= uint4korr(packet);
ulong flags= (ulong) ((uchar) packet[4]);
+ Statement stmt_backup;
Cursor *cursor;
/*
Query text for binary log, or empty string if the query is not put into
@@ -2026,8 +2028,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query))
goto set_params_data_err;
#endif
- thd->stmt_backup.set_statement(thd);
- thd->set_statement(stmt);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
thd->current_arena= stmt;
reinit_stmt_before_use(thd, stmt->lex);
/* From now cursors assume that thd->mem_root is clean */
@@ -2064,7 +2065,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
reset_stmt_params(stmt);
}
- thd->set_statement(&thd->stmt_backup);
+ thd->set_statement(&stmt_backup);
thd->current_arena= thd;
DBUG_VOID_RETURN;
@@ -2089,6 +2090,7 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
binary log.
*/
String expanded_query;
+ Statement stmt_backup;
DBUG_ENTER("mysql_sql_stmt_execute");
DBUG_ASSERT(thd->free_list == NULL);
@@ -2110,16 +2112,16 @@ void mysql_sql_stmt_execute(THD *thd, LEX_STRING *stmt_name)
/* Must go before setting variables, as it clears thd->user_var_events */
mysql_reset_thd_for_next_command(thd);
- thd->set_n_backup_statement(stmt, &thd->stmt_backup);
- thd->set_statement(stmt);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
if (stmt->set_params_from_vars(stmt,
- thd->stmt_backup.lex->prepared_stmt_params,
+ stmt_backup.lex->prepared_stmt_params,
&expanded_query))
{
my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
}
thd->command= COM_STMT_EXECUTE; /* For nice messages in general log */
execute_stmt(thd, stmt, &expanded_query);
+ thd->set_statement(&stmt_backup);
DBUG_VOID_RETURN;
}
@@ -2176,7 +2178,6 @@ static void execute_stmt(THD *thd, Prepared_statement *stmt,
close_thread_tables(thd); // to close derived tables
cleanup_stmt_and_thd_after_use(stmt, thd);
reset_stmt_params(stmt);
- thd->set_statement(&thd->stmt_backup);
thd->current_arena= thd;
if (stmt->state == Query_arena::PREPARED)
@@ -2201,6 +2202,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
ulong stmt_id= uint4korr(packet);
ulong num_rows= uint4korr(packet+4);
Prepared_statement *stmt;
+ Statement stmt_backup;
DBUG_ENTER("mysql_stmt_fetch");
statistic_increment(thd->status_var.com_stmt_fetch, &LOCK_status);
@@ -2214,7 +2216,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
}
thd->current_arena= stmt;
- thd->set_n_backup_statement(stmt, &thd->stmt_backup);
+ thd->set_n_backup_statement(stmt, &stmt_backup);
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), QUERY_PRIOR);
@@ -2226,7 +2228,7 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length)
if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
- thd->restore_backup_statement(stmt, &thd->stmt_backup);
+ thd->restore_backup_statement(stmt, &stmt_backup);
thd->current_arena= thd;
if (!stmt->cursor->is_open())
@@ -2386,7 +2388,9 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
Prepared_statement::Prepared_statement(THD *thd_arg)
- :Statement(thd_arg),
+ :Statement(INITIALIZED, ++thd_arg->statement_id_counter,
+ thd_arg->variables.query_alloc_block_size,
+ thd_arg->variables.query_prealloc_size),
thd(thd_arg),
param_array(0),
param_count(0),
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 92a0b68ffa5..bea68bf4da5 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1820,6 +1820,7 @@ Cursor::fetch(ulong num_rows)
THD *thd= join->thd;
JOIN_TAB *join_tab= join->join_tab + join->const_tables;
enum_nested_loop_state error= NESTED_LOOP_OK;
+ Query_arena backup_arena;
DBUG_ENTER("Cursor::fetch");
DBUG_PRINT("enter",("rows: %lu", num_rows));
@@ -1831,7 +1832,7 @@ Cursor::fetch(ulong num_rows)
thd->lock= lock;
thd->query_id= query_id;
/* save references to memory, allocated during fetch */
- thd->set_n_backup_item_arena(this, &thd->stmt_backup);
+ thd->set_n_backup_item_arena(this, &backup_arena);
join->fetch_limit+= num_rows;
@@ -1847,7 +1848,7 @@ Cursor::fetch(ulong num_rows)
ha_release_temporary_latches(thd);
#endif
- thd->restore_backup_item_arena(this, &thd->stmt_backup);
+ thd->restore_backup_item_arena(this, &backup_arena);
DBUG_ASSERT(thd->free_list == 0);
reset_thd(thd);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index f987063642e..edca9cf3c5f 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -6120,9 +6120,24 @@ insert_update_elem:
simple_ident_nospvar equal expr_or_default
{
LEX *lex= Lex;
+ uint8 tmp= MY_ITEM_PREFER_1ST_TABLE;
if (lex->update_list.push_back($1) ||
lex->value_list.push_back($3))
YYABORT;
+ /*
+ INSERT INTO a1(a) SELECT b1.a FROM b1 ON DUPLICATE KEY
+ UPDATE a= a + b1.b
+
+ Set MY_ITEM_PREFER_1ST_TABLE flag to $1 and $3 items
+ to prevent find_field_in_tables() doing further item searching
+ if it finds item occurence in first table in insert_table_list.
+ This allows to avoid ambiguity in resolving 'a' field in
+ example above.
+ */
+ $1->walk(&Item::set_flags_processor,
+ (byte *) &tmp);
+ $3->walk(&Item::set_flags_processor,
+ (byte *) &tmp);
};
opt_low_priority: