MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
row0mysql.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 2000, 2013, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
27 #include "row0mysql.h"
28 
29 #ifdef UNIV_NONINL
30 #include "row0mysql.ic"
31 #endif
32 
33 #include <debug_sync.h>
34 #include <my_dbug.h>
35 
36 #include "row0ins.h"
37 #include "row0merge.h"
38 #include "row0sel.h"
39 #include "row0upd.h"
40 #include "row0row.h"
41 #include "que0que.h"
42 #include "pars0pars.h"
43 #include "dict0dict.h"
44 #include "dict0crea.h"
45 #include "dict0load.h"
46 #include "dict0boot.h"
47 #include "dict0stats.h"
48 #include "dict0stats_bg.h"
49 #include "trx0roll.h"
50 #include "trx0purge.h"
51 #include "trx0rec.h"
52 #include "trx0undo.h"
53 #include "lock0lock.h"
54 #include "rem0cmp.h"
55 #include "log0log.h"
56 #include "btr0sea.h"
57 #include "fil0fil.h"
58 #include "ibuf0ibuf.h"
59 #include "fts0fts.h"
60 #include "fts0types.h"
61 #include "srv0start.h"
62 #include "row0import.h"
63 #include "m_string.h"
64 #include "my_sys.h"
65 #include "ha_prototypes.h"
66 
68 UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
69 
72  char* table_name;
73  UT_LIST_NODE_T(row_mysql_drop_t)row_mysql_drop_list;
75 };
76 
77 #ifdef UNIV_PFS_MUTEX
78 /* Key to register drop list mutex with performance schema */
79 UNIV_INTERN mysql_pfs_key_t row_drop_list_mutex_key;
80 #endif /* UNIV_PFS_MUTEX */
81 
87 static UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
88 
90 static ib_mutex_t row_drop_list_mutex;
91 
93 static ibool row_mysql_drop_list_inited = FALSE;
94 
96 /* @{ */
97 static const char S_innodb_monitor[] = "innodb_monitor";
98 static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
99 static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
100 static const char S_innodb_table_monitor[] = "innodb_table_monitor";
101 #ifdef UNIV_MEM_DEBUG
102 static const char S_innodb_mem_validate[] = "innodb_mem_validate";
103 #endif /* UNIV_MEM_DEBUG */
104 /* @} */
105 
112 #define STR_EQ(str1, str1_len, str2_onstack) \
113  ((str1_len) == sizeof(str2_onstack) \
114  && memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
115 
116 /*******************************************************************/
119 static
120 ibool
121 row_mysql_is_system_table(
122 /*======================*/
123  const char* name)
124 {
125  if (strncmp(name, "mysql/", 6) != 0) {
126 
127  return(FALSE);
128  }
129 
130  return(0 == strcmp(name + 6, "host")
131  || 0 == strcmp(name + 6, "user")
132  || 0 == strcmp(name + 6, "db"));
133 }
134 
135 /*********************************************************************/
142 static
143 ibool
144 row_add_table_to_background_drop_list(
145 /*==================================*/
146  const char* name);
148 /*******************************************************************/
150 static
151 void
152 row_mysql_delay_if_needed(void)
153 /*===========================*/
154 {
155  if (srv_dml_needed_delay) {
156  os_thread_sleep(srv_dml_needed_delay);
157  }
158 }
159 
160 /*******************************************************************/
162 UNIV_INTERN
163 void
165 /*==============================*/
166  row_prebuilt_t* prebuilt)
168 {
169  mem_heap_free(prebuilt->blob_heap);
170  prebuilt->blob_heap = NULL;
171 }
172 
173 /*******************************************************************/
178 UNIV_INTERN
179 byte*
181 /*=========================*/
182  byte* dest,
183  ulint len,
184  ulint lenlen)
185 {
186  if (lenlen == 2) {
187  ut_a(len < 256 * 256);
188 
190 
191  return(dest + 2);
192  }
193 
194  ut_a(lenlen == 1);
195  ut_a(len < 256);
196 
197  mach_write_to_1(dest, len);
198 
199  return(dest + 1);
200 }
201 
202 /*******************************************************************/
207 UNIV_INTERN
208 const byte*
210 /*========================*/
211  ulint* len,
212  const byte* field,
213  ulint lenlen)
215 {
216  if (lenlen == 2) {
217  *len = mach_read_from_2_little_endian(field);
218 
219  return(field + 2);
220  }
221 
222  ut_a(lenlen == 1);
223 
224  *len = mach_read_from_1(field);
225 
226  return(field + 1);
227 }
228 
229 /*******************************************************************/
231 UNIV_INTERN
232 void
234 /*=====================*/
235  byte* dest,
236  ulint col_len,
240  const void* data,
242  ulint len)
246 {
247  /* MySQL might assume the field is set to zero except the length and
248  the pointer fields */
249 
250  memset(dest, '\0', col_len);
251 
252  /* In dest there are 1 - 4 bytes reserved for the BLOB length,
253  and after that 8 bytes reserved for the pointer to the data.
254  In 32-bit architectures we only use the first 4 bytes of the pointer
255  slot. */
256 
257  ut_a(col_len - 8 > 1 || len < 256);
258  ut_a(col_len - 8 > 2 || len < 256 * 256);
259  ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
260 
261  mach_write_to_n_little_endian(dest, col_len - 8, len);
262 
263  memcpy(dest + col_len - 8, &data, sizeof data);
264 }
265 
266 /*******************************************************************/
269 UNIV_INTERN
270 const byte*
272 /*====================*/
273  ulint* len,
274  const byte* ref,
276  ulint col_len)
278 {
279  byte* data;
280 
281  *len = mach_read_from_n_little_endian(ref, col_len - 8);
282 
283  memcpy(&data, ref + col_len - 8, sizeof data);
284 
285  return(data);
286 }
287 
288 /**************************************************************/
290 UNIV_INTERN
291 void
293 /*==============*/
294  ulint mbminlen,
296  byte* pad,
297  ulint len)
298 {
299  const byte* pad_end;
300 
301  switch (UNIV_EXPECT(mbminlen, 1)) {
302  default:
303  ut_error;
304  case 1:
305  /* space=0x20 */
306  memset(pad, 0x20, len);
307  break;
308  case 2:
309  /* space=0x0020 */
310  pad_end = pad + len;
311  ut_a(!(len % 2));
312  while (pad < pad_end) {
313  *pad++ = 0x00;
314  *pad++ = 0x20;
315  };
316  break;
317  case 4:
318  /* space=0x00000020 */
319  pad_end = pad + len;
320  ut_a(!(len % 4));
321  while (pad < pad_end) {
322  *pad++ = 0x00;
323  *pad++ = 0x00;
324  *pad++ = 0x00;
325  *pad++ = 0x20;
326  }
327  break;
328  }
329 }
330 
331 /**************************************************************/
336 UNIV_INTERN
337 byte*
339 /*===================================*/
340  dfield_t* dfield,
343  byte* buf,
349  ibool row_format_col,
356  const byte* mysql_data,
361  ulint col_len,
367  ulint comp)
368 {
369  const byte* ptr = mysql_data;
370  const dtype_t* dtype;
371  ulint type;
372  ulint lenlen;
373 
374  dtype = dfield_get_type(dfield);
375 
376  type = dtype->mtype;
377 
378  if (type == DATA_INT) {
379  /* Store integer data in Innobase in a big-endian format,
380  sign bit negated if the data is a signed integer. In MySQL,
381  integers are stored in a little-endian format. */
382 
383  byte* p = buf + col_len;
384 
385  for (;;) {
386  p--;
387  *p = *mysql_data;
388  if (p == buf) {
389  break;
390  }
391  mysql_data++;
392  }
393 
394  if (!(dtype->prtype & DATA_UNSIGNED)) {
395 
396  *buf ^= 128;
397  }
398 
399  ptr = buf;
400  buf += col_len;
401  } else if ((type == DATA_VARCHAR
402  || type == DATA_VARMYSQL
403  || type == DATA_BINARY)) {
404 
405  if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
406  /* The length of the actual data is stored to 1 or 2
407  bytes at the start of the field */
408 
409  if (row_format_col) {
410  if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
411  lenlen = 2;
412  } else {
413  lenlen = 1;
414  }
415  } else {
416  /* In a MySQL key value, lenlen is always 2 */
417  lenlen = 2;
418  }
419 
420  ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
421  lenlen);
422  } else {
423  /* Remove trailing spaces from old style VARCHAR
424  columns. */
425 
426  /* Handle Unicode strings differently. */
427  ulint mbminlen = dtype_get_mbminlen(dtype);
428 
429  ptr = mysql_data;
430 
431  switch (mbminlen) {
432  default:
433  ut_error;
434  case 4:
435  /* space=0x00000020 */
436  /* Trim "half-chars", just in case. */
437  col_len &= ~3;
438 
439  while (col_len >= 4
440  && ptr[col_len - 4] == 0x00
441  && ptr[col_len - 3] == 0x00
442  && ptr[col_len - 2] == 0x00
443  && ptr[col_len - 1] == 0x20) {
444  col_len -= 4;
445  }
446  break;
447  case 2:
448  /* space=0x0020 */
449  /* Trim "half-chars", just in case. */
450  col_len &= ~1;
451 
452  while (col_len >= 2 && ptr[col_len - 2] == 0x00
453  && ptr[col_len - 1] == 0x20) {
454  col_len -= 2;
455  }
456  break;
457  case 1:
458  /* space=0x20 */
459  while (col_len > 0
460  && ptr[col_len - 1] == 0x20) {
461  col_len--;
462  }
463  }
464  }
465  } else if (comp && type == DATA_MYSQL
466  && dtype_get_mbminlen(dtype) == 1
467  && dtype_get_mbmaxlen(dtype) > 1) {
468  /* In some cases we strip trailing spaces from UTF-8 and other
469  multibyte charsets, from FIXED-length CHAR columns, to save
470  space. UTF-8 would otherwise normally use 3 * the string length
471  bytes to store an ASCII string! */
472 
473  /* We assume that this CHAR field is encoded in a
474  variable-length character set where spaces have
475  1:1 correspondence to 0x20 bytes, such as UTF-8.
476 
477  Consider a CHAR(n) field, a field of n characters.
478  It will contain between n * mbminlen and n * mbmaxlen bytes.
479  We will try to truncate it to n bytes by stripping
480  space padding. If the field contains single-byte
481  characters only, it will be truncated to n characters.
482  Consider a CHAR(5) field containing the string ".a "
483  where "." denotes a 3-byte character represented by
484  the bytes "$%&". After our stripping, the string will
485  be stored as "$%&a " (5 bytes). The string ".abc "
486  will be stored as "$%&abc" (6 bytes).
487 
488  The space padding will be restored in row0sel.cc, function
489  row_sel_field_store_in_mysql_format(). */
490 
491  ulint n_chars;
492 
493  ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
494 
495  n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
496 
497  /* Strip space padding. */
498  while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
499  col_len--;
500  }
501  } else if (type == DATA_BLOB && row_format_col) {
502 
503  ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
504  }
505 
506  dfield_set_data(dfield, ptr, col_len);
507 
508  return(buf);
509 }
510 
511 /**************************************************************/
515 static
516 void
517 row_mysql_convert_row_to_innobase(
518 /*==============================*/
519  dtuple_t* row,
522  row_prebuilt_t* prebuilt,
524  byte* mysql_rec)
528 {
529  const mysql_row_templ_t*templ;
530  dfield_t* dfield;
531  ulint i;
532 
533  ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
534  ut_ad(prebuilt->mysql_template);
535 
536  for (i = 0; i < prebuilt->n_template; i++) {
537 
538  templ = prebuilt->mysql_template + i;
539  dfield = dtuple_get_nth_field(row, i);
540 
541  if (templ->mysql_null_bit_mask != 0) {
542  /* Column may be SQL NULL */
543 
544  if (mysql_rec[templ->mysql_null_byte_offset]
545  & (byte) (templ->mysql_null_bit_mask)) {
546 
547  /* It is SQL NULL */
548 
549  dfield_set_null(dfield);
550 
551  goto next_column;
552  }
553  }
554 
556  dfield,
557  prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
558  TRUE, /* MySQL row format data */
559  mysql_rec + templ->mysql_col_offset,
560  templ->mysql_col_len,
561  dict_table_is_comp(prebuilt->table));
562 next_column:
563  ;
564  }
565 
566  /* If there is a FTS doc id column and it is not user supplied (
567  generated by server) then assign it a new doc id. */
568  if (prebuilt->table->fts) {
569 
570  ut_a(prebuilt->table->fts->doc_col != ULINT_UNDEFINED);
571 
572  fts_create_doc_id(prebuilt->table, row, prebuilt->heap);
573  }
574 }
575 
576 /****************************************************************/
580 UNIV_INTERN
581 bool
583 /*====================*/
584  dberr_t* new_err,
588  trx_t* trx,
589  que_thr_t* thr,
590  trx_savept_t* savept)
591 {
592  dberr_t err;
593 
594 handle_new_error:
595  err = trx->error_state;
596 
597  ut_a(err != DB_SUCCESS);
598 
599  trx->error_state = DB_SUCCESS;
600 
601  switch (err) {
604  trx_rollback_to_savepoint(trx, NULL);
605  break;
606  }
607  /* fall through */
608  case DB_DUPLICATE_KEY:
610  case DB_TOO_BIG_RECORD:
616  case DB_OUT_OF_FILE_SPACE:
617  case DB_READ_ONLY:
618  case DB_FTS_INVALID_DOCID:
619  case DB_INTERRUPTED:
620  case DB_DICT_CHANGED:
621  if (savept) {
622  /* Roll back the latest, possibly incomplete insertion
623  or update */
624 
625  trx_rollback_to_savepoint(trx, savept);
626  }
627  /* MySQL will roll back the latest SQL statement */
628  break;
629  case DB_LOCK_WAIT:
631 
632  if (trx->error_state != DB_SUCCESS) {
634 
635  goto handle_new_error;
636  }
637 
638  *new_err = err;
639 
640  return(true);
641 
642  case DB_DEADLOCK:
643  case DB_LOCK_TABLE_FULL:
644  /* Roll back the whole transaction; this resolution was added
645  to version 3.23.43 */
646 
647  trx_rollback_to_savepoint(trx, NULL);
648  break;
649 
651  fputs("InnoDB: The database cannot continue"
652  " operation because of\n"
653  "InnoDB: lack of space. You must add"
654  " a new data file to\n"
655  "InnoDB: my.cnf and restart the database.\n", stderr);
656 
657  ut_ad(0);
658  exit(1);
659 
660  case DB_CORRUPTION:
661  fputs("InnoDB: We detected index corruption"
662  " in an InnoDB type table.\n"
663  "InnoDB: You have to dump + drop + reimport"
664  " the table or, in\n"
665  "InnoDB: a case of widespread corruption,"
666  " dump all InnoDB\n"
667  "InnoDB: tables and recreate the"
668  " whole InnoDB tablespace.\n"
669  "InnoDB: If the mysqld server crashes"
670  " after the startup or when\n"
671  "InnoDB: you dump the tables, look at\n"
672  "InnoDB: " REFMAN "forcing-innodb-recovery.html"
673  " for help.\n", stderr);
674  break;
676  fprintf(stderr, "InnoDB: Cannot delete/update rows with"
677  " cascading foreign key constraints that exceed max"
678  " depth of %lu\n"
679  "Please drop excessive foreign constraints"
680  " and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
681  break;
682  default:
683  fprintf(stderr, "InnoDB: unknown error code %lu\n",
684  (ulong) err);
685  ut_error;
686  }
687 
688  if (trx->error_state != DB_SUCCESS) {
689  *new_err = trx->error_state;
690  } else {
691  *new_err = err;
692  }
693 
694  trx->error_state = DB_SUCCESS;
695 
696  return(false);
697 }
698 
699 /********************************************************************/
702 UNIV_INTERN
705 /*================*/
707  ulint mysql_row_len)
709 {
710  row_prebuilt_t* prebuilt;
711  mem_heap_t* heap;
712  dict_index_t* clust_index;
713  dtuple_t* ref;
714  ulint ref_len;
715  ulint search_tuple_n_fields;
716 
717  search_tuple_n_fields = 2 * dict_table_get_n_cols(table);
718 
719  clust_index = dict_table_get_first_index(table);
720 
721  /* Make sure that search_tuple is long enough for clustered index */
722  ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
723 
724  ref_len = dict_index_get_n_unique(clust_index);
725 
726 #define PREBUILT_HEAP_INITIAL_SIZE \
727  ( \
728  sizeof(*prebuilt) \
729  /* allocd in this function */ \
730  + DTUPLE_EST_ALLOC(search_tuple_n_fields) \
731  + DTUPLE_EST_ALLOC(ref_len) \
732  /* allocd in row_prebuild_sel_graph() */ \
733  + sizeof(sel_node_t) \
734  + sizeof(que_fork_t) \
735  + sizeof(que_thr_t) \
736  /* allocd in row_get_prebuilt_update_vector() */ \
737  + sizeof(upd_node_t) \
738  + sizeof(upd_t) \
739  + sizeof(upd_field_t) \
740  * dict_table_get_n_cols(table) \
741  + sizeof(que_fork_t) \
742  + sizeof(que_thr_t) \
743  /* allocd in row_get_prebuilt_insert_row() */ \
744  + sizeof(ins_node_t) \
745  /* mysql_row_len could be huge and we are not \
746  sure if this prebuilt instance is going to be \
747  used in inserts */ \
748  + (mysql_row_len < 256 ? mysql_row_len : 0) \
749  + DTUPLE_EST_ALLOC(dict_table_get_n_cols(table)) \
750  + sizeof(que_fork_t) \
751  + sizeof(que_thr_t) \
752  )
753 
754  /* We allocate enough space for the objects that are likely to
755  be created later in order to minimize the number of malloc()
756  calls */
757  heap = mem_heap_create(PREBUILT_HEAP_INITIAL_SIZE);
758 
759  prebuilt = static_cast<row_prebuilt_t*>(
760  mem_heap_zalloc(heap, sizeof(*prebuilt)));
761 
762  prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
763  prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
764 
765  prebuilt->table = table;
766 
767  prebuilt->sql_stat_start = TRUE;
768  prebuilt->heap = heap;
769 
770  btr_pcur_reset(&prebuilt->pcur);
771  btr_pcur_reset(&prebuilt->clust_pcur);
772 
773  prebuilt->select_lock_type = LOCK_NONE;
774  prebuilt->stored_select_lock_type = LOCK_NONE_UNSET;
775 
776  prebuilt->search_tuple = dtuple_create(heap, search_tuple_n_fields);
777 
778  ref = dtuple_create(heap, ref_len);
779 
780  dict_index_copy_types(ref, clust_index, ref_len);
781 
782  prebuilt->clust_ref = ref;
783 
784  prebuilt->autoinc_error = DB_SUCCESS;
785  prebuilt->autoinc_offset = 0;
786 
787  /* Default to 1, we will set the actual value later in
788  ha_innobase::get_auto_increment(). */
789  prebuilt->autoinc_increment = 1;
790 
791  prebuilt->autoinc_last_value = 0;
792 
793  /* During UPDATE and DELETE we need the doc id. */
794  prebuilt->fts_doc_id = 0;
795 
796  prebuilt->mysql_row_len = mysql_row_len;
797 
798  return(prebuilt);
799 }
800 
801 /********************************************************************/
803 UNIV_INTERN
804 void
806 /*==============*/
807  row_prebuilt_t* prebuilt,
808  ibool dict_locked)
809 {
810  ulint i;
811 
812  if (UNIV_UNLIKELY
813  (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
814  || prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED)) {
815 
816  fprintf(stderr,
817  "InnoDB: Error: trying to free a corrupt\n"
818  "InnoDB: table handle. Magic n %lu,"
819  " magic n2 %lu, table name ",
820  (ulong) prebuilt->magic_n,
821  (ulong) prebuilt->magic_n2);
822  ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
823  putc('\n', stderr);
824 
825  mem_analyze_corruption(prebuilt);
826 
827  ut_error;
828  }
829 
830  prebuilt->magic_n = ROW_PREBUILT_FREED;
831  prebuilt->magic_n2 = ROW_PREBUILT_FREED;
832 
833  btr_pcur_reset(&prebuilt->pcur);
834  btr_pcur_reset(&prebuilt->clust_pcur);
835 
836  if (prebuilt->mysql_template) {
837  mem_free(prebuilt->mysql_template);
838  }
839 
840  if (prebuilt->ins_graph) {
842  }
843 
844  if (prebuilt->sel_graph) {
846  }
847 
848  if (prebuilt->upd_graph) {
850  }
851 
852  if (prebuilt->blob_heap) {
853  mem_heap_free(prebuilt->blob_heap);
854  }
855 
856  if (prebuilt->old_vers_heap) {
857  mem_heap_free(prebuilt->old_vers_heap);
858  }
859 
860  if (prebuilt->fetch_cache[0] != NULL) {
861  byte* base = prebuilt->fetch_cache[0] - 4;
862  byte* ptr = base;
863 
864  for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
865  byte* row;
866  ulint magic1;
867  ulint magic2;
868 
869  magic1 = mach_read_from_4(ptr);
870  ptr += 4;
871 
872  row = ptr;
873  ptr += prebuilt->mysql_row_len;
874 
875  magic2 = mach_read_from_4(ptr);
876  ptr += 4;
877 
878  if (ROW_PREBUILT_FETCH_MAGIC_N != magic1
879  || row != prebuilt->fetch_cache[i]
880  || ROW_PREBUILT_FETCH_MAGIC_N != magic2) {
881 
882  fputs("InnoDB: Error: trying to free"
883  " a corrupt fetch buffer.\n", stderr);
884 
886  ut_error;
887  }
888  }
889 
890  mem_free(base);
891  }
892 
893  dict_table_close(prebuilt->table, dict_locked, TRUE);
894 
895  mem_heap_free(prebuilt->heap);
896 }
897 
898 /*********************************************************************/
901 UNIV_INTERN
902 void
904 /*====================*/
905  row_prebuilt_t* prebuilt,
907  trx_t* trx)
908 {
909  if (trx->magic_n != TRX_MAGIC_N) {
910  fprintf(stderr,
911  "InnoDB: Error: trying to use a corrupt\n"
912  "InnoDB: trx handle. Magic n %lu\n",
913  (ulong) trx->magic_n);
914 
916 
917  ut_error;
918  }
919 
920  if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
921  fprintf(stderr,
922  "InnoDB: Error: trying to use a corrupt\n"
923  "InnoDB: table handle. Magic n %lu, table name ",
924  (ulong) prebuilt->magic_n);
925  ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
926  putc('\n', stderr);
927 
928  mem_analyze_corruption(prebuilt);
929 
930  ut_error;
931  }
932 
933  prebuilt->trx = trx;
934 
935  if (prebuilt->ins_graph) {
936  prebuilt->ins_graph->trx = trx;
937  }
938 
939  if (prebuilt->upd_graph) {
940  prebuilt->upd_graph->trx = trx;
941  }
942 
943  if (prebuilt->sel_graph) {
944  prebuilt->sel_graph->trx = trx;
945  }
946 }
947 
948 /*********************************************************************/
953 static
954 dtuple_t*
955 row_get_prebuilt_insert_row(
956 /*========================*/
957  row_prebuilt_t* prebuilt)
959 {
960  dict_table_t* table = prebuilt->table;
961 
962  ut_ad(prebuilt && table && prebuilt->trx);
963 
964  if (prebuilt->ins_node != 0) {
965 
966  /* Check if indexes have been dropped or added and we
967  may need to rebuild the row insert template. */
968 
969  if (prebuilt->trx_id == table->def_trx_id
970  && UT_LIST_GET_LEN(prebuilt->ins_node->entry_list)
971  == UT_LIST_GET_LEN(table->indexes)) {
972 
973  return(prebuilt->ins_node->row);
974  }
975 
976  ut_ad(prebuilt->trx_id < table->def_trx_id);
977 
979 
980  prebuilt->ins_graph = 0;
981  }
982 
983  /* Create an insert node and query graph to the prebuilt struct */
984 
985  ins_node_t* node;
986 
987  node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
988 
989  prebuilt->ins_node = node;
990 
991  if (prebuilt->ins_upd_rec_buff == 0) {
992  prebuilt->ins_upd_rec_buff = static_cast<byte*>(
994  prebuilt->heap,
995  prebuilt->mysql_row_len));
996  }
997 
998  dtuple_t* row;
999 
1000  row = dtuple_create(prebuilt->heap, dict_table_get_n_cols(table));
1001 
1002  dict_table_copy_types(row, table);
1003 
1004  ins_node_set_new_row(node, row);
1005 
1006  prebuilt->ins_graph = static_cast<que_fork_t*>(
1009  node,
1010  prebuilt->trx, prebuilt->heap)));
1011 
1012  prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
1013 
1014  prebuilt->trx_id = table->def_trx_id;
1015 
1016  return(prebuilt->ins_node->row);
1017 }
1018 
1019 /*********************************************************************/
1022 UNIV_INLINE
1023 void
1025 /*============================*/
1026  dict_table_t* table)
1027 {
1028  ib_uint64_t counter;
1029  ib_uint64_t n_rows;
1030 
1031  if (!table->stat_initialized) {
1032  DBUG_EXECUTE_IF(
1033  "test_upd_stats_if_needed_not_inited",
1034  fprintf(stderr, "test_upd_stats_if_needed_not_inited "
1035  "was executed\n");
1036  );
1037  return;
1038  }
1039 
1040  counter = table->stat_modified_counter++;
1041  n_rows = dict_table_get_n_rows(table);
1042 
1043  if (dict_stats_is_persistent_enabled(table)) {
1044  if (counter > n_rows / 10 /* 10% */
1046 
1048  table->stat_modified_counter = 0;
1049  }
1050  return;
1051  }
1052 
1053  /* Calculate new statistics if 1 / 16 of table has been modified
1054  since the last time a statistics batch was run.
1055  We calculate statistics at most every 16th round, since we may have
1056  a counter table which is very small and updated very often. */
1057 
1058  if (counter > 16 + n_rows / 16 /* 6.25% */) {
1059 
1060  ut_ad(!mutex_own(&dict_sys->mutex));
1061  /* this will reset table->stat_modified_counter to 0 */
1062  dict_stats_update(table, DICT_STATS_RECALC_TRANSIENT);
1063  }
1064 }
1065 
1066 /*********************************************************************/
1073 UNIV_INTERN
1074 dberr_t
1076 /*=============================*/
1077  row_prebuilt_t* prebuilt)
1079 {
1080  trx_t* trx = prebuilt->trx;
1081  ins_node_t* node = prebuilt->ins_node;
1082  const dict_table_t* table = prebuilt->table;
1083  que_thr_t* thr;
1084  dberr_t err;
1085  ibool was_lock_wait;
1086 
1087  ut_ad(trx);
1088 
1089  /* If we already hold an AUTOINC lock on the table then do nothing.
1090  Note: We peek at the value of the current owner without acquiring
1091  the lock mutex. **/
1092  if (trx == table->autoinc_trx) {
1093 
1094  return(DB_SUCCESS);
1095  }
1096 
1097  trx->op_info = "setting auto-inc lock";
1098 
1099  row_get_prebuilt_insert_row(prebuilt);
1100  node = prebuilt->ins_node;
1101 
1102  /* We use the insert query graph as the dummy graph needed
1103  in the lock module call */
1104 
1105  thr = que_fork_get_first_thr(prebuilt->ins_graph);
1106 
1108 
1109 run_again:
1110  thr->run_node = node;
1111  thr->prev_node = node;
1112 
1113  /* It may be that the current session has not yet started
1114  its transaction, or it has been committed: */
1115 
1116  trx_start_if_not_started_xa(trx);
1117 
1118  err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
1119 
1120  trx->error_state = err;
1121 
1122  if (err != DB_SUCCESS) {
1124 
1125  was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1126 
1127  if (was_lock_wait) {
1128  goto run_again;
1129  }
1130 
1131  trx->op_info = "";
1132 
1133  return(err);
1134  }
1135 
1137 
1138  trx->op_info = "";
1139 
1140  return(err);
1141 }
1142 
1143 /*********************************************************************/
1146 UNIV_INTERN
1147 dberr_t
1149 /*=====================*/
1150  row_prebuilt_t* prebuilt,
1152  dict_table_t* table,
1156  ulint mode)
1158 {
1159  trx_t* trx = prebuilt->trx;
1160  que_thr_t* thr;
1161  dberr_t err;
1162  ibool was_lock_wait;
1163 
1164  ut_ad(trx);
1165 
1166  trx->op_info = "setting table lock";
1167 
1168  if (prebuilt->sel_graph == NULL) {
1169  /* Build a dummy select query graph */
1170  row_prebuild_sel_graph(prebuilt);
1171  }
1172 
1173  /* We use the select query graph as the dummy graph needed
1174  in the lock module call */
1175 
1176  thr = que_fork_get_first_thr(prebuilt->sel_graph);
1177 
1179 
1180 run_again:
1181  thr->run_node = thr;
1182  thr->prev_node = thr->common.parent;
1183 
1184  /* It may be that the current session has not yet started
1185  its transaction, or it has been committed: */
1186 
1187  trx_start_if_not_started_xa(trx);
1188 
1189  if (table) {
1190  err = lock_table(
1191  0, table,
1192  static_cast<enum lock_mode>(mode), thr);
1193  } else {
1194  err = lock_table(
1195  0, prebuilt->table,
1196  static_cast<enum lock_mode>(
1197  prebuilt->select_lock_type),
1198  thr);
1199  }
1200 
1201  trx->error_state = err;
1202 
1203  if (err != DB_SUCCESS) {
1205 
1206  was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1207 
1208  if (was_lock_wait) {
1209  goto run_again;
1210  }
1211 
1212  trx->op_info = "";
1213 
1214  return(err);
1215  }
1216 
1218 
1219  trx->op_info = "";
1220 
1221  return(err);
1222 }
1223 
1224 /*********************************************************************/
1227 UNIV_INTERN
1228 dberr_t
1230 /*=================*/
1231  byte* mysql_rec,
1232  row_prebuilt_t* prebuilt)
1234 {
1235  trx_savept_t savept;
1236  que_thr_t* thr;
1237  dberr_t err;
1238  ibool was_lock_wait;
1239  trx_t* trx = prebuilt->trx;
1240  ins_node_t* node = prebuilt->ins_node;
1241  dict_table_t* table = prebuilt->table;
1242 
1243  ut_ad(trx);
1244 
1245  if (dict_table_is_discarded(prebuilt->table)) {
1246  ib_logf(IB_LOG_LEVEL_ERROR,
1247  "The table %s doesn't have a corresponding "
1248  "tablespace, it was discarded.",
1249  prebuilt->table->name);
1250 
1251  return(DB_TABLESPACE_DELETED);
1252 
1253  } else if (prebuilt->table->ibd_file_missing) {
1254 
1255  ib_logf(IB_LOG_LEVEL_ERROR,
1256  ".ibd file is missing for table %s",
1257  prebuilt->table->name);
1258 
1259  return(DB_TABLESPACE_NOT_FOUND);
1260 
1261  } else if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
1262  fprintf(stderr,
1263  "InnoDB: Error: trying to free a corrupt\n"
1264  "InnoDB: table handle. Magic n %lu, table name ",
1265  (ulong) prebuilt->magic_n);
1266  ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1267  putc('\n', stderr);
1268 
1269  mem_analyze_corruption(prebuilt);
1270 
1271  ut_error;
1272  } else if (srv_created_new_raw || srv_force_recovery) {
1273  fputs("InnoDB: A new raw disk partition was initialized or\n"
1274  "InnoDB: innodb_force_recovery is on: we do not allow\n"
1275  "InnoDB: database modifications by the user. Shut down\n"
1276  "InnoDB: mysqld and edit my.cnf so that"
1277  " newraw is replaced\n"
1278  "InnoDB: with raw, and innodb_force_... is removed.\n",
1279  stderr);
1280 
1281  return(DB_ERROR);
1282  }
1283 
1284  trx->op_info = "inserting";
1285 
1286  row_mysql_delay_if_needed();
1287 
1288  trx_start_if_not_started_xa(trx);
1289 
1290  row_get_prebuilt_insert_row(prebuilt);
1291  node = prebuilt->ins_node;
1292 
1293  row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
1294 
1295  savept = trx_savept_take(trx);
1296 
1297  thr = que_fork_get_first_thr(prebuilt->ins_graph);
1298 
1299  if (prebuilt->sql_stat_start) {
1300  node->state = INS_NODE_SET_IX_LOCK;
1301  prebuilt->sql_stat_start = FALSE;
1302  } else {
1303  node->state = INS_NODE_ALLOC_ROW_ID;
1304  }
1305 
1307 
1308 run_again:
1309  thr->run_node = node;
1310  thr->prev_node = node;
1311 
1312  row_ins_step(thr);
1313 
1314  err = trx->error_state;
1315 
1316  if (err != DB_SUCCESS) {
1317 error_exit:
1319 
1320  /* FIXME: What's this ? */
1321  thr->lock_state = QUE_THR_LOCK_ROW;
1322 
1323  was_lock_wait = row_mysql_handle_errors(
1324  &err, trx, thr, &savept);
1325 
1326  thr->lock_state = QUE_THR_LOCK_NOLOCK;
1327 
1328  if (was_lock_wait) {
1329  ut_ad(node->state == INS_NODE_INSERT_ENTRIES
1330  || node->state == INS_NODE_ALLOC_ROW_ID);
1331  goto run_again;
1332  }
1333 
1334  trx->op_info = "";
1335 
1336  return(err);
1337  }
1338 
1339  if (dict_table_has_fts_index(table)) {
1340  doc_id_t doc_id;
1341 
1342  /* Extract the doc id from the hidden FTS column */
1343  doc_id = fts_get_doc_id_from_row(table, node->row);
1344 
1345  if (doc_id <= 0) {
1346  fprintf(stderr,
1347  "InnoDB: FTS Doc ID must be large than 0 \n");
1348  err = DB_FTS_INVALID_DOCID;
1349  trx->error_state = DB_FTS_INVALID_DOCID;
1350  goto error_exit;
1351  }
1352 
1353  if (!DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)) {
1354  doc_id_t next_doc_id
1355  = table->fts->cache->next_doc_id;
1356 
1357  if (doc_id < next_doc_id) {
1358  fprintf(stderr,
1359  "InnoDB: FTS Doc ID must be large than"
1360  " "UINT64PF" for table",
1361  next_doc_id - 1);
1362  ut_print_name(stderr, trx, TRUE, table->name);
1363  putc('\n', stderr);
1364 
1365  err = DB_FTS_INVALID_DOCID;
1366  trx->error_state = DB_FTS_INVALID_DOCID;
1367  goto error_exit;
1368  }
1369 
1370  /* Difference between Doc IDs are restricted within
1371  4 bytes integer. See fts_get_encoded_len() */
1372 
1373  if (doc_id - next_doc_id >= FTS_DOC_ID_MAX_STEP) {
1374  fprintf(stderr,
1375  "InnoDB: Doc ID "UINT64PF" is too"
1376  " big. Its difference with largest"
1377  " used Doc ID "UINT64PF" cannot"
1378  " exceed or equal to %d\n",
1379  doc_id, next_doc_id - 1,
1380  FTS_DOC_ID_MAX_STEP);
1381  err = DB_FTS_INVALID_DOCID;
1382  trx->error_state = DB_FTS_INVALID_DOCID;
1383  goto error_exit;
1384  }
1385  }
1386 
1387  /* Pass NULL for the columns affected, since an INSERT affects
1388  all FTS indexes. */
1389  fts_trx_add_op(trx, table, doc_id, FTS_INSERT, NULL);
1390  }
1391 
1393 
1394  srv_stats.n_rows_inserted.add((size_t)trx->id, 1);
1395 
1396  /* Not protected by dict_table_stats_lock() for performance
1397  reasons, we would rather get garbage in stat_n_rows (which is
1398  just an estimate anyway) than protecting the following code
1399  with a latch. */
1400  dict_table_n_rows_inc(table);
1401 
1403  trx->op_info = "";
1404 
1405  return(err);
1406 }
1407 
1408 /*********************************************************************/
1410 UNIV_INTERN
1411 void
1413 /*===================*/
1414  row_prebuilt_t* prebuilt)
1416 {
1417  sel_node_t* node;
1418 
1419  ut_ad(prebuilt && prebuilt->trx);
1420 
1421  if (prebuilt->sel_graph == NULL) {
1422 
1423  node = sel_node_create(prebuilt->heap);
1424 
1425  prebuilt->sel_graph = static_cast<que_fork_t*>(
1428  static_cast<sel_node_t*>(node),
1429  prebuilt->trx, prebuilt->heap)));
1430 
1431  prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1432  }
1433 }
1434 
1435 /*********************************************************************/
1439 UNIV_INTERN
1440 upd_node_t*
1442 /*=============================*/
1443  dict_table_t* table,
1444  mem_heap_t* heap)
1445 {
1446  upd_node_t* node;
1447 
1448  node = upd_node_create(heap);
1449 
1450  node->in_mysql_interface = TRUE;
1451  node->is_delete = FALSE;
1452  node->searched_update = FALSE;
1453  node->select = NULL;
1454  node->pcur = btr_pcur_create_for_mysql();
1455  node->table = table;
1456 
1457  node->update = upd_create(dict_table_get_n_cols(table), heap);
1458 
1459  node->update_n_fields = dict_table_get_n_cols(table);
1460 
1461  UT_LIST_INIT(node->columns);
1462  node->has_clust_rec_x_lock = TRUE;
1463  node->cmpl_info = 0;
1464 
1465  node->table_sym = NULL;
1466  node->col_assign_list = NULL;
1467 
1468  return(node);
1469 }
1470 
1471 /*********************************************************************/
1476 UNIV_INTERN
1477 upd_t*
1479 /*===========================*/
1480  row_prebuilt_t* prebuilt)
1482 {
1483  dict_table_t* table = prebuilt->table;
1484  upd_node_t* node;
1485 
1486  ut_ad(prebuilt && table && prebuilt->trx);
1487 
1488  if (prebuilt->upd_node == NULL) {
1489 
1490  /* Not called before for this handle: create an update node
1491  and query graph to the prebuilt struct */
1492 
1493  node = row_create_update_node_for_mysql(table, prebuilt->heap);
1494 
1495  prebuilt->upd_node = node;
1496 
1497  prebuilt->upd_graph = static_cast<que_fork_t*>(
1500  static_cast<upd_node_t*>(node),
1501  prebuilt->trx, prebuilt->heap)));
1502 
1503  prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1504  }
1505 
1506  return(prebuilt->upd_node->update);
1507 }
1508 
1509 /********************************************************************
1510 Handle an update of a column that has an FTS index. */
1511 static
1512 void
1513 row_fts_do_update(
1514 /*==============*/
1515  trx_t* trx, /* in: transaction */
1516  dict_table_t* table, /* in: Table with FTS index */
1517  doc_id_t old_doc_id, /* in: old document id */
1518  doc_id_t new_doc_id) /* in: new document id */
1519 {
1520  if (trx->fts_next_doc_id) {
1521  fts_trx_add_op(trx, table, old_doc_id, FTS_DELETE, NULL);
1522  fts_trx_add_op(trx, table, new_doc_id, FTS_INSERT, NULL);
1523  }
1524 }
1525 
1526 /************************************************************************
1527 Handles FTS matters for an update or a delete.
1528 NOTE: should not be called if the table does not have an FTS index. .*/
1529 static
1530 dberr_t
1531 row_fts_update_or_delete(
1532 /*=====================*/
1533  row_prebuilt_t* prebuilt) /* in: prebuilt struct in MySQL
1534  handle */
1535 {
1536  trx_t* trx = prebuilt->trx;
1537  dict_table_t* table = prebuilt->table;
1538  upd_node_t* node = prebuilt->upd_node;
1539  doc_id_t old_doc_id = prebuilt->fts_doc_id;
1540 
1541  ut_a(dict_table_has_fts_index(prebuilt->table));
1542 
1543  /* Deletes are simple; get them out of the way first. */
1544  if (node->is_delete) {
1545  /* A delete affects all FTS indexes, so we pass NULL */
1546  fts_trx_add_op(trx, table, old_doc_id, FTS_DELETE, NULL);
1547  } else {
1548  doc_id_t new_doc_id;
1549 
1550  new_doc_id = fts_read_doc_id((byte*) &trx->fts_next_doc_id);
1551 
1552  if (new_doc_id == 0) {
1553  fprintf(stderr, " InnoDB FTS: Doc ID cannot be 0 \n");
1554  return(DB_FTS_INVALID_DOCID);
1555  }
1556 
1557  row_fts_do_update(trx, table, old_doc_id, new_doc_id);
1558  }
1559 
1560  return(DB_SUCCESS);
1561 }
1562 
1563 /*********************************************************************/
1565 static
1566 void
1567 init_fts_doc_id_for_ref(
1568 /*====================*/
1569  dict_table_t* table,
1570  ulint* depth)
1571 {
1572  dict_foreign_t* foreign;
1573 
1574  foreign = UT_LIST_GET_FIRST(table->referenced_list);
1575 
1576  table->fk_max_recusive_level = 0;
1577 
1578  (*depth)++;
1579 
1580  /* Limit on tables involved in cascading delete/update */
1581  if (*depth > FK_MAX_CASCADE_DEL) {
1582  return;
1583  }
1584 
1585  /* Loop through this table's referenced list and also
1586  recursively traverse each table's foreign table list */
1587  while (foreign && foreign->foreign_table) {
1588  if (foreign->foreign_table->fts) {
1589  fts_init_doc_id(foreign->foreign_table);
1590  }
1591 
1593  > 0 && foreign->foreign_table != table) {
1594  init_fts_doc_id_for_ref(foreign->foreign_table, depth);
1595  }
1596 
1597  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
1598  }
1599 }
1600 
1601 /*********************************************************************/
1604 UNIV_INTERN
1605 dberr_t
1607 /*=================*/
1608  byte* mysql_rec,
1610  row_prebuilt_t* prebuilt)
1612 {
1613  trx_savept_t savept;
1614  dberr_t err;
1615  que_thr_t* thr;
1616  ibool was_lock_wait;
1617  dict_index_t* clust_index;
1618  /* ulint ref_len; */
1619  upd_node_t* node;
1620  dict_table_t* table = prebuilt->table;
1621  trx_t* trx = prebuilt->trx;
1622  ulint fk_depth = 0;
1623 
1624  ut_ad(prebuilt && trx);
1625  UT_NOT_USED(mysql_rec);
1626 
1627  if (prebuilt->table->ibd_file_missing) {
1628  ut_print_timestamp(stderr);
1629  fprintf(stderr, " InnoDB: Error:\n"
1630  "InnoDB: MySQL is trying to use a table handle"
1631  " but the .ibd file for\n"
1632  "InnoDB: table %s does not exist.\n"
1633  "InnoDB: Have you deleted the .ibd file"
1634  " from the database directory under\n"
1635  "InnoDB: the MySQL datadir, or have you"
1636  " used DISCARD TABLESPACE?\n"
1637  "InnoDB: Look from\n"
1638  "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1639  "InnoDB: how you can resolve the problem.\n",
1640  prebuilt->table->name);
1641  return(DB_ERROR);
1642  }
1643 
1644  if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1645  fprintf(stderr,
1646  "InnoDB: Error: trying to free a corrupt\n"
1647  "InnoDB: table handle. Magic n %lu, table name ",
1648  (ulong) prebuilt->magic_n);
1649  ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1650  putc('\n', stderr);
1651 
1652  mem_analyze_corruption(prebuilt);
1653 
1654  ut_error;
1655  }
1656 
1657  if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1658  fputs("InnoDB: A new raw disk partition was initialized or\n"
1659  "InnoDB: innodb_force_recovery is on: we do not allow\n"
1660  "InnoDB: database modifications by the user. Shut down\n"
1661  "InnoDB: mysqld and edit my.cnf so that newraw"
1662  " is replaced\n"
1663  "InnoDB: with raw, and innodb_force_... is removed.\n",
1664  stderr);
1665 
1666  return(DB_ERROR);
1667  }
1668 
1669  DEBUG_SYNC_C("innodb_row_update_for_mysql_begin");
1670 
1671  trx->op_info = "updating or deleting";
1672 
1673  row_mysql_delay_if_needed();
1674 
1675  trx_start_if_not_started_xa(trx);
1676 
1678  /* Share lock the data dictionary to prevent any
1679  table dictionary (for foreign constraint) change.
1680  This is similar to row_ins_check_foreign_constraint
1681  check protect by the dictionary lock as well.
1682  In the future, this can be removed once the Foreign
1683  key MDL is implemented */
1684  row_mysql_freeze_data_dictionary(trx);
1685  init_fts_doc_id_for_ref(table, &fk_depth);
1687  }
1688 
1689  node = prebuilt->upd_node;
1690 
1691  clust_index = dict_table_get_first_index(table);
1692 
1693  if (prebuilt->pcur.btr_cur.index == clust_index) {
1694  btr_pcur_copy_stored_position(node->pcur, &prebuilt->pcur);
1695  } else {
1697  &prebuilt->clust_pcur);
1698  }
1699 
1700  ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
1701 
1702  /* MySQL seems to call rnd_pos before updating each row it
1703  has cached: we can get the correct cursor position from
1704  prebuilt->pcur; NOTE that we cannot build the row reference
1705  from mysql_rec if the clustered index was automatically
1706  generated for the table: MySQL does not know anything about
1707  the row id used as the clustered index key */
1708 
1709  savept = trx_savept_take(trx);
1710 
1711  thr = que_fork_get_first_thr(prebuilt->upd_graph);
1712 
1713  node->state = UPD_NODE_UPDATE_CLUSTERED;
1714 
1715  ut_ad(!prebuilt->sql_stat_start);
1716 
1718 
1719 run_again:
1720  thr->run_node = node;
1721  thr->prev_node = node;
1722  thr->fk_cascade_depth = 0;
1723 
1724  row_upd_step(thr);
1725 
1726  err = trx->error_state;
1727 
1728  /* Reset fk_cascade_depth back to 0 */
1729  thr->fk_cascade_depth = 0;
1730 
1731  if (err != DB_SUCCESS) {
1733 
1734  if (err == DB_RECORD_NOT_FOUND) {
1735  trx->error_state = DB_SUCCESS;
1736  trx->op_info = "";
1737 
1738  return(err);
1739  }
1740 
1741  thr->lock_state= QUE_THR_LOCK_ROW;
1742 
1743  DEBUG_SYNC(trx->mysql_thd, "row_update_for_mysql_error");
1744 
1745  was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1746  &savept);
1747  thr->lock_state= QUE_THR_LOCK_NOLOCK;
1748 
1749  if (was_lock_wait) {
1750  goto run_again;
1751  }
1752 
1753  trx->op_info = "";
1754 
1755  return(err);
1756  }
1757 
1759 
1760  if (dict_table_has_fts_index(table)
1761  && trx->fts_next_doc_id != UINT64_UNDEFINED) {
1762  err = row_fts_update_or_delete(prebuilt);
1763  if (err != DB_SUCCESS) {
1764  trx->op_info = "";
1765  return(err);
1766  }
1767  }
1768 
1769  if (node->is_delete) {
1770  /* Not protected by dict_table_stats_lock() for performance
1771  reasons, we would rather get garbage in stat_n_rows (which is
1772  just an estimate anyway) than protecting the following code
1773  with a latch. */
1774  dict_table_n_rows_dec(prebuilt->table);
1775 
1776  srv_stats.n_rows_deleted.add((size_t)trx->id, 1);
1777  } else {
1778  srv_stats.n_rows_updated.add((size_t)trx->id, 1);
1779  }
1780 
1781  /* We update table statistics only if it is a DELETE or UPDATE
1782  that changes indexed columns, UPDATEs that change only non-indexed
1783  columns would not affect statistics. */
1784  if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
1786  }
1787 
1788  trx->op_info = "";
1789 
1790  return(err);
1791 }
1792 
1793 /*********************************************************************/
1803 UNIV_INTERN
1804 void
1806 /*=================*/
1807  row_prebuilt_t* prebuilt,
1809  ibool has_latches_on_recs)
1814 {
1815  btr_pcur_t* pcur = &prebuilt->pcur;
1816  btr_pcur_t* clust_pcur = &prebuilt->clust_pcur;
1817  trx_t* trx = prebuilt->trx;
1818 
1819  ut_ad(prebuilt && trx);
1820 
1821  if (UNIV_UNLIKELY
1823  && trx->isolation_level > TRX_ISO_READ_COMMITTED)) {
1824 
1825  fprintf(stderr,
1826  "InnoDB: Error: calling row_unlock_for_mysql though\n"
1827  "InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
1828  "InnoDB: this session is not using"
1829  " READ COMMITTED isolation level.\n");
1830  return;
1831  }
1832 
1833  trx->op_info = "unlock_row";
1834 
1835  if (prebuilt->new_rec_locks >= 1) {
1836 
1837  const rec_t* rec;
1839  trx_id_t rec_trx_id;
1840  mtr_t mtr;
1841 
1842  mtr_start(&mtr);
1843 
1844  /* Restore the cursor position and find the record */
1845 
1846  if (!has_latches_on_recs) {
1847  btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
1848  }
1849 
1850  rec = btr_pcur_get_rec(pcur);
1851  index = btr_pcur_get_btr_cur(pcur)->index;
1852 
1853  if (prebuilt->new_rec_locks >= 2) {
1854  /* Restore the cursor position and find the record
1855  in the clustered index. */
1856 
1857  if (!has_latches_on_recs) {
1858  btr_pcur_restore_position(BTR_SEARCH_LEAF,
1859  clust_pcur, &mtr);
1860  }
1861 
1862  rec = btr_pcur_get_rec(clust_pcur);
1863  index = btr_pcur_get_btr_cur(clust_pcur)->index;
1864  }
1865 
1866  if (!dict_index_is_clust(index)) {
1867  /* This is not a clustered index record. We
1868  do not know how to unlock the record. */
1869  goto no_unlock;
1870  }
1871 
1872  /* If the record has been modified by this
1873  transaction, do not unlock it. */
1874 
1875  if (index->trx_id_offset) {
1876  rec_trx_id = trx_read_trx_id(rec
1877  + index->trx_id_offset);
1878  } else {
1879  mem_heap_t* heap = NULL;
1880  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1881  ulint* offsets = offsets_;
1882 
1883  rec_offs_init(offsets_);
1884  offsets = rec_get_offsets(rec, index, offsets,
1885  ULINT_UNDEFINED, &heap);
1886 
1887  rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
1888 
1889  if (UNIV_LIKELY_NULL(heap)) {
1890  mem_heap_free(heap);
1891  }
1892  }
1893 
1894  if (rec_trx_id != trx->id) {
1895  /* We did not update the record: unlock it */
1896 
1897  rec = btr_pcur_get_rec(pcur);
1898 
1900  trx,
1901  btr_pcur_get_block(pcur),
1902  rec,
1903  static_cast<enum lock_mode>(
1904  prebuilt->select_lock_type));
1905 
1906  if (prebuilt->new_rec_locks >= 2) {
1907  rec = btr_pcur_get_rec(clust_pcur);
1908 
1910  trx,
1911  btr_pcur_get_block(clust_pcur),
1912  rec,
1913  static_cast<enum lock_mode>(
1914  prebuilt->select_lock_type));
1915  }
1916  }
1917 no_unlock:
1918  mtr_commit(&mtr);
1919  }
1920 
1921  trx->op_info = "";
1922 }
1923 
1924 /**********************************************************************/
1927 UNIV_INTERN
1928 dberr_t
1930 /*=========================*/
1931  que_thr_t* thr,
1932  upd_node_t* node,
1934  dict_table_t* table)
1935 {
1936  dberr_t err;
1937  trx_t* trx;
1938 
1939  trx = thr_get_trx(thr);
1940 
1941  /* Increment fk_cascade_depth to record the recursive call depth on
1942  a single update/delete that affects multiple tables chained
1943  together with foreign key relations. */
1944  thr->fk_cascade_depth++;
1945 
1946  if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
1948  }
1949 run_again:
1950  thr->run_node = node;
1951  thr->prev_node = node;
1952 
1953  DEBUG_SYNC_C("foreign_constraint_update_cascade");
1954 
1955  row_upd_step(thr);
1956 
1957  /* The recursive call for cascading update/delete happens
1958  in above row_upd_step(), reset the counter once we come
1959  out of the recursive call, so it does not accumulate for
1960  different row deletes */
1961  thr->fk_cascade_depth = 0;
1962 
1963  err = trx->error_state;
1964 
1965  /* Note that the cascade node is a subnode of another InnoDB
1966  query graph node. We do a normal lock wait in this node, but
1967  all errors are handled by the parent node. */
1968 
1969  if (err == DB_LOCK_WAIT) {
1970  /* Handle lock wait here */
1971 
1973 
1975 
1976  /* Note that a lock wait may also end in a lock wait timeout,
1977  or this transaction is picked as a victim in selective
1978  deadlock resolution */
1979 
1980  if (trx->error_state != DB_SUCCESS) {
1981 
1982  return(trx->error_state);
1983  }
1984 
1985  /* Retry operation after a normal lock wait */
1986 
1987  goto run_again;
1988  }
1989 
1990  if (err != DB_SUCCESS) {
1991 
1992  return(err);
1993  }
1994 
1995  if (node->is_delete) {
1996  /* Not protected by dict_table_stats_lock() for performance
1997  reasons, we would rather get garbage in stat_n_rows (which is
1998  just an estimate anyway) than protecting the following code
1999  with a latch. */
2000  dict_table_n_rows_dec(table);
2001 
2002  srv_stats.n_rows_deleted.add((size_t)trx->id, 1);
2003  } else {
2004  srv_stats.n_rows_updated.add((size_t)trx->id, 1);
2005  }
2006 
2008 
2009  return(err);
2010 }
2011 
2012 /*********************************************************************/
2016 UNIV_INTERN
2017 ibool
2019 /*==============================*/
2020  const dict_table_t* table)
2021 {
2022  const dict_index_t* clust_index;
2023 
2024  clust_index = dict_table_get_first_index(table);
2025 
2026  return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
2027 }
2028 
2029 /*********************************************************************/
2032 UNIV_INTERN
2033 void
2035 /*==================================*/
2036  trx_t* trx,
2037  const char* file,
2038  ulint line)
2039 {
2040  ut_a(trx->dict_operation_lock_mode == 0);
2041 
2042  rw_lock_s_lock_inline(&dict_operation_lock, 0, file, line);
2043 
2044  trx->dict_operation_lock_mode = RW_S_LATCH;
2045 }
2046 
2047 /*********************************************************************/
2049 UNIV_INTERN
2050 void
2052 /*===============================*/
2053  trx_t* trx)
2054 {
2055  ut_ad(lock_trx_has_sys_table_locks(trx) == NULL);
2056 
2057  ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
2058 
2059  rw_lock_s_unlock(&dict_operation_lock);
2060 
2061  trx->dict_operation_lock_mode = 0;
2062 }
2063 
2064 /*********************************************************************/
2067 UNIV_INTERN
2068 void
2070 /*================================*/
2071  trx_t* trx,
2072  const char* file,
2073  ulint line)
2074 {
2075  ut_a(trx->dict_operation_lock_mode == 0
2076  || trx->dict_operation_lock_mode == RW_X_LATCH);
2077 
2078  /* Serialize data dictionary operations with dictionary mutex:
2079  no deadlocks or lock waits can occur then in these operations */
2080 
2081  rw_lock_x_lock_inline(&dict_operation_lock, 0, file, line);
2082  trx->dict_operation_lock_mode = RW_X_LATCH;
2083 
2084  mutex_enter(&(dict_sys->mutex));
2085 }
2086 
2087 /*********************************************************************/
2089 UNIV_INTERN
2090 void
2092 /*=============================*/
2093  trx_t* trx)
2094 {
2095  ut_ad(lock_trx_has_sys_table_locks(trx) == NULL);
2096 
2097  ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
2098 
2099  /* Serialize data dictionary operations with dictionary mutex:
2100  no deadlocks can occur then in these operations */
2101 
2102  mutex_exit(&(dict_sys->mutex));
2103  rw_lock_x_unlock(&dict_operation_lock);
2104 
2105  trx->dict_operation_lock_mode = 0;
2106 }
2107 
2108 /*********************************************************************/
2116 UNIV_INTERN
2117 dberr_t
2119 /*=======================*/
2120  dict_table_t* table,
2123  trx_t* trx,
2124  bool commit)
2125 {
2126  tab_node_t* node;
2127  mem_heap_t* heap;
2128  que_thr_t* thr;
2129  const char* table_name;
2130  ulint table_name_len;
2131  dberr_t err;
2132 
2133 #ifdef UNIV_SYNC_DEBUG
2134  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2135 #endif /* UNIV_SYNC_DEBUG */
2136  ut_ad(mutex_own(&(dict_sys->mutex)));
2137  ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
2138 
2139  DBUG_EXECUTE_IF(
2140  "ib_create_table_fail_at_start_of_row_create_table_for_mysql",
2141  goto err_exit;
2142  );
2143 
2144  if (srv_created_new_raw) {
2145  fputs("InnoDB: A new raw disk partition was initialized:\n"
2146  "InnoDB: we do not allow database modifications"
2147  " by the user.\n"
2148  "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2149  " is replaced with raw.\n", stderr);
2150 err_exit:
2151  dict_mem_table_free(table);
2152 
2153  if (commit) {
2154  trx_commit_for_mysql(trx);
2155  }
2156 
2157  return(DB_ERROR);
2158  }
2159 
2160  trx->op_info = "creating table";
2161 
2162  if (row_mysql_is_system_table(table->name)) {
2163 
2164  fprintf(stderr,
2165  "InnoDB: Error: trying to create a MySQL system"
2166  " table %s of type InnoDB.\n"
2167  "InnoDB: MySQL system tables must be"
2168  " of the MyISAM type!\n",
2169  table->name);
2170  goto err_exit;
2171  }
2172 
2173  trx_start_if_not_started_xa(trx);
2174 
2175  /* The table name is prefixed with the database name and a '/'.
2176  Certain table names starting with 'innodb_' have their special
2177  meaning regardless of the database name. Thus, we need to
2178  ignore the database name prefix in the comparisons. */
2179  table_name = dict_remove_db_name(table->name);
2180  table_name_len = strlen(table_name) + 1;
2181 
2182  if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
2183 
2184  /* Table equals "innodb_monitor":
2185  start monitor prints */
2186 
2187  srv_print_innodb_monitor = TRUE;
2188 
2189  /* The lock timeout monitor thread also takes care
2190  of InnoDB monitor prints */
2191 
2193  } else if (STR_EQ(table_name, table_name_len,
2194  S_innodb_lock_monitor)) {
2195 
2196  srv_print_innodb_monitor = TRUE;
2197  srv_print_innodb_lock_monitor = TRUE;
2199  } else if (STR_EQ(table_name, table_name_len,
2200  S_innodb_tablespace_monitor)) {
2201 
2202  srv_print_innodb_tablespace_monitor = TRUE;
2204  } else if (STR_EQ(table_name, table_name_len,
2205  S_innodb_table_monitor)) {
2206 
2207  srv_print_innodb_table_monitor = TRUE;
2209 #ifdef UNIV_MEM_DEBUG
2210  } else if (STR_EQ(table_name, table_name_len,
2211  S_innodb_mem_validate)) {
2212  /* We define here a debugging feature intended for
2213  developers */
2214 
2215  fputs("Validating InnoDB memory:\n"
2216  "to use this feature you must compile InnoDB with\n"
2217  "UNIV_MEM_DEBUG defined in univ.i and"
2218  " the server must be\n"
2219  "quiet because allocation from a mem heap"
2220  " is not protected\n"
2221  "by any semaphore.\n", stderr);
2222  ut_a(mem_validate());
2223  fputs("Memory validated\n", stderr);
2224 #endif /* UNIV_MEM_DEBUG */
2225  }
2226 
2227  heap = mem_heap_create(512);
2228 
2229  switch (trx_get_dict_operation(trx)) {
2230  case TRX_DICT_OP_NONE:
2232  case TRX_DICT_OP_TABLE:
2233  break;
2234  case TRX_DICT_OP_INDEX:
2235  /* If the transaction was previously flagged as
2236  TRX_DICT_OP_INDEX, we should be creating auxiliary
2237  tables for full-text indexes. */
2238  ut_ad(strstr(table->name, "/FTS_") != NULL);
2239  }
2240 
2241  node = tab_create_graph_create(table, heap, commit);
2242 
2243  thr = pars_complete_graph_for_exec(node, trx, heap);
2244 
2246  static_cast<que_fork_t*>(que_node_get_parent(thr))));
2247 
2248  que_run_threads(thr);
2249 
2250  err = trx->error_state;
2251 
2252  if (table->space != TRX_SYS_SPACE) {
2253  ut_a(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_USE_TABLESPACE));
2254 
2255  /* Update SYS_TABLESPACES and SYS_DATAFILES if a new
2256  tablespace was created. */
2257  if (err == DB_SUCCESS) {
2258  char* path;
2259  path = fil_space_get_first_path(table->space);
2260 
2262  table->space, table->name,
2263  fil_space_get_flags(table->space),
2264  path, trx, commit);
2265 
2266  mem_free(path);
2267  }
2268 
2269  if (err != DB_SUCCESS) {
2270  /* We must delete the link file. */
2271  fil_delete_link_file(table->name);
2272  }
2273  }
2274 
2275  switch (err) {
2276  case DB_SUCCESS:
2277  break;
2278  case DB_OUT_OF_FILE_SPACE:
2279  trx->error_state = DB_SUCCESS;
2280  trx_rollback_to_savepoint(trx, NULL);
2281 
2282  ut_print_timestamp(stderr);
2283  fputs(" InnoDB: Warning: cannot create table ",
2284  stderr);
2285  ut_print_name(stderr, trx, TRUE, table->name);
2286  fputs(" because tablespace full\n", stderr);
2287 
2288  if (dict_table_open_on_name(table->name, TRUE, FALSE,
2290 
2291  /* Make things easy for the drop table code. */
2292 
2293  if (table->can_be_evicted) {
2295  }
2296 
2297  dict_table_close(table, TRUE, FALSE);
2298 
2299  row_drop_table_for_mysql(table->name, trx, FALSE);
2300 
2301  if (commit) {
2302  trx_commit_for_mysql(trx);
2303  }
2304  } else {
2305  dict_mem_table_free(table);
2306  }
2307 
2308  break;
2309 
2311  /* We already have .ibd file here. it should be deleted. */
2312 
2313  if (table->space
2315  table->space,
2317  != DB_SUCCESS) {
2318 
2319  ut_print_timestamp(stderr);
2320  fprintf(stderr,
2321  " InnoDB: Error: not able to"
2322  " delete tablespace %lu of table ",
2323  (ulong) table->space);
2324  ut_print_name(stderr, trx, TRUE, table->name);
2325  fputs("!\n", stderr);
2326  }
2327  /* fall through */
2328 
2329  case DB_DUPLICATE_KEY:
2330  case DB_TABLESPACE_EXISTS:
2331  default:
2332  trx->error_state = DB_SUCCESS;
2333  trx_rollback_to_savepoint(trx, NULL);
2334  dict_mem_table_free(table);
2335  break;
2336  }
2337 
2339 
2340  trx->op_info = "";
2341 
2342  return(err);
2343 }
2344 
2345 /*********************************************************************/
2350 UNIV_INTERN
2351 dberr_t
2353 /*=======================*/
2354  dict_index_t* index,
2356  trx_t* trx,
2357  const ulint* field_lengths)
2363 {
2364  ind_node_t* node;
2365  mem_heap_t* heap;
2366  que_thr_t* thr;
2367  dberr_t err;
2368  ulint i;
2369  ulint len;
2370  char* table_name;
2371  char* index_name;
2373  ibool is_fts;
2374 
2375 #ifdef UNIV_SYNC_DEBUG
2376  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2377 #endif /* UNIV_SYNC_DEBUG */
2378  ut_ad(mutex_own(&(dict_sys->mutex)));
2379 
2380  trx->op_info = "creating index";
2381 
2382  /* Copy the table name because we may want to drop the
2383  table later, after the index object is freed (inside
2384  que_run_threads()) and thus index->table_name is not available. */
2385  table_name = mem_strdup(index->table_name);
2386  index_name = mem_strdup(index->name);
2387 
2388  is_fts = (index->type == DICT_FTS);
2389 
2390  table = dict_table_open_on_name(table_name, TRUE, TRUE,
2392 
2393  trx_start_if_not_started_xa(trx);
2394 
2395  for (i = 0; i < index->n_def; i++) {
2396  /* Check that prefix_len and actual length
2397  < DICT_MAX_INDEX_COL_LEN */
2398 
2399  len = dict_index_get_nth_field(index, i)->prefix_len;
2400 
2401  if (field_lengths && field_lengths[i]) {
2402  len = ut_max(len, field_lengths[i]);
2403  }
2404 
2405  DBUG_EXECUTE_IF(
2406  "ib_create_table_fail_at_create_index",
2407  len = DICT_MAX_FIELD_LEN_BY_FORMAT(table) + 1;
2408  );
2409 
2410  /* Column or prefix length exceeds maximum column length */
2411  if (len > (ulint) DICT_MAX_FIELD_LEN_BY_FORMAT(table)) {
2412  err = DB_TOO_BIG_INDEX_COL;
2413 
2414  dict_mem_index_free(index);
2415  goto error_handling;
2416  }
2417  }
2418 
2419  heap = mem_heap_create(512);
2420 
2422 
2423  /* Note that the space id where we store the index is inherited from
2424  the table in dict_build_index_def_step() in dict0crea.cc. */
2425 
2426  node = ind_create_graph_create(index, heap, true);
2427 
2428  thr = pars_complete_graph_for_exec(node, trx, heap);
2429 
2431  static_cast<que_fork_t*>(que_node_get_parent(thr))));
2432 
2433  que_run_threads(thr);
2434 
2435  err = trx->error_state;
2436 
2438 
2439  /* Create the index specific FTS auxiliary tables. */
2440  if (err == DB_SUCCESS && is_fts) {
2441  dict_index_t* idx;
2442 
2443  idx = dict_table_get_index_on_name(table, index_name);
2444 
2445  ut_ad(idx);
2446  err = fts_create_index_tables(trx, idx);
2447  }
2448 
2449 error_handling:
2450  dict_table_close(table, TRUE, FALSE);
2451 
2452  if (err != DB_SUCCESS) {
2453  /* We have special error handling here */
2454 
2455  trx->error_state = DB_SUCCESS;
2456 
2457  trx_rollback_to_savepoint(trx, NULL);
2458 
2459  row_drop_table_for_mysql(table_name, trx, FALSE);
2460 
2461  trx_commit_for_mysql(trx);
2462 
2463  trx->error_state = DB_SUCCESS;
2464  }
2465 
2466  trx->op_info = "";
2467 
2468  mem_free(table_name);
2469  mem_free(index_name);
2470 
2471  return(err);
2472 }
2473 
2474 /*********************************************************************/
2483 UNIV_INTERN
2484 dberr_t
2486 /*==============================*/
2487  trx_t* trx,
2488  const char* sql_string,
2493  size_t sql_length,
2494  const char* name,
2497  ibool reject_fks)
2500 {
2501  dberr_t err;
2502 
2503  ut_ad(mutex_own(&(dict_sys->mutex)));
2504 #ifdef UNIV_SYNC_DEBUG
2505  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2506 #endif /* UNIV_SYNC_DEBUG */
2507  ut_a(sql_string);
2508 
2509  trx->op_info = "adding foreign keys";
2510 
2511  trx_start_if_not_started_xa(trx);
2512 
2514 
2515  err = dict_create_foreign_constraints(trx, sql_string, sql_length,
2516  name, reject_fks);
2517 
2518  DBUG_EXECUTE_IF("ib_table_add_foreign_fail",
2519  err = DB_DUPLICATE_KEY;);
2520 
2521  DEBUG_SYNC_C("table_add_foreign_constraints");
2522 
2523  if (err == DB_SUCCESS) {
2524  /* Check that also referencing constraints are ok */
2525  err = dict_load_foreigns(name, NULL, false, true,
2527  }
2528 
2529  if (err != DB_SUCCESS) {
2530  /* We have special error handling here */
2531 
2532  trx->error_state = DB_SUCCESS;
2533 
2534  trx_rollback_to_savepoint(trx, NULL);
2535 
2536  row_drop_table_for_mysql(name, trx, FALSE);
2537 
2538  trx_commit_for_mysql(trx);
2539 
2540  trx->error_state = DB_SUCCESS;
2541  }
2542 
2543  return(err);
2544 }
2545 
2546 /*********************************************************************/
2554 static
2555 dberr_t
2556 row_drop_table_for_mysql_in_background(
2557 /*===================================*/
2558  const char* name)
2559 {
2560  dberr_t error;
2561  trx_t* trx;
2562 
2564 
2565  /* If the original transaction was dropping a table referenced by
2566  foreign keys, we must set the following to be able to drop the
2567  table: */
2568 
2569  trx->check_foreigns = FALSE;
2570 
2571  /* fputs("InnoDB: Error: Dropping table ", stderr);
2572  ut_print_name(stderr, trx, TRUE, name);
2573  fputs(" in background drop list\n", stderr); */
2574 
2575  /* Try to drop the table in InnoDB */
2576 
2577  error = row_drop_table_for_mysql(name, trx, FALSE);
2578 
2579  /* Flush the log to reduce probability that the .frm files and
2580  the InnoDB data dictionary get out-of-sync if the user runs
2581  with innodb_flush_log_at_trx_commit = 0 */
2582 
2584 
2585  trx_commit_for_mysql(trx);
2586 
2588 
2589  return(error);
2590 }
2591 
2592 /*********************************************************************/
2597 UNIV_INTERN
2598 ulint
2600 /*=========================================*/
2601 {
2602  row_mysql_drop_t* drop;
2604  ulint n_tables;
2605  ulint n_tables_dropped = 0;
2606 loop:
2607  mutex_enter(&row_drop_list_mutex);
2608 
2609  ut_a(row_mysql_drop_list_inited);
2610 
2611  drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2612 
2613  n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
2614 
2615  mutex_exit(&row_drop_list_mutex);
2616 
2617  if (drop == NULL) {
2618  /* All tables dropped */
2619 
2620  return(n_tables + n_tables_dropped);
2621  }
2622 
2623  table = dict_table_open_on_name(drop->table_name, FALSE, FALSE,
2625 
2626  if (table == NULL) {
2627  /* If for some reason the table has already been dropped
2628  through some other mechanism, do not try to drop it */
2629 
2630  goto already_dropped;
2631  }
2632 
2633  ut_a(!table->can_be_evicted);
2634 
2635  dict_table_close(table, FALSE, FALSE);
2636 
2637  if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2638  drop->table_name)) {
2639  /* If the DROP fails for some table, we return, and let the
2640  main thread retry later */
2641 
2642  return(n_tables + n_tables_dropped);
2643  }
2644 
2645  n_tables_dropped++;
2646 
2647 already_dropped:
2648  mutex_enter(&row_drop_list_mutex);
2649 
2650  UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2651 
2652  MONITOR_DEC(MONITOR_BACKGROUND_DROP_TABLE);
2653 
2654  ut_print_timestamp(stderr);
2655  fputs(" InnoDB: Dropped table ", stderr);
2656  ut_print_name(stderr, NULL, TRUE, drop->table_name);
2657  fputs(" in background drop queue.\n", stderr);
2658 
2659  mem_free(drop->table_name);
2660 
2661  mem_free(drop);
2662 
2663  mutex_exit(&row_drop_list_mutex);
2664 
2665  goto loop;
2666 }
2667 
2668 /*********************************************************************/
2672 UNIV_INTERN
2673 ulint
2675 /*======================================*/
2676 {
2677  ulint len;
2678 
2679  mutex_enter(&row_drop_list_mutex);
2680 
2681  ut_a(row_mysql_drop_list_inited);
2682 
2683  len = UT_LIST_GET_LEN(row_mysql_drop_list);
2684 
2685  mutex_exit(&row_drop_list_mutex);
2686 
2687  return(len);
2688 }
2689 
2690 /*********************************************************************/
2697 static
2698 ibool
2699 row_add_table_to_background_drop_list(
2700 /*==================================*/
2701  const char* name)
2702 {
2703  row_mysql_drop_t* drop;
2704 
2705  mutex_enter(&row_drop_list_mutex);
2706 
2707  ut_a(row_mysql_drop_list_inited);
2708 
2709  /* Look if the table already is in the drop list */
2710  for (drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2711  drop != NULL;
2712  drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop)) {
2713 
2714  if (strcmp(drop->table_name, name) == 0) {
2715  /* Already in the list */
2716 
2717  mutex_exit(&row_drop_list_mutex);
2718 
2719  return(FALSE);
2720  }
2721  }
2722 
2723  drop = static_cast<row_mysql_drop_t*>(
2724  mem_alloc(sizeof(row_mysql_drop_t)));
2725 
2726  drop->table_name = mem_strdup(name);
2727 
2728  UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
2729 
2730  MONITOR_INC(MONITOR_BACKGROUND_DROP_TABLE);
2731 
2732  /* fputs("InnoDB: Adding table ", stderr);
2733  ut_print_name(stderr, trx, TRUE, drop->table_name);
2734  fputs(" to background drop list\n", stderr); */
2735 
2736  mutex_exit(&row_drop_list_mutex);
2737 
2738  return(TRUE);
2739 }
2740 
2741 /*********************************************************************/
2744 UNIV_INTERN
2745 dberr_t
2747 /*========================*/
2748  dict_table_t* table,
2749  trx_t* trx,
2750  table_id_t* new_id)
2751 {
2752  dberr_t err;
2753  pars_info_t* info = pars_info_create();
2754 
2755  dict_hdr_get_new_id(new_id, NULL, NULL);
2756 
2757  /* Remove all locks except the table-level S and X locks. */
2758  lock_remove_all_on_table(table, FALSE);
2759 
2760  pars_info_add_ull_literal(info, "old_id", table->id);
2761  pars_info_add_ull_literal(info, "new_id", *new_id);
2762 
2763  err = que_eval_sql(
2764  info,
2765  "PROCEDURE RENUMBER_TABLE_PROC () IS\n"
2766  "BEGIN\n"
2767  "UPDATE SYS_TABLES SET ID = :new_id\n"
2768  " WHERE ID = :old_id;\n"
2769  "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2770  " WHERE TABLE_ID = :old_id;\n"
2771  "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2772  " WHERE TABLE_ID = :old_id;\n"
2773  "END;\n", FALSE, trx);
2774 
2775  return(err);
2776 }
2777 
2778 /*********************************************************************/
2782 static
2783 dict_table_t*
2784 row_discard_tablespace_begin(
2785 /*=========================*/
2786  const char* name,
2787  trx_t* trx)
2788 {
2789  trx->op_info = "discarding tablespace";
2790 
2792 
2793  trx_start_if_not_started_xa(trx);
2794 
2795  /* Serialize data dictionary operations with dictionary mutex:
2796  this is to avoid deadlocks during data dictionary operations */
2797 
2798  row_mysql_lock_data_dictionary(trx);
2799 
2801 
2802  table = dict_table_open_on_name(
2803  name, TRUE, FALSE, DICT_ERR_IGNORE_NONE);
2804 
2805  if (table) {
2807  ut_a(table->space != TRX_SYS_SPACE);
2808  ut_a(table->n_foreign_key_checks_running == 0);
2809  }
2810 
2811  return(table);
2812 }
2813 
2814 /*********************************************************************/
2817 static
2818 dberr_t
2819 row_discard_tablespace_foreign_key_checks(
2820 /*======================================*/
2821  const trx_t* trx,
2822  const dict_table_t* table)
2823 {
2824  const dict_foreign_t* foreign;
2825 
2826  /* Check if the table is referenced by foreign key constraints from
2827  some other table (not the table itself) */
2828 
2829  for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
2830  foreign && foreign->foreign_table == table;
2831  foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
2832 
2833  }
2834 
2835  if (!srv_read_only_mode && foreign && trx->check_foreigns) {
2836 
2837  FILE* ef = dict_foreign_err_file;
2838 
2839  /* We only allow discarding a referenced table if
2840  FOREIGN_KEY_CHECKS is set to 0 */
2841 
2842  mutex_enter(&dict_foreign_err_mutex);
2843 
2844  rewind(ef);
2845 
2846  ut_print_timestamp(ef);
2847 
2848  fputs(" Cannot DISCARD table ", ef);
2849  ut_print_name(stderr, trx, TRUE, table->name);
2850  fputs("\n"
2851  "because it is referenced by ", ef);
2852  ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
2853  putc('\n', ef);
2854 
2855  mutex_exit(&dict_foreign_err_mutex);
2856 
2857  return(DB_CANNOT_DROP_CONSTRAINT);
2858  }
2859 
2860  return(DB_SUCCESS);
2861 }
2862 
2863 /*********************************************************************/
2866 static
2867 dberr_t
2868 row_discard_tablespace_end(
2869 /*=======================*/
2870  trx_t* trx,
2871  dict_table_t* table,
2872  dberr_t err)
2873 {
2874  if (table != 0) {
2875  dict_table_close(table, TRUE, FALSE);
2876  }
2877 
2878  DBUG_EXECUTE_IF("ib_discard_before_commit_crash",
2879  log_make_checkpoint_at(LSN_MAX, TRUE);
2880  DBUG_SUICIDE(););
2881 
2882  trx_commit_for_mysql(trx);
2883 
2884  DBUG_EXECUTE_IF("ib_discard_after_commit_crash",
2885  log_make_checkpoint_at(LSN_MAX, TRUE);
2886  DBUG_SUICIDE(););
2887 
2889 
2890  trx->op_info = "";
2891 
2892  return(err);
2893 }
2894 
2895 /*********************************************************************/
2898 static
2899 dberr_t
2900 row_discard_tablespace(
2901 /*===================*/
2902  trx_t* trx,
2903  dict_table_t* table)
2904 {
2905  dberr_t err;
2906 
2907  /* How do we prevent crashes caused by ongoing operations on
2908  the table? Old operations could try to access non-existent
2909  pages. MySQL will block all DML on the table using MDL and a
2910  DISCARD will not start unless all existing operations on the
2911  table to be discarded are completed.
2912 
2913  1) Acquire the data dictionary latch in X mode. To prevent any
2914  internal operations that MySQL is not aware off and also for
2915  the internal SQL parser.
2916 
2917  2) Purge and rollback: we assign a new table id for the
2918  table. Since purge and rollback look for the table based on
2919  the table id, they see the table as 'dropped' and discard
2920  their operations.
2921 
2922  3) Insert buffer: we remove all entries for the tablespace in
2923  the insert buffer tree.
2924 
2925  4) FOREIGN KEY operations: if table->n_foreign_key_checks_running > 0,
2926  we do not allow the discard. */
2927 
2928  /* Play safe and remove all insert buffer entries, though we should
2929  have removed them already when DISCARD TABLESPACE was called */
2930 
2932 
2933  table_id_t new_id;
2934 
2935  /* Set the TABLESPACE DISCARD flag in the table definition on disk. */
2936 
2937  err = row_import_update_discarded_flag(trx, table->id, true, true);
2938 
2939  if (err != DB_SUCCESS) {
2940  return(err);
2941  }
2942 
2943  /* Update the index root pages in the system tables, on disk */
2944 
2945  err = row_import_update_index_root(trx, table, true, true);
2946 
2947  if (err != DB_SUCCESS) {
2948  return(err);
2949  }
2950 
2951  /* Drop all the FTS auxiliary tables. */
2952  if (dict_table_has_fts_index(table)
2953  || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)) {
2954 
2955  fts_drop_tables(trx, table);
2956  }
2957 
2958  /* Assign a new space ID to the table definition so that purge
2959  can ignore the changes. Update the system table on disk. */
2960 
2961  err = row_mysql_table_id_reassign(table, trx, &new_id);
2962 
2963  if (err != DB_SUCCESS) {
2964  return(err);
2965  }
2966 
2967  /* Discard the physical file that is used for the tablespace. */
2968 
2969  err = fil_discard_tablespace(table->space);
2970 
2971  switch(err) {
2972  case DB_SUCCESS:
2973  case DB_IO_ERROR:
2974  case DB_TABLESPACE_NOT_FOUND:
2975  /* All persistent operations successful, update the
2976  data dictionary memory cache. */
2977 
2978  table->ibd_file_missing = TRUE;
2979 
2980  table->flags2 |= DICT_TF2_DISCARDED;
2981 
2982  dict_table_change_id_in_cache(table, new_id);
2983 
2984  /* Reset the root page numbers. */
2985 
2986  for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
2987  index != 0;
2988  index = UT_LIST_GET_NEXT(indexes, index)) {
2989 
2990  index->page = FIL_NULL;
2991  index->space = FIL_NULL;
2992  }
2993 
2994  /* If the tablespace did not already exist or we couldn't
2995  write to it, we treat that as a successful DISCARD. It is
2996  unusable anyway. */
2997 
2998  err = DB_SUCCESS;
2999  break;
3000 
3001  default:
3002  /* We need to rollback the disk changes, something failed. */
3003 
3004  trx->error_state = DB_SUCCESS;
3005 
3006  trx_rollback_to_savepoint(trx, NULL);
3007 
3008  trx->error_state = DB_SUCCESS;
3009  }
3010 
3011  return(err);
3012 }
3013 
3014 /*********************************************************************/
3019 UNIV_INTERN
3020 dberr_t
3022 /*=============================*/
3023  const char* name,
3024  trx_t* trx)
3025 {
3026  dberr_t err;
3028 
3029  /* Open the table and start the transaction if not started. */
3030 
3031  table = row_discard_tablespace_begin(name, trx);
3032 
3033  if (table == 0) {
3034  err = DB_TABLE_NOT_FOUND;
3035  } else if (table->space == TRX_SYS_SPACE) {
3036  char table_name[MAX_FULL_NAME_LEN + 1];
3037 
3039  table_name, sizeof(table_name), table->name, FALSE);
3040 
3041  ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
3042  ER_TABLE_IN_SYSTEM_TABLESPACE, table_name);
3043 
3044  err = DB_ERROR;
3045 
3046  } else if (table->n_foreign_key_checks_running > 0) {
3047  char table_name[MAX_FULL_NAME_LEN + 1];
3048 
3050  table_name, sizeof(table_name), table->name, FALSE);
3051 
3052  ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
3053  ER_DISCARD_FK_CHECKS_RUNNING, table_name);
3054 
3055  err = DB_ERROR;
3056 
3057  } else {
3058  /* Do foreign key constraint checks. */
3059 
3060  err = row_discard_tablespace_foreign_key_checks(trx, table);
3061 
3062  if (err == DB_SUCCESS) {
3063  err = row_discard_tablespace(trx, table);
3064  }
3065  }
3066 
3067  return(row_discard_tablespace_end(trx, table, err));
3068 }
3069 
3070 /*********************************************************************/
3073 UNIV_INTERN
3074 dberr_t
3076 /*=================*/
3077  trx_t* trx,
3078  dict_table_t* table,
3079  enum lock_mode mode,
3080  const char* op_info)
3081 {
3082  mem_heap_t* heap;
3083  que_thr_t* thr;
3084  dberr_t err;
3085  sel_node_t* node;
3086 
3087  ut_ad(trx);
3088  ut_ad(mode == LOCK_X || mode == LOCK_S);
3089 
3090  heap = mem_heap_create(512);
3091 
3092  trx->op_info = op_info;
3093 
3094  node = sel_node_create(heap);
3095  thr = pars_complete_graph_for_exec(node, trx, heap);
3096  thr->graph->state = QUE_FORK_ACTIVE;
3097 
3098  /* We use the select query graph as the dummy graph needed
3099  in the lock module call */
3100 
3101  thr = que_fork_get_first_thr(
3102  static_cast<que_fork_t*>(que_node_get_parent(thr)));
3103 
3105 
3106 run_again:
3107  thr->run_node = thr;
3108  thr->prev_node = thr->common.parent;
3109 
3110  err = lock_table(0, table, mode, thr);
3111 
3112  trx->error_state = err;
3113 
3114  if (err == DB_SUCCESS) {
3116  } else {
3118 
3119  if (err != DB_QUE_THR_SUSPENDED) {
3120  ibool was_lock_wait;
3121 
3122  was_lock_wait = row_mysql_handle_errors(
3123  &err, trx, thr, NULL);
3124 
3125  if (was_lock_wait) {
3126  goto run_again;
3127  }
3128  } else {
3129  que_thr_t* run_thr;
3130  que_node_t* parent;
3131 
3132  parent = que_node_get_parent(thr);
3133 
3134  run_thr = que_fork_start_command(
3135  static_cast<que_fork_t*>(parent));
3136 
3137  ut_a(run_thr == thr);
3138 
3139  /* There was a lock wait but the thread was not
3140  in a ready to run or running state. */
3141  trx->error_state = DB_LOCK_WAIT;
3142 
3143  goto run_again;
3144  }
3145  }
3146 
3147  que_graph_free(thr->graph);
3148  trx->op_info = "";
3149 
3150  return(err);
3151 }
3152 
3153 /*********************************************************************/
3156 UNIV_INTERN
3157 dberr_t
3159 /*=========================*/
3160  dict_table_t* table,
3161  trx_t* trx)
3162 {
3163  dict_foreign_t* foreign;
3164  dberr_t err;
3165  mem_heap_t* heap;
3166  byte* buf;
3167  dtuple_t* tuple;
3168  dfield_t* dfield;
3169  dict_index_t* sys_index;
3170  btr_pcur_t pcur;
3171  mtr_t mtr;
3172  table_id_t new_id;
3173  ulint recreate_space = 0;
3174  pars_info_t* info = NULL;
3175  ibool has_internal_doc_id;
3176  ulint old_space = table->space;
3177 
3178  /* How do we prevent crashes caused by ongoing operations on
3179  the table? Old operations could try to access non-existent
3180  pages.
3181 
3182  1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
3183  InnoDB table lock on the table before we can do TRUNCATE
3184  TABLE. Then there are no running queries on the table.
3185 
3186  2) Purge and rollback: we assign a new table id for the
3187  table. Since purge and rollback look for the table based on
3188  the table id, they see the table as 'dropped' and discard
3189  their operations.
3190 
3191  3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
3192  so we do not have to remove insert buffer records, as the
3193  insert buffer works at a low level. If a freed page is later
3194  reallocated, the allocator will remove the ibuf entries for
3195  it.
3196 
3197  When we truncate *.ibd files by recreating them (analogous to
3198  DISCARD TABLESPACE), we remove all entries for the table in the
3199  insert buffer tree. This is not strictly necessary, because
3200  in 6) we will assign a new tablespace identifier, but we can
3201  free up some space in the system tablespace.
3202 
3203  4) Linear readahead and random readahead: we use the same
3204  method as in 3) to discard ongoing operations. (This is only
3205  relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
3206 
3207  5) FOREIGN KEY operations: if
3208  table->n_foreign_key_checks_running > 0, we do not allow the
3209  TRUNCATE. We also reserve the data dictionary latch.
3210 
3211  6) Crash recovery: To prevent the application of pre-truncation
3212  redo log records on the truncated tablespace, we will assign
3213  a new tablespace identifier to the truncated tablespace. */
3214 
3215  ut_ad(table);
3216 
3217  if (srv_created_new_raw) {
3218  fputs("InnoDB: A new raw disk partition was initialized:\n"
3219  "InnoDB: we do not allow database modifications"
3220  " by the user.\n"
3221  "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
3222  " is replaced with raw.\n", stderr);
3223 
3224  return(DB_ERROR);
3225  }
3226 
3227  if (dict_table_is_discarded(table)) {
3228  return(DB_TABLESPACE_DELETED);
3229  } else if (table->ibd_file_missing) {
3230  return(DB_TABLESPACE_NOT_FOUND);
3231  }
3232 
3233  trx_start_for_ddl(trx, TRX_DICT_OP_TABLE);
3234 
3235  trx->op_info = "truncating table";
3236 
3237  /* Serialize data dictionary operations with dictionary mutex:
3238  no deadlocks can occur then in these operations */
3239 
3240  ut_a(trx->dict_operation_lock_mode == 0);
3241  /* Prevent foreign key checks etc. while we are truncating the
3242  table */
3243 
3244  row_mysql_lock_data_dictionary(trx);
3245 
3246  ut_ad(mutex_own(&(dict_sys->mutex)));
3247 #ifdef UNIV_SYNC_DEBUG
3248  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3249 #endif /* UNIV_SYNC_DEBUG */
3250 
3252 
3253  /* Check if the table is referenced by foreign key constraints from
3254  some other table (not the table itself) */
3255 
3256  for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
3257  foreign != 0 && foreign->foreign_table == table;
3258  foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
3259 
3260  /* Do nothing. */
3261  }
3262 
3263  if (!srv_read_only_mode
3264  && foreign
3265  && trx->check_foreigns) {
3266 
3267  FILE* ef = dict_foreign_err_file;
3268 
3269  /* We only allow truncating a referenced table if
3270  FOREIGN_KEY_CHECKS is set to 0 */
3271 
3272  mutex_enter(&dict_foreign_err_mutex);
3273  rewind(ef);
3274  ut_print_timestamp(ef);
3275 
3276  fputs(" Cannot truncate table ", ef);
3277  ut_print_name(ef, trx, TRUE, table->name);
3278  fputs(" by DROP+CREATE\n"
3279  "InnoDB: because it is referenced by ", ef);
3280  ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3281  putc('\n', ef);
3282  mutex_exit(&dict_foreign_err_mutex);
3283 
3284  err = DB_ERROR;
3285  goto funct_exit;
3286  }
3287 
3288  /* TODO: could we replace the counter n_foreign_key_checks_running
3289  with lock checks on the table? Acquire here an exclusive lock on the
3290  table, and rewrite lock0lock.cc and the lock wait in srv0srv.cc so that
3291  they can cope with the table having been truncated here? Foreign key
3292  checks take an IS or IX lock on the table. */
3293 
3294  if (table->n_foreign_key_checks_running > 0) {
3295  ut_print_timestamp(stderr);
3296  fputs(" InnoDB: Cannot truncate table ", stderr);
3297  ut_print_name(stderr, trx, TRUE, table->name);
3298  fputs(" by DROP+CREATE\n"
3299  "InnoDB: because there is a foreign key check"
3300  " running on it.\n",
3301  stderr);
3302  err = DB_ERROR;
3303 
3304  goto funct_exit;
3305  }
3306 
3307  /* Remove all locks except the table-level X lock. */
3308 
3309  lock_remove_all_on_table(table, FALSE);
3310 
3311  /* Ensure that the table will be dropped by
3312  trx_rollback_active() in case of a crash. */
3313 
3314  trx->table_id = table->id;
3316 
3317  /* Assign an undo segment for the transaction, so that the
3318  transaction will be recovered after a crash. */
3319 
3320  mutex_enter(&trx->undo_mutex);
3321 
3322  err = trx_undo_assign_undo(trx, TRX_UNDO_UPDATE);
3323 
3324  mutex_exit(&trx->undo_mutex);
3325 
3326  if (err != DB_SUCCESS) {
3327 
3328  goto funct_exit;
3329  }
3330 
3331  if (table->space && !table->dir_path_of_temp_table) {
3332  /* Discard and create the single-table tablespace. */
3333  ulint space = table->space;
3334  ulint flags = fil_space_get_flags(space);
3335 
3336  ut_a(!DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY));
3337 
3338  dict_get_and_save_data_dir_path(table, true);
3339 
3340  if (flags != ULINT_UNDEFINED
3341  && fil_discard_tablespace(space) == DB_SUCCESS) {
3342 
3344 
3345  dict_hdr_get_new_id(NULL, NULL, &space);
3346 
3347  /* Lock all index trees for this table. We must
3348  do so after dict_hdr_get_new_id() to preserve
3349  the latch order */
3351 
3352  if (space == ULINT_UNDEFINED
3354  space, table->name,
3355  table->data_dir_path,
3356  flags, table->flags2,
3358  != DB_SUCCESS) {
3360 
3361  ib_logf(IB_LOG_LEVEL_ERROR,
3362  "TRUNCATE TABLE %s failed to "
3363  "create a new tablespace",
3364  table->name);
3365 
3366  table->ibd_file_missing = 1;
3367  err = DB_ERROR;
3368  goto funct_exit;
3369  }
3370 
3371  recreate_space = space;
3372 
3373  /* Replace the space_id in the data dictionary cache.
3374  The persisent data dictionary (SYS_TABLES.SPACE
3375  and SYS_INDEXES.SPACE) are updated later in this
3376  function. */
3377  table->space = space;
3378  index = dict_table_get_first_index(table);
3379  do {
3380  index->space = space;
3381  index = dict_table_get_next_index(index);
3382  } while (index);
3383 
3384  mtr_start(&mtr);
3385  fsp_header_init(space,
3387  mtr_commit(&mtr);
3388  }
3389  } else {
3390  /* Lock all index trees for this table, as we will
3391  truncate the table/index and possibly change their metadata.
3392  All DML/DDL are blocked by table level lock, with
3393  a few exceptions such as queries into information schema
3394  about the table, MySQL could try to access index stats
3395  for this kind of query, we need to use index locks to
3396  sync up */
3398  }
3399 
3400  /* scan SYS_INDEXES for all indexes of the table */
3401  heap = mem_heap_create(800);
3402 
3403  tuple = dtuple_create(heap, 1);
3404  dfield = dtuple_get_nth_field(tuple, 0);
3405 
3406  buf = static_cast<byte*>(mem_heap_alloc(heap, 8));
3407  mach_write_to_8(buf, table->id);
3408 
3409  dfield_set_data(dfield, buf, 8);
3410  sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
3411  dict_index_copy_types(tuple, sys_index, 1);
3412 
3413  mtr_start(&mtr);
3414  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
3415  BTR_MODIFY_LEAF, &pcur, &mtr);
3416  for (;;) {
3417  rec_t* rec;
3418  const byte* field;
3419  ulint len;
3420  ulint root_page_no;
3421 
3422  if (!btr_pcur_is_on_user_rec(&pcur)) {
3423  /* The end of SYS_INDEXES has been reached. */
3424  break;
3425  }
3426 
3427  rec = btr_pcur_get_rec(&pcur);
3428 
3429  field = rec_get_nth_field_old(
3430  rec, DICT_FLD__SYS_INDEXES__TABLE_ID, &len);
3431  ut_ad(len == 8);
3432 
3433  if (memcmp(buf, field, len) != 0) {
3434  /* End of indexes for the table (TABLE_ID mismatch). */
3435  break;
3436  }
3437 
3438  if (rec_get_deleted_flag(rec, FALSE)) {
3439  /* The index has been dropped. */
3440  goto next_rec;
3441  }
3442 
3443  /* This call may commit and restart mtr
3444  and reposition pcur. */
3445  root_page_no = dict_truncate_index_tree(table, recreate_space,
3446  &pcur, &mtr);
3447 
3448  rec = btr_pcur_get_rec(&pcur);
3449 
3450  if (root_page_no != FIL_NULL) {
3452  rec, DICT_FLD__SYS_INDEXES__PAGE_NO,
3453  root_page_no, &mtr);
3454  /* We will need to commit and restart the
3455  mini-transaction in order to avoid deadlocks.
3456  The dict_truncate_index_tree() call has allocated
3457  a page in this mini-transaction, and the rest of
3458  this loop could latch another index page. */
3459  mtr_commit(&mtr);
3460  mtr_start(&mtr);
3461  btr_pcur_restore_position(BTR_MODIFY_LEAF,
3462  &pcur, &mtr);
3463  }
3464 
3465 next_rec:
3466  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
3467  }
3468 
3469  btr_pcur_close(&pcur);
3470  mtr_commit(&mtr);
3471 
3472  mem_heap_free(heap);
3473  /* Done with index truncation, release index tree locks,
3474  subsequent work relates to table level metadata change */
3476 
3477  dict_hdr_get_new_id(&new_id, NULL, NULL);
3478 
3479  /* Create new FTS auxiliary tables with the new_id, and
3480  drop the old index later, only if everything runs successful. */
3481  has_internal_doc_id = dict_table_has_fts_index(table)
3482  || DICT_TF2_FLAG_IS_SET(
3483  table, DICT_TF2_FTS_HAS_DOC_ID);
3484  if (has_internal_doc_id) {
3486  ulint i;
3487 
3488  fts_table.name = table->name;
3489  fts_table.id = new_id;
3490 
3492  trx, &fts_table, table->name, TRUE);
3493 
3494  for (i = 0;
3495  i < ib_vector_size(table->fts->indexes)
3496  && err == DB_SUCCESS;
3497  i++) {
3498 
3499  dict_index_t* fts_index;
3500 
3501  fts_index = static_cast<dict_index_t*>(
3502  ib_vector_getp(table->fts->indexes, i));
3503 
3505  trx, fts_index, table->name, new_id);
3506  }
3507 
3508  if (err != DB_SUCCESS) {
3509  trx->error_state = DB_SUCCESS;
3510  trx_rollback_to_savepoint(trx, NULL);
3511  trx->error_state = DB_SUCCESS;
3512  ut_print_timestamp(stderr);
3513  fputs(" InnoDB: Unable to truncate FTS index for"
3514  " table", stderr);
3515  ut_print_name(stderr, trx, TRUE, table->name);
3516  fputs("\n", stderr);
3517 
3518  goto funct_exit;
3519  } else {
3520  ut_ad(trx->state != TRX_STATE_NOT_STARTED);
3521  }
3522  }
3523 
3524  info = pars_info_create();
3525 
3526  pars_info_add_int4_literal(info, "new_space", (lint) table->space);
3527  pars_info_add_ull_literal(info, "old_id", table->id);
3528  pars_info_add_ull_literal(info, "new_id", new_id);
3529 
3530  err = que_eval_sql(info,
3531  "PROCEDURE RENUMBER_TABLE_ID_PROC () IS\n"
3532  "BEGIN\n"
3533  "UPDATE SYS_TABLES"
3534  " SET ID = :new_id, SPACE = :new_space\n"
3535  " WHERE ID = :old_id;\n"
3536  "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
3537  " WHERE TABLE_ID = :old_id;\n"
3538  "UPDATE SYS_INDEXES"
3539  " SET TABLE_ID = :new_id, SPACE = :new_space\n"
3540  " WHERE TABLE_ID = :old_id;\n"
3541  "END;\n"
3542  , FALSE, trx);
3543 
3544  if (err == DB_SUCCESS && old_space != table->space) {
3545  info = pars_info_create();
3546 
3547  pars_info_add_int4_literal(info, "old_space", (lint) old_space);
3548 
3550  info, "new_space", (lint) table->space);
3551 
3552  err = que_eval_sql(info,
3553  "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
3554  "BEGIN\n"
3555  "UPDATE SYS_TABLESPACES"
3556  " SET SPACE = :new_space\n"
3557  " WHERE SPACE = :old_space;\n"
3558  "UPDATE SYS_DATAFILES"
3559  " SET SPACE = :new_space"
3560  " WHERE SPACE = :old_space;\n"
3561  "END;\n"
3562  , FALSE, trx);
3563  }
3564  DBUG_EXECUTE_IF("ib_ddl_crash_before_fts_truncate", err = DB_ERROR;);
3565 
3566  if (err != DB_SUCCESS) {
3567  trx->error_state = DB_SUCCESS;
3568  trx_rollback_to_savepoint(trx, NULL);
3569  trx->error_state = DB_SUCCESS;
3570 
3571  /* Update system table failed. Table in memory metadata
3572  could be in an inconsistent state, mark the in-memory
3573  table->corrupted to be true. In the long run, this should
3574  be fixed by atomic truncate table */
3575  table->corrupted = true;
3576 
3577  ut_print_timestamp(stderr);
3578  fputs(" InnoDB: Unable to assign a new identifier to table ",
3579  stderr);
3580  ut_print_name(stderr, trx, TRUE, table->name);
3581  fputs("\n"
3582  "InnoDB: after truncating it. Background processes"
3583  " may corrupt the table!\n", stderr);
3584 
3585  /* Failed to update the table id, so drop the new
3586  FTS auxiliary tables */
3587  if (has_internal_doc_id) {
3588  ut_ad(trx->state == TRX_STATE_NOT_STARTED);
3589 
3590  table_id_t id = table->id;
3591 
3592  table->id = new_id;
3593 
3594  fts_drop_tables(trx, table);
3595 
3596  table->id = id;
3597 
3598  ut_ad(trx->state != TRX_STATE_NOT_STARTED);
3599  }
3600 
3601  err = DB_ERROR;
3602  } else {
3603  /* Drop the old FTS index */
3604  if (has_internal_doc_id) {
3605  ut_ad(trx->state != TRX_STATE_NOT_STARTED);
3606  fts_drop_tables(trx, table);
3607  ut_ad(trx->state != TRX_STATE_NOT_STARTED);
3608  }
3609 
3610  DBUG_EXECUTE_IF("ib_truncate_crash_after_fts_drop",
3611  DBUG_SUICIDE(););
3612 
3613  dict_table_change_id_in_cache(table, new_id);
3614 
3615  /* Reset the Doc ID in cache to 0 */
3616  if (has_internal_doc_id && table->fts->cache) {
3617  table->fts->fts_status |= TABLE_DICT_LOCKED;
3618  fts_update_next_doc_id(trx, table, NULL, 0);
3619  fts_cache_clear(table->fts->cache, TRUE);
3620  fts_cache_init(table->fts->cache);
3621  table->fts->fts_status &= ~TABLE_DICT_LOCKED;
3622  }
3623  }
3624 
3625  /* Reset auto-increment. */
3626  dict_table_autoinc_lock(table);
3629 
3630  trx_commit_for_mysql(trx);
3631 
3632 funct_exit:
3633 
3635 
3636  dict_stats_update(table, DICT_STATS_EMPTY_TABLE);
3637 
3638  trx->op_info = "";
3639 
3641 
3642  return(err);
3643 }
3644 
3645 /*********************************************************************/
3653 UNIV_INTERN
3654 dberr_t
3656 /*=====================*/
3657  const char* name,
3658  trx_t* trx,
3659  bool drop_db,
3660  bool nonatomic)
3663 {
3664  dberr_t err;
3665  dict_foreign_t* foreign;
3667  ibool print_msg;
3668  ulint space_id;
3669  char* filepath = NULL;
3670  const char* tablename_minus_db;
3671  char* tablename = NULL;
3672  bool ibd_file_missing;
3673  ulint namelen;
3674  bool locked_dictionary = false;
3675  pars_info_t* info = NULL;
3676  mem_heap_t* heap = NULL;
3677 
3678  ut_a(name != NULL);
3679 
3680  if (srv_created_new_raw) {
3681  fputs("InnoDB: A new raw disk partition was initialized:\n"
3682  "InnoDB: we do not allow database modifications"
3683  " by the user.\n"
3684  "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
3685  " is replaced with raw.\n", stderr);
3686 
3687  return(DB_ERROR);
3688  }
3689 
3690  /* The table name is prefixed with the database name and a '/'.
3691  Certain table names starting with 'innodb_' have their special
3692  meaning regardless of the database name. Thus, we need to
3693  ignore the database name prefix in the comparisons. */
3694  tablename_minus_db = strchr(name, '/');
3695 
3696  if (tablename_minus_db) {
3697  tablename_minus_db++;
3698  } else {
3699  /* Ancillary FTS tables don't have '/' characters. */
3700  tablename_minus_db = name;
3701  }
3702 
3703  namelen = strlen(tablename_minus_db) + 1;
3704 
3705  if (namelen == sizeof S_innodb_monitor
3706  && !memcmp(tablename_minus_db, S_innodb_monitor,
3707  sizeof S_innodb_monitor)) {
3708 
3709  /* Table name equals "innodb_monitor":
3710  stop monitor prints */
3711 
3712  srv_print_innodb_monitor = FALSE;
3713  srv_print_innodb_lock_monitor = FALSE;
3714  } else if (namelen == sizeof S_innodb_lock_monitor
3715  && !memcmp(tablename_minus_db, S_innodb_lock_monitor,
3716  sizeof S_innodb_lock_monitor)) {
3717  srv_print_innodb_monitor = FALSE;
3718  srv_print_innodb_lock_monitor = FALSE;
3719  } else if (namelen == sizeof S_innodb_tablespace_monitor
3720  && !memcmp(tablename_minus_db, S_innodb_tablespace_monitor,
3721  sizeof S_innodb_tablespace_monitor)) {
3722 
3723  srv_print_innodb_tablespace_monitor = FALSE;
3724  } else if (namelen == sizeof S_innodb_table_monitor
3725  && !memcmp(tablename_minus_db, S_innodb_table_monitor,
3726  sizeof S_innodb_table_monitor)) {
3727 
3728  srv_print_innodb_table_monitor = FALSE;
3729  }
3730 
3731  /* Serialize data dictionary operations with dictionary mutex:
3732  no deadlocks can occur then in these operations */
3733 
3734  trx->op_info = "dropping table";
3735 
3736  /* This function is called recursively via fts_drop_tables(). */
3737  if (trx->state == TRX_STATE_NOT_STARTED) {
3738  trx_start_for_ddl(trx, TRX_DICT_OP_TABLE);
3739  }
3740 
3741  if (trx->dict_operation_lock_mode != RW_X_LATCH) {
3742  /* Prevent foreign key checks etc. while we are dropping the
3743  table */
3744 
3745  row_mysql_lock_data_dictionary(trx);
3746 
3747  locked_dictionary = true;
3748  nonatomic = true;
3749  }
3750 
3751  ut_ad(mutex_own(&(dict_sys->mutex)));
3752 #ifdef UNIV_SYNC_DEBUG
3753  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3754 #endif /* UNIV_SYNC_DEBUG */
3755 
3756  table = dict_table_open_on_name(
3757  name, TRUE, FALSE,
3758  static_cast<dict_err_ignore_t>(
3760 
3761  if (!table) {
3762  err = DB_TABLE_NOT_FOUND;
3763  ut_print_timestamp(stderr);
3764 
3765  fputs(" InnoDB: Error: table ", stderr);
3766  ut_print_name(stderr, trx, TRUE, name);
3767  fputs(" does not exist in the InnoDB internal\n"
3768  "InnoDB: data dictionary though MySQL is"
3769  " trying to drop it.\n"
3770  "InnoDB: Have you copied the .frm file"
3771  " of the table to the\n"
3772  "InnoDB: MySQL database directory"
3773  " from another database?\n"
3774  "InnoDB: You can look for further help from\n"
3775  "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3776  stderr);
3777  goto funct_exit;
3778  }
3779 
3780  /* Turn on this drop bit before we could release the dictionary
3781  latch */
3782  table->to_be_dropped = true;
3783 
3784  if (nonatomic) {
3785  /* This trx did not acquire any locks on dictionary
3786  table records yet. Thus it is safe to release and
3787  reacquire the data dictionary latches. */
3788  if (table->fts) {
3789  ut_ad(!table->fts->add_wq);
3790  ut_ad(lock_trx_has_sys_table_locks(trx) == 0);
3791 
3794  row_mysql_lock_data_dictionary(trx);
3795  }
3796 
3797  /* Do not bother to deal with persistent stats for temp
3798  tables since we know temp tables do not use persistent
3799  stats. */
3800  if (!dict_table_is_temporary(table)) {
3802  table, trx);
3803  }
3804  }
3805 
3806  /* make sure background stats thread is not running on the table */
3808 
3809  /* Delete the link file if used. */
3810  if (DICT_TF_HAS_DATA_DIR(table->flags)) {
3811  fil_delete_link_file(name);
3812  }
3813 
3814  if (!dict_table_is_temporary(table)) {
3815 
3817 
3818  /* Remove stats for this table and all of its indexes from the
3819  persistent storage if it exists and if there are stats for this
3820  table in there. This function creates its own trx and commits
3821  it. */
3822  char errstr[1024];
3823  err = dict_stats_drop_table(name, errstr, sizeof(errstr));
3824 
3825  if (err != DB_SUCCESS) {
3826  ib_logf(IB_LOG_LEVEL_WARN, "%s", errstr);
3827  }
3828  }
3829 
3830  /* Move the table the the non-LRU list so that it isn't
3831  considered for eviction. */
3832 
3833  if (table->can_be_evicted) {
3835  }
3836 
3837  dict_table_close(table, TRUE, FALSE);
3838 
3839  /* Check if the table is referenced by foreign key constraints from
3840  some other table (not the table itself) */
3841 
3842  foreign = UT_LIST_GET_FIRST(table->referenced_list);
3843 
3844  while (foreign && foreign->foreign_table == table) {
3845 check_next_foreign:
3846  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3847  }
3848 
3849  if (!srv_read_only_mode
3850  && foreign
3851  && trx->check_foreigns
3852  && !(drop_db && dict_tables_have_same_db(
3853  name, foreign->foreign_table_name_lookup))) {
3854  FILE* ef = dict_foreign_err_file;
3855 
3856  /* We only allow dropping a referenced table if
3857  FOREIGN_KEY_CHECKS is set to 0 */
3858 
3860 
3861  mutex_enter(&dict_foreign_err_mutex);
3862  rewind(ef);
3863  ut_print_timestamp(ef);
3864 
3865  fputs(" Cannot drop table ", ef);
3866  ut_print_name(ef, trx, TRUE, name);
3867  fputs("\n"
3868  "because it is referenced by ", ef);
3869  ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3870  putc('\n', ef);
3871  mutex_exit(&dict_foreign_err_mutex);
3872 
3873  goto funct_exit;
3874  }
3875 
3876  if (foreign && trx->check_foreigns) {
3877  goto check_next_foreign;
3878  }
3879 
3880  /* TODO: could we replace the counter n_foreign_key_checks_running
3881  with lock checks on the table? Acquire here an exclusive lock on the
3882  table, and rewrite lock0lock.cc and the lock wait in srv0srv.cc so that
3883  they can cope with the table having been dropped here? Foreign key
3884  checks take an IS or IX lock on the table. */
3885 
3886  if (table->n_foreign_key_checks_running > 0) {
3887 
3888  const char* save_tablename = table->name;
3889  ibool added;
3890 
3891  added = row_add_table_to_background_drop_list(save_tablename);
3892 
3893  if (added) {
3894  ut_print_timestamp(stderr);
3895  fputs(" InnoDB: You are trying to drop table ",
3896  stderr);
3897  ut_print_name(stderr, trx, TRUE, save_tablename);
3898  fputs("\n"
3899  "InnoDB: though there is a"
3900  " foreign key check running on it.\n"
3901  "InnoDB: Adding the table to"
3902  " the background drop queue.\n",
3903  stderr);
3904 
3905  /* We return DB_SUCCESS to MySQL though the drop will
3906  happen lazily later */
3907 
3908  err = DB_SUCCESS;
3909  } else {
3910  /* The table is already in the background drop list */
3911  err = DB_ERROR;
3912  }
3913 
3914  goto funct_exit;
3915  }
3916 
3917  /* Remove all locks that are on the table or its records, if there
3918  are no refernces to the table but it has record locks, we release
3919  the record locks unconditionally. One use case is:
3920 
3921  CREATE TABLE t2 (PRIMARY KEY (a)) SELECT * FROM t1;
3922 
3923  If after the user transaction has done the SELECT and there is a
3924  problem in completing the CREATE TABLE operation, MySQL will drop
3925  the table. InnoDB will create a new background transaction to do the
3926  actual drop, the trx instance that is passed to this function. To
3927  preserve existing behaviour we remove the locks but ideally we
3928  shouldn't have to. There should never be record locks on a table
3929  that is going to be dropped. */
3930 
3931  if (table->n_ref_count == 0) {
3932  lock_remove_all_on_table(table, TRUE);
3933  ut_a(table->n_rec_locks == 0);
3934  } else if (table->n_ref_count > 0 || table->n_rec_locks > 0) {
3935  ibool added;
3936 
3937  added = row_add_table_to_background_drop_list(table->name);
3938 
3939  if (added) {
3940  ut_print_timestamp(stderr);
3941  fputs(" InnoDB: Warning: MySQL is"
3942  " trying to drop table ", stderr);
3943  ut_print_name(stderr, trx, TRUE, table->name);
3944  fputs("\n"
3945  "InnoDB: though there are still"
3946  " open handles to it.\n"
3947  "InnoDB: Adding the table to the"
3948  " background drop queue.\n",
3949  stderr);
3950 
3951  /* We return DB_SUCCESS to MySQL though the drop will
3952  happen lazily later */
3953  err = DB_SUCCESS;
3954  } else {
3955  /* The table is already in the background drop list */
3956  err = DB_ERROR;
3957  }
3958 
3959  goto funct_exit;
3960  }
3961 
3962  /* The "to_be_dropped" marks table that is to be dropped, but
3963  has not been dropped, instead, was put in the background drop
3964  list due to being used by concurrent DML operations. Clear it
3965  here since there are no longer any concurrent activities on it,
3966  and it is free to be dropped */
3967  table->to_be_dropped = false;
3968 
3969  /* If we get this far then the table to be dropped must not have
3970  any table or record locks on it. */
3971 
3972  ut_a(!lock_table_has_locks(table));
3973 
3974  switch (trx_get_dict_operation(trx)) {
3975  case TRX_DICT_OP_NONE:
3977  trx->table_id = table->id;
3978  case TRX_DICT_OP_TABLE:
3979  break;
3980  case TRX_DICT_OP_INDEX:
3981  /* If the transaction was previously flagged as
3982  TRX_DICT_OP_INDEX, we should be dropping auxiliary
3983  tables for full-text indexes. */
3984  ut_ad(strstr(table->name, "/FTS_") != NULL);
3985  }
3986 
3987  /* Mark all indexes unavailable in the data dictionary cache
3988  before starting to drop the table. */
3989 
3990  unsigned* page_no;
3991  unsigned* page_nos;
3992  heap = mem_heap_create(
3993  200 + UT_LIST_GET_LEN(table->indexes) * sizeof *page_nos);
3994  tablename = mem_heap_strdup(heap, name);
3995 
3996  page_no = page_nos = static_cast<unsigned*>(
3998  heap,
3999  UT_LIST_GET_LEN(table->indexes) * sizeof *page_no));
4000 
4001  for (dict_index_t* index = dict_table_get_first_index(table);
4002  index != NULL;
4003  index = dict_table_get_next_index(index)) {
4004  rw_lock_x_lock(dict_index_get_lock(index));
4005  /* Save the page numbers so that we can restore them
4006  if the operation fails. */
4007  *page_no++ = index->page;
4008  /* Mark the index unusable. */
4009  index->page = FIL_NULL;
4010  rw_lock_x_unlock(dict_index_get_lock(index));
4011  }
4012 
4013  /* We use the private SQL parser of Innobase to generate the
4014  query graphs needed in deleting the dictionary data from system
4015  tables in Innobase. Deleting a row from SYS_INDEXES table also
4016  frees the file segments of the B-tree associated with the index. */
4017 
4018  info = pars_info_create();
4019 
4020  pars_info_add_str_literal(info, "table_name", name);
4021 
4022  err = que_eval_sql(info,
4023  "PROCEDURE DROP_TABLE_PROC () IS\n"
4024  "sys_foreign_id CHAR;\n"
4025  "table_id CHAR;\n"
4026  "index_id CHAR;\n"
4027  "foreign_id CHAR;\n"
4028  "space_id INT;\n"
4029  "found INT;\n"
4030 
4031  "DECLARE CURSOR cur_fk IS\n"
4032  "SELECT ID FROM SYS_FOREIGN\n"
4033  "WHERE FOR_NAME = :table_name\n"
4034  "AND TO_BINARY(FOR_NAME)\n"
4035  " = TO_BINARY(:table_name)\n"
4036  "LOCK IN SHARE MODE;\n"
4037 
4038  "DECLARE CURSOR cur_idx IS\n"
4039  "SELECT ID FROM SYS_INDEXES\n"
4040  "WHERE TABLE_ID = table_id\n"
4041  "LOCK IN SHARE MODE;\n"
4042 
4043  "BEGIN\n"
4044  "SELECT ID INTO table_id\n"
4045  "FROM SYS_TABLES\n"
4046  "WHERE NAME = :table_name\n"
4047  "LOCK IN SHARE MODE;\n"
4048  "IF (SQL % NOTFOUND) THEN\n"
4049  " RETURN;\n"
4050  "END IF;\n"
4051  "SELECT SPACE INTO space_id\n"
4052  "FROM SYS_TABLES\n"
4053  "WHERE NAME = :table_name;\n"
4054  "IF (SQL % NOTFOUND) THEN\n"
4055  " RETURN;\n"
4056  "END IF;\n"
4057  "found := 1;\n"
4058  "SELECT ID INTO sys_foreign_id\n"
4059  "FROM SYS_TABLES\n"
4060  "WHERE NAME = 'SYS_FOREIGN'\n"
4061  "LOCK IN SHARE MODE;\n"
4062  "IF (SQL % NOTFOUND) THEN\n"
4063  " found := 0;\n"
4064  "END IF;\n"
4065  "IF (:table_name = 'SYS_FOREIGN') THEN\n"
4066  " found := 0;\n"
4067  "END IF;\n"
4068  "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
4069  " found := 0;\n"
4070  "END IF;\n"
4071  "OPEN cur_fk;\n"
4072  "WHILE found = 1 LOOP\n"
4073  " FETCH cur_fk INTO foreign_id;\n"
4074  " IF (SQL % NOTFOUND) THEN\n"
4075  " found := 0;\n"
4076  " ELSE\n"
4077  " DELETE FROM SYS_FOREIGN_COLS\n"
4078  " WHERE ID = foreign_id;\n"
4079  " DELETE FROM SYS_FOREIGN\n"
4080  " WHERE ID = foreign_id;\n"
4081  " END IF;\n"
4082  "END LOOP;\n"
4083  "CLOSE cur_fk;\n"
4084  "found := 1;\n"
4085  "OPEN cur_idx;\n"
4086  "WHILE found = 1 LOOP\n"
4087  " FETCH cur_idx INTO index_id;\n"
4088  " IF (SQL % NOTFOUND) THEN\n"
4089  " found := 0;\n"
4090  " ELSE\n"
4091  " DELETE FROM SYS_FIELDS\n"
4092  " WHERE INDEX_ID = index_id;\n"
4093  " DELETE FROM SYS_INDEXES\n"
4094  " WHERE ID = index_id\n"
4095  " AND TABLE_ID = table_id;\n"
4096  " END IF;\n"
4097  "END LOOP;\n"
4098  "CLOSE cur_idx;\n"
4099  "DELETE FROM SYS_TABLESPACES\n"
4100  "WHERE SPACE = space_id;\n"
4101  "DELETE FROM SYS_DATAFILES\n"
4102  "WHERE SPACE = space_id;\n"
4103  "DELETE FROM SYS_COLUMNS\n"
4104  "WHERE TABLE_ID = table_id;\n"
4105  "DELETE FROM SYS_TABLES\n"
4106  "WHERE NAME = :table_name;\n"
4107  "END;\n"
4108  , FALSE, trx);
4109 
4110  switch (err) {
4111  ibool is_temp;
4112 
4113  case DB_SUCCESS:
4114  /* Clone the name, in case it has been allocated
4115  from table->heap, which will be freed by
4116  dict_table_remove_from_cache(table) below. */
4117  space_id = table->space;
4118  ibd_file_missing = table->ibd_file_missing;
4119 
4120  is_temp = DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY);
4121 
4122  /* If there is a temp path then the temp flag is set.
4123  However, during recovery, we might have a temp flag but
4124  not know the temp path */
4125  ut_a(table->dir_path_of_temp_table == NULL || is_temp);
4126  if (dict_table_is_discarded(table)
4127  || table->ibd_file_missing) {
4128  /* Do not attempt to drop known-to-be-missing
4129  tablespaces. */
4130  space_id = 0;
4131  }
4132 
4133  /* We do not allow temporary tables with a remote path. */
4134  ut_a(!(is_temp && DICT_TF_HAS_DATA_DIR(table->flags)));
4135 
4136  if (space_id && DICT_TF_HAS_DATA_DIR(table->flags)) {
4137  dict_get_and_save_data_dir_path(table, true);
4138  ut_a(table->data_dir_path);
4139 
4140  filepath = os_file_make_remote_pathname(
4141  table->data_dir_path, table->name, "ibd");
4142  } else if (table->dir_path_of_temp_table) {
4143  filepath = fil_make_ibd_name(
4144  table->dir_path_of_temp_table, true);
4145  } else {
4146  filepath = fil_make_ibd_name(tablename, false);
4147  }
4148 
4149  if (dict_table_has_fts_index(table)
4150  || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)) {
4151  ut_ad(table->n_ref_count == 0);
4152  ut_ad(trx->state != TRX_STATE_NOT_STARTED);
4153  err = fts_drop_tables(trx, table);
4154 
4155  if (err != DB_SUCCESS) {
4156  ut_print_timestamp(stderr);
4157  fprintf(stderr," InnoDB: Error: (%s) not "
4158  "able to remove ancillary FTS tables "
4159  "for table ", ut_strerr(err));
4160  ut_print_name(stderr, trx, TRUE, tablename);
4161  fputs("\n", stderr);
4162 
4163  goto funct_exit;
4164  }
4165  }
4166 
4167  /* The table->fts flag can be set on the table for which
4168  the cluster index is being rebuilt. Such table might not have
4169  DICT_TF2_FTS flag set. So keep this out of above
4170  dict_table_has_fts_index condition */
4171  if (table->fts) {
4172  /* Need to set TABLE_DICT_LOCKED bit, since
4173  fts_que_graph_free_check_lock would try to acquire
4174  dict mutex lock */
4175  table->fts->fts_status |= TABLE_DICT_LOCKED;
4176 
4177  fts_free(table);
4178  }
4179 
4181 
4182  if (dict_load_table(tablename, TRUE,
4183  DICT_ERR_IGNORE_NONE) != NULL) {
4184  ut_print_timestamp(stderr);
4185  fputs(" InnoDB: Error: not able to remove table ",
4186  stderr);
4187  ut_print_name(stderr, trx, TRUE, tablename);
4188  fputs(" from the dictionary cache!\n", stderr);
4189  err = DB_ERROR;
4190  }
4191 
4192  /* Do not drop possible .ibd tablespace if something went
4193  wrong: we do not want to delete valuable data of the user */
4194 
4195  /* Don't spam the log if we can't find the tablespace of
4196  a temp table or if the tablesace has been discarded. */
4197  print_msg = !(is_temp || ibd_file_missing);
4198 
4199  if (err == DB_SUCCESS && space_id > TRX_SYS_SPACE) {
4200  if (!is_temp
4202  space_id, tablename, FALSE,
4203  print_msg, false, NULL, 0)) {
4204  /* This might happen if we are dropping a
4205  discarded tablespace */
4206  err = DB_SUCCESS;
4207 
4208  if (print_msg) {
4209  char msg_tablename[MAX_FULL_NAME_LEN + 1];
4210 
4212  msg_tablename, sizeof(tablename),
4213  tablename, FALSE);
4214 
4215  ib_logf(IB_LOG_LEVEL_INFO,
4216  "Removed the table %s from "
4217  "InnoDB's data dictionary",
4218  msg_tablename);
4219  }
4220 
4221  /* Force a delete of any discarded
4222  or temporary files. */
4223 
4224  fil_delete_file(filepath);
4225 
4226  } else if (fil_delete_tablespace(
4227  space_id,
4229  != DB_SUCCESS) {
4230  fprintf(stderr,
4231  "InnoDB: We removed now the InnoDB"
4232  " internal data dictionary entry\n"
4233  "InnoDB: of table ");
4234  ut_print_name(stderr, trx, TRUE, tablename);
4235  fprintf(stderr, ".\n");
4236 
4237  ut_print_timestamp(stderr);
4238  fprintf(stderr,
4239  " InnoDB: Error: not able to"
4240  " delete tablespace %lu of table ",
4241  (ulong) space_id);
4242  ut_print_name(stderr, trx, TRUE, tablename);
4243  fputs("!\n", stderr);
4244  err = DB_ERROR;
4245  }
4246  }
4247 
4248  break;
4249 
4250  case DB_OUT_OF_FILE_SPACE:
4252 
4253  row_mysql_handle_errors(&err, trx, NULL, NULL);
4254 
4255  /* raise error */
4256  ut_error;
4257  break;
4258 
4260  /* Cannot even find a free slot for the
4261  the undo log. We can directly exit here
4262  and return the DB_TOO_MANY_CONCURRENT_TRXS
4263  error. */
4264 
4265  default:
4266  /* This is some error we do not expect. Print
4267  the error number and rollback transaction */
4268  ut_print_timestamp(stderr);
4269 
4270  fprintf(stderr, "InnoDB: unknown error code %lu"
4271  " while dropping table:", (ulong) err);
4272  ut_print_name(stderr, trx, TRUE, tablename);
4273  fprintf(stderr, ".\n");
4274 
4275  trx->error_state = DB_SUCCESS;
4276  trx_rollback_to_savepoint(trx, NULL);
4277  trx->error_state = DB_SUCCESS;
4278 
4279  /* Mark all indexes available in the data dictionary
4280  cache again. */
4281 
4282  page_no = page_nos;
4283 
4284  for (dict_index_t* index = dict_table_get_first_index(table);
4285  index != NULL;
4286  index = dict_table_get_next_index(index)) {
4287  rw_lock_x_lock(dict_index_get_lock(index));
4288  ut_a(index->page == FIL_NULL);
4289  index->page = *page_no++;
4290  rw_lock_x_unlock(dict_index_get_lock(index));
4291  }
4292  }
4293 
4294 funct_exit:
4295  if (heap) {
4296  mem_heap_free(heap);
4297  }
4298  if (filepath) {
4299  mem_free(filepath);
4300  }
4301 
4302  if (locked_dictionary) {
4303  trx_commit_for_mysql(trx);
4304 
4306  }
4307 
4308  trx->op_info = "";
4309 
4311 
4312  return(err);
4313 }
4314 
4315 /*********************************************************************/
4317 UNIV_INTERN
4318 void
4320 /*============================*/
4321 {
4322  trx_t* trx;
4323  btr_pcur_t pcur;
4324  mtr_t mtr;
4325  mem_heap_t* heap;
4326 
4328  trx->op_info = "dropping temporary tables";
4329  row_mysql_lock_data_dictionary(trx);
4330 
4331  heap = mem_heap_create(200);
4332 
4333  mtr_start(&mtr);
4334 
4336  true,
4337  dict_table_get_first_index(dict_sys->sys_tables),
4338  BTR_SEARCH_LEAF, &pcur, true, 0, &mtr);
4339 
4340  for (;;) {
4341  const rec_t* rec;
4342  const byte* field;
4343  ulint len;
4344  const char* table_name;
4346 
4347  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
4348 
4349  if (!btr_pcur_is_on_user_rec(&pcur)) {
4350  break;
4351  }
4352 
4353  /* The high order bit of N_COLS is set unless
4354  ROW_FORMAT=REDUNDANT. */
4355  rec = btr_pcur_get_rec(&pcur);
4356  field = rec_get_nth_field_old(
4357  rec, DICT_FLD__SYS_TABLES__NAME, &len);
4358  field = rec_get_nth_field_old(
4359  rec, DICT_FLD__SYS_TABLES__N_COLS, &len);
4360  if (len != 4
4361  || !(mach_read_from_4(field) & DICT_N_COLS_COMPACT)) {
4362  continue;
4363  }
4364 
4365  /* Older versions of InnoDB, which only supported tables
4366  in ROW_FORMAT=REDUNDANT could write garbage to
4367  SYS_TABLES.MIX_LEN, where we now store the is_temp flag.
4368  Above, we assumed is_temp=0 if ROW_FORMAT=REDUNDANT. */
4369  field = rec_get_nth_field_old(
4370  rec, DICT_FLD__SYS_TABLES__MIX_LEN, &len);
4371  if (len != 4
4372  || !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) {
4373  continue;
4374  }
4375 
4376  /* This is a temporary table. */
4377  field = rec_get_nth_field_old(
4378  rec, DICT_FLD__SYS_TABLES__NAME, &len);
4379  if (len == UNIV_SQL_NULL || len == 0) {
4380  /* Corrupted SYS_TABLES.NAME */
4381  continue;
4382  }
4383 
4384  table_name = mem_heap_strdupl(heap, (const char*) field, len);
4385 
4386  btr_pcur_store_position(&pcur, &mtr);
4387  btr_pcur_commit_specify_mtr(&pcur, &mtr);
4388 
4389  table = dict_load_table(table_name, TRUE, DICT_ERR_IGNORE_NONE);
4390 
4391  if (table) {
4392  row_drop_table_for_mysql(table_name, trx, FALSE);
4393  trx_commit_for_mysql(trx);
4394  }
4395 
4396  mtr_start(&mtr);
4397  btr_pcur_restore_position(BTR_SEARCH_LEAF,
4398  &pcur, &mtr);
4399  }
4400 
4401  btr_pcur_close(&pcur);
4402  mtr_commit(&mtr);
4403  mem_heap_free(heap);
4406 }
4407 
4408 /*******************************************************************/
4412 static __attribute__((nonnull, warn_unused_result))
4413 dberr_t
4414 drop_all_foreign_keys_in_db(
4415 /*========================*/
4416  const char* name,
4417  trx_t* trx)
4418 {
4419  pars_info_t* pinfo;
4420  dberr_t err;
4421 
4422  ut_a(name[strlen(name) - 1] == '/');
4423 
4424  pinfo = pars_info_create();
4425 
4426  pars_info_add_str_literal(pinfo, "dbname", name);
4427 
4429 #define TABLE_NOT_IN_THIS_DB \
4430 "SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
4431 
4432  err = que_eval_sql(pinfo,
4433  "PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
4434  "foreign_id CHAR;\n"
4435  "for_name CHAR;\n"
4436  "found INT;\n"
4437  "DECLARE CURSOR cur IS\n"
4438  "SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
4439  "WHERE FOR_NAME >= :dbname\n"
4440  "LOCK IN SHARE MODE\n"
4441  "ORDER BY FOR_NAME;\n"
4442  "BEGIN\n"
4443  "found := 1;\n"
4444  "OPEN cur;\n"
4445  "WHILE found = 1 LOOP\n"
4446  " FETCH cur INTO foreign_id, for_name;\n"
4447  " IF (SQL % NOTFOUND) THEN\n"
4448  " found := 0;\n"
4449  " ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
4450  " found := 0;\n"
4451  " ELSIF (1=1) THEN\n"
4452  " DELETE FROM SYS_FOREIGN_COLS\n"
4453  " WHERE ID = foreign_id;\n"
4454  " DELETE FROM SYS_FOREIGN\n"
4455  " WHERE ID = foreign_id;\n"
4456  " END IF;\n"
4457  "END LOOP;\n"
4458  "CLOSE cur;\n"
4459  "COMMIT WORK;\n"
4460  "END;\n",
4461  FALSE, /* do not reserve dict mutex,
4462  we are already holding it */
4463  trx);
4464 
4465  return(err);
4466 }
4467 
4468 /*********************************************************************/
4471 UNIV_INTERN
4472 dberr_t
4474 /*========================*/
4475  const char* name,
4476  trx_t* trx)
4477 {
4479  char* table_name;
4480  dberr_t err = DB_SUCCESS;
4481  ulint namelen = strlen(name);
4482 
4483  ut_a(name != NULL);
4484  ut_a(name[namelen - 1] == '/');
4485 
4486  trx->op_info = "dropping database";
4487 
4489 
4490  trx_start_if_not_started_xa(trx);
4491 loop:
4492  row_mysql_lock_data_dictionary(trx);
4493 
4494  while ((table_name = dict_get_first_table_name_in_db(name))) {
4495  ut_a(memcmp(table_name, name, namelen) == 0);
4496 
4497  table = dict_table_open_on_name(
4498  table_name, TRUE, FALSE, static_cast<dict_err_ignore_t>(
4501 
4502  if (!table) {
4503  ib_logf(IB_LOG_LEVEL_ERROR,
4504  "Cannot load table %s from InnoDB internal "
4505  "data dictionary during drop database",
4506  table_name);
4507  mem_free(table_name);
4508  err = DB_TABLE_NOT_FOUND;
4509  break;
4510 
4511  }
4512 
4513  if (!row_is_mysql_tmp_table_name(table->name)) {
4514  /* There could be orphan temp tables left from
4515  interrupted alter table. Leave them, and handle
4516  the rest.*/
4517  if (table->can_be_evicted) {
4518  ib_logf(IB_LOG_LEVEL_WARN,
4519  "Orphan table encountered during "
4520  "DROP DATABASE. This is possible if "
4521  "'%s.frm' was lost.", table->name);
4522  }
4523 
4524  if (table->ibd_file_missing) {
4525  ib_logf(IB_LOG_LEVEL_WARN,
4526  "Missing %s.ibd file for table %s.",
4527  table->name, table->name);
4528  }
4529  }
4530 
4531  dict_table_close(table, TRUE, FALSE);
4532 
4533  /* The dict_table_t object must not be accessed before
4534  dict_table_open() or after dict_table_close(). But this is OK
4535  if we are holding, the dict_sys->mutex. */
4536  ut_ad(mutex_own(&dict_sys->mutex));
4537 
4538  /* Wait until MySQL does not have any queries running on
4539  the table */
4540 
4541  if (table->n_ref_count > 0) {
4543 
4544  ut_print_timestamp(stderr);
4545  fputs(" InnoDB: Warning: MySQL is trying to"
4546  " drop database ", stderr);
4547  ut_print_name(stderr, trx, TRUE, name);
4548  fputs("\n"
4549  "InnoDB: though there are still"
4550  " open handles to table ", stderr);
4551  ut_print_name(stderr, trx, TRUE, table_name);
4552  fputs(".\n", stderr);
4553 
4554  os_thread_sleep(1000000);
4555 
4556  mem_free(table_name);
4557 
4558  goto loop;
4559  }
4560 
4561  err = row_drop_table_for_mysql(table_name, trx, TRUE);
4562  trx_commit_for_mysql(trx);
4563 
4564  if (err != DB_SUCCESS) {
4565  fputs("InnoDB: DROP DATABASE ", stderr);
4566  ut_print_name(stderr, trx, TRUE, name);
4567  fprintf(stderr, " failed with error (%s) for table ",
4568  ut_strerr(err));
4569  ut_print_name(stderr, trx, TRUE, table_name);
4570  putc('\n', stderr);
4571  mem_free(table_name);
4572  break;
4573  }
4574 
4575  mem_free(table_name);
4576  }
4577 
4578  if (err == DB_SUCCESS) {
4579  /* after dropping all tables try to drop all leftover
4580  foreign keys in case orphaned ones exist */
4581  err = drop_all_foreign_keys_in_db(name, trx);
4582 
4583  if (err != DB_SUCCESS) {
4584  fputs("InnoDB: DROP DATABASE ", stderr);
4585  ut_print_name(stderr, trx, TRUE, name);
4586  fprintf(stderr, " failed with error %d while "
4587  "dropping all foreign keys", err);
4588  }
4589  }
4590 
4591  trx_commit_for_mysql(trx);
4592 
4594 
4595  trx->op_info = "";
4596 
4597  return(err);
4598 }
4599 
4600 /*********************************************************************/
4604 UNIV_INTERN __attribute__((warn_unused_result))
4605 bool
4607 /*========================*/
4608  const char* name)
4610 {
4611  return(strstr(name, "/#sql") != NULL);
4612  /* return(strstr(name, "/@0023sql") != NULL); */
4613 }
4614 
4615 /****************************************************************/
4618 static __attribute__((nonnull, warn_unused_result))
4619 dberr_t
4620 row_delete_constraint_low(
4621 /*======================*/
4622  const char* id,
4623  trx_t* trx)
4624 {
4625  pars_info_t* info = pars_info_create();
4626 
4627  pars_info_add_str_literal(info, "id", id);
4628 
4629  return(que_eval_sql(info,
4630  "PROCEDURE DELETE_CONSTRAINT () IS\n"
4631  "BEGIN\n"
4632  "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
4633  "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
4634  "END;\n"
4635  , FALSE, trx));
4636 }
4637 
4638 /****************************************************************/
4641 static __attribute__((nonnull, warn_unused_result))
4642 dberr_t
4643 row_delete_constraint(
4644 /*==================*/
4645  const char* id,
4646  const char* database_name,
4648  mem_heap_t* heap,
4649  trx_t* trx)
4650 {
4651  dberr_t err;
4652 
4653  /* New format constraints have ids <databasename>/<constraintname>. */
4654  err = row_delete_constraint_low(
4655  mem_heap_strcat(heap, database_name, id), trx);
4656 
4657  if ((err == DB_SUCCESS) && !strchr(id, '/')) {
4658  /* Old format < 4.0.18 constraints have constraint ids
4659  NUMBER_NUMBER. We only try deleting them if the
4660  constraint name does not contain a '/' character, otherwise
4661  deleting a new format constraint named 'foo/bar' from
4662  database 'baz' would remove constraint 'bar' from database
4663  'foo', if it existed. */
4664 
4665  err = row_delete_constraint_low(id, trx);
4666  }
4667 
4668  return(err);
4669 }
4670 
4671 /*********************************************************************/
4674 UNIV_INTERN
4675 dberr_t
4677 /*=======================*/
4678  const char* old_name,
4679  const char* new_name,
4680  trx_t* trx,
4681  bool commit)
4682 {
4683  dict_table_t* table = NULL;
4684  ibool dict_locked = FALSE;
4685  dberr_t err = DB_ERROR;
4686  mem_heap_t* heap = NULL;
4687  const char** constraints_to_drop = NULL;
4688  ulint n_constraints_to_drop = 0;
4689  ibool old_is_tmp, new_is_tmp;
4690  pars_info_t* info = NULL;
4691  int retry;
4692 
4693  ut_a(old_name != NULL);
4694  ut_a(new_name != NULL);
4695  ut_ad(trx->state == TRX_STATE_ACTIVE);
4696 
4697  if (srv_created_new_raw || srv_force_recovery) {
4698  fputs("InnoDB: A new raw disk partition was initialized or\n"
4699  "InnoDB: innodb_force_recovery is on: we do not allow\n"
4700  "InnoDB: database modifications by the user. Shut down\n"
4701  "InnoDB: mysqld and edit my.cnf so that newraw"
4702  " is replaced\n"
4703  "InnoDB: with raw, and innodb_force_... is removed.\n",
4704  stderr);
4705 
4706  goto funct_exit;
4707  } else if (row_mysql_is_system_table(new_name)) {
4708 
4709  fprintf(stderr,
4710  "InnoDB: Error: trying to create a MySQL"
4711  " system table %s of type InnoDB.\n"
4712  "InnoDB: MySQL system tables must be"
4713  " of the MyISAM type!\n",
4714  new_name);
4715 
4716  goto funct_exit;
4717  }
4718 
4719  trx->op_info = "renaming table";
4720 
4721  old_is_tmp = row_is_mysql_tmp_table_name(old_name);
4722  new_is_tmp = row_is_mysql_tmp_table_name(new_name);
4723 
4724  dict_locked = trx->dict_operation_lock_mode == RW_X_LATCH;
4725 
4726  table = dict_table_open_on_name(old_name, dict_locked, FALSE,
4728 
4729  if (!table) {
4730  err = DB_TABLE_NOT_FOUND;
4731  ut_print_timestamp(stderr);
4732 
4733  fputs(" InnoDB: Error: table ", stderr);
4734  ut_print_name(stderr, trx, TRUE, old_name);
4735  fputs(" does not exist in the InnoDB internal\n"
4736  "InnoDB: data dictionary though MySQL is"
4737  " trying to rename the table.\n"
4738  "InnoDB: Have you copied the .frm file"
4739  " of the table to the\n"
4740  "InnoDB: MySQL database directory"
4741  " from another database?\n"
4742  "InnoDB: You can look for further help from\n"
4743  "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
4744  stderr);
4745  goto funct_exit;
4746 
4747  } else if (table->ibd_file_missing
4748  && !dict_table_is_discarded(table)) {
4749 
4750  err = DB_TABLE_NOT_FOUND;
4751 
4752  ib_logf(IB_LOG_LEVEL_ERROR,
4753  "Table %s does not have an .ibd file in the database "
4754  "directory. See " REFMAN "innodb-troubleshooting.html",
4755  old_name);
4756 
4757  goto funct_exit;
4758 
4759  } else if (new_is_tmp) {
4760  /* MySQL is doing an ALTER TABLE command and it renames the
4761  original table to a temporary table name. We want to preserve
4762  the original foreign key constraint definitions despite the
4763  name change. An exception is those constraints for which
4764  the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
4765 
4766  heap = mem_heap_create(100);
4767 
4769  heap, trx, table, &n_constraints_to_drop,
4770  &constraints_to_drop);
4771 
4772  if (err != DB_SUCCESS) {
4773  goto funct_exit;
4774  }
4775  }
4776 
4777  /* Is a foreign key check running on this table? */
4778  for (retry = 0; retry < 100
4779  && table->n_foreign_key_checks_running > 0; ++retry) {
4781  os_thread_yield();
4782  row_mysql_lock_data_dictionary(trx);
4783  }
4784 
4785  if (table->n_foreign_key_checks_running > 0) {
4786  ut_print_timestamp(stderr);
4787  fputs(" InnoDB: Error: in ALTER TABLE ", stderr);
4788  ut_print_name(stderr, trx, TRUE, old_name);
4789  fprintf(stderr, "\n"
4790  "InnoDB: a FOREIGN KEY check is running.\n"
4791  "InnoDB: Cannot rename table.\n");
4792  err = DB_TABLE_IN_FK_CHECK;
4793  goto funct_exit;
4794  }
4795 
4796  /* We use the private SQL parser of Innobase to generate the query
4797  graphs needed in updating the dictionary data from system tables. */
4798 
4799  info = pars_info_create();
4800 
4801  pars_info_add_str_literal(info, "new_table_name", new_name);
4802  pars_info_add_str_literal(info, "old_table_name", old_name);
4803 
4804  err = que_eval_sql(info,
4805  "PROCEDURE RENAME_TABLE () IS\n"
4806  "BEGIN\n"
4807  "UPDATE SYS_TABLES"
4808  " SET NAME = :new_table_name\n"
4809  " WHERE NAME = :old_table_name;\n"
4810  "END;\n"
4811  , FALSE, trx);
4812 
4813  /* SYS_TABLESPACES and SYS_DATAFILES track non-system tablespaces
4814  which have space IDs > 0. */
4815  if (err == DB_SUCCESS
4816  && table->space != TRX_SYS_SPACE
4817  && !table->ibd_file_missing) {
4818  /* Make a new pathname to update SYS_DATAFILES. */
4819  char* new_path = row_make_new_pathname(table, new_name);
4820 
4821  info = pars_info_create();
4822 
4823  pars_info_add_str_literal(info, "new_table_name", new_name);
4824  pars_info_add_str_literal(info, "new_path_name", new_path);
4825  pars_info_add_int4_literal(info, "space_id", table->space);
4826 
4827  err = que_eval_sql(info,
4828  "PROCEDURE RENAME_SPACE () IS\n"
4829  "BEGIN\n"
4830  "UPDATE SYS_TABLESPACES"
4831  " SET NAME = :new_table_name\n"
4832  " WHERE SPACE = :space_id;\n"
4833  "UPDATE SYS_DATAFILES"
4834  " SET PATH = :new_path_name\n"
4835  " WHERE SPACE = :space_id;\n"
4836  "END;\n"
4837  , FALSE, trx);
4838 
4839  mem_free(new_path);
4840  }
4841  if (err != DB_SUCCESS) {
4842  goto end;
4843  }
4844 
4845  if (!new_is_tmp) {
4846  /* Rename all constraints. */
4847  char new_table_name[MAX_TABLE_NAME_LEN] = "";
4848  char old_table_utf8[MAX_TABLE_NAME_LEN] = "";
4849  uint errors = 0;
4850 
4851  strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN);
4852  innobase_convert_to_system_charset(
4853  strchr(old_table_utf8, '/') + 1,
4854  strchr(old_name, '/') +1,
4855  MAX_TABLE_NAME_LEN, &errors);
4856 
4857  if (errors) {
4858  /* Table name could not be converted from charset
4859  my_charset_filename to UTF-8. This means that the
4860  table name is already in UTF-8 (#mysql#50). */
4861  strncpy(old_table_utf8, old_name, MAX_TABLE_NAME_LEN);
4862  }
4863 
4864  info = pars_info_create();
4865 
4866  pars_info_add_str_literal(info, "new_table_name", new_name);
4867  pars_info_add_str_literal(info, "old_table_name", old_name);
4868  pars_info_add_str_literal(info, "old_table_name_utf8",
4869  old_table_utf8);
4870 
4871  strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN);
4872  innobase_convert_to_system_charset(
4873  strchr(new_table_name, '/') + 1,
4874  strchr(new_name, '/') +1,
4875  MAX_TABLE_NAME_LEN, &errors);
4876 
4877  if (errors) {
4878  /* Table name could not be converted from charset
4879  my_charset_filename to UTF-8. This means that the
4880  table name is already in UTF-8 (#mysql#50). */
4881  strncpy(new_table_name, new_name, MAX_TABLE_NAME_LEN);
4882  }
4883 
4884  pars_info_add_str_literal(info, "new_table_utf8", new_table_name);
4885 
4886  err = que_eval_sql(
4887  info,
4888  "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
4889  "gen_constr_prefix CHAR;\n"
4890  "new_db_name CHAR;\n"
4891  "foreign_id CHAR;\n"
4892  "new_foreign_id CHAR;\n"
4893  "old_db_name_len INT;\n"
4894  "old_t_name_len INT;\n"
4895  "new_db_name_len INT;\n"
4896  "id_len INT;\n"
4897  "offset INT;\n"
4898  "found INT;\n"
4899  "BEGIN\n"
4900  "found := 1;\n"
4901  "old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
4902  "new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
4903  "new_db_name := SUBSTR(:new_table_name, 0,\n"
4904  " new_db_name_len);\n"
4905  "old_t_name_len := LENGTH(:old_table_name);\n"
4906  "gen_constr_prefix := CONCAT(:old_table_name_utf8,\n"
4907  " '_ibfk_');\n"
4908  "WHILE found = 1 LOOP\n"
4909  " SELECT ID INTO foreign_id\n"
4910  " FROM SYS_FOREIGN\n"
4911  " WHERE FOR_NAME = :old_table_name\n"
4912  " AND TO_BINARY(FOR_NAME)\n"
4913  " = TO_BINARY(:old_table_name)\n"
4914  " LOCK IN SHARE MODE;\n"
4915  " IF (SQL % NOTFOUND) THEN\n"
4916  " found := 0;\n"
4917  " ELSE\n"
4918  " UPDATE SYS_FOREIGN\n"
4919  " SET FOR_NAME = :new_table_name\n"
4920  " WHERE ID = foreign_id;\n"
4921  " id_len := LENGTH(foreign_id);\n"
4922  " IF (INSTR(foreign_id, '/') > 0) THEN\n"
4923  " IF (INSTR(foreign_id,\n"
4924  " gen_constr_prefix) > 0)\n"
4925  " THEN\n"
4926  " offset := INSTR(foreign_id, '_ibfk_') - 1;\n"
4927  " new_foreign_id :=\n"
4928  " CONCAT(:new_table_utf8,\n"
4929  " SUBSTR(foreign_id, offset,\n"
4930  " id_len - offset));\n"
4931  " ELSE\n"
4932  " new_foreign_id :=\n"
4933  " CONCAT(new_db_name,\n"
4934  " SUBSTR(foreign_id,\n"
4935  " old_db_name_len,\n"
4936  " id_len - old_db_name_len));\n"
4937  " END IF;\n"
4938  " UPDATE SYS_FOREIGN\n"
4939  " SET ID = new_foreign_id\n"
4940  " WHERE ID = foreign_id;\n"
4941  " UPDATE SYS_FOREIGN_COLS\n"
4942  " SET ID = new_foreign_id\n"
4943  " WHERE ID = foreign_id;\n"
4944  " END IF;\n"
4945  " END IF;\n"
4946  "END LOOP;\n"
4947  "UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
4948  "WHERE REF_NAME = :old_table_name\n"
4949  " AND TO_BINARY(REF_NAME)\n"
4950  " = TO_BINARY(:old_table_name);\n"
4951  "END;\n"
4952  , FALSE, trx);
4953 
4954  } else if (n_constraints_to_drop > 0) {
4955  /* Drop some constraints of tmp tables. */
4956 
4957  ulint db_name_len = dict_get_db_name_len(old_name) + 1;
4958  char* db_name = mem_heap_strdupl(heap, old_name,
4959  db_name_len);
4960  ulint i;
4961 
4962  for (i = 0; i < n_constraints_to_drop; i++) {
4963  err = row_delete_constraint(constraints_to_drop[i],
4964  db_name, heap, trx);
4965 
4966  if (err != DB_SUCCESS) {
4967  break;
4968  }
4969  }
4970  }
4971 
4972  if (dict_table_has_fts_index(table)
4973  && !dict_tables_have_same_db(old_name, new_name)) {
4974  err = fts_rename_aux_tables(table, new_name, trx);
4975 
4976  if (err != DB_SUCCESS && (table->space != 0)) {
4977  char* orig_name = table->name;
4978 
4979  /* If rename fails and table has its own tablespace,
4980  we need to call fts_rename_aux_tables again to
4981  revert the ibd file rename, which is not under the
4982  control of trx. Also notice the parent table name
4983  in cache is not changed yet. */
4984  table->name = const_cast<char*>(new_name);
4985  fts_rename_aux_tables(table, old_name, trx);
4986  table->name = orig_name;
4987  }
4988  }
4989 
4990 end:
4991  if (err != DB_SUCCESS) {
4992  if (err == DB_DUPLICATE_KEY) {
4993  ut_print_timestamp(stderr);
4994  fputs(" InnoDB: Error; possible reasons:\n"
4995  "InnoDB: 1) Table rename would cause"
4996  " two FOREIGN KEY constraints\n"
4997  "InnoDB: to have the same internal name"
4998  " in case-insensitive comparison.\n"
4999  "InnoDB: 2) table ", stderr);
5000  ut_print_name(stderr, trx, TRUE, new_name);
5001  fputs(" exists in the InnoDB internal data\n"
5002  "InnoDB: dictionary though MySQL is"
5003  " trying to rename table ", stderr);
5004  ut_print_name(stderr, trx, TRUE, old_name);
5005  fputs(" to it.\n"
5006  "InnoDB: Have you deleted the .frm file"
5007  " and not used DROP TABLE?\n"
5008  "InnoDB: You can look for further help from\n"
5009  "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
5010  "InnoDB: If table ", stderr);
5011  ut_print_name(stderr, trx, TRUE, new_name);
5012  fputs(" is a temporary table #sql..., then"
5013  " it can be that\n"
5014  "InnoDB: there are still queries running"
5015  " on the table, and it will be\n"
5016  "InnoDB: dropped automatically when"
5017  " the queries end.\n"
5018  "InnoDB: You can drop the orphaned table"
5019  " inside InnoDB by\n"
5020  "InnoDB: creating an InnoDB table with"
5021  " the same name in another\n"
5022  "InnoDB: database and copying the .frm file"
5023  " to the current database.\n"
5024  "InnoDB: Then MySQL thinks the table exists,"
5025  " and DROP TABLE will\n"
5026  "InnoDB: succeed.\n", stderr);
5027  }
5028  trx->error_state = DB_SUCCESS;
5029  trx_rollback_to_savepoint(trx, NULL);
5030  trx->error_state = DB_SUCCESS;
5031  } else {
5032  /* The following call will also rename the .ibd data file if
5033  the table is stored in a single-table tablespace */
5034 
5036  table, new_name, !new_is_tmp);
5037  if (err != DB_SUCCESS) {
5038  trx->error_state = DB_SUCCESS;
5039  trx_rollback_to_savepoint(trx, NULL);
5040  trx->error_state = DB_SUCCESS;
5041  goto funct_exit;
5042  }
5043 
5044  /* We only want to switch off some of the type checking in
5045  an ALTER, not in a RENAME. */
5046 
5047  err = dict_load_foreigns(
5048  new_name, NULL,
5049  false, !old_is_tmp || trx->check_foreigns,
5051 
5052  if (err != DB_SUCCESS) {
5053  ut_print_timestamp(stderr);
5054 
5055  if (old_is_tmp) {
5056  fputs(" InnoDB: Error: in ALTER TABLE ",
5057  stderr);
5058  ut_print_name(stderr, trx, TRUE, new_name);
5059  fputs("\n"
5060  "InnoDB: has or is referenced"
5061  " in foreign key constraints\n"
5062  "InnoDB: which are not compatible"
5063  " with the new table definition.\n",
5064  stderr);
5065  } else {
5066  fputs(" InnoDB: Error: in RENAME TABLE"
5067  " table ",
5068  stderr);
5069  ut_print_name(stderr, trx, TRUE, new_name);
5070  fputs("\n"
5071  "InnoDB: is referenced in"
5072  " foreign key constraints\n"
5073  "InnoDB: which are not compatible"
5074  " with the new table definition.\n",
5075  stderr);
5076  }
5077 
5078  ut_a(DB_SUCCESS == dict_table_rename_in_cache(
5079  table, old_name, FALSE));
5080  trx->error_state = DB_SUCCESS;
5081  trx_rollback_to_savepoint(trx, NULL);
5082  trx->error_state = DB_SUCCESS;
5083  }
5084  }
5085 
5086 funct_exit:
5087  if (table != NULL) {
5088  dict_table_close(table, dict_locked, FALSE);
5089  }
5090 
5091  if (commit) {
5092  trx_commit_for_mysql(trx);
5093  }
5094 
5095  if (UNIV_LIKELY_NULL(heap)) {
5096  mem_heap_free(heap);
5097  }
5098 
5099  trx->op_info = "";
5100 
5101  return(err);
5102 }
5103 
5104 /*********************************************************************/
5109 UNIV_INTERN
5110 bool
5112 /*======================*/
5113  row_prebuilt_t* prebuilt,
5115  const dict_index_t* index,
5116  ulint* n_rows)
5118 {
5119  dtuple_t* prev_entry = NULL;
5120  ulint matched_fields;
5121  ulint matched_bytes;
5122  byte* buf;
5123  ulint ret;
5124  rec_t* rec;
5125  bool is_ok = true;
5126  int cmp;
5127  ibool contains_null;
5128  ulint i;
5129  ulint cnt;
5130  mem_heap_t* heap = NULL;
5131  ulint n_ext;
5132  ulint offsets_[REC_OFFS_NORMAL_SIZE];
5133  ulint* offsets;
5134  rec_offs_init(offsets_);
5135 
5136  *n_rows = 0;
5137 
5138  if (dict_index_is_clust(index)) {
5139  /* The clustered index of a table is always available.
5140  During online ALTER TABLE that rebuilds the table, the
5141  clustered index in the old table will have
5142  index->online_log pointing to the new table. All
5143  indexes of the old table will remain valid and the new
5144  table will be unaccessible to MySQL until the
5145  completion of the ALTER TABLE. */
5146  } else if (dict_index_is_online_ddl(index)
5147  || (index->type & DICT_FTS)) {
5148  /* Full Text index are implemented by auxiliary tables,
5149  not the B-tree. We also skip secondary indexes that are
5150  being created online. */
5151  return(true);
5152  }
5153 
5154  buf = static_cast<byte*>(mem_alloc(UNIV_PAGE_SIZE));
5155  heap = mem_heap_create(100);
5156 
5157  cnt = 1000;
5158 
5159  ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
5160 loop:
5161  /* Check thd->killed every 1,000 scanned rows */
5162  if (--cnt == 0) {
5163  if (trx_is_interrupted(prebuilt->trx)) {
5164  goto func_exit;
5165  }
5166  cnt = 1000;
5167  }
5168 
5169  switch (ret) {
5170  case DB_SUCCESS:
5171  break;
5172  default:
5173  ut_print_timestamp(stderr);
5174  fputs(" InnoDB: Warning: CHECK TABLE on ", stderr);
5175  dict_index_name_print(stderr, prebuilt->trx, index);
5176  fprintf(stderr, " returned %lu\n", ret);
5177  /* fall through (this error is ignored by CHECK TABLE) */
5178  case DB_END_OF_INDEX:
5179 func_exit:
5180  mem_free(buf);
5181  mem_heap_free(heap);
5182 
5183  return(is_ok);
5184  }
5185 
5186  *n_rows = *n_rows + 1;
5187 
5188  /* row_search... returns the index record in buf, record origin offset
5189  within buf stored in the first 4 bytes, because we have built a dummy
5190  template */
5191 
5192  rec = buf + mach_read_from_4(buf);
5193 
5194  offsets = rec_get_offsets(rec, index, offsets_,
5195  ULINT_UNDEFINED, &heap);
5196 
5197  if (prev_entry != NULL) {
5198  matched_fields = 0;
5199  matched_bytes = 0;
5200 
5201  cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
5202  &matched_fields,
5203  &matched_bytes);
5204  contains_null = FALSE;
5205 
5206  /* In a unique secondary index we allow equal key values if
5207  they contain SQL NULLs */
5208 
5209  for (i = 0;
5211  i++) {
5212  if (UNIV_SQL_NULL == dfield_get_len(
5213  dtuple_get_nth_field(prev_entry, i))) {
5214 
5215  contains_null = TRUE;
5216  break;
5217  }
5218  }
5219 
5220  if (cmp > 0) {
5221  fputs("InnoDB: index records in a wrong order in ",
5222  stderr);
5223 not_ok:
5224  dict_index_name_print(stderr,
5225  prebuilt->trx, index);
5226  fputs("\n"
5227  "InnoDB: prev record ", stderr);
5228  dtuple_print(stderr, prev_entry);
5229  fputs("\n"
5230  "InnoDB: record ", stderr);
5231  rec_print_new(stderr, rec, offsets);
5232  putc('\n', stderr);
5233  is_ok = false;
5234  } else if (dict_index_is_unique(index)
5235  && !contains_null
5236  && matched_fields
5238  index)) {
5239 
5240  fputs("InnoDB: duplicate key in ", stderr);
5241  goto not_ok;
5242  }
5243  }
5244 
5245  {
5246  mem_heap_t* tmp_heap = NULL;
5247 
5248  /* Empty the heap on each round. But preserve offsets[]
5249  for the row_rec_to_index_entry() call, by copying them
5250  into a separate memory heap when needed. */
5251  if (UNIV_UNLIKELY(offsets != offsets_)) {
5252  ulint size = rec_offs_get_n_alloc(offsets)
5253  * sizeof *offsets;
5254 
5255  tmp_heap = mem_heap_create(size);
5256 
5257  offsets = static_cast<ulint*>(
5258  mem_heap_dup(tmp_heap, offsets, size));
5259  }
5260 
5261  mem_heap_empty(heap);
5262 
5263  prev_entry = row_rec_to_index_entry(
5264  rec, index, offsets, &n_ext, heap);
5265 
5266  if (UNIV_LIKELY_NULL(tmp_heap)) {
5267  mem_heap_free(tmp_heap);
5268  }
5269  }
5270 
5271  ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
5272 
5273  goto loop;
5274 }
5275 
5276 /*********************************************************************/
5279 UNIV_INTERN
5280 bool
5282 /*=======================*/
5283  const char* table_name)
5285 {
5286  const char* name; /* table_name without database/ */
5287  ulint len;
5288 
5289  name = dict_remove_db_name(table_name);
5290  len = strlen(name) + 1;
5291 
5292  return(STR_EQ(name, len, S_innodb_monitor)
5293  || STR_EQ(name, len, S_innodb_lock_monitor)
5294  || STR_EQ(name, len, S_innodb_tablespace_monitor)
5295  || STR_EQ(name, len, S_innodb_table_monitor)
5296 #ifdef UNIV_MEM_DEBUG
5297  || STR_EQ(name, len, S_innodb_mem_validate)
5298 #endif /* UNIV_MEM_DEBUG */
5299  );
5300 }
5301 
5302 /*********************************************************************/
5304 UNIV_INTERN
5305 void
5306 row_mysql_init(void)
5307 /*================*/
5308 {
5309  mutex_create(
5310  row_drop_list_mutex_key,
5311  &row_drop_list_mutex, SYNC_NO_ORDER_CHECK);
5312 
5313  UT_LIST_INIT(row_mysql_drop_list);
5314 
5315  row_mysql_drop_list_inited = TRUE;
5316 }
5317 
5318 /*********************************************************************/
5320 UNIV_INTERN
5321 void
5322 row_mysql_close(void)
5323 /*================*/
5324 {
5325  ut_a(UT_LIST_GET_LEN(row_mysql_drop_list) == 0);
5326 
5327  mutex_free(&row_drop_list_mutex);
5328 
5329  row_mysql_drop_list_inited = FALSE;
5330 }