| 1 | /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. |
| 2 | Copyright (c) 2008, 2018, MariaDB |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or modify |
| 5 | it under the terms of the GNU General Public License as published by |
| 6 | the Free Software Foundation; version 2 of the License. |
| 7 | |
| 8 | This program is distributed in the hope that it will be useful, |
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | GNU General Public License for more details. |
| 12 | |
| 13 | You should have received a copy of the GNU General Public License |
| 14 | along with this program; if not, write to the Free Software |
| 15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
| 16 | |
| 17 | #define MYSQL_LEX 1 |
| 18 | #include "mariadb.h" |
| 19 | #include "sql_priv.h" |
| 20 | #include "sql_parse.h" // sql_kill, *_precheck, *_prepare |
| 21 | #include "lock.h" // try_transactional_lock, |
| 22 | // check_transactional_lock, |
| 23 | // set_handler_table_locks, |
| 24 | // lock_global_read_lock, |
| 25 | // make_global_read_lock_block_commit |
| 26 | #include "sql_base.h" // open_tables, open_and_lock_tables, |
| 27 | // lock_tables, unique_table, |
| 28 | // close_thread_tables, is_temporary_table |
| 29 | // table_cache.h |
| 30 | #include "sql_cache.h" // QUERY_CACHE_FLAGS_SIZE, query_cache_* |
| 31 | #include "sql_show.h" // mysqld_list_*, mysqld_show_*, |
| 32 | // calc_sum_of_all_status |
| 33 | #include "mysqld.h" |
| 34 | #include "sql_locale.h" // my_locale_en_US |
| 35 | #include "log.h" // flush_error_log |
| 36 | #include "sql_view.h" // mysql_create_view, mysql_drop_view |
| 37 | #include "sql_delete.h" // mysql_delete |
| 38 | #include "sql_insert.h" // mysql_insert |
| 39 | #include "sql_update.h" // mysql_update, mysql_multi_update |
| 40 | #include "sql_partition.h" // struct partition_info |
| 41 | #include "sql_db.h" // mysql_change_db, mysql_create_db, |
| 42 | // mysql_rm_db, mysql_upgrade_db, |
| 43 | // mysql_alter_db, |
| 44 | // check_db_dir_existence, |
| 45 | // my_dbopt_cleanup |
| 46 | #include "sql_table.h" // mysql_create_like_table, |
| 47 | // mysql_create_table, |
| 48 | // mysql_alter_table, |
| 49 | // mysql_backup_table, |
| 50 | // mysql_restore_table |
| 51 | #include "sql_reload.h" // reload_acl_and_cache |
| 52 | #include "sql_admin.h" // mysql_assign_to_keycache |
| 53 | #include "sql_connect.h" // decrease_user_connections, |
| 54 | // check_mqh, |
| 55 | // reset_mqh |
| 56 | #include "sql_rename.h" // mysql_rename_tables |
| 57 | #include "sql_tablespace.h" // mysql_alter_tablespace |
| 58 | #include "hostname.h" // hostname_cache_refresh |
| 59 | #include "sql_acl.h" // *_ACL, check_grant, is_acl_user, |
| 60 | // has_any_table_level_privileges, |
| 61 | // mysql_drop_user, mysql_rename_user, |
| 62 | // check_grant_routine, |
| 63 | // mysql_routine_grant, |
| 64 | // mysql_show_grants, |
| 65 | // sp_grant_privileges, ... |
| 66 | #include "sql_test.h" // mysql_print_status |
| 67 | #include "sql_select.h" // handle_select, mysql_select, |
| 68 | // mysql_explain_union |
| 69 | #include "sql_load.h" // mysql_load |
| 70 | #include "sql_servers.h" // create_servers, alter_servers, |
| 71 | // drop_servers, servers_reload |
| 72 | #include "sql_handler.h" // mysql_ha_open, mysql_ha_close, |
| 73 | // mysql_ha_read |
| 74 | #include "sql_binlog.h" // mysql_client_binlog_statement |
| 75 | #include "sql_do.h" // mysql_do |
| 76 | #include "sql_help.h" // mysqld_help |
| 77 | #include "rpl_constants.h" // Incident, INCIDENT_LOST_EVENTS |
| 78 | #include "log_event.h" |
| 79 | #include "sql_repl.h" |
| 80 | #include "rpl_filter.h" |
| 81 | #include "repl_failsafe.h" |
| 82 | #include <m_ctype.h> |
| 83 | #include <myisam.h> |
| 84 | #include <my_dir.h> |
| 85 | #include "rpl_mi.h" |
| 86 | |
| 87 | #include "sql_digest.h" |
| 88 | |
| 89 | #include "sp_head.h" |
| 90 | #include "sp.h" |
| 91 | #include "sp_cache.h" |
| 92 | #include "events.h" |
| 93 | #include "sql_trigger.h" |
| 94 | #include "transaction.h" |
| 95 | #include "sql_audit.h" |
| 96 | #include "sql_prepare.h" |
| 97 | #include "sql_cte.h" |
| 98 | #include "debug_sync.h" |
| 99 | #include "probes_mysql.h" |
| 100 | #include "set_var.h" |
| 101 | #include "sql_bootstrap.h" |
| 102 | #include "sql_sequence.h" |
| 103 | |
| 104 | #include "my_json_writer.h" |
| 105 | |
| 106 | #define FLAGSTR(V,F) ((V)&(F)?#F" ":"") |
| 107 | |
| 108 | #ifdef WITH_ARIA_STORAGE_ENGINE |
| 109 | #include "../storage/maria/ha_maria.h" |
| 110 | #endif |
| 111 | |
| 112 | #include "wsrep_mysqld.h" |
| 113 | #include "wsrep_thd.h" |
| 114 | |
| 115 | static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, |
| 116 | Parser_state *parser_state, |
| 117 | bool is_com_multi, |
| 118 | bool is_next_command); |
| 119 | |
| 120 | /** |
| 121 | @defgroup Runtime_Environment Runtime Environment |
| 122 | @{ |
| 123 | */ |
| 124 | |
| 125 | static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); |
| 126 | static void sql_kill(THD *thd, longlong id, killed_state state, killed_type type); |
| 127 | static void sql_kill_user(THD *thd, LEX_USER *user, killed_state state); |
| 128 | static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables); |
| 129 | static bool execute_show_status(THD *, TABLE_LIST *); |
| 130 | static bool check_rename_table(THD *, TABLE_LIST *, TABLE_LIST *); |
| 131 | |
| 132 | const char *any_db="*any*" ; // Special symbol for check_access |
| 133 | |
| 134 | const LEX_CSTRING command_name[257]={ |
| 135 | { STRING_WITH_LEN("Sleep" ) }, //0 |
| 136 | { STRING_WITH_LEN("Quit" ) }, //1 |
| 137 | { STRING_WITH_LEN("Init DB" ) }, //2 |
| 138 | { STRING_WITH_LEN("Query" ) }, //3 |
| 139 | { STRING_WITH_LEN("Field List" ) }, //4 |
| 140 | { STRING_WITH_LEN("Create DB" ) }, //5 |
| 141 | { STRING_WITH_LEN("Drop DB" ) }, //6 |
| 142 | { STRING_WITH_LEN("Refresh" ) }, //7 |
| 143 | { STRING_WITH_LEN("Shutdown" ) }, //8 |
| 144 | { STRING_WITH_LEN("Statistics" ) }, //9 |
| 145 | { STRING_WITH_LEN("Processlist" ) }, //10 |
| 146 | { STRING_WITH_LEN("Connect" ) }, //11 |
| 147 | { STRING_WITH_LEN("Kill" ) }, //12 |
| 148 | { STRING_WITH_LEN("Debug" ) }, //13 |
| 149 | { STRING_WITH_LEN("Ping" ) }, //14 |
| 150 | { STRING_WITH_LEN("Time" ) }, //15 |
| 151 | { STRING_WITH_LEN("Delayed insert" ) }, //16 |
| 152 | { STRING_WITH_LEN("Change user" ) }, //17 |
| 153 | { STRING_WITH_LEN("Binlog Dump" ) }, //18 |
| 154 | { STRING_WITH_LEN("Table Dump" ) }, //19 |
| 155 | { STRING_WITH_LEN("Connect Out" ) }, //20 |
| 156 | { STRING_WITH_LEN("Register Slave" ) }, //21 |
| 157 | { STRING_WITH_LEN("Prepare" ) }, //22 |
| 158 | { STRING_WITH_LEN("Execute" ) }, //23 |
| 159 | { STRING_WITH_LEN("Long Data" ) }, //24 |
| 160 | { STRING_WITH_LEN("Close stmt" ) }, //25 |
| 161 | { STRING_WITH_LEN("Reset stmt" ) }, //26 |
| 162 | { STRING_WITH_LEN("Set option" ) }, //27 |
| 163 | { STRING_WITH_LEN("Fetch" ) }, //28 |
| 164 | { STRING_WITH_LEN("Daemon" ) }, //29 |
| 165 | { STRING_WITH_LEN("Unimpl get tid" ) }, //30 |
| 166 | { STRING_WITH_LEN("Reset connection" ) },//31 |
| 167 | { 0, 0 }, //32 |
| 168 | { 0, 0 }, //33 |
| 169 | { 0, 0 }, //34 |
| 170 | { 0, 0 }, //35 |
| 171 | { 0, 0 }, //36 |
| 172 | { 0, 0 }, //37 |
| 173 | { 0, 0 }, //38 |
| 174 | { 0, 0 }, //39 |
| 175 | { 0, 0 }, //40 |
| 176 | { 0, 0 }, //41 |
| 177 | { 0, 0 }, //42 |
| 178 | { 0, 0 }, //43 |
| 179 | { 0, 0 }, //44 |
| 180 | { 0, 0 }, //45 |
| 181 | { 0, 0 }, //46 |
| 182 | { 0, 0 }, //47 |
| 183 | { 0, 0 }, //48 |
| 184 | { 0, 0 }, //49 |
| 185 | { 0, 0 }, //50 |
| 186 | { 0, 0 }, //51 |
| 187 | { 0, 0 }, //52 |
| 188 | { 0, 0 }, //53 |
| 189 | { 0, 0 }, //54 |
| 190 | { 0, 0 }, //55 |
| 191 | { 0, 0 }, //56 |
| 192 | { 0, 0 }, //57 |
| 193 | { 0, 0 }, //58 |
| 194 | { 0, 0 }, //59 |
| 195 | { 0, 0 }, //60 |
| 196 | { 0, 0 }, //61 |
| 197 | { 0, 0 }, //62 |
| 198 | { 0, 0 }, //63 |
| 199 | { 0, 0 }, //64 |
| 200 | { 0, 0 }, //65 |
| 201 | { 0, 0 }, //66 |
| 202 | { 0, 0 }, //67 |
| 203 | { 0, 0 }, //68 |
| 204 | { 0, 0 }, //69 |
| 205 | { 0, 0 }, //70 |
| 206 | { 0, 0 }, //71 |
| 207 | { 0, 0 }, //72 |
| 208 | { 0, 0 }, //73 |
| 209 | { 0, 0 }, //74 |
| 210 | { 0, 0 }, //75 |
| 211 | { 0, 0 }, //76 |
| 212 | { 0, 0 }, //77 |
| 213 | { 0, 0 }, //78 |
| 214 | { 0, 0 }, //79 |
| 215 | { 0, 0 }, //80 |
| 216 | { 0, 0 }, //81 |
| 217 | { 0, 0 }, //82 |
| 218 | { 0, 0 }, //83 |
| 219 | { 0, 0 }, //84 |
| 220 | { 0, 0 }, //85 |
| 221 | { 0, 0 }, //86 |
| 222 | { 0, 0 }, //87 |
| 223 | { 0, 0 }, //88 |
| 224 | { 0, 0 }, //89 |
| 225 | { 0, 0 }, //90 |
| 226 | { 0, 0 }, //91 |
| 227 | { 0, 0 }, //92 |
| 228 | { 0, 0 }, //93 |
| 229 | { 0, 0 }, //94 |
| 230 | { 0, 0 }, //95 |
| 231 | { 0, 0 }, //96 |
| 232 | { 0, 0 }, //97 |
| 233 | { 0, 0 }, //98 |
| 234 | { 0, 0 }, //99 |
| 235 | { 0, 0 }, //100 |
| 236 | { 0, 0 }, //101 |
| 237 | { 0, 0 }, //102 |
| 238 | { 0, 0 }, //103 |
| 239 | { 0, 0 }, //104 |
| 240 | { 0, 0 }, //105 |
| 241 | { 0, 0 }, //106 |
| 242 | { 0, 0 }, //107 |
| 243 | { 0, 0 }, //108 |
| 244 | { 0, 0 }, //109 |
| 245 | { 0, 0 }, //110 |
| 246 | { 0, 0 }, //111 |
| 247 | { 0, 0 }, //112 |
| 248 | { 0, 0 }, //113 |
| 249 | { 0, 0 }, //114 |
| 250 | { 0, 0 }, //115 |
| 251 | { 0, 0 }, //116 |
| 252 | { 0, 0 }, //117 |
| 253 | { 0, 0 }, //118 |
| 254 | { 0, 0 }, //119 |
| 255 | { 0, 0 }, //120 |
| 256 | { 0, 0 }, //121 |
| 257 | { 0, 0 }, //122 |
| 258 | { 0, 0 }, //123 |
| 259 | { 0, 0 }, //124 |
| 260 | { 0, 0 }, //125 |
| 261 | { 0, 0 }, //126 |
| 262 | { 0, 0 }, //127 |
| 263 | { 0, 0 }, //128 |
| 264 | { 0, 0 }, //129 |
| 265 | { 0, 0 }, //130 |
| 266 | { 0, 0 }, //131 |
| 267 | { 0, 0 }, //132 |
| 268 | { 0, 0 }, //133 |
| 269 | { 0, 0 }, //134 |
| 270 | { 0, 0 }, //135 |
| 271 | { 0, 0 }, //136 |
| 272 | { 0, 0 }, //137 |
| 273 | { 0, 0 }, //138 |
| 274 | { 0, 0 }, //139 |
| 275 | { 0, 0 }, //140 |
| 276 | { 0, 0 }, //141 |
| 277 | { 0, 0 }, //142 |
| 278 | { 0, 0 }, //143 |
| 279 | { 0, 0 }, //144 |
| 280 | { 0, 0 }, //145 |
| 281 | { 0, 0 }, //146 |
| 282 | { 0, 0 }, //147 |
| 283 | { 0, 0 }, //148 |
| 284 | { 0, 0 }, //149 |
| 285 | { 0, 0 }, //150 |
| 286 | { 0, 0 }, //151 |
| 287 | { 0, 0 }, //152 |
| 288 | { 0, 0 }, //153 |
| 289 | { 0, 0 }, //154 |
| 290 | { 0, 0 }, //155 |
| 291 | { 0, 0 }, //156 |
| 292 | { 0, 0 }, //157 |
| 293 | { 0, 0 }, //158 |
| 294 | { 0, 0 }, //159 |
| 295 | { 0, 0 }, //160 |
| 296 | { 0, 0 }, //161 |
| 297 | { 0, 0 }, //162 |
| 298 | { 0, 0 }, //163 |
| 299 | { 0, 0 }, //164 |
| 300 | { 0, 0 }, //165 |
| 301 | { 0, 0 }, //166 |
| 302 | { 0, 0 }, //167 |
| 303 | { 0, 0 }, //168 |
| 304 | { 0, 0 }, //169 |
| 305 | { 0, 0 }, //170 |
| 306 | { 0, 0 }, //171 |
| 307 | { 0, 0 }, //172 |
| 308 | { 0, 0 }, //173 |
| 309 | { 0, 0 }, //174 |
| 310 | { 0, 0 }, //175 |
| 311 | { 0, 0 }, //176 |
| 312 | { 0, 0 }, //177 |
| 313 | { 0, 0 }, //178 |
| 314 | { 0, 0 }, //179 |
| 315 | { 0, 0 }, //180 |
| 316 | { 0, 0 }, //181 |
| 317 | { 0, 0 }, //182 |
| 318 | { 0, 0 }, //183 |
| 319 | { 0, 0 }, //184 |
| 320 | { 0, 0 }, //185 |
| 321 | { 0, 0 }, //186 |
| 322 | { 0, 0 }, //187 |
| 323 | { 0, 0 }, //188 |
| 324 | { 0, 0 }, //189 |
| 325 | { 0, 0 }, //190 |
| 326 | { 0, 0 }, //191 |
| 327 | { 0, 0 }, //192 |
| 328 | { 0, 0 }, //193 |
| 329 | { 0, 0 }, //194 |
| 330 | { 0, 0 }, //195 |
| 331 | { 0, 0 }, //196 |
| 332 | { 0, 0 }, //197 |
| 333 | { 0, 0 }, //198 |
| 334 | { 0, 0 }, //199 |
| 335 | { 0, 0 }, //200 |
| 336 | { 0, 0 }, //201 |
| 337 | { 0, 0 }, //202 |
| 338 | { 0, 0 }, //203 |
| 339 | { 0, 0 }, //204 |
| 340 | { 0, 0 }, //205 |
| 341 | { 0, 0 }, //206 |
| 342 | { 0, 0 }, //207 |
| 343 | { 0, 0 }, //208 |
| 344 | { 0, 0 }, //209 |
| 345 | { 0, 0 }, //210 |
| 346 | { 0, 0 }, //211 |
| 347 | { 0, 0 }, //212 |
| 348 | { 0, 0 }, //213 |
| 349 | { 0, 0 }, //214 |
| 350 | { 0, 0 }, //215 |
| 351 | { 0, 0 }, //216 |
| 352 | { 0, 0 }, //217 |
| 353 | { 0, 0 }, //218 |
| 354 | { 0, 0 }, //219 |
| 355 | { 0, 0 }, //220 |
| 356 | { 0, 0 }, //221 |
| 357 | { 0, 0 }, //222 |
| 358 | { 0, 0 }, //223 |
| 359 | { 0, 0 }, //224 |
| 360 | { 0, 0 }, //225 |
| 361 | { 0, 0 }, //226 |
| 362 | { 0, 0 }, //227 |
| 363 | { 0, 0 }, //228 |
| 364 | { 0, 0 }, //229 |
| 365 | { 0, 0 }, //230 |
| 366 | { 0, 0 }, //231 |
| 367 | { 0, 0 }, //232 |
| 368 | { 0, 0 }, //233 |
| 369 | { 0, 0 }, //234 |
| 370 | { 0, 0 }, //235 |
| 371 | { 0, 0 }, //236 |
| 372 | { 0, 0 }, //237 |
| 373 | { 0, 0 }, //238 |
| 374 | { 0, 0 }, //239 |
| 375 | { 0, 0 }, //240 |
| 376 | { 0, 0 }, //241 |
| 377 | { 0, 0 }, //242 |
| 378 | { 0, 0 }, //243 |
| 379 | { 0, 0 }, //244 |
| 380 | { 0, 0 }, //245 |
| 381 | { 0, 0 }, //246 |
| 382 | { 0, 0 }, //247 |
| 383 | { 0, 0 }, //248 |
| 384 | { 0, 0 }, //249 |
| 385 | { STRING_WITH_LEN("Bulk_execute" ) }, //250 |
| 386 | { STRING_WITH_LEN("Slave_worker" ) }, //251 |
| 387 | { STRING_WITH_LEN("Slave_IO" ) }, //252 |
| 388 | { STRING_WITH_LEN("Slave_SQL" ) }, //253 |
| 389 | { STRING_WITH_LEN("Com_multi" ) }, //254 |
| 390 | { STRING_WITH_LEN("Error" ) } // Last command number 255 |
| 391 | }; |
| 392 | |
| 393 | const char *xa_state_names[]={ |
| 394 | "NON-EXISTING" , "ACTIVE" , "IDLE" , "PREPARED" , "ROLLBACK ONLY" |
| 395 | }; |
| 396 | |
| 397 | #ifdef HAVE_REPLICATION |
| 398 | /** |
| 399 | Returns true if all tables should be ignored. |
| 400 | */ |
| 401 | inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) |
| 402 | { |
| 403 | Rpl_filter *rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; |
| 404 | return rpl_filter->is_on() && tables && !thd->spcont && |
| 405 | !rpl_filter->tables_ok(thd->db.str, tables); |
| 406 | } |
| 407 | #endif |
| 408 | |
| 409 | |
| 410 | static bool some_non_temp_table_to_be_updated(THD *thd, TABLE_LIST *tables) |
| 411 | { |
| 412 | for (TABLE_LIST *table= tables; table; table= table->next_global) |
| 413 | { |
| 414 | DBUG_ASSERT(table->db.str && table->table_name.str); |
| 415 | if (table->updating && !thd->find_tmp_table_share(table)) |
| 416 | return 1; |
| 417 | } |
| 418 | return 0; |
| 419 | } |
| 420 | |
| 421 | |
| 422 | /* |
| 423 | Check whether the statement implicitly commits an active transaction. |
| 424 | |
| 425 | @param thd Thread handle. |
| 426 | @param mask Bitmask used for the SQL command match. |
| 427 | |
| 428 | @return 0 No implicit commit |
| 429 | @return 1 Do a commit |
| 430 | */ |
| 431 | bool stmt_causes_implicit_commit(THD *thd, uint mask) |
| 432 | { |
| 433 | LEX *lex= thd->lex; |
| 434 | bool skip= FALSE; |
| 435 | DBUG_ENTER("stmt_causes_implicit_commit" ); |
| 436 | |
| 437 | if (!(sql_command_flags[lex->sql_command] & mask)) |
| 438 | DBUG_RETURN(FALSE); |
| 439 | |
| 440 | switch (lex->sql_command) { |
| 441 | case SQLCOM_DROP_TABLE: |
| 442 | case SQLCOM_DROP_SEQUENCE: |
| 443 | skip= (lex->tmp_table() || |
| 444 | (thd->variables.option_bits & OPTION_GTID_BEGIN)); |
| 445 | break; |
| 446 | case SQLCOM_ALTER_TABLE: |
| 447 | case SQLCOM_ALTER_SEQUENCE: |
| 448 | /* If ALTER TABLE of non-temporary table, do implicit commit */ |
| 449 | skip= (lex->tmp_table()); |
| 450 | break; |
| 451 | case SQLCOM_CREATE_TABLE: |
| 452 | case SQLCOM_CREATE_SEQUENCE: |
| 453 | /* |
| 454 | If CREATE TABLE of non-temporary table and the table is not part |
| 455 | if a BEGIN GTID ... COMMIT group, do a implicit commit. |
| 456 | This ensures that CREATE ... SELECT will in the same GTID group on the |
| 457 | master and slave. |
| 458 | */ |
| 459 | skip= (lex->tmp_table() || |
| 460 | (thd->variables.option_bits & OPTION_GTID_BEGIN)); |
| 461 | break; |
| 462 | case SQLCOM_SET_OPTION: |
| 463 | skip= lex->autocommit ? FALSE : TRUE; |
| 464 | break; |
| 465 | default: |
| 466 | break; |
| 467 | } |
| 468 | |
| 469 | DBUG_RETURN(!skip); |
| 470 | } |
| 471 | |
| 472 | |
| 473 | /** |
| 474 | Mark all commands that somehow changes a table. |
| 475 | |
| 476 | This is used to check number of updates / hour. |
| 477 | |
| 478 | sql_command is actually set to SQLCOM_END sometimes |
| 479 | so we need the +1 to include it in the array. |
| 480 | |
| 481 | See COMMAND_FLAG_xxx for different type of commands |
| 482 | 2 - query that returns meaningful ROW_COUNT() - |
| 483 | a number of modified rows |
| 484 | */ |
| 485 | |
| 486 | uint sql_command_flags[SQLCOM_END+1]; |
| 487 | uint server_command_flags[COM_END+1]; |
| 488 | |
| 489 | void init_update_queries(void) |
| 490 | { |
| 491 | /* Initialize the server command flags array. */ |
| 492 | memset(server_command_flags, 0, sizeof(server_command_flags)); |
| 493 | |
| 494 | server_command_flags[COM_STATISTICS]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; |
| 495 | server_command_flags[COM_PING]= CF_SKIP_QUERY_ID | CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK | CF_NO_COM_MULTI; |
| 496 | |
| 497 | server_command_flags[COM_QUIT]= CF_SKIP_WSREP_CHECK; |
| 498 | server_command_flags[COM_PROCESS_INFO]= CF_SKIP_WSREP_CHECK; |
| 499 | server_command_flags[COM_PROCESS_KILL]= CF_SKIP_WSREP_CHECK; |
| 500 | server_command_flags[COM_SHUTDOWN]= CF_SKIP_WSREP_CHECK; |
| 501 | server_command_flags[COM_SLEEP]= CF_SKIP_WSREP_CHECK; |
| 502 | server_command_flags[COM_TIME]= CF_SKIP_WSREP_CHECK; |
| 503 | server_command_flags[COM_INIT_DB]= CF_SKIP_WSREP_CHECK; |
| 504 | server_command_flags[COM_END]= CF_SKIP_WSREP_CHECK; |
| 505 | for (uint i= COM_MDB_GAP_BEG; i <= COM_MDB_GAP_END; i++) |
| 506 | { |
| 507 | server_command_flags[i]= CF_SKIP_WSREP_CHECK; |
| 508 | } |
| 509 | |
| 510 | /* |
| 511 | COM_QUERY, COM_SET_OPTION and COM_STMT_XXX are allowed to pass the early |
| 512 | COM_xxx filter, they're checked later in mysql_execute_command(). |
| 513 | */ |
| 514 | server_command_flags[COM_QUERY]= CF_SKIP_WSREP_CHECK; |
| 515 | server_command_flags[COM_SET_OPTION]= CF_SKIP_WSREP_CHECK; |
| 516 | server_command_flags[COM_STMT_PREPARE]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; |
| 517 | server_command_flags[COM_STMT_EXECUTE]= CF_SKIP_WSREP_CHECK; |
| 518 | server_command_flags[COM_STMT_FETCH]= CF_SKIP_WSREP_CHECK; |
| 519 | server_command_flags[COM_STMT_CLOSE]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; |
| 520 | server_command_flags[COM_STMT_RESET]= CF_SKIP_QUESTIONS | CF_SKIP_WSREP_CHECK; |
| 521 | server_command_flags[COM_STMT_EXECUTE]= CF_SKIP_WSREP_CHECK; |
| 522 | server_command_flags[COM_STMT_SEND_LONG_DATA]= CF_SKIP_WSREP_CHECK; |
| 523 | server_command_flags[COM_REGISTER_SLAVE]= CF_SKIP_WSREP_CHECK; |
| 524 | server_command_flags[COM_MULTI]= CF_SKIP_WSREP_CHECK | CF_NO_COM_MULTI; |
| 525 | server_command_flags[CF_NO_COM_MULTI]= CF_NO_COM_MULTI; |
| 526 | |
| 527 | /* Initialize the sql command flags array. */ |
| 528 | memset(sql_command_flags, 0, sizeof(sql_command_flags)); |
| 529 | |
| 530 | /* |
| 531 | In general, DDL statements do not generate row events and do not go |
| 532 | through a cache before being written to the binary log. However, the |
| 533 | CREATE TABLE...SELECT is an exception because it may generate row |
| 534 | events. For that reason, the SQLCOM_CREATE_TABLE which represents |
| 535 | a CREATE TABLE, including the CREATE TABLE...SELECT, has the |
| 536 | CF_CAN_GENERATE_ROW_EVENTS flag. The distinction between a regular |
| 537 | CREATE TABLE and the CREATE TABLE...SELECT is made in other parts of |
| 538 | the code, in particular in the Query_log_event's constructor. |
| 539 | */ |
| 540 | sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 541 | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | |
| 542 | CF_CAN_GENERATE_ROW_EVENTS | |
| 543 | CF_SCHEMA_CHANGE; |
| 544 | sql_command_flags[SQLCOM_CREATE_SEQUENCE]= (CF_CHANGES_DATA | |
| 545 | CF_REEXECUTION_FRAGILE | |
| 546 | CF_AUTO_COMMIT_TRANS | |
| 547 | CF_SCHEMA_CHANGE); |
| 548 | sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; |
| 549 | sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | |
| 550 | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS | |
| 551 | CF_INSERTS_DATA; |
| 552 | sql_command_flags[SQLCOM_ALTER_SEQUENCE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | |
| 553 | CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE; |
| 554 | sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | |
| 555 | CF_AUTO_COMMIT_TRANS; |
| 556 | sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE; |
| 557 | sql_command_flags[SQLCOM_DROP_SEQUENCE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_SCHEMA_CHANGE; |
| 558 | sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 559 | CF_CAN_GENERATE_ROW_EVENTS | CF_REPORT_PROGRESS | |
| 560 | CF_INSERTS_DATA; |
| 561 | sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE; |
| 562 | sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_DB_CHANGE; |
| 563 | sql_command_flags[SQLCOM_CREATE_PACKAGE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 564 | sql_command_flags[SQLCOM_DROP_PACKAGE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 565 | sql_command_flags[SQLCOM_CREATE_PACKAGE_BODY]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 566 | sql_command_flags[SQLCOM_DROP_PACKAGE_BODY]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 567 | sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS; |
| 568 | sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 569 | sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 570 | sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; |
| 571 | sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 572 | CF_AUTO_COMMIT_TRANS; |
| 573 | sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 574 | sql_command_flags[SQLCOM_CREATE_TRIGGER]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 575 | sql_command_flags[SQLCOM_DROP_TRIGGER]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 576 | sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 577 | sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 578 | sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 579 | |
| 580 | sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 581 | CF_CAN_GENERATE_ROW_EVENTS | |
| 582 | CF_OPTIMIZER_TRACE | |
| 583 | CF_CAN_BE_EXPLAINED | |
| 584 | CF_UPDATES_DATA | CF_SP_BULK_SAFE; |
| 585 | sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 586 | CF_CAN_GENERATE_ROW_EVENTS | |
| 587 | CF_OPTIMIZER_TRACE | |
| 588 | CF_CAN_BE_EXPLAINED | |
| 589 | CF_UPDATES_DATA | CF_SP_BULK_SAFE; |
| 590 | sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 591 | CF_CAN_GENERATE_ROW_EVENTS | |
| 592 | CF_OPTIMIZER_TRACE | |
| 593 | CF_CAN_BE_EXPLAINED | |
| 594 | CF_INSERTS_DATA | |
| 595 | CF_SP_BULK_SAFE | |
| 596 | CF_SP_BULK_OPTIMIZED; |
| 597 | sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 598 | CF_CAN_GENERATE_ROW_EVENTS | |
| 599 | CF_OPTIMIZER_TRACE | |
| 600 | CF_CAN_BE_EXPLAINED | |
| 601 | CF_INSERTS_DATA; |
| 602 | sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 603 | CF_CAN_GENERATE_ROW_EVENTS | |
| 604 | CF_OPTIMIZER_TRACE | |
| 605 | CF_CAN_BE_EXPLAINED; |
| 606 | sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 607 | CF_CAN_GENERATE_ROW_EVENTS | |
| 608 | CF_OPTIMIZER_TRACE | |
| 609 | CF_CAN_BE_EXPLAINED; |
| 610 | sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 611 | CF_CAN_GENERATE_ROW_EVENTS | |
| 612 | CF_OPTIMIZER_TRACE | |
| 613 | CF_CAN_BE_EXPLAINED | |
| 614 | CF_INSERTS_DATA | CF_SP_BULK_SAFE; |
| 615 | sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | |
| 616 | CF_CAN_GENERATE_ROW_EVENTS | |
| 617 | CF_OPTIMIZER_TRACE | |
| 618 | CF_CAN_BE_EXPLAINED | |
| 619 | CF_INSERTS_DATA; |
| 620 | sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE | |
| 621 | CF_CAN_GENERATE_ROW_EVENTS | |
| 622 | CF_OPTIMIZER_TRACE | |
| 623 | CF_CAN_BE_EXPLAINED; |
| 624 | // (1) so that subquery is traced when doing "SET @var = (subquery)" |
| 625 | /* |
| 626 | @todo SQLCOM_SET_OPTION should have CF_CAN_GENERATE_ROW_EVENTS |
| 627 | set, because it may invoke a stored function that generates row |
| 628 | events. /Sven |
| 629 | */ |
| 630 | sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE | |
| 631 | CF_AUTO_COMMIT_TRANS | |
| 632 | CF_CAN_GENERATE_ROW_EVENTS | |
| 633 | CF_OPTIMIZER_TRACE; // (1) |
| 634 | // (1) so that subquery is traced when doing "DO @var := (subquery)" |
| 635 | sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE | |
| 636 | CF_CAN_GENERATE_ROW_EVENTS | |
| 637 | CF_OPTIMIZER_TRACE; // (1) |
| 638 | |
| 639 | sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 640 | sql_command_flags[SQLCOM_SHOW_STATUS_PACKAGE]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 641 | sql_command_flags[SQLCOM_SHOW_STATUS_PACKAGE_BODY]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 642 | sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 643 | sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 644 | sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 645 | sql_command_flags[SQLCOM_SHOW_EVENTS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 646 | sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 647 | sql_command_flags[SQLCOM_SHOW_PLUGINS]= CF_STATUS_COMMAND; |
| 648 | sql_command_flags[SQLCOM_SHOW_GENERIC]= CF_STATUS_COMMAND; |
| 649 | sql_command_flags[SQLCOM_SHOW_FIELDS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 650 | sql_command_flags[SQLCOM_SHOW_KEYS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 651 | sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 652 | sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 653 | sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 654 | sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND; |
| 655 | sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS]= CF_STATUS_COMMAND; |
| 656 | sql_command_flags[SQLCOM_SHOW_BINLOG_EVENTS]= CF_STATUS_COMMAND; |
| 657 | sql_command_flags[SQLCOM_SHOW_STORAGE_ENGINES]= CF_STATUS_COMMAND; |
| 658 | sql_command_flags[SQLCOM_SHOW_AUTHORS]= CF_STATUS_COMMAND; |
| 659 | sql_command_flags[SQLCOM_SHOW_CONTRIBUTORS]= CF_STATUS_COMMAND; |
| 660 | sql_command_flags[SQLCOM_SHOW_PRIVILEGES]= CF_STATUS_COMMAND; |
| 661 | sql_command_flags[SQLCOM_SHOW_WARNS]= CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT; |
| 662 | sql_command_flags[SQLCOM_SHOW_ERRORS]= CF_STATUS_COMMAND | CF_DIAGNOSTIC_STMT; |
| 663 | sql_command_flags[SQLCOM_SHOW_ENGINE_STATUS]= CF_STATUS_COMMAND; |
| 664 | sql_command_flags[SQLCOM_SHOW_ENGINE_MUTEX]= CF_STATUS_COMMAND; |
| 665 | sql_command_flags[SQLCOM_SHOW_ENGINE_LOGS]= CF_STATUS_COMMAND; |
| 666 | sql_command_flags[SQLCOM_SHOW_EXPLAIN]= CF_STATUS_COMMAND; |
| 667 | sql_command_flags[SQLCOM_SHOW_PROCESSLIST]= CF_STATUS_COMMAND; |
| 668 | sql_command_flags[SQLCOM_SHOW_GRANTS]= CF_STATUS_COMMAND; |
| 669 | sql_command_flags[SQLCOM_SHOW_CREATE_USER]= CF_STATUS_COMMAND; |
| 670 | sql_command_flags[SQLCOM_SHOW_CREATE_DB]= CF_STATUS_COMMAND; |
| 671 | sql_command_flags[SQLCOM_SHOW_CREATE]= CF_STATUS_COMMAND; |
| 672 | sql_command_flags[SQLCOM_SHOW_MASTER_STAT]= CF_STATUS_COMMAND; |
| 673 | sql_command_flags[SQLCOM_SHOW_SLAVE_STAT]= CF_STATUS_COMMAND; |
| 674 | sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND; |
| 675 | sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND; |
| 676 | sql_command_flags[SQLCOM_SHOW_CREATE_PACKAGE]= CF_STATUS_COMMAND; |
| 677 | sql_command_flags[SQLCOM_SHOW_CREATE_PACKAGE_BODY]= CF_STATUS_COMMAND; |
| 678 | sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND; |
| 679 | sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; |
| 680 | sql_command_flags[SQLCOM_SHOW_PROC_CODE]= CF_STATUS_COMMAND; |
| 681 | sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND; |
| 682 | sql_command_flags[SQLCOM_SHOW_PACKAGE_BODY_CODE]= CF_STATUS_COMMAND; |
| 683 | sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND; |
| 684 | sql_command_flags[SQLCOM_SHOW_PROFILES]= CF_STATUS_COMMAND; |
| 685 | sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND; |
| 686 | sql_command_flags[SQLCOM_BINLOG_BASE64_EVENT]= CF_STATUS_COMMAND | CF_CAN_GENERATE_ROW_EVENTS; |
| 687 | sql_command_flags[SQLCOM_SHOW_TABLES]= (CF_STATUS_COMMAND | CF_SHOW_TABLE_COMMAND | CF_REEXECUTION_FRAGILE); |
| 688 | sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND | CF_SHOW_TABLE_COMMAND | CF_REEXECUTION_FRAGILE); |
| 689 | |
| 690 | |
| 691 | sql_command_flags[SQLCOM_CREATE_USER]= CF_CHANGES_DATA; |
| 692 | sql_command_flags[SQLCOM_RENAME_USER]= CF_CHANGES_DATA; |
| 693 | sql_command_flags[SQLCOM_DROP_USER]= CF_CHANGES_DATA; |
| 694 | sql_command_flags[SQLCOM_ALTER_USER]= CF_CHANGES_DATA; |
| 695 | sql_command_flags[SQLCOM_CREATE_ROLE]= CF_CHANGES_DATA; |
| 696 | sql_command_flags[SQLCOM_GRANT]= CF_CHANGES_DATA; |
| 697 | sql_command_flags[SQLCOM_GRANT_ROLE]= CF_CHANGES_DATA; |
| 698 | sql_command_flags[SQLCOM_REVOKE]= CF_CHANGES_DATA; |
| 699 | sql_command_flags[SQLCOM_REVOKE_ROLE]= CF_CHANGES_DATA; |
| 700 | sql_command_flags[SQLCOM_OPTIMIZE]= CF_CHANGES_DATA; |
| 701 | sql_command_flags[SQLCOM_CREATE_FUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 702 | sql_command_flags[SQLCOM_CREATE_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 703 | sql_command_flags[SQLCOM_CREATE_SPFUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 704 | sql_command_flags[SQLCOM_DROP_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 705 | sql_command_flags[SQLCOM_DROP_FUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 706 | sql_command_flags[SQLCOM_ALTER_PROCEDURE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 707 | sql_command_flags[SQLCOM_ALTER_FUNCTION]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 708 | sql_command_flags[SQLCOM_INSTALL_PLUGIN]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 709 | sql_command_flags[SQLCOM_UNINSTALL_PLUGIN]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; |
| 710 | |
| 711 | /* |
| 712 | The following is used to preserver CF_ROW_COUNT during the |
| 713 | a CALL or EXECUTE statement, so the value generated by the |
| 714 | last called (or executed) statement is preserved. |
| 715 | See mysql_execute_command() for how CF_ROW_COUNT is used. |
| 716 | */ |
| 717 | /* |
| 718 | (1): without it, in "CALL some_proc((subq))", subquery would not be |
| 719 | traced. |
| 720 | */ |
| 721 | sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE | |
| 722 | CF_CAN_GENERATE_ROW_EVENTS | |
| 723 | CF_OPTIMIZER_TRACE; // (1) |
| 724 | sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS; |
| 725 | sql_command_flags[SQLCOM_EXECUTE_IMMEDIATE]= CF_CAN_GENERATE_ROW_EVENTS; |
| 726 | sql_command_flags[SQLCOM_COMPOUND]= CF_CAN_GENERATE_ROW_EVENTS; |
| 727 | |
| 728 | /* |
| 729 | We don't want to change to statement based replication for these commands |
| 730 | */ |
| 731 | sql_command_flags[SQLCOM_ROLLBACK]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; |
| 732 | /* We don't want to replicate ALTER TABLE for temp tables in row format */ |
| 733 | sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; |
| 734 | /* We don't want to replicate TRUNCATE for temp tables in row format */ |
| 735 | sql_command_flags[SQLCOM_TRUNCATE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; |
| 736 | /* We don't want to replicate DROP for temp tables in row format */ |
| 737 | sql_command_flags[SQLCOM_DROP_TABLE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; |
| 738 | sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; |
| 739 | /* One can change replication mode with SET */ |
| 740 | sql_command_flags[SQLCOM_SET_OPTION]|= CF_FORCE_ORIGINAL_BINLOG_FORMAT; |
| 741 | |
| 742 | /* |
| 743 | The following admin table operations are allowed |
| 744 | on log tables. |
| 745 | */ |
| 746 | sql_command_flags[SQLCOM_REPAIR]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; |
| 747 | sql_command_flags[SQLCOM_OPTIMIZE]|= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; |
| 748 | sql_command_flags[SQLCOM_ANALYZE]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; |
| 749 | sql_command_flags[SQLCOM_CHECK]= CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_REPORT_PROGRESS; |
| 750 | sql_command_flags[SQLCOM_CHECKSUM]= CF_REPORT_PROGRESS; |
| 751 | |
| 752 | sql_command_flags[SQLCOM_CREATE_USER]|= CF_AUTO_COMMIT_TRANS; |
| 753 | sql_command_flags[SQLCOM_ALTER_USER]|= CF_AUTO_COMMIT_TRANS; |
| 754 | sql_command_flags[SQLCOM_DROP_USER]|= CF_AUTO_COMMIT_TRANS; |
| 755 | sql_command_flags[SQLCOM_RENAME_USER]|= CF_AUTO_COMMIT_TRANS; |
| 756 | sql_command_flags[SQLCOM_CREATE_ROLE]|= CF_AUTO_COMMIT_TRANS; |
| 757 | sql_command_flags[SQLCOM_DROP_ROLE]|= CF_AUTO_COMMIT_TRANS; |
| 758 | sql_command_flags[SQLCOM_REVOKE]|= CF_AUTO_COMMIT_TRANS; |
| 759 | sql_command_flags[SQLCOM_REVOKE_ALL]= CF_AUTO_COMMIT_TRANS; |
| 760 | sql_command_flags[SQLCOM_REVOKE_ROLE]|= CF_AUTO_COMMIT_TRANS; |
| 761 | sql_command_flags[SQLCOM_GRANT]|= CF_AUTO_COMMIT_TRANS; |
| 762 | sql_command_flags[SQLCOM_GRANT_ROLE]|= CF_AUTO_COMMIT_TRANS; |
| 763 | |
| 764 | sql_command_flags[SQLCOM_FLUSH]= CF_AUTO_COMMIT_TRANS; |
| 765 | sql_command_flags[SQLCOM_RESET]= CF_AUTO_COMMIT_TRANS; |
| 766 | sql_command_flags[SQLCOM_CREATE_SERVER]= CF_AUTO_COMMIT_TRANS; |
| 767 | sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS; |
| 768 | sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS; |
| 769 | |
| 770 | /* |
| 771 | The following statements can deal with temporary tables, |
| 772 | so temporary tables should be pre-opened for those statements to |
| 773 | simplify privilege checking. |
| 774 | |
| 775 | There are other statements that deal with temporary tables and open |
| 776 | them, but which are not listed here. The thing is that the order of |
| 777 | pre-opening temporary tables for those statements is somewhat custom. |
| 778 | */ |
| 779 | sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES; |
| 780 | sql_command_flags[SQLCOM_DROP_TABLE]|= CF_PREOPEN_TMP_TABLES; |
| 781 | sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_PREOPEN_TMP_TABLES; |
| 782 | sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_PREOPEN_TMP_TABLES; |
| 783 | sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_PREOPEN_TMP_TABLES; |
| 784 | sql_command_flags[SQLCOM_TRUNCATE]|= CF_PREOPEN_TMP_TABLES; |
| 785 | sql_command_flags[SQLCOM_LOAD]|= CF_PREOPEN_TMP_TABLES; |
| 786 | sql_command_flags[SQLCOM_DROP_INDEX]|= CF_PREOPEN_TMP_TABLES; |
| 787 | sql_command_flags[SQLCOM_UPDATE]|= CF_PREOPEN_TMP_TABLES; |
| 788 | sql_command_flags[SQLCOM_UPDATE_MULTI]|= CF_PREOPEN_TMP_TABLES; |
| 789 | sql_command_flags[SQLCOM_INSERT_SELECT]|= CF_PREOPEN_TMP_TABLES; |
| 790 | sql_command_flags[SQLCOM_DELETE]|= CF_PREOPEN_TMP_TABLES; |
| 791 | sql_command_flags[SQLCOM_DELETE_MULTI]|= CF_PREOPEN_TMP_TABLES; |
| 792 | sql_command_flags[SQLCOM_RENAME_TABLE]|= CF_PREOPEN_TMP_TABLES; |
| 793 | sql_command_flags[SQLCOM_REPLACE_SELECT]|= CF_PREOPEN_TMP_TABLES; |
| 794 | sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES; |
| 795 | sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES; |
| 796 | sql_command_flags[SQLCOM_DO]|= CF_PREOPEN_TMP_TABLES; |
| 797 | sql_command_flags[SQLCOM_HA_OPEN]|= CF_PREOPEN_TMP_TABLES; |
| 798 | sql_command_flags[SQLCOM_CALL]|= CF_PREOPEN_TMP_TABLES; |
| 799 | sql_command_flags[SQLCOM_CHECKSUM]|= CF_PREOPEN_TMP_TABLES; |
| 800 | sql_command_flags[SQLCOM_ANALYZE]|= CF_PREOPEN_TMP_TABLES; |
| 801 | sql_command_flags[SQLCOM_CHECK]|= CF_PREOPEN_TMP_TABLES; |
| 802 | sql_command_flags[SQLCOM_OPTIMIZE]|= CF_PREOPEN_TMP_TABLES; |
| 803 | sql_command_flags[SQLCOM_REPAIR]|= CF_PREOPEN_TMP_TABLES; |
| 804 | sql_command_flags[SQLCOM_PRELOAD_KEYS]|= CF_PREOPEN_TMP_TABLES; |
| 805 | sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_PREOPEN_TMP_TABLES; |
| 806 | |
| 807 | /* |
| 808 | DDL statements that should start with closing opened handlers. |
| 809 | |
| 810 | We use this flag only for statements for which open HANDLERs |
| 811 | have to be closed before temporary tables are pre-opened. |
| 812 | */ |
| 813 | sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_HA_CLOSE; |
| 814 | sql_command_flags[SQLCOM_CREATE_SEQUENCE]|= CF_HA_CLOSE; |
| 815 | sql_command_flags[SQLCOM_DROP_TABLE]|= CF_HA_CLOSE; |
| 816 | sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_HA_CLOSE; |
| 817 | sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_HA_CLOSE; |
| 818 | sql_command_flags[SQLCOM_TRUNCATE]|= CF_HA_CLOSE; |
| 819 | sql_command_flags[SQLCOM_REPAIR]|= CF_HA_CLOSE; |
| 820 | sql_command_flags[SQLCOM_OPTIMIZE]|= CF_HA_CLOSE; |
| 821 | sql_command_flags[SQLCOM_ANALYZE]|= CF_HA_CLOSE; |
| 822 | sql_command_flags[SQLCOM_CHECK]|= CF_HA_CLOSE; |
| 823 | sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_HA_CLOSE; |
| 824 | sql_command_flags[SQLCOM_DROP_INDEX]|= CF_HA_CLOSE; |
| 825 | sql_command_flags[SQLCOM_PRELOAD_KEYS]|= CF_HA_CLOSE; |
| 826 | sql_command_flags[SQLCOM_ASSIGN_TO_KEYCACHE]|= CF_HA_CLOSE; |
| 827 | |
| 828 | /* |
| 829 | Mark statements that always are disallowed in read-only |
| 830 | transactions. Note that according to the SQL standard, |
| 831 | even temporary table DDL should be disallowed. |
| 832 | */ |
| 833 | sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_DISALLOW_IN_RO_TRANS; |
| 834 | sql_command_flags[SQLCOM_CREATE_SEQUENCE]|= CF_DISALLOW_IN_RO_TRANS; |
| 835 | sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_DISALLOW_IN_RO_TRANS; |
| 836 | sql_command_flags[SQLCOM_DROP_TABLE]|= CF_DISALLOW_IN_RO_TRANS; |
| 837 | sql_command_flags[SQLCOM_DROP_SEQUENCE]|= CF_DISALLOW_IN_RO_TRANS; |
| 838 | sql_command_flags[SQLCOM_RENAME_TABLE]|= CF_DISALLOW_IN_RO_TRANS; |
| 839 | sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_DISALLOW_IN_RO_TRANS; |
| 840 | sql_command_flags[SQLCOM_DROP_INDEX]|= CF_DISALLOW_IN_RO_TRANS; |
| 841 | sql_command_flags[SQLCOM_CREATE_DB]|= CF_DISALLOW_IN_RO_TRANS; |
| 842 | sql_command_flags[SQLCOM_DROP_DB]|= CF_DISALLOW_IN_RO_TRANS; |
| 843 | sql_command_flags[SQLCOM_CREATE_PACKAGE]|= CF_DISALLOW_IN_RO_TRANS; |
| 844 | sql_command_flags[SQLCOM_DROP_PACKAGE]|= CF_DISALLOW_IN_RO_TRANS; |
| 845 | sql_command_flags[SQLCOM_CREATE_PACKAGE_BODY]|= CF_DISALLOW_IN_RO_TRANS; |
| 846 | sql_command_flags[SQLCOM_DROP_PACKAGE_BODY]|= CF_DISALLOW_IN_RO_TRANS; |
| 847 | sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]|= CF_DISALLOW_IN_RO_TRANS; |
| 848 | sql_command_flags[SQLCOM_ALTER_DB]|= CF_DISALLOW_IN_RO_TRANS; |
| 849 | sql_command_flags[SQLCOM_CREATE_VIEW]|= CF_DISALLOW_IN_RO_TRANS; |
| 850 | sql_command_flags[SQLCOM_DROP_VIEW]|= CF_DISALLOW_IN_RO_TRANS; |
| 851 | sql_command_flags[SQLCOM_CREATE_TRIGGER]|= CF_DISALLOW_IN_RO_TRANS; |
| 852 | sql_command_flags[SQLCOM_DROP_TRIGGER]|= CF_DISALLOW_IN_RO_TRANS; |
| 853 | sql_command_flags[SQLCOM_CREATE_EVENT]|= CF_DISALLOW_IN_RO_TRANS; |
| 854 | sql_command_flags[SQLCOM_ALTER_EVENT]|= CF_DISALLOW_IN_RO_TRANS; |
| 855 | sql_command_flags[SQLCOM_DROP_EVENT]|= CF_DISALLOW_IN_RO_TRANS; |
| 856 | sql_command_flags[SQLCOM_CREATE_USER]|= CF_DISALLOW_IN_RO_TRANS; |
| 857 | sql_command_flags[SQLCOM_ALTER_USER]|= CF_DISALLOW_IN_RO_TRANS; |
| 858 | sql_command_flags[SQLCOM_RENAME_USER]|= CF_DISALLOW_IN_RO_TRANS; |
| 859 | sql_command_flags[SQLCOM_DROP_USER]|= CF_DISALLOW_IN_RO_TRANS; |
| 860 | sql_command_flags[SQLCOM_CREATE_SERVER]|= CF_DISALLOW_IN_RO_TRANS; |
| 861 | sql_command_flags[SQLCOM_ALTER_SERVER]|= CF_DISALLOW_IN_RO_TRANS; |
| 862 | sql_command_flags[SQLCOM_DROP_SERVER]|= CF_DISALLOW_IN_RO_TRANS; |
| 863 | sql_command_flags[SQLCOM_CREATE_FUNCTION]|= CF_DISALLOW_IN_RO_TRANS; |
| 864 | sql_command_flags[SQLCOM_CREATE_PROCEDURE]|= CF_DISALLOW_IN_RO_TRANS; |
| 865 | sql_command_flags[SQLCOM_CREATE_SPFUNCTION]|=CF_DISALLOW_IN_RO_TRANS; |
| 866 | sql_command_flags[SQLCOM_DROP_PROCEDURE]|= CF_DISALLOW_IN_RO_TRANS; |
| 867 | sql_command_flags[SQLCOM_DROP_FUNCTION]|= CF_DISALLOW_IN_RO_TRANS; |
| 868 | sql_command_flags[SQLCOM_ALTER_PROCEDURE]|= CF_DISALLOW_IN_RO_TRANS; |
| 869 | sql_command_flags[SQLCOM_ALTER_FUNCTION]|= CF_DISALLOW_IN_RO_TRANS; |
| 870 | sql_command_flags[SQLCOM_TRUNCATE]|= CF_DISALLOW_IN_RO_TRANS; |
| 871 | sql_command_flags[SQLCOM_ALTER_TABLESPACE]|= CF_DISALLOW_IN_RO_TRANS; |
| 872 | sql_command_flags[SQLCOM_REPAIR]|= CF_DISALLOW_IN_RO_TRANS; |
| 873 | sql_command_flags[SQLCOM_OPTIMIZE]|= CF_DISALLOW_IN_RO_TRANS; |
| 874 | sql_command_flags[SQLCOM_GRANT]|= CF_DISALLOW_IN_RO_TRANS; |
| 875 | sql_command_flags[SQLCOM_REVOKE]|= CF_DISALLOW_IN_RO_TRANS; |
| 876 | sql_command_flags[SQLCOM_REVOKE_ALL]|= CF_DISALLOW_IN_RO_TRANS; |
| 877 | sql_command_flags[SQLCOM_INSTALL_PLUGIN]|= CF_DISALLOW_IN_RO_TRANS; |
| 878 | sql_command_flags[SQLCOM_UNINSTALL_PLUGIN]|= CF_DISALLOW_IN_RO_TRANS; |
| 879 | } |
| 880 | |
| 881 | bool sqlcom_can_generate_row_events(const THD *thd) |
| 882 | { |
| 883 | return (sql_command_flags[thd->lex->sql_command] & |
| 884 | CF_CAN_GENERATE_ROW_EVENTS); |
| 885 | } |
| 886 | |
| 887 | bool is_update_query(enum enum_sql_command command) |
| 888 | { |
| 889 | DBUG_ASSERT(command <= SQLCOM_END); |
| 890 | return (sql_command_flags[command] & CF_CHANGES_DATA) != 0; |
| 891 | } |
| 892 | |
| 893 | /** |
| 894 | Check if a sql command is allowed to write to log tables. |
| 895 | @param command The SQL command |
| 896 | @return true if writing is allowed |
| 897 | */ |
| 898 | bool is_log_table_write_query(enum enum_sql_command command) |
| 899 | { |
| 900 | DBUG_ASSERT(command <= SQLCOM_END); |
| 901 | return (sql_command_flags[command] & CF_WRITE_LOGS_COMMAND) != 0; |
| 902 | } |
| 903 | |
| 904 | void execute_init_command(THD *thd, LEX_STRING *init_command, |
| 905 | mysql_rwlock_t *var_lock) |
| 906 | { |
| 907 | Vio* save_vio; |
| 908 | ulonglong save_client_capabilities; |
| 909 | |
| 910 | mysql_rwlock_rdlock(var_lock); |
| 911 | if (!init_command->length) |
| 912 | { |
| 913 | mysql_rwlock_unlock(var_lock); |
| 914 | return; |
| 915 | } |
| 916 | |
| 917 | /* |
| 918 | copy the value under a lock, and release the lock. |
| 919 | init_command has to be executed without a lock held, |
| 920 | as it may try to change itself |
| 921 | */ |
| 922 | size_t len= init_command->length; |
| 923 | char *buf= thd->strmake(init_command->str, len); |
| 924 | mysql_rwlock_unlock(var_lock); |
| 925 | |
| 926 | #if defined(ENABLED_PROFILING) |
| 927 | thd->profiling.start_new_query(); |
| 928 | thd->profiling.set_query_source(buf, len); |
| 929 | #endif |
| 930 | |
| 931 | THD_STAGE_INFO(thd, stage_execution_of_init_command); |
| 932 | save_client_capabilities= thd->client_capabilities; |
| 933 | thd->client_capabilities|= CLIENT_MULTI_QUERIES; |
| 934 | /* |
| 935 | We don't need return result of execution to client side. |
| 936 | To forbid this we should set thd->net.vio to 0. |
| 937 | */ |
| 938 | save_vio= thd->net.vio; |
| 939 | thd->net.vio= 0; |
| 940 | thd->clear_error(1); |
| 941 | dispatch_command(COM_QUERY, thd, buf, (uint)len, FALSE, FALSE); |
| 942 | thd->client_capabilities= save_client_capabilities; |
| 943 | thd->net.vio= save_vio; |
| 944 | |
| 945 | #if defined(ENABLED_PROFILING) |
| 946 | thd->profiling.finish_current_query(); |
| 947 | #endif |
| 948 | } |
| 949 | |
| 950 | |
| 951 | static char *fgets_fn(char *buffer, size_t size, fgets_input_t input, int *error) |
| 952 | { |
| 953 | MYSQL_FILE *in= static_cast<MYSQL_FILE*> (input); |
| 954 | char *line= mysql_file_fgets(buffer, (int)size, in); |
| 955 | if (unlikely(error)) |
| 956 | *error= (line == NULL) ? ferror(in->m_file) : 0; |
| 957 | return line; |
| 958 | } |
| 959 | |
| 960 | |
| 961 | static void handle_bootstrap_impl(THD *thd) |
| 962 | { |
| 963 | MYSQL_FILE *file= bootstrap_file; |
| 964 | DBUG_ENTER("handle_bootstrap_impl" ); |
| 965 | |
| 966 | #ifndef EMBEDDED_LIBRARY |
| 967 | pthread_detach_this_thread(); |
| 968 | thd->thread_stack= (char*) &thd; |
| 969 | #endif /* EMBEDDED_LIBRARY */ |
| 970 | |
| 971 | thd->security_ctx->user= (char*) my_strdup("boot" , MYF(MY_WME)); |
| 972 | thd->security_ctx->priv_user[0]= thd->security_ctx->priv_host[0]= |
| 973 | thd->security_ctx->priv_role[0]= 0; |
| 974 | /* |
| 975 | Make the "client" handle multiple results. This is necessary |
| 976 | to enable stored procedures with SELECTs and Dynamic SQL |
| 977 | in init-file. |
| 978 | */ |
| 979 | thd->client_capabilities|= CLIENT_MULTI_RESULTS; |
| 980 | |
| 981 | thd->init_for_queries(); |
| 982 | |
| 983 | for ( ; ; ) |
| 984 | { |
| 985 | char buffer[MAX_BOOTSTRAP_QUERY_SIZE] = "" ; |
| 986 | int rc, length; |
| 987 | char *query; |
| 988 | int error= 0; |
| 989 | |
| 990 | rc= read_bootstrap_query(buffer, &length, file, fgets_fn, &error); |
| 991 | |
| 992 | if (rc == READ_BOOTSTRAP_EOF) |
| 993 | break; |
| 994 | /* |
| 995 | Check for bootstrap file errors. SQL syntax errors will be |
| 996 | caught below. |
| 997 | */ |
| 998 | if (rc != READ_BOOTSTRAP_SUCCESS) |
| 999 | { |
| 1000 | /* |
| 1001 | mysql_parse() may have set a successful error status for the previous |
| 1002 | query. We must clear the error status to report the bootstrap error. |
| 1003 | */ |
| 1004 | thd->get_stmt_da()->reset_diagnostics_area(); |
| 1005 | |
| 1006 | /* Get the nearest query text for reference. */ |
| 1007 | char *err_ptr= buffer + (length <= MAX_BOOTSTRAP_ERROR_LEN ? |
| 1008 | 0 : (length - MAX_BOOTSTRAP_ERROR_LEN)); |
| 1009 | switch (rc) |
| 1010 | { |
| 1011 | case READ_BOOTSTRAP_ERROR: |
| 1012 | my_printf_error(ER_UNKNOWN_ERROR, "Bootstrap file error, return code (%d). " |
| 1013 | "Nearest query: '%s'" , MYF(0), error, err_ptr); |
| 1014 | break; |
| 1015 | |
| 1016 | case READ_BOOTSTRAP_QUERY_SIZE: |
| 1017 | my_printf_error(ER_UNKNOWN_ERROR, "Boostrap file error. Query size " |
| 1018 | "exceeded %d bytes near '%s'." , MYF(0), |
| 1019 | MAX_BOOTSTRAP_LINE_SIZE, err_ptr); |
| 1020 | break; |
| 1021 | |
| 1022 | default: |
| 1023 | DBUG_ASSERT(false); |
| 1024 | break; |
| 1025 | } |
| 1026 | |
| 1027 | thd->protocol->end_statement(); |
| 1028 | bootstrap_error= 1; |
| 1029 | break; |
| 1030 | } |
| 1031 | |
| 1032 | query= (char *) thd->memdup_w_gap(buffer, length + 1, |
| 1033 | thd->db.length + 1 + |
| 1034 | QUERY_CACHE_DB_LENGTH_SIZE + |
| 1035 | QUERY_CACHE_FLAGS_SIZE); |
| 1036 | size_t db_len= 0; |
| 1037 | memcpy(query + length + 1, (char *) &db_len, sizeof(size_t)); |
| 1038 | thd->set_query_and_id(query, length, thd->charset(), next_query_id()); |
| 1039 | int2store(query + length + 1, 0); // No db in bootstrap |
| 1040 | DBUG_PRINT("query" ,("%-.4096s" ,thd->query())); |
| 1041 | #if defined(ENABLED_PROFILING) |
| 1042 | thd->profiling.start_new_query(); |
| 1043 | thd->profiling.set_query_source(thd->query(), length); |
| 1044 | #endif |
| 1045 | |
| 1046 | /* |
| 1047 | We don't need to obtain LOCK_thread_count here because in bootstrap |
| 1048 | mode we have only one thread. |
| 1049 | */ |
| 1050 | thd->set_time(); |
| 1051 | Parser_state parser_state; |
| 1052 | if (parser_state.init(thd, thd->query(), length)) |
| 1053 | { |
| 1054 | thd->protocol->end_statement(); |
| 1055 | bootstrap_error= 1; |
| 1056 | break; |
| 1057 | } |
| 1058 | |
| 1059 | mysql_parse(thd, thd->query(), length, &parser_state, FALSE, FALSE); |
| 1060 | |
| 1061 | bootstrap_error= thd->is_error(); |
| 1062 | thd->protocol->end_statement(); |
| 1063 | |
| 1064 | #if defined(ENABLED_PROFILING) |
| 1065 | thd->profiling.finish_current_query(); |
| 1066 | #endif |
| 1067 | delete_explain_query(thd->lex); |
| 1068 | |
| 1069 | if (unlikely(bootstrap_error)) |
| 1070 | break; |
| 1071 | |
| 1072 | thd->reset_kill_query(); /* Ensure that killed_errmsg is released */ |
| 1073 | free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); |
| 1074 | free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC)); |
| 1075 | thd->lex->restore_set_statement_var(); |
| 1076 | } |
| 1077 | |
| 1078 | DBUG_VOID_RETURN; |
| 1079 | } |
| 1080 | |
| 1081 | |
| 1082 | /** |
| 1083 | Execute commands from bootstrap_file. |
| 1084 | |
| 1085 | Used when creating the initial grant tables. |
| 1086 | */ |
| 1087 | |
| 1088 | pthread_handler_t handle_bootstrap(void *arg) |
| 1089 | { |
| 1090 | THD *thd=(THD*) arg; |
| 1091 | |
| 1092 | mysql_thread_set_psi_id(thd->thread_id); |
| 1093 | |
| 1094 | do_handle_bootstrap(thd); |
| 1095 | return 0; |
| 1096 | } |
| 1097 | |
| 1098 | void do_handle_bootstrap(THD *thd) |
| 1099 | { |
| 1100 | /* The following must be called before DBUG_ENTER */ |
| 1101 | thd->thread_stack= (char*) &thd; |
| 1102 | if (my_thread_init() || thd->store_globals()) |
| 1103 | { |
| 1104 | #ifndef EMBEDDED_LIBRARY |
| 1105 | close_connection(thd, ER_OUT_OF_RESOURCES); |
| 1106 | #endif |
| 1107 | thd->fatal_error(); |
| 1108 | goto end; |
| 1109 | } |
| 1110 | |
| 1111 | handle_bootstrap_impl(thd); |
| 1112 | |
| 1113 | end: |
| 1114 | delete thd; |
| 1115 | |
| 1116 | mysql_mutex_lock(&LOCK_thread_count); |
| 1117 | in_bootstrap = FALSE; |
| 1118 | mysql_cond_broadcast(&COND_thread_count); |
| 1119 | mysql_mutex_unlock(&LOCK_thread_count); |
| 1120 | |
| 1121 | #ifndef EMBEDDED_LIBRARY |
| 1122 | my_thread_end(); |
| 1123 | pthread_exit(0); |
| 1124 | #endif |
| 1125 | |
| 1126 | return; |
| 1127 | } |
| 1128 | |
| 1129 | |
| 1130 | /* This works because items are allocated on THD::mem_root */ |
| 1131 | |
| 1132 | void free_items(Item *item) |
| 1133 | { |
| 1134 | Item *next; |
| 1135 | DBUG_ENTER("free_items" ); |
| 1136 | for (; item ; item=next) |
| 1137 | { |
| 1138 | next=item->next; |
| 1139 | item->delete_self(); |
| 1140 | } |
| 1141 | DBUG_VOID_RETURN; |
| 1142 | } |
| 1143 | |
| 1144 | /** |
| 1145 | This works because items are allocated on THD::mem_root. |
| 1146 | @note The function also handles null pointers (empty list). |
| 1147 | */ |
| 1148 | void cleanup_items(Item *item) |
| 1149 | { |
| 1150 | DBUG_ENTER("cleanup_items" ); |
| 1151 | for (; item ; item=item->next) |
| 1152 | item->cleanup(); |
| 1153 | DBUG_VOID_RETURN; |
| 1154 | } |
| 1155 | |
| 1156 | static enum enum_server_command fetch_command(THD *thd, char *packet) |
| 1157 | { |
| 1158 | enum enum_server_command |
| 1159 | command= (enum enum_server_command) (uchar) packet[0]; |
| 1160 | DBUG_ENTER("fetch_command" ); |
| 1161 | |
| 1162 | if (command >= COM_END || |
| 1163 | (command >= COM_MDB_GAP_BEG && command <= COM_MDB_GAP_END)) |
| 1164 | command= COM_END; // Wrong command |
| 1165 | |
| 1166 | DBUG_PRINT("info" ,("Command on %s = %d (%s)" , |
| 1167 | vio_description(thd->net.vio), command, |
| 1168 | command_name[command].str)); |
| 1169 | DBUG_RETURN(command); |
| 1170 | } |
| 1171 | |
| 1172 | |
| 1173 | #ifdef WITH_WSREP |
| 1174 | static bool wsrep_tables_accessible_when_detached(const TABLE_LIST *tables) |
| 1175 | { |
| 1176 | for (const TABLE_LIST *table= tables; table; table= table->next_global) |
| 1177 | { |
| 1178 | TABLE_CATEGORY c; |
| 1179 | LEX_CSTRING db= table->db, tn= table->table_name; |
| 1180 | c= get_table_category(&db, &tn); |
| 1181 | if (c != TABLE_CATEGORY_INFORMATION && c != TABLE_CATEGORY_PERFORMANCE) |
| 1182 | return false; |
| 1183 | } |
| 1184 | return true; |
| 1185 | } |
| 1186 | #endif /* WITH_WSREP */ |
| 1187 | #ifndef EMBEDDED_LIBRARY |
| 1188 | |
| 1189 | /** |
| 1190 | Read one command from connection and execute it (query or simple command). |
| 1191 | This function is called in loop from thread function. |
| 1192 | |
| 1193 | For profiling to work, it must never be called recursively. |
| 1194 | |
| 1195 | @retval |
| 1196 | 0 success |
| 1197 | @retval |
| 1198 | 1 request of thread shutdown (see dispatch_command() description) |
| 1199 | */ |
| 1200 | |
| 1201 | bool do_command(THD *thd) |
| 1202 | { |
| 1203 | bool return_value; |
| 1204 | char *packet= 0; |
| 1205 | #ifdef WITH_WSREP |
| 1206 | ulong packet_length= 0; // just to avoid (false positive) compiler warning |
| 1207 | #else |
| 1208 | ulong packet_length; |
| 1209 | #endif /* WITH_WSREP */ |
| 1210 | NET *net= &thd->net; |
| 1211 | enum enum_server_command command; |
| 1212 | DBUG_ENTER("do_command" ); |
| 1213 | |
| 1214 | #ifdef WITH_WSREP |
| 1215 | if (WSREP(thd)) |
| 1216 | { |
| 1217 | mysql_mutex_lock(&thd->LOCK_thd_data); |
| 1218 | thd->wsrep_query_state= QUERY_IDLE; |
| 1219 | if (thd->wsrep_conflict_state==MUST_ABORT) |
| 1220 | { |
| 1221 | wsrep_client_rollback(thd); |
| 1222 | } |
| 1223 | mysql_mutex_unlock(&thd->LOCK_thd_data); |
| 1224 | } |
| 1225 | #endif /* WITH_WSREP */ |
| 1226 | |
| 1227 | /* |
| 1228 | indicator of uninitialized lex => normal flow of errors handling |
| 1229 | (see my_message_sql) |
| 1230 | */ |
| 1231 | thd->lex->current_select= 0; |
| 1232 | |
| 1233 | /* |
| 1234 | This thread will do a blocking read from the client which |
| 1235 | will be interrupted when the next command is received from |
| 1236 | the client, the connection is closed or "net_wait_timeout" |
| 1237 | number of seconds has passed. |
| 1238 | */ |
| 1239 | if (!thd->skip_wait_timeout) |
| 1240 | my_net_set_read_timeout(net, thd->get_net_wait_timeout()); |
| 1241 | |
| 1242 | /* Errors and diagnostics are cleared once here before query */ |
| 1243 | thd->clear_error(1); |
| 1244 | |
| 1245 | net_new_transaction(net); |
| 1246 | |
| 1247 | /* Save for user statistics */ |
| 1248 | thd->start_bytes_received= thd->status_var.bytes_received; |
| 1249 | |
| 1250 | /* |
| 1251 | Synchronization point for testing of KILL_CONNECTION. |
| 1252 | This sync point can wait here, to simulate slow code execution |
| 1253 | between the last test of thd->killed and blocking in read(). |
| 1254 | |
| 1255 | The goal of this test is to verify that a connection does not |
| 1256 | hang, if it is killed at this point of execution. |
| 1257 | (Bug#37780 - main.kill fails randomly) |
| 1258 | |
| 1259 | Note that the sync point wait itself will be terminated by a |
| 1260 | kill. In this case it consumes a condition broadcast, but does |
| 1261 | not change anything else. The consumed broadcast should not |
| 1262 | matter here, because the read/recv() below doesn't use it. |
| 1263 | */ |
| 1264 | DEBUG_SYNC(thd, "before_do_command_net_read" ); |
| 1265 | |
| 1266 | packet_length= my_net_read_packet(net, 1); |
| 1267 | #ifdef WITH_WSREP |
| 1268 | if (WSREP(thd)) { |
| 1269 | mysql_mutex_lock(&thd->LOCK_thd_data); |
| 1270 | |
| 1271 | /* these THD's are aborted or are aborting during being idle */ |
| 1272 | if (thd->wsrep_conflict_state == ABORTING) |
| 1273 | { |
| 1274 | while (thd->wsrep_conflict_state == ABORTING) { |
| 1275 | mysql_mutex_unlock(&thd->LOCK_thd_data); |
| 1276 | my_sleep(1000); |
| 1277 | mysql_mutex_lock(&thd->LOCK_thd_data); |
| 1278 | } |
| 1279 | thd->store_globals(); |
| 1280 | } |
| 1281 | else if (thd->wsrep_conflict_state == ABORTED) |
| 1282 | { |
| 1283 | thd->store_globals(); |
| 1284 | } |
| 1285 | |
| 1286 | thd->wsrep_query_state= QUERY_EXEC; |
| 1287 | mysql_mutex_unlock(&thd->LOCK_thd_data); |
| 1288 | } |
| 1289 | #endif /* WITH_WSREP */ |
| 1290 | |
| 1291 | if (unlikely(packet_length == packet_error)) |
| 1292 | { |
| 1293 | DBUG_PRINT("info" ,("Got error %d reading command from socket %s" , |
| 1294 | net->error, |
| 1295 | vio_description(net->vio))); |
| 1296 | |
| 1297 | #ifdef WITH_WSREP |
| 1298 | if (WSREP(thd)) |
| 1299 | { |
| 1300 | mysql_mutex_lock(&thd->LOCK_thd_data); |
| 1301 | if (thd->wsrep_conflict_state == MUST_ABORT) |
| 1302 | { |
| 1303 | DBUG_PRINT("wsrep" ,("aborted for wsrep rollback: %lu" , |
| 1304 | (ulong) thd->real_id)); |
| 1305 | wsrep_client_rollback(thd); |
| 1306 | } |
| 1307 | mysql_mutex_unlock(&thd->LOCK_thd_data); |
| 1308 | } |
| 1309 | #endif /* WITH_WSREP */ |
| 1310 | |
| 1311 | /* Instrument this broken statement as "statement/com/error" */ |
| 1312 | thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, |
| 1313 | com_statement_info[COM_END]. |
| 1314 | m_key); |
| 1315 | |
| 1316 | |
| 1317 | /* Check if we can continue without closing the connection */ |
| 1318 | |
| 1319 | /* The error must be set. */ |
| 1320 | DBUG_ASSERT(thd->is_error()); |
| 1321 | thd->protocol->end_statement(); |
| 1322 | |
| 1323 | /* Mark the statement completed. */ |
| 1324 | MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); |
| 1325 | thd->m_statement_psi= NULL; |
| 1326 | thd->m_digest= NULL; |
| 1327 | |
| 1328 | if (net->error != 3) |
| 1329 | { |
| 1330 | return_value= TRUE; // We have to close it. |
| 1331 | goto out; |
| 1332 | } |
| 1333 | |
| 1334 | net->error= 0; |
| 1335 | return_value= FALSE; |
| 1336 | goto out; |
| 1337 | } |
| 1338 | |
| 1339 | packet= (char*) net->read_pos; |
| 1340 | /* |
| 1341 | 'packet_length' contains length of data, as it was stored in packet |
| 1342 | header. In case of malformed header, my_net_read returns zero. |
| 1343 | If packet_length is not zero, my_net_read ensures that the returned |
| 1344 | number of bytes was actually read from network. |
| 1345 | There is also an extra safety measure in my_net_read: |
| 1346 | it sets packet[packet_length]= 0, but only for non-zero packets. |
| 1347 | */ |
| 1348 | if (packet_length == 0) /* safety */ |
| 1349 | { |
| 1350 | /* Initialize with COM_SLEEP packet */ |
| 1351 | packet[0]= (uchar) COM_SLEEP; |
| 1352 | packet_length= 1; |
| 1353 | } |
| 1354 | /* Do not rely on my_net_read, extra safety against programming errors. */ |
| 1355 | packet[packet_length]= '\0'; /* safety */ |
| 1356 | |
| 1357 | |
| 1358 | command= fetch_command(thd, packet); |
| 1359 | |
| 1360 | #ifdef WITH_WSREP |
| 1361 | if (WSREP(thd)) |
| 1362 | { |
| 1363 | /* |
| 1364 | Bail out if DB snapshot has not been installed. |
| 1365 | */ |
| 1366 | if (!thd->wsrep_applier && |
| 1367 | (!wsrep_ready || wsrep_reject_queries != WSREP_REJECT_NONE) && |
| 1368 | (server_command_flags[command] & CF_SKIP_WSREP_CHECK) == 0) |
| 1369 | { |
| 1370 | my_message(ER_UNKNOWN_COM_ERROR, |
| 1371 | "WSREP has not yet prepared node for application use" , MYF(0)); |
| 1372 | thd->protocol->end_statement(); |
| 1373 | |
| 1374 | /* Performance Schema Interface instrumentation end. */ |
| 1375 | MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); |
| 1376 | thd->m_statement_psi= NULL; |
| 1377 | thd->m_digest= NULL; |
| 1378 | |
| 1379 | return_value= FALSE; |
| 1380 | goto out; |
| 1381 | } |
| 1382 | } |
| 1383 | #endif |
| 1384 | |
| 1385 | /* Restore read timeout value */ |
| 1386 | my_net_set_read_timeout(net, thd->variables.net_read_timeout); |
| 1387 | |
| 1388 | DBUG_ASSERT(packet_length); |
| 1389 | DBUG_ASSERT(!thd->apc_target.is_enabled()); |
| 1390 | return_value= dispatch_command(command, thd, packet+1, |
| 1391 | (uint) (packet_length-1), FALSE, FALSE); |
| 1392 | #ifdef WITH_WSREP |
| 1393 | if (WSREP(thd)) |
| 1394 | { |
| 1395 | while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) |
| 1396 | { |
| 1397 | WSREP_DEBUG("Retry autocommit for: %s\n" , thd->wsrep_retry_query); |
| 1398 | CHARSET_INFO *current_charset = thd->variables.character_set_client; |
| 1399 | if (!is_supported_parser_charset(current_charset)) |
| 1400 | { |
| 1401 | /* Do not use non-supported parser character sets */ |
| 1402 | WSREP_WARN("Current client character set is non-supported parser " |
| 1403 | "character set: %s" , current_charset->csname); |
| 1404 | thd->variables.character_set_client = &my_charset_latin1; |
| 1405 | WSREP_WARN("For retry temporally setting character set to : %s" , |
| 1406 | my_charset_latin1.csname); |
| 1407 | } |
| 1408 | thd->clear_error(); |
| 1409 | return_value= dispatch_command(command, thd, thd->wsrep_retry_query, |
| 1410 | thd->wsrep_retry_query_len, FALSE, FALSE); |
| 1411 | thd->variables.character_set_client = current_charset; |
| 1412 | } |
| 1413 | |
| 1414 | if (thd->wsrep_retry_query && thd->wsrep_conflict_state != REPLAYING) |
| 1415 | { |
| 1416 | my_free(thd->wsrep_retry_query); |
| 1417 | thd->wsrep_retry_query = NULL; |
| 1418 | thd->wsrep_retry_query_len = 0; |
| 1419 | thd->wsrep_retry_command = COM_CONNECT; |
| 1420 | } |
| 1421 | } |
| 1422 | #endif /* WITH_WSREP */ |
| 1423 | DBUG_ASSERT(!thd->apc_target.is_enabled()); |
| 1424 | |
| 1425 | out: |
| 1426 | thd->lex->restore_set_statement_var(); |
| 1427 | /* The statement instrumentation must be closed in all cases. */ |
| 1428 | DBUG_ASSERT(thd->m_digest == NULL); |
| 1429 | DBUG_ASSERT(thd->m_statement_psi == NULL); |
| 1430 | DBUG_RETURN(return_value); |
| 1431 | } |
| 1432 | #endif /* EMBEDDED_LIBRARY */ |
| 1433 | |
| 1434 | /** |
| 1435 | @brief Determine if an attempt to update a non-temporary table while the |
| 1436 | read-only option was enabled has been made. |
| 1437 | |
| 1438 | This is a helper function to mysql_execute_command. |
| 1439 | |
| 1440 | @note SQLCOM_MULTI_UPDATE is an exception and dealt with elsewhere. |
| 1441 | |
| 1442 | @see mysql_execute_command |
| 1443 | @returns Status code |
| 1444 | @retval TRUE The statement should be denied. |
| 1445 | @retval FALSE The statement isn't updating any relevant tables. |
| 1446 | */ |
| 1447 | |
| 1448 | static bool deny_updates_if_read_only_option(THD *thd, TABLE_LIST *all_tables) |
| 1449 | { |
| 1450 | DBUG_ENTER("deny_updates_if_read_only_option" ); |
| 1451 | |
| 1452 | if (!opt_readonly) |
| 1453 | DBUG_RETURN(FALSE); |
| 1454 | |
| 1455 | LEX *lex= thd->lex; |
| 1456 | |
| 1457 | /* Super user is allowed to do changes */ |
| 1458 | if (((ulong)(thd->security_ctx->master_access & SUPER_ACL) == |
| 1459 | (ulong)SUPER_ACL)) |
| 1460 | DBUG_RETURN(FALSE); |
| 1461 | |
| 1462 | /* Check if command doesn't update anything */ |
| 1463 | if (!(sql_command_flags[lex->sql_command] & CF_CHANGES_DATA)) |
| 1464 | DBUG_RETURN(FALSE); |
| 1465 | |
| 1466 | /* Multi update is an exception and is dealt with later. */ |
| 1467 | if (lex->sql_command == SQLCOM_UPDATE_MULTI) |
| 1468 | DBUG_RETURN(FALSE); |
| 1469 | |
| 1470 | /* |
| 1471 | a table-to-be-created is not in the temp table list yet, |
| 1472 | so CREATE TABLE needs a special treatment |
| 1473 | */ |
| 1474 | if (lex->sql_command == SQLCOM_CREATE_TABLE) |
| 1475 | DBUG_RETURN(!lex->tmp_table()); |
| 1476 | |
| 1477 | /* |
| 1478 | a table-to-be-dropped might not exist (DROP TEMPORARY TABLE IF EXISTS), |
| 1479 | cannot use the temp table list either. |
| 1480 | */ |
| 1481 | if (lex->sql_command == SQLCOM_DROP_TABLE && lex->tmp_table()) |
| 1482 | DBUG_RETURN(FALSE); |
| 1483 | |
| 1484 | /* Check if we created or dropped databases */ |
| 1485 | if ((sql_command_flags[lex->sql_command] & CF_DB_CHANGE)) |
| 1486 | DBUG_RETURN(TRUE); |
| 1487 | |
| 1488 | if (some_non_temp_table_to_be_updated(thd, all_tables)) |
| 1489 | DBUG_RETURN(TRUE); |
| 1490 | |
| 1491 | /* Assuming that only temporary tables are modified. */ |
| 1492 | DBUG_RETURN(FALSE); |
| 1493 | } |
| 1494 | |
| 1495 | |
| 1496 | /** |
| 1497 | check COM_MULTI packet |
| 1498 | |
| 1499 | @param thd thread handle |
| 1500 | @param packet pointer on the packet of commands |
| 1501 | @param packet_length length of this packet |
| 1502 | |
| 1503 | @retval 0 - Error |
| 1504 | @retval # - Number of commands in the batch |
| 1505 | */ |
| 1506 | |
| 1507 | uint maria_multi_check(THD *thd, char *packet, size_t packet_length) |
| 1508 | { |
| 1509 | uint counter= 0; |
| 1510 | DBUG_ENTER("maria_multi_check" ); |
| 1511 | while (packet_length) |
| 1512 | { |
| 1513 | char *packet_start= packet; |
| 1514 | size_t subpacket_length= net_field_length((uchar **)&packet_start); |
| 1515 | size_t length_length= packet_start - packet; |
| 1516 | // length of command + 3 bytes where that length was stored |
| 1517 | DBUG_PRINT("info" , ("sub-packet length: %zu + %zu command: %x" , |
| 1518 | subpacket_length, length_length, |
| 1519 | packet_start[3])); |
| 1520 | |
| 1521 | if (subpacket_length == 0 || |
| 1522 | (subpacket_length + length_length) > packet_length) |
| 1523 | { |
| 1524 | my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR), |
| 1525 | MYF(0)); |
| 1526 | DBUG_RETURN(0); |
| 1527 | } |
| 1528 | |
| 1529 | counter++; |
| 1530 | packet= packet_start + subpacket_length; |
| 1531 | packet_length-= (subpacket_length + length_length); |
| 1532 | } |
| 1533 | DBUG_RETURN(counter); |
| 1534 | } |
| 1535 | |
| 1536 | |
| 1537 | /** |
| 1538 | Perform one connection-level (COM_XXXX) command. |
| 1539 | |
| 1540 | @param command type of command to perform |
| 1541 | @param thd connection handle |
| 1542 | @param packet data for the command, packet is always null-terminated |
| 1543 | @param packet_length length of packet + 1 (to show that data is |
| 1544 | null-terminated) except for COM_SLEEP, where it |
| 1545 | can be zero. |
| 1546 | @param is_com_multi recursive call from COM_MULTI |
| 1547 | @param is_next_command there will be more command in the COM_MULTI batch |
| 1548 | |
| 1549 | @todo |
| 1550 | set thd->lex->sql_command to SQLCOM_END here. |
| 1551 | @todo |
| 1552 | The following has to be changed to an 8 byte integer |
| 1553 | |
| 1554 | @retval |
| 1555 | 0 ok |
| 1556 | @retval |
| 1557 | 1 request of thread shutdown, i. e. if command is |
| 1558 | COM_QUIT/COM_SHUTDOWN |
| 1559 | */ |
| 1560 | bool dispatch_command(enum enum_server_command command, THD *thd, |
| 1561 | char* packet, uint packet_length, bool is_com_multi, |
| 1562 | bool is_next_command) |
| 1563 | { |
| 1564 | NET *net= &thd->net; |
| 1565 | bool error= 0; |
| 1566 | bool do_end_of_statement= true; |
| 1567 | DBUG_ENTER("dispatch_command" ); |
| 1568 | DBUG_PRINT("info" , ("command: %d %s" , command, |
| 1569 | (command_name[command].str != 0 ? |
| 1570 | command_name[command].str : |
| 1571 | "<?>" ))); |
| 1572 | bool drop_more_results= 0; |
| 1573 | |
| 1574 | /* keep it withing 1 byte */ |
| 1575 | compile_time_assert(COM_END == 255); |
| 1576 | |
| 1577 | #ifdef WITH_WSREP |
| 1578 | if (WSREP(thd)) |
| 1579 | { |
| 1580 | if (!thd->in_multi_stmt_transaction_mode()) |
| 1581 | { |
| 1582 | thd->wsrep_PA_safe= true; |
| 1583 | } |
| 1584 | |
| 1585 | mysql_mutex_lock(&thd->LOCK_thd_data); |
| 1586 | thd->wsrep_query_state= QUERY_EXEC; |
| 1587 | if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) |
| 1588 | { |
| 1589 | thd->wsrep_conflict_state= NO_CONFLICT; |
| 1590 | } |
| 1591 | if (thd->wsrep_conflict_state== MUST_ABORT) |
| 1592 | { |
| 1593 | wsrep_client_rollback(thd); |
| 1594 | } |
| 1595 | /* We let COM_QUIT and COM_STMT_CLOSE to execute even if wsrep aborted. */ |
| 1596 | if (thd->wsrep_conflict_state == ABORTED && |
| 1597 | command != COM_STMT_CLOSE && command != COM_QUIT) |
| 1598 | { |
| 1599 | my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction" , |
| 1600 | MYF(0)); |
| 1601 | WSREP_DEBUG("Deadlock error for: %s" , thd->query()); |
| 1602 | mysql_mutex_unlock(&thd->LOCK_thd_data); |
| 1603 | thd->reset_killed(); |
| 1604 | thd->mysys_var->abort = 0; |
| 1605 | thd->wsrep_conflict_state = NO_CONFLICT; |
| 1606 | thd->wsrep_retry_counter = 0; |
| 1607 | goto dispatch_end; |
| 1608 | } |
| 1609 | mysql_mutex_unlock(&thd->LOCK_thd_data); |
| 1610 | } |
| 1611 | #endif /* WITH_WSREP */ |
| 1612 | #if defined(ENABLED_PROFILING) |
| 1613 | thd->profiling.start_new_query(); |
| 1614 | #endif |
| 1615 | MYSQL_COMMAND_START(thd->thread_id, command, |
| 1616 | &thd->security_ctx->priv_user[0], |
| 1617 | (char *) thd->security_ctx->host_or_ip); |
| 1618 | |
| 1619 | DBUG_EXECUTE_IF("crash_dispatch_command_before" , |
| 1620 | { DBUG_PRINT("crash_dispatch_command_before" , ("now" )); |
| 1621 | DBUG_SUICIDE(); }); |
| 1622 | |
| 1623 | /* Performance Schema Interface instrumentation, begin */ |
| 1624 | thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, |
| 1625 | com_statement_info[command]. |
| 1626 | m_key); |
| 1627 | /* |
| 1628 | We should always call reset_for_next_command() before a query. |
| 1629 | mysql_parse() will do this for queries. Ensure it's also done |
| 1630 | for other commands. |
| 1631 | */ |
| 1632 | if (command != COM_QUERY) |
| 1633 | thd->reset_for_next_command(); |
| 1634 | thd->set_command(command); |
| 1635 | |
| 1636 | /* |
| 1637 | thd->variables.log_slow_disabled_statements defines which statements |
| 1638 | are logged to slow log |
| 1639 | */ |
| 1640 | thd->enable_slow_log= thd->variables.sql_log_slow; |
| 1641 | thd->query_plan_flags= QPLAN_INIT; |
| 1642 | thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ |
| 1643 | thd->reset_kill_query(); |
| 1644 | |
| 1645 | DEBUG_SYNC(thd,"dispatch_command_before_set_time" ); |
| 1646 | |
| 1647 | thd->set_time(); |
| 1648 | if (!(server_command_flags[command] & CF_SKIP_QUERY_ID)) |
| 1649 | thd->set_query_id(next_query_id()); |
| 1650 | else |
| 1651 | { |
| 1652 | /* |
| 1653 | ping, get statistics or similar stateless command. |
| 1654 | No reason to increase query id here. |
| 1655 | */ |
| 1656 | thd->set_query_id(get_query_id()); |
| 1657 | } |
| 1658 | |
| 1659 | if (!(server_command_flags[command] & CF_SKIP_QUESTIONS)) |
| 1660 | statistic_increment(thd->status_var.questions, &LOCK_status); |
| 1661 | |
| 1662 | /* Copy data for user stats */ |
| 1663 | if ((thd->userstat_running= opt_userstat_running)) |
| 1664 | { |
| 1665 | thd->start_cpu_time= my_getcputime(); |
| 1666 | memcpy(&thd->org_status_var, &thd->status_var, sizeof(thd->status_var)); |
| 1667 | thd->select_commands= thd->update_commands= thd->other_commands= 0; |
| 1668 | } |
| 1669 | |
| 1670 | /** |
| 1671 | Clear the set of flags that are expected to be cleared at the |
| 1672 | beginning of each command. |
| 1673 | */ |
| 1674 | thd->server_status&= ~SERVER_STATUS_CLEAR_SET; |
| 1675 | if (is_next_command) |
| 1676 | { |
| 1677 | drop_more_results= !MY_TEST(thd->server_status & |
| 1678 | SERVER_MORE_RESULTS_EXISTS); |
| 1679 | thd->server_status|= SERVER_MORE_RESULTS_EXISTS; |
| 1680 | if (is_com_multi) |
| 1681 | thd->get_stmt_da()->set_skip_flush(); |
| 1682 | } |
| 1683 | |
| 1684 | switch (command) { |
| 1685 | case COM_INIT_DB: |
| 1686 | { |
| 1687 | LEX_CSTRING tmp; |
| 1688 | status_var_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB]); |
| 1689 | if (unlikely(thd->copy_with_error(system_charset_info, (LEX_STRING*) &tmp, |
| 1690 | thd->charset(), packet, packet_length))) |
| 1691 | break; |
| 1692 | if (!mysql_change_db(thd, &tmp, FALSE)) |
| 1693 | { |
| 1694 | general_log_write(thd, command, thd->db.str, thd->db.length); |
| 1695 | my_ok(thd); |
| 1696 | } |
| 1697 | break; |
| 1698 | } |
| 1699 | #ifdef HAVE_REPLICATION |
| 1700 | case COM_REGISTER_SLAVE: |
| 1701 | { |
| 1702 | status_var_increment(thd->status_var.com_register_slave); |
| 1703 | if (!register_slave(thd, (uchar*)packet, packet_length)) |
| 1704 | my_ok(thd); |
| 1705 | break; |
| 1706 | } |
| 1707 | #endif |
| 1708 | case COM_RESET_CONNECTION: |
| 1709 | { |
| 1710 | thd->status_var.com_other++; |
| 1711 | thd->change_user(); |
| 1712 | thd->clear_error(); // if errors from rollback |
| 1713 | my_ok(thd, 0, 0, 0); |
| 1714 | break; |
| 1715 | } |
| 1716 | case COM_CHANGE_USER: |
| 1717 | { |
| 1718 | int auth_rc; |
| 1719 | status_var_increment(thd->status_var.com_other); |
| 1720 | |
| 1721 | thd->change_user(); |
| 1722 | thd->clear_error(); // if errors from rollback |
| 1723 | |
| 1724 | /* acl_authenticate() takes the data from net->read_pos */ |
| 1725 | net->read_pos= (uchar*)packet; |
| 1726 | |
| 1727 | LEX_CSTRING save_db= thd->db; |
| 1728 | USER_CONN *save_user_connect= thd->user_connect; |
| 1729 | Security_context save_security_ctx= *thd->security_ctx; |
| 1730 | CHARSET_INFO *save_character_set_client= |
| 1731 | thd->variables.character_set_client; |
| 1732 | CHARSET_INFO *save_collation_connection= |
| 1733 | thd->variables.collation_connection; |
| 1734 | CHARSET_INFO *save_character_set_results= |
| 1735 | thd->variables.character_set_results; |
| 1736 | |
| 1737 | /* Ensure we don't free security_ctx->user in case we have to revert */ |
| 1738 | thd->security_ctx->user= 0; |
| 1739 | thd->user_connect= 0; |
| 1740 | |
| 1741 | /* |
| 1742 | to limit COM_CHANGE_USER ability to brute-force passwords, |
| 1743 | we only allow three unsuccessful COM_CHANGE_USER per connection. |
| 1744 | */ |
| 1745 | if (thd->failed_com_change_user >= 3) |
| 1746 | { |
| 1747 | my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd,ER_UNKNOWN_COM_ERROR), |
| 1748 | MYF(0)); |
| 1749 | auth_rc= 1; |
| 1750 | } |
| 1751 | else |
| 1752 | auth_rc= acl_authenticate(thd, packet_length); |
| 1753 | |
| 1754 | mysql_audit_notify_connection_change_user(thd); |
| 1755 | if (auth_rc) |
| 1756 | { |
| 1757 | /* Free user if allocated by acl_authenticate */ |
| 1758 | my_free(const_cast<char*>(thd->security_ctx->user)); |
| 1759 | *thd->security_ctx= save_security_ctx; |
| 1760 | if (thd->user_connect) |
| 1761 | decrease_user_connections(thd->user_connect); |
| 1762 | thd->user_connect= save_user_connect; |
| 1763 | thd->reset_db(&save_db); |
| 1764 | thd->update_charset(save_character_set_client, save_collation_connection, |
| 1765 | save_character_set_results); |
| 1766 | thd->failed_com_change_user++; |
| 1767 | my_sleep(1000000); |
| 1768 | } |
| 1769 | else |
| 1770 | { |
| 1771 | #ifndef NO_EMBEDDED_ACCESS_CHECKS |
| 1772 | /* we've authenticated new user */ |
| 1773 | if (save_user_connect) |
| 1774 | decrease_user_connections(save_user_connect); |
| 1775 | #endif /* NO_EMBEDDED_ACCESS_CHECKS */ |
| 1776 | my_free((char*) save_db.str); |
| 1777 | my_free(const_cast<char*>(save_security_ctx.user)); |
| 1778 | } |
| 1779 | break; |
| 1780 | } |
| 1781 | case COM_STMT_BULK_EXECUTE: |
| 1782 | { |
| 1783 | mysqld_stmt_bulk_execute(thd, packet, packet_length); |
| 1784 | break; |
| 1785 | } |
| 1786 | case COM_STMT_EXECUTE: |
| 1787 | { |
| 1788 | mysqld_stmt_execute(thd, packet, packet_length); |
| 1789 | break; |
| 1790 | } |
| 1791 | case COM_STMT_FETCH: |
| 1792 | { |
| 1793 | mysqld_stmt_fetch(thd, packet, packet_length); |
| 1794 | break; |
| 1795 | } |
| 1796 | case COM_STMT_SEND_LONG_DATA: |
| 1797 | { |
| 1798 | mysql_stmt_get_longdata(thd, packet, packet_length); |
| 1799 | break; |
| 1800 | } |
| 1801 | case COM_STMT_PREPARE: |
| 1802 | { |
| 1803 | mysqld_stmt_prepare(thd, packet, packet_length); |
| 1804 | break; |
| 1805 | } |
| 1806 | case COM_STMT_CLOSE: |
| 1807 | { |
| 1808 | mysqld_stmt_close(thd, packet); |
| 1809 | break; |
| 1810 | } |
| 1811 | case COM_STMT_RESET: |
| 1812 | { |
| 1813 | mysqld_stmt_reset(thd, packet); |
| 1814 | break; |
| 1815 | } |
| 1816 | case COM_QUERY: |
| 1817 | { |
| 1818 | DBUG_ASSERT(thd->m_digest == NULL); |
| 1819 | thd->m_digest= & thd->m_digest_state; |
| 1820 | thd->m_digest->reset(thd->m_token_array, max_digest_length); |
| 1821 | |
| 1822 | if (unlikely(alloc_query(thd, packet, packet_length))) |
| 1823 | break; // fatal error is set |
| 1824 | MYSQL_QUERY_START(thd->query(), thd->thread_id, |
| 1825 | thd->get_db(), |
| 1826 | &thd->security_ctx->priv_user[0], |
| 1827 | (char *) thd->security_ctx->host_or_ip); |
| 1828 | char *packet_end= thd->query() + thd->query_length(); |
| 1829 | general_log_write(thd, command, thd->query(), thd->query_length()); |
| 1830 | DBUG_PRINT("query" ,("%-.4096s" ,thd->query())); |
| 1831 | #if defined(ENABLED_PROFILING) |
| 1832 | thd->profiling.set_query_source(thd->query(), thd->query_length()); |
| 1833 | #endif |
| 1834 | MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), |
| 1835 | thd->query_length()); |
| 1836 | |
| 1837 | Parser_state parser_state; |
| 1838 | if (unlikely(parser_state.init(thd, thd->query(), thd->query_length()))) |
| 1839 | break; |
| 1840 | |
| 1841 | if (WSREP_ON) |
| 1842 | wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state, |
| 1843 | is_com_multi, is_next_command); |
| 1844 | else |
| 1845 | mysql_parse(thd, thd->query(), thd->query_length(), &parser_state, |
| 1846 | is_com_multi, is_next_command); |
| 1847 | |
| 1848 | while (!thd->killed && (parser_state.m_lip.found_semicolon != NULL) && |
| 1849 | ! thd->is_error()) |
| 1850 | { |
| 1851 | thd->get_stmt_da()->set_skip_flush(); |
| 1852 | /* |
| 1853 | Multiple queries exist, execute them individually |
| 1854 | */ |
| 1855 | char *beginning_of_next_stmt= (char*) parser_state.m_lip.found_semicolon; |
| 1856 | |
| 1857 | #ifdef WITH_ARIA_STORAGE_ENGINE |
| 1858 | ha_maria::implicit_commit(thd, FALSE); |
| 1859 | #endif |
| 1860 | |
| 1861 | /* Finalize server status flags after executing a statement. */ |
| 1862 | thd->update_server_status(); |
| 1863 | thd->protocol->end_statement(); |
| 1864 | query_cache_end_of_result(thd); |
| 1865 | |
| 1866 | mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_STATUS, |
| 1867 | thd->get_stmt_da()->is_error() |
| 1868 | ? thd->get_stmt_da()->sql_errno() |
| 1869 | : 0, |
| 1870 | command_name[command].str); |
| 1871 | |
| 1872 | ulong length= (ulong)(packet_end - beginning_of_next_stmt); |
| 1873 | |
| 1874 | log_slow_statement(thd); |
| 1875 | DBUG_ASSERT(!thd->apc_target.is_enabled()); |
| 1876 | |
| 1877 | /* Remove garbage at start of query */ |
| 1878 | while (length > 0 && my_isspace(thd->charset(), *beginning_of_next_stmt)) |
| 1879 | { |
| 1880 | beginning_of_next_stmt++; |
| 1881 | length--; |
| 1882 | } |
| 1883 | |
| 1884 | /* PSI end */ |
| 1885 | MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); |
| 1886 | thd->m_statement_psi= NULL; |
| 1887 | thd->m_digest= NULL; |
| 1888 | |
| 1889 | /* DTRACE end */ |
| 1890 | if (MYSQL_QUERY_DONE_ENABLED()) |
| 1891 | { |
| 1892 | MYSQL_QUERY_DONE(thd->is_error()); |
| 1893 | } |
| 1894 | |
| 1895 | #if defined(ENABLED_PROFILING) |
| 1896 | thd->profiling.finish_current_query(); |
| 1897 | thd->profiling.start_new_query("continuing" ); |
| 1898 | thd->profiling.set_query_source(beginning_of_next_stmt, length); |
| 1899 | #endif |
| 1900 | |
| 1901 | /* DTRACE begin */ |
| 1902 | MYSQL_QUERY_START(beginning_of_next_stmt, thd->thread_id, |
| 1903 | thd->get_db(), |
| 1904 | &thd->security_ctx->priv_user[0], |
| 1905 | (char *) thd->security_ctx->host_or_ip); |
| 1906 | |
| 1907 | /* PSI begin */ |
| 1908 | thd->m_digest= & thd->m_digest_state; |
| 1909 | |
| 1910 | thd->m_statement_psi= MYSQL_START_STATEMENT(&thd->m_statement_state, |
| 1911 | com_statement_info[command].m_key, |
| 1912 | thd->db.str, thd->db.length, |
| 1913 | thd->charset()); |
| 1914 | THD_STAGE_INFO(thd, stage_init); |
| 1915 | MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, beginning_of_next_stmt, |
| 1916 | length); |
| 1917 | |
| 1918 | thd->set_query_and_id(beginning_of_next_stmt, length, |
| 1919 | thd->charset(), next_query_id()); |
| 1920 | |
| 1921 | /* |
| 1922 | Count each statement from the client. |
| 1923 | */ |
| 1924 | statistic_increment(thd->status_var.questions, &LOCK_status); |
| 1925 | |
| 1926 | if(!WSREP(thd)) |
| 1927 | thd->set_time(); /* Reset the query start time. */ |
| 1928 | |
| 1929 | parser_state.reset(beginning_of_next_stmt, length); |
| 1930 | |
| 1931 | if (WSREP_ON) |
| 1932 | wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state, |
| 1933 | is_com_multi, is_next_command); |
| 1934 | else |
| 1935 | mysql_parse(thd, beginning_of_next_stmt, length, &parser_state, |
| 1936 | is_com_multi, is_next_command); |
| 1937 | |
| 1938 | } |
| 1939 | |
| 1940 | DBUG_PRINT("info" ,("query ready" )); |
| 1941 | break; |
| 1942 | } |
| 1943 | case COM_FIELD_LIST: // This isn't actually needed |
| 1944 | #ifdef DONT_ALLOW_SHOW_COMMANDS |
| 1945 | my_message(ER_NOT_ALLOWED_COMMAND, ER_THD(thd, ER_NOT_ALLOWED_COMMAND), |
| 1946 | MYF(0)); /* purecov: inspected */ |
| 1947 | break; |
| 1948 | #else |
| 1949 | { |
| 1950 | char *fields, *packet_end= packet + packet_length, *arg_end; |
| 1951 | /* Locked closure of all tables */ |
| 1952 | TABLE_LIST table_list; |
| 1953 | LEX_STRING table_name; |
| 1954 | LEX_CSTRING db; |
| 1955 | /* |
| 1956 | SHOW statements should not add the used tables to the list of tables |
| 1957 | used in a transaction. |
| 1958 | */ |
| 1959 | MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); |
| 1960 | |
| 1961 | status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]); |
| 1962 | if (thd->copy_db_to(&db)) |
| 1963 | break; |
| 1964 | /* |
| 1965 | We have name + wildcard in packet, separated by endzero |
| 1966 | (The packet is guaranteed to end with an end zero) |
| 1967 | */ |
| 1968 | arg_end= strend(packet); |
| 1969 | uint arg_length= (uint)(arg_end - packet); |
| 1970 | |
| 1971 | /* Check given table name length. */ |
| 1972 | if (packet_length - arg_length > NAME_LEN + 1 || arg_length > SAFE_NAME_LEN) |
| 1973 | { |
| 1974 | my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR), |
| 1975 | MYF(0)); |
| 1976 | break; |
| 1977 | } |
| 1978 | thd->convert_string(&table_name, system_charset_info, |
| 1979 | packet, arg_length, thd->charset()); |
| 1980 | if (check_table_name(table_name.str, table_name.length, FALSE)) |
| 1981 | { |
| 1982 | /* this is OK due to convert_string() null-terminating the string */ |
| 1983 | my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str); |
| 1984 | break; |
| 1985 | } |
| 1986 | packet= arg_end + 1; |
| 1987 | // thd->reset_for_next_command reset state => restore it |
| 1988 | if (is_next_command) |
| 1989 | { |
| 1990 | thd->server_status|= SERVER_MORE_RESULTS_EXISTS; |
| 1991 | if (is_com_multi) |
| 1992 | thd->get_stmt_da()->set_skip_flush(); |
| 1993 | } |
| 1994 | |
| 1995 | lex_start(thd); |
| 1996 | /* Must be before we init the table list. */ |
| 1997 | if (lower_case_table_names) |
| 1998 | { |
| 1999 | table_name.length= my_casedn_str(files_charset_info, table_name.str); |
| 2000 | db.length= my_casedn_str(files_charset_info, (char*) db.str); |
| 2001 | } |
| 2002 | table_list.init_one_table(&db, (LEX_CSTRING*) &table_name, 0, TL_READ); |
| 2003 | /* |
| 2004 | Init TABLE_LIST members necessary when the undelrying |
| 2005 | table is view. |
| 2006 | */ |
| 2007 | table_list.select_lex= &(thd->lex->select_lex); |
| 2008 | thd->lex-> |
| 2009 | select_lex.table_list.link_in_list(&table_list, |
| 2010 | &table_list.next_local); |
| 2011 | thd->lex->add_to_query_tables(&table_list); |
| 2012 | |
| 2013 | if (is_infoschema_db(&table_list.db)) |
| 2014 | { |
| 2015 | ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, &table_list.alias); |
| 2016 | if (schema_table) |
| 2017 | table_list.schema_table= schema_table; |
| 2018 | } |
| 2019 | |
| 2020 | uint query_length= (uint) (packet_end - packet); // Don't count end \0 |
| 2021 | if (!(fields= (char *) thd->memdup(packet, query_length + 1))) |
| 2022 | break; |
| 2023 | thd->set_query(fields, query_length); |
| 2024 | general_log_print(thd, command, "%s %s" , table_list.table_name.str, |
| 2025 | fields); |
| 2026 | |
| 2027 | if (thd->open_temporary_tables(&table_list)) |
| 2028 | break; |
| 2029 | |
| 2030 | if (check_table_access(thd, SELECT_ACL, &table_list, |
| 2031 | TRUE, UINT_MAX, FALSE)) |
| 2032 | break; |
| 2033 | /* |
| 2034 | Turn on an optimization relevant if the underlying table |
| 2035 | is a view: do not fill derived tables. |
| 2036 | */ |
| 2037 | thd->lex->sql_command= SQLCOM_SHOW_FIELDS; |
| 2038 | |
| 2039 | mysqld_list_fields(thd,&table_list,fields); |
| 2040 | thd->lex->unit.cleanup(); |
| 2041 | /* No need to rollback statement transaction, it's not started. */ |
| 2042 | DBUG_ASSERT(thd->transaction.stmt.is_empty()); |
| 2043 | close_thread_tables(thd); |
| 2044 | thd->mdl_context.rollback_to_savepoint(mdl_savepoint); |
| 2045 | |
| 2046 | if (thd->transaction_rollback_request) |
| 2047 | { |
| 2048 | /* |
| 2049 | Transaction rollback was requested since MDL deadlock was |
| 2050 | discovered while trying to open tables. Rollback transaction |
| 2051 | in all storage engines including binary log and release all |
| 2052 | locks. |
| 2053 | */ |
| 2054 | trans_rollback_implicit(thd); |
| 2055 | thd->mdl_context.release_transactional_locks(); |
| 2056 | } |
| 2057 | |
| 2058 | thd->cleanup_after_query(); |
| 2059 | break; |
| 2060 | } |
| 2061 | #endif |
| 2062 | case COM_QUIT: |
| 2063 | /* Note: We don't calculate statistics for this command */ |
| 2064 | |
| 2065 | /* Ensure that quit works even if max_mem_used is set */ |
| 2066 | thd->variables.max_mem_used= LONGLONG_MAX; |
| 2067 | general_log_print(thd, command, NullS); |
| 2068 | net->error=0; // Don't give 'abort' message |
| 2069 | thd->get_stmt_da()->disable_status(); // Don't send anything back |
| 2070 | error=TRUE; // End server |
| 2071 | break; |
| 2072 | #ifndef EMBEDDED_LIBRARY |
| 2073 | case COM_BINLOG_DUMP: |
| 2074 | { |
| 2075 | ulong pos; |
| 2076 | ushort flags; |
| 2077 | uint32 slave_server_id; |
| 2078 | |
| 2079 | status_var_increment(thd->status_var.com_other); |
| 2080 | |
| 2081 | thd->prepare_logs_for_admin_command(); |
| 2082 | if (check_global_access(thd, REPL_SLAVE_ACL)) |
| 2083 | break; |
| 2084 | |
| 2085 | /* TODO: The following has to be changed to an 8 byte integer */ |
| 2086 | pos = uint4korr(packet); |
| 2087 | flags = uint2korr(packet + 4); |
| 2088 | thd->variables.server_id=0; /* avoid suicide */ |
| 2089 | if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0 |
| 2090 | kill_zombie_dump_threads(slave_server_id); |
| 2091 | thd->variables.server_id = slave_server_id; |
| 2092 | |
| 2093 | const char *name= packet + 10; |
| 2094 | size_t nlen= strlen(name); |
| 2095 | |
| 2096 | general_log_print(thd, command, "Log: '%s' Pos: %lu" , name, pos); |
| 2097 | if (nlen < FN_REFLEN) |
| 2098 | mysql_binlog_send(thd, thd->strmake(name, nlen), (my_off_t)pos, flags); |
| 2099 | unregister_slave(thd,1,1); |
| 2100 | /* fake COM_QUIT -- if we get here, the thread needs to terminate */ |
| 2101 | error = TRUE; |
| 2102 | break; |
| 2103 | } |
| 2104 | #endif |
| 2105 | case COM_REFRESH: |
| 2106 | { |
| 2107 | int not_used; |
| 2108 | |
| 2109 | /* |
| 2110 | Initialize thd->lex since it's used in many base functions, such as |
| 2111 | open_tables(). Otherwise, it remains unitialized and may cause crash |
| 2112 | during execution of COM_REFRESH. |
| 2113 | */ |
| 2114 | lex_start(thd); |
| 2115 | |
| 2116 | status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]); |
| 2117 | ulonglong options= (ulonglong) (uchar) packet[0]; |
| 2118 | if (trans_commit_implicit(thd)) |
| 2119 | break; |
| 2120 | thd->mdl_context.release_transactional_locks(); |
| 2121 | if (check_global_access(thd,RELOAD_ACL)) |
| 2122 | break; |
| 2123 | general_log_print(thd, command, NullS); |
| 2124 | #ifndef DBUG_OFF |
| 2125 | bool debug_simulate= FALSE; |
| 2126 | DBUG_EXECUTE_IF("simulate_detached_thread_refresh" , debug_simulate= TRUE;); |
| 2127 | if (debug_simulate) |
| 2128 | { |
| 2129 | /* |
| 2130 | Simulate a reload without a attached thread session. |
| 2131 | Provides a environment similar to that of when the |
| 2132 | server receives a SIGHUP signal and reloads caches |
| 2133 | and flushes tables. |
| 2134 | */ |
| 2135 | bool res; |
| 2136 | set_current_thd(0); |
| 2137 | res= reload_acl_and_cache(NULL, options | REFRESH_FAST, |
| 2138 | NULL, ¬_used); |
| 2139 | set_current_thd(thd); |
| 2140 | if (res) |
| 2141 | break; |
| 2142 | } |
| 2143 | else |
| 2144 | #endif |
| 2145 | { |
| 2146 | thd->lex->relay_log_connection_name= empty_clex_str; |
| 2147 | if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) |
| 2148 | break; |
| 2149 | } |
| 2150 | if (trans_commit_implicit(thd)) |
| 2151 | break; |
| 2152 | close_thread_tables(thd); |
| 2153 | thd->mdl_context.release_transactional_locks(); |
| 2154 | my_ok(thd); |
| 2155 | break; |
| 2156 | } |
| 2157 | #ifndef EMBEDDED_LIBRARY |
| 2158 | case COM_SHUTDOWN: |
| 2159 | { |
| 2160 | status_var_increment(thd->status_var.com_other); |
| 2161 | if (check_global_access(thd,SHUTDOWN_ACL)) |
| 2162 | break; /* purecov: inspected */ |
| 2163 | /* |
| 2164 | If the client is < 4.1.3, it is going to send us no argument; then |
| 2165 | packet_length is 0, packet[0] is the end 0 of the packet. Note that |
| 2166 | SHUTDOWN_DEFAULT is 0. If client is >= 4.1.3, the shutdown level is in |
| 2167 | packet[0]. |
| 2168 | */ |
| 2169 | enum mysql_enum_shutdown_level level; |
| 2170 | level= (enum mysql_enum_shutdown_level) (uchar) packet[0]; |
| 2171 | if (level == SHUTDOWN_DEFAULT) |
| 2172 | level= SHUTDOWN_WAIT_ALL_BUFFERS; // soon default will be configurable |
| 2173 | else if (level != SHUTDOWN_WAIT_ALL_BUFFERS) |
| 2174 | { |
| 2175 | my_error(ER_NOT_SUPPORTED_YET, MYF(0), "this shutdown level" ); |
| 2176 | break; |
| 2177 | } |
| 2178 | DBUG_PRINT("quit" ,("Got shutdown command for level %u" , level)); |
| 2179 | general_log_print(thd, command, NullS); |
| 2180 | my_eof(thd); |
| 2181 | kill_mysql(thd); |
| 2182 | error=TRUE; |
| 2183 | break; |
| 2184 | } |
| 2185 | #endif |
| 2186 | case COM_STATISTICS: |
| 2187 | { |
| 2188 | STATUS_VAR *current_global_status_var; // Big; Don't allocate on stack |
| 2189 | ulong uptime; |
| 2190 | ulonglong queries_per_second1000; |
| 2191 | char buff[250]; |
| 2192 | uint buff_len= sizeof(buff); |
| 2193 | |
| 2194 | if (!(current_global_status_var= (STATUS_VAR*) |
| 2195 | thd->alloc(sizeof(STATUS_VAR)))) |
| 2196 | break; |
| 2197 | general_log_print(thd, command, NullS); |
| 2198 | status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS]); |
| 2199 | calc_sum_of_all_status(current_global_status_var); |
| 2200 | if (!(uptime= (ulong) (thd->start_time - server_start_time))) |
| 2201 | queries_per_second1000= 0; |
| 2202 | else |
| 2203 | queries_per_second1000= thd->query_id * 1000 / uptime; |
| 2204 | #ifndef EMBEDDED_LIBRARY |
| 2205 | size_t length= |
| 2206 | #endif |
| 2207 | my_snprintf(buff, buff_len - 1, |
| 2208 | "Uptime: %lu Threads: %d Questions: %lu " |
| 2209 | "Slow queries: %lu Opens: %lu Flush tables: %lld " |
| 2210 | "Open tables: %u Queries per second avg: %u.%03u" , |
| 2211 | uptime, |
| 2212 | (int) thread_count, (ulong) thd->query_id, |
| 2213 | current_global_status_var->long_query_count, |
| 2214 | current_global_status_var->opened_tables, |
| 2215 | tdc_refresh_version(), |
| 2216 | tc_records(), |
| 2217 | (uint) (queries_per_second1000 / 1000), |
| 2218 | (uint) (queries_per_second1000 % 1000)); |
| 2219 | #ifdef EMBEDDED_LIBRARY |
| 2220 | /* Store the buffer in permanent memory */ |
| 2221 | my_ok(thd, 0, 0, buff); |
| 2222 | #else |
| 2223 | (void) my_net_write(net, (uchar*) buff, length); |
| 2224 | (void) net_flush(net); |
| 2225 | thd->get_stmt_da()->disable_status(); |
| 2226 | #endif |
| 2227 | break; |
| 2228 | } |
| 2229 | case COM_PING: |
| 2230 | status_var_increment(thd->status_var.com_other); |
| 2231 | my_ok(thd); // Tell client we are alive |
| 2232 | break; |
| 2233 | case COM_PROCESS_INFO: |
| 2234 | status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]); |
| 2235 | if (!thd->security_ctx->priv_user[0] && |
| 2236 | check_global_access(thd, PROCESS_ACL)) |
| 2237 | break; |
| 2238 | general_log_print(thd, command, NullS); |
| 2239 | mysqld_list_processes(thd, |
| 2240 | thd->security_ctx->master_access & PROCESS_ACL ? |
| 2241 | NullS : thd->security_ctx->priv_user, 0); |
| 2242 | break; |
| 2243 | case COM_PROCESS_KILL: |
| 2244 | { |
| 2245 | status_var_increment(thd->status_var.com_stat[SQLCOM_KILL]); |
| 2246 | ulong id=(ulong) uint4korr(packet); |
| 2247 | sql_kill(thd, id, KILL_CONNECTION_HARD, KILL_TYPE_ID); |
| 2248 | break; |
| 2249 | } |
| 2250 | case COM_SET_OPTION: |
| 2251 | { |
| 2252 | status_var_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION]); |
| 2253 | uint opt_command= uint2korr(packet); |
| 2254 | |
| 2255 | switch (opt_command) { |
| 2256 | case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON: |
| 2257 | thd->client_capabilities|= CLIENT_MULTI_STATEMENTS; |
| 2258 | my_eof(thd); |
| 2259 | break; |
| 2260 | case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF: |
| 2261 | thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS; |
| 2262 | my_eof(thd); |
| 2263 | break; |
| 2264 | default: |
| 2265 | my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR), |
| 2266 | MYF(0)); |
| 2267 | break; |
| 2268 | } |
| 2269 | break; |
| 2270 | } |
| 2271 | case COM_DEBUG: |
| 2272 | status_var_increment(thd->status_var.com_other); |
| 2273 | if (check_global_access(thd, SUPER_ACL)) |
| 2274 | break; /* purecov: inspected */ |
| 2275 | mysql_print_status(); |
| 2276 | general_log_print(thd, command, NullS); |
| 2277 | my_eof(thd); |
| 2278 | break; |
| 2279 | case COM_MULTI: |
| 2280 | { |
| 2281 | uint counter; |
| 2282 | uint current_com= 0; |
| 2283 | DBUG_ASSERT(!is_com_multi); |
| 2284 | if (!(thd->client_capabilities & CLIENT_MULTI_RESULTS)) |
| 2285 | { |
| 2286 | /* The client does not support multiple result sets being sent back */ |
| 2287 | my_error(ER_COMMULTI_BADCONTEXT, MYF(0)); |
| 2288 | break; |
| 2289 | } |
| 2290 | |
| 2291 | if (!(counter= maria_multi_check(thd, packet, packet_length))) |
| 2292 | break; |
| 2293 | |
| 2294 | { |
| 2295 | char *packet_start= packet; |
| 2296 | /* We have to store next length because it will be destroyed by '\0' */ |
| 2297 | size_t next_subpacket_length= net_field_length((uchar **)&packet_start); |
| 2298 | size_t next_length_length= packet_start - packet; |
| 2299 | unsigned char *readbuff= net->buff; |
| 2300 | |
| 2301 | if (net_allocate_new_packet(net, thd, MYF(0))) |
| 2302 | break; |
| 2303 | |
| 2304 | PSI_statement_locker *save_locker= thd->m_statement_psi; |
| 2305 | sql_digest_state *save_digest= thd->m_digest; |
| 2306 | thd->m_statement_psi= NULL; |
| 2307 | thd->m_digest= NULL; |
| 2308 | |
| 2309 | while (packet_length) |
| 2310 | { |
| 2311 | current_com++; |
| 2312 | size_t subpacket_length= next_subpacket_length + next_length_length; |
| 2313 | size_t length_length= next_length_length; |
| 2314 | if (subpacket_length < packet_length) |
| 2315 | { |
| 2316 | packet_start= packet + subpacket_length; |
| 2317 | next_subpacket_length= net_field_length((uchar**)&packet_start); |
| 2318 | next_length_length= packet_start - (packet + subpacket_length); |
| 2319 | } |
| 2320 | /* safety like in do_command() */ |
| 2321 | packet[subpacket_length]= '\0'; |
| 2322 | |
| 2323 | enum enum_server_command subcommand= |
| 2324 | fetch_command(thd, (packet + length_length)); |
| 2325 | |
| 2326 | if (server_command_flags[subcommand] & CF_NO_COM_MULTI) |
| 2327 | { |
| 2328 | my_error(ER_BAD_COMMAND_IN_MULTI, MYF(0), |
| 2329 | command_name[subcommand].str); |
| 2330 | goto com_multi_end; |
| 2331 | } |
| 2332 | |
| 2333 | if (dispatch_command(subcommand, thd, packet + (1 + length_length), |
| 2334 | (uint)(subpacket_length - (1 + length_length)), TRUE, |
| 2335 | (current_com != counter))) |
| 2336 | { |
| 2337 | DBUG_ASSERT(thd->is_error()); |
| 2338 | goto com_multi_end; |
| 2339 | } |
| 2340 | |
| 2341 | DBUG_ASSERT(subpacket_length <= packet_length); |
| 2342 | packet+= subpacket_length; |
| 2343 | packet_length-= (uint)subpacket_length; |
| 2344 | } |
| 2345 | |
| 2346 | com_multi_end: |
| 2347 | thd->m_statement_psi= save_locker; |
| 2348 | thd->m_digest= save_digest; |
| 2349 | |
| 2350 | /* release old buffer */ |
| 2351 | net_flush(net); |
| 2352 | DBUG_ASSERT(net->buff == net->write_pos); // nothing to send |
| 2353 | my_free(readbuff); |
| 2354 | } |
| 2355 | break; |
| 2356 | } |
| 2357 | case COM_SLEEP: |
| 2358 | case COM_CONNECT: // Impossible here |
| 2359 | case COM_TIME: // Impossible from client |
| 2360 | case COM_DELAYED_INSERT: |
| 2361 | case COM_END: |
| 2362 | case COM_UNIMPLEMENTED: |
| 2363 | default: |
| 2364 | my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR), |
| 2365 | MYF(0)); |
| 2366 | break; |
| 2367 | } |
| 2368 | |
| 2369 | #ifdef WITH_WSREP |
| 2370 | dispatch_end: |
| 2371 | |
| 2372 | if (WSREP(thd)) |
| 2373 | { |
| 2374 | /* |
| 2375 | MDEV-10812 |
| 2376 | In the case of COM_QUIT/COM_STMT_CLOSE thread status should be disabled. |
| 2377 | */ |
| 2378 | DBUG_ASSERT((command != COM_QUIT && command != COM_STMT_CLOSE) |
| 2379 | || thd->get_stmt_da()->is_disabled()); |
| 2380 | /* wsrep BF abort in query exec phase */ |
| 2381 | mysql_mutex_lock(&thd->LOCK_thd_data); |
| 2382 | do_end_of_statement= thd->wsrep_conflict_state != REPLAYING && |
| 2383 | thd->wsrep_conflict_state != RETRY_AUTOCOMMIT; |
| 2384 | mysql_mutex_unlock(&thd->LOCK_thd_data); |
| 2385 | } |
| 2386 | else |
| 2387 | do_end_of_statement= true; |
| 2388 | |
| 2389 | #endif /* WITH_WSREP */ |
| 2390 | |
| 2391 | if (do_end_of_statement) |
| 2392 | { |
| 2393 | DBUG_ASSERT(thd->derived_tables == NULL && |
| 2394 | (thd->open_tables == NULL || |
| 2395 | (thd->locked_tables_mode == LTM_LOCK_TABLES))); |
| 2396 | |
| 2397 | thd_proc_info(thd, "Updating status" ); |
| 2398 | /* Finalize server status flags after executing a command. */ |
| 2399 | thd->update_server_status(); |
| 2400 | if (command != COM_MULTI) |
| 2401 | { |
| 2402 | thd->protocol->end_statement(); |
| 2403 | query_cache_end_of_result(thd); |
| 2404 | } |
| 2405 | } |
| 2406 | if (drop_more_results) |
| 2407 | thd->server_status&= ~SERVER_MORE_RESULTS_EXISTS; |
| 2408 | |
| 2409 | if (likely(!thd->is_error() && !thd->killed_errno())) |
| 2410 | mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0); |
| 2411 | |
| 2412 | mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_STATUS, |
| 2413 | thd->get_stmt_da()->is_error() ? |
| 2414 | thd->get_stmt_da()->sql_errno() : 0, |
| 2415 | command_name[command].str); |
| 2416 | |
| 2417 | thd->update_all_stats(); |
| 2418 | |
| 2419 | log_slow_statement(thd); |
| 2420 | |
| 2421 | THD_STAGE_INFO(thd, stage_cleaning_up); |
| 2422 | thd->reset_query(); |
| 2423 | |
| 2424 | /* Performance Schema Interface instrumentation, end */ |
| 2425 | MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); |
| 2426 | thd->set_examined_row_count(0); // For processlist |
| 2427 | thd->set_command(COM_SLEEP); |
| 2428 | |
| 2429 | thd->m_statement_psi= NULL; |
| 2430 | thd->m_digest= NULL; |
| 2431 | |
| 2432 | if (!is_com_multi) |
| 2433 | thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory |
| 2434 | |
| 2435 | thd->reset_kill_query(); /* Ensure that killed_errmsg is released */ |
| 2436 | free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); |
| 2437 | |
| 2438 | #if defined(ENABLED_PROFILING) |
| 2439 | thd->profiling.finish_current_query(); |
| 2440 | #endif |
| 2441 | if (MYSQL_QUERY_DONE_ENABLED() || MYSQL_COMMAND_DONE_ENABLED()) |
| 2442 | { |
| 2443 | int res __attribute__((unused)); |
| 2444 | res= (int) thd->is_error(); |
| 2445 | if (command == COM_QUERY) |
| 2446 | { |
| 2447 | MYSQL_QUERY_DONE(res); |
| 2448 | } |
| 2449 | MYSQL_COMMAND_DONE(res); |
| 2450 | } |
| 2451 | DEBUG_SYNC(thd,"dispatch_command_end" ); |
| 2452 | |
| 2453 | /* Check that some variables are reset properly */ |
| 2454 | DBUG_ASSERT(thd->abort_on_warning == 0); |
| 2455 | thd->lex->restore_set_statement_var(); |
| 2456 | DBUG_RETURN(error); |
| 2457 | } |
| 2458 | |
| 2459 | |
| 2460 | /* |
| 2461 | Log query to slow queries, if it passes filtering |
| 2462 | |
| 2463 | @note |
| 2464 | This function must call delete_explain_query(). |
| 2465 | */ |
| 2466 | |
| 2467 | void log_slow_statement(THD *thd) |
| 2468 | { |
| 2469 | DBUG_ENTER("log_slow_statement" ); |
| 2470 | |
| 2471 | /* |
| 2472 | The following should never be true with our current code base, |
| 2473 | but better to keep this here so we don't accidently try to log a |
| 2474 | statement in a trigger or stored function |
| 2475 | */ |
| 2476 | if (unlikely(thd->in_sub_stmt)) |
| 2477 | goto end; // Don't set time for sub stmt |
| 2478 | if (!thd->enable_slow_log || !global_system_variables.sql_log_slow) |
| 2479 | goto end; |
| 2480 | |
| 2481 | if ((thd->server_status & |
| 2482 | (SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) && |
| 2483 | !(sql_command_flags[thd->last_sql_command] & CF_STATUS_COMMAND) && |
| 2484 | (!thd->variables.log_slow_filter || |
| 2485 | (thd->variables.log_slow_filter & QPLAN_NOT_USING_INDEX))) |
| 2486 | { |
| 2487 | thd->query_plan_flags|= QPLAN_NOT_USING_INDEX; |
| 2488 | /* We are always logging no index queries if enabled in filter */ |
| 2489 | thd->server_status|= SERVER_QUERY_WAS_SLOW; |
| 2490 | } |
| 2491 | |
| 2492 | /* Follow the slow log filter configuration. */ |
| 2493 | if (thd->variables.log_slow_filter && |
| 2494 | !(thd->variables.log_slow_filter & thd->query_plan_flags)) |
| 2495 | goto end; |
| 2496 | |
| 2497 | if ((thd->server_status & SERVER_QUERY_WAS_SLOW) && |
| 2498 | thd->get_examined_row_count() >= thd->variables.min_examined_row_limit) |
| 2499 | { |
| 2500 | thd->status_var.long_query_count++; |
| 2501 | /* |
| 2502 | If rate limiting of slow log writes is enabled, decide whether to log |
| 2503 | this query to the log or not. |
| 2504 | */ |
| 2505 | if (thd->variables.log_slow_rate_limit > 1 && |
| 2506 | (global_query_id % thd->variables.log_slow_rate_limit) != 0) |
| 2507 | goto end; |
| 2508 | |
| 2509 | THD_STAGE_INFO(thd, stage_logging_slow_query); |
| 2510 | slow_log_print(thd, thd->query(), thd->query_length(), |
| 2511 | thd->utime_after_query); |
| 2512 | } |
| 2513 | |
| 2514 | end: |
| 2515 | delete_explain_query(thd->lex); |
| 2516 | DBUG_VOID_RETURN; |
| 2517 | } |
| 2518 | |
| 2519 | |
| 2520 | /** |
| 2521 | Create a TABLE_LIST object for an INFORMATION_SCHEMA table. |
| 2522 | |
| 2523 | This function is used in the parser to convert a SHOW or DESCRIBE |
| 2524 | table_name command to a SELECT from INFORMATION_SCHEMA. |
| 2525 | It prepares a SELECT_LEX and a TABLE_LIST object to represent the |
| 2526 | given command as a SELECT parse tree. |
| 2527 | |
| 2528 | @param thd thread handle |
| 2529 | @param lex current lex |
| 2530 | @param table_ident table alias if it's used |
| 2531 | @param schema_table_idx the type of the INFORMATION_SCHEMA table to be |
| 2532 | created |
| 2533 | |
| 2534 | @note |
| 2535 | Due to the way this function works with memory and LEX it cannot |
| 2536 | be used outside the parser (parse tree transformations outside |
| 2537 | the parser break PS and SP). |
| 2538 | |
| 2539 | @retval |
| 2540 | 0 success |
| 2541 | @retval |
| 2542 | 1 out of memory or SHOW commands are not allowed |
| 2543 | in this version of the server. |
| 2544 | */ |
| 2545 | |
| 2546 | int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, |
| 2547 | enum enum_schema_tables schema_table_idx) |
| 2548 | { |
| 2549 | SELECT_LEX *schema_select_lex= NULL; |
| 2550 | DBUG_ENTER("prepare_schema_table" ); |
| 2551 | |
| 2552 | switch (schema_table_idx) { |
| 2553 | case SCH_SCHEMATA: |
| 2554 | #if defined(DONT_ALLOW_SHOW_COMMANDS) |
| 2555 | my_message(ER_NOT_ALLOWED_COMMAND, |
| 2556 | ER_THD(thd, ER_NOT_ALLOWED_COMMAND), MYF(0)); |
| 2557 | DBUG_RETURN(1); |
| 2558 | #else |
| 2559 | break; |
| 2560 | #endif |
| 2561 | |
| 2562 | case SCH_TABLE_NAMES: |
| 2563 | case SCH_TABLES: |
| 2564 | case SCH_VIEWS: |
| 2565 | case SCH_TRIGGERS: |
| 2566 | case SCH_EVENTS: |
| 2567 | #ifdef DONT_ALLOW_SHOW_COMMANDS |
| 2568 | my_message(ER_NOT_ALLOWED_COMMAND, |
| 2569 | ER_THD(thd, ER_NOT_ALLOWED_COMMAND), MYF(0)); |
| 2570 | DBUG_RETURN(1); |
| 2571 | #else |
| 2572 | { |
| 2573 | if (lex->select_lex.db.str == NULL && |
| 2574 | lex->copy_db_to(&lex->select_lex.db)) |
| 2575 | { |
| 2576 | DBUG_RETURN(1); |
| 2577 | } |
| 2578 | schema_select_lex= new (thd->mem_root) SELECT_LEX(); |
| 2579 | schema_select_lex->table_list.first= NULL; |
| 2580 | if (lower_case_table_names == 1) |
| 2581 | lex->select_lex.db.str= thd->strdup(lex->select_lex.db.str); |
| 2582 | schema_select_lex->db= lex->select_lex.db; |
| 2583 | /* |
| 2584 | check_db_name() may change db.str if lower_case_table_names == 1, |
| 2585 | but that's ok as the db is allocted above in this case. |
| 2586 | */ |
| 2587 | if (check_db_name((LEX_STRING*) &lex->select_lex.db)) |
| 2588 | { |
| 2589 | my_error(ER_WRONG_DB_NAME, MYF(0), lex->select_lex.db.str); |
| 2590 | DBUG_RETURN(1); |
| 2591 | } |
| 2592 | break; |
| 2593 | } |
| 2594 | #endif |
| 2595 | case SCH_COLUMNS: |
| 2596 | case SCH_STATISTICS: |
| 2597 | #ifdef DONT_ALLOW_SHOW_COMMANDS |
| 2598 | my_message(ER_NOT_ALLOWED_COMMAND, |
| 2599 | ER_THD(thd, ER_NOT_ALLOWED_COMMAND), MYF(0)); |
| 2600 | DBUG_RETURN(1); |
| 2601 | #else |
| 2602 | { |
| 2603 | DBUG_ASSERT(table_ident); |
| 2604 | TABLE_LIST **query_tables_last= lex->query_tables_last; |
| 2605 | schema_select_lex= new (thd->mem_root) SELECT_LEX(); |
| 2606 | /* 'parent_lex' is used in init_query() so it must be before it. */ |
| 2607 | schema_select_lex->parent_lex= lex; |
| 2608 | schema_select_lex->init_query(); |
| 2609 | if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ, |
| 2610 | MDL_SHARED_READ)) |
| 2611 | DBUG_RETURN(1); |
| 2612 | lex->query_tables_last= query_tables_last; |
| 2613 | break; |
| 2614 | #endif |
| 2615 | } |
| 2616 | case SCH_PROFILES: |
| 2617 | /* |
| 2618 | Mark this current profiling record to be discarded. We don't |
| 2619 | wish to have SHOW commands show up in profiling. |
| 2620 | */ |
| 2621 | #if defined(ENABLED_PROFILING) |
| 2622 | thd->profiling.discard_current_query(); |
| 2623 | #endif |
| 2624 | break; |
| 2625 | default: |
| 2626 | break; |
| 2627 | } |
| 2628 | |
| 2629 | SELECT_LEX *select_lex= lex->current_select; |
| 2630 | if (make_schema_select(thd, select_lex, get_schema_table(schema_table_idx))) |
| 2631 | DBUG_RETURN(1); |
| 2632 | |
| 2633 | select_lex->table_list.first->schema_select_lex= schema_select_lex; |
| 2634 | DBUG_RETURN(0); |
| 2635 | } |
| 2636 | |
| 2637 | |
| 2638 | /** |
| 2639 | Read query from packet and store in thd->query. |
| 2640 | Used in COM_QUERY and COM_STMT_PREPARE. |
| 2641 | |
| 2642 | Sets the following THD variables: |
| 2643 | - query |
| 2644 | - query_length |
| 2645 | |
| 2646 | @retval |
| 2647 | FALSE ok |
| 2648 | @retval |
| 2649 | TRUE error; In this case thd->fatal_error is set |
| 2650 | */ |
| 2651 | |
| 2652 | bool alloc_query(THD *thd, const char *packet, size_t packet_length) |
| 2653 | { |
| 2654 | char *query; |
| 2655 | /* Remove garbage at start and end of query */ |
| 2656 | while (packet_length > 0 && my_isspace(thd->charset(), packet[0])) |
| 2657 | { |
| 2658 | packet++; |
| 2659 | packet_length--; |
| 2660 | } |
| 2661 | const char *pos= packet + packet_length; // Point at end null |
| 2662 | while (packet_length > 0 && |
| 2663 | (pos[-1] == ';' || my_isspace(thd->charset() ,pos[-1]))) |
| 2664 | { |
| 2665 | pos--; |
| 2666 | packet_length--; |
| 2667 | } |
| 2668 | /* We must allocate some extra memory for query cache |
| 2669 | |
| 2670 | The query buffer layout is: |
| 2671 | buffer :== |
| 2672 | <statement> The input statement(s) |
| 2673 | '\0' Terminating null char (1 byte) |
| 2674 | <length> Length of following current database name (size_t) |
| 2675 | <db_name> Name of current database |
| 2676 | <flags> Flags struct |
| 2677 | */ |
| 2678 | if (! (query= (char*) thd->memdup_w_gap(packet, |
| 2679 | packet_length, |
| 2680 | 1 + thd->db.length + |
| 2681 | QUERY_CACHE_DB_LENGTH_SIZE + |
| 2682 | QUERY_CACHE_FLAGS_SIZE))) |
| 2683 | return TRUE; |
| 2684 | query[packet_length]= '\0'; |
| 2685 | /* |
| 2686 | Space to hold the name of the current database is allocated. We |
| 2687 | also store this length, in case current database is changed during |
| 2688 | execution. We might need to reallocate the 'query' buffer |
| 2689 | */ |
| 2690 | int2store(query + packet_length + 1, thd->db.length); |
| 2691 | |
| 2692 | thd->set_query(query, packet_length); |
| 2693 | |
| 2694 | /* Reclaim some memory */ |
| 2695 | thd->packet.shrink(thd->variables.net_buffer_length); |
| 2696 | thd->convert_buffer.shrink(thd->variables.net_buffer_length); |
| 2697 | |
| 2698 | return FALSE; |
| 2699 | } |
| 2700 | |
| 2701 | |
| 2702 | bool sp_process_definer(THD *thd) |
| 2703 | { |
| 2704 | DBUG_ENTER("sp_process_definer" ); |
| 2705 | |
| 2706 | LEX *lex= thd->lex; |
| 2707 | |
| 2708 | /* |
| 2709 | If the definer is not specified, this means that CREATE-statement missed |
| 2710 | DEFINER-clause. DEFINER-clause can be missed in two cases: |
| 2711 | |
| 2712 | - The user submitted a statement w/o the clause. This is a normal |
| 2713 | case, we should assign CURRENT_USER as definer. |
| 2714 | |
| 2715 | - Our slave received an updated from the master, that does not |
| 2716 | replicate definer for stored rountines. We should also assign |
| 2717 | CURRENT_USER as definer here, but also we should mark this routine |
| 2718 | as NON-SUID. This is essential for the sake of backward |
| 2719 | compatibility. |
| 2720 | |
| 2721 | The problem is the slave thread is running under "special" user (@), |
| 2722 | that actually does not exist. In the older versions we do not fail |
| 2723 | execution of a stored routine if its definer does not exist and |
| 2724 | continue the execution under the authorization of the invoker |
| 2725 | (BUG#13198). And now if we try to switch to slave-current-user (@), |
| 2726 | we will fail. |
| 2727 | |
| 2728 | Actually, this leads to the inconsistent state of master and |
| 2729 | slave (different definers, different SUID behaviour), but it seems, |
| 2730 | this is the best we can do. |
| 2731 | */ |
| 2732 | |
| 2733 | if (!lex->definer) |
| 2734 | { |
| 2735 | Query_arena original_arena; |
| 2736 | Query_arena *ps_arena= thd->activate_stmt_arena_if_needed(&original_arena); |
| 2737 | |
| 2738 | lex->definer= create_default_definer(thd, false); |
| 2739 | |
| 2740 | if (ps_arena) |
| 2741 | thd->restore_active_arena(ps_arena, &original_arena); |
| 2742 | |
| 2743 | /* Error has been already reported. */ |
| 2744 | if (lex->definer == NULL) |
| 2745 | DBUG_RETURN(TRUE); |
| 2746 | |
| 2747 | if (thd->slave_thread && lex->sphead) |
| 2748 | lex->sphead->set_suid(SP_IS_NOT_SUID); |
| 2749 | } |
| 2750 | else |
| 2751 | { |
| 2752 | LEX_USER *d= lex->definer= get_current_user(thd, lex->definer); |
| 2753 | if (!d) |
| 2754 | DBUG_RETURN(TRUE); |
| 2755 | |
| 2756 | /* |
| 2757 | If the specified definer differs from the current user or role, we |
| 2758 | should check that the current user has SUPER privilege (in order |
| 2759 | to create a stored routine under another user one must have |
| 2760 | SUPER privilege). |
| 2761 | */ |
| 2762 | bool curuser= !strcmp(d->user.str, thd->security_ctx->priv_user); |
| 2763 | bool currole= !curuser && !strcmp(d->user.str, thd->security_ctx->priv_role); |
| 2764 | bool curuserhost= curuser && d->host.str && |
| 2765 | !my_strcasecmp(system_charset_info, d->host.str, |
| 2766 | thd->security_ctx->priv_host); |
| 2767 | if (!curuserhost && !currole && |
| 2768 | check_global_access(thd, SUPER_ACL, false)) |
| 2769 | DBUG_RETURN(TRUE); |
| 2770 | } |
| 2771 | |
| 2772 | /* Check that the specified definer exists. Emit a warning if not. */ |
| 2773 | |
| 2774 | #ifndef NO_EMBEDDED_ACCESS_CHECKS |
| 2775 | if (!is_acl_user(lex->definer->host.str, lex->definer->user.str)) |
| 2776 | { |
| 2777 | push_warning_printf(thd, |
| 2778 | Sql_condition::WARN_LEVEL_NOTE, |
| 2779 | ER_NO_SUCH_USER, |
| 2780 | ER_THD(thd, ER_NO_SUCH_USER), |
| 2781 | lex->definer->user.str, |
| 2782 | lex->definer->host.str); |
| 2783 | } |
| 2784 | #endif /* NO_EMBEDDED_ACCESS_CHECKS */ |
| 2785 | |
| 2786 | DBUG_RETURN(FALSE); |
| 2787 | } |
| 2788 | |
| 2789 | |
| 2790 | /** |
| 2791 | Auxiliary call that opens and locks tables for LOCK TABLES statement |
| 2792 | and initializes the list of locked tables. |
| 2793 | |
| 2794 | @param thd Thread context. |
| 2795 | @param tables List of tables to be locked. |
| 2796 | |
| 2797 | @return FALSE in case of success, TRUE in case of error. |
| 2798 | */ |
| 2799 | |
| 2800 | static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables) |
| 2801 | { |
| 2802 | Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; |
| 2803 | MDL_deadlock_and_lock_abort_error_handler deadlock_handler; |
| 2804 | MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); |
| 2805 | uint counter; |
| 2806 | TABLE_LIST *table; |
| 2807 | |
| 2808 | thd->in_lock_tables= 1; |
| 2809 | |
| 2810 | retry: |
| 2811 | |
| 2812 | if (open_tables(thd, &tables, &counter, 0, &lock_tables_prelocking_strategy)) |
| 2813 | goto err; |
| 2814 | |
| 2815 | for (table= tables; table; table= table->next_global) |
| 2816 | { |
| 2817 | if (!table->placeholder()) |
| 2818 | { |
| 2819 | if (table->table->s->tmp_table) |
| 2820 | { |
| 2821 | /* |
| 2822 | We allow to change temporary tables even if they were locked for read |
| 2823 | by LOCK TABLES. To avoid a discrepancy between lock acquired at LOCK |
| 2824 | TABLES time and by the statement which is later executed under LOCK |
| 2825 | TABLES we ensure that for temporary tables we always request a write |
| 2826 | lock (such discrepancy can cause problems for the storage engine). |
| 2827 | We don't set TABLE_LIST::lock_type in this case as this might result |
| 2828 | in extra warnings from THD::decide_logging_format() even though |
| 2829 | binary logging is totally irrelevant for LOCK TABLES. |
| 2830 | */ |
| 2831 | table->table->reginfo.lock_type= TL_WRITE; |
| 2832 | } |
| 2833 | else if (table->mdl_request.type == MDL_SHARED_READ && |
| 2834 | ! table->prelocking_placeholder && |
| 2835 | table->table->file->lock_count() == 0) |
| 2836 | { |
| 2837 | enum enum_mdl_type lock_type; |
| 2838 | /* |
| 2839 | In case when LOCK TABLE ... READ LOCAL was issued for table with |
| 2840 | storage engine which doesn't support READ LOCAL option and doesn't |
| 2841 | use THR_LOCK locks we need to upgrade weak SR metadata lock acquired |
| 2842 | in open_tables() to stronger SRO metadata lock. |
| 2843 | This is not needed for tables used through stored routines or |
| 2844 | triggers as we always acquire SRO (or even stronger SNRW) metadata |
| 2845 | lock for them. |
| 2846 | */ |
| 2847 | deadlock_handler.init(); |
| 2848 | thd->push_internal_handler(&deadlock_handler); |
| 2849 | |
| 2850 | lock_type= table->table->mdl_ticket->get_type() == MDL_SHARED_WRITE ? |
| 2851 | MDL_SHARED_NO_READ_WRITE : MDL_SHARED_READ_ONLY; |
| 2852 | |
| 2853 | bool result= thd->mdl_context.upgrade_shared_lock( |
| 2854 | table->table->mdl_ticket, |
| 2855 | lock_type, |
| 2856 | thd->variables.lock_wait_timeout); |
| 2857 | |
| 2858 | thd->pop_internal_handler(); |
| 2859 | |
| 2860 | if (deadlock_handler.need_reopen()) |
| 2861 | { |
| 2862 | /* |
| 2863 | Deadlock occurred during upgrade of metadata lock. |
| 2864 | Let us restart acquring and opening tables for LOCK TABLES. |
| 2865 | */ |
| 2866 | close_tables_for_reopen(thd, &tables, mdl_savepoint); |
| 2867 | if (thd->open_temporary_tables(tables)) |
| 2868 | goto err; |
| 2869 | goto retry; |
| 2870 | } |
| 2871 | |
| 2872 | if (result) |
| 2873 | goto err; |
| 2874 | } |
| 2875 | } |
| 2876 | } |
| 2877 | |
| 2878 | if (lock_tables(thd, tables, counter, 0) || |
| 2879 | thd->locked_tables_list.init_locked_tables(thd)) |
| 2880 | goto err; |
| 2881 | |
| 2882 | thd->in_lock_tables= 0; |
| 2883 | |
| 2884 | return FALSE; |
| 2885 | |
| 2886 | err: |
| 2887 | thd->in_lock_tables= 0; |
| 2888 | |
| 2889 | trans_rollback_stmt(thd); |
| 2890 | /* |
| 2891 | Need to end the current transaction, so the storage engine (InnoDB) |
| 2892 | can free its locks if LOCK TABLES locked some tables before finding |
| 2893 | that it can't lock a table in its list |
| 2894 | */ |
| 2895 | trans_rollback(thd); |
| 2896 | /* Close tables and release metadata locks. */ |
| 2897 | close_thread_tables(thd); |
| 2898 | DBUG_ASSERT(!thd->locked_tables_mode); |
| 2899 | thd->mdl_context.release_transactional_locks(); |
| 2900 | return TRUE; |
| 2901 | } |
| 2902 | |
| 2903 | |
| 2904 | static bool do_execute_sp(THD *thd, sp_head *sp) |
| 2905 | { |
| 2906 | /* bits that should be cleared in thd->server_status */ |
| 2907 | uint bits_to_be_cleared= 0; |
| 2908 | ulonglong affected_rows; |
| 2909 | if (sp->m_flags & sp_head::MULTI_RESULTS) |
| 2910 | { |
| 2911 | if (!(thd->client_capabilities & CLIENT_MULTI_RESULTS)) |
| 2912 | { |
| 2913 | /* The client does not support multiple result sets being sent back */ |
| 2914 | my_error(ER_SP_BADSELECT, MYF(0), ErrConvDQName(sp).ptr()); |
| 2915 | return 1; |
| 2916 | } |
| 2917 | /* |
| 2918 | If SERVER_MORE_RESULTS_EXISTS is not set, |
| 2919 | then remember that it should be cleared |
| 2920 | */ |
| 2921 | bits_to_be_cleared= (~thd->server_status & |
| 2922 | SERVER_MORE_RESULTS_EXISTS); |
| 2923 | thd->server_status|= SERVER_MORE_RESULTS_EXISTS; |
| 2924 | } |
| 2925 | |
| 2926 | ha_rows select_limit= thd->variables.select_limit; |
| 2927 | thd->variables.select_limit= HA_POS_ERROR; |
| 2928 | |
| 2929 | /* |
| 2930 | Reset current_select as it may point to random data as a |
| 2931 | result of previous parsing. |
| 2932 | */ |
| 2933 | thd->lex->current_select= NULL; |
| 2934 | thd->lex->in_sum_func= 0; // For Item_field::fix_fields() |
| 2935 | |
| 2936 | /* |
| 2937 | We never write CALL statements into binlog: |
| 2938 | - If the mode is non-prelocked, each statement will be logged |
| 2939 | separately. |
| 2940 | - If the mode is prelocked, the invoking statement will care |
| 2941 | about writing into binlog. |
| 2942 | So just execute the statement. |
| 2943 | */ |
| 2944 | int res= sp->execute_procedure(thd, &thd->lex->value_list); |
| 2945 | |
| 2946 | thd->variables.select_limit= select_limit; |
| 2947 | thd->server_status&= ~bits_to_be_cleared; |
| 2948 | |
| 2949 | if (res) |
| 2950 | { |
| 2951 | DBUG_ASSERT(thd->is_error() || thd->killed); |
| 2952 | return 1; // Substatement should already have sent error |
| 2953 | } |
| 2954 | |
| 2955 | affected_rows= thd->affected_rows; // Affected rows for all sub statements |
| 2956 | thd->affected_rows= 0; // Reset total, as my_ok() adds to it |
| 2957 | my_ok(thd, affected_rows); |
| 2958 | return 0; |
| 2959 | } |
| 2960 | |
| 2961 | |
| 2962 | static int mysql_create_routine(THD *thd, LEX *lex) |
| 2963 | { |
| 2964 | DBUG_ASSERT(lex->sphead != 0); |
| 2965 | DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */ |
| 2966 | /* |
| 2967 | Verify that the database name is allowed, optionally |
| 2968 | lowercase it. |
| 2969 | */ |
| 2970 | if (check_db_name((LEX_STRING*) &lex->sphead->m_db)) |
| 2971 | { |
| 2972 | my_error(ER_WRONG_DB_NAME, MYF(0), lex->sphead->m_db.str); |
| 2973 | return true; |
| 2974 | } |
| 2975 | |
| 2976 | if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, |
| 2977 | NULL, NULL, 0, 0)) |
| 2978 | return true; |
| 2979 | |
| 2980 | /* Checking the drop permissions if CREATE OR REPLACE is used */ |
| 2981 | if (lex->create_info.or_replace()) |
| 2982 | { |
| 2983 | if (check_routine_access(thd, ALTER_PROC_ACL, &lex->sphead->m_db, |
| 2984 | &lex->sphead->m_name, |
| 2985 | Sp_handler::handler(lex->sql_command), 0)) |
| 2986 | return true; |
| 2987 | } |
| 2988 | |
| 2989 | const LEX_CSTRING *name= lex->sphead->name(); |
| 2990 | #ifdef HAVE_DLOPEN |
| 2991 | if (lex->sphead->m_handler->type() == TYPE_ENUM_FUNCTION) |
| 2992 | { |
| 2993 | udf_func *udf = find_udf(name->str, name->length); |
| 2994 | |
| 2995 | if (udf) |
| 2996 | { |
| 2997 | my_error(ER_UDF_EXISTS, MYF(0), name->str); |
| 2998 | return true; |
| 2999 | } |
| 3000 | } |
| 3001 | #endif |
| 3002 | |
| 3003 | if (sp_process_definer(thd)) |
| 3004 | return true; |
| 3005 | |
| 3006 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL) |
| 3007 | if (!lex->sphead->m_handler->sp_create_routine(thd, lex->sphead)) |
| 3008 | { |
| 3009 | #ifndef NO_EMBEDDED_ACCESS_CHECKS |
| 3010 | /* only add privileges if really neccessary */ |
| 3011 | |
| 3012 | Security_context security_context; |
| 3013 | bool restore_backup_context= false; |
| 3014 | Security_context *backup= NULL; |
| 3015 | LEX_USER *definer= thd->lex->definer; |
| 3016 | /* |
| 3017 | We're going to issue an implicit GRANT statement so we close all |
| 3018 | open tables. We have to keep metadata locks as this ensures that |
| 3019 | this statement is atomic against concurent FLUSH TABLES WITH READ |
| 3020 | LOCK. Deadlocks which can arise due to fact that this implicit |
| 3021 | statement takes metadata locks should be detected by a deadlock |
| 3022 | detector in MDL subsystem and reported as errors. |
| 3023 | |
| 3024 | No need to commit/rollback statement transaction, it's not started. |
| 3025 | |
| 3026 | TODO: Long-term we should either ensure that implicit GRANT statement |
| 3027 | is written into binary log as a separate statement or make both |
| 3028 | creation of routine and implicit GRANT parts of one fully atomic |
| 3029 | statement. |
| 3030 | */ |
| 3031 | DBUG_ASSERT(thd->transaction.stmt.is_empty()); |
| 3032 | close_thread_tables(thd); |
| 3033 | /* |
| 3034 | Check if the definer exists on slave, |
| 3035 | then use definer privilege to insert routine privileges to mysql.procs_priv. |
| 3036 | |
| 3037 | For current user of SQL thread has GLOBAL_ACL privilege, |
| 3038 | which doesn't any check routine privileges, |
| 3039 | so no routine privilege record will insert into mysql.procs_priv. |
| 3040 | */ |
| 3041 | if (thd->slave_thread && is_acl_user(definer->host.str, definer->user.str)) |
| 3042 | { |
| 3043 | security_context.change_security_context(thd, |
| 3044 | &thd->lex->definer->user, |
| 3045 | &thd->lex->definer->host, |
| 3046 | &thd->lex->sphead->m_db, |
| 3047 | &backup); |
| 3048 | restore_backup_context= true; |
| 3049 | } |
| 3050 | |
| 3051 | if (sp_automatic_privileges && !opt_noacl && |
| 3052 | check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS, |
| 3053 | &lex->sphead->m_db, name, |
| 3054 | Sp_handler::handler(lex->sql_command), 1)) |
| 3055 | { |
| 3056 | if (sp_grant_privileges(thd, lex->sphead->m_db.str, name->str, |
| 3057 | Sp_handler::handler(lex->sql_command))) |
| 3058 | push_warning(thd, Sql_condition::WARN_LEVEL_WARN, |
| 3059 | ER_PROC_AUTO_GRANT_FAIL, ER_THD(thd, ER_PROC_AUTO_GRANT_FAIL)); |
| 3060 | thd->clear_error(); |
| 3061 | } |
| 3062 | |
| 3063 | /* |
| 3064 | Restore current user with GLOBAL_ACL privilege of SQL thread |
| 3065 | */ |
| 3066 | if (restore_backup_context) |
| 3067 | { |
| 3068 | DBUG_ASSERT(thd->slave_thread == 1); |
| 3069 | thd->security_ctx->restore_security_context(thd, backup); |
| 3070 | } |
| 3071 | |
| 3072 | #endif |
| 3073 | return false; |
| 3074 | } |
| 3075 | #ifdef WITH_WSREP |
| 3076 | error: /* Used by WSREP_TO_ISOLATION_BEGIN */ |
| 3077 | #endif |
| 3078 | return true; |
| 3079 | } |
| 3080 | |
| 3081 | |
| 3082 | /** |
| 3083 | Prepare for CREATE DATABASE, ALTER DATABASE, DROP DATABASE. |
| 3084 | |
| 3085 | @param thd - current THD |
| 3086 | @param want_access - access needed |
| 3087 | @param dbname - the database name |
| 3088 | |
| 3089 | @retval false - Ok to proceed with CREATE/ALTER/DROP |
| 3090 | @retval true - not OK to proceed (error, or filtered) |
| 3091 | |
| 3092 | Note, on slave this function returns true if the database |
| 3093 | is in the ignore filter. The caller must distinguish this case |
| 3094 | from other cases: bad database error, no access error. |
| 3095 | This can be done by testing thd->is_error(). |
| 3096 | */ |
| 3097 | static bool prepare_db_action(THD *thd, ulong want_access, LEX_CSTRING *dbname) |
| 3098 | { |
| 3099 | if (check_db_name((LEX_STRING*)dbname)) |
| 3100 | { |
| 3101 | my_error(ER_WRONG_DB_NAME, MYF(0), dbname->str); |
| 3102 | return true; |
| 3103 | } |
| 3104 | /* |
| 3105 | If in a slave thread : |
| 3106 | - CREATE DATABASE DB was certainly not preceded by USE DB. |
| 3107 | - ALTER DATABASE DB may not be preceded by USE DB. |
| 3108 | - DROP DATABASE DB may not be preceded by USE DB. |
| 3109 | For that reason, db_ok() in sql/slave.cc did not check the |
| 3110 | do_db/ignore_db. And as this query involves no tables, tables_ok() |
| 3111 | was not called. So we have to check rules again here. |
| 3112 | */ |
| 3113 | #ifdef HAVE_REPLICATION |
| 3114 | if (thd->slave_thread) |
| 3115 | { |
| 3116 | Rpl_filter *rpl_filter; |
| 3117 | rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; |
| 3118 | if (!rpl_filter->db_ok(dbname->str) || |
| 3119 | !rpl_filter->db_ok_with_wild_table(dbname->str)) |
| 3120 | { |
| 3121 | my_message(ER_SLAVE_IGNORED_TABLE, |
| 3122 | ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); |
| 3123 | return true; |
| 3124 | } |
| 3125 | } |
| 3126 | #endif |
| 3127 | return check_access(thd, want_access, dbname->str, NULL, NULL, 1, 0); |
| 3128 | } |
| 3129 | |
| 3130 | |
| 3131 | bool Sql_cmd_call::execute(THD *thd) |
| 3132 | { |
| 3133 | TABLE_LIST *all_tables= thd->lex->query_tables; |
| 3134 | sp_head *sp; |
| 3135 | /* |
| 3136 | This will cache all SP and SF and open and lock all tables |
| 3137 | required for execution. |
| 3138 | */ |
| 3139 | if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, |
| 3140 | UINT_MAX, FALSE) || |
| 3141 | open_and_lock_tables(thd, all_tables, TRUE, 0)) |
| 3142 | return true; |
| 3143 | |
| 3144 | /* |
| 3145 | By this moment all needed SPs should be in cache so no need to look |
| 3146 | into DB. |
| 3147 | */ |
| 3148 | if (!(sp= m_handler->sp_find_routine(thd, m_name, true))) |
| 3149 | { |
| 3150 | /* |
| 3151 | If the routine is not found, let's still check EXECUTE_ACL to decide |
| 3152 | whether to return "Access denied" or "Routine does not exist". |
| 3153 | */ |
| 3154 | if (check_routine_access(thd, EXECUTE_ACL, &m_name->m_db, |
| 3155 | &m_name->m_name, |
| 3156 | &sp_handler_procedure, |
| 3157 | false)) |
| 3158 | return true; |
| 3159 | /* |
| 3160 | sp_find_routine can have issued an ER_SP_RECURSION_LIMIT error. |
| 3161 | Send message ER_SP_DOES_NOT_EXIST only if procedure is not found in |
| 3162 | cache. |
| 3163 | */ |
| 3164 | if (!sp_cache_lookup(&thd->sp_proc_cache, m_name)) |
| 3165 | my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PROCEDURE" , |
| 3166 | ErrConvDQName(m_name).ptr()); |
| 3167 | return true; |
| 3168 | } |
| 3169 | else |
| 3170 | { |
| 3171 | if (sp->check_execute_access(thd)) |
| 3172 | return true; |
| 3173 | /* |
| 3174 | Check that the stored procedure doesn't contain Dynamic SQL |
| 3175 | and doesn't return result sets: such stored procedures can't |
| 3176 | be called from a function or trigger. |
| 3177 | */ |
| 3178 | if (thd->in_sub_stmt) |
| 3179 | { |
| 3180 | const char *where= (thd->in_sub_stmt & SUB_STMT_TRIGGER ? |
| 3181 | "trigger" : "function" ); |
| 3182 | if (sp->is_not_allowed_in_function(where)) |
| 3183 | return true; |
| 3184 | } |
| 3185 | |
| 3186 | if (do_execute_sp(thd, sp)) |
| 3187 | return true; |
| 3188 | |
| 3189 | /* |
| 3190 | Disable slow log for the above call(), if calls are disabled. |
| 3191 | Instead we will log the executed statements to the slow log. |
| 3192 | */ |
| 3193 | if (thd->variables.log_slow_disabled_statements & LOG_SLOW_DISABLE_CALL) |
| 3194 | thd->enable_slow_log= 0; |
| 3195 | } |
| 3196 | return false; |
| 3197 | } |
| 3198 | |
| 3199 | |
| 3200 | /** |
| 3201 | Execute command saved in thd and lex->sql_command. |
| 3202 | |
| 3203 | @param thd Thread handle |
| 3204 | |
| 3205 | @todo |
| 3206 | - Invalidate the table in the query cache if something changed |
| 3207 | after unlocking when changes become visible. |
| 3208 | TODO: this is workaround. right way will be move invalidating in |
| 3209 | the unlock procedure. |
| 3210 | - TODO: use check_change_password() |
| 3211 | |
| 3212 | @retval |
| 3213 | FALSE OK |
| 3214 | @retval |
| 3215 | TRUE Error |
| 3216 | */ |
| 3217 | |
| 3218 | int |
| 3219 | mysql_execute_command(THD *thd) |
| 3220 | { |
| 3221 | int res= 0; |
| 3222 | int up_result= 0; |
| 3223 | LEX *lex= thd->lex; |
| 3224 | /* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */ |
| 3225 | SELECT_LEX *select_lex= &lex->select_lex; |
| 3226 | /* first table of first SELECT_LEX */ |
| 3227 | TABLE_LIST *first_table= select_lex->table_list.first; |
| 3228 | /* list of all tables in query */ |
| 3229 | TABLE_LIST *all_tables; |
| 3230 | /* most outer SELECT_LEX_UNIT of query */ |
| 3231 | SELECT_LEX_UNIT *unit= &lex->unit; |
| 3232 | #ifdef HAVE_REPLICATION |
| 3233 | /* have table map for update for multi-update statement (BUG#37051) */ |
| 3234 | bool have_table_map_for_update= FALSE; |
| 3235 | /* */ |
| 3236 | Rpl_filter *rpl_filter; |
| 3237 | #endif |
| 3238 | DBUG_ENTER("mysql_execute_command" ); |
| 3239 | |
| 3240 | #ifdef WITH_PARTITION_STORAGE_ENGINE |
| 3241 | thd->work_part_info= 0; |
| 3242 | #endif |
| 3243 | |
| 3244 | DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt); |
| 3245 | /* |
| 3246 | Each statement or replication event which might produce deadlock |
| 3247 | should handle transaction rollback on its own. So by the start of |
| 3248 | the next statement transaction rollback request should be fulfilled |
| 3249 | already. |
| 3250 | */ |
| 3251 | DBUG_ASSERT(! thd->transaction_rollback_request || thd->in_sub_stmt); |
| 3252 | /* |
| 3253 | In many cases first table of main SELECT_LEX have special meaning => |
| 3254 | check that it is first table in global list and relink it first in |
| 3255 | queries_tables list if it is necessary (we need such relinking only |
| 3256 | for queries with subqueries in select list, in this case tables of |
| 3257 | subqueries will go to global list first) |
| 3258 | |
| 3259 | all_tables will differ from first_table only if most upper SELECT_LEX |
| 3260 | do not contain tables. |
| 3261 | |
| 3262 | Because of above in place where should be at least one table in most |
| 3263 | outer SELECT_LEX we have following check: |
| 3264 | DBUG_ASSERT(first_table == all_tables); |
| 3265 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 3266 | */ |
| 3267 | lex->first_lists_tables_same(); |
| 3268 | /* should be assigned after making first tables same */ |
| 3269 | all_tables= lex->query_tables; |
| 3270 | /* set context for commands which do not use setup_tables */ |
| 3271 | select_lex-> |
| 3272 | context.resolve_in_table_list_only(select_lex-> |
| 3273 | table_list.first); |
| 3274 | |
| 3275 | /* |
| 3276 | Remember last commmand executed, so that we can use it in functions called by |
| 3277 | dispatch_command() |
| 3278 | */ |
| 3279 | thd->last_sql_command= lex->sql_command; |
| 3280 | |
| 3281 | /* |
| 3282 | Reset warning count for each query that uses tables |
| 3283 | A better approach would be to reset this for any commands |
| 3284 | that is not a SHOW command or a select that only access local |
| 3285 | variables, but for now this is probably good enough. |
| 3286 | */ |
| 3287 | if ((sql_command_flags[lex->sql_command] & CF_DIAGNOSTIC_STMT) != 0) |
| 3288 | thd->get_stmt_da()->set_warning_info_read_only(TRUE); |
| 3289 | else |
| 3290 | { |
| 3291 | thd->get_stmt_da()->set_warning_info_read_only(FALSE); |
| 3292 | if (all_tables) |
| 3293 | thd->get_stmt_da()->opt_clear_warning_info(thd->query_id); |
| 3294 | } |
| 3295 | |
| 3296 | if (check_dependencies_in_with_clauses(thd->lex->with_clauses_list)) |
| 3297 | DBUG_RETURN(1); |
| 3298 | |
| 3299 | #ifdef HAVE_REPLICATION |
| 3300 | if (unlikely(thd->slave_thread)) |
| 3301 | { |
| 3302 | if (lex->sql_command == SQLCOM_DROP_TRIGGER) |
| 3303 | { |
| 3304 | /* |
| 3305 | When dropping a trigger, we need to load its table name |
| 3306 | before checking slave filter rules. |
| 3307 | */ |
| 3308 | add_table_for_trigger(thd, thd->lex->spname, 1, &all_tables); |
| 3309 | |
| 3310 | if (!all_tables) |
| 3311 | { |
| 3312 | /* |
| 3313 | If table name cannot be loaded, |
| 3314 | it means the trigger does not exists possibly because |
| 3315 | CREATE TRIGGER was previously skipped for this trigger |
| 3316 | according to slave filtering rules. |
| 3317 | Returning success without producing any errors in this case. |
| 3318 | */ |
| 3319 | if (!thd->lex->create_info.if_exists()) |
| 3320 | DBUG_RETURN(0); |
| 3321 | /* |
| 3322 | DROP TRIGGER IF NOT EXISTS will return without an error later |
| 3323 | after possibly writing the query to a binlog |
| 3324 | */ |
| 3325 | } |
| 3326 | else // force searching in slave.cc:tables_ok() |
| 3327 | all_tables->updating= 1; |
| 3328 | } |
| 3329 | |
| 3330 | /* |
| 3331 | For fix of BUG#37051, the master stores the table map for update |
| 3332 | in the Query_log_event, and the value is assigned to |
| 3333 | thd->variables.table_map_for_update before executing the update |
| 3334 | query. |
| 3335 | |
| 3336 | If thd->variables.table_map_for_update is set, then we are |
| 3337 | replicating from a new master, we can use this value to apply |
| 3338 | filter rules without opening all the tables. However If |
| 3339 | thd->variables.table_map_for_update is not set, then we are |
| 3340 | replicating from an old master, so we just skip this and |
| 3341 | continue with the old method. And of course, the bug would still |
| 3342 | exist for old masters. |
| 3343 | */ |
| 3344 | if (lex->sql_command == SQLCOM_UPDATE_MULTI && |
| 3345 | thd->table_map_for_update) |
| 3346 | { |
| 3347 | have_table_map_for_update= TRUE; |
| 3348 | table_map table_map_for_update= thd->table_map_for_update; |
| 3349 | uint nr= 0; |
| 3350 | TABLE_LIST *table; |
| 3351 | for (table=all_tables; table; table=table->next_global, nr++) |
| 3352 | { |
| 3353 | if (table_map_for_update & ((table_map)1 << nr)) |
| 3354 | table->updating= TRUE; |
| 3355 | else |
| 3356 | table->updating= FALSE; |
| 3357 | } |
| 3358 | |
| 3359 | if (all_tables_not_ok(thd, all_tables)) |
| 3360 | { |
| 3361 | /* we warn the slave SQL thread */ |
| 3362 | my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE), |
| 3363 | MYF(0)); |
| 3364 | } |
| 3365 | |
| 3366 | for (table=all_tables; table; table=table->next_global) |
| 3367 | table->updating= TRUE; |
| 3368 | } |
| 3369 | |
| 3370 | /* |
| 3371 | Check if statment should be skipped because of slave filtering |
| 3372 | rules |
| 3373 | |
| 3374 | Exceptions are: |
| 3375 | - UPDATE MULTI: For this statement, we want to check the filtering |
| 3376 | rules later in the code |
| 3377 | - SET: we always execute it (Not that many SET commands exists in |
| 3378 | the binary log anyway -- only 4.1 masters write SET statements, |
| 3379 | in 5.0 there are no SET statements in the binary log) |
| 3380 | - DROP TEMPORARY TABLE IF EXISTS: we always execute it (otherwise we |
| 3381 | have stale files on slave caused by exclusion of one tmp table). |
| 3382 | */ |
| 3383 | if (!(lex->sql_command == SQLCOM_UPDATE_MULTI) && |
| 3384 | !(lex->sql_command == SQLCOM_SET_OPTION) && |
| 3385 | !((lex->sql_command == SQLCOM_DROP_TABLE || |
| 3386 | lex->sql_command == SQLCOM_DROP_SEQUENCE) && |
| 3387 | lex->tmp_table() && lex->if_exists()) && |
| 3388 | all_tables_not_ok(thd, all_tables)) |
| 3389 | { |
| 3390 | /* we warn the slave SQL thread */ |
| 3391 | my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE), |
| 3392 | MYF(0)); |
| 3393 | DBUG_RETURN(0); |
| 3394 | } |
| 3395 | /* |
| 3396 | Execute deferred events first |
| 3397 | */ |
| 3398 | if (slave_execute_deferred_events(thd)) |
| 3399 | DBUG_RETURN(-1); |
| 3400 | } |
| 3401 | else |
| 3402 | { |
| 3403 | #endif /* HAVE_REPLICATION */ |
| 3404 | /* |
| 3405 | When option readonly is set deny operations which change non-temporary |
| 3406 | tables. Except for the replication thread and the 'super' users. |
| 3407 | */ |
| 3408 | if (deny_updates_if_read_only_option(thd, all_tables)) |
| 3409 | { |
| 3410 | my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only" ); |
| 3411 | DBUG_RETURN(-1); |
| 3412 | } |
| 3413 | #ifdef HAVE_REPLICATION |
| 3414 | } /* endif unlikely slave */ |
| 3415 | #endif |
| 3416 | #ifdef WITH_WSREP |
| 3417 | if (wsrep && WSREP(thd)) |
| 3418 | { |
| 3419 | /* |
| 3420 | change LOCK TABLE WRITE to transaction |
| 3421 | */ |
| 3422 | if (lex->sql_command== SQLCOM_LOCK_TABLES && wsrep_convert_LOCK_to_trx) |
| 3423 | { |
| 3424 | for (TABLE_LIST *table= all_tables; table; table= table->next_global) |
| 3425 | { |
| 3426 | if (table->lock_type >= TL_WRITE_ALLOW_WRITE) |
| 3427 | { |
| 3428 | lex->sql_command= SQLCOM_BEGIN; |
| 3429 | thd->wsrep_converted_lock_session= true; |
| 3430 | break; |
| 3431 | } |
| 3432 | } |
| 3433 | } |
| 3434 | if (lex->sql_command== SQLCOM_UNLOCK_TABLES && |
| 3435 | thd->wsrep_converted_lock_session) |
| 3436 | { |
| 3437 | thd->wsrep_converted_lock_session= false; |
| 3438 | lex->sql_command= SQLCOM_COMMIT; |
| 3439 | lex->tx_release= TVL_NO; |
| 3440 | } |
| 3441 | |
| 3442 | /* |
| 3443 | * Bail out if DB snapshot has not been installed. We however, |
| 3444 | * allow SET and SHOW queries and reads from information schema |
| 3445 | * and dirty reads (if configured) |
| 3446 | */ |
| 3447 | if (!thd->wsrep_applier && |
| 3448 | !(wsrep_ready && wsrep_reject_queries == WSREP_REJECT_NONE) && |
| 3449 | !(thd->variables.wsrep_dirty_reads && |
| 3450 | (sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) == 0) && |
| 3451 | !wsrep_tables_accessible_when_detached(all_tables) && |
| 3452 | lex->sql_command != SQLCOM_SET_OPTION && |
| 3453 | !wsrep_is_show_query(lex->sql_command)) |
| 3454 | { |
| 3455 | my_message(ER_UNKNOWN_COM_ERROR, |
| 3456 | "WSREP has not yet prepared node for application use" , MYF(0)); |
| 3457 | goto error; |
| 3458 | } |
| 3459 | } |
| 3460 | #endif /* WITH_WSREP */ |
| 3461 | status_var_increment(thd->status_var.com_stat[lex->sql_command]); |
| 3462 | thd->progress.report_to_client= MY_TEST(sql_command_flags[lex->sql_command] & |
| 3463 | CF_REPORT_PROGRESS); |
| 3464 | |
| 3465 | DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE); |
| 3466 | |
| 3467 | /* store old value of binlog format */ |
| 3468 | enum_binlog_format orig_binlog_format,orig_current_stmt_binlog_format; |
| 3469 | |
| 3470 | thd->get_binlog_format(&orig_binlog_format, |
| 3471 | &orig_current_stmt_binlog_format); |
| 3472 | |
| 3473 | if (!lex->stmt_var_list.is_empty() && !thd->slave_thread) |
| 3474 | { |
| 3475 | Query_arena backup; |
| 3476 | DBUG_PRINT("info" , ("SET STATEMENT %d vars" , lex->stmt_var_list.elements)); |
| 3477 | |
| 3478 | lex->old_var_list.empty(); |
| 3479 | List_iterator_fast<set_var_base> it(lex->stmt_var_list); |
| 3480 | set_var_base *var; |
| 3481 | |
| 3482 | if (lex->set_arena_for_set_stmt(&backup)) |
| 3483 | goto error; |
| 3484 | |
| 3485 | MEM_ROOT *mem_root= thd->mem_root; |
| 3486 | while ((var= it++)) |
| 3487 | { |
| 3488 | DBUG_ASSERT(var->is_system()); |
| 3489 | set_var *o= NULL, *v= (set_var*)var; |
| 3490 | if (!v->var->is_set_stmt_ok()) |
| 3491 | { |
| 3492 | my_error(ER_SET_STATEMENT_NOT_SUPPORTED, MYF(0), v->var->name.str); |
| 3493 | lex->reset_arena_for_set_stmt(&backup); |
| 3494 | lex->old_var_list.empty(); |
| 3495 | lex->free_arena_for_set_stmt(); |
| 3496 | goto error; |
| 3497 | } |
| 3498 | if (v->var->session_is_default(thd)) |
| 3499 | o= new set_var(thd,v->type, v->var, &v->base, NULL); |
| 3500 | else |
| 3501 | { |
| 3502 | switch (v->var->option.var_type & GET_TYPE_MASK) |
| 3503 | { |
| 3504 | case GET_BOOL: |
| 3505 | case GET_INT: |
| 3506 | case GET_LONG: |
| 3507 | case GET_LL: |
| 3508 | { |
| 3509 | bool null_value; |
| 3510 | longlong val= v->var->val_int(&null_value, thd, v->type, &v->base); |
| 3511 | o= new set_var(thd, v->type, v->var, &v->base, |
| 3512 | (null_value ? |
| 3513 | (Item *) new (mem_root) Item_null(thd) : |
| 3514 | (Item *) new (mem_root) Item_int(thd, val))); |
| 3515 | } |
| 3516 | break; |
| 3517 | case GET_UINT: |
| 3518 | case GET_ULONG: |
| 3519 | case GET_ULL: |
| 3520 | { |
| 3521 | bool null_value; |
| 3522 | ulonglong val= v->var->val_int(&null_value, thd, v->type, &v->base); |
| 3523 | o= new set_var(thd, v->type, v->var, &v->base, |
| 3524 | (null_value ? |
| 3525 | (Item *) new (mem_root) Item_null(thd) : |
| 3526 | (Item *) new (mem_root) Item_uint(thd, val))); |
| 3527 | } |
| 3528 | break; |
| 3529 | case GET_DOUBLE: |
| 3530 | { |
| 3531 | bool null_value; |
| 3532 | double val= v->var->val_real(&null_value, thd, v->type, &v->base); |
| 3533 | o= new set_var(thd, v->type, v->var, &v->base, |
| 3534 | (null_value ? |
| 3535 | (Item *) new (mem_root) Item_null(thd) : |
| 3536 | (Item *) new (mem_root) Item_float(thd, val, 1))); |
| 3537 | } |
| 3538 | break; |
| 3539 | default: |
| 3540 | case GET_NO_ARG: |
| 3541 | case GET_DISABLED: |
| 3542 | DBUG_ASSERT(0); |
| 3543 | case 0: |
| 3544 | case GET_FLAGSET: |
| 3545 | case GET_ENUM: |
| 3546 | case GET_SET: |
| 3547 | case GET_STR: |
| 3548 | case GET_STR_ALLOC: |
| 3549 | { |
| 3550 | char buff[STRING_BUFFER_USUAL_SIZE]; |
| 3551 | String tmp(buff, sizeof(buff), v->var->charset(thd)),*val; |
| 3552 | val= v->var->val_str(&tmp, thd, v->type, &v->base); |
| 3553 | if (val) |
| 3554 | { |
| 3555 | Item_string *str= new (mem_root) Item_string(thd, v->var->charset(thd), |
| 3556 | val->ptr(), val->length()); |
| 3557 | o= new set_var(thd, v->type, v->var, &v->base, str); |
| 3558 | } |
| 3559 | else |
| 3560 | o= new set_var(thd, v->type, v->var, &v->base, |
| 3561 | new (mem_root) Item_null(thd)); |
| 3562 | } |
| 3563 | break; |
| 3564 | } |
| 3565 | } |
| 3566 | DBUG_ASSERT(o); |
| 3567 | lex->old_var_list.push_back(o, thd->mem_root); |
| 3568 | } |
| 3569 | lex->reset_arena_for_set_stmt(&backup); |
| 3570 | if (lex->old_var_list.is_empty()) |
| 3571 | lex->free_arena_for_set_stmt(); |
| 3572 | if (thd->is_error() || |
| 3573 | (res= sql_set_variables(thd, &lex->stmt_var_list, false))) |
| 3574 | { |
| 3575 | if (!thd->is_error()) |
| 3576 | my_error(ER_WRONG_ARGUMENTS, MYF(0), "SET" ); |
| 3577 | lex->restore_set_statement_var(); |
| 3578 | goto error; |
| 3579 | } |
| 3580 | /* |
| 3581 | The value of last_insert_id is remembered in THD to be written to binlog |
| 3582 | when it's used *the first time* in the statement. But SET STATEMENT |
| 3583 | must read the old value of last_insert_id to be able to restore it at |
| 3584 | the end. This should not count at "reading of last_insert_id" and |
| 3585 | should not remember last_insert_id for binlog. That is, it should clear |
| 3586 | stmt_depends_on_first_successful_insert_id_in_prev_stmt flag. |
| 3587 | */ |
| 3588 | if (!thd->in_sub_stmt) |
| 3589 | { |
| 3590 | thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; |
| 3591 | } |
| 3592 | } |
| 3593 | |
| 3594 | if (thd->lex->mi.connection_name.str == NULL) |
| 3595 | thd->lex->mi.connection_name= thd->variables.default_master_connection; |
| 3596 | |
| 3597 | /* |
| 3598 | Force statement logging for DDL commands to allow us to update |
| 3599 | privilege, system or statistic tables directly without the updates |
| 3600 | getting logged. |
| 3601 | */ |
| 3602 | if (!(sql_command_flags[lex->sql_command] & |
| 3603 | (CF_CAN_GENERATE_ROW_EVENTS | CF_FORCE_ORIGINAL_BINLOG_FORMAT | |
| 3604 | CF_STATUS_COMMAND))) |
| 3605 | thd->set_binlog_format_stmt(); |
| 3606 | |
| 3607 | /* |
| 3608 | End a active transaction so that this command will have it's |
| 3609 | own transaction and will also sync the binary log. If a DDL is |
| 3610 | not run in it's own transaction it may simply never appear on |
| 3611 | the slave in case the outside transaction rolls back. |
| 3612 | */ |
| 3613 | if (stmt_causes_implicit_commit(thd, CF_IMPLICT_COMMIT_BEGIN)) |
| 3614 | { |
| 3615 | /* |
| 3616 | Note that this should never happen inside of stored functions |
| 3617 | or triggers as all such statements prohibited there. |
| 3618 | */ |
| 3619 | DBUG_ASSERT(! thd->in_sub_stmt); |
| 3620 | /* Statement transaction still should not be started. */ |
| 3621 | DBUG_ASSERT(thd->transaction.stmt.is_empty()); |
| 3622 | if (!(thd->variables.option_bits & OPTION_GTID_BEGIN)) |
| 3623 | { |
| 3624 | /* Commit the normal transaction if one is active. */ |
| 3625 | bool commit_failed= trans_commit_implicit(thd); |
| 3626 | /* Release metadata locks acquired in this transaction. */ |
| 3627 | thd->mdl_context.release_transactional_locks(); |
| 3628 | if (commit_failed) |
| 3629 | { |
| 3630 | WSREP_DEBUG("implicit commit failed, MDL released: %lld" , |
| 3631 | (longlong) thd->thread_id); |
| 3632 | goto error; |
| 3633 | } |
| 3634 | } |
| 3635 | thd->transaction.stmt.mark_trans_did_ddl(); |
| 3636 | } |
| 3637 | |
| 3638 | #ifndef DBUG_OFF |
| 3639 | if (lex->sql_command != SQLCOM_SET_OPTION) |
| 3640 | DEBUG_SYNC(thd,"before_execute_sql_command" ); |
| 3641 | #endif |
| 3642 | |
| 3643 | /* |
| 3644 | Check if we are in a read-only transaction and we're trying to |
| 3645 | execute a statement which should always be disallowed in such cases. |
| 3646 | |
| 3647 | Note that this check is done after any implicit commits. |
| 3648 | */ |
| 3649 | if (thd->tx_read_only && |
| 3650 | (sql_command_flags[lex->sql_command] & CF_DISALLOW_IN_RO_TRANS)) |
| 3651 | { |
| 3652 | my_error(ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION, MYF(0)); |
| 3653 | goto error; |
| 3654 | } |
| 3655 | |
| 3656 | /* |
| 3657 | Close tables open by HANDLERs before executing DDL statement |
| 3658 | which is going to affect those tables. |
| 3659 | |
| 3660 | This should happen before temporary tables are pre-opened as |
| 3661 | otherwise we will get errors about attempt to re-open tables |
| 3662 | if table to be changed is open through HANDLER. |
| 3663 | |
| 3664 | Note that even although this is done before any privilege |
| 3665 | checks there is no security problem here as closing open |
| 3666 | HANDLER doesn't require any privileges anyway. |
| 3667 | */ |
| 3668 | if (sql_command_flags[lex->sql_command] & CF_HA_CLOSE) |
| 3669 | mysql_ha_rm_tables(thd, all_tables); |
| 3670 | |
| 3671 | /* |
| 3672 | Pre-open temporary tables to simplify privilege checking |
| 3673 | for statements which need this. |
| 3674 | */ |
| 3675 | if (sql_command_flags[lex->sql_command] & CF_PREOPEN_TMP_TABLES) |
| 3676 | { |
| 3677 | if (thd->open_temporary_tables(all_tables)) |
| 3678 | goto error; |
| 3679 | } |
| 3680 | |
| 3681 | /* Start timeouts */ |
| 3682 | thd->set_query_timer(); |
| 3683 | |
| 3684 | switch (lex->sql_command) { |
| 3685 | |
| 3686 | case SQLCOM_SHOW_EVENTS: |
| 3687 | #ifndef HAVE_EVENT_SCHEDULER |
| 3688 | my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server" ); |
| 3689 | break; |
| 3690 | #endif |
| 3691 | case SQLCOM_SHOW_STATUS: |
| 3692 | { |
| 3693 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); |
| 3694 | execute_show_status(thd, all_tables); |
| 3695 | break; |
| 3696 | } |
| 3697 | case SQLCOM_SHOW_EXPLAIN: |
| 3698 | { |
| 3699 | if (!thd->security_ctx->priv_user[0] && |
| 3700 | check_global_access(thd,PROCESS_ACL)) |
| 3701 | break; |
| 3702 | |
| 3703 | /* |
| 3704 | The select should use only one table, it's the SHOW EXPLAIN pseudo-table |
| 3705 | */ |
| 3706 | if (lex->sroutines.records || lex->query_tables->next_global) |
| 3707 | { |
| 3708 | my_message(ER_SET_CONSTANTS_ONLY, ER_THD(thd, ER_SET_CONSTANTS_ONLY), |
| 3709 | MYF(0)); |
| 3710 | goto error; |
| 3711 | } |
| 3712 | |
| 3713 | Item **it= lex->value_list.head_ref(); |
| 3714 | if (!(*it)->basic_const_item() || |
| 3715 | (!(*it)->fixed && (*it)->fix_fields(lex->thd, it)) || |
| 3716 | (*it)->check_cols(1)) |
| 3717 | { |
| 3718 | my_message(ER_SET_CONSTANTS_ONLY, ER_THD(thd, ER_SET_CONSTANTS_ONLY), |
| 3719 | MYF(0)); |
| 3720 | goto error; |
| 3721 | } |
| 3722 | } |
| 3723 | /* fall through */ |
| 3724 | case SQLCOM_SHOW_STATUS_PROC: |
| 3725 | case SQLCOM_SHOW_STATUS_FUNC: |
| 3726 | case SQLCOM_SHOW_STATUS_PACKAGE: |
| 3727 | case SQLCOM_SHOW_STATUS_PACKAGE_BODY: |
| 3728 | case SQLCOM_SHOW_DATABASES: |
| 3729 | case SQLCOM_SHOW_TABLES: |
| 3730 | case SQLCOM_SHOW_TRIGGERS: |
| 3731 | case SQLCOM_SHOW_TABLE_STATUS: |
| 3732 | case SQLCOM_SHOW_OPEN_TABLES: |
| 3733 | case SQLCOM_SHOW_GENERIC: |
| 3734 | case SQLCOM_SHOW_PLUGINS: |
| 3735 | case SQLCOM_SHOW_FIELDS: |
| 3736 | case SQLCOM_SHOW_KEYS: |
| 3737 | case SQLCOM_SHOW_VARIABLES: |
| 3738 | case SQLCOM_SHOW_CHARSETS: |
| 3739 | case SQLCOM_SHOW_COLLATIONS: |
| 3740 | case SQLCOM_SHOW_STORAGE_ENGINES: |
| 3741 | case SQLCOM_SHOW_PROFILE: |
| 3742 | case SQLCOM_SELECT: |
| 3743 | { |
| 3744 | #ifdef WITH_WSREP |
| 3745 | if (lex->sql_command == SQLCOM_SELECT) |
| 3746 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ) |
| 3747 | else |
| 3748 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW) |
| 3749 | #endif /* WITH_WSREP */ |
| 3750 | |
| 3751 | thd->status_var.last_query_cost= 0.0; |
| 3752 | |
| 3753 | /* |
| 3754 | lex->exchange != NULL implies SELECT .. INTO OUTFILE and this |
| 3755 | requires FILE_ACL access. |
| 3756 | */ |
| 3757 | ulong privileges_requested= lex->exchange ? SELECT_ACL | FILE_ACL : |
| 3758 | SELECT_ACL; |
| 3759 | |
| 3760 | if (all_tables) |
| 3761 | res= check_table_access(thd, |
| 3762 | privileges_requested, |
| 3763 | all_tables, FALSE, UINT_MAX, FALSE); |
| 3764 | else |
| 3765 | res= check_access(thd, privileges_requested, any_db, NULL, NULL, 0, 0); |
| 3766 | |
| 3767 | if (!res) |
| 3768 | res= execute_sqlcom_select(thd, all_tables); |
| 3769 | |
| 3770 | break; |
| 3771 | } |
| 3772 | case SQLCOM_EXECUTE_IMMEDIATE: |
| 3773 | { |
| 3774 | mysql_sql_stmt_execute_immediate(thd); |
| 3775 | break; |
| 3776 | } |
| 3777 | case SQLCOM_PREPARE: |
| 3778 | { |
| 3779 | mysql_sql_stmt_prepare(thd); |
| 3780 | break; |
| 3781 | } |
| 3782 | case SQLCOM_EXECUTE: |
| 3783 | { |
| 3784 | mysql_sql_stmt_execute(thd); |
| 3785 | break; |
| 3786 | } |
| 3787 | case SQLCOM_DEALLOCATE_PREPARE: |
| 3788 | { |
| 3789 | mysql_sql_stmt_close(thd); |
| 3790 | break; |
| 3791 | } |
| 3792 | case SQLCOM_DO: |
| 3793 | if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) |
| 3794 | || open_and_lock_tables(thd, all_tables, TRUE, 0)) |
| 3795 | goto error; |
| 3796 | |
| 3797 | res= mysql_do(thd, *lex->insert_list); |
| 3798 | break; |
| 3799 | |
| 3800 | case SQLCOM_EMPTY_QUERY: |
| 3801 | my_ok(thd); |
| 3802 | break; |
| 3803 | |
| 3804 | case SQLCOM_HELP: |
| 3805 | res= mysqld_help(thd,lex->help_arg); |
| 3806 | break; |
| 3807 | |
| 3808 | #ifndef EMBEDDED_LIBRARY |
| 3809 | case SQLCOM_PURGE: |
| 3810 | { |
| 3811 | if (check_global_access(thd, SUPER_ACL)) |
| 3812 | goto error; |
| 3813 | /* PURGE MASTER LOGS TO 'file' */ |
| 3814 | res = purge_master_logs(thd, lex->to_log); |
| 3815 | break; |
| 3816 | } |
| 3817 | case SQLCOM_PURGE_BEFORE: |
| 3818 | { |
| 3819 | Item *it; |
| 3820 | |
| 3821 | if (check_global_access(thd, SUPER_ACL)) |
| 3822 | goto error; |
| 3823 | /* PURGE MASTER LOGS BEFORE 'data' */ |
| 3824 | it= (Item *)lex->value_list.head(); |
| 3825 | if ((!it->fixed && it->fix_fields(lex->thd, &it)) || |
| 3826 | it->check_cols(1)) |
| 3827 | { |
| 3828 | my_error(ER_WRONG_ARGUMENTS, MYF(0), "PURGE LOGS BEFORE" ); |
| 3829 | goto error; |
| 3830 | } |
| 3831 | it= new (thd->mem_root) Item_func_unix_timestamp(thd, it); |
| 3832 | it->fix_fields(thd, &it); |
| 3833 | res = purge_master_logs_before_date(thd, (ulong)it->val_int()); |
| 3834 | break; |
| 3835 | } |
| 3836 | #endif |
| 3837 | case SQLCOM_SHOW_WARNS: |
| 3838 | { |
| 3839 | res= mysqld_show_warnings(thd, (ulong) |
| 3840 | ((1L << (uint) Sql_condition::WARN_LEVEL_NOTE) | |
| 3841 | (1L << (uint) Sql_condition::WARN_LEVEL_WARN) | |
| 3842 | (1L << (uint) Sql_condition::WARN_LEVEL_ERROR) |
| 3843 | )); |
| 3844 | break; |
| 3845 | } |
| 3846 | case SQLCOM_SHOW_ERRORS: |
| 3847 | { |
| 3848 | res= mysqld_show_warnings(thd, (ulong) |
| 3849 | (1L << (uint) Sql_condition::WARN_LEVEL_ERROR)); |
| 3850 | break; |
| 3851 | } |
| 3852 | case SQLCOM_SHOW_PROFILES: |
| 3853 | { |
| 3854 | #if defined(ENABLED_PROFILING) |
| 3855 | thd->profiling.discard_current_query(); |
| 3856 | res= thd->profiling.show_profiles(); |
| 3857 | if (res) |
| 3858 | goto error; |
| 3859 | #else |
| 3860 | my_error(ER_FEATURE_DISABLED, MYF(0), "SHOW PROFILES" , "enable-profiling" ); |
| 3861 | goto error; |
| 3862 | #endif |
| 3863 | break; |
| 3864 | } |
| 3865 | |
| 3866 | #ifdef HAVE_REPLICATION |
| 3867 | case SQLCOM_SHOW_SLAVE_HOSTS: |
| 3868 | { |
| 3869 | if (check_global_access(thd, REPL_SLAVE_ACL)) |
| 3870 | goto error; |
| 3871 | res = show_slave_hosts(thd); |
| 3872 | break; |
| 3873 | } |
| 3874 | case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */ |
| 3875 | case SQLCOM_SHOW_BINLOG_EVENTS: |
| 3876 | { |
| 3877 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); |
| 3878 | if (check_global_access(thd, REPL_SLAVE_ACL)) |
| 3879 | goto error; |
| 3880 | res = mysql_show_binlog_events(thd); |
| 3881 | break; |
| 3882 | } |
| 3883 | #endif |
| 3884 | |
| 3885 | case SQLCOM_ASSIGN_TO_KEYCACHE: |
| 3886 | { |
| 3887 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 3888 | if (check_access(thd, INDEX_ACL, first_table->db.str, |
| 3889 | &first_table->grant.privilege, |
| 3890 | &first_table->grant.m_internal, |
| 3891 | 0, 0)) |
| 3892 | goto error; |
| 3893 | res= mysql_assign_to_keycache(thd, first_table, &lex->ident); |
| 3894 | break; |
| 3895 | } |
| 3896 | case SQLCOM_PRELOAD_KEYS: |
| 3897 | { |
| 3898 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 3899 | if (check_access(thd, INDEX_ACL, first_table->db.str, |
| 3900 | &first_table->grant.privilege, |
| 3901 | &first_table->grant.m_internal, |
| 3902 | 0, 0)) |
| 3903 | goto error; |
| 3904 | res = mysql_preload_keys(thd, first_table); |
| 3905 | break; |
| 3906 | } |
| 3907 | #ifdef HAVE_REPLICATION |
| 3908 | case SQLCOM_CHANGE_MASTER: |
| 3909 | { |
| 3910 | LEX_MASTER_INFO *lex_mi= &thd->lex->mi; |
| 3911 | Master_info *mi; |
| 3912 | bool new_master= 0; |
| 3913 | bool master_info_added; |
| 3914 | |
| 3915 | if (check_global_access(thd, SUPER_ACL)) |
| 3916 | goto error; |
| 3917 | /* |
| 3918 | In this code it's ok to use LOCK_active_mi as we are adding new things |
| 3919 | into master_info_index |
| 3920 | */ |
| 3921 | mysql_mutex_lock(&LOCK_active_mi); |
| 3922 | if (!master_info_index) |
| 3923 | { |
| 3924 | mysql_mutex_unlock(&LOCK_active_mi); |
| 3925 | my_error(ER_SERVER_SHUTDOWN, MYF(0)); |
| 3926 | goto error; |
| 3927 | } |
| 3928 | |
| 3929 | mi= master_info_index->get_master_info(&lex_mi->connection_name, |
| 3930 | Sql_condition::WARN_LEVEL_NOTE); |
| 3931 | |
| 3932 | if (mi == NULL) |
| 3933 | { |
| 3934 | /* New replication created */ |
| 3935 | mi= new Master_info(&lex_mi->connection_name, relay_log_recovery); |
| 3936 | if (unlikely(!mi || mi->error())) |
| 3937 | { |
| 3938 | delete mi; |
| 3939 | res= 1; |
| 3940 | mysql_mutex_unlock(&LOCK_active_mi); |
| 3941 | break; |
| 3942 | } |
| 3943 | new_master= 1; |
| 3944 | } |
| 3945 | |
| 3946 | res= change_master(thd, mi, &master_info_added); |
| 3947 | if (res && new_master) |
| 3948 | { |
| 3949 | /* |
| 3950 | If the new master was added by change_master(), remove it as it didn't |
| 3951 | work (this will free mi as well). |
| 3952 | |
| 3953 | If new master was not added, we still need to free mi. |
| 3954 | */ |
| 3955 | if (master_info_added) |
| 3956 | master_info_index->remove_master_info(mi); |
| 3957 | else |
| 3958 | delete mi; |
| 3959 | } |
| 3960 | else |
| 3961 | { |
| 3962 | mi->rpl_filter= get_or_create_rpl_filter(lex_mi->connection_name.str, |
| 3963 | lex_mi->connection_name.length); |
| 3964 | } |
| 3965 | |
| 3966 | mysql_mutex_unlock(&LOCK_active_mi); |
| 3967 | break; |
| 3968 | } |
| 3969 | case SQLCOM_SHOW_SLAVE_STAT: |
| 3970 | { |
| 3971 | /* Accept one of two privileges */ |
| 3972 | if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) |
| 3973 | goto error; |
| 3974 | |
| 3975 | if (lex->verbose) |
| 3976 | { |
| 3977 | mysql_mutex_lock(&LOCK_active_mi); |
| 3978 | res= show_all_master_info(thd); |
| 3979 | mysql_mutex_unlock(&LOCK_active_mi); |
| 3980 | } |
| 3981 | else |
| 3982 | { |
| 3983 | LEX_MASTER_INFO *lex_mi= &thd->lex->mi; |
| 3984 | Master_info *mi; |
| 3985 | if ((mi= get_master_info(&lex_mi->connection_name, |
| 3986 | Sql_condition::WARN_LEVEL_ERROR))) |
| 3987 | { |
| 3988 | res= show_master_info(thd, mi, 0); |
| 3989 | mi->release(); |
| 3990 | } |
| 3991 | } |
| 3992 | break; |
| 3993 | } |
| 3994 | case SQLCOM_SHOW_MASTER_STAT: |
| 3995 | { |
| 3996 | /* Accept one of two privileges */ |
| 3997 | if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) |
| 3998 | goto error; |
| 3999 | res = show_binlog_info(thd); |
| 4000 | break; |
| 4001 | } |
| 4002 | |
| 4003 | #endif /* HAVE_REPLICATION */ |
| 4004 | case SQLCOM_SHOW_ENGINE_STATUS: |
| 4005 | { |
| 4006 | if (check_global_access(thd, PROCESS_ACL)) |
| 4007 | goto error; |
| 4008 | res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_STATUS); |
| 4009 | break; |
| 4010 | } |
| 4011 | case SQLCOM_SHOW_ENGINE_MUTEX: |
| 4012 | { |
| 4013 | if (check_global_access(thd, PROCESS_ACL)) |
| 4014 | goto error; |
| 4015 | res = ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_MUTEX); |
| 4016 | break; |
| 4017 | } |
| 4018 | case SQLCOM_CREATE_SEQUENCE: |
| 4019 | case SQLCOM_CREATE_TABLE: |
| 4020 | { |
| 4021 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 4022 | bool link_to_local; |
| 4023 | TABLE_LIST *create_table= first_table; |
| 4024 | TABLE_LIST *select_tables= lex->create_last_non_select_table->next_global; |
| 4025 | |
| 4026 | if (lex->tmp_table()) |
| 4027 | { |
| 4028 | status_var_decrement(thd->status_var.com_stat[SQLCOM_CREATE_TABLE]); |
| 4029 | status_var_increment(thd->status_var.com_create_tmp_table); |
| 4030 | } |
| 4031 | |
| 4032 | /* |
| 4033 | Code below (especially in mysql_create_table() and select_create |
| 4034 | methods) may modify HA_CREATE_INFO structure in LEX, so we have to |
| 4035 | use a copy of this structure to make execution prepared statement- |
| 4036 | safe. A shallow copy is enough as this code won't modify any memory |
| 4037 | referenced from this structure. |
| 4038 | */ |
| 4039 | Table_specification_st create_info(lex->create_info); |
| 4040 | /* |
| 4041 | We need to copy alter_info for the same reasons of re-execution |
| 4042 | safety, only in case of Alter_info we have to do (almost) a deep |
| 4043 | copy. |
| 4044 | */ |
| 4045 | Alter_info alter_info(lex->alter_info, thd->mem_root); |
| 4046 | if (unlikely(thd->is_fatal_error)) |
| 4047 | { |
| 4048 | /* If out of memory when creating a copy of alter_info. */ |
| 4049 | res= 1; |
| 4050 | goto end_with_restore_list; |
| 4051 | } |
| 4052 | |
| 4053 | /* Check privileges */ |
| 4054 | if ((res= create_table_precheck(thd, select_tables, create_table))) |
| 4055 | goto end_with_restore_list; |
| 4056 | |
| 4057 | /* Might have been updated in create_table_precheck */ |
| 4058 | create_info.alias= create_table->alias; |
| 4059 | |
| 4060 | /* Fix names if symlinked or relocated tables */ |
| 4061 | if (append_file_to_dir(thd, &create_info.data_file_name, |
| 4062 | &create_table->table_name) || |
| 4063 | append_file_to_dir(thd, &create_info.index_file_name, |
| 4064 | &create_table->table_name)) |
| 4065 | goto end_with_restore_list; |
| 4066 | |
| 4067 | /* |
| 4068 | If no engine type was given, work out the default now |
| 4069 | rather than at parse-time. |
| 4070 | */ |
| 4071 | if (!(create_info.used_fields & HA_CREATE_USED_ENGINE)) |
| 4072 | create_info.use_default_db_type(thd); |
| 4073 | |
| 4074 | /* |
| 4075 | If we are using SET CHARSET without DEFAULT, add an implicit |
| 4076 | DEFAULT to not confuse old users. (This may change). |
| 4077 | */ |
| 4078 | if ((create_info.used_fields & |
| 4079 | (HA_CREATE_USED_DEFAULT_CHARSET | HA_CREATE_USED_CHARSET)) == |
| 4080 | HA_CREATE_USED_CHARSET) |
| 4081 | { |
| 4082 | create_info.used_fields&= ~HA_CREATE_USED_CHARSET; |
| 4083 | create_info.used_fields|= HA_CREATE_USED_DEFAULT_CHARSET; |
| 4084 | create_info.default_table_charset= create_info.table_charset; |
| 4085 | create_info.table_charset= 0; |
| 4086 | } |
| 4087 | |
| 4088 | /* |
| 4089 | If we are a slave, we should add OR REPLACE if we don't have |
| 4090 | IF EXISTS. This will help a slave to recover from |
| 4091 | CREATE TABLE OR EXISTS failures by dropping the table and |
| 4092 | retrying the create. |
| 4093 | */ |
| 4094 | if (thd->slave_thread && |
| 4095 | slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT && |
| 4096 | !lex->create_info.if_not_exists()) |
| 4097 | { |
| 4098 | create_info.add(DDL_options_st::OPT_OR_REPLACE); |
| 4099 | create_info.add(DDL_options_st::OPT_OR_REPLACE_SLAVE_GENERATED); |
| 4100 | } |
| 4101 | |
| 4102 | #ifdef WITH_PARTITION_STORAGE_ENGINE |
| 4103 | { |
| 4104 | partition_info *part_info= thd->lex->part_info; |
| 4105 | if (part_info && !(part_info= part_info->get_clone(thd))) |
| 4106 | { |
| 4107 | res= -1; |
| 4108 | goto end_with_restore_list; |
| 4109 | } |
| 4110 | thd->work_part_info= part_info; |
| 4111 | } |
| 4112 | #endif |
| 4113 | |
| 4114 | if (select_lex->item_list.elements) // With select |
| 4115 | { |
| 4116 | select_result *result; |
| 4117 | |
| 4118 | /* |
| 4119 | CREATE TABLE...IGNORE/REPLACE SELECT... can be unsafe, unless |
| 4120 | ORDER BY PRIMARY KEY clause is used in SELECT statement. We therefore |
| 4121 | use row based logging if mixed or row based logging is available. |
| 4122 | TODO: Check if the order of the output of the select statement is |
| 4123 | deterministic. Waiting for BUG#42415 |
| 4124 | */ |
| 4125 | if(lex->ignore) |
| 4126 | lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_IGNORE_SELECT); |
| 4127 | |
| 4128 | if(lex->duplicates == DUP_REPLACE) |
| 4129 | lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_REPLACE_SELECT); |
| 4130 | |
| 4131 | /* |
| 4132 | If: |
| 4133 | a) we inside an SP and there was NAME_CONST substitution, |
| 4134 | b) binlogging is on (STMT mode), |
| 4135 | c) we log the SP as separate statements |
| 4136 | raise a warning, as it may cause problems |
| 4137 | (see 'NAME_CONST issues' in 'Binary Logging of Stored Programs') |
| 4138 | */ |
| 4139 | if (thd->query_name_consts && mysql_bin_log.is_open() && |
| 4140 | thd->wsrep_binlog_format() == BINLOG_FORMAT_STMT && |
| 4141 | !mysql_bin_log.is_query_in_union(thd, thd->query_id)) |
| 4142 | { |
| 4143 | List_iterator_fast<Item> it(select_lex->item_list); |
| 4144 | Item *item; |
| 4145 | uint splocal_refs= 0; |
| 4146 | /* Count SP local vars in the top-level SELECT list */ |
| 4147 | while ((item= it++)) |
| 4148 | { |
| 4149 | if (item->get_item_splocal()) |
| 4150 | splocal_refs++; |
| 4151 | } |
| 4152 | /* |
| 4153 | If it differs from number of NAME_CONST substitution applied, |
| 4154 | we may have a SOME_FUNC(NAME_CONST()) in the SELECT list, |
| 4155 | that may cause a problem with binary log (see BUG#35383), |
| 4156 | raise a warning. |
| 4157 | */ |
| 4158 | if (splocal_refs != thd->query_name_consts) |
| 4159 | push_warning(thd, |
| 4160 | Sql_condition::WARN_LEVEL_WARN, |
| 4161 | ER_UNKNOWN_ERROR, |
| 4162 | "Invoked routine ran a statement that may cause problems with " |
| 4163 | "binary log, see 'NAME_CONST issues' in 'Binary Logging of Stored Programs' " |
| 4164 | "section of the manual." ); |
| 4165 | } |
| 4166 | |
| 4167 | select_lex->options|= SELECT_NO_UNLOCK; |
| 4168 | unit->set_limit(select_lex); |
| 4169 | |
| 4170 | /* |
| 4171 | Disable non-empty MERGE tables with CREATE...SELECT. Too |
| 4172 | complicated. See Bug #26379. Empty MERGE tables are read-only |
| 4173 | and don't allow CREATE...SELECT anyway. |
| 4174 | */ |
| 4175 | if (create_info.used_fields & HA_CREATE_USED_UNION) |
| 4176 | { |
| 4177 | my_error(ER_WRONG_OBJECT, MYF(0), create_table->db.str, |
| 4178 | create_table->table_name.str, "BASE TABLE" ); |
| 4179 | res= 1; |
| 4180 | goto end_with_restore_list; |
| 4181 | } |
| 4182 | |
| 4183 | /* Copy temporarily the statement flags to thd for lock_table_names() */ |
| 4184 | uint save_thd_create_info_options= thd->lex->create_info.options; |
| 4185 | thd->lex->create_info.options|= create_info.options; |
| 4186 | res= open_and_lock_tables(thd, create_info, lex->query_tables, TRUE, 0); |
| 4187 | thd->lex->create_info.options= save_thd_create_info_options; |
| 4188 | if (unlikely(res)) |
| 4189 | { |
| 4190 | /* Got error or warning. Set res to 1 if error */ |
| 4191 | if (!(res= thd->is_error())) |
| 4192 | my_ok(thd); // CREATE ... IF NOT EXISTS |
| 4193 | goto end_with_restore_list; |
| 4194 | } |
| 4195 | |
| 4196 | /* Ensure we don't try to create something from which we select from */ |
| 4197 | if (create_info.or_replace() && !create_info.tmp_table()) |
| 4198 | { |
| 4199 | TABLE_LIST *duplicate; |
| 4200 | if (unlikely((duplicate= unique_table(thd, lex->query_tables, |
| 4201 | lex->query_tables->next_global, |
| 4202 | CHECK_DUP_FOR_CREATE)))) |
| 4203 | { |
| 4204 | update_non_unique_table_error(lex->query_tables, "CREATE" , |
| 4205 | duplicate); |
| 4206 | res= TRUE; |
| 4207 | goto end_with_restore_list; |
| 4208 | } |
| 4209 | } |
| 4210 | { |
| 4211 | /* |
| 4212 | Remove target table from main select and name resolution |
| 4213 | context. This can't be done earlier as it will break view merging in |
| 4214 | statements like "CREATE TABLE IF NOT EXISTS existing_view SELECT". |
| 4215 | */ |
| 4216 | lex->unlink_first_table(&link_to_local); |
| 4217 | |
| 4218 | /* Store reference to table in case of LOCK TABLES */ |
| 4219 | create_info.table= create_table->table; |
| 4220 | |
| 4221 | /* |
| 4222 | select_create is currently not re-execution friendly and |
| 4223 | needs to be created for every execution of a PS/SP. |
| 4224 | Note: In wsrep-patch, CTAS is handled like a regular transaction. |
| 4225 | */ |
| 4226 | if (unlikely((result= new (thd->mem_root) |
| 4227 | select_create(thd, create_table, |
| 4228 | &create_info, |
| 4229 | &alter_info, |
| 4230 | select_lex->item_list, |
| 4231 | lex->duplicates, |
| 4232 | lex->ignore, |
| 4233 | select_tables)))) |
| 4234 | { |
| 4235 | /* |
| 4236 | CREATE from SELECT give its SELECT_LEX for SELECT, |
| 4237 | and item_list belong to SELECT |
| 4238 | */ |
| 4239 | if (!(res= handle_select(thd, lex, result, 0))) |
| 4240 | { |
| 4241 | if (create_info.tmp_table()) |
| 4242 | thd->variables.option_bits|= OPTION_KEEP_LOG; |
| 4243 | } |
| 4244 | delete result; |
| 4245 | } |
| 4246 | lex->link_first_table_back(create_table, link_to_local); |
| 4247 | } |
| 4248 | } |
| 4249 | else |
| 4250 | { |
| 4251 | /* regular create */ |
| 4252 | if (create_info.like()) |
| 4253 | { |
| 4254 | /* CREATE TABLE ... LIKE ... */ |
| 4255 | res= mysql_create_like_table(thd, create_table, select_tables, |
| 4256 | &create_info); |
| 4257 | } |
| 4258 | else |
| 4259 | { |
| 4260 | if (create_info.vers_fix_system_fields(thd, &alter_info, *create_table) || |
| 4261 | create_info.vers_check_system_fields(thd, &alter_info, *create_table)) |
| 4262 | goto end_with_restore_list; |
| 4263 | |
| 4264 | /* |
| 4265 | In STATEMENT format, we probably have to replicate also temporary |
| 4266 | tables, like mysql replication does. Also check if the requested |
| 4267 | engine is allowed/supported. |
| 4268 | */ |
| 4269 | if (WSREP(thd) && |
| 4270 | !check_engine(thd, create_table->db.str, create_table->table_name.str, |
| 4271 | &create_info) && |
| 4272 | (!thd->is_current_stmt_binlog_format_row() || |
| 4273 | !create_info.tmp_table())) |
| 4274 | { |
| 4275 | WSREP_TO_ISOLATION_BEGIN(create_table->db.str, create_table->table_name.str, NULL); |
| 4276 | } |
| 4277 | /* Regular CREATE TABLE */ |
| 4278 | res= mysql_create_table(thd, create_table, &create_info, &alter_info); |
| 4279 | } |
| 4280 | |
| 4281 | if (!res) |
| 4282 | { |
| 4283 | /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ |
| 4284 | if (create_info.tmp_table()) |
| 4285 | thd->variables.option_bits|= OPTION_KEEP_LOG; |
| 4286 | /* in case of create temp tables if @@session_track_state_change is |
| 4287 | ON then send session state notification in OK packet */ |
| 4288 | if(create_info.options & HA_LEX_CREATE_TMP_TABLE) |
| 4289 | { |
| 4290 | SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL); |
| 4291 | } |
| 4292 | my_ok(thd); |
| 4293 | } |
| 4294 | } |
| 4295 | |
| 4296 | end_with_restore_list: |
| 4297 | break; |
| 4298 | } |
| 4299 | case SQLCOM_CREATE_INDEX: |
| 4300 | case SQLCOM_DROP_INDEX: |
| 4301 | /* |
| 4302 | CREATE INDEX and DROP INDEX are implemented by calling ALTER |
| 4303 | TABLE with proper arguments. |
| 4304 | |
| 4305 | In the future ALTER TABLE will notice that the request is to |
| 4306 | only add indexes and create these one by one for the existing |
| 4307 | table without having to do a full rebuild. |
| 4308 | */ |
| 4309 | { |
| 4310 | /* Prepare stack copies to be re-execution safe */ |
| 4311 | HA_CREATE_INFO create_info; |
| 4312 | Alter_info alter_info(lex->alter_info, thd->mem_root); |
| 4313 | |
| 4314 | if (unlikely(thd->is_fatal_error)) /* out of memory creating alter_info */ |
| 4315 | goto error; |
| 4316 | |
| 4317 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 4318 | if (check_one_table_access(thd, INDEX_ACL, all_tables)) |
| 4319 | goto error; /* purecov: inspected */ |
| 4320 | WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL); |
| 4321 | /* |
| 4322 | Currently CREATE INDEX or DROP INDEX cause a full table rebuild |
| 4323 | and thus classify as slow administrative statements just like |
| 4324 | ALTER TABLE. |
| 4325 | */ |
| 4326 | thd->prepare_logs_for_admin_command(); |
| 4327 | |
| 4328 | bzero((char*) &create_info, sizeof(create_info)); |
| 4329 | create_info.db_type= 0; |
| 4330 | create_info.row_type= ROW_TYPE_NOT_USED; |
| 4331 | create_info.default_table_charset= thd->variables.collation_database; |
| 4332 | |
| 4333 | res= mysql_alter_table(thd, &first_table->db, &first_table->table_name, |
| 4334 | &create_info, first_table, &alter_info, |
| 4335 | 0, (ORDER*) 0, 0); |
| 4336 | break; |
| 4337 | } |
| 4338 | #ifdef HAVE_REPLICATION |
| 4339 | case SQLCOM_SLAVE_START: |
| 4340 | { |
| 4341 | LEX_MASTER_INFO* lex_mi= &thd->lex->mi; |
| 4342 | Master_info *mi; |
| 4343 | int load_error; |
| 4344 | |
| 4345 | load_error= rpl_load_gtid_slave_state(thd); |
| 4346 | |
| 4347 | /* |
| 4348 | We don't need to ensure that only one user is using master_info |
| 4349 | as start_slave is protected against simultaneous usage |
| 4350 | */ |
| 4351 | if (unlikely((mi= get_master_info(&lex_mi->connection_name, |
| 4352 | Sql_condition::WARN_LEVEL_ERROR)))) |
| 4353 | { |
| 4354 | if (load_error) |
| 4355 | { |
| 4356 | /* |
| 4357 | We cannot start a slave using GTID if we cannot load the |
| 4358 | GTID position from the mysql.gtid_slave_pos table. But we |
| 4359 | can allow non-GTID replication (useful eg. during upgrade). |
| 4360 | */ |
| 4361 | if (mi->using_gtid != Master_info::USE_GTID_NO) |
| 4362 | { |
| 4363 | mi->release(); |
| 4364 | break; |
| 4365 | } |
| 4366 | else |
| 4367 | thd->clear_error(); |
| 4368 | } |
| 4369 | if (!start_slave(thd, mi, 1 /* net report*/)) |
| 4370 | my_ok(thd); |
| 4371 | mi->release(); |
| 4372 | } |
| 4373 | break; |
| 4374 | } |
| 4375 | case SQLCOM_SLAVE_STOP: |
| 4376 | { |
| 4377 | LEX_MASTER_INFO *lex_mi; |
| 4378 | Master_info *mi; |
| 4379 | /* |
| 4380 | If the client thread has locked tables, a deadlock is possible. |
| 4381 | Assume that |
| 4382 | - the client thread does LOCK TABLE t READ. |
| 4383 | - then the master updates t. |
| 4384 | - then the SQL slave thread wants to update t, |
| 4385 | so it waits for the client thread because t is locked by it. |
| 4386 | - then the client thread does SLAVE STOP. |
| 4387 | SLAVE STOP waits for the SQL slave thread to terminate its |
| 4388 | update t, which waits for the client thread because t is locked by it. |
| 4389 | To prevent that, refuse SLAVE STOP if the |
| 4390 | client thread has locked tables |
| 4391 | */ |
| 4392 | if (thd->locked_tables_mode || |
| 4393 | thd->in_active_multi_stmt_transaction() || |
| 4394 | thd->global_read_lock.is_acquired()) |
| 4395 | { |
| 4396 | my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, |
| 4397 | ER_THD(thd, ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); |
| 4398 | goto error; |
| 4399 | } |
| 4400 | |
| 4401 | lex_mi= &thd->lex->mi; |
| 4402 | if ((mi= get_master_info(&lex_mi->connection_name, |
| 4403 | Sql_condition::WARN_LEVEL_ERROR))) |
| 4404 | { |
| 4405 | if (stop_slave(thd, mi, 1/* net report*/)) |
| 4406 | res= 1; |
| 4407 | mi->release(); |
| 4408 | if (rpl_parallel_resize_pool_if_no_slaves()) |
| 4409 | res= 1; |
| 4410 | if (!res) |
| 4411 | my_ok(thd); |
| 4412 | } |
| 4413 | break; |
| 4414 | } |
| 4415 | case SQLCOM_SLAVE_ALL_START: |
| 4416 | { |
| 4417 | mysql_mutex_lock(&LOCK_active_mi); |
| 4418 | if (master_info_index && !master_info_index->start_all_slaves(thd)) |
| 4419 | my_ok(thd); |
| 4420 | mysql_mutex_unlock(&LOCK_active_mi); |
| 4421 | break; |
| 4422 | } |
| 4423 | case SQLCOM_SLAVE_ALL_STOP: |
| 4424 | { |
| 4425 | if (thd->locked_tables_mode || |
| 4426 | thd->in_active_multi_stmt_transaction() || |
| 4427 | thd->global_read_lock.is_acquired()) |
| 4428 | { |
| 4429 | my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, |
| 4430 | ER_THD(thd, ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); |
| 4431 | goto error; |
| 4432 | } |
| 4433 | mysql_mutex_lock(&LOCK_active_mi); |
| 4434 | if (master_info_index && !master_info_index->stop_all_slaves(thd)) |
| 4435 | my_ok(thd); |
| 4436 | mysql_mutex_unlock(&LOCK_active_mi); |
| 4437 | break; |
| 4438 | } |
| 4439 | #endif /* HAVE_REPLICATION */ |
| 4440 | case SQLCOM_RENAME_TABLE: |
| 4441 | { |
| 4442 | if (check_rename_table(thd, first_table, all_tables)) |
| 4443 | goto error; |
| 4444 | |
| 4445 | WSREP_TO_ISOLATION_BEGIN(0, 0, first_table); |
| 4446 | |
| 4447 | if (mysql_rename_tables(thd, first_table, 0)) |
| 4448 | goto error; |
| 4449 | break; |
| 4450 | } |
| 4451 | #ifndef EMBEDDED_LIBRARY |
| 4452 | case SQLCOM_SHOW_BINLOGS: |
| 4453 | #ifdef DONT_ALLOW_SHOW_COMMANDS |
| 4454 | my_message(ER_NOT_ALLOWED_COMMAND, ER_THD(thd, ER_NOT_ALLOWED_COMMAND), |
| 4455 | MYF(0)); /* purecov: inspected */ |
| 4456 | goto error; |
| 4457 | #else |
| 4458 | { |
| 4459 | if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL)) |
| 4460 | goto error; |
| 4461 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); |
| 4462 | res = show_binlogs(thd); |
| 4463 | break; |
| 4464 | } |
| 4465 | #endif |
| 4466 | #endif /* EMBEDDED_LIBRARY */ |
| 4467 | case SQLCOM_SHOW_CREATE: |
| 4468 | { |
| 4469 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 4470 | #ifdef DONT_ALLOW_SHOW_COMMANDS |
| 4471 | my_message(ER_NOT_ALLOWED_COMMAND, ER_THD(thd, ER_NOT_ALLOWED_COMMAND), |
| 4472 | MYF(0)); /* purecov: inspected */ |
| 4473 | goto error; |
| 4474 | #else |
| 4475 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); |
| 4476 | |
| 4477 | /* |
| 4478 | Access check: |
| 4479 | SHOW CREATE TABLE require any privileges on the table level (ie |
| 4480 | effecting all columns in the table). |
| 4481 | SHOW CREATE VIEW require the SHOW_VIEW and SELECT ACLs on the table |
| 4482 | level. |
| 4483 | NOTE: SHOW_VIEW ACL is checked when the view is created. |
| 4484 | */ |
| 4485 | |
| 4486 | DBUG_PRINT("debug" , ("lex->only_view: %d, table: %s.%s" , |
| 4487 | lex->table_type == TABLE_TYPE_VIEW, |
| 4488 | first_table->db.str, first_table->table_name.str)); |
| 4489 | if (lex->table_type == TABLE_TYPE_VIEW) |
| 4490 | { |
| 4491 | if (check_table_access(thd, SELECT_ACL, first_table, FALSE, 1, FALSE)) |
| 4492 | { |
| 4493 | DBUG_PRINT("debug" , ("check_table_access failed" )); |
| 4494 | my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), |
| 4495 | "SHOW" , thd->security_ctx->priv_user, |
| 4496 | thd->security_ctx->host_or_ip, first_table->alias.str); |
| 4497 | goto error; |
| 4498 | } |
| 4499 | DBUG_PRINT("debug" , ("check_table_access succeeded" )); |
| 4500 | |
| 4501 | /* Ignore temporary tables if this is "SHOW CREATE VIEW" */ |
| 4502 | first_table->open_type= OT_BASE_ONLY; |
| 4503 | } |
| 4504 | else |
| 4505 | { |
| 4506 | /* |
| 4507 | Temporary tables should be opened for SHOW CREATE TABLE, but not |
| 4508 | for SHOW CREATE VIEW. |
| 4509 | */ |
| 4510 | if (thd->open_temporary_tables(all_tables)) |
| 4511 | goto error; |
| 4512 | |
| 4513 | /* |
| 4514 | The fact that check_some_access() returned FALSE does not mean that |
| 4515 | access is granted. We need to check if first_table->grant.privilege |
| 4516 | contains any table-specific privilege. |
| 4517 | */ |
| 4518 | DBUG_PRINT("debug" , ("first_table->grant.privilege: %lx" , |
| 4519 | first_table->grant.privilege)); |
| 4520 | if (check_some_access(thd, SHOW_CREATE_TABLE_ACLS, first_table) || |
| 4521 | (first_table->grant.privilege & SHOW_CREATE_TABLE_ACLS) == 0) |
| 4522 | { |
| 4523 | my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), |
| 4524 | "SHOW" , thd->security_ctx->priv_user, |
| 4525 | thd->security_ctx->host_or_ip, first_table->alias.str); |
| 4526 | goto error; |
| 4527 | } |
| 4528 | } |
| 4529 | |
| 4530 | /* Access is granted. Execute the command. */ |
| 4531 | res= mysqld_show_create(thd, first_table); |
| 4532 | break; |
| 4533 | #endif |
| 4534 | } |
| 4535 | case SQLCOM_CHECKSUM: |
| 4536 | { |
| 4537 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 4538 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_READ); |
| 4539 | |
| 4540 | if (check_table_access(thd, SELECT_ACL, all_tables, |
| 4541 | FALSE, UINT_MAX, FALSE)) |
| 4542 | goto error; /* purecov: inspected */ |
| 4543 | |
| 4544 | res = mysql_checksum_table(thd, first_table, &lex->check_opt); |
| 4545 | break; |
| 4546 | } |
| 4547 | case SQLCOM_UPDATE: |
| 4548 | { |
| 4549 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); |
| 4550 | ha_rows found= 0, updated= 0; |
| 4551 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 4552 | if (WSREP_CLIENT(thd) && |
| 4553 | wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) |
| 4554 | goto error; |
| 4555 | |
| 4556 | if (update_precheck(thd, all_tables)) |
| 4557 | break; |
| 4558 | |
| 4559 | /* |
| 4560 | UPDATE IGNORE can be unsafe. We therefore use row based |
| 4561 | logging if mixed or row based logging is available. |
| 4562 | TODO: Check if the order of the output of the select statement is |
| 4563 | deterministic. Waiting for BUG#42415 |
| 4564 | */ |
| 4565 | if (lex->ignore) |
| 4566 | lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_UPDATE_IGNORE); |
| 4567 | |
| 4568 | DBUG_ASSERT(select_lex->offset_limit == 0); |
| 4569 | unit->set_limit(select_lex); |
| 4570 | MYSQL_UPDATE_START(thd->query()); |
| 4571 | res= up_result= mysql_update(thd, all_tables, |
| 4572 | select_lex->item_list, |
| 4573 | lex->value_list, |
| 4574 | select_lex->where, |
| 4575 | select_lex->order_list.elements, |
| 4576 | select_lex->order_list.first, |
| 4577 | unit->select_limit_cnt, |
| 4578 | lex->duplicates, lex->ignore, |
| 4579 | &found, &updated); |
| 4580 | MYSQL_UPDATE_DONE(res, found, updated); |
| 4581 | /* mysql_update return 2 if we need to switch to multi-update */ |
| 4582 | if (up_result != 2) |
| 4583 | break; |
| 4584 | } |
| 4585 | /* fall through */ |
| 4586 | case SQLCOM_UPDATE_MULTI: |
| 4587 | { |
| 4588 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 4589 | /* if we switched from normal update, rights are checked */ |
| 4590 | if (up_result != 2) |
| 4591 | { |
| 4592 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); |
| 4593 | if ((res= multi_update_precheck(thd, all_tables))) |
| 4594 | break; |
| 4595 | } |
| 4596 | else |
| 4597 | res= 0; |
| 4598 | |
| 4599 | unit->set_limit(select_lex); |
| 4600 | res= mysql_multi_update_prepare(thd); |
| 4601 | |
| 4602 | #ifdef HAVE_REPLICATION |
| 4603 | /* Check slave filtering rules */ |
| 4604 | if (unlikely(thd->slave_thread && !have_table_map_for_update)) |
| 4605 | { |
| 4606 | if (all_tables_not_ok(thd, all_tables)) |
| 4607 | { |
| 4608 | if (res!= 0) |
| 4609 | { |
| 4610 | res= 0; /* don't care of prev failure */ |
| 4611 | thd->clear_error(); /* filters are of highest prior */ |
| 4612 | } |
| 4613 | /* we warn the slave SQL thread */ |
| 4614 | my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); |
| 4615 | break; |
| 4616 | } |
| 4617 | if (res) |
| 4618 | break; |
| 4619 | } |
| 4620 | else |
| 4621 | { |
| 4622 | #endif /* HAVE_REPLICATION */ |
| 4623 | if (res) |
| 4624 | break; |
| 4625 | if (opt_readonly && |
| 4626 | !(thd->security_ctx->master_access & SUPER_ACL) && |
| 4627 | some_non_temp_table_to_be_updated(thd, all_tables)) |
| 4628 | { |
| 4629 | my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only" ); |
| 4630 | break; |
| 4631 | } |
| 4632 | #ifdef HAVE_REPLICATION |
| 4633 | } /* unlikely */ |
| 4634 | #endif |
| 4635 | { |
| 4636 | multi_update *result_obj; |
| 4637 | MYSQL_MULTI_UPDATE_START(thd->query()); |
| 4638 | res= mysql_multi_update(thd, all_tables, |
| 4639 | &select_lex->item_list, |
| 4640 | &lex->value_list, |
| 4641 | select_lex->where, |
| 4642 | select_lex->options, |
| 4643 | lex->duplicates, |
| 4644 | lex->ignore, |
| 4645 | unit, |
| 4646 | select_lex, |
| 4647 | &result_obj); |
| 4648 | if (result_obj) |
| 4649 | { |
| 4650 | MYSQL_MULTI_UPDATE_DONE(res, result_obj->num_found(), |
| 4651 | result_obj->num_updated()); |
| 4652 | res= FALSE; /* Ignore errors here */ |
| 4653 | delete result_obj; |
| 4654 | } |
| 4655 | else |
| 4656 | { |
| 4657 | MYSQL_MULTI_UPDATE_DONE(1, 0, 0); |
| 4658 | } |
| 4659 | } |
| 4660 | break; |
| 4661 | } |
| 4662 | case SQLCOM_REPLACE: |
| 4663 | #ifndef DBUG_OFF |
| 4664 | if (mysql_bin_log.is_open()) |
| 4665 | { |
| 4666 | /* |
| 4667 | Generate an incident log event before writing the real event |
| 4668 | to the binary log. We put this event is before the statement |
| 4669 | since that makes it simpler to check that the statement was |
| 4670 | not executed on the slave (since incidents usually stop the |
| 4671 | slave). |
| 4672 | |
| 4673 | Observe that any row events that are generated will be |
| 4674 | generated before. |
| 4675 | |
| 4676 | This is only for testing purposes and will not be present in a |
| 4677 | release build. |
| 4678 | */ |
| 4679 | |
| 4680 | Incident incident= INCIDENT_NONE; |
| 4681 | DBUG_PRINT("debug" , ("Just before generate_incident()" )); |
| 4682 | DBUG_EXECUTE_IF("incident_database_resync_on_replace" , |
| 4683 | incident= INCIDENT_LOST_EVENTS;); |
| 4684 | if (incident) |
| 4685 | { |
| 4686 | Incident_log_event ev(thd, incident); |
| 4687 | (void) mysql_bin_log.write(&ev); /* error is ignored */ |
| 4688 | if (mysql_bin_log.rotate_and_purge(true)) |
| 4689 | { |
| 4690 | res= 1; |
| 4691 | break; |
| 4692 | } |
| 4693 | } |
| 4694 | DBUG_PRINT("debug" , ("Just after generate_incident()" )); |
| 4695 | } |
| 4696 | #endif |
| 4697 | /* fall through */ |
| 4698 | case SQLCOM_INSERT: |
| 4699 | { |
| 4700 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE); |
| 4701 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 4702 | |
| 4703 | if (WSREP_CLIENT(thd) && |
| 4704 | wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) |
| 4705 | goto error; |
| 4706 | |
| 4707 | /* |
| 4708 | Since INSERT DELAYED doesn't support temporary tables, we could |
| 4709 | not pre-open temporary tables for SQLCOM_INSERT / SQLCOM_REPLACE. |
| 4710 | Open them here instead. |
| 4711 | */ |
| 4712 | if (first_table->lock_type != TL_WRITE_DELAYED) |
| 4713 | { |
| 4714 | res= (thd->open_temporary_tables(all_tables)) ? TRUE : FALSE; |
| 4715 | if (res) |
| 4716 | break; |
| 4717 | } |
| 4718 | |
| 4719 | if ((res= insert_precheck(thd, all_tables))) |
| 4720 | break; |
| 4721 | |
| 4722 | MYSQL_INSERT_START(thd->query()); |
| 4723 | res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, |
| 4724 | lex->update_list, lex->value_list, |
| 4725 | lex->duplicates, lex->ignore); |
| 4726 | MYSQL_INSERT_DONE(res, (ulong) thd->get_row_count_func()); |
| 4727 | /* |
| 4728 | If we have inserted into a VIEW, and the base table has |
| 4729 | AUTO_INCREMENT column, but this column is not accessible through |
| 4730 | a view, then we should restore LAST_INSERT_ID to the value it |
| 4731 | had before the statement. |
| 4732 | */ |
| 4733 | if (first_table->view && !first_table->contain_auto_increment) |
| 4734 | thd->first_successful_insert_id_in_cur_stmt= |
| 4735 | thd->first_successful_insert_id_in_prev_stmt; |
| 4736 | |
| 4737 | #ifdef ENABLED_DEBUG_SYNC |
| 4738 | DBUG_EXECUTE_IF("after_mysql_insert" , |
| 4739 | { |
| 4740 | const char act1[]= |
| 4741 | "now " |
| 4742 | "wait_for signal.continue" ; |
| 4743 | const char act2[]= |
| 4744 | "now " |
| 4745 | "signal signal.continued" ; |
| 4746 | DBUG_ASSERT(debug_sync_service); |
| 4747 | DBUG_ASSERT(!debug_sync_set_action(thd, |
| 4748 | STRING_WITH_LEN(act1))); |
| 4749 | DBUG_ASSERT(!debug_sync_set_action(thd, |
| 4750 | STRING_WITH_LEN(act2))); |
| 4751 | };); |
| 4752 | DEBUG_SYNC(thd, "after_mysql_insert" ); |
| 4753 | #endif |
| 4754 | break; |
| 4755 | } |
| 4756 | case SQLCOM_REPLACE_SELECT: |
| 4757 | case SQLCOM_INSERT_SELECT: |
| 4758 | { |
| 4759 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE); |
| 4760 | select_result *sel_result; |
| 4761 | bool explain= MY_TEST(lex->describe); |
| 4762 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 4763 | if (WSREP_CLIENT(thd) && |
| 4764 | wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_INSERT_REPLACE)) |
| 4765 | goto error; |
| 4766 | |
| 4767 | if ((res= insert_precheck(thd, all_tables))) |
| 4768 | break; |
| 4769 | #ifdef WITH_WSREP |
| 4770 | if (WSREP(thd) && thd->wsrep_consistency_check == CONSISTENCY_CHECK_DECLARED) |
| 4771 | { |
| 4772 | thd->wsrep_consistency_check = CONSISTENCY_CHECK_RUNNING; |
| 4773 | WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL); |
| 4774 | } |
| 4775 | #endif /* WITH_WSREP */ |
| 4776 | |
| 4777 | /* |
| 4778 | INSERT...SELECT...ON DUPLICATE KEY UPDATE/REPLACE SELECT/ |
| 4779 | INSERT...IGNORE...SELECT can be unsafe, unless ORDER BY PRIMARY KEY |
| 4780 | clause is used in SELECT statement. We therefore use row based |
| 4781 | logging if mixed or row based logging is available. |
| 4782 | TODO: Check if the order of the output of the select statement is |
| 4783 | deterministic. Waiting for BUG#42415 |
| 4784 | */ |
| 4785 | if (lex->sql_command == SQLCOM_INSERT_SELECT && |
| 4786 | lex->duplicates == DUP_UPDATE) |
| 4787 | lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_SELECT_UPDATE); |
| 4788 | |
| 4789 | if (lex->sql_command == SQLCOM_INSERT_SELECT && lex->ignore) |
| 4790 | lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_IGNORE_SELECT); |
| 4791 | |
| 4792 | if (lex->sql_command == SQLCOM_REPLACE_SELECT) |
| 4793 | lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_REPLACE_SELECT); |
| 4794 | |
| 4795 | /* Fix lock for first table */ |
| 4796 | if (first_table->lock_type == TL_WRITE_DELAYED) |
| 4797 | first_table->lock_type= TL_WRITE; |
| 4798 | |
| 4799 | /* Don't unlock tables until command is written to binary log */ |
| 4800 | select_lex->options|= SELECT_NO_UNLOCK; |
| 4801 | |
| 4802 | unit->set_limit(select_lex); |
| 4803 | |
| 4804 | if (!(res=open_and_lock_tables(thd, all_tables, TRUE, 0))) |
| 4805 | { |
| 4806 | MYSQL_INSERT_SELECT_START(thd->query()); |
| 4807 | /* |
| 4808 | Only the INSERT table should be merged. Other will be handled by |
| 4809 | select. |
| 4810 | */ |
| 4811 | /* Skip first table, which is the table we are inserting in */ |
| 4812 | TABLE_LIST *second_table= first_table->next_local; |
| 4813 | select_lex->table_list.first= second_table; |
| 4814 | select_lex->context.table_list= |
| 4815 | select_lex->context.first_name_resolution_table= second_table; |
| 4816 | res= mysql_insert_select_prepare(thd); |
| 4817 | if (!res && (sel_result= new (thd->mem_root) select_insert(thd, |
| 4818 | first_table, |
| 4819 | first_table->table, |
| 4820 | &lex->field_list, |
| 4821 | &lex->update_list, |
| 4822 | &lex->value_list, |
| 4823 | lex->duplicates, |
| 4824 | lex->ignore))) |
| 4825 | { |
| 4826 | if (lex->analyze_stmt) |
| 4827 | ((select_result_interceptor*)sel_result)->disable_my_ok_calls(); |
| 4828 | |
| 4829 | if (explain) |
| 4830 | res= mysql_explain_union(thd, &thd->lex->unit, sel_result); |
| 4831 | else |
| 4832 | res= handle_select(thd, lex, sel_result, OPTION_SETUP_TABLES_DONE); |
| 4833 | /* |
| 4834 | Invalidate the table in the query cache if something changed |
| 4835 | after unlocking when changes become visible. |
| 4836 | TODO: this is workaround. right way will be move invalidating in |
| 4837 | the unlock procedure. |
| 4838 | */ |
| 4839 | if (!res && first_table->lock_type == TL_WRITE_CONCURRENT_INSERT && |
| 4840 | thd->lock) |
| 4841 | { |
| 4842 | /* INSERT ... SELECT should invalidate only the very first table */ |
| 4843 | TABLE_LIST *save_table= first_table->next_local; |
| 4844 | first_table->next_local= 0; |
| 4845 | query_cache_invalidate3(thd, first_table, 1); |
| 4846 | first_table->next_local= save_table; |
| 4847 | } |
| 4848 | if (explain) |
| 4849 | { |
| 4850 | /* |
| 4851 | sel_result needs to be cleaned up properly. |
| 4852 | INSERT... SELECT statement will call either send_eof() or |
| 4853 | abort_result_set(). EXPLAIN doesn't call either, so we need |
| 4854 | to cleanup manually. |
| 4855 | */ |
| 4856 | sel_result->abort_result_set(); |
| 4857 | } |
| 4858 | delete sel_result; |
| 4859 | } |
| 4860 | |
| 4861 | if (!res && (explain || lex->analyze_stmt)) |
| 4862 | res= thd->lex->explain->send_explain(thd); |
| 4863 | |
| 4864 | /* revert changes for SP */ |
| 4865 | MYSQL_INSERT_SELECT_DONE(res, (ulong) thd->get_row_count_func()); |
| 4866 | select_lex->table_list.first= first_table; |
| 4867 | } |
| 4868 | /* |
| 4869 | If we have inserted into a VIEW, and the base table has |
| 4870 | AUTO_INCREMENT column, but this column is not accessible through |
| 4871 | a view, then we should restore LAST_INSERT_ID to the value it |
| 4872 | had before the statement. |
| 4873 | */ |
| 4874 | if (first_table->view && !first_table->contain_auto_increment) |
| 4875 | thd->first_successful_insert_id_in_cur_stmt= |
| 4876 | thd->first_successful_insert_id_in_prev_stmt; |
| 4877 | |
| 4878 | break; |
| 4879 | } |
| 4880 | case SQLCOM_DELETE: |
| 4881 | { |
| 4882 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); |
| 4883 | select_result *sel_result=lex->result; |
| 4884 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 4885 | if (WSREP_CLIENT(thd) && |
| 4886 | wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) |
| 4887 | goto error; |
| 4888 | |
| 4889 | if ((res= delete_precheck(thd, all_tables))) |
| 4890 | break; |
| 4891 | DBUG_ASSERT(select_lex->offset_limit == 0); |
| 4892 | unit->set_limit(select_lex); |
| 4893 | |
| 4894 | MYSQL_DELETE_START(thd->query()); |
| 4895 | Protocol * UNINIT_VAR(save_protocol); |
| 4896 | bool replaced_protocol= false; |
| 4897 | |
| 4898 | if (!select_lex->item_list.is_empty()) |
| 4899 | { |
| 4900 | /* This is DELETE ... RETURNING. It will return output to the client */ |
| 4901 | if (thd->lex->analyze_stmt) |
| 4902 | { |
| 4903 | /* |
| 4904 | Actually, it is ANALYZE .. DELETE .. RETURNING. We need to produce |
| 4905 | output and then discard it. |
| 4906 | */ |
| 4907 | sel_result= new (thd->mem_root) select_send_analyze(thd); |
| 4908 | replaced_protocol= true; |
| 4909 | save_protocol= thd->protocol; |
| 4910 | thd->protocol= new Protocol_discard(thd); |
| 4911 | } |
| 4912 | else |
| 4913 | { |
| 4914 | if (!(sel_result= lex->result) && |
| 4915 | !(sel_result= new (thd->mem_root) select_send(thd))) |
| 4916 | return 1; |
| 4917 | } |
| 4918 | } |
| 4919 | |
| 4920 | res = mysql_delete(thd, all_tables, |
| 4921 | select_lex->where, &select_lex->order_list, |
| 4922 | unit->select_limit_cnt, select_lex->options, |
| 4923 | sel_result); |
| 4924 | |
| 4925 | if (replaced_protocol) |
| 4926 | { |
| 4927 | delete thd->protocol; |
| 4928 | thd->protocol= save_protocol; |
| 4929 | } |
| 4930 | |
| 4931 | if (thd->lex->analyze_stmt || thd->lex->describe) |
| 4932 | { |
| 4933 | if (!res) |
| 4934 | res= thd->lex->explain->send_explain(thd); |
| 4935 | } |
| 4936 | |
| 4937 | delete sel_result; |
| 4938 | MYSQL_DELETE_DONE(res, (ulong) thd->get_row_count_func()); |
| 4939 | break; |
| 4940 | } |
| 4941 | case SQLCOM_DELETE_MULTI: |
| 4942 | { |
| 4943 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE); |
| 4944 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 4945 | TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; |
| 4946 | multi_delete *result; |
| 4947 | if (WSREP_CLIENT(thd) && |
| 4948 | wsrep_sync_wait(thd, WSREP_SYNC_WAIT_BEFORE_UPDATE_DELETE)) |
| 4949 | goto error; |
| 4950 | |
| 4951 | if ((res= multi_delete_precheck(thd, all_tables))) |
| 4952 | break; |
| 4953 | |
| 4954 | /* condition will be TRUE on SP re-excuting */ |
| 4955 | if (select_lex->item_list.elements != 0) |
| 4956 | select_lex->item_list.empty(); |
| 4957 | if (add_item_to_list(thd, new (thd->mem_root) Item_null(thd))) |
| 4958 | goto error; |
| 4959 | |
| 4960 | THD_STAGE_INFO(thd, stage_init); |
| 4961 | if ((res= open_and_lock_tables(thd, all_tables, TRUE, 0))) |
| 4962 | break; |
| 4963 | |
| 4964 | MYSQL_MULTI_DELETE_START(thd->query()); |
| 4965 | if (unlikely(res= mysql_multi_delete_prepare(thd))) |
| 4966 | { |
| 4967 | MYSQL_MULTI_DELETE_DONE(1, 0); |
| 4968 | goto error; |
| 4969 | } |
| 4970 | |
| 4971 | if (likely(!thd->is_fatal_error)) |
| 4972 | { |
| 4973 | result= new (thd->mem_root) multi_delete(thd, aux_tables, |
| 4974 | lex->table_count); |
| 4975 | if (unlikely(result)) |
| 4976 | { |
| 4977 | res= mysql_select(thd, |
| 4978 | select_lex->get_table_list(), |
| 4979 | select_lex->with_wild, |
| 4980 | select_lex->item_list, |
| 4981 | select_lex->where, |
| 4982 | 0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, |
| 4983 | (ORDER *)NULL, |
| 4984 | (select_lex->options | thd->variables.option_bits | |
| 4985 | SELECT_NO_JOIN_CACHE | SELECT_NO_UNLOCK | |
| 4986 | OPTION_SETUP_TABLES_DONE) & ~OPTION_BUFFER_RESULT, |
| 4987 | result, unit, select_lex); |
| 4988 | res|= (int)(thd->is_error()); |
| 4989 | |
| 4990 | MYSQL_MULTI_DELETE_DONE(res, result->num_deleted()); |
| 4991 | if (res) |
| 4992 | result->abort_result_set(); /* for both DELETE and EXPLAIN DELETE */ |
| 4993 | else |
| 4994 | { |
| 4995 | if (lex->describe || lex->analyze_stmt) |
| 4996 | res= thd->lex->explain->send_explain(thd); |
| 4997 | } |
| 4998 | delete result; |
| 4999 | } |
| 5000 | } |
| 5001 | else |
| 5002 | { |
| 5003 | res= TRUE; // Error |
| 5004 | MYSQL_MULTI_DELETE_DONE(1, 0); |
| 5005 | } |
| 5006 | break; |
| 5007 | } |
| 5008 | case SQLCOM_DROP_SEQUENCE: |
| 5009 | case SQLCOM_DROP_TABLE: |
| 5010 | { |
| 5011 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 5012 | if (!lex->tmp_table()) |
| 5013 | { |
| 5014 | if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)) |
| 5015 | goto error; /* purecov: inspected */ |
| 5016 | } |
| 5017 | else |
| 5018 | { |
| 5019 | status_var_decrement(thd->status_var.com_stat[lex->sql_command]); |
| 5020 | status_var_increment(thd->status_var.com_drop_tmp_table); |
| 5021 | |
| 5022 | /* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */ |
| 5023 | thd->variables.option_bits|= OPTION_KEEP_LOG; |
| 5024 | } |
| 5025 | /* |
| 5026 | If we are a slave, we should add IF EXISTS if the query executed |
| 5027 | on the master without an error. This will help a slave to |
| 5028 | recover from multi-table DROP TABLE that was aborted in the |
| 5029 | middle. |
| 5030 | */ |
| 5031 | if (thd->slave_thread && !thd->slave_expected_error && |
| 5032 | slave_ddl_exec_mode_options == SLAVE_EXEC_MODE_IDEMPOTENT) |
| 5033 | lex->create_info.set(DDL_options_st::OPT_IF_EXISTS); |
| 5034 | |
| 5035 | if (WSREP(thd)) |
| 5036 | { |
| 5037 | for (TABLE_LIST *table= all_tables; table; table= table->next_global) |
| 5038 | { |
| 5039 | if (!lex->tmp_table() && |
| 5040 | (!thd->is_current_stmt_binlog_format_row() || |
| 5041 | !thd->find_temporary_table(table))) |
| 5042 | { |
| 5043 | WSREP_TO_ISOLATION_BEGIN(NULL, NULL, all_tables); |
| 5044 | break; |
| 5045 | } |
| 5046 | } |
| 5047 | } |
| 5048 | |
| 5049 | /* DDL and binlog write order are protected by metadata locks. */ |
| 5050 | res= mysql_rm_table(thd, first_table, lex->if_exists(), lex->tmp_table(), |
| 5051 | lex->table_type == TABLE_TYPE_SEQUENCE); |
| 5052 | |
| 5053 | /* |
| 5054 | When dropping temporary tables if @@session_track_state_change is ON |
| 5055 | then send the boolean tracker in the OK packet |
| 5056 | */ |
| 5057 | if(!res && (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)) |
| 5058 | { |
| 5059 | SESSION_TRACKER_CHANGED(thd, SESSION_STATE_CHANGE_TRACKER, NULL); |
| 5060 | } |
| 5061 | break; |
| 5062 | } |
| 5063 | case SQLCOM_SHOW_PROCESSLIST: |
| 5064 | if (!thd->security_ctx->priv_user[0] && |
| 5065 | check_global_access(thd,PROCESS_ACL)) |
| 5066 | break; |
| 5067 | mysqld_list_processes(thd, |
| 5068 | (thd->security_ctx->master_access & PROCESS_ACL ? |
| 5069 | NullS : |
| 5070 | thd->security_ctx->priv_user), |
| 5071 | lex->verbose); |
| 5072 | break; |
| 5073 | case SQLCOM_SHOW_AUTHORS: |
| 5074 | res= mysqld_show_authors(thd); |
| 5075 | break; |
| 5076 | case SQLCOM_SHOW_CONTRIBUTORS: |
| 5077 | res= mysqld_show_contributors(thd); |
| 5078 | break; |
| 5079 | case SQLCOM_SHOW_PRIVILEGES: |
| 5080 | res= mysqld_show_privileges(thd); |
| 5081 | break; |
| 5082 | case SQLCOM_SHOW_ENGINE_LOGS: |
| 5083 | #ifdef DONT_ALLOW_SHOW_COMMANDS |
| 5084 | my_message(ER_NOT_ALLOWED_COMMAND, ER_THD(thd, ER_NOT_ALLOWED_COMMAND), |
| 5085 | MYF(0)); /* purecov: inspected */ |
| 5086 | goto error; |
| 5087 | #else |
| 5088 | { |
| 5089 | if (check_access(thd, FILE_ACL, any_db, NULL, NULL, 0, 0)) |
| 5090 | goto error; |
| 5091 | res= ha_show_status(thd, lex->create_info.db_type, HA_ENGINE_LOGS); |
| 5092 | break; |
| 5093 | } |
| 5094 | #endif |
| 5095 | case SQLCOM_CHANGE_DB: |
| 5096 | { |
| 5097 | if (!mysql_change_db(thd, &select_lex->db, FALSE)) |
| 5098 | my_ok(thd); |
| 5099 | |
| 5100 | break; |
| 5101 | } |
| 5102 | |
| 5103 | case SQLCOM_LOAD: |
| 5104 | { |
| 5105 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 5106 | uint privilege= (lex->duplicates == DUP_REPLACE ? |
| 5107 | INSERT_ACL | DELETE_ACL : INSERT_ACL) | |
| 5108 | (lex->local_file ? 0 : FILE_ACL); |
| 5109 | |
| 5110 | if (lex->local_file) |
| 5111 | { |
| 5112 | if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) || |
| 5113 | !opt_local_infile) |
| 5114 | { |
| 5115 | my_message(ER_NOT_ALLOWED_COMMAND, ER_THD(thd, ER_NOT_ALLOWED_COMMAND), MYF(0)); |
| 5116 | goto error; |
| 5117 | } |
| 5118 | } |
| 5119 | |
| 5120 | if (check_one_table_access(thd, privilege, all_tables)) |
| 5121 | goto error; |
| 5122 | |
| 5123 | res= mysql_load(thd, lex->exchange, first_table, lex->field_list, |
| 5124 | lex->update_list, lex->value_list, lex->duplicates, |
| 5125 | lex->ignore, (bool) lex->local_file); |
| 5126 | break; |
| 5127 | } |
| 5128 | |
| 5129 | case SQLCOM_SET_OPTION: |
| 5130 | { |
| 5131 | List<set_var_base> *lex_var_list= &lex->var_list; |
| 5132 | |
| 5133 | if ((check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE) |
| 5134 | || open_and_lock_tables(thd, all_tables, TRUE, 0))) |
| 5135 | goto error; |
| 5136 | if (likely(!(res= sql_set_variables(thd, lex_var_list, true)))) |
| 5137 | { |
| 5138 | if (likely(!thd->is_error())) |
| 5139 | my_ok(thd); |
| 5140 | } |
| 5141 | else |
| 5142 | { |
| 5143 | /* |
| 5144 | We encountered some sort of error, but no message was sent. |
| 5145 | Send something semi-generic here since we don't know which |
| 5146 | assignment in the list caused the error. |
| 5147 | */ |
| 5148 | if (!thd->is_error()) |
| 5149 | my_error(ER_WRONG_ARGUMENTS,MYF(0),"SET" ); |
| 5150 | goto error; |
| 5151 | } |
| 5152 | |
| 5153 | break; |
| 5154 | } |
| 5155 | |
| 5156 | case SQLCOM_UNLOCK_TABLES: |
| 5157 | /* |
| 5158 | It is critical for mysqldump --single-transaction --master-data that |
| 5159 | UNLOCK TABLES does not implicitely commit a connection which has only |
| 5160 | done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes |
| 5161 | false, mysqldump will not work. |
| 5162 | */ |
| 5163 | if (thd->variables.option_bits & OPTION_TABLE_LOCK) |
| 5164 | { |
| 5165 | res= trans_commit_implicit(thd); |
| 5166 | thd->locked_tables_list.unlock_locked_tables(thd); |
| 5167 | thd->mdl_context.release_transactional_locks(); |
| 5168 | thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); |
| 5169 | } |
| 5170 | if (thd->global_read_lock.is_acquired()) |
| 5171 | thd->global_read_lock.unlock_global_read_lock(thd); |
| 5172 | if (res) |
| 5173 | goto error; |
| 5174 | my_ok(thd); |
| 5175 | break; |
| 5176 | case SQLCOM_LOCK_TABLES: |
| 5177 | /* We must end the transaction first, regardless of anything */ |
| 5178 | res= trans_commit_implicit(thd); |
| 5179 | thd->locked_tables_list.unlock_locked_tables(thd); |
| 5180 | /* Release transactional metadata locks. */ |
| 5181 | thd->mdl_context.release_transactional_locks(); |
| 5182 | if (res) |
| 5183 | goto error; |
| 5184 | |
| 5185 | /* |
| 5186 | Here we have to pre-open temporary tables for LOCK TABLES. |
| 5187 | |
| 5188 | CF_PREOPEN_TMP_TABLES is not set for this SQL statement simply |
| 5189 | because LOCK TABLES calls close_thread_tables() as a first thing |
| 5190 | (it's called from unlock_locked_tables() above). So even if |
| 5191 | CF_PREOPEN_TMP_TABLES was set and the tables would be pre-opened |
| 5192 | in a usual way, they would have been closed. |
| 5193 | */ |
| 5194 | if (thd->open_temporary_tables(all_tables)) |
| 5195 | goto error; |
| 5196 | |
| 5197 | if (lock_tables_precheck(thd, all_tables)) |
| 5198 | goto error; |
| 5199 | |
| 5200 | thd->variables.option_bits|= OPTION_TABLE_LOCK; |
| 5201 | |
| 5202 | res= lock_tables_open_and_lock_tables(thd, all_tables); |
| 5203 | |
| 5204 | if (res) |
| 5205 | { |
| 5206 | thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); |
| 5207 | } |
| 5208 | else |
| 5209 | { |
| 5210 | #ifdef HAVE_QUERY_CACHE |
| 5211 | if (thd->variables.query_cache_wlock_invalidate) |
| 5212 | query_cache.invalidate_locked_for_write(thd, first_table); |
| 5213 | #endif /*HAVE_QUERY_CACHE*/ |
| 5214 | my_ok(thd); |
| 5215 | } |
| 5216 | break; |
| 5217 | case SQLCOM_CREATE_DB: |
| 5218 | { |
| 5219 | if (prepare_db_action(thd, lex->create_info.or_replace() ? |
| 5220 | (CREATE_ACL | DROP_ACL) : CREATE_ACL, |
| 5221 | &lex->name)) |
| 5222 | break; |
| 5223 | WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL); |
| 5224 | res= mysql_create_db(thd, &lex->name, |
| 5225 | lex->create_info, &lex->create_info); |
| 5226 | break; |
| 5227 | } |
| 5228 | case SQLCOM_DROP_DB: |
| 5229 | { |
| 5230 | if (prepare_db_action(thd, DROP_ACL, &lex->name)) |
| 5231 | break; |
| 5232 | WSREP_TO_ISOLATION_BEGIN(lex->name.str, NULL, NULL); |
| 5233 | res= mysql_rm_db(thd, &lex->name, lex->if_exists()); |
| 5234 | break; |
| 5235 | } |
| 5236 | case SQLCOM_ALTER_DB_UPGRADE: |
| 5237 | { |
| 5238 | LEX_CSTRING *db= &lex->name; |
| 5239 | #ifdef HAVE_REPLICATION |
| 5240 | if (thd->slave_thread) |
| 5241 | { |
| 5242 | rpl_filter= thd->system_thread_info.rpl_sql_info->rpl_filter; |
| 5243 | if (!rpl_filter->db_ok(db->str) || |
| 5244 | !rpl_filter->db_ok_with_wild_table(db->str)) |
| 5245 | { |
| 5246 | res= 1; |
| 5247 | my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE), MYF(0)); |
| 5248 | break; |
| 5249 | } |
| 5250 | } |
| 5251 | #endif |
| 5252 | if (check_db_name((LEX_STRING*) db)) |
| 5253 | { |
| 5254 | my_error(ER_WRONG_DB_NAME, MYF(0), db->str); |
| 5255 | break; |
| 5256 | } |
| 5257 | if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0) || |
| 5258 | check_access(thd, DROP_ACL, db->str, NULL, NULL, 1, 0) || |
| 5259 | check_access(thd, CREATE_ACL, db->str, NULL, NULL, 1, 0)) |
| 5260 | { |
| 5261 | res= 1; |
| 5262 | break; |
| 5263 | } |
| 5264 | WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL); |
| 5265 | res= mysql_upgrade_db(thd, db); |
| 5266 | if (!res) |
| 5267 | my_ok(thd); |
| 5268 | break; |
| 5269 | } |
| 5270 | case SQLCOM_ALTER_DB: |
| 5271 | { |
| 5272 | LEX_CSTRING *db= &lex->name; |
| 5273 | if (prepare_db_action(thd, ALTER_ACL, db)) |
| 5274 | break; |
| 5275 | WSREP_TO_ISOLATION_BEGIN(db->str, NULL, NULL); |
| 5276 | res= mysql_alter_db(thd, db, &lex->create_info); |
| 5277 | break; |
| 5278 | } |
| 5279 | case SQLCOM_SHOW_CREATE_DB: |
| 5280 | { |
| 5281 | char db_name_buff[NAME_LEN+1]; |
| 5282 | LEX_CSTRING db_name; |
| 5283 | DBUG_EXECUTE_IF("4x_server_emul" , |
| 5284 | my_error(ER_UNKNOWN_ERROR, MYF(0)); goto error;); |
| 5285 | |
| 5286 | db_name.str= db_name_buff; |
| 5287 | db_name.length= lex->name.length; |
| 5288 | strmov(db_name_buff, lex->name.str); |
| 5289 | |
| 5290 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); |
| 5291 | |
| 5292 | if (check_db_name((LEX_STRING*) &db_name)) |
| 5293 | { |
| 5294 | my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); |
| 5295 | break; |
| 5296 | } |
| 5297 | res= mysqld_show_create_db(thd, &db_name, &lex->name, lex->create_info); |
| 5298 | break; |
| 5299 | } |
| 5300 | case SQLCOM_CREATE_EVENT: |
| 5301 | case SQLCOM_ALTER_EVENT: |
| 5302 | #ifdef HAVE_EVENT_SCHEDULER |
| 5303 | do |
| 5304 | { |
| 5305 | DBUG_ASSERT(lex->event_parse_data); |
| 5306 | if (lex->table_or_sp_used()) |
| 5307 | { |
| 5308 | my_error(ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "CREATE/ALTER EVENT" ); |
| 5309 | break; |
| 5310 | } |
| 5311 | |
| 5312 | res= sp_process_definer(thd); |
| 5313 | if (res) |
| 5314 | break; |
| 5315 | |
| 5316 | switch (lex->sql_command) { |
| 5317 | case SQLCOM_CREATE_EVENT: |
| 5318 | { |
| 5319 | res= Events::create_event(thd, lex->event_parse_data); |
| 5320 | break; |
| 5321 | } |
| 5322 | case SQLCOM_ALTER_EVENT: |
| 5323 | res= Events::update_event(thd, lex->event_parse_data, |
| 5324 | lex->spname ? &lex->spname->m_db : NULL, |
| 5325 | lex->spname ? &lex->spname->m_name : NULL); |
| 5326 | break; |
| 5327 | default: |
| 5328 | DBUG_ASSERT(0); |
| 5329 | } |
| 5330 | DBUG_PRINT("info" ,("DDL error code=%d" , res)); |
| 5331 | if (!res) |
| 5332 | my_ok(thd); |
| 5333 | |
| 5334 | } while (0); |
| 5335 | /* Don't do it, if we are inside a SP */ |
| 5336 | if (!thd->spcont) |
| 5337 | { |
| 5338 | delete lex->sphead; |
| 5339 | lex->sphead= NULL; |
| 5340 | } |
| 5341 | /* lex->unit.cleanup() is called outside, no need to call it here */ |
| 5342 | break; |
| 5343 | case SQLCOM_SHOW_CREATE_EVENT: |
| 5344 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); |
| 5345 | res= Events::show_create_event(thd, &lex->spname->m_db, |
| 5346 | &lex->spname->m_name); |
| 5347 | break; |
| 5348 | case SQLCOM_DROP_EVENT: |
| 5349 | if (!(res= Events::drop_event(thd, |
| 5350 | &lex->spname->m_db, &lex->spname->m_name, |
| 5351 | lex->if_exists()))) |
| 5352 | my_ok(thd); |
| 5353 | break; |
| 5354 | #else |
| 5355 | my_error(ER_NOT_SUPPORTED_YET,MYF(0),"embedded server" ); |
| 5356 | break; |
| 5357 | #endif |
| 5358 | case SQLCOM_CREATE_FUNCTION: // UDF function |
| 5359 | { |
| 5360 | if (check_access(thd, lex->create_info.or_replace() ? |
| 5361 | (INSERT_ACL | DELETE_ACL) : INSERT_ACL, |
| 5362 | "mysql" , NULL, NULL, 1, 0)) |
| 5363 | break; |
| 5364 | #ifdef HAVE_DLOPEN |
| 5365 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 5366 | if (!(res = mysql_create_function(thd, &lex->udf))) |
| 5367 | my_ok(thd); |
| 5368 | #else |
| 5369 | my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled" ); |
| 5370 | res= TRUE; |
| 5371 | #endif |
| 5372 | break; |
| 5373 | } |
| 5374 | #ifndef NO_EMBEDDED_ACCESS_CHECKS |
| 5375 | case SQLCOM_CREATE_USER: |
| 5376 | case SQLCOM_CREATE_ROLE: |
| 5377 | { |
| 5378 | if (check_access(thd, lex->create_info.or_replace() ? |
| 5379 | INSERT_ACL | DELETE_ACL : INSERT_ACL, |
| 5380 | "mysql" , NULL, NULL, 1, 1) && |
| 5381 | check_global_access(thd,CREATE_USER_ACL)) |
| 5382 | break; |
| 5383 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 5384 | /* Conditionally writes to binlog */ |
| 5385 | if (!(res= mysql_create_user(thd, lex->users_list, |
| 5386 | lex->sql_command == SQLCOM_CREATE_ROLE))) |
| 5387 | my_ok(thd); |
| 5388 | break; |
| 5389 | } |
| 5390 | case SQLCOM_DROP_USER: |
| 5391 | case SQLCOM_DROP_ROLE: |
| 5392 | { |
| 5393 | if (check_access(thd, DELETE_ACL, "mysql" , NULL, NULL, 1, 1) && |
| 5394 | check_global_access(thd,CREATE_USER_ACL)) |
| 5395 | break; |
| 5396 | /* Conditionally writes to binlog */ |
| 5397 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 5398 | if (!(res= mysql_drop_user(thd, lex->users_list, |
| 5399 | lex->sql_command == SQLCOM_DROP_ROLE))) |
| 5400 | my_ok(thd); |
| 5401 | break; |
| 5402 | } |
| 5403 | case SQLCOM_ALTER_USER: |
| 5404 | case SQLCOM_RENAME_USER: |
| 5405 | { |
| 5406 | if (check_access(thd, UPDATE_ACL, "mysql" , NULL, NULL, 1, 1) && |
| 5407 | check_global_access(thd,CREATE_USER_ACL)) |
| 5408 | break; |
| 5409 | /* Conditionally writes to binlog */ |
| 5410 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 5411 | if (lex->sql_command == SQLCOM_ALTER_USER) |
| 5412 | res= mysql_alter_user(thd, lex->users_list); |
| 5413 | else |
| 5414 | res= mysql_rename_user(thd, lex->users_list); |
| 5415 | if (!res) |
| 5416 | my_ok(thd); |
| 5417 | break; |
| 5418 | } |
| 5419 | case SQLCOM_REVOKE_ALL: |
| 5420 | { |
| 5421 | if (check_access(thd, UPDATE_ACL, "mysql" , NULL, NULL, 1, 1) && |
| 5422 | check_global_access(thd,CREATE_USER_ACL)) |
| 5423 | break; |
| 5424 | |
| 5425 | /* Conditionally writes to binlog */ |
| 5426 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 5427 | if (!(res = mysql_revoke_all(thd, lex->users_list))) |
| 5428 | my_ok(thd); |
| 5429 | break; |
| 5430 | } |
| 5431 | case SQLCOM_REVOKE: |
| 5432 | case SQLCOM_GRANT: |
| 5433 | { |
| 5434 | if (lex->type != TYPE_ENUM_PROXY && |
| 5435 | check_access(thd, lex->grant | lex->grant_tot_col | GRANT_ACL, |
| 5436 | first_table ? first_table->db.str : select_lex->db.str, |
| 5437 | first_table ? &first_table->grant.privilege : NULL, |
| 5438 | first_table ? &first_table->grant.m_internal : NULL, |
| 5439 | first_table ? 0 : 1, 0)) |
| 5440 | goto error; |
| 5441 | |
| 5442 | /* Replicate current user as grantor */ |
| 5443 | thd->binlog_invoker(false); |
| 5444 | |
| 5445 | if (thd->security_ctx->user) // If not replication |
| 5446 | { |
| 5447 | LEX_USER *user; |
| 5448 | bool first_user= TRUE; |
| 5449 | |
| 5450 | List_iterator <LEX_USER> user_list(lex->users_list); |
| 5451 | while ((user= user_list++)) |
| 5452 | { |
| 5453 | if (specialflag & SPECIAL_NO_RESOLVE && |
| 5454 | hostname_requires_resolving(user->host.str)) |
| 5455 | push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, |
| 5456 | ER_WARN_HOSTNAME_WONT_WORK, |
| 5457 | ER_THD(thd, ER_WARN_HOSTNAME_WONT_WORK)); |
| 5458 | |
| 5459 | /* |
| 5460 | GRANT/REVOKE PROXY has the target user as a first entry in the list. |
| 5461 | */ |
| 5462 | if (lex->type == TYPE_ENUM_PROXY && first_user) |
| 5463 | { |
| 5464 | if (!(user= get_current_user(thd, user)) || !user->host.str) |
| 5465 | goto error; |
| 5466 | |
| 5467 | first_user= FALSE; |
| 5468 | if (acl_check_proxy_grant_access (thd, user->host.str, user->user.str, |
| 5469 | lex->grant & GRANT_ACL)) |
| 5470 | goto error; |
| 5471 | } |
| 5472 | } |
| 5473 | } |
| 5474 | if (first_table) |
| 5475 | { |
| 5476 | const Sp_handler *sph= Sp_handler::handler((stored_procedure_type) |
| 5477 | lex->type); |
| 5478 | if (sph) |
| 5479 | { |
| 5480 | uint grants= lex->all_privileges |
| 5481 | ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL) |
| 5482 | : lex->grant; |
| 5483 | if (check_grant_routine(thd, grants | GRANT_ACL, all_tables, sph, 0)) |
| 5484 | goto error; |
| 5485 | /* Conditionally writes to binlog */ |
| 5486 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 5487 | res= mysql_routine_grant(thd, all_tables, sph, |
| 5488 | lex->users_list, grants, |
| 5489 | lex->sql_command == SQLCOM_REVOKE, TRUE); |
| 5490 | if (!res) |
| 5491 | my_ok(thd); |
| 5492 | } |
| 5493 | else |
| 5494 | { |
| 5495 | if (check_grant(thd,(lex->grant | lex->grant_tot_col | GRANT_ACL), |
| 5496 | all_tables, FALSE, UINT_MAX, FALSE)) |
| 5497 | goto error; |
| 5498 | /* Conditionally writes to binlog */ |
| 5499 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 5500 | res= mysql_table_grant(thd, all_tables, lex->users_list, |
| 5501 | lex->columns, lex->grant, |
| 5502 | lex->sql_command == SQLCOM_REVOKE); |
| 5503 | } |
| 5504 | } |
| 5505 | else |
| 5506 | { |
| 5507 | if (lex->columns.elements || (lex->type && lex->type != TYPE_ENUM_PROXY)) |
| 5508 | { |
| 5509 | my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER_THD(thd, ER_ILLEGAL_GRANT_FOR_TABLE), |
| 5510 | MYF(0)); |
| 5511 | goto error; |
| 5512 | } |
| 5513 | else |
| 5514 | { |
| 5515 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 5516 | /* Conditionally writes to binlog */ |
| 5517 | res= mysql_grant(thd, select_lex->db.str, lex->users_list, lex->grant, |
| 5518 | lex->sql_command == SQLCOM_REVOKE, |
| 5519 | lex->type == TYPE_ENUM_PROXY); |
| 5520 | } |
| 5521 | if (!res) |
| 5522 | { |
| 5523 | if (lex->sql_command == SQLCOM_GRANT) |
| 5524 | { |
| 5525 | List_iterator <LEX_USER> str_list(lex->users_list); |
| 5526 | LEX_USER *user, *tmp_user; |
| 5527 | while ((tmp_user=str_list++)) |
| 5528 | { |
| 5529 | if (!(user= get_current_user(thd, tmp_user))) |
| 5530 | goto error; |
| 5531 | reset_mqh(user, 0); |
| 5532 | } |
| 5533 | } |
| 5534 | } |
| 5535 | } |
| 5536 | break; |
| 5537 | } |
| 5538 | case SQLCOM_REVOKE_ROLE: |
| 5539 | case SQLCOM_GRANT_ROLE: |
| 5540 | { |
| 5541 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 5542 | if (!(res= mysql_grant_role(thd, lex->users_list, |
| 5543 | lex->sql_command != SQLCOM_GRANT_ROLE))) |
| 5544 | my_ok(thd); |
| 5545 | break; |
| 5546 | } |
| 5547 | #endif /*!NO_EMBEDDED_ACCESS_CHECKS*/ |
| 5548 | case SQLCOM_RESET: |
| 5549 | /* |
| 5550 | RESET commands are never written to the binary log, so we have to |
| 5551 | initialize this variable because RESET shares the same code as FLUSH |
| 5552 | */ |
| 5553 | lex->no_write_to_binlog= 1; |
| 5554 | /* fall through */ |
| 5555 | case SQLCOM_FLUSH: |
| 5556 | { |
| 5557 | int write_to_binlog; |
| 5558 | if (check_global_access(thd,RELOAD_ACL)) |
| 5559 | goto error; |
| 5560 | |
| 5561 | if (first_table && lex->type & (REFRESH_READ_LOCK|REFRESH_FOR_EXPORT)) |
| 5562 | { |
| 5563 | /* Check table-level privileges. */ |
| 5564 | if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, |
| 5565 | FALSE, UINT_MAX, FALSE)) |
| 5566 | goto error; |
| 5567 | |
| 5568 | if (flush_tables_with_read_lock(thd, all_tables)) |
| 5569 | goto error; |
| 5570 | |
| 5571 | my_ok(thd); |
| 5572 | break; |
| 5573 | } |
| 5574 | |
| 5575 | #ifdef WITH_WSREP |
| 5576 | if (lex->type & ( |
| 5577 | REFRESH_GRANT | |
| 5578 | REFRESH_HOSTS | |
| 5579 | #ifdef HAVE_OPENSSL |
| 5580 | REFRESH_DES_KEY_FILE | |
| 5581 | #endif |
| 5582 | /* |
| 5583 | Write all flush log statements except |
| 5584 | FLUSH LOGS |
| 5585 | FLUSH BINARY LOGS |
| 5586 | Check reload_acl_and_cache for why. |
| 5587 | */ |
| 5588 | REFRESH_RELAY_LOG | |
| 5589 | REFRESH_SLOW_LOG | |
| 5590 | REFRESH_GENERAL_LOG | |
| 5591 | REFRESH_ENGINE_LOG | |
| 5592 | REFRESH_ERROR_LOG | |
| 5593 | #ifdef HAVE_QUERY_CACHE |
| 5594 | REFRESH_QUERY_CACHE_FREE | |
| 5595 | #endif /* HAVE_QUERY_CACHE */ |
| 5596 | REFRESH_STATUS | |
| 5597 | REFRESH_USER_RESOURCES)) |
| 5598 | { |
| 5599 | WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL); |
| 5600 | } |
| 5601 | #endif /* WITH_WSREP*/ |
| 5602 | |
| 5603 | #ifdef HAVE_REPLICATION |
| 5604 | if (lex->type & REFRESH_READ_LOCK) |
| 5605 | { |
| 5606 | /* |
| 5607 | We need to pause any parallel replication slave workers during FLUSH |
| 5608 | TABLES WITH READ LOCK. Otherwise we might cause a deadlock, as |
| 5609 | worker threads eun run in arbitrary order but need to commit in a |
| 5610 | specific given order. |
| 5611 | */ |
| 5612 | if (rpl_pause_for_ftwrl(thd)) |
| 5613 | goto error; |
| 5614 | } |
| 5615 | #endif |
| 5616 | /* |
| 5617 | reload_acl_and_cache() will tell us if we are allowed to write to the |
| 5618 | binlog or not. |
| 5619 | */ |
| 5620 | if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog)) |
| 5621 | { |
| 5622 | #ifdef WITH_WSREP |
| 5623 | if ((lex->type & REFRESH_TABLES) && !(lex->type & (REFRESH_FOR_EXPORT|REFRESH_READ_LOCK))) |
| 5624 | { |
| 5625 | /* |
| 5626 | This is done after reload_acl_and_cache is because |
| 5627 | LOCK TABLES is not replicated in galera, the upgrade of which |
| 5628 | is checked in reload_acl_and_cache. |
| 5629 | Hence, done after/if we are able to upgrade locks. |
| 5630 | */ |
| 5631 | if (first_table) |
| 5632 | { |
| 5633 | WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table); |
| 5634 | } |
| 5635 | else |
| 5636 | { |
| 5637 | WSREP_TO_ISOLATION_BEGIN_WRTCHK(WSREP_MYSQL_DB, NULL, NULL); |
| 5638 | } |
| 5639 | } |
| 5640 | #endif /* WITH_WSREP */ |
| 5641 | /* |
| 5642 | We WANT to write and we CAN write. |
| 5643 | ! we write after unlocking the table. |
| 5644 | */ |
| 5645 | /* |
| 5646 | Presumably, RESET and binlog writing doesn't require synchronization |
| 5647 | */ |
| 5648 | |
| 5649 | if (write_to_binlog > 0) // we should write |
| 5650 | { |
| 5651 | if (!lex->no_write_to_binlog) |
| 5652 | res= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); |
| 5653 | } else if (write_to_binlog < 0) |
| 5654 | { |
| 5655 | /* |
| 5656 | We should not write, but rather report error because |
| 5657 | reload_acl_and_cache binlog interactions failed |
| 5658 | */ |
| 5659 | res= 1; |
| 5660 | } |
| 5661 | |
| 5662 | if (!res) |
| 5663 | my_ok(thd); |
| 5664 | } |
| 5665 | else |
| 5666 | res= 1; // reload_acl_and_cache failed |
| 5667 | #ifdef HAVE_REPLICATION |
| 5668 | if (lex->type & REFRESH_READ_LOCK) |
| 5669 | rpl_unpause_after_ftwrl(thd); |
| 5670 | #endif |
| 5671 | |
| 5672 | break; |
| 5673 | } |
| 5674 | case SQLCOM_KILL: |
| 5675 | { |
| 5676 | if (lex->table_or_sp_used()) |
| 5677 | { |
| 5678 | my_error(ER_SUBQUERIES_NOT_SUPPORTED, MYF(0), "KILL" ); |
| 5679 | break; |
| 5680 | } |
| 5681 | |
| 5682 | if (lex->kill_type == KILL_TYPE_ID || lex->kill_type == KILL_TYPE_QUERY) |
| 5683 | { |
| 5684 | Item *it= (Item *)lex->value_list.head(); |
| 5685 | if ((!it->fixed && it->fix_fields(lex->thd, &it)) || it->check_cols(1)) |
| 5686 | { |
| 5687 | my_message(ER_SET_CONSTANTS_ONLY, ER_THD(thd, ER_SET_CONSTANTS_ONLY), |
| 5688 | MYF(0)); |
| 5689 | goto error; |
| 5690 | } |
| 5691 | sql_kill(thd, it->val_int(), lex->kill_signal, lex->kill_type); |
| 5692 | } |
| 5693 | else |
| 5694 | sql_kill_user(thd, get_current_user(thd, lex->users_list.head()), |
| 5695 | lex->kill_signal); |
| 5696 | break; |
| 5697 | } |
| 5698 | case SQLCOM_SHUTDOWN: |
| 5699 | #ifndef EMBEDDED_LIBRARY |
| 5700 | DBUG_EXECUTE_IF("crash_shutdown" , DBUG_SUICIDE();); |
| 5701 | if (check_global_access(thd,SHUTDOWN_ACL)) |
| 5702 | goto error; |
| 5703 | kill_mysql(thd); |
| 5704 | my_ok(thd); |
| 5705 | #else |
| 5706 | my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server" ); |
| 5707 | #endif |
| 5708 | break; |
| 5709 | |
| 5710 | #ifndef NO_EMBEDDED_ACCESS_CHECKS |
| 5711 | case SQLCOM_SHOW_CREATE_USER: |
| 5712 | { |
| 5713 | LEX_USER *grant_user= lex->grant_user; |
| 5714 | if (!grant_user) |
| 5715 | goto error; |
| 5716 | |
| 5717 | res = mysql_show_create_user(thd, grant_user); |
| 5718 | break; |
| 5719 | } |
| 5720 | case SQLCOM_SHOW_GRANTS: |
| 5721 | { |
| 5722 | LEX_USER *grant_user= lex->grant_user; |
| 5723 | if (!grant_user) |
| 5724 | goto error; |
| 5725 | |
| 5726 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); |
| 5727 | res = mysql_show_grants(thd, grant_user); |
| 5728 | break; |
| 5729 | } |
| 5730 | #endif |
| 5731 | case SQLCOM_HA_OPEN: |
| 5732 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 5733 | if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)) |
| 5734 | goto error; |
| 5735 | /* Close temporary tables which were pre-opened for privilege checking. */ |
| 5736 | close_thread_tables(thd); |
| 5737 | all_tables->table= NULL; |
| 5738 | res= mysql_ha_open(thd, first_table, 0); |
| 5739 | break; |
| 5740 | case SQLCOM_HA_CLOSE: |
| 5741 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 5742 | res= mysql_ha_close(thd, first_table); |
| 5743 | break; |
| 5744 | case SQLCOM_HA_READ: |
| 5745 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 5746 | /* |
| 5747 | There is no need to check for table permissions here, because |
| 5748 | if a user has no permissions to read a table, he won't be |
| 5749 | able to open it (with SQLCOM_HA_OPEN) in the first place. |
| 5750 | */ |
| 5751 | unit->set_limit(select_lex); |
| 5752 | |
| 5753 | res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str, |
| 5754 | lex->insert_list, lex->ha_rkey_mode, select_lex->where, |
| 5755 | unit->select_limit_cnt, unit->offset_limit_cnt); |
| 5756 | break; |
| 5757 | |
| 5758 | case SQLCOM_BEGIN: |
| 5759 | DBUG_PRINT("info" , ("Executing SQLCOM_BEGIN thd: %p" , thd)); |
| 5760 | if (trans_begin(thd, lex->start_transaction_opt)) |
| 5761 | { |
| 5762 | thd->mdl_context.release_transactional_locks(); |
| 5763 | WSREP_DEBUG("BEGIN failed, MDL released: %lld" , |
| 5764 | (longlong) thd->thread_id); |
| 5765 | goto error; |
| 5766 | } |
| 5767 | my_ok(thd); |
| 5768 | break; |
| 5769 | case SQLCOM_COMMIT: |
| 5770 | { |
| 5771 | DBUG_ASSERT(thd->lock == NULL || |
| 5772 | thd->locked_tables_mode == LTM_LOCK_TABLES); |
| 5773 | bool tx_chain= (lex->tx_chain == TVL_YES || |
| 5774 | (thd->variables.completion_type == 1 && |
| 5775 | lex->tx_chain != TVL_NO)); |
| 5776 | bool tx_release= (lex->tx_release == TVL_YES || |
| 5777 | (thd->variables.completion_type == 2 && |
| 5778 | lex->tx_release != TVL_NO)); |
| 5779 | bool commit_failed= trans_commit(thd); |
| 5780 | thd->mdl_context.release_transactional_locks(); |
| 5781 | if (commit_failed) |
| 5782 | { |
| 5783 | WSREP_DEBUG("COMMIT failed, MDL released: %lld" , |
| 5784 | (longlong) thd->thread_id); |
| 5785 | goto error; |
| 5786 | } |
| 5787 | /* Begin transaction with the same isolation level. */ |
| 5788 | if (tx_chain) |
| 5789 | { |
| 5790 | if (trans_begin(thd)) |
| 5791 | goto error; |
| 5792 | } |
| 5793 | else |
| 5794 | { |
| 5795 | /* Reset the isolation level and access mode if no chaining transaction.*/ |
| 5796 | trans_reset_one_shot_chistics(thd); |
| 5797 | } |
| 5798 | /* Disconnect the current client connection. */ |
| 5799 | if (tx_release) |
| 5800 | { |
| 5801 | thd->set_killed(KILL_CONNECTION); |
| 5802 | thd->print_aborted_warning(3, "RELEASE" ); |
| 5803 | } |
| 5804 | #ifdef WITH_WSREP |
| 5805 | if (WSREP(thd)) { |
| 5806 | |
| 5807 | if (thd->wsrep_conflict_state == NO_CONFLICT || |
| 5808 | thd->wsrep_conflict_state == REPLAYING) |
| 5809 | { |
| 5810 | my_ok(thd); |
| 5811 | } |
| 5812 | } else { |
| 5813 | #endif /* WITH_WSREP */ |
| 5814 | my_ok(thd); |
| 5815 | #ifdef WITH_WSREP |
| 5816 | } |
| 5817 | #endif /* WITH_WSREP */ |
| 5818 | break; |
| 5819 | } |
| 5820 | case SQLCOM_ROLLBACK: |
| 5821 | { |
| 5822 | DBUG_ASSERT(thd->lock == NULL || |
| 5823 | thd->locked_tables_mode == LTM_LOCK_TABLES); |
| 5824 | bool tx_chain= (lex->tx_chain == TVL_YES || |
| 5825 | (thd->variables.completion_type == 1 && |
| 5826 | lex->tx_chain != TVL_NO)); |
| 5827 | bool tx_release= (lex->tx_release == TVL_YES || |
| 5828 | (thd->variables.completion_type == 2 && |
| 5829 | lex->tx_release != TVL_NO)); |
| 5830 | bool rollback_failed= trans_rollback(thd); |
| 5831 | thd->mdl_context.release_transactional_locks(); |
| 5832 | |
| 5833 | if (rollback_failed) |
| 5834 | { |
| 5835 | WSREP_DEBUG("rollback failed, MDL released: %lld" , |
| 5836 | (longlong) thd->thread_id); |
| 5837 | goto error; |
| 5838 | } |
| 5839 | /* Begin transaction with the same isolation level. */ |
| 5840 | if (tx_chain) |
| 5841 | { |
| 5842 | if (trans_begin(thd)) |
| 5843 | goto error; |
| 5844 | } |
| 5845 | else |
| 5846 | { |
| 5847 | /* Reset the isolation level and access mode if no chaining transaction.*/ |
| 5848 | trans_reset_one_shot_chistics(thd); |
| 5849 | } |
| 5850 | /* Disconnect the current client connection. */ |
| 5851 | if (tx_release) |
| 5852 | thd->set_killed(KILL_CONNECTION); |
| 5853 | #ifdef WITH_WSREP |
| 5854 | if (WSREP(thd)) { |
| 5855 | if (thd->wsrep_conflict_state == NO_CONFLICT) { |
| 5856 | my_ok(thd); |
| 5857 | } |
| 5858 | } else { |
| 5859 | #endif /* WITH_WSREP */ |
| 5860 | my_ok(thd); |
| 5861 | #ifdef WITH_WSREP |
| 5862 | } |
| 5863 | #endif /* WITH_WSREP */ |
| 5864 | break; |
| 5865 | } |
| 5866 | case SQLCOM_RELEASE_SAVEPOINT: |
| 5867 | if (trans_release_savepoint(thd, lex->ident)) |
| 5868 | goto error; |
| 5869 | my_ok(thd); |
| 5870 | break; |
| 5871 | case SQLCOM_ROLLBACK_TO_SAVEPOINT: |
| 5872 | if (trans_rollback_to_savepoint(thd, lex->ident)) |
| 5873 | goto error; |
| 5874 | my_ok(thd); |
| 5875 | break; |
| 5876 | case SQLCOM_SAVEPOINT: |
| 5877 | if (trans_savepoint(thd, lex->ident)) |
| 5878 | goto error; |
| 5879 | my_ok(thd); |
| 5880 | break; |
| 5881 | case SQLCOM_CREATE_PROCEDURE: |
| 5882 | case SQLCOM_CREATE_SPFUNCTION: |
| 5883 | case SQLCOM_CREATE_PACKAGE: |
| 5884 | case SQLCOM_CREATE_PACKAGE_BODY: |
| 5885 | { |
| 5886 | if (mysql_create_routine(thd, lex)) |
| 5887 | goto error; |
| 5888 | my_ok(thd); |
| 5889 | break; /* break super switch */ |
| 5890 | } /* end case group bracket */ |
| 5891 | case SQLCOM_COMPOUND: |
| 5892 | DBUG_ASSERT(all_tables == 0); |
| 5893 | DBUG_ASSERT(thd->in_sub_stmt == 0); |
| 5894 | lex->sphead->m_sql_mode= thd->variables.sql_mode; |
| 5895 | if (do_execute_sp(thd, lex->sphead)) |
| 5896 | goto error; |
| 5897 | break; |
| 5898 | |
| 5899 | case SQLCOM_ALTER_PROCEDURE: |
| 5900 | case SQLCOM_ALTER_FUNCTION: |
| 5901 | { |
| 5902 | int sp_result; |
| 5903 | const Sp_handler *sph= Sp_handler::handler(lex->sql_command); |
| 5904 | if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db, |
| 5905 | &lex->spname->m_name, sph, 0)) |
| 5906 | goto error; |
| 5907 | |
| 5908 | /* |
| 5909 | Note that if you implement the capability of ALTER FUNCTION to |
| 5910 | alter the body of the function, this command should be made to |
| 5911 | follow the restrictions that log-bin-trust-function-creators=0 |
| 5912 | already puts on CREATE FUNCTION. |
| 5913 | */ |
| 5914 | /* Conditionally writes to binlog */ |
| 5915 | sp_result= sph->sp_update_routine(thd, lex->spname, &lex->sp_chistics); |
| 5916 | switch (sp_result) |
| 5917 | { |
| 5918 | case SP_OK: |
| 5919 | my_ok(thd); |
| 5920 | break; |
| 5921 | case SP_KEY_NOT_FOUND: |
| 5922 | my_error(ER_SP_DOES_NOT_EXIST, MYF(0), |
| 5923 | sph->type_str(), ErrConvDQName(lex->spname).ptr()); |
| 5924 | goto error; |
| 5925 | default: |
| 5926 | my_error(ER_SP_CANT_ALTER, MYF(0), |
| 5927 | sph->type_str(), ErrConvDQName(lex->spname).ptr()); |
| 5928 | goto error; |
| 5929 | } |
| 5930 | break; |
| 5931 | } |
| 5932 | case SQLCOM_DROP_PROCEDURE: |
| 5933 | case SQLCOM_DROP_FUNCTION: |
| 5934 | case SQLCOM_DROP_PACKAGE: |
| 5935 | case SQLCOM_DROP_PACKAGE_BODY: |
| 5936 | { |
| 5937 | #ifdef HAVE_DLOPEN |
| 5938 | if (lex->sql_command == SQLCOM_DROP_FUNCTION && |
| 5939 | ! lex->spname->m_explicit_name) |
| 5940 | { |
| 5941 | /* DROP FUNCTION <non qualified name> */ |
| 5942 | udf_func *udf = find_udf(lex->spname->m_name.str, |
| 5943 | lex->spname->m_name.length); |
| 5944 | if (udf) |
| 5945 | { |
| 5946 | if (check_access(thd, DELETE_ACL, "mysql" , NULL, NULL, 1, 0)) |
| 5947 | goto error; |
| 5948 | |
| 5949 | if (!(res = mysql_drop_function(thd, &lex->spname->m_name))) |
| 5950 | { |
| 5951 | my_ok(thd); |
| 5952 | break; |
| 5953 | } |
| 5954 | my_error(ER_SP_DROP_FAILED, MYF(0), |
| 5955 | "FUNCTION (UDF)" , lex->spname->m_name.str); |
| 5956 | goto error; |
| 5957 | } |
| 5958 | |
| 5959 | if (lex->spname->m_db.str == NULL) |
| 5960 | { |
| 5961 | if (lex->if_exists()) |
| 5962 | { |
| 5963 | push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, |
| 5964 | ER_SP_DOES_NOT_EXIST, ER_THD(thd, ER_SP_DOES_NOT_EXIST), |
| 5965 | "FUNCTION (UDF)" , lex->spname->m_name.str); |
| 5966 | res= FALSE; |
| 5967 | my_ok(thd); |
| 5968 | break; |
| 5969 | } |
| 5970 | my_error(ER_SP_DOES_NOT_EXIST, MYF(0), |
| 5971 | "FUNCTION (UDF)" , lex->spname->m_name.str); |
| 5972 | goto error; |
| 5973 | } |
| 5974 | /* Fall thought to test for a stored function */ |
| 5975 | } |
| 5976 | #endif |
| 5977 | |
| 5978 | int sp_result; |
| 5979 | const Sp_handler *sph= Sp_handler::handler(lex->sql_command); |
| 5980 | |
| 5981 | if (check_routine_access(thd, ALTER_PROC_ACL, &lex->spname->m_db, &lex->spname->m_name, |
| 5982 | Sp_handler::handler(lex->sql_command), 0)) |
| 5983 | goto error; |
| 5984 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 5985 | |
| 5986 | /* Conditionally writes to binlog */ |
| 5987 | sp_result= sph->sp_drop_routine(thd, lex->spname); |
| 5988 | |
| 5989 | #ifndef NO_EMBEDDED_ACCESS_CHECKS |
| 5990 | /* |
| 5991 | We're going to issue an implicit REVOKE statement so we close all |
| 5992 | open tables. We have to keep metadata locks as this ensures that |
| 5993 | this statement is atomic against concurent FLUSH TABLES WITH READ |
| 5994 | LOCK. Deadlocks which can arise due to fact that this implicit |
| 5995 | statement takes metadata locks should be detected by a deadlock |
| 5996 | detector in MDL subsystem and reported as errors. |
| 5997 | |
| 5998 | No need to commit/rollback statement transaction, it's not started. |
| 5999 | |
| 6000 | TODO: Long-term we should either ensure that implicit REVOKE statement |
| 6001 | is written into binary log as a separate statement or make both |
| 6002 | dropping of routine and implicit REVOKE parts of one fully atomic |
| 6003 | statement. |
| 6004 | */ |
| 6005 | DBUG_ASSERT(thd->transaction.stmt.is_empty()); |
| 6006 | close_thread_tables(thd); |
| 6007 | |
| 6008 | if (sp_result != SP_KEY_NOT_FOUND && |
| 6009 | sp_automatic_privileges && !opt_noacl && |
| 6010 | sp_revoke_privileges(thd, lex->spname->m_db.str, lex->spname->m_name.str, |
| 6011 | Sp_handler::handler(lex->sql_command))) |
| 6012 | { |
| 6013 | push_warning(thd, Sql_condition::WARN_LEVEL_WARN, |
| 6014 | ER_PROC_AUTO_REVOKE_FAIL, |
| 6015 | ER_THD(thd, ER_PROC_AUTO_REVOKE_FAIL)); |
| 6016 | /* If this happens, an error should have been reported. */ |
| 6017 | goto error; |
| 6018 | } |
| 6019 | #endif |
| 6020 | |
| 6021 | res= sp_result; |
| 6022 | switch (sp_result) { |
| 6023 | case SP_OK: |
| 6024 | my_ok(thd); |
| 6025 | break; |
| 6026 | case SP_KEY_NOT_FOUND: |
| 6027 | if (lex->if_exists()) |
| 6028 | { |
| 6029 | res= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); |
| 6030 | push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, |
| 6031 | ER_SP_DOES_NOT_EXIST, ER_THD(thd, ER_SP_DOES_NOT_EXIST), |
| 6032 | sph->type_str(), |
| 6033 | ErrConvDQName(lex->spname).ptr()); |
| 6034 | if (!res) |
| 6035 | my_ok(thd); |
| 6036 | break; |
| 6037 | } |
| 6038 | my_error(ER_SP_DOES_NOT_EXIST, MYF(0), |
| 6039 | sph->type_str(), ErrConvDQName(lex->spname).ptr()); |
| 6040 | goto error; |
| 6041 | default: |
| 6042 | my_error(ER_SP_DROP_FAILED, MYF(0), |
| 6043 | sph->type_str(), ErrConvDQName(lex->spname).ptr()); |
| 6044 | goto error; |
| 6045 | } |
| 6046 | break; |
| 6047 | } |
| 6048 | case SQLCOM_SHOW_CREATE_PROC: |
| 6049 | case SQLCOM_SHOW_CREATE_FUNC: |
| 6050 | case SQLCOM_SHOW_CREATE_PACKAGE: |
| 6051 | case SQLCOM_SHOW_CREATE_PACKAGE_BODY: |
| 6052 | { |
| 6053 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); |
| 6054 | const Sp_handler *sph= Sp_handler::handler(lex->sql_command); |
| 6055 | if (sph->sp_show_create_routine(thd, lex->spname)) |
| 6056 | goto error; |
| 6057 | break; |
| 6058 | } |
| 6059 | case SQLCOM_SHOW_PROC_CODE: |
| 6060 | case SQLCOM_SHOW_FUNC_CODE: |
| 6061 | case SQLCOM_SHOW_PACKAGE_BODY_CODE: |
| 6062 | { |
| 6063 | #ifndef DBUG_OFF |
| 6064 | Database_qualified_name pkgname(&null_clex_str, &null_clex_str); |
| 6065 | sp_head *sp; |
| 6066 | const Sp_handler *sph= Sp_handler::handler(lex->sql_command); |
| 6067 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); |
| 6068 | if (sph->sp_resolve_package_routine(thd, thd->lex->sphead, |
| 6069 | lex->spname, &sph, &pkgname)) |
| 6070 | return true; |
| 6071 | if (sph->sp_cache_routine(thd, lex->spname, false, &sp)) |
| 6072 | goto error; |
| 6073 | if (!sp || sp->show_routine_code(thd)) |
| 6074 | { |
| 6075 | /* We don't distinguish between errors for now */ |
| 6076 | my_error(ER_SP_DOES_NOT_EXIST, MYF(0), |
| 6077 | sph->type_str(), lex->spname->m_name.str); |
| 6078 | goto error; |
| 6079 | } |
| 6080 | break; |
| 6081 | #else |
| 6082 | my_error(ER_FEATURE_DISABLED, MYF(0), |
| 6083 | "SHOW PROCEDURE|FUNCTION CODE" , "--with-debug" ); |
| 6084 | goto error; |
| 6085 | #endif // ifndef DBUG_OFF |
| 6086 | } |
| 6087 | case SQLCOM_SHOW_CREATE_TRIGGER: |
| 6088 | { |
| 6089 | if (check_ident_length(&lex->spname->m_name)) |
| 6090 | goto error; |
| 6091 | |
| 6092 | WSREP_SYNC_WAIT(thd, WSREP_SYNC_WAIT_BEFORE_SHOW); |
| 6093 | if (show_create_trigger(thd, lex->spname)) |
| 6094 | goto error; /* Error has been already logged. */ |
| 6095 | |
| 6096 | break; |
| 6097 | } |
| 6098 | case SQLCOM_CREATE_VIEW: |
| 6099 | { |
| 6100 | /* |
| 6101 | Note: SQLCOM_CREATE_VIEW also handles 'ALTER VIEW' commands |
| 6102 | as specified through the thd->lex->create_view->mode flag. |
| 6103 | */ |
| 6104 | res= mysql_create_view(thd, first_table, thd->lex->create_view->mode); |
| 6105 | break; |
| 6106 | } |
| 6107 | case SQLCOM_DROP_VIEW: |
| 6108 | { |
| 6109 | if (check_table_access(thd, DROP_ACL, all_tables, FALSE, UINT_MAX, FALSE)) |
| 6110 | goto error; |
| 6111 | /* Conditionally writes to binlog. */ |
| 6112 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 6113 | res= mysql_drop_view(thd, first_table, thd->lex->drop_mode); |
| 6114 | break; |
| 6115 | } |
| 6116 | case SQLCOM_CREATE_TRIGGER: |
| 6117 | { |
| 6118 | /* Conditionally writes to binlog. */ |
| 6119 | res= mysql_create_or_drop_trigger(thd, all_tables, 1); |
| 6120 | |
| 6121 | break; |
| 6122 | } |
| 6123 | case SQLCOM_DROP_TRIGGER: |
| 6124 | { |
| 6125 | /* Conditionally writes to binlog. */ |
| 6126 | res= mysql_create_or_drop_trigger(thd, all_tables, 0); |
| 6127 | break; |
| 6128 | } |
| 6129 | case SQLCOM_XA_START: |
| 6130 | if (trans_xa_start(thd)) |
| 6131 | goto error; |
| 6132 | my_ok(thd); |
| 6133 | break; |
| 6134 | case SQLCOM_XA_END: |
| 6135 | if (trans_xa_end(thd)) |
| 6136 | goto error; |
| 6137 | my_ok(thd); |
| 6138 | break; |
| 6139 | case SQLCOM_XA_PREPARE: |
| 6140 | if (trans_xa_prepare(thd)) |
| 6141 | goto error; |
| 6142 | my_ok(thd); |
| 6143 | break; |
| 6144 | case SQLCOM_XA_COMMIT: |
| 6145 | { |
| 6146 | bool commit_failed= trans_xa_commit(thd); |
| 6147 | thd->mdl_context.release_transactional_locks(); |
| 6148 | if (commit_failed) |
| 6149 | { |
| 6150 | WSREP_DEBUG("XA commit failed, MDL released: %lld" , |
| 6151 | (longlong) thd->thread_id); |
| 6152 | goto error; |
| 6153 | } |
| 6154 | /* |
| 6155 | We've just done a commit, reset transaction |
| 6156 | isolation level and access mode to the session default. |
| 6157 | */ |
| 6158 | trans_reset_one_shot_chistics(thd); |
| 6159 | my_ok(thd); |
| 6160 | break; |
| 6161 | } |
| 6162 | case SQLCOM_XA_ROLLBACK: |
| 6163 | { |
| 6164 | bool rollback_failed= trans_xa_rollback(thd); |
| 6165 | thd->mdl_context.release_transactional_locks(); |
| 6166 | if (rollback_failed) |
| 6167 | { |
| 6168 | WSREP_DEBUG("XA rollback failed, MDL released: %lld" , |
| 6169 | (longlong) thd->thread_id); |
| 6170 | goto error; |
| 6171 | } |
| 6172 | /* |
| 6173 | We've just done a rollback, reset transaction |
| 6174 | isolation level and access mode to the session default. |
| 6175 | */ |
| 6176 | trans_reset_one_shot_chistics(thd); |
| 6177 | my_ok(thd); |
| 6178 | break; |
| 6179 | } |
| 6180 | case SQLCOM_XA_RECOVER: |
| 6181 | res= mysql_xa_recover(thd); |
| 6182 | break; |
| 6183 | case SQLCOM_ALTER_TABLESPACE: |
| 6184 | if (check_global_access(thd, CREATE_TABLESPACE_ACL)) |
| 6185 | break; |
| 6186 | if (!(res= mysql_alter_tablespace(thd, lex->alter_tablespace_info))) |
| 6187 | my_ok(thd); |
| 6188 | break; |
| 6189 | case SQLCOM_INSTALL_PLUGIN: |
| 6190 | if (! (res= mysql_install_plugin(thd, &thd->lex->comment, |
| 6191 | &thd->lex->ident))) |
| 6192 | my_ok(thd); |
| 6193 | break; |
| 6194 | case SQLCOM_UNINSTALL_PLUGIN: |
| 6195 | if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment, |
| 6196 | &thd->lex->ident))) |
| 6197 | my_ok(thd); |
| 6198 | break; |
| 6199 | case SQLCOM_BINLOG_BASE64_EVENT: |
| 6200 | { |
| 6201 | #ifndef EMBEDDED_LIBRARY |
| 6202 | mysql_client_binlog_statement(thd); |
| 6203 | #else /* EMBEDDED_LIBRARY */ |
| 6204 | my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "embedded" ); |
| 6205 | #endif /* EMBEDDED_LIBRARY */ |
| 6206 | break; |
| 6207 | } |
| 6208 | case SQLCOM_CREATE_SERVER: |
| 6209 | { |
| 6210 | DBUG_PRINT("info" , ("case SQLCOM_CREATE_SERVER" )); |
| 6211 | |
| 6212 | if (check_global_access(thd, SUPER_ACL)) |
| 6213 | break; |
| 6214 | |
| 6215 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 6216 | |
| 6217 | res= create_server(thd, &lex->server_options); |
| 6218 | break; |
| 6219 | } |
| 6220 | case SQLCOM_ALTER_SERVER: |
| 6221 | { |
| 6222 | int error; |
| 6223 | DBUG_PRINT("info" , ("case SQLCOM_ALTER_SERVER" )); |
| 6224 | |
| 6225 | if (check_global_access(thd, SUPER_ACL)) |
| 6226 | break; |
| 6227 | |
| 6228 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 6229 | |
| 6230 | if (unlikely((error= alter_server(thd, &lex->server_options)))) |
| 6231 | { |
| 6232 | DBUG_PRINT("info" , ("problem altering server <%s>" , |
| 6233 | lex->server_options.server_name.str)); |
| 6234 | my_error(error, MYF(0), lex->server_options.server_name.str); |
| 6235 | break; |
| 6236 | } |
| 6237 | my_ok(thd, 1); |
| 6238 | break; |
| 6239 | } |
| 6240 | case SQLCOM_DROP_SERVER: |
| 6241 | { |
| 6242 | int err_code; |
| 6243 | DBUG_PRINT("info" , ("case SQLCOM_DROP_SERVER" )); |
| 6244 | |
| 6245 | if (check_global_access(thd, SUPER_ACL)) |
| 6246 | break; |
| 6247 | |
| 6248 | WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); |
| 6249 | |
| 6250 | if ((err_code= drop_server(thd, &lex->server_options))) |
| 6251 | { |
| 6252 | if (! lex->if_exists() && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST) |
| 6253 | { |
| 6254 | DBUG_PRINT("info" , ("problem dropping server %s" , |
| 6255 | lex->server_options.server_name.str)); |
| 6256 | my_error(err_code, MYF(0), lex->server_options.server_name.str); |
| 6257 | } |
| 6258 | else |
| 6259 | { |
| 6260 | my_ok(thd, 0); |
| 6261 | } |
| 6262 | break; |
| 6263 | } |
| 6264 | my_ok(thd, 1); |
| 6265 | break; |
| 6266 | } |
| 6267 | case SQLCOM_ANALYZE: |
| 6268 | case SQLCOM_CHECK: |
| 6269 | case SQLCOM_OPTIMIZE: |
| 6270 | case SQLCOM_REPAIR: |
| 6271 | case SQLCOM_TRUNCATE: |
| 6272 | case SQLCOM_ALTER_TABLE: |
| 6273 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 6274 | /* fall through */ |
| 6275 | case SQLCOM_ALTER_SEQUENCE: |
| 6276 | thd->query_plan_flags|= QPLAN_ADMIN; |
| 6277 | /* fall through */ |
| 6278 | case SQLCOM_SIGNAL: |
| 6279 | case SQLCOM_RESIGNAL: |
| 6280 | case SQLCOM_GET_DIAGNOSTICS: |
| 6281 | case SQLCOM_CALL: |
| 6282 | DBUG_ASSERT(lex->m_sql_cmd != NULL); |
| 6283 | res= lex->m_sql_cmd->execute(thd); |
| 6284 | break; |
| 6285 | default: |
| 6286 | |
| 6287 | #ifndef EMBEDDED_LIBRARY |
| 6288 | DBUG_ASSERT(0); /* Impossible */ |
| 6289 | #endif |
| 6290 | my_ok(thd); |
| 6291 | break; |
| 6292 | } |
| 6293 | THD_STAGE_INFO(thd, stage_query_end); |
| 6294 | thd->update_stats(); |
| 6295 | |
| 6296 | goto finish; |
| 6297 | |
| 6298 | error: |
| 6299 | res= TRUE; |
| 6300 | |
| 6301 | finish: |
| 6302 | |
| 6303 | thd->reset_query_timer(); |
| 6304 | DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() || |
| 6305 | thd->in_multi_stmt_transaction_mode()); |
| 6306 | |
| 6307 | |
| 6308 | lex->unit.cleanup(); |
| 6309 | |
| 6310 | /* close/reopen tables that were marked to need reopen under LOCK TABLES */ |
| 6311 | if (! thd->lex->requires_prelocking()) |
| 6312 | thd->locked_tables_list.reopen_tables(thd, true); |
| 6313 | |
| 6314 | if (! thd->in_sub_stmt) |
| 6315 | { |
| 6316 | if (thd->killed != NOT_KILLED) |
| 6317 | { |
| 6318 | /* report error issued during command execution */ |
| 6319 | if (thd->killed_errno()) |
| 6320 | { |
| 6321 | /* If we already sent 'ok', we can ignore any kill query statements */ |
| 6322 | if (! thd->get_stmt_da()->is_set()) |
| 6323 | thd->send_kill_message(); |
| 6324 | } |
| 6325 | thd->reset_kill_query(); |
| 6326 | } |
| 6327 | if (unlikely(thd->is_error()) || |
| 6328 | (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR)) |
| 6329 | { |
| 6330 | THD_STAGE_INFO(thd, stage_rollback); |
| 6331 | trans_rollback_stmt(thd); |
| 6332 | } |
| 6333 | #ifdef WITH_WSREP |
| 6334 | if (thd->spcont && |
| 6335 | (thd->wsrep_conflict_state == MUST_ABORT || |
| 6336 | thd->wsrep_conflict_state == ABORTED || |
| 6337 | thd->wsrep_conflict_state == CERT_FAILURE)) |
| 6338 | { |
| 6339 | /* |
| 6340 | The error was cleared, but THD was aborted by wsrep and |
| 6341 | wsrep_conflict_state is still set accordingly. This |
| 6342 | situation is expected if we are running a stored procedure |
| 6343 | that declares a handler that catches ER_LOCK_DEADLOCK error. |
| 6344 | In which case the error may have been cleared in method |
| 6345 | sp_rcontext::handle_sql_condition(). |
| 6346 | */ |
| 6347 | trans_rollback_stmt(thd); |
| 6348 | thd->wsrep_conflict_state= NO_CONFLICT; |
| 6349 | thd->killed= NOT_KILLED; |
| 6350 | } |
| 6351 | #endif /* WITH_WSREP */ |
| 6352 | else |
| 6353 | { |
| 6354 | /* If commit fails, we should be able to reset the OK status. */ |
| 6355 | THD_STAGE_INFO(thd, stage_commit); |
| 6356 | thd->get_stmt_da()->set_overwrite_status(true); |
| 6357 | trans_commit_stmt(thd); |
| 6358 | thd->get_stmt_da()->set_overwrite_status(false); |
| 6359 | } |
| 6360 | #ifdef WITH_ARIA_STORAGE_ENGINE |
| 6361 | ha_maria::implicit_commit(thd, FALSE); |
| 6362 | #endif |
| 6363 | } |
| 6364 | |
| 6365 | /* Free tables. Set stage 'closing tables' */ |
| 6366 | close_thread_tables(thd); |
| 6367 | #ifdef WITH_WSREP |
| 6368 | thd->wsrep_consistency_check= NO_CONSISTENCY_CHECK; |
| 6369 | #endif /* WITH_WSREP */ |
| 6370 | |
| 6371 | |
| 6372 | #ifndef DBUG_OFF |
| 6373 | if (lex->sql_command != SQLCOM_SET_OPTION && ! thd->in_sub_stmt) |
| 6374 | DEBUG_SYNC(thd, "execute_command_after_close_tables" ); |
| 6375 | #endif |
| 6376 | if (!(sql_command_flags[lex->sql_command] & |
| 6377 | (CF_CAN_GENERATE_ROW_EVENTS | CF_FORCE_ORIGINAL_BINLOG_FORMAT | |
| 6378 | CF_STATUS_COMMAND))) |
| 6379 | thd->set_binlog_format(orig_binlog_format, |
| 6380 | orig_current_stmt_binlog_format); |
| 6381 | |
| 6382 | if (! thd->in_sub_stmt && thd->transaction_rollback_request) |
| 6383 | { |
| 6384 | /* |
| 6385 | We are not in sub-statement and transaction rollback was requested by |
| 6386 | one of storage engines (e.g. due to deadlock). Rollback transaction in |
| 6387 | all storage engines including binary log. |
| 6388 | */ |
| 6389 | THD_STAGE_INFO(thd, stage_rollback_implicit); |
| 6390 | trans_rollback_implicit(thd); |
| 6391 | thd->mdl_context.release_transactional_locks(); |
| 6392 | } |
| 6393 | else if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END)) |
| 6394 | { |
| 6395 | /* No transaction control allowed in sub-statements. */ |
| 6396 | DBUG_ASSERT(! thd->in_sub_stmt); |
| 6397 | if (!(thd->variables.option_bits & OPTION_GTID_BEGIN)) |
| 6398 | { |
| 6399 | THD_STAGE_INFO(thd, stage_commit_implicit); |
| 6400 | /* If commit fails, we should be able to reset the OK status. */ |
| 6401 | thd->get_stmt_da()->set_overwrite_status(true); |
| 6402 | /* Commit the normal transaction if one is active. */ |
| 6403 | trans_commit_implicit(thd); |
| 6404 | thd->get_stmt_da()->set_overwrite_status(false); |
| 6405 | thd->mdl_context.release_transactional_locks(); |
| 6406 | } |
| 6407 | } |
| 6408 | else if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) |
| 6409 | { |
| 6410 | /* |
| 6411 | - If inside a multi-statement transaction, |
| 6412 | defer the release of metadata locks until the current |
| 6413 | transaction is either committed or rolled back. This prevents |
| 6414 | other statements from modifying the table for the entire |
| 6415 | duration of this transaction. This provides commit ordering |
| 6416 | and guarantees serializability across multiple transactions. |
| 6417 | - If in autocommit mode, or outside a transactional context, |
| 6418 | automatically release metadata locks of the current statement. |
| 6419 | */ |
| 6420 | thd->mdl_context.release_transactional_locks(); |
| 6421 | } |
| 6422 | else if (! thd->in_sub_stmt) |
| 6423 | { |
| 6424 | thd->mdl_context.release_statement_locks(); |
| 6425 | } |
| 6426 | |
| 6427 | THD_STAGE_INFO(thd, stage_starting_cleanup); |
| 6428 | |
| 6429 | TRANSACT_TRACKER(add_trx_state_from_thd(thd)); |
| 6430 | |
| 6431 | WSREP_TO_ISOLATION_END; |
| 6432 | |
| 6433 | #ifdef WITH_WSREP |
| 6434 | /* |
| 6435 | Force release of transactional locks if not in active MST and wsrep is on. |
| 6436 | */ |
| 6437 | if (WSREP(thd) && |
| 6438 | ! thd->in_sub_stmt && |
| 6439 | ! thd->in_active_multi_stmt_transaction() && |
| 6440 | thd->mdl_context.has_transactional_locks()) |
| 6441 | { |
| 6442 | WSREP_DEBUG("Forcing release of transactional locks for thd: %lld" , |
| 6443 | (longlong) thd->thread_id); |
| 6444 | thd->mdl_context.release_transactional_locks(); |
| 6445 | } |
| 6446 | #endif /* WITH_WSREP */ |
| 6447 | |
| 6448 | DBUG_RETURN(res || thd->is_error()); |
| 6449 | } |
| 6450 | |
| 6451 | |
| 6452 | static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables) |
| 6453 | { |
| 6454 | LEX *lex= thd->lex; |
| 6455 | select_result *result=lex->result; |
| 6456 | bool res; |
| 6457 | /* assign global limit variable if limit is not given */ |
| 6458 | { |
| 6459 | SELECT_LEX *param= lex->unit.global_parameters(); |
| 6460 | if (!param->explicit_limit) |
| 6461 | param->select_limit= |
| 6462 | new (thd->mem_root) Item_int(thd, |
| 6463 | (ulonglong) thd->variables.select_limit); |
| 6464 | } |
| 6465 | |
| 6466 | if (!(res= open_and_lock_tables(thd, all_tables, TRUE, 0))) |
| 6467 | { |
| 6468 | if (lex->describe) |
| 6469 | { |
| 6470 | /* |
| 6471 | We always use select_send for EXPLAIN, even if it's an EXPLAIN |
| 6472 | for SELECT ... INTO OUTFILE: a user application should be able |
| 6473 | to prepend EXPLAIN to any query and receive output for it, |
| 6474 | even if the query itself redirects the output. |
| 6475 | */ |
| 6476 | if (unlikely(!(result= new (thd->mem_root) select_send(thd)))) |
| 6477 | return 1; /* purecov: inspected */ |
| 6478 | thd->send_explain_fields(result, lex->describe, lex->analyze_stmt); |
| 6479 | |
| 6480 | /* |
| 6481 | This will call optimize() for all parts of query. The query plan is |
| 6482 | printed out below. |
| 6483 | */ |
| 6484 | res= mysql_explain_union(thd, &lex->unit, result); |
| 6485 | |
| 6486 | /* Print EXPLAIN only if we don't have an error */ |
| 6487 | if (likely(!res)) |
| 6488 | { |
| 6489 | /* |
| 6490 | Do like the original select_describe did: remove OFFSET from the |
| 6491 | top-level LIMIT |
| 6492 | */ |
| 6493 | result->reset_offset_limit(); |
| 6494 | if (lex->explain_json) |
| 6495 | { |
| 6496 | lex->explain->print_explain_json(result, lex->analyze_stmt); |
| 6497 | } |
| 6498 | else |
| 6499 | { |
| 6500 | lex->explain->print_explain(result, thd->lex->describe, |
| 6501 | thd->lex->analyze_stmt); |
| 6502 | if (lex->describe & DESCRIBE_EXTENDED) |
| 6503 | { |
| 6504 | char buff[1024]; |
| 6505 | String str(buff,(uint32) sizeof(buff), system_charset_info); |
| 6506 | str.length(0); |
| 6507 | /* |
| 6508 | The warnings system requires input in utf8, @see |
| 6509 | mysqld_show_warnings(). |
| 6510 | */ |
| 6511 | lex->unit.print(&str, QT_EXPLAIN_EXTENDED); |
| 6512 | push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, |
| 6513 | ER_YES, str.c_ptr_safe()); |
| 6514 | } |
| 6515 | } |
| 6516 | } |
| 6517 | |
| 6518 | if (res) |
| 6519 | result->abort_result_set(); |
| 6520 | else |
| 6521 | result->send_eof(); |
| 6522 | delete result; |
| 6523 | } |
| 6524 | else |
| 6525 | { |
| 6526 | Protocol *save_protocol= NULL; |
| 6527 | if (lex->analyze_stmt) |
| 6528 | { |
| 6529 | if (result && result->is_result_interceptor()) |
| 6530 | ((select_result_interceptor*)result)->disable_my_ok_calls(); |
| 6531 | else |
| 6532 | { |
| 6533 | DBUG_ASSERT(thd->protocol); |
| 6534 | result= new (thd->mem_root) select_send_analyze(thd); |
| 6535 | save_protocol= thd->protocol; |
| 6536 | thd->protocol= new Protocol_discard(thd); |
| 6537 | } |
| 6538 | } |
| 6539 | else |
| 6540 | { |
| 6541 | if (!result && !(result= new (thd->mem_root) select_send(thd))) |
| 6542 | return 1; /* purecov: inspected */ |
| 6543 | } |
| 6544 | query_cache_store_query(thd, all_tables); |
| 6545 | res= handle_select(thd, lex, result, 0); |
| 6546 | if (result != lex->result) |
| 6547 | delete result; |
| 6548 | |
| 6549 | if (lex->analyze_stmt) |
| 6550 | { |
| 6551 | if (save_protocol) |
| 6552 | { |
| 6553 | delete thd->protocol; |
| 6554 | thd->protocol= save_protocol; |
| 6555 | } |
| 6556 | if (!res) |
| 6557 | res= thd->lex->explain->send_explain(thd); |
| 6558 | } |
| 6559 | } |
| 6560 | } |
| 6561 | /* Count number of empty select queries */ |
| 6562 | if (!thd->get_sent_row_count() && !res) |
| 6563 | status_var_increment(thd->status_var.empty_queries); |
| 6564 | else |
| 6565 | status_var_add(thd->status_var.rows_sent, thd->get_sent_row_count()); |
| 6566 | |
| 6567 | return res; |
| 6568 | } |
| 6569 | |
| 6570 | |
| 6571 | static bool execute_show_status(THD *thd, TABLE_LIST *all_tables) |
| 6572 | { |
| 6573 | bool res; |
| 6574 | system_status_var old_status_var= thd->status_var; |
| 6575 | thd->initial_status_var= &old_status_var; |
| 6576 | if (!(res= check_table_access(thd, SELECT_ACL, all_tables, FALSE, |
| 6577 | UINT_MAX, FALSE))) |
| 6578 | res= execute_sqlcom_select(thd, all_tables); |
| 6579 | |
| 6580 | /* Don't log SHOW STATUS commands to slow query log */ |
| 6581 | thd->server_status&= ~(SERVER_QUERY_NO_INDEX_USED | |
| 6582 | SERVER_QUERY_NO_GOOD_INDEX_USED); |
| 6583 | /* |
| 6584 | restore status variables, as we don't want 'show status' to cause |
| 6585 | changes |
| 6586 | */ |
| 6587 | mysql_mutex_lock(&LOCK_status); |
| 6588 | add_diff_to_status(&global_status_var, &thd->status_var, |
| 6589 | &old_status_var); |
| 6590 | memcpy(&thd->status_var, &old_status_var, |
| 6591 | offsetof(STATUS_VAR, last_cleared_system_status_var)); |
| 6592 | mysql_mutex_unlock(&LOCK_status); |
| 6593 | return res; |
| 6594 | } |
| 6595 | |
| 6596 | |
| 6597 | static bool check_rename_table(THD *thd, TABLE_LIST *first_table, |
| 6598 | TABLE_LIST *all_tables) |
| 6599 | { |
| 6600 | DBUG_ASSERT(first_table == all_tables && first_table != 0); |
| 6601 | TABLE_LIST *table; |
| 6602 | for (table= first_table; table; table= table->next_local->next_local) |
| 6603 | { |
| 6604 | if (check_access(thd, ALTER_ACL | DROP_ACL, table->db.str, |
| 6605 | &table->grant.privilege, |
| 6606 | &table->grant.m_internal, |
| 6607 | 0, 0) || |
| 6608 | check_access(thd, INSERT_ACL | CREATE_ACL, table->next_local->db.str, |
| 6609 | &table->next_local->grant.privilege, |
| 6610 | &table->next_local->grant.m_internal, |
| 6611 | 0, 0)) |
| 6612 | return 1; |
| 6613 | TABLE_LIST old_list, new_list; |
| 6614 | /* |
| 6615 | we do not need initialize old_list and new_list because we will |
| 6616 | come table[0] and table->next[0] there |
| 6617 | */ |
| 6618 | old_list= table[0]; |
| 6619 | new_list= table->next_local[0]; |
| 6620 | if (check_grant(thd, ALTER_ACL | DROP_ACL, &old_list, FALSE, 1, FALSE) || |
| 6621 | (!test_all_bits(table->next_local->grant.privilege, |
| 6622 | INSERT_ACL | CREATE_ACL) && |
| 6623 | check_grant(thd, INSERT_ACL | CREATE_ACL, &new_list, FALSE, 1, |
| 6624 | FALSE))) |
| 6625 | return 1; |
| 6626 | } |
| 6627 | |
| 6628 | return 0; |
| 6629 | } |
| 6630 | |
| 6631 | |
| 6632 | /** |
| 6633 | @brief Compare requested privileges with the privileges acquired from the |
| 6634 | User- and Db-tables. |
| 6635 | @param thd Thread handler |
| 6636 | @param want_access The requested access privileges. |
| 6637 | @param db A pointer to the Db name. |
| 6638 | @param[out] save_priv A pointer to the granted privileges will be stored. |
| 6639 | @param grant_internal_info A pointer to the internal grant cache. |
| 6640 | @param dont_check_global_grants True if no global grants are checked. |
| 6641 | @param no_error True if no errors should be sent to the client. |
| 6642 | |
| 6643 | 'save_priv' is used to save the User-table (global) and Db-table grants for |
| 6644 | the supplied db name. Note that we don't store db level grants if the global |
| 6645 | grants is enough to satisfy the request AND the global grants contains a |
| 6646 | SELECT grant. |
| 6647 | |
| 6648 | For internal databases (INFORMATION_SCHEMA, PERFORMANCE_SCHEMA), |
| 6649 | additional rules apply, see ACL_internal_schema_access. |
| 6650 | |
| 6651 | @see check_grant |
| 6652 | |
| 6653 | @return Status of denial of access by exclusive ACLs. |
| 6654 | @retval FALSE Access can't exclusively be denied by Db- and User-table |
| 6655 | access unless Column- and Table-grants are checked too. |
| 6656 | @retval TRUE Access denied. |
| 6657 | */ |
| 6658 | |
| 6659 | bool |
| 6660 | check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, |
| 6661 | GRANT_INTERNAL_INFO *grant_internal_info, |
| 6662 | bool dont_check_global_grants, bool no_errors) |
| 6663 | { |
| 6664 | #ifdef NO_EMBEDDED_ACCESS_CHECKS |
| 6665 | if (save_priv) |
| 6666 | *save_priv= GLOBAL_ACLS; |
| 6667 | return false; |
| 6668 | #else |
| 6669 | Security_context *sctx= thd->security_ctx; |
| 6670 | ulong db_access; |
| 6671 | |
| 6672 | /* |
| 6673 | GRANT command: |
| 6674 | In case of database level grant the database name may be a pattern, |
| 6675 | in case of table|column level grant the database name can not be a pattern. |
| 6676 | We use 'dont_check_global_grants' as a flag to determine |
| 6677 | if it's database level grant command |
| 6678 | (see SQLCOM_GRANT case, mysql_execute_command() function) and |
| 6679 | set db_is_pattern according to 'dont_check_global_grants' value. |
| 6680 | */ |
| 6681 | bool db_is_pattern= ((want_access & GRANT_ACL) && dont_check_global_grants); |
| 6682 | ulong dummy; |
| 6683 | DBUG_ENTER("check_access" ); |
| 6684 | DBUG_PRINT("enter" ,("db: %s want_access: %lu master_access: %lu" , |
| 6685 | db ? db : "" , want_access, sctx->master_access)); |
| 6686 | |
| 6687 | if (save_priv) |
| 6688 | *save_priv=0; |
| 6689 | else |
| 6690 | { |
| 6691 | save_priv= &dummy; |
| 6692 | dummy= 0; |
| 6693 | } |
| 6694 | |
| 6695 | /* check access may be called twice in a row. Don't change to same stage */ |
| 6696 | if (thd->proc_info != stage_checking_permissions.m_name) |
| 6697 | THD_STAGE_INFO(thd, stage_checking_permissions); |
| 6698 | if (unlikely((!db || !db[0]) && !thd->db.str && !dont_check_global_grants)) |
| 6699 | { |
| 6700 | DBUG_PRINT("error" ,("No database" )); |
| 6701 | if (!no_errors) |
| 6702 | my_message(ER_NO_DB_ERROR, ER_THD(thd, ER_NO_DB_ERROR), |
| 6703 | MYF(0)); /* purecov: tested */ |
| 6704 | DBUG_RETURN(TRUE); /* purecov: tested */ |
| 6705 | } |
| 6706 | |
| 6707 | if (likely((db != NULL) && (db != any_db))) |
| 6708 | { |
| 6709 | /* |
| 6710 | Check if this is reserved database, like information schema or |
| 6711 | performance schema |
| 6712 | */ |
| 6713 | const ACL_internal_schema_access *access; |
| 6714 | access= get_cached_schema_access(grant_internal_info, db); |
| 6715 | if (access) |
| 6716 | { |
| 6717 | switch (access->check(want_access, save_priv)) |
| 6718 | { |
| 6719 | case ACL_INTERNAL_ACCESS_GRANTED: |
| 6720 | /* |
| 6721 | All the privileges requested have been granted internally. |
| 6722 | [out] *save_privileges= Internal privileges. |
| 6723 | */ |
| 6724 | DBUG_RETURN(FALSE); |
| 6725 | case ACL_INTERNAL_ACCESS_DENIED: |
| 6726 | if (! no_errors) |
| 6727 | { |
| 6728 | status_var_increment(thd->status_var.access_denied_errors); |
| 6729 | my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), |
| 6730 | sctx->priv_user, sctx->priv_host, db); |
| 6731 | } |
| 6732 | DBUG_RETURN(TRUE); |
| 6733 | case ACL_INTERNAL_ACCESS_CHECK_GRANT: |
| 6734 | /* |
| 6735 | Only some of the privilege requested have been granted internally, |
| 6736 | proceed with the remaining bits of the request (want_access). |
| 6737 | */ |
| 6738 | want_access&= ~(*save_priv); |
| 6739 | break; |
| 6740 | } |
| 6741 | } |
| 6742 | } |
| 6743 | |
| 6744 | if ((sctx->master_access & want_access) == want_access) |
| 6745 | { |
| 6746 | /* |
| 6747 | 1. If we don't have a global SELECT privilege, we have to get the |
| 6748 | database specific access rights to be able to handle queries of type |
| 6749 | UPDATE t1 SET a=1 WHERE b > 0 |
| 6750 | 2. Change db access if it isn't current db which is being addressed |
| 6751 | */ |
| 6752 | if (!(sctx->master_access & SELECT_ACL)) |
| 6753 | { |
| 6754 | if (db && (!thd->db.str || db_is_pattern || strcmp(db, thd->db.str))) |
| 6755 | { |
| 6756 | db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, |
| 6757 | db_is_pattern); |
| 6758 | if (sctx->priv_role[0]) |
| 6759 | db_access|= acl_get("" , "" , sctx->priv_role, db, db_is_pattern); |
| 6760 | } |
| 6761 | else |
| 6762 | { |
| 6763 | /* get access for current db */ |
| 6764 | db_access= sctx->db_access; |
| 6765 | } |
| 6766 | /* |
| 6767 | The effective privileges are the union of the global privileges |
| 6768 | and the intersection of db- and host-privileges, |
| 6769 | plus the internal privileges. |
| 6770 | */ |
| 6771 | *save_priv|= sctx->master_access | db_access; |
| 6772 | } |
| 6773 | else |
| 6774 | *save_priv|= sctx->master_access; |
| 6775 | DBUG_RETURN(FALSE); |
| 6776 | } |
| 6777 | if (unlikely(((want_access & ~sctx->master_access) & ~DB_ACLS) || |
| 6778 | (! db && dont_check_global_grants))) |
| 6779 | { // We can never grant this |
| 6780 | DBUG_PRINT("error" ,("No possible access" )); |
| 6781 | if (!no_errors) |
| 6782 | { |
| 6783 | status_var_increment(thd->status_var.access_denied_errors); |
| 6784 | my_error(access_denied_error_code(thd->password), MYF(0), |
| 6785 | sctx->priv_user, |
| 6786 | sctx->priv_host, |
| 6787 | (thd->password ? |
| 6788 | ER_THD(thd, ER_YES) : |
| 6789 | ER_THD(thd, ER_NO))); /* purecov: tested */ |
| 6790 | } |
| 6791 | DBUG_RETURN(TRUE); /* purecov: tested */ |
| 6792 | } |
| 6793 | |
| 6794 | if (unlikely(db == any_db)) |
| 6795 | { |
| 6796 | /* |
| 6797 | Access granted; Allow select on *any* db. |
| 6798 | [out] *save_privileges= 0 |
| 6799 | */ |
| 6800 | DBUG_RETURN(FALSE); |
| 6801 | } |
| 6802 | |
| 6803 | if (db && (!thd->db.str || db_is_pattern || strcmp(db, thd->db.str))) |
| 6804 | { |
| 6805 | db_access= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, |
| 6806 | db_is_pattern); |
| 6807 | if (sctx->priv_role[0]) |
| 6808 | { |
| 6809 | db_access|= acl_get("" , "" , sctx->priv_role, db, db_is_pattern); |
| 6810 | } |
| 6811 | } |
| 6812 | else |
| 6813 | db_access= sctx->db_access; |
| 6814 | DBUG_PRINT("info" ,("db_access: %lu want_access: %lu" , |
| 6815 | db_access, want_access)); |
| 6816 | |
| 6817 | /* |
| 6818 | Save the union of User-table and the intersection between Db-table and |
| 6819 | Host-table privileges, with the already saved internal privileges. |
| 6820 | */ |
| 6821 | db_access= (db_access | sctx->master_access); |
| 6822 | *save_priv|= db_access; |
| 6823 | |
| 6824 | /* |
| 6825 | We need to investigate column- and table access if all requested privileges |
| 6826 | belongs to the bit set of . |
| 6827 | */ |
| 6828 | bool need_table_or_column_check= |
| 6829 | (want_access & (TABLE_ACLS | PROC_ACLS | db_access)) == want_access; |
| 6830 | |
| 6831 | /* |
| 6832 | Grant access if the requested access is in the intersection of |
| 6833 | host- and db-privileges (as retrieved from the acl cache), |
| 6834 | also grant access if all the requested privileges are in the union of |
| 6835 | TABLES_ACLS and PROC_ACLS; see check_grant. |
| 6836 | */ |
| 6837 | if ( (db_access & want_access) == want_access || |
| 6838 | (!dont_check_global_grants && |
| 6839 | need_table_or_column_check)) |
| 6840 | { |
| 6841 | /* |
| 6842 | Ok; but need to check table- and column privileges. |
| 6843 | [out] *save_privileges is (User-priv | (Db-priv & Host-priv) | Internal-priv) |
| 6844 | */ |
| 6845 | DBUG_RETURN(FALSE); |
| 6846 | } |
| 6847 | |
| 6848 | /* |
| 6849 | Access is denied; |
| 6850 | [out] *save_privileges is (User-priv | (Db-priv & Host-priv) | Internal-priv) |
| 6851 | */ |
| 6852 | DBUG_PRINT("error" ,("Access denied" )); |
| 6853 | if (!no_errors) |
| 6854 | { |
| 6855 | status_var_increment(thd->status_var.access_denied_errors); |
| 6856 | my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), |
| 6857 | sctx->priv_user, sctx->priv_host, |
| 6858 | (db ? db : (thd->db.str ? |
| 6859 | thd->db.str : |
| 6860 | "unknown" ))); |
| 6861 | } |
| 6862 | DBUG_RETURN(TRUE); |
| 6863 | #endif // NO_EMBEDDED_ACCESS_CHECKS |
| 6864 | } |
| 6865 | |
| 6866 | |
| 6867 | #ifndef NO_EMBEDDED_ACCESS_CHECKS |
| 6868 | /** |
| 6869 | Check grants for commands which work only with one table. |
| 6870 | |
| 6871 | @param thd Thread handler |
| 6872 | @param privilege requested privilege |
| 6873 | @param all_tables global table list of query |
| 6874 | @param no_errors FALSE/TRUE - report/don't report error to |
| 6875 | the client (using my_error() call). |
| 6876 | |
| 6877 | @retval |
| 6878 | 0 OK |
| 6879 | @retval |
| 6880 | 1 access denied, error is sent to client |
| 6881 | */ |
| 6882 | |
| 6883 | bool check_single_table_access(THD *thd, ulong privilege, |
| 6884 | TABLE_LIST *all_tables, bool no_errors) |
| 6885 | { |
| 6886 | Security_context * backup_ctx= thd->security_ctx; |
| 6887 | |
| 6888 | /* we need to switch to the saved context (if any) */ |
| 6889 | if (all_tables->security_ctx) |
| 6890 | thd->security_ctx= all_tables->security_ctx; |
| 6891 | |
| 6892 | const char *db_name; |
| 6893 | if ((all_tables->view || all_tables->field_translation) && |
| 6894 | !all_tables->schema_table) |
| 6895 | db_name= all_tables->view_db.str; |
| 6896 | else |
| 6897 | db_name= all_tables->db.str; |
| 6898 | |
| 6899 | if (check_access(thd, privilege, db_name, |
| 6900 | &all_tables->grant.privilege, |
| 6901 | &all_tables->grant.m_internal, |
| 6902 | 0, no_errors)) |
| 6903 | goto deny; |
| 6904 | |
| 6905 | /* Show only 1 table for check_grant */ |
| 6906 | if (!(all_tables->belong_to_view && |
| 6907 | (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && |
| 6908 | check_grant(thd, privilege, all_tables, FALSE, 1, no_errors)) |
| 6909 | goto deny; |
| 6910 | |
| 6911 | thd->security_ctx= backup_ctx; |
| 6912 | return 0; |
| 6913 | |
| 6914 | deny: |
| 6915 | thd->security_ctx= backup_ctx; |
| 6916 | return 1; |
| 6917 | } |
| 6918 | |
| 6919 | /** |
| 6920 | Check grants for commands which work only with one table and all other |
| 6921 | tables belonging to subselects or implicitly opened tables. |
| 6922 | |
| 6923 | @param thd Thread handler |
| 6924 | @param privilege requested privilege |
| 6925 | @param all_tables global table list of query |
| 6926 | |
| 6927 | @retval |
| 6928 | 0 OK |
| 6929 | @retval |
| 6930 | 1 access denied, error is sent to client |
| 6931 | */ |
| 6932 | |
| 6933 | bool check_one_table_access(THD *thd, ulong privilege, TABLE_LIST *all_tables) |
| 6934 | { |
| 6935 | if (check_single_table_access (thd,privilege,all_tables, FALSE)) |
| 6936 | return 1; |
| 6937 | |
| 6938 | /* Check rights on tables of subselects and implictly opened tables */ |
| 6939 | TABLE_LIST *subselects_tables, *view= all_tables->view ? all_tables : 0; |
| 6940 | if ((subselects_tables= all_tables->next_global)) |
| 6941 | { |
| 6942 | /* |
| 6943 | Access rights asked for the first table of a view should be the same |
| 6944 | as for the view |
| 6945 | */ |
| 6946 | if (view && subselects_tables->belong_to_view == view) |
| 6947 | { |
| 6948 | if (check_single_table_access (thd, privilege, subselects_tables, FALSE)) |
| 6949 | return 1; |
| 6950 | subselects_tables= subselects_tables->next_global; |
| 6951 | } |
| 6952 | if (subselects_tables && |
| 6953 | (check_table_access(thd, SELECT_ACL, subselects_tables, FALSE, |
| 6954 | UINT_MAX, FALSE))) |
| 6955 | return 1; |
| 6956 | } |
| 6957 | return 0; |
| 6958 | } |
| 6959 | |
| 6960 | |
| 6961 | static bool check_show_access(THD *thd, TABLE_LIST *table) |
| 6962 | { |
| 6963 | /* |
| 6964 | This is a SHOW command using an INFORMATION_SCHEMA table. |
| 6965 | check_access() has not been called for 'table', |
| 6966 | and SELECT is currently always granted on the I_S, so we automatically |
| 6967 | grant SELECT on table here, to bypass a call to check_access(). |
| 6968 | Note that not calling check_access(table) is an optimization, |
| 6969 | which needs to be revisited if the INFORMATION_SCHEMA does |
| 6970 | not always automatically grant SELECT but use the grant tables. |
| 6971 | See Bug#38837 need a way to disable information_schema for security |
| 6972 | */ |
| 6973 | table->grant.privilege= SELECT_ACL; |
| 6974 | |
| 6975 | switch (get_schema_table_idx(table->schema_table)) { |
| 6976 | case SCH_SCHEMATA: |
| 6977 | return (specialflag & SPECIAL_SKIP_SHOW_DB) && |
| 6978 | check_global_access(thd, SHOW_DB_ACL); |
| 6979 | |
| 6980 | case SCH_TABLE_NAMES: |
| 6981 | case SCH_TABLES: |
| 6982 | case SCH_VIEWS: |
| 6983 | case SCH_TRIGGERS: |
| 6984 | case SCH_EVENTS: |
| 6985 | { |
| 6986 | const char *dst_db_name= table->schema_select_lex->db.str; |
| 6987 | |
| 6988 | DBUG_ASSERT(dst_db_name); |
| 6989 | |
| 6990 | if (check_access(thd, SELECT_ACL, dst_db_name, |
| 6991 | &thd->col_access, NULL, FALSE, FALSE)) |
| 6992 | return TRUE; |
| 6993 | |
| 6994 | if (!thd->col_access && check_grant_db(thd, dst_db_name)) |
| 6995 | { |
| 6996 | status_var_increment(thd->status_var.access_denied_errors); |
| 6997 | my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), |
| 6998 | thd->security_ctx->priv_user, |
| 6999 | thd->security_ctx->priv_host, |
| 7000 | dst_db_name); |
| 7001 | return TRUE; |
| 7002 | } |
| 7003 | |
| 7004 | return FALSE; |
| 7005 | } |
| 7006 | |
| 7007 | case SCH_COLUMNS: |
| 7008 | case SCH_STATISTICS: |
| 7009 | { |
| 7010 | TABLE_LIST *dst_table; |
| 7011 | dst_table= table->schema_select_lex->table_list.first; |
| 7012 | |
| 7013 | DBUG_ASSERT(dst_table); |
| 7014 | |
| 7015 | /* |
| 7016 | Open temporary tables to be able to detect them during privilege check. |
| 7017 | */ |
| 7018 | if (thd->open_temporary_tables(dst_table)) |
| 7019 | return TRUE; |
| 7020 | |
| 7021 | if (check_access(thd, SELECT_ACL, dst_table->db.str, |
| 7022 | &dst_table->grant.privilege, |
| 7023 | &dst_table->grant.m_internal, |
| 7024 | FALSE, FALSE)) |
| 7025 | return TRUE; /* Access denied */ |
| 7026 | |
| 7027 | /* |
| 7028 | Check_grant will grant access if there is any column privileges on |
| 7029 | all of the tables thanks to the fourth parameter (bool show_table). |
| 7030 | */ |
| 7031 | if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE)) |
| 7032 | return TRUE; /* Access denied */ |
| 7033 | |
| 7034 | close_thread_tables(thd); |
| 7035 | dst_table->table= NULL; |
| 7036 | |
| 7037 | /* Access granted */ |
| 7038 | return FALSE; |
| 7039 | } |
| 7040 | default: |
| 7041 | break; |
| 7042 | } |
| 7043 | |
| 7044 | return FALSE; |
| 7045 | } |
| 7046 | |
| 7047 | |
| 7048 | |
| 7049 | /** |
| 7050 | @brief Check if the requested privileges exists in either User-, Host- or |
| 7051 | Db-tables. |
| 7052 | @param thd Thread context |
| 7053 | @param want_access Privileges requested |
| 7054 | @param tables List of tables to be compared against |
| 7055 | @param no_errors Don't report error to the client (using my_error() call). |
| 7056 | @param any_combination_of_privileges_will_do TRUE if any privileges on any |
| 7057 | column combination is enough. |
| 7058 | @param number Only the first 'number' tables in the linked list are |
| 7059 | relevant. |
| 7060 | |
| 7061 | The suppled table list contains cached privileges. This functions calls the |
| 7062 | help functions check_access and check_grant to verify the first three steps |
| 7063 | in the privileges check queue: |
| 7064 | 1. Global privileges |
| 7065 | 2. OR (db privileges AND host privileges) |
| 7066 | 3. OR table privileges |
| 7067 | 4. OR column privileges (not checked by this function!) |
| 7068 | 5. OR routine privileges (not checked by this function!) |
| 7069 | |
| 7070 | @see check_access |
| 7071 | @see check_grant |
| 7072 | |
| 7073 | @note This functions assumes that table list used and |
| 7074 | thd->lex->query_tables_own_last value correspond to each other |
| 7075 | (the latter should be either 0 or point to next_global member |
| 7076 | of one of elements of this table list). |
| 7077 | |
| 7078 | @return |
| 7079 | @retval FALSE OK |
| 7080 | @retval TRUE Access denied; But column or routine privileges might need to |
| 7081 | be checked also. |
| 7082 | */ |
| 7083 | |
| 7084 | bool |
| 7085 | check_table_access(THD *thd, ulong requirements,TABLE_LIST *tables, |
| 7086 | bool any_combination_of_privileges_will_do, |
| 7087 | uint number, bool no_errors) |
| 7088 | { |
| 7089 | TABLE_LIST *org_tables= tables; |
| 7090 | TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); |
| 7091 | Security_context *sctx= thd->security_ctx, *backup_ctx= thd->security_ctx; |
| 7092 | uint i= 0; |
| 7093 | /* |
| 7094 | The check that first_not_own_table is not reached is for the case when |
| 7095 | the given table list refers to the list for prelocking (contains tables |
| 7096 | of other queries). For simple queries first_not_own_table is 0. |
| 7097 | */ |
| 7098 | for (; i < number && tables != first_not_own_table && tables; |
| 7099 | tables= tables->next_global, i++) |
| 7100 | { |
| 7101 | TABLE_LIST *const table_ref= tables->correspondent_table ? |
| 7102 | tables->correspondent_table : tables; |
| 7103 | |
| 7104 | ulong want_access= requirements; |
| 7105 | if (table_ref->security_ctx) |
| 7106 | sctx= table_ref->security_ctx; |
| 7107 | else |
| 7108 | sctx= backup_ctx; |
| 7109 | |
| 7110 | /* |
| 7111 | Register access for view underlying table. |
| 7112 | Remove SHOW_VIEW_ACL, because it will be checked during making view |
| 7113 | */ |
| 7114 | table_ref->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL); |
| 7115 | |
| 7116 | if (table_ref->schema_table_reformed) |
| 7117 | { |
| 7118 | if (check_show_access(thd, table_ref)) |
| 7119 | goto deny; |
| 7120 | continue; |
| 7121 | } |
| 7122 | |
| 7123 | DBUG_PRINT("info" , ("derived: %d view: %d" , table_ref->derived != 0, |
| 7124 | table_ref->view != 0)); |
| 7125 | |
| 7126 | if (table_ref->is_anonymous_derived_table()) |
| 7127 | continue; |
| 7128 | |
| 7129 | thd->security_ctx= sctx; |
| 7130 | |
| 7131 | if (table_ref->sequence) |
| 7132 | { |
| 7133 | /* We want to have either SELECT or INSERT rights to sequences depending |
| 7134 | on how they are accessed |
| 7135 | */ |
| 7136 | want_access= ((table_ref->lock_type == TL_WRITE_ALLOW_WRITE) ? |
| 7137 | INSERT_ACL : SELECT_ACL); |
| 7138 | } |
| 7139 | |
| 7140 | if (check_access(thd, want_access, table_ref->get_db_name(), |
| 7141 | &table_ref->grant.privilege, |
| 7142 | &table_ref->grant.m_internal, |
| 7143 | 0, no_errors)) |
| 7144 | goto deny; |
| 7145 | } |
| 7146 | thd->security_ctx= backup_ctx; |
| 7147 | return check_grant(thd,requirements,org_tables, |
| 7148 | any_combination_of_privileges_will_do, |
| 7149 | number, no_errors); |
| 7150 | deny: |
| 7151 | thd->security_ctx= backup_ctx; |
| 7152 | return TRUE; |
| 7153 | } |
| 7154 | |
| 7155 | |
| 7156 | bool |
| 7157 | check_routine_access(THD *thd, ulong want_access, const LEX_CSTRING *db, |
| 7158 | const LEX_CSTRING *name, |
| 7159 | const Sp_handler *sph, bool no_errors) |
| 7160 | { |
| 7161 | TABLE_LIST tables[1]; |
| 7162 | |
| 7163 | bzero((char *)tables, sizeof(TABLE_LIST)); |
| 7164 | tables->db= *db; |
| 7165 | tables->table_name= tables->alias= *name; |
| 7166 | |
| 7167 | /* |
| 7168 | The following test is just a shortcut for check_access() (to avoid |
| 7169 | calculating db_access) under the assumption that it's common to |
| 7170 | give persons global right to execute all stored SP (but not |
| 7171 | necessary to create them). |
| 7172 | Note that this effectively bypasses the ACL_internal_schema_access checks |
| 7173 | that are implemented for the INFORMATION_SCHEMA and PERFORMANCE_SCHEMA, |
| 7174 | which are located in check_access(). |
| 7175 | Since the I_S and P_S do not contain routines, this bypass is ok, |
| 7176 | as long as this code path is not abused to create routines. |
| 7177 | The assert enforce that. |
| 7178 | */ |
| 7179 | DBUG_ASSERT((want_access & CREATE_PROC_ACL) == 0); |
| 7180 | if ((thd->security_ctx->master_access & want_access) == want_access) |
| 7181 | tables->grant.privilege= want_access; |
| 7182 | else if (check_access(thd, want_access, db->str, |
| 7183 | &tables->grant.privilege, |
| 7184 | &tables->grant.m_internal, |
| 7185 | 0, no_errors)) |
| 7186 | return TRUE; |
| 7187 | |
| 7188 | return check_grant_routine(thd, want_access, tables, sph, no_errors); |
| 7189 | } |
| 7190 | |
| 7191 | |
| 7192 | /** |
| 7193 | Check if the routine has any of the routine privileges. |
| 7194 | |
| 7195 | @param thd Thread handler |
| 7196 | @param db Database name |
| 7197 | @param name Routine name |
| 7198 | |
| 7199 | @retval |
| 7200 | 0 ok |
| 7201 | @retval |
| 7202 | 1 error |
| 7203 | */ |
| 7204 | |
| 7205 | bool check_some_routine_access(THD *thd, const char *db, const char *name, |
| 7206 | const Sp_handler *sph) |
| 7207 | { |
| 7208 | ulong save_priv; |
| 7209 | /* |
| 7210 | The following test is just a shortcut for check_access() (to avoid |
| 7211 | calculating db_access) |
| 7212 | Note that this effectively bypasses the ACL_internal_schema_access checks |
| 7213 | that are implemented for the INFORMATION_SCHEMA and PERFORMANCE_SCHEMA, |
| 7214 | which are located in check_access(). |
| 7215 | Since the I_S and P_S do not contain routines, this bypass is ok, |
| 7216 | as it only opens SHOW_PROC_ACLS. |
| 7217 | */ |
| 7218 | if (thd->security_ctx->master_access & SHOW_PROC_ACLS) |
| 7219 | return FALSE; |
| 7220 | if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, NULL, 0, 1) || |
| 7221 | (save_priv & SHOW_PROC_ACLS)) |
| 7222 | return FALSE; |
| 7223 | return check_routine_level_acl(thd, db, name, sph); |
| 7224 | } |
| 7225 | |
| 7226 | |
| 7227 | /* |
| 7228 | Check if the given table has any of the asked privileges |
| 7229 | |
| 7230 | @param thd Thread handler |
| 7231 | @param want_access Bitmap of possible privileges to check for |
| 7232 | |
| 7233 | @retval |
| 7234 | 0 ok |
| 7235 | @retval |
| 7236 | 1 error |
| 7237 | */ |
| 7238 | |
| 7239 | bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table) |
| 7240 | { |
| 7241 | ulong access; |
| 7242 | DBUG_ENTER("check_some_access" ); |
| 7243 | |
| 7244 | /* This loop will work as long as we have less than 32 privileges */ |
| 7245 | for (access= 1; access < want_access ; access<<= 1) |
| 7246 | { |
| 7247 | if (access & want_access) |
| 7248 | { |
| 7249 | if (!check_access(thd, access, table->db.str, |
| 7250 | &table->grant.privilege, |
| 7251 | &table->grant.m_internal, |
| 7252 | 0, 1) && |
| 7253 | !check_grant(thd, access, table, FALSE, 1, TRUE)) |
| 7254 | DBUG_RETURN(0); |
| 7255 | } |
| 7256 | } |
| 7257 | DBUG_PRINT("exit" ,("no matching access rights" )); |
| 7258 | DBUG_RETURN(1); |
| 7259 | } |
| 7260 | |
| 7261 | #endif /*NO_EMBEDDED_ACCESS_CHECKS*/ |
| 7262 | |
| 7263 | |
| 7264 | /** |
| 7265 | check for global access and give descriptive error message if it fails. |
| 7266 | |
| 7267 | @param thd Thread handler |
| 7268 | @param want_access Use should have any of these global rights |
| 7269 | |
| 7270 | @warning |
| 7271 | One gets access right if one has ANY of the rights in want_access. |
| 7272 | This is useful as one in most cases only need one global right, |
| 7273 | but in some case we want to check if the user has SUPER or |
| 7274 | REPL_CLIENT_ACL rights. |
| 7275 | |
| 7276 | @retval |
| 7277 | 0 ok |
| 7278 | @retval |
| 7279 | 1 Access denied. In this case an error is sent to the client |
| 7280 | */ |
| 7281 | |
| 7282 | bool check_global_access(THD *thd, ulong want_access, bool no_errors) |
| 7283 | { |
| 7284 | #ifndef NO_EMBEDDED_ACCESS_CHECKS |
| 7285 | char command[128]; |
| 7286 | if ((thd->security_ctx->master_access & want_access)) |
| 7287 | return 0; |
| 7288 | if (unlikely(!no_errors)) |
| 7289 | { |
| 7290 | get_privilege_desc(command, sizeof(command), want_access); |
| 7291 | my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command); |
| 7292 | } |
| 7293 | status_var_increment(thd->status_var.access_denied_errors); |
| 7294 | return 1; |
| 7295 | #else |
| 7296 | return 0; |
| 7297 | #endif |
| 7298 | } |
| 7299 | |
| 7300 | |
| 7301 | /** |
| 7302 | Checks foreign key's parent table access. |
| 7303 | |
| 7304 | @param thd [in] Thread handler |
| 7305 | @param create_info [in] Create information (like MAX_ROWS, ENGINE or |
| 7306 | temporary table flag) |
| 7307 | @param alter_info [in] Initial list of columns and indexes for the |
| 7308 | table to be created |
| 7309 | @param create_db [in] Database of the created table |
| 7310 | |
| 7311 | @retval |
| 7312 | false ok. |
| 7313 | @retval |
| 7314 | true error or access denied. Error is sent to client in this case. |
| 7315 | */ |
| 7316 | bool check_fk_parent_table_access(THD *thd, |
| 7317 | HA_CREATE_INFO *create_info, |
| 7318 | Alter_info *alter_info, |
| 7319 | const char* create_db) |
| 7320 | { |
| 7321 | Key *key; |
| 7322 | List_iterator<Key> key_iterator(alter_info->key_list); |
| 7323 | |
| 7324 | while ((key= key_iterator++)) |
| 7325 | { |
| 7326 | if (key->type == Key::FOREIGN_KEY) |
| 7327 | { |
| 7328 | TABLE_LIST parent_table; |
| 7329 | bool is_qualified_table_name; |
| 7330 | Foreign_key *fk_key= (Foreign_key *)key; |
| 7331 | LEX_CSTRING db_name; |
| 7332 | LEX_CSTRING table_name= { fk_key->ref_table.str, |
| 7333 | fk_key->ref_table.length }; |
| 7334 | const ulong privileges= (SELECT_ACL | INSERT_ACL | UPDATE_ACL | |
| 7335 | DELETE_ACL | REFERENCES_ACL); |
| 7336 | |
| 7337 | // Check if tablename is valid or not. |
| 7338 | DBUG_ASSERT(table_name.str != NULL); |
| 7339 | if (check_table_name(table_name.str, table_name.length, false)) |
| 7340 | { |
| 7341 | my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str); |
| 7342 | return true; |
| 7343 | } |
| 7344 | |
| 7345 | if (fk_key->ref_db.str) |
| 7346 | { |
| 7347 | is_qualified_table_name= true; |
| 7348 | if (!(db_name.str= (char *) thd->memdup(fk_key->ref_db.str, |
| 7349 | fk_key->ref_db.length+1))) |
| 7350 | return true; |
| 7351 | db_name.length= fk_key->ref_db.length; |
| 7352 | |
| 7353 | // Check if database name is valid or not. |
| 7354 | if (check_db_name((LEX_STRING*) &db_name)) |
| 7355 | { |
| 7356 | my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); |
| 7357 | return true; |
| 7358 | } |
| 7359 | } |
| 7360 | else |
| 7361 | { |
| 7362 | if (!thd->db.str) |
| 7363 | { |
| 7364 | DBUG_ASSERT(create_db); |
| 7365 | db_name.length= strlen(create_db); |
| 7366 | if (!(db_name.str= (char *) thd->memdup(create_db, |
| 7367 | db_name.length+1))) |
| 7368 | return true; |
| 7369 | is_qualified_table_name= true; |
| 7370 | |
| 7371 | if (check_db_name((LEX_STRING*) &db_name)) |
| 7372 | { |
| 7373 | my_error(ER_WRONG_DB_NAME, MYF(0), db_name.str); |
| 7374 | return true; |
| 7375 | } |
| 7376 | } |
| 7377 | else |
| 7378 | { |
| 7379 | if (thd->lex->copy_db_to(&db_name)) |
| 7380 | return true; |
| 7381 | else |
| 7382 | is_qualified_table_name= false; |
| 7383 | } |
| 7384 | } |
| 7385 | |
| 7386 | // if lower_case_table_names is set then convert tablename to lower case. |
| 7387 | if (lower_case_table_names) |
| 7388 | { |
| 7389 | char *name; |
| 7390 | table_name.str= name= (char *) thd->memdup(fk_key->ref_table.str, |
| 7391 | fk_key->ref_table.length+1); |
| 7392 | table_name.length= my_casedn_str(files_charset_info, name); |
| 7393 | db_name.length= my_casedn_str(files_charset_info, (char*) db_name.str); |
| 7394 | } |
| 7395 | |
| 7396 | parent_table.init_one_table(&db_name, &table_name, 0, TL_IGNORE); |
| 7397 | |
| 7398 | /* |
| 7399 | Check if user has any of the "privileges" at table level on |
| 7400 | "parent_table". |
| 7401 | Having privilege on any of the parent_table column is not |
| 7402 | enough so checking whether user has any of the "privileges" |
| 7403 | at table level only here. |
| 7404 | */ |
| 7405 | if (check_some_access(thd, privileges, &parent_table) || |
| 7406 | parent_table.grant.want_privilege) |
| 7407 | { |
| 7408 | if (is_qualified_table_name) |
| 7409 | { |
| 7410 | const size_t qualified_table_name_len= NAME_LEN + 1 + NAME_LEN + 1; |
| 7411 | char *qualified_table_name= (char *) thd->alloc(qualified_table_name_len); |
| 7412 | |
| 7413 | my_snprintf(qualified_table_name, qualified_table_name_len, "%s.%s" , |
| 7414 | db_name.str, table_name.str); |
| 7415 | table_name.str= qualified_table_name; |
| 7416 | } |
| 7417 | |
| 7418 | my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), |
| 7419 | "REFERENCES" , |
| 7420 | thd->security_ctx->priv_user, |
| 7421 | thd->security_ctx->host_or_ip, |
| 7422 | table_name.str); |
| 7423 | |
| 7424 | return true; |
| 7425 | } |
| 7426 | } |
| 7427 | } |
| 7428 | |
| 7429 | return false; |
| 7430 | } |
| 7431 | |
| 7432 | |
| 7433 | /**************************************************************************** |
| 7434 | Check stack size; Send error if there isn't enough stack to continue |
| 7435 | ****************************************************************************/ |
| 7436 | |
| 7437 | |
| 7438 | #ifndef DBUG_OFF |
| 7439 | long max_stack_used; |
| 7440 | #endif |
| 7441 | |
| 7442 | /** |
| 7443 | @note |
| 7444 | Note: The 'buf' parameter is necessary, even if it is unused here. |
| 7445 | - fix_fields functions has a "dummy" buffer large enough for the |
| 7446 | corresponding exec. (Thus we only have to check in fix_fields.) |
| 7447 | - Passing to check_stack_overrun() prevents the compiler from removing it. |
| 7448 | */ |
| 7449 | bool check_stack_overrun(THD *thd, long margin, |
| 7450 | uchar *buf __attribute__((unused))) |
| 7451 | { |
| 7452 | long stack_used; |
| 7453 | DBUG_ASSERT(thd == current_thd); |
| 7454 | if ((stack_used= available_stack_size(thd->thread_stack, &stack_used)) >= |
| 7455 | (long) (my_thread_stack_size - margin)) |
| 7456 | { |
| 7457 | thd->is_fatal_error= 1; |
| 7458 | /* |
| 7459 | Do not use stack for the message buffer to ensure correct |
| 7460 | behaviour in cases we have close to no stack left. |
| 7461 | */ |
| 7462 | char* ebuff= new char[MYSQL_ERRMSG_SIZE]; |
| 7463 | if (ebuff) { |
| 7464 | my_snprintf(ebuff, MYSQL_ERRMSG_SIZE, ER_THD(thd, ER_STACK_OVERRUN_NEED_MORE), |
| 7465 | stack_used, my_thread_stack_size, margin); |
| 7466 | my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR)); |
| 7467 | delete [] ebuff; |
| 7468 | } |
| 7469 | return 1; |
| 7470 | } |
| 7471 | #ifndef DBUG_OFF |
| 7472 | max_stack_used= MY_MAX(max_stack_used, stack_used); |
| 7473 | #endif |
| 7474 | return 0; |
| 7475 | } |
| 7476 | |
| 7477 | |
| 7478 | #define MY_YACC_INIT 1000 // Start with big alloc |
| 7479 | #define MY_YACC_MAX 32000 // Because of 'short' |
| 7480 | |
| 7481 | bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, size_t *yystacksize) |
| 7482 | { |
| 7483 | Yacc_state *state= & current_thd->m_parser_state->m_yacc; |
| 7484 | size_t old_info=0; |
| 7485 | DBUG_ASSERT(state); |
| 7486 | if ( *yystacksize >= MY_YACC_MAX) |
| 7487 | return 1; |
| 7488 | if (!state->yacc_yyvs) |
| 7489 | old_info= *yystacksize; |
| 7490 | *yystacksize= set_zone((int)(*yystacksize)*2,MY_YACC_INIT,MY_YACC_MAX); |
| 7491 | if (!(state->yacc_yyvs= (uchar*) |
| 7492 | my_realloc(state->yacc_yyvs, |
| 7493 | *yystacksize*sizeof(**yyvs), |
| 7494 | MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR))) || |
| 7495 | !(state->yacc_yyss= (uchar*) |
| 7496 | my_realloc(state->yacc_yyss, |
| 7497 | *yystacksize*sizeof(**yyss), |
| 7498 | MYF(MY_ALLOW_ZERO_PTR | MY_FREE_ON_ERROR)))) |
| 7499 | return 1; |
| 7500 | if (old_info) |
| 7501 | { |
| 7502 | /* |
| 7503 | Only copy the old stack on the first call to my_yyoverflow(), |
| 7504 | when replacing a static stack (YYINITDEPTH) by a dynamic stack. |
| 7505 | For subsequent calls, my_realloc already did preserve the old stack. |
| 7506 | */ |
| 7507 | memcpy(state->yacc_yyss, *yyss, old_info*sizeof(**yyss)); |
| 7508 | memcpy(state->yacc_yyvs, *yyvs, old_info*sizeof(**yyvs)); |
| 7509 | } |
| 7510 | *yyss= (short*) state->yacc_yyss; |
| 7511 | *yyvs= (YYSTYPE*) state->yacc_yyvs; |
| 7512 | return 0; |
| 7513 | } |
| 7514 | |
| 7515 | |
| 7516 | /** |
| 7517 | Reset the part of THD responsible for the state of command |
| 7518 | processing. |
| 7519 | |
| 7520 | @param do_clear_error Set if we should clear errors |
| 7521 | |
| 7522 | This needs to be called before execution of every statement |
| 7523 | (prepared or conventional). It is not called by substatements of |
| 7524 | routines. |
| 7525 | |
| 7526 | @todo Call it after we use THD for queries, not before. |
| 7527 | */ |
| 7528 | |
| 7529 | void THD::reset_for_next_command(bool do_clear_error) |
| 7530 | { |
| 7531 | DBUG_ENTER("THD::reset_for_next_command" ); |
| 7532 | DBUG_ASSERT(!spcont); /* not for substatements of routines */ |
| 7533 | DBUG_ASSERT(!in_sub_stmt); |
| 7534 | |
| 7535 | if (likely(do_clear_error)) |
| 7536 | clear_error(1); |
| 7537 | |
| 7538 | free_list= 0; |
| 7539 | /* |
| 7540 | We also assign stmt_lex in lex_start(), but during bootstrap this |
| 7541 | code is executed first. |
| 7542 | */ |
| 7543 | DBUG_ASSERT(lex == &main_lex); |
| 7544 | main_lex.stmt_lex= &main_lex; main_lex.current_select_number= 1; |
| 7545 | DBUG_PRINT("info" , ("Lex and stmt_lex: %p" , &main_lex)); |
| 7546 | /* |
| 7547 | Those two lines below are theoretically unneeded as |
| 7548 | THD::cleanup_after_query() should take care of this already. |
| 7549 | */ |
| 7550 | auto_inc_intervals_in_cur_stmt_for_binlog.empty(); |
| 7551 | stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0; |
| 7552 | |
| 7553 | #ifdef WITH_WSREP |
| 7554 | /* |
| 7555 | Autoinc variables should be adjusted only for locally executed |
| 7556 | transactions. Appliers and replayers are either processing ROW |
| 7557 | events or get autoinc variable values from Query_log_event and |
| 7558 | mysql slave may be processing STATEMENT format events, but he should |
| 7559 | use autoinc values passed in binlog events, not the values forced by |
| 7560 | the cluster. |
| 7561 | */ |
| 7562 | if (WSREP(this) && wsrep_exec_mode == LOCAL_STATE && |
| 7563 | !slave_thread && wsrep_auto_increment_control) |
| 7564 | { |
| 7565 | variables.auto_increment_offset= |
| 7566 | global_system_variables.auto_increment_offset; |
| 7567 | variables.auto_increment_increment= |
| 7568 | global_system_variables.auto_increment_increment; |
| 7569 | } |
| 7570 | #endif /* WITH_WSREP */ |
| 7571 | query_start_sec_part_used= 0; |
| 7572 | is_fatal_error= time_zone_used= 0; |
| 7573 | log_current_statement= 0; |
| 7574 | |
| 7575 | /* |
| 7576 | Clear the status flag that are expected to be cleared at the |
| 7577 | beginning of each SQL statement. |
| 7578 | */ |
| 7579 | server_status&= ~SERVER_STATUS_CLEAR_SET; |
| 7580 | /* |
| 7581 | If in autocommit mode and not in a transaction, reset |
| 7582 | OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG to not get warnings |
| 7583 | in ha_rollback_trans() about some tables couldn't be rolled back. |
| 7584 | */ |
| 7585 | if (!in_multi_stmt_transaction_mode()) |
| 7586 | { |
| 7587 | variables.option_bits&= ~OPTION_KEEP_LOG; |
| 7588 | transaction.all.reset(); |
| 7589 | } |
| 7590 | DBUG_ASSERT(security_ctx== &main_security_ctx); |
| 7591 | thread_specific_used= FALSE; |
| 7592 | |
| 7593 | if (opt_bin_log) |
| 7594 | reset_dynamic(&user_var_events); |
| 7595 | DBUG_ASSERT(user_var_events_alloc == &main_mem_root); |
| 7596 | enable_slow_log= variables.sql_log_slow; |
| 7597 | get_stmt_da()->reset_for_next_command(); |
| 7598 | rand_used= 0; |
| 7599 | m_sent_row_count= m_examined_row_count= 0; |
| 7600 | accessed_rows_and_keys= 0; |
| 7601 | |
| 7602 | reset_slow_query_state(); |
| 7603 | |
| 7604 | reset_current_stmt_binlog_format_row(); |
| 7605 | binlog_unsafe_warning_flags= 0; |
| 7606 | |
| 7607 | save_prep_leaf_list= false; |
| 7608 | |
| 7609 | DBUG_PRINT("debug" , |
| 7610 | ("is_current_stmt_binlog_format_row(): %d" , |
| 7611 | is_current_stmt_binlog_format_row())); |
| 7612 | |
| 7613 | DBUG_VOID_RETURN; |
| 7614 | } |
| 7615 | |
| 7616 | |
| 7617 | /** |
| 7618 | Resets the lex->current_select object. |
| 7619 | @note It is assumed that lex->current_select != NULL |
| 7620 | |
| 7621 | This function is a wrapper around select_lex->init_select() with an added |
| 7622 | check for the special situation when using INTO OUTFILE and LOAD DATA. |
| 7623 | */ |
| 7624 | |
| 7625 | void |
| 7626 | mysql_init_select(LEX *lex) |
| 7627 | { |
| 7628 | SELECT_LEX *select_lex= lex->current_select; |
| 7629 | select_lex->init_select(); |
| 7630 | lex->wild= 0; |
| 7631 | if (select_lex == &lex->select_lex) |
| 7632 | { |
| 7633 | DBUG_ASSERT(lex->result == 0); |
| 7634 | lex->exchange= 0; |
| 7635 | } |
| 7636 | } |
| 7637 | |
| 7638 | |
| 7639 | /** |
| 7640 | Used to allocate a new SELECT_LEX object on the current thd mem_root and |
| 7641 | link it into the relevant lists. |
| 7642 | |
| 7643 | This function is always followed by mysql_init_select. |
| 7644 | |
| 7645 | @see mysql_init_select |
| 7646 | |
| 7647 | @retval TRUE An error occurred |
| 7648 | @retval FALSE The new SELECT_LEX was successfully allocated. |
| 7649 | */ |
| 7650 | |
| 7651 | bool |
| 7652 | mysql_new_select(LEX *lex, bool move_down, SELECT_LEX *select_lex) |
| 7653 | { |
| 7654 | THD *thd= lex->thd; |
| 7655 | bool new_select= select_lex == NULL; |
| 7656 | DBUG_ENTER("mysql_new_select" ); |
| 7657 | |
| 7658 | if (new_select) |
| 7659 | { |
| 7660 | if (!(select_lex= new (thd->mem_root) SELECT_LEX())) |
| 7661 | DBUG_RETURN(1); |
| 7662 | select_lex->select_number= ++thd->lex->stmt_lex->current_select_number; |
| 7663 | select_lex->parent_lex= lex; /* Used in init_query. */ |
| 7664 | select_lex->init_query(); |
| 7665 | select_lex->init_select(); |
| 7666 | } |
| 7667 | lex->nest_level++; |
| 7668 | if (lex->nest_level > (int) MAX_SELECT_NESTING) |
| 7669 | { |
| 7670 | my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT, MYF(0)); |
| 7671 | DBUG_RETURN(1); |
| 7672 | } |
| 7673 | select_lex->nest_level= lex->nest_level; |
| 7674 | select_lex->nest_level_base= &thd->lex->unit; |
| 7675 | if (move_down) |
| 7676 | { |
| 7677 | SELECT_LEX_UNIT *unit; |
| 7678 | lex->subqueries= TRUE; |
| 7679 | /* first select_lex of subselect or derived table */ |
| 7680 | if (!(unit= new (thd->mem_root) SELECT_LEX_UNIT())) |
| 7681 | DBUG_RETURN(1); |
| 7682 | |
| 7683 | unit->init_query(); |
| 7684 | unit->thd= thd; |
| 7685 | unit->include_down(lex->current_select); |
| 7686 | unit->link_next= 0; |
| 7687 | unit->link_prev= 0; |
| 7688 | unit->return_to= lex->current_select; |
| 7689 | select_lex->include_down(unit); |
| 7690 | /* |
| 7691 | By default we assume that it is usual subselect and we have outer name |
| 7692 | resolution context, if no we will assign it to 0 later |
| 7693 | */ |
| 7694 | select_lex->context.outer_context= &select_lex->outer_select()->context; |
| 7695 | } |
| 7696 | else |
| 7697 | { |
| 7698 | bool const outer_most= (lex->current_select->master_unit() == &lex->unit); |
| 7699 | if (outer_most && lex->result) |
| 7700 | { |
| 7701 | my_error(ER_WRONG_USAGE, MYF(0), "UNION" , "INTO" ); |
| 7702 | DBUG_RETURN(TRUE); |
| 7703 | } |
| 7704 | |
| 7705 | /* |
| 7706 | This type of query is not possible in the grammar: |
| 7707 | SELECT 1 FROM t1 PROCEDURE ANALYSE() UNION ... ; |
| 7708 | |
| 7709 | But this type of query is still possible: |
| 7710 | (SELECT 1 FROM t1 PROCEDURE ANALYSE()) UNION ... ; |
| 7711 | and it's not easy to disallow this grammatically, |
| 7712 | because there can be any parenthesis nest level: |
| 7713 | (((SELECT 1 FROM t1 PROCEDURE ANALYSE()))) UNION ... ; |
| 7714 | */ |
| 7715 | if (lex->proc_list.elements!=0) |
| 7716 | { |
| 7717 | my_error(ER_WRONG_USAGE, MYF(0), "UNION" , |
| 7718 | "SELECT ... PROCEDURE ANALYSE()" ); |
| 7719 | DBUG_RETURN(TRUE); |
| 7720 | } |
| 7721 | // SELECT 1 FROM t1 ORDER BY 1 UNION SELECT 1 FROM t1 -- not possible |
| 7722 | DBUG_ASSERT(!lex->current_select->order_list.first || |
| 7723 | lex->current_select->braces); |
| 7724 | // SELECT 1 FROM t1 LIMIT 1 UNION SELECT 1 FROM t1; -- not possible |
| 7725 | DBUG_ASSERT(!lex->current_select->explicit_limit || |
| 7726 | lex->current_select->braces); |
| 7727 | |
| 7728 | select_lex->include_neighbour(lex->current_select); |
| 7729 | SELECT_LEX_UNIT *unit= select_lex->master_unit(); |
| 7730 | if (!unit->fake_select_lex && unit->add_fake_select_lex(lex->thd)) |
| 7731 | DBUG_RETURN(1); |
| 7732 | select_lex->context.outer_context= |
| 7733 | unit->first_select()->context.outer_context; |
| 7734 | } |
| 7735 | |
| 7736 | if (new_select) |
| 7737 | select_lex->include_global((st_select_lex_node**)&lex->all_selects_list); |
| 7738 | lex->current_select= select_lex; |
| 7739 | /* |
| 7740 | in subquery is SELECT query and we allow resolution of names in SELECT |
| 7741 | list |
| 7742 | */ |
| 7743 | select_lex->context.resolve_in_select_list= TRUE; |
| 7744 | DBUG_RETURN(0); |
| 7745 | } |
| 7746 | |
| 7747 | /** |
| 7748 | Create a select to return the same output as 'SELECT @@var_name'. |
| 7749 | |
| 7750 | Used for SHOW COUNT(*) [ WARNINGS | ERROR]. |
| 7751 | |
| 7752 | This will crash with a core dump if the variable doesn't exists. |
| 7753 | |
| 7754 | @param var_name Variable name |
| 7755 | */ |
| 7756 | |
| 7757 | void create_select_for_variable(THD *thd, LEX_CSTRING *var_name) |
| 7758 | { |
| 7759 | LEX *lex; |
| 7760 | Item *var; |
| 7761 | char buff[MAX_SYS_VAR_LENGTH*2+4+8], *end; |
| 7762 | DBUG_ENTER("create_select_for_variable" ); |
| 7763 | |
| 7764 | lex= thd->lex; |
| 7765 | mysql_init_select(lex); |
| 7766 | lex->sql_command= SQLCOM_SELECT; |
| 7767 | /* |
| 7768 | We set the name of Item to @@session.var_name because that then is used |
| 7769 | as the column name in the output. |
| 7770 | */ |
| 7771 | if ((var= get_system_var(thd, OPT_SESSION, var_name, &null_clex_str))) |
| 7772 | { |
| 7773 | end= strxmov(buff, "@@session." , var_name->str, NullS); |
| 7774 | var->set_name(thd, buff, (uint)(end-buff), system_charset_info); |
| 7775 | add_item_to_list(thd, var); |
| 7776 | } |
| 7777 | DBUG_VOID_RETURN; |
| 7778 | } |
| 7779 | |
| 7780 | |
| 7781 | void mysql_init_multi_delete(LEX *lex) |
| 7782 | { |
| 7783 | lex->sql_command= SQLCOM_DELETE_MULTI; |
| 7784 | mysql_init_select(lex); |
| 7785 | lex->select_lex.select_limit= 0; |
| 7786 | lex->unit.select_limit_cnt= HA_POS_ERROR; |
| 7787 | lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list); |
| 7788 | lex->query_tables= 0; |
| 7789 | lex->query_tables_last= &lex->query_tables; |
| 7790 | } |
| 7791 | |
| 7792 | static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length, |
| 7793 | Parser_state *parser_state, |
| 7794 | bool is_com_multi, |
| 7795 | bool is_next_command) |
| 7796 | { |
| 7797 | #ifdef WITH_WSREP |
| 7798 | bool is_autocommit= |
| 7799 | !thd->in_multi_stmt_transaction_mode() && |
| 7800 | thd->wsrep_conflict_state == NO_CONFLICT && |
| 7801 | !thd->wsrep_applier; |
| 7802 | |
| 7803 | do |
| 7804 | { |
| 7805 | if (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT) |
| 7806 | { |
| 7807 | thd->wsrep_conflict_state= NO_CONFLICT; |
| 7808 | /* Performance Schema Interface instrumentation, begin */ |
| 7809 | thd->m_statement_psi= MYSQL_REFINE_STATEMENT(thd->m_statement_psi, |
| 7810 | com_statement_info[thd->get_command()].m_key); |
| 7811 | MYSQL_SET_STATEMENT_TEXT(thd->m_statement_psi, thd->query(), |
| 7812 | thd->query_length()); |
| 7813 | |
| 7814 | DBUG_EXECUTE_IF("sync.wsrep_retry_autocommit" , |
| 7815 | { |
| 7816 | const char act[]= |
| 7817 | "now " |
| 7818 | "SIGNAL wsrep_retry_autocommit_reached " |
| 7819 | "WAIT_FOR wsrep_retry_autocommit_continue" ; |
| 7820 | DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act))); |
| 7821 | }); |
| 7822 | } |
| 7823 | mysql_parse(thd, rawbuf, length, parser_state, is_com_multi, |
| 7824 | is_next_command); |
| 7825 | |
| 7826 | if (WSREP(thd)) { |
| 7827 | /* wsrep BF abort in query exec phase */ |
| 7828 | mysql_mutex_lock(&thd->LOCK_thd_data); |
| 7829 | if (thd->wsrep_conflict_state == MUST_ABORT) { |
| 7830 | wsrep_client_rollback(thd); |
| 7831 | |
| 7832 | WSREP_DEBUG("abort in exec query state, avoiding autocommit" ); |
| 7833 | } |
| 7834 | |
| 7835 | if (thd->wsrep_conflict_state == MUST_REPLAY) |
| 7836 | { |
| 7837 | mysql_mutex_unlock(&thd->LOCK_thd_data); |
| 7838 | if (thd->lex->explain) |
| 7839 | delete_explain_query(thd->lex); |
| 7840 | mysql_mutex_lock(&thd->LOCK_thd_data); |
| 7841 | |
| 7842 | wsrep_replay_transaction(thd); |
| 7843 | } |
| 7844 | |
| 7845 | /* setting error code for BF aborted trxs */ |
| 7846 | if (thd->wsrep_conflict_state == ABORTED || |
| 7847 | thd->wsrep_conflict_state == CERT_FAILURE) |
| 7848 | { |
| 7849 | thd->reset_for_next_command(); |
| 7850 | if (is_autocommit && |
| 7851 | thd->lex->sql_command != SQLCOM_SELECT && |
| 7852 | (thd->wsrep_retry_counter < thd->variables.wsrep_retry_autocommit)) |
| 7853 | { |
| 7854 | WSREP_DEBUG("wsrep retrying AC query: %s" , |
| 7855 | (thd->query()) ? thd->query() : "void" ); |
| 7856 | |
| 7857 | /* Performance Schema Interface instrumentation, end */ |
| 7858 | MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da()); |
| 7859 | thd->m_statement_psi= NULL; |
| 7860 | thd->m_digest= NULL; |
| 7861 | close_thread_tables(thd); |
| 7862 | |
| 7863 | thd->wsrep_conflict_state= RETRY_AUTOCOMMIT; |
| 7864 | thd->wsrep_retry_counter++; // grow |
| 7865 | wsrep_copy_query(thd); |
| 7866 | thd->set_time(); |
| 7867 | parser_state->reset(rawbuf, length); |
| 7868 | } |
| 7869 | else |
| 7870 | { |
| 7871 | WSREP_DEBUG("%s, thd: %lld is_AC: %d, retry: %lu - %lu SQL: %s" , |
| 7872 | (thd->wsrep_conflict_state == ABORTED) ? |
| 7873 | "BF Aborted" : "cert failure" , |
| 7874 | (longlong) thd->thread_id, is_autocommit, |
| 7875 | thd->wsrep_retry_counter, |
| 7876 | thd->variables.wsrep_retry_autocommit, thd->query()); |
| 7877 | my_message(ER_LOCK_DEADLOCK, "Deadlock: wsrep aborted transaction" , |
| 7878 | MYF(0)); |
| 7879 | thd->wsrep_conflict_state= NO_CONFLICT; |
| 7880 | if (thd->wsrep_conflict_state != REPLAYING) |
| 7881 | thd->wsrep_retry_counter= 0; // reset |
| 7882 | } |
| 7883 | mysql_mutex_unlock(&thd->LOCK_thd_data); |
| 7884 | thd->reset_killed(); |
| 7885 | } |
| 7886 | else |
| 7887 | { |
| 7888 | set_if_smaller(thd->wsrep_retry_counter, 0); // reset; eventually ok |
| 7889 | mysql_mutex_unlock(&thd->LOCK_thd_data); |
| 7890 | } |
| 7891 | } |
| 7892 | |
| 7893 | /* If retry is requested clean up explain structure */ |
| 7894 | if ((thd->wsrep_conflict_state == RETRY_AUTOCOMMIT || |
| 7895 | thd->wsrep_conflict_state == MUST_REPLAY ) |
| 7896 | && thd->lex->explain) |
| 7897 | { |
| 7898 | delete_explain_query(thd->lex); |
| 7899 | } |
| 7900 | |
| 7901 | } while (thd->wsrep_conflict_state== RETRY_AUTOCOMMIT); |
| 7902 | |
| 7903 | if (thd->wsrep_retry_query) |
| 7904 | { |
| 7905 | WSREP_DEBUG("releasing retry_query: conf %d sent %d kill %d errno %d SQL %s" , |
| 7906 | thd->wsrep_conflict_state, |
| 7907 | thd->get_stmt_da()->is_sent(), |
| 7908 | thd->killed, |
| 7909 | thd->get_stmt_da()->is_error() ? thd->get_stmt_da()->sql_errno() : 0, |
| 7910 | thd->wsrep_retry_query); |
| 7911 | my_free(thd->wsrep_retry_query); |
| 7912 | thd->wsrep_retry_query = NULL; |
| 7913 | thd->wsrep_retry_query_len = 0; |
| 7914 | thd->wsrep_retry_command = COM_CONNECT; |
| 7915 | } |
| 7916 | #endif /* WITH_WSREP */ |
| 7917 | } |
| 7918 | |
| 7919 | /* |
| 7920 | When you modify mysql_parse(), you may need to modify |
| 7921 | mysql_test_parse_for_slave() in this same file. |
| 7922 | */ |
| 7923 | |
| 7924 | /** |
| 7925 | Parse a query. |
| 7926 | |
| 7927 | @param thd Current thread |
| 7928 | @param rawbuf Begining of the query text |
| 7929 | @param length Length of the query text |
| 7930 | @param[out] found_semicolon For multi queries, position of the character of |
| 7931 | the next query in the query text. |
| 7932 | @param is_next_command there will be more command in the COM_MULTI batch |
| 7933 | */ |
| 7934 | |
| 7935 | void mysql_parse(THD *thd, char *rawbuf, uint length, |
| 7936 | Parser_state *parser_state, |
| 7937 | bool is_com_multi, |
| 7938 | bool is_next_command) |
| 7939 | { |
| 7940 | int error __attribute__((unused)); |
| 7941 | DBUG_ENTER("mysql_parse" ); |
| 7942 | DBUG_EXECUTE_IF("parser_debug" , turn_parser_debug_on();); |
| 7943 | |
| 7944 | /* |
| 7945 | Warning. |
| 7946 | The purpose of query_cache_send_result_to_client() is to lookup the |
| 7947 | query in the query cache first, to avoid parsing and executing it. |
| 7948 | So, the natural implementation would be to: |
| 7949 | - first, call query_cache_send_result_to_client, |
| 7950 | - second, if caching failed, initialise the lexical and syntactic parser. |
| 7951 | The problem is that the query cache depends on a clean initialization |
| 7952 | of (among others) lex->safe_to_cache_query and thd->server_status, |
| 7953 | which are reset respectively in |
| 7954 | - lex_start() |
| 7955 | - THD::reset_for_next_command() |
| 7956 | So, initializing the lexical analyser *before* using the query cache |
| 7957 | is required for the cache to work properly. |
| 7958 | FIXME: cleanup the dependencies in the code to simplify this. |
| 7959 | */ |
| 7960 | lex_start(thd); |
| 7961 | thd->reset_for_next_command(); |
| 7962 | if (is_next_command) |
| 7963 | { |
| 7964 | thd->server_status|= SERVER_MORE_RESULTS_EXISTS; |
| 7965 | if (is_com_multi) |
| 7966 | thd->get_stmt_da()->set_skip_flush(); |
| 7967 | } |
| 7968 | |
| 7969 | if (query_cache_send_result_to_client(thd, rawbuf, length) <= 0) |
| 7970 | { |
| 7971 | LEX *lex= thd->lex; |
| 7972 | |
| 7973 | bool err= parse_sql(thd, parser_state, NULL, true); |
| 7974 | |
| 7975 | if (likely(!err)) |
| 7976 | { |
| 7977 | thd->m_statement_psi= |
| 7978 | MYSQL_REFINE_STATEMENT(thd->m_statement_psi, |
| 7979 | sql_statement_info[thd->lex->sql_command]. |
| 7980 | m_key); |
| 7981 | #ifndef NO_EMBEDDED_ACCESS_CHECKS |
| 7982 | if (mqh_used && thd->user_connect && |
| 7983 | check_mqh(thd, lex->sql_command)) |
| 7984 | { |
| 7985 | thd->net.error = 0; |
| 7986 | } |
| 7987 | else |
| 7988 | #endif |
| 7989 | { |
| 7990 | if (likely(! thd->is_error())) |
| 7991 | { |
| 7992 | const char *found_semicolon= parser_state->m_lip.found_semicolon; |
| 7993 | /* |
| 7994 | Binlog logs a string starting from thd->query and having length |
| 7995 | thd->query_length; so we set thd->query_length correctly (to not |
| 7996 | log several statements in one event, when we executed only first). |
| 7997 | We set it to not see the ';' (otherwise it would get into binlog |
| 7998 | and Query_log_event::print() would give ';;' output). |
| 7999 | This also helps display only the current query in SHOW |
| 8000 | PROCESSLIST. |
| 8001 | */ |
| 8002 | if (found_semicolon && (ulong) (found_semicolon - thd->query())) |
| 8003 | thd->set_query(thd->query(), |
| 8004 | (uint32) (found_semicolon - thd->query() - 1), |
| 8005 | thd->charset()); |
| 8006 | /* Actually execute the query */ |
| 8007 | if (found_semicolon) |
| 8008 | { |
| 8009 | lex->safe_to_cache_query= 0; |
| 8010 | thd->server_status|= SERVER_MORE_RESULTS_EXISTS; |
| 8011 | } |
| 8012 | lex->set_trg_event_type_for_tables(); |
| 8013 | MYSQL_QUERY_EXEC_START(thd->query(), |
| 8014 | thd->thread_id, |
| 8015 | thd->get_db(), |
| 8016 | &thd->security_ctx->priv_user[0], |
| 8017 | (char *) thd->security_ctx->host_or_ip, |
| 8018 | 0); |
| 8019 | |
| 8020 | error= mysql_execute_command(thd); |
| 8021 | MYSQL_QUERY_EXEC_DONE(error); |
| 8022 | } |
| 8023 | } |
| 8024 | } |
| 8025 | else |
| 8026 | { |
| 8027 | /* Instrument this broken statement as "statement/sql/error" */ |
| 8028 | thd->m_statement_psi= |
| 8029 | MYSQL_REFINE_STATEMENT(thd->m_statement_psi, |
| 8030 | sql_statement_info[SQLCOM_END].m_key); |
| 8031 | DBUG_ASSERT(thd->is_error()); |
| 8032 | DBUG_PRINT("info" ,("Command aborted. Fatal_error: %d" , |
| 8033 | thd->is_fatal_error)); |
| 8034 | |
| 8035 | query_cache_abort(thd, &thd->query_cache_tls); |
| 8036 | } |
| 8037 | THD_STAGE_INFO(thd, stage_freeing_items); |
| 8038 | sp_cache_enforce_limit(thd->sp_proc_cache, stored_program_cache_size); |
| 8039 | sp_cache_enforce_limit(thd->sp_func_cache, stored_program_cache_size); |
| 8040 | sp_cache_enforce_limit(thd->sp_package_spec_cache, stored_program_cache_size); |
| 8041 | sp_cache_enforce_limit(thd->sp_package_body_cache, stored_program_cache_size); |
| 8042 | thd->end_statement(); |
| 8043 | thd->cleanup_after_query(); |
| 8044 | DBUG_ASSERT(thd->Item_change_list::is_empty()); |
| 8045 | } |
| 8046 | else |
| 8047 | { |
| 8048 | /* Update statistics for getting the query from the cache */ |
| 8049 | thd->lex->sql_command= SQLCOM_SELECT; |
| 8050 | thd->m_statement_psi= |
| 8051 | MYSQL_REFINE_STATEMENT(thd->m_statement_psi, |
| 8052 | sql_statement_info[SQLCOM_SELECT].m_key); |
| 8053 | status_var_increment(thd->status_var.com_stat[SQLCOM_SELECT]); |
| 8054 | thd->update_stats(); |
| 8055 | #ifdef WITH_WSREP |
| 8056 | if (WSREP_CLIENT(thd)) |
| 8057 | { |
| 8058 | thd->wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED; |
| 8059 | } |
| 8060 | #endif /* WITH_WSREP */ |
| 8061 | } |
| 8062 | DBUG_VOID_RETURN; |
| 8063 | } |
| 8064 | |
| 8065 | |
| 8066 | #ifdef HAVE_REPLICATION |
| 8067 | /* |
| 8068 | Usable by the replication SQL thread only: just parse a query to know if it |
| 8069 | can be ignored because of replicate-*-table rules. |
| 8070 | |
| 8071 | @retval |
| 8072 | 0 cannot be ignored |
| 8073 | @retval |
| 8074 | 1 can be ignored |
| 8075 | */ |
| 8076 | |
| 8077 | bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length) |
| 8078 | { |
| 8079 | LEX *lex= thd->lex; |
| 8080 | bool error= 0; |
| 8081 | DBUG_ENTER("mysql_test_parse_for_slave" ); |
| 8082 | |
| 8083 | Parser_state parser_state; |
| 8084 | if (likely(!(error= parser_state.init(thd, rawbuf, length)))) |
| 8085 | { |
| 8086 | lex_start(thd); |
| 8087 | thd->reset_for_next_command(); |
| 8088 | |
| 8089 | if (!parse_sql(thd, & parser_state, NULL, true) && |
| 8090 | all_tables_not_ok(thd, lex->select_lex.table_list.first)) |
| 8091 | error= 1; /* Ignore question */ |
| 8092 | thd->end_statement(); |
| 8093 | } |
| 8094 | thd->cleanup_after_query(); |
| 8095 | DBUG_RETURN(error); |
| 8096 | } |
| 8097 | #endif |
| 8098 | |
| 8099 | |
| 8100 | bool |
| 8101 | add_proc_to_list(THD* thd, Item *item) |
| 8102 | { |
| 8103 | ORDER *order; |
| 8104 | Item **item_ptr; |
| 8105 | |
| 8106 | if (unlikely(!(order = (ORDER *) thd->alloc(sizeof(ORDER)+sizeof(Item*))))) |
| 8107 | return 1; |
| 8108 | item_ptr = (Item**) (order+1); |
| 8109 | *item_ptr= item; |
| 8110 | order->item=item_ptr; |
| 8111 | thd->lex->proc_list.link_in_list(order, &order->next); |
| 8112 | return 0; |
| 8113 | } |
| 8114 | |
| 8115 | |
| 8116 | /** |
| 8117 | save order by and tables in own lists. |
| 8118 | */ |
| 8119 | |
| 8120 | bool add_to_list(THD *thd, SQL_I_List<ORDER> &list, Item *item,bool asc) |
| 8121 | { |
| 8122 | ORDER *order; |
| 8123 | DBUG_ENTER("add_to_list" ); |
| 8124 | if (unlikely(!(order = (ORDER *) thd->alloc(sizeof(ORDER))))) |
| 8125 | DBUG_RETURN(1); |
| 8126 | order->item_ptr= item; |
| 8127 | order->item= &order->item_ptr; |
| 8128 | order->direction= (asc ? ORDER::ORDER_ASC : ORDER::ORDER_DESC); |
| 8129 | order->used=0; |
| 8130 | order->counter_used= 0; |
| 8131 | order->fast_field_copier_setup= 0; |
| 8132 | list.link_in_list(order, &order->next); |
| 8133 | DBUG_RETURN(0); |
| 8134 | } |
| 8135 | |
| 8136 | |
| 8137 | /** |
| 8138 | Add a table to list of used tables. |
| 8139 | |
| 8140 | @param table Table to add |
| 8141 | @param alias alias for table (or null if no alias) |
| 8142 | @param table_options A set of the following bits: |
| 8143 | - TL_OPTION_UPDATING : Table will be updated |
| 8144 | - TL_OPTION_FORCE_INDEX : Force usage of index |
| 8145 | - TL_OPTION_ALIAS : an alias in multi table DELETE |
| 8146 | @param lock_type How table should be locked |
| 8147 | @param mdl_type Type of metadata lock to acquire on the table. |
| 8148 | @param use_index List of indexed used in USE INDEX |
| 8149 | @param ignore_index List of indexed used in IGNORE INDEX |
| 8150 | |
| 8151 | @retval |
| 8152 | 0 Error |
| 8153 | @retval |
| 8154 | \# Pointer to TABLE_LIST element added to the total table list |
| 8155 | */ |
| 8156 | |
| 8157 | TABLE_LIST *st_select_lex::add_table_to_list(THD *thd, |
| 8158 | Table_ident *table, |
| 8159 | LEX_CSTRING *alias, |
| 8160 | ulong table_options, |
| 8161 | thr_lock_type lock_type, |
| 8162 | enum_mdl_type mdl_type, |
| 8163 | List<Index_hint> *index_hints_arg, |
| 8164 | List<String> *partition_names, |
| 8165 | LEX_STRING *option) |
| 8166 | { |
| 8167 | TABLE_LIST *ptr; |
| 8168 | TABLE_LIST *UNINIT_VAR(previous_table_ref); /* The table preceding the current one. */ |
| 8169 | LEX_CSTRING alias_str; |
| 8170 | LEX *lex= thd->lex; |
| 8171 | DBUG_ENTER("add_table_to_list" ); |
| 8172 | |
| 8173 | if (unlikely(!table)) |
| 8174 | DBUG_RETURN(0); // End of memory |
| 8175 | alias_str= alias ? *alias : table->table; |
| 8176 | DBUG_ASSERT(alias_str.str); |
| 8177 | if (!MY_TEST(table_options & TL_OPTION_ALIAS) && |
| 8178 | unlikely(check_table_name(table->table.str, table->table.length, FALSE))) |
| 8179 | { |
| 8180 | my_error(ER_WRONG_TABLE_NAME, MYF(0), table->table.str); |
| 8181 | DBUG_RETURN(0); |
| 8182 | } |
| 8183 | |
| 8184 | if (unlikely(table->is_derived_table() == FALSE && table->db.str && |
| 8185 | check_db_name((LEX_STRING*) &table->db))) |
| 8186 | { |
| 8187 | my_error(ER_WRONG_DB_NAME, MYF(0), table->db.str); |
| 8188 | DBUG_RETURN(0); |
| 8189 | } |
| 8190 | |
| 8191 | if (!alias) /* Alias is case sensitive */ |
| 8192 | { |
| 8193 | if (unlikely(table->sel)) |
| 8194 | { |
| 8195 | my_message(ER_DERIVED_MUST_HAVE_ALIAS, |
| 8196 | ER_THD(thd, ER_DERIVED_MUST_HAVE_ALIAS), MYF(0)); |
| 8197 | DBUG_RETURN(0); |
| 8198 | } |
| 8199 | /* alias_str points to table->table; Let's make a copy */ |
| 8200 | if (unlikely(!(alias_str.str= (char*) thd->memdup(alias_str.str, alias_str.length+1)))) |
| 8201 | DBUG_RETURN(0); |
| 8202 | } |
| 8203 | if (unlikely(!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))) |
| 8204 | DBUG_RETURN(0); /* purecov: inspected */ |
| 8205 | if (table->db.str) |
| 8206 | { |
| 8207 | ptr->is_fqtn= TRUE; |
| 8208 | ptr->db= table->db; |
| 8209 | } |
| 8210 | else if (lex->copy_db_to(&ptr->db)) |
| 8211 | DBUG_RETURN(0); |
| 8212 | else |
| 8213 | ptr->is_fqtn= FALSE; |
| 8214 | |
| 8215 | ptr->alias= alias_str; |
| 8216 | ptr->is_alias= alias ? TRUE : FALSE; |
| 8217 | if (lower_case_table_names) |
| 8218 | { |
| 8219 | if (table->table.length) |
| 8220 | table->table.length= my_casedn_str(files_charset_info, |
| 8221 | (char*) table->table.str); |
| 8222 | if (ptr->db.length && ptr->db.str != any_db) |
| 8223 | ptr->db.length= my_casedn_str(files_charset_info, (char*) ptr->db.str); |
| 8224 | } |
| 8225 | |
| 8226 | ptr->table_name= table->table; |
| 8227 | ptr->lock_type= lock_type; |
| 8228 | ptr->updating= MY_TEST(table_options & TL_OPTION_UPDATING); |
| 8229 | /* TODO: remove TL_OPTION_FORCE_INDEX as it looks like it's not used */ |
| 8230 | ptr->force_index= MY_TEST(table_options & TL_OPTION_FORCE_INDEX); |
| 8231 | ptr->ignore_leaves= MY_TEST(table_options & TL_OPTION_IGNORE_LEAVES); |
| 8232 | ptr->sequence= MY_TEST(table_options & TL_OPTION_SEQUENCE); |
| 8233 | ptr->derived= table->sel; |
| 8234 | if (!ptr->derived && is_infoschema_db(&ptr->db)) |
| 8235 | { |
| 8236 | ST_SCHEMA_TABLE *schema_table; |
| 8237 | if (ptr->updating && |
| 8238 | /* Special cases which are processed by commands itself */ |
| 8239 | lex->sql_command != SQLCOM_CHECK && |
| 8240 | lex->sql_command != SQLCOM_CHECKSUM) |
| 8241 | { |
| 8242 | my_error(ER_DBACCESS_DENIED_ERROR, MYF(0), |
| 8243 | thd->security_ctx->priv_user, |
| 8244 | thd->security_ctx->priv_host, |
| 8245 | INFORMATION_SCHEMA_NAME.str); |
| 8246 | DBUG_RETURN(0); |
| 8247 | } |
| 8248 | schema_table= find_schema_table(thd, &ptr->table_name); |
| 8249 | if (unlikely(!schema_table) || |
| 8250 | (schema_table->hidden && |
| 8251 | ((sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) == 0 || |
| 8252 | /* |
| 8253 | this check is used for show columns|keys from I_S hidden table |
| 8254 | */ |
| 8255 | lex->sql_command == SQLCOM_SHOW_FIELDS || |
| 8256 | lex->sql_command == SQLCOM_SHOW_KEYS))) |
| 8257 | { |
| 8258 | my_error(ER_UNKNOWN_TABLE, MYF(0), |
| 8259 | ptr->table_name.str, INFORMATION_SCHEMA_NAME.str); |
| 8260 | DBUG_RETURN(0); |
| 8261 | } |
| 8262 | ptr->schema_table_name= ptr->table_name; |
| 8263 | ptr->schema_table= schema_table; |
| 8264 | } |
| 8265 | ptr->select_lex= lex->current_select; |
| 8266 | /* |
| 8267 | We can't cache internal temporary tables between prepares as the |
| 8268 | table may be deleted before next exection. |
| 8269 | */ |
| 8270 | ptr->cacheable_table= !table->is_derived_table(); |
| 8271 | ptr->index_hints= index_hints_arg; |
| 8272 | ptr->option= option ? option->str : 0; |
| 8273 | /* check that used name is unique. Sequences are ignored */ |
| 8274 | if (lock_type != TL_IGNORE && !ptr->sequence) |
| 8275 | { |
| 8276 | TABLE_LIST *first_table= table_list.first; |
| 8277 | if (lex->sql_command == SQLCOM_CREATE_VIEW) |
| 8278 | first_table= first_table ? first_table->next_local : NULL; |
| 8279 | for (TABLE_LIST *tables= first_table ; |
| 8280 | tables ; |
| 8281 | tables=tables->next_local) |
| 8282 | { |
| 8283 | if (unlikely(!my_strcasecmp(table_alias_charset, alias_str.str, |
| 8284 | tables->alias.str) && |
| 8285 | !cmp(&ptr->db, &tables->db) && ! tables->sequence)) |
| 8286 | { |
| 8287 | my_error(ER_NONUNIQ_TABLE, MYF(0), alias_str.str); /* purecov: tested */ |
| 8288 | DBUG_RETURN(0); /* purecov: tested */ |
| 8289 | } |
| 8290 | } |
| 8291 | } |
| 8292 | /* Store the table reference preceding the current one. */ |
| 8293 | if (table_list.elements > 0 && likely(!ptr->sequence)) |
| 8294 | { |
| 8295 | /* |
| 8296 | table_list.next points to the last inserted TABLE_LIST->next_local' |
| 8297 | element |
| 8298 | We don't use the offsetof() macro here to avoid warnings from gcc |
| 8299 | */ |
| 8300 | previous_table_ref= (TABLE_LIST*) ((char*) table_list.next - |
| 8301 | ((char*) &(ptr->next_local) - |
| 8302 | (char*) ptr)); |
| 8303 | /* |
| 8304 | Set next_name_resolution_table of the previous table reference to point |
| 8305 | to the current table reference. In effect the list |
| 8306 | TABLE_LIST::next_name_resolution_table coincides with |
| 8307 | TABLE_LIST::next_local. Later this may be changed in |
| 8308 | store_top_level_join_columns() for NATURAL/USING joins. |
| 8309 | */ |
| 8310 | previous_table_ref->next_name_resolution_table= ptr; |
| 8311 | } |
| 8312 | |
| 8313 | /* |
| 8314 | Link the current table reference in a local list (list for current select). |
| 8315 | Notice that as a side effect here we set the next_local field of the |
| 8316 | previous table reference to 'ptr'. Here we also add one element to the |
| 8317 | list 'table_list'. |
| 8318 | We don't store sequences into the local list to hide them from INSERT |
| 8319 | and SELECT. |
| 8320 | */ |
| 8321 | if (likely(!ptr->sequence)) |
| 8322 | table_list.link_in_list(ptr, &ptr->next_local); |
| 8323 | ptr->next_name_resolution_table= NULL; |
| 8324 | #ifdef WITH_PARTITION_STORAGE_ENGINE |
| 8325 | ptr->partition_names= partition_names; |
| 8326 | #endif /* WITH_PARTITION_STORAGE_ENGINE */ |
| 8327 | /* Link table in global list (all used tables) */ |
| 8328 | lex->add_to_query_tables(ptr); |
| 8329 | |
| 8330 | // Pure table aliases do not need to be locked: |
| 8331 | if (!MY_TEST(table_options & TL_OPTION_ALIAS)) |
| 8332 | { |
| 8333 | ptr->mdl_request.init(MDL_key::TABLE, ptr->db.str, ptr->table_name.str, |
| 8334 | mdl_type, |
| 8335 | MDL_TRANSACTION); |
| 8336 | } |
| 8337 | DBUG_RETURN(ptr); |
| 8338 | } |
| 8339 | |
| 8340 | |
| 8341 | /** |
| 8342 | Initialize a new table list for a nested join. |
| 8343 | |
| 8344 | The function initializes a structure of the TABLE_LIST type |
| 8345 | for a nested join. It sets up its nested join list as empty. |
| 8346 | The created structure is added to the front of the current |
| 8347 | join list in the st_select_lex object. Then the function |
| 8348 | changes the current nest level for joins to refer to the newly |
| 8349 | created empty list after having saved the info on the old level |
| 8350 | in the initialized structure. |
| 8351 | |
| 8352 | @param thd current thread |
| 8353 | |
| 8354 | @retval |
| 8355 | 0 if success |
| 8356 | @retval |
| 8357 | 1 otherwise |
| 8358 | */ |
| 8359 | |
| 8360 | bool st_select_lex::init_nested_join(THD *thd) |
| 8361 | { |
| 8362 | TABLE_LIST *ptr; |
| 8363 | NESTED_JOIN *nested_join; |
| 8364 | DBUG_ENTER("init_nested_join" ); |
| 8365 | |
| 8366 | if (unlikely(!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+ |
| 8367 | sizeof(NESTED_JOIN))))) |
| 8368 | DBUG_RETURN(1); |
| 8369 | nested_join= ptr->nested_join= |
| 8370 | ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST)))); |
| 8371 | |
| 8372 | if (unlikely(join_list->push_front(ptr, thd->mem_root))) |
| 8373 | DBUG_RETURN(1); |
| 8374 | ptr->embedding= embedding; |
| 8375 | ptr->join_list= join_list; |
| 8376 | ptr->alias.str="(nested_join)" ; |
| 8377 | ptr->alias.length= sizeof("(nested_join)" )-1; |
| 8378 | embedding= ptr; |
| 8379 | join_list= &nested_join->join_list; |
| 8380 | join_list->empty(); |
| 8381 | DBUG_RETURN(0); |
| 8382 | } |
| 8383 | |
| 8384 | |
| 8385 | /** |
| 8386 | End a nested join table list. |
| 8387 | |
| 8388 | The function returns to the previous join nest level. |
| 8389 | If the current level contains only one member, the function |
| 8390 | moves it one level up, eliminating the nest. |
| 8391 | |
| 8392 | @param thd current thread |
| 8393 | |
| 8394 | @return |
| 8395 | - Pointer to TABLE_LIST element added to the total table list, if success |
| 8396 | - 0, otherwise |
| 8397 | */ |
| 8398 | |
| 8399 | TABLE_LIST *st_select_lex::end_nested_join(THD *thd) |
| 8400 | { |
| 8401 | TABLE_LIST *ptr; |
| 8402 | NESTED_JOIN *nested_join; |
| 8403 | DBUG_ENTER("end_nested_join" ); |
| 8404 | |
| 8405 | DBUG_ASSERT(embedding); |
| 8406 | ptr= embedding; |
| 8407 | join_list= ptr->join_list; |
| 8408 | embedding= ptr->embedding; |
| 8409 | nested_join= ptr->nested_join; |
| 8410 | if (nested_join->join_list.elements == 1) |
| 8411 | { |
| 8412 | TABLE_LIST *embedded= nested_join->join_list.head(); |
| 8413 | join_list->pop(); |
| 8414 | embedded->join_list= join_list; |
| 8415 | embedded->embedding= embedding; |
| 8416 | join_list->push_front(embedded, thd->mem_root); |
| 8417 | ptr= embedded; |
| 8418 | embedded->lifted= 1; |
| 8419 | } |
| 8420 | else if (nested_join->join_list.elements == 0) |
| 8421 | { |
| 8422 | join_list->pop(); |
| 8423 | ptr= 0; // return value |
| 8424 | } |
| 8425 | DBUG_RETURN(ptr); |
| 8426 | } |
| 8427 | |
| 8428 | |
| 8429 | /** |
| 8430 | Nest last join operation. |
| 8431 | |
| 8432 | The function nest last join operation as if it was enclosed in braces. |
| 8433 | |
| 8434 | @param thd current thread |
| 8435 | |
| 8436 | @retval |
| 8437 | 0 Error |
| 8438 | @retval |
| 8439 | \# Pointer to TABLE_LIST element created for the new nested join |
| 8440 | */ |
| 8441 | |
| 8442 | TABLE_LIST *st_select_lex::nest_last_join(THD *thd) |
| 8443 | { |
| 8444 | TABLE_LIST *ptr; |
| 8445 | NESTED_JOIN *nested_join; |
| 8446 | List<TABLE_LIST> *embedded_list; |
| 8447 | DBUG_ENTER("nest_last_join" ); |
| 8448 | |
| 8449 | if (unlikely(!(ptr= (TABLE_LIST*) thd->calloc(ALIGN_SIZE(sizeof(TABLE_LIST))+ |
| 8450 | sizeof(NESTED_JOIN))))) |
| 8451 | DBUG_RETURN(0); |
| 8452 | nested_join= ptr->nested_join= |
| 8453 | ((NESTED_JOIN*) ((uchar*) ptr + ALIGN_SIZE(sizeof(TABLE_LIST)))); |
| 8454 | |
| 8455 | ptr->embedding= embedding; |
| 8456 | ptr->join_list= join_list; |
| 8457 | ptr->alias.str= "(nest_last_join)" ; |
| 8458 | ptr->alias.length= sizeof("(nest_last_join)" )-1; |
| 8459 | embedded_list= &nested_join->join_list; |
| 8460 | embedded_list->empty(); |
| 8461 | |
| 8462 | for (uint i=0; i < 2; i++) |
| 8463 | { |
| 8464 | TABLE_LIST *table= join_list->pop(); |
| 8465 | if (unlikely(!table)) |
| 8466 | DBUG_RETURN(NULL); |
| 8467 | table->join_list= embedded_list; |
| 8468 | table->embedding= ptr; |
| 8469 | embedded_list->push_back(table); |
| 8470 | if (table->natural_join) |
| 8471 | { |
| 8472 | ptr->is_natural_join= TRUE; |
| 8473 | /* |
| 8474 | If this is a JOIN ... USING, move the list of joined fields to the |
| 8475 | table reference that describes the join. |
| 8476 | */ |
| 8477 | if (prev_join_using) |
| 8478 | ptr->join_using_fields= prev_join_using; |
| 8479 | } |
| 8480 | } |
| 8481 | join_list->push_front(ptr, thd->mem_root); |
| 8482 | nested_join->used_tables= nested_join->not_null_tables= (table_map) 0; |
| 8483 | DBUG_RETURN(ptr); |
| 8484 | } |
| 8485 | |
| 8486 | |
| 8487 | /** |
| 8488 | Add a table to the current join list. |
| 8489 | |
| 8490 | The function puts a table in front of the current join list |
| 8491 | of st_select_lex object. |
| 8492 | Thus, joined tables are put into this list in the reverse order |
| 8493 | (the most outer join operation follows first). |
| 8494 | |
| 8495 | @param table the table to add |
| 8496 | |
| 8497 | @return |
| 8498 | None |
| 8499 | */ |
| 8500 | |
| 8501 | void st_select_lex::add_joined_table(TABLE_LIST *table) |
| 8502 | { |
| 8503 | DBUG_ENTER("add_joined_table" ); |
| 8504 | join_list->push_front(table, parent_lex->thd->mem_root); |
| 8505 | table->join_list= join_list; |
| 8506 | table->embedding= embedding; |
| 8507 | DBUG_VOID_RETURN; |
| 8508 | } |
| 8509 | |
| 8510 | |
| 8511 | /** |
| 8512 | Convert a right join into equivalent left join. |
| 8513 | |
| 8514 | The function takes the current join list t[0],t[1] ... and |
| 8515 | effectively converts it into the list t[1],t[0] ... |
| 8516 | Although the outer_join flag for the new nested table contains |
| 8517 | JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join |
| 8518 | operation. |
| 8519 | |
| 8520 | EXAMPLES |
| 8521 | @verbatim |
| 8522 | SELECT * FROM t1 RIGHT JOIN t2 ON on_expr => |
| 8523 | SELECT * FROM t2 LEFT JOIN t1 ON on_expr |
| 8524 | |
| 8525 | SELECT * FROM t1,t2 RIGHT JOIN t3 ON on_expr => |
| 8526 | SELECT * FROM t1,t3 LEFT JOIN t2 ON on_expr |
| 8527 | |
| 8528 | SELECT * FROM t1,t2 RIGHT JOIN (t3,t4) ON on_expr => |
| 8529 | SELECT * FROM t1,(t3,t4) LEFT JOIN t2 ON on_expr |
| 8530 | |
| 8531 | SELECT * FROM t1 LEFT JOIN t2 ON on_expr1 RIGHT JOIN t3 ON on_expr2 => |
| 8532 | SELECT * FROM t3 LEFT JOIN (t1 LEFT JOIN t2 ON on_expr2) ON on_expr1 |
| 8533 | @endverbatim |
| 8534 | |
| 8535 | @param thd current thread |
| 8536 | |
| 8537 | @return |
| 8538 | - Pointer to the table representing the inner table, if success |
| 8539 | - 0, otherwise |
| 8540 | */ |
| 8541 | |
| 8542 | TABLE_LIST *st_select_lex::convert_right_join() |
| 8543 | { |
| 8544 | TABLE_LIST *tab2= join_list->pop(); |
| 8545 | TABLE_LIST *tab1= join_list->pop(); |
| 8546 | DBUG_ENTER("convert_right_join" ); |
| 8547 | |
| 8548 | join_list->push_front(tab2, parent_lex->thd->mem_root); |
| 8549 | join_list->push_front(tab1, parent_lex->thd->mem_root); |
| 8550 | tab1->outer_join|= JOIN_TYPE_RIGHT; |
| 8551 | |
| 8552 | DBUG_RETURN(tab1); |
| 8553 | } |
| 8554 | |
| 8555 | |
| 8556 | void st_select_lex::prepare_add_window_spec(THD *thd) |
| 8557 | { |
| 8558 | LEX *lex= thd->lex; |
| 8559 | lex->save_group_list= group_list; |
| 8560 | lex->save_order_list= order_list; |
| 8561 | lex->win_ref= NULL; |
| 8562 | lex->win_frame= NULL; |
| 8563 | lex->frame_top_bound= NULL; |
| 8564 | lex->frame_bottom_bound= NULL; |
| 8565 | group_list.empty(); |
| 8566 | order_list.empty(); |
| 8567 | } |
| 8568 | |
| 8569 | bool st_select_lex::add_window_def(THD *thd, |
| 8570 | LEX_CSTRING *win_name, |
| 8571 | LEX_CSTRING *win_ref, |
| 8572 | SQL_I_List<ORDER> win_partition_list, |
| 8573 | SQL_I_List<ORDER> win_order_list, |
| 8574 | Window_frame *win_frame) |
| 8575 | { |
| 8576 | SQL_I_List<ORDER> *win_part_list_ptr= |
| 8577 | new (thd->mem_root) SQL_I_List<ORDER> (win_partition_list); |
| 8578 | SQL_I_List<ORDER> *win_order_list_ptr= |
| 8579 | new (thd->mem_root) SQL_I_List<ORDER> (win_order_list); |
| 8580 | if (!(win_part_list_ptr && win_order_list_ptr)) |
| 8581 | return true; |
| 8582 | Window_def *win_def= new (thd->mem_root) Window_def(win_name, |
| 8583 | win_ref, |
| 8584 | win_part_list_ptr, |
| 8585 | win_order_list_ptr, |
| 8586 | win_frame); |
| 8587 | group_list= thd->lex->save_group_list; |
| 8588 | order_list= thd->lex->save_order_list; |
| 8589 | return (win_def == NULL || window_specs.push_back(win_def)); |
| 8590 | } |
| 8591 | |
| 8592 | bool st_select_lex::add_window_spec(THD *thd, |
| 8593 | LEX_CSTRING *win_ref, |
| 8594 | SQL_I_List<ORDER> win_partition_list, |
| 8595 | SQL_I_List<ORDER> win_order_list, |
| 8596 | Window_frame *win_frame) |
| 8597 | { |
| 8598 | SQL_I_List<ORDER> *win_part_list_ptr= |
| 8599 | new (thd->mem_root) SQL_I_List<ORDER> (win_partition_list); |
| 8600 | SQL_I_List<ORDER> *win_order_list_ptr= |
| 8601 | new (thd->mem_root) SQL_I_List<ORDER> (win_order_list); |
| 8602 | if (!(win_part_list_ptr && win_order_list_ptr)) |
| 8603 | return true; |
| 8604 | Window_spec *win_spec= new (thd->mem_root) Window_spec(win_ref, |
| 8605 | win_part_list_ptr, |
| 8606 | win_order_list_ptr, |
| 8607 | win_frame); |
| 8608 | group_list= thd->lex->save_group_list; |
| 8609 | order_list= thd->lex->save_order_list; |
| 8610 | thd->lex->win_spec= win_spec; |
| 8611 | return (win_spec == NULL || window_specs.push_back(win_spec)); |
| 8612 | } |
| 8613 | |
| 8614 | /** |
| 8615 | Set lock for all tables in current select level. |
| 8616 | |
| 8617 | @param lock_type Lock to set for tables |
| 8618 | |
| 8619 | @note |
| 8620 | If lock is a write lock, then tables->updating is set 1 |
| 8621 | This is to get tables_ok to know that the table is updated by the |
| 8622 | query |
| 8623 | */ |
| 8624 | |
| 8625 | void st_select_lex::set_lock_for_tables(thr_lock_type lock_type) |
| 8626 | { |
| 8627 | bool for_update= lock_type >= TL_READ_NO_INSERT; |
| 8628 | DBUG_ENTER("set_lock_for_tables" ); |
| 8629 | DBUG_PRINT("enter" , ("lock_type: %d for_update: %d" , lock_type, |
| 8630 | for_update)); |
| 8631 | for (TABLE_LIST *tables= table_list.first; |
| 8632 | tables; |
| 8633 | tables= tables->next_local) |
| 8634 | { |
| 8635 | tables->lock_type= lock_type; |
| 8636 | tables->updating= for_update; |
| 8637 | tables->mdl_request.set_type((lock_type >= TL_WRITE_ALLOW_WRITE) ? |
| 8638 | MDL_SHARED_WRITE : MDL_SHARED_READ); |
| 8639 | } |
| 8640 | DBUG_VOID_RETURN; |
| 8641 | } |
| 8642 | |
| 8643 | |
| 8644 | /** |
| 8645 | Create a fake SELECT_LEX for a unit. |
| 8646 | |
| 8647 | The method create a fake SELECT_LEX object for a unit. |
| 8648 | This object is created for any union construct containing a union |
| 8649 | operation and also for any single select union construct of the form |
| 8650 | @verbatim |
| 8651 | (SELECT ... ORDER BY order_list [LIMIT n]) ORDER BY ... |
| 8652 | @endvarbatim |
| 8653 | or of the form |
| 8654 | @varbatim |
| 8655 | (SELECT ... ORDER BY LIMIT n) ORDER BY ... |
| 8656 | @endvarbatim |
| 8657 | |
| 8658 | @param thd_arg thread handle |
| 8659 | |
| 8660 | @note |
| 8661 | The object is used to retrieve rows from the temporary table |
| 8662 | where the result on the union is obtained. |
| 8663 | |
| 8664 | @retval |
| 8665 | 1 on failure to create the object |
| 8666 | @retval |
| 8667 | 0 on success |
| 8668 | */ |
| 8669 | |
| 8670 | bool st_select_lex_unit::add_fake_select_lex(THD *thd_arg) |
| 8671 | { |
| 8672 | SELECT_LEX *first_sl= first_select(); |
| 8673 | DBUG_ENTER("add_fake_select_lex" ); |
| 8674 | DBUG_ASSERT(!fake_select_lex); |
| 8675 | |
| 8676 | if (!(fake_select_lex= new (thd_arg->mem_root) SELECT_LEX())) |
| 8677 | DBUG_RETURN(1); |
| 8678 | fake_select_lex->include_standalone(this, |
| 8679 | (SELECT_LEX_NODE**)&fake_select_lex); |
| 8680 | fake_select_lex->select_number= INT_MAX; |
| 8681 | fake_select_lex->parent_lex= thd_arg->lex; /* Used in init_query. */ |
| 8682 | fake_select_lex->make_empty_select(); |
| 8683 | fake_select_lex->linkage= GLOBAL_OPTIONS_TYPE; |
| 8684 | fake_select_lex->select_limit= 0; |
| 8685 | |
| 8686 | fake_select_lex->context.outer_context=first_sl->context.outer_context; |
| 8687 | /* allow item list resolving in fake select for ORDER BY */ |
| 8688 | fake_select_lex->context.resolve_in_select_list= TRUE; |
| 8689 | fake_select_lex->context.select_lex= fake_select_lex; |
| 8690 | |
| 8691 | fake_select_lex->nest_level_base= first_select()->nest_level_base; |
| 8692 | fake_select_lex->nest_level=first_select()->nest_level; |
| 8693 | |
| 8694 | if (!is_unit_op()) |
| 8695 | { |
| 8696 | /* |
| 8697 | This works only for |
| 8698 | (SELECT ... ORDER BY list [LIMIT n]) ORDER BY order_list [LIMIT m], |
| 8699 | (SELECT ... LIMIT n) ORDER BY order_list [LIMIT m] |
| 8700 | just before the parser starts processing order_list |
| 8701 | */ |
| 8702 | fake_select_lex->no_table_names_allowed= 1; |
| 8703 | thd_arg->lex->current_select= fake_select_lex; |
| 8704 | } |
| 8705 | thd_arg->lex->pop_context(); |
| 8706 | DBUG_RETURN(0); |
| 8707 | } |
| 8708 | |
| 8709 | |
| 8710 | /** |
| 8711 | Push a new name resolution context for a JOIN ... ON clause to the |
| 8712 | context stack of a query block. |
| 8713 | |
| 8714 | Create a new name resolution context for a JOIN ... ON clause, |
| 8715 | set the first and last leaves of the list of table references |
| 8716 | to be used for name resolution, and push the newly created |
| 8717 | context to the stack of contexts of the query. |
| 8718 | |
| 8719 | @param thd pointer to current thread |
| 8720 | @param left_op left operand of the JOIN |
| 8721 | @param right_op rigth operand of the JOIN |
| 8722 | |
| 8723 | @retval |
| 8724 | FALSE if all is OK |
| 8725 | @retval |
| 8726 | TRUE if a memory allocation error occurred |
| 8727 | */ |
| 8728 | |
| 8729 | bool |
| 8730 | push_new_name_resolution_context(THD *thd, |
| 8731 | TABLE_LIST *left_op, TABLE_LIST *right_op) |
| 8732 | { |
| 8733 | Name_resolution_context *on_context; |
| 8734 | if (!(on_context= new (thd->mem_root) Name_resolution_context)) |
| 8735 | return TRUE; |
| 8736 | on_context->init(); |
| 8737 | on_context->first_name_resolution_table= |
| 8738 | left_op->first_leaf_for_name_resolution(); |
| 8739 | on_context->last_name_resolution_table= |
| 8740 | right_op->last_leaf_for_name_resolution(); |
| 8741 | return thd->lex->push_context(on_context, thd->mem_root); |
| 8742 | } |
| 8743 | |
| 8744 | |
| 8745 | /** |
| 8746 | Fix condition which contains only field (f turns to f <> 0 ) |
| 8747 | |
| 8748 | @param cond The condition to fix |
| 8749 | |
| 8750 | @return fixed condition |
| 8751 | */ |
| 8752 | |
| 8753 | Item *normalize_cond(THD *thd, Item *cond) |
| 8754 | { |
| 8755 | if (cond) |
| 8756 | { |
| 8757 | Item::Type type= cond->type(); |
| 8758 | if (type == Item::FIELD_ITEM || type == Item::REF_ITEM) |
| 8759 | { |
| 8760 | cond= new (thd->mem_root) Item_func_ne(thd, cond, new (thd->mem_root) Item_int(thd, 0)); |
| 8761 | } |
| 8762 | } |
| 8763 | return cond; |
| 8764 | } |
| 8765 | |
| 8766 | |
| 8767 | /** |
| 8768 | Add an ON condition to the second operand of a JOIN ... ON. |
| 8769 | |
| 8770 | Add an ON condition to the right operand of a JOIN ... ON clause. |
| 8771 | |
| 8772 | @param b the second operand of a JOIN ... ON |
| 8773 | @param expr the condition to be added to the ON clause |
| 8774 | |
| 8775 | @retval |
| 8776 | FALSE if there was some error |
| 8777 | @retval |
| 8778 | TRUE if all is OK |
| 8779 | */ |
| 8780 | |
| 8781 | void add_join_on(THD *thd, TABLE_LIST *b, Item *expr) |
| 8782 | { |
| 8783 | if (expr) |
| 8784 | { |
| 8785 | expr= normalize_cond(thd, expr); |
| 8786 | if (!b->on_expr) |
| 8787 | b->on_expr= expr; |
| 8788 | else |
| 8789 | { |
| 8790 | /* |
| 8791 | If called from the parser, this happens if you have both a |
| 8792 | right and left join. If called later, it happens if we add more |
| 8793 | than one condition to the ON clause. |
| 8794 | */ |
| 8795 | b->on_expr= new (thd->mem_root) Item_cond_and(thd, b->on_expr,expr); |
| 8796 | } |
| 8797 | b->on_expr->top_level_item(); |
| 8798 | } |
| 8799 | } |
| 8800 | |
| 8801 | |
| 8802 | /** |
| 8803 | Mark that there is a NATURAL JOIN or JOIN ... USING between two |
| 8804 | tables. |
| 8805 | |
| 8806 | This function marks that table b should be joined with a either via |
| 8807 | a NATURAL JOIN or via JOIN ... USING. Both join types are special |
| 8808 | cases of each other, so we treat them together. The function |
| 8809 | setup_conds() creates a list of equal condition between all fields |
| 8810 | of the same name for NATURAL JOIN or the fields in 'using_fields' |
| 8811 | for JOIN ... USING. The list of equality conditions is stored |
| 8812 | either in b->on_expr, or in JOIN::conds, depending on whether there |
| 8813 | was an outer join. |
| 8814 | |
| 8815 | EXAMPLE |
| 8816 | @verbatim |
| 8817 | SELECT * FROM t1 NATURAL LEFT JOIN t2 |
| 8818 | <=> |
| 8819 | SELECT * FROM t1 LEFT JOIN t2 ON (t1.i=t2.i and t1.j=t2.j ... ) |
| 8820 | |
| 8821 | SELECT * FROM t1 NATURAL JOIN t2 WHERE <some_cond> |
| 8822 | <=> |
| 8823 | SELECT * FROM t1, t2 WHERE (t1.i=t2.i and t1.j=t2.j and <some_cond>) |
| 8824 | |
| 8825 | SELECT * FROM t1 JOIN t2 USING(j) WHERE <some_cond> |
| 8826 | <=> |
| 8827 | SELECT * FROM t1, t2 WHERE (t1.j=t2.j and <some_cond>) |
| 8828 | @endverbatim |
| 8829 | |
| 8830 | @param a Left join argument |
| 8831 | @param b Right join argument |
| 8832 | @param using_fields Field names from USING clause |
| 8833 | */ |
| 8834 | |
| 8835 | void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields, |
| 8836 | SELECT_LEX *lex) |
| 8837 | { |
| 8838 | b->natural_join= a; |
| 8839 | lex->prev_join_using= using_fields; |
| 8840 | } |
| 8841 | |
| 8842 | |
| 8843 | /** |
| 8844 | Find a thread by id and return it, locking it LOCK_thd_kill |
| 8845 | |
| 8846 | @param id Identifier of the thread we're looking for |
| 8847 | @param query_id If true, search by query_id instead of thread_id |
| 8848 | |
| 8849 | @return NULL - not found |
| 8850 | pointer - thread found, and its LOCK_thd_kill is locked. |
| 8851 | */ |
| 8852 | |
| 8853 | THD *find_thread_by_id(longlong id, bool query_id) |
| 8854 | { |
| 8855 | THD *tmp; |
| 8856 | mysql_mutex_lock(&LOCK_thread_count); // For unlink from list |
| 8857 | I_List_iterator<THD> it(threads); |
| 8858 | while ((tmp=it++)) |
| 8859 | { |
| 8860 | if (tmp->get_command() == COM_DAEMON) |
| 8861 | continue; |
| 8862 | if (id == (query_id ? tmp->query_id : (longlong) tmp->thread_id)) |
| 8863 | { |
| 8864 | mysql_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete |
| 8865 | break; |
| 8866 | } |
| 8867 | } |
| 8868 | mysql_mutex_unlock(&LOCK_thread_count); |
| 8869 | return tmp; |
| 8870 | } |
| 8871 | |
| 8872 | |
| 8873 | /** |
| 8874 | kill one thread. |
| 8875 | |
| 8876 | @param thd Thread class |
| 8877 | @param id Thread id or query id |
| 8878 | @param kill_signal Should it kill the query or the connection |
| 8879 | @param type Type of id: thread id or query id |
| 8880 | |
| 8881 | @note |
| 8882 | This is written such that we have a short lock on LOCK_thread_count |
| 8883 | */ |
| 8884 | |
| 8885 | uint |
| 8886 | kill_one_thread(THD *thd, longlong id, killed_state kill_signal, killed_type type) |
| 8887 | { |
| 8888 | THD *tmp; |
| 8889 | uint error= (type == KILL_TYPE_QUERY ? ER_NO_SUCH_QUERY : ER_NO_SUCH_THREAD); |
| 8890 | DBUG_ENTER("kill_one_thread" ); |
| 8891 | DBUG_PRINT("enter" , ("id: %lld signal: %u" , id, (uint) kill_signal)); |
| 8892 | |
| 8893 | if (id && (tmp= find_thread_by_id(id, type == KILL_TYPE_QUERY))) |
| 8894 | { |
| 8895 | /* |
| 8896 | If we're SUPER, we can KILL anything, including system-threads. |
| 8897 | No further checks. |
| 8898 | |
| 8899 | KILLer: thd->security_ctx->user could in theory be NULL while |
| 8900 | we're still in "unauthenticated" state. This is a theoretical |
| 8901 | case (the code suggests this could happen, so we play it safe). |
| 8902 | |
| 8903 | KILLee: tmp->security_ctx->user will be NULL for system threads. |
| 8904 | We need to check so Jane Random User doesn't crash the server |
| 8905 | when trying to kill a) system threads or b) unauthenticated users' |
| 8906 | threads (Bug#43748). |
| 8907 | |
| 8908 | If user of both killer and killee are non-NULL, proceed with |
| 8909 | slayage if both are string-equal. |
| 8910 | |
| 8911 | It's ok to also kill DELAYED threads with KILL_CONNECTION instead of |
| 8912 | KILL_SYSTEM_THREAD; The difference is that KILL_CONNECTION may be |
| 8913 | faster and do a harder kill than KILL_SYSTEM_THREAD; |
| 8914 | */ |
| 8915 | |
| 8916 | if (((thd->security_ctx->master_access & SUPER_ACL) || |
| 8917 | thd->security_ctx->user_matches(tmp->security_ctx)) && |
| 8918 | !wsrep_thd_is_BF(tmp, false)) |
| 8919 | { |
| 8920 | tmp->awake_no_mutex(kill_signal); |
| 8921 | error=0; |
| 8922 | } |
| 8923 | else |
| 8924 | error= (type == KILL_TYPE_QUERY ? ER_KILL_QUERY_DENIED_ERROR : |
| 8925 | ER_KILL_DENIED_ERROR); |
| 8926 | mysql_mutex_unlock(&tmp->LOCK_thd_kill); |
| 8927 | } |
| 8928 | DBUG_PRINT("exit" , ("%d" , error)); |
| 8929 | DBUG_RETURN(error); |
| 8930 | } |
| 8931 | |
| 8932 | |
| 8933 | /** |
| 8934 | kill all threads from one user |
| 8935 | |
| 8936 | @param thd Thread class |
| 8937 | @param user_name User name for threads we should kill |
| 8938 | @param only_kill_query Should it kill the query or the connection |
| 8939 | |
| 8940 | @note |
| 8941 | This is written such that we have a short lock on LOCK_thread_count |
| 8942 | |
| 8943 | If we can't kill all threads because of security issues, no threads |
| 8944 | are killed. |
| 8945 | */ |
| 8946 | |
| 8947 | static uint kill_threads_for_user(THD *thd, LEX_USER *user, |
| 8948 | killed_state kill_signal, ha_rows *rows) |
| 8949 | { |
| 8950 | THD *tmp; |
| 8951 | List<THD> threads_to_kill; |
| 8952 | DBUG_ENTER("kill_threads_for_user" ); |
| 8953 | |
| 8954 | *rows= 0; |
| 8955 | |
| 8956 | if (unlikely(thd->is_fatal_error)) // If we run out of memory |
| 8957 | DBUG_RETURN(ER_OUT_OF_RESOURCES); |
| 8958 | |
| 8959 | DBUG_PRINT("enter" , ("user: %s signal: %u" , user->user.str, |
| 8960 | (uint) kill_signal)); |
| 8961 | |
| 8962 | mysql_mutex_lock(&LOCK_thread_count); // For unlink from list |
| 8963 | I_List_iterator<THD> it(threads); |
| 8964 | while ((tmp=it++)) |
| 8965 | { |
| 8966 | if (!tmp->security_ctx->user) |
| 8967 | continue; |
| 8968 | /* |
| 8969 | Check that hostname (if given) and user name matches. |
| 8970 | |
| 8971 | host.str[0] == '%' means that host name was not given. See sql_yacc.yy |
| 8972 | */ |
| 8973 | if (((user->host.str[0] == '%' && !user->host.str[1]) || |
| 8974 | !strcmp(tmp->security_ctx->host_or_ip, user->host.str)) && |
| 8975 | !strcmp(tmp->security_ctx->user, user->user.str)) |
| 8976 | { |
| 8977 | if (!(thd->security_ctx->master_access & SUPER_ACL) && |
| 8978 | !thd->security_ctx->user_matches(tmp->security_ctx)) |
| 8979 | { |
| 8980 | mysql_mutex_unlock(&LOCK_thread_count); |
| 8981 | DBUG_RETURN(ER_KILL_DENIED_ERROR); |
| 8982 | } |
| 8983 | if (!threads_to_kill.push_back(tmp, thd->mem_root)) |
| 8984 | mysql_mutex_lock(&tmp->LOCK_thd_kill); // Lock from delete |
| 8985 | } |
| 8986 | } |
| 8987 | mysql_mutex_unlock(&LOCK_thread_count); |
| 8988 | if (!threads_to_kill.is_empty()) |
| 8989 | { |
| 8990 | List_iterator_fast<THD> it2(threads_to_kill); |
| 8991 | THD *next_ptr; |
| 8992 | THD *ptr= it2++; |
| 8993 | do |
| 8994 | { |
| 8995 | ptr->awake_no_mutex(kill_signal); |
| 8996 | /* |
| 8997 | Careful here: The list nodes are allocated on the memroots of the |
| 8998 | THDs to be awakened. |
| 8999 | But those THDs may be terminated and deleted as soon as we release |
| 9000 | LOCK_thd_kill, which will make the list nodes invalid. |
| 9001 | Since the operation "it++" dereferences the "next" pointer of the |
| 9002 | previous list node, we need to do this while holding LOCK_thd_kill. |
| 9003 | */ |
| 9004 | next_ptr= it2++; |
| 9005 | mysql_mutex_unlock(&ptr->LOCK_thd_kill); |
| 9006 | (*rows)++; |
| 9007 | } while ((ptr= next_ptr)); |
| 9008 | } |
| 9009 | DBUG_RETURN(0); |
| 9010 | } |
| 9011 | |
| 9012 | |
| 9013 | /** |
| 9014 | kills a thread and sends response. |
| 9015 | |
| 9016 | @param thd Thread class |
| 9017 | @param id Thread id or query id |
| 9018 | @param state Should it kill the query or the connection |
| 9019 | @param type Type of id: thread id or query id |
| 9020 | */ |
| 9021 | |
| 9022 | static |
| 9023 | void sql_kill(THD *thd, longlong id, killed_state state, killed_type type) |
| 9024 | { |
| 9025 | uint error; |
| 9026 | if (likely(!(error= kill_one_thread(thd, id, state, type)))) |
| 9027 | { |
| 9028 | if (!thd->killed) |
| 9029 | my_ok(thd); |
| 9030 | else |
| 9031 | thd->send_kill_message(); |
| 9032 | } |
| 9033 | else |
| 9034 | my_error(error, MYF(0), id); |
| 9035 | } |
| 9036 | |
| 9037 | |
| 9038 | static |
| 9039 | void sql_kill_user(THD *thd, LEX_USER *user, killed_state state) |
| 9040 | { |
| 9041 | uint error; |
| 9042 | ha_rows rows; |
| 9043 | if (likely(!(error= kill_threads_for_user(thd, user, state, &rows)))) |
| 9044 | my_ok(thd, rows); |
| 9045 | else |
| 9046 | { |
| 9047 | /* |
| 9048 | This is probably ER_OUT_OF_RESOURCES, but in the future we may |
| 9049 | want to write the name of the user we tried to kill |
| 9050 | */ |
| 9051 | my_error(error, MYF(0), user->host.str, user->user.str); |
| 9052 | } |
| 9053 | } |
| 9054 | |
| 9055 | |
| 9056 | /** If pointer is not a null pointer, append filename to it. */ |
| 9057 | |
| 9058 | bool append_file_to_dir(THD *thd, const char **filename_ptr, |
| 9059 | const LEX_CSTRING *table_name) |
| 9060 | { |
| 9061 | char buff[FN_REFLEN],*ptr, *end; |
| 9062 | if (!*filename_ptr) |
| 9063 | return 0; // nothing to do |
| 9064 | |
| 9065 | /* Check that the filename is not too long and it's a hard path */ |
| 9066 | if (strlen(*filename_ptr)+table_name->length >= FN_REFLEN-1 || |
| 9067 | !test_if_hard_path(*filename_ptr)) |
| 9068 | { |
| 9069 | my_error(ER_WRONG_TABLE_NAME, MYF(0), *filename_ptr); |
| 9070 | return 1; |
| 9071 | } |
| 9072 | /* Fix is using unix filename format on dos */ |
| 9073 | strmov(buff,*filename_ptr); |
| 9074 | end=convert_dirname(buff, *filename_ptr, NullS); |
| 9075 | if (unlikely(!(ptr= (char*) thd->alloc((size_t) (end-buff) + |
| 9076 | table_name->length + 1)))) |
| 9077 | return 1; // End of memory |
| 9078 | *filename_ptr=ptr; |
| 9079 | strxmov(ptr,buff,table_name->str,NullS); |
| 9080 | return 0; |
| 9081 | } |
| 9082 | |
| 9083 | |
| 9084 | Comp_creator *comp_eq_creator(bool invert) |
| 9085 | { |
| 9086 | return invert?(Comp_creator *)&ne_creator:(Comp_creator *)&eq_creator; |
| 9087 | } |
| 9088 | |
| 9089 | |
| 9090 | Comp_creator *comp_ge_creator(bool invert) |
| 9091 | { |
| 9092 | return invert?(Comp_creator *)<_creator:(Comp_creator *)&ge_creator; |
| 9093 | } |
| 9094 | |
| 9095 | |
| 9096 | Comp_creator *comp_gt_creator(bool invert) |
| 9097 | { |
| 9098 | return invert?(Comp_creator *)&le_creator:(Comp_creator *)>_creator; |
| 9099 | } |
| 9100 | |
| 9101 | |
| 9102 | Comp_creator *comp_le_creator(bool invert) |
| 9103 | { |
| 9104 | return invert?(Comp_creator *)>_creator:(Comp_creator *)&le_creator; |
| 9105 | } |
| 9106 | |
| 9107 | |
| 9108 | Comp_creator *comp_lt_creator(bool invert) |
| 9109 | { |
| 9110 | return invert?(Comp_creator *)&ge_creator:(Comp_creator *)<_creator; |
| 9111 | } |
| 9112 | |
| 9113 | |
| 9114 | Comp_creator *comp_ne_creator(bool invert) |
| 9115 | { |
| 9116 | return invert?(Comp_creator *)&eq_creator:(Comp_creator *)&ne_creator; |
| 9117 | } |
| 9118 | |
| 9119 | |
| 9120 | /** |
| 9121 | Construct ALL/ANY/SOME subquery Item. |
| 9122 | |
| 9123 | @param left_expr pointer to left expression |
| 9124 | @param cmp compare function creator |
| 9125 | @param all true if we create ALL subquery |
| 9126 | @param select_lex pointer on parsed subquery structure |
| 9127 | |
| 9128 | @return |
| 9129 | constructed Item (or 0 if out of memory) |
| 9130 | */ |
| 9131 | Item * all_any_subquery_creator(THD *thd, Item *left_expr, |
| 9132 | chooser_compare_func_creator cmp, |
| 9133 | bool all, |
| 9134 | SELECT_LEX *select_lex) |
| 9135 | { |
| 9136 | if ((cmp == &comp_eq_creator) && !all) // = ANY <=> IN |
| 9137 | return new (thd->mem_root) Item_in_subselect(thd, left_expr, select_lex); |
| 9138 | |
| 9139 | if ((cmp == &comp_ne_creator) && all) // <> ALL <=> NOT IN |
| 9140 | return new (thd->mem_root) Item_func_not(thd, |
| 9141 | new (thd->mem_root) Item_in_subselect(thd, left_expr, select_lex)); |
| 9142 | |
| 9143 | Item_allany_subselect *it= |
| 9144 | new (thd->mem_root) Item_allany_subselect(thd, left_expr, cmp, select_lex, |
| 9145 | all); |
| 9146 | if (all) /* ALL */ |
| 9147 | return it->upper_item= new (thd->mem_root) Item_func_not_all(thd, it); |
| 9148 | |
| 9149 | /* ANY/SOME */ |
| 9150 | return it->upper_item= new (thd->mem_root) Item_func_nop_all(thd, it); |
| 9151 | } |
| 9152 | |
| 9153 | |
| 9154 | /** |
| 9155 | Multi update query pre-check. |
| 9156 | |
| 9157 | @param thd Thread handler |
| 9158 | @param tables Global/local table list (have to be the same) |
| 9159 | |
| 9160 | @retval |
| 9161 | FALSE OK |
| 9162 | @retval |
| 9163 | TRUE Error |
| 9164 | */ |
| 9165 | |
| 9166 | bool multi_update_precheck(THD *thd, TABLE_LIST *tables) |
| 9167 | { |
| 9168 | TABLE_LIST *table; |
| 9169 | LEX *lex= thd->lex; |
| 9170 | SELECT_LEX *select_lex= &lex->select_lex; |
| 9171 | DBUG_ENTER("multi_update_precheck" ); |
| 9172 | |
| 9173 | if (select_lex->item_list.elements != lex->value_list.elements) |
| 9174 | { |
| 9175 | my_message(ER_WRONG_VALUE_COUNT, ER_THD(thd, ER_WRONG_VALUE_COUNT), MYF(0)); |
| 9176 | DBUG_RETURN(TRUE); |
| 9177 | } |
| 9178 | /* |
| 9179 | Ensure that we have UPDATE or SELECT privilege for each table |
| 9180 | The exact privilege is checked in mysql_multi_update() |
| 9181 | */ |
| 9182 | for (table= tables; table; table= table->next_local) |
| 9183 | { |
| 9184 | if (table->is_jtbm()) |
| 9185 | continue; |
| 9186 | if (table->derived) |
| 9187 | table->grant.privilege= SELECT_ACL; |
| 9188 | else if ((check_access(thd, UPDATE_ACL, table->db.str, |
| 9189 | &table->grant.privilege, |
| 9190 | &table->grant.m_internal, |
| 9191 | 0, 1) || |
| 9192 | check_grant(thd, UPDATE_ACL, table, FALSE, 1, TRUE)) && |
| 9193 | (check_access(thd, SELECT_ACL, table->db.str, |
| 9194 | &table->grant.privilege, |
| 9195 | &table->grant.m_internal, |
| 9196 | 0, 0) || |
| 9197 | check_grant(thd, SELECT_ACL, table, FALSE, 1, FALSE))) |
| 9198 | DBUG_RETURN(TRUE); |
| 9199 | |
| 9200 | table->grant.orig_want_privilege= 0; |
| 9201 | table->table_in_first_from_clause= 1; |
| 9202 | } |
| 9203 | /* |
| 9204 | Is there tables of subqueries? |
| 9205 | */ |
| 9206 | if (&lex->select_lex != lex->all_selects_list) |
| 9207 | { |
| 9208 | DBUG_PRINT("info" ,("Checking sub query list" )); |
| 9209 | for (table= tables; table; table= table->next_global) |
| 9210 | { |
| 9211 | if (!table->table_in_first_from_clause) |
| 9212 | { |
| 9213 | if (check_access(thd, SELECT_ACL, table->db.str, |
| 9214 | &table->grant.privilege, |
| 9215 | &table->grant.m_internal, |
| 9216 | 0, 0) || |
| 9217 | check_grant(thd, SELECT_ACL, table, FALSE, 1, FALSE)) |
| 9218 | DBUG_RETURN(TRUE); |
| 9219 | } |
| 9220 | } |
| 9221 | } |
| 9222 | |
| 9223 | DBUG_RETURN(FALSE); |
| 9224 | } |
| 9225 | |
| 9226 | /** |
| 9227 | Multi delete query pre-check. |
| 9228 | |
| 9229 | @param thd Thread handler |
| 9230 | @param tables Global/local table list |
| 9231 | |
| 9232 | @retval |
| 9233 | FALSE OK |
| 9234 | @retval |
| 9235 | TRUE error |
| 9236 | */ |
| 9237 | |
| 9238 | bool multi_delete_precheck(THD *thd, TABLE_LIST *tables) |
| 9239 | { |
| 9240 | SELECT_LEX *select_lex= &thd->lex->select_lex; |
| 9241 | TABLE_LIST *aux_tables= thd->lex->auxiliary_table_list.first; |
| 9242 | TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last; |
| 9243 | DBUG_ENTER("multi_delete_precheck" ); |
| 9244 | |
| 9245 | /* |
| 9246 | Temporary tables are pre-opened in 'tables' list only. Here we need to |
| 9247 | initialize TABLE instances in 'aux_tables' list. |
| 9248 | */ |
| 9249 | for (TABLE_LIST *tl= aux_tables; tl; tl= tl->next_global) |
| 9250 | { |
| 9251 | if (tl->table) |
| 9252 | continue; |
| 9253 | |
| 9254 | if (tl->correspondent_table) |
| 9255 | tl->table= tl->correspondent_table->table; |
| 9256 | } |
| 9257 | |
| 9258 | /* sql_yacc guarantees that tables and aux_tables are not zero */ |
| 9259 | DBUG_ASSERT(aux_tables != 0); |
| 9260 | if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) |
| 9261 | DBUG_RETURN(TRUE); |
| 9262 | |
| 9263 | /* |
| 9264 | Since aux_tables list is not part of LEX::query_tables list we |
| 9265 | have to juggle with LEX::query_tables_own_last value to be able |
| 9266 | call check_table_access() safely. |
| 9267 | */ |
| 9268 | thd->lex->query_tables_own_last= 0; |
| 9269 | if (check_table_access(thd, DELETE_ACL, aux_tables, FALSE, UINT_MAX, FALSE)) |
| 9270 | { |
| 9271 | thd->lex->query_tables_own_last= save_query_tables_own_last; |
| 9272 | DBUG_RETURN(TRUE); |
| 9273 | } |
| 9274 | thd->lex->query_tables_own_last= save_query_tables_own_last; |
| 9275 | |
| 9276 | if ((thd->variables.option_bits & OPTION_SAFE_UPDATES) && !select_lex->where) |
| 9277 | { |
| 9278 | my_message(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, |
| 9279 | ER_THD(thd, ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE), MYF(0)); |
| 9280 | DBUG_RETURN(TRUE); |
| 9281 | } |
| 9282 | DBUG_RETURN(FALSE); |
| 9283 | } |
| 9284 | |
| 9285 | |
| 9286 | /* |
| 9287 | Given a table in the source list, find a correspondent table in the |
| 9288 | table references list. |
| 9289 | |
| 9290 | @param lex Pointer to LEX representing multi-delete. |
| 9291 | @param src Source table to match. |
| 9292 | @param ref Table references list. |
| 9293 | |
| 9294 | @remark The source table list (tables listed before the FROM clause |
| 9295 | or tables listed in the FROM clause before the USING clause) may |
| 9296 | contain table names or aliases that must match unambiguously one, |
| 9297 | and only one, table in the target table list (table references list, |
| 9298 | after FROM/USING clause). |
| 9299 | |
| 9300 | @return Matching table, NULL otherwise. |
| 9301 | */ |
| 9302 | |
| 9303 | static TABLE_LIST *multi_delete_table_match(LEX *lex, TABLE_LIST *tbl, |
| 9304 | TABLE_LIST *tables) |
| 9305 | { |
| 9306 | TABLE_LIST *match= NULL; |
| 9307 | DBUG_ENTER("multi_delete_table_match" ); |
| 9308 | |
| 9309 | for (TABLE_LIST *elem= tables; elem; elem= elem->next_local) |
| 9310 | { |
| 9311 | int res; |
| 9312 | |
| 9313 | if (tbl->is_fqtn && elem->is_alias) |
| 9314 | continue; /* no match */ |
| 9315 | if (tbl->is_fqtn && elem->is_fqtn) |
| 9316 | res= (my_strcasecmp(table_alias_charset, tbl->table_name.str, elem->table_name.str) || |
| 9317 | cmp(&tbl->db, &elem->db)); |
| 9318 | else if (elem->is_alias) |
| 9319 | res= my_strcasecmp(table_alias_charset, tbl->alias.str, elem->alias.str); |
| 9320 | else |
| 9321 | res= (my_strcasecmp(table_alias_charset, tbl->table_name.str, elem->table_name.str) || |
| 9322 | cmp(&tbl->db, &elem->db)); |
| 9323 | |
| 9324 | if (res) |
| 9325 | continue; |
| 9326 | |
| 9327 | if (match) |
| 9328 | { |
| 9329 | my_error(ER_NONUNIQ_TABLE, MYF(0), elem->alias.str); |
| 9330 | DBUG_RETURN(NULL); |
| 9331 | } |
| 9332 | |
| 9333 | match= elem; |
| 9334 | } |
| 9335 | |
| 9336 | if (!match) |
| 9337 | my_error(ER_UNKNOWN_TABLE, MYF(0), tbl->table_name.str, "MULTI DELETE" ); |
| 9338 | |
| 9339 | DBUG_RETURN(match); |
| 9340 | } |
| 9341 | |
| 9342 | |
| 9343 | /** |
| 9344 | Link tables in auxilary table list of multi-delete with corresponding |
| 9345 | elements in main table list, and set proper locks for them. |
| 9346 | |
| 9347 | @param lex pointer to LEX representing multi-delete |
| 9348 | |
| 9349 | @retval |
| 9350 | FALSE success |
| 9351 | @retval |
| 9352 | TRUE error |
| 9353 | */ |
| 9354 | |
| 9355 | bool multi_delete_set_locks_and_link_aux_tables(LEX *lex) |
| 9356 | { |
| 9357 | TABLE_LIST *tables= lex->select_lex.table_list.first; |
| 9358 | TABLE_LIST *target_tbl; |
| 9359 | DBUG_ENTER("multi_delete_set_locks_and_link_aux_tables" ); |
| 9360 | |
| 9361 | lex->table_count= 0; |
| 9362 | |
| 9363 | for (target_tbl= lex->auxiliary_table_list.first; |
| 9364 | target_tbl; target_tbl= target_tbl->next_local) |
| 9365 | { |
| 9366 | lex->table_count++; |
| 9367 | /* All tables in aux_tables must be found in FROM PART */ |
| 9368 | TABLE_LIST *walk= multi_delete_table_match(lex, target_tbl, tables); |
| 9369 | if (!walk) |
| 9370 | DBUG_RETURN(TRUE); |
| 9371 | if (!walk->derived) |
| 9372 | target_tbl->table_name= walk->table_name; |
| 9373 | walk->updating= target_tbl->updating; |
| 9374 | walk->lock_type= target_tbl->lock_type; |
| 9375 | /* We can assume that tables to be deleted from are locked for write. */ |
| 9376 | DBUG_ASSERT(walk->lock_type >= TL_WRITE_ALLOW_WRITE); |
| 9377 | walk->mdl_request.set_type(MDL_SHARED_WRITE); |
| 9378 | target_tbl->correspondent_table= walk; // Remember corresponding table |
| 9379 | } |
| 9380 | DBUG_RETURN(FALSE); |
| 9381 | } |
| 9382 | |
| 9383 | |
| 9384 | /** |
| 9385 | simple UPDATE query pre-check. |
| 9386 | |
| 9387 | @param thd Thread handler |
| 9388 | @param tables Global table list |
| 9389 | |
| 9390 | @retval |
| 9391 | FALSE OK |
| 9392 | @retval |
| 9393 | TRUE Error |
| 9394 | */ |
| 9395 | |
| 9396 | bool update_precheck(THD *thd, TABLE_LIST *tables) |
| 9397 | { |
| 9398 | DBUG_ENTER("update_precheck" ); |
| 9399 | if (thd->lex->select_lex.item_list.elements != thd->lex->value_list.elements) |
| 9400 | { |
| 9401 | my_message(ER_WRONG_VALUE_COUNT, ER_THD(thd, ER_WRONG_VALUE_COUNT), MYF(0)); |
| 9402 | DBUG_RETURN(TRUE); |
| 9403 | } |
| 9404 | DBUG_RETURN(check_one_table_access(thd, UPDATE_ACL, tables)); |
| 9405 | } |
| 9406 | |
| 9407 | |
| 9408 | /** |
| 9409 | simple DELETE query pre-check. |
| 9410 | |
| 9411 | @param thd Thread handler |
| 9412 | @param tables Global table list |
| 9413 | |
| 9414 | @retval |
| 9415 | FALSE OK |
| 9416 | @retval |
| 9417 | TRUE error |
| 9418 | */ |
| 9419 | |
| 9420 | bool delete_precheck(THD *thd, TABLE_LIST *tables) |
| 9421 | { |
| 9422 | DBUG_ENTER("delete_precheck" ); |
| 9423 | if (tables->vers_conditions.is_set()) |
| 9424 | { |
| 9425 | if (check_one_table_access(thd, DELETE_HISTORY_ACL, tables)) |
| 9426 | DBUG_RETURN(TRUE); |
| 9427 | } |
| 9428 | else |
| 9429 | { |
| 9430 | if (check_one_table_access(thd, DELETE_ACL, tables)) |
| 9431 | DBUG_RETURN(TRUE); |
| 9432 | /* Set privilege for the WHERE clause */ |
| 9433 | tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); |
| 9434 | } |
| 9435 | DBUG_RETURN(FALSE); |
| 9436 | } |
| 9437 | |
| 9438 | |
| 9439 | /** |
| 9440 | simple INSERT query pre-check. |
| 9441 | |
| 9442 | @param thd Thread handler |
| 9443 | @param tables Global table list |
| 9444 | |
| 9445 | @retval |
| 9446 | FALSE OK |
| 9447 | @retval |
| 9448 | TRUE error |
| 9449 | */ |
| 9450 | |
| 9451 | bool insert_precheck(THD *thd, TABLE_LIST *tables) |
| 9452 | { |
| 9453 | LEX *lex= thd->lex; |
| 9454 | DBUG_ENTER("insert_precheck" ); |
| 9455 | |
| 9456 | /* |
| 9457 | Check that we have modify privileges for the first table and |
| 9458 | select privileges for the rest |
| 9459 | */ |
| 9460 | ulong privilege= (INSERT_ACL | |
| 9461 | (lex->duplicates == DUP_REPLACE ? DELETE_ACL : 0) | |
| 9462 | (lex->value_list.elements ? UPDATE_ACL : 0)); |
| 9463 | |
| 9464 | if (check_one_table_access(thd, privilege, tables)) |
| 9465 | DBUG_RETURN(TRUE); |
| 9466 | |
| 9467 | if (lex->update_list.elements != lex->value_list.elements) |
| 9468 | { |
| 9469 | my_message(ER_WRONG_VALUE_COUNT, ER_THD(thd, ER_WRONG_VALUE_COUNT), MYF(0)); |
| 9470 | DBUG_RETURN(TRUE); |
| 9471 | } |
| 9472 | DBUG_RETURN(FALSE); |
| 9473 | } |
| 9474 | |
| 9475 | |
| 9476 | /** |
| 9477 | Set proper open mode and table type for element representing target table |
| 9478 | of CREATE TABLE statement, also adjust statement table list if necessary. |
| 9479 | */ |
| 9480 | |
| 9481 | void create_table_set_open_action_and_adjust_tables(LEX *lex) |
| 9482 | { |
| 9483 | TABLE_LIST *create_table= lex->query_tables; |
| 9484 | |
| 9485 | if (lex->tmp_table()) |
| 9486 | create_table->open_type= OT_TEMPORARY_ONLY; |
| 9487 | else |
| 9488 | create_table->open_type= OT_BASE_ONLY; |
| 9489 | |
| 9490 | if (!lex->select_lex.item_list.elements) |
| 9491 | { |
| 9492 | /* |
| 9493 | Avoid opening and locking target table for ordinary CREATE TABLE |
| 9494 | or CREATE TABLE LIKE for write (unlike in CREATE ... SELECT we |
| 9495 | won't do any insertions in it anyway). Not doing this causes |
| 9496 | problems when running CREATE TABLE IF NOT EXISTS for already |
| 9497 | existing log table. |
| 9498 | */ |
| 9499 | create_table->lock_type= TL_READ; |
| 9500 | } |
| 9501 | } |
| 9502 | |
| 9503 | |
| 9504 | /** |
| 9505 | CREATE TABLE query pre-check. |
| 9506 | |
| 9507 | @param thd Thread handler |
| 9508 | @param tables Global table list |
| 9509 | @param create_table Table which will be created |
| 9510 | |
| 9511 | @retval |
| 9512 | FALSE OK |
| 9513 | @retval |
| 9514 | TRUE Error |
| 9515 | */ |
| 9516 | |
| 9517 | bool create_table_precheck(THD *thd, TABLE_LIST *tables, |
| 9518 | TABLE_LIST *create_table) |
| 9519 | { |
| 9520 | LEX *lex= thd->lex; |
| 9521 | SELECT_LEX *select_lex= &lex->select_lex; |
| 9522 | ulong want_priv; |
| 9523 | bool error= TRUE; // Error message is given |
| 9524 | DBUG_ENTER("create_table_precheck" ); |
| 9525 | |
| 9526 | /* |
| 9527 | Require CREATE [TEMPORARY] privilege on new table; for |
| 9528 | CREATE TABLE ... SELECT, also require INSERT. |
| 9529 | */ |
| 9530 | |
| 9531 | want_priv= lex->tmp_table() ? CREATE_TMP_ACL : |
| 9532 | (CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0)); |
| 9533 | |
| 9534 | /* CREATE OR REPLACE on not temporary tables require DROP_ACL */ |
| 9535 | if (lex->create_info.or_replace() && !lex->tmp_table()) |
| 9536 | want_priv|= DROP_ACL; |
| 9537 | |
| 9538 | if (check_access(thd, want_priv, create_table->db.str, |
| 9539 | &create_table->grant.privilege, |
| 9540 | &create_table->grant.m_internal, |
| 9541 | 0, 0)) |
| 9542 | goto err; |
| 9543 | |
| 9544 | /* If it is a merge table, check privileges for merge children. */ |
| 9545 | if (lex->create_info.merge_list.first) |
| 9546 | { |
| 9547 | /* |
| 9548 | The user must have (SELECT_ACL | UPDATE_ACL | DELETE_ACL) on the |
| 9549 | underlying base tables, even if there are temporary tables with the same |
| 9550 | names. |
| 9551 | |
| 9552 | From user's point of view, it might look as if the user must have these |
| 9553 | privileges on temporary tables to create a merge table over them. This is |
| 9554 | one of two cases when a set of privileges is required for operations on |
| 9555 | temporary tables (see also CREATE TABLE). |
| 9556 | |
| 9557 | The reason for this behavior stems from the following facts: |
| 9558 | |
| 9559 | - For merge tables, the underlying table privileges are checked only |
| 9560 | at CREATE TABLE / ALTER TABLE time. |
| 9561 | |
| 9562 | In other words, once a merge table is created, the privileges of |
| 9563 | the underlying tables can be revoked, but the user will still have |
| 9564 | access to the merge table (provided that the user has privileges on |
| 9565 | the merge table itself). |
| 9566 | |
| 9567 | - Temporary tables shadow base tables. |
| 9568 | |
| 9569 | I.e. there might be temporary and base tables with the same name, and |
| 9570 | the temporary table takes the precedence in all operations. |
| 9571 | |
| 9572 | - For temporary MERGE tables we do not track if their child tables are |
| 9573 | base or temporary. As result we can't guarantee that privilege check |
| 9574 | which was done in presence of temporary child will stay relevant |
| 9575 | later as this temporary table might be removed. |
| 9576 | |
| 9577 | If SELECT_ACL | UPDATE_ACL | DELETE_ACL privileges were not checked for |
| 9578 | the underlying *base* tables, it would create a security breach as in |
| 9579 | Bug#12771903. |
| 9580 | */ |
| 9581 | |
| 9582 | if (check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, |
| 9583 | lex->create_info.merge_list.first, |
| 9584 | FALSE, UINT_MAX, FALSE)) |
| 9585 | goto err; |
| 9586 | } |
| 9587 | |
| 9588 | if (want_priv != CREATE_TMP_ACL && |
| 9589 | check_grant(thd, want_priv, create_table, FALSE, 1, FALSE)) |
| 9590 | goto err; |
| 9591 | |
| 9592 | if (select_lex->item_list.elements) |
| 9593 | { |
| 9594 | /* Check permissions for used tables in CREATE TABLE ... SELECT */ |
| 9595 | if (tables && check_table_access(thd, SELECT_ACL, tables, FALSE, |
| 9596 | UINT_MAX, FALSE)) |
| 9597 | goto err; |
| 9598 | } |
| 9599 | else if (lex->create_info.like()) |
| 9600 | { |
| 9601 | if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) |
| 9602 | goto err; |
| 9603 | } |
| 9604 | |
| 9605 | if (check_fk_parent_table_access(thd, &lex->create_info, &lex->alter_info, |
| 9606 | create_table->db.str)) |
| 9607 | goto err; |
| 9608 | |
| 9609 | error= FALSE; |
| 9610 | |
| 9611 | err: |
| 9612 | DBUG_RETURN(error); |
| 9613 | } |
| 9614 | |
| 9615 | |
| 9616 | /** |
| 9617 | Check privileges for LOCK TABLES statement. |
| 9618 | |
| 9619 | @param thd Thread context. |
| 9620 | @param tables List of tables to be locked. |
| 9621 | |
| 9622 | @retval FALSE - Success. |
| 9623 | @retval TRUE - Failure. |
| 9624 | */ |
| 9625 | |
| 9626 | static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables) |
| 9627 | { |
| 9628 | TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); |
| 9629 | |
| 9630 | for (TABLE_LIST *table= tables; table != first_not_own_table && table; |
| 9631 | table= table->next_global) |
| 9632 | { |
| 9633 | if (is_temporary_table(table)) |
| 9634 | continue; |
| 9635 | |
| 9636 | if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, table, |
| 9637 | FALSE, 1, FALSE)) |
| 9638 | return TRUE; |
| 9639 | } |
| 9640 | |
| 9641 | return FALSE; |
| 9642 | } |
| 9643 | |
| 9644 | |
| 9645 | /** |
| 9646 | negate given expression. |
| 9647 | |
| 9648 | @param thd thread handler |
| 9649 | @param expr expression for negation |
| 9650 | |
| 9651 | @return |
| 9652 | negated expression |
| 9653 | */ |
| 9654 | |
| 9655 | Item *negate_expression(THD *thd, Item *expr) |
| 9656 | { |
| 9657 | Item *negated; |
| 9658 | if (expr->type() == Item::FUNC_ITEM && |
| 9659 | ((Item_func *) expr)->functype() == Item_func::NOT_FUNC) |
| 9660 | { |
| 9661 | /* it is NOT(NOT( ... )) */ |
| 9662 | Item *arg= ((Item_func *) expr)->arguments()[0]; |
| 9663 | enum_parsing_place place= thd->lex->current_select->parsing_place; |
| 9664 | if (arg->is_bool_type() || place == IN_WHERE || place == IN_HAVING) |
| 9665 | return arg; |
| 9666 | /* |
| 9667 | if it is not boolean function then we have to emulate value of |
| 9668 | not(not(a)), it will be a != 0 |
| 9669 | */ |
| 9670 | return new (thd->mem_root) Item_func_ne(thd, arg, new (thd->mem_root) Item_int(thd, (char*) "0" , 0, 1)); |
| 9671 | } |
| 9672 | |
| 9673 | if ((negated= expr->neg_transformer(thd)) != 0) |
| 9674 | return negated; |
| 9675 | return new (thd->mem_root) Item_func_not(thd, expr); |
| 9676 | } |
| 9677 | |
| 9678 | /** |
| 9679 | Set the specified definer to the default value, which is the |
| 9680 | current user in the thread. |
| 9681 | |
| 9682 | @param[in] thd thread handler |
| 9683 | @param[out] definer definer |
| 9684 | */ |
| 9685 | |
| 9686 | void get_default_definer(THD *thd, LEX_USER *definer, bool role) |
| 9687 | { |
| 9688 | const Security_context *sctx= thd->security_ctx; |
| 9689 | |
| 9690 | if (role) |
| 9691 | { |
| 9692 | definer->user.str= const_cast<char*>(sctx->priv_role); |
| 9693 | definer->host= empty_clex_str; |
| 9694 | } |
| 9695 | else |
| 9696 | { |
| 9697 | definer->user.str= const_cast<char*>(sctx->priv_user); |
| 9698 | definer->host.str= const_cast<char*>(sctx->priv_host); |
| 9699 | definer->host.length= strlen(definer->host.str); |
| 9700 | } |
| 9701 | definer->user.length= strlen(definer->user.str); |
| 9702 | |
| 9703 | definer->reset_auth(); |
| 9704 | } |
| 9705 | |
| 9706 | |
| 9707 | /** |
| 9708 | Create default definer for the specified THD. |
| 9709 | |
| 9710 | @param[in] thd thread handler |
| 9711 | |
| 9712 | @return |
| 9713 | - On success, return a valid pointer to the created and initialized |
| 9714 | LEX_USER, which contains definer information. |
| 9715 | - On error, return 0. |
| 9716 | */ |
| 9717 | |
| 9718 | LEX_USER *create_default_definer(THD *thd, bool role) |
| 9719 | { |
| 9720 | LEX_USER *definer; |
| 9721 | |
| 9722 | if (unlikely(! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))) |
| 9723 | return 0; |
| 9724 | |
| 9725 | thd->get_definer(definer, role); |
| 9726 | |
| 9727 | if (role && definer->user.length == 0) |
| 9728 | { |
| 9729 | my_error(ER_MALFORMED_DEFINER, MYF(0)); |
| 9730 | return 0; |
| 9731 | } |
| 9732 | else |
| 9733 | return definer; |
| 9734 | } |
| 9735 | |
| 9736 | |
| 9737 | /** |
| 9738 | Create definer with the given user and host names. |
| 9739 | |
| 9740 | @param[in] thd thread handler |
| 9741 | @param[in] user_name user name |
| 9742 | @param[in] host_name host name |
| 9743 | |
| 9744 | @return |
| 9745 | - On success, return a valid pointer to the created and initialized |
| 9746 | LEX_USER, which contains definer information. |
| 9747 | - On error, return 0. |
| 9748 | */ |
| 9749 | |
| 9750 | LEX_USER *create_definer(THD *thd, LEX_CSTRING *user_name, |
| 9751 | LEX_CSTRING *host_name) |
| 9752 | { |
| 9753 | LEX_USER *definer; |
| 9754 | |
| 9755 | /* Create and initialize. */ |
| 9756 | |
| 9757 | if (unlikely(!(definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))) |
| 9758 | return 0; |
| 9759 | |
| 9760 | definer->user= *user_name; |
| 9761 | definer->host= *host_name; |
| 9762 | definer->reset_auth(); |
| 9763 | |
| 9764 | return definer; |
| 9765 | } |
| 9766 | |
| 9767 | |
| 9768 | /** |
| 9769 | Check that byte length of a string does not exceed some limit. |
| 9770 | |
| 9771 | @param str string to be checked |
| 9772 | @param err_msg Number of error message to be displayed if the string |
| 9773 | is too long. 0 if empty error message. |
| 9774 | @param max_length max length |
| 9775 | |
| 9776 | @retval |
| 9777 | FALSE the passed string is not longer than max_length |
| 9778 | @retval |
| 9779 | TRUE the passed string is longer than max_length |
| 9780 | |
| 9781 | NOTE |
| 9782 | The function is not used in existing code but can be useful later? |
| 9783 | */ |
| 9784 | |
| 9785 | bool check_string_byte_length(const LEX_CSTRING *str, uint err_msg, |
| 9786 | size_t max_byte_length) |
| 9787 | { |
| 9788 | if (str->length <= max_byte_length) |
| 9789 | return FALSE; |
| 9790 | |
| 9791 | my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, |
| 9792 | err_msg ? ER(err_msg) : "" , max_byte_length); |
| 9793 | |
| 9794 | return TRUE; |
| 9795 | } |
| 9796 | |
| 9797 | |
| 9798 | /* |
| 9799 | Check that char length of a string does not exceed some limit. |
| 9800 | |
| 9801 | SYNOPSIS |
| 9802 | check_string_char_length() |
| 9803 | str string to be checked |
| 9804 | err_msg Number of error message to be displayed if the string |
| 9805 | is too long. 0 if empty error message. |
| 9806 | max_char_length max length in symbols |
| 9807 | cs string charset |
| 9808 | |
| 9809 | RETURN |
| 9810 | FALSE the passed string is not longer than max_char_length |
| 9811 | TRUE the passed string is longer than max_char_length |
| 9812 | */ |
| 9813 | |
| 9814 | |
| 9815 | bool check_string_char_length(const LEX_CSTRING *str, uint err_msg, |
| 9816 | size_t max_char_length, CHARSET_INFO *cs, |
| 9817 | bool no_error) |
| 9818 | { |
| 9819 | Well_formed_prefix prefix(cs, str->str, str->length, max_char_length); |
| 9820 | if (likely(!prefix.well_formed_error_pos() && |
| 9821 | str->length == prefix.length())) |
| 9822 | return FALSE; |
| 9823 | |
| 9824 | if (!no_error) |
| 9825 | { |
| 9826 | ErrConvString err(str->str, str->length, cs); |
| 9827 | my_error(ER_WRONG_STRING_LENGTH, MYF(0), err.ptr(), |
| 9828 | err_msg ? ER(err_msg) : "" , |
| 9829 | max_char_length); |
| 9830 | } |
| 9831 | return TRUE; |
| 9832 | } |
| 9833 | |
| 9834 | |
| 9835 | bool check_ident_length(const LEX_CSTRING *ident) |
| 9836 | { |
| 9837 | if (check_string_char_length(ident, 0, NAME_CHAR_LEN, system_charset_info, 1)) |
| 9838 | { |
| 9839 | my_error(ER_TOO_LONG_IDENT, MYF(0), ident->str); |
| 9840 | return 1; |
| 9841 | } |
| 9842 | return 0; |
| 9843 | } |
| 9844 | |
| 9845 | |
| 9846 | /* |
| 9847 | Check if path does not contain mysql data home directory |
| 9848 | |
| 9849 | SYNOPSIS |
| 9850 | path_starts_from_data_home_dir() |
| 9851 | dir directory, with all symlinks resolved |
| 9852 | |
| 9853 | RETURN VALUES |
| 9854 | 0 ok |
| 9855 | 1 error ; Given path contains data directory |
| 9856 | */ |
| 9857 | extern "C" { |
| 9858 | |
| 9859 | int path_starts_from_data_home_dir(const char *path) |
| 9860 | { |
| 9861 | size_t dir_len= strlen(path); |
| 9862 | DBUG_ENTER("path_starts_from_data_home_dir" ); |
| 9863 | |
| 9864 | if (mysql_unpacked_real_data_home_len<= dir_len) |
| 9865 | { |
| 9866 | if (dir_len > mysql_unpacked_real_data_home_len && |
| 9867 | path[mysql_unpacked_real_data_home_len] != FN_LIBCHAR) |
| 9868 | DBUG_RETURN(0); |
| 9869 | |
| 9870 | if (lower_case_file_system) |
| 9871 | { |
| 9872 | if (!my_strnncoll(default_charset_info, (const uchar*) path, |
| 9873 | mysql_unpacked_real_data_home_len, |
| 9874 | (const uchar*) mysql_unpacked_real_data_home, |
| 9875 | mysql_unpacked_real_data_home_len)) |
| 9876 | { |
| 9877 | DBUG_PRINT("error" , ("Path is part of mysql_real_data_home" )); |
| 9878 | DBUG_RETURN(1); |
| 9879 | } |
| 9880 | } |
| 9881 | else if (!memcmp(path, mysql_unpacked_real_data_home, |
| 9882 | mysql_unpacked_real_data_home_len)) |
| 9883 | { |
| 9884 | DBUG_PRINT("error" , ("Path is part of mysql_real_data_home" )); |
| 9885 | DBUG_RETURN(1); |
| 9886 | } |
| 9887 | } |
| 9888 | DBUG_RETURN(0); |
| 9889 | } |
| 9890 | |
| 9891 | } |
| 9892 | |
| 9893 | /* |
| 9894 | Check if path does not contain mysql data home directory |
| 9895 | |
| 9896 | SYNOPSIS |
| 9897 | test_if_data_home_dir() |
| 9898 | dir directory |
| 9899 | |
| 9900 | RETURN VALUES |
| 9901 | 0 ok |
| 9902 | 1 error ; Given path contains data directory |
| 9903 | */ |
| 9904 | |
| 9905 | int test_if_data_home_dir(const char *dir) |
| 9906 | { |
| 9907 | char path[FN_REFLEN]; |
| 9908 | DBUG_ENTER("test_if_data_home_dir" ); |
| 9909 | |
| 9910 | if (!dir) |
| 9911 | DBUG_RETURN(0); |
| 9912 | |
| 9913 | (void) fn_format(path, dir, "" , "" , MY_RETURN_REAL_PATH); |
| 9914 | DBUG_RETURN(path_starts_from_data_home_dir(path)); |
| 9915 | } |
| 9916 | |
| 9917 | |
| 9918 | int error_if_data_home_dir(const char *path, const char *what) |
| 9919 | { |
| 9920 | size_t dirlen; |
| 9921 | char dirpath[FN_REFLEN]; |
| 9922 | if (path) |
| 9923 | { |
| 9924 | dirname_part(dirpath, path, &dirlen); |
| 9925 | if (test_if_data_home_dir(dirpath)) |
| 9926 | { |
| 9927 | my_error(ER_WRONG_ARGUMENTS, MYF(0), what); |
| 9928 | return 1; |
| 9929 | } |
| 9930 | } |
| 9931 | return 0; |
| 9932 | } |
| 9933 | |
| 9934 | /** |
| 9935 | Check that host name string is valid. |
| 9936 | |
| 9937 | @param[in] str string to be checked |
| 9938 | |
| 9939 | @return Operation status |
| 9940 | @retval FALSE host name is ok |
| 9941 | @retval TRUE host name string is longer than max_length or |
| 9942 | has invalid symbols |
| 9943 | */ |
| 9944 | |
| 9945 | bool check_host_name(LEX_CSTRING *str) |
| 9946 | { |
| 9947 | const char *name= str->str; |
| 9948 | const char *end= str->str + str->length; |
| 9949 | if (check_string_byte_length(str, ER_HOSTNAME, HOSTNAME_LENGTH)) |
| 9950 | return TRUE; |
| 9951 | |
| 9952 | while (name != end) |
| 9953 | { |
| 9954 | if (*name == '@') |
| 9955 | { |
| 9956 | my_printf_error(ER_UNKNOWN_ERROR, |
| 9957 | "Malformed hostname (illegal symbol: '%c')" , MYF(0), |
| 9958 | *name); |
| 9959 | return TRUE; |
| 9960 | } |
| 9961 | name++; |
| 9962 | } |
| 9963 | return FALSE; |
| 9964 | } |
| 9965 | |
| 9966 | |
| 9967 | extern int MYSQLparse(THD *thd); // from sql_yacc.cc |
| 9968 | extern int ORAparse(THD *thd); // from sql_yacc_ora.cc |
| 9969 | |
| 9970 | |
| 9971 | /** |
| 9972 | This is a wrapper of MYSQLparse(). All the code should call parse_sql() |
| 9973 | instead of MYSQLparse(). |
| 9974 | |
| 9975 | @param thd Thread context. |
| 9976 | @param parser_state Parser state. |
| 9977 | @param creation_ctx Object creation context. |
| 9978 | |
| 9979 | @return Error status. |
| 9980 | @retval FALSE on success. |
| 9981 | @retval TRUE on parsing error. |
| 9982 | */ |
| 9983 | |
| 9984 | bool parse_sql(THD *thd, Parser_state *parser_state, |
| 9985 | Object_creation_ctx *creation_ctx, bool do_pfs_digest) |
| 9986 | { |
| 9987 | bool ret_value; |
| 9988 | DBUG_ENTER("parse_sql" ); |
| 9989 | DBUG_ASSERT(thd->m_parser_state == NULL); |
| 9990 | DBUG_ASSERT(thd->lex->m_sql_cmd == NULL); |
| 9991 | |
| 9992 | MYSQL_QUERY_PARSE_START(thd->query()); |
| 9993 | /* Backup creation context. */ |
| 9994 | |
| 9995 | Object_creation_ctx *backup_ctx= NULL; |
| 9996 | |
| 9997 | if (creation_ctx) |
| 9998 | backup_ctx= creation_ctx->set_n_backup(thd); |
| 9999 | |
| 10000 | /* Set parser state. */ |
| 10001 | |
| 10002 | thd->m_parser_state= parser_state; |
| 10003 | |
| 10004 | parser_state->m_digest_psi= NULL; |
| 10005 | parser_state->m_lip.m_digest= NULL; |
| 10006 | |
| 10007 | if (do_pfs_digest) |
| 10008 | { |
| 10009 | /* Start Digest */ |
| 10010 | parser_state->m_digest_psi= MYSQL_DIGEST_START(thd->m_statement_psi); |
| 10011 | |
| 10012 | if (parser_state->m_input.m_compute_digest || |
| 10013 | (parser_state->m_digest_psi != NULL)) |
| 10014 | { |
| 10015 | /* |
| 10016 | If either: |
| 10017 | - the caller wants to compute a digest |
| 10018 | - the performance schema wants to compute a digest |
| 10019 | set the digest listener in the lexer. |
| 10020 | */ |
| 10021 | parser_state->m_lip.m_digest= thd->m_digest; |
| 10022 | parser_state->m_lip.m_digest->m_digest_storage.m_charset_number= thd->charset()->number; |
| 10023 | } |
| 10024 | } |
| 10025 | |
| 10026 | /* Parse the query. */ |
| 10027 | |
| 10028 | bool mysql_parse_status= |
| 10029 | ((thd->variables.sql_mode & MODE_ORACLE) ? |
| 10030 | ORAparse(thd) : |
| 10031 | MYSQLparse(thd)) != 0; |
| 10032 | |
| 10033 | /* |
| 10034 | Check that if MYSQLparse() failed either thd->is_error() is set, or an |
| 10035 | internal error handler is set. |
| 10036 | |
| 10037 | The assert will not catch a situation where parsing fails without an |
| 10038 | error reported if an error handler exists. The problem is that the |
| 10039 | error handler might have intercepted the error, so thd->is_error() is |
| 10040 | not set. However, there is no way to be 100% sure here (the error |
| 10041 | handler might be for other errors than parsing one). |
| 10042 | */ |
| 10043 | |
| 10044 | DBUG_ASSERT(!mysql_parse_status || |
| 10045 | thd->is_error() || |
| 10046 | thd->get_internal_handler()); |
| 10047 | |
| 10048 | /* Reset parser state. */ |
| 10049 | |
| 10050 | thd->m_parser_state= NULL; |
| 10051 | |
| 10052 | /* Restore creation context. */ |
| 10053 | |
| 10054 | if (creation_ctx) |
| 10055 | creation_ctx->restore_env(thd, backup_ctx); |
| 10056 | |
| 10057 | /* That's it. */ |
| 10058 | |
| 10059 | ret_value= mysql_parse_status || thd->is_fatal_error; |
| 10060 | |
| 10061 | if ((ret_value == 0) && (parser_state->m_digest_psi != NULL)) |
| 10062 | { |
| 10063 | /* |
| 10064 | On parsing success, record the digest in the performance schema. |
| 10065 | */ |
| 10066 | DBUG_ASSERT(do_pfs_digest); |
| 10067 | DBUG_ASSERT(thd->m_digest != NULL); |
| 10068 | MYSQL_DIGEST_END(parser_state->m_digest_psi, |
| 10069 | & thd->m_digest->m_digest_storage); |
| 10070 | } |
| 10071 | |
| 10072 | MYSQL_QUERY_PARSE_DONE(ret_value); |
| 10073 | DBUG_RETURN(ret_value); |
| 10074 | } |
| 10075 | |
| 10076 | /** |
| 10077 | @} (end of group Runtime_Environment) |
| 10078 | */ |
| 10079 | |
| 10080 | |
| 10081 | |
| 10082 | /** |
| 10083 | Check and merge "CHARACTER SET cs [ COLLATE cl ]" clause |
| 10084 | |
| 10085 | @param cs character set pointer. |
| 10086 | @param cl collation pointer. |
| 10087 | |
| 10088 | Check if collation "cl" is applicable to character set "cs". |
| 10089 | |
| 10090 | If "cl" is NULL (e.g. when COLLATE clause is not specified), |
| 10091 | then simply "cs" is returned. |
| 10092 | |
| 10093 | @return Error status. |
| 10094 | @retval NULL, if "cl" is not applicable to "cs". |
| 10095 | @retval pointer to merged CHARSET_INFO on success. |
| 10096 | */ |
| 10097 | |
| 10098 | |
| 10099 | CHARSET_INFO* |
| 10100 | merge_charset_and_collation(CHARSET_INFO *cs, CHARSET_INFO *cl) |
| 10101 | { |
| 10102 | if (cl) |
| 10103 | { |
| 10104 | if (!my_charset_same(cs, cl)) |
| 10105 | { |
| 10106 | my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0), cl->name, cs->csname); |
| 10107 | return NULL; |
| 10108 | } |
| 10109 | return cl; |
| 10110 | } |
| 10111 | return cs; |
| 10112 | } |
| 10113 | |
| 10114 | /** find a collation with binary comparison rules |
| 10115 | */ |
| 10116 | CHARSET_INFO *find_bin_collation(CHARSET_INFO *cs) |
| 10117 | { |
| 10118 | const char *csname= cs->csname; |
| 10119 | cs= get_charset_by_csname(csname, MY_CS_BINSORT, MYF(0)); |
| 10120 | if (!cs) |
| 10121 | { |
| 10122 | char tmp[65]; |
| 10123 | strxnmov(tmp, sizeof(tmp)-1, csname, "_bin" , NULL); |
| 10124 | my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp); |
| 10125 | } |
| 10126 | return cs; |
| 10127 | } |
| 10128 | |