summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOleksandr Byelkin <sanja@mariadb.com>2018-01-26 16:59:53 +0100
committerOleksandr Byelkin <sanja@mariadb.com>2018-02-01 09:51:47 +0100
commit80d3eee072025f34984e474ea160651eac9e11e5 (patch)
tree71339d70b7ff7e338c19543e2939a1d0dde1a982
parentad0013c8e2b01acf2128580599aa6d54bf234b2d (diff)
downloadmariadb-git-80d3eee072025f34984e474ea160651eac9e11e5.tar.gz
MDEV-14857: problem with 10.2.11 server crashing when executing stored procedure
Counter for select numbering made stored with the statement (before was global) So now it does have always accurate value which does not depend on interruption of statement prepare by errors like lack of table in a view definition.
-rw-r--r--mysql-test/r/sp.result123
-rw-r--r--mysql-test/t/sp.test149
-rw-r--r--sql/sp.cc1
-rw-r--r--sql/sp_head.cc35
-rw-r--r--sql/sp_head.h3
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_class.h16
-rw-r--r--sql/sql_explain.h6
-rw-r--r--sql/sql_lex.cc2
-rw-r--r--sql/sql_lex.h10
-rw-r--r--sql/sql_parse.cc9
-rw-r--r--sql/sql_prepare.cc18
-rw-r--r--sql/sql_select.cc16
-rw-r--r--sql/sql_trigger.cc7
-rw-r--r--sql/sql_view.cc7
15 files changed, 341 insertions, 63 deletions
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 9b0ace5c002..57d704c36be 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -8119,4 +8119,127 @@ SET @aux = f1();
DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1;
+#
+# MDEV-14857: problem with 10.2.11 server crashing when
+# executing stored procedure
+#
+SET max_sp_recursion_depth=10;
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (b INT);
+CREATE PROCEDURE proc_0()
+BEGIN
+CALL empty_1();
+CALL proc_1();
+END ||
+CREATE PROCEDURE proc_1()
+BEGIN
+CALL proc_2();
+CALL proc_3();
+CALL proc_4();
+CALL proc_5();
+END ||
+CREATE PROCEDURE proc_2()
+CALL proc_6();
+||
+CREATE PROCEDURE proc_3()
+BEGIN
+CALL empty_2();
+CALL empty_3();
+END ||
+CREATE PROCEDURE proc_4()
+CALL proc_7();
+||
+CREATE PROCEDURE proc_5()
+CALL proc_select();
+||
+CREATE PROCEDURE proc_6()
+BEGIN
+CALL empty_4();
+CALL empty_5();
+CALL empty_6();
+CALL empty_7();
+CALL proc_8();
+END ||
+CREATE PROCEDURE proc_7()
+CALL proc_9('foo');
+||
+CREATE PROCEDURE proc_8()
+CALL proc_10();
+||
+CREATE PROCEDURE proc_9(IN opt VARCHAR(40))
+IF LEFT(opt,1) <> '_' THEN
+CALL proc_11();
+END IF;
+||
+CREATE PROCEDURE proc_10()
+CALL proc_12();
+||
+CREATE PROCEDURE proc_11()
+BEGIN
+CALL empty_8();
+CALL empty_9();
+CALL empty_10();
+CALL proc_13();
+END ||
+CREATE PROCEDURE proc_12()
+BEGIN
+CALL empty_11();
+CALL empty_12();
+CALL empty_13();
+END ||
+CREATE PROCEDURE proc_13()
+BEGIN
+CALL proc_9('_bar');
+CALL empty_14();
+END ||
+CREATE PROCEDURE empty_1() BEGIN END ;
+CREATE PROCEDURE empty_2() BEGIN END ;
+CREATE PROCEDURE empty_3() BEGIN END ;
+CREATE PROCEDURE empty_4() BEGIN END ;
+CREATE PROCEDURE empty_5() BEGIN END ;
+CREATE PROCEDURE empty_6() BEGIN END ;
+CREATE PROCEDURE empty_7() BEGIN END ;
+CREATE PROCEDURE empty_8() BEGIN END ;
+CREATE PROCEDURE empty_9() BEGIN END ;
+CREATE PROCEDURE empty_10() BEGIN END ;
+CREATE PROCEDURE empty_11() BEGIN END ;
+CREATE PROCEDURE empty_12() BEGIN END ;
+CREATE PROCEDURE empty_13() BEGIN END ;
+CREATE PROCEDURE empty_14() BEGIN END ;
+CREATE PROCEDURE proc_select()
+SELECT * FROM t1 WHERE NOT EXISTS ( SELECT * FROM t2)
+;
+CALL proc_0();
+a
+DROP PROCEDURE empty_1;
+DROP PROCEDURE empty_2;
+DROP PROCEDURE empty_3;
+DROP PROCEDURE empty_4;
+DROP PROCEDURE empty_5;
+DROP PROCEDURE empty_6;
+DROP PROCEDURE empty_7;
+DROP PROCEDURE empty_8;
+DROP PROCEDURE empty_9;
+DROP PROCEDURE empty_10;
+DROP PROCEDURE empty_11;
+DROP PROCEDURE empty_12;
+DROP PROCEDURE empty_13;
+DROP PROCEDURE empty_14;
+DROP PROCEDURE proc_0;
+DROP PROCEDURE proc_1;
+DROP PROCEDURE proc_2;
+DROP PROCEDURE proc_3;
+DROP PROCEDURE proc_4;
+DROP PROCEDURE proc_5;
+DROP PROCEDURE proc_6;
+DROP PROCEDURE proc_7;
+DROP PROCEDURE proc_8;
+DROP PROCEDURE proc_9;
+DROP PROCEDURE proc_10;
+DROP PROCEDURE proc_11;
+DROP PROCEDURE proc_12;
+DROP PROCEDURE proc_13;
+DROP PROCEDURE proc_select;
+DROP TABLE t1, t2;
+SET max_sp_recursion_depth=default;
#End of 10.1 tests
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 7453cec8f21..4b2230ea7da 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -9605,4 +9605,153 @@ DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1;
+--echo #
+--echo # MDEV-14857: problem with 10.2.11 server crashing when
+--echo # executing stored procedure
+--echo #
+
+SET max_sp_recursion_depth=10;
+
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (b INT);
+
+delimiter ||;
+
+CREATE PROCEDURE proc_0()
+BEGIN
+ CALL empty_1();
+ CALL proc_1();
+END ||
+
+CREATE PROCEDURE proc_1()
+BEGIN
+ CALL proc_2();
+ CALL proc_3();
+ CALL proc_4();
+ CALL proc_5();
+END ||
+
+CREATE PROCEDURE proc_2()
+ CALL proc_6();
+||
+
+CREATE PROCEDURE proc_3()
+BEGIN
+ CALL empty_2();
+ CALL empty_3();
+END ||
+
+CREATE PROCEDURE proc_4()
+ CALL proc_7();
+||
+
+CREATE PROCEDURE proc_5()
+ CALL proc_select();
+||
+
+CREATE PROCEDURE proc_6()
+BEGIN
+ CALL empty_4();
+ CALL empty_5();
+ CALL empty_6();
+ CALL empty_7();
+ CALL proc_8();
+END ||
+
+CREATE PROCEDURE proc_7()
+ CALL proc_9('foo');
+||
+
+CREATE PROCEDURE proc_8()
+ CALL proc_10();
+||
+
+CREATE PROCEDURE proc_9(IN opt VARCHAR(40))
+ IF LEFT(opt,1) <> '_' THEN
+ CALL proc_11();
+ END IF;
+||
+
+CREATE PROCEDURE proc_10()
+ CALL proc_12();
+||
+
+CREATE PROCEDURE proc_11()
+BEGIN
+ CALL empty_8();
+ CALL empty_9();
+ CALL empty_10();
+ CALL proc_13();
+END ||
+
+CREATE PROCEDURE proc_12()
+BEGIN
+ CALL empty_11();
+ CALL empty_12();
+ CALL empty_13();
+END ||
+
+CREATE PROCEDURE proc_13()
+BEGIN
+ CALL proc_9('_bar');
+ CALL empty_14();
+END ||
+
+delimiter ;||
+
+CREATE PROCEDURE empty_1() BEGIN END ;
+CREATE PROCEDURE empty_2() BEGIN END ;
+CREATE PROCEDURE empty_3() BEGIN END ;
+CREATE PROCEDURE empty_4() BEGIN END ;
+CREATE PROCEDURE empty_5() BEGIN END ;
+CREATE PROCEDURE empty_6() BEGIN END ;
+CREATE PROCEDURE empty_7() BEGIN END ;
+CREATE PROCEDURE empty_8() BEGIN END ;
+CREATE PROCEDURE empty_9() BEGIN END ;
+CREATE PROCEDURE empty_10() BEGIN END ;
+CREATE PROCEDURE empty_11() BEGIN END ;
+CREATE PROCEDURE empty_12() BEGIN END ;
+CREATE PROCEDURE empty_13() BEGIN END ;
+CREATE PROCEDURE empty_14() BEGIN END ;
+
+CREATE PROCEDURE proc_select()
+ SELECT * FROM t1 WHERE NOT EXISTS ( SELECT * FROM t2)
+;
+
+CALL proc_0();
+
+# Cleanup
+DROP PROCEDURE empty_1;
+DROP PROCEDURE empty_2;
+DROP PROCEDURE empty_3;
+DROP PROCEDURE empty_4;
+DROP PROCEDURE empty_5;
+DROP PROCEDURE empty_6;
+DROP PROCEDURE empty_7;
+DROP PROCEDURE empty_8;
+DROP PROCEDURE empty_9;
+DROP PROCEDURE empty_10;
+DROP PROCEDURE empty_11;
+DROP PROCEDURE empty_12;
+DROP PROCEDURE empty_13;
+DROP PROCEDURE empty_14;
+DROP PROCEDURE proc_0;
+DROP PROCEDURE proc_1;
+DROP PROCEDURE proc_2;
+DROP PROCEDURE proc_3;
+DROP PROCEDURE proc_4;
+DROP PROCEDURE proc_5;
+DROP PROCEDURE proc_6;
+DROP PROCEDURE proc_7;
+DROP PROCEDURE proc_8;
+DROP PROCEDURE proc_9;
+DROP PROCEDURE proc_10;
+DROP PROCEDURE proc_11;
+DROP PROCEDURE proc_12;
+DROP PROCEDURE proc_13;
+DROP PROCEDURE proc_select;
+DROP TABLE t1, t2;
+
+SET max_sp_recursion_depth=default;
+
--echo #End of 10.1 tests
diff --git a/sql/sp.cc b/sql/sp.cc
index 5a64c28865e..2e268e483e7 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -760,7 +760,6 @@ static sp_head *sp_compile(THD *thd, String *defstr, ulonglong sql_mode,
else
{
sp= thd->lex->sphead;
- sp->set_select_number(thd->select_number);
}
thd->pop_internal_handler();
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index eceebd1d13f..8bf78d97670 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -597,7 +597,7 @@ sp_head::sp_head()
m_flags(0),
m_sp_cache_version(0),
m_creation_ctx(0),
- unsafe_flags(0), m_select_number(1),
+ unsafe_flags(0),
m_recursion_level(0),
m_next_cached_sp(0),
m_cont_level(0)
@@ -840,7 +840,7 @@ sp_head::~sp_head()
thd->lex->sphead= NULL;
lex_end(thd->lex);
delete thd->lex;
- thd->lex= lex;
+ thd->lex= thd->stmt_lex= lex;
}
my_hash_free(&m_sptabs);
@@ -1121,7 +1121,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
backup_arena;
query_id_t old_query_id;
TABLE *old_derived_tables;
- LEX *old_lex;
+ LEX *old_lex, *old_stmt_lex;
Item_change_list old_change_list;
String old_packet;
uint old_server_status;
@@ -1136,19 +1136,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet))
DBUG_RETURN(TRUE);
- /*
- Normally the counter is not reset between parsing and first execution,
- but it is possible in case of error to have parsing on one CALL and
- first execution (where VIEW will be parsed and added). So we store the
- counter after parsing and restore it before execution just to avoid
- repeating SELECT numbers.
-
- Other problem is that it can be more SELECTs parsed in case of fixing
- error causes previous interruption of the SP. So it is save not just
- assign old value but add it.
- */
- thd->select_number+= m_select_number;
-
/* init per-instruction memroot */
init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
@@ -1237,6 +1224,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
do it in each instruction
*/
old_lex= thd->lex;
+ old_stmt_lex= thd->stmt_lex;
/*
We should also save Item tree change list to avoid rollback something
too early in the calling query.
@@ -1384,6 +1372,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
DBUG_ASSERT(thd->change_list.is_empty());
old_change_list.move_elements_to(&thd->change_list);
thd->lex= old_lex;
+ thd->stmt_lex= old_stmt_lex;
thd->set_query_id(old_query_id);
DBUG_ASSERT(!thd->derived_tables);
thd->derived_tables= old_derived_tables;
@@ -1482,16 +1471,6 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
m_recursion_level + 1));
m_first_instance->m_first_free_instance= this;
- /*
- This execution of the SP was aborted with an error (e.g. "Table not
- found"). However it might still have consumed some numbers from the
- thd->select_number counter. The next sp->exec() call must not use the
- consumed numbers, so we remember the first free number (We know that
- nobody will use it as this execution has stopped with an error).
- */
- if (err_status)
- set_select_number(thd->select_number);
-
DBUG_RETURN(err_status);
}
@@ -2228,7 +2207,7 @@ sp_head::reset_lex(THD *thd)
if (sublex == 0)
DBUG_RETURN(TRUE);
- thd->lex= sublex;
+ thd->lex= thd->stmt_lex= sublex;
(void)m_lex.push_front(oldlex);
/* Reset most stuff. */
@@ -2974,7 +2953,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
We should not save old value since it is saved/restored in
sp_head::execute() when we are entering/leaving routine.
*/
- thd->lex= m_lex;
+ thd->lex= thd->stmt_lex= m_lex;
thd->set_query_id(next_query_id());
diff --git a/sql/sp_head.h b/sql/sp_head.h
index 5d3697daa16..604190079cb 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -232,7 +232,6 @@ private:
*/
uint32 unsafe_flags;
- uint m_select_number;
public:
inline Stored_program_creation_ctx *get_creation_ctx()
{
@@ -522,8 +521,6 @@ public:
sp_pcontext *get_parse_context() { return m_pcont; }
- void set_select_number(uint num) { m_select_number= num; }
-
private:
MEM_ROOT *m_thd_root; ///< Temp. store for thd's mem_root
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index a226b920673..8359ad3ac97 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -3654,7 +3654,7 @@ void Statement::set_statement(Statement *stmt)
{
id= stmt->id;
mark_used_columns= stmt->mark_used_columns;
- lex= stmt->lex;
+ stmt_lex= lex= stmt->lex;
query_string= stmt->query_string;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 4556487bdfe..76e55d5d3de 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1028,6 +1028,21 @@ public:
LEX_STRING name; /* name for named prepared statements */
LEX *lex; // parse tree descriptor
/*
+ LEX which represents current statement (conventional, SP or PS)
+
+ For example during view parsing THD::lex will point to the views LEX and
+ THD::stmt_lex will point to LEX of the statement where the view will be
+ included
+
+ Currently it is used to have always correct select numbering inside
+ statement (LEX::current_select_number) without storing and restoring a
+ global counter which was THD::select_number.
+
+ TODO: make some unified statement representation (now SP has different)
+ to store such data like LEX::current_select_number.
+ */
+ LEX *stmt_lex;
+ /*
Points to the query associated with this statement. It's const, but
we need to declare it char * because all table handlers are written
in C and need to point to it.
@@ -2690,7 +2705,6 @@ public:
uint tmp_table, global_disable_checkpoint;
uint server_status,open_options;
enum enum_thread_type system_thread;
- uint select_number; //number of select (used for EXPLAIN)
/*
Current or next transaction isolation level.
When a connection is established, the value is taken from
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
index 4d0ba38d810..caacf6b3a2f 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -208,6 +208,9 @@ public:
Explain_select(MEM_ROOT *root, bool is_analyze) :
Explain_basic_join(root),
+#ifndef DBUG_OFF
+ select_lex(NULL),
+#endif
message(NULL),
having(NULL), having_value(Item::COND_UNDEF),
using_temporary(false), using_filesort(false),
@@ -222,6 +225,9 @@ public:
void replace_table(uint idx, Explain_table_access *new_tab);
public:
+#ifndef DBUG_OFF
+ SELECT_LEX *select_lex;
+#endif
const char *select_type;
/*
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 63ab6b5d046..5b8327d6f59 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -657,6 +657,7 @@ void lex_start(THD *thd)
{
LEX *lex= thd->lex;
DBUG_ENTER("lex_start");
+ DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex));
lex->thd= lex->unit.thd= thd;
@@ -668,6 +669,7 @@ void lex_start(THD *thd)
/* 'parent_lex' is used in init_query() so it must be before it. */
lex->select_lex.parent_lex= lex;
lex->select_lex.init_query();
+ lex->current_select_number= 1;
lex->value_list.empty();
lex->update_list.empty();
lex->set_var_list.empty();
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index b57fba08b47..292f3d6d90f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -727,7 +727,13 @@ public:
Item *prep_having;/* saved HAVING clause for prepared statement processing */
/* Saved values of the WHERE and HAVING clauses*/
Item::cond_result cond_value, having_value;
- /* point on lex in which it was created, used in view subquery detection */
+ /*
+ Point to the LEX in which it was created, used in view subquery detection.
+
+ TODO: make also st_select_lex::parent_stmt_lex (see THD::stmt_lex)
+ and use st_select_lex::parent_lex & st_select_lex::parent_stmt_lex
+ instead of global (from THD) references where it is possible.
+ */
LEX *parent_lex;
enum olap_type olap;
/* FROM clause - points to the beginning of the TABLE_LIST::next_local list. */
@@ -2452,7 +2458,7 @@ struct LEX: public Query_tables_list
/** SELECT of CREATE VIEW statement */
LEX_STRING create_view_select;
- uint number_of_selects; // valid only for view
+ uint current_select_number; // valid for statment LEX (not view)
/** Start of 'ON table', in trigger statements. */
const char* raw_trg_on_table_name_begin;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 6084c59a257..4dd8d9e124e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -6903,7 +6903,12 @@ void THD::reset_for_next_command(bool do_clear_error)
clear_error(1);
thd->free_list= 0;
- thd->select_number= 1;
+ /*
+ We also assign thd->stmt_lex in lex_start(), but during bootstrap this
+ code is executed first.
+ */
+ thd->stmt_lex= &main_lex; thd->stmt_lex->current_select_number= 1;
+ DBUG_PRINT("info", ("Lex %p stmt_lex: %p", thd->lex, thd->stmt_lex));
/*
Those two lines below are theoretically unneeded as
THD::cleanup_after_query() should take care of this already.
@@ -7021,7 +7026,7 @@ mysql_new_select(LEX *lex, bool move_down)
if (!(select_lex= new (thd->mem_root) SELECT_LEX()))
DBUG_RETURN(1);
- select_lex->select_number= ++thd->select_number;
+ select_lex->select_number= ++thd->stmt_lex->current_select_number;
select_lex->parent_lex= lex; /* Used in init_query. */
select_lex->init_query();
select_lex->init_select();
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index e5b85c3be45..64212d15548 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -164,20 +164,6 @@ public:
uint param_count;
uint last_errno;
uint flags;
- /*
- The value of thd->select_number at the end of the PREPARE phase.
-
- The issue is: each statement execution opens VIEWs, which may cause
- select_lex objects to be created, and select_number values to be assigned.
-
- On the other hand, PREPARE assigns select_number values for triggers and
- subqueries.
-
- In order for select_number values from EXECUTE not to conflict with
- select_number values from PREPARE, we keep the number and set it at each
- execution.
- */
- uint select_number_after_prepare;
char last_error[MYSQL_ERRMSG_SIZE];
#ifndef EMBEDDED_LIBRARY
bool (*set_params)(Prepared_statement *st, uchar *data, uchar *data_end,
@@ -3649,6 +3635,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
if (! (lex= new (mem_root) st_lex_local))
DBUG_RETURN(TRUE);
+ stmt_lex= lex;
if (set_db(thd->db, thd->db_length))
DBUG_RETURN(TRUE);
@@ -3754,8 +3741,6 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
trans_rollback_implicit(thd);
thd->mdl_context.release_transactional_locks();
}
-
- select_number_after_prepare= thd->select_number;
/* Preserve CHANGE MASTER attributes */
lex_end_stage1(lex);
@@ -3891,7 +3876,6 @@ Prepared_statement::execute_loop(String *expanded_query,
*/
DBUG_ASSERT(thd->free_list == NULL);
- thd->select_number= select_number_after_prepare;
/* Check if we got an error when sending long data */
if (state == Query_arena::STMT_ERROR)
{
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index b9fe8f3162a..7a6a028ee9c 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2462,6 +2462,17 @@ void JOIN::save_explain_data(Explain_query *output, bool can_overwrite,
bool need_tmp_table, bool need_order,
bool distinct)
{
+ /*
+ If there is SELECT in this statemet with the same number it must be the
+ same SELECT
+ */
+ DBUG_ASSERT(select_lex->select_number == UINT_MAX ||
+ select_lex->select_number == INT_MAX ||
+ !output ||
+ !output->get_select(select_lex->select_number) ||
+ output->get_select(select_lex->select_number)->select_lex ==
+ select_lex);
+
if (select_lex->select_number != UINT_MAX &&
select_lex->select_number != INT_MAX /* this is not a UNION's "fake select */ &&
have_query_plan != JOIN::QEP_NOT_PRESENT_YET &&
@@ -24601,6 +24612,11 @@ int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
{
explain= new (output->mem_root) Explain_select(output->mem_root,
thd->lex->analyze_stmt);
+ if (!explain)
+ DBUG_RETURN(1); // EoM
+#ifndef DBUG_OFF
+ explain->select_lex= select_lex;
+#endif
join->select_lex->set_explain_type(true);
explain->select_id= join->select_lex->select_number;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 0b4978b2862..70e9b36c56e 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1373,12 +1373,13 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
List_iterator_fast<LEX_STRING> it_client_cs_name(triggers->client_cs_names);
List_iterator_fast<LEX_STRING> it_connection_cl_name(triggers->connection_cl_names);
List_iterator_fast<LEX_STRING> it_db_cl_name(triggers->db_cl_names);
- LEX *old_lex= thd->lex, lex;
+ LEX *old_lex= thd->lex, *old_stmt_lex= thd->stmt_lex;
+ LEX lex;
sp_rcontext *save_spcont= thd->spcont;
ulonglong save_sql_mode= thd->variables.sql_mode;
LEX_STRING *on_table_name;
- thd->lex= &lex;
+ thd->lex= thd->stmt_lex= &lex;
save_db.str= thd->db;
save_db.length= thd->db_length;
@@ -1577,6 +1578,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
}
thd->reset_db(save_db.str, save_db.length);
thd->lex= old_lex;
+ thd->stmt_lex= old_stmt_lex;
thd->spcont= save_spcont;
thd->variables.sql_mode= save_sql_mode;
@@ -1589,6 +1591,7 @@ err_with_lex_cleanup:
// QQ: anything else ?
lex_end(&lex);
thd->lex= old_lex;
+ thd->stmt_lex= old_stmt_lex;
thd->spcont= save_spcont;
thd->variables.sql_mode= save_sql_mode;
thd->reset_db(save_db.str, save_db.length);
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 0f08883639a..1bdc76a66ea 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -1187,8 +1187,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
*/
mysql_derived_reinit(thd, NULL, table);
- thd->select_number+= table->view->number_of_selects;
-
DEBUG_SYNC(thd, "after_cached_view_opened");
DBUG_RETURN(0);
}
@@ -1343,7 +1341,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
lex_start(thd);
view_select= &lex->select_lex;
- view_select->select_number= ++thd->select_number;
+ view_select->select_number= ++thd->stmt_lex->current_select_number;
ulonglong saved_mode= thd->variables.sql_mode;
/* switch off modes which can prevent normal parsing of VIEW
@@ -1377,9 +1375,6 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
parse_status= parse_sql(thd, & parser_state, table->view_creation_ctx);
- lex->number_of_selects=
- (thd->select_number - view_select->select_number) + 1;
-
/* Restore environment. */
if ((old_lex->sql_command == SQLCOM_SHOW_FIELDS) ||