summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel-Solo <dansolo@mail.ru>2020-01-15 15:08:42 +0300
committerSergey Vojtovich <svoj@mariadb.org>2020-02-27 14:37:19 +0400
commit127fee998f7275485aeca91ad82030e6f796d809 (patch)
treeaca553e1416a10111f0bb68218d3573b3980ddfe
parent98adcffe460447c43a86afdf6588e31379b7f52d (diff)
downloadmariadb-git-127fee998f7275485aeca91ad82030e6f796d809.tar.gz
MDEV-10569: Add RELEASE_ALL_LOCKS function. Implementing the SQL
function to release all named locks
-rw-r--r--mysql-test/main/func_misc.result91
-rw-r--r--mysql-test/main/func_misc.test59
-rw-r--r--sql/item_create.cc22
-rw-r--r--sql/item_func.cc28
-rw-r--r--sql/item_func.h66
5 files changed, 237 insertions, 29 deletions
diff --git a/mysql-test/main/func_misc.result b/mysql-test/main/func_misc.result
index ae6686ecadc..311b9c083fa 100644
--- a/mysql-test/main/func_misc.result
+++ b/mysql-test/main/func_misc.result
@@ -1641,3 +1641,94 @@ DROP TABLE t1;
#
# End of 10.4 tests
#
+#
+# MDEV-10569 Add RELEASE_ALL_LOCKS SQL-function
+#
+# Test function without any locks
+SELECT RELEASE_ALL_LOCKS();
+RELEASE_ALL_LOCKS()
+0
+# Test function with one lock only
+SELECT GET_LOCK('l1',10);
+GET_LOCK('l1',10)
+1
+SELECT RELEASE_ALL_LOCKS();
+RELEASE_ALL_LOCKS()
+1
+SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA
+FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA;
+LOCK_MODE LOCK_TYPE TABLE_SCHEMA
+# Test function with multiple locks
+SELECT GET_LOCK('l01',10),
+GET_LOCK('l02',10),
+GET_LOCK('l03',10),
+GET_LOCK('l04',10),
+GET_LOCK('l05',10),
+GET_LOCK('l06',10),
+GET_LOCK('l07',10),
+GET_LOCK('l08',10),
+GET_LOCK('l09',10),
+GET_LOCK('l10',10),
+GET_LOCK('l11',10),
+GET_LOCK('l12',10),
+GET_LOCK('l13',10),
+GET_LOCK('l14',10),
+GET_LOCK('l15',10);
+GET_LOCK('l01',10) GET_LOCK('l02',10) GET_LOCK('l03',10) GET_LOCK('l04',10) GET_LOCK('l05',10) GET_LOCK('l06',10) GET_LOCK('l07',10) GET_LOCK('l08',10) GET_LOCK('l09',10) GET_LOCK('l10',10) GET_LOCK('l11',10) GET_LOCK('l12',10) GET_LOCK('l13',10) GET_LOCK('l14',10) GET_LOCK('l15',10)
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA
+FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA;
+LOCK_MODE LOCK_TYPE TABLE_SCHEMA
+MDL_SHARED_NO_WRITE User lock l01
+MDL_SHARED_NO_WRITE User lock l02
+MDL_SHARED_NO_WRITE User lock l03
+MDL_SHARED_NO_WRITE User lock l04
+MDL_SHARED_NO_WRITE User lock l05
+MDL_SHARED_NO_WRITE User lock l06
+MDL_SHARED_NO_WRITE User lock l07
+MDL_SHARED_NO_WRITE User lock l08
+MDL_SHARED_NO_WRITE User lock l09
+MDL_SHARED_NO_WRITE User lock l10
+MDL_SHARED_NO_WRITE User lock l11
+MDL_SHARED_NO_WRITE User lock l12
+MDL_SHARED_NO_WRITE User lock l13
+MDL_SHARED_NO_WRITE User lock l14
+MDL_SHARED_NO_WRITE User lock l15
+SELECT RELEASE_ALL_LOCKS();
+RELEASE_ALL_LOCKS()
+15
+SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA
+FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA;
+LOCK_MODE LOCK_TYPE TABLE_SCHEMA
+# Test function with recursive locks
+SELECT GET_LOCK('l1',10),
+GET_LOCK('l2',10),
+GET_LOCK('l2',10),
+GET_LOCK('l3',10),
+GET_LOCK('l3',10),
+GET_LOCK('l3',10),
+GET_LOCK('l4',10),
+GET_LOCK('l4',10),
+GET_LOCK('l4',10),
+GET_LOCK('l4',10),
+GET_LOCK('l5',10),
+GET_LOCK('l5',10),
+GET_LOCK('l5',10),
+GET_LOCK('l5',10),
+GET_LOCK('l5',10);
+GET_LOCK('l1',10) GET_LOCK('l2',10) GET_LOCK('l2',10) GET_LOCK('l3',10) GET_LOCK('l3',10) GET_LOCK('l3',10) GET_LOCK('l4',10) GET_LOCK('l4',10) GET_LOCK('l4',10) GET_LOCK('l4',10) GET_LOCK('l5',10) GET_LOCK('l5',10) GET_LOCK('l5',10) GET_LOCK('l5',10) GET_LOCK('l5',10)
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA
+FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA;
+LOCK_MODE LOCK_TYPE TABLE_SCHEMA
+MDL_SHARED_NO_WRITE User lock l1
+MDL_SHARED_NO_WRITE User lock l2
+MDL_SHARED_NO_WRITE User lock l3
+MDL_SHARED_NO_WRITE User lock l4
+MDL_SHARED_NO_WRITE User lock l5
+SELECT RELEASE_ALL_LOCKS();
+RELEASE_ALL_LOCKS()
+15
+SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA
+FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA;
+LOCK_MODE LOCK_TYPE TABLE_SCHEMA
diff --git a/mysql-test/main/func_misc.test b/mysql-test/main/func_misc.test
index 7d19c9e58af..951553705ab 100644
--- a/mysql-test/main/func_misc.test
+++ b/mysql-test/main/func_misc.test
@@ -1,7 +1,7 @@
#
# Testing of misc functions
#
-
+--source include/have_metadata_lock_info.inc
--source include/default_optimizer_switch.inc
--disable_warnings
DROP TABLE IF EXISTS t1, t2;
@@ -1278,3 +1278,60 @@ DROP TABLE t1;
--echo #
--echo # End of 10.4 tests
--echo #
+
+--echo #
+--echo # MDEV-10569 Add RELEASE_ALL_LOCKS SQL-function
+--echo #
+
+--echo # Test function without any locks
+SELECT RELEASE_ALL_LOCKS();
+
+--echo # Test function with one lock only
+SELECT GET_LOCK('l1',10);
+SELECT RELEASE_ALL_LOCKS();
+SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA
+FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA;
+
+--echo # Test function with multiple locks
+SELECT GET_LOCK('l01',10),
+ GET_LOCK('l02',10),
+ GET_LOCK('l03',10),
+ GET_LOCK('l04',10),
+ GET_LOCK('l05',10),
+ GET_LOCK('l06',10),
+ GET_LOCK('l07',10),
+ GET_LOCK('l08',10),
+ GET_LOCK('l09',10),
+ GET_LOCK('l10',10),
+ GET_LOCK('l11',10),
+ GET_LOCK('l12',10),
+ GET_LOCK('l13',10),
+ GET_LOCK('l14',10),
+ GET_LOCK('l15',10);
+SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA
+FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA;
+SELECT RELEASE_ALL_LOCKS();
+SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA
+FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA;
+
+--echo # Test function with recursive locks
+SELECT GET_LOCK('l1',10),
+ GET_LOCK('l2',10),
+ GET_LOCK('l2',10),
+ GET_LOCK('l3',10),
+ GET_LOCK('l3',10),
+ GET_LOCK('l3',10),
+ GET_LOCK('l4',10),
+ GET_LOCK('l4',10),
+ GET_LOCK('l4',10),
+ GET_LOCK('l4',10),
+ GET_LOCK('l5',10),
+ GET_LOCK('l5',10),
+ GET_LOCK('l5',10),
+ GET_LOCK('l5',10),
+ GET_LOCK('l5',10);
+SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA
+FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA;
+SELECT RELEASE_ALL_LOCKS();
+SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA
+FROM information_schema.metadata_lock_info WHERE thread_id>0 ORDER BY TABLE_SCHEMA; \ No newline at end of file
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 486f4fc591e..57e402999ea 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -1765,6 +1765,15 @@ protected:
};
+class Create_func_release_all_locks : public Create_func_arg0
+{
+public:
+ virtual Item *create_builder(THD *thd);
+
+ static Create_func_release_all_locks s_singleton;
+};
+
+
class Create_func_release_lock : public Create_func_arg1
{
public:
@@ -4762,6 +4771,17 @@ Create_func_rand::create_native(THD *thd, LEX_CSTRING *name,
}
+Create_func_release_all_locks Create_func_release_all_locks::s_singleton;
+
+Item*
+Create_func_release_all_locks::create_builder(THD *thd)
+{
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION);
+ thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
+ return new (thd->mem_root) Item_func_release_all_locks(thd);
+}
+
+
Create_func_release_lock Create_func_release_lock::s_singleton;
Item*
@@ -5525,6 +5545,8 @@ static Native_func_registry func_array[] =
{ { STRING_WITH_LEN("REGEXP_SUBSTR") }, BUILDER(Create_func_regexp_substr)},
{ { STRING_WITH_LEN("RADIANS") }, BUILDER(Create_func_radians)},
{ { STRING_WITH_LEN("RAND") }, BUILDER(Create_func_rand)},
+ { { STRING_WITH_LEN("RELEASE_ALL_LOCKS") },
+ BUILDER(Create_func_release_all_locks)},
{ { STRING_WITH_LEN("RELEASE_LOCK") }, BUILDER(Create_func_release_lock)},
{ { STRING_WITH_LEN("REPLACE_ORACLE") },
BUILDER(Create_func_replace_oracle)},
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 0419d55cc58..14a17bd09de 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -4028,7 +4028,7 @@ longlong Item_func_get_lock::val_int()
MDL_request ull_request;
ull_request.init(MDL_key::USER_LOCK, res->c_ptr_safe(), "",
MDL_SHARED_NO_WRITE, MDL_EXPLICIT);
- MDL_key *ull_key = &ull_request.key;
+ MDL_key *ull_key= &ull_request.key;
if ((ull= (User_level_lock*)
@@ -4036,7 +4036,7 @@ longlong Item_func_get_lock::val_int()
{
/* Recursive lock */
ull->refs++;
- null_value = 0;
+ null_value= 0;
DBUG_PRINT("info", ("recursive lock, ref-count: %d", (int) ull->refs));
DBUG_RETURN(1);
}
@@ -4076,6 +4076,30 @@ longlong Item_func_get_lock::val_int()
/**
+ Release all user level locks.
+ @return
+ - N if N-lock released
+ - 0 if lock wasn't held
+*/
+longlong Item_func_release_all_locks::val_int()
+{
+ DBUG_ASSERT(fixed == 1);
+ THD *thd= current_thd;
+ ulong num_unlocked= 0;
+ DBUG_ENTER("Item_func_release_all_locks::val_int");
+ for (size_t i= 0; i < thd->ull_hash.records; i++)
+ {
+ auto ull= (User_level_lock *) my_hash_element(&thd->ull_hash, i);
+ thd->mdl_context.release_lock(ull->lock);
+ num_unlocked+= ull->refs;
+ my_free(ull);
+ }
+ my_hash_free(&thd->ull_hash);
+ DBUG_RETURN(num_unlocked);
+}
+
+
+/**
Release a user level lock.
@return
- 1 if lock released
diff --git a/sql/item_func.h b/sql/item_func.h
index dced158bb86..2ff806492cf 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -2654,19 +2654,13 @@ public:
void mysql_ull_cleanup(THD *thd);
void mysql_ull_set_explicit_lock_duration(THD *thd);
-class Item_func_get_lock :public Item_long_func
+
+class Item_func_lock :public Item_long_func
{
- bool check_arguments() const
- {
- return args[0]->check_type_general_purpose_string(func_name()) ||
- args[1]->check_type_can_return_real(func_name());
- }
- String value;
public:
- Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_long_func(thd, a, b) {}
- longlong val_int();
- const char *func_name() const { return "get_lock"; }
- bool fix_length_and_dec() { max_length=1; maybe_null=1; return FALSE; }
+ Item_func_lock(THD *thd): Item_long_func(thd) { }
+ Item_func_lock(THD *thd, Item *a): Item_long_func(thd, a) {}
+ Item_func_lock(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) {}
table_map used_tables() const
{
return used_tables_cache | RAND_TABLE_BIT;
@@ -2677,34 +2671,54 @@ class Item_func_get_lock :public Item_long_func
{
return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE);
}
- Item *get_copy(THD *thd)
+};
+
+
+class Item_func_get_lock final :public Item_func_lock
+{
+ bool check_arguments() const
+ {
+ return args[0]->check_type_general_purpose_string(func_name()) ||
+ args[1]->check_type_can_return_real(func_name());
+ }
+ String value;
+ public:
+ Item_func_get_lock(THD *thd, Item *a, Item *b) :Item_func_lock(thd, a, b) {}
+ longlong val_int() final;
+ const char *func_name() const final { return "get_lock"; }
+ bool fix_length_and_dec() { max_length= 1; maybe_null= 1; return FALSE; }
+ Item *get_copy(THD *thd) final
{ return get_item_copy<Item_func_get_lock>(thd, this); }
};
-class Item_func_release_lock :public Item_long_func
+
+class Item_func_release_all_locks final :public Item_func_lock
+{
+public:
+ Item_func_release_all_locks(THD *thd): Item_func_lock(thd)
+ { unsigned_flag= 1; }
+ longlong val_int() final;
+ const char *func_name() const final { return "release_all_locks"; }
+ Item *get_copy(THD *thd) final
+ { return get_item_copy<Item_func_release_all_locks>(thd, this); }
+};
+
+
+class Item_func_release_lock final :public Item_func_lock
{
bool check_arguments() const
{ return args[0]->check_type_general_purpose_string(func_name()); }
String value;
public:
- Item_func_release_lock(THD *thd, Item *a): Item_long_func(thd, a) {}
- longlong val_int();
+ Item_func_release_lock(THD *thd, Item *a): Item_func_lock(thd, a) {}
+ longlong val_int() final;
const char *func_name() const { return "release_lock"; }
bool fix_length_and_dec() { max_length= 1; maybe_null= 1; return FALSE; }
- table_map used_tables() const
- {
- return used_tables_cache | RAND_TABLE_BIT;
- }
- bool const_item() const { return 0; }
- bool is_expensive() { return 1; }
- bool check_vcol_func_processor(void *arg)
- {
- return mark_unsupported_function(func_name(), "()", arg, VCOL_IMPOSSIBLE);
- }
- Item *get_copy(THD *thd)
+ Item *get_copy(THD *thd) final
{ return get_item_copy<Item_func_release_lock>(thd, this); }
};
+
/* replication functions */
class Item_master_pos_wait :public Item_longlong_func