1 /* Copyright (c) 1999, 2020, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #include "sql/sql_parse.h"
24 
25 #include "my_config.h"
26 #include "mysql/psi/mysql_table.h"
27 
28 #include <limits.h>
29 #include <stdint.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34 #include <algorithm>
35 #include <atomic>
36 #include <thread>
37 #include <utility>
38 
39 #ifdef HAVE_LSAN_DO_RECOVERABLE_LEAK_CHECK
40 #include <sanitizer/lsan_interface.h>
41 #endif
42 
43 #include "auth/auth_internal.h"
44 #include "dur_prop.h"
45 #include "field_types.h"  // enum_field_types
46 #include "m_ctype.h"
47 #include "m_string.h"
48 #include "my_alloc.h"
49 #include "my_compiler.h"
50 #include "my_dbug.h"
51 #include "my_inttypes.h"
52 #include "my_io.h"
53 #include "my_loglevel.h"
54 #include "my_macros.h"
55 #include "my_psi_config.h"
56 #include "my_sys.h"
57 #include "my_table_map.h"
58 #include "my_thread_local.h"
59 #include "my_time.h"
60 #include "mysql/com_data.h"
61 #include "mysql/components/services/log_builtins.h"
62 #include "mysql/components/services/log_shared.h"
63 #include "mysql/components/services/psi_statement_bits.h"
64 #include "mysql/plugin_audit.h"
65 #include "mysql/psi/mysql_mutex.h"
66 #include "mysql/psi/mysql_rwlock.h"
67 #include "mysql/psi/mysql_statement.h"
68 #include "mysql/service_mysql_alloc.h"
69 #include "mysqld_error.h"
70 #include "mysys_err.h"  // EE_CAPACITY_EXCEEDED
71 #include "nullable.h"
72 #include "pfs_thread_provider.h"
73 #include "prealloced_array.h"
74 #include "sql/auth/auth_acls.h"
75 #include "sql/auth/auth_common.h"  // acl_authenticate
76 #include "sql/auth/sql_security_ctx.h"
77 #include "sql/binlog.h"  // purge_master_logs
78 #include "sql/clone_handler.h"
79 #include "sql/current_thd.h"
80 #include "sql/dd/cache/dictionary_client.h"  // dd::cache::Dictionary_client::Auto_releaser
81 #include "sql/dd/dd.h"                       // dd::get_dictionary
82 #include "sql/dd/dd_schema.h"                // Schema_MDL_locker
83 #include "sql/dd/dictionary.h"  // dd::Dictionary::is_system_view_name
84 #include "sql/dd/info_schema/table_stats.h"
85 #include "sql/debug_sync.h"  // DEBUG_SYNC
86 #include "sql/derror.h"      // ER_THD
87 #include "sql/discrete_interval.h"
88 #include "sql/error_handler.h"  // Strict_error_handler
89 #include "sql/events.h"         // Events
90 #include "sql/field.h"
91 #include "sql/gis/srid.h"
92 #include "sql/item.h"
93 #include "sql/item_cmpfunc.h"
94 #include "sql/item_func.h"
95 #include "sql/item_subselect.h"
96 #include "sql/item_timefunc.h"  // Item_func_unix_timestamp
97 #include "sql/key_spec.h"       // Key_spec
98 #include "sql/log.h"            // query_logger
99 #include "sql/log_event.h"      // slave_execute_deferred_events
100 #include "sql/mdl.h"
101 #include "sql/mem_root_array.h"
102 #include "sql/mysqld.h"              // stage_execution_of_init_command
103 #include "sql/mysqld_thd_manager.h"  // Find_thd_with_id
104 #include "sql/nested_join.h"
105 #include "sql/opt_hints.h"
106 #include "sql/opt_trace.h"  // Opt_trace_start
107 #include "sql/parse_location.h"
108 #include "sql/parse_tree_node_base.h"
109 #include "sql/parse_tree_nodes.h"
110 #include "sql/parser_yystype.h"
111 #include "sql/persisted_variable.h"
112 #include "sql/protocol.h"
113 #include "sql/protocol_classic.h"
114 #include "sql/psi_memory_key.h"
115 #include "sql/query_options.h"
116 #include "sql/query_result.h"
117 #include "sql/resourcegroups/resource_group_basic_types.h"
118 #include "sql/resourcegroups/resource_group_mgr.h"  // Resource_group_mgr::instance
119 #include "sql/rpl_context.h"
120 #include "sql/rpl_filter.h"             // rpl_filter
121 #include "sql/rpl_group_replication.h"  // group_replication_start
122 #include "sql/rpl_gtid.h"
123 #include "sql/rpl_handler.h"  // launch_hook_trans_begin
124 #include "sql/rpl_master.h"   // register_slave
125 #include "sql/rpl_rli.h"      // mysql_show_relaylog_events
126 #include "sql/rpl_slave.h"    // change_master_cmd
127 #include "sql/session_tracker.h"
128 #include "sql/set_var.h"
129 #include "sql/sp.h"        // sp_create_routine
130 #include "sql/sp_cache.h"  // sp_cache_enforce_limit
131 #include "sql/sp_head.h"   // sp_head
132 #include "sql/sql_alter.h"
133 #include "sql/sql_audit.h"        // MYSQL_AUDIT_NOTIFY_CONNECTION_CHANGE_USER
134 #include "sql/sql_backup_lock.h"  // acquire_shared_mdl_for_backup
135 #include "sql/sql_base.h"         // find_temporary_table
136 #include "sql/sql_binlog.h"       // mysql_client_binlog_statement
137 #include "sql/sql_class.h"
138 #include "sql/sql_cmd.h"
139 #include "sql/sql_connect.h"  // decrease_user_connections
140 #include "sql/sql_const.h"
141 #include "sql/sql_db.h"  // mysql_change_db
142 #include "sql/sql_digest.h"
143 #include "sql/sql_digest_stream.h"
144 #include "sql/sql_error.h"
145 #include "sql/sql_handler.h"  // mysql_ha_rm_tables
146 #include "sql/sql_help.h"     // mysqld_help
147 #include "sql/sql_lex.h"
148 #include "sql/sql_list.h"
149 #include "sql/sql_prepare.h"  // mysql_stmt_execute
150 #include "sql/sql_profile.h"
151 #include "sql/sql_query_rewrite.h"  // invoke_pre_parse_rewrite_plugins
152 #include "sql/sql_reload.h"         // handle_reload_request
153 #include "sql/sql_rename.h"         // mysql_rename_tables
154 #include "sql/sql_rewrite.h"        // mysql_rewrite_query
155 #include "sql/sql_select.h"         // handle_query
156 #include "sql/sql_show.h"           // find_schema_table
157 #include "sql/sql_table.h"          // mysql_create_table
158 #include "sql/sql_trigger.h"        // add_table_for_trigger
159 #include "sql/sql_udf.h"
160 #include "sql/sql_view.h"  // mysql_create_view
161 #include "sql/strfunc.h"
162 #include "sql/system_variables.h"  // System_status_var
163 #include "sql/table.h"
164 #include "sql/table_cache.h"  // table_cache_manager
165 #include "sql/thd_raii.h"
166 #include "sql/transaction.h"  // trans_rollback_implicit
167 #include "sql/transaction_info.h"
168 #include "sql_string.h"
169 #include "thr_lock.h"
170 #include "violite.h"
171 
172 #ifdef WITH_LOCK_ORDER
173 #include "sql/debug_lock_order.h"
174 #endif /* WITH_LOCK_ORDER */
175 
176 namespace dd {
177 class Spatial_reference_system;
178 }  // namespace dd
179 namespace resourcegroups {
180 class Resource_group;
181 }  // namespace resourcegroups
182 struct mysql_rwlock_t;
183 
184 namespace dd {
185 class Schema;
186 }  // namespace dd
187 
188 namespace dd {
189 class Abstract_table;
190 }  // namespace dd
191 
192 using Mysql::Nullable;
193 using std::max;
194 
195 /**
196   @defgroup Runtime_Environment Runtime Environment
197   @{
198 */
199 
200 /* Used in error handling only */
201 #define SP_COM_STRING(LP)                                  \
202   ((LP)->sql_command == SQLCOM_CREATE_SPFUNCTION ||        \
203            (LP)->sql_command == SQLCOM_ALTER_FUNCTION ||   \
204            (LP)->sql_command == SQLCOM_SHOW_CREATE_FUNC || \
205            (LP)->sql_command == SQLCOM_DROP_FUNCTION       \
206        ? "FUNCTION"                                        \
207        : "PROCEDURE")
208 
209 static void sql_kill(THD *thd, my_thread_id id, bool only_kill_query);
210 
211 const LEX_CSTRING command_name[] = {
212     {STRING_WITH_LEN("Sleep")},
213     {STRING_WITH_LEN("Quit")},
214     {STRING_WITH_LEN("Init DB")},
215     {STRING_WITH_LEN("Query")},
216     {STRING_WITH_LEN("Field List")},
217     {STRING_WITH_LEN("Create DB")},
218     {STRING_WITH_LEN("Drop DB")},
219     {STRING_WITH_LEN("Refresh")},
220     {STRING_WITH_LEN("Shutdown")},
221     {STRING_WITH_LEN("Statistics")},
222     {STRING_WITH_LEN("Processlist")},
223     {STRING_WITH_LEN("Connect")},
224     {STRING_WITH_LEN("Kill")},
225     {STRING_WITH_LEN("Debug")},
226     {STRING_WITH_LEN("Ping")},
227     {STRING_WITH_LEN("Time")},
228     {STRING_WITH_LEN("Delayed insert")},
229     {STRING_WITH_LEN("Change user")},
230     {STRING_WITH_LEN("Binlog Dump")},
231     {STRING_WITH_LEN("Table Dump")},
232     {STRING_WITH_LEN("Connect Out")},
233     {STRING_WITH_LEN("Register Slave")},
234     {STRING_WITH_LEN("Prepare")},
235     {STRING_WITH_LEN("Execute")},
236     {STRING_WITH_LEN("Long Data")},
237     {STRING_WITH_LEN("Close stmt")},
238     {STRING_WITH_LEN("Reset stmt")},
239     {STRING_WITH_LEN("Set option")},
240     {STRING_WITH_LEN("Fetch")},
241     {STRING_WITH_LEN("Daemon")},
242     {STRING_WITH_LEN("Binlog Dump GTID")},
243     {STRING_WITH_LEN("Reset Connection")},
244     {STRING_WITH_LEN("clone")},
245     {STRING_WITH_LEN("Error")}  // Last command number
246 };
247 
command_satisfy_acl_cache_requirement(unsigned command)248 bool command_satisfy_acl_cache_requirement(unsigned command) {
249   if ((sql_command_flags[command] & CF_REQUIRE_ACL_CACHE) > 0 &&
250       skip_grant_tables() == true)
251     return false;
252   else
253     return true;
254 }
255 
256 /**
257   Returns true if all tables should be ignored.
258 */
all_tables_not_ok(THD * thd,TABLE_LIST * tables)259 bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) {
260   Rpl_filter *rpl_filter = thd->rli_slave->rpl_filter;
261 
262   return rpl_filter->is_on() && tables && !thd->sp_runtime_ctx &&
263          !rpl_filter->tables_ok(thd->db().str, tables);
264 }
265 
266 /**
267   Checks whether the event for the given database, db, should
268   be ignored or not. This is done by checking whether there are
269   active rules in ignore_db or in do_db containers. If there
270   are, then check if there is a match, if not then check the
271   wild_do rules.
272 
273   NOTE: This means that when using this function replicate-do-db
274         and replicate-ignore-db take precedence over wild do
275         rules.
276 
277   @param thd  Thread handle.
278   @param db   Database name used while evaluating the filtering
279               rules.
280   @param sql_cmd Represents the current query that needs to be
281                  verified against the database filter rules.
282   @return true Query should not be filtered out from the execution.
283           false Query should be filtered out from the execution.
284 
285 */
check_database_filters(THD * thd,const char * db,enum_sql_command sql_cmd)286 inline bool check_database_filters(THD *thd, const char *db,
287                                    enum_sql_command sql_cmd) {
288   DBUG_TRACE;
289   DBUG_ASSERT(thd->slave_thread);
290   if (!db) return true;
291   Rpl_filter *rpl_filter = thd->rli_slave->rpl_filter;
292 
293   bool need_increase_counter = true;
294   switch (sql_cmd) {
295     case SQLCOM_BEGIN:
296     case SQLCOM_COMMIT:
297     case SQLCOM_SAVEPOINT:
298     case SQLCOM_ROLLBACK:
299     case SQLCOM_ROLLBACK_TO_SAVEPOINT:
300       return true;
301     case SQLCOM_XA_START:
302     case SQLCOM_XA_END:
303     case SQLCOM_XA_COMMIT:
304     case SQLCOM_XA_ROLLBACK:
305       need_increase_counter = false;
306     default:
307       break;
308   }
309 
310   bool db_ok = rpl_filter->db_ok(db, need_increase_counter);
311   /*
312     No filters exist in ignore/do_db ? Then, just check
313     wild_do_table filtering for 'DATABASE' related
314     statements (CREATE/DROP/ATLER DATABASE)
315   */
316   if (db_ok && (rpl_filter->get_do_db()->is_empty() &&
317                 rpl_filter->get_ignore_db()->is_empty())) {
318     switch (sql_cmd) {
319       case SQLCOM_CREATE_DB:
320       case SQLCOM_ALTER_DB:
321       case SQLCOM_DROP_DB:
322         db_ok = rpl_filter->db_ok_with_wild_table(db);
323       default:
324         break;
325     }
326   }
327   return db_ok;
328 }
329 
some_non_temp_table_to_be_updated(THD * thd,TABLE_LIST * tables)330 bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) {
331   for (TABLE_LIST *table = tables; table; table = table->next_global) {
332     DBUG_ASSERT(table->db && table->table_name);
333     /*
334       Update on performance_schema and temp tables are allowed
335       in readonly mode.
336     */
337     if (table->updating && !find_temporary_table(thd, table) &&
338         !is_perfschema_db(table->db, table->db_length))
339       return true;
340   }
341   return false;
342 }
343 
344 /**
345   Returns whether the command in thd->lex->sql_command should cause an
346   implicit commit. An active transaction should be implicitly commited if the
347   statement requires so.
348 
349   @param thd    Thread handle.
350   @param mask   Bitmask used for the SQL command match.
351 
352   @retval true This statement shall cause an implicit commit.
353   @retval false This statement shall not cause an implicit commit.
354 */
stmt_causes_implicit_commit(const THD * thd,uint mask)355 bool stmt_causes_implicit_commit(const THD *thd, uint mask) {
356   DBUG_TRACE;
357   const LEX *lex = thd->lex;
358 
359   if ((sql_command_flags[lex->sql_command] & mask) == 0 ||
360       thd->is_plugin_fake_ddl())
361     return false;
362 
363   switch (lex->sql_command) {
364     case SQLCOM_DROP_TABLE:
365       return !lex->drop_temporary;
366     case SQLCOM_ALTER_TABLE:
367     case SQLCOM_CREATE_TABLE:
368       /* If CREATE TABLE of non-temporary table or without
369         START TRANSACTION, do implicit commit */
370       return (lex->create_info->options & HA_LEX_CREATE_TMP_TABLE ||
371               lex->create_info->m_transactional_ddl) == 0;
372     case SQLCOM_SET_OPTION:
373       /* Implicitly commit a transaction started by a SET statement */
374       return lex->autocommit;
375     case SQLCOM_RESET:
376       return lex->option_type != OPT_PERSIST;
377     default:
378       return true;
379   }
380 }
381 
382 /**
383   Mark all commands that somehow changes a table.
384 
385   This is used to check number of updates / hour.
386 
387   sql_command is actually set to SQLCOM_END sometimes
388   so we need the +1 to include it in the array.
389 
390   See COMMAND_FLAG_xxx for different type of commands
391      2  - query that returns meaningful ROW_COUNT() -
392           a number of modified rows
393 */
394 
395 uint sql_command_flags[SQLCOM_END + 1];
396 uint server_command_flags[COM_END + 1];
397 
init_sql_command_flags(void)398 void init_sql_command_flags(void) {
399   /* Initialize the server command flags array. */
400   memset(server_command_flags, 0, sizeof(server_command_flags));
401 
402   server_command_flags[COM_SLEEP] = CF_ALLOW_PROTOCOL_PLUGIN;
403   server_command_flags[COM_INIT_DB] = CF_ALLOW_PROTOCOL_PLUGIN;
404   server_command_flags[COM_QUERY] = CF_ALLOW_PROTOCOL_PLUGIN;
405   server_command_flags[COM_FIELD_LIST] = CF_ALLOW_PROTOCOL_PLUGIN;
406   server_command_flags[COM_REFRESH] = CF_ALLOW_PROTOCOL_PLUGIN;
407   server_command_flags[COM_STATISTICS] = CF_SKIP_QUESTIONS;
408   server_command_flags[COM_PROCESS_KILL] = CF_ALLOW_PROTOCOL_PLUGIN;
409   server_command_flags[COM_PING] = CF_SKIP_QUESTIONS;
410   server_command_flags[COM_STMT_PREPARE] =
411       CF_SKIP_QUESTIONS | CF_ALLOW_PROTOCOL_PLUGIN;
412   server_command_flags[COM_STMT_EXECUTE] = CF_ALLOW_PROTOCOL_PLUGIN;
413   server_command_flags[COM_STMT_SEND_LONG_DATA] = CF_ALLOW_PROTOCOL_PLUGIN;
414   server_command_flags[COM_STMT_CLOSE] =
415       CF_SKIP_QUESTIONS | CF_ALLOW_PROTOCOL_PLUGIN;
416   server_command_flags[COM_STMT_RESET] =
417       CF_SKIP_QUESTIONS | CF_ALLOW_PROTOCOL_PLUGIN;
418   server_command_flags[COM_STMT_FETCH] = CF_ALLOW_PROTOCOL_PLUGIN;
419   server_command_flags[COM_RESET_CONNECTION] = CF_ALLOW_PROTOCOL_PLUGIN;
420   server_command_flags[COM_END] = CF_ALLOW_PROTOCOL_PLUGIN;
421 
422   /* Initialize the sql command flags array. */
423   memset(sql_command_flags, 0, sizeof(sql_command_flags));
424 
425   /*
426     In general, DDL statements do not generate row events and do not go
427     through a cache before being written to the binary log. However, the
428     CREATE TABLE...SELECT is an exception because it may generate row
429     events. For that reason,  the SQLCOM_CREATE_TABLE  which represents
430     a CREATE TABLE, including the CREATE TABLE...SELECT, has the
431     CF_CAN_GENERATE_ROW_EVENTS flag. The distinction between a regular
432     CREATE TABLE and the CREATE TABLE...SELECT is made in other parts of
433     the code, in particular in the Query_log_event's constructor.
434   */
435   sql_command_flags[SQLCOM_CREATE_TABLE] =
436       CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS |
437       CF_CAN_GENERATE_ROW_EVENTS;
438   sql_command_flags[SQLCOM_CREATE_INDEX] =
439       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
440   sql_command_flags[SQLCOM_ALTER_TABLE] =
441       CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
442   sql_command_flags[SQLCOM_TRUNCATE] =
443       CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
444   sql_command_flags[SQLCOM_DROP_TABLE] = CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
445   sql_command_flags[SQLCOM_LOAD] =
446       CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS;
447   sql_command_flags[SQLCOM_CREATE_DB] = CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
448   sql_command_flags[SQLCOM_DROP_DB] = CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
449   sql_command_flags[SQLCOM_ALTER_DB] = CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
450   sql_command_flags[SQLCOM_RENAME_TABLE] =
451       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
452   sql_command_flags[SQLCOM_DROP_INDEX] = CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
453   sql_command_flags[SQLCOM_CREATE_VIEW] =
454       CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS;
455   sql_command_flags[SQLCOM_DROP_VIEW] = CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
456   sql_command_flags[SQLCOM_CREATE_TRIGGER] =
457       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
458   sql_command_flags[SQLCOM_DROP_TRIGGER] =
459       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
460   sql_command_flags[SQLCOM_CREATE_EVENT] =
461       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
462   sql_command_flags[SQLCOM_ALTER_EVENT] =
463       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
464   sql_command_flags[SQLCOM_DROP_EVENT] = CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
465   sql_command_flags[SQLCOM_IMPORT] = CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
466 
467   sql_command_flags[SQLCOM_UPDATE] = CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
468                                      CF_CAN_GENERATE_ROW_EVENTS |
469                                      CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED;
470   sql_command_flags[SQLCOM_UPDATE_MULTI] =
471       CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS |
472       CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED;
473   // This is INSERT VALUES(...), can be VALUES(stored_func()) so we trace it
474   sql_command_flags[SQLCOM_INSERT] = CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
475                                      CF_CAN_GENERATE_ROW_EVENTS |
476                                      CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED;
477   sql_command_flags[SQLCOM_INSERT_SELECT] =
478       CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS |
479       CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED;
480   sql_command_flags[SQLCOM_DELETE] = CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
481                                      CF_CAN_GENERATE_ROW_EVENTS |
482                                      CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED;
483   sql_command_flags[SQLCOM_DELETE_MULTI] =
484       CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS |
485       CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED;
486   sql_command_flags[SQLCOM_REPLACE] = CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
487                                       CF_CAN_GENERATE_ROW_EVENTS |
488                                       CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED;
489   sql_command_flags[SQLCOM_REPLACE_SELECT] =
490       CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS |
491       CF_OPTIMIZER_TRACE | CF_CAN_BE_EXPLAINED;
492   sql_command_flags[SQLCOM_SELECT] =
493       CF_REEXECUTION_FRAGILE | CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE |
494       CF_HAS_RESULT_SET | CF_CAN_BE_EXPLAINED;
495   // (1) so that subquery is traced when doing "SET @var = (subquery)"
496   /*
497     @todo SQLCOM_SET_OPTION should have CF_CAN_GENERATE_ROW_EVENTS
498     set, because it may invoke a stored function that generates row
499     events. /Sven
500   */
501   sql_command_flags[SQLCOM_SET_OPTION] =
502       CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS |
503       CF_CAN_GENERATE_ROW_EVENTS | CF_OPTIMIZER_TRACE;  // (1)
504   // (1) so that subquery is traced when doing "DO @var := (subquery)"
505   sql_command_flags[SQLCOM_DO] = CF_REEXECUTION_FRAGILE |
506                                  CF_CAN_GENERATE_ROW_EVENTS |
507                                  CF_OPTIMIZER_TRACE;  // (1)
508 
509   sql_command_flags[SQLCOM_SET_PASSWORD] =
510       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_NEEDS_AUTOCOMMIT_OFF |
511       CF_POTENTIAL_ATOMIC_DDL | CF_DISALLOW_IN_RO_TRANS;
512 
513   sql_command_flags[SQLCOM_SHOW_STATUS_PROC] =
514       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
515   sql_command_flags[SQLCOM_SHOW_STATUS] =
516       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
517   sql_command_flags[SQLCOM_SHOW_DATABASES] =
518       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
519   sql_command_flags[SQLCOM_SHOW_TRIGGERS] =
520       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
521   sql_command_flags[SQLCOM_SHOW_EVENTS] =
522       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
523   sql_command_flags[SQLCOM_SHOW_OPEN_TABLES] =
524       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
525   sql_command_flags[SQLCOM_SHOW_PLUGINS] = CF_STATUS_COMMAND;
526   sql_command_flags[SQLCOM_SHOW_FIELDS] =
527       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
528   sql_command_flags[SQLCOM_SHOW_KEYS] =
529       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
530   sql_command_flags[SQLCOM_SHOW_VARIABLES] =
531       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
532   sql_command_flags[SQLCOM_SHOW_CHARSETS] =
533       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
534   sql_command_flags[SQLCOM_SHOW_COLLATIONS] =
535       CF_STATUS_COMMAND | CF_HAS_RESULT_SET | CF_REEXECUTION_FRAGILE;
536   sql_command_flags[SQLCOM_SHOW_BINLOGS] = CF_STATUS_COMMAND;
537   sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS] = CF_STATUS_COMMAND;
538   sql_command_flags[SQLCOM_SHOW_BINLOG_EVENTS] = CF_STATUS_COMMAND;
539   sql_command_flags[SQLCOM_SHOW_STORAGE_ENGINES] = CF_STATUS_COMMAND;
540   sql_command_flags[SQLCOM_SHOW_PRIVILEGES] = CF_STATUS_COMMAND;
541   sql_command_flags[SQLCOM_SHOW_WARNS] = CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT;
542   sql_command_flags[SQLCOM_SHOW_ERRORS] =
543       CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT;
544   sql_command_flags[SQLCOM_SHOW_ENGINE_STATUS] = CF_STATUS_COMMAND;
545   sql_command_flags[SQLCOM_SHOW_ENGINE_MUTEX] = CF_STATUS_COMMAND;
546   sql_command_flags[SQLCOM_SHOW_ENGINE_LOGS] = CF_STATUS_COMMAND;
547   sql_command_flags[SQLCOM_SHOW_PROCESSLIST] = CF_STATUS_COMMAND;
548   sql_command_flags[SQLCOM_SHOW_GRANTS] = CF_STATUS_COMMAND;
549   sql_command_flags[SQLCOM_SHOW_CREATE_DB] = CF_STATUS_COMMAND;
550   sql_command_flags[SQLCOM_SHOW_CREATE] = CF_STATUS_COMMAND;
551   sql_command_flags[SQLCOM_SHOW_MASTER_STAT] = CF_STATUS_COMMAND;
552   sql_command_flags[SQLCOM_SHOW_SLAVE_STAT] = CF_STATUS_COMMAND;
553   sql_command_flags[SQLCOM_SHOW_CREATE_PROC] = CF_STATUS_COMMAND;
554   sql_command_flags[SQLCOM_SHOW_CREATE_FUNC] = CF_STATUS_COMMAND;
555   sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER] = CF_STATUS_COMMAND;
556   sql_command_flags[SQLCOM_SHOW_STATUS_FUNC] =
557       CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE | CF_HAS_RESULT_SET;
558   sql_command_flags[SQLCOM_SHOW_PROC_CODE] = CF_STATUS_COMMAND;
559   sql_command_flags[SQLCOM_SHOW_FUNC_CODE] = CF_STATUS_COMMAND;
560   sql_command_flags[SQLCOM_SHOW_CREATE_EVENT] = CF_STATUS_COMMAND;
561   sql_command_flags[SQLCOM_SHOW_PROFILES] = CF_STATUS_COMMAND;
562   sql_command_flags[SQLCOM_SHOW_PROFILE] = CF_STATUS_COMMAND;
563   sql_command_flags[SQLCOM_BINLOG_BASE64_EVENT] =
564       CF_STATUS_COMMAND | CF_CAN_GENERATE_ROW_EVENTS;
565 
566   sql_command_flags[SQLCOM_SHOW_TABLES] =
567       (CF_STATUS_COMMAND | CF_SHOW_TABLE_COMMAND | CF_HAS_RESULT_SET |
568        CF_REEXECUTION_FRAGILE);
569   sql_command_flags[SQLCOM_SHOW_TABLE_STATUS] =
570       (CF_STATUS_COMMAND | CF_SHOW_TABLE_COMMAND | CF_HAS_RESULT_SET |
571        CF_REEXECUTION_FRAGILE);
572   /**
573     ACL DDLs do not access data-dictionary tables. However, they still
574     need to be marked to avoid autocommit. This is necessary because
575     code which saves GTID state or slave state in the system tables
576     at commit time does statement commit on low-level (see
577     System_table_access::close_table()) and thus can pre-maturely commit
578     DDL otherwise.
579   */
580   sql_command_flags[SQLCOM_CREATE_USER] =
581       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
582   sql_command_flags[SQLCOM_RENAME_USER] =
583       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
584   sql_command_flags[SQLCOM_DROP_USER] =
585       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
586   sql_command_flags[SQLCOM_ALTER_USER] =
587       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
588   sql_command_flags[SQLCOM_GRANT] =
589       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
590   sql_command_flags[SQLCOM_REVOKE] =
591       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
592   sql_command_flags[SQLCOM_REVOKE_ALL] =
593       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
594   sql_command_flags[SQLCOM_ALTER_USER_DEFAULT_ROLE] =
595       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
596   sql_command_flags[SQLCOM_GRANT_ROLE] =
597       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
598   sql_command_flags[SQLCOM_REVOKE_ROLE] =
599       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
600   sql_command_flags[SQLCOM_DROP_ROLE] =
601       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
602   sql_command_flags[SQLCOM_CREATE_ROLE] =
603       CF_CHANGES_DATA | CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
604 
605   sql_command_flags[SQLCOM_OPTIMIZE] = CF_CHANGES_DATA;
606   sql_command_flags[SQLCOM_ALTER_INSTANCE] = CF_CHANGES_DATA;
607   sql_command_flags[SQLCOM_CREATE_FUNCTION] =
608       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
609   sql_command_flags[SQLCOM_CREATE_PROCEDURE] =
610       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
611   sql_command_flags[SQLCOM_CREATE_SPFUNCTION] =
612       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
613   sql_command_flags[SQLCOM_DROP_PROCEDURE] =
614       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
615   sql_command_flags[SQLCOM_DROP_FUNCTION] =
616       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
617   sql_command_flags[SQLCOM_ALTER_PROCEDURE] =
618       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
619   sql_command_flags[SQLCOM_ALTER_FUNCTION] =
620       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
621   sql_command_flags[SQLCOM_INSTALL_PLUGIN] =
622       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
623   sql_command_flags[SQLCOM_UNINSTALL_PLUGIN] =
624       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
625   sql_command_flags[SQLCOM_INSTALL_COMPONENT] =
626       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
627   sql_command_flags[SQLCOM_UNINSTALL_COMPONENT] =
628       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS;
629   sql_command_flags[SQLCOM_CREATE_RESOURCE_GROUP] =
630       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_ALLOW_PROTOCOL_PLUGIN;
631   sql_command_flags[SQLCOM_ALTER_RESOURCE_GROUP] =
632       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_ALLOW_PROTOCOL_PLUGIN;
633   sql_command_flags[SQLCOM_DROP_RESOURCE_GROUP] =
634       CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_ALLOW_PROTOCOL_PLUGIN;
635   sql_command_flags[SQLCOM_SET_RESOURCE_GROUP] =
636       CF_CHANGES_DATA | CF_ALLOW_PROTOCOL_PLUGIN;
637 
638   sql_command_flags[SQLCOM_CLONE] =
639       CF_AUTO_COMMIT_TRANS | CF_ALLOW_PROTOCOL_PLUGIN;
640 
641   /* Does not change the contents of the Diagnostics Area. */
642   sql_command_flags[SQLCOM_GET_DIAGNOSTICS] = CF_DIAGNOSTIC_STMT;
643 
644   /*
645     (1): without it, in "CALL some_proc((subq))", subquery would not be
646     traced.
647   */
648   sql_command_flags[SQLCOM_CALL] = CF_REEXECUTION_FRAGILE |
649                                    CF_CAN_GENERATE_ROW_EVENTS |
650                                    CF_OPTIMIZER_TRACE;  // (1)
651   sql_command_flags[SQLCOM_EXECUTE] = CF_CAN_GENERATE_ROW_EVENTS;
652 
653   /*
654     The following admin table operations are allowed
655     on log tables.
656   */
657   sql_command_flags[SQLCOM_REPAIR] =
658       CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
659   sql_command_flags[SQLCOM_OPTIMIZE] |=
660       CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
661   sql_command_flags[SQLCOM_ANALYZE] =
662       CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
663   sql_command_flags[SQLCOM_CHECK] =
664       CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS;
665 
666   sql_command_flags[SQLCOM_CREATE_USER] |= CF_AUTO_COMMIT_TRANS;
667   sql_command_flags[SQLCOM_CREATE_ROLE] |= CF_AUTO_COMMIT_TRANS;
668   sql_command_flags[SQLCOM_DROP_USER] |= CF_AUTO_COMMIT_TRANS;
669   sql_command_flags[SQLCOM_DROP_ROLE] |= CF_AUTO_COMMIT_TRANS;
670   sql_command_flags[SQLCOM_RENAME_USER] |= CF_AUTO_COMMIT_TRANS;
671   sql_command_flags[SQLCOM_ALTER_USER] |= CF_AUTO_COMMIT_TRANS;
672   sql_command_flags[SQLCOM_RESTART_SERVER] =
673       CF_AUTO_COMMIT_TRANS | CF_ALLOW_PROTOCOL_PLUGIN;
674   sql_command_flags[SQLCOM_REVOKE] |= CF_AUTO_COMMIT_TRANS;
675   sql_command_flags[SQLCOM_REVOKE_ALL] |= CF_AUTO_COMMIT_TRANS;
676   sql_command_flags[SQLCOM_REVOKE_ROLE] |= CF_AUTO_COMMIT_TRANS;
677   sql_command_flags[SQLCOM_GRANT] |= CF_AUTO_COMMIT_TRANS;
678   sql_command_flags[SQLCOM_GRANT_ROLE] |= CF_AUTO_COMMIT_TRANS;
679   sql_command_flags[SQLCOM_ALTER_USER_DEFAULT_ROLE] |= CF_AUTO_COMMIT_TRANS;
680 
681   sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE] = CF_AUTO_COMMIT_TRANS;
682   sql_command_flags[SQLCOM_PRELOAD_KEYS] = CF_AUTO_COMMIT_TRANS;
683   sql_command_flags[SQLCOM_ALTER_INSTANCE] |= CF_AUTO_COMMIT_TRANS;
684 
685   sql_command_flags[SQLCOM_FLUSH] = CF_AUTO_COMMIT_TRANS;
686   sql_command_flags[SQLCOM_RESET] = CF_AUTO_COMMIT_TRANS;
687   sql_command_flags[SQLCOM_CREATE_SERVER] = CF_AUTO_COMMIT_TRANS;
688   sql_command_flags[SQLCOM_ALTER_SERVER] = CF_AUTO_COMMIT_TRANS;
689   sql_command_flags[SQLCOM_DROP_SERVER] = CF_AUTO_COMMIT_TRANS;
690   sql_command_flags[SQLCOM_CHANGE_MASTER] = CF_AUTO_COMMIT_TRANS;
691   sql_command_flags[SQLCOM_CHANGE_REPLICATION_FILTER] = CF_AUTO_COMMIT_TRANS;
692   sql_command_flags[SQLCOM_SLAVE_START] = CF_AUTO_COMMIT_TRANS;
693   sql_command_flags[SQLCOM_SLAVE_STOP] = CF_AUTO_COMMIT_TRANS;
694   sql_command_flags[SQLCOM_ALTER_TABLESPACE] |= CF_AUTO_COMMIT_TRANS;
695   sql_command_flags[SQLCOM_CREATE_SRS] |= CF_AUTO_COMMIT_TRANS;
696   sql_command_flags[SQLCOM_DROP_SRS] |= CF_AUTO_COMMIT_TRANS;
697 
698   /*
699     The following statements can deal with temporary tables,
700     so temporary tables should be pre-opened for those statements to
701     simplify privilege checking.
702 
703     There are other statements that deal with temporary tables and open
704     them, but which are not listed here. The thing is that the order of
705     pre-opening temporary tables for those statements is somewhat custom.
706   */
707   sql_command_flags[SQLCOM_CREATE_TABLE] |= CF_PREOPEN_TMP_TABLES;
708   sql_command_flags[SQLCOM_DROP_TABLE] |= CF_PREOPEN_TMP_TABLES;
709   sql_command_flags[SQLCOM_CREATE_INDEX] |= CF_PREOPEN_TMP_TABLES;
710   sql_command_flags[SQLCOM_ALTER_TABLE] |= CF_PREOPEN_TMP_TABLES;
711   sql_command_flags[SQLCOM_TRUNCATE] |= CF_PREOPEN_TMP_TABLES;
712   sql_command_flags[SQLCOM_LOAD] |= CF_PREOPEN_TMP_TABLES;
713   sql_command_flags[SQLCOM_DROP_INDEX] |= CF_PREOPEN_TMP_TABLES;
714   sql_command_flags[SQLCOM_UPDATE] |= CF_PREOPEN_TMP_TABLES;
715   sql_command_flags[SQLCOM_UPDATE_MULTI] |= CF_PREOPEN_TMP_TABLES;
716   sql_command_flags[SQLCOM_INSERT] |= CF_PREOPEN_TMP_TABLES;
717   sql_command_flags[SQLCOM_INSERT_SELECT] |= CF_PREOPEN_TMP_TABLES;
718   sql_command_flags[SQLCOM_DELETE] |= CF_PREOPEN_TMP_TABLES;
719   sql_command_flags[SQLCOM_DELETE_MULTI] |= CF_PREOPEN_TMP_TABLES;
720   sql_command_flags[SQLCOM_REPLACE] |= CF_PREOPEN_TMP_TABLES;
721   sql_command_flags[SQLCOM_REPLACE_SELECT] |= CF_PREOPEN_TMP_TABLES;
722   sql_command_flags[SQLCOM_SELECT] |= CF_PREOPEN_TMP_TABLES;
723   sql_command_flags[SQLCOM_SET_OPTION] |= CF_PREOPEN_TMP_TABLES;
724   sql_command_flags[SQLCOM_DO] |= CF_PREOPEN_TMP_TABLES;
725   sql_command_flags[SQLCOM_CALL] |= CF_PREOPEN_TMP_TABLES;
726   sql_command_flags[SQLCOM_CHECKSUM] |= CF_PREOPEN_TMP_TABLES;
727   sql_command_flags[SQLCOM_ANALYZE] |= CF_PREOPEN_TMP_TABLES;
728   sql_command_flags[SQLCOM_CHECK] |= CF_PREOPEN_TMP_TABLES;
729   sql_command_flags[SQLCOM_OPTIMIZE] |= CF_PREOPEN_TMP_TABLES;
730   sql_command_flags[SQLCOM_REPAIR] |= CF_PREOPEN_TMP_TABLES;
731   sql_command_flags[SQLCOM_PRELOAD_KEYS] |= CF_PREOPEN_TMP_TABLES;
732   sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE] |= CF_PREOPEN_TMP_TABLES;
733 
734   /*
735     DDL statements that should start with closing opened handlers.
736 
737     We use this flag only for statements for which open HANDLERs
738     have to be closed before emporary tables are pre-opened.
739   */
740   sql_command_flags[SQLCOM_CREATE_TABLE] |= CF_HA_CLOSE;
741   sql_command_flags[SQLCOM_DROP_TABLE] |= CF_HA_CLOSE;
742   sql_command_flags[SQLCOM_ALTER_TABLE] |= CF_HA_CLOSE;
743   sql_command_flags[SQLCOM_TRUNCATE] |= CF_HA_CLOSE;
744   sql_command_flags[SQLCOM_REPAIR] |= CF_HA_CLOSE;
745   sql_command_flags[SQLCOM_OPTIMIZE] |= CF_HA_CLOSE;
746   sql_command_flags[SQLCOM_ANALYZE] |= CF_HA_CLOSE;
747   sql_command_flags[SQLCOM_CHECK] |= CF_HA_CLOSE;
748   sql_command_flags[SQLCOM_CREATE_INDEX] |= CF_HA_CLOSE;
749   sql_command_flags[SQLCOM_DROP_INDEX] |= CF_HA_CLOSE;
750   sql_command_flags[SQLCOM_PRELOAD_KEYS] |= CF_HA_CLOSE;
751   sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE] |= CF_HA_CLOSE;
752 
753   /*
754     Mark statements that always are disallowed in read-only
755     transactions. Note that according to the SQL standard,
756     even temporary table DDL should be disallowed.
757   */
758   sql_command_flags[SQLCOM_CREATE_TABLE] |= CF_DISALLOW_IN_RO_TRANS;
759   sql_command_flags[SQLCOM_ALTER_TABLE] |= CF_DISALLOW_IN_RO_TRANS;
760   sql_command_flags[SQLCOM_DROP_TABLE] |= CF_DISALLOW_IN_RO_TRANS;
761   sql_command_flags[SQLCOM_RENAME_TABLE] |= CF_DISALLOW_IN_RO_TRANS;
762   sql_command_flags[SQLCOM_CREATE_INDEX] |= CF_DISALLOW_IN_RO_TRANS;
763   sql_command_flags[SQLCOM_DROP_INDEX] |= CF_DISALLOW_IN_RO_TRANS;
764   sql_command_flags[SQLCOM_CREATE_DB] |= CF_DISALLOW_IN_RO_TRANS;
765   sql_command_flags[SQLCOM_DROP_DB] |= CF_DISALLOW_IN_RO_TRANS;
766   sql_command_flags[SQLCOM_ALTER_DB] |= CF_DISALLOW_IN_RO_TRANS;
767   sql_command_flags[SQLCOM_CREATE_VIEW] |= CF_DISALLOW_IN_RO_TRANS;
768   sql_command_flags[SQLCOM_DROP_VIEW] |= CF_DISALLOW_IN_RO_TRANS;
769   sql_command_flags[SQLCOM_CREATE_TRIGGER] |= CF_DISALLOW_IN_RO_TRANS;
770   sql_command_flags[SQLCOM_DROP_TRIGGER] |= CF_DISALLOW_IN_RO_TRANS;
771   sql_command_flags[SQLCOM_CREATE_EVENT] |= CF_DISALLOW_IN_RO_TRANS;
772   sql_command_flags[SQLCOM_ALTER_EVENT] |= CF_DISALLOW_IN_RO_TRANS;
773   sql_command_flags[SQLCOM_DROP_EVENT] |= CF_DISALLOW_IN_RO_TRANS;
774   sql_command_flags[SQLCOM_CREATE_USER] |= CF_DISALLOW_IN_RO_TRANS;
775   sql_command_flags[SQLCOM_CREATE_ROLE] |= CF_DISALLOW_IN_RO_TRANS;
776   sql_command_flags[SQLCOM_RENAME_USER] |= CF_DISALLOW_IN_RO_TRANS;
777   sql_command_flags[SQLCOM_ALTER_USER] |= CF_DISALLOW_IN_RO_TRANS;
778   sql_command_flags[SQLCOM_DROP_USER] |= CF_DISALLOW_IN_RO_TRANS;
779   sql_command_flags[SQLCOM_DROP_ROLE] |= CF_DISALLOW_IN_RO_TRANS;
780   sql_command_flags[SQLCOM_CREATE_SERVER] |= CF_DISALLOW_IN_RO_TRANS;
781   sql_command_flags[SQLCOM_ALTER_SERVER] |= CF_DISALLOW_IN_RO_TRANS;
782   sql_command_flags[SQLCOM_DROP_SERVER] |= CF_DISALLOW_IN_RO_TRANS;
783   sql_command_flags[SQLCOM_CREATE_FUNCTION] |= CF_DISALLOW_IN_RO_TRANS;
784   sql_command_flags[SQLCOM_CREATE_PROCEDURE] |= CF_DISALLOW_IN_RO_TRANS;
785   sql_command_flags[SQLCOM_CREATE_SPFUNCTION] |= CF_DISALLOW_IN_RO_TRANS;
786   sql_command_flags[SQLCOM_DROP_PROCEDURE] |= CF_DISALLOW_IN_RO_TRANS;
787   sql_command_flags[SQLCOM_DROP_FUNCTION] |= CF_DISALLOW_IN_RO_TRANS;
788   sql_command_flags[SQLCOM_ALTER_PROCEDURE] |= CF_DISALLOW_IN_RO_TRANS;
789   sql_command_flags[SQLCOM_ALTER_FUNCTION] |= CF_DISALLOW_IN_RO_TRANS;
790   sql_command_flags[SQLCOM_TRUNCATE] |= CF_DISALLOW_IN_RO_TRANS;
791   sql_command_flags[SQLCOM_ALTER_TABLESPACE] |= CF_DISALLOW_IN_RO_TRANS;
792   sql_command_flags[SQLCOM_REPAIR] |= CF_DISALLOW_IN_RO_TRANS;
793   sql_command_flags[SQLCOM_OPTIMIZE] |= CF_DISALLOW_IN_RO_TRANS;
794   sql_command_flags[SQLCOM_GRANT] |= CF_DISALLOW_IN_RO_TRANS;
795   sql_command_flags[SQLCOM_GRANT_ROLE] |= CF_DISALLOW_IN_RO_TRANS;
796   sql_command_flags[SQLCOM_REVOKE] |= CF_DISALLOW_IN_RO_TRANS;
797   sql_command_flags[SQLCOM_REVOKE_ALL] |= CF_DISALLOW_IN_RO_TRANS;
798   sql_command_flags[SQLCOM_REVOKE_ROLE] |= CF_DISALLOW_IN_RO_TRANS;
799   sql_command_flags[SQLCOM_INSTALL_PLUGIN] |= CF_DISALLOW_IN_RO_TRANS;
800   sql_command_flags[SQLCOM_UNINSTALL_PLUGIN] |= CF_DISALLOW_IN_RO_TRANS;
801   sql_command_flags[SQLCOM_INSTALL_COMPONENT] |= CF_DISALLOW_IN_RO_TRANS;
802   sql_command_flags[SQLCOM_UNINSTALL_COMPONENT] |= CF_DISALLOW_IN_RO_TRANS;
803   sql_command_flags[SQLCOM_ALTER_INSTANCE] |= CF_DISALLOW_IN_RO_TRANS;
804   sql_command_flags[SQLCOM_IMPORT] |= CF_DISALLOW_IN_RO_TRANS;
805   sql_command_flags[SQLCOM_CREATE_SRS] |= CF_DISALLOW_IN_RO_TRANS;
806   sql_command_flags[SQLCOM_DROP_SRS] |= CF_DISALLOW_IN_RO_TRANS;
807 
808   /*
809     Mark statements that are allowed to be executed by the plugins.
810   */
811   sql_command_flags[SQLCOM_SELECT] |= CF_ALLOW_PROTOCOL_PLUGIN;
812   sql_command_flags[SQLCOM_CREATE_TABLE] |= CF_ALLOW_PROTOCOL_PLUGIN;
813   sql_command_flags[SQLCOM_CREATE_INDEX] |= CF_ALLOW_PROTOCOL_PLUGIN;
814   sql_command_flags[SQLCOM_ALTER_TABLE] |= CF_ALLOW_PROTOCOL_PLUGIN;
815   sql_command_flags[SQLCOM_UPDATE] |= CF_ALLOW_PROTOCOL_PLUGIN;
816   sql_command_flags[SQLCOM_INSERT] |= CF_ALLOW_PROTOCOL_PLUGIN;
817   sql_command_flags[SQLCOM_INSERT_SELECT] |= CF_ALLOW_PROTOCOL_PLUGIN;
818   sql_command_flags[SQLCOM_DELETE] |= CF_ALLOW_PROTOCOL_PLUGIN;
819   sql_command_flags[SQLCOM_TRUNCATE] |= CF_ALLOW_PROTOCOL_PLUGIN;
820   sql_command_flags[SQLCOM_DROP_TABLE] |= CF_ALLOW_PROTOCOL_PLUGIN;
821   sql_command_flags[SQLCOM_DROP_INDEX] |= CF_ALLOW_PROTOCOL_PLUGIN;
822   sql_command_flags[SQLCOM_SHOW_DATABASES] |= CF_ALLOW_PROTOCOL_PLUGIN;
823   sql_command_flags[SQLCOM_SHOW_TABLES] |= CF_ALLOW_PROTOCOL_PLUGIN;
824   sql_command_flags[SQLCOM_SHOW_FIELDS] |= CF_ALLOW_PROTOCOL_PLUGIN;
825   sql_command_flags[SQLCOM_SHOW_KEYS] |= CF_ALLOW_PROTOCOL_PLUGIN;
826   sql_command_flags[SQLCOM_SHOW_VARIABLES] |= CF_ALLOW_PROTOCOL_PLUGIN;
827   sql_command_flags[SQLCOM_SHOW_STATUS] |= CF_ALLOW_PROTOCOL_PLUGIN;
828   sql_command_flags[SQLCOM_SHOW_ENGINE_LOGS] |= CF_ALLOW_PROTOCOL_PLUGIN;
829   sql_command_flags[SQLCOM_SHOW_ENGINE_STATUS] |= CF_ALLOW_PROTOCOL_PLUGIN;
830   sql_command_flags[SQLCOM_SHOW_ENGINE_MUTEX] |= CF_ALLOW_PROTOCOL_PLUGIN;
831   sql_command_flags[SQLCOM_SHOW_PROCESSLIST] |= CF_ALLOW_PROTOCOL_PLUGIN;
832   sql_command_flags[SQLCOM_SHOW_MASTER_STAT] |= CF_ALLOW_PROTOCOL_PLUGIN;
833   sql_command_flags[SQLCOM_SHOW_SLAVE_STAT] |= CF_ALLOW_PROTOCOL_PLUGIN;
834   sql_command_flags[SQLCOM_SHOW_GRANTS] |= CF_ALLOW_PROTOCOL_PLUGIN;
835   sql_command_flags[SQLCOM_SHOW_CREATE] |= CF_ALLOW_PROTOCOL_PLUGIN;
836   sql_command_flags[SQLCOM_SHOW_CHARSETS] |= CF_ALLOW_PROTOCOL_PLUGIN;
837   sql_command_flags[SQLCOM_SHOW_COLLATIONS] |= CF_ALLOW_PROTOCOL_PLUGIN;
838   sql_command_flags[SQLCOM_SHOW_CREATE_DB] |= CF_ALLOW_PROTOCOL_PLUGIN;
839   sql_command_flags[SQLCOM_SHOW_TABLE_STATUS] |= CF_ALLOW_PROTOCOL_PLUGIN;
840   sql_command_flags[SQLCOM_SHOW_TRIGGERS] |= CF_ALLOW_PROTOCOL_PLUGIN;
841   sql_command_flags[SQLCOM_LOAD] |= CF_ALLOW_PROTOCOL_PLUGIN;
842   sql_command_flags[SQLCOM_SET_OPTION] |= CF_ALLOW_PROTOCOL_PLUGIN;
843   sql_command_flags[SQLCOM_LOCK_TABLES] |= CF_ALLOW_PROTOCOL_PLUGIN;
844   sql_command_flags[SQLCOM_UNLOCK_TABLES] |= CF_ALLOW_PROTOCOL_PLUGIN;
845   sql_command_flags[SQLCOM_GRANT] |= CF_ALLOW_PROTOCOL_PLUGIN;
846   sql_command_flags[SQLCOM_CHANGE_DB] |= CF_ALLOW_PROTOCOL_PLUGIN;
847   sql_command_flags[SQLCOM_CREATE_DB] |= CF_ALLOW_PROTOCOL_PLUGIN;
848   sql_command_flags[SQLCOM_DROP_DB] |= CF_ALLOW_PROTOCOL_PLUGIN;
849   sql_command_flags[SQLCOM_ALTER_DB] |= CF_ALLOW_PROTOCOL_PLUGIN;
850   sql_command_flags[SQLCOM_REPAIR] |= CF_ALLOW_PROTOCOL_PLUGIN;
851   sql_command_flags[SQLCOM_REPLACE] |= CF_ALLOW_PROTOCOL_PLUGIN;
852   sql_command_flags[SQLCOM_REPLACE_SELECT] |= CF_ALLOW_PROTOCOL_PLUGIN;
853   sql_command_flags[SQLCOM_CREATE_FUNCTION] |= CF_ALLOW_PROTOCOL_PLUGIN;
854   sql_command_flags[SQLCOM_DROP_FUNCTION] |= CF_ALLOW_PROTOCOL_PLUGIN;
855   sql_command_flags[SQLCOM_REVOKE] |= CF_ALLOW_PROTOCOL_PLUGIN;
856   sql_command_flags[SQLCOM_OPTIMIZE] |= CF_ALLOW_PROTOCOL_PLUGIN;
857   sql_command_flags[SQLCOM_CHECK] |= CF_ALLOW_PROTOCOL_PLUGIN;
858   sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE] |= CF_ALLOW_PROTOCOL_PLUGIN;
859   sql_command_flags[SQLCOM_PRELOAD_KEYS] |= CF_ALLOW_PROTOCOL_PLUGIN;
860   sql_command_flags[SQLCOM_FLUSH] |= CF_ALLOW_PROTOCOL_PLUGIN;
861   sql_command_flags[SQLCOM_KILL] |= CF_ALLOW_PROTOCOL_PLUGIN;
862   sql_command_flags[SQLCOM_ANALYZE] |= CF_ALLOW_PROTOCOL_PLUGIN;
863   sql_command_flags[SQLCOM_ROLLBACK] |= CF_ALLOW_PROTOCOL_PLUGIN;
864   sql_command_flags[SQLCOM_ROLLBACK_TO_SAVEPOINT] |= CF_ALLOW_PROTOCOL_PLUGIN;
865   sql_command_flags[SQLCOM_COMMIT] |= CF_ALLOW_PROTOCOL_PLUGIN;
866   sql_command_flags[SQLCOM_SAVEPOINT] |= CF_ALLOW_PROTOCOL_PLUGIN;
867   sql_command_flags[SQLCOM_RELEASE_SAVEPOINT] |= CF_ALLOW_PROTOCOL_PLUGIN;
868   sql_command_flags[SQLCOM_SLAVE_START] |= CF_ALLOW_PROTOCOL_PLUGIN;
869   sql_command_flags[SQLCOM_SLAVE_STOP] |= CF_ALLOW_PROTOCOL_PLUGIN;
870   sql_command_flags[SQLCOM_START_GROUP_REPLICATION] |= CF_ALLOW_PROTOCOL_PLUGIN;
871   sql_command_flags[SQLCOM_STOP_GROUP_REPLICATION] |= CF_ALLOW_PROTOCOL_PLUGIN;
872   sql_command_flags[SQLCOM_BEGIN] |= CF_ALLOW_PROTOCOL_PLUGIN;
873   sql_command_flags[SQLCOM_CHANGE_MASTER] |= CF_ALLOW_PROTOCOL_PLUGIN;
874   sql_command_flags[SQLCOM_CHANGE_REPLICATION_FILTER] |=
875       CF_ALLOW_PROTOCOL_PLUGIN;
876   sql_command_flags[SQLCOM_RENAME_TABLE] |= CF_ALLOW_PROTOCOL_PLUGIN;
877   sql_command_flags[SQLCOM_RESET] |= CF_ALLOW_PROTOCOL_PLUGIN;
878   sql_command_flags[SQLCOM_PURGE] |= CF_ALLOW_PROTOCOL_PLUGIN;
879   sql_command_flags[SQLCOM_PURGE_BEFORE] |= CF_ALLOW_PROTOCOL_PLUGIN;
880   sql_command_flags[SQLCOM_SHOW_BINLOGS] |= CF_ALLOW_PROTOCOL_PLUGIN;
881   sql_command_flags[SQLCOM_SHOW_OPEN_TABLES] |= CF_ALLOW_PROTOCOL_PLUGIN;
882   sql_command_flags[SQLCOM_HA_OPEN] |= CF_ALLOW_PROTOCOL_PLUGIN;
883   sql_command_flags[SQLCOM_HA_CLOSE] |= CF_ALLOW_PROTOCOL_PLUGIN;
884   sql_command_flags[SQLCOM_HA_READ] |= CF_ALLOW_PROTOCOL_PLUGIN;
885   sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS] |= CF_ALLOW_PROTOCOL_PLUGIN;
886   sql_command_flags[SQLCOM_DELETE_MULTI] |= CF_ALLOW_PROTOCOL_PLUGIN;
887   sql_command_flags[SQLCOM_UPDATE_MULTI] |= CF_ALLOW_PROTOCOL_PLUGIN;
888   sql_command_flags[SQLCOM_SHOW_BINLOG_EVENTS] |= CF_ALLOW_PROTOCOL_PLUGIN;
889   sql_command_flags[SQLCOM_DO] |= CF_ALLOW_PROTOCOL_PLUGIN;
890   sql_command_flags[SQLCOM_SHOW_WARNS] |= CF_ALLOW_PROTOCOL_PLUGIN;
891   sql_command_flags[SQLCOM_EMPTY_QUERY] |= CF_ALLOW_PROTOCOL_PLUGIN;
892   sql_command_flags[SQLCOM_SHOW_ERRORS] |= CF_ALLOW_PROTOCOL_PLUGIN;
893   sql_command_flags[SQLCOM_SHOW_STORAGE_ENGINES] |= CF_ALLOW_PROTOCOL_PLUGIN;
894   sql_command_flags[SQLCOM_SHOW_PRIVILEGES] |= CF_ALLOW_PROTOCOL_PLUGIN;
895   sql_command_flags[SQLCOM_HELP] |= CF_ALLOW_PROTOCOL_PLUGIN;
896   sql_command_flags[SQLCOM_CREATE_USER] |= CF_ALLOW_PROTOCOL_PLUGIN;
897   sql_command_flags[SQLCOM_DROP_USER] |= CF_ALLOW_PROTOCOL_PLUGIN;
898   sql_command_flags[SQLCOM_RENAME_USER] |= CF_ALLOW_PROTOCOL_PLUGIN;
899   sql_command_flags[SQLCOM_REVOKE_ALL] |= CF_ALLOW_PROTOCOL_PLUGIN;
900   sql_command_flags[SQLCOM_CHECKSUM] |= CF_ALLOW_PROTOCOL_PLUGIN;
901   sql_command_flags[SQLCOM_CREATE_PROCEDURE] |= CF_ALLOW_PROTOCOL_PLUGIN;
902   sql_command_flags[SQLCOM_CREATE_SPFUNCTION] |= CF_ALLOW_PROTOCOL_PLUGIN;
903   sql_command_flags[SQLCOM_CALL] |= CF_ALLOW_PROTOCOL_PLUGIN;
904   sql_command_flags[SQLCOM_DROP_PROCEDURE] |= CF_ALLOW_PROTOCOL_PLUGIN;
905   sql_command_flags[SQLCOM_ALTER_PROCEDURE] |= CF_ALLOW_PROTOCOL_PLUGIN;
906   sql_command_flags[SQLCOM_ALTER_FUNCTION] |= CF_ALLOW_PROTOCOL_PLUGIN;
907   sql_command_flags[SQLCOM_SHOW_CREATE_PROC] |= CF_ALLOW_PROTOCOL_PLUGIN;
908   sql_command_flags[SQLCOM_SHOW_CREATE_FUNC] |= CF_ALLOW_PROTOCOL_PLUGIN;
909   sql_command_flags[SQLCOM_SHOW_STATUS_PROC] |= CF_ALLOW_PROTOCOL_PLUGIN;
910   sql_command_flags[SQLCOM_SHOW_STATUS_FUNC] |= CF_ALLOW_PROTOCOL_PLUGIN;
911   sql_command_flags[SQLCOM_PREPARE] |= CF_ALLOW_PROTOCOL_PLUGIN;
912   sql_command_flags[SQLCOM_EXECUTE] |= CF_ALLOW_PROTOCOL_PLUGIN;
913   sql_command_flags[SQLCOM_DEALLOCATE_PREPARE] |= CF_ALLOW_PROTOCOL_PLUGIN;
914   sql_command_flags[SQLCOM_CREATE_VIEW] |= CF_ALLOW_PROTOCOL_PLUGIN;
915   sql_command_flags[SQLCOM_DROP_VIEW] |= CF_ALLOW_PROTOCOL_PLUGIN;
916   sql_command_flags[SQLCOM_CREATE_TRIGGER] |= CF_ALLOW_PROTOCOL_PLUGIN;
917   sql_command_flags[SQLCOM_DROP_TRIGGER] |= CF_ALLOW_PROTOCOL_PLUGIN;
918   sql_command_flags[SQLCOM_XA_START] |= CF_ALLOW_PROTOCOL_PLUGIN;
919   sql_command_flags[SQLCOM_XA_END] |= CF_ALLOW_PROTOCOL_PLUGIN;
920   sql_command_flags[SQLCOM_XA_PREPARE] |= CF_ALLOW_PROTOCOL_PLUGIN;
921   sql_command_flags[SQLCOM_XA_COMMIT] |= CF_ALLOW_PROTOCOL_PLUGIN;
922   sql_command_flags[SQLCOM_XA_ROLLBACK] |= CF_ALLOW_PROTOCOL_PLUGIN;
923   sql_command_flags[SQLCOM_XA_RECOVER] |= CF_ALLOW_PROTOCOL_PLUGIN;
924   sql_command_flags[SQLCOM_SHOW_PROC_CODE] |= CF_ALLOW_PROTOCOL_PLUGIN;
925   sql_command_flags[SQLCOM_SHOW_FUNC_CODE] |= CF_ALLOW_PROTOCOL_PLUGIN;
926   sql_command_flags[SQLCOM_ALTER_TABLESPACE] |= CF_ALLOW_PROTOCOL_PLUGIN;
927   sql_command_flags[SQLCOM_BINLOG_BASE64_EVENT] |= CF_ALLOW_PROTOCOL_PLUGIN;
928   sql_command_flags[SQLCOM_SHOW_PLUGINS] |= CF_ALLOW_PROTOCOL_PLUGIN;
929   sql_command_flags[SQLCOM_CREATE_SERVER] |= CF_ALLOW_PROTOCOL_PLUGIN;
930   sql_command_flags[SQLCOM_DROP_SERVER] |= CF_ALLOW_PROTOCOL_PLUGIN;
931   sql_command_flags[SQLCOM_ALTER_SERVER] |= CF_ALLOW_PROTOCOL_PLUGIN;
932   sql_command_flags[SQLCOM_CREATE_EVENT] |= CF_ALLOW_PROTOCOL_PLUGIN;
933   sql_command_flags[SQLCOM_ALTER_EVENT] |= CF_ALLOW_PROTOCOL_PLUGIN;
934   sql_command_flags[SQLCOM_DROP_EVENT] |= CF_ALLOW_PROTOCOL_PLUGIN;
935   sql_command_flags[SQLCOM_SHOW_CREATE_EVENT] |= CF_ALLOW_PROTOCOL_PLUGIN;
936   sql_command_flags[SQLCOM_SHOW_EVENTS] |= CF_ALLOW_PROTOCOL_PLUGIN;
937   sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER] |= CF_ALLOW_PROTOCOL_PLUGIN;
938   sql_command_flags[SQLCOM_SHOW_PROFILE] |= CF_ALLOW_PROTOCOL_PLUGIN;
939   sql_command_flags[SQLCOM_SHOW_PROFILES] |= CF_ALLOW_PROTOCOL_PLUGIN;
940   sql_command_flags[SQLCOM_SIGNAL] |= CF_ALLOW_PROTOCOL_PLUGIN;
941   sql_command_flags[SQLCOM_RESIGNAL] |= CF_ALLOW_PROTOCOL_PLUGIN;
942   sql_command_flags[SQLCOM_SHOW_RELAYLOG_EVENTS] |= CF_ALLOW_PROTOCOL_PLUGIN;
943   sql_command_flags[SQLCOM_GET_DIAGNOSTICS] |= CF_ALLOW_PROTOCOL_PLUGIN;
944   sql_command_flags[SQLCOM_ALTER_USER] |= CF_ALLOW_PROTOCOL_PLUGIN;
945   sql_command_flags[SQLCOM_EXPLAIN_OTHER] |= CF_ALLOW_PROTOCOL_PLUGIN;
946   sql_command_flags[SQLCOM_SHOW_CREATE_USER] |= CF_ALLOW_PROTOCOL_PLUGIN;
947   sql_command_flags[SQLCOM_SET_PASSWORD] |= CF_ALLOW_PROTOCOL_PLUGIN;
948   sql_command_flags[SQLCOM_DROP_ROLE] |= CF_ALLOW_PROTOCOL_PLUGIN;
949   sql_command_flags[SQLCOM_CREATE_ROLE] |= CF_ALLOW_PROTOCOL_PLUGIN;
950   sql_command_flags[SQLCOM_SET_ROLE] |= CF_ALLOW_PROTOCOL_PLUGIN;
951   sql_command_flags[SQLCOM_GRANT_ROLE] |= CF_ALLOW_PROTOCOL_PLUGIN;
952   sql_command_flags[SQLCOM_REVOKE_ROLE] |= CF_ALLOW_PROTOCOL_PLUGIN;
953   sql_command_flags[SQLCOM_ALTER_USER_DEFAULT_ROLE] |= CF_ALLOW_PROTOCOL_PLUGIN;
954   sql_command_flags[SQLCOM_IMPORT] |= CF_ALLOW_PROTOCOL_PLUGIN;
955   sql_command_flags[SQLCOM_END] |= CF_ALLOW_PROTOCOL_PLUGIN;
956   sql_command_flags[SQLCOM_CREATE_SRS] |= CF_ALLOW_PROTOCOL_PLUGIN;
957   sql_command_flags[SQLCOM_DROP_SRS] |= CF_ALLOW_PROTOCOL_PLUGIN;
958 
959   /*
960     Mark DDL statements which require that auto-commit mode to be temporarily
961     turned off. See sqlcom_needs_autocommit_off() for more details.
962 
963     CREATE TABLE and DROP TABLE are not marked as such as they have special
964     variants dealing with temporary tables which don't update data-dictionary
965     at all and which should be allowed in the middle of transaction.
966   */
967   sql_command_flags[SQLCOM_CREATE_INDEX] |=
968       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
969   sql_command_flags[SQLCOM_ALTER_TABLE] |=
970       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
971   sql_command_flags[SQLCOM_TRUNCATE] |=
972       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
973   sql_command_flags[SQLCOM_DROP_INDEX] |=
974       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
975   sql_command_flags[SQLCOM_CREATE_DB] |=
976       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
977   sql_command_flags[SQLCOM_DROP_DB] |=
978       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
979   sql_command_flags[SQLCOM_ALTER_DB] |=
980       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
981   sql_command_flags[SQLCOM_REPAIR] |= CF_NEEDS_AUTOCOMMIT_OFF;
982   sql_command_flags[SQLCOM_OPTIMIZE] |= CF_NEEDS_AUTOCOMMIT_OFF;
983   sql_command_flags[SQLCOM_RENAME_TABLE] |=
984       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
985   sql_command_flags[SQLCOM_CREATE_VIEW] |=
986       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
987   sql_command_flags[SQLCOM_DROP_VIEW] |=
988       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
989   sql_command_flags[SQLCOM_ALTER_TABLESPACE] |=
990       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
991   sql_command_flags[SQLCOM_CREATE_SPFUNCTION] |=
992       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
993   sql_command_flags[SQLCOM_DROP_FUNCTION] |=
994       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
995   sql_command_flags[SQLCOM_ALTER_FUNCTION] |=
996       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
997   sql_command_flags[SQLCOM_CREATE_FUNCTION] |=
998       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
999   sql_command_flags[SQLCOM_CREATE_PROCEDURE] |=
1000       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1001   sql_command_flags[SQLCOM_DROP_PROCEDURE] |=
1002       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1003   sql_command_flags[SQLCOM_ALTER_PROCEDURE] |=
1004       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1005   sql_command_flags[SQLCOM_CREATE_TRIGGER] |=
1006       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1007   sql_command_flags[SQLCOM_DROP_TRIGGER] |=
1008       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1009   sql_command_flags[SQLCOM_IMPORT] |=
1010       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1011   sql_command_flags[SQLCOM_INSTALL_PLUGIN] |= CF_NEEDS_AUTOCOMMIT_OFF;
1012   sql_command_flags[SQLCOM_UNINSTALL_PLUGIN] |= CF_NEEDS_AUTOCOMMIT_OFF;
1013   sql_command_flags[SQLCOM_CREATE_EVENT] |=
1014       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1015   sql_command_flags[SQLCOM_ALTER_EVENT] |=
1016       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1017   sql_command_flags[SQLCOM_DROP_EVENT] |=
1018       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1019   sql_command_flags[SQLCOM_CREATE_SRS] |=
1020       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1021   sql_command_flags[SQLCOM_DROP_SRS] |=
1022       CF_NEEDS_AUTOCOMMIT_OFF | CF_POTENTIAL_ATOMIC_DDL;
1023 
1024   /*
1025     Mark these statements as SHOW commands using INFORMATION_SCHEMA system
1026     views.
1027   */
1028   sql_command_flags[SQLCOM_SHOW_CHARSETS] |= CF_SHOW_USES_SYSTEM_VIEW;
1029   sql_command_flags[SQLCOM_SHOW_COLLATIONS] |= CF_SHOW_USES_SYSTEM_VIEW;
1030   sql_command_flags[SQLCOM_SHOW_DATABASES] |= CF_SHOW_USES_SYSTEM_VIEW;
1031   sql_command_flags[SQLCOM_SHOW_TABLES] |= CF_SHOW_USES_SYSTEM_VIEW;
1032   sql_command_flags[SQLCOM_SHOW_TABLE_STATUS] |= CF_SHOW_USES_SYSTEM_VIEW;
1033   sql_command_flags[SQLCOM_SHOW_FIELDS] |= CF_SHOW_USES_SYSTEM_VIEW;
1034   sql_command_flags[SQLCOM_SHOW_KEYS] |= CF_SHOW_USES_SYSTEM_VIEW;
1035   sql_command_flags[SQLCOM_SHOW_EVENTS] |= CF_SHOW_USES_SYSTEM_VIEW;
1036   sql_command_flags[SQLCOM_SHOW_TRIGGERS] |= CF_SHOW_USES_SYSTEM_VIEW;
1037   sql_command_flags[SQLCOM_SHOW_STATUS_PROC] |= CF_SHOW_USES_SYSTEM_VIEW;
1038   sql_command_flags[SQLCOM_SHOW_STATUS_FUNC] |= CF_SHOW_USES_SYSTEM_VIEW;
1039 
1040   /**
1041     Some statements doesn't if the ACL CACHE is disabled using the
1042     --skip-grant-tables server option.
1043   */
1044   sql_command_flags[SQLCOM_SET_ROLE] |= CF_REQUIRE_ACL_CACHE;
1045   sql_command_flags[SQLCOM_ALTER_USER_DEFAULT_ROLE] |= CF_REQUIRE_ACL_CACHE;
1046   sql_command_flags[SQLCOM_CREATE_ROLE] |= CF_REQUIRE_ACL_CACHE;
1047   sql_command_flags[SQLCOM_DROP_ROLE] |= CF_REQUIRE_ACL_CACHE;
1048   sql_command_flags[SQLCOM_GRANT_ROLE] |= CF_REQUIRE_ACL_CACHE;
1049   sql_command_flags[SQLCOM_ALTER_USER] |= CF_REQUIRE_ACL_CACHE;
1050   sql_command_flags[SQLCOM_GRANT] |= CF_REQUIRE_ACL_CACHE;
1051   sql_command_flags[SQLCOM_REVOKE] |= CF_REQUIRE_ACL_CACHE;
1052   sql_command_flags[SQLCOM_REVOKE_ALL] |= CF_REQUIRE_ACL_CACHE;
1053   sql_command_flags[SQLCOM_REVOKE_ROLE] |= CF_REQUIRE_ACL_CACHE;
1054   sql_command_flags[SQLCOM_CREATE_USER] |= CF_REQUIRE_ACL_CACHE;
1055   sql_command_flags[SQLCOM_DROP_USER] |= CF_REQUIRE_ACL_CACHE;
1056   sql_command_flags[SQLCOM_RENAME_USER] |= CF_REQUIRE_ACL_CACHE;
1057   sql_command_flags[SQLCOM_SHOW_GRANTS] |= CF_REQUIRE_ACL_CACHE;
1058   sql_command_flags[SQLCOM_SET_PASSWORD] |= CF_REQUIRE_ACL_CACHE;
1059 }
1060 
sqlcom_can_generate_row_events(enum enum_sql_command command)1061 bool sqlcom_can_generate_row_events(enum enum_sql_command command) {
1062   return (sql_command_flags[command] & CF_CAN_GENERATE_ROW_EVENTS);
1063 }
1064 
is_update_query(enum enum_sql_command command)1065 bool is_update_query(enum enum_sql_command command) {
1066   DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
1067   return (sql_command_flags[command] & CF_CHANGES_DATA) != 0;
1068 }
1069 
is_explainable_query(enum enum_sql_command command)1070 bool is_explainable_query(enum enum_sql_command command) {
1071   DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
1072   return (sql_command_flags[command] & CF_CAN_BE_EXPLAINED) != 0;
1073 }
1074 
1075 /**
1076   Check if a sql command is allowed to write to log tables.
1077   @param command The SQL command
1078   @return true if writing is allowed
1079 */
is_log_table_write_query(enum enum_sql_command command)1080 bool is_log_table_write_query(enum enum_sql_command command) {
1081   DBUG_ASSERT(command >= 0 && command <= SQLCOM_END);
1082   return (sql_command_flags[command] & CF_WRITE_LOGS_COMMAND) != 0;
1083 }
1084 
1085 /**
1086   Check if statement (typically DDL) needs auto-commit mode temporarily
1087   turned off.
1088 
1089   @note This is necessary to prevent InnoDB from automatically committing
1090         InnoDB transaction each time data-dictionary tables are closed
1091         after being updated.
1092 */
sqlcom_needs_autocommit_off(const LEX * lex)1093 static bool sqlcom_needs_autocommit_off(const LEX *lex) {
1094   return (sql_command_flags[lex->sql_command] & CF_NEEDS_AUTOCOMMIT_OFF) ||
1095          (lex->sql_command == SQLCOM_CREATE_TABLE &&
1096           !(lex->create_info->options & HA_LEX_CREATE_TMP_TABLE)) ||
1097          (lex->sql_command == SQLCOM_DROP_TABLE && !lex->drop_temporary);
1098 }
1099 
execute_init_command(THD * thd,LEX_STRING * init_command,mysql_rwlock_t * var_lock)1100 void execute_init_command(THD *thd, LEX_STRING *init_command,
1101                           mysql_rwlock_t *var_lock) {
1102   Protocol_classic *protocol = thd->get_protocol_classic();
1103   Vio *save_vio;
1104   ulong save_client_capabilities;
1105   COM_DATA com_data;
1106 
1107   mysql_rwlock_rdlock(var_lock);
1108   if (!init_command->length) {
1109     mysql_rwlock_unlock(var_lock);
1110     return;
1111   }
1112 
1113   /*
1114     copy the value under a lock, and release the lock.
1115     init_command has to be executed without a lock held,
1116     as it may try to change itself
1117   */
1118   size_t len = init_command->length;
1119   char *buf = thd->strmake(init_command->str, len);
1120   mysql_rwlock_unlock(var_lock);
1121 
1122 #if defined(ENABLED_PROFILING)
1123   thd->profiling->start_new_query();
1124   thd->profiling->set_query_source(buf, len);
1125 #endif
1126 
1127   THD_STAGE_INFO(thd, stage_execution_of_init_command);
1128   save_client_capabilities = protocol->get_client_capabilities();
1129   protocol->add_client_capability(CLIENT_MULTI_QUERIES);
1130   /*
1131     We don't need return result of execution to client side.
1132     To forbid this we should set thd->net.vio to 0.
1133   */
1134   save_vio = protocol->get_vio();
1135   protocol->set_vio(nullptr);
1136   protocol->create_command(&com_data, COM_QUERY, (uchar *)buf, len);
1137   dispatch_command(thd, &com_data, COM_QUERY);
1138   protocol->set_client_capabilities(save_client_capabilities);
1139   protocol->set_vio(save_vio);
1140 
1141 #if defined(ENABLED_PROFILING)
1142   thd->profiling->finish_current_query();
1143 #endif
1144 }
1145 
1146 /* This works because items are allocated with (*THR_MALLOC)->Alloc() */
1147 
free_items(Item * item)1148 void free_items(Item *item) {
1149   Item *next;
1150   DBUG_TRACE;
1151   for (; item; item = next) {
1152     next = item->next_free;
1153     item->delete_self();
1154   }
1155 }
1156 
1157 /**
1158    This works because items are allocated with (*THR_MALLOC)->Alloc().
1159    @note The function also handles null pointers (empty list).
1160 */
cleanup_items(Item * item)1161 void cleanup_items(Item *item) {
1162   DBUG_TRACE;
1163   for (; item; item = item->next_free) item->cleanup();
1164 }
1165 
1166 /**
1167   Read one command from connection and execute it (query or simple command).
1168   This function is called in loop from thread function.
1169 
1170   For profiling to work, it must never be called recursively.
1171 
1172   @retval
1173     0  success
1174   @retval
1175     1  request of thread shutdown (see dispatch_command() description)
1176 */
1177 
do_command(THD * thd)1178 bool do_command(THD *thd) {
1179   bool return_value;
1180   int rc;
1181   NET *net = nullptr;
1182   enum enum_server_command command;
1183   COM_DATA com_data;
1184   DBUG_TRACE;
1185   DBUG_ASSERT(thd->is_classic_protocol());
1186 
1187   /*
1188     indicator of uninitialized lex => normal flow of errors handling
1189     (see my_message_sql)
1190   */
1191   thd->lex->set_current_select(nullptr);
1192 
1193   /*
1194     XXX: this code is here only to clear possible errors of init_connect.
1195     Consider moving to prepare_new_connection_state() instead.
1196     That requires making sure the DA is cleared before non-parsing statements
1197     such as COM_QUIT.
1198   */
1199   thd->clear_error();  // Clear error message
1200   thd->get_stmt_da()->reset_diagnostics_area();
1201 
1202   /*
1203     This thread will do a blocking read from the client which
1204     will be interrupted when the next command is received from
1205     the client, the connection is closed or "net_wait_timeout"
1206     number of seconds has passed.
1207   */
1208   net = thd->get_protocol_classic()->get_net();
1209   my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
1210   net_new_transaction(net);
1211 
1212   /*
1213     Synchronization point for testing of KILL_CONNECTION.
1214     This sync point can wait here, to simulate slow code execution
1215     between the last test of thd->killed and blocking in read().
1216 
1217     The goal of this test is to verify that a connection does not
1218     hang, if it is killed at this point of execution.
1219     (Bug#37780 - main.kill fails randomly)
1220 
1221     Note that the sync point wait itself will be terminated by a
1222     kill. In this case it consumes a condition broadcast, but does
1223     not change anything else. The consumed broadcast should not
1224     matter here, because the read/recv() below doesn't use it.
1225   */
1226   DEBUG_SYNC(thd, "before_do_command_net_read");
1227 
1228   /*
1229     Because of networking layer callbacks in place,
1230     this call will maintain the following instrumentation:
1231     - IDLE events
1232     - SOCKET events
1233     - STATEMENT events
1234     - STAGE events
1235     when reading a new network packet.
1236     In particular, a new instrumented statement is started.
1237     See init_net_server_extension()
1238   */
1239   thd->m_server_idle = true;
1240   rc = thd->get_protocol()->get_command(&com_data, &command);
1241   thd->m_server_idle = false;
1242 
1243   if (rc) {
1244 #ifndef DBUG_OFF
1245     char desc[VIO_DESCRIPTION_SIZE];
1246     vio_description(net->vio, desc);
1247     DBUG_PRINT("info", ("Got error %d reading command from socket %s",
1248                         net->error, desc));
1249 #endif  // DBUG_OFF
1250     /* Instrument this broken statement as "statement/com/error" */
1251     thd->m_statement_psi = MYSQL_REFINE_STATEMENT(
1252         thd->m_statement_psi, com_statement_info[COM_END].m_key);
1253 
1254     /* Check if we can continue without closing the connection */
1255 
1256     /* The error must be set. */
1257     DBUG_ASSERT(thd->is_error());
1258     thd->send_statement_status();
1259 
1260     /* Mark the statement completed. */
1261     MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
1262     thd->m_statement_psi = nullptr;
1263     thd->m_digest = nullptr;
1264 
1265     if (rc < 0) {
1266       return_value = true;  // We have to close it.
1267       goto out;
1268     }
1269     net->error = 0;
1270     return_value = false;
1271     goto out;
1272   }
1273 
1274 #ifndef DBUG_OFF
1275   char desc[VIO_DESCRIPTION_SIZE];
1276   vio_description(net->vio, desc);
1277   DBUG_PRINT("info", ("Command on %s = %d (%s)", desc, command,
1278                       command_name[command].str));
1279 #endif  // DBUG_OFF
1280   DBUG_PRINT("info", ("packet: '%*.s'; command: %d",
1281                       (int)thd->get_protocol_classic()->get_packet_length(),
1282                       thd->get_protocol_classic()->get_raw_packet(), command));
1283   if (thd->get_protocol_classic()->bad_packet)
1284     DBUG_ASSERT(0);  // Should be caught earlier
1285 
1286   // Reclaim some memory
1287   thd->get_protocol_classic()->get_output_packet()->shrink(
1288       thd->variables.net_buffer_length);
1289   /* Restore read timeout value */
1290   my_net_set_read_timeout(net, thd->variables.net_read_timeout);
1291 
1292   DEBUG_SYNC(thd, "before_command_dispatch");
1293 
1294   return_value = dispatch_command(thd, &com_data, command);
1295   thd->get_protocol_classic()->get_output_packet()->shrink(
1296       thd->variables.net_buffer_length);
1297 
1298 out:
1299   /* The statement instrumentation must be closed in all cases. */
1300   DBUG_ASSERT(thd->m_digest == nullptr);
1301   DBUG_ASSERT(thd->m_statement_psi == nullptr);
1302   return return_value;
1303 }
1304 
1305 /**
1306   @brief Determine if an attempt to update a non-temporary table while the
1307     read-only option was enabled has been made.
1308 
1309   This is a helper function to mysql_execute_command.
1310 
1311   @note SQLCOM_UPDATE_MULTI is an exception and delt with elsewhere.
1312 
1313   @see mysql_execute_command
1314   @returns Status code
1315     @retval true The statement should be denied.
1316     @retval false The statement isn't updating any relevant tables.
1317 */
deny_updates_if_read_only_option(THD * thd,TABLE_LIST * all_tables)1318 static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) {
1319   DBUG_TRACE;
1320 
1321   if (!check_readonly(thd, false)) return false;
1322 
1323   LEX *lex = thd->lex;
1324   if (!(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA)) return false;
1325 
1326   /* Multi update is an exception and is dealt with later. */
1327   if (lex->sql_command == SQLCOM_UPDATE_MULTI) return false;
1328 
1329   const bool create_temp_tables =
1330       (lex->sql_command == SQLCOM_CREATE_TABLE) &&
1331       (lex->create_info->options & HA_LEX_CREATE_TMP_TABLE);
1332 
1333   const bool create_real_tables =
1334       (lex->sql_command == SQLCOM_CREATE_TABLE) &&
1335       !(lex->create_info->options & HA_LEX_CREATE_TMP_TABLE);
1336 
1337   const bool drop_temp_tables =
1338       (lex->sql_command == SQLCOM_DROP_TABLE) && lex->drop_temporary;
1339 
1340   /* RENAME TABLES ignores shadowing temporary tables. */
1341   const bool rename_tables = (lex->sql_command == SQLCOM_RENAME_TABLE);
1342 
1343   const bool update_real_tables =
1344       ((create_real_tables || rename_tables ||
1345         some_non_temp_table_to_be_updated(thd, all_tables)) &&
1346        !(create_temp_tables || drop_temp_tables));
1347 
1348   const bool create_or_drop_databases =
1349       (lex->sql_command == SQLCOM_CREATE_DB) ||
1350       (lex->sql_command == SQLCOM_DROP_DB);
1351 
1352   if (update_real_tables || create_or_drop_databases) {
1353     /*
1354       An attempt was made to modify one or more non-temporary tables.
1355     */
1356     return true;
1357   }
1358 
1359   /* Assuming that only temporary tables are modified. */
1360   return false;
1361 }
1362 
1363 /**
1364   Check whether the statement is a SHOW command using INFORMATION_SCHEMA system
1365   views.
1366 
1367   @param  thd   Thread (session) context.
1368 
1369   @return true  if command uses INFORMATION_SCHEMA system view.
1370   @return false otherwise.
1371 
1372 */
is_show_cmd_using_system_view(THD * thd)1373 inline bool is_show_cmd_using_system_view(THD *thd) {
1374   return sql_command_flags[thd->lex->sql_command] & CF_SHOW_USES_SYSTEM_VIEW;
1375 }
1376 
1377 /**
1378   Check whether max statement time is applicable to statement or not.
1379 
1380 
1381   @param  thd   Thread (session) context.
1382 
1383   @return true  if max statement time is applicable to statement
1384   @return false otherwise.
1385 */
is_timer_applicable_to_statement(THD * thd)1386 static inline bool is_timer_applicable_to_statement(THD *thd) {
1387   bool timer_value_is_set =
1388       (thd->lex->max_execution_time || thd->variables.max_execution_time);
1389 
1390   /**
1391     Following conditions are checked,
1392       - is SELECT statement.
1393       - timer support is implemented and it is initialized.
1394       - statement is not made by the slave threads.
1395       - timer is not set for statement
1396       - timer out value of is set
1397       - SELECT statement is not from any stored programs.
1398   */
1399   return (thd->lex->sql_command == SQLCOM_SELECT &&
1400           (have_statement_timeout == SHOW_OPTION_YES) && !thd->slave_thread &&
1401           !thd->timer && timer_value_is_set && !thd->sp_runtime_ctx);
1402 }
1403 
1404 /**
1405   Check if a statement should be restarted in another storage engine,
1406   and restart the statement if needed.
1407 
1408   @param thd            the session
1409   @param parser_state   the parser state
1410   @param query_string   the query to reprepare and execute
1411   @param query_length   the length of the query
1412 */
check_secondary_engine_statement(THD * thd,Parser_state * parser_state,const char * query_string,size_t query_length)1413 static void check_secondary_engine_statement(THD *thd,
1414                                              Parser_state *parser_state,
1415                                              const char *query_string,
1416                                              size_t query_length) {
1417   // Only restart the statement if a non-fatal error was raised.
1418   if (!thd->is_error() || thd->is_killed() || thd->is_fatal_error()) return;
1419 
1420   // Only SQL commands can be restarted with another storage engine.
1421   if (thd->lex->m_sql_cmd == nullptr) return;
1422 
1423   // The query cannot be restarted if it had started executing, since
1424   // it may have started sending results to the client.
1425   if (thd->lex->unit->is_executed()) return;
1426 
1427   // Decide which storage engine to use when retrying.
1428   switch (thd->secondary_engine_optimization()) {
1429     case Secondary_engine_optimization::PRIMARY_TENTATIVELY:
1430       // If a request to prepare for the secondary engine was
1431       // signalled, retry in the secondary engine.
1432       if (thd->get_stmt_da()->mysql_errno() != ER_PREPARE_FOR_SECONDARY_ENGINE)
1433         return;
1434       thd->set_secondary_engine_optimization(
1435           Secondary_engine_optimization::SECONDARY);
1436       break;
1437     case Secondary_engine_optimization::SECONDARY:
1438       // If the query failed during offloading to a secondary engine,
1439       // retry in the primary engine. Don't retry if the failing query
1440       // was already using the primary storage engine.
1441       if (!thd->lex->m_sql_cmd->using_secondary_storage_engine()) return;
1442       thd->set_secondary_engine_optimization(
1443           Secondary_engine_optimization::PRIMARY_ONLY);
1444       break;
1445     default:
1446       return;
1447   }
1448 
1449   // Forget about the error raised in the previous attempt at preparing the
1450   // query.
1451   thd->clear_error();
1452 
1453   // Tell performance schema that the statement is restarted.
1454   MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
1455   thd->m_statement_psi = MYSQL_START_STATEMENT(
1456       &thd->m_statement_state, com_statement_info[thd->get_command()].m_key,
1457       thd->db().str, thd->db().length, thd->charset(), nullptr);
1458 
1459   // Reset the statement digest state.
1460   thd->m_digest = &thd->m_digest_state;
1461   thd->m_digest->reset(thd->m_token_array, max_digest_length);
1462 
1463   // Reset the parser state.
1464   thd->set_query(query_string, query_length);
1465   parser_state->reset(query_string, query_length);
1466 
1467   // Disable the general log. The query was written to the general log in the
1468   // first attempt to execute it. No need to write it twice.
1469   const uint64_t saved_option_bits = thd->variables.option_bits;
1470   thd->variables.option_bits |= OPTION_LOG_OFF;
1471 
1472   // Restart the statement.
1473   mysql_parse(thd, parser_state);
1474 
1475   // Restore the original option bits.
1476   thd->variables.option_bits = saved_option_bits;
1477 
1478   // Check if the restarted statement failed, and if so, if it needs
1479   // another restart/fallback to the primary storage engine.
1480   check_secondary_engine_statement(thd, parser_state, query_string,
1481                                    query_length);
1482 }
1483 
1484 /**
1485   Perform one connection-level (COM_XXXX) command.
1486 
1487   @param thd             connection handle
1488   @param command         type of command to perform
1489   @param com_data        com_data union to store the generated command
1490 
1491   @todo
1492     set thd->lex->sql_command to SQLCOM_END here.
1493   @todo
1494     The following has to be changed to an 8 byte integer
1495 
1496   @retval
1497     0   ok
1498   @retval
1499     1   request of thread shutdown, i. e. if command is
1500         COM_QUIT
1501 */
dispatch_command(THD * thd,const COM_DATA * com_data,enum enum_server_command command)1502 bool dispatch_command(THD *thd, const COM_DATA *com_data,
1503                       enum enum_server_command command) {
1504   bool error = false;
1505   Global_THD_manager *thd_manager = Global_THD_manager::get_instance();
1506   DBUG_TRACE;
1507   DBUG_PRINT("info", ("command: %d", command));
1508 
1509   Sql_cmd_clone *clone_cmd = nullptr;
1510 
1511   /* For per-query performance counters with log_slow_statement */
1512   struct System_status_var query_start_status;
1513   struct System_status_var *query_start_status_ptr = nullptr;
1514   if (opt_log_slow_extra) {
1515     query_start_status_ptr = &query_start_status;
1516     query_start_status = thd->status_var;
1517   }
1518 
1519   /* SHOW PROFILE instrumentation, begin */
1520 #if defined(ENABLED_PROFILING)
1521   thd->profiling->start_new_query();
1522 #endif
1523 
1524   /* Performance Schema Interface instrumentation, begin */
1525   thd->m_statement_psi = MYSQL_REFINE_STATEMENT(
1526       thd->m_statement_psi, com_statement_info[command].m_key);
1527 
1528   thd->set_command(command);
1529   /*
1530     Commands which always take a long time are logged into
1531     the slow log only if opt_log_slow_admin_statements is set.
1532   */
1533   thd->enable_slow_log = true;
1534   thd->lex->sql_command = SQLCOM_END; /* to avoid confusing VIEW detectors */
1535   /*
1536     KILL QUERY may come after cleanup in mysql_execute_command(). Next query
1537     execution is interrupted due to this. So resetting THD::killed here.
1538 
1539     THD::killed value can not be KILL_TIMEOUT here as timer used for statement
1540     max execution time is disarmed in the cleanup stage of
1541     mysql_execute_command. KILL CONNECTION should terminate the connection.
1542     Hence resetting THD::killed only for KILL QUERY case here.
1543   */
1544   if (thd->killed == THD::KILL_QUERY) thd->killed = THD::NOT_KILLED;
1545   thd->set_time();
1546   if (is_time_t_valid_for_timestamp(thd->query_start_in_secs()) == false) {
1547     /*
1548       If the time has gone past 2038 we need to shutdown the server. But
1549       there is possibility of getting invalid time value on some platforms.
1550       For example, gettimeofday() might return incorrect value on solaris
1551       platform. Hence validating the current time with 5 iterations before
1552       initiating the normal server shutdown process because of time getting
1553       past 2038.
1554     */
1555     const int max_tries = 5;
1556     LogErr(WARNING_LEVEL, ER_CONFIRMING_THE_FUTURE, max_tries);
1557 
1558     int tries = 0;
1559     while (++tries <= max_tries) {
1560       thd->set_time();
1561       if (is_time_t_valid_for_timestamp(thd->query_start_in_secs()) == true) {
1562         LogErr(WARNING_LEVEL, ER_BACK_IN_TIME, tries);
1563         break;
1564       }
1565       LogErr(WARNING_LEVEL, ER_FUTURE_DATE, tries);
1566     }
1567     if (tries > max_tries) {
1568       /*
1569         If the time has got past 2038 we need to shut this server down
1570         We do this by making sure every command is a shutdown and we
1571         have enough privileges to shut the server down
1572 
1573         TODO: remove this when we have full 64 bit my_time_t support
1574       */
1575       LogErr(ERROR_LEVEL, ER_UNSUPPORTED_DATE);
1576       ulong master_access = thd->security_context()->master_access();
1577       thd->security_context()->set_master_access(master_access | SHUTDOWN_ACL);
1578       error = true;
1579       kill_mysql();
1580     }
1581   }
1582   thd->set_query_id(next_query_id());
1583   thd->reset_rewritten_query();
1584   thd_manager->inc_thread_running();
1585 
1586   if (!(server_command_flags[command] & CF_SKIP_QUESTIONS))
1587     thd->status_var.questions++;
1588 
1589   /**
1590     Clear the set of flags that are expected to be cleared at the
1591     beginning of each command.
1592   */
1593   thd->server_status &= ~SERVER_STATUS_CLEAR_SET;
1594 
1595   if (thd->get_protocol()->type() == Protocol::PROTOCOL_PLUGIN &&
1596       !(server_command_flags[command] & CF_ALLOW_PROTOCOL_PLUGIN)) {
1597     my_error(ER_PLUGGABLE_PROTOCOL_COMMAND_NOT_SUPPORTED, MYF(0));
1598     thd->killed = THD::KILL_CONNECTION;
1599     error = true;
1600     goto done;
1601   }
1602 
1603   /**
1604     Enforce password expiration for all RPC commands, except the
1605     following:
1606 
1607     COM_QUERY/COM_STMT_PREPARE and COM_STMT_EXECUTE do a more
1608     fine-grained check later.
1609     COM_STMT_CLOSE and COM_STMT_SEND_LONG_DATA don't return anything.
1610     COM_PING only discloses information that the server is running,
1611        and that's available through other means.
1612     COM_QUIT should work even for expired statements.
1613   */
1614   if (unlikely(thd->security_context()->password_expired() &&
1615                command != COM_QUERY && command != COM_STMT_CLOSE &&
1616                command != COM_STMT_SEND_LONG_DATA && command != COM_PING &&
1617                command != COM_QUIT && command != COM_STMT_PREPARE &&
1618                command != COM_STMT_EXECUTE)) {
1619     my_error(ER_MUST_CHANGE_PASSWORD, MYF(0));
1620     goto done;
1621   }
1622 
1623   if (mysql_audit_notify(thd, AUDIT_EVENT(MYSQL_AUDIT_COMMAND_START), command,
1624                          command_name[command].str)) {
1625     goto done;
1626   }
1627 
1628   switch (command) {
1629     case COM_INIT_DB: {
1630       LEX_STRING tmp;
1631       thd->status_var.com_stat[SQLCOM_CHANGE_DB]++;
1632       thd->convert_string(&tmp, system_charset_info,
1633                           com_data->com_init_db.db_name,
1634                           com_data->com_init_db.length, thd->charset());
1635 
1636       LEX_CSTRING tmp_cstr = {tmp.str, tmp.length};
1637       if (!mysql_change_db(thd, tmp_cstr, false)) {
1638         query_logger.general_log_write(thd, command, thd->db().str,
1639                                        thd->db().length);
1640         my_ok(thd);
1641       }
1642       break;
1643     }
1644     case COM_REGISTER_SLAVE: {
1645       // TODO: access of protocol_classic should be removed
1646       if (!register_slave(thd, thd->get_protocol_classic()->get_raw_packet(),
1647                           thd->get_protocol_classic()->get_packet_length()))
1648         my_ok(thd);
1649       break;
1650     }
1651     case COM_RESET_CONNECTION: {
1652       thd->status_var.com_other++;
1653       thd->cleanup_connection();
1654       my_ok(thd);
1655       break;
1656     }
1657     case COM_CLONE: {
1658       thd->status_var.com_other++;
1659 
1660       /* Try loading clone plugin */
1661       clone_cmd = new (thd->mem_root) Sql_cmd_clone();
1662 
1663       if (clone_cmd && clone_cmd->load(thd)) {
1664         clone_cmd = nullptr;
1665       }
1666 
1667       thd->lex->m_sql_cmd = clone_cmd;
1668       thd->lex->sql_command = SQLCOM_CLONE;
1669 
1670       break;
1671     }
1672     case COM_CHANGE_USER: {
1673       int auth_rc;
1674       thd->status_var.com_other++;
1675 
1676       thd->cleanup_connection();
1677       USER_CONN *save_user_connect =
1678           const_cast<USER_CONN *>(thd->get_user_connect());
1679       LEX_CSTRING save_db = thd->db();
1680       Security_context save_security_ctx(*(thd->security_context()));
1681 
1682       auth_rc = acl_authenticate(thd, COM_CHANGE_USER);
1683       auth_rc |= mysql_audit_notify(
1684           thd, AUDIT_EVENT(MYSQL_AUDIT_CONNECTION_CHANGE_USER));
1685       if (auth_rc) {
1686         *thd->security_context() = save_security_ctx;
1687         thd->set_user_connect(save_user_connect);
1688         thd->reset_db(save_db);
1689 
1690         my_error(ER_ACCESS_DENIED_CHANGE_USER_ERROR, MYF(0),
1691                  thd->security_context()->user().str,
1692                  thd->security_context()->host_or_ip().str,
1693                  (thd->password ? ER_THD(thd, ER_YES) : ER_THD(thd, ER_NO)));
1694         thd->killed = THD::KILL_CONNECTION;
1695         error = true;
1696       } else {
1697 #ifdef HAVE_PSI_THREAD_INTERFACE
1698         /* we've authenticated new user */
1699         PSI_THREAD_CALL(notify_session_change_user)(thd->get_psi());
1700 #endif /* HAVE_PSI_THREAD_INTERFACE */
1701 
1702         if (save_user_connect) decrease_user_connections(save_user_connect);
1703         mysql_mutex_lock(&thd->LOCK_thd_data);
1704         my_free(const_cast<char *>(save_db.str));
1705         save_db = NULL_CSTR;
1706         mysql_mutex_unlock(&thd->LOCK_thd_data);
1707       }
1708       break;
1709     }
1710     case COM_STMT_EXECUTE: {
1711       /* Clear possible warnings from the previous command */
1712       thd->reset_for_next_command();
1713 
1714       Prepared_statement *stmt = nullptr;
1715       if (!mysql_stmt_precheck(thd, com_data, command, &stmt)) {
1716         PS_PARAM *parameters = com_data->com_stmt_execute.parameters;
1717         mysqld_stmt_execute(thd, stmt, com_data->com_stmt_execute.has_new_types,
1718                             com_data->com_stmt_execute.open_cursor, parameters);
1719       }
1720       break;
1721     }
1722     case COM_STMT_FETCH: {
1723       /* Clear possible warnings from the previous command */
1724       thd->reset_for_next_command();
1725 
1726       Prepared_statement *stmt = nullptr;
1727       if (!mysql_stmt_precheck(thd, com_data, command, &stmt))
1728         mysqld_stmt_fetch(thd, stmt, com_data->com_stmt_fetch.num_rows);
1729 
1730       break;
1731     }
1732     case COM_STMT_SEND_LONG_DATA: {
1733       Prepared_statement *stmt;
1734       thd->get_stmt_da()->disable_status();
1735       if (!mysql_stmt_precheck(thd, com_data, command, &stmt))
1736         mysql_stmt_get_longdata(thd, stmt,
1737                                 com_data->com_stmt_send_long_data.param_number,
1738                                 com_data->com_stmt_send_long_data.longdata,
1739                                 com_data->com_stmt_send_long_data.length);
1740       break;
1741     }
1742     case COM_STMT_PREPARE: {
1743       /* Clear possible warnings from the previous command */
1744       thd->reset_for_next_command();
1745       Prepared_statement *stmt = nullptr;
1746 
1747       DBUG_EXECUTE_IF("parser_stmt_to_error_log", {
1748         LogErr(INFORMATION_LEVEL, ER_PARSER_TRACE,
1749                com_data->com_stmt_prepare.query);
1750       });
1751       DBUG_EXECUTE_IF("parser_stmt_to_error_log_with_system_prio", {
1752         LogErr(SYSTEM_LEVEL, ER_PARSER_TRACE, com_data->com_stmt_prepare.query);
1753       });
1754 
1755       if (!mysql_stmt_precheck(thd, com_data, command, &stmt))
1756         mysqld_stmt_prepare(thd, com_data->com_stmt_prepare.query,
1757                             com_data->com_stmt_prepare.length, stmt);
1758       break;
1759     }
1760     case COM_STMT_CLOSE: {
1761       Prepared_statement *stmt = nullptr;
1762       thd->get_stmt_da()->disable_status();
1763       if (!mysql_stmt_precheck(thd, com_data, command, &stmt))
1764         mysqld_stmt_close(thd, stmt);
1765       break;
1766     }
1767     case COM_STMT_RESET: {
1768       /* Clear possible warnings from the previous command */
1769       thd->reset_for_next_command();
1770 
1771       Prepared_statement *stmt = nullptr;
1772       if (!mysql_stmt_precheck(thd, com_data, command, &stmt))
1773         mysqld_stmt_reset(thd, stmt);
1774       break;
1775     }
1776     case COM_QUERY: {
1777       DBUG_ASSERT(thd->m_digest == nullptr);
1778       thd->m_digest = &thd->m_digest_state;
1779       thd->m_digest->reset(thd->m_token_array, max_digest_length);
1780 
1781       if (alloc_query(thd, com_data->com_query.query,
1782                       com_data->com_query.length))
1783         break;  // fatal error is set
1784 
1785       const char *packet_end = thd->query().str + thd->query().length;
1786 
1787       if (opt_general_log_raw)
1788         query_logger.general_log_write(thd, command, thd->query().str,
1789                                        thd->query().length);
1790 
1791       DBUG_PRINT("query", ("%-.4096s", thd->query().str));
1792 
1793 #if defined(ENABLED_PROFILING)
1794       thd->profiling->set_query_source(thd->query().str, thd->query().length);
1795 #endif
1796 
1797       const LEX_CSTRING orig_query = thd->query();
1798 
1799       Parser_state parser_state;
1800       if (parser_state.init(thd, thd->query().str, thd->query().length)) break;
1801 
1802       // Initially, prepare and optimize the statement for the primary
1803       // storage engine. If an eligible secondary storage engine is
1804       // found, the statement may be reprepared for the secondary
1805       // storage engine later.
1806       const auto saved_secondary_engine = thd->secondary_engine_optimization();
1807       thd->set_secondary_engine_optimization(
1808           Secondary_engine_optimization::PRIMARY_TENTATIVELY);
1809 
1810       mysql_parse(thd, &parser_state);
1811 
1812       // Check if the statement failed and needs to be restarted in
1813       // another storage engine.
1814       check_secondary_engine_statement(thd, &parser_state, orig_query.str,
1815                                        orig_query.length);
1816 
1817       thd->set_secondary_engine_optimization(saved_secondary_engine);
1818 
1819       DBUG_EXECUTE_IF("parser_stmt_to_error_log", {
1820         LogErr(INFORMATION_LEVEL, ER_PARSER_TRACE, thd->query().str);
1821       });
1822       DBUG_EXECUTE_IF("parser_stmt_to_error_log_with_system_prio", {
1823         LogErr(SYSTEM_LEVEL, ER_PARSER_TRACE, thd->query().str);
1824       });
1825 
1826       while (!thd->killed && (parser_state.m_lip.found_semicolon != nullptr) &&
1827              !thd->is_error()) {
1828         /*
1829           Multiple queries exits, execute them individually
1830         */
1831         const char *beginning_of_next_stmt = parser_state.m_lip.found_semicolon;
1832 
1833         /* Finalize server status flags after executing a statement. */
1834         thd->update_slow_query_status();
1835         thd->send_statement_status();
1836 
1837         mysql_audit_notify(
1838             thd, AUDIT_EVENT(MYSQL_AUDIT_GENERAL_STATUS),
1839             thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->mysql_errno()
1840                                            : 0,
1841             command_name[command].str, command_name[command].length);
1842 
1843         size_t length =
1844             static_cast<size_t>(packet_end - beginning_of_next_stmt);
1845 
1846         log_slow_statement(thd, query_start_status_ptr);
1847         if (query_start_status_ptr) {
1848           /* Reset for values at start of next statement */
1849           query_start_status = thd->status_var;
1850         }
1851 
1852         /* Remove garbage at start of query */
1853         while (length > 0 &&
1854                my_isspace(thd->charset(), *beginning_of_next_stmt)) {
1855           beginning_of_next_stmt++;
1856           length--;
1857         }
1858 
1859         /* PSI end */
1860         MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
1861         thd->m_statement_psi = nullptr;
1862         thd->m_digest = nullptr;
1863 
1864 /* SHOW PROFILE end */
1865 #if defined(ENABLED_PROFILING)
1866         thd->profiling->finish_current_query();
1867 #endif
1868 
1869 /* SHOW PROFILE begin */
1870 #if defined(ENABLED_PROFILING)
1871         thd->profiling->start_new_query("continuing");
1872         thd->profiling->set_query_source(beginning_of_next_stmt, length);
1873 #endif
1874 
1875         /* PSI begin */
1876         thd->m_digest = &thd->m_digest_state;
1877         thd->m_digest->reset(thd->m_token_array, max_digest_length);
1878 
1879         thd->m_statement_psi = MYSQL_START_STATEMENT(
1880             &thd->m_statement_state, com_statement_info[command].m_key,
1881             thd->db().str, thd->db().length, thd->charset(), nullptr);
1882         THD_STAGE_INFO(thd, stage_starting);
1883 
1884         thd->set_query(beginning_of_next_stmt, length);
1885         thd->set_query_id(next_query_id());
1886         /*
1887           Count each statement from the client.
1888         */
1889         thd->status_var.questions++;
1890         thd->set_time(); /* Reset the query start time. */
1891         parser_state.reset(beginning_of_next_stmt, length);
1892         thd->set_secondary_engine_optimization(
1893             Secondary_engine_optimization::PRIMARY_TENTATIVELY);
1894         /* TODO: set thd->lex->sql_command to SQLCOM_END here */
1895         mysql_parse(thd, &parser_state);
1896 
1897         check_secondary_engine_statement(thd, &parser_state,
1898                                          beginning_of_next_stmt, length);
1899 
1900         thd->set_secondary_engine_optimization(saved_secondary_engine);
1901       }
1902 
1903       /* Need to set error to true for graceful shutdown */
1904       if ((thd->lex->sql_command == SQLCOM_SHUTDOWN) &&
1905           (thd->get_stmt_da()->is_ok()))
1906         error = true;
1907 
1908       DBUG_PRINT("info", ("query ready"));
1909       break;
1910     }
1911     case COM_FIELD_LIST:  // This isn't actually needed
1912     {
1913       char *fields;
1914       /* Locked closure of all tables */
1915       LEX_STRING table_name;
1916       LEX_STRING db;
1917       push_deprecated_warn(thd, "COM_FIELD_LIST",
1918                            "SHOW COLUMNS FROM statement");
1919       /*
1920         SHOW statements should not add the used tables to the list of tables
1921         used in a transaction.
1922       */
1923       MDL_savepoint mdl_savepoint = thd->mdl_context.mdl_savepoint();
1924 
1925       thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]++;
1926       if (thd->copy_db_to(&db.str, &db.length)) break;
1927       thd->convert_string(&table_name, system_charset_info,
1928                           (char *)com_data->com_field_list.table_name,
1929                           com_data->com_field_list.table_name_length,
1930                           thd->charset());
1931       Ident_name_check ident_check_status =
1932           check_table_name(table_name.str, table_name.length);
1933       if (ident_check_status == Ident_name_check::WRONG) {
1934         /* this is OK due to convert_string() null-terminating the string */
1935         my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str);
1936         break;
1937       } else if (ident_check_status == Ident_name_check::TOO_LONG) {
1938         my_error(ER_TOO_LONG_IDENT, MYF(0), table_name.str);
1939         break;
1940       }
1941       mysql_reset_thd_for_next_command(thd);
1942       lex_start(thd);
1943       /* Must be before we init the table list. */
1944       if (lower_case_table_names && !is_infoschema_db(db.str, db.length))
1945         table_name.length = my_casedn_str(files_charset_info, table_name.str);
1946       TABLE_LIST table_list(db.str, db.length, table_name.str,
1947                             table_name.length, table_name.str, TL_READ);
1948       /*
1949         Init TABLE_LIST members necessary when the undelrying
1950         table is view.
1951       */
1952       table_list.select_lex = thd->lex->select_lex;
1953       thd->lex->select_lex->table_list.link_in_list(&table_list,
1954                                                     &table_list.next_local);
1955       thd->lex->add_to_query_tables(&table_list);
1956 
1957       if (is_infoschema_db(table_list.db, table_list.db_length)) {
1958         ST_SCHEMA_TABLE *schema_table =
1959             find_schema_table(thd, table_list.alias);
1960         if (schema_table) table_list.schema_table = schema_table;
1961       }
1962 
1963       if (!(fields =
1964                 (char *)thd->memdup(com_data->com_field_list.query,
1965                                     com_data->com_field_list.query_length)))
1966         break;
1967       // Don't count end \0
1968       thd->set_query(fields, com_data->com_field_list.query_length - 1);
1969       query_logger.general_log_print(thd, command, "%s %s",
1970                                      table_list.table_name, fields);
1971 
1972       if (open_temporary_tables(thd, &table_list)) break;
1973 
1974       if (check_table_access(thd, SELECT_ACL, &table_list, true, UINT_MAX,
1975                              false))
1976         break;
1977 
1978       // See comment in opt_trace_disable_if_no_security_context_access()
1979       Opt_trace_start ots(thd, &table_list, thd->lex->sql_command, nullptr,
1980                           nullptr, 0, nullptr, nullptr);
1981 
1982       mysqld_list_fields(thd, &table_list, fields);
1983 
1984       thd->lex->unit->cleanup(thd, true);
1985       /* No need to rollback statement transaction, it's not started. */
1986       DBUG_ASSERT(thd->get_transaction()->is_empty(Transaction_ctx::STMT));
1987       close_thread_tables(thd);
1988       thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
1989 
1990       if (thd->transaction_rollback_request) {
1991         /*
1992           Transaction rollback was requested since MDL deadlock was
1993           discovered while trying to open tables. Rollback transaction
1994           in all storage engines including binary log and release all
1995           locks.
1996         */
1997         trans_rollback_implicit(thd);
1998         thd->mdl_context.release_transactional_locks();
1999       }
2000 
2001       thd->cleanup_after_query();
2002       break;
2003     }
2004     case COM_QUIT:
2005       /* Prevent results of the form, "n>0 rows sent, 0 bytes sent" */
2006       thd->set_sent_row_count(0);
2007       /* We don't calculate statistics for this command */
2008       query_logger.general_log_print(thd, command, NullS);
2009       // Don't give 'abort' message
2010       // TODO: access of protocol_classic should be removed
2011       if (thd->is_classic_protocol())
2012         thd->get_protocol_classic()->get_net()->error = 0;
2013       thd->get_stmt_da()->disable_status();  // Don't send anything back
2014       error = true;                          // End server
2015       break;
2016     case COM_BINLOG_DUMP_GTID:
2017       // TODO: access of protocol_classic should be removed
2018       error = com_binlog_dump_gtid(
2019           thd, (char *)thd->get_protocol_classic()->get_raw_packet(),
2020           thd->get_protocol_classic()->get_packet_length());
2021       break;
2022     case COM_BINLOG_DUMP:
2023       // TODO: access of protocol_classic should be removed
2024       error = com_binlog_dump(
2025           thd, (char *)thd->get_protocol_classic()->get_raw_packet(),
2026           thd->get_protocol_classic()->get_packet_length());
2027       break;
2028     case COM_REFRESH: {
2029       int not_used;
2030       push_deprecated_warn(thd, "COM_REFRESH", "FLUSH statement");
2031       /*
2032         Initialize thd->lex since it's used in many base functions, such as
2033         open_tables(). Otherwise, it remains uninitialized and may cause crash
2034         during execution of COM_REFRESH.
2035       */
2036       lex_start(thd);
2037 
2038       thd->status_var.com_stat[SQLCOM_FLUSH]++;
2039       ulong options = (ulong)com_data->com_refresh.options;
2040       if (trans_commit_implicit(thd)) break;
2041       thd->mdl_context.release_transactional_locks();
2042       if (check_global_access(thd, RELOAD_ACL)) break;
2043       query_logger.general_log_print(thd, command, NullS);
2044 #ifndef DBUG_OFF
2045       bool debug_simulate = false;
2046       DBUG_EXECUTE_IF("simulate_detached_thread_refresh",
2047                       debug_simulate = true;);
2048       if (debug_simulate) {
2049         /*
2050           Simulate a reload without a attached thread session.
2051           Provides a environment similar to that of when the
2052           server receives a SIGHUP signal and reloads caches
2053           and flushes tables.
2054         */
2055         bool res;
2056         current_thd = nullptr;
2057         res = handle_reload_request(nullptr, options | REFRESH_FAST, nullptr,
2058                                     &not_used);
2059         current_thd = thd;
2060         if (res) break;
2061       } else
2062 #endif
2063           if (handle_reload_request(thd, options, (TABLE_LIST *)nullptr,
2064                                     &not_used))
2065         break;
2066       if (trans_commit_implicit(thd)) break;
2067       close_thread_tables(thd);
2068       thd->mdl_context.release_transactional_locks();
2069       my_ok(thd);
2070       break;
2071     }
2072     case COM_STATISTICS: {
2073       System_status_var current_global_status_var;
2074       ulong uptime;
2075       size_t length MY_ATTRIBUTE((unused));
2076       ulonglong queries_per_second1000;
2077       char buff[250];
2078       size_t buff_len = sizeof(buff);
2079 
2080       query_logger.general_log_print(thd, command, NullS);
2081       thd->status_var.com_stat[SQLCOM_SHOW_STATUS]++;
2082       mysql_mutex_lock(&LOCK_status);
2083       calc_sum_of_all_status(&current_global_status_var);
2084       mysql_mutex_unlock(&LOCK_status);
2085       if (!(uptime = (ulong)(thd->query_start_in_secs() - server_start_time)))
2086         queries_per_second1000 = 0;
2087       else
2088         queries_per_second1000 = thd->query_id * 1000LL / uptime;
2089 
2090       length = snprintf(buff, buff_len - 1,
2091                         "Uptime: %lu  Threads: %d  Questions: %lu  "
2092                         "Slow queries: %llu  Opens: %llu  Flush tables: %lu  "
2093                         "Open tables: %u  Queries per second avg: %u.%03u",
2094                         uptime, (int)thd_manager->get_thd_count(),
2095                         (ulong)thd->query_id,
2096                         current_global_status_var.long_query_count,
2097                         current_global_status_var.opened_tables,
2098                         refresh_version, table_cache_manager.cached_tables(),
2099                         (uint)(queries_per_second1000 / 1000),
2100                         (uint)(queries_per_second1000 % 1000));
2101       // TODO: access of protocol_classic should be removed.
2102       // should be rewritten using store functions
2103       if (thd->get_protocol_classic()->write(pointer_cast<const uchar *>(buff),
2104                                              length))
2105         break;
2106       if (thd->get_protocol()->flush()) break;
2107       thd->get_stmt_da()->disable_status();
2108       break;
2109     }
2110     case COM_PING:
2111       thd->status_var.com_other++;
2112       my_ok(thd);  // Tell client we are alive
2113       break;
2114     case COM_PROCESS_INFO:
2115       bool global_access;
2116       LEX_CSTRING db_saved;
2117       thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]++;
2118       push_deprecated_warn(thd, "COM_PROCESS_INFO",
2119                            "SHOW PROCESSLIST statement");
2120       global_access = (check_global_access(thd, PROCESS_ACL) == 0);
2121       if (!thd->security_context()->priv_user().str[0] && !global_access) break;
2122       query_logger.general_log_print(thd, command, NullS);
2123       db_saved = thd->db();
2124 
2125       DBUG_EXECUTE_IF("force_db_name_to_null", thd->reset_db(NULL_CSTR););
2126 
2127       mysqld_list_processes(
2128           thd, global_access ? NullS : thd->security_context()->priv_user().str,
2129           false);
2130 
2131       DBUG_EXECUTE_IF("force_db_name_to_null", thd->reset_db(db_saved););
2132       break;
2133     case COM_PROCESS_KILL: {
2134       push_deprecated_warn(thd, "COM_PROCESS_KILL",
2135                            "KILL CONNECTION/QUERY statement");
2136       if (thd_manager->get_thread_id() & (~0xfffffffful))
2137         my_error(ER_DATA_OUT_OF_RANGE, MYF(0), "thread_id", "mysql_kill()");
2138       else {
2139         thd->status_var.com_stat[SQLCOM_KILL]++;
2140         sql_kill(thd, com_data->com_kill.id, false);
2141       }
2142       break;
2143     }
2144     case COM_SET_OPTION: {
2145       thd->status_var.com_stat[SQLCOM_SET_OPTION]++;
2146 
2147       switch (com_data->com_set_option.opt_command) {
2148         case (int)MYSQL_OPTION_MULTI_STATEMENTS_ON:
2149           // TODO: access of protocol_classic should be removed
2150           thd->get_protocol_classic()->add_client_capability(
2151               CLIENT_MULTI_STATEMENTS);
2152           my_eof(thd);
2153           break;
2154         case (int)MYSQL_OPTION_MULTI_STATEMENTS_OFF:
2155           thd->get_protocol_classic()->remove_client_capability(
2156               CLIENT_MULTI_STATEMENTS);
2157           my_eof(thd);
2158           break;
2159         default:
2160           my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
2161           break;
2162       }
2163       break;
2164     }
2165     case COM_DEBUG:
2166       thd->status_var.com_other++;
2167       if (check_global_access(thd, SUPER_ACL)) break; /* purecov: inspected */
2168       query_logger.general_log_print(thd, command, NullS);
2169       my_eof(thd);
2170 #ifdef WITH_LOCK_ORDER
2171       LO_dump();
2172 #endif /* WITH_LOCK_ORDER */
2173       break;
2174     case COM_SLEEP:
2175     case COM_CONNECT:         // Impossible here
2176     case COM_TIME:            // Impossible from client
2177     case COM_DELAYED_INSERT:  // INSERT DELAYED has been removed.
2178     case COM_END:
2179     default:
2180       my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
2181       break;
2182   }
2183 
2184 done:
2185   DBUG_ASSERT(thd->open_tables == nullptr ||
2186               (thd->locked_tables_mode == LTM_LOCK_TABLES));
2187 
2188   /* Finalize server status flags after executing a command. */
2189   thd->update_slow_query_status();
2190   if (thd->killed) thd->send_kill_message();
2191   thd->send_statement_status();
2192 
2193   /* After sending response, switch to clone protocol */
2194   if (clone_cmd != nullptr) {
2195     DBUG_ASSERT(command == COM_CLONE);
2196     error = clone_cmd->execute_server(thd);
2197   }
2198 
2199   thd->rpl_thd_ctx.session_gtids_ctx().notify_after_response_packet(thd);
2200 
2201   if (!thd->is_error() && !thd->killed)
2202     mysql_audit_notify(thd, AUDIT_EVENT(MYSQL_AUDIT_GENERAL_RESULT), 0, nullptr,
2203                        0);
2204 
2205   mysql_audit_notify(
2206       thd, AUDIT_EVENT(MYSQL_AUDIT_GENERAL_STATUS),
2207       thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->mysql_errno() : 0,
2208       command_name[command].str, command_name[command].length);
2209 
2210   /* command_end is informational only. The plugin cannot abort
2211      execution of the command at thie point. */
2212   mysql_audit_notify(thd, AUDIT_EVENT(MYSQL_AUDIT_COMMAND_END), command,
2213                      command_name[command].str);
2214 
2215   log_slow_statement(thd, query_start_status_ptr);
2216 
2217   THD_STAGE_INFO(thd, stage_cleaning_up);
2218 
2219   thd->reset_query();
2220   thd->set_command(COM_SLEEP);
2221   thd->proc_info = nullptr;
2222   thd->lex->sql_command = SQLCOM_END;
2223 
2224   /* Performance Schema Interface instrumentation, end */
2225   MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
2226   thd->m_statement_psi = nullptr;
2227   thd->m_digest = nullptr;
2228 
2229   /* Prevent rewritten query from getting "stuck" in SHOW PROCESSLIST. */
2230   thd->reset_rewritten_query();
2231 
2232   thd_manager->dec_thread_running();
2233 
2234   /* Freeing the memroot will leave the THD::work_part_info invalid. */
2235   thd->work_part_info = nullptr;
2236 
2237   /*
2238     If we've allocated a lot of memory (compared to the user's desired
2239     preallocation size; note that we don't actually preallocate anymore), free
2240     it so that one big query won't cause us to hold on to a lot of RAM forever.
2241     If not, keep the last block so that the next query will hopefully be able to
2242     run without allocating memory from the OS.
2243 
2244     The factor 5 is pretty much arbitrary, but ends up allowing three
2245     allocations (1 + 1.5 + 1.5²) under the current allocation policy.
2246   */
2247   if (thd->mem_root->allocated_size() < 5 * thd->variables.query_prealloc_size)
2248     thd->mem_root->ClearForReuse();
2249   else
2250     thd->mem_root->Clear();
2251 
2252     /* SHOW PROFILE instrumentation, end */
2253 #if defined(ENABLED_PROFILING)
2254   thd->profiling->finish_current_query();
2255 #endif
2256 
2257   return error;
2258 }
2259 
2260 /**
2261   Shutdown the mysqld server.
2262 
2263   @param  thd        Thread (session) context.
2264   @param  level      Shutdown level.
2265 
2266   @retval
2267     true                 success
2268   @retval
2269     false                When user has insufficient privilege or unsupported
2270   shutdown level
2271 
2272 */
2273 
shutdown(THD * thd,enum mysql_enum_shutdown_level level)2274 bool shutdown(THD *thd, enum mysql_enum_shutdown_level level) {
2275   DBUG_TRACE;
2276   bool res = false;
2277   thd->lex->no_write_to_binlog = true;
2278 
2279   if (check_global_access(thd, SHUTDOWN_ACL))
2280     goto error; /* purecov: inspected */
2281 
2282   if (level == SHUTDOWN_DEFAULT)
2283     level = SHUTDOWN_WAIT_ALL_BUFFERS;  // soon default will be configurable
2284   else if (level != SHUTDOWN_WAIT_ALL_BUFFERS) {
2285     my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level");
2286     goto error;
2287     ;
2288   }
2289 
2290   my_ok(thd);
2291 
2292   LogErr(SYSTEM_LEVEL, ER_SERVER_SHUTDOWN_INFO,
2293          thd->security_context()->user().str, server_version,
2294          MYSQL_COMPILATION_COMMENT_SERVER);
2295 
2296   DBUG_PRINT("quit", ("Got shutdown command for level %u", level));
2297   query_logger.general_log_print(thd, COM_QUERY, NullS);
2298   kill_mysql();
2299   res = true;
2300 
2301 error:
2302   return res;
2303 }
2304 
2305 /**
2306   Create a TABLE_LIST object for an INFORMATION_SCHEMA table.
2307 
2308     This function is used in the parser to convert a SHOW or DESCRIBE
2309     table_name command to a SELECT from INFORMATION_SCHEMA.
2310     It prepares a SELECT_LEX and a TABLE_LIST object to represent the
2311     given command as a SELECT parse tree.
2312 
2313   @param thd              thread handle
2314   @param lex              current lex
2315   @param table_ident      table alias if it's used
2316   @param schema_table_idx the type of the INFORMATION_SCHEMA table to be
2317                           created
2318 
2319   @note
2320     Due to the way this function works with memory and LEX it cannot
2321     be used outside the parser (parse tree transformations outside
2322     the parser break PS and SP).
2323 
2324   @retval
2325     0                 success
2326   @retval
2327     1                 out of memory or SHOW commands are not allowed
2328                       in this version of the server.
2329 */
2330 
prepare_schema_table(THD * thd,LEX * lex,Table_ident * table_ident,enum enum_schema_tables schema_table_idx)2331 int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
2332                          enum enum_schema_tables schema_table_idx) {
2333   SELECT_LEX *schema_select_lex = nullptr;
2334   DBUG_TRACE;
2335 
2336   switch (schema_table_idx) {
2337     case SCH_TMP_TABLE_COLUMNS:
2338     case SCH_TMP_TABLE_KEYS: {
2339       DBUG_ASSERT(table_ident);
2340       TABLE_LIST **query_tables_last = lex->query_tables_last;
2341       if ((schema_select_lex = lex->new_empty_query_block()) == nullptr)
2342         return 1; /* purecov: inspected */
2343       if (!schema_select_lex->add_table_to_list(thd, table_ident, nullptr, 0,
2344                                                 TL_READ, MDL_SHARED_READ))
2345         return 1;
2346       lex->query_tables_last = query_tables_last;
2347       break;
2348     }
2349     case SCH_PROFILES:
2350       /*
2351         Mark this current profiling record to be discarded.  We don't
2352         wish to have SHOW commands show up in profiling->
2353       */
2354 #if defined(ENABLED_PROFILING)
2355       thd->profiling->discard_current_query();
2356 #endif
2357       break;
2358     case SCH_OPTIMIZER_TRACE:
2359     case SCH_OPEN_TABLES:
2360     case SCH_ENGINES:
2361     case SCH_USER_PRIVILEGES:
2362     case SCH_SCHEMA_PRIVILEGES:
2363     case SCH_TABLE_PRIVILEGES:
2364     case SCH_COLUMN_PRIVILEGES:
2365     default:
2366       break;
2367   }
2368 
2369   SELECT_LEX *select_lex = lex->current_select();
2370   if (make_schema_select(thd, select_lex, schema_table_idx)) {
2371     return 1;
2372   }
2373   TABLE_LIST *table_list = select_lex->table_list.first;
2374   table_list->schema_select_lex = schema_select_lex;
2375   table_list->schema_table_reformed = true;
2376   return 0;
2377 }
2378 
2379 /**
2380   Read query from packet and store in thd->query.
2381   Used in COM_QUERY and COM_STMT_PREPARE.
2382 
2383     Sets the following THD variables:
2384   - query
2385   - query_length
2386 
2387   @retval
2388     false ok
2389   @retval
2390     true  error;  In this case thd->fatal_error is set
2391 */
2392 
alloc_query(THD * thd,const char * packet,size_t packet_length)2393 bool alloc_query(THD *thd, const char *packet, size_t packet_length) {
2394   /* Remove garbage at start and end of query */
2395   while (packet_length > 0 && my_isspace(thd->charset(), packet[0])) {
2396     packet++;
2397     packet_length--;
2398   }
2399   const char *pos = packet + packet_length;  // Point at end null
2400   while (packet_length > 0 &&
2401          (pos[-1] == ';' || my_isspace(thd->charset(), pos[-1]))) {
2402     pos--;
2403     packet_length--;
2404   }
2405 
2406   char *query = static_cast<char *>(thd->alloc(packet_length + 1));
2407   if (!query) return true;
2408   memcpy(query, packet, packet_length);
2409   query[packet_length] = '\0';
2410 
2411   thd->set_query(query, packet_length);
2412 
2413   return false;
2414 }
2415 
sp_process_definer(THD * thd)2416 static bool sp_process_definer(THD *thd) {
2417   DBUG_TRACE;
2418 
2419   LEX *lex = thd->lex;
2420 
2421   /*
2422     If the definer is not specified, this means that CREATE-statement missed
2423     DEFINER-clause. DEFINER-clause can be missed in two cases:
2424 
2425       - The user submitted a statement w/o the clause. This is a normal
2426         case, we should assign CURRENT_USER as definer.
2427 
2428       - Our slave received an updated from the master, that does not
2429         replicate definer for stored rountines. We should also assign
2430         CURRENT_USER as definer here, but also we should mark this routine
2431         as NON-SUID. This is essential for the sake of backward
2432         compatibility.
2433 
2434         The problem is the slave thread is running under "special" user (@),
2435         that actually does not exist. In the older versions we do not fail
2436         execution of a stored routine if its definer does not exist and
2437         continue the execution under the authorization of the invoker
2438         (BUG#13198). And now if we try to switch to slave-current-user (@),
2439         we will fail.
2440 
2441         Actually, this leads to the inconsistent state of master and
2442         slave (different definers, different SUID behaviour), but it seems,
2443         this is the best we can do.
2444   */
2445 
2446   if (!lex->definer) {
2447     Prepared_stmt_arena_holder ps_arena_holder(thd);
2448 
2449     lex->definer = create_default_definer(thd);
2450 
2451     /* Error has been already reported. */
2452     if (lex->definer == nullptr) return true;
2453 
2454     if (thd->slave_thread && lex->sphead)
2455       lex->sphead->m_chistics->suid = SP_IS_NOT_SUID;
2456   } else {
2457     /*
2458       If the specified definer differs from the current user, we
2459       should check that the current user has a set_user_id privilege
2460       (in order to create a stored routine under another user one must
2461        have a set_user_id privilege).
2462     */
2463     Security_context *sctx = thd->security_context();
2464     if ((strcmp(lex->definer->user.str,
2465                 thd->security_context()->priv_user().str) ||
2466          my_strcasecmp(system_charset_info, lex->definer->host.str,
2467                        thd->security_context()->priv_host().str))) {
2468       if (!(sctx->check_access(SUPER_ACL) ||
2469             sctx->has_global_grant(STRING_WITH_LEN("SET_USER_ID")).first)) {
2470         my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0),
2471                  "SUPER or SET_USER_ID");
2472         return true;
2473       }
2474       if (sctx->can_operate_with({lex->definer}, consts::system_user))
2475         return true;
2476     }
2477   }
2478 
2479   /* Check that the specified definer exists. Emit a warning if not. */
2480 
2481   if (!is_acl_user(thd, lex->definer->host.str, lex->definer->user.str)) {
2482     push_warning_printf(thd, Sql_condition::SL_NOTE, ER_NO_SUCH_USER,
2483                         ER_THD(thd, ER_NO_SUCH_USER), lex->definer->user.str,
2484                         lex->definer->host.str);
2485   }
2486 
2487   return false;
2488 }
2489 
2490 /**
2491   Auxiliary call that opens and locks tables for LOCK TABLES statement
2492   and initializes the list of locked tables.
2493 
2494   @param thd     Thread context.
2495   @param tables  List of tables to be locked.
2496 
2497   @return false in case of success, true in case of error.
2498 */
2499 
lock_tables_open_and_lock_tables(THD * thd,TABLE_LIST * tables)2500 static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables) {
2501   Lock_tables_prelocking_strategy lock_tables_prelocking_strategy;
2502   MDL_deadlock_and_lock_abort_error_handler deadlock_handler;
2503   MDL_savepoint mdl_savepoint = thd->mdl_context.mdl_savepoint();
2504   uint counter;
2505   TABLE_LIST *table;
2506 
2507   thd->in_lock_tables = true;
2508 
2509 retry:
2510 
2511   if (open_tables(thd, &tables, &counter, 0, &lock_tables_prelocking_strategy))
2512     goto err;
2513 
2514   deadlock_handler.init();
2515   thd->push_internal_handler(&deadlock_handler);
2516 
2517   for (table = tables; table; table = table->next_global) {
2518     if (!table->is_placeholder()) {
2519       if (table->table->s->tmp_table) {
2520         /*
2521           We allow to change temporary tables even if they were locked for read
2522           by LOCK TABLES. To avoid a discrepancy between lock acquired at LOCK
2523           TABLES time and by the statement which is later executed under LOCK
2524           TABLES we ensure that for temporary tables we always request a write
2525           lock (such discrepancy can cause problems for the storage engine).
2526           We don't set TABLE_LIST::lock_type in this case as this might result
2527           in extra warnings from THD::decide_logging_format() even though
2528           binary logging is totally irrelevant for LOCK TABLES.
2529         */
2530         table->table->reginfo.lock_type = TL_WRITE;
2531       } else if (table->lock_descriptor().type == TL_READ &&
2532                  !table->prelocking_placeholder &&
2533                  table->table->file->ha_table_flags() & HA_NO_READ_LOCAL_LOCK) {
2534         /*
2535           In case when LOCK TABLE ... READ LOCAL was issued for table with
2536           storage engine which doesn't support READ LOCAL option and doesn't
2537           use THR_LOCK locks we need to upgrade weak SR metadata lock acquired
2538           in open_tables() to stronger SRO metadata lock.
2539           This is not needed for tables used through stored routines or
2540           triggers as we always acquire SRO (or even stronger SNRW) metadata
2541           lock for them.
2542         */
2543         bool result = thd->mdl_context.upgrade_shared_lock(
2544             table->table->mdl_ticket, MDL_SHARED_READ_ONLY,
2545             thd->variables.lock_wait_timeout);
2546 
2547         if (deadlock_handler.need_reopen()) {
2548           /*
2549             Deadlock occurred during upgrade of metadata lock.
2550             Let us restart acquring and opening tables for LOCK TABLES.
2551           */
2552           thd->pop_internal_handler();
2553           close_tables_for_reopen(thd, &tables, mdl_savepoint);
2554           if (open_temporary_tables(thd, tables)) goto err;
2555           goto retry;
2556         }
2557 
2558         if (result) {
2559           thd->pop_internal_handler();
2560           goto err;
2561         }
2562       }
2563     }
2564   }
2565 
2566   thd->pop_internal_handler();
2567 
2568   if (lock_tables(thd, tables, counter, 0) ||
2569       thd->locked_tables_list.init_locked_tables(thd))
2570     goto err;
2571 
2572   thd->in_lock_tables = false;
2573 
2574   return false;
2575 
2576 err:
2577   thd->in_lock_tables = false;
2578 
2579   trans_rollback_stmt(thd);
2580   /*
2581     Need to end the current transaction, so the storage engine (InnoDB)
2582     can free its locks if LOCK TABLES locked some tables before finding
2583     that it can't lock a table in its list
2584   */
2585   trans_rollback(thd);
2586   /* Close tables and release metadata locks. */
2587   close_thread_tables(thd);
2588   DBUG_ASSERT(!thd->locked_tables_mode);
2589   thd->mdl_context.release_transactional_locks();
2590   return true;
2591 }
2592 
2593 /**
2594   This is a wrapper for MYSQL_BIN_LOG::gtid_end_transaction. For normal
2595   statements, the function gtid_end_transaction is called in the commit
2596   handler. However, if the statement is filtered out or not written to
2597   the binary log, the commit handler is not invoked. Therefore, this
2598   wrapper calls gtid_end_transaction in case the current statement is
2599   committing but was not written to the binary log.
2600   (The function gtid_end_transaction ensures that gtid-related
2601   end-of-transaction operations are performed; this includes
2602   generating an empty transaction and calling
2603   Gtid_state::update_gtids_impl.)
2604 
2605   @param thd Thread (session) context.
2606 */
2607 
binlog_gtid_end_transaction(THD * thd)2608 static inline void binlog_gtid_end_transaction(THD *thd) {
2609   DBUG_TRACE;
2610 
2611   /*
2612     This performs end-of-transaction actions needed by GTIDs:
2613     in particular, it generates an empty transaction if
2614     needed (e.g., if the statement was filtered out).
2615 
2616     It is executed at the end of an implicitly or explicitly
2617     committing statement.
2618 
2619     In addition, it is executed after CREATE TEMPORARY TABLE
2620     or DROP TEMPORARY TABLE when they occur outside
2621     transactional context.  When enforce_gtid_consistency is
2622     enabled, these statements cannot occur in transactional
2623     context, and then they behave exactly as implicitly
2624     committing: they are written to the binary log
2625     immediately, not wrapped in BEGIN/COMMIT, and cannot be
2626     rolled back. However, they do not count as implicitly
2627     committing according to stmt_causes_implicit_commit(), so
2628     we need to add special cases in the condition below. Hence
2629     the clauses for SQLCOM_CREATE_TABLE and SQLCOM_DROP_TABLE.
2630 
2631     If enforce_gtid_consistency=off, CREATE TEMPORARY TABLE
2632     and DROP TEMPORARY TABLE can occur in the middle of a
2633     transaction.  Then they do not behave as DDL; they are
2634     written to the binary log inside BEGIN/COMMIT.
2635 
2636     (For base tables, SQLCOM_[CREATE|DROP]_TABLE match both
2637     the stmt_causes_implicit_commit(...) clause and the
2638     thd->lex->sql_command == SQLCOM_* clause; for temporary
2639     tables they match only thd->lex->sql_command == SQLCOM_*.)
2640   */
2641   if (thd->lex->sql_command == SQLCOM_COMMIT ||
2642       thd->lex->sql_command == SQLCOM_XA_PREPARE ||
2643       thd->lex->sql_command == SQLCOM_XA_COMMIT ||
2644       thd->lex->sql_command == SQLCOM_XA_ROLLBACK ||
2645       stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END) ||
2646       ((thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
2647         thd->lex->sql_command == SQLCOM_DROP_TABLE) &&
2648        !thd->in_multi_stmt_transaction_mode()))
2649     (void)mysql_bin_log.gtid_end_transaction(thd);
2650 }
2651 
2652 /**
2653   Execute command saved in thd and lex->sql_command.
2654 
2655   @param thd                       Thread handle
2656   @param first_level               whether invocation of the
2657   mysql_execute_command() is a top level query or sub query. At the highest
2658   level, first_level value is true. Stored procedures can execute sub queries.
2659   In such cases first_level (recursive mysql_execute_command() call) will be
2660   false.
2661 
2662   @todo this is workaround. right way will be move invalidating in
2663     the unlock procedure.
2664   @todo use check_change_password()
2665 
2666   @retval false       OK
2667   @retval true        Error
2668 */
2669 
mysql_execute_command(THD * thd,bool first_level)2670 int mysql_execute_command(THD *thd, bool first_level) {
2671   int res = false;
2672   LEX *const lex = thd->lex;
2673   /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
2674   SELECT_LEX *const select_lex = lex->select_lex;
2675   /* first table of first SELECT_LEX */
2676   TABLE_LIST *const first_table = select_lex->get_table_list();
2677   /* list of all tables in query */
2678   TABLE_LIST *all_tables;
2679   // keep GTID violation state in order to roll it back on statement failure
2680   bool gtid_consistency_violation_state = thd->has_gtid_consistency_violation;
2681   DBUG_ASSERT(select_lex->master_unit() == lex->unit);
2682   DBUG_TRACE;
2683   /* EXPLAIN OTHER isn't explainable command, but can have describe flag. */
2684   DBUG_ASSERT(!lex->is_explain() || is_explainable_query(lex->sql_command) ||
2685               lex->sql_command == SQLCOM_EXPLAIN_OTHER);
2686 
2687   DBUG_ASSERT(!thd->m_transactional_ddl.inited() ||
2688               thd->in_active_multi_stmt_transaction());
2689 
2690   /*
2691     If there is a CREATE TABLE...START TRANSACTION command which
2692     is not yet committed or rollbacked, then we should allow only
2693     BINLOG INSERT, COMMIT or ROLLBACK command.
2694     TODO: Should we really check name of table when we cable BINLOG INSERT ?
2695   */
2696   if (thd->m_transactional_ddl.inited() && lex->sql_command != SQLCOM_COMMIT &&
2697       lex->sql_command != SQLCOM_ROLLBACK &&
2698       lex->sql_command != SQLCOM_BINLOG_BASE64_EVENT) {
2699     my_error(ER_STATEMENT_NOT_ALLOWED_AFTER_START_TRANSACTION, MYF(0));
2700     binlog_gtid_end_transaction(thd);
2701     return 1;
2702   }
2703 
2704   thd->work_part_info = nullptr;
2705 
2706   if (thd->optimizer_switch_flag(OPTIMIZER_SWITCH_SUBQUERY_TO_DERIVED))
2707     lex->add_statement_options(OPTION_NO_CONST_TABLES);
2708 
2709   /*
2710     Each statement or replication event which might produce deadlock
2711     should handle transaction rollback on its own. So by the start of
2712     the next statement transaction rollback request should be fulfilled
2713     already.
2714   */
2715   DBUG_ASSERT(!thd->transaction_rollback_request || thd->in_sub_stmt);
2716   /*
2717     In many cases first table of main SELECT_LEX have special meaning =>
2718     check that it is first table in global list and relink it first in
2719     queries_tables list if it is necessary (we need such relinking only
2720     for queries with subqueries in select list, in this case tables of
2721     subqueries will go to global list first)
2722 
2723     all_tables will differ from first_table only if most upper SELECT_LEX
2724     do not contain tables.
2725 
2726     Because of above in place where should be at least one table in most
2727     outer SELECT_LEX we have following check:
2728     DBUG_ASSERT(first_table == all_tables);
2729     DBUG_ASSERT(first_table == all_tables && first_table != 0);
2730   */
2731   lex->first_lists_tables_same();
2732   /* should be assigned after making first tables same */
2733   all_tables = lex->query_tables;
2734   /* set context for commands which do not use setup_tables */
2735   select_lex->context.resolve_in_table_list_only(select_lex->get_table_list());
2736 
2737   thd->get_stmt_da()->reset_diagnostics_area();
2738   if ((thd->lex->keep_diagnostics != DA_KEEP_PARSE_ERROR) &&
2739       (thd->lex->keep_diagnostics != DA_KEEP_DIAGNOSTICS)) {
2740     /*
2741       No parse errors, and it's not a diagnostic statement:
2742       remove the sql conditions from the DA!
2743       For diagnostic statements we need to keep the conditions
2744       around so we can inspec them.
2745     */
2746     thd->get_stmt_da()->reset_condition_info(thd);
2747   }
2748 
2749   if (thd->resource_group_ctx()->m_warn != 0) {
2750     auto res_grp_name = thd->resource_group_ctx()->m_switch_resource_group_str;
2751     switch (thd->resource_group_ctx()->m_warn) {
2752       case WARN_RESOURCE_GROUP_UNSUPPORTED: {
2753         auto res_grp_mgr = resourcegroups::Resource_group_mgr::instance();
2754         push_warning_printf(thd, Sql_condition::SL_WARNING,
2755                             ER_FEATURE_UNSUPPORTED,
2756                             ER_THD(thd, ER_FEATURE_UNSUPPORTED),
2757                             "Resource groups", res_grp_mgr->unsupport_reason());
2758         break;
2759       }
2760       case WARN_RESOURCE_GROUP_UNSUPPORTED_HINT:
2761         push_warning_printf(thd, Sql_condition::SL_WARNING,
2762                             ER_WARN_UNSUPPORTED_HINT,
2763                             ER_THD(thd, ER_WARN_UNSUPPORTED_HINT),
2764                             "Subquery or Stored procedure or Trigger");
2765         break;
2766       case WARN_RESOURCE_GROUP_TYPE_MISMATCH: {
2767         ulonglong pfs_thread_id = 0;
2768         /*
2769           Resource group is unsupported with DISABLE_PSI_THREAD.
2770           The below #ifdef is required for compilation when DISABLE_PSI_THREAD
2771           is enabled.
2772         */
2773 #ifdef HAVE_PSI_THREAD_INTERFACE
2774         pfs_thread_id = PSI_THREAD_CALL(get_current_thread_internal_id)();
2775 #endif  // HAVE_PSI_THREAD_INTERFACE
2776         push_warning_printf(thd, Sql_condition::SL_WARNING,
2777                             ER_RESOURCE_GROUP_BIND_FAILED,
2778                             ER_THD(thd, ER_RESOURCE_GROUP_BIND_FAILED),
2779                             res_grp_name, pfs_thread_id,
2780                             "System resource group can't be bound"
2781                             " with a session thread");
2782         break;
2783       }
2784       case WARN_RESOURCE_GROUP_NOT_EXISTS:
2785         push_warning_printf(
2786             thd, Sql_condition::SL_WARNING, ER_RESOURCE_GROUP_NOT_EXISTS,
2787             ER_THD(thd, ER_RESOURCE_GROUP_NOT_EXISTS), res_grp_name);
2788         break;
2789       case WARN_RESOURCE_GROUP_ACCESS_DENIED:
2790         push_warning_printf(thd, Sql_condition::SL_WARNING,
2791                             ER_SPECIFIC_ACCESS_DENIED_ERROR,
2792                             ER_THD(thd, ER_SPECIFIC_ACCESS_DENIED_ERROR),
2793                             "SUPER OR RESOURCE_GROUP_ADMIN OR "
2794                             "RESOURCE_GROUP_USER");
2795     }
2796     thd->resource_group_ctx()->m_warn = 0;
2797     res_grp_name[0] = '\0';
2798   }
2799 
2800   if (unlikely(thd->slave_thread)) {
2801     if (!check_database_filters(thd, thd->db().str, lex->sql_command)) {
2802       binlog_gtid_end_transaction(thd);
2803       return 0;
2804     }
2805 
2806     if (lex->sql_command == SQLCOM_DROP_TRIGGER) {
2807       /*
2808         When dropping a trigger, we need to load its table name
2809         before checking slave filter rules.
2810       */
2811       TABLE_LIST *trigger_table = nullptr;
2812       (void)get_table_for_trigger(thd, lex->spname->m_db, lex->spname->m_name,
2813                                   true, &trigger_table);
2814       if (trigger_table != nullptr) {
2815         lex->add_to_query_tables(trigger_table);
2816         all_tables = trigger_table;
2817       } else {
2818         /*
2819           If table name cannot be loaded,
2820           it means the trigger does not exists possibly because
2821           CREATE TRIGGER was previously skipped for this trigger
2822           according to slave filtering rules.
2823           Returning success without producing any errors in this case.
2824         */
2825         binlog_gtid_end_transaction(thd);
2826         return 0;
2827       }
2828 
2829       // force searching in slave.cc:tables_ok()
2830       all_tables->updating = true;
2831     }
2832 
2833     /*
2834       For fix of BUG#37051, the master stores the table map for update
2835       in the Query_log_event, and the value is assigned to
2836       thd->variables.table_map_for_update before executing the update
2837       query.
2838 
2839       If thd->variables.table_map_for_update is set, then we are
2840       replicating from a new master, we can use this value to apply
2841       filter rules without opening all the tables. However If
2842       thd->variables.table_map_for_update is not set, then we are
2843       replicating from an old master, so we just skip this and
2844       continue with the old method. And of course, the bug would still
2845       exist for old masters.
2846     */
2847     if (lex->sql_command == SQLCOM_UPDATE_MULTI && thd->table_map_for_update) {
2848       table_map table_map_for_update = thd->table_map_for_update;
2849       uint nr = 0;
2850       TABLE_LIST *table;
2851       for (table = all_tables; table; table = table->next_global, nr++) {
2852         if (table_map_for_update & ((table_map)1 << nr))
2853           table->updating = true;
2854         else
2855           table->updating = false;
2856       }
2857 
2858       if (all_tables_not_ok(thd, all_tables)) {
2859         /* we warn the slave SQL thread */
2860         my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
2861         binlog_gtid_end_transaction(thd);
2862         return 0;
2863       }
2864 
2865       for (table = all_tables; table; table = table->next_global)
2866         table->updating = true;
2867     }
2868 
2869     /*
2870       Check if statement should be skipped because of slave filtering
2871       rules
2872 
2873       Exceptions are:
2874       - UPDATE MULTI: For this statement, we want to check the filtering
2875         rules later in the code
2876       - SET: we always execute it (Not that many SET commands exists in
2877         the binary log anyway -- only 4.1 masters write SET statements,
2878         in 5.0 there are no SET statements in the binary log)
2879       - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we
2880         have stale files on slave caused by exclusion of one tmp table).
2881     */
2882     if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) &&
2883         !(lex->sql_command == SQLCOM_SET_OPTION) &&
2884         !(lex->sql_command == SQLCOM_DROP_TABLE && lex->drop_temporary &&
2885           lex->drop_if_exists) &&
2886         all_tables_not_ok(thd, all_tables)) {
2887       /* we warn the slave SQL thread */
2888       my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
2889       binlog_gtid_end_transaction(thd);
2890       return 0;
2891     }
2892     /*
2893        Execute deferred events first
2894     */
2895     if (slave_execute_deferred_events(thd)) return -1;
2896 
2897     int ret = launch_hook_trans_begin(thd, all_tables);
2898     if (ret) {
2899       my_error(ret, MYF(0));
2900       return -1;
2901     }
2902 
2903   } else {
2904     int ret = launch_hook_trans_begin(thd, all_tables);
2905     if (ret) {
2906       my_error(ret, MYF(0));
2907       return -1;
2908     }
2909 
2910     /*
2911       When option readonly is set deny operations which change non-temporary
2912       tables. Except for the replication thread and the 'super' users.
2913     */
2914     if (deny_updates_if_read_only_option(thd, all_tables)) {
2915       err_readonly(thd);
2916       return -1;
2917     }
2918   } /* endif unlikely slave */
2919 
2920   thd->status_var.com_stat[lex->sql_command]++;
2921 
2922   Opt_trace_start ots(thd, all_tables, lex->sql_command, &lex->var_list,
2923                       thd->query().str, thd->query().length, nullptr,
2924                       thd->variables.character_set_client);
2925 
2926   Opt_trace_object trace_command(&thd->opt_trace);
2927   Opt_trace_array trace_command_steps(&thd->opt_trace, "steps");
2928 
2929   DBUG_ASSERT(thd->get_transaction()->cannot_safely_rollback(
2930                   Transaction_ctx::STMT) == false);
2931 
2932   switch (gtid_pre_statement_checks(thd)) {
2933     case GTID_STATEMENT_EXECUTE:
2934       break;
2935     case GTID_STATEMENT_CANCEL:
2936       return -1;
2937     case GTID_STATEMENT_SKIP:
2938       my_ok(thd);
2939       binlog_gtid_end_transaction(thd);
2940       return 0;
2941   }
2942 
2943   if (thd->variables.require_row_format) {
2944     if (evaluate_command_row_only_restrictions(thd)) {
2945       my_error(ER_CLIENT_QUERY_FAILURE_INVALID_NON_ROW_FORMAT, MYF(0));
2946       return -1;
2947     }
2948   }
2949 
2950   /*
2951     End a active transaction so that this command will have it's
2952     own transaction and will also sync the binary log. If a DDL is
2953     not run in it's own transaction it may simply never appear on
2954     the slave in case the outside transaction rolls back.
2955   */
2956   if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_BEGIN)) {
2957     /*
2958       Note that this should never happen inside of stored functions
2959       or triggers as all such statements prohibited there.
2960     */
2961     DBUG_ASSERT(!thd->in_sub_stmt);
2962     /* Statement transaction still should not be started. */
2963     DBUG_ASSERT(thd->get_transaction()->is_empty(Transaction_ctx::STMT));
2964 
2965     /*
2966       Implicit commit is not allowed with an active XA transaction.
2967       In this case we should not release metadata locks as the XA transaction
2968       will not be rolled back. Therefore we simply return here.
2969     */
2970     if (trans_check_state(thd)) return -1;
2971 
2972     /* Commit the normal transaction if one is active. */
2973     if (trans_commit_implicit(thd)) return -1;
2974     /* Release metadata locks acquired in this transaction. */
2975     thd->mdl_context.release_transactional_locks();
2976   }
2977 
2978   DEBUG_SYNC(thd, "after_implicit_pre_commit");
2979 
2980   if (gtid_pre_statement_post_implicit_commit_checks(thd)) return -1;
2981 
2982   if (mysql_audit_notify(thd,
2983                          first_level ? MYSQL_AUDIT_QUERY_START
2984                                      : MYSQL_AUDIT_QUERY_NESTED_START,
2985                          first_level ? "MYSQL_AUDIT_QUERY_START"
2986                                      : "MYSQL_AUDIT_QUERY_NESTED_START")) {
2987     return 1;
2988   }
2989 
2990 #ifndef DBUG_OFF
2991   if (lex->sql_command != SQLCOM_SET_OPTION)
2992     DEBUG_SYNC(thd, "before_execute_sql_command");
2993 #endif
2994 
2995   /*
2996     Start a new transaction if CREATE TABLE has START TRANSACTION clause.
2997     Disable binlog so that the BEGIN is not logged in binlog.
2998    */
2999   if (lex->create_info && lex->create_info->m_transactional_ddl &&
3000       !thd->slave_thread) {
3001     Disable_binlog_guard binlog_guard(thd);
3002     if (trans_begin(thd, MYSQL_START_TRANS_OPT_READ_WRITE)) return true;
3003   }
3004 
3005   /*
3006     For statements which need this, prevent InnoDB from automatically
3007     committing InnoDB transaction each time data-dictionary tables are
3008     closed after being updated.
3009   */
3010   Disable_autocommit_guard autocommit_guard(
3011       sqlcom_needs_autocommit_off(lex) && !thd->is_plugin_fake_ddl() ? thd
3012                                                                      : nullptr);
3013 
3014   /*
3015     Check if we are in a read-only transaction and we're trying to
3016     execute a statement which should always be disallowed in such cases.
3017 
3018     Note that this check is done after any implicit commits.
3019   */
3020   if (thd->tx_read_only &&
3021       (sql_command_flags[lex->sql_command] & CF_DISALLOW_IN_RO_TRANS)) {
3022     my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0));
3023     goto error;
3024   }
3025 
3026   /*
3027     Close tables open by HANDLERs before executing DDL statement
3028     which is going to affect those tables.
3029 
3030     This should happen before temporary tables are pre-opened as
3031     otherwise we will get errors about attempt to re-open tables
3032     if table to be changed is open through HANDLER.
3033 
3034     Note that even although this is done before any privilege
3035     checks there is no security problem here as closing open
3036     HANDLER doesn't require any privileges anyway.
3037   */
3038   if (sql_command_flags[lex->sql_command] & CF_HA_CLOSE)
3039     mysql_ha_rm_tables(thd, all_tables);
3040 
3041   /*
3042     Check that the command is allowed on the PROTOCOL_PLUGIN
3043   */
3044   if (thd->get_protocol()->type() == Protocol::PROTOCOL_PLUGIN &&
3045       !(sql_command_flags[lex->sql_command] & CF_ALLOW_PROTOCOL_PLUGIN)) {
3046     my_error(ER_PLUGGABLE_PROTOCOL_COMMAND_NOT_SUPPORTED, MYF(0));
3047     goto error;
3048   }
3049 
3050   /*
3051     Pre-open temporary tables to simplify privilege checking
3052     for statements which need this.
3053   */
3054   if (sql_command_flags[lex->sql_command] & CF_PREOPEN_TMP_TABLES) {
3055     if (open_temporary_tables(thd, all_tables)) goto error;
3056   }
3057 
3058   // Save original info for EXPLAIN FOR CONNECTION
3059   if (!thd->in_sub_stmt)
3060     thd->query_plan.set_query_plan(lex->sql_command, lex,
3061                                    !thd->stmt_arena->is_regular());
3062 
3063   /* Update system variables specified in SET_VAR hints. */
3064   if (lex->opt_hints_global && lex->opt_hints_global->sys_var_hint)
3065     lex->opt_hints_global->sys_var_hint->update_vars(thd);
3066 
3067   /* Check if the statement fulfill the requirements on ACL CACHE */
3068   if (!command_satisfy_acl_cache_requirement(lex->sql_command)) {
3069     my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
3070     goto error;
3071   }
3072 
3073   DBUG_EXECUTE_IF(
3074       "force_rollback_in_slave_on_transactional_ddl_commit",
3075       if (thd->m_transactional_ddl.inited() &&
3076           thd->lex->sql_command == SQLCOM_COMMIT) {
3077         lex->sql_command = SQLCOM_ROLLBACK;
3078       });
3079 
3080   /*
3081     We do not flag "is DML" (TX_STMT_DML) here as replication expects us to
3082     test for LOCK TABLE etc. first. To rephrase, we try not to set TX_STMT_DML
3083     until we have the MDL, and LOCK TABLE could massively delay this.
3084   */
3085 
3086   switch (lex->sql_command) {
3087     case SQLCOM_SHOW_STATUS: {
3088       System_status_var old_status_var = thd->status_var;
3089       thd->initial_status_var = &old_status_var;
3090 
3091       if (!(res = show_precheck(thd, lex, true)))
3092         res = execute_show(thd, all_tables);
3093 
3094       /* Don't log SHOW STATUS commands to slow query log */
3095       thd->server_status &=
3096           ~(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED);
3097       /*
3098         restore status variables, as we don't want 'show status' to cause
3099         changes
3100       */
3101       mysql_mutex_lock(&LOCK_status);
3102       add_diff_to_status(&global_status_var, &thd->status_var, &old_status_var);
3103       thd->status_var = old_status_var;
3104       thd->initial_status_var = nullptr;
3105       mysql_mutex_unlock(&LOCK_status);
3106       break;
3107     }
3108     case SQLCOM_SHOW_EVENTS:
3109     case SQLCOM_SHOW_STATUS_PROC:
3110     case SQLCOM_SHOW_STATUS_FUNC:
3111     case SQLCOM_SHOW_DATABASES:
3112     case SQLCOM_SHOW_TRIGGERS:
3113     case SQLCOM_SHOW_TABLE_STATUS:
3114     case SQLCOM_SHOW_OPEN_TABLES:
3115     case SQLCOM_SHOW_PLUGINS:
3116     case SQLCOM_SHOW_VARIABLES:
3117     case SQLCOM_SHOW_CHARSETS:
3118     case SQLCOM_SHOW_COLLATIONS:
3119     case SQLCOM_SHOW_STORAGE_ENGINES:
3120     case SQLCOM_SHOW_PROFILE: {
3121       DBUG_EXECUTE_IF("use_attachable_trx",
3122                       thd->begin_attachable_ro_transaction(););
3123 
3124       thd->clear_current_query_costs();
3125 
3126       Enable_derived_merge_guard derived_merge_guard(
3127           thd, is_show_cmd_using_system_view(thd));
3128 
3129       res = show_precheck(thd, lex, true);
3130 
3131       if (!res) res = execute_show(thd, all_tables);
3132 
3133       thd->save_current_query_costs();
3134 
3135       DBUG_EXECUTE_IF("use_attachable_trx", thd->end_attachable_transaction(););
3136 
3137       break;
3138     }
3139     case SQLCOM_PREPARE: {
3140       mysql_sql_stmt_prepare(thd);
3141       break;
3142     }
3143     case SQLCOM_EXECUTE: {
3144       mysql_sql_stmt_execute(thd);
3145       break;
3146     }
3147     case SQLCOM_DEALLOCATE_PREPARE: {
3148       mysql_sql_stmt_close(thd);
3149       break;
3150     }
3151 
3152     case SQLCOM_EMPTY_QUERY:
3153       my_ok(thd);
3154       break;
3155 
3156     case SQLCOM_HELP:
3157       res = mysqld_help(thd, lex->help_arg);
3158       break;
3159 
3160     case SQLCOM_PURGE: {
3161       Security_context *sctx = thd->security_context();
3162       if (!sctx->check_access(SUPER_ACL) &&
3163           !sctx->has_global_grant(STRING_WITH_LEN("BINLOG_ADMIN")).first) {
3164         my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0),
3165                  "SUPER or BINLOG_ADMIN");
3166         goto error;
3167       }
3168       /* PURGE MASTER LOGS TO 'file' */
3169       res = purge_master_logs(thd, lex->to_log);
3170       break;
3171     }
3172     case SQLCOM_PURGE_BEFORE: {
3173       Item *it;
3174       Security_context *sctx = thd->security_context();
3175       if (!sctx->check_access(SUPER_ACL) &&
3176           !sctx->has_global_grant(STRING_WITH_LEN("BINLOG_ADMIN")).first) {
3177         my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0),
3178                  "SUPER or BINLOG_ADMIN");
3179         goto error;
3180       }
3181       /* PURGE MASTER LOGS BEFORE 'data' */
3182       it = lex->purge_value_list.head();
3183       if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) {
3184         my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE");
3185         goto error;
3186       }
3187       it = new Item_func_unix_timestamp(it);
3188       /*
3189         it is OK only emulate fix_fieds, because we need only
3190         value of constant
3191       */
3192       it->quick_fix_field();
3193       time_t purge_time = static_cast<time_t>(it->val_int());
3194       if (thd->is_error()) goto error;
3195       res = purge_master_logs_before_date(thd, purge_time);
3196       break;
3197     }
3198     case SQLCOM_SHOW_WARNS: {
3199       res = mysqld_show_warnings(
3200           thd, (ulong)((1L << (uint)Sql_condition::SL_NOTE) |
3201                        (1L << (uint)Sql_condition::SL_WARNING) |
3202                        (1L << (uint)Sql_condition::SL_ERROR)));
3203       break;
3204     }
3205     case SQLCOM_SHOW_ERRORS: {
3206       res = mysqld_show_warnings(thd,
3207                                  (ulong)(1L << (uint)Sql_condition::SL_ERROR));
3208       break;
3209     }
3210     case SQLCOM_SHOW_PROFILES: {
3211 #if defined(ENABLED_PROFILING)
3212       thd->profiling->discard_current_query();
3213       res = thd->profiling->show_profiles();
3214       if (res) goto error;
3215 #else
3216       my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILES",
3217                "enable-profiling");
3218       goto error;
3219 #endif
3220       break;
3221     }
3222     case SQLCOM_SHOW_SLAVE_HOSTS: {
3223       if (check_global_access(thd, REPL_SLAVE_ACL)) goto error;
3224       res = show_slave_hosts(thd);
3225       break;
3226     }
3227     case SQLCOM_SHOW_RELAYLOG_EVENTS: {
3228       if (check_global_access(thd, REPL_SLAVE_ACL)) goto error;
3229       res = mysql_show_relaylog_events(thd);
3230       break;
3231     }
3232     case SQLCOM_SHOW_BINLOG_EVENTS: {
3233       if (check_global_access(thd, REPL_SLAVE_ACL)) goto error;
3234       res = mysql_show_binlog_events(thd);
3235       break;
3236     }
3237     case SQLCOM_CHANGE_MASTER: {
3238       Security_context *sctx = thd->security_context();
3239       if (!sctx->check_access(SUPER_ACL) &&
3240           !sctx->has_global_grant(STRING_WITH_LEN("REPLICATION_SLAVE_ADMIN"))
3241                .first) {
3242         my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0),
3243                  "SUPER or REPLICATION_SLAVE_ADMIN");
3244         goto error;
3245       }
3246       res = change_master_cmd(thd);
3247       break;
3248     }
3249     case SQLCOM_SHOW_SLAVE_STAT: {
3250       /* Accept one of two privileges */
3251       if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error;
3252       res = show_slave_status_cmd(thd);
3253       break;
3254     }
3255     case SQLCOM_SHOW_MASTER_STAT: {
3256       /* Accept one of two privileges */
3257       if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error;
3258       res = show_master_status(thd);
3259       break;
3260     }
3261     case SQLCOM_SHOW_ENGINE_STATUS: {
3262       if (check_global_access(thd, PROCESS_ACL)) goto error;
3263       res = ha_show_status(thd, lex->create_info->db_type, HA_ENGINE_STATUS);
3264       break;
3265     }
3266     case SQLCOM_SHOW_ENGINE_MUTEX: {
3267       if (check_global_access(thd, PROCESS_ACL)) goto error;
3268       res = ha_show_status(thd, lex->create_info->db_type, HA_ENGINE_MUTEX);
3269       break;
3270     }
3271     case SQLCOM_START_GROUP_REPLICATION: {
3272       Security_context *sctx = thd->security_context();
3273       if (!sctx->check_access(SUPER_ACL) &&
3274           !sctx->has_global_grant(STRING_WITH_LEN("GROUP_REPLICATION_ADMIN"))
3275                .first) {
3276         my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0),
3277                  "SUPER or GROUP_REPLICATION_ADMIN");
3278         goto error;
3279       }
3280       if (lex->slave_connection.password && !lex->slave_connection.user) {
3281         my_error(ER_GROUP_REPLICATION_USER_MANDATORY_MSG, MYF(0));
3282         goto error;
3283       }
3284 
3285       /*
3286         If the client thread has locked tables, a deadlock is possible.
3287         Assume that
3288         - the client thread does LOCK TABLE t READ.
3289         - then the client thread does START GROUP_REPLICATION.
3290              -try to make the server in super ready only mode
3291              -acquire MDL lock ownership which will be waiting for
3292               LOCK on table t to be released.
3293         To prevent that, refuse START GROUP_REPLICATION if the
3294         client thread has locked tables
3295       */
3296       if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction() ||
3297           thd->in_sub_stmt) {
3298         my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
3299         goto error;
3300       }
3301 
3302       if (Clone_handler::is_provisioning()) {
3303         my_error(ER_GROUP_REPLICATION_COMMAND_FAILURE, MYF(0),
3304                  "START GROUP_REPLICATION",
3305                  "This server is being provisioned by CLONE INSTANCE, "
3306                  "please wait until it is complete.");
3307         goto error;
3308       }
3309 
3310       char *error_message = nullptr;
3311       res = group_replication_start(&error_message, thd);
3312 
3313       // To reduce server dependency, server errors are not used here
3314       switch (res) {
3315         case 1:  // GROUP_REPLICATION_CONFIGURATION_ERROR
3316           my_error(ER_GROUP_REPLICATION_CONFIGURATION, MYF(0));
3317           goto error;
3318         case 2:  // GROUP_REPLICATION_ALREADY_RUNNING
3319           my_error(ER_GROUP_REPLICATION_RUNNING, MYF(0));
3320           goto error;
3321         case 3:  // GROUP_REPLICATION_REPLICATION_APPLIER_INIT_ERROR
3322           my_error(ER_GROUP_REPLICATION_APPLIER_INIT_ERROR, MYF(0));
3323           goto error;
3324         case 4:  // GROUP_REPLICATION_COMMUNICATION_LAYER_SESSION_ERROR
3325           my_error(ER_GROUP_REPLICATION_COMMUNICATION_LAYER_SESSION_ERROR,
3326                    MYF(0));
3327           goto error;
3328         case 5:  // GROUP_REPLICATION_COMMUNICATION_LAYER_JOIN_ERROR
3329           my_error(ER_GROUP_REPLICATION_COMMUNICATION_LAYER_JOIN_ERROR, MYF(0));
3330           goto error;
3331         case 7:  // GROUP_REPLICATION_MAX_GROUP_SIZE
3332           my_error(ER_GROUP_REPLICATION_MAX_GROUP_SIZE, MYF(0));
3333           goto error;
3334         case 8:  // GROUP_REPLICATION_COMMAND_FAILURE
3335           if (error_message == nullptr) {
3336             my_error(ER_GROUP_REPLICATION_COMMAND_FAILURE, MYF(0),
3337                      "START GROUP_REPLICATION",
3338                      "Please check error log for additional details.");
3339           } else {
3340             my_error(ER_GROUP_REPLICATION_COMMAND_FAILURE, MYF(0),
3341                      "START GROUP_REPLICATION", error_message);
3342             my_free(error_message);
3343           }
3344           goto error;
3345         case 9:  // GROUP_REPLICATION_SERVICE_MESSAGE_INIT_FAILURE
3346           my_error(ER_GRP_RPL_MESSAGE_SERVICE_INIT_FAILURE, MYF(0));
3347           goto error;
3348       }
3349       my_ok(thd);
3350       res = 0;
3351       break;
3352     }
3353 
3354     case SQLCOM_STOP_GROUP_REPLICATION: {
3355       Security_context *sctx = thd->security_context();
3356       if (!sctx->check_access(SUPER_ACL) &&
3357           !sctx->has_global_grant(STRING_WITH_LEN("GROUP_REPLICATION_ADMIN"))
3358                .first) {
3359         my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0),
3360                  "SUPER or GROUP_REPLICATION_ADMIN");
3361         goto error;
3362       }
3363 
3364       /*
3365         Please see explanation @SQLCOM_SLAVE_STOP case
3366         to know the reason for thd->locked_tables_mode in
3367         the below if condition.
3368       */
3369       if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction() ||
3370           thd->in_sub_stmt) {
3371         my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
3372         goto error;
3373       }
3374 
3375       char *error_message = nullptr;
3376       res = group_replication_stop(&error_message);
3377       if (res == 1)  // GROUP_REPLICATION_CONFIGURATION_ERROR
3378       {
3379         my_error(ER_GROUP_REPLICATION_CONFIGURATION, MYF(0));
3380         goto error;
3381       }
3382       if (res == 6)  // GROUP_REPLICATION_APPLIER_THREAD_TIMEOUT
3383       {
3384         my_error(ER_GROUP_REPLICATION_STOP_APPLIER_THREAD_TIMEOUT, MYF(0));
3385         goto error;
3386       }
3387       if (res == 8)  // GROUP_REPLICATION_COMMAND_FAILURE
3388       {
3389         if (error_message == nullptr) {
3390           my_error(ER_GROUP_REPLICATION_COMMAND_FAILURE, MYF(0),
3391                    "STOP GROUP_REPLICATION",
3392                    "Please check error log for additonal details.");
3393         } else {
3394           my_error(ER_GROUP_REPLICATION_COMMAND_FAILURE, MYF(0),
3395                    "STOP GROUP_REPLICATION", error_message);
3396           my_free(error_message);
3397         }
3398         goto error;
3399       }
3400       my_ok(thd);
3401       res = 0;
3402       break;
3403     }
3404 
3405     case SQLCOM_SLAVE_START: {
3406       res = start_slave_cmd(thd);
3407       break;
3408     }
3409     case SQLCOM_SLAVE_STOP: {
3410       /*
3411         If the client thread has locked tables, a deadlock is possible.
3412         Assume that
3413         - the client thread does LOCK TABLE t READ.
3414         - then the master updates t.
3415         - then the SQL slave thread wants to update t,
3416           so it waits for the client thread because t is locked by it.
3417         - then the client thread does SLAVE STOP.
3418           SLAVE STOP waits for the SQL slave thread to terminate its
3419           update t, which waits for the client thread because t is locked by it.
3420         To prevent that, refuse SLAVE STOP if the
3421         client thread has locked tables
3422       */
3423       if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction() ||
3424           thd->global_read_lock.is_acquired()) {
3425         my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0));
3426         goto error;
3427       }
3428 
3429       res = stop_slave_cmd(thd);
3430       break;
3431     }
3432     case SQLCOM_RENAME_TABLE: {
3433       DBUG_ASSERT(first_table == all_tables && first_table != nullptr);
3434       TABLE_LIST *table;
3435       for (table = first_table; table; table = table->next_local->next_local) {
3436         if (check_access(thd, ALTER_ACL | DROP_ACL, table->db,
3437                          &table->grant.privilege, &table->grant.m_internal,
3438                          false, false) ||
3439             check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db,
3440                          &table->next_local->grant.privilege,
3441                          &table->next_local->grant.m_internal, false, false))
3442           goto error;
3443 
3444         TABLE_LIST old_list = table[0];
3445         TABLE_LIST new_list = table->next_local[0];
3446         /*
3447           It's not clear what the above assignments actually want to
3448           accomplish. What we do know is that they do *not* want to copy the MDL
3449           requests, so we overwrite them with uninitialized request.
3450         */
3451         old_list.mdl_request = MDL_request();
3452         new_list.mdl_request = MDL_request();
3453 
3454         if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, false, 1,
3455                         false) ||
3456             (!test_all_bits(table->next_local->grant.privilege,
3457                             INSERT_ACL | CREATE_ACL) &&
3458              check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, false, 1,
3459                          false)))
3460           goto error;
3461       }
3462 
3463       if (mysql_rename_tables(thd, first_table)) goto error;
3464       break;
3465     }
3466     case SQLCOM_SHOW_BINLOGS: {
3467       if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) goto error;
3468       res = show_binlogs(thd);
3469       break;
3470     }
3471     case SQLCOM_SHOW_CREATE:
3472       DBUG_ASSERT(first_table == all_tables && first_table != nullptr);
3473       {
3474         /*
3475            Access check:
3476            SHOW CREATE TABLE require any privileges on the table level (ie
3477            effecting all columns in the table).
3478            SHOW CREATE VIEW require the SHOW_VIEW and SELECT ACLs on the table
3479            level.
3480            NOTE: SHOW_VIEW ACL is checked when the view is created.
3481          */
3482 
3483         DBUG_PRINT("debug", ("lex->only_view: %d, table: %s.%s", lex->only_view,
3484                              first_table->db, first_table->table_name));
3485         if (lex->only_view) {
3486           if (check_table_access(thd, SELECT_ACL, first_table, false, 1,
3487                                  false)) {
3488             DBUG_PRINT("debug", ("check_table_access failed"));
3489             my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "SHOW",
3490                      thd->security_context()->priv_user().str,
3491                      thd->security_context()->host_or_ip().str,
3492                      first_table->alias);
3493             goto error;
3494           }
3495           DBUG_PRINT("debug", ("check_table_access succeeded"));
3496 
3497           /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
3498           first_table->open_type = OT_BASE_ONLY;
3499 
3500         } else {
3501           /*
3502             Temporary tables should be opened for SHOW CREATE TABLE, but not
3503             for SHOW CREATE VIEW.
3504           */
3505           if (open_temporary_tables(thd, all_tables)) goto error;
3506 
3507           /*
3508             The fact that check_some_access() returned false does not mean that
3509             access is granted. We need to check if first_table->grant.privilege
3510             contains any table-specific privilege.
3511           */
3512           DBUG_PRINT("debug", ("first_table->grant.privilege: %lx",
3513                                first_table->grant.privilege));
3514           if (check_some_access(thd, TABLE_OP_ACLS, first_table) ||
3515               (first_table->grant.privilege & TABLE_OP_ACLS) == 0) {
3516             my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "SHOW",
3517                      thd->security_context()->priv_user().str,
3518                      thd->security_context()->host_or_ip().str,
3519                      first_table->alias);
3520             goto error;
3521           }
3522         }
3523 
3524         /* Access is granted. Execute the command.  */
3525         res = mysqld_show_create(thd, first_table);
3526         break;
3527       }
3528     case SQLCOM_CHECKSUM: {
3529       DBUG_ASSERT(first_table == all_tables && first_table != nullptr);
3530       if (check_table_access(thd, SELECT_ACL, all_tables, false, UINT_MAX,
3531                              false))
3532         goto error; /* purecov: inspected */
3533 
3534       res = mysql_checksum_table(thd, first_table, &lex->check_opt);
3535       break;
3536     }
3537     case SQLCOM_REPLACE:
3538     case SQLCOM_INSERT:
3539     case SQLCOM_REPLACE_SELECT:
3540     case SQLCOM_INSERT_SELECT:
3541     case SQLCOM_DELETE:
3542     case SQLCOM_DELETE_MULTI:
3543     case SQLCOM_UPDATE:
3544     case SQLCOM_UPDATE_MULTI:
3545     case SQLCOM_CREATE_TABLE:
3546     case SQLCOM_CREATE_INDEX:
3547     case SQLCOM_DROP_INDEX:
3548     case SQLCOM_ASSIGN_TO_KEYCACHE:
3549     case SQLCOM_PRELOAD_KEYS:
3550     case SQLCOM_LOAD: {
3551       DBUG_ASSERT(first_table == all_tables && first_table != nullptr);
3552       DBUG_ASSERT(lex->m_sql_cmd != nullptr);
3553       res = lex->m_sql_cmd->execute(thd);
3554       break;
3555     }
3556     case SQLCOM_DROP_TABLE: {
3557       DBUG_ASSERT(first_table == all_tables && first_table != nullptr);
3558       if (!lex->drop_temporary) {
3559         if (check_table_access(thd, DROP_ACL, all_tables, false, UINT_MAX,
3560                                false))
3561           goto error; /* purecov: inspected */
3562       }
3563       /* DDL and binlog write order are protected by metadata locks. */
3564       res = mysql_rm_table(thd, first_table, lex->drop_if_exists,
3565                            lex->drop_temporary);
3566       /* when dropping temporary tables if @@session_track_state_change is ON
3567          then send the boolean tracker in the OK packet */
3568       if (!res && lex->drop_temporary) {
3569         if (thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)
3570                 ->is_enabled())
3571           thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)
3572               ->mark_as_changed(thd, nullptr);
3573       }
3574     } break;
3575     case SQLCOM_SHOW_PROCESSLIST:
3576       if (!thd->security_context()->priv_user().str[0] &&
3577           check_global_access(thd, PROCESS_ACL))
3578         break;
3579       mysqld_list_processes(thd,
3580                             (thd->security_context()->check_access(PROCESS_ACL)
3581                                  ? NullS
3582                                  : thd->security_context()->priv_user().str),
3583                             lex->verbose);
3584       break;
3585     case SQLCOM_SHOW_ENGINE_LOGS: {
3586       if (check_access(thd, FILE_ACL, any_db, nullptr, nullptr, false, false))
3587         goto error;
3588       res = ha_show_status(thd, lex->create_info->db_type, HA_ENGINE_LOGS);
3589       break;
3590     }
3591     case SQLCOM_CHANGE_DB: {
3592       const LEX_CSTRING db_str = {select_lex->db, strlen(select_lex->db)};
3593 
3594       if (!mysql_change_db(thd, db_str, false)) my_ok(thd);
3595 
3596       break;
3597     }
3598 
3599     case SQLCOM_SET_OPTION: {
3600       List<set_var_base> *lex_var_list = &lex->var_list;
3601 
3602       if (check_table_access(thd, SELECT_ACL, all_tables, false, UINT_MAX,
3603                              false))
3604         goto error;
3605       if (open_tables_for_query(thd, all_tables, false)) goto error;
3606       if (!(res = sql_set_variables(thd, lex_var_list, true)))
3607         my_ok(thd);
3608       else {
3609         /*
3610           We encountered some sort of error, but no message was sent.
3611           Send something semi-generic here since we don't know which
3612           assignment in the list caused the error.
3613         */
3614         if (!thd->is_error()) my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET");
3615         goto error;
3616       }
3617 
3618 #ifndef DBUG_OFF
3619       /*
3620         Makes server crash when executing SET SESSION debug = 'd,crash_now';
3621         See mysql-test/include/dbug_crash[_all].inc
3622       */
3623       const bool force_server_crash_dbug = false;
3624       DBUG_EXECUTE_IF("crash_now", DBUG_ASSERT(force_server_crash_dbug););
3625       DBUG_EXECUTE_IF("crash_now_safe", DBUG_SUICIDE(););
3626 #endif
3627 
3628       break;
3629     }
3630     case SQLCOM_SET_PASSWORD: {
3631       List<set_var_base> *lex_var_list = &lex->var_list;
3632 
3633       DBUG_ASSERT(lex_var_list->elements == 1);
3634       DBUG_ASSERT(all_tables == nullptr);
3635       Userhostpassword_list generated_passwords;
3636       if (!(res = sql_set_variables(thd, lex_var_list, false))) {
3637         List_iterator_fast<set_var_base> it(*lex_var_list);
3638         set_var_base *var;
3639         while ((var = it++)) {
3640           set_var_password *setpasswd = static_cast<set_var_password *>(var);
3641           if (setpasswd->has_generated_password()) {
3642             const LEX_USER *user = setpasswd->get_user();
3643             generated_passwords.push_back(
3644                 {std::string(user->user.str, user->user.length),
3645                  std::string(user->host.str, user->host.length),
3646                  setpasswd->get_generated_password()});
3647           }
3648         }
3649         if (generated_passwords.size() > 0) {
3650           if (send_password_result_set(thd, generated_passwords)) goto error;
3651         }  // end if generated_passwords
3652         if (generated_passwords.size() == 0) my_ok(thd);
3653       } else {
3654         // We encountered some sort of error, but no message was sent.
3655         if (!thd->is_error())
3656           my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET PASSWORD");
3657         goto error;
3658       }
3659 
3660       break;
3661     }
3662 
3663     case SQLCOM_UNLOCK_TABLES:
3664       /*
3665         It is critical for mysqldump --single-transaction --master-data that
3666         UNLOCK TABLES does not implicitely commit a connection which has only
3667         done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes
3668         false, mysqldump will not work.
3669       */
3670       if (thd->variables.option_bits & OPTION_TABLE_LOCK) {
3671         /*
3672           Can we commit safely? If not, return to avoid releasing
3673           transactional metadata locks.
3674         */
3675         if (trans_check_state(thd)) return -1;
3676         res = trans_commit_implicit(thd);
3677         thd->locked_tables_list.unlock_locked_tables(thd);
3678         thd->mdl_context.release_transactional_locks();
3679         thd->variables.option_bits &= ~(OPTION_TABLE_LOCK);
3680       }
3681       if (thd->global_read_lock.is_acquired())
3682         thd->global_read_lock.unlock_global_read_lock(thd);
3683       if (res) goto error;
3684       my_ok(thd);
3685       break;
3686     case SQLCOM_LOCK_TABLES:
3687       /*
3688         Can we commit safely? If not, return to avoid releasing
3689         transactional metadata locks.
3690       */
3691       if (trans_check_state(thd)) return -1;
3692       /* We must end the transaction first, regardless of anything */
3693       res = trans_commit_implicit(thd);
3694       thd->locked_tables_list.unlock_locked_tables(thd);
3695       /* Release transactional metadata locks. */
3696       thd->mdl_context.release_transactional_locks();
3697       if (res) goto error;
3698 
3699       /*
3700         Here we have to pre-open temporary tables for LOCK TABLES.
3701 
3702         CF_PREOPEN_TMP_TABLES is not set for this SQL statement simply
3703         because LOCK TABLES calls close_thread_tables() as a first thing
3704         (it's called from unlock_locked_tables() above). So even if
3705         CF_PREOPEN_TMP_TABLES was set and the tables would be pre-opened
3706         in a usual way, they would have been closed.
3707       */
3708 
3709       if (open_temporary_tables(thd, all_tables)) goto error;
3710 
3711       if (lock_tables_precheck(thd, all_tables)) goto error;
3712 
3713       thd->variables.option_bits |= OPTION_TABLE_LOCK;
3714 
3715       res = lock_tables_open_and_lock_tables(thd, all_tables);
3716 
3717       if (res) {
3718         thd->variables.option_bits &= ~(OPTION_TABLE_LOCK);
3719       } else {
3720         my_ok(thd);
3721       }
3722       break;
3723 
3724     case SQLCOM_IMPORT:
3725       res = lex->m_sql_cmd->execute(thd);
3726       break;
3727     case SQLCOM_CREATE_DB: {
3728       const char *alias;
3729       if (!(alias = thd->strmake(lex->name.str, lex->name.length)) ||
3730           (check_and_convert_db_name(&lex->name, false) !=
3731            Ident_name_check::OK))
3732         break;
3733       if (check_access(thd, CREATE_ACL, lex->name.str, nullptr, nullptr, true,
3734                        false))
3735         break;
3736       /*
3737         As mysql_create_db() may modify HA_CREATE_INFO structure passed to
3738         it, we need to use a copy of LEX::create_info to make execution
3739         prepared statement- safe.
3740       */
3741       HA_CREATE_INFO create_info(*lex->create_info);
3742       res = mysql_create_db(
3743           thd, (lower_case_table_names == 2 ? alias : lex->name.str),
3744           &create_info);
3745       break;
3746     }
3747     case SQLCOM_DROP_DB: {
3748       if (check_and_convert_db_name(&lex->name, false) != Ident_name_check::OK)
3749         break;
3750       if (check_access(thd, DROP_ACL, lex->name.str, nullptr, nullptr, true,
3751                        false))
3752         break;
3753       res = mysql_rm_db(thd, to_lex_cstring(lex->name), lex->drop_if_exists);
3754       break;
3755     }
3756     case SQLCOM_ALTER_DB: {
3757       if (check_and_convert_db_name(&lex->name, false) != Ident_name_check::OK)
3758         break;
3759       if (check_access(thd, ALTER_ACL, lex->name.str, nullptr, nullptr, true,
3760                        false))
3761         break;
3762       /*
3763         As mysql_alter_db() may modify HA_CREATE_INFO structure passed to
3764         it, we need to use a copy of LEX::create_info to make execution
3765         prepared statement- safe.
3766       */
3767       HA_CREATE_INFO create_info(*lex->create_info);
3768       res = mysql_alter_db(thd, lex->name.str, &create_info);
3769       break;
3770     }
3771     case SQLCOM_SHOW_CREATE_DB: {
3772       DBUG_EXECUTE_IF("4x_server_emul", my_error(ER_UNKNOWN_ERROR, MYF(0));
3773                       goto error;);
3774       if (check_and_convert_db_name(&lex->name, true) != Ident_name_check::OK)
3775         break;
3776       res = mysqld_show_create_db(thd, lex->name.str, lex->create_info);
3777       break;
3778     }
3779     case SQLCOM_CREATE_EVENT:
3780     case SQLCOM_ALTER_EVENT:
3781       do {
3782         DBUG_ASSERT(lex->event_parse_data);
3783         if (lex->table_or_sp_used()) {
3784           my_error(ER_NOT_SUPPORTED_YET, MYF(0),
3785                    "Usage of subqueries or stored "
3786                    "function calls as part of this statement");
3787           break;
3788         }
3789 
3790         res = sp_process_definer(thd);
3791         if (res) break;
3792 
3793         switch (lex->sql_command) {
3794           case SQLCOM_CREATE_EVENT: {
3795             bool if_not_exists =
3796                 (lex->create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS);
3797             res =
3798                 Events::create_event(thd, lex->event_parse_data, if_not_exists);
3799             break;
3800           }
3801           case SQLCOM_ALTER_EVENT: {
3802             LEX_CSTRING name_lex_str = NULL_CSTR;
3803             if (lex->spname) {
3804               name_lex_str.str = lex->spname->m_name.str;
3805               name_lex_str.length = lex->spname->m_name.length;
3806             }
3807 
3808             res =
3809                 Events::update_event(thd, lex->event_parse_data,
3810                                      lex->spname ? &lex->spname->m_db : nullptr,
3811                                      lex->spname ? &name_lex_str : nullptr);
3812             break;
3813           }
3814           default:
3815             DBUG_ASSERT(0);
3816         }
3817         DBUG_PRINT("info", ("DDL error code=%d", res));
3818         if (!res && !thd->killed) my_ok(thd);
3819 
3820       } while (false);
3821       /* Don't do it, if we are inside a SP */
3822       if (!thd->sp_runtime_ctx) {
3823         sp_head::destroy(lex->sphead);
3824         lex->sphead = nullptr;
3825       }
3826       /* lex->unit->cleanup() is called outside, no need to call it here */
3827       break;
3828     case SQLCOM_SHOW_CREATE_EVENT: {
3829       res = Events::show_create_event(thd, lex->spname->m_db,
3830                                       to_lex_cstring(lex->spname->m_name));
3831       break;
3832     }
3833     case SQLCOM_DROP_EVENT: {
3834       if (!(res = Events::drop_event(thd, lex->spname->m_db,
3835                                      to_lex_cstring(lex->spname->m_name),
3836                                      lex->drop_if_exists)))
3837         my_ok(thd);
3838       break;
3839     }
3840     case SQLCOM_CREATE_FUNCTION:  // UDF function
3841     {
3842       if (check_access(thd, INSERT_ACL, "mysql", nullptr, nullptr, true, false))
3843         break;
3844       if (!(res = mysql_create_function(thd, &lex->udf))) my_ok(thd);
3845       break;
3846     }
3847     case SQLCOM_CREATE_USER: {
3848       if (check_access(thd, INSERT_ACL, "mysql", nullptr, nullptr, true,
3849                        true) &&
3850           check_global_access(thd, CREATE_USER_ACL))
3851         break;
3852       /* Conditionally writes to binlog */
3853       HA_CREATE_INFO create_info(*lex->create_info);
3854       if (!(res = mysql_create_user(
3855                 thd, lex->users_list,
3856                 create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS, false))) {
3857         // OK or result set was already sent.
3858       }
3859 
3860       break;
3861     }
3862     case SQLCOM_DROP_USER: {
3863       if (check_access(thd, DELETE_ACL, "mysql", nullptr, nullptr, true,
3864                        true) &&
3865           check_global_access(thd, CREATE_USER_ACL))
3866         break;
3867       /* Conditionally writes to binlog */
3868       if (!(res = mysql_drop_user(thd, lex->users_list, lex->drop_if_exists,
3869                                   false)))
3870         my_ok(thd);
3871 
3872       break;
3873     }
3874     case SQLCOM_RENAME_USER: {
3875       if (check_access(thd, UPDATE_ACL, "mysql", nullptr, nullptr, true,
3876                        true) &&
3877           check_global_access(thd, CREATE_USER_ACL))
3878         break;
3879       /* Conditionally writes to binlog */
3880       if (!(res = mysql_rename_user(thd, lex->users_list))) my_ok(thd);
3881       break;
3882     }
3883     case SQLCOM_REVOKE_ALL: {
3884       if (check_access(thd, UPDATE_ACL, "mysql", nullptr, nullptr, true,
3885                        true) &&
3886           check_global_access(thd, CREATE_USER_ACL))
3887         break;
3888 
3889       /* Replicate current user as grantor */
3890       thd->binlog_invoker();
3891 
3892       /* Conditionally writes to binlog */
3893       if (!(res = mysql_revoke_all(thd, lex->users_list))) my_ok(thd);
3894       break;
3895     }
3896     case SQLCOM_REVOKE:
3897     case SQLCOM_GRANT: {
3898       /* GRANT ... AS preliminery checks */
3899       if (lex->grant_as.grant_as_used) {
3900         if ((first_table || select_lex->db)) {
3901           my_error(ER_UNSUPPORTED_USE_OF_GRANT_AS, MYF(0));
3902           goto error;
3903         }
3904       }
3905       /*
3906         Skip access check if we're granting a proxy
3907       */
3908       if (lex->type != TYPE_ENUM_PROXY) {
3909         /*
3910           If there are static grants in the GRANT statement or there are no
3911           dynamic privileges we perform check_access on GRANT_OPTION based on
3912           static global privilege level and set the DA accordingly.
3913         */
3914         if (lex->grant > 0 || lex->dynamic_privileges.elements == 0) {
3915           /*
3916             check_access sets DA error message based on GRANT arguments.
3917           */
3918           if (check_access(
3919                   thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
3920                   first_table ? first_table->db : select_lex->db,
3921                   first_table ? &first_table->grant.privilege : nullptr,
3922                   first_table ? &first_table->grant.m_internal : nullptr,
3923                   first_table ? false : true, false)) {
3924             goto error;
3925           }
3926         }
3927         /*
3928           ..else we still call check_access to load internal structures, but
3929           defer checking of global dynamic GRANT_OPTION to mysql_grant. We still
3930           ignore checks if this was a grant of a proxy.
3931         */
3932         else {
3933           /*
3934             check_access will load grant.privilege and grant.m_internal with
3935             values which are used later during column privilege checking. The
3936             return value isn't interesting as we'll check for dynamic global
3937             privileges later.
3938           */
3939           check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL,
3940                        first_table ? first_table->db : select_lex->db,
3941                        first_table ? &first_table->grant.privilege : nullptr,
3942                        first_table ? &first_table->grant.m_internal : nullptr,
3943                        first_table ? false : true, true);
3944         }
3945       }
3946 
3947       /* Replicate current user as grantor */
3948       thd->binlog_invoker();
3949 
3950       if (thd->security_context()->user().str)  // If not replication
3951       {
3952         LEX_USER *user, *tmp_user;
3953         bool first_user = true;
3954 
3955         List_iterator<LEX_USER> user_list(lex->users_list);
3956         while ((tmp_user = user_list++)) {
3957           if (!(user = get_current_user(thd, tmp_user))) goto error;
3958           if (specialflag & SPECIAL_NO_RESOLVE &&
3959               hostname_requires_resolving(user->host.str))
3960             push_warning(thd, Sql_condition::SL_WARNING,
3961                          ER_WARN_HOSTNAME_WONT_WORK,
3962                          ER_THD(thd, ER_WARN_HOSTNAME_WONT_WORK));
3963           // Are we trying to change a password of another user
3964           DBUG_ASSERT(user->host.str != nullptr);
3965 
3966           /*
3967             GRANT/REVOKE PROXY has the target user as a first entry in the list.
3968            */
3969           if (lex->type == TYPE_ENUM_PROXY && first_user) {
3970             first_user = false;
3971             if (acl_check_proxy_grant_access(thd, user->host.str,
3972                                              user->user.str,
3973                                              lex->grant & GRANT_ACL))
3974               goto error;
3975           }
3976         }
3977       }
3978       if (first_table) {
3979         if (lex->dynamic_privileges.elements > 0) {
3980           my_error(ER_ILLEGAL_PRIVILEGE_LEVEL, MYF(0), all_tables->table_name);
3981           goto error;
3982         }
3983         if (lex->type == TYPE_ENUM_PROCEDURE ||
3984             lex->type == TYPE_ENUM_FUNCTION) {
3985           uint grants = lex->all_privileges
3986                             ? (PROC_OP_ACLS) | (lex->grant & GRANT_ACL)
3987                             : lex->grant;
3988           if (check_grant_routine(thd, grants | GRANT_ACL, all_tables,
3989                                   lex->type == TYPE_ENUM_PROCEDURE, false))
3990             goto error;
3991           /* Conditionally writes to binlog */
3992           res = mysql_routine_grant(
3993               thd, all_tables, lex->type == TYPE_ENUM_PROCEDURE,
3994               lex->users_list, grants, lex->sql_command == SQLCOM_REVOKE, true);
3995           if (!res) my_ok(thd);
3996         } else {
3997           if (check_grant(thd, (lex->grant | lex->grant_tot_col | GRANT_ACL),
3998                           all_tables, false, UINT_MAX, false))
3999             goto error;
4000           /* Conditionally writes to binlog */
4001           res =
4002               mysql_table_grant(thd, all_tables, lex->users_list, lex->columns,
4003                                 lex->grant, lex->sql_command == SQLCOM_REVOKE);
4004         }
4005       } else {
4006         if (lex->columns.elements ||
4007             (lex->type && lex->type != TYPE_ENUM_PROXY)) {
4008           my_error(ER_ILLEGAL_GRANT_FOR_TABLE, MYF(0));
4009           goto error;
4010         } else {
4011           /* Conditionally writes to binlog */
4012           res = mysql_grant(
4013               thd, select_lex->db, lex->users_list, lex->grant,
4014               lex->sql_command == SQLCOM_REVOKE, lex->type == TYPE_ENUM_PROXY,
4015               lex->dynamic_privileges, lex->all_privileges, &lex->grant_as);
4016         }
4017       }
4018       break;
4019     }
4020     case SQLCOM_RESET:
4021       /*
4022         RESET commands are never written to the binary log, so we have to
4023         initialize this variable because RESET shares the same code as FLUSH
4024       */
4025       lex->no_write_to_binlog = true;
4026       if ((lex->type & REFRESH_PERSIST) && (lex->option_type == OPT_PERSIST)) {
4027         Persisted_variables_cache *pv =
4028             Persisted_variables_cache::get_instance();
4029         if (pv)
4030           if (pv->reset_persisted_variables(thd, lex->name.str,
4031                                             lex->drop_if_exists))
4032             goto error;
4033         my_ok(thd);
4034         break;
4035       }
4036       // Fall through.
4037     case SQLCOM_FLUSH: {
4038       int write_to_binlog;
4039       if (check_global_access(thd, RELOAD_ACL)) goto error;
4040 
4041       if (first_table && lex->type & REFRESH_READ_LOCK) {
4042         /* Check table-level privileges. */
4043         if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
4044                                false, UINT_MAX, false))
4045           goto error;
4046         if (flush_tables_with_read_lock(thd, all_tables)) goto error;
4047         my_ok(thd);
4048         break;
4049       } else if (first_table && lex->type & REFRESH_FOR_EXPORT) {
4050         /* Check table-level privileges. */
4051         if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables,
4052                                false, UINT_MAX, false))
4053           goto error;
4054         if (flush_tables_for_export(thd, all_tables)) goto error;
4055         my_ok(thd);
4056         break;
4057       }
4058 
4059       /*
4060         handle_reload_request() will tell us if we are allowed to write to the
4061         binlog or not.
4062       */
4063       if (!handle_reload_request(thd, lex->type, first_table,
4064                                  &write_to_binlog)) {
4065         /*
4066           We WANT to write and we CAN write.
4067           ! we write after unlocking the table.
4068         */
4069         /*
4070           Presumably, RESET and binlog writing doesn't require synchronization
4071         */
4072 
4073         if (write_to_binlog > 0)  // we should write
4074         {
4075           if (!lex->no_write_to_binlog)
4076             res = write_bin_log(thd, false, thd->query().str,
4077                                 thd->query().length);
4078         } else if (write_to_binlog < 0) {
4079           /*
4080              We should not write, but rather report error because
4081              handle_reload_request binlog interactions failed
4082            */
4083           res = 1;
4084         }
4085 
4086         if (!res) my_ok(thd);
4087       }
4088 
4089       break;
4090     }
4091     case SQLCOM_KILL: {
4092       Item *it = lex->kill_value_list.head();
4093 
4094       if (lex->table_or_sp_used()) {
4095         my_error(ER_NOT_SUPPORTED_YET, MYF(0),
4096                  "Usage of subqueries or stored "
4097                  "function calls as part of this statement");
4098         goto error;
4099       }
4100 
4101       if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) {
4102         my_error(ER_SET_CONSTANTS_ONLY, MYF(0));
4103         goto error;
4104       }
4105 
4106       my_thread_id thread_id = static_cast<my_thread_id>(it->val_int());
4107       if (thd->is_error()) goto error;
4108 
4109       sql_kill(thd, thread_id, lex->type & ONLY_KILL_QUERY);
4110       break;
4111     }
4112     case SQLCOM_SHOW_PRIVILEGES: {
4113       mysqld_show_privileges(thd);
4114       break;
4115     }
4116     case SQLCOM_SHOW_CREATE_USER: {
4117       LEX_USER *show_user = get_current_user(thd, lex->grant_user);
4118       Security_context *sctx = thd->security_context();
4119       bool are_both_users_same =
4120           !strcmp(sctx->priv_user().str, show_user->user.str) &&
4121           !my_strcasecmp(system_charset_info, show_user->host.str,
4122                          sctx->priv_host().str);
4123       if (are_both_users_same || !check_access(thd, SELECT_ACL, "mysql",
4124                                                nullptr, nullptr, true, false))
4125         res = mysql_show_create_user(thd, show_user, are_both_users_same);
4126       break;
4127     }
4128     case SQLCOM_BEGIN:
4129       if (trans_begin(thd, lex->start_transaction_opt)) goto error;
4130       my_ok(thd);
4131       break;
4132     case SQLCOM_COMMIT: {
4133       DBUG_ASSERT(thd->lock == nullptr ||
4134                   thd->locked_tables_mode == LTM_LOCK_TABLES);
4135       bool tx_chain =
4136           (lex->tx_chain == TVL_YES ||
4137            (thd->variables.completion_type == 1 && lex->tx_chain != TVL_NO));
4138       bool tx_release =
4139           (lex->tx_release == TVL_YES ||
4140            (thd->variables.completion_type == 2 && lex->tx_release != TVL_NO));
4141       if (trans_commit(thd)) goto error;
4142       thd->mdl_context.release_transactional_locks();
4143       /* Begin transaction with the same isolation level. */
4144       if (tx_chain) {
4145         if (trans_begin(thd)) goto error;
4146       } else {
4147         /* Reset the isolation level and access mode if no chaining
4148          * transaction.*/
4149         trans_reset_one_shot_chistics(thd);
4150       }
4151       /* Disconnect the current client connection. */
4152       if (tx_release) thd->killed = THD::KILL_CONNECTION;
4153       my_ok(thd);
4154       break;
4155     }
4156     case SQLCOM_ROLLBACK: {
4157       DBUG_ASSERT(thd->lock == nullptr ||
4158                   thd->locked_tables_mode == LTM_LOCK_TABLES);
4159       bool tx_chain =
4160           (lex->tx_chain == TVL_YES ||
4161            (thd->variables.completion_type == 1 && lex->tx_chain != TVL_NO));
4162       bool tx_release =
4163           (lex->tx_release == TVL_YES ||
4164            (thd->variables.completion_type == 2 && lex->tx_release != TVL_NO));
4165       if (trans_rollback(thd)) goto error;
4166       thd->mdl_context.release_transactional_locks();
4167       /* Begin transaction with the same isolation level. */
4168       if (tx_chain) {
4169         if (trans_begin(thd)) goto error;
4170       } else {
4171         /* Reset the isolation level and access mode if no chaining
4172          * transaction.*/
4173         trans_reset_one_shot_chistics(thd);
4174       }
4175       /* Disconnect the current client connection. */
4176       if (tx_release) thd->killed = THD::KILL_CONNECTION;
4177       my_ok(thd);
4178       break;
4179     }
4180     case SQLCOM_RELEASE_SAVEPOINT:
4181       if (trans_release_savepoint(thd, lex->ident)) goto error;
4182       my_ok(thd);
4183       break;
4184     case SQLCOM_ROLLBACK_TO_SAVEPOINT:
4185       if (trans_rollback_to_savepoint(thd, lex->ident)) goto error;
4186       my_ok(thd);
4187       break;
4188     case SQLCOM_SAVEPOINT:
4189       if (trans_savepoint(thd, lex->ident)) goto error;
4190       my_ok(thd);
4191       break;
4192     case SQLCOM_CREATE_PROCEDURE:
4193     case SQLCOM_CREATE_SPFUNCTION: {
4194       uint namelen;
4195       char *name;
4196 
4197       DBUG_ASSERT(lex->sphead != nullptr);
4198       DBUG_ASSERT(
4199           lex->sphead->m_db.str); /* Must be initialized in the parser */
4200       /*
4201         Verify that the database name is allowed, optionally
4202         lowercase it.
4203       */
4204       if (check_and_convert_db_name(&lex->sphead->m_db, false) !=
4205           Ident_name_check::OK)
4206         goto error;
4207 
4208       if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, nullptr,
4209                        nullptr, false, false))
4210         goto error;
4211 
4212       name = lex->sphead->name(&namelen);
4213       if (lex->sphead->m_type == enum_sp_type::FUNCTION) {
4214         udf_func *udf = find_udf(name, namelen);
4215 
4216         if (udf) {
4217           my_error(ER_UDF_EXISTS, MYF(0), name);
4218           goto error;
4219         }
4220       }
4221 
4222       if (sp_process_definer(thd)) goto error;
4223 
4224       /*
4225         Record the CURRENT_USER in binlog. The CURRENT_USER is used on slave to
4226         grant default privileges when sp_automatic_privileges variable is set.
4227       */
4228       thd->binlog_invoker();
4229 
4230       if (!(res = sp_create_routine(thd, lex->sphead, thd->lex->definer))) {
4231         /* only add privileges if really neccessary */
4232 
4233         Security_context security_context;
4234         bool restore_backup_context = false;
4235         Security_context *backup = nullptr;
4236         /*
4237           We're going to issue an implicit GRANT statement so we close all
4238           open tables. We have to keep metadata locks as this ensures that
4239           this statement is atomic against concurent FLUSH TABLES WITH READ
4240           LOCK. Deadlocks which can arise due to fact that this implicit
4241           statement takes metadata locks should be detected by a deadlock
4242           detector in MDL subsystem and reported as errors.
4243 
4244           No need to commit/rollback statement transaction, it's not started.
4245 
4246           TODO: Long-term we should either ensure that implicit GRANT statement
4247                 is written into binary log as a separate statement or make both
4248                 creation of routine and implicit GRANT parts of one fully atomic
4249                 statement.
4250         */
4251         DBUG_ASSERT(thd->get_transaction()->is_empty(Transaction_ctx::STMT));
4252         close_thread_tables(thd);
4253         /*
4254           Check if invoker exists on slave, then use invoker privilege to
4255           insert routine privileges to mysql.procs_priv. If invoker is not
4256           available then consider using definer.
4257 
4258           Check if the definer exists on slave,
4259           then use definer privilege to insert routine privileges to
4260           mysql.procs_priv.
4261 
4262           For current user of SQL thread has GLOBAL_ACL privilege,
4263           which doesn't any check routine privileges,
4264           so no routine privilege record  will insert into mysql.procs_priv.
4265         */
4266 
4267         if (thd->slave_thread) {
4268           LEX_CSTRING current_user;
4269           LEX_CSTRING current_host;
4270           if (thd->has_invoker()) {
4271             current_host = thd->get_invoker_host();
4272             current_user = thd->get_invoker_user();
4273           } else {
4274             current_host = lex->definer->host;
4275             current_user = lex->definer->user;
4276           }
4277           if (is_acl_user(thd, current_host.str, current_user.str)) {
4278             security_context.change_security_context(
4279                 thd, current_user, current_host, thd->lex->sphead->m_db.str,
4280                 &backup);
4281             restore_backup_context = true;
4282           }
4283         }
4284 
4285         if (sp_automatic_privileges && !opt_noacl &&
4286             check_routine_access(
4287                 thd, DEFAULT_CREATE_PROC_ACLS, lex->sphead->m_db.str, name,
4288                 lex->sql_command == SQLCOM_CREATE_PROCEDURE, true)) {
4289           if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
4290                                   lex->sql_command == SQLCOM_CREATE_PROCEDURE))
4291             push_warning(thd, Sql_condition::SL_WARNING,
4292                          ER_PROC_AUTO_GRANT_FAIL,
4293                          ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL));
4294           thd->clear_error();
4295         }
4296 
4297         /*
4298           Restore current user with GLOBAL_ACL privilege of SQL thread
4299         */
4300         if (restore_backup_context) {
4301           DBUG_ASSERT(thd->slave_thread == 1);
4302           thd->security_context()->restore_security_context(thd, backup);
4303         }
4304         my_ok(thd);
4305       }
4306       break; /* break super switch */
4307     }        /* end case group bracket */
4308 
4309     case SQLCOM_ALTER_PROCEDURE:
4310     case SQLCOM_ALTER_FUNCTION: {
4311       if (check_routine_access(thd, ALTER_PROC_ACL, lex->spname->m_db.str,
4312                                lex->spname->m_name.str,
4313                                lex->sql_command == SQLCOM_ALTER_PROCEDURE,
4314                                false))
4315         goto error;
4316 
4317       enum_sp_type sp_type = (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
4318                                  ? enum_sp_type::PROCEDURE
4319                                  : enum_sp_type::FUNCTION;
4320       /*
4321         Note that if you implement the capability of ALTER FUNCTION to
4322         alter the body of the function, this command should be made to
4323         follow the restrictions that log-bin-trust-function-creators=0
4324         already puts on CREATE FUNCTION.
4325       */
4326       /* Conditionally writes to binlog */
4327       res = sp_update_routine(thd, sp_type, lex->spname, &lex->sp_chistics);
4328       if (res || thd->killed) goto error;
4329 
4330       my_ok(thd);
4331       break;
4332     }
4333     case SQLCOM_DROP_PROCEDURE:
4334     case SQLCOM_DROP_FUNCTION: {
4335       if (lex->sql_command == SQLCOM_DROP_FUNCTION &&
4336           !lex->spname->m_explicit_name) {
4337         /* DROP FUNCTION <non qualified name> */
4338         udf_func *udf =
4339             find_udf(lex->spname->m_name.str, lex->spname->m_name.length);
4340         if (udf) {
4341           if (check_access(thd, DELETE_ACL, "mysql", nullptr, nullptr, true,
4342                            false))
4343             goto error;
4344 
4345           if (!(res = mysql_drop_function(thd, &lex->spname->m_name))) {
4346             my_ok(thd);
4347             break;
4348           }
4349           my_error(ER_SP_DROP_FAILED, MYF(0), "FUNCTION (UDF)",
4350                    lex->spname->m_name.str);
4351           goto error;
4352         }
4353 
4354         if (lex->spname->m_db.str == nullptr) {
4355           if (lex->drop_if_exists) {
4356             push_warning_printf(thd, Sql_condition::SL_NOTE,
4357                                 ER_SP_DOES_NOT_EXIST,
4358                                 ER_THD(thd, ER_SP_DOES_NOT_EXIST),
4359                                 "FUNCTION (UDF)", lex->spname->m_name.str);
4360             res = false;
4361             my_ok(thd);
4362             break;
4363           }
4364           my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION (UDF)",
4365                    lex->spname->m_name.str);
4366           goto error;
4367         }
4368         /* Fall thought to test for a stored function */
4369       }
4370 
4371       const char *db = lex->spname->m_db.str;
4372       char *name = lex->spname->m_name.str;
4373 
4374       if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
4375                                lex->sql_command == SQLCOM_DROP_PROCEDURE,
4376                                false))
4377         goto error;
4378 
4379       enum_sp_type sp_type = (lex->sql_command == SQLCOM_DROP_PROCEDURE)
4380                                  ? enum_sp_type::PROCEDURE
4381                                  : enum_sp_type::FUNCTION;
4382 
4383       /* Conditionally writes to binlog */
4384       enum_sp_return_code sp_result =
4385           sp_drop_routine(thd, sp_type, lex->spname);
4386 
4387       /*
4388         We're going to issue an implicit REVOKE statement so we close all
4389         open tables. We have to keep metadata locks as this ensures that
4390         this statement is atomic against concurent FLUSH TABLES WITH READ
4391         LOCK. Deadlocks which can arise due to fact that this implicit
4392         statement takes metadata locks should be detected by a deadlock
4393         detector in MDL subsystem and reported as errors.
4394 
4395         No need to commit/rollback statement transaction, it's not started.
4396 
4397         TODO: Long-term we should either ensure that implicit REVOKE statement
4398               is written into binary log as a separate statement or make both
4399               dropping of routine and implicit REVOKE parts of one fully atomic
4400               statement.
4401       */
4402       DBUG_ASSERT(thd->get_transaction()->is_empty(Transaction_ctx::STMT));
4403       close_thread_tables(thd);
4404 
4405       if (sp_result != SP_DOES_NOT_EXISTS && sp_automatic_privileges &&
4406           !opt_noacl &&
4407           sp_revoke_privileges(thd, db, name,
4408                                lex->sql_command == SQLCOM_DROP_PROCEDURE)) {
4409         push_warning(thd, Sql_condition::SL_WARNING, ER_PROC_AUTO_REVOKE_FAIL,
4410                      ER_THD(thd, ER_PROC_AUTO_REVOKE_FAIL));
4411         /* If this happens, an error should have been reported. */
4412         goto error;
4413       }
4414 
4415       res = sp_result;
4416       switch (sp_result) {
4417         case SP_OK:
4418           my_ok(thd);
4419           break;
4420         case SP_DOES_NOT_EXISTS:
4421           if (lex->drop_if_exists) {
4422             res =
4423                 write_bin_log(thd, true, thd->query().str, thd->query().length);
4424             push_warning_printf(thd, Sql_condition::SL_NOTE,
4425                                 ER_SP_DOES_NOT_EXIST,
4426                                 ER_THD(thd, ER_SP_DOES_NOT_EXIST),
4427                                 SP_COM_STRING(lex), lex->spname->m_qname.str);
4428             if (!res) my_ok(thd);
4429             break;
4430           }
4431           my_error(ER_SP_DOES_NOT_EXIST, MYF(0), SP_COM_STRING(lex),
4432                    lex->spname->m_qname.str);
4433           goto error;
4434         default:
4435           my_error(ER_SP_DROP_FAILED, MYF(0), SP_COM_STRING(lex),
4436                    lex->spname->m_qname.str);
4437           goto error;
4438       }
4439       break;
4440     }
4441     case SQLCOM_SHOW_CREATE_PROC: {
4442       if (sp_show_create_routine(thd, enum_sp_type::PROCEDURE, lex->spname))
4443         goto error;
4444       break;
4445     }
4446     case SQLCOM_SHOW_CREATE_FUNC: {
4447       if (sp_show_create_routine(thd, enum_sp_type::FUNCTION, lex->spname))
4448         goto error;
4449       break;
4450     }
4451     case SQLCOM_SHOW_PROC_CODE:
4452     case SQLCOM_SHOW_FUNC_CODE: {
4453 #ifndef DBUG_OFF
4454       sp_head *sp;
4455       enum_sp_type sp_type = (lex->sql_command == SQLCOM_SHOW_PROC_CODE)
4456                                  ? enum_sp_type::PROCEDURE
4457                                  : enum_sp_type::FUNCTION;
4458 
4459       if (sp_cache_routine(thd, sp_type, lex->spname, false, &sp)) goto error;
4460       if (!sp || sp->show_routine_code(thd)) {
4461         /* We don't distinguish between errors for now */
4462         my_error(ER_SP_DOES_NOT_EXIST, MYF(0), SP_COM_STRING(lex),
4463                  lex->spname->m_name.str);
4464         goto error;
4465       }
4466       break;
4467 #else
4468       my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROCEDURE|FUNCTION CODE",
4469                "--with-debug");
4470       goto error;
4471 #endif  // ifndef DBUG_OFF
4472     }
4473     case SQLCOM_SHOW_CREATE_TRIGGER: {
4474       if (lex->spname->m_name.length > NAME_LEN) {
4475         my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
4476         goto error;
4477       }
4478 
4479       if (show_create_trigger(thd, lex->spname))
4480         goto error; /* Error has been already logged. */
4481 
4482       break;
4483     }
4484     case SQLCOM_CREATE_VIEW: {
4485       /*
4486         Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands
4487         as specified through the thd->lex->create_view_mode flag.
4488       */
4489       res = mysql_create_view(thd, first_table, thd->lex->create_view_mode);
4490       break;
4491     }
4492     case SQLCOM_DROP_VIEW: {
4493       if (check_table_access(thd, DROP_ACL, all_tables, false, UINT_MAX, false))
4494         goto error;
4495       /* Conditionally writes to binlog. */
4496       res = mysql_drop_view(thd, first_table);
4497       break;
4498     }
4499     case SQLCOM_CREATE_TRIGGER:
4500     case SQLCOM_DROP_TRIGGER: {
4501       /* Conditionally writes to binlog. */
4502       DBUG_ASSERT(lex->m_sql_cmd != nullptr);
4503       static_cast<Sql_cmd_ddl_trigger_common *>(lex->m_sql_cmd)
4504           ->set_table(all_tables);
4505 
4506       res = lex->m_sql_cmd->execute(thd);
4507       break;
4508     }
4509     case SQLCOM_BINLOG_BASE64_EVENT: {
4510       mysql_client_binlog_statement(thd);
4511       break;
4512     }
4513     case SQLCOM_ANALYZE:
4514     case SQLCOM_CHECK:
4515     case SQLCOM_OPTIMIZE:
4516     case SQLCOM_REPAIR:
4517     case SQLCOM_TRUNCATE:
4518     case SQLCOM_ALTER_TABLE:
4519     case SQLCOM_HA_OPEN:
4520     case SQLCOM_HA_READ:
4521     case SQLCOM_HA_CLOSE:
4522       DBUG_ASSERT(first_table == all_tables && first_table != nullptr);
4523       /* fall through */
4524     case SQLCOM_CREATE_SERVER:
4525     case SQLCOM_CREATE_RESOURCE_GROUP:
4526     case SQLCOM_ALTER_SERVER:
4527     case SQLCOM_ALTER_RESOURCE_GROUP:
4528     case SQLCOM_DROP_RESOURCE_GROUP:
4529     case SQLCOM_DROP_SERVER:
4530     case SQLCOM_SET_RESOURCE_GROUP:
4531     case SQLCOM_SIGNAL:
4532     case SQLCOM_RESIGNAL:
4533     case SQLCOM_GET_DIAGNOSTICS:
4534     case SQLCOM_CHANGE_REPLICATION_FILTER:
4535     case SQLCOM_XA_START:
4536     case SQLCOM_XA_END:
4537     case SQLCOM_XA_PREPARE:
4538     case SQLCOM_XA_COMMIT:
4539     case SQLCOM_XA_ROLLBACK:
4540     case SQLCOM_XA_RECOVER:
4541     case SQLCOM_INSTALL_PLUGIN:
4542     case SQLCOM_UNINSTALL_PLUGIN:
4543     case SQLCOM_INSTALL_COMPONENT:
4544     case SQLCOM_UNINSTALL_COMPONENT:
4545     case SQLCOM_SHUTDOWN:
4546     case SQLCOM_ALTER_INSTANCE:
4547     case SQLCOM_SELECT:
4548     case SQLCOM_DO:
4549     case SQLCOM_CALL:
4550     case SQLCOM_CREATE_ROLE:
4551     case SQLCOM_DROP_ROLE:
4552     case SQLCOM_SET_ROLE:
4553     case SQLCOM_GRANT_ROLE:
4554     case SQLCOM_REVOKE_ROLE:
4555     case SQLCOM_ALTER_USER_DEFAULT_ROLE:
4556     case SQLCOM_SHOW_GRANTS:
4557     case SQLCOM_SHOW_FIELDS:
4558     case SQLCOM_SHOW_KEYS:
4559     case SQLCOM_SHOW_TABLES:
4560     case SQLCOM_CLONE:
4561     case SQLCOM_LOCK_INSTANCE:
4562     case SQLCOM_UNLOCK_INSTANCE:
4563     case SQLCOM_ALTER_TABLESPACE:
4564     case SQLCOM_EXPLAIN_OTHER:
4565     case SQLCOM_RESTART_SERVER:
4566     case SQLCOM_CREATE_SRS:
4567     case SQLCOM_DROP_SRS: {
4568       DBUG_ASSERT(lex->m_sql_cmd != nullptr);
4569 
4570       Enable_derived_merge_guard derived_merge_guard(
4571           thd, is_show_cmd_using_system_view(thd));
4572 
4573       res = lex->m_sql_cmd->execute(thd);
4574 
4575       break;
4576     }
4577     case SQLCOM_ALTER_USER: {
4578       LEX_USER *user, *tmp_user;
4579       bool changing_own_password = false;
4580       Security_context *sctx = thd->security_context();
4581       bool own_password_expired = sctx->password_expired();
4582       bool check_permission = true;
4583 
4584       List_iterator<LEX_USER> user_list(lex->users_list);
4585       while ((tmp_user = user_list++)) {
4586         bool update_password_only = false;
4587         bool is_self = false;
4588         bool second_password = false;
4589 
4590         /* If it is an empty lex_user update it with current user */
4591         if (!tmp_user->host.str && !tmp_user->user.str) {
4592           /* set user information as of the current user */
4593           DBUG_ASSERT(sctx->priv_host().str);
4594           tmp_user->host.str = sctx->priv_host().str;
4595           tmp_user->host.length = strlen(sctx->priv_host().str);
4596           DBUG_ASSERT(sctx->user().str);
4597           tmp_user->user.str = sctx->user().str;
4598           tmp_user->user.length = strlen(sctx->user().str);
4599         }
4600         if (!(user = get_current_user(thd, tmp_user))) goto error;
4601 
4602         /* copy password expire attributes to individual lex user */
4603         user->alter_status = thd->lex->alter_password;
4604 
4605         /*
4606           Only self password change is non-privileged operation. To detect the
4607           same, we find :
4608           (1) If it is only password change operation
4609           (2) If this operation is on self
4610         */
4611         if (user->uses_identified_by_clause &&
4612             !user->uses_identified_with_clause &&
4613             !thd->lex->mqh.specified_limits &&
4614             !user->alter_status.update_account_locked_column &&
4615             !user->alter_status.update_password_expired_column &&
4616             !user->alter_status.expire_after_days &&
4617             user->alter_status.use_default_password_lifetime &&
4618             (user->alter_status.update_password_require_current ==
4619              Lex_acl_attrib_udyn::UNCHANGED) &&
4620             !user->alter_status.update_password_history &&
4621             !user->alter_status.update_password_reuse_interval &&
4622             !user->alter_status.update_failed_login_attempts &&
4623             !user->alter_status.update_password_lock_time &&
4624             (thd->lex->ssl_type == SSL_TYPE_NOT_SPECIFIED))
4625           update_password_only = true;
4626 
4627         is_self = !strcmp(sctx->user().length ? sctx->user().str : "",
4628                           user->user.str) &&
4629                   !my_strcasecmp(&my_charset_latin1, user->host.str,
4630                                  sctx->priv_host().str);
4631         /*
4632           if user executes ALTER statement to change password only
4633           for himself then skip access check - Provided preference to
4634           retain/discard current password was specified.
4635         */
4636 
4637         if (user->discard_old_password || user->retain_current_password) {
4638           second_password = true;
4639         }
4640         if ((update_password_only || user->discard_old_password) && is_self) {
4641           changing_own_password = update_password_only;
4642           if (second_password) {
4643             if (check_access(thd, UPDATE_ACL, consts::mysql.c_str(), nullptr,
4644                              nullptr, true, true) &&
4645                 !sctx->check_access(CREATE_USER_ACL, consts::mysql.c_str()) &&
4646                 !(sctx->has_global_grant(
4647                           STRING_WITH_LEN("APPLICATION_PASSWORD_ADMIN"))
4648                       .first)) {
4649               my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0),
4650                        "CREATE USER or APPLICATION_PASSWORD_ADMIN");
4651               goto error;
4652             }
4653           }
4654           continue;
4655         } else if (check_permission) {
4656           if (check_access(thd, UPDATE_ACL, "mysql", nullptr, nullptr, true,
4657                            true) &&
4658               check_global_access(thd, CREATE_USER_ACL))
4659             goto error;
4660 
4661           check_permission = false;
4662         }
4663 
4664         if (is_self && (user->uses_identified_by_clause ||
4665                         user->uses_identified_with_clause ||
4666                         user->uses_authentication_string_clause)) {
4667           changing_own_password = true;
4668           break;
4669         }
4670 
4671         if (update_password_only &&
4672             likely((get_server_state() == SERVER_OPERATING)) &&
4673             !strcmp(sctx->priv_user().str, "")) {
4674           my_error(ER_PASSWORD_ANONYMOUS_USER, MYF(0));
4675           goto error;
4676         }
4677       }
4678 
4679       if (unlikely(own_password_expired && !changing_own_password)) {
4680         my_error(ER_MUST_CHANGE_PASSWORD, MYF(0));
4681         goto error;
4682       }
4683 
4684       /* Conditionally writes to binlog */
4685       res = mysql_alter_user(thd, lex->users_list, lex->drop_if_exists);
4686       break;
4687     }
4688     default:
4689       DBUG_ASSERT(0); /* Impossible */
4690       my_ok(thd);
4691       break;
4692   }
4693   goto finish;
4694 
4695 error:
4696   res = true;
4697 
4698 finish:
4699   /* Restore system variables which were changed by SET_VAR hint. */
4700   if (lex->opt_hints_global && lex->opt_hints_global->sys_var_hint)
4701     lex->opt_hints_global->sys_var_hint->restore_vars(thd);
4702 
4703   THD_STAGE_INFO(thd, stage_query_end);
4704 
4705   if (!res) lex->set_exec_started();
4706 
4707   // Cleanup EXPLAIN info
4708   if (!thd->in_sub_stmt) {
4709     if (is_explainable_query(lex->sql_command)) {
4710       DEBUG_SYNC(thd, "before_reset_query_plan");
4711       /*
4712         We want EXPLAIN CONNECTION to work until the explained statement ends,
4713         thus it is only now that we may fully clean up any unit of this
4714         statement.
4715       */
4716       lex->unit->assert_not_fully_clean();
4717     }
4718     thd->query_plan.set_query_plan(SQLCOM_END, nullptr, false);
4719   }
4720 
4721   DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() ||
4722               thd->in_multi_stmt_transaction_mode());
4723 
4724   if (!thd->in_sub_stmt) {
4725     mysql_audit_notify(thd,
4726                        first_level ? MYSQL_AUDIT_QUERY_STATUS_END
4727                                    : MYSQL_AUDIT_QUERY_NESTED_STATUS_END,
4728                        first_level ? "MYSQL_AUDIT_QUERY_STATUS_END"
4729                                    : "MYSQL_AUDIT_QUERY_NESTED_STATUS_END");
4730 
4731     /* report error issued during command execution */
4732     if (thd->killed) thd->send_kill_message();
4733     if (thd->is_error() ||
4734         (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR))
4735       trans_rollback_stmt(thd);
4736     else {
4737       /* If commit fails, we should be able to reset the OK status. */
4738       thd->get_stmt_da()->set_overwrite_status(true);
4739       trans_commit_stmt(thd);
4740       thd->get_stmt_da()->set_overwrite_status(false);
4741     }
4742     /*
4743       Reset thd killed flag during cleanup so that commands which are
4744       dispatched using service session API's start with a clean state.
4745     */
4746     if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_TIMEOUT) {
4747       thd->killed = THD::NOT_KILLED;
4748       thd->reset_query_for_display();
4749     }
4750   }
4751 
4752   lex->unit->cleanup(thd, true);
4753   /* Free tables */
4754   THD_STAGE_INFO(thd, stage_closing_tables);
4755   close_thread_tables(thd);
4756 
4757 #ifndef DBUG_OFF
4758   if (lex->sql_command != SQLCOM_SET_OPTION && !thd->in_sub_stmt)
4759     DEBUG_SYNC(thd, "execute_command_after_close_tables");
4760 #endif
4761 
4762   if (!thd->in_sub_stmt && thd->transaction_rollback_request) {
4763     /*
4764       We are not in sub-statement and transaction rollback was requested by
4765       one of storage engines (e.g. due to deadlock). Rollback transaction in
4766       all storage engines including binary log.
4767     */
4768     trans_rollback_implicit(thd);
4769     thd->mdl_context.release_transactional_locks();
4770   } else if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END)) {
4771     /* No transaction control allowed in sub-statements. */
4772     DBUG_ASSERT(!thd->in_sub_stmt);
4773     /* If commit fails, we should be able to reset the OK status. */
4774     thd->get_stmt_da()->set_overwrite_status(true);
4775     /* Commit the normal transaction if one is active. */
4776     trans_commit_implicit(thd);
4777     thd->get_stmt_da()->set_overwrite_status(false);
4778     thd->mdl_context.release_transactional_locks();
4779   } else if (!thd->in_sub_stmt && !thd->in_multi_stmt_transaction_mode()) {
4780     /*
4781       - If inside a multi-statement transaction,
4782       defer the release of metadata locks until the current
4783       transaction is either committed or rolled back. This prevents
4784       other statements from modifying the table for the entire
4785       duration of this transaction.  This provides commit ordering
4786       and guarantees serializability across multiple transactions.
4787       - If in autocommit mode, or outside a transactional context,
4788       automatically release metadata locks of the current statement.
4789     */
4790     thd->mdl_context.release_transactional_locks();
4791   } else if (!thd->in_sub_stmt &&
4792              (thd->lex->sql_command != SQLCOM_CREATE_TABLE ||
4793               !thd->lex->create_info->m_transactional_ddl)) {
4794     thd->mdl_context.release_statement_locks();
4795   }
4796 
4797   // If the client wishes to have transaction state reported, we add whatever
4798   // is set on THD to our set here.
4799   {
4800     TX_TRACKER_GET(tst);
4801 
4802     if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
4803       tst->add_trx_state_from_thd(thd);
4804 
4805     // We're done. Clear "is DML" flag.
4806     tst->clear_trx_state(thd, TX_STMT_DML);
4807   }
4808 
4809 #ifdef HAVE_LSAN_DO_RECOVERABLE_LEAK_CHECK
4810   // Get incremental leak reports, for easier leak hunting.
4811   // ./mtr --mem --mysqld='-T 4096' --sanitize main.1st
4812   // Don't waste time calling leak sanitizer during bootstrap.
4813   if (!opt_initialize && (test_flags & TEST_DO_QUICK_LEAK_CHECK)) {
4814     int have_leaks = __lsan_do_recoverable_leak_check();
4815     if (have_leaks > 0) {
4816       fprintf(stderr, "LSAN found leaks for Query: %*s\n",
4817               static_cast<int>(thd->query().length), thd->query().str);
4818       fflush(stderr);
4819     }
4820   }
4821 #endif
4822 
4823 #if defined(VALGRIND_DO_QUICK_LEAK_CHECK)
4824   // Get incremental leak reports, for easier leak hunting.
4825   // ./mtr --mem --mysqld='-T 4096' --valgrind-mysqld main.1st
4826   // Note that with multiple connections, the report below may be misleading.
4827   if (test_flags & TEST_DO_QUICK_LEAK_CHECK) {
4828     static unsigned long total_leaked_bytes = 0;
4829     unsigned long leaked = 0;
4830     unsigned long dubious MY_ATTRIBUTE((unused));
4831     unsigned long reachable MY_ATTRIBUTE((unused));
4832     unsigned long suppressed MY_ATTRIBUTE((unused));
4833     /*
4834       We could possibly use VALGRIND_DO_CHANGED_LEAK_CHECK here,
4835       but that is a fairly new addition to the Valgrind api.
4836       Note: we dont want to check 'reachable' until we have done shutdown,
4837       and that is handled by the final report anyways.
4838       We print some extra information, to tell mtr to ignore this report.
4839     */
4840     LogErr(INFORMATION_LEVEL, ER_VALGRIND_DO_QUICK_LEAK_CHECK);
4841     VALGRIND_DO_QUICK_LEAK_CHECK;
4842     VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed);
4843     if (leaked > total_leaked_bytes) {
4844       LogErr(ERROR_LEVEL, ER_VALGRIND_COUNT_LEAKS, leaked - total_leaked_bytes,
4845              static_cast<int>(thd->query().length), thd->query().str);
4846     }
4847     total_leaked_bytes = leaked;
4848   }
4849 #endif
4850 
4851   if (!res && !thd->is_error()) {      // if statement succeeded
4852     binlog_gtid_end_transaction(thd);  // finalize GTID life-cycle
4853     DEBUG_SYNC(thd, "persist_new_state_after_statement_succeeded");
4854   } else if (!gtid_consistency_violation_state &&    // if the consistency state
4855              thd->has_gtid_consistency_violation) {  // was set by the failing
4856                                                      // statement
4857     gtid_state->end_gtid_violating_transaction(thd);  // just roll it back
4858     DEBUG_SYNC(thd, "restore_previous_state_after_statement_failed");
4859   }
4860 
4861   return res || thd->is_error();
4862 }
4863 
4864 /**
4865    Try acquire high priority share metadata lock on a table (with
4866    optional wait for conflicting locks to go away).
4867 
4868    @param thd            Thread context.
4869    @param table          Table list element for the table
4870    @param can_deadlock   Indicates that deadlocks are possible due to
4871                          metadata locks, so to avoid them we should not
4872                          wait in case if conflicting lock is present.
4873 
4874    @note This is an auxiliary function to be used in cases when we want to
4875          access table's description by looking up info in TABLE_SHARE without
4876          going through full-blown table open.
4877    @note This function assumes that there are no other metadata lock requests
4878          in the current metadata locking context.
4879 
4880    @retval false  No error, if lock was obtained TABLE_LIST::mdl_request::ticket
4881                   is set to non-NULL value.
4882    @retval true   Some error occurred (probably thread was killed).
4883 */
4884 
try_acquire_high_prio_shared_mdl_lock(THD * thd,TABLE_LIST * table,bool can_deadlock)4885 static bool try_acquire_high_prio_shared_mdl_lock(THD *thd, TABLE_LIST *table,
4886                                                   bool can_deadlock) {
4887   bool error;
4888   MDL_REQUEST_INIT(&table->mdl_request, MDL_key::TABLE, table->db,
4889                    table->table_name, MDL_SHARED_HIGH_PRIO, MDL_TRANSACTION);
4890 
4891   if (can_deadlock) {
4892     /*
4893       When .FRM is being open in order to get data for an I_S table,
4894       we might have some tables not only open but also locked.
4895       E.g. this happens when a SHOW or I_S statement is run
4896       under LOCK TABLES or inside a stored function.
4897       By waiting for the conflicting metadata lock to go away we
4898       might create a deadlock which won't entirely belong to the
4899       MDL subsystem and thus won't be detectable by this subsystem's
4900       deadlock detector. To avoid such situation, when there are
4901       other locked tables, we prefer not to wait on a conflicting
4902       lock.
4903     */
4904     error = thd->mdl_context.try_acquire_lock(&table->mdl_request);
4905   } else
4906     error = thd->mdl_context.acquire_lock(&table->mdl_request,
4907                                           thd->variables.lock_wait_timeout);
4908 
4909   return error;
4910 }
4911 
4912 /**
4913   Do special checking for SHOW statements.
4914 
4915   @param thd              Thread context.
4916   @param lex              LEX for SHOW statement.
4917   @param lock             If true, lock metadata for schema objects
4918 
4919   @returns false if check is successful, true if error
4920 */
4921 
show_precheck(THD * thd,LEX * lex,bool lock)4922 bool show_precheck(THD *thd, LEX *lex, bool lock) {
4923   bool new_dd_show = false;
4924 
4925   TABLE_LIST *const tables = lex->query_tables;
4926 
4927   switch (lex->sql_command) {
4928     // For below show commands, perform check_show_access() call
4929     case SQLCOM_SHOW_DATABASES:
4930     case SQLCOM_SHOW_EVENTS:
4931       new_dd_show = true;
4932       break;
4933 
4934     case SQLCOM_SHOW_TABLES:
4935     case SQLCOM_SHOW_TABLE_STATUS:
4936     case SQLCOM_SHOW_TRIGGERS: {
4937       new_dd_show = true;
4938 
4939       if (!lock) break;
4940 
4941       LEX_STRING lex_str_db;
4942       if (lex_string_strmake(thd->mem_root, &lex_str_db, lex->select_lex->db,
4943                              strlen(lex->select_lex->db)))
4944         return true;
4945 
4946       // Acquire IX MDL lock on schema name.
4947       MDL_request mdl_request;
4948       MDL_REQUEST_INIT(&mdl_request, MDL_key::SCHEMA, lex_str_db.str, "",
4949                        MDL_INTENTION_EXCLUSIVE, MDL_TRANSACTION);
4950       if (thd->mdl_context.acquire_lock(&mdl_request,
4951                                         thd->variables.lock_wait_timeout))
4952         return true;
4953 
4954       // Stop if given database does not exist.
4955       bool exists = false;
4956       if (dd::schema_exists(thd, lex_str_db.str, &exists)) return true;
4957 
4958       if (!exists) {
4959         my_error(ER_BAD_DB_ERROR, MYF(0), lex->select_lex->db);
4960         return true;
4961       }
4962 
4963       break;
4964     }
4965     case SQLCOM_SHOW_FIELDS:
4966     case SQLCOM_SHOW_KEYS: {
4967       new_dd_show = true;
4968 
4969       if (!lock) break;
4970 
4971       enum enum_schema_tables schema_table_idx;
4972       if (tables->schema_table) {
4973         schema_table_idx = get_schema_table_idx(tables->schema_table);
4974         if (schema_table_idx == SCH_TMP_TABLE_COLUMNS ||
4975             schema_table_idx == SCH_TMP_TABLE_KEYS)
4976           break;
4977       }
4978 
4979       bool can_deadlock = thd->mdl_context.has_locks();
4980       TABLE_LIST *dst_table = tables->schema_select_lex->table_list.first;
4981       if (try_acquire_high_prio_shared_mdl_lock(thd, dst_table, can_deadlock)) {
4982         /*
4983           Some error occurred (most probably we have been killed while
4984           waiting for conflicting locks to go away), let the caller to
4985           handle the situation.
4986         */
4987         return true;
4988       }
4989 
4990       if (dst_table->mdl_request.ticket == nullptr) {
4991         /*
4992           We are in situation when we have encountered conflicting metadata
4993           lock and deadlocks can occur due to waiting for it to go away.
4994           So instead of waiting skip this table with an appropriate warning.
4995         */
4996         DBUG_ASSERT(can_deadlock);
4997         my_error(ER_WARN_I_S_SKIPPED_TABLE, MYF(0), dst_table->db,
4998                  dst_table->table_name);
4999         return true;
5000       }
5001 
5002       // Stop if given database does not exist.
5003       dd::Schema_MDL_locker mdl_handler(thd);
5004       dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
5005       const dd::Schema *schema = nullptr;
5006       if (mdl_handler.ensure_locked(dst_table->db) ||
5007           thd->dd_client()->acquire(dst_table->db, &schema))
5008         return true;
5009 
5010       if (schema == nullptr) {
5011         my_error(ER_BAD_DB_ERROR, MYF(0), dst_table->db);
5012         return true;
5013       }
5014 
5015       const dd::Abstract_table *at = nullptr;
5016       if (thd->dd_client()->acquire(dst_table->db, dst_table->table_name, &at))
5017         return true;
5018 
5019       if (at == nullptr) {
5020         my_error(ER_NO_SUCH_TABLE, MYF(0), dst_table->db,
5021                  dst_table->table_name);
5022         return true;
5023       }
5024       break;
5025     }
5026     default:
5027       break;
5028   }
5029 
5030   if (tables != nullptr) {
5031     if (check_table_access(thd, SELECT_ACL, tables, false, UINT_MAX, false))
5032       return true;
5033 
5034     if ((tables->schema_table_reformed || new_dd_show) &&
5035         check_show_access(thd, tables))
5036       return true;
5037   }
5038   return false;
5039 }
5040 
execute_show(THD * thd,TABLE_LIST * all_tables)5041 bool execute_show(THD *thd, TABLE_LIST *all_tables) {
5042   DBUG_TRACE;
5043   LEX *lex = thd->lex;
5044   bool statement_timer_armed = false;
5045   bool res;
5046 
5047   /* assign global limit variable if limit is not given */
5048   {
5049     SELECT_LEX *param = lex->unit->global_parameters();
5050     if (!param->explicit_limit)
5051       param->select_limit =
5052           new Item_int((ulonglong)thd->variables.select_limit);
5053   }
5054 
5055   // check if timer is applicable to statement, if applicable then set timer.
5056   if (is_timer_applicable_to_statement(thd))
5057     statement_timer_armed = set_statement_timer(thd);
5058 
5059   if (!(res = open_tables_for_query(thd, all_tables, false))) {
5060     if (lex->is_explain()) {
5061       /*
5062         We always use Query_result_send for EXPLAIN, even if it's an EXPLAIN
5063         for SELECT ... INTO OUTFILE: a user application should be able
5064         to prepend EXPLAIN to any query and receive output for it,
5065         even if the query itself redirects the output.
5066       */
5067       Query_result *const result = new (thd->mem_root) Query_result_send();
5068       if (!result) return true; /* purecov: inspected */
5069       res = handle_query(thd, lex, result, 0, 0);
5070     } else {
5071       Query_result *result = lex->result;
5072       if (!result && !(result = new (thd->mem_root) Query_result_send()))
5073         return true; /* purecov: inspected */
5074       Query_result *save_result = result;
5075       res = handle_query(thd, lex, result, 0, 0);
5076       if (save_result != lex->result) destroy(save_result);
5077     }
5078   }
5079 
5080   if (statement_timer_armed && thd->timer) reset_statement_timer(thd);
5081 
5082   return res;
5083 }
5084 
5085 #define MY_YACC_INIT 1000  // Start with big alloc
5086 #define MY_YACC_MAX 32000  // Because of 'short'
5087 
my_yyoverflow(short ** yyss,YYSTYPE ** yyvs,YYLTYPE ** yyls,ulong * yystacksize)5088 bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, YYLTYPE **yyls,
5089                    ulong *yystacksize) {
5090   Yacc_state *state = &current_thd->m_parser_state->m_yacc;
5091   ulong old_info = 0;
5092   DBUG_ASSERT(state);
5093   if ((uint)*yystacksize >= MY_YACC_MAX) return true;
5094   if (!state->yacc_yyvs) old_info = *yystacksize;
5095   *yystacksize = set_zone((*yystacksize) * 2, MY_YACC_INIT, MY_YACC_MAX);
5096   if (!(state->yacc_yyvs =
5097             (uchar *)my_realloc(key_memory_bison_stack, state->yacc_yyvs,
5098                                 *yystacksize * sizeof(**yyvs),
5099                                 MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
5100       !(state->yacc_yyss =
5101             (uchar *)my_realloc(key_memory_bison_stack, state->yacc_yyss,
5102                                 *yystacksize * sizeof(**yyss),
5103                                 MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) ||
5104       !(state->yacc_yyls =
5105             (uchar *)my_realloc(key_memory_bison_stack, state->yacc_yyls,
5106                                 *yystacksize * sizeof(**yyls),
5107                                 MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))))
5108     return true;
5109   if (old_info) {
5110     /*
5111       Only copy the old stack on the first call to my_yyoverflow(),
5112       when replacing a static stack (YYINITDEPTH) by a dynamic stack.
5113       For subsequent calls, my_realloc already did preserve the old stack.
5114     */
5115     memcpy(state->yacc_yyss, *yyss, old_info * sizeof(**yyss));
5116     memcpy(state->yacc_yyvs, *yyvs, old_info * sizeof(**yyvs));
5117     memcpy(state->yacc_yyls, *yyls, old_info * sizeof(**yyls));
5118   }
5119   *yyss = (short *)state->yacc_yyss;
5120   *yyvs = (YYSTYPE *)state->yacc_yyvs;
5121   *yyls = (YYLTYPE *)state->yacc_yyls;
5122   return false;
5123 }
5124 
5125 /**
5126   Reset the part of THD responsible for the state of command
5127   processing.
5128 
5129   This needs to be called before execution of every statement
5130   (prepared or conventional).  It is not called by substatements of
5131   routines.
5132 
5133   @todo Remove mysql_reset_thd_for_next_command and only use the
5134   member function.
5135 
5136   @todo Call it after we use THD for queries, not before.
5137 */
mysql_reset_thd_for_next_command(THD * thd)5138 void mysql_reset_thd_for_next_command(THD *thd) {
5139   thd->reset_for_next_command();
5140 }
5141 
reset_for_next_command()5142 void THD::reset_for_next_command() {
5143   // TODO: Why on earth is this here?! We should probably fix this
5144   // function and move it to the proper file. /Matz
5145   THD *thd = this;
5146   DBUG_TRACE;
5147   DBUG_ASSERT(!thd->sp_runtime_ctx); /* not for substatements of routines */
5148   DBUG_ASSERT(!thd->in_sub_stmt);
5149   thd->reset_item_list();
5150   /*
5151     Those two lines below are theoretically unneeded as
5152     THD::cleanup_after_query() should take care of this already.
5153   */
5154   thd->auto_inc_intervals_in_cur_stmt_for_binlog.empty();
5155   thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt = false;
5156 
5157   thd->query_start_usec_used = false;
5158   thd->m_is_fatal_error = false;
5159   thd->time_zone_used = false;
5160   /*
5161     Clear the status flag that are expected to be cleared at the
5162     beginning of each SQL statement.
5163   */
5164   thd->server_status &= ~SERVER_STATUS_CLEAR_SET;
5165   /*
5166     If in autocommit mode and not in a transaction, reset flag
5167     that identifies if a transaction has done some operations
5168     that cannot be safely rolled back.
5169 
5170     If the flag is set an warning message is printed out in
5171     ha_rollback_trans() saying that some tables couldn't be
5172     rolled back.
5173   */
5174   if (!thd->in_multi_stmt_transaction_mode()) {
5175     thd->get_transaction()->reset_unsafe_rollback_flags(
5176         Transaction_ctx::SESSION);
5177   }
5178   DBUG_ASSERT(thd->security_context() == &thd->m_main_security_ctx);
5179   thd->thread_specific_used = false;
5180 
5181   if (opt_bin_log) {
5182     thd->user_var_events.clear();
5183     thd->user_var_events_alloc = thd->mem_root;
5184   }
5185   thd->clear_error();
5186   thd->get_stmt_da()->reset_diagnostics_area();
5187   thd->get_stmt_da()->reset_statement_cond_count();
5188 
5189   thd->rand_used = false;
5190   thd->m_sent_row_count = thd->m_examined_row_count = 0;
5191 
5192   thd->reset_current_stmt_binlog_format_row();
5193   thd->binlog_unsafe_warning_flags = 0;
5194   thd->binlog_need_explicit_defaults_ts = false;
5195 
5196   thd->commit_error = THD::CE_NONE;
5197   thd->durability_property = HA_REGULAR_DURABILITY;
5198   thd->set_trans_pos(nullptr, 0);
5199 
5200   thd->derived_tables_processing = false;
5201   thd->parsing_system_view = false;
5202 
5203   // Need explicit setting, else demand all privileges to a table.
5204   thd->want_privilege = ~NO_ACCESS;
5205 
5206   thd->reset_skip_readonly_check();
5207   thd->tx_commit_pending = false;
5208 
5209   DBUG_PRINT("debug", ("is_current_stmt_binlog_format_row(): %d",
5210                        thd->is_current_stmt_binlog_format_row()));
5211 
5212   /*
5213     In case we're processing multiple statements we need to checkout a new
5214     acl access map here as the global acl version might have increased due to
5215     a grant/revoke or flush.
5216   */
5217   thd->security_context()->checkout_access_maps();
5218 #ifndef DBUG_OFF
5219   thd->set_tmp_table_seq_id(1);
5220 #endif
5221 }
5222 
5223 /**
5224   Create a select to return the same output as 'SELECT @@var_name'.
5225 
5226   Used for SHOW COUNT(*) [ WARNINGS | ERROR].
5227 
5228   This will crash with a core dump if the variable doesn't exists.
5229 
5230   @param pc                     Current parse context
5231   @param var_name		Variable name
5232 
5233   @returns false if success, true if error
5234 
5235   @todo - replace this function with one that generates a PT_select node
5236           and performs MAKE_CMD on it.
5237 */
5238 
create_select_for_variable(Parse_context * pc,const char * var_name)5239 bool create_select_for_variable(Parse_context *pc, const char *var_name) {
5240   LEX_STRING tmp, null_lex_string;
5241   char buff[MAX_SYS_VAR_LENGTH * 2 + 4 + 8];
5242   DBUG_TRACE;
5243 
5244   THD *thd = pc->thd;
5245   LEX *lex = thd->lex;
5246   lex->sql_command = SQLCOM_SELECT;
5247   tmp.str = const_cast<char *>(var_name);
5248   tmp.length = strlen(var_name);
5249   memset(&null_lex_string, 0, sizeof(null_lex_string));
5250   /*
5251     We set the name of Item to @@session.var_name because that then is used
5252     as the column name in the output.
5253   */
5254   Item *var = get_system_var(pc, OPT_SESSION, tmp, null_lex_string);
5255   if (var == nullptr) return true; /* purecov: inspected */
5256 
5257   char *end = strxmov(buff, "@@session.", var_name, NullS);
5258   var->item_name.copy(buff, end - buff);
5259   add_item_to_list(thd, var);
5260 
5261   return false;
5262 }
5263 
5264 /*
5265   When you modify mysql_parse(), you may need to mofify
5266   mysql_test_parse_for_slave() in this same file.
5267 */
5268 
5269 /**
5270   Parse a query.
5271 
5272   @param thd          Current session.
5273   @param parser_state Parser state.
5274 */
5275 
mysql_parse(THD * thd,Parser_state * parser_state)5276 void mysql_parse(THD *thd, Parser_state *parser_state) {
5277   DBUG_TRACE;
5278   DBUG_PRINT("mysql_parse", ("query: '%s'", thd->query().str));
5279 
5280   DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
5281 
5282   mysql_reset_thd_for_next_command(thd);
5283   lex_start(thd);
5284 
5285   thd->m_parser_state = parser_state;
5286   invoke_pre_parse_rewrite_plugins(thd);
5287   thd->m_parser_state = nullptr;
5288 
5289   enable_digest_if_any_plugin_needs_it(thd, parser_state);
5290 
5291   LEX *lex = thd->lex;
5292   const char *found_semicolon = nullptr;
5293 
5294   bool err = thd->get_stmt_da()->is_error();
5295 
5296   if (!err) {
5297     err = parse_sql(thd, parser_state, nullptr);
5298     if (!err) err = invoke_post_parse_rewrite_plugins(thd, false);
5299 
5300     found_semicolon = parser_state->m_lip.found_semicolon;
5301   }
5302 
5303   if (!err) {
5304     /*
5305       Rewrite the query for logging and for the Performance Schema
5306       statement tables. (Raw logging happened earlier.)
5307 
5308       Sub-routines of mysql_rewrite_query() should try to only rewrite when
5309       necessary (e.g. not do password obfuscation when query contains no
5310       password).
5311 
5312       If rewriting does not happen here, thd->m_rewritten_query is still
5313       empty from being reset in alloc_query().
5314     */
5315     if (thd->rewritten_query().length() == 0) mysql_rewrite_query(thd);
5316 
5317     if (thd->rewritten_query().length()) {
5318       lex->safe_to_cache_query = false;  // see comments below
5319 
5320       thd->set_query_for_display(thd->rewritten_query().ptr(),
5321                                  thd->rewritten_query().length());
5322     } else if (thd->slave_thread) {
5323       /*
5324         In the slave, we add the information to pfs.events_statements_history,
5325         but not to pfs.threads, as that is what the test suite expects.
5326       */
5327       MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query().str,
5328                                thd->query().length);
5329     } else {
5330       thd->set_query_for_display(thd->query().str, thd->query().length);
5331     }
5332 
5333     if (!(opt_general_log_raw || thd->slave_thread)) {
5334       if (thd->rewritten_query().length())
5335         query_logger.general_log_write(thd, COM_QUERY,
5336                                        thd->rewritten_query().ptr(),
5337                                        thd->rewritten_query().length());
5338       else {
5339         size_t qlen = found_semicolon ? (found_semicolon - thd->query().str)
5340                                       : thd->query().length;
5341 
5342         query_logger.general_log_write(thd, COM_QUERY, thd->query().str, qlen);
5343       }
5344     }
5345   }
5346 
5347   if (!err) {
5348     thd->m_statement_psi = MYSQL_REFINE_STATEMENT(
5349         thd->m_statement_psi, sql_statement_info[thd->lex->sql_command].m_key);
5350 
5351     if (mqh_used && thd->get_user_connect() &&
5352         check_mqh(thd, lex->sql_command)) {
5353       if (thd->is_classic_protocol())
5354         thd->get_protocol_classic()->get_net()->error = 0;
5355     } else {
5356       if (!thd->is_error()) {
5357         /*
5358           Binlog logs a string starting from thd->query and having length
5359           thd->query_length; so we set thd->query_length correctly (to not
5360           log several statements in one event, when we executed only first).
5361           We set it to not see the ';' (otherwise it would get into binlog
5362           and Query_log_event::print() would give ';;' output).
5363           This also helps display only the current query in SHOW
5364           PROCESSLIST.
5365         */
5366         if (found_semicolon && (ulong)(found_semicolon - thd->query().str))
5367           thd->set_query(
5368               thd->query().str,
5369               static_cast<size_t>(found_semicolon - thd->query().str - 1));
5370         /* Actually execute the query */
5371         if (found_semicolon) {
5372           lex->safe_to_cache_query = false;
5373           thd->server_status |= SERVER_MORE_RESULTS_EXISTS;
5374         }
5375         lex->set_trg_event_type_for_tables();
5376 
5377         int error MY_ATTRIBUTE((unused));
5378         if (unlikely(thd->security_context()->password_expired() &&
5379                      lex->sql_command != SQLCOM_SET_PASSWORD &&
5380                      lex->sql_command != SQLCOM_SET_OPTION &&
5381                      lex->sql_command != SQLCOM_ALTER_USER)) {
5382           my_error(ER_MUST_CHANGE_PASSWORD, MYF(0));
5383           error = 1;
5384         } else {
5385           resourcegroups::Resource_group *src_res_grp = nullptr;
5386           resourcegroups::Resource_group *dest_res_grp = nullptr;
5387           MDL_ticket *ticket = nullptr;
5388           MDL_ticket *cur_ticket = nullptr;
5389           auto mgr_ptr = resourcegroups::Resource_group_mgr::instance();
5390           bool switched = mgr_ptr->switch_resource_group_if_needed(
5391               thd, &src_res_grp, &dest_res_grp, &ticket, &cur_ticket);
5392 
5393           error = mysql_execute_command(thd, true);
5394 
5395           if (switched)
5396             mgr_ptr->restore_original_resource_group(thd, src_res_grp,
5397                                                      dest_res_grp);
5398           thd->resource_group_ctx()->m_switch_resource_group_str[0] = '\0';
5399           if (ticket != nullptr)
5400             mgr_ptr->release_shared_mdl_for_resource_group(thd, ticket);
5401           if (cur_ticket != nullptr)
5402             mgr_ptr->release_shared_mdl_for_resource_group(thd, cur_ticket);
5403         }
5404       }
5405     }
5406   } else {
5407     /*
5408       Log the failed raw query in the Performance Schema. This statement did not
5409       parse, so there is no way to tell if it may contain a password of not.
5410 
5411       The tradeoff is:
5412         a) If we do log the query, a user typing by accident a broken query
5413            containing a password will have the password exposed. This is very
5414            unlikely, and this behavior can be documented. Remediation is to use
5415            a new password when retyping the corrected query.
5416 
5417         b) If we do not log the query, finding broken queries in the client
5418            application will be much more difficult. This is much more likely.
5419 
5420       Considering that broken queries can typically be generated by attempts at
5421       SQL injection, finding the source of the SQL injection is critical, so the
5422       design choice is to log the query text of broken queries (a).
5423     */
5424     thd->set_query_for_display(thd->query().str, thd->query().length);
5425 
5426     /* Instrument this broken statement as "statement/sql/error" */
5427     thd->m_statement_psi = MYSQL_REFINE_STATEMENT(
5428         thd->m_statement_psi, sql_statement_info[SQLCOM_END].m_key);
5429 
5430     DBUG_ASSERT(thd->is_error());
5431     DBUG_PRINT("info",
5432                ("Command aborted. Fatal_error: %d", thd->is_fatal_error()));
5433   }
5434 
5435   THD_STAGE_INFO(thd, stage_freeing_items);
5436   sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size);
5437   sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size);
5438   thd->end_statement();
5439   thd->cleanup_after_query();
5440   DBUG_ASSERT(thd->change_list.is_empty());
5441 
5442   DEBUG_SYNC(thd, "query_rewritten");
5443 }
5444 
5445 /**
5446   Usable by the replication SQL thread only: just parse a query to know if it
5447   can be ignored because of replicate-*-table rules.
5448 
5449   @retval
5450     0	cannot be ignored
5451   @retval
5452     1	can be ignored
5453 */
5454 
mysql_test_parse_for_slave(THD * thd)5455 bool mysql_test_parse_for_slave(THD *thd) {
5456   LEX *lex = thd->lex;
5457   bool ignorable = false;
5458   sql_digest_state *parent_digest = thd->m_digest;
5459   PSI_statement_locker *parent_locker = thd->m_statement_psi;
5460   DBUG_TRACE;
5461 
5462   DBUG_ASSERT(thd->slave_thread);
5463 
5464   Parser_state parser_state;
5465   if (parser_state.init(thd, thd->query().str, thd->query().length) == 0) {
5466     lex_start(thd);
5467     mysql_reset_thd_for_next_command(thd);
5468 
5469     thd->m_digest = nullptr;
5470     thd->m_statement_psi = nullptr;
5471     if (parse_sql(thd, &parser_state, nullptr) == 0) {
5472       if (all_tables_not_ok(thd, lex->select_lex->table_list.first))
5473         ignorable = true;
5474       else if (!check_database_filters(thd, thd->db().str, lex->sql_command))
5475         ignorable = true;
5476     }
5477     thd->m_digest = parent_digest;
5478     thd->m_statement_psi = parent_locker;
5479     thd->end_statement();
5480   }
5481   thd->cleanup_after_query();
5482   return ignorable;
5483 }
5484 
5485 /**
5486   Store field definition for create.
5487 
5488   @param thd                       The thread handler.
5489   @param field_name                The field name.
5490   @param type                      The type of the field.
5491   @param length                    The length of the field or NULL.
5492   @param decimals                  The length of a decimal part or NULL.
5493   @param type_modifier             Type modifiers & constraint flags of the
5494                                    field.
5495   @param default_value             The default value or NULL.
5496   @param on_update_value           The ON UPDATE expression or NULL.
5497   @param comment                   The comment.
5498   @param change                    The old column name (if renaming) or NULL.
5499   @param interval_list             The list of ENUM/SET values or NULL.
5500   @param cs                        The character set of the field.
5501   @param has_explicit_collation    Column has an explicit COLLATE attribute.
5502   @param uint_geom_type            The GIS type of the field.
5503   @param gcol_info                 The generated column data or NULL.
5504   @param default_val_expr          The expression for generating default values,
5505                                    if there is one, or nullptr.
5506   @param opt_after                 The name of the field to add after or
5507                                    the @see first_keyword pointer to insert
5508                                    first.
5509   @param srid                      The SRID for this column (only relevant if
5510                                    this is a geometry column).
5511   @param col_check_const_spec_list List of column check constraints.
5512   @param hidden                    Whether or not this field shoud be hidden.
5513   @param is_array                  Whether it's a typed array field
5514 
5515   @return
5516     Return 0 if ok
5517 */
add_field(THD * thd,const LEX_STRING * field_name,enum_field_types type,const char * length,const char * decimals,uint type_modifier,Item * default_value,Item * on_update_value,LEX_CSTRING * comment,const char * change,List<String> * interval_list,const CHARSET_INFO * cs,bool has_explicit_collation,uint uint_geom_type,Value_generator * gcol_info,Value_generator * default_val_expr,const char * opt_after,Nullable<gis::srid_t> srid,Sql_check_constraint_spec_list * col_check_const_spec_list,dd::Column::enum_hidden_type hidden,bool is_array)5518 bool Alter_info::add_field(
5519     THD *thd, const LEX_STRING *field_name, enum_field_types type,
5520     const char *length, const char *decimals, uint type_modifier,
5521     Item *default_value, Item *on_update_value, LEX_CSTRING *comment,
5522     const char *change, List<String> *interval_list, const CHARSET_INFO *cs,
5523     bool has_explicit_collation, uint uint_geom_type,
5524     Value_generator *gcol_info, Value_generator *default_val_expr,
5525     const char *opt_after, Nullable<gis::srid_t> srid,
5526     Sql_check_constraint_spec_list *col_check_const_spec_list,
5527     dd::Column::enum_hidden_type hidden, bool is_array) {
5528   uint8 datetime_precision = decimals ? atoi(decimals) : 0;
5529   DBUG_TRACE;
5530   DBUG_ASSERT(!is_array || hidden != dd::Column::enum_hidden_type::HT_VISIBLE);
5531 
5532   LEX_CSTRING field_name_cstr = {field_name->str, field_name->length};
5533 
5534   if (check_string_char_length(field_name_cstr, "", NAME_CHAR_LEN,
5535                                system_charset_info, true)) {
5536     my_error(ER_TOO_LONG_IDENT, MYF(0),
5537              field_name->str); /* purecov: inspected */
5538     return true;               /* purecov: inspected */
5539   }
5540   if (type_modifier & PRI_KEY_FLAG) {
5541     List<Key_part_spec> key_parts;
5542     auto key_part_spec =
5543         new (thd->mem_root) Key_part_spec(field_name_cstr, 0, ORDER_ASC);
5544     if (key_part_spec == nullptr || key_parts.push_back(key_part_spec))
5545       return true;
5546     Key_spec *key = new (thd->mem_root)
5547         Key_spec(thd->mem_root, KEYTYPE_PRIMARY, NULL_CSTR,
5548                  &default_key_create_info, false, true, key_parts);
5549     if (key == nullptr || key_list.push_back(key)) return true;
5550   }
5551   if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG)) {
5552     List<Key_part_spec> key_parts;
5553     auto key_part_spec =
5554         new (thd->mem_root) Key_part_spec(field_name_cstr, 0, ORDER_ASC);
5555     if (key_part_spec == nullptr || key_parts.push_back(key_part_spec))
5556       return true;
5557     Key_spec *key = new (thd->mem_root)
5558         Key_spec(thd->mem_root, KEYTYPE_UNIQUE, NULL_CSTR,
5559                  &default_key_create_info, false, true, key_parts);
5560     if (key == nullptr || key_list.push_back(key)) return true;
5561   }
5562 
5563   if (default_value) {
5564     /*
5565       Default value should be literal => basic constants =>
5566       no need fix_fields()
5567 
5568       We allow only CURRENT_TIMESTAMP as function default for the TIMESTAMP or
5569       DATETIME types. In addition, TRUE and FALSE are allowed for bool types.
5570     */
5571     if (default_value->type() == Item::FUNC_ITEM) {
5572       Item_func *func = down_cast<Item_func *>(default_value);
5573       if (func->basic_const_item()) {
5574         if (func->result_type() != INT_RESULT) {
5575           my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5576           return true;
5577         }
5578         DBUG_ASSERT(dynamic_cast<Item_func_true *>(func) ||
5579                     dynamic_cast<Item_func_false *>(func));
5580         default_value = new Item_int(func->val_int());
5581         if (default_value == nullptr) return true;
5582       } else if (func->functype() != Item_func::NOW_FUNC ||
5583                  !real_type_with_now_as_default(type) ||
5584                  default_value->decimals != datetime_precision) {
5585         my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5586         return true;
5587       }
5588     } else if (default_value->type() == Item::NULL_ITEM) {
5589       default_value = nullptr;
5590       if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) ==
5591           NOT_NULL_FLAG) {
5592         my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5593         return true;
5594       }
5595     } else if (type_modifier & AUTO_INCREMENT_FLAG) {
5596       my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5597       return true;
5598     }
5599   }
5600 
5601   // 1) Reject combinations of DEFAULT <value> and DEFAULT (<expression>).
5602   // 2) Reject combinations of DEFAULT (<expression>) and AUTO_INCREMENT.
5603   // (Combinations of DEFAULT <value> and AUTO_INCREMENT are rejected above.)
5604   if ((default_val_expr && default_value) ||
5605       (default_val_expr && (type_modifier & AUTO_INCREMENT_FLAG))) {
5606     my_error(ER_INVALID_DEFAULT, MYF(0), field_name->str);
5607     return true;
5608   }
5609 
5610   if (on_update_value && (!real_type_with_now_on_update(type) ||
5611                           on_update_value->decimals != datetime_precision)) {
5612     my_error(ER_INVALID_ON_UPDATE, MYF(0), field_name->str);
5613     return true;
5614   }
5615 
5616   // If the SRID is specified on a non-geometric column, return an error
5617   if (type != MYSQL_TYPE_GEOMETRY && srid.has_value()) {
5618     my_error(ER_WRONG_USAGE, MYF(0), "SRID", "non-geometry column");
5619     return true;
5620   }
5621 
5622   Create_field *new_field = new (thd->mem_root) Create_field();
5623   if ((new_field == nullptr) ||
5624       new_field->init(thd, field_name->str, type, length, decimals,
5625                       type_modifier, default_value, on_update_value, comment,
5626                       change, interval_list, cs, has_explicit_collation,
5627                       uint_geom_type, gcol_info, default_val_expr, srid, hidden,
5628                       is_array))
5629     return true;
5630 
5631   for (const auto &a : cf_appliers) {
5632     if (a(new_field, this)) return true;
5633   }
5634 
5635   // Since Alter_info objects are allocated on a mem_root and never
5636   // destroyed we (move)-assign an empty vector to cf_appliers to
5637   // ensure any dynamic memory is released
5638   cf_appliers = decltype(cf_appliers)();
5639 
5640   create_list.push_back(new_field);
5641   if (opt_after != nullptr) {
5642     flags |= Alter_info::ALTER_COLUMN_ORDER;
5643     new_field->after = opt_after;
5644   }
5645 
5646   if (col_check_const_spec_list) {
5647     /*
5648       Set column name, required for column check constraint validation in
5649       Sql_check_constraint_spec::pre_validate().
5650     */
5651     for (auto &cc_spec : *col_check_const_spec_list) {
5652       cc_spec->column_name = *field_name;
5653     }
5654     /*
5655       Move column check constraint specifications to table check constraints
5656       specfications list.
5657     */
5658     std::move(col_check_const_spec_list->begin(),
5659               col_check_const_spec_list->end(),
5660               std::back_inserter(check_constraint_spec_list));
5661   }
5662 
5663   return false;
5664 }
5665 
5666 /**
5667   save order by and tables in own lists.
5668 */
5669 
add_to_list(SQL_I_List<ORDER> & list,ORDER * order)5670 void add_to_list(SQL_I_List<ORDER> &list, ORDER *order) {
5671   DBUG_TRACE;
5672   order->item = &order->item_ptr;
5673   order->used_alias = false;
5674   order->used = 0;
5675   list.link_in_list(order, &order->next);
5676 }
5677 
5678 /**
5679   Produces a PT_subquery object from a subquery's text.
5680   @param thd      Thread handler
5681   @param text     Subquery's text
5682   @param text_length  Length of 'text'
5683   @param text_offset Offset in bytes of 'text' in the original statement
5684   @param[out] node Produced PT_subquery object
5685 
5686   @returns true if error
5687  */
reparse_common_table_expr(THD * thd,const char * text,size_t text_length,uint text_offset,PT_subquery ** node)5688 static bool reparse_common_table_expr(THD *thd, const char *text,
5689                                       size_t text_length, uint text_offset,
5690                                       PT_subquery **node) {
5691   Common_table_expr_parser_state parser_state;
5692   parser_state.init(thd, text, text_length);
5693 
5694   Parser_state *old = thd->m_parser_state;
5695   thd->m_parser_state = &parser_state;
5696 
5697   /*
5698     Re-parsing a CTE creates Item_param-s and Item_sp_local-s which are
5699     special, as they do not exist in the original query: thus they should not
5700     exist from the points of view of logging.
5701     This is achieved like this:
5702     - for SP local vars: their pos_in_query is set to 0
5703     - for PS parameters: they are not added to LEX::param_list and thus not to
5704     Prepared_statement::param_array.
5705     They still need a value, which they get like this:
5706     - for SP local vars: through the ordinary look-up of SP local
5707     variables' values by name of the variable.
5708     - for PS parameters: first the first-parsed, 'non-special' Item-params,
5709     which are in param_array, get their value bound from user-supplied data,
5710     then they propagate their value to their 'special' clones (@see
5711     Item_param::m_clones).
5712   */
5713   parser_state.m_lip.stmt_prepare_mode = old->m_lip.stmt_prepare_mode;
5714   parser_state.m_lip.multi_statements = false;  // A safety measure.
5715   parser_state.m_lip.m_digest = nullptr;
5716 
5717   // This is saved and restored by caller:
5718   thd->lex->reparse_common_table_expr_at = text_offset;
5719 
5720   /*
5721     As this function is called during parsing only, it can and should use the
5722     current Query_arena, character_set_client, etc.
5723     It intentionally uses THD::sql_parser() directly without the parse_sql()
5724     wrapper: because it's building a node of the statement currently being
5725     parsed at the upper call site.
5726   */
5727   bool mysql_parse_status = thd->sql_parser();
5728   thd->m_parser_state = old;
5729   if (mysql_parse_status) return true; /* purecov: inspected */
5730 
5731   *node = parser_state.result;
5732   return false;
5733 }
5734 
make_subquery_node(THD * thd,PT_subquery ** node)5735 bool PT_common_table_expr::make_subquery_node(THD *thd, PT_subquery **node) {
5736   if (m_postparse.references.size() >= 2) {
5737     // m_subq_node was already attached elsewhere, make new node:
5738     return reparse_common_table_expr(thd, m_subq_text.str, m_subq_text.length,
5739                                      m_subq_text_offset, node);
5740   }
5741   *node = m_subq_node;
5742   return false;
5743 }
5744 
5745 /**
5746    Tries to match an identifier to the CTEs in scope; if matched, it
5747    modifies *table_name, *tl', and the matched with-list-element.
5748 
5749    @param          thd      Thread handler
5750    @param[out]     table_name Identifier
5751    @param[in,out]  tl       TABLE_LIST for the identifier
5752    @param          pc       Current parsing context, if available
5753    @param[out]     found    Is set to true if found.
5754 
5755    @returns true if error (OOM).
5756 */
find_common_table_expr(THD * thd,Table_ident * table_name,TABLE_LIST * tl,Parse_context * pc,bool * found)5757 bool SELECT_LEX::find_common_table_expr(THD *thd, Table_ident *table_name,
5758                                         TABLE_LIST *tl, Parse_context *pc,
5759                                         bool *found) {
5760   *found = false;
5761   if (!pc) return false;
5762 
5763   PT_with_clause *wc;
5764   PT_common_table_expr *cte = nullptr;
5765   SELECT_LEX *select = this;
5766   SELECT_LEX_UNIT *unit;
5767   do {
5768     DBUG_ASSERT(select->first_execution);
5769     unit = select->master_unit();
5770     if (!(wc = unit->m_with_clause)) continue;
5771     if (wc->lookup(tl, &cte)) return true;
5772     /*
5773       If no match in the WITH clause of 'select', maybe this is a subquery, so
5774       look up in the outer query's WITH clause:
5775     */
5776   } while (cte == nullptr && (select = unit->outer_select()));
5777 
5778   if (cte == nullptr) return false;
5779   *found = true;
5780 
5781   const auto save_reparse_cte = thd->lex->reparse_common_table_expr_at;
5782   PT_subquery *node;
5783   if (tl->is_recursive_reference()) {
5784     LEX_CSTRING dummy_subq = {STRING_WITH_LEN("(select 0)")};
5785     if (reparse_common_table_expr(thd, dummy_subq.str, dummy_subq.length, 0,
5786                                   &node))
5787       return true; /* purecov: inspected */
5788   } else if (cte->make_subquery_node(thd, &node))
5789     return true; /* purecov: inspected */
5790   // We imitate derived tables as much as possible.
5791   DBUG_ASSERT(parsing_place == CTX_NONE && linkage != GLOBAL_OPTIONS_TYPE);
5792   parsing_place = CTX_DERIVED;
5793   node->m_is_derived_table = true;
5794   auto wc_save = wc->enter_parsing_definition(tl);
5795 
5796   /*
5797     The proper outer context for the CTE, is not the query block where the CTE
5798     reference is; neither is it the outer query block of this. It is the query
5799     block which immediately contains the query expression where the CTE
5800     definition is. Indeed, per the standard, evaluation of the CTE happens
5801     as first step of evaluation of the said query expression; so the CTE may
5802     not contain references into the said query expression.
5803   */
5804   thd->lex->push_context(unit->outer_select() ? &unit->outer_select()->context
5805                                               : nullptr);
5806   DBUG_ASSERT(thd->lex->will_contextualize);
5807   if (node->contextualize(pc)) return true;
5808 
5809   thd->lex->pop_context();
5810 
5811   wc->leave_parsing_definition(wc_save);
5812   parsing_place = CTX_NONE;
5813   /*
5814     Prepared statement's parameters and SP local variables are spotted as
5815     'made during re-parsing' by node->contextualize(), which is why we
5816     ran that call _before_ restoring lex->reparse_common_table_expr_at.
5817   */
5818   thd->lex->reparse_common_table_expr_at = save_reparse_cte;
5819   tl->is_alias = true;
5820   SELECT_LEX_UNIT *node_unit = node->value()->master_unit();
5821   *table_name = Table_ident(node_unit);
5822   if (tl->is_recursive_reference()) recursive_dummy_unit = node_unit;
5823   DBUG_ASSERT(table_name->is_derived_table());
5824   tl->db = table_name->db.str;
5825   tl->db_length = table_name->db.length;
5826   tl->save_name_temporary();
5827   return false;
5828 }
5829 
lookup(TABLE_LIST * tl,PT_common_table_expr ** found)5830 bool PT_with_clause::lookup(TABLE_LIST *tl, PT_common_table_expr **found) {
5831   *found = nullptr;
5832   DBUG_ASSERT(tl->select_lex != nullptr);
5833   /*
5834     If right_bound!=NULL, it means we are currently parsing the
5835     definition of CTE 'right_bound' and this definition contains
5836     'tl'.
5837   */
5838   const Common_table_expr *right_bound =
5839       m_most_inner_in_parsing ? m_most_inner_in_parsing->common_table_expr()
5840                               : nullptr;
5841   bool in_self = false;
5842   for (auto el : m_list->elements()) {
5843     // Search for a CTE named like 'tl', in this list, from left to right.
5844     if (el->is(right_bound)) {
5845       /*
5846         We meet right_bound.
5847         If not RECURSIVE:
5848         we must stop the search in this WITH clause;
5849         indeed right_bound must not reference itself or any CTE defined after it
5850         in the WITH list (forward references are forbidden, preventing any
5851         cycle).
5852         If RECURSIVE:
5853         If right_bound matches 'tl', it is a recursive reference.
5854       */
5855       if (!m_recursive) break;  // Prevent forward reference.
5856       in_self = true;           // Accept a recursive reference.
5857     }
5858     bool match;
5859     if (el->match_table_ref(tl, in_self, &match)) return true;
5860     if (!match) {
5861       if (in_self) break;  // Prevent forward reference.
5862       continue;
5863     }
5864     if (in_self &&
5865         tl->select_lex->outer_select() != m_most_inner_in_parsing->select_lex) {
5866       /*
5867         SQL2011 says a recursive CTE cannot contain a subquery
5868         referencing the CTE, except if this subquery is a derived table
5869         like:
5870         WITH RECURSIVE qn AS (non-rec-SELECT UNION ALL
5871         SELECT * FROM (SELECT * FROM qn) AS dt)
5872         However, we don't allow this, as:
5873         - it simplifies detection and substitution correct recursive
5874         references (they're all on "level 0" of the UNION)
5875         - it's not limiting the user so much (in most cases, he can just
5876         merge his DT up manually, as the DT cannot contain aggregation).
5877         - Oracle bans it:
5878         with qn (a) as (
5879         select 123 from dual
5880         union all
5881         select 1+a from (select * from qn) where a<130) select * from qn
5882         ORA-32042: recursive WITH clause must reference itself directly in one
5883         of the UNION ALL branches.
5884 
5885         The above if() works because, when we parse such example query, we
5886         first resolve the 'qn' reference in the top query, making it a derived
5887         table:
5888 
5889         select * from (
5890            select 123 from dual
5891            union all
5892            select 1+a from (select * from qn) where a<130) qn(a);
5893                                                            ^most_inner_in_parsing
5894         Then we contextualize that derived table (containing the union);
5895         when we contextualize the recursive query block of the union, the
5896         inner 'qn' is recognized as a recursive reference, and its
5897         select_lex->outer_select() is _not_ the select_lex of
5898         most_inner_in_parsing, which indicates that the inner 'qn' is placed
5899         too deep.
5900       */
5901       my_error(ER_CTE_RECURSIVE_REQUIRES_SINGLE_REFERENCE, MYF(0),
5902                el->name().str);
5903       return true;
5904     }
5905     *found = el;
5906     break;
5907   }
5908   return false;
5909 }
5910 
match_table_ref(TABLE_LIST * tl,bool in_self,bool * found)5911 bool PT_common_table_expr::match_table_ref(TABLE_LIST *tl, bool in_self,
5912                                            bool *found) {
5913   *found = false;
5914   if (tl->table_name_length == m_name.length &&
5915       /*
5916         memcmp() is fine even if lower_case_table_names==1, as CTE names
5917         have been lowercased in the ctor.
5918       */
5919       !memcmp(tl->table_name, m_name.str, m_name.length)) {
5920     *found = true;
5921     // 'tl' is a reference to CTE 'el'.
5922     if (in_self) {
5923       m_postparse.recursive = true;
5924       if (tl->set_recursive_reference()) {
5925         my_error(ER_CTE_RECURSIVE_REQUIRES_SINGLE_REFERENCE, MYF(0),
5926                  name().str);
5927         return true;
5928       }
5929     } else {
5930       if (m_postparse.references.push_back(tl))
5931         return true; /* purecov: inspected */
5932       tl->set_common_table_expr(&m_postparse);
5933       if (m_column_names.size()) tl->set_derived_column_names(&m_column_names);
5934     }
5935   }
5936   return false;
5937 }
5938 
5939 /**
5940   Add a table to list of used tables.
5941 
5942   @param thd      Current session.
5943   @param table_name	Table to add
5944   @param alias		alias for table (or null if no alias)
5945   @param table_options	A set of the following bits:
5946                          - TL_OPTION_UPDATING : Table will be updated
5947                          - TL_OPTION_FORCE_INDEX : Force usage of index
5948                          - TL_OPTION_ALIAS : an alias in multi table DELETE
5949   @param lock_type	How table should be locked
5950   @param mdl_type       Type of metadata lock to acquire on the table.
5951   @param index_hints_arg a list of index hints(FORCE/USE/IGNORE INDEX).
5952   @param partition_names List to carry partition names from PARTITION (...)
5953   clause in statement
5954   @param option         Used by cache index
5955   @param pc             Current parsing context, if available.
5956 
5957   @return Pointer to TABLE_LIST element added to the total table list
5958   @retval
5959       0		Error
5960 */
5961 
add_table_to_list(THD * thd,Table_ident * table_name,const char * alias,ulong table_options,thr_lock_type lock_type,enum_mdl_type mdl_type,List<Index_hint> * index_hints_arg,List<String> * partition_names,LEX_STRING * option,Parse_context * pc)5962 TABLE_LIST *SELECT_LEX::add_table_to_list(
5963     THD *thd, Table_ident *table_name, const char *alias, ulong table_options,
5964     thr_lock_type lock_type, enum_mdl_type mdl_type,
5965     List<Index_hint> *index_hints_arg, List<String> *partition_names,
5966     LEX_STRING *option, Parse_context *pc) {
5967   TABLE_LIST *previous_table_ref =
5968       nullptr; /* The table preceding the current one. */
5969   LEX *lex = thd->lex;
5970   DBUG_TRACE;
5971 
5972   DBUG_ASSERT(table_name != nullptr);
5973   // A derived table has no table name, only an alias.
5974   if (!(table_options & TL_OPTION_ALIAS) && !table_name->is_derived_table()) {
5975     Ident_name_check ident_check_status =
5976         check_table_name(table_name->table.str, table_name->table.length);
5977     if (ident_check_status == Ident_name_check::WRONG) {
5978       my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name->table.str);
5979       return nullptr;
5980     } else if (ident_check_status == Ident_name_check::TOO_LONG) {
5981       my_error(ER_TOO_LONG_IDENT, MYF(0), table_name->table.str);
5982       return nullptr;
5983     }
5984   }
5985   LEX_STRING db = to_lex_string(table_name->db);
5986   if (!table_name->is_derived_table() && !table_name->is_table_function() &&
5987       table_name->db.str &&
5988       (check_and_convert_db_name(&db, false) != Ident_name_check::OK))
5989     return nullptr;
5990 
5991   const char *alias_str = alias ? alias : table_name->table.str;
5992   if (!alias) /* Alias is case sensitive */
5993   {
5994     if (table_name->sel) {
5995       my_error(ER_DERIVED_MUST_HAVE_ALIAS, MYF(0));
5996       return nullptr;
5997     }
5998     if (!(alias_str =
5999               (char *)thd->memdup(alias_str, table_name->table.length + 1)))
6000       return nullptr;
6001   }
6002 
6003   TABLE_LIST *ptr = new (thd->mem_root) TABLE_LIST;
6004   if (ptr == nullptr) return nullptr; /* purecov: inspected */
6005 
6006   if (lower_case_table_names && table_name->table.length)
6007     table_name->table.length = my_casedn_str(
6008         files_charset_info, const_cast<char *>(table_name->table.str));
6009 
6010   ptr->select_lex = this;
6011   ptr->table_name = table_name->table.str;
6012   ptr->table_name_length = table_name->table.length;
6013   ptr->alias = alias_str;
6014   ptr->is_alias = alias != nullptr;
6015   ptr->table_function = table_name->table_function;
6016   if (table_name->table_function) {
6017     table_func_count++;
6018     ptr->derived_key_list.empty();
6019   }
6020 
6021   if (table_name->db.str) {
6022     ptr->is_fqtn = true;
6023     ptr->db = table_name->db.str;
6024     ptr->db_length = table_name->db.length;
6025   } else {
6026     bool found_cte;
6027     if (find_common_table_expr(thd, table_name, ptr, pc, &found_cte))
6028       return nullptr;
6029     if (!found_cte && lex->copy_db_to(&ptr->db, &ptr->db_length))
6030       return nullptr;
6031   }
6032 
6033   ptr->set_tableno(0);
6034   ptr->set_lock({lock_type, THR_DEFAULT});
6035   ptr->updating = (table_options & TL_OPTION_UPDATING);
6036   /* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */
6037   ptr->force_index = (table_options & TL_OPTION_FORCE_INDEX);
6038   ptr->ignore_leaves = (table_options & TL_OPTION_IGNORE_LEAVES);
6039   ptr->set_derived_unit(table_name->sel);
6040   if (!ptr->is_derived() && !ptr->is_table_function() &&
6041       is_infoschema_db(ptr->db, ptr->db_length)) {
6042     dd::info_schema::convert_table_name_case(
6043         const_cast<char *>(ptr->db), const_cast<char *>(ptr->table_name));
6044 
6045     bool hidden_system_view = false;
6046     ptr->is_system_view = dd::get_dictionary()->is_system_view_name(
6047         ptr->db, ptr->table_name, &hidden_system_view);
6048 
6049     ST_SCHEMA_TABLE *schema_table;
6050     if (ptr->updating &&
6051         /* Special cases which are processed by commands itself */
6052         lex->sql_command != SQLCOM_CHECK &&
6053         lex->sql_command != SQLCOM_CHECKSUM &&
6054         !(lex->sql_command == SQLCOM_CREATE_VIEW && ptr->is_system_view)) {
6055       my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
6056                thd->security_context()->priv_user().str,
6057                thd->security_context()->priv_host().str,
6058                INFORMATION_SCHEMA_NAME.str);
6059       return nullptr;
6060     }
6061     if (ptr->is_system_view) {
6062       if (thd->lex->sql_command != SQLCOM_CREATE_VIEW) {
6063         /*
6064           Stop users from using hidden system views, unless
6065           it is used by SHOW commands.
6066         */
6067         if (thd->lex->select_lex && hidden_system_view &&
6068             !(thd->lex->select_lex->active_options() &
6069               OPTION_SELECT_FOR_SHOW)) {
6070           my_error(ER_NO_SYSTEM_VIEW_ACCESS, MYF(0), ptr->table_name);
6071           return nullptr;
6072         }
6073 
6074         /*
6075           Stop users from accessing I_S.FILES if they do not have
6076           PROCESS privilege.
6077         */
6078         if (!strcmp(ptr->table_name, "FILES") &&
6079             check_global_access(thd, PROCESS_ACL))
6080           return nullptr;
6081       }
6082     } else {
6083       schema_table = find_schema_table(thd, ptr->table_name);
6084       /*
6085         Report an error
6086           if hidden schema table name is used in the statement other than
6087           SHOW statement OR
6088           if unknown schema table is used in the statement other than
6089           SHOW CREATE VIEW statement.
6090         Invalid view warning is reported for SHOW CREATE VIEW statement in
6091         the table open stage.
6092       */
6093       if ((!schema_table &&
6094            !(thd->query_plan.get_command() == SQLCOM_SHOW_CREATE &&
6095              thd->query_plan.get_lex()->only_view)) ||
6096           (schema_table && schema_table->hidden &&
6097            (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0)) {
6098         my_error(ER_UNKNOWN_TABLE, MYF(0), ptr->table_name,
6099                  INFORMATION_SCHEMA_NAME.str);
6100         return nullptr;
6101       }
6102 
6103       if (schema_table) {
6104         ptr->schema_table_name = ptr->table_name;
6105         ptr->schema_table = schema_table;
6106       }
6107     }
6108   }
6109 
6110   ptr->cacheable_table = true;
6111   ptr->index_hints = index_hints_arg;
6112   ptr->option = option ? option->str : nullptr;
6113   /* check that used name is unique */
6114   if (lock_type != TL_IGNORE) {
6115     TABLE_LIST *first_table = table_list.first;
6116     if (lex->sql_command == SQLCOM_CREATE_VIEW)
6117       first_table = first_table ? first_table->next_local : nullptr;
6118     for (TABLE_LIST *tables = first_table; tables;
6119          tables = tables->next_local) {
6120       if (!my_strcasecmp(table_alias_charset, alias_str, tables->alias) &&
6121           !strcmp(ptr->db, tables->db)) {
6122         my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str); /* purecov: tested */
6123         return nullptr;                                /* purecov: tested */
6124       }
6125     }
6126   }
6127   /* Store the table reference preceding the current one. */
6128   if (table_list.elements > 0) {
6129     /*
6130       table_list.next points to the last inserted TABLE_LIST->next_local'
6131       element
6132       We don't use the offsetof() macro here to avoid warnings from gcc
6133     */
6134     previous_table_ref =
6135         (TABLE_LIST *)((char *)table_list.next -
6136                        ((char *)&(ptr->next_local) - (char *)ptr));
6137     /*
6138       Set next_name_resolution_table of the previous table reference to point
6139       to the current table reference. In effect the list
6140       TABLE_LIST::next_name_resolution_table coincides with
6141       TABLE_LIST::next_local. Later this may be changed in
6142       store_top_level_join_columns() for NATURAL/USING joins.
6143     */
6144     previous_table_ref->next_name_resolution_table = ptr;
6145   }
6146 
6147   /*
6148     Link the current table reference in a local list (list for current select).
6149     Notice that as a side effect here we set the next_local field of the
6150     previous table reference to 'ptr'. Here we also add one element to the
6151     list 'table_list'.
6152   */
6153   table_list.link_in_list(ptr, &ptr->next_local);
6154   ptr->next_name_resolution_table = nullptr;
6155   ptr->partition_names = partition_names;
6156   /* Link table in global list (all used tables) */
6157   lex->add_to_query_tables(ptr);
6158 
6159   // Pure table aliases do not need to be locked:
6160   if (!(table_options & TL_OPTION_ALIAS)) {
6161     MDL_REQUEST_INIT(&ptr->mdl_request, MDL_key::TABLE, ptr->db,
6162                      ptr->table_name, mdl_type, MDL_TRANSACTION);
6163   }
6164   if (table_name->is_derived_table()) {
6165     ptr->derived_key_list.empty();
6166     derived_table_count++;
6167     ptr->save_name_temporary();
6168   }
6169 
6170   // Check access to DD tables. We must allow CHECK and ALTER TABLE
6171   // for the DDSE tables, since this is expected by the upgrade
6172   // client. We must also allow DDL access for the initialize thread,
6173   // since this thread is creating the I_S views.
6174   // Note that at this point, the mdl request for CREATE TABLE is still
6175   // MDL_SHARED, so we must explicitly check for SQLCOM_CREATE_TABLE.
6176   const dd::Dictionary *dictionary = dd::get_dictionary();
6177   if (dictionary &&
6178       !dictionary->is_dd_table_access_allowed(
6179           thd->is_dd_system_thread() || thd->is_initialize_system_thread() ||
6180               thd->is_server_upgrade_thread(),
6181           (ptr->mdl_request.is_ddl_or_lock_tables_lock_request() ||
6182            (lex->sql_command == SQLCOM_CREATE_TABLE &&
6183             ptr == lex->query_tables)) &&
6184               lex->sql_command != SQLCOM_CHECK &&
6185               lex->sql_command != SQLCOM_ALTER_TABLE,
6186           ptr->db, ptr->db_length, ptr->table_name)) {
6187     // We must allow creation of the system views even for non-system
6188     // threads since this is expected by the mysql_upgrade utility.
6189     if (!(lex->sql_command == SQLCOM_CREATE_VIEW &&
6190           dd::get_dictionary()->is_system_view_name(
6191               lex->query_tables->db, lex->query_tables->table_name))) {
6192       my_error(ER_NO_SYSTEM_TABLE_ACCESS, MYF(0),
6193                ER_THD_NONCONST(thd, dictionary->table_type_error_code(
6194                                         ptr->db, ptr->table_name)),
6195                ptr->db, ptr->table_name);
6196       // Take error handler into account to see if we should return.
6197       if (thd->is_error()) return nullptr;
6198     }
6199   }
6200 
6201   return ptr;
6202 }
6203 
6204 /**
6205   Initialize a new table list for a nested join.
6206 
6207     The function initializes a structure of the TABLE_LIST type
6208     for a nested join. It sets up its nested join list as empty.
6209     The created structure is added to the front of the current
6210     join list in the SELECT_LEX object. Then the function
6211     changes the current nest level for joins to refer to the newly
6212     created empty list after having saved the info on the old level
6213     in the initialized structure.
6214 
6215   @param thd         current thread
6216 
6217   @retval
6218     0   if success
6219   @retval
6220     1   otherwise
6221 */
6222 
init_nested_join(THD * thd)6223 bool SELECT_LEX::init_nested_join(THD *thd) {
6224   DBUG_TRACE;
6225 
6226   TABLE_LIST *const ptr = TABLE_LIST::new_nested_join(
6227       thd->mem_root, "(nested_join)", embedding, join_list, this);
6228   if (ptr == nullptr) return true;
6229 
6230   join_list->push_front(ptr);
6231   embedding = ptr;
6232   join_list = &ptr->nested_join->join_list;
6233 
6234   return false;
6235 }
6236 
6237 /**
6238   End a nested join table list.
6239 
6240     The function returns to the previous join nest level.
6241     If the current level contains only one member, the function
6242     moves it one level up, eliminating the nest.
6243 
6244   @return
6245     - Pointer to TABLE_LIST element added to the total table list, if success
6246     - 0, otherwise
6247 */
6248 
end_nested_join()6249 TABLE_LIST *SELECT_LEX::end_nested_join() {
6250   TABLE_LIST *ptr;
6251   NESTED_JOIN *nested_join;
6252   DBUG_TRACE;
6253 
6254   DBUG_ASSERT(embedding);
6255   ptr = embedding;
6256   join_list = ptr->join_list;
6257   embedding = ptr->embedding;
6258   nested_join = ptr->nested_join;
6259   if (nested_join->join_list.size() == 1) {
6260     TABLE_LIST *embedded = nested_join->join_list.front();
6261     join_list->pop_front();
6262     embedded->join_list = join_list;
6263     embedded->embedding = embedding;
6264     join_list->push_front(embedded);
6265     ptr = embedded;
6266   } else if (nested_join->join_list.empty()) {
6267     join_list->pop_front();
6268     ptr = nullptr;  // return value
6269   }
6270   return ptr;
6271 }
6272 
6273 /**
6274   Nest last join operations.
6275 
6276   The function nest last table_cnt join operations as if they were
6277   the components of a cross join operation.
6278 
6279   @param thd         current thread
6280   @param table_cnt   2 for regular joins: t1 JOIN t2.
6281                      N for the MySQL join-like extension: (t1, t2, ... tN).
6282 
6283   @return Pointer to TABLE_LIST element created for the new nested join
6284   @retval
6285     0  Error
6286 */
6287 
nest_last_join(THD * thd,size_t table_cnt)6288 TABLE_LIST *SELECT_LEX::nest_last_join(THD *thd, size_t table_cnt) {
6289   DBUG_TRACE;
6290 
6291   TABLE_LIST *const ptr = TABLE_LIST::new_nested_join(
6292       thd->mem_root, "(nest_last_join)", embedding, join_list, this);
6293   if (ptr == nullptr) return nullptr;
6294 
6295   mem_root_deque<TABLE_LIST *> *const embedded_list =
6296       &ptr->nested_join->join_list;
6297 
6298   for (uint i = 0; i < table_cnt; i++) {
6299     TABLE_LIST *table = join_list->front();
6300     join_list->pop_front();
6301     table->join_list = embedded_list;
6302     table->embedding = ptr;
6303     embedded_list->push_back(table);
6304     if (table->natural_join) ptr->is_natural_join = true;
6305   }
6306   join_list->push_front(ptr);
6307 
6308   return ptr;
6309 }
6310 
6311 /**
6312   Add a table to the current join list.
6313 
6314     The function puts a table in front of the current join list
6315     of SELECT_LEX object.
6316     Thus, joined tables are put into this list in the reverse order
6317     (the most outer join operation follows first).
6318 
6319   @param table       The table to add.
6320 
6321   @returns false if success, true if error (OOM).
6322 */
6323 
add_joined_table(TABLE_LIST * table)6324 bool SELECT_LEX::add_joined_table(TABLE_LIST *table) {
6325   DBUG_TRACE;
6326   join_list->push_front(table);
6327   table->join_list = join_list;
6328   table->embedding = embedding;
6329   return false;
6330 }
6331 
6332 /**
6333   Convert a right join into equivalent left join.
6334 
6335     The function takes the current join list t[0],t[1] ... and
6336     effectively converts it into the list t[1],t[0] ...
6337     Although the outer_join flag for the new nested table contains
6338     JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
6339     operation.
6340 
6341   EXAMPLES
6342   @verbatim
6343     SELECT * FROM t1 RIGHT JOIN t2 ON on_expr =>
6344       SELECT * FROM t2 LEFT JOIN t1 ON on_expr
6345 
6346     SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr =>
6347       SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr
6348 
6349     SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr =>
6350       SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr
6351 
6352     SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3  ON on_expr2 =>
6353       SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1
6354    @endverbatim
6355 
6356   @return
6357     - Pointer to the table representing the inner table, if success
6358     - 0, otherwise
6359 */
6360 
convert_right_join()6361 TABLE_LIST *SELECT_LEX::convert_right_join() {
6362   TABLE_LIST *tab2 = join_list->front();
6363   join_list->pop_front();
6364   TABLE_LIST *tab1 = join_list->front();
6365   join_list->pop_front();
6366 
6367   join_list->push_front(tab2);
6368   join_list->push_front(tab1);
6369   tab1->outer_join = JOIN_TYPE_RIGHT;
6370 
6371   return tab1;
6372 }
6373 
set_lock_for_table(const Lock_descriptor & descriptor,TABLE_LIST * table)6374 void SELECT_LEX::set_lock_for_table(const Lock_descriptor &descriptor,
6375                                     TABLE_LIST *table) {
6376   thr_lock_type lock_type = descriptor.type;
6377   bool for_update = lock_type >= TL_READ_NO_INSERT;
6378   enum_mdl_type mdl_type = mdl_type_for_dml(lock_type);
6379   DBUG_TRACE;
6380   DBUG_PRINT("enter", ("lock_type: %d  for_update: %d", lock_type, for_update));
6381   table->set_lock(descriptor);
6382   table->updating = for_update;
6383   table->mdl_request.set_type(mdl_type);
6384 }
6385 
6386 /**
6387   Set lock for all tables in current query block.
6388 
6389   @param lock_type Lock to set for tables.
6390 
6391   @note
6392     If the lock is a write lock, then tables->updating is set to true.
6393     This is to get tables_ok to know that the table is being updated by the
6394     query.
6395     Sets the type of metadata lock to request according to lock_type.
6396 */
set_lock_for_tables(thr_lock_type lock_type)6397 void SELECT_LEX::set_lock_for_tables(thr_lock_type lock_type) {
6398   DBUG_TRACE;
6399   DBUG_PRINT("enter", ("lock_type: %d  for_update: %d", lock_type,
6400                        lock_type >= TL_READ_NO_INSERT));
6401   for (TABLE_LIST *table = table_list.first; table; table = table->next_local)
6402     set_lock_for_table({lock_type, THR_WAIT}, table);
6403 }
6404 
6405 /**
6406   Create a fake SELECT_LEX for a unit.
6407 
6408     The method create a fake SELECT_LEX object for a unit.
6409     This object is created for any union construct containing a union
6410     operation and also for any single select union construct of the form
6411     @verbatim
6412     (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ...
6413     @endverbatim
6414     or of the form
6415     @verbatim
6416     (SELECT ... ORDER BY LIMIT n) ORDER BY ...
6417     @endverbatim
6418 
6419   @param thd       thread handle
6420 
6421   @note
6422     The object is used to retrieve rows from the temporary table
6423     where the result on the union is obtained.
6424 
6425   @retval
6426     1     on failure to create the object
6427   @retval
6428     0     on success
6429 */
6430 
add_fake_select_lex(THD * thd)6431 bool SELECT_LEX_UNIT::add_fake_select_lex(THD *thd) {
6432   SELECT_LEX *first_sl = first_select();
6433   DBUG_TRACE;
6434   DBUG_ASSERT(!fake_select_lex);
6435 
6436   if (!(fake_select_lex = thd->lex->new_empty_query_block()))
6437     return true; /* purecov: inspected */
6438   fake_select_lex->include_standalone(this, &fake_select_lex);
6439   fake_select_lex->select_number = INT_MAX;
6440   fake_select_lex->linkage = GLOBAL_OPTIONS_TYPE;
6441   fake_select_lex->select_limit = nullptr;
6442 
6443   fake_select_lex->set_context(first_sl->context.outer_context);
6444 
6445   /* allow item list resolving in fake select for ORDER BY */
6446   fake_select_lex->context.resolve_in_select_list = true;
6447 
6448   if (!is_union()) {
6449     /*
6450       This works only for
6451       (SELECT ... ORDER BY list [LIMIT n]) ORDER BY order_list [LIMIT m],
6452       (SELECT ... LIMIT n) ORDER BY order_list [LIMIT m]
6453       just before the parser starts processing order_list
6454     */
6455     fake_select_lex->no_table_names_allowed = true;
6456   }
6457   thd->lex->pop_context();
6458   return false;
6459 }
6460 
6461 /**
6462   Push a new name resolution context for a JOIN ... ON clause to the
6463   context stack of a query block.
6464 
6465     Create a new name resolution context for a JOIN ... ON clause,
6466     set the first and last leaves of the list of table references
6467     to be used for name resolution, and push the newly created
6468     context to the stack of contexts of the query.
6469 
6470   @param pc        current parse context
6471   @param left_op   left  operand of the JOIN
6472   @param right_op  rigth operand of the JOIN
6473 
6474   @retval
6475     false  if all is OK
6476   @retval
6477     true   if a memory allocation error occurred
6478 */
6479 
push_new_name_resolution_context(Parse_context * pc,TABLE_LIST * left_op,TABLE_LIST * right_op)6480 bool push_new_name_resolution_context(Parse_context *pc, TABLE_LIST *left_op,
6481                                       TABLE_LIST *right_op) {
6482   THD *thd = pc->thd;
6483   Name_resolution_context *on_context;
6484   if (!(on_context = new (thd->mem_root) Name_resolution_context)) return true;
6485   on_context->init();
6486   on_context->first_name_resolution_table =
6487       left_op->first_leaf_for_name_resolution();
6488   on_context->last_name_resolution_table =
6489       right_op->last_leaf_for_name_resolution();
6490   on_context->select_lex = pc->select;
6491   // Other tables in FROM clause of this JOIN are not visible:
6492   on_context->outer_context = thd->lex->current_context()->outer_context;
6493   on_context->next_context = pc->select->first_context;
6494   pc->select->first_context = on_context;
6495 
6496   return thd->lex->push_context(on_context);
6497 }
6498 
6499 /**
6500   Add an ON condition to the second operand of a JOIN ... ON.
6501 
6502     Add an ON condition to the right operand of a JOIN ... ON clause.
6503 
6504   @param b     the second operand of a JOIN ... ON
6505   @param expr  the condition to be added to the ON clause
6506 */
6507 
add_join_on(TABLE_LIST * b,Item * expr)6508 void add_join_on(TABLE_LIST *b, Item *expr) {
6509   if (expr) {
6510     b->set_join_cond_optim((Item *)1);  // m_join_cond_optim is not ready
6511     if (!b->join_cond())
6512       b->set_join_cond(expr);
6513     else {
6514       /*
6515         If called from the parser, this happens if you have both a
6516         right and left join. If called later, it happens if we add more
6517         than one condition to the ON clause.
6518       */
6519       b->set_join_cond(new Item_cond_and(b->join_cond(), expr));
6520     }
6521     b->join_cond()->apply_is_true();
6522   }
6523 }
6524 
get_bin_collation(const CHARSET_INFO * cs)6525 const CHARSET_INFO *get_bin_collation(const CHARSET_INFO *cs) {
6526   const CHARSET_INFO *ret =
6527       get_charset_by_csname(cs->csname, MY_CS_BINSORT, MYF(0));
6528   if (ret) return ret;
6529 
6530   char tmp[65];
6531   strmake(strmake(tmp, cs->csname, sizeof(tmp) - 4), STRING_WITH_LEN("_bin"));
6532   my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp);
6533   return nullptr;
6534 }
6535 
6536 /**
6537   kill on thread.
6538 
6539   @param thd			Thread class
6540   @param id			Thread id
6541   @param only_kill_query        Should it kill the query or the connection
6542 
6543   @note
6544     This is written such that we have a short lock on LOCK_thd_list
6545 */
6546 
kill_one_thread(THD * thd,my_thread_id id,bool only_kill_query)6547 static uint kill_one_thread(THD *thd, my_thread_id id, bool only_kill_query) {
6548   THD *tmp = nullptr;
6549   uint error = ER_NO_SUCH_THREAD;
6550   Find_thd_with_id find_thd_with_id(id);
6551 
6552   DBUG_TRACE;
6553   DBUG_PRINT("enter", ("id=%u only_kill=%d", id, only_kill_query));
6554   tmp = Global_THD_manager::get_instance()->find_thd(&find_thd_with_id);
6555   Security_context *sctx = thd->security_context();
6556   if (tmp) {
6557     /*
6558       If we're SUPER, we can KILL anything, including system-threads.
6559       No further checks.
6560 
6561       KILLer: thd->m_security_ctx->user could in theory be NULL while
6562       we're still in "unauthenticated" state. This is a theoretical
6563       case (the code suggests this could happen, so we play it safe).
6564 
6565       KILLee: tmp->m_security_ctx->user will be NULL for system threads.
6566       We need to check so Jane Random User doesn't crash the server
6567       when trying to kill a) system threads or b) unauthenticated users'
6568       threads (Bug#43748).
6569 
6570       If user of both killer and killee are non-NULL, proceed with
6571       slayage if both are string-equal.
6572     */
6573 
6574     if (sctx->check_access(SUPER_ACL) ||
6575         sctx->has_global_grant(STRING_WITH_LEN("CONNECTION_ADMIN")).first ||
6576         sctx->user_matches(tmp->security_context())) {
6577       /*
6578         Process the kill:
6579         if thread is not already undergoing any kill connection.
6580         Killer must have SYSTEM_USER privilege iff killee has the same privilege
6581       */
6582       if (tmp->killed != THD::KILL_CONNECTION) {
6583         if (tmp->is_system_user() && !thd->is_system_user()) {
6584           error = ER_KILL_DENIED_ERROR;
6585         } else {
6586           tmp->awake(only_kill_query ? THD::KILL_QUERY : THD::KILL_CONNECTION);
6587           error = 0;
6588         }
6589       } else
6590         error = 0;
6591     } else
6592       error = ER_KILL_DENIED_ERROR;
6593     mysql_mutex_unlock(&tmp->LOCK_thd_data);
6594   }
6595   DEBUG_SYNC(thd, "kill_thd_end");
6596   DBUG_PRINT("exit", ("%d", error));
6597   return error;
6598 }
6599 
6600 /*
6601   kills a thread and sends response
6602 
6603   SYNOPSIS
6604     sql_kill()
6605     thd			Thread class
6606     id			Thread id
6607     only_kill_query     Should it kill the query or the connection
6608 */
6609 
sql_kill(THD * thd,my_thread_id id,bool only_kill_query)6610 static void sql_kill(THD *thd, my_thread_id id, bool only_kill_query) {
6611   uint error;
6612   if (!(error = kill_one_thread(thd, id, only_kill_query))) {
6613     if (!thd->killed) my_ok(thd);
6614   } else
6615     my_error(error, MYF(0), id);
6616 }
6617 
6618 /**
6619   This class implements callback function used by killall_non_super_threads
6620   to kill all threads that do not have the SUPER privilege
6621 */
6622 
6623 class Kill_non_super_conn : public Do_THD_Impl {
6624  private:
6625   /* THD of connected client. */
6626   THD *m_client_thd;
6627 
6628  public:
Kill_non_super_conn(THD * thd)6629   Kill_non_super_conn(THD *thd) : m_client_thd(thd) {
6630     DBUG_ASSERT(
6631         m_client_thd->security_context()->check_access(SUPER_ACL) ||
6632         m_client_thd->security_context()
6633             ->has_global_grant(STRING_WITH_LEN("SYSTEM_VARIABLES_ADMIN"))
6634             .first);
6635   }
6636 
operator ()(THD * thd_to_kill)6637   virtual void operator()(THD *thd_to_kill) {
6638     mysql_mutex_lock(&thd_to_kill->LOCK_thd_data);
6639 
6640     Security_context *sctx = thd_to_kill->security_context();
6641     /* Kill only if non-privileged thread and non slave thread.
6642        If an account has not yet been assigned to the security context of the
6643        thread we cannot tell if the account is super user or not. In this case
6644        we cannot kill that thread. In offline mode, after the account is
6645        assigned to this thread and it turns out it is not privileged user
6646        thread, the authentication for this thread will fail and the thread will
6647        be terminated.
6648     */
6649     if (sctx->has_account_assigned() &&
6650         !(sctx->check_access(SUPER_ACL) ||
6651           sctx->has_global_grant(STRING_WITH_LEN("CONNECTION_ADMIN")).first) &&
6652         thd_to_kill->killed != THD::KILL_CONNECTION &&
6653         !thd_to_kill->slave_thread)
6654       thd_to_kill->awake(THD::KILL_CONNECTION);
6655 
6656     mysql_mutex_unlock(&thd_to_kill->LOCK_thd_data);
6657   }
6658 };
6659 
6660 /*
6661   kills all the threads that do not have the
6662   SUPER privilege.
6663 
6664   SYNOPSIS
6665     killall_non_super_threads()
6666     thd                 Thread class
6667 */
6668 
killall_non_super_threads(THD * thd)6669 void killall_non_super_threads(THD *thd) {
6670   Kill_non_super_conn kill_non_super_conn(thd);
6671   Global_THD_manager *thd_manager = Global_THD_manager::get_instance();
6672   thd_manager->do_for_all_thd(&kill_non_super_conn);
6673 }
6674 
6675 /**
6676   prepares the index and data directory path.
6677 
6678   @param thd                    Thread handle
6679   @param data_file_name         Pathname for data directory
6680   @param index_file_name        Pathname for index directory
6681   @param table_name             Table name to be appended to the pathname
6682   specified
6683 
6684   @return false                 success
6685   @return true                  An error occurred
6686 */
6687 
prepare_index_and_data_dir_path(THD * thd,const char ** data_file_name,const char ** index_file_name,const char * table_name)6688 bool prepare_index_and_data_dir_path(THD *thd, const char **data_file_name,
6689                                      const char **index_file_name,
6690                                      const char *table_name) {
6691   int ret_val;
6692   const char *file_name;
6693   const char *directory_type;
6694 
6695   /*
6696     If a data directory path is passed, check if the path exists and append
6697     table_name to it.
6698   */
6699   if (data_file_name &&
6700       (ret_val = append_file_to_dir(thd, data_file_name, table_name))) {
6701     file_name = *data_file_name;
6702     directory_type = "DATA DIRECTORY";
6703     goto err;
6704   }
6705 
6706   /*
6707     If an index directory path is passed, check if the path exists and append
6708     table_name to it.
6709   */
6710   if (index_file_name &&
6711       (ret_val = append_file_to_dir(thd, index_file_name, table_name))) {
6712     file_name = *index_file_name;
6713     directory_type = "INDEX DIRECTORY";
6714     goto err;
6715   }
6716 
6717   return false;
6718 err:
6719   if (ret_val == ER_PATH_LENGTH)
6720     my_error(ER_PATH_LENGTH, MYF(0), directory_type);
6721   if (ret_val == ER_WRONG_VALUE)
6722     my_error(ER_WRONG_VALUE, MYF(0), "path", file_name);
6723   return true;
6724 }
6725 
6726 /** If pointer is not a null pointer, append filename to it. */
6727 
append_file_to_dir(THD * thd,const char ** filename_ptr,const char * table_name)6728 int append_file_to_dir(THD *thd, const char **filename_ptr,
6729                        const char *table_name) {
6730   char tbbuff[FN_REFLEN];
6731   char buff[FN_REFLEN];
6732   char *ptr;
6733   char *end;
6734 
6735   if (!*filename_ptr) return 0;  // nothing to do
6736 
6737   /* Convert tablename to filename charset so that "/" gets converted
6738   appropriately */
6739   size_t tab_len = tablename_to_filename(table_name, tbbuff, sizeof(tbbuff));
6740 
6741   /* Check that the filename is not too long and it's a hard path */
6742   if (strlen(*filename_ptr) + tab_len >= FN_REFLEN - 1) return ER_PATH_LENGTH;
6743 
6744   if (!test_if_hard_path(*filename_ptr)) return ER_WRONG_VALUE;
6745 
6746   /* Fix is using unix filename format on dos */
6747   my_stpcpy(buff, *filename_ptr);
6748   end = convert_dirname(buff, *filename_ptr, NullS);
6749 
6750   ptr = (char *)thd->alloc((size_t)(end - buff) + tab_len + 1);
6751   if (ptr == nullptr) return ER_OUTOFMEMORY;  // End of memory
6752   *filename_ptr = ptr;
6753   strxmov(ptr, buff, tbbuff, NullS);
6754   return 0;
6755 }
6756 
comp_eq_creator(bool invert)6757 Comp_creator *comp_eq_creator(bool invert) {
6758   return invert ? (Comp_creator *)&ne_creator : (Comp_creator *)&eq_creator;
6759 }
6760 
comp_equal_creator(bool invert MY_ATTRIBUTE ((unused)))6761 Comp_creator *comp_equal_creator(bool invert MY_ATTRIBUTE((unused))) {
6762   DBUG_ASSERT(!invert);  // Function never called with true.
6763   return &equal_creator;
6764 }
6765 
comp_ge_creator(bool invert)6766 Comp_creator *comp_ge_creator(bool invert) {
6767   return invert ? (Comp_creator *)&lt_creator : (Comp_creator *)&ge_creator;
6768 }
6769 
comp_gt_creator(bool invert)6770 Comp_creator *comp_gt_creator(bool invert) {
6771   return invert ? (Comp_creator *)&le_creator : (Comp_creator *)&gt_creator;
6772 }
6773 
comp_le_creator(bool invert)6774 Comp_creator *comp_le_creator(bool invert) {
6775   return invert ? (Comp_creator *)&gt_creator : (Comp_creator *)&le_creator;
6776 }
6777 
comp_lt_creator(bool invert)6778 Comp_creator *comp_lt_creator(bool invert) {
6779   return invert ? (Comp_creator *)&ge_creator : (Comp_creator *)&lt_creator;
6780 }
6781 
comp_ne_creator(bool invert)6782 Comp_creator *comp_ne_creator(bool invert) {
6783   return invert ? (Comp_creator *)&eq_creator : (Comp_creator *)&ne_creator;
6784 }
6785 
6786 /**
6787   Construct ALL/ANY/SOME subquery Item.
6788 
6789   @param left_expr   pointer to left expression
6790   @param cmp         compare function creator
6791   @param all         true if we create ALL subquery
6792   @param select_lex  pointer on parsed subquery structure
6793 
6794   @return
6795     constructed Item (or 0 if out of memory)
6796 */
all_any_subquery_creator(Item * left_expr,chooser_compare_func_creator cmp,bool all,SELECT_LEX * select_lex)6797 Item *all_any_subquery_creator(Item *left_expr,
6798                                chooser_compare_func_creator cmp, bool all,
6799                                SELECT_LEX *select_lex) {
6800   if ((cmp == &comp_eq_creator) && !all)  //  = ANY <=> IN
6801     return new Item_in_subselect(left_expr, select_lex);
6802   if ((cmp == &comp_ne_creator) && all)  // <> ALL <=> NOT IN
6803   {
6804     Item *i = new Item_in_subselect(left_expr, select_lex);
6805     if (i == nullptr) return nullptr;
6806     Item *neg_i = i->truth_transformer(nullptr, Item::BOOL_NEGATED);
6807     if (neg_i != nullptr) return neg_i;
6808     return new Item_func_not(i);
6809   }
6810   Item_allany_subselect *it =
6811       new Item_allany_subselect(left_expr, cmp, select_lex, all);
6812   if (all) return it->upper_item = new Item_func_not_all(it); /* ALL */
6813 
6814   return it->upper_item = new Item_func_nop_all(it); /* ANY/SOME */
6815 }
6816 
6817 /**
6818    Set proper open mode and table type for element representing target table
6819    of CREATE TABLE statement, also adjust statement table list if necessary.
6820 */
6821 
create_table_set_open_action_and_adjust_tables(LEX * lex)6822 void create_table_set_open_action_and_adjust_tables(LEX *lex) {
6823   TABLE_LIST *create_table = lex->query_tables;
6824 
6825   if (lex->create_info->options & HA_LEX_CREATE_TMP_TABLE)
6826     create_table->open_type = OT_TEMPORARY_ONLY;
6827   else
6828     create_table->open_type = OT_BASE_ONLY;
6829 
6830   if (!lex->select_lex->fields_list.elements) {
6831     /*
6832       Avoid opening and locking target table for ordinary CREATE TABLE
6833       or CREATE TABLE LIKE for write (unlike in CREATE ... SELECT we
6834       won't do any insertions in it anyway). Not doing this causes
6835       problems when running CREATE TABLE IF NOT EXISTS for already
6836       existing log table.
6837     */
6838     create_table->set_lock({TL_READ, THR_DEFAULT});
6839   }
6840 }
6841 
6842 /**
6843   Set the specified definer to the default value, which is the
6844   current user in the thread.
6845 
6846   @param[in]  thd       thread handler
6847   @param[out] definer   definer
6848 */
6849 
get_default_definer(THD * thd,LEX_USER * definer)6850 void get_default_definer(THD *thd, LEX_USER *definer) {
6851   const Security_context *sctx = thd->security_context();
6852 
6853   definer->user.str = sctx->priv_user().str;
6854   definer->user.length = strlen(definer->user.str);
6855 
6856   definer->host.str = sctx->priv_host().str;
6857   definer->host.length = strlen(definer->host.str);
6858 
6859   definer->plugin = EMPTY_CSTR;
6860   definer->auth = NULL_CSTR;
6861   definer->current_auth = NULL_CSTR;
6862   definer->uses_identified_with_clause = false;
6863   definer->uses_identified_by_clause = false;
6864   definer->uses_authentication_string_clause = false;
6865   definer->uses_replace_clause = false;
6866   definer->retain_current_password = false;
6867   definer->discard_old_password = false;
6868   definer->alter_status.update_password_expired_column = false;
6869   definer->alter_status.use_default_password_lifetime = true;
6870   definer->alter_status.expire_after_days = 0;
6871   definer->alter_status.update_account_locked_column = false;
6872   definer->alter_status.account_locked = false;
6873   definer->alter_status.update_password_require_current =
6874       Lex_acl_attrib_udyn::DEFAULT;
6875   definer->has_password_generator = false;
6876   definer->alter_status.failed_login_attempts = 0;
6877   definer->alter_status.password_lock_time = 0;
6878   definer->alter_status.update_failed_login_attempts = false;
6879   definer->alter_status.update_password_lock_time = false;
6880 }
6881 
6882 /**
6883   Create default definer for the specified THD.
6884 
6885   @param[in] thd         thread handler
6886 
6887   @return
6888     - On success, return a valid pointer to the created and initialized
6889     LEX_USER, which contains definer information.
6890     - On error, return 0.
6891 */
6892 
create_default_definer(THD * thd)6893 LEX_USER *create_default_definer(THD *thd) {
6894   LEX_USER *definer;
6895 
6896   if (!(definer = (LEX_USER *)thd->alloc(sizeof(LEX_USER)))) return nullptr;
6897 
6898   thd->get_definer(definer);
6899 
6900   return definer;
6901 }
6902 
6903 /**
6904   Retuns information about user or current user.
6905 
6906   @param[in] thd          thread handler
6907   @param[in] user         user
6908 
6909   @return
6910     - On success, return a valid pointer to initialized
6911     LEX_USER, which contains user information.
6912     - On error, return 0.
6913 */
6914 
get_current_user(THD * thd,LEX_USER * user)6915 LEX_USER *get_current_user(THD *thd, LEX_USER *user) {
6916   if (!user || !user->user.str)  // current_user
6917   {
6918     LEX_USER *default_definer = create_default_definer(thd);
6919     if (default_definer) {
6920       /*
6921         Inherit parser semantics from the statement in which the user parameter
6922         was used.
6923         This is needed because a LEX_USER is both used as a component in an
6924         AST and as a specifier for a particular user in the ACL subsystem.
6925       */
6926       default_definer->uses_authentication_string_clause =
6927           user->uses_authentication_string_clause;
6928       default_definer->uses_identified_by_clause =
6929           user->uses_identified_by_clause;
6930       default_definer->uses_identified_with_clause =
6931           user->uses_identified_with_clause;
6932       default_definer->uses_replace_clause = user->uses_replace_clause;
6933       default_definer->current_auth.str = user->current_auth.str;
6934       default_definer->current_auth.length = user->current_auth.length;
6935       default_definer->retain_current_password = user->retain_current_password;
6936       default_definer->discard_old_password = user->discard_old_password;
6937       default_definer->plugin.str = user->plugin.str;
6938       default_definer->plugin.length = user->plugin.length;
6939       default_definer->auth.str = user->auth.str;
6940       default_definer->auth.length = user->auth.length;
6941       default_definer->alter_status = user->alter_status;
6942       default_definer->has_password_generator = user->has_password_generator;
6943       return default_definer;
6944     }
6945   }
6946 
6947   return user;
6948 }
6949 
6950 /**
6951   Check that byte length of a string does not exceed some limit.
6952 
6953   @param str         string to be checked
6954   @param err_msg     error message to be displayed if the string is too long
6955   @param max_byte_length  max length
6956 
6957   @retval
6958     false   the passed string is not longer than max_length
6959   @retval
6960     true    the passed string is longer than max_length
6961 
6962   NOTE
6963     The function is not used in existing code but can be useful later?
6964 */
6965 
check_string_byte_length(const LEX_CSTRING & str,const char * err_msg,size_t max_byte_length)6966 static bool check_string_byte_length(const LEX_CSTRING &str,
6967                                      const char *err_msg,
6968                                      size_t max_byte_length) {
6969   if (str.length <= max_byte_length) return false;
6970 
6971   my_error(ER_WRONG_STRING_LENGTH, MYF(0), str.str, err_msg, max_byte_length);
6972 
6973   return true;
6974 }
6975 
6976 /*
6977   Check that char length of a string does not exceed some limit.
6978 
6979   SYNOPSIS
6980   check_string_char_length()
6981       str              string to be checked
6982       err_msg          error message to be displayed if the string is too long
6983       max_char_length  max length in symbols
6984       cs               string charset
6985 
6986   RETURN
6987     false   the passed string is not longer than max_char_length
6988     true    the passed string is longer than max_char_length
6989 */
6990 
check_string_char_length(const LEX_CSTRING & str,const char * err_msg,size_t max_char_length,const CHARSET_INFO * cs,bool no_error)6991 bool check_string_char_length(const LEX_CSTRING &str, const char *err_msg,
6992                               size_t max_char_length, const CHARSET_INFO *cs,
6993                               bool no_error) {
6994   int well_formed_error;
6995   size_t res = cs->cset->well_formed_len(cs, str.str, str.str + str.length,
6996                                          max_char_length, &well_formed_error);
6997 
6998   if (!well_formed_error && str.length == res) return false;
6999 
7000   if (!no_error) {
7001     ErrConvString err(str.str, str.length, cs);
7002     my_error(ER_WRONG_STRING_LENGTH, MYF(0), err.ptr(), err_msg,
7003              max_char_length);
7004   }
7005   return true;
7006 }
7007 
7008 /*
7009   Check if path does not contain mysql data home directory
7010   SYNOPSIS
7011     test_if_data_home_dir()
7012     dir                     directory
7013     conv_home_dir           converted data home directory
7014     home_dir_len            converted data home directory length
7015 
7016   RETURN VALUES
7017     0	ok
7018     1	error
7019 */
test_if_data_home_dir(const char * dir)7020 int test_if_data_home_dir(const char *dir) {
7021   char path[FN_REFLEN];
7022   size_t dir_len;
7023   DBUG_TRACE;
7024 
7025   if (!dir) return 0;
7026 
7027   (void)fn_format(path, dir, "", "",
7028                   (MY_RETURN_REAL_PATH | MY_RESOLVE_SYMLINKS));
7029   dir_len = strlen(path);
7030   if (mysql_unpacked_real_data_home_len <= dir_len) {
7031     if (dir_len > mysql_unpacked_real_data_home_len &&
7032         path[mysql_unpacked_real_data_home_len] != FN_LIBCHAR)
7033       return 0;
7034 
7035     if (lower_case_file_system) {
7036       if (!my_strnncoll(default_charset_info, (const uchar *)path,
7037                         mysql_unpacked_real_data_home_len,
7038                         (const uchar *)mysql_unpacked_real_data_home,
7039                         mysql_unpacked_real_data_home_len))
7040         return 1;
7041     } else if (!memcmp(path, mysql_unpacked_real_data_home,
7042                        mysql_unpacked_real_data_home_len))
7043       return 1;
7044   }
7045   return 0;
7046 }
7047 
7048 /**
7049   Check that host name string is valid.
7050 
7051   @param[in] str string to be checked
7052 
7053   @return             Operation status
7054     @retval  false    host name is ok
7055     @retval  true     host name string is longer than max_length or
7056                       has invalid symbols
7057 */
7058 
check_host_name(const LEX_CSTRING & str)7059 bool check_host_name(const LEX_CSTRING &str) {
7060   const char *name = str.str;
7061   const char *end = str.str + str.length;
7062   if (check_string_byte_length(str, ER_THD(current_thd, ER_HOSTNAME),
7063                                HOSTNAME_LENGTH))
7064     return true;
7065 
7066   while (name != end) {
7067     if (*name == '@') {
7068       my_printf_error(ER_UNKNOWN_ERROR,
7069                       "Malformed hostname (illegal symbol: '%c')", MYF(0),
7070                       *name);
7071       return true;
7072     }
7073     name++;
7074   }
7075   return false;
7076 }
7077 
7078 class Parser_oom_handler : public Internal_error_handler {
7079  public:
Parser_oom_handler()7080   Parser_oom_handler() : m_has_errors(false), m_is_mem_error(false) {}
handle_condition(THD * thd,uint sql_errno,const char *,Sql_condition::enum_severity_level * level,const char *)7081   virtual bool handle_condition(THD *thd, uint sql_errno, const char *,
7082                                 Sql_condition::enum_severity_level *level,
7083                                 const char *) {
7084     if (*level == Sql_condition::SL_ERROR) {
7085       m_has_errors = true;
7086       /* Out of memory error is reported only once. Return as handled */
7087       if (m_is_mem_error &&
7088           (sql_errno == EE_CAPACITY_EXCEEDED || sql_errno == EE_OUTOFMEMORY))
7089         return true;
7090       if (sql_errno == EE_CAPACITY_EXCEEDED || sql_errno == EE_OUTOFMEMORY) {
7091         m_is_mem_error = true;
7092         if (sql_errno == EE_CAPACITY_EXCEEDED)
7093           my_error(ER_CAPACITY_EXCEEDED, MYF(0),
7094                    static_cast<ulonglong>(thd->variables.parser_max_mem_size),
7095                    "parser_max_mem_size",
7096                    ER_THD(thd, ER_CAPACITY_EXCEEDED_IN_PARSER));
7097         else
7098           my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
7099         return true;
7100       }
7101     }
7102     return false;
7103   }
7104 
7105  private:
7106   bool m_has_errors;
7107   bool m_is_mem_error;
7108 };
7109 
7110 /**
7111   Transform an SQL statement into an AST that is ready for resolving, using the
7112   supplied parser state and object creation context.
7113 
7114   This is a wrapper() for THD::sql_parser() and should generally be used for AST
7115   construction.
7116 
7117   The function may optionally generate a query digest, invoke this function as
7118   follows:
7119 
7120 
7121   @verbatim
7122     THD *thd = ...;
7123     const char *query_text = ...;
7124     uint query_length = ...;
7125     Object_creation_ctx *ctx = ...;
7126     bool rc;
7127 
7128     Parser_state parser_state;
7129     if (parser_state.init(thd, query_text, query_length)
7130     {
7131       ... handle error
7132     }
7133 
7134     parser_state.m_input.m_compute_digest= true;
7135 
7136     rc= parse_sql(the, &parser_state, ctx);
7137     if (! rc)
7138     {
7139       unsigned char md5[MD5_HASH_SIZE];
7140       char digest_text[1024];
7141       bool truncated;
7142       const sql_digest_storage *digest= & thd->m_digest->m_digest_storage;
7143 
7144       compute_digest_md5(digest, & md5[0]);
7145       compute_digest_text(digest, & digest_text[0], sizeof(digest_text), &
7146   truncated);
7147     }
7148   @endverbatim
7149 
7150   @param thd Thread context.
7151   @param parser_state Parser state.
7152   @param creation_ctx Object creation context.
7153 
7154   @return Error status.
7155     @retval false on success.
7156     @retval true on parsing error.
7157 */
7158 
parse_sql(THD * thd,Parser_state * parser_state,Object_creation_ctx * creation_ctx)7159 bool parse_sql(THD *thd, Parser_state *parser_state,
7160                Object_creation_ctx *creation_ctx) {
7161   DBUG_TRACE;
7162   bool ret_value;
7163   DBUG_ASSERT(thd->m_parser_state == nullptr);
7164   // TODO fix to allow parsing gcol exprs after main query.
7165   //  DBUG_ASSERT(thd->lex->m_sql_cmd == NULL);
7166 
7167   /* Backup creation context. */
7168 
7169   Object_creation_ctx *backup_ctx = nullptr;
7170 
7171   if (creation_ctx) backup_ctx = creation_ctx->set_n_backup(thd);
7172 
7173   /* Set parser state. */
7174 
7175   thd->m_parser_state = parser_state;
7176 
7177   parser_state->m_digest_psi = nullptr;
7178   parser_state->m_lip.m_digest = nullptr;
7179 
7180   if (thd->m_digest != nullptr) {
7181     /* Start Digest */
7182     parser_state->m_digest_psi = MYSQL_DIGEST_START(thd->m_statement_psi);
7183 
7184     if (parser_state->m_input.m_compute_digest ||
7185         (parser_state->m_digest_psi != nullptr)) {
7186       /*
7187         If either:
7188         - the caller wants to compute a digest
7189         - the performance schema wants to compute a digest
7190         set the digest listener in the lexer.
7191       */
7192       parser_state->m_lip.m_digest = thd->m_digest;
7193       parser_state->m_lip.m_digest->m_digest_storage.m_charset_number =
7194           thd->charset()->number;
7195     }
7196   }
7197 
7198   /* Parse the query. */
7199 
7200   /*
7201     Use a temporary DA while parsing. We don't know until after parsing
7202     whether the current command is a diagnostic statement, in which case
7203     we'll need to have the previous DA around to answer questions about it.
7204   */
7205   Diagnostics_area *parser_da = thd->get_parser_da();
7206   Diagnostics_area *da = thd->get_stmt_da();
7207 
7208   Parser_oom_handler poomh;
7209   // Note that we may be called recursively here, on INFORMATION_SCHEMA queries.
7210 
7211   thd->mem_root->set_max_capacity(thd->variables.parser_max_mem_size);
7212   thd->mem_root->set_error_for_capacity_exceeded(true);
7213   thd->push_internal_handler(&poomh);
7214 
7215   thd->push_diagnostics_area(parser_da, false);
7216 
7217   bool mysql_parse_status = thd->sql_parser();
7218 
7219   thd->pop_internal_handler();
7220   thd->mem_root->set_max_capacity(0);
7221   thd->mem_root->set_error_for_capacity_exceeded(false);
7222   /*
7223     Unwind diagnostics area.
7224 
7225     If any issues occurred during parsing, they will become
7226     the sole conditions for the current statement.
7227 
7228     Otherwise, if we have a diagnostic statement on our hands,
7229     we'll preserve the previous diagnostics area here so we
7230     can answer questions about it.  This specifically means
7231     that repeatedly asking about a DA won't clear it.
7232 
7233     Otherwise, it's a regular command with no issues during
7234     parsing, so we'll just clear the DA in preparation for
7235     the processing of this command.
7236   */
7237 
7238   if (parser_da->current_statement_cond_count() != 0) {
7239     /*
7240       Error/warning during parsing: top DA should contain parse error(s)!  Any
7241       pre-existing conditions will be replaced. The exception is diagnostics
7242       statements, in which case we wish to keep the errors so they can be sent
7243       to the client.
7244     */
7245     if (thd->lex->sql_command != SQLCOM_SHOW_WARNS &&
7246         thd->lex->sql_command != SQLCOM_GET_DIAGNOSTICS)
7247       da->reset_condition_info(thd);
7248 
7249     /*
7250       We need to put any errors in the DA as well as the condition list.
7251     */
7252     if (parser_da->is_error() && !da->is_error()) {
7253       da->set_error_status(parser_da->mysql_errno(), parser_da->message_text(),
7254                            parser_da->returned_sqlstate());
7255     }
7256 
7257     da->copy_sql_conditions_from_da(thd, parser_da);
7258 
7259     parser_da->reset_diagnostics_area();
7260     parser_da->reset_condition_info(thd);
7261 
7262     /*
7263       Do not clear the condition list when starting execution as it
7264       now contains not the results of the previous executions, but
7265       a non-zero number of errors/warnings thrown during parsing!
7266     */
7267     thd->lex->keep_diagnostics = DA_KEEP_PARSE_ERROR;
7268   }
7269 
7270   thd->pop_diagnostics_area();
7271 
7272   /*
7273     Check that if THD::sql_parser() failed either thd->is_error() is set, or an
7274     internal error handler is set.
7275 
7276     The assert will not catch a situation where parsing fails without an
7277     error reported if an error handler exists. The problem is that the
7278     error handler might have intercepted the error, so thd->is_error() is
7279     not set. However, there is no way to be 100% sure here (the error
7280     handler might be for other errors than parsing one).
7281   */
7282 
7283   DBUG_ASSERT(!mysql_parse_status || (mysql_parse_status && thd->is_error()) ||
7284               (mysql_parse_status && thd->get_internal_handler()));
7285 
7286   /* Reset parser state. */
7287 
7288   thd->m_parser_state = nullptr;
7289 
7290   /* Restore creation context. */
7291 
7292   if (creation_ctx) creation_ctx->restore_env(thd, backup_ctx);
7293 
7294   /* That's it. */
7295 
7296   ret_value = mysql_parse_status || thd->is_fatal_error();
7297 
7298   if ((ret_value == 0) && (parser_state->m_digest_psi != nullptr)) {
7299     /*
7300       On parsing success, record the digest in the performance schema.
7301     */
7302     DBUG_ASSERT(thd->m_digest != nullptr);
7303     MYSQL_DIGEST_END(parser_state->m_digest_psi,
7304                      &thd->m_digest->m_digest_storage);
7305   }
7306 
7307   return ret_value;
7308 }
7309 
7310 /**
7311   @} (end of group Runtime_Environment)
7312 */
7313 
7314 /**
7315   Check and merge "[ CHARACTER SET charset ] [ COLLATE collation ]" clause
7316 
7317   @param [in]  charset    Character set pointer or NULL.
7318   @param [in]  collation  Collation pointer or NULL.
7319   @param [out] to         Resulting character set/collation/NULL on success,
7320                           untouched on failure.
7321 
7322   Check if collation "collation" is applicable to character set "charset".
7323 
7324   If "collation" is NULL (e.g. when COLLATE clause is not specified),
7325   then simply "charset" is returned in "to".
7326   And vice versa, if "charset" is NULL, "collation" is returned in "to".
7327 
7328   @returns false on success,
7329    otherwise returns true and pushes an error message on the error stack
7330 */
7331 
merge_charset_and_collation(const CHARSET_INFO * charset,const CHARSET_INFO * collation,const CHARSET_INFO ** to)7332 bool merge_charset_and_collation(const CHARSET_INFO *charset,
7333                                  const CHARSET_INFO *collation,
7334                                  const CHARSET_INFO **to) {
7335   if (charset != nullptr && collation != nullptr &&
7336       !my_charset_same(charset, collation)) {
7337     my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), collation->name,
7338              charset->csname);
7339     return true;
7340   }
7341 
7342   *to = collation != nullptr ? collation : charset;
7343   return false;
7344 }
7345 
merge_sp_var_charset_and_collation(const CHARSET_INFO * charset,const CHARSET_INFO * collation,const CHARSET_INFO ** to)7346 bool merge_sp_var_charset_and_collation(const CHARSET_INFO *charset,
7347                                         const CHARSET_INFO *collation,
7348                                         const CHARSET_INFO **to) {
7349   if (charset == nullptr && collation != nullptr) {
7350     my_error(
7351         ER_NOT_SUPPORTED_YET, MYF(0),
7352         "COLLATE with no CHARACTER SET in SP parameters, RETURNS, DECLARE");
7353     return true;
7354   }
7355   return merge_charset_and_collation(charset, collation, to);
7356 }
7357