mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
merge 10.5 to 10.6
This commit is contained in:
commit
e7f4daf88c
35 changed files with 442 additions and 49 deletions
|
@ -1,4 +1,5 @@
|
|||
-- require include/have_pool_of_threads.require
|
||||
--source include/not_aix.inc
|
||||
--require include/have_pool_of_threads.require
|
||||
disable_query_log;
|
||||
show variables like 'thread_handling';
|
||||
enable_query_log;
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
# run with and without threadpool
|
||||
--source include/not_aix.inc
|
||||
|
|
|
@ -496,3 +496,22 @@ natural right outer join t3;
|
|||
drop table t1,t2,t3;
|
||||
set optimizer_prune_level=@mdev4270_opl;
|
||||
set optimizer_search_depth=@mdev4270_osd;
|
||||
#
|
||||
# Bug #20939184:INNODB: UNLOCK ROW COULD NOT FIND A 2 MODE LOCK ON THE
|
||||
# RECORD
|
||||
#
|
||||
CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, PRIMARY KEY (c1,c2) ) engine=innodb;
|
||||
CREATE TABLE t2 (c1 INT, c2 INT, c3 INT, PRIMARY KEY (c1), KEY (c2)) engine=innodb;
|
||||
INSERT INTO t1 VALUES (1,2,3),(2,3,4),(3,4,5);
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
START TRANSACTION;
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.c2=t2.c2 AND t2.c1=1 FOR UPDATE;
|
||||
c1 c2 c3 c1 c2 c3
|
||||
1 2 3 1 2 3
|
||||
2 3 4 NULL NULL NULL
|
||||
3 4 5 NULL NULL NULL
|
||||
UPDATE t1 LEFT JOIN t2 ON t1.c1 = t2.c2 AND t2.c1 = 3 SET t1.c3 = RAND()*10;
|
||||
COMMIT;
|
||||
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
|
||||
DROP TABLE t1,t2;
|
||||
|
|
|
@ -374,3 +374,20 @@ drop table t1,t2,t3;
|
|||
set optimizer_prune_level=@mdev4270_opl;
|
||||
set optimizer_search_depth=@mdev4270_osd;
|
||||
|
||||
--echo #
|
||||
--echo # Bug #20939184:INNODB: UNLOCK ROW COULD NOT FIND A 2 MODE LOCK ON THE
|
||||
--echo # RECORD
|
||||
--echo #
|
||||
CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, PRIMARY KEY (c1,c2) ) engine=innodb;
|
||||
CREATE TABLE t2 (c1 INT, c2 INT, c3 INT, PRIMARY KEY (c1), KEY (c2)) engine=innodb;
|
||||
INSERT INTO t1 VALUES (1,2,3),(2,3,4),(3,4,5);
|
||||
INSERT INTO t2 SELECT * FROM t1;
|
||||
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
|
||||
START TRANSACTION;
|
||||
#unlocks rows in table t2 where c1 = 1
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON t1.c2=t2.c2 AND t2.c1=1 FOR UPDATE;
|
||||
UPDATE t1 LEFT JOIN t2 ON t1.c1 = t2.c2 AND t2.c1 = 3 SET t1.c3 = RAND()*10;
|
||||
COMMIT;
|
||||
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
source include/not_embedded.inc;
|
||||
source include/not_windows.inc;
|
||||
source include/not_aix.inc;
|
||||
|
||||
# All these tests refer to configuration files that do not exist
|
||||
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result
|
||||
index 7b0ce27ead3..38176dcaa86 100644
|
||||
--- a/mysql-test/main/mysqld--help.result
|
||||
+++ b/mysql-test/main/mysqld--help.result
|
||||
@@ -1301,8 +1301,6 @@ The following specify which files/extra groups are read (specified before remain
|
||||
WHERE clause, or a LIMIT clause, or else they will
|
||||
aborted. Prevents the common mistake of accidentally
|
||||
deleting or updating every row in a table.
|
||||
- --stack-trace Print a symbolic stack trace on failure
|
||||
- (Defaults to on; use --skip-stack-trace to disable.)
|
||||
--standard-compliant-cte
|
||||
Allow only CTEs compliant to SQL standard
|
||||
(Defaults to on; use --skip-standard-compliant-cte to disable.)
|
||||
@@ -1367,39 +1365,6 @@ The following specify which files/extra groups are read (specified before remain
|
||||
--thread-cache-size=#
|
||||
How many threads we should keep in a cache for reuse.
|
||||
These are freed after 5 minutes of idle time
|
||||
- --thread-pool-dedicated-listener
|
||||
- If set to 1,listener thread will not pick up queries
|
||||
- --thread-pool-exact-stats
|
||||
- If set to 1, provides better statistics in
|
||||
- information_schema threadpool tables
|
||||
- --thread-pool-idle-timeout=#
|
||||
- Timeout in seconds for an idle thread in the thread
|
||||
- pool.Worker thread will be shut down after timeout
|
||||
- --thread-pool-max-threads=#
|
||||
- Maximum allowed number of worker threads in the thread
|
||||
- pool
|
||||
- --thread-pool-oversubscribe=#
|
||||
- How many additional active worker threads in a group are
|
||||
- allowed.
|
||||
- --thread-pool-prio-kickup-timer=#
|
||||
- The number of milliseconds before a dequeued low-priority
|
||||
- statement is moved to the high-priority queue
|
||||
- --thread-pool-priority=name
|
||||
- Threadpool priority. High priority connections usually
|
||||
- start executing earlier than low priority.If priority set
|
||||
- to 'auto', the the actual priority(low or high) is
|
||||
- determined based on whether or not connection is inside
|
||||
- transaction.
|
||||
- --thread-pool-size=#
|
||||
- Number of thread groups in the pool. This parameter is
|
||||
- roughly equivalent to maximum number of concurrently
|
||||
- executing threads (threads in a waiting state do not
|
||||
- count as executing).
|
||||
- --thread-pool-stall-limit=#
|
||||
- Maximum query execution time in milliseconds,before an
|
||||
- executing non-yielding thread is considered stalled.If a
|
||||
- worker thread is stalled, additional worker thread may be
|
||||
- created to handle remaining clients.
|
||||
--thread-stack=# The stack size for each thread
|
||||
--time-format=name The TIME format (ignored)
|
||||
--tls-version=name TLS protocol version for secure connections.. Any
|
||||
@@ -1788,7 +1753,6 @@ slow-query-log FALSE
|
||||
sort-buffer-size 2097152
|
||||
sql-mode STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
|
||||
sql-safe-updates FALSE
|
||||
-stack-trace TRUE
|
||||
standard-compliant-cte TRUE
|
||||
stored-program-cache 256
|
||||
strict-password-validation TRUE
|
||||
@@ -1807,14 +1771,6 @@ tcp-keepalive-probes 0
|
||||
tcp-keepalive-time 0
|
||||
tcp-nodelay TRUE
|
||||
thread-cache-size 151
|
||||
-thread-pool-dedicated-listener FALSE
|
||||
-thread-pool-exact-stats FALSE
|
||||
-thread-pool-idle-timeout 60
|
||||
-thread-pool-max-threads 65536
|
||||
-thread-pool-oversubscribe 3
|
||||
-thread-pool-prio-kickup-timer 1000
|
||||
-thread-pool-priority auto
|
||||
-thread-pool-stall-limit 500
|
||||
thread-stack 299008
|
||||
time-format %H:%i:%s
|
||||
tmp-disk-table-size 18446744073709551615
|
|
@ -1 +1 @@
|
|||
--skip-stack-trace --skip-core-file
|
||||
--loose-skip-stack-trace --skip-core-file
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# uint global
|
||||
--source include/not_windows.inc
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_aix.inc
|
||||
SET @start_global_value = @@global.thread_pool_idle_timeout;
|
||||
|
||||
#
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
--source include/not_windows.inc
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_aix.inc
|
||||
|
||||
SET @global=@@global.thread_pool_idle_timeout;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# uint global
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_aix.inc
|
||||
SET @start_global_value = @@global.thread_pool_max_threads;
|
||||
|
||||
#
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# uint global
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_aix.inc
|
||||
|
||||
SET @global=@@global.thread_pool_max_threads;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# uint global
|
||||
--source include/not_embedded.inc
|
||||
--source include/windows.inc
|
||||
--source include/not_aix.inc
|
||||
SET @start_global_value = @@global.thread_pool_min_threads;
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# uint global
|
||||
--source include/not_windows.inc
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_aix.inc
|
||||
SET @start_global_value = @@global.thread_pool_oversubscribe;
|
||||
|
||||
#
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
--source include/not_windows.inc
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_aix.inc
|
||||
|
||||
SET @global=@@global.thread_pool_oversubscribe;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# uint global
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_aix.inc
|
||||
SET @start_global_value = @@global.thread_pool_stall_limit;
|
||||
|
||||
#
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# uint global
|
||||
--source include/not_embedded.inc
|
||||
--source include/not_aix.inc
|
||||
|
||||
SET @global=@@global.thread_pool_stall_limit;
|
||||
|
||||
|
|
|
@ -179,14 +179,26 @@ my_bool my_net_init(NET *net, Vio *vio, void *thd, uint my_flags)
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Allocate and assign new net buffer
|
||||
|
||||
@note In case of error the old buffer left
|
||||
|
||||
@retval TRUE error
|
||||
@retval FALSE success
|
||||
*/
|
||||
|
||||
my_bool net_allocate_new_packet(NET *net, void *thd, uint my_flags)
|
||||
{
|
||||
uchar *tmp;
|
||||
DBUG_ENTER("net_allocate_new_packet");
|
||||
if (!(net->buff=(uchar*) my_malloc(key_memory_NET_buff,
|
||||
(size_t) net->max_packet +
|
||||
NET_HEADER_SIZE + COMP_HEADER_SIZE + 1,
|
||||
MYF(MY_WME | my_flags))))
|
||||
if (!(tmp= (uchar*) my_malloc(key_memory_NET_buff,
|
||||
(size_t) net->max_packet +
|
||||
NET_HEADER_SIZE + COMP_HEADER_SIZE + 1,
|
||||
MYF(MY_WME | my_flags))))
|
||||
DBUG_RETURN(1);
|
||||
net->buff= tmp;
|
||||
net->buff_end=net->buff+net->max_packet;
|
||||
net->write_pos=net->read_pos = net->buff;
|
||||
DBUG_RETURN(0);
|
||||
|
|
|
@ -597,6 +597,7 @@ void Protocol::end_statement()
|
|||
thd->get_stmt_da()->get_sqlstate());
|
||||
break;
|
||||
case Diagnostics_area::DA_EOF:
|
||||
case Diagnostics_area::DA_EOF_BULK:
|
||||
error= send_eof(thd->server_status,
|
||||
thd->get_stmt_da()->statement_warn_count());
|
||||
break;
|
||||
|
|
|
@ -709,7 +709,12 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
|
|||
!table->prepare_triggers_for_delete_stmt_or_event())
|
||||
will_batch= !table->file->start_bulk_delete();
|
||||
|
||||
if (returning)
|
||||
/*
|
||||
thd->get_stmt_da()->is_set() means first iteration of prepared statement
|
||||
with array binding operation execution (non optimized so it is not
|
||||
INSERT)
|
||||
*/
|
||||
if (returning && !thd->get_stmt_da()->is_set())
|
||||
{
|
||||
if (result->send_result_set_metadata(returning->item_list,
|
||||
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
|
||||
|
|
|
@ -371,7 +371,7 @@ Diagnostics_area::set_eof_status(THD *thd)
|
|||
{
|
||||
DBUG_ENTER("set_eof_status");
|
||||
/* Only allowed to report eof if has not yet reported an error */
|
||||
DBUG_ASSERT(! is_set());
|
||||
DBUG_ASSERT(!is_set() || (m_status == DA_EOF_BULK && is_bulk_op()));
|
||||
/*
|
||||
In production, refuse to overwrite an error or a custom response
|
||||
with an EOF packet.
|
||||
|
@ -384,11 +384,23 @@ Diagnostics_area::set_eof_status(THD *thd)
|
|||
number of warnings, since they are not available to the client
|
||||
anyway.
|
||||
*/
|
||||
m_statement_warn_count= (thd->spcont ?
|
||||
0 :
|
||||
current_statement_warn_count());
|
||||
if (m_status == DA_EOF_BULK)
|
||||
{
|
||||
if (!thd->spcont)
|
||||
m_statement_warn_count+= current_statement_warn_count();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (thd->spcont)
|
||||
{
|
||||
m_statement_warn_count= 0;
|
||||
m_affected_rows= 0;
|
||||
}
|
||||
else
|
||||
m_statement_warn_count= current_statement_warn_count();
|
||||
m_status= (is_bulk_op() ? DA_EOF_BULK : DA_EOF);
|
||||
}
|
||||
|
||||
m_status= DA_EOF;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
|
|
@ -970,6 +970,8 @@ public:
|
|||
DA_EOF,
|
||||
/** Set whenever one calls my_ok() in PS bulk mode. */
|
||||
DA_OK_BULK,
|
||||
/** Set whenever one calls my_eof() in PS bulk mode. */
|
||||
DA_EOF_BULK,
|
||||
/** Set whenever one calls my_error() or my_message(). */
|
||||
DA_ERROR,
|
||||
/** Set in case of a custom response, such as one from COM_STMT_PREPARE. */
|
||||
|
@ -1029,8 +1031,11 @@ public:
|
|||
enum_diagnostics_status status() const { return m_status; }
|
||||
|
||||
const char *message() const
|
||||
{ DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK ||
|
||||
m_status == DA_OK_BULK); return m_message; }
|
||||
{
|
||||
DBUG_ASSERT(m_status == DA_ERROR || m_status == DA_OK ||
|
||||
m_status == DA_OK_BULK || m_status == DA_EOF_BULK);
|
||||
return m_message;
|
||||
}
|
||||
|
||||
|
||||
uint sql_errno() const
|
||||
|
@ -1057,7 +1062,7 @@ public:
|
|||
uint statement_warn_count() const
|
||||
{
|
||||
DBUG_ASSERT(m_status == DA_OK || m_status == DA_OK_BULK ||
|
||||
m_status == DA_EOF);
|
||||
m_status == DA_EOF ||m_status == DA_EOF_BULK );
|
||||
return m_statement_warn_count;
|
||||
}
|
||||
|
||||
|
|
|
@ -710,6 +710,7 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
|
|||
Name_resolution_context *context;
|
||||
Name_resolution_context_state ctx_state;
|
||||
SELECT_LEX *returning= thd->lex->has_returning() ? thd->lex->returning() : 0;
|
||||
unsigned char *readbuff= NULL;
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
char *query= thd->query();
|
||||
|
@ -786,7 +787,25 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list,
|
|||
|
||||
/* Prepares LEX::returing_list if it is not empty */
|
||||
if (returning)
|
||||
{
|
||||
result->prepare(returning->item_list, NULL);
|
||||
if (thd->is_bulk_op())
|
||||
{
|
||||
/*
|
||||
It is RETURNING which needs network buffer to write result set and
|
||||
it is array binfing which need network buffer to read parameters.
|
||||
So we allocate yet another network buffer.
|
||||
The old buffer will be freed at the end of operation.
|
||||
*/
|
||||
DBUG_ASSERT(thd->protocol == &thd->protocol_binary);
|
||||
readbuff= thd->net.buff; // old buffer
|
||||
if (net_allocate_new_packet(&thd->net, thd, MYF(MY_THREAD_SPECIFIC)))
|
||||
{
|
||||
readbuff= NULL; // failure, net_allocate_new_packet keeps old buffer
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context= &thd->lex->first_select_lex()->context;
|
||||
/*
|
||||
|
@ -1322,7 +1341,8 @@ values_loop_end:
|
|||
thd->lex->current_select->save_leaf_tables(thd);
|
||||
thd->lex->current_select->first_cond_optimization= 0;
|
||||
}
|
||||
|
||||
if (readbuff)
|
||||
my_free(readbuff);
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
abort:
|
||||
|
@ -1336,6 +1356,8 @@ abort:
|
|||
if (!joins_freed)
|
||||
free_underlaid_joins(thd, thd->lex->first_select_lex());
|
||||
thd->abort_on_warning= 0;
|
||||
if (readbuff)
|
||||
my_free(readbuff);
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
|
||||
|
|
|
@ -903,6 +903,9 @@ static bool insert_bulk_params(Prepared_statement *stmt,
|
|||
case STMT_INDICATOR_IGNORE:
|
||||
param->set_ignore();
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -4680,6 +4683,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
|
|||
uchar *packet_end_arg)
|
||||
{
|
||||
Reprepare_observer reprepare_observer;
|
||||
unsigned char *readbuff= NULL;
|
||||
bool error= 0;
|
||||
packet= packet_arg;
|
||||
packet_end= packet_end_arg;
|
||||
|
@ -4693,24 +4697,37 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
|
|||
if (state == Query_arena::STMT_ERROR)
|
||||
{
|
||||
my_message(last_errno, last_error, MYF(0));
|
||||
thd->set_bulk_execution(0);
|
||||
return TRUE;
|
||||
goto err;
|
||||
}
|
||||
/* Check for non zero parameter count*/
|
||||
if (param_count == 0)
|
||||
{
|
||||
DBUG_PRINT("error", ("Statement with no parameters for bulk execution."));
|
||||
my_error(ER_UNSUPPORTED_PS, MYF(0));
|
||||
thd->set_bulk_execution(0);
|
||||
return TRUE;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(sql_command_flags[lex->sql_command] & CF_PS_ARRAY_BINDING_SAFE))
|
||||
{
|
||||
DBUG_PRINT("error", ("Command is not supported in bulk execution."));
|
||||
my_error(ER_UNSUPPORTED_PS, MYF(0));
|
||||
thd->set_bulk_execution(0);
|
||||
return TRUE;
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
Here second buffer for not optimized commands,
|
||||
optimized commands do it inside thier internal loop.
|
||||
*/
|
||||
if (!(sql_command_flags[lex->sql_command] & CF_PS_ARRAY_BINDING_OPTIMIZED) &&
|
||||
this->lex->has_returning())
|
||||
{
|
||||
// Above check can be true for SELECT in future
|
||||
DBUG_ASSERT(lex->sql_command != SQLCOM_SELECT);
|
||||
readbuff= thd->net.buff; // old buffer
|
||||
if (net_allocate_new_packet(&thd->net, thd, MYF(MY_THREAD_SPECIFIC)))
|
||||
{
|
||||
readbuff= NULL; // failure, net_allocate_new_packet keeps old buffer
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
|
@ -4722,9 +4739,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
|
|||
{
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0),
|
||||
"mysqld_stmt_bulk_execute");
|
||||
reset_stmt_params(this);
|
||||
thd->set_bulk_execution(0);
|
||||
return true;
|
||||
goto err;
|
||||
}
|
||||
read_types= FALSE;
|
||||
|
||||
|
@ -4741,8 +4756,7 @@ Prepared_statement::execute_bulk_loop(String *expanded_query,
|
|||
{
|
||||
if (set_bulk_parameters(TRUE))
|
||||
{
|
||||
thd->set_bulk_execution(0);
|
||||
return true;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4806,8 +4820,16 @@ reexecute:
|
|||
}
|
||||
reset_stmt_params(this);
|
||||
thd->set_bulk_execution(0);
|
||||
|
||||
if (readbuff)
|
||||
my_free(readbuff);
|
||||
return error;
|
||||
|
||||
err:
|
||||
reset_stmt_params(this);
|
||||
thd->set_bulk_execution(0);
|
||||
if (readbuff)
|
||||
my_free(readbuff);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -190,6 +190,7 @@ static int join_read_system(JOIN_TAB *tab);
|
|||
static int join_read_const(JOIN_TAB *tab);
|
||||
static int join_read_key(JOIN_TAB *tab);
|
||||
static void join_read_key_unlock_row(st_join_table *tab);
|
||||
static void join_const_unlock_row(JOIN_TAB *tab);
|
||||
static int join_read_always_key(JOIN_TAB *tab);
|
||||
static int join_read_last_key(JOIN_TAB *tab);
|
||||
static int join_no_more_records(READ_RECORD *info);
|
||||
|
@ -11189,8 +11190,12 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
|
|||
else
|
||||
j->type=JT_EQ_REF;
|
||||
|
||||
j->read_record.unlock_row= (j->type == JT_EQ_REF)?
|
||||
join_read_key_unlock_row : rr_unlock_row;
|
||||
if (j->type == JT_EQ_REF)
|
||||
j->read_record.unlock_row= join_read_key_unlock_row;
|
||||
else if (j->type == JT_CONST)
|
||||
j->read_record.unlock_row= join_const_unlock_row;
|
||||
else
|
||||
j->read_record.unlock_row= rr_unlock_row;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@ -13455,6 +13460,7 @@ make_join_readinfo(JOIN *join, ulonglong options, uint no_jbuf_after)
|
|||
/* Only happens with outer joins */
|
||||
tab->read_first_record= tab->type == JT_SYSTEM ? join_read_system
|
||||
: join_read_const;
|
||||
tab->read_record.unlock_row= join_const_unlock_row;
|
||||
if (!(table->covering_keys.is_set(tab->ref.key) && !table->no_keyread) &&
|
||||
(!jcl || jcl > 4) && !tab->ref.is_access_triggered())
|
||||
push_index_cond(tab, tab->ref.key);
|
||||
|
@ -21726,6 +21732,19 @@ join_read_key_unlock_row(st_join_table *tab)
|
|||
tab->ref.use_count--;
|
||||
}
|
||||
|
||||
/**
|
||||
Rows from const tables are read once but potentially used
|
||||
multiple times during execution of a query.
|
||||
Ensure such rows are never unlocked during query execution.
|
||||
*/
|
||||
|
||||
void
|
||||
join_const_unlock_row(JOIN_TAB *tab)
|
||||
{
|
||||
DBUG_ASSERT(tab->type == JT_CONST);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ref access method implementation: "read_first" function
|
||||
|
||||
|
@ -24178,8 +24197,12 @@ check_reverse_order:
|
|||
else if (select && select->quick)
|
||||
select->quick->need_sorted_output();
|
||||
|
||||
tab->read_record.unlock_row= (tab->type == JT_EQ_REF) ?
|
||||
join_read_key_unlock_row : rr_unlock_row;
|
||||
if (tab->type == JT_EQ_REF)
|
||||
tab->read_record.unlock_row= join_read_key_unlock_row;
|
||||
else if (tab->type == JT_CONST)
|
||||
tab->read_record.unlock_row= join_const_unlock_row;
|
||||
else
|
||||
tab->read_record.unlock_row= rr_unlock_row;
|
||||
|
||||
} // QEP has been modified
|
||||
|
||||
|
|
|
@ -674,8 +674,7 @@ void buf_dblwr_t::flush_buffered_writes_completed(const IORequest &request)
|
|||
static_cast<const byte*>(frame)));
|
||||
ut_ad(lsn);
|
||||
ut_ad(lsn >= bpage->oldest_modification());
|
||||
if (lsn > log_sys.get_flushed_lsn())
|
||||
log_write_up_to(lsn, true);
|
||||
log_write_up_to(lsn, true);
|
||||
e.request.node->space->io(e.request, bpage->physical_offset(), e_size,
|
||||
frame, bpage);
|
||||
}
|
||||
|
|
|
@ -15432,7 +15432,7 @@ ha_innobase::extra(
|
|||
case HA_EXTRA_END_ALTER_COPY:
|
||||
m_prebuilt->table->skip_alter_undo = 0;
|
||||
if (!m_prebuilt->table->is_temporary()) {
|
||||
log_write_up_to(LSN_MAX, true);
|
||||
log_buffer_flush_to_disk();
|
||||
}
|
||||
break;
|
||||
default:/* Do nothing */
|
||||
|
|
|
@ -705,15 +705,6 @@ public:
|
|||
|
||||
/** Shut down the redo log subsystem. */
|
||||
void close();
|
||||
|
||||
/** Initiate a write of the log buffer to the file if needed.
|
||||
@param flush whether to initiate a durable write */
|
||||
inline void initiate_write(bool flush)
|
||||
{
|
||||
const lsn_t lsn= get_lsn();
|
||||
if (!flush || get_flushed_lsn() < lsn)
|
||||
log_write_up_to(lsn, flush);
|
||||
}
|
||||
};
|
||||
|
||||
/** Redo log system */
|
||||
|
|
|
@ -791,6 +791,7 @@ void log_write_up_to(lsn_t lsn, bool flush_to_disk, bool rotate_key,
|
|||
{
|
||||
ut_ad(!srv_read_only_mode);
|
||||
ut_ad(!rotate_key || flush_to_disk);
|
||||
ut_ad(lsn != LSN_MAX);
|
||||
|
||||
if (recv_no_ibuf_operations)
|
||||
{
|
||||
|
|
|
@ -702,7 +702,7 @@ static lsn_t log_reserve_and_open(size_t len)
|
|||
DEBUG_SYNC_C("log_buf_size_exceeded");
|
||||
|
||||
/* Not enough free space, do a write of the log buffer */
|
||||
log_sys.initiate_write(false);
|
||||
log_write_up_to(log_sys.get_lsn(), false);
|
||||
|
||||
srv_stats.log_waits.inc();
|
||||
|
||||
|
|
|
@ -2672,7 +2672,7 @@ rollback:
|
|||
ALTER TABLE...DISCARD TABLESPACE operation altogether. */
|
||||
err= row_discard_tablespace(trx, table);
|
||||
DBUG_EXECUTE_IF("ib_discard_before_commit_crash",
|
||||
log_write_up_to(LSN_MAX, true); DBUG_SUICIDE(););
|
||||
log_buffer_flush_to_disk(); DBUG_SUICIDE(););
|
||||
/* FTS_ tables may be deleted */
|
||||
std::vector<pfs_os_file_t> deleted;
|
||||
trx->commit(deleted);
|
||||
|
|
|
@ -1477,7 +1477,7 @@ static void srv_sync_log_buffer_in_background()
|
|||
srv_main_thread_op_info = "flushing log";
|
||||
if (difftime(current_time, srv_last_log_flush_time)
|
||||
>= srv_flush_log_at_timeout) {
|
||||
log_sys.initiate_write(true);
|
||||
log_buffer_flush_to_disk();
|
||||
srv_last_log_flush_time = current_time;
|
||||
srv_log_writes_and_flush++;
|
||||
}
|
||||
|
|
|
@ -328,7 +328,7 @@ static dberr_t create_log_file(bool create_new_db, lsn_t lsn,
|
|||
mysql_mutex_unlock(&log_sys.mutex);
|
||||
|
||||
log_make_checkpoint();
|
||||
log_write_up_to(LSN_MAX, true);
|
||||
log_buffer_flush_to_disk();
|
||||
|
||||
return DB_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -777,7 +777,7 @@ not_free:
|
|||
|
||||
DBUG_EXECUTE_IF("ib_undo_trunc",
|
||||
ib::info() << "ib_undo_trunc";
|
||||
log_write_up_to(LSN_MAX, true);
|
||||
log_buffer_flush_to_disk();
|
||||
DBUG_SUICIDE(););
|
||||
|
||||
for (auto& rseg : trx_sys.rseg_array) {
|
||||
|
|
|
@ -5466,6 +5466,7 @@ void pfs_end_statement_v1(PSI_statement_locker *locker, void *stmt_da)
|
|||
switch(da->status())
|
||||
{
|
||||
case Diagnostics_area::DA_OK_BULK:
|
||||
case Diagnostics_area::DA_EOF_BULK:
|
||||
case Diagnostics_area::DA_EMPTY:
|
||||
break;
|
||||
case Diagnostics_area::DA_OK:
|
||||
|
@ -5706,6 +5707,7 @@ void pfs_end_statement_v1(PSI_statement_locker *locker, void *stmt_da)
|
|||
switch (da->status())
|
||||
{
|
||||
case Diagnostics_area::DA_OK_BULK:
|
||||
case Diagnostics_area::DA_EOF_BULK:
|
||||
case Diagnostics_area::DA_EMPTY:
|
||||
break;
|
||||
case Diagnostics_area::DA_OK:
|
||||
|
|
|
@ -20547,6 +20547,178 @@ static void test_bulk_replace()
|
|||
rc= mysql_query(mysql, "DROP TABLE t1");
|
||||
myquery(rc);
|
||||
}
|
||||
|
||||
|
||||
static void test_bulk_insert_returning()
|
||||
{
|
||||
int rc;
|
||||
MYSQL_STMT *stmt;
|
||||
MYSQL_BIND bind[2], res_bind[2];
|
||||
MYSQL_ROW row;
|
||||
MYSQL_RES *result;
|
||||
int i,
|
||||
id[]= {1, 2, 3, 4},
|
||||
val[]= {1, 1, 1, 1},
|
||||
count= sizeof(id)/sizeof(id[0]);
|
||||
unsigned long length[2];
|
||||
my_bool is_null[2];
|
||||
my_bool error[2];
|
||||
int32 res[2];
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql,
|
||||
"CREATE TABLE t1 (id int not null primary key, active int)");
|
||||
myquery(rc);
|
||||
|
||||
stmt= mysql_stmt_init(mysql);
|
||||
rc= mysql_stmt_prepare(stmt,
|
||||
"insert into t1 values (?, ?) returning id, active",
|
||||
-1);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
memset(bind, 0, sizeof(bind));
|
||||
bind[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[0].buffer = (void *)id;
|
||||
bind[0].buffer_length = 0;
|
||||
bind[1].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[1].buffer = (void *)val;
|
||||
bind[1].buffer_length = 0;
|
||||
|
||||
mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, (void*)&count);
|
||||
rc= mysql_stmt_bind_param(stmt, bind);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
myquery(rc);
|
||||
|
||||
memset(res_bind, 0, sizeof(res_bind));
|
||||
for (i= 0; i < 2; i++)
|
||||
{
|
||||
res_bind[i].buffer_type= MYSQL_TYPE_LONG;
|
||||
res_bind[i].buffer= (char *)&res[i];
|
||||
res_bind[i].is_null= &is_null[i];
|
||||
res_bind[i].length= &length[i];
|
||||
res_bind[i].error= &error[i];
|
||||
}
|
||||
rc= mysql_stmt_bind_result(stmt, res_bind);
|
||||
myquery(rc);
|
||||
rc= mysql_stmt_store_result(stmt);
|
||||
myquery(rc);
|
||||
|
||||
i= 0;
|
||||
while (!mysql_stmt_fetch(stmt))
|
||||
{
|
||||
i++;
|
||||
DIE_IF(is_null[0] || is_null[1]);
|
||||
DIE_IF(res[0] != i);
|
||||
DIE_IF(res[1] != 1);
|
||||
}
|
||||
DIE_IF(i != 4);
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
|
||||
rc= mysql_query(mysql, "SELECT id,active FROM t1");
|
||||
myquery(rc);
|
||||
|
||||
result= mysql_store_result(mysql);
|
||||
mytest(result);
|
||||
|
||||
i= 0;
|
||||
while ((row= mysql_fetch_row(result)))
|
||||
{
|
||||
i++;
|
||||
DIE_IF(atoi(row[0]) != i);
|
||||
DIE_IF(atoi(row[1]) != 1);
|
||||
}
|
||||
DIE_IF(i != 4);
|
||||
mysql_free_result(result);
|
||||
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE t1");
|
||||
myquery(rc);
|
||||
}
|
||||
|
||||
static void test_bulk_delete_returning()
|
||||
{
|
||||
int rc;
|
||||
MYSQL_STMT *stmt;
|
||||
MYSQL_BIND bind[2], res_bind[2];
|
||||
MYSQL_ROW row;
|
||||
MYSQL_RES *result;
|
||||
int i,
|
||||
id[]= {1, 2, 3, 4},
|
||||
count= sizeof(id)/sizeof(id[0]);
|
||||
unsigned long length[1];
|
||||
my_bool is_null[1];
|
||||
my_bool error[1];
|
||||
int32 res[1];
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "CREATE TABLE t1 (id int not null primary key)");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "insert into t1 values (1), (2), (3), (4)");
|
||||
myquery(rc);
|
||||
verify_affected_rows(4);
|
||||
|
||||
stmt= mysql_stmt_init(mysql);
|
||||
rc= mysql_stmt_prepare(stmt, "DELETE FROM t1 WHERE id=? RETURNING id", -1);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
memset(bind, 0, sizeof(bind));
|
||||
bind[0].buffer_type = MYSQL_TYPE_LONG;
|
||||
bind[0].buffer = (void *)id;
|
||||
bind[0].buffer_length = 0;
|
||||
|
||||
mysql_stmt_attr_set(stmt, STMT_ATTR_ARRAY_SIZE, (void*)&count);
|
||||
rc= mysql_stmt_bind_param(stmt, bind);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
myquery(rc);
|
||||
|
||||
memset(res_bind, 0, sizeof(res_bind));
|
||||
res_bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||
res_bind[0].buffer= (char *)&res[0];
|
||||
res_bind[0].is_null= &is_null[0];
|
||||
res_bind[0].length= &length[0];
|
||||
res_bind[0].error= &error[0];
|
||||
rc= mysql_stmt_bind_result(stmt, res_bind);
|
||||
myquery(rc);
|
||||
rc= mysql_stmt_store_result(stmt);
|
||||
myquery(rc);
|
||||
|
||||
i= 0;
|
||||
while (!mysql_stmt_fetch(stmt))
|
||||
{
|
||||
i++;
|
||||
DIE_IF(is_null[0]);
|
||||
DIE_IF(res[0] != i);
|
||||
}
|
||||
DIE_IF(i != 4);
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
|
||||
rc= mysql_query(mysql, "SELECT id FROM t1");
|
||||
myquery(rc);
|
||||
|
||||
result= mysql_store_result(mysql);
|
||||
mytest(result);
|
||||
|
||||
i= 0;
|
||||
while ((row= mysql_fetch_row(result)))
|
||||
{
|
||||
i++;
|
||||
printf("\nResult (SHOULD NOT BE HERE!!!) %d %s \n", i, row[0]);
|
||||
}
|
||||
DIE_IF(i != 0 );
|
||||
mysql_free_result(result);
|
||||
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE t1");
|
||||
myquery(rc);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -21556,6 +21728,8 @@ static struct my_tests_st my_tests[]= {
|
|||
{ "test_bulk_autoinc", test_bulk_autoinc},
|
||||
{ "test_bulk_delete", test_bulk_delete },
|
||||
{ "test_bulk_replace", test_bulk_replace },
|
||||
{ "test_bulk_insert_returning", test_bulk_insert_returning },
|
||||
{ "test_bulk_delete_returning", test_bulk_delete_returning },
|
||||
#endif
|
||||
{ "test_ps_params_in_ctes", test_ps_params_in_ctes },
|
||||
{ "test_explain_meta", test_explain_meta },
|
||||
|
|
Loading…
Reference in a new issue