summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladislav Vaintroub <wlad@mariadb.com>2021-07-16 22:12:09 +0200
committerVladislav Vaintroub <wlad@mariadb.com>2021-07-16 22:12:09 +0200
commite7f4daf88c4348bb018d04d298b104617554f310 (patch)
tree8cb54b53e75db7fa848ad93c4a3640736116c97e
parent461cac890170c8a903972d4c8e6f4576cf8558e6 (diff)
parentfc2ec25733c6f1a305bf14df960ee7a02b48ef2c (diff)
downloadmariadb-git-e7f4daf88c4348bb018d04d298b104617554f310.tar.gz
merge 10.5 to 10.6
-rw-r--r--mysql-test/include/have_pool_of_threads.inc3
-rw-r--r--mysql-test/include/maybe_pool_of_threads.inc1
-rw-r--r--mysql-test/main/join_outer_innodb.result19
-rw-r--r--mysql-test/main/join_outer_innodb.test17
-rw-r--r--mysql-test/main/mysqld--defaults-file.test1
-rw-r--r--mysql-test/main/mysqld--help,aix.rdiff76
-rw-r--r--mysql-test/suite/innodb/t/innodb_bug53756-master.opt2
-rw-r--r--mysql-test/suite/sys_vars/t/thread_pool_idle_timeout_basic.test1
-rw-r--r--mysql-test/suite/sys_vars/t/thread_pool_idle_timeout_grant.test1
-rw-r--r--mysql-test/suite/sys_vars/t/thread_pool_max_threads_basic.test1
-rw-r--r--mysql-test/suite/sys_vars/t/thread_pool_max_threads_grant.test1
-rw-r--r--mysql-test/suite/sys_vars/t/thread_pool_min_threads_basic.test1
-rw-r--r--mysql-test/suite/sys_vars/t/thread_pool_oversubscribe_basic.test1
-rw-r--r--mysql-test/suite/sys_vars/t/thread_pool_oversubscribe_grant.test1
-rw-r--r--mysql-test/suite/sys_vars/t/thread_pool_stall_limit_basic.test1
-rw-r--r--mysql-test/suite/sys_vars/t/thread_pool_stall_limit_grant.test1
-rw-r--r--sql/net_serv.cc20
-rw-r--r--sql/protocol.cc1
-rw-r--r--sql/sql_delete.cc7
-rw-r--r--sql/sql_error.cc22
-rw-r--r--sql/sql_error.h11
-rw-r--r--sql/sql_insert.cc24
-rw-r--r--sql/sql_prepare.cc46
-rw-r--r--sql/sql_select.cc31
-rw-r--r--storage/innobase/buf/buf0dblwr.cc3
-rw-r--r--storage/innobase/handler/ha_innodb.cc2
-rw-r--r--storage/innobase/include/log0log.h9
-rw-r--r--storage/innobase/log/log0log.cc1
-rw-r--r--storage/innobase/mtr/mtr0mtr.cc2
-rw-r--r--storage/innobase/row/row0mysql.cc2
-rw-r--r--storage/innobase/srv/srv0srv.cc2
-rw-r--r--storage/innobase/srv/srv0start.cc2
-rw-r--r--storage/innobase/trx/trx0purge.cc2
-rw-r--r--storage/perfschema/pfs.cc2
-rw-r--r--tests/mysql_client_test.c174
35 files changed, 442 insertions, 49 deletions
diff --git a/mysql-test/include/have_pool_of_threads.inc b/mysql-test/include/have_pool_of_threads.inc
index 432c6216804..62460127d88 100644
--- a/mysql-test/include/have_pool_of_threads.inc
+++ b/mysql-test/include/have_pool_of_threads.inc
@@ -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;
diff --git a/mysql-test/include/maybe_pool_of_threads.inc b/mysql-test/include/maybe_pool_of_threads.inc
index 51a179b4426..d25e3864333 100644
--- a/mysql-test/include/maybe_pool_of_threads.inc
+++ b/mysql-test/include/maybe_pool_of_threads.inc
@@ -1 +1,2 @@
# run with and without threadpool
+--source include/not_aix.inc
diff --git a/mysql-test/main/join_outer_innodb.result b/mysql-test/main/join_outer_innodb.result
index 0b34a399d77..09a37a29702 100644
--- a/mysql-test/main/join_outer_innodb.result
+++ b/mysql-test/main/join_outer_innodb.result
@@ -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;
diff --git a/mysql-test/main/join_outer_innodb.test b/mysql-test/main/join_outer_innodb.test
index c26cd62fbc7..6b332f3d155 100644
--- a/mysql-test/main/join_outer_innodb.test
+++ b/mysql-test/main/join_outer_innodb.test
@@ -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;
+
diff --git a/mysql-test/main/mysqld--defaults-file.test b/mysql-test/main/mysqld--defaults-file.test
index 4859cc17b42..9ca427568ef 100644
--- a/mysql-test/main/mysqld--defaults-file.test
+++ b/mysql-test/main/mysqld--defaults-file.test
@@ -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
diff --git a/mysql-test/main/mysqld--help,aix.rdiff b/mysql-test/main/mysqld--help,aix.rdiff
index e69de29bb2d..972f8b1844b 100644
--- a/mysql-test/main/mysqld--help,aix.rdiff
+++ b/mysql-test/main/mysqld--help,aix.rdiff
@@ -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
diff --git a/mysql-test/suite/innodb/t/innodb_bug53756-master.opt b/mysql-test/suite/innodb/t/innodb_bug53756-master.opt
index 425fda95086..590d44a6d12 100644
--- a/mysql-test/suite/innodb/t/innodb_bug53756-master.opt
+++ b/mysql-test/suite/innodb/t/innodb_bug53756-master.opt
@@ -1 +1 @@
---skip-stack-trace --skip-core-file
+--loose-skip-stack-trace --skip-core-file
diff --git a/mysql-test/suite/sys_vars/t/thread_pool_idle_timeout_basic.test b/mysql-test/suite/sys_vars/t/thread_pool_idle_timeout_basic.test
index 4afcc0379f0..b06a5069514 100644
--- a/mysql-test/suite/sys_vars/t/thread_pool_idle_timeout_basic.test
+++ b/mysql-test/suite/sys_vars/t/thread_pool_idle_timeout_basic.test
@@ -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;
#
diff --git a/mysql-test/suite/sys_vars/t/thread_pool_idle_timeout_grant.test b/mysql-test/suite/sys_vars/t/thread_pool_idle_timeout_grant.test
index 71b007bde23..8f5f2491e12 100644
--- a/mysql-test/suite/sys_vars/t/thread_pool_idle_timeout_grant.test
+++ b/mysql-test/suite/sys_vars/t/thread_pool_idle_timeout_grant.test
@@ -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;
diff --git a/mysql-test/suite/sys_vars/t/thread_pool_max_threads_basic.test b/mysql-test/suite/sys_vars/t/thread_pool_max_threads_basic.test
index 3d5cd5f5198..392dbd3a145 100644
--- a/mysql-test/suite/sys_vars/t/thread_pool_max_threads_basic.test
+++ b/mysql-test/suite/sys_vars/t/thread_pool_max_threads_basic.test
@@ -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;
#
diff --git a/mysql-test/suite/sys_vars/t/thread_pool_max_threads_grant.test b/mysql-test/suite/sys_vars/t/thread_pool_max_threads_grant.test
index 29a9ac42ea0..299d5ff4f44 100644
--- a/mysql-test/suite/sys_vars/t/thread_pool_max_threads_grant.test
+++ b/mysql-test/suite/sys_vars/t/thread_pool_max_threads_grant.test
@@ -1,5 +1,6 @@
# uint global
--source include/not_embedded.inc
+--source include/not_aix.inc
SET @global=@@global.thread_pool_max_threads;
diff --git a/mysql-test/suite/sys_vars/t/thread_pool_min_threads_basic.test b/mysql-test/suite/sys_vars/t/thread_pool_min_threads_basic.test
index 131fbe98502..1447c83d39c 100644
--- a/mysql-test/suite/sys_vars/t/thread_pool_min_threads_basic.test
+++ b/mysql-test/suite/sys_vars/t/thread_pool_min_threads_basic.test
@@ -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;
#
diff --git a/mysql-test/suite/sys_vars/t/thread_pool_oversubscribe_basic.test b/mysql-test/suite/sys_vars/t/thread_pool_oversubscribe_basic.test
index 74f0f5e6ea7..43817febafd 100644
--- a/mysql-test/suite/sys_vars/t/thread_pool_oversubscribe_basic.test
+++ b/mysql-test/suite/sys_vars/t/thread_pool_oversubscribe_basic.test
@@ -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;
#
diff --git a/mysql-test/suite/sys_vars/t/thread_pool_oversubscribe_grant.test b/mysql-test/suite/sys_vars/t/thread_pool_oversubscribe_grant.test
index cbffb94c297..f3a96c69e8a 100644
--- a/mysql-test/suite/sys_vars/t/thread_pool_oversubscribe_grant.test
+++ b/mysql-test/suite/sys_vars/t/thread_pool_oversubscribe_grant.test
@@ -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;
diff --git a/mysql-test/suite/sys_vars/t/thread_pool_stall_limit_basic.test b/mysql-test/suite/sys_vars/t/thread_pool_stall_limit_basic.test
index 1ab27907535..2d1dc59476c 100644
--- a/mysql-test/suite/sys_vars/t/thread_pool_stall_limit_basic.test
+++ b/mysql-test/suite/sys_vars/t/thread_pool_stall_limit_basic.test
@@ -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;
#
diff --git a/mysql-test/suite/sys_vars/t/thread_pool_stall_limit_grant.test b/mysql-test/suite/sys_vars/t/thread_pool_stall_limit_grant.test
index 8c0908fe2c0..ae0ed8a785b 100644
--- a/mysql-test/suite/sys_vars/t/thread_pool_stall_limit_grant.test
+++ b/mysql-test/suite/sys_vars/t/thread_pool_stall_limit_grant.test
@@ -1,5 +1,6 @@
# uint global
--source include/not_embedded.inc
+--source include/not_aix.inc
SET @global=@@global.thread_pool_stall_limit;
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 8b0f1eed46d..39b4290a161 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -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);
diff --git a/sql/protocol.cc b/sql/protocol.cc
index c0a5f2327a0..1aea0dae3de 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -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;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 34fa14d4324..0a2db2ea93a 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -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))
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index bb47502b3ce..cef9e6cec00 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -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;
}
diff --git a/sql/sql_error.h b/sql/sql_error.h
index a3782048c79..6b0d4d7749c 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -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;
}
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 24ffad7368a..e258d46f78a 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -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);
}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 2f5470db123..e7d02aaeb0d 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -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;
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 5a02218bb4a..08de2565caf 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -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
diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc
index 44db9986df6..447fba38323 100644
--- a/storage/innobase/buf/buf0dblwr.cc
+++ b/storage/innobase/buf/buf0dblwr.cc
@@ -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);
}
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 2a91106ba22..65dc7fcae1a 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -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 */
diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h
index 89cef8d69ed..0fe7b22fb04 100644
--- a/storage/innobase/include/log0log.h
+++ b/storage/innobase/include/log0log.h
@@ -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 */
diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc
index 5e64007ef84..1c0a617191e 100644
--- a/storage/innobase/log/log0log.cc
+++ b/storage/innobase/log/log0log.cc
@@ -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)
{
diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc
index d7bb3ce886b..76a703b7496 100644
--- a/storage/innobase/mtr/mtr0mtr.cc
+++ b/storage/innobase/mtr/mtr0mtr.cc
@@ -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();
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index bb85e82cbb8..b8f78775624 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -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);
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index ce020a6b88d..8692eaa0e89 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -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++;
}
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index d0596cded6b..bac9a3b25b5 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -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;
}
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc
index 40fa8172e6f..609e058ca52 100644
--- a/storage/innobase/trx/trx0purge.cc
+++ b/storage/innobase/trx/trx0purge.cc
@@ -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) {
diff --git a/storage/perfschema/pfs.cc b/storage/perfschema/pfs.cc
index 1bb712f64cc..3e9198a6b6c 100644
--- a/storage/perfschema/pfs.cc
+++ b/storage/perfschema/pfs.cc
@@ -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:
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index 77ebf0ae3b8..e6c5f4ab654 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -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 },