MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sql_admin.cc
1 /* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "sql_class.h" // THD
17 #include "keycaches.h" // get_key_cache
18 #include "sql_base.h" // Open_table_context
19 #include "lock.h" // MYSQL_OPEN_*
20 #include "partition_element.h" // PART_ADMIN
21 #include "sql_partition.h" // set_part_state
22 #include "transaction.h" // trans_rollback_stmt
23 #include "sql_view.h" // view_checksum
24 #include "sql_table.h" // mysql_recreate_table
25 #include "debug_sync.h" // DEBUG_SYNC
26 #include "sql_acl.h" // *_ACL
27 #include "sp.h" // Sroutine_hash_entry
28 #include "sql_parse.h" // check_table_access
29 #include "sql_admin.h"
30 
31 static int send_check_errmsg(THD *thd, TABLE_LIST* table,
32  const char* operator_name, const char* errmsg)
33 
34 {
35  Protocol *protocol= thd->protocol;
36  protocol->prepare_for_resend();
37  protocol->store(table->alias, system_charset_info);
38  protocol->store((char*) operator_name, system_charset_info);
39  protocol->store(STRING_WITH_LEN("error"), system_charset_info);
40  protocol->store(errmsg, system_charset_info);
41  thd->clear_error();
42  if (protocol->write())
43  return -1;
44  return 1;
45 }
46 
47 
48 static int prepare_for_repair(THD *thd, TABLE_LIST *table_list,
49  HA_CHECK_OPT *check_opt)
50 {
51  int error= 0;
52  TABLE tmp_table, *table;
53  TABLE_SHARE *share;
54  bool has_mdl_lock= FALSE;
55  char from[FN_REFLEN],tmp[FN_REFLEN+32];
56  const char **ext;
57  MY_STAT stat_info;
58  Open_table_context ot_ctx(thd, (MYSQL_OPEN_IGNORE_FLUSH |
59  MYSQL_OPEN_HAS_MDL_LOCK |
60  MYSQL_LOCK_IGNORE_TIMEOUT));
61  DBUG_ENTER("prepare_for_repair");
62 
63  if (!(check_opt->sql_flags & TT_USEFRM))
64  DBUG_RETURN(0);
65 
66  if (!(table= table_list->table))
67  {
68  const char *key;
69  uint key_length;
70  /*
71  If the table didn't exist, we have a shared metadata lock
72  on it that is left from mysql_admin_table()'s attempt to
73  open it. Release the shared metadata lock before trying to
74  acquire the exclusive lock to satisfy MDL asserts and avoid
75  deadlocks.
76  */
77  thd->mdl_context.release_transactional_locks();
78  /*
79  Attempt to do full-blown table open in mysql_admin_table() has failed.
80  Let us try to open at least a .FRM for this table.
81  */
82  my_hash_value_type hash_value;
83 
84  table_list->mdl_request.init(MDL_key::TABLE,
85  table_list->db, table_list->table_name,
86  MDL_EXCLUSIVE, MDL_TRANSACTION);
87 
88  if (lock_table_names(thd, table_list, table_list->next_global,
89  thd->variables.lock_wait_timeout, 0))
90  DBUG_RETURN(0);
91  has_mdl_lock= TRUE;
92 
93  key_length= get_table_def_key(table_list, &key);
94 
95  hash_value= my_calc_hash(&table_def_cache, (uchar*) key, key_length);
97  share= get_table_share(thd, table_list, key, key_length, 0,
98  &error, hash_value);
100  if (share == NULL)
101  DBUG_RETURN(0); // Can't open frm file
102 
103  if (open_table_from_share(thd, share, "", 0, 0, 0, &tmp_table, FALSE))
104  {
106  release_table_share(share);
108  DBUG_RETURN(0); // Out of memory
109  }
110  table= &tmp_table;
111  }
112 
113  /*
114  REPAIR TABLE ... USE_FRM for temporary tables makes little sense.
115  */
116  if (table->s->tmp_table)
117  {
118  error= send_check_errmsg(thd, table_list, "repair",
119  "Cannot repair temporary table from .frm file");
120  goto end;
121  }
122 
123  /*
124  User gave us USE_FRM which means that the header in the index file is
125  trashed.
126  In this case we will try to fix the table the following way:
127  - Rename the data file to a temporary name
128  - Truncate the table
129  - Replace the new data file with the old one
130  - Run a normal repair using the new index file and the old data file
131  */
132 
133  if (table->s->frm_version != FRM_VER_TRUE_VARCHAR)
134  {
135  error= send_check_errmsg(thd, table_list, "repair",
136  "Failed repairing incompatible .frm file");
137  goto end;
138  }
139 
140  /*
141  Check if this is a table type that stores index and data separately,
142  like ISAM or MyISAM. We assume fixed order of engine file name
143  extentions array. First element of engine file name extentions array
144  is meta/index file extention. Second element - data file extention.
145  */
146  ext= table->file->bas_ext();
147  if (!ext[0] || !ext[1])
148  goto end; // No data file
149 
150  /* A MERGE table must not come here. */
151  DBUG_ASSERT(table->file->ht->db_type != DB_TYPE_MRG_MYISAM);
152 
153  // Name of data file
154  strxmov(from, table->s->normalized_path.str, ext[1], NullS);
155  if (!mysql_file_stat(key_file_misc, from, &stat_info, MYF(0)))
156  goto end; // Can't use USE_FRM flag
157 
158  my_snprintf(tmp, sizeof(tmp), "%s-%lx_%lx",
159  from, current_pid, thd->thread_id);
160 
161  if (table_list->table)
162  {
163  /*
164  Table was successfully open in mysql_admin_table(). Now we need
165  to close it, but leave it protected by exclusive metadata lock.
166  */
167  if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN))
168  goto end;
169  close_all_tables_for_name(thd, table_list->table->s, false, NULL);
170  table_list->table= 0;
171  }
172  /*
173  After this point we have an exclusive metadata lock on our table
174  in both cases when table was successfully open in mysql_admin_table()
175  and when it was open in prepare_for_repair().
176  */
177 
178  if (my_rename(from, tmp, MYF(MY_WME)))
179  {
180  error= send_check_errmsg(thd, table_list, "repair",
181  "Failed renaming data file");
182  goto end;
183  }
184  if (dd_recreate_table(thd, table_list->db, table_list->table_name))
185  {
186  error= send_check_errmsg(thd, table_list, "repair",
187  "Failed generating table from .frm file");
188  goto end;
189  }
190  /*
191  'FALSE' for 'using_transactions' means don't postpone
192  invalidation till the end of a transaction, but do it
193  immediately.
194  */
195  query_cache_invalidate3(thd, table_list, FALSE);
196  if (mysql_file_rename(key_file_misc, tmp, from, MYF(MY_WME)))
197  {
198  error= send_check_errmsg(thd, table_list, "repair",
199  "Failed restoring .MYD file");
200  goto end;
201  }
202 
203  if (thd->locked_tables_list.reopen_tables(thd))
204  goto end;
205 
206  /*
207  Now we should be able to open the partially repaired table
208  to finish the repair in the handler later on.
209  */
210  if (open_table(thd, table_list, &ot_ctx))
211  {
212  error= send_check_errmsg(thd, table_list, "repair",
213  "Failed to open partially repaired table");
214  goto end;
215  }
216 
217 end:
218  thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
219  if (table == &tmp_table)
220  {
222  closefrm(table, 1); // Free allocated memory
224  }
225  /* In case of a temporary table there will be no metadata lock. */
226  if (error && has_mdl_lock)
227  thd->mdl_context.release_transactional_locks();
228 
229  DBUG_RETURN(error);
230 }
231 
232 
243 static inline bool table_not_corrupt_error(uint sql_errno)
244 {
245  return (sql_errno == ER_NO_SUCH_TABLE ||
246  sql_errno == ER_FILE_NOT_FOUND ||
247  sql_errno == ER_LOCK_WAIT_TIMEOUT ||
248  sql_errno == ER_LOCK_DEADLOCK ||
249  sql_errno == ER_CANT_LOCK_LOG_TABLE ||
250  sql_errno == ER_OPEN_AS_READONLY);
251 }
252 
253 
254 /*
255  RETURN VALUES
256  FALSE Message sent to net (admin operation went ok)
257  TRUE Message should be sent by caller
258  (admin operation or network communication failed)
259 */
260 static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
261  HA_CHECK_OPT* check_opt,
262  const char *operator_name,
263  thr_lock_type lock_type,
264  bool open_for_modify,
265  bool repair_table_use_frm,
266  uint extra_open_options,
267  int (*prepare_func)(THD *, TABLE_LIST *,
268  HA_CHECK_OPT *),
269  int (handler::*operator_func)(THD *,
270  HA_CHECK_OPT *),
271  int (view_operator_func)(THD *, TABLE_LIST*))
272 {
273  TABLE_LIST *table;
274  SELECT_LEX *select= &thd->lex->select_lex;
275  List<Item> field_list;
276  Item *item;
277  Protocol *protocol= thd->protocol;
278  LEX *lex= thd->lex;
279  int result_code;
280  DBUG_ENTER("mysql_admin_table");
281 
282  field_list.push_back(item = new Item_empty_string("Table", NAME_CHAR_LEN*2));
283  item->maybe_null = 1;
284  field_list.push_back(item = new Item_empty_string("Op", 10));
285  item->maybe_null = 1;
286  field_list.push_back(item = new Item_empty_string("Msg_type", 10));
287  item->maybe_null = 1;
288  field_list.push_back(item = new Item_empty_string("Msg_text",
289  SQL_ADMIN_MSG_TEXT_SIZE));
290  item->maybe_null = 1;
291  if (protocol->send_result_set_metadata(&field_list,
292  Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
293  DBUG_RETURN(TRUE);
294 
295  /*
296  Close all temporary tables which were pre-open to simplify
297  privilege checking. Clear all references to closed tables.
298  */
299  close_thread_tables(thd);
300  for (table= tables; table; table= table->next_local)
301  table->table= NULL;
302 
303  for (table= tables; table; table= table->next_local)
304  {
305  char table_name[NAME_LEN*2+2];
306  char* db = table->db;
307  bool fatal_error=0;
308  bool open_error;
309 
310  DBUG_PRINT("admin", ("table: '%s'.'%s'", table->db, table->table_name));
311  DBUG_PRINT("admin", ("extra_open_options: %u", extra_open_options));
312  strxmov(table_name, db, ".", table->table_name, NullS);
313  thd->open_options|= extra_open_options;
314  table->lock_type= lock_type;
315  /*
316  To make code safe for re-execution we need to reset type of MDL
317  request as code below may change it.
318  To allow concurrent execution of read-only operations we acquire
319  weak metadata lock for them.
320  */
321  table->mdl_request.set_type((lock_type >= TL_WRITE_ALLOW_WRITE) ?
322  MDL_SHARED_NO_READ_WRITE : MDL_SHARED_READ);
323  /* open only one table from local list of command */
324  {
325  TABLE_LIST *save_next_global, *save_next_local;
326  save_next_global= table->next_global;
327  table->next_global= 0;
328  save_next_local= table->next_local;
329  table->next_local= 0;
330  select->table_list.first= table;
331  /*
332  Time zone tables and SP tables can be add to lex->query_tables list,
333  so it have to be prepared.
334  TODO: Investigate if we can put extra tables into argument instead of
335  using lex->query_tables
336  */
337  lex->query_tables= table;
338  lex->query_tables_last= &table->next_global;
339  lex->query_tables_own_last= 0;
340 
341  if (view_operator_func == NULL)
342  table->required_type=FRMTYPE_TABLE;
343 
344  if (!thd->locked_tables_mode && repair_table_use_frm)
345  {
346  /*
347  If we're not under LOCK TABLES and we're executing REPAIR TABLE
348  USE_FRM, we need to ignore errors from open_and_lock_tables().
349  REPAIR TABLE USE_FRM is a heavy weapon used when a table is
350  critically damaged, so open_and_lock_tables() will most likely
351  report errors. Those errors are not interesting for the user
352  because it's already known that the table is badly damaged.
353  */
354 
355  Diagnostics_area *da= thd->get_stmt_da();
356  Warning_info tmp_wi(thd->query_id, false);
357 
358  da->push_warning_info(&tmp_wi);
359 
360  open_error= open_temporary_tables(thd, table);
361 
362  if (!open_error)
363  open_error= open_and_lock_tables(thd, table, TRUE, 0);
364 
365  da->pop_warning_info();
366  }
367  else
368  {
369  /*
370  It's assumed that even if it is REPAIR TABLE USE_FRM, the table
371  can be opened if we're under LOCK TABLES (otherwise LOCK TABLES
372  would fail). Thus, the only errors we could have from
373  open_and_lock_tables() are logical ones, like incorrect locking
374  mode. It does make sense for the user to see such errors.
375  */
376 
377  open_error= open_temporary_tables(thd, table);
378 
379  if (!open_error)
380  open_error= open_and_lock_tables(thd, table, TRUE, 0);
381  }
382 
383  table->next_global= save_next_global;
384  table->next_local= save_next_local;
385  thd->open_options&= ~extra_open_options;
386 
387  /*
388  If open_and_lock_tables() failed, close_thread_tables() will close
389  the table and table->table can therefore be invalid.
390  */
391  if (open_error)
392  table->table= NULL;
393 
394  /*
395  Under locked tables, we know that the table can be opened,
396  so any errors opening the table are logical errors.
397  In these cases it does not make sense to try to repair.
398  */
399  if (open_error && thd->locked_tables_mode)
400  {
401  result_code= HA_ADMIN_FAILED;
402  goto send_result;
403  }
404 #ifdef WITH_PARTITION_STORAGE_ENGINE
405  if (table->table)
406  {
407  /*
408  Set up which partitions that should be processed
409  if ALTER TABLE t ANALYZE/CHECK/OPTIMIZE/REPAIR PARTITION ..
410  CACHE INDEX/LOAD INDEX for specified partitions
411  */
412  Alter_info *alter_info= &lex->alter_info;
413 
414  if (alter_info->flags & Alter_info::ALTER_ADMIN_PARTITION)
415  {
416  if (!table->table->part_info)
417  {
418  my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0));
419  DBUG_RETURN(TRUE);
420  }
421 
422  if (set_part_state(alter_info, table->table->part_info, PART_ADMIN))
423  {
424  char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE];
425  size_t length;
426  DBUG_PRINT("admin", ("sending non existent partition error"));
427  protocol->prepare_for_resend();
428  protocol->store(table_name, system_charset_info);
429  protocol->store(operator_name, system_charset_info);
430  protocol->store(STRING_WITH_LEN("error"), system_charset_info);
431  length= my_snprintf(buff, sizeof(buff),
432  ER(ER_DROP_PARTITION_NON_EXISTENT),
433  table_name);
434  protocol->store(buff, length, system_charset_info);
435  if(protocol->write())
436  goto err;
437  my_eof(thd);
438  goto err;
439  }
440  }
441  }
442 #endif
443  }
444  DBUG_PRINT("admin", ("table: 0x%lx", (long) table->table));
445 
446  if (prepare_func)
447  {
448  DBUG_PRINT("admin", ("calling prepare_func"));
449  switch ((*prepare_func)(thd, table, check_opt)) {
450  case 1: // error, message written to net
451  trans_rollback_stmt(thd);
452  trans_rollback(thd);
453  /* Make sure this table instance is not reused after the operation. */
454  if (table->table)
455  table->table->m_needs_reopen= true;
456  close_thread_tables(thd);
457  thd->mdl_context.release_transactional_locks();
458  DBUG_PRINT("admin", ("simple error, admin next table"));
459  continue;
460  case -1: // error, message could be written to net
461  /* purecov: begin inspected */
462  DBUG_PRINT("admin", ("severe error, stop"));
463  goto err;
464  /* purecov: end */
465  default: // should be 0 otherwise
466  DBUG_PRINT("admin", ("prepare_func succeeded"));
467  ;
468  }
469  }
470 
471  /*
472  CHECK TABLE command is only command where VIEW allowed here and this
473  command use only temporary teble method for VIEWs resolving => there
474  can't be VIEW tree substitition of join view => if opening table
475  succeed then table->table will have real TABLE pointer as value (in
476  case of join view substitution table->table can be 0, but here it is
477  impossible)
478  */
479  if (!table->table)
480  {
481  DBUG_PRINT("admin", ("open table failed"));
482  if (thd->get_stmt_da()->is_warning_info_empty())
483  push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
484  ER_CHECK_NO_SUCH_TABLE, ER(ER_CHECK_NO_SUCH_TABLE));
485  /* if it was a view will check md5 sum */
486  if (table->view &&
487  view_checksum(thd, table) == HA_ADMIN_WRONG_CHECKSUM)
488  push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
489  ER_VIEW_CHECKSUM, ER(ER_VIEW_CHECKSUM));
490  if (thd->get_stmt_da()->is_error() &&
491  table_not_corrupt_error(thd->get_stmt_da()->sql_errno()))
492  result_code= HA_ADMIN_FAILED;
493  else
494  /* Default failure code is corrupt table */
495  result_code= HA_ADMIN_CORRUPT;
496  goto send_result;
497  }
498 
499  if (table->view)
500  {
501  DBUG_PRINT("admin", ("calling view_operator_func"));
502  result_code= (*view_operator_func)(thd, table);
503  goto send_result;
504  }
505 
506  if (table->schema_table)
507  {
508  result_code= HA_ADMIN_NOT_IMPLEMENTED;
509  goto send_result;
510  }
511 
512  if ((table->table->db_stat & HA_READ_ONLY) && open_for_modify)
513  {
514  /* purecov: begin inspected */
515  char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE];
516  size_t length;
517  enum_sql_command save_sql_command= lex->sql_command;
518  DBUG_PRINT("admin", ("sending error message"));
519  protocol->prepare_for_resend();
520  protocol->store(table_name, system_charset_info);
521  protocol->store(operator_name, system_charset_info);
522  protocol->store(STRING_WITH_LEN("error"), system_charset_info);
523  length= my_snprintf(buff, sizeof(buff), ER(ER_OPEN_AS_READONLY),
524  table_name);
525  protocol->store(buff, length, system_charset_info);
526  trans_commit_stmt(thd);
527  trans_commit(thd);
528  /* Make sure this table instance is not reused after the operation. */
529  if (table->table)
530  table->table->m_needs_reopen= true;
531  close_thread_tables(thd);
532  thd->mdl_context.release_transactional_locks();
533  lex->reset_query_tables_list(FALSE);
534  /*
535  Restore Query_tables_list::sql_command value to make statement
536  safe for re-execution.
537  */
538  lex->sql_command= save_sql_command;
539  table->table=0; // For query cache
540  if (protocol->write())
541  goto err;
542  thd->get_stmt_da()->reset_diagnostics_area();
543  continue;
544  /* purecov: end */
545  }
546 
547  /*
548  Close all instances of the table to allow MyISAM "repair"
549  to rename files.
550  @todo: This code does not close all instances of the table.
551  It only closes instances in other connections, but if this
552  connection has LOCK TABLE t1 a READ, t1 b WRITE,
553  both t1 instances will be kept open.
554  There is no need to execute this branch for InnoDB, which does
555  repair by recreate. There is no need to do it for OPTIMIZE,
556  which doesn't move files around.
557  Hence, this code should be moved to prepare_for_repair(),
558  and executed only for MyISAM engine.
559  */
560  if (lock_type == TL_WRITE && !table->table->s->tmp_table)
561  {
562  if (wait_while_table_is_used(thd, table->table,
563  HA_EXTRA_PREPARE_FOR_RENAME))
564  goto err;
565  DEBUG_SYNC(thd, "after_admin_flush");
566  /* Flush entries in the query cache involving this table. */
567  query_cache_invalidate3(thd, table->table, 0);
568  /*
569  XXX: hack: switch off open_for_modify to skip the
570  flush that is made later in the execution flow.
571  */
572  open_for_modify= 0;
573  }
574 
575  if (table->table->s->crashed && operator_func == &handler::ha_check)
576  {
577  /* purecov: begin inspected */
578  DBUG_PRINT("admin", ("sending crashed warning"));
579  protocol->prepare_for_resend();
580  protocol->store(table_name, system_charset_info);
581  protocol->store(operator_name, system_charset_info);
582  protocol->store(STRING_WITH_LEN("warning"), system_charset_info);
583  protocol->store(STRING_WITH_LEN("Table is marked as crashed"),
584  system_charset_info);
585  if (protocol->write())
586  goto err;
587  /* purecov: end */
588  }
589 
590  if (operator_func == &handler::ha_repair &&
591  !(check_opt->sql_flags & TT_USEFRM))
592  {
593  if ((table->table->file->check_old_types() == HA_ADMIN_NEEDS_ALTER) ||
594  (table->table->file->ha_check_for_upgrade(check_opt) ==
595  HA_ADMIN_NEEDS_ALTER))
596  {
597  DBUG_PRINT("admin", ("recreating table"));
598  /*
599  Temporary table are always created by current server so they never
600  require upgrade. So we don't need to pre-open them before calling
601  mysql_recreate_table().
602  */
603  DBUG_ASSERT(! table->table->s->tmp_table);
604 
605  trans_rollback_stmt(thd);
606  trans_rollback(thd);
607  /* Make sure this table instance is not reused after the operation. */
608  if (table->table)
609  table->table->m_needs_reopen= true;
610  close_thread_tables(thd);
611  thd->mdl_context.release_transactional_locks();
612 
613  /*
614  table_list->table has been closed and freed. Do not reference
615  uninitialized data. open_tables() could fail.
616  */
617  table->table= NULL;
618  /* Same applies to MDL ticket. */
619  table->mdl_request.ticket= NULL;
620 
621  tmp_disable_binlog(thd); // binlogging is done by caller if wanted
622  result_code= mysql_recreate_table(thd, table);
623  reenable_binlog(thd);
624  /*
625  mysql_recreate_table() can push OK or ERROR.
626  Clear 'OK' status. If there is an error, keep it:
627  we will store the error message in a result set row
628  and then clear.
629  */
630  if (thd->get_stmt_da()->is_ok())
631  thd->get_stmt_da()->reset_diagnostics_area();
632  table->table= NULL;
633  result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK;
634  goto send_result;
635  }
636  }
637 
638  DBUG_PRINT("admin", ("calling operator_func '%s'", operator_name));
639  result_code = (table->table->file->*operator_func)(thd, check_opt);
640  DBUG_PRINT("admin", ("operator_func returned: %d", result_code));
641 
642 send_result:
643 
644  lex->cleanup_after_one_table_open();
645  thd->clear_error(); // these errors shouldn't get client
646  {
648  thd->get_stmt_da()->sql_conditions();
649  const Sql_condition *err;
650  while ((err= it++))
651  {
652  protocol->prepare_for_resend();
653  protocol->store(table_name, system_charset_info);
654  protocol->store((char*) operator_name, system_charset_info);
655  protocol->store(warning_level_names[err->get_level()].str,
656  warning_level_names[err->get_level()].length,
657  system_charset_info);
658  protocol->store(err->get_message_text(), system_charset_info);
659  if (protocol->write())
660  goto err;
661  }
662  thd->get_stmt_da()->clear_warning_info(thd->query_id);
663  }
664  protocol->prepare_for_resend();
665  protocol->store(table_name, system_charset_info);
666  protocol->store(operator_name, system_charset_info);
667 
668 send_result_message:
669 
670  DBUG_PRINT("info", ("result_code: %d", result_code));
671  switch (result_code) {
672  case HA_ADMIN_NOT_IMPLEMENTED:
673  {
674  char buf[MYSQL_ERRMSG_SIZE];
675  size_t length=my_snprintf(buf, sizeof(buf),
676  ER(ER_CHECK_NOT_IMPLEMENTED), operator_name);
677  protocol->store(STRING_WITH_LEN("note"), system_charset_info);
678  protocol->store(buf, length, system_charset_info);
679  }
680  break;
681 
682  case HA_ADMIN_NOT_BASE_TABLE:
683  {
684  char buf[MYSQL_ERRMSG_SIZE];
685 
686  String tbl_name;
687  tbl_name.append(String(db,system_charset_info));
688  tbl_name.append('.');
689  tbl_name.append(String(table_name,system_charset_info));
690 
691  size_t length= my_snprintf(buf, sizeof(buf),
692  ER(ER_BAD_TABLE_ERROR), tbl_name.c_ptr());
693  protocol->store(STRING_WITH_LEN("note"), system_charset_info);
694  protocol->store(buf, length, system_charset_info);
695  }
696  break;
697 
698  case HA_ADMIN_OK:
699  protocol->store(STRING_WITH_LEN("status"), system_charset_info);
700  protocol->store(STRING_WITH_LEN("OK"), system_charset_info);
701  break;
702 
703  case HA_ADMIN_FAILED:
704  protocol->store(STRING_WITH_LEN("status"), system_charset_info);
705  protocol->store(STRING_WITH_LEN("Operation failed"),
706  system_charset_info);
707  break;
708 
709  case HA_ADMIN_REJECT:
710  protocol->store(STRING_WITH_LEN("status"), system_charset_info);
711  protocol->store(STRING_WITH_LEN("Operation need committed state"),
712  system_charset_info);
713  open_for_modify= FALSE;
714  break;
715 
716  case HA_ADMIN_ALREADY_DONE:
717  protocol->store(STRING_WITH_LEN("status"), system_charset_info);
718  protocol->store(STRING_WITH_LEN("Table is already up to date"),
719  system_charset_info);
720  break;
721 
722  case HA_ADMIN_CORRUPT:
723  protocol->store(STRING_WITH_LEN("error"), system_charset_info);
724  protocol->store(STRING_WITH_LEN("Corrupt"), system_charset_info);
725  fatal_error=1;
726  break;
727 
728  case HA_ADMIN_INVALID:
729  protocol->store(STRING_WITH_LEN("error"), system_charset_info);
730  protocol->store(STRING_WITH_LEN("Invalid argument"),
731  system_charset_info);
732  break;
733 
734  case HA_ADMIN_TRY_ALTER:
735  {
736  uint save_flags;
737  Alter_info *alter_info= &lex->alter_info;
738 
739  /* Store the original value of alter_info->flags */
740  save_flags= alter_info->flags;
741  /*
742  This is currently used only by InnoDB. ha_innobase::optimize() answers
743  "try with alter", so here we close the table, do an ALTER TABLE,
744  reopen the table and do ha_innobase::analyze() on it.
745  We have to end the row, so analyze could return more rows.
746  */
747  trans_commit_stmt(thd);
748  trans_commit(thd);
749  close_thread_tables(thd);
750  thd->mdl_context.release_transactional_locks();
751 
752  /*
753  table_list->table has been closed and freed. Do not reference
754  uninitialized data. open_tables() could fail.
755  */
756  table->table= NULL;
757  /* Same applies to MDL ticket. */
758  table->mdl_request.ticket= NULL;
759 
760  DEBUG_SYNC(thd, "ha_admin_try_alter");
761  protocol->store(STRING_WITH_LEN("note"), system_charset_info);
762  if(alter_info->flags & Alter_info::ALTER_ADMIN_PARTITION)
763  {
764  protocol->store(STRING_WITH_LEN(
765  "Table does not support optimize on partitions. All partitions "
766  "will be rebuilt and analyzed."),system_charset_info);
767  }
768  else
769  {
770  protocol->store(STRING_WITH_LEN(
771  "Table does not support optimize, doing recreate + analyze instead"),
772  system_charset_info);
773  }
774  if (protocol->write())
775  goto err;
776  DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze..."));
777  TABLE_LIST *save_next_local= table->next_local,
778  *save_next_global= table->next_global;
779  table->next_local= table->next_global= 0;
780  tmp_disable_binlog(thd); // binlogging is done by caller if wanted
781  /* Don't forget to pre-open temporary tables. */
782  result_code= (open_temporary_tables(thd, table) ||
783  mysql_recreate_table(thd, table));
784  reenable_binlog(thd);
785  /*
786  mysql_recreate_table() can push OK or ERROR.
787  Clear 'OK' status. If there is an error, keep it:
788  we will store the error message in a result set row
789  and then clear.
790  */
791  if (thd->get_stmt_da()->is_ok())
792  thd->get_stmt_da()->reset_diagnostics_area();
793  trans_commit_stmt(thd);
794  trans_commit(thd);
795  close_thread_tables(thd);
796  thd->mdl_context.release_transactional_locks();
797  /* Clear references to TABLE and MDL_ticket after releasing them. */
798  table->table= NULL;
799  table->mdl_request.ticket= NULL;
800  if (!result_code) // recreation went ok
801  {
802  DEBUG_SYNC(thd, "ha_admin_open_ltable");
803  table->mdl_request.set_type(MDL_SHARED_WRITE);
804  if (!open_temporary_tables(thd, table) &&
805  (table->table= open_n_lock_single_table(thd, table, lock_type, 0)))
806  {
807  /*
808  Reset the ALTER_ADMIN_PARTITION bit in alter_info->flags
809  to force analyze on all partitions.
810  */
811  alter_info->flags &= ~(Alter_info::ALTER_ADMIN_PARTITION);
812  result_code= table->table->file->ha_analyze(thd, check_opt);
813  if (result_code == HA_ADMIN_ALREADY_DONE)
814  result_code= HA_ADMIN_OK;
815  else if (result_code) // analyze failed
816  table->table->file->print_error(result_code, MYF(0));
817  alter_info->flags= save_flags;
818  }
819  else
820  result_code= -1; // open failed
821  }
822  /* Start a new row for the final status row */
823  protocol->prepare_for_resend();
824  protocol->store(table_name, system_charset_info);
825  protocol->store(operator_name, system_charset_info);
826  if (result_code) // either mysql_recreate_table or analyze failed
827  {
828  DBUG_ASSERT(thd->is_error() || thd->killed);
829  if (thd->is_error())
830  {
831  const char *err_msg= thd->get_stmt_da()->message();
832  if (!thd->vio_ok())
833  {
834  sql_print_error("%s", err_msg);
835  }
836  else
837  {
838  /* Hijack the row already in-progress. */
839  protocol->store(STRING_WITH_LEN("error"), system_charset_info);
840  protocol->store(err_msg, system_charset_info);
841  if (protocol->write())
842  goto err;
843  /* Start off another row for HA_ADMIN_FAILED */
844  protocol->prepare_for_resend();
845  protocol->store(table_name, system_charset_info);
846  protocol->store(operator_name, system_charset_info);
847  }
848  thd->clear_error();
849  }
850  /* Make sure this table instance is not reused after the operation. */
851  if (table->table)
852  table->table->m_needs_reopen= true;
853  }
854  result_code= result_code ? HA_ADMIN_FAILED : HA_ADMIN_OK;
855  table->next_local= save_next_local;
856  table->next_global= save_next_global;
857  goto send_result_message;
858  }
859  case HA_ADMIN_WRONG_CHECKSUM:
860  {
861  protocol->store(STRING_WITH_LEN("note"), system_charset_info);
862  protocol->store(ER(ER_VIEW_CHECKSUM), strlen(ER(ER_VIEW_CHECKSUM)),
863  system_charset_info);
864  break;
865  }
866 
867  case HA_ADMIN_NEEDS_UPGRADE:
868  case HA_ADMIN_NEEDS_ALTER:
869  {
870  char buf[MYSQL_ERRMSG_SIZE];
871  size_t length;
872 
873  protocol->store(STRING_WITH_LEN("error"), system_charset_info);
874  if (table->table->file->ha_table_flags() & HA_CAN_REPAIR)
875  length= my_snprintf(buf, sizeof(buf), ER(ER_TABLE_NEEDS_UPGRADE),
876  table->table_name);
877  else
878  length= my_snprintf(buf, sizeof(buf), ER(ER_TABLE_NEEDS_REBUILD),
879  table->table_name);
880  protocol->store(buf, length, system_charset_info);
881  fatal_error=1;
882  break;
883  }
884 
885  default: // Probably HA_ADMIN_INTERNAL_ERROR
886  {
887  char buf[MYSQL_ERRMSG_SIZE];
888  size_t length=my_snprintf(buf, sizeof(buf),
889  "Unknown - internal error %d during operation",
890  result_code);
891  protocol->store(STRING_WITH_LEN("error"), system_charset_info);
892  protocol->store(buf, length, system_charset_info);
893  fatal_error=1;
894  break;
895  }
896  }
897  if (table->table)
898  {
899  if (table->table->s->tmp_table)
900  {
901  /*
902  If the table was not opened successfully, do not try to get
903  status information. (Bug#47633)
904  */
905  if (open_for_modify && !open_error)
906  table->table->file->info(HA_STATUS_CONST);
907  }
908  else if (open_for_modify || fatal_error)
909  {
910  tdc_remove_table(thd, TDC_RT_REMOVE_UNUSED,
911  table->db, table->table_name, FALSE);
912  /*
913  May be something modified. Consequently, we have to
914  invalidate the query cache.
915  */
916  table->table= 0; // For query cache
917  query_cache_invalidate3(thd, table, 0);
918  }
919  }
920  /* Error path, a admin command failed. */
921  if (thd->transaction_rollback_request)
922  {
923  /*
924  Unlikely, but transaction rollback was requested by one of storage
925  engines (e.g. due to deadlock). Perform it.
926  */
927  if (trans_rollback_stmt(thd) || trans_rollback_implicit(thd))
928  goto err;
929  }
930  else
931  {
932  if (trans_commit_stmt(thd) || trans_commit_implicit(thd))
933  goto err;
934  }
935  close_thread_tables(thd);
936  thd->mdl_context.release_transactional_locks();
937 
938  /*
939  If it is CHECK TABLE v1, v2, v3, and v1, v2, v3 are views, we will run
940  separate open_tables() for each CHECK TABLE argument.
941  Right now we do not have a separate method to reset the prelocking
942  state in the lex to the state after parsing, so each open will pollute
943  this state: add elements to lex->srotuines_list, TABLE_LISTs to
944  lex->query_tables. Below is a lame attempt to recover from this
945  pollution.
946  @todo: have a method to reset a prelocking context, or use separate
947  contexts for each open.
948  */
949  for (Sroutine_hash_entry *rt=
950  (Sroutine_hash_entry*)thd->lex->sroutines_list.first;
951  rt; rt= rt->next)
952  rt->mdl_request.ticket= NULL;
953 
954  if (protocol->write())
955  goto err;
956  }
957 
958  my_eof(thd);
959  DBUG_RETURN(FALSE);
960 
961 err:
962  trans_rollback_stmt(thd);
963  trans_rollback(thd);
964  /* Make sure this table instance is not reused after the operation. */
965  if (table->table)
966  table->table->m_needs_reopen= true;
967  close_thread_tables(thd); // Shouldn't be needed
968  thd->mdl_context.release_transactional_locks();
969  DBUG_RETURN(TRUE);
970 }
971 
972 
973 /*
974  Assigned specified indexes for a table into key cache
975 
976  SYNOPSIS
977  mysql_assign_to_keycache()
978  thd Thread object
979  tables Table list (one table only)
980 
981  RETURN VALUES
982  FALSE ok
983  TRUE error
984 */
985 
986 bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables,
987  LEX_STRING *key_cache_name)
988 {
989  HA_CHECK_OPT check_opt;
990  KEY_CACHE *key_cache;
991  DBUG_ENTER("mysql_assign_to_keycache");
992 
993  check_opt.init();
994  mysql_mutex_lock(&LOCK_global_system_variables);
995  if (!(key_cache= get_key_cache(key_cache_name)))
996  {
997  mysql_mutex_unlock(&LOCK_global_system_variables);
998  my_error(ER_UNKNOWN_KEY_CACHE, MYF(0), key_cache_name->str);
999  DBUG_RETURN(TRUE);
1000  }
1001  mysql_mutex_unlock(&LOCK_global_system_variables);
1002  if (!key_cache->key_cache_inited)
1003  {
1004  my_error(ER_UNKNOWN_KEY_CACHE, MYF(0), key_cache_name->str);
1005  DBUG_RETURN(true);
1006  }
1007  check_opt.key_cache= key_cache;
1008  DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt,
1009  "assign_to_keycache", TL_READ_NO_INSERT, 0, 0,
1010  0, 0, &handler::assign_to_keycache, 0));
1011 }
1012 
1013 
1014 /*
1015  Preload specified indexes for a table into key cache
1016 
1017  SYNOPSIS
1018  mysql_preload_keys()
1019  thd Thread object
1020  tables Table list (one table only)
1021 
1022  RETURN VALUES
1023  FALSE ok
1024  TRUE error
1025 */
1026 
1027 bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
1028 {
1029  DBUG_ENTER("mysql_preload_keys");
1030  /*
1031  We cannot allow concurrent inserts. The storage engine reads
1032  directly from the index file, bypassing the cache. It could read
1033  outdated information if parallel inserts into cache blocks happen.
1034  */
1035  DBUG_RETURN(mysql_admin_table(thd, tables, 0,
1036  "preload_keys", TL_READ_NO_INSERT, 0, 0, 0, 0,
1037  &handler::preload_keys, 0));
1038 }
1039 
1040 
1042 {
1043  TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
1044  bool res= TRUE;
1045  thr_lock_type lock_type = TL_READ_NO_INSERT;
1046  DBUG_ENTER("Sql_cmd_analyze_table::execute");
1047 
1048  if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
1049  FALSE, UINT_MAX, FALSE))
1050  goto error;
1051  thd->enable_slow_log= opt_log_slow_admin_statements;
1052  res= mysql_admin_table(thd, first_table, &thd->lex->check_opt,
1053  "analyze", lock_type, 1, 0, 0, 0,
1054  &handler::ha_analyze, 0);
1055  /* ! we write after unlocking the table */
1056  if (!res && !thd->lex->no_write_to_binlog)
1057  {
1058  /*
1059  Presumably, ANALYZE and binlog writing doesn't require synchronization
1060  */
1061  res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
1062  }
1063  thd->lex->select_lex.table_list.first= first_table;
1064  thd->lex->query_tables= first_table;
1065 
1066 error:
1067  DBUG_RETURN(res);
1068 }
1069 
1070 
1072 {
1073  TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
1074  thr_lock_type lock_type = TL_READ_NO_INSERT;
1075  bool res= TRUE;
1076  DBUG_ENTER("Sql_cmd_check_table::execute");
1077 
1078  if (check_table_access(thd, SELECT_ACL, first_table,
1079  TRUE, UINT_MAX, FALSE))
1080  goto error; /* purecov: inspected */
1081  thd->enable_slow_log= opt_log_slow_admin_statements;
1082 
1083  res= mysql_admin_table(thd, first_table, &thd->lex->check_opt, "check",
1084  lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0,
1085  &handler::ha_check, &view_checksum);
1086 
1087  thd->lex->select_lex.table_list.first= first_table;
1088  thd->lex->query_tables= first_table;
1089 
1090 error:
1091  DBUG_RETURN(res);
1092 }
1093 
1094 
1096 {
1097  TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
1098  bool res= TRUE;
1099  DBUG_ENTER("Sql_cmd_optimize_table::execute");
1100 
1101  if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
1102  FALSE, UINT_MAX, FALSE))
1103  goto error; /* purecov: inspected */
1104  thd->enable_slow_log= opt_log_slow_admin_statements;
1105  res= (specialflag & SPECIAL_NO_NEW_FUNC) ?
1106  mysql_recreate_table(thd, first_table) :
1107  mysql_admin_table(thd, first_table, &thd->lex->check_opt,
1108  "optimize", TL_WRITE, 1, 0, 0, 0,
1109  &handler::ha_optimize, 0);
1110  /* ! we write after unlocking the table */
1111  if (!res && !thd->lex->no_write_to_binlog)
1112  {
1113  /*
1114  Presumably, OPTIMIZE and binlog writing doesn't require synchronization
1115  */
1116  res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
1117  }
1118  thd->lex->select_lex.table_list.first= first_table;
1119  thd->lex->query_tables= first_table;
1120 
1121 error:
1122  DBUG_RETURN(res);
1123 }
1124 
1125 
1127 {
1128  TABLE_LIST *first_table= thd->lex->select_lex.table_list.first;
1129  bool res= TRUE;
1130  DBUG_ENTER("Sql_cmd_repair_table::execute");
1131 
1132  if (check_table_access(thd, SELECT_ACL | INSERT_ACL, first_table,
1133  FALSE, UINT_MAX, FALSE))
1134  goto error; /* purecov: inspected */
1135  thd->enable_slow_log= opt_log_slow_admin_statements;
1136  res= mysql_admin_table(thd, first_table, &thd->lex->check_opt, "repair",
1137  TL_WRITE, 1,
1138  test(thd->lex->check_opt.sql_flags & TT_USEFRM),
1139  HA_OPEN_FOR_REPAIR, &prepare_for_repair,
1140  &handler::ha_repair, 0);
1141 
1142  /* ! we write after unlocking the table */
1143  if (!res && !thd->lex->no_write_to_binlog)
1144  {
1145  /*
1146  Presumably, REPAIR and binlog writing doesn't require synchronization
1147  */
1148  res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
1149  }
1150  thd->lex->select_lex.table_list.first= first_table;
1151  thd->lex->query_tables= first_table;
1152 
1153 error:
1154  DBUG_RETURN(res);
1155 }