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 | |