Merge 50 -> 51 (-opt changesets)
This commit is contained in:
commit
b13de9343f
@ -59,3 +59,109 @@ INSERT INTO t4 SELECT * FROM t3 ORDER BY CONCAT(a);
|
|||||||
SELECT SUM(id) FROM t3;
|
SELECT SUM(id) FROM t3;
|
||||||
|
|
||||||
DROP TABLE t1,t2,t3,t4;
|
DROP TABLE t1,t2,t3,t4;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug#24989: The DEADLOCK error is improperly handled by InnoDB.
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (f1 int NOT NULL) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t2 (f2 int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
|
||||||
|
DELIMITER |;
|
||||||
|
CREATE TRIGGER t1_bi before INSERT
|
||||||
|
ON t1 FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @a:= 'deadlock';
|
||||||
|
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception';
|
||||||
|
INSERT INTO t2 (f2) VALUES (1);
|
||||||
|
DELETE FROM t2 WHERE f2 = 1;
|
||||||
|
END;|
|
||||||
|
|
||||||
|
CREATE PROCEDURE proc24989()
|
||||||
|
BEGIN
|
||||||
|
DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @b:= 'deadlock';
|
||||||
|
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception';
|
||||||
|
INSERT INTO t2 (f2) VALUES (1);
|
||||||
|
DELETE FROM t2 WHERE f2 = 1;
|
||||||
|
END;|
|
||||||
|
|
||||||
|
create procedure proc24989_2()
|
||||||
|
deterministic
|
||||||
|
begin
|
||||||
|
declare continue handler for sqlexception
|
||||||
|
select 'Outer handler' as 'exception';
|
||||||
|
|
||||||
|
insert into t1 values(1);
|
||||||
|
select "continued";
|
||||||
|
end|
|
||||||
|
|
||||||
|
DELIMITER ;|
|
||||||
|
|
||||||
|
connect (con1,localhost,root,,);
|
||||||
|
connect (con2,localhost,root,,);
|
||||||
|
|
||||||
|
connection con1;
|
||||||
|
start transaction;
|
||||||
|
insert into t1 values(1);
|
||||||
|
|
||||||
|
connection con2;
|
||||||
|
start transaction;
|
||||||
|
insert into t2 values(123);
|
||||||
|
send insert into t1 values(1);
|
||||||
|
|
||||||
|
connection con1;
|
||||||
|
--sleep 1
|
||||||
|
insert into t1 values(1);
|
||||||
|
|
||||||
|
connection con2;
|
||||||
|
--error 1213
|
||||||
|
reap;
|
||||||
|
select @a;
|
||||||
|
# check that the whole transaction was rolled back
|
||||||
|
select * from t2;
|
||||||
|
|
||||||
|
connection con1;
|
||||||
|
commit;
|
||||||
|
start transaction;
|
||||||
|
insert into t1 values(1);
|
||||||
|
|
||||||
|
connection con2;
|
||||||
|
start transaction;
|
||||||
|
insert into t2 values(123);
|
||||||
|
send call proc24989();
|
||||||
|
|
||||||
|
connection con1;
|
||||||
|
--sleep 1
|
||||||
|
insert into t1 values(1);
|
||||||
|
|
||||||
|
connection con2;
|
||||||
|
reap;
|
||||||
|
select @a,@b;
|
||||||
|
# check that the whole transaction was rolled back
|
||||||
|
select * from t2;
|
||||||
|
|
||||||
|
connection con1;
|
||||||
|
commit;
|
||||||
|
start transaction;
|
||||||
|
insert into t1 values(1);
|
||||||
|
|
||||||
|
connection con2;
|
||||||
|
start transaction;
|
||||||
|
insert into t2 values(123);
|
||||||
|
send call proc24989_2();
|
||||||
|
|
||||||
|
connection con1;
|
||||||
|
--sleep 1
|
||||||
|
insert into t1 values(1);
|
||||||
|
commit;
|
||||||
|
|
||||||
|
connection con2;
|
||||||
|
reap;
|
||||||
|
# check that the whole transaction was rolled back
|
||||||
|
select * from t2;
|
||||||
|
|
||||||
|
disconnect con1;
|
||||||
|
disconnect con2;
|
||||||
|
connection default;
|
||||||
|
drop procedure proc24989;
|
||||||
|
drop procedure proc24989_2;
|
||||||
|
drop table t1,t2;
|
||||||
|
|
||||||
|
@ -33,3 +33,69 @@ SELECT SUM(id) FROM t3;
|
|||||||
SUM(id)
|
SUM(id)
|
||||||
2199024304128
|
2199024304128
|
||||||
DROP TABLE t1,t2,t3,t4;
|
DROP TABLE t1,t2,t3,t4;
|
||||||
|
CREATE TABLE t1 (f1 int NOT NULL) ENGINE=InnoDB;
|
||||||
|
CREATE TABLE t2 (f2 int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB;
|
||||||
|
CREATE TRIGGER t1_bi before INSERT
|
||||||
|
ON t1 FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @a:= 'deadlock';
|
||||||
|
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception';
|
||||||
|
INSERT INTO t2 (f2) VALUES (1);
|
||||||
|
DELETE FROM t2 WHERE f2 = 1;
|
||||||
|
END;|
|
||||||
|
CREATE PROCEDURE proc24989()
|
||||||
|
BEGIN
|
||||||
|
DECLARE CONTINUE HANDLER FOR SQLSTATE '40001' SET @b:= 'deadlock';
|
||||||
|
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET @a:= 'exception';
|
||||||
|
INSERT INTO t2 (f2) VALUES (1);
|
||||||
|
DELETE FROM t2 WHERE f2 = 1;
|
||||||
|
END;|
|
||||||
|
create procedure proc24989_2()
|
||||||
|
deterministic
|
||||||
|
begin
|
||||||
|
declare continue handler for sqlexception
|
||||||
|
select 'Outer handler' as 'exception';
|
||||||
|
insert into t1 values(1);
|
||||||
|
select "continued";
|
||||||
|
end|
|
||||||
|
start transaction;
|
||||||
|
insert into t1 values(1);
|
||||||
|
start transaction;
|
||||||
|
insert into t2 values(123);
|
||||||
|
insert into t1 values(1);
|
||||||
|
insert into t1 values(1);
|
||||||
|
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
|
||||||
|
select @a;
|
||||||
|
@a
|
||||||
|
NULL
|
||||||
|
select * from t2;
|
||||||
|
f2
|
||||||
|
commit;
|
||||||
|
start transaction;
|
||||||
|
insert into t1 values(1);
|
||||||
|
start transaction;
|
||||||
|
insert into t2 values(123);
|
||||||
|
call proc24989();
|
||||||
|
insert into t1 values(1);
|
||||||
|
select @a,@b;
|
||||||
|
@a @b
|
||||||
|
exception deadlock
|
||||||
|
select * from t2;
|
||||||
|
f2
|
||||||
|
commit;
|
||||||
|
start transaction;
|
||||||
|
insert into t1 values(1);
|
||||||
|
start transaction;
|
||||||
|
insert into t2 values(123);
|
||||||
|
call proc24989_2();
|
||||||
|
insert into t1 values(1);
|
||||||
|
commit;
|
||||||
|
exception
|
||||||
|
Outer handler
|
||||||
|
continued
|
||||||
|
continued
|
||||||
|
select * from t2;
|
||||||
|
f2
|
||||||
|
drop procedure proc24989;
|
||||||
|
drop procedure proc24989_2;
|
||||||
|
drop table t1,t2;
|
||||||
|
@ -851,6 +851,9 @@ int ha_rollback_trans(THD *thd, bool all)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* USING_TRANSACTIONS */
|
#endif /* USING_TRANSACTIONS */
|
||||||
|
if (all)
|
||||||
|
thd->transaction_rollback_request= FALSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
If a non-transactional table was updated, warn; don't warn if this is a
|
If a non-transactional table was updated, warn; don't warn if this is a
|
||||||
slave thread (because when a slave thread executes a ROLLBACK, it has
|
slave thread (because when a slave thread executes a ROLLBACK, it has
|
||||||
@ -887,6 +890,8 @@ int ha_autocommit_or_rollback(THD *thd, int error)
|
|||||||
if (ha_commit_stmt(thd))
|
if (ha_commit_stmt(thd))
|
||||||
error=1;
|
error=1;
|
||||||
}
|
}
|
||||||
|
else if (thd->transaction_rollback_request && !thd->in_sub_stmt)
|
||||||
|
(void) ha_rollback(thd);
|
||||||
else
|
else
|
||||||
(void) ha_rollback_stmt(thd);
|
(void) ha_rollback_stmt(thd);
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ sp_rcontext::sp_rcontext(sp_pcontext *root_parsing_ctx,
|
|||||||
m_var_items(0),
|
m_var_items(0),
|
||||||
m_return_value_fld(return_value_fld),
|
m_return_value_fld(return_value_fld),
|
||||||
m_return_value_set(FALSE),
|
m_return_value_set(FALSE),
|
||||||
|
in_sub_stmt(FALSE),
|
||||||
m_hcount(0),
|
m_hcount(0),
|
||||||
m_hsp(0),
|
m_hsp(0),
|
||||||
m_ihsp(0),
|
m_ihsp(0),
|
||||||
@ -67,6 +68,8 @@ sp_rcontext::~sp_rcontext()
|
|||||||
|
|
||||||
bool sp_rcontext::init(THD *thd)
|
bool sp_rcontext::init(THD *thd)
|
||||||
{
|
{
|
||||||
|
in_sub_stmt= thd->in_sub_stmt;
|
||||||
|
|
||||||
if (init_var_table(thd) || init_var_items())
|
if (init_var_table(thd) || init_var_items())
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
@ -191,7 +194,7 @@ sp_rcontext::set_return_value(THD *thd, Item **return_value_item)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sp_rcontext::find_handler(uint sql_errno,
|
sp_rcontext::find_handler(THD *thd, uint sql_errno,
|
||||||
MYSQL_ERROR::enum_warning_level level)
|
MYSQL_ERROR::enum_warning_level level)
|
||||||
{
|
{
|
||||||
if (m_hfound >= 0)
|
if (m_hfound >= 0)
|
||||||
@ -200,6 +203,15 @@ sp_rcontext::find_handler(uint sql_errno,
|
|||||||
const char *sqlstate= mysql_errno_to_sqlstate(sql_errno);
|
const char *sqlstate= mysql_errno_to_sqlstate(sql_errno);
|
||||||
int i= m_hcount, found= -1;
|
int i= m_hcount, found= -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
If this is a fatal sub-statement error, and this runtime
|
||||||
|
context corresponds to a sub-statement, no CONTINUE/EXIT
|
||||||
|
handlers from this context are applicable: try to locate one
|
||||||
|
in the outer scope.
|
||||||
|
*/
|
||||||
|
if (thd->is_fatal_sub_stmt_error && in_sub_stmt)
|
||||||
|
i= 0;
|
||||||
|
|
||||||
/* Search handlers from the latest (innermost) to the oldest (outermost) */
|
/* Search handlers from the latest (innermost) to the oldest (outermost) */
|
||||||
while (i--)
|
while (i--)
|
||||||
{
|
{
|
||||||
@ -252,7 +264,7 @@ sp_rcontext::find_handler(uint sql_errno,
|
|||||||
*/
|
*/
|
||||||
if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
|
if (m_prev_runtime_ctx && IS_EXCEPTION_CONDITION(sqlstate) &&
|
||||||
level == MYSQL_ERROR::WARN_LEVEL_ERROR)
|
level == MYSQL_ERROR::WARN_LEVEL_ERROR)
|
||||||
return m_prev_runtime_ctx->find_handler(sql_errno, level);
|
return m_prev_runtime_ctx->find_handler(thd, sql_errno, level);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
m_hfound= found;
|
m_hfound= found;
|
||||||
@ -298,7 +310,7 @@ sp_rcontext::handle_error(uint sql_errno,
|
|||||||
elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
|
elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (find_handler(sql_errno, elevated_level))
|
if (find_handler(thd, sql_errno, elevated_level))
|
||||||
{
|
{
|
||||||
if (elevated_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
|
if (elevated_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
|
||||||
{
|
{
|
||||||
|
@ -125,7 +125,7 @@ class sp_rcontext : public Sql_alloc
|
|||||||
|
|
||||||
// Returns 1 if a handler was found, 0 otherwise.
|
// Returns 1 if a handler was found, 0 otherwise.
|
||||||
bool
|
bool
|
||||||
find_handler(uint sql_errno,MYSQL_ERROR::enum_warning_level level);
|
find_handler(THD *thd, uint sql_errno,MYSQL_ERROR::enum_warning_level level);
|
||||||
|
|
||||||
// If there is an error handler for this error, handle it and return TRUE.
|
// If there is an error handler for this error, handle it and return TRUE.
|
||||||
bool
|
bool
|
||||||
@ -236,6 +236,10 @@ private:
|
|||||||
during execution.
|
during execution.
|
||||||
*/
|
*/
|
||||||
bool m_return_value_set;
|
bool m_return_value_set;
|
||||||
|
/**
|
||||||
|
TRUE if the context is created for a sub-statement.
|
||||||
|
*/
|
||||||
|
bool in_sub_stmt;
|
||||||
|
|
||||||
sp_handler_t *m_handler; // Visible handlers
|
sp_handler_t *m_handler; // Visible handlers
|
||||||
uint m_hcount; // Stack pointer for m_handler
|
uint m_hcount; // Stack pointer for m_handler
|
||||||
|
@ -367,6 +367,8 @@ THD::THD()
|
|||||||
stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
|
stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
|
||||||
global_read_lock(0),
|
global_read_lock(0),
|
||||||
is_fatal_error(0),
|
is_fatal_error(0),
|
||||||
|
transaction_rollback_request(0),
|
||||||
|
is_fatal_sub_stmt_error(0),
|
||||||
rand_used(0),
|
rand_used(0),
|
||||||
time_zone_used(0),
|
time_zone_used(0),
|
||||||
in_lock_tables(0),
|
in_lock_tables(0),
|
||||||
@ -1304,7 +1306,7 @@ void select_send::abort()
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("select_send::abort");
|
DBUG_ENTER("select_send::abort");
|
||||||
if (status && thd->spcont &&
|
if (status && thd->spcont &&
|
||||||
thd->spcont->find_handler(thd->net.last_errno,
|
thd->spcont->find_handler(thd, thd->net.last_errno,
|
||||||
MYSQL_ERROR::WARN_LEVEL_ERROR))
|
MYSQL_ERROR::WARN_LEVEL_ERROR))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -2682,6 +2684,13 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
|
|||||||
limit_found_rows= backup->limit_found_rows;
|
limit_found_rows= backup->limit_found_rows;
|
||||||
sent_row_count= backup->sent_row_count;
|
sent_row_count= backup->sent_row_count;
|
||||||
client_capabilities= backup->client_capabilities;
|
client_capabilities= backup->client_capabilities;
|
||||||
|
/*
|
||||||
|
If we've left sub-statement mode, reset the fatal error flag.
|
||||||
|
Otherwise keep the current value, to propagate it up the sub-statement
|
||||||
|
stack.
|
||||||
|
*/
|
||||||
|
if (!in_sub_stmt)
|
||||||
|
is_fatal_sub_stmt_error= FALSE;
|
||||||
|
|
||||||
if ((options & OPTION_BIN_LOG) && is_update_query(lex->sql_command) &&
|
if ((options & OPTION_BIN_LOG) && is_update_query(lex->sql_command) &&
|
||||||
!current_stmt_binlog_row_based)
|
!current_stmt_binlog_row_based)
|
||||||
@ -2696,6 +2705,18 @@ void THD::restore_sub_statement_state(Sub_statement_state *backup)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Mark transaction to rollback and mark error as fatal to a sub-statement.
|
||||||
|
|
||||||
|
@param thd Thread handle
|
||||||
|
@param all TRUE <=> rollback main transaction.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void mark_transaction_to_rollback(THD *thd, bool all)
|
||||||
|
{
|
||||||
|
thd->is_fatal_sub_stmt_error= TRUE;
|
||||||
|
thd->transaction_rollback_request= all;
|
||||||
|
}
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
Handling of XA id cacheing
|
Handling of XA id cacheing
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
@ -1411,7 +1411,33 @@ public:
|
|||||||
bool current_stmt_binlog_row_based;
|
bool current_stmt_binlog_row_based;
|
||||||
bool locked, some_tables_deleted;
|
bool locked, some_tables_deleted;
|
||||||
bool last_cuted_field;
|
bool last_cuted_field;
|
||||||
bool no_errors, password, is_fatal_error;
|
bool no_errors, password;
|
||||||
|
/**
|
||||||
|
Set to TRUE if execution of the current compound statement
|
||||||
|
can not continue. In particular, disables activation of
|
||||||
|
CONTINUE or EXIT handlers of stored routines.
|
||||||
|
Reset in the end of processing of the current user request, in
|
||||||
|
@see mysql_reset_thd_for_next_command().
|
||||||
|
*/
|
||||||
|
bool is_fatal_error;
|
||||||
|
/**
|
||||||
|
Set by a storage engine to request the entire
|
||||||
|
transaction (that possibly spans multiple engines) to
|
||||||
|
rollback. Reset in ha_rollback.
|
||||||
|
*/
|
||||||
|
bool transaction_rollback_request;
|
||||||
|
/**
|
||||||
|
TRUE if we are in a sub-statement and the current error can
|
||||||
|
not be safely recovered until we left the sub-statement mode.
|
||||||
|
In particular, disables activation of CONTINUE and EXIT
|
||||||
|
handlers inside sub-statements. E.g. if it is a deadlock
|
||||||
|
error and requires a transaction-wide rollback, this flag is
|
||||||
|
raised (traditionally, MySQL first has to close all the reads
|
||||||
|
via @see handler::ha_index_or_rnd_end() and only then perform
|
||||||
|
the rollback).
|
||||||
|
Reset to FALSE when we leave the sub-statement mode.
|
||||||
|
*/
|
||||||
|
bool is_fatal_sub_stmt_error;
|
||||||
bool query_start_used, rand_used, time_zone_used;
|
bool query_start_used, rand_used, time_zone_used;
|
||||||
/* for IS NULL => = last_insert_id() fix in remove_eq_conds() */
|
/* for IS NULL => = last_insert_id() fix in remove_eq_conds() */
|
||||||
bool substitute_null_with_insert_id;
|
bool substitute_null_with_insert_id;
|
||||||
@ -2455,4 +2481,6 @@ public:
|
|||||||
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
|
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
|
||||||
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
|
void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var,
|
||||||
STATUS_VAR *dec_var);
|
STATUS_VAR *dec_var);
|
||||||
|
void mark_transaction_to_rollback(THD *thd, bool all);
|
||||||
|
|
||||||
#endif /* MYSQL_SERVER */
|
#endif /* MYSQL_SERVER */
|
||||||
|
@ -2455,7 +2455,7 @@ make_join_statistics(JOIN *join, TABLE_LIST *tables, COND *conds,
|
|||||||
no_partitions_used) &&
|
no_partitions_used) &&
|
||||||
!s->dependent &&
|
!s->dependent &&
|
||||||
(table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
|
(table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
|
||||||
!table->fulltext_searched)
|
!table->fulltext_searched && !join->no_const_tables)
|
||||||
{
|
{
|
||||||
set_position(join,const_count++,s,(KEYUSE*) 0);
|
set_position(join,const_count++,s,(KEYUSE*) 0);
|
||||||
}
|
}
|
||||||
|
@ -316,6 +316,14 @@ public:
|
|||||||
SELECT_LEX_UNIT *unit;
|
SELECT_LEX_UNIT *unit;
|
||||||
// select that processed
|
// select that processed
|
||||||
SELECT_LEX *select_lex;
|
SELECT_LEX *select_lex;
|
||||||
|
/*
|
||||||
|
TRUE <=> optimizer must not mark any table as a constant table.
|
||||||
|
This is needed for subqueries in form "a IN (SELECT .. UNION SELECT ..):
|
||||||
|
when we optimize the select that reads the results of the union from a
|
||||||
|
temporary table, we must not mark the temp. table as constant because
|
||||||
|
the number of rows in it may vary from one subquery execution to another.
|
||||||
|
*/
|
||||||
|
bool no_const_tables;
|
||||||
|
|
||||||
JOIN *tmp_join; // copy of this JOIN to be used with temporary tables
|
JOIN *tmp_join; // copy of this JOIN to be used with temporary tables
|
||||||
ROLLUP rollup; // Used with rollup
|
ROLLUP rollup; // Used with rollup
|
||||||
@ -445,6 +453,8 @@ public:
|
|||||||
tmp_table_param.init();
|
tmp_table_param.init();
|
||||||
tmp_table_param.end_write_records= HA_POS_ERROR;
|
tmp_table_param.end_write_records= HA_POS_ERROR;
|
||||||
rollup.state= ROLLUP::STATE_NONE;
|
rollup.state= ROLLUP::STATE_NONE;
|
||||||
|
|
||||||
|
no_const_tables= FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
|
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
|
||||||
|
@ -547,6 +547,10 @@ bool st_select_lex_unit::exec()
|
|||||||
/*
|
/*
|
||||||
allocate JOIN for fake select only once (prevent
|
allocate JOIN for fake select only once (prevent
|
||||||
mysql_select automatic allocation)
|
mysql_select automatic allocation)
|
||||||
|
TODO: The above is nonsense. mysql_select() will not allocate the
|
||||||
|
join if one already exists. There must be some other reason why we
|
||||||
|
don't let it allocate the join. Perhaps this is because we need
|
||||||
|
some special parameter values passed to join constructor?
|
||||||
*/
|
*/
|
||||||
if (!(fake_select_lex->join= new JOIN(thd, item_list,
|
if (!(fake_select_lex->join= new JOIN(thd, item_list,
|
||||||
fake_select_lex->options, result)))
|
fake_select_lex->options, result)))
|
||||||
@ -554,33 +558,52 @@ bool st_select_lex_unit::exec()
|
|||||||
fake_select_lex->table_list.empty();
|
fake_select_lex->table_list.empty();
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
fake_select_lex->join->no_const_tables= TRUE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fake st_select_lex should have item list for correctref_array
|
Fake st_select_lex should have item list for correctref_array
|
||||||
allocation.
|
allocation.
|
||||||
*/
|
*/
|
||||||
fake_select_lex->item_list= item_list;
|
fake_select_lex->item_list= item_list;
|
||||||
|
saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
|
||||||
|
&result_table_list,
|
||||||
|
0, item_list, NULL,
|
||||||
|
global_parameters->order_list.elements,
|
||||||
|
(ORDER*)global_parameters->order_list.first,
|
||||||
|
(ORDER*) NULL, NULL, (ORDER*) NULL,
|
||||||
|
fake_select_lex->options | SELECT_NO_UNLOCK,
|
||||||
|
result, this, fake_select_lex);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JOIN_TAB *tab,*end;
|
if (describe)
|
||||||
for (tab=join->join_tab, end=tab+join->tables ;
|
{
|
||||||
tab && tab != end ;
|
/*
|
||||||
tab++)
|
In EXPLAIN command, constant subqueries that do not use any
|
||||||
{
|
tables are executed two times:
|
||||||
delete tab->select;
|
- 1st time is a real evaluation to get the subquery value
|
||||||
delete tab->quick;
|
- 2nd time is to produce EXPLAIN output rows.
|
||||||
}
|
1st execution sets certain members (e.g. select_result) to perform
|
||||||
join->init(thd, item_list, fake_select_lex->options, result);
|
subquery execution rather than EXPLAIN line production. In order
|
||||||
|
to reset them back, we re-do all of the actions (yes it is ugly):
|
||||||
|
*/
|
||||||
|
join->init(thd, item_list, fake_select_lex->options, result);
|
||||||
|
saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
|
||||||
|
&result_table_list,
|
||||||
|
0, item_list, NULL,
|
||||||
|
global_parameters->order_list.elements,
|
||||||
|
(ORDER*)global_parameters->order_list.first,
|
||||||
|
(ORDER*) NULL, NULL, (ORDER*) NULL,
|
||||||
|
fake_select_lex->options | SELECT_NO_UNLOCK,
|
||||||
|
result, this, fake_select_lex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
join->examined_rows= 0;
|
||||||
|
saved_error= join->reinit();
|
||||||
|
join->exec();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array,
|
|
||||||
&result_table_list,
|
|
||||||
0, item_list, NULL,
|
|
||||||
global_parameters->order_list.elements,
|
|
||||||
(ORDER*)global_parameters->order_list.first,
|
|
||||||
(ORDER*) NULL, NULL, (ORDER*) NULL,
|
|
||||||
fake_select_lex->options | SELECT_NO_UNLOCK,
|
|
||||||
result, this, fake_select_lex);
|
|
||||||
|
|
||||||
fake_select_lex->table_list.empty();
|
fake_select_lex->table_list.empty();
|
||||||
if (!saved_error)
|
if (!saved_error)
|
||||||
|
@ -601,9 +601,7 @@ convert_error_code_to_mysql(
|
|||||||
tell it also to MySQL so that MySQL knows to empty the
|
tell it also to MySQL so that MySQL knows to empty the
|
||||||
cached binlog for this transaction */
|
cached binlog for this transaction */
|
||||||
|
|
||||||
if (thd) {
|
mark_transaction_to_rollback(thd, TRUE);
|
||||||
ha_rollback(thd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(HA_ERR_LOCK_DEADLOCK);
|
return(HA_ERR_LOCK_DEADLOCK);
|
||||||
|
|
||||||
@ -613,9 +611,8 @@ convert_error_code_to_mysql(
|
|||||||
latest SQL statement in a lock wait timeout. Previously, we
|
latest SQL statement in a lock wait timeout. Previously, we
|
||||||
rolled back the whole transaction. */
|
rolled back the whole transaction. */
|
||||||
|
|
||||||
if (thd && row_rollback_on_timeout) {
|
mark_transaction_to_rollback(thd,
|
||||||
ha_rollback(thd);
|
(bool)row_rollback_on_timeout);
|
||||||
}
|
|
||||||
|
|
||||||
return(HA_ERR_LOCK_WAIT_TIMEOUT);
|
return(HA_ERR_LOCK_WAIT_TIMEOUT);
|
||||||
|
|
||||||
@ -667,9 +664,7 @@ convert_error_code_to_mysql(
|
|||||||
tell it also to MySQL so that MySQL knows to empty the
|
tell it also to MySQL so that MySQL knows to empty the
|
||||||
cached binlog for this transaction */
|
cached binlog for this transaction */
|
||||||
|
|
||||||
if (thd) {
|
mark_transaction_to_rollback(thd, TRUE);
|
||||||
ha_rollback(thd);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(HA_ERR_LOCK_TABLE_FULL);
|
return(HA_ERR_LOCK_TABLE_FULL);
|
||||||
} else if (error == DB_TOO_MANY_CONCURRENT_TRXS) {
|
} else if (error == DB_TOO_MANY_CONCURRENT_TRXS) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user