Skip to content

Commit

Permalink
FB8-117: Add thread ID option for SQL SET command (facebook#1012) (fa…
Browse files Browse the repository at this point in the history
…cebook#1012)

Summary:
Jira issue: https://jira.percona.com/browse/FB8-117

Reference Patch: facebook@19f5aad

Added thread ID option to the SQL SET command. The syntax of the command is as follows:

`SET SESSION [THREAD_ID] var_name = var_value [, [SESSION [THREAD_ID]] var_name = var_value]`

Notes:
- The thread ID can be specified only with the SESSION keyword
- If no thread ID is provided, it is assumed to be the current thread
- Similarly, if own thread ID is provided, it is equivalent to `SET var_name = var_value`
- If the thread with given ID does not exist, it will fail
- For commands like `SET SESSION THREAD_ID var1 = var_value1, var2 = var_value2, var3 = var_value3` the SESSION THREAD_ID will apply to all three variables as explained in https://dev.mysql.com/doc/refman/5.6/en/set-variable.html
Pull Request resolved: facebook#1012

Reviewed By: lloyd

Differential Revision: D15773495

Pulled By: lth
  • Loading branch information
yashtc authored and inikep committed Jun 14, 2024
1 parent 5c4e509 commit 77d1bc3
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 68 deletions.
42 changes: 42 additions & 0 deletions mysql-test/r/set_thread_var.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
CREATE USER mysqluser1;
SET max_join_size = 1000;
include/assert.inc [Check if max_join_size is correct]
SET max_join_size = 2000;
include/assert.inc [Check if max_join_size is correct]
SET SESSION $mysqluser1 max_join_size = 1001;
include/assert.inc [Check if max_join_size is correct]
SET SESSION $mysqluser1 innodb_lock_wait_timeout = 100;
SET SESSION $conn_root max_join_size = 2001;
include/assert.inc [Check if max_join_size is correct]
SET SESSION max_join_size = 2002;
include/assert.inc [Check if max_join_size is correct]
include/assert.inc [Check if max_join_size is correct]
include/assert.inc [Check if innodb_lock_wait_timeout is correct]
SET SESSION $conn_mysqluser1 max_join_size = 1002, SESSION $conn_root max_join_size = 2003;
include/assert.inc [Check if max_join_size is correct]
include/assert.inc [Check if max_join_size is correct]
SET SESSION $conn_root max_join_size = 1003, SESSION $conn_root max_join_size = 2004;
ERROR 42000: Access denied; you need (at least one of) the SUPER or SYSTEM_VARIABLES_ADMIN privilege(s) for this operation
include/assert.inc [Check if max_join_size is correct]
SET SESSION $mysqluser1 max_join_size = 1003;
include/assert.inc [Check if max_join_size is correct]
SET SESSION max_join_size = 1004;
include/assert.inc [Check if max_join_size is correct]
include/assert.inc [Check if max_join_size is correct]
SET SESSION $conn_mysqluser1 max_join_size = 1005, max_sort_length = 30, SESSION $conn_root max_join_size = 2004, max_sort_length = 31;
include/assert.inc [Check if max_join_size is correct]
include/assert.inc [Check if max_join_size is correct]
SET SESSION 999 max_join_size = 9999;
ERROR HY000: Unknown thread id: 999
SET GLOBAL 1 max_join_size = 1000;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1 max_join_size = 1000' at line 1
SET SESSION -1 max_join_size = 1000;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-1 max_join_size = 1000' at line 1
SET SESSION 1 TRANSACTION READ WRITE;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'READ WRITE' at line 1
SET GLOBAL TRANSACTION READ ONLY;
SET SESSION TRANSACTION READ ONLY;
include/assert.inc [Check if SET SESSION/GLOBAL TRANSACTION READ ONLY works correctly]
SET GLOBAL TRANSACTION READ WRITE;
SET SESSION TRANSACTION READ WRITE;
DROP USER mysqluser1;
159 changes: 159 additions & 0 deletions mysql-test/t/set_thread_var.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
--source include/count_sessions.inc

#
# test SET VARIABLES with thread id
#

--let $conn_root = `SELECT CONNECTION_ID()`

# Create a regular user
CREATE USER mysqluser1;

--connect (user1,localhost,mysqluser1)
--let $conn_mysqluser1 = `SELECT CONNECTION_ID()`

# Set a variable for current thd
SET max_join_size = 1000;

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 1000
--source include/assert.inc


# Connect as root
--connection default

# Set a variable for current thd
SET max_join_size = 2000;

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 2000
--source include/assert.inc

# Set variable for user1 thd from root thd
--replace_regex /SESSION [0-9]*/SESSION $mysqluser1/
--eval SET SESSION $conn_mysqluser1 max_join_size = 1001

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 2000
--source include/assert.inc

--replace_regex /SESSION [0-9]*/SESSION $mysqluser1/
--eval SET SESSION $conn_mysqluser1 innodb_lock_wait_timeout = 100

# Set variable for root thd from root thd
--replace_regex /SESSION [0-9]*/SESSION $conn_root/
--eval SET SESSION $conn_root max_join_size = 2001

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 2001
--source include/assert.inc

# Set variable for root thd from root thd without session ID
SET SESSION max_join_size = 2002;

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 2002
--source include/assert.inc


--connection user1

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 1001
--source include/assert.inc

--let $assert_text = Check if innodb_lock_wait_timeout is correct
--let $assert_cond = @@innodb_lock_wait_timeout = 100
--source include/assert.inc


# Reconnect as root
--connection default

# Set variable for both current thd and user1 from root thd
--replace_regex /SESSION [0-9]* max_join_size = 1002, SESSION [0-9]* max_join_size = 2003/SESSION $conn_mysqluser1 max_join_size = 1002, SESSION $conn_root max_join_size = 2003/
--eval SET SESSION $conn_mysqluser1 max_join_size = 1002, SESSION $conn_root max_join_size = 2003

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 2003
--source include/assert.inc


--connection user1

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 1002
--source include/assert.inc

# Set variable for root thd from user1 thd
--replace_regex /SESSION [0-9]*/SESSION $conn_root/ /thread [0-9]*/thread $root/
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
--eval SET SESSION $conn_mysqluser1 max_join_size = 1003, SESSION $conn_root max_join_size = 2004

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 1002
--source include/assert.inc

# Set variable for user1 thd from user1 thd
--replace_regex /SESSION [0-9]*/SESSION $mysqluser1/
--eval SET SESSION $conn_mysqluser1 max_join_size = 1003

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 1003
--source include/assert.inc

# Set variable for user1 thd from user1 thd without session ID
SET SESSION max_join_size = 1004;

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 1004
--source include/assert.inc


--connection default

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 2003
--source include/assert.inc

# Set multiple variables for both current thd and user1 from root thd
--replace_regex /SESSION [0-9]* max_join_size = 1005/SESSION $conn_mysqluser1 max_join_size = 1005/ /SESSION [0-9]* max_join_size = 2004/SESSION $conn_root max_join_size = 2004/
--eval SET SESSION $conn_mysqluser1 max_join_size = 1005, max_sort_length = 30, SESSION $conn_root max_join_size = 2004, max_sort_length = 31

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 2004 AND @@max_sort_length = 31
--source include/assert.inc


--connection user1

--let $assert_text = Check if max_join_size is correct
--let $assert_cond = @@max_join_size = 1005 AND @@max_sort_length = 30
--source include/assert.inc

--error ER_NO_SUCH_THREAD
--eval SET SESSION 999 max_join_size = 9999

--error ER_PARSE_ERROR
--eval SET GLOBAL 1 max_join_size = 1000

--error ER_PARSE_ERROR
--eval SET SESSION -1 max_join_size = 1000

--error ER_PARSE_ERROR
--eval SET SESSION 1 TRANSACTION READ WRITE

--connection default
SET GLOBAL TRANSACTION READ ONLY;
SET SESSION TRANSACTION READ ONLY;
--let $assert_text = Check if SET SESSION/GLOBAL TRANSACTION READ ONLY works correctly
--let $assert_cond = @@GLOBAL.transaction_read_only = 1 AND @@transaction_read_only = 1
--source include/assert.inc
SET GLOBAL TRANSACTION READ WRITE;
SET SESSION TRANSACTION READ WRITE;

# cleanup
DROP USER mysqluser1;
--disconnect user1
--source include/wait_until_count_sessions.inc
2 changes: 2 additions & 0 deletions sql/parse_tree_helpers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,13 @@ bool sp_create_assignment_instr(THD *thd, const char *expr_end_ptr) {

/* Remember option_type of the currently parsed LEX. */
const enum_var_type inner_option_type = lex->option_type;
const ulong thd_id_opt = lex->thread_id_opt;

if (sp->restore_lex(thd)) return true;

/* Copy option_type to outer lex in case it has changed. */
thd->lex->option_type = inner_option_type;
thd->lex->thread_id_opt = thd_id_opt;

return false;
}
Expand Down
10 changes: 7 additions & 3 deletions sql/parse_tree_nodes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,7 @@ static bool add_system_variable_assignment(THD *thd, LEX_CSTRING prefix,
set_var *var = new (thd->mem_root) set_var(var_type, var_tracker, val);
if (var == nullptr) return true;

var->thd_id = lex->thread_id_opt;
return lex->var_list.push_back(var);
}

Expand Down Expand Up @@ -4133,8 +4134,9 @@ bool PT_set_system_variable::do_contextualize(Parse_context *pc) {
}

bool PT_option_value_type::do_contextualize(Parse_context *pc) {
pc->thd->lex->option_type = type;
return super::do_contextualize(pc) || value->contextualize(pc);
pc->thd->lex->option_type = option_type;
pc->thd->lex->thread_id_opt = thread_id;
return Parse_tree_node::do_contextualize(pc) || value->contextualize(pc);
}

bool PT_option_value_list_head::do_contextualize(Parse_context *pc) {
Expand Down Expand Up @@ -4206,6 +4208,8 @@ bool PT_start_option_value_list_transaction::do_contextualize(

bool PT_start_option_value_list_following_option_type_eq::do_contextualize(
Parse_context *pc) {
pc->thd->lex->option_type = option_type;
pc->thd->lex->thread_id_opt = thread_id;
if (super::do_contextualize(pc) || head->contextualize(pc)) return true;

if (sp_create_assignment_instr(pc->thd, head_pos.raw.end)) return true;
Expand All @@ -4219,6 +4223,7 @@ bool PT_start_option_value_list_following_option_type_eq::do_contextualize(

bool PT_start_option_value_list_following_option_type_transaction::
do_contextualize(Parse_context *pc) {
pc->thd->lex->option_type = type;
if (super::do_contextualize(pc) || characteristics->contextualize(pc))
return true;

Expand All @@ -4231,7 +4236,6 @@ bool PT_start_option_value_list_following_option_type_transaction::
}

bool PT_start_option_value_list_type::do_contextualize(Parse_context *pc) {
pc->thd->lex->option_type = type;
return super::do_contextualize(pc) || list->contextualize(pc);
}

Expand Down
30 changes: 21 additions & 9 deletions sql/parse_tree_nodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1047,13 +1047,18 @@ class PT_option_value_no_option_type_password_for
class PT_option_value_type : public Parse_tree_node {
typedef Parse_tree_node super;

enum_var_type type;
enum_var_type option_type;
ulong thread_id;
PT_set_scoped_system_variable *value;

public:
PT_option_value_type(const POS &pos, enum_var_type type_arg,
PT_option_value_type(const POS &pos, enum_var_type option_type_arg,
ulong thread_id_arg,
PT_set_scoped_system_variable *value_arg)
: super(pos), type(type_arg), value(value_arg) {}
: super(pos),
option_type(option_type_arg),
thread_id(thread_id_arg),
value(value_arg) {}

bool do_contextualize(Parse_context *pc) override;
};
Expand Down Expand Up @@ -1189,15 +1194,20 @@ class PT_start_option_value_list_following_option_type_eq
: public PT_start_option_value_list_following_option_type {
typedef PT_start_option_value_list_following_option_type super;

enum_var_type option_type;
ulong thread_id;
PT_set_scoped_system_variable *head;
POS head_pos;
PT_option_value_list_head *opt_tail;

public:
PT_start_option_value_list_following_option_type_eq(
const POS &pos, PT_set_scoped_system_variable *head_arg,
const POS &head_pos_arg, PT_option_value_list_head *opt_tail_arg)
const POS &pos, enum_var_type option_type_arg, ulong thread_id_arg,
PT_set_scoped_system_variable *head_arg, const POS &head_pos_arg,
PT_option_value_list_head *opt_tail_arg)
: super(pos),
option_type(option_type_arg),
thread_id(thread_id_arg),
head(head_arg),
head_pos(head_pos_arg),
opt_tail(opt_tail_arg) {}
Expand All @@ -1209,14 +1219,17 @@ class PT_start_option_value_list_following_option_type_transaction
: public PT_start_option_value_list_following_option_type {
typedef PT_start_option_value_list_following_option_type super;

enum_var_type type;
PT_transaction_characteristics *characteristics;
POS characteristics_pos;

public:
PT_start_option_value_list_following_option_type_transaction(
const POS &pos, PT_transaction_characteristics *characteristics_arg,
const POS &pos, enum_var_type type_arg,
PT_transaction_characteristics *characteristics_arg,
const POS &characteristics_pos_arg)
: super(pos),
type(type_arg),
characteristics(characteristics_arg),
characteristics_pos(characteristics_pos_arg) {}

Expand All @@ -1226,14 +1239,13 @@ class PT_start_option_value_list_following_option_type_transaction
class PT_start_option_value_list_type : public PT_start_option_value_list {
typedef PT_start_option_value_list super;

enum_var_type type;
PT_start_option_value_list_following_option_type *list;

public:
PT_start_option_value_list_type(
const POS &pos, enum_var_type type_arg,
const POS &pos,
PT_start_option_value_list_following_option_type *list_arg)
: super(pos), type(type_arg), list(list_arg) {}
: super(pos), list(list_arg) {}

bool do_contextualize(Parse_context *pc) override;
};
Expand Down
Loading

0 comments on commit 77d1bc3

Please sign in to comment.