Drizzled Public API Documentation

row0mysql.cc
1 /*****************************************************************************
2 
3 Copyright (C) 2000, 2010, Innobase Oy. 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., 51 Franklin
15 St, Fifth Floor, Boston, MA 02110-1301 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
27 #include "row0mysql.h"
28 
29 #ifdef UNIV_NONINL
30 #include "row0mysql.ic"
31 #endif
32 
33 #include "row0ins.h"
34 #include "row0merge.h"
35 #include "row0sel.h"
36 #include "row0upd.h"
37 #include "row0row.h"
38 #include "que0que.h"
39 #include "pars0pars.h"
40 #include "dict0dict.h"
41 #include "dict0crea.h"
42 #include "dict0load.h"
43 #include "dict0boot.h"
44 #include "trx0roll.h"
45 #include "trx0purge.h"
46 #include "trx0rec.h"
47 #include "trx0undo.h"
48 #include "lock0lock.h"
49 #include "rem0cmp.h"
50 #include "log0log.h"
51 #include "btr0sea.h"
52 #include "fil0fil.h"
53 #include "ibuf0ibuf.h"
54 
55 #include <errno.h>
56 
58 UNIV_INTERN ibool row_rollback_on_timeout = FALSE;
59 
62 
65  char* table_name;
66  UT_LIST_NODE_T(row_mysql_drop_t)row_mysql_drop_list;
68 };
69 
75 static UT_LIST_BASE_NODE_T(row_mysql_drop_t) row_mysql_drop_list;
77 static ibool row_mysql_drop_list_inited = FALSE;
78 
80 /* @{ */
81 static const char S_innodb_monitor[] = "innodb_monitor";
82 static const char S_innodb_lock_monitor[] = "innodb_lock_monitor";
83 static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor";
84 static const char S_innodb_table_monitor[] = "innodb_table_monitor";
85 static const char S_innodb_mem_validate[] = "innodb_mem_validate";
86 /* @} */
87 
94 #define STR_EQ(str1, str1_len, str2_onstack) \
95  ((str1_len) == sizeof(str2_onstack) \
96  && memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0)
97 
98 /*********************************************************************/
105 static
106 ibool
107 row_add_table_to_background_drop_list(
108 /*==================================*/
109  const char* name);
111 /*******************************************************************/
113 static
114 void
115 row_mysql_delay_if_needed(void)
116 /*===========================*/
117 {
118  if (srv_dml_needed_delay) {
119  os_thread_sleep(srv_dml_needed_delay);
120  }
121 }
122 
123 /*******************************************************************/
125 UNIV_INTERN
126 void
128 /*==============================*/
129  row_prebuilt_t* prebuilt)
131 {
132  mem_heap_free(prebuilt->blob_heap);
133  prebuilt->blob_heap = NULL;
134 }
135 
136 /*******************************************************************/
141 UNIV_INTERN
142 byte*
144 /*=========================*/
145  byte* dest,
146  ulint len,
147  ulint lenlen)
148 {
149  if (lenlen == 2) {
150  ut_a(len < 256 * 256);
151 
153 
154  return(dest + 2);
155  }
156 
157  ut_a(lenlen == 1);
158  ut_a(len < 256);
159 
160  mach_write_to_1(dest, len);
161 
162  return(dest + 1);
163 }
164 
165 /*******************************************************************/
170 UNIV_INTERN
171 const byte*
173 /*========================*/
174  ulint* len,
175  const byte* field,
176  ulint lenlen)
178 {
179  if (lenlen == 2) {
180  *len = mach_read_from_2_little_endian(field);
181 
182  return(field + 2);
183  }
184 
185  ut_a(lenlen == 1);
186 
187  *len = mach_read_from_1(field);
188 
189  return(field + 1);
190 }
191 
192 /*******************************************************************/
194 UNIV_INTERN
195 void
197 /*=====================*/
198  byte* dest,
199  ulint col_len,
203  const void* data,
205  ulint len)
209 {
210  /* MySQL might assume the field is set to zero except the length and
211  the pointer fields */
212 
213  memset(dest, '\0', col_len);
214 
215  /* In dest there are 1 - 4 bytes reserved for the BLOB length,
216  and after that 8 bytes reserved for the pointer to the data.
217  In 32-bit architectures we only use the first 4 bytes of the pointer
218  slot. */
219 
220  ut_a(col_len - 8 > 1 || len < 256);
221  ut_a(col_len - 8 > 2 || len < 256 * 256);
222  ut_a(col_len - 8 > 3 || len < 256 * 256 * 256);
223 
224  mach_write_to_n_little_endian(dest, col_len - 8, len);
225 
226  memcpy(dest + col_len - 8, &data, sizeof data);
227 }
228 
229 /*******************************************************************/
232 UNIV_INTERN
233 const byte*
235 /*====================*/
236  ulint* len,
237  const byte* ref,
239  ulint col_len)
241 {
242  byte* data;
243 
244  *len = mach_read_from_n_little_endian(ref, col_len - 8);
245 
246  memcpy(&data, ref + col_len - 8, sizeof data);
247 
248  return(data);
249 }
250 
251 /**************************************************************/
253 UNIV_INTERN
254 void
256 /*==============*/
257  ulint mbminlen,
259  byte* pad,
260  ulint len)
261 {
262  const byte* pad_end;
263 
264  switch (UNIV_EXPECT(mbminlen, 1)) {
265  default:
266  ut_error;
267  case 1:
268  /* space=0x20 */
269  memset(pad, 0x20, len);
270  break;
271  case 2:
272  /* space=0x0020 */
273  pad_end = pad + len;
274  ut_a(!(len % 2));
275  do {
276  *pad++ = 0x00;
277  *pad++ = 0x20;
278  } while (pad < pad_end);
279  break;
280  case 4:
281  /* space=0x00000020 */
282  pad_end = pad + len;
283  ut_a(!(len % 4));
284  do {
285  *pad++ = 0x00;
286  *pad++ = 0x00;
287  *pad++ = 0x00;
288  *pad++ = 0x20;
289  } while (pad < pad_end);
290  break;
291  }
292 }
293 
294 /**************************************************************/
299 UNIV_INTERN
300 byte*
302 /*===================================*/
303  dfield_t* dfield,
306  byte* buf,
309  ibool row_format_col,
316  const byte* mysql_data,
321  ulint col_len,
327  ulint comp)
328 {
329  const byte* ptr = mysql_data;
330  const dtype_t* dtype;
331  ulint type;
332  ulint lenlen;
333 
334  dtype = dfield_get_type(dfield);
335 
336  type = dtype->mtype;
337 
338  if (type == DATA_INT) {
339  /* Store integer data in Innobase in a big-endian format,
340  sign bit negated if the data is a signed integer. In MySQL,
341  integers are stored in a little-endian format. */
342 
343  byte* p = buf + col_len;
344 
345  for (;;) {
346  p--;
347  *p = *mysql_data;
348  if (p == buf) {
349  break;
350  }
351  mysql_data++;
352  }
353 
354  if (!(dtype->prtype & DATA_UNSIGNED)) {
355 
356  *buf ^= 128;
357  }
358 
359  ptr = buf;
360  buf += col_len;
361  } else if ((type == DATA_VARCHAR
362  || type == DATA_VARMYSQL
363  || type == DATA_BINARY)) {
364 
365  if (dtype_get_mysql_type(dtype) == DATA_MYSQL_TRUE_VARCHAR) {
366  /* The length of the actual data is stored to 1 or 2
367  bytes at the start of the field */
368 
369  if (row_format_col) {
370  if (dtype->prtype & DATA_LONG_TRUE_VARCHAR) {
371  lenlen = 2;
372  } else {
373  lenlen = 1;
374  }
375  } else {
376  /* In a MySQL key value, lenlen is always 2 */
377  lenlen = 2;
378  }
379 
380  ptr = row_mysql_read_true_varchar(&col_len, mysql_data,
381  lenlen);
382  } else {
383  /* Remove trailing spaces from old style VARCHAR
384  columns. */
385 
386  /* Handle Unicode strings differently. */
387  ulint mbminlen = dtype_get_mbminlen(dtype);
388 
389  ptr = mysql_data;
390 
391  switch (mbminlen) {
392  default:
393  ut_error;
394  case 4:
395  /* space=0x00000020 */
396  /* Trim "half-chars", just in case. */
397  col_len &= ~3;
398 
399  while (col_len >= 4
400  && ptr[col_len - 4] == 0x00
401  && ptr[col_len - 3] == 0x00
402  && ptr[col_len - 2] == 0x00
403  && ptr[col_len - 1] == 0x20) {
404  col_len -= 4;
405  }
406  break;
407  case 2:
408  /* space=0x0020 */
409  /* Trim "half-chars", just in case. */
410  col_len &= ~1;
411 
412  while (col_len >= 2 && ptr[col_len - 2] == 0x00
413  && ptr[col_len - 1] == 0x20) {
414  col_len -= 2;
415  }
416  break;
417  case 1:
418  /* space=0x20 */
419  while (col_len > 0
420  && ptr[col_len - 1] == 0x20) {
421  col_len--;
422  }
423  }
424  }
425  } else if (comp && type == DATA_MYSQL
426  && dtype_get_mbminlen(dtype) == 1
427  && dtype_get_mbmaxlen(dtype) > 1) {
428  /* In some cases we strip trailing spaces from UTF-8 and other
429  multibyte charsets, from FIXED-length CHAR columns, to save
430  space. UTF-8 would otherwise normally use 3 * the string length
431  bytes to store an ASCII string! */
432 
433  /* We assume that this CHAR field is encoded in a
434  variable-length character set where spaces have
435  1:1 correspondence to 0x20 bytes, such as UTF-8.
436 
437  Consider a CHAR(n) field, a field of n characters.
438  It will contain between n * mbminlen and n * mbmaxlen bytes.
439  We will try to truncate it to n bytes by stripping
440  space padding. If the field contains single-byte
441  characters only, it will be truncated to n characters.
442  Consider a CHAR(5) field containing the string ".a "
443  where "." denotes a 3-byte character represented by
444  the bytes "$%&". After our stripping, the string will
445  be stored as "$%&a " (5 bytes). The string ".abc "
446  will be stored as "$%&abc" (6 bytes).
447 
448  The space padding will be restored in row0sel.c, function
449  row_sel_field_store_in_mysql_format(). */
450 
451  ulint n_chars;
452 
453  ut_a(!(dtype_get_len(dtype) % dtype_get_mbmaxlen(dtype)));
454 
455  n_chars = dtype_get_len(dtype) / dtype_get_mbmaxlen(dtype);
456 
457  /* Strip space padding. */
458  while (col_len > n_chars && ptr[col_len - 1] == 0x20) {
459  col_len--;
460  }
461  } else if (type == DATA_BLOB && row_format_col) {
462 
463  ptr = row_mysql_read_blob_ref(&col_len, mysql_data, col_len);
464  }
465 
466  dfield_set_data(dfield, ptr, col_len);
467 
468  return(buf);
469 }
470 
471 /**************************************************************/
475 static
476 void
477 row_mysql_convert_row_to_innobase(
478 /*==============================*/
479  dtuple_t* row,
482  row_prebuilt_t* prebuilt,
484  byte* mysql_rec)
488 {
489  const mysql_row_templ_t*templ;
490  dfield_t* dfield;
491  ulint i;
492 
493  ut_ad(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
494  ut_ad(prebuilt->mysql_template);
495 
496  for (i = 0; i < prebuilt->n_template; i++) {
497 
498  templ = prebuilt->mysql_template + i;
499  dfield = dtuple_get_nth_field(row, i);
500 
501  if (templ->mysql_null_bit_mask != 0) {
502  /* Column may be SQL NULL */
503 
504  if (mysql_rec[templ->mysql_null_byte_offset]
505  & (byte) (templ->mysql_null_bit_mask)) {
506 
507  /* It is SQL NULL */
508 
509  dfield_set_null(dfield);
510 
511  goto next_column;
512  }
513  }
514 
516  dfield,
517  prebuilt->ins_upd_rec_buff + templ->mysql_col_offset,
518  TRUE, /* MySQL row format data */
519  mysql_rec + templ->mysql_col_offset,
520  templ->mysql_col_len,
521  dict_table_is_comp(prebuilt->table));
522 next_column:
523  ;
524  }
525 }
526 
527 /****************************************************************/
531 UNIV_INTERN
532 ibool
534 /*====================*/
535  ulint* new_err,
539  trx_t* trx,
540  que_thr_t* thr,
541  trx_savept_t* savept)
542 {
543  ulint err;
544 
545 handle_new_error:
546  err = trx->error_state;
547 
548  ut_a(err != DB_SUCCESS);
549 
550  trx->error_state = DB_SUCCESS;
551 
552  switch (err) {
553  case DB_LOCK_WAIT_TIMEOUT:
556  break;
557  }
558  /* fall through */
559  case DB_DUPLICATE_KEY:
560  case DB_FOREIGN_DUPLICATE_KEY:
561  case DB_TOO_BIG_RECORD:
562  case DB_ROW_IS_REFERENCED:
563  case DB_NO_REFERENCED_ROW:
564  case DB_CANNOT_ADD_CONSTRAINT:
565  case DB_TOO_MANY_CONCURRENT_TRXS:
566  case DB_OUT_OF_FILE_SPACE:
567  case DB_INTERRUPTED:
568  if (savept) {
569  /* Roll back the latest, possibly incomplete
570  insertion or update */
571 
572  trx_general_rollback_for_mysql(trx, savept);
573  }
574  /* MySQL will roll back the latest SQL statement */
575  break;
576  case DB_LOCK_WAIT:
578 
579  if (trx->error_state != DB_SUCCESS) {
581 
582  goto handle_new_error;
583  }
584 
585  *new_err = err;
586 
587  return(TRUE);
588 
589  case DB_DEADLOCK:
590  case DB_LOCK_TABLE_FULL:
591  /* Roll back the whole transaction; this resolution was added
592  to version 3.23.43 */
593 
595  break;
596 
597  case DB_MUST_GET_MORE_FILE_SPACE:
598  fputs("InnoDB: The database cannot continue"
599  " operation because of\n"
600  "InnoDB: lack of space. You must add"
601  " a new data file to\n"
602  "InnoDB: my.cnf and restart the database.\n", stderr);
603 
604  exit(1);
605 
606  case DB_CORRUPTION:
607  fputs("InnoDB: We detected index corruption"
608  " in an InnoDB type table.\n"
609  "InnoDB: You have to dump + drop + reimport"
610  " the table or, in\n"
611  "InnoDB: a case of widespread corruption,"
612  " dump all InnoDB\n"
613  "InnoDB: tables and recreate the"
614  " whole InnoDB tablespace.\n"
615  "InnoDB: If the mysqld server crashes"
616  " after the startup or when\n"
617  "InnoDB: you dump the tables, look at\n"
618  "InnoDB: " REFMAN "forcing-innodb-recovery.html"
619  " for help.\n", stderr);
620  break;
621  case DB_FOREIGN_EXCEED_MAX_CASCADE:
622  fprintf(stderr, "InnoDB: Cannot delete/update rows with"
623  " cascading foreign key constraints that exceed max"
624  " depth of %lu\n"
625  "Please drop excessive foreign constraints"
626  " and try again\n", (ulong) DICT_FK_MAX_RECURSIVE_LOAD);
627  break;
628  default:
629  fprintf(stderr, "InnoDB: unknown error code %lu\n",
630  (ulong) err);
631  ut_error;
632  }
633 
634  if (trx->error_state != DB_SUCCESS) {
635  *new_err = trx->error_state;
636  } else {
637  *new_err = err;
638  }
639 
640  trx->error_state = DB_SUCCESS;
641 
642  return(FALSE);
643 }
644 
645 /********************************************************************/
648 UNIV_INTERN
651 /*================*/
652  dict_table_t* table)
653 {
654  row_prebuilt_t* prebuilt;
655  mem_heap_t* heap;
656  dict_index_t* clust_index;
657  dtuple_t* ref;
658  ulint ref_len;
659 
660  heap = mem_heap_create(sizeof *prebuilt + 128);
661 
662  prebuilt = static_cast<row_prebuilt_t *>(mem_heap_zalloc(heap, sizeof *prebuilt));
663 
664  prebuilt->magic_n = ROW_PREBUILT_ALLOCATED;
665  prebuilt->magic_n2 = ROW_PREBUILT_ALLOCATED;
666 
667  prebuilt->table = table;
668 
669  prebuilt->sql_stat_start = TRUE;
670  prebuilt->heap = heap;
671 
672  prebuilt->pcur = btr_pcur_create_for_mysql();
674 
675  prebuilt->select_lock_type = LOCK_NONE;
676  prebuilt->stored_select_lock_type = 99999999;
677  UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type,
678  sizeof prebuilt->stored_select_lock_type);
679 
680  prebuilt->search_tuple = dtuple_create(
681  heap, 2 * dict_table_get_n_cols(table));
682 
683  clust_index = dict_table_get_first_index(table);
684 
685  /* Make sure that search_tuple is long enough for clustered index */
686  ut_a(2 * dict_table_get_n_cols(table) >= clust_index->n_fields);
687 
688  ref_len = dict_index_get_n_unique(clust_index);
689 
690  ref = dtuple_create(heap, ref_len);
691 
692  dict_index_copy_types(ref, clust_index, ref_len);
693 
694  prebuilt->clust_ref = ref;
695 
696  prebuilt->autoinc_error = 0;
697  prebuilt->autoinc_offset = 0;
698 
699  /* Default to 1, we will set the actual value later in
700  ha_innobase::get_auto_increment(). */
701  prebuilt->autoinc_increment = 1;
702 
703  prebuilt->autoinc_last_value = 0;
704 
705  return(prebuilt);
706 }
707 
708 /********************************************************************/
710 UNIV_INTERN
711 void
713 /*==============*/
714  row_prebuilt_t* prebuilt,
715  ibool dict_locked)
716 {
717  ulint i;
718 
719  if (UNIV_UNLIKELY
720  (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED
721  || prebuilt->magic_n2 != ROW_PREBUILT_ALLOCATED)) {
722 
723  fprintf(stderr,
724  "InnoDB: Error: trying to free a corrupt\n"
725  "InnoDB: table handle. Magic n %lu,"
726  " magic n2 %lu, table name ",
727  (ulong) prebuilt->magic_n,
728  (ulong) prebuilt->magic_n2);
729  ut_print_name(stderr, NULL, TRUE, prebuilt->table->name);
730  putc('\n', stderr);
731 
732  mem_analyze_corruption(prebuilt);
733 
734  ut_error;
735  }
736 
737  prebuilt->magic_n = ROW_PREBUILT_FREED;
738  prebuilt->magic_n2 = ROW_PREBUILT_FREED;
739 
740  btr_pcur_free_for_mysql(prebuilt->pcur);
742 
743  if (prebuilt->mysql_template) {
744  mem_free(prebuilt->mysql_template);
745  }
746 
747  if (prebuilt->ins_graph) {
749  }
750 
751  if (prebuilt->sel_graph) {
753  }
754 
755  if (prebuilt->upd_graph) {
757  }
758 
759  if (prebuilt->blob_heap) {
760  mem_heap_free(prebuilt->blob_heap);
761  }
762 
763  if (prebuilt->old_vers_heap) {
764  mem_heap_free(prebuilt->old_vers_heap);
765  }
766 
767  for (i = 0; i < MYSQL_FETCH_CACHE_SIZE; i++) {
768  if (prebuilt->fetch_cache[i] != NULL) {
769 
770  if ((ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
771  (prebuilt->fetch_cache[i]) - 4))
772  || (ROW_PREBUILT_FETCH_MAGIC_N != mach_read_from_4(
773  (prebuilt->fetch_cache[i])
774  + prebuilt->mysql_row_len))) {
775  fputs("InnoDB: Error: trying to free"
776  " a corrupt fetch buffer.\n", stderr);
777 
779  prebuilt->fetch_cache[i]);
780 
781  ut_error;
782  }
783 
784  mem_free((prebuilt->fetch_cache[i]) - 4);
785  }
786  }
787 
788  dict_table_decrement_handle_count(prebuilt->table, dict_locked);
789 
790  mem_heap_free(prebuilt->heap);
791 }
792 
793 /*********************************************************************/
796 UNIV_INTERN
797 void
799 /*====================*/
800  row_prebuilt_t* prebuilt,
802  trx_t* trx)
803 {
804  if (trx->magic_n != TRX_MAGIC_N) {
805  fprintf(stderr,
806  "InnoDB: Error: trying to use a corrupt\n"
807  "InnoDB: trx handle. Magic n %lu\n",
808  (ulong) trx->magic_n);
809 
811 
812  ut_error;
813  }
814 
815  if (prebuilt->magic_n != ROW_PREBUILT_ALLOCATED) {
816  fprintf(stderr,
817  "InnoDB: Error: trying to use a corrupt\n"
818  "InnoDB: table handle. Magic n %lu, table name ",
819  (ulong) prebuilt->magic_n);
820  ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
821  putc('\n', stderr);
822 
823  mem_analyze_corruption(prebuilt);
824 
825  ut_error;
826  }
827 
828  prebuilt->trx = trx;
829 
830  if (prebuilt->ins_graph) {
831  prebuilt->ins_graph->trx = trx;
832  }
833 
834  if (prebuilt->upd_graph) {
835  prebuilt->upd_graph->trx = trx;
836  }
837 
838  if (prebuilt->sel_graph) {
839  prebuilt->sel_graph->trx = trx;
840  }
841 }
842 
843 dtuple_t* row_get_prebuilt_insert_row(row_prebuilt_t* prebuilt);
844 
845 /*********************************************************************/
850 dtuple_t*
851 row_get_prebuilt_insert_row(
852 /*========================*/
853  row_prebuilt_t* prebuilt)
855 {
856  ins_node_t* node;
857  dtuple_t* row;
858  dict_table_t* table = prebuilt->table;
859 
860  ut_ad(prebuilt && table && prebuilt->trx);
861 
862  if (prebuilt->ins_node == NULL) {
863 
864  /* Not called before for this handle: create an insert node
865  and query graph to the prebuilt struct */
866 
867  node = ins_node_create(INS_DIRECT, table, prebuilt->heap);
868 
869  prebuilt->ins_node = node;
870 
871  if (prebuilt->ins_upd_rec_buff == NULL) {
872  prebuilt->ins_upd_rec_buff = static_cast<byte *>(mem_heap_alloc(
873  prebuilt->heap, prebuilt->mysql_row_len));
874  }
875 
876  row = dtuple_create(prebuilt->heap,
877  dict_table_get_n_cols(table));
878 
879  dict_table_copy_types(row, table);
880 
881  ins_node_set_new_row(node, row);
882 
883  prebuilt->ins_graph = static_cast<que_fork_t *>(que_node_get_parent(
885  prebuilt->trx,
886  prebuilt->heap)));
887  prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
888  }
889 
890  return(prebuilt->ins_node->row);
891 }
892 
893 /*********************************************************************/
896 UNIV_INLINE
897 void
898 row_update_statistics_if_needed(
899 /*============================*/
900  dict_table_t* table)
901 {
902  ulint counter;
903 
904  counter = table->stat_modified_counter;
905 
906  table->stat_modified_counter = counter + 1;
907 
908  /* Calculate new statistics if 1 / 16 of table has been modified
909  since the last time a statistics batch was run, or if
910  stat_modified_counter > 2 000 000 000 (to avoid wrap-around).
911  We calculate statistics at most every 16th round, since we may have
912  a counter table which is very small and updated very often. */
913 
914  if (counter > 2000000000
915  || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
916 
917  dict_update_statistics(table, FALSE /* update even if stats
918  are initialized */);
919  }
920 }
921 
922 /*********************************************************************/
926 UNIV_INTERN
927 void
929 /*===============================*/
930  trx_t* trx)
931 {
932  if (lock_trx_holds_autoinc_locks(trx)) {
933  mutex_enter(&kernel_mutex);
934 
936 
937  mutex_exit(&kernel_mutex);
938  }
939 }
940 
941 /*********************************************************************/
948 UNIV_INTERN
949 int
951 /*=============================*/
952  row_prebuilt_t* prebuilt)
954 {
955  trx_t* trx = prebuilt->trx;
956  ins_node_t* node = prebuilt->ins_node;
957  const dict_table_t* table = prebuilt->table;
958  que_thr_t* thr;
959  ulint err;
960  ibool was_lock_wait;
961 
962  ut_ad(trx);
963  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
964 
965  /* If we already hold an AUTOINC lock on the table then do nothing.
966  Note: We peek at the value of the current owner without acquiring
967  the kernel mutex. **/
968  if (trx == table->autoinc_trx) {
969 
970  return(DB_SUCCESS);
971  }
972 
973  trx->op_info = "setting auto-inc lock";
974 
975  if (node == NULL) {
976  row_get_prebuilt_insert_row(prebuilt);
977  node = prebuilt->ins_node;
978  }
979 
980  /* We use the insert query graph as the dummy graph needed
981  in the lock module call */
982 
983  thr = que_fork_get_first_thr(prebuilt->ins_graph);
984 
986 
987 run_again:
988  thr->run_node = node;
989  thr->prev_node = node;
990 
991  /* It may be that the current session has not yet started
992  its transaction, or it has been committed: */
993 
995 
996  err = lock_table(0, prebuilt->table, LOCK_AUTO_INC, thr);
997 
998  trx->error_state = err;
999 
1000  if (err != DB_SUCCESS) {
1002 
1003  was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1004 
1005  if (was_lock_wait) {
1006  goto run_again;
1007  }
1008 
1009  trx->op_info = "";
1010 
1011  return((int) err);
1012  }
1013 
1015 
1016  trx->op_info = "";
1017 
1018  return((int) err);
1019 }
1020 
1021 /*********************************************************************/
1024 UNIV_INTERN
1025 int
1027 /*=====================*/
1028  row_prebuilt_t* prebuilt,
1030  dict_table_t* table,
1034  ulint mode)
1036 {
1037  trx_t* trx = prebuilt->trx;
1038  que_thr_t* thr;
1039  ulint err;
1040  ibool was_lock_wait;
1041 
1042  ut_ad(trx);
1043  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1044 
1045  trx->op_info = "setting table lock";
1046 
1047  if (prebuilt->sel_graph == NULL) {
1048  /* Build a dummy select query graph */
1049  row_prebuild_sel_graph(prebuilt);
1050  }
1051 
1052  /* We use the select query graph as the dummy graph needed
1053  in the lock module call */
1054 
1055  thr = que_fork_get_first_thr(prebuilt->sel_graph);
1056 
1058 
1059 run_again:
1060  thr->run_node = thr;
1061  thr->prev_node = thr->common.parent;
1062 
1063  /* It may be that the current session has not yet started
1064  its transaction, or it has been committed: */
1065 
1067 
1068  if (table) {
1069  err = lock_table(0, table, static_cast<lock_mode>(mode), thr);
1070  } else {
1071  err = lock_table(0, prebuilt->table,
1072  static_cast<lock_mode>(prebuilt->select_lock_type), thr);
1073  }
1074 
1075  trx->error_state = err;
1076 
1077  if (err != DB_SUCCESS) {
1079 
1080  was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
1081 
1082  if (was_lock_wait) {
1083  goto run_again;
1084  }
1085 
1086  trx->op_info = "";
1087 
1088  return((int) err);
1089  }
1090 
1092 
1093  trx->op_info = "";
1094 
1095  return((int) err);
1096 }
1097 
1098 /*********************************************************************/
1101 UNIV_INTERN
1102 int
1104 /*=================*/
1105  byte* mysql_rec,
1106  row_prebuilt_t* prebuilt)
1108 {
1109  trx_savept_t savept;
1110  que_thr_t* thr;
1111  ulint err;
1112  ibool was_lock_wait;
1113  trx_t* trx = prebuilt->trx;
1114  ins_node_t* node = prebuilt->ins_node;
1115 
1116  ut_ad(trx);
1117  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1118 
1119  if (prebuilt->table->ibd_file_missing) {
1120  ut_print_timestamp(stderr);
1121  fprintf(stderr, " InnoDB: Error:\n"
1122  "InnoDB: MySQL is trying to use a table handle"
1123  " but the .ibd file for\n"
1124  "InnoDB: table %s does not exist.\n"
1125  "InnoDB: Have you deleted the .ibd file"
1126  " from the database directory under\n"
1127  "InnoDB: the MySQL datadir, or have you"
1128  " used DISCARD TABLESPACE?\n"
1129  "InnoDB: Look from\n"
1130  "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1131  "InnoDB: how you can resolve the problem.\n",
1132  prebuilt->table->name);
1133  return(DB_ERROR);
1134  }
1135 
1136  if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1137  fprintf(stderr,
1138  "InnoDB: Error: trying to free a corrupt\n"
1139  "InnoDB: table handle. Magic n %lu, table name ",
1140  (ulong) prebuilt->magic_n);
1141  ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1142  putc('\n', stderr);
1143 
1144  mem_analyze_corruption(prebuilt);
1145 
1146  ut_error;
1147  }
1148 
1149  if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1150  fputs("InnoDB: A new raw disk partition was initialized or\n"
1151  "InnoDB: innodb_force_recovery is on: we do not allow\n"
1152  "InnoDB: database modifications by the user. Shut down\n"
1153  "InnoDB: mysqld and edit my.cnf so that"
1154  " newraw is replaced\n"
1155  "InnoDB: with raw, and innodb_force_... is removed.\n",
1156  stderr);
1157 
1158  return(DB_ERROR);
1159  }
1160 
1161  trx->op_info = "inserting";
1162 
1163  row_mysql_delay_if_needed();
1164 
1166 
1167  if (node == NULL) {
1168  row_get_prebuilt_insert_row(prebuilt);
1169  node = prebuilt->ins_node;
1170  }
1171 
1172  row_mysql_convert_row_to_innobase(node->row, prebuilt, mysql_rec);
1173 
1174  savept = trx_savept_take(trx);
1175 
1176  thr = que_fork_get_first_thr(prebuilt->ins_graph);
1177 
1178  if (prebuilt->sql_stat_start) {
1179  node->state = INS_NODE_SET_IX_LOCK;
1180  prebuilt->sql_stat_start = FALSE;
1181  } else {
1182  node->state = INS_NODE_ALLOC_ROW_ID;
1183  }
1184 
1186 
1187 run_again:
1188  thr->run_node = node;
1189  thr->prev_node = node;
1190 
1191  row_ins_step(thr);
1192 
1193  err = trx->error_state;
1194 
1195  if (err != DB_SUCCESS) {
1197 
1198  /* TODO: what is this? */ thr->lock_state= QUE_THR_LOCK_ROW;
1199 
1200  was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1201  &savept);
1202  thr->lock_state= QUE_THR_LOCK_NOLOCK;
1203 
1204  if (was_lock_wait) {
1205  goto run_again;
1206  }
1207 
1208  trx->op_info = "";
1209 
1210  return((int) err);
1211  }
1212 
1214 
1215  prebuilt->table->stat_n_rows++;
1216 
1217  srv_n_rows_inserted++;
1218 
1219  if (prebuilt->table->stat_n_rows == 0) {
1220  /* Avoid wrap-over */
1221  prebuilt->table->stat_n_rows--;
1222  }
1223 
1224  row_update_statistics_if_needed(prebuilt->table);
1225  trx->op_info = "";
1226 
1227  return((int) err);
1228 }
1229 
1230 /*********************************************************************/
1232 UNIV_INTERN
1233 void
1235 /*===================*/
1236  row_prebuilt_t* prebuilt)
1238 {
1239  sel_node_t* node;
1240 
1241  ut_ad(prebuilt && prebuilt->trx);
1242 
1243  if (prebuilt->sel_graph == NULL) {
1244 
1245  node = sel_node_create(prebuilt->heap);
1246 
1247  prebuilt->sel_graph = static_cast<que_fork_t *>(que_node_get_parent(
1249  prebuilt->trx,
1250  prebuilt->heap)));
1251 
1252  prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
1253  }
1254 }
1255 
1256 /*********************************************************************/
1260 UNIV_INTERN
1261 upd_node_t*
1263 /*=============================*/
1264  dict_table_t* table,
1265  mem_heap_t* heap)
1266 {
1267  upd_node_t* node;
1268 
1269  node = upd_node_create(heap);
1270 
1271  node->in_mysql_interface = TRUE;
1272  node->is_delete = FALSE;
1273  node->searched_update = FALSE;
1274  node->select = NULL;
1275  node->pcur = btr_pcur_create_for_mysql();
1276  node->table = table;
1277 
1278  node->update = upd_create(dict_table_get_n_cols(table), heap);
1279 
1280  node->update_n_fields = dict_table_get_n_cols(table);
1281 
1282  UT_LIST_INIT(node->columns);
1283  node->has_clust_rec_x_lock = TRUE;
1284  node->cmpl_info = 0;
1285 
1286  node->table_sym = NULL;
1287  node->col_assign_list = NULL;
1288 
1289  return(node);
1290 }
1291 
1292 /*********************************************************************/
1297 UNIV_INTERN
1298 upd_t*
1300 /*===========================*/
1301  row_prebuilt_t* prebuilt)
1303 {
1304  dict_table_t* table = prebuilt->table;
1305  upd_node_t* node;
1306 
1307  ut_ad(prebuilt && table && prebuilt->trx);
1308 
1309  if (prebuilt->upd_node == NULL) {
1310 
1311  /* Not called before for this handle: create an update node
1312  and query graph to the prebuilt struct */
1313 
1314  node = row_create_update_node_for_mysql(table, prebuilt->heap);
1315 
1316  prebuilt->upd_node = node;
1317 
1318  prebuilt->upd_graph = static_cast<que_fork_t *>(que_node_get_parent(
1320  prebuilt->trx,
1321  prebuilt->heap)));
1322  prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
1323  }
1324 
1325  return(prebuilt->upd_node->update);
1326 }
1327 
1328 /*********************************************************************/
1331 UNIV_INTERN
1332 int
1334 /*=================*/
1335  byte* mysql_rec,
1337  row_prebuilt_t* prebuilt)
1339 {
1340  trx_savept_t savept;
1341  ulint err;
1342  que_thr_t* thr;
1343  ibool was_lock_wait;
1344  dict_index_t* clust_index;
1345  /* ulint ref_len; */
1346  upd_node_t* node;
1347  dict_table_t* table = prebuilt->table;
1348  trx_t* trx = prebuilt->trx;
1349 
1350  ut_ad(prebuilt && trx);
1351  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1352  UT_NOT_USED(mysql_rec);
1353 
1354  if (prebuilt->table->ibd_file_missing) {
1355  ut_print_timestamp(stderr);
1356  fprintf(stderr, " InnoDB: Error:\n"
1357  "InnoDB: MySQL is trying to use a table handle"
1358  " but the .ibd file for\n"
1359  "InnoDB: table %s does not exist.\n"
1360  "InnoDB: Have you deleted the .ibd file"
1361  " from the database directory under\n"
1362  "InnoDB: the MySQL datadir, or have you"
1363  " used DISCARD TABLESPACE?\n"
1364  "InnoDB: Look from\n"
1365  "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
1366  "InnoDB: how you can resolve the problem.\n",
1367  prebuilt->table->name);
1368  return(DB_ERROR);
1369  }
1370 
1371  if (UNIV_UNLIKELY(prebuilt->magic_n != ROW_PREBUILT_ALLOCATED)) {
1372  fprintf(stderr,
1373  "InnoDB: Error: trying to free a corrupt\n"
1374  "InnoDB: table handle. Magic n %lu, table name ",
1375  (ulong) prebuilt->magic_n);
1376  ut_print_name(stderr, trx, TRUE, prebuilt->table->name);
1377  putc('\n', stderr);
1378 
1379  mem_analyze_corruption(prebuilt);
1380 
1381  ut_error;
1382  }
1383 
1384  if (UNIV_UNLIKELY(srv_created_new_raw || srv_force_recovery)) {
1385  fputs("InnoDB: A new raw disk partition was initialized or\n"
1386  "InnoDB: innodb_force_recovery is on: we do not allow\n"
1387  "InnoDB: database modifications by the user. Shut down\n"
1388  "InnoDB: mysqld and edit my.cnf so that newraw"
1389  " is replaced\n"
1390  "InnoDB: with raw, and innodb_force_... is removed.\n",
1391  stderr);
1392 
1393  return(DB_ERROR);
1394  }
1395 
1396  trx->op_info = "updating or deleting";
1397 
1398  row_mysql_delay_if_needed();
1399 
1401 
1402  node = prebuilt->upd_node;
1403 
1404  clust_index = dict_table_get_first_index(table);
1405 
1406  if (prebuilt->pcur->btr_cur.index == clust_index) {
1407  btr_pcur_copy_stored_position(node->pcur, prebuilt->pcur);
1408  } else {
1410  prebuilt->clust_pcur);
1411  }
1412 
1413  ut_a(node->pcur->rel_pos == BTR_PCUR_ON);
1414 
1415  /* MySQL seems to call rnd_pos before updating each row it
1416  has cached: we can get the correct cursor position from
1417  prebuilt->pcur; NOTE that we cannot build the row reference
1418  from mysql_rec if the clustered index was automatically
1419  generated for the table: MySQL does not know anything about
1420  the row id used as the clustered index key */
1421 
1422  savept = trx_savept_take(trx);
1423 
1424  thr = que_fork_get_first_thr(prebuilt->upd_graph);
1425 
1426  node->state = UPD_NODE_UPDATE_CLUSTERED;
1427 
1428  ut_ad(!prebuilt->sql_stat_start);
1429 
1431 
1432 run_again:
1433  thr->run_node = node;
1434  thr->prev_node = node;
1435  thr->fk_cascade_depth = 0;
1436 
1437  row_upd_step(thr);
1438 
1439  /* The recursive call for cascading update/delete happens
1440  in above row_upd_step(), reset the counter once we come
1441  out of the recursive call, so it does not accumulate for
1442  different row deletes */
1443  thr->fk_cascade_depth = 0;
1444 
1445  err = trx->error_state;
1446 
1447  /* Reset fk_cascade_depth back to 0 */
1448  thr->fk_cascade_depth = 0;
1449 
1450  if (err != DB_SUCCESS) {
1452 
1453  if (err == DB_RECORD_NOT_FOUND) {
1454  trx->error_state = DB_SUCCESS;
1455  trx->op_info = "";
1456 
1457  return((int) err);
1458  }
1459 
1460  thr->lock_state= QUE_THR_LOCK_ROW;
1461  was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
1462  &savept);
1463  thr->lock_state= QUE_THR_LOCK_NOLOCK;
1464 
1465  if (was_lock_wait) {
1466  goto run_again;
1467  }
1468 
1469  trx->op_info = "";
1470 
1471  return((int) err);
1472  }
1473 
1475 
1476  if (node->is_delete) {
1477  if (prebuilt->table->stat_n_rows > 0) {
1478  prebuilt->table->stat_n_rows--;
1479  }
1480 
1481  srv_n_rows_deleted++;
1482  } else {
1483  srv_n_rows_updated++;
1484  }
1485 
1486  /* We update table statistics only if it is a DELETE or UPDATE
1487  that changes indexed columns, UPDATEs that change only non-indexed
1488  columns would not affect statistics. */
1489  if (node->is_delete || !(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
1490  row_update_statistics_if_needed(prebuilt->table);
1491  }
1492 
1493  trx->op_info = "";
1494 
1495  return((int) err);
1496 }
1497 
1498 /*********************************************************************/
1508 UNIV_INTERN
1509 int
1511 /*=================*/
1512  row_prebuilt_t* prebuilt,
1514  ibool has_latches_on_recs)
1519 {
1520  btr_pcur_t* pcur = prebuilt->pcur;
1521  btr_pcur_t* clust_pcur = prebuilt->clust_pcur;
1522  trx_t* trx = prebuilt->trx;
1523 
1524  ut_ad(prebuilt && trx);
1525  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1526 
1527  if (UNIV_UNLIKELY
1529  && trx->isolation_level > TRX_ISO_READ_COMMITTED)) {
1530 
1531  fprintf(stderr,
1532  "InnoDB: Error: calling row_unlock_for_mysql though\n"
1533  "InnoDB: innodb_locks_unsafe_for_binlog is FALSE and\n"
1534  "InnoDB: this session is not using"
1535  " READ COMMITTED isolation level.\n");
1536 
1537  return(DB_SUCCESS);
1538  }
1539 
1540  trx->op_info = "unlock_row";
1541 
1542  if (prebuilt->new_rec_locks >= 1) {
1543 
1544  const rec_t* rec;
1545  dict_index_t* index;
1546  trx_id_t rec_trx_id;
1547  mtr_t mtr;
1548 
1549  mtr_start(&mtr);
1550 
1551  /* Restore the cursor position and find the record */
1552 
1553  if (!has_latches_on_recs) {
1554  btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, &mtr);
1555  }
1556 
1557  rec = btr_pcur_get_rec(pcur);
1558  index = btr_pcur_get_btr_cur(pcur)->index;
1559 
1560  if (prebuilt->new_rec_locks >= 2) {
1561  /* Restore the cursor position and find the record
1562  in the clustered index. */
1563 
1564  if (!has_latches_on_recs) {
1565  btr_pcur_restore_position(BTR_SEARCH_LEAF,
1566  clust_pcur, &mtr);
1567  }
1568 
1569  rec = btr_pcur_get_rec(clust_pcur);
1570  index = btr_pcur_get_btr_cur(clust_pcur)->index;
1571  }
1572 
1573  if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
1574  /* This is not a clustered index record. We
1575  do not know how to unlock the record. */
1576  goto no_unlock;
1577  }
1578 
1579  /* If the record has been modified by this
1580  transaction, do not unlock it. */
1581 
1582  if (index->trx_id_offset) {
1583  rec_trx_id = trx_read_trx_id(rec
1584  + index->trx_id_offset);
1585  } else {
1586  mem_heap_t* heap = NULL;
1587  ulint offsets_[REC_OFFS_NORMAL_SIZE];
1588  ulint* offsets = offsets_;
1589 
1590  rec_offs_init(offsets_);
1591  offsets = rec_get_offsets(rec, index, offsets,
1592  ULINT_UNDEFINED, &heap);
1593 
1594  rec_trx_id = row_get_rec_trx_id(rec, index, offsets);
1595 
1596  if (UNIV_LIKELY_NULL(heap)) {
1597  mem_heap_free(heap);
1598  }
1599  }
1600 
1601  if (rec_trx_id != trx->id) {
1602  /* We did not update the record: unlock it */
1603 
1604  rec = btr_pcur_get_rec(pcur);
1605  index = btr_pcur_get_btr_cur(pcur)->index;
1606 
1607  lock_rec_unlock(trx, btr_pcur_get_block(pcur),
1608  rec, static_cast<lock_mode>(prebuilt->select_lock_type));
1609 
1610  if (prebuilt->new_rec_locks >= 2) {
1611  rec = btr_pcur_get_rec(clust_pcur);
1612  index = btr_pcur_get_btr_cur(clust_pcur)->index;
1613 
1614  lock_rec_unlock(trx,
1615  btr_pcur_get_block(clust_pcur),
1616  rec,
1617  static_cast<lock_mode>(prebuilt->select_lock_type));
1618  }
1619  }
1620 no_unlock:
1621  mtr_commit(&mtr);
1622  }
1623 
1624  trx->op_info = "";
1625 
1626  return(DB_SUCCESS);
1627 }
1628 
1629 /**********************************************************************/
1632 UNIV_INTERN
1633 ulint
1635 /*=========================*/
1636  que_thr_t* thr,
1637  upd_node_t* node,
1639  dict_table_t* table)
1640 {
1641  ulint err;
1642  trx_t* trx;
1643 
1644  trx = thr_get_trx(thr);
1645 
1646  /* Increment fk_cascade_depth to record the recursive call depth on
1647  a single update/delete that affects multiple tables chained
1648  together with foreign key relations. */
1649  thr->fk_cascade_depth++;
1650 
1651  if (thr->fk_cascade_depth > FK_MAX_CASCADE_DEL) {
1652  return (DB_FOREIGN_EXCEED_MAX_CASCADE);
1653  }
1654 run_again:
1655  thr->run_node = node;
1656  thr->prev_node = node;
1657 
1658  row_upd_step(thr);
1659 
1660  /* The recursive call for cascading update/delete happens
1661  in above row_upd_step(), reset the counter once we come
1662  out of the recursive call, so it does not accumulate for
1663  different row deletes */
1664  thr->fk_cascade_depth = 0;
1665 
1666  err = trx->error_state;
1667 
1668  /* Note that the cascade node is a subnode of another InnoDB
1669  query graph node. We do a normal lock wait in this node, but
1670  all errors are handled by the parent node. */
1671 
1672  if (err == DB_LOCK_WAIT) {
1673  /* Handle lock wait here */
1674 
1676 
1678 
1679  /* Note that a lock wait may also end in a lock wait timeout,
1680  or this transaction is picked as a victim in selective
1681  deadlock resolution */
1682 
1683  if (trx->error_state != DB_SUCCESS) {
1684 
1685  return(trx->error_state);
1686  }
1687 
1688  /* Retry operation after a normal lock wait */
1689 
1690  goto run_again;
1691  }
1692 
1693  if (err != DB_SUCCESS) {
1694 
1695  return(err);
1696  }
1697 
1698  if (node->is_delete) {
1699  if (table->stat_n_rows > 0) {
1700  table->stat_n_rows--;
1701  }
1702 
1703  srv_n_rows_deleted++;
1704  } else {
1705  srv_n_rows_updated++;
1706  }
1707 
1708  row_update_statistics_if_needed(table);
1709 
1710  return(err);
1711 }
1712 
1713 /*********************************************************************/
1717 UNIV_INTERN
1718 ibool
1720 /*==============================*/
1721  const dict_table_t* table)
1722 {
1723  const dict_index_t* clust_index;
1724 
1725  clust_index = dict_table_get_first_index(table);
1726 
1727  return(dict_index_get_nth_col(clust_index, 0)->mtype == DATA_SYS);
1728 }
1729 
1730 /*********************************************************************/
1733 UNIV_INTERN
1734 void
1736 /*==================================*/
1737  trx_t* trx,
1738  const char* file,
1739  ulint line)
1740 {
1741  ut_a(trx->dict_operation_lock_mode == 0);
1742 
1743  rw_lock_s_lock_func(&dict_operation_lock, 0, file, line);
1744 
1745  trx->dict_operation_lock_mode = RW_S_LATCH;
1746 }
1747 
1748 /*********************************************************************/
1750 UNIV_INTERN
1751 void
1753 /*===============================*/
1754  trx_t* trx)
1755 {
1756  ut_a(trx->dict_operation_lock_mode == RW_S_LATCH);
1757 
1758  rw_lock_s_unlock(&dict_operation_lock);
1759 
1760  trx->dict_operation_lock_mode = 0;
1761 }
1762 
1763 /*********************************************************************/
1766 UNIV_INTERN
1767 void
1769 /*================================*/
1770  trx_t* trx,
1771  const char* file,
1772  ulint line)
1773 {
1774  ut_a(trx->dict_operation_lock_mode == 0
1775  || trx->dict_operation_lock_mode == RW_X_LATCH);
1776 
1777  /* Serialize data dictionary operations with dictionary mutex:
1778  no deadlocks or lock waits can occur then in these operations */
1779 
1780  rw_lock_x_lock_func(&dict_operation_lock, 0, file, line);
1781  trx->dict_operation_lock_mode = RW_X_LATCH;
1782 
1783  mutex_enter(&(dict_sys->mutex));
1784 }
1785 
1786 /*********************************************************************/
1788 UNIV_INTERN
1789 void
1791 /*=============================*/
1792  trx_t* trx)
1793 {
1794  ut_a(trx->dict_operation_lock_mode == RW_X_LATCH);
1795 
1796  /* Serialize data dictionary operations with dictionary mutex:
1797  no deadlocks can occur then in these operations */
1798 
1799  mutex_exit(&(dict_sys->mutex));
1800  rw_lock_x_unlock(&dict_operation_lock);
1801 
1802  trx->dict_operation_lock_mode = 0;
1803 }
1804 
1805 /*********************************************************************/
1812 UNIV_INTERN
1813 int
1815 /*=======================*/
1816  dict_table_t* table,
1818  trx_t* trx)
1819 {
1820  tab_node_t* node;
1821  mem_heap_t* heap;
1822  que_thr_t* thr;
1823  const char* table_name;
1824  ulint table_name_len;
1825  ulint err;
1826 
1827  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1828 #ifdef UNIV_SYNC_DEBUG
1829  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1830 #endif /* UNIV_SYNC_DEBUG */
1831  ut_ad(mutex_own(&(dict_sys->mutex)));
1832  ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
1833 
1834  if (srv_created_new_raw) {
1835  fputs("InnoDB: A new raw disk partition was initialized:\n"
1836  "InnoDB: we do not allow database modifications"
1837  " by the user.\n"
1838  "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
1839  " is replaced with raw.\n", stderr);
1840  dict_mem_table_free(table);
1841  trx_commit_for_mysql(trx);
1842 
1843  return(DB_ERROR);
1844  }
1845 
1846  trx->op_info = "creating table";
1847 
1849 
1850  /* The table name is prefixed with the database name and a '/'.
1851  Certain table names starting with 'innodb_' have their special
1852  meaning regardless of the database name. Thus, we need to
1853  ignore the database name prefix in the comparisons. */
1854  table_name = strchr(table->name, '/');
1855  ut_a(table_name);
1856  table_name++;
1857  table_name_len = strlen(table_name) + 1;
1858 
1859  if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
1860 
1861  /* Table equals "innodb_monitor":
1862  start monitor prints */
1863 
1864  srv_print_innodb_monitor = TRUE;
1865 
1866  /* The lock timeout monitor thread also takes care
1867  of InnoDB monitor prints */
1868 
1869  os_event_set(srv_lock_timeout_thread_event);
1870  } else if (STR_EQ(table_name, table_name_len,
1871  S_innodb_lock_monitor)) {
1872 
1873  srv_print_innodb_monitor = TRUE;
1874  srv_print_innodb_lock_monitor = TRUE;
1875  os_event_set(srv_lock_timeout_thread_event);
1876  } else if (STR_EQ(table_name, table_name_len,
1877  S_innodb_tablespace_monitor)) {
1878 
1879  srv_print_innodb_tablespace_monitor = TRUE;
1880  os_event_set(srv_lock_timeout_thread_event);
1881  } else if (STR_EQ(table_name, table_name_len,
1882  S_innodb_table_monitor)) {
1883 
1884  srv_print_innodb_table_monitor = TRUE;
1885  os_event_set(srv_lock_timeout_thread_event);
1886  } else if (STR_EQ(table_name, table_name_len,
1887  S_innodb_mem_validate)) {
1888  /* We define here a debugging feature intended for
1889  developers */
1890 
1891  fputs("Validating InnoDB memory:\n"
1892  "to use this feature you must compile InnoDB with\n"
1893  "UNIV_MEM_DEBUG defined in univ.i and"
1894  " the server must be\n"
1895  "quiet because allocation from a mem heap"
1896  " is not protected\n"
1897  "by any semaphore.\n", stderr);
1898 #ifdef UNIV_MEM_DEBUG
1899  ut_a(mem_validate());
1900  fputs("Memory validated\n", stderr);
1901 #else /* UNIV_MEM_DEBUG */
1902  fputs("Memory NOT validated (recompile with UNIV_MEM_DEBUG)\n",
1903  stderr);
1904 #endif /* UNIV_MEM_DEBUG */
1905  }
1906 
1907  heap = mem_heap_create(512);
1908 
1910 
1911  node = tab_create_graph_create(table, heap);
1912 
1913  thr = pars_complete_graph_for_exec(node, trx, heap);
1914 
1915  ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
1916  que_run_threads(thr);
1917 
1918  err = trx->error_state;
1919 
1920  switch (err) {
1921  case DB_SUCCESS:
1922  break;
1923  case DB_OUT_OF_FILE_SPACE:
1924  trx->error_state = DB_SUCCESS;
1925  trx_general_rollback_for_mysql(trx, NULL);
1926 
1927  ut_print_timestamp(stderr);
1928  fputs(" InnoDB: Warning: cannot create table ",
1929  stderr);
1930  ut_print_name(stderr, trx, TRUE, table->name);
1931  fputs(" because tablespace full\n", stderr);
1932 
1933  if (dict_table_get_low(table->name)) {
1934 
1935  row_drop_table_for_mysql(table->name, trx, FALSE);
1936  trx_commit_for_mysql(trx);
1937  }
1938  break;
1939 
1940  case DB_DUPLICATE_KEY:
1941  default:
1942  /* We may also get err == DB_ERROR if the .ibd file for the
1943  table already exists */
1944 
1945  trx->error_state = DB_SUCCESS;
1946  trx_general_rollback_for_mysql(trx, NULL);
1947  dict_mem_table_free(table);
1948  break;
1949  }
1950 
1952 
1953  trx->op_info = "";
1954 
1955  return((int) err);
1956 }
1957 
1958 /*********************************************************************/
1963 UNIV_INTERN
1964 int
1966 /*=======================*/
1967  dict_index_t* index,
1969  trx_t* trx,
1970  const ulint* field_lengths)
1976 {
1977  ind_node_t* node;
1978  mem_heap_t* heap;
1979  que_thr_t* thr;
1980  ulint err;
1981  ulint i;
1982  ulint len;
1983  char* table_name;
1984 
1985 #ifdef UNIV_SYNC_DEBUG
1986  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
1987 #endif /* UNIV_SYNC_DEBUG */
1988  ut_ad(mutex_own(&(dict_sys->mutex)));
1989  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
1990 
1991  trx->op_info = "creating index";
1992 
1993  /* Copy the table name because we may want to drop the
1994  table later, after the index object is freed (inside
1995  que_run_threads()) and thus index->table_name is not available. */
1996  table_name = mem_strdup(index->table_name);
1997 
1999 
2000  /* Check that the same column does not appear twice in the index.
2001  Starting from 4.0.14, InnoDB should be able to cope with that, but
2002  safer not to allow them. */
2003 
2004  for (i = 0; i < dict_index_get_n_fields(index); i++) {
2005  ulint j;
2006 
2007  for (j = 0; j < i; j++) {
2008  if (0 == ut_strcmp(
2009  dict_index_get_nth_field(index, j)->name,
2010  dict_index_get_nth_field(index, i)->name)) {
2011  ut_print_timestamp(stderr);
2012 
2013  fputs(" InnoDB: Error: column ", stderr);
2014  ut_print_name(stderr, trx, FALSE,
2015  dict_index_get_nth_field(
2016  index, i)->name);
2017  fputs(" appears twice in ", stderr);
2018  dict_index_name_print(stderr, trx, index);
2019  fputs("\n"
2020  "InnoDB: This is not allowed"
2021  " in InnoDB.\n", stderr);
2022 
2023  err = DB_COL_APPEARS_TWICE_IN_INDEX;
2024 
2025  goto error_handling;
2026  }
2027  }
2028 
2029  /* Check also that prefix_len and actual length
2030  < DICT_MAX_INDEX_COL_LEN */
2031 
2032  len = dict_index_get_nth_field(index, i)->prefix_len;
2033 
2034  if (field_lengths) {
2035  len = ut_max(len, field_lengths[i]);
2036  }
2037 
2038  if (len >= DICT_MAX_INDEX_COL_LEN) {
2039  err = DB_TOO_BIG_RECORD;
2040 
2041  goto error_handling;
2042  }
2043  }
2044 
2045  heap = mem_heap_create(512);
2046 
2048 
2049  /* Note that the space id where we store the index is inherited from
2050  the table in dict_build_index_def_step() in dict0crea.c. */
2051 
2052  node = ind_create_graph_create(index, heap);
2053 
2054  thr = pars_complete_graph_for_exec(node, trx, heap);
2055 
2056  ut_a(thr == que_fork_start_command(static_cast<que_fork_t *>(que_node_get_parent(thr))));
2057  que_run_threads(thr);
2058 
2059  err = trx->error_state;
2060 
2062 
2063 error_handling:
2064  if (err != DB_SUCCESS) {
2065  /* We have special error handling here */
2066 
2067  trx->error_state = DB_SUCCESS;
2068 
2069  trx_general_rollback_for_mysql(trx, NULL);
2070 
2071  row_drop_table_for_mysql(table_name, trx, FALSE);
2072 
2073  trx_commit_for_mysql(trx);
2074 
2075  trx->error_state = DB_SUCCESS;
2076  }
2077 
2078  trx->op_info = "";
2079 
2080  mem_free(table_name);
2081 
2082  return((int) err);
2083 }
2084 
2085 /*********************************************************************/
2094 UNIV_INTERN
2095 int
2097 /*==============================*/
2098  trx_t* trx,
2099  const char* sql_string,
2104  size_t sql_length,
2105  const char* name,
2108  ibool reject_fks)
2111 {
2112  ulint err;
2113 
2114  ut_ad(mutex_own(&(dict_sys->mutex)));
2115 #ifdef UNIV_SYNC_DEBUG
2116  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2117 #endif /* UNIV_SYNC_DEBUG */
2118  ut_a(sql_string);
2119 
2120  trx->op_info = "adding foreign keys";
2121 
2123 
2125 
2126  err = dict_create_foreign_constraints(trx, sql_string, sql_length,
2127  name, reject_fks);
2128  if (err == DB_SUCCESS) {
2129  /* Check that also referencing constraints are ok */
2130  err = dict_load_foreigns(name, FALSE, TRUE);
2131  }
2132 
2133  if (err != DB_SUCCESS) {
2134  /* We have special error handling here */
2135 
2136  trx->error_state = DB_SUCCESS;
2137 
2138  trx_general_rollback_for_mysql(trx, NULL);
2139 
2140  row_drop_table_for_mysql(name, trx, FALSE);
2141 
2142  trx_commit_for_mysql(trx);
2143 
2144  trx->error_state = DB_SUCCESS;
2145  }
2146 
2147  return((int) err);
2148 }
2149 
2150 /*********************************************************************/
2158 static
2159 int
2160 row_drop_table_for_mysql_in_background(
2161 /*===================================*/
2162  const char* name)
2163 {
2164  ulint error;
2165  trx_t* trx;
2166 
2168 
2169  /* If the original transaction was dropping a table referenced by
2170  foreign keys, we must set the following to be able to drop the
2171  table: */
2172 
2173  trx->check_foreigns = FALSE;
2174 
2175  /* fputs("InnoDB: Error: Dropping table ", stderr);
2176  ut_print_name(stderr, trx, TRUE, name);
2177  fputs(" in background drop list\n", stderr); */
2178 
2179  /* Try to drop the table in InnoDB */
2180 
2181  error = row_drop_table_for_mysql(name, trx, FALSE);
2182 
2183  /* Flush the log to reduce probability that the .frm files and
2184  the InnoDB data dictionary get out-of-sync if the user runs
2185  with innodb_flush_log_at_trx_commit = 0 */
2186 
2188 
2189  trx_commit_for_mysql(trx);
2190 
2192 
2193  return((int) error);
2194 }
2195 
2196 /*********************************************************************/
2201 UNIV_INTERN
2202 ulint
2204 /*=========================================*/
2205 {
2206  row_mysql_drop_t* drop;
2207  dict_table_t* table;
2208  ulint n_tables;
2209  ulint n_tables_dropped = 0;
2210 loop:
2211  mutex_enter(&kernel_mutex);
2212 
2213  if (!row_mysql_drop_list_inited) {
2214 
2215  UT_LIST_INIT(row_mysql_drop_list);
2216  row_mysql_drop_list_inited = TRUE;
2217  }
2218 
2219  drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2220 
2221  n_tables = UT_LIST_GET_LEN(row_mysql_drop_list);
2222 
2223  mutex_exit(&kernel_mutex);
2224 
2225  if (drop == NULL) {
2226  /* All tables dropped */
2227 
2228  return(n_tables + n_tables_dropped);
2229  }
2230 
2231  mutex_enter(&(dict_sys->mutex));
2232  table = dict_table_get_low(drop->table_name);
2233  mutex_exit(&(dict_sys->mutex));
2234 
2235  if (table == NULL) {
2236  /* If for some reason the table has already been dropped
2237  through some other mechanism, do not try to drop it */
2238 
2239  goto already_dropped;
2240  }
2241 
2242  if (DB_SUCCESS != row_drop_table_for_mysql_in_background(
2243  drop->table_name)) {
2244  /* If the DROP fails for some table, we return, and let the
2245  main thread retry later */
2246 
2247  return(n_tables + n_tables_dropped);
2248  }
2249 
2250  n_tables_dropped++;
2251 
2252 already_dropped:
2253  mutex_enter(&kernel_mutex);
2254 
2255  UT_LIST_REMOVE(row_mysql_drop_list, row_mysql_drop_list, drop);
2256 
2257  ut_print_timestamp(stderr);
2258  fputs(" InnoDB: Dropped table ", stderr);
2259  ut_print_name(stderr, NULL, TRUE, drop->table_name);
2260  fputs(" in background drop queue.\n", stderr);
2261 
2262  mem_free(drop->table_name);
2263 
2264  mem_free(drop);
2265 
2266  mutex_exit(&kernel_mutex);
2267 
2268  goto loop;
2269 }
2270 
2271 /*********************************************************************/
2275 UNIV_INTERN
2276 ulint
2278 /*======================================*/
2279 {
2280  ut_ad(mutex_own(&kernel_mutex));
2281 
2282  if (!row_mysql_drop_list_inited) {
2283 
2284  UT_LIST_INIT(row_mysql_drop_list);
2285  row_mysql_drop_list_inited = TRUE;
2286  }
2287 
2288  return(UT_LIST_GET_LEN(row_mysql_drop_list));
2289 }
2290 
2291 /*********************************************************************/
2298 static
2299 ibool
2300 row_add_table_to_background_drop_list(
2301 /*==================================*/
2302  const char* name)
2303 {
2304  row_mysql_drop_t* drop;
2305 
2306  mutex_enter(&kernel_mutex);
2307 
2308  if (!row_mysql_drop_list_inited) {
2309 
2310  UT_LIST_INIT(row_mysql_drop_list);
2311  row_mysql_drop_list_inited = TRUE;
2312  }
2313 
2314  /* Look if the table already is in the drop list */
2315  drop = UT_LIST_GET_FIRST(row_mysql_drop_list);
2316 
2317  while (drop != NULL) {
2318  if (strcmp(drop->table_name, name) == 0) {
2319  /* Already in the list */
2320 
2321  mutex_exit(&kernel_mutex);
2322 
2323  return(FALSE);
2324  }
2325 
2326  drop = UT_LIST_GET_NEXT(row_mysql_drop_list, drop);
2327  }
2328 
2329  drop = static_cast<row_mysql_drop_t *>(mem_alloc(sizeof(row_mysql_drop_t)));
2330 
2331  drop->table_name = mem_strdup(name);
2332 
2333  UT_LIST_ADD_LAST(row_mysql_drop_list, row_mysql_drop_list, drop);
2334 
2335  /* fputs("InnoDB: Adding table ", stderr);
2336  ut_print_name(stderr, trx, TRUE, drop->table_name);
2337  fputs(" to background drop list\n", stderr); */
2338 
2339  mutex_exit(&kernel_mutex);
2340 
2341  return(TRUE);
2342 }
2343 
2344 /*********************************************************************/
2349 UNIV_INTERN
2350 int
2352 /*=============================*/
2353  const char* name,
2354  trx_t* trx)
2355 {
2356  dict_foreign_t* foreign;
2357  table_id_t new_id;
2358  dict_table_t* table;
2359  ibool success;
2360  ulint err;
2361  pars_info_t* info = NULL;
2362 
2363  /* How do we prevent crashes caused by ongoing operations on
2364  the table? Old operations could try to access non-existent
2365  pages.
2366 
2367  1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2368  MySQL table lock on the table before we can do DISCARD
2369  TABLESPACE. Then there are no running queries on the table.
2370 
2371  2) Purge and rollback: we assign a new table id for the
2372  table. Since purge and rollback look for the table based on
2373  the table id, they see the table as 'dropped' and discard
2374  their operations.
2375 
2376  3) Insert buffer: we remove all entries for the tablespace in
2377  the insert buffer tree; as long as the tablespace mem object
2378  does not exist, ongoing insert buffer page merges are
2379  discarded in buf0rea.c. If we recreate the tablespace mem
2380  object with IMPORT TABLESPACE later, then the tablespace will
2381  have the same id, but the tablespace_version field in the mem
2382  object is different, and ongoing old insert buffer page merges
2383  get discarded.
2384 
2385  4) Linear readahead and random readahead: we use the same
2386  method as in 3) to discard ongoing operations.
2387 
2388  5) FOREIGN KEY operations: if
2389  table->n_foreign_key_checks_running > 0, we do not allow the
2390  discard. We also reserve the data dictionary latch. */
2391 
2392  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2393 
2394  trx->op_info = "discarding tablespace";
2396 
2397  /* Serialize data dictionary operations with dictionary mutex:
2398  no deadlocks can occur then in these operations */
2399 
2400  row_mysql_lock_data_dictionary(trx);
2401 
2402  table = dict_table_get_low(name);
2403 
2404  if (!table) {
2405  err = DB_TABLE_NOT_FOUND;
2406 
2407  goto funct_exit;
2408  }
2409 
2410  if (table->space == 0) {
2411  ut_print_timestamp(stderr);
2412  fputs(" InnoDB: Error: table ", stderr);
2413  ut_print_name(stderr, trx, TRUE, name);
2414  fputs("\n"
2415  "InnoDB: is in the system tablespace 0"
2416  " which cannot be discarded\n", stderr);
2417  err = DB_ERROR;
2418 
2419  goto funct_exit;
2420  }
2421 
2422  if (table->n_foreign_key_checks_running > 0) {
2423 
2424  ut_print_timestamp(stderr);
2425  fputs(" InnoDB: You are trying to DISCARD table ", stderr);
2426  ut_print_name(stderr, trx, TRUE, table->name);
2427  fputs("\n"
2428  "InnoDB: though there is a foreign key check"
2429  " running on it.\n"
2430  "InnoDB: Cannot discard the table.\n",
2431  stderr);
2432 
2433  err = DB_ERROR;
2434 
2435  goto funct_exit;
2436  }
2437 
2438  /* Check if the table is referenced by foreign key constraints from
2439  some other table (not the table itself) */
2440 
2441  foreign = UT_LIST_GET_FIRST(table->referenced_list);
2442 
2443  while (foreign && foreign->foreign_table == table) {
2444  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2445  }
2446 
2447  if (foreign && trx->check_foreigns) {
2448 
2449  FILE* ef = dict_foreign_err_file;
2450 
2451  /* We only allow discarding a referenced table if
2452  FOREIGN_KEY_CHECKS is set to 0 */
2453 
2454  err = DB_CANNOT_DROP_CONSTRAINT;
2455 
2456  mutex_enter(&dict_foreign_err_mutex);
2457  rewind(ef);
2458  ut_print_timestamp(ef);
2459 
2460  fputs(" Cannot DISCARD table ", ef);
2461  ut_print_name(stderr, trx, TRUE, name);
2462  fputs("\n"
2463  "because it is referenced by ", ef);
2464  ut_print_name(stderr, trx, TRUE, foreign->foreign_table_name);
2465  putc('\n', ef);
2466  mutex_exit(&dict_foreign_err_mutex);
2467 
2468  goto funct_exit;
2469  }
2470 
2471  dict_hdr_get_new_id(&new_id, NULL, NULL);
2472 
2473  /* Remove all locks except the table-level S and X locks. */
2474  lock_remove_all_on_table(table, FALSE);
2475 
2476  info = pars_info_create();
2477 
2478  pars_info_add_str_literal(info, "table_name", name);
2479  pars_info_add_ull_literal(info, "new_id", new_id);
2480 
2481  err = que_eval_sql(info,
2482  "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
2483  "old_id CHAR;\n"
2484  "BEGIN\n"
2485  "SELECT ID INTO old_id\n"
2486  "FROM SYS_TABLES\n"
2487  "WHERE NAME = :table_name\n"
2488  "LOCK IN SHARE MODE;\n"
2489  "IF (SQL % NOTFOUND) THEN\n"
2490  " COMMIT WORK;\n"
2491  " RETURN;\n"
2492  "END IF;\n"
2493  "UPDATE SYS_TABLES SET ID = :new_id\n"
2494  " WHERE ID = old_id;\n"
2495  "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2496  " WHERE TABLE_ID = old_id;\n"
2497  "UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
2498  " WHERE TABLE_ID = old_id;\n"
2499  "COMMIT WORK;\n"
2500  "END;\n"
2501  , FALSE, trx);
2502 
2503  if (err != DB_SUCCESS) {
2504  trx->error_state = DB_SUCCESS;
2505  trx_general_rollback_for_mysql(trx, NULL);
2506  trx->error_state = DB_SUCCESS;
2507  } else {
2508  dict_table_change_id_in_cache(table, new_id);
2509 
2510  success = fil_discard_tablespace(table->space);
2511 
2512  if (!success) {
2513  trx->error_state = DB_SUCCESS;
2514  trx_general_rollback_for_mysql(trx, NULL);
2515  trx->error_state = DB_SUCCESS;
2516 
2517  err = DB_ERROR;
2518  } else {
2519  /* Set the flag which tells that now it is legal to
2520  IMPORT a tablespace for this table */
2521  table->tablespace_discarded = TRUE;
2522  table->ibd_file_missing = TRUE;
2523  }
2524  }
2525 
2526 funct_exit:
2527  trx_commit_for_mysql(trx);
2528 
2530 
2531  trx->op_info = "";
2532 
2533  return((int) err);
2534 }
2535 
2536 /*****************************************************************/
2540 UNIV_INTERN
2541 int
2543 /*============================*/
2544  const char* name,
2545  trx_t* trx)
2546 {
2547  dict_table_t* table;
2548  ibool success;
2549  ib_uint64_t current_lsn;
2550  ulint err = DB_SUCCESS;
2551 
2552  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2553 
2555 
2556  trx->op_info = "importing tablespace";
2557 
2558  current_lsn = log_get_lsn();
2559 
2560  /* It is possible, though very improbable, that the lsn's in the
2561  tablespace to be imported have risen above the current system lsn, if
2562  a lengthy purge, ibuf merge, or rollback was performed on a backup
2563  taken with ibbackup. If that is the case, reset page lsn's in the
2564  file. We assume that mysqld was shut down after it performed these
2565  cleanup operations on the .ibd file, so that it stamped the latest lsn
2566  to the FIL_PAGE_FILE_FLUSH_LSN in the first page of the .ibd file.
2567 
2568  TODO: reset also the trx id's in clustered index records and write
2569  a new space id to each data page. That would allow us to import clean
2570  .ibd files from another MySQL installation. */
2571 
2572  success = fil_reset_too_high_lsns(name, current_lsn);
2573 
2574  if (!success) {
2575  ut_print_timestamp(stderr);
2576  fputs(" InnoDB: Error: cannot reset lsn's in table ", stderr);
2577  ut_print_name(stderr, trx, TRUE, name);
2578  fputs("\n"
2579  "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2580  stderr);
2581 
2582  err = DB_ERROR;
2583 
2584  row_mysql_lock_data_dictionary(trx);
2585 
2586  goto funct_exit;
2587  }
2588 
2589  /* Serialize data dictionary operations with dictionary mutex:
2590  no deadlocks can occur then in these operations */
2591 
2592  row_mysql_lock_data_dictionary(trx);
2593 
2594  table = dict_table_get_low(name);
2595 
2596  if (!table) {
2597  ut_print_timestamp(stderr);
2598  fputs(" InnoDB: table ", stderr);
2599  ut_print_name(stderr, trx, TRUE, name);
2600  fputs("\n"
2601  "InnoDB: does not exist in the InnoDB data dictionary\n"
2602  "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2603  stderr);
2604 
2605  err = DB_TABLE_NOT_FOUND;
2606 
2607  goto funct_exit;
2608  }
2609 
2610  if (table->space == 0) {
2611  ut_print_timestamp(stderr);
2612  fputs(" InnoDB: Error: table ", stderr);
2613  ut_print_name(stderr, trx, TRUE, name);
2614  fputs("\n"
2615  "InnoDB: is in the system tablespace 0"
2616  " which cannot be imported\n", stderr);
2617  err = DB_ERROR;
2618 
2619  goto funct_exit;
2620  }
2621 
2622  if (!table->tablespace_discarded) {
2623  ut_print_timestamp(stderr);
2624  fputs(" InnoDB: Error: you are trying to"
2625  " IMPORT a tablespace\n"
2626  "InnoDB: ", stderr);
2627  ut_print_name(stderr, trx, TRUE, name);
2628  fputs(", though you have not called DISCARD on it yet\n"
2629  "InnoDB: during the lifetime of the mysqld process!\n",
2630  stderr);
2631 
2632  err = DB_ERROR;
2633 
2634  goto funct_exit;
2635  }
2636 
2637  /* Play safe and remove all insert buffer entries, though we should
2638  have removed them already when DISCARD TABLESPACE was called */
2639 
2641 
2643  TRUE, table->space,
2644  table->flags == DICT_TF_COMPACT ? 0 : table->flags,
2645  table->name);
2646  if (success) {
2647  table->ibd_file_missing = FALSE;
2648  table->tablespace_discarded = FALSE;
2649  } else {
2650  if (table->ibd_file_missing) {
2651  ut_print_timestamp(stderr);
2652  fputs(" InnoDB: cannot find or open in the"
2653  " database directory the .ibd file of\n"
2654  "InnoDB: table ", stderr);
2655  ut_print_name(stderr, trx, TRUE, name);
2656  fputs("\n"
2657  "InnoDB: in ALTER TABLE ... IMPORT TABLESPACE\n",
2658  stderr);
2659  }
2660 
2661  err = DB_ERROR;
2662  }
2663 
2664 funct_exit:
2665  trx_commit_for_mysql(trx);
2666 
2668 
2669  trx->op_info = "";
2670 
2671  return((int) err);
2672 }
2673 
2674 /*********************************************************************/
2677 UNIV_INTERN
2678 int
2680 /*=========================*/
2681  dict_table_t* table,
2682  trx_t* trx)
2683 {
2684  dict_foreign_t* foreign;
2685  ulint err;
2686  mem_heap_t* heap;
2687  byte* buf;
2688  dtuple_t* tuple;
2689  dfield_t* dfield;
2690  dict_index_t* sys_index;
2691  btr_pcur_t pcur;
2692  mtr_t mtr;
2693  table_id_t new_id;
2694  ulint recreate_space = 0;
2695  pars_info_t* info = NULL;
2696 
2697  /* How do we prevent crashes caused by ongoing operations on
2698  the table? Old operations could try to access non-existent
2699  pages.
2700 
2701  1) SQL queries, INSERT, SELECT, ...: we must get an exclusive
2702  MySQL table lock on the table before we can do TRUNCATE
2703  TABLE. Then there are no running queries on the table. This is
2704  guaranteed, because in ha_innobase::store_lock(), we do not
2705  weaken the TL_WRITE lock requested by MySQL when executing
2706  SQLCOM_TRUNCATE.
2707 
2708  2) Purge and rollback: we assign a new table id for the
2709  table. Since purge and rollback look for the table based on
2710  the table id, they see the table as 'dropped' and discard
2711  their operations.
2712 
2713  3) Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
2714  so we do not have to remove insert buffer records, as the
2715  insert buffer works at a low level. If a freed page is later
2716  reallocated, the allocator will remove the ibuf entries for
2717  it.
2718 
2719  When we truncate *.ibd files by recreating them (analogous to
2720  DISCARD TABLESPACE), we remove all entries for the table in the
2721  insert buffer tree. This is not strictly necessary, because
2722  in 6) we will assign a new tablespace identifier, but we can
2723  free up some space in the system tablespace.
2724 
2725  4) Linear readahead and random readahead: we use the same
2726  method as in 3) to discard ongoing operations. (This is only
2727  relevant for TRUNCATE TABLE by DISCARD TABLESPACE.)
2728 
2729  5) FOREIGN KEY operations: if
2730  table->n_foreign_key_checks_running > 0, we do not allow the
2731  TRUNCATE. We also reserve the data dictionary latch.
2732 
2733  6) Crash recovery: To prevent the application of pre-truncation
2734  redo log records on the truncated tablespace, we will assign
2735  a new tablespace identifier to the truncated tablespace. */
2736 
2737  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
2738  ut_ad(table);
2739 
2740  if (srv_created_new_raw) {
2741  fputs("InnoDB: A new raw disk partition was initialized:\n"
2742  "InnoDB: we do not allow database modifications"
2743  " by the user.\n"
2744  "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
2745  " is replaced with raw.\n", stderr);
2746 
2747  return(DB_ERROR);
2748  }
2749 
2750  trx->op_info = "truncating table";
2751 
2753 
2754  /* Serialize data dictionary operations with dictionary mutex:
2755  no deadlocks can occur then in these operations */
2756 
2757  ut_a(trx->dict_operation_lock_mode == 0);
2758  /* Prevent foreign key checks etc. while we are truncating the
2759  table */
2760 
2761  row_mysql_lock_data_dictionary(trx);
2762 
2763  ut_ad(mutex_own(&(dict_sys->mutex)));
2764 #ifdef UNIV_SYNC_DEBUG
2765  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
2766 #endif /* UNIV_SYNC_DEBUG */
2767 
2768  /* Check if the table is referenced by foreign key constraints from
2769  some other table (not the table itself) */
2770 
2771  foreign = UT_LIST_GET_FIRST(table->referenced_list);
2772 
2773  while (foreign && foreign->foreign_table == table) {
2774  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
2775  }
2776 
2777  if (foreign && trx->check_foreigns) {
2778  FILE* ef = dict_foreign_err_file;
2779 
2780  /* We only allow truncating a referenced table if
2781  FOREIGN_KEY_CHECKS is set to 0 */
2782 
2783  mutex_enter(&dict_foreign_err_mutex);
2784  rewind(ef);
2785  ut_print_timestamp(ef);
2786 
2787  fputs(" Cannot truncate table ", ef);
2788  ut_print_name(ef, trx, TRUE, table->name);
2789  fputs(" by DROP+CREATE\n"
2790  "InnoDB: because it is referenced by ", ef);
2791  ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
2792  putc('\n', ef);
2793  mutex_exit(&dict_foreign_err_mutex);
2794 
2795  err = DB_ERROR;
2796  goto funct_exit;
2797  }
2798 
2799  /* TODO: could we replace the counter n_foreign_key_checks_running
2800  with lock checks on the table? Acquire here an exclusive lock on the
2801  table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
2802  they can cope with the table having been truncated here? Foreign key
2803  checks take an IS or IX lock on the table. */
2804 
2805  if (table->n_foreign_key_checks_running > 0) {
2806  ut_print_timestamp(stderr);
2807  fputs(" InnoDB: Cannot truncate table ", stderr);
2808  ut_print_name(stderr, trx, TRUE, table->name);
2809  fputs(" by DROP+CREATE\n"
2810  "InnoDB: because there is a foreign key check"
2811  " running on it.\n",
2812  stderr);
2813  err = DB_ERROR;
2814 
2815  goto funct_exit;
2816  }
2817 
2818  /* Remove all locks except the table-level S and X locks. */
2819  lock_remove_all_on_table(table, FALSE);
2820 
2821  trx->table_id = table->id;
2822 
2823  if (table->space && !table->dir_path_of_temp_table) {
2824  /* Discard and create the single-table tablespace. */
2825  ulint space = table->space;
2826  ulint flags = fil_space_get_flags(space);
2827 
2828  if (flags != ULINT_UNDEFINED
2829  && fil_discard_tablespace(space)) {
2830 
2831  dict_index_t* index;
2832 
2833  dict_hdr_get_new_id(NULL, NULL, &space);
2834 
2835  /* Lock all index trees for this table. We must
2836  do so after dict_hdr_get_new_id() to preserve
2837  the latch order */
2839 
2840  if (space == ULINT_UNDEFINED
2842  space, table->name, FALSE, flags,
2843  FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) {
2845  ut_print_timestamp(stderr);
2846  fprintf(stderr,
2847  " InnoDB: TRUNCATE TABLE %s failed to"
2848  " create a new tablespace\n",
2849  table->name);
2850  table->ibd_file_missing = 1;
2851  err = DB_ERROR;
2852  goto funct_exit;
2853  }
2854 
2855  recreate_space = space;
2856 
2857  /* Replace the space_id in the data dictionary cache.
2858  The persisent data dictionary (SYS_TABLES.SPACE
2859  and SYS_INDEXES.SPACE) are updated later in this
2860  function. */
2861  table->space = space;
2862  index = dict_table_get_first_index(table);
2863  do {
2864  index->space = space;
2865  index = dict_table_get_next_index(index);
2866  } while (index);
2867 
2868  mtr_start(&mtr);
2869  fsp_header_init(space,
2871  mtr_commit(&mtr);
2872  }
2873  } else {
2874  /* Lock all index trees for this table, as we will
2875  truncate the table/index and possibly change their metadata.
2876  All DML/DDL are blocked by table level lock, with
2877  a few exceptions such as queries into information schema
2878  about the table, MySQL could try to access index stats
2879  for this kind of query, we need to use index locks to
2880  sync up */
2882  }
2883 
2884  /* scan SYS_INDEXES for all indexes of the table */
2885  heap = mem_heap_create(800);
2886 
2887  tuple = dtuple_create(heap, 1);
2888  dfield = dtuple_get_nth_field(tuple, 0);
2889 
2890  buf = static_cast<byte *>(mem_heap_alloc(heap, 8));
2891  mach_write_to_8(buf, table->id);
2892 
2893  dfield_set_data(dfield, buf, 8);
2894  sys_index = dict_table_get_first_index(dict_sys->sys_indexes);
2895  dict_index_copy_types(tuple, sys_index, 1);
2896 
2897  mtr_start(&mtr);
2898  btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
2899  BTR_MODIFY_LEAF, &pcur, &mtr);
2900  for (;;) {
2901  rec_t* rec;
2902  const byte* field;
2903  ulint len;
2904  ulint root_page_no;
2905 
2906  if (!btr_pcur_is_on_user_rec(&pcur)) {
2907  /* The end of SYS_INDEXES has been reached. */
2908  break;
2909  }
2910 
2911  rec = btr_pcur_get_rec(&pcur);
2912 
2913  field = rec_get_nth_field_old(rec, 0, &len);
2914  ut_ad(len == 8);
2915 
2916  if (memcmp(buf, field, len) != 0) {
2917  /* End of indexes for the table (TABLE_ID mismatch). */
2918  break;
2919  }
2920 
2921  if (rec_get_deleted_flag(rec, FALSE)) {
2922  /* The index has been dropped. */
2923  goto next_rec;
2924  }
2925 
2926  /* This call may commit and restart mtr
2927  and reposition pcur. */
2928  root_page_no = dict_truncate_index_tree(table, recreate_space,
2929  &pcur, &mtr);
2930 
2931  rec = btr_pcur_get_rec(&pcur);
2932 
2933  if (root_page_no != FIL_NULL) {
2935  rec, DICT_SYS_INDEXES_PAGE_NO_FIELD,
2936  root_page_no, &mtr);
2937  /* We will need to commit and restart the
2938  mini-transaction in order to avoid deadlocks.
2939  The dict_truncate_index_tree() call has allocated
2940  a page in this mini-transaction, and the rest of
2941  this loop could latch another index page. */
2942  mtr_commit(&mtr);
2943  mtr_start(&mtr);
2944  btr_pcur_restore_position(BTR_MODIFY_LEAF,
2945  &pcur, &mtr);
2946  }
2947 
2948 next_rec:
2949  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
2950  }
2951 
2952  btr_pcur_close(&pcur);
2953  mtr_commit(&mtr);
2954 
2955  mem_heap_free(heap);
2956 
2957  /* Done with index truncation, release index tree locks,
2958  subsequent work relates to table level metadata change */
2960 
2961  dict_hdr_get_new_id(&new_id, NULL, NULL);
2962 
2963  info = pars_info_create();
2964 
2965  pars_info_add_int4_literal(info, "space", (lint) table->space);
2966  pars_info_add_ull_literal(info, "old_id", table->id);
2967  pars_info_add_ull_literal(info, "new_id", new_id);
2968 
2969  err = que_eval_sql(info,
2970  "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n"
2971  "BEGIN\n"
2972  "UPDATE SYS_TABLES"
2973  " SET ID = :new_id, SPACE = :space\n"
2974  " WHERE ID = :old_id;\n"
2975  "UPDATE SYS_COLUMNS SET TABLE_ID = :new_id\n"
2976  " WHERE TABLE_ID = :old_id;\n"
2977  "UPDATE SYS_INDEXES"
2978  " SET TABLE_ID = :new_id, SPACE = :space\n"
2979  " WHERE TABLE_ID = :old_id;\n"
2980  "COMMIT WORK;\n"
2981  "END;\n"
2982  , FALSE, trx);
2983 
2984  if (err != DB_SUCCESS) {
2985  trx->error_state = DB_SUCCESS;
2986  trx_general_rollback_for_mysql(trx, NULL);
2987  trx->error_state = DB_SUCCESS;
2988  ut_print_timestamp(stderr);
2989  fputs(" InnoDB: Unable to assign a new identifier to table ",
2990  stderr);
2991  ut_print_name(stderr, trx, TRUE, table->name);
2992  fputs("\n"
2993  "InnoDB: after truncating it. Background processes"
2994  " may corrupt the table!\n", stderr);
2995  err = DB_ERROR;
2996  } else {
2997  dict_table_change_id_in_cache(table, new_id);
2998  }
2999 
3000  /*
3001  MySQL calls ha_innobase::reset_auto_increment() which does
3002  the same thing.
3003  */
3004  dict_table_autoinc_lock(table);
3007  dict_update_statistics(table, FALSE /* update even if stats are
3008  initialized */);
3009 
3010  trx_commit_for_mysql(trx);
3011 
3012 funct_exit:
3013 
3015 
3016  trx->op_info = "";
3017 
3019 
3020  return((int) err);
3021 }
3022 
3023 /*********************************************************************/
3031 UNIV_INTERN
3032 int
3034 /*=====================*/
3035  const char* name,
3036  trx_t* trx,
3037  ibool drop_db)
3038 {
3039  dict_foreign_t* foreign;
3040  dict_table_t* table;
3041  ulint space_id;
3042  ulint err;
3043  const char* table_name;
3044  ulint namelen;
3045  ibool locked_dictionary = FALSE;
3046  pars_info_t* info = NULL;
3047 
3048  ut_a(name != NULL);
3049 
3050  if (srv_created_new_raw) {
3051  fputs("InnoDB: A new raw disk partition was initialized:\n"
3052  "InnoDB: we do not allow database modifications"
3053  " by the user.\n"
3054  "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
3055  " is replaced with raw.\n", stderr);
3056 
3057  return(DB_ERROR);
3058  }
3059 
3060  trx->op_info = "dropping table";
3061 
3063 
3064  /* The table name is prefixed with the database name and a '/'.
3065  Certain table names starting with 'innodb_' have their special
3066  meaning regardless of the database name. Thus, we need to
3067  ignore the database name prefix in the comparisons. */
3068  table_name = strchr(name, '/');
3069  ut_a(table_name);
3070  table_name++;
3071  namelen = strlen(table_name) + 1;
3072 
3073  if (namelen == sizeof S_innodb_monitor
3074  && !memcmp(table_name, S_innodb_monitor,
3075  sizeof S_innodb_monitor)) {
3076 
3077  /* Table name equals "innodb_monitor":
3078  stop monitor prints */
3079 
3080  srv_print_innodb_monitor = FALSE;
3081  srv_print_innodb_lock_monitor = FALSE;
3082  } else if (namelen == sizeof S_innodb_lock_monitor
3083  && !memcmp(table_name, S_innodb_lock_monitor,
3084  sizeof S_innodb_lock_monitor)) {
3085  srv_print_innodb_monitor = FALSE;
3086  srv_print_innodb_lock_monitor = FALSE;
3087  } else if (namelen == sizeof S_innodb_tablespace_monitor
3088  && !memcmp(table_name, S_innodb_tablespace_monitor,
3089  sizeof S_innodb_tablespace_monitor)) {
3090 
3091  srv_print_innodb_tablespace_monitor = FALSE;
3092  } else if (namelen == sizeof S_innodb_table_monitor
3093  && !memcmp(table_name, S_innodb_table_monitor,
3094  sizeof S_innodb_table_monitor)) {
3095 
3096  srv_print_innodb_table_monitor = FALSE;
3097  }
3098 
3099  /* Serialize data dictionary operations with dictionary mutex:
3100  no deadlocks can occur then in these operations */
3101 
3102  if (trx->dict_operation_lock_mode != RW_X_LATCH) {
3103  /* Prevent foreign key checks etc. while we are dropping the
3104  table */
3105 
3106  row_mysql_lock_data_dictionary(trx);
3107 
3108  locked_dictionary = TRUE;
3109  }
3110 
3111  ut_ad(mutex_own(&(dict_sys->mutex)));
3112 #ifdef UNIV_SYNC_DEBUG
3113  ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
3114 #endif /* UNIV_SYNC_DEBUG */
3115 
3117 
3118  if (!table) {
3119 #if defined(BUILD_DRIZZLE)
3120  err = ENOENT;
3121 #else
3122  err = DB_TABLE_NOT_FOUND;
3123  ut_print_timestamp(stderr);
3124 
3125  fputs(" InnoDB: Error: table ", stderr);
3126  ut_print_name(stderr, trx, TRUE, name);
3127  fputs(" does not exist in the InnoDB internal\n"
3128  "InnoDB: data dictionary though MySQL is"
3129  " trying to drop it.\n"
3130  "InnoDB: Have you copied the .frm file"
3131  " of the table to the\n"
3132  "InnoDB: MySQL database directory"
3133  " from another database?\n"
3134  "InnoDB: You can look for further help from\n"
3135  "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3136  stderr);
3137 #endif /* BUILD_DRIZZLE */
3138  goto funct_exit;
3139  }
3140 
3141  /* Check if the table is referenced by foreign key constraints from
3142  some other table (not the table itself) */
3143 
3144  foreign = UT_LIST_GET_FIRST(table->referenced_list);
3145 
3146  while (foreign && foreign->foreign_table == table) {
3147 check_next_foreign:
3148  foreign = UT_LIST_GET_NEXT(referenced_list, foreign);
3149  }
3150 
3151  if (foreign && trx->check_foreigns
3152  && !(drop_db && dict_tables_have_same_db(
3153  name, foreign->foreign_table_name_lookup))) {
3154  FILE* ef = dict_foreign_err_file;
3155 
3156  /* We only allow dropping a referenced table if
3157  FOREIGN_KEY_CHECKS is set to 0 */
3158 
3159  err = DB_CANNOT_DROP_CONSTRAINT;
3160 
3161  mutex_enter(&dict_foreign_err_mutex);
3162  rewind(ef);
3163  ut_print_timestamp(ef);
3164 
3165  fputs(" Cannot drop table ", ef);
3166  ut_print_name(ef, trx, TRUE, name);
3167  fputs("\n"
3168  "because it is referenced by ", ef);
3169  ut_print_name(ef, trx, TRUE, foreign->foreign_table_name);
3170  putc('\n', ef);
3171  mutex_exit(&dict_foreign_err_mutex);
3172 
3173  goto funct_exit;
3174  }
3175 
3176  if (foreign && trx->check_foreigns) {
3177  goto check_next_foreign;
3178  }
3179 
3180  if (table->n_mysql_handles_opened > 0) {
3181  ibool added;
3182 
3183  added = row_add_table_to_background_drop_list(table->name);
3184 
3185  if (added) {
3186  ut_print_timestamp(stderr);
3187  fputs(" InnoDB: Warning: MySQL is"
3188  " trying to drop table ", stderr);
3189  ut_print_name(stderr, trx, TRUE, table->name);
3190  fputs("\n"
3191  "InnoDB: though there are still"
3192  " open handles to it.\n"
3193  "InnoDB: Adding the table to the"
3194  " background drop queue.\n",
3195  stderr);
3196 
3197  /* We return DB_SUCCESS to MySQL though the drop will
3198  happen lazily later */
3199  err = DB_SUCCESS;
3200  } else {
3201  /* The table is already in the background drop list */
3202  err = DB_ERROR;
3203  }
3204 
3205  goto funct_exit;
3206  }
3207 
3208  /* TODO: could we replace the counter n_foreign_key_checks_running
3209  with lock checks on the table? Acquire here an exclusive lock on the
3210  table, and rewrite lock0lock.c and the lock wait in srv0srv.c so that
3211  they can cope with the table having been dropped here? Foreign key
3212  checks take an IS or IX lock on the table. */
3213 
3214  if (table->n_foreign_key_checks_running > 0) {
3215 
3216  const char* i_table_name = table->name;
3217  ibool added;
3218 
3219  added = row_add_table_to_background_drop_list(i_table_name);
3220 
3221  if (added) {
3222  ut_print_timestamp(stderr);
3223  fputs(" InnoDB: You are trying to drop table ",
3224  stderr);
3225  ut_print_name(stderr, trx, TRUE, i_table_name);
3226  fputs("\n"
3227  "InnoDB: though there is a"
3228  " foreign key check running on it.\n"
3229  "InnoDB: Adding the table to"
3230  " the background drop queue.\n",
3231  stderr);
3232 
3233  /* We return DB_SUCCESS to MySQL though the drop will
3234  happen lazily later */
3235 
3236  err = DB_SUCCESS;
3237  } else {
3238  /* The table is already in the background drop list */
3239  err = DB_ERROR;
3240  }
3241 
3242  goto funct_exit;
3243  }
3244 
3245  /* Remove all locks there are on the table or its records */
3246  lock_remove_all_on_table(table, TRUE);
3247 
3249  trx->table_id = table->id;
3250 
3251  /* We use the private SQL parser of Innobase to generate the
3252  query graphs needed in deleting the dictionary data from system
3253  tables in Innobase. Deleting a row from SYS_INDEXES table also
3254  frees the file segments of the B-tree associated with the index. */
3255 
3256  info = pars_info_create();
3257 
3258  pars_info_add_str_literal(info, "table_name", name);
3259 
3260  err = que_eval_sql(info,
3261  "PROCEDURE DROP_TABLE_PROC () IS\n"
3262  "sys_foreign_id CHAR;\n"
3263  "table_id CHAR;\n"
3264  "index_id CHAR;\n"
3265  "foreign_id CHAR;\n"
3266  "found INT;\n"
3267  "BEGIN\n"
3268  "SELECT ID INTO table_id\n"
3269  "FROM SYS_TABLES\n"
3270  "WHERE NAME = :table_name\n"
3271  "LOCK IN SHARE MODE;\n"
3272  "IF (SQL % NOTFOUND) THEN\n"
3273  " RETURN;\n"
3274  "END IF;\n"
3275  "found := 1;\n"
3276  "SELECT ID INTO sys_foreign_id\n"
3277  "FROM SYS_TABLES\n"
3278  "WHERE NAME = 'SYS_FOREIGN'\n"
3279  "LOCK IN SHARE MODE;\n"
3280  "IF (SQL % NOTFOUND) THEN\n"
3281  " found := 0;\n"
3282  "END IF;\n"
3283  "IF (:table_name = 'SYS_FOREIGN') THEN\n"
3284  " found := 0;\n"
3285  "END IF;\n"
3286  "IF (:table_name = 'SYS_FOREIGN_COLS') THEN\n"
3287  " found := 0;\n"
3288  "END IF;\n"
3289  "WHILE found = 1 LOOP\n"
3290  " SELECT ID INTO foreign_id\n"
3291  " FROM SYS_FOREIGN\n"
3292  " WHERE FOR_NAME = :table_name\n"
3293  " AND TO_BINARY(FOR_NAME)\n"
3294  " = TO_BINARY(:table_name)\n"
3295  " LOCK IN SHARE MODE;\n"
3296  " IF (SQL % NOTFOUND) THEN\n"
3297  " found := 0;\n"
3298  " ELSE\n"
3299  " DELETE FROM SYS_FOREIGN_COLS\n"
3300  " WHERE ID = foreign_id;\n"
3301  " DELETE FROM SYS_FOREIGN\n"
3302  " WHERE ID = foreign_id;\n"
3303  " END IF;\n"
3304  "END LOOP;\n"
3305  "found := 1;\n"
3306  "WHILE found = 1 LOOP\n"
3307  " SELECT ID INTO index_id\n"
3308  " FROM SYS_INDEXES\n"
3309  " WHERE TABLE_ID = table_id\n"
3310  " LOCK IN SHARE MODE;\n"
3311  " IF (SQL % NOTFOUND) THEN\n"
3312  " found := 0;\n"
3313  " ELSE\n"
3314  " DELETE FROM SYS_FIELDS\n"
3315  " WHERE INDEX_ID = index_id;\n"
3316  " DELETE FROM SYS_INDEXES\n"
3317  " WHERE ID = index_id\n"
3318  " AND TABLE_ID = table_id;\n"
3319  " END IF;\n"
3320  "END LOOP;\n"
3321  "DELETE FROM SYS_COLUMNS\n"
3322  "WHERE TABLE_ID = table_id;\n"
3323  "DELETE FROM SYS_TABLES\n"
3324  "WHERE ID = table_id;\n"
3325  "END;\n"
3326  , FALSE, trx);
3327 
3328  switch (err) {
3329  ibool is_temp;
3330  const char* name_or_path;
3331  mem_heap_t* heap;
3332 
3333  case DB_SUCCESS:
3334 
3335  heap = mem_heap_create(200);
3336 
3337  /* Clone the name, in case it has been allocated
3338  from table->heap, which will be freed by
3339  dict_table_remove_from_cache(table) below. */
3340  name = mem_heap_strdup(heap, name);
3341  space_id = table->space;
3342 
3343  if (table->dir_path_of_temp_table != NULL) {
3344  name_or_path = mem_heap_strdup(
3345  heap, table->dir_path_of_temp_table);
3346  is_temp = TRUE;
3347  } else {
3348  name_or_path = name;
3349  is_temp = (table->flags >> DICT_TF2_SHIFT)
3351  }
3352 
3354 
3355  if (dict_load_table(name, TRUE, DICT_ERR_IGNORE_NONE) != NULL) {
3356  ut_print_timestamp(stderr);
3357  fputs(" InnoDB: Error: not able to remove table ",
3358  stderr);
3359  ut_print_name(stderr, trx, TRUE, name);
3360  fputs(" from the dictionary cache!\n", stderr);
3361  err = DB_ERROR;
3362  }
3363 
3364  /* Do not drop possible .ibd tablespace if something went
3365  wrong: we do not want to delete valuable data of the user */
3366 
3367  if (err == DB_SUCCESS && space_id > 0) {
3368  if (!fil_space_for_table_exists_in_mem(space_id,
3369  name_or_path,
3370  is_temp, FALSE,
3371  !is_temp)) {
3372  err = DB_SUCCESS;
3373 
3374  fprintf(stderr,
3375  "InnoDB: We removed now the InnoDB"
3376  " internal data dictionary entry\n"
3377  "InnoDB: of table ");
3378  ut_print_name(stderr, trx, TRUE, name);
3379  fprintf(stderr, ".\n");
3380  } else if (!fil_delete_tablespace(space_id)) {
3381  fprintf(stderr,
3382  "InnoDB: We removed now the InnoDB"
3383  " internal data dictionary entry\n"
3384  "InnoDB: of table ");
3385  ut_print_name(stderr, trx, TRUE, name);
3386  fprintf(stderr, ".\n");
3387 
3388  ut_print_timestamp(stderr);
3389  fprintf(stderr,
3390  " InnoDB: Error: not able to"
3391  " delete tablespace %lu of table ",
3392  (ulong) space_id);
3393  ut_print_name(stderr, trx, TRUE, name);
3394  fputs("!\n", stderr);
3395  err = DB_ERROR;
3396  }
3397  }
3398 
3399  mem_heap_free(heap);
3400  break;
3401 
3402  case DB_TOO_MANY_CONCURRENT_TRXS:
3403  /* Cannot even find a free slot for the
3404  the undo log. We can directly exit here
3405  and return the DB_TOO_MANY_CONCURRENT_TRXS
3406  error. */
3407  break;
3408 
3409  case DB_OUT_OF_FILE_SPACE:
3410  err = DB_MUST_GET_MORE_FILE_SPACE;
3411 
3412  row_mysql_handle_errors(&err, trx, NULL, NULL);
3413 
3414  /* Fall through to raise error */
3415 
3416  default:
3417  /* No other possible error returns */
3418  ut_error;
3419  }
3420 
3421 funct_exit:
3422 
3423  if (locked_dictionary) {
3424  trx_commit_for_mysql(trx);
3425 
3427  }
3428 
3429  trx->op_info = "";
3430 
3432 
3433  return((int) err);
3434 }
3435 
3436 /*********************************************************************/
3438 UNIV_INTERN
3439 void
3441 /*============================*/
3442 {
3443  trx_t* trx;
3444  btr_pcur_t pcur;
3445  mtr_t mtr;
3446  mem_heap_t* heap;
3447 
3449  trx->op_info = "dropping temporary tables";
3450  row_mysql_lock_data_dictionary(trx);
3451 
3452  heap = mem_heap_create(200);
3453 
3454  mtr_start(&mtr);
3455 
3457  TRUE,
3458  dict_table_get_first_index(dict_sys->sys_tables),
3459  BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
3460 
3461  for (;;) {
3462  const rec_t* rec;
3463  const byte* field;
3464  ulint len;
3465  const char* table_name;
3466  dict_table_t* table;
3467 
3468  btr_pcur_move_to_next_user_rec(&pcur, &mtr);
3469 
3470  if (!btr_pcur_is_on_user_rec(&pcur)) {
3471  break;
3472  }
3473 
3474  rec = btr_pcur_get_rec(&pcur);
3475  field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len);
3476  if (len != 4 || !(mach_read_from_4(field) & 0x80000000UL)) {
3477  continue;
3478  }
3479 
3480  /* Because this is not a ROW_FORMAT=REDUNDANT table,
3481  the is_temp flag is valid. Examine it. */
3482 
3483  field = rec_get_nth_field_old(rec, 7/*MIX_LEN*/, &len);
3484  if (len != 4
3485  || !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) {
3486  continue;
3487  }
3488 
3489  /* This is a temporary table. */
3490  field = rec_get_nth_field_old(rec, 0/*NAME*/, &len);
3491  if (len == UNIV_SQL_NULL || len == 0) {
3492  /* Corrupted SYS_TABLES.NAME */
3493  continue;
3494  }
3495 
3496  table_name = mem_heap_strdupl(heap, (const char*) field, len);
3497 
3498  btr_pcur_store_position(&pcur, &mtr);
3499  btr_pcur_commit_specify_mtr(&pcur, &mtr);
3500 
3501  table = dict_load_table(table_name, TRUE, DICT_ERR_IGNORE_NONE);
3502 
3503  if (table) {
3504  row_drop_table_for_mysql(table_name, trx, FALSE);
3505  trx_commit_for_mysql(trx);
3506  }
3507 
3508  mtr_start(&mtr);
3509  btr_pcur_restore_position(BTR_SEARCH_LEAF,
3510  &pcur, &mtr);
3511  }
3512 
3513  btr_pcur_close(&pcur);
3514  mtr_commit(&mtr);
3515  mem_heap_free(heap);
3518 }
3519 
3520 /*******************************************************************/
3524 static
3525 ulint
3526 drop_all_foreign_keys_in_db(
3527 /*========================*/
3528  const char* name,
3529  trx_t* trx)
3530 {
3531  pars_info_t* pinfo;
3532  ulint err;
3533 
3534  ut_a(name[strlen(name) - 1] == '/');
3535 
3536  pinfo = pars_info_create();
3537 
3538  pars_info_add_str_literal(pinfo, "dbname", name);
3539 
3541 #define TABLE_NOT_IN_THIS_DB \
3542 "SUBSTR(for_name, 0, LENGTH(:dbname)) <> :dbname"
3543 
3544  err = que_eval_sql(pinfo,
3545  "PROCEDURE DROP_ALL_FOREIGN_KEYS_PROC () IS\n"
3546  "foreign_id CHAR;\n"
3547  "for_name CHAR;\n"
3548  "found INT;\n"
3549  "DECLARE CURSOR cur IS\n"
3550  "SELECT ID, FOR_NAME FROM SYS_FOREIGN\n"
3551  "WHERE FOR_NAME >= :dbname\n"
3552  "LOCK IN SHARE MODE\n"
3553  "ORDER BY FOR_NAME;\n"
3554  "BEGIN\n"
3555  "found := 1;\n"
3556  "OPEN cur;\n"
3557  "WHILE found = 1 LOOP\n"
3558  " FETCH cur INTO foreign_id, for_name;\n"
3559  " IF (SQL % NOTFOUND) THEN\n"
3560  " found := 0;\n"
3561  " ELSIF (" TABLE_NOT_IN_THIS_DB ") THEN\n"
3562  " found := 0;\n"
3563  " ELSIF (1=1) THEN\n"
3564  " DELETE FROM SYS_FOREIGN_COLS\n"
3565  " WHERE ID = foreign_id;\n"
3566  " DELETE FROM SYS_FOREIGN\n"
3567  " WHERE ID = foreign_id;\n"
3568  " END IF;\n"
3569  "END LOOP;\n"
3570  "CLOSE cur;\n"
3571  "COMMIT WORK;\n"
3572  "END;\n",
3573  FALSE, /* do not reserve dict mutex,
3574  we are already holding it */
3575  trx);
3576 
3577  return(err);
3578 }
3579 
3580 /*********************************************************************/
3583 UNIV_INTERN
3584 int
3586 /*========================*/
3587  const char* name,
3588  trx_t* trx)
3589 {
3590  dict_table_t* table;
3591  char* table_name;
3592  int err = DB_SUCCESS;
3593  ulint namelen = strlen(name);
3594 
3595  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3596  ut_a(name != NULL);
3597  ut_a(name[namelen - 1] == '/');
3598 
3599  trx->op_info = "dropping database";
3600 
3602 loop:
3603  row_mysql_lock_data_dictionary(trx);
3604 
3605  while ((table_name = dict_get_first_table_name_in_db(name))) {
3606  ut_a(memcmp(table_name, name, namelen) == 0);
3607 
3608  // For the time being I would like to see how often we see
3609  // lost temporary tables. --Brian
3610  fprintf(stderr, "Dropping lost temporary table %s\n", table_name);
3611 
3612  table = dict_table_get_low(table_name);
3613 
3614  ut_a(table);
3615 
3616  /* Wait until MySQL does not have any queries running on
3617  the table */
3618 
3619  if (table->n_mysql_handles_opened > 0) {
3621 
3622  ut_print_timestamp(stderr);
3623  fputs(" InnoDB: Warning: MySQL is trying to"
3624  " drop database ", stderr);
3625  ut_print_name(stderr, trx, TRUE, name);
3626  fputs("\n"
3627  "InnoDB: though there are still"
3628  " open handles to table ", stderr);
3629  ut_print_name(stderr, trx, TRUE, table_name);
3630  fputs(".\n", stderr);
3631 
3632  os_thread_sleep(1000000);
3633 
3634  mem_free(table_name);
3635 
3636  goto loop;
3637  }
3638 
3639  err = row_drop_table_for_mysql(table_name, trx, TRUE);
3640  trx_commit_for_mysql(trx);
3641 
3642  if (err != DB_SUCCESS) {
3643  fputs("InnoDB: DROP DATABASE ", stderr);
3644  ut_print_name(stderr, trx, TRUE, name);
3645  fprintf(stderr, " failed with error %lu for table ",
3646  (ulint) err);
3647  ut_print_name(stderr, trx, TRUE, table_name);
3648  putc('\n', stderr);
3649  mem_free(table_name);
3650  break;
3651  }
3652 
3653  mem_free(table_name);
3654  }
3655 
3656  if (err == DB_SUCCESS) {
3657  /* after dropping all tables try to drop all leftover
3658  foreign keys in case orphaned ones exist */
3659  err = (int) drop_all_foreign_keys_in_db(name, trx);
3660 
3661  if (err != DB_SUCCESS) {
3662  fputs("InnoDB: DROP DATABASE ", stderr);
3663  ut_print_name(stderr, trx, TRUE, name);
3664  fprintf(stderr, " failed with error %d while "
3665  "dropping all foreign keys", err);
3666  }
3667  }
3668 
3669  trx_commit_for_mysql(trx);
3670 
3672 
3673  trx->op_info = "";
3674 
3675  return(err);
3676 }
3677 
3678 /*********************************************************************/
3682 static
3683 ibool
3684 row_is_mysql_tmp_table_name(
3685 /*========================*/
3686  const char* name)
3688 {
3689  return(strstr(name, "/#sql") != NULL);
3690  /* return(strstr(name, "/@0023sql") != NULL); */
3691 }
3692 
3693 /****************************************************************/
3696 static
3697 int
3698 row_delete_constraint_low(
3699 /*======================*/
3700  const char* id,
3701  trx_t* trx)
3702 {
3703  pars_info_t* info = pars_info_create();
3704 
3705  pars_info_add_str_literal(info, "id", id);
3706 
3707  return((int) que_eval_sql(info,
3708  "PROCEDURE DELETE_CONSTRAINT () IS\n"
3709  "BEGIN\n"
3710  "DELETE FROM SYS_FOREIGN_COLS WHERE ID = :id;\n"
3711  "DELETE FROM SYS_FOREIGN WHERE ID = :id;\n"
3712  "END;\n"
3713  , FALSE, trx));
3714 }
3715 
3716 /****************************************************************/
3719 static
3720 int
3721 row_delete_constraint(
3722 /*==================*/
3723  const char* id,
3724  const char* database_name,
3726  mem_heap_t* heap,
3727  trx_t* trx)
3728 {
3729  ulint err;
3730 
3731  /* New format constraints have ids <databasename>/<constraintname>. */
3732  err = row_delete_constraint_low(
3733  mem_heap_strcat(heap, database_name, id), trx);
3734 
3735  if ((err == DB_SUCCESS) && !strchr(id, '/')) {
3736  /* Old format < 4.0.18 constraints have constraint ids
3737  <number>_<number>. We only try deleting them if the
3738  constraint name does not contain a '/' character, otherwise
3739  deleting a new format constraint named 'foo/bar' from
3740  database 'baz' would remove constraint 'bar' from database
3741  'foo', if it existed. */
3742 
3743  err = row_delete_constraint_low(id, trx);
3744  }
3745 
3746  return((int) err);
3747 }
3748 
3749 /*********************************************************************/
3752 UNIV_INTERN
3753 ulint
3755 /*=======================*/
3756  const char* old_name,
3757  const char* new_name,
3758  trx_t* trx,
3759  ibool commit)
3760 {
3761  dict_table_t* table;
3762  ulint err = DB_ERROR;
3763  mem_heap_t* heap = NULL;
3764  const char** constraints_to_drop = NULL;
3765  ulint n_constraints_to_drop = 0;
3766  ibool old_is_tmp, new_is_tmp;
3767  pars_info_t* info = NULL;
3768 
3769  ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
3770  ut_a(old_name != NULL);
3771  ut_a(new_name != NULL);
3772 
3773  if (srv_created_new_raw || srv_force_recovery) {
3774  fputs("InnoDB: A new raw disk partition was initialized or\n"
3775  "InnoDB: innodb_force_recovery is on: we do not allow\n"
3776  "InnoDB: database modifications by the user. Shut down\n"
3777  "InnoDB: mysqld and edit my.cnf so that newraw"
3778  " is replaced\n"
3779  "InnoDB: with raw, and innodb_force_... is removed.\n",
3780  stderr);
3781 
3782  goto funct_exit;
3783  }
3784 
3785  trx->op_info = "renaming table";
3787 
3788  old_is_tmp = row_is_mysql_tmp_table_name(old_name);
3789  new_is_tmp = row_is_mysql_tmp_table_name(new_name);
3790 
3791  table = dict_table_get_low(old_name);
3792 
3793  if (!table) {
3794 #if defined(BUILD_DRIZZLE)
3795  err = ENOENT;
3796 #else
3797  err = DB_TABLE_NOT_FOUND;
3798  ut_print_timestamp(stderr);
3799 
3800  fputs(" InnoDB: Error: table ", stderr);
3801  ut_print_name(stderr, trx, TRUE, old_name);
3802  fputs(" does not exist in the InnoDB internal\n"
3803  "InnoDB: data dictionary though MySQL is"
3804  " trying to rename the table.\n"
3805  "InnoDB: Have you copied the .frm file"
3806  " of the table to the\n"
3807  "InnoDB: MySQL database directory"
3808  " from another database?\n"
3809  "InnoDB: You can look for further help from\n"
3810  "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3811  stderr);
3812 #endif /* BUILD_DRIZZLE */
3813  goto funct_exit;
3814  } else if (table->ibd_file_missing) {
3815  err = DB_TABLE_NOT_FOUND;
3816  ut_print_timestamp(stderr);
3817 
3818  fputs(" InnoDB: Error: table ", stderr);
3819  ut_print_name(stderr, trx, TRUE, old_name);
3820  fputs(" does not have an .ibd file"
3821  " in the database directory.\n"
3822  "InnoDB: You can look for further help from\n"
3823  "InnoDB: " REFMAN "innodb-troubleshooting.html\n",
3824  stderr);
3825  goto funct_exit;
3826  } else if (new_is_tmp) {
3827  /* MySQL is doing an ALTER TABLE command and it renames the
3828  original table to a temporary table name. We want to preserve
3829  the original foreign key constraint definitions despite the
3830  name change. An exception is those constraints for which
3831  the ALTER TABLE contained DROP FOREIGN KEY <foreign key id>.*/
3832 
3833  heap = mem_heap_create(100);
3834 
3836  heap, trx, table, &n_constraints_to_drop,
3837  &constraints_to_drop);
3838 
3839  if (err != DB_SUCCESS) {
3840 
3841  goto funct_exit;
3842  }
3843  }
3844 
3845  /* We use the private SQL parser of Innobase to generate the query
3846  graphs needed in updating the dictionary data from system tables. */
3847 
3848  info = pars_info_create();
3849 
3850  pars_info_add_str_literal(info, "new_table_name", new_name);
3851  pars_info_add_str_literal(info, "old_table_name", old_name);
3852 
3853  err = que_eval_sql(info,
3854  "PROCEDURE RENAME_TABLE () IS\n"
3855  "BEGIN\n"
3856  "UPDATE SYS_TABLES SET NAME = :new_table_name\n"
3857  " WHERE NAME = :old_table_name;\n"
3858  "END;\n"
3859  , FALSE, trx);
3860 
3861  if (err != DB_SUCCESS) {
3862 
3863  goto end;
3864  } else if (!new_is_tmp) {
3865  /* Rename all constraints. */
3866 
3867  info = pars_info_create();
3868 
3869  pars_info_add_str_literal(info, "new_table_name", new_name);
3870  pars_info_add_str_literal(info, "old_table_name", old_name);
3871 
3872  err = que_eval_sql(
3873  info,
3874  "PROCEDURE RENAME_CONSTRAINT_IDS () IS\n"
3875  "gen_constr_prefix CHAR;\n"
3876  "new_db_name CHAR;\n"
3877  "foreign_id CHAR;\n"
3878  "new_foreign_id CHAR;\n"
3879  "old_db_name_len INT;\n"
3880  "old_t_name_len INT;\n"
3881  "new_db_name_len INT;\n"
3882  "id_len INT;\n"
3883  "found INT;\n"
3884  "BEGIN\n"
3885  "found := 1;\n"
3886  "old_db_name_len := INSTR(:old_table_name, '/')-1;\n"
3887  "new_db_name_len := INSTR(:new_table_name, '/')-1;\n"
3888  "new_db_name := SUBSTR(:new_table_name, 0,\n"
3889  " new_db_name_len);\n"
3890  "old_t_name_len := LENGTH(:old_table_name);\n"
3891  "gen_constr_prefix := CONCAT(:old_table_name,\n"
3892  " '_ibfk_');\n"
3893  "WHILE found = 1 LOOP\n"
3894  " SELECT ID INTO foreign_id\n"
3895  " FROM SYS_FOREIGN\n"
3896  " WHERE FOR_NAME = :old_table_name\n"
3897  " AND TO_BINARY(FOR_NAME)\n"
3898  " = TO_BINARY(:old_table_name)\n"
3899  " LOCK IN SHARE MODE;\n"
3900  " IF (SQL % NOTFOUND) THEN\n"
3901  " found := 0;\n"
3902  " ELSE\n"
3903  " UPDATE SYS_FOREIGN\n"
3904  " SET FOR_NAME = :new_table_name\n"
3905  " WHERE ID = foreign_id;\n"
3906  " id_len := LENGTH(foreign_id);\n"
3907  " IF (INSTR(foreign_id, '/') > 0) THEN\n"
3908  " IF (INSTR(foreign_id,\n"
3909  " gen_constr_prefix) > 0)\n"
3910  " THEN\n"
3911  " new_foreign_id :=\n"
3912  " CONCAT(:new_table_name,\n"
3913  " SUBSTR(foreign_id, old_t_name_len,\n"
3914  " id_len - old_t_name_len));\n"
3915  " ELSE\n"
3916  " new_foreign_id :=\n"
3917  " CONCAT(new_db_name,\n"
3918  " SUBSTR(foreign_id,\n"
3919  " old_db_name_len,\n"
3920  " id_len - old_db_name_len));\n"
3921  " END IF;\n"
3922  " UPDATE SYS_FOREIGN\n"
3923  " SET ID = new_foreign_id\n"
3924  " WHERE ID = foreign_id;\n"
3925  " UPDATE SYS_FOREIGN_COLS\n"
3926  " SET ID = new_foreign_id\n"
3927  " WHERE ID = foreign_id;\n"
3928  " END IF;\n"
3929  " END IF;\n"
3930  "END LOOP;\n"
3931  "UPDATE SYS_FOREIGN SET REF_NAME = :new_table_name\n"
3932  "WHERE REF_NAME = :old_table_name\n"
3933  " AND TO_BINARY(REF_NAME)\n"
3934  " = TO_BINARY(:old_table_name);\n"
3935  "END;\n"
3936  , FALSE, trx);
3937 
3938  } else if (n_constraints_to_drop > 0) {
3939  /* Drop some constraints of tmp tables. */
3940 
3941  ulint db_name_len = dict_get_db_name_len(old_name) + 1;
3942  char* db_name = mem_heap_strdupl(heap, old_name,
3943  db_name_len);
3944  ulint i;
3945 
3946  for (i = 0; i < n_constraints_to_drop; i++) {
3947  err = row_delete_constraint(constraints_to_drop[i],
3948  db_name, heap, trx);
3949 
3950  if (err != DB_SUCCESS) {
3951  break;
3952  }
3953  }
3954  }
3955 
3956 end:
3957  if (err != DB_SUCCESS) {
3958  if (err == DB_DUPLICATE_KEY) {
3959  ut_print_timestamp(stderr);
3960  fputs(" InnoDB: Error; possible reasons:\n"
3961  "InnoDB: 1) Table rename would cause"
3962  " two FOREIGN KEY constraints\n"
3963  "InnoDB: to have the same internal name"
3964  " in case-insensitive comparison.\n"
3965  "InnoDB: 2) table ", stderr);
3966  ut_print_name(stderr, trx, TRUE, new_name);
3967  fputs(" exists in the InnoDB internal data\n"
3968  "InnoDB: dictionary though MySQL is"
3969  " trying to rename table ", stderr);
3970  ut_print_name(stderr, trx, TRUE, old_name);
3971  fputs(" to it.\n"
3972  "InnoDB: Have you deleted the .frm file"
3973  " and not used DROP TABLE?\n"
3974  "InnoDB: You can look for further help from\n"
3975  "InnoDB: " REFMAN "innodb-troubleshooting.html\n"
3976  "InnoDB: If table ", stderr);
3977  ut_print_name(stderr, trx, TRUE, new_name);
3978  fputs(" is a temporary table #sql..., then"
3979  " it can be that\n"
3980  "InnoDB: there are still queries running"
3981  " on the table, and it will be\n"
3982  "InnoDB: dropped automatically when"
3983  " the queries end.\n"
3984  "InnoDB: You can drop the orphaned table"
3985  " inside InnoDB by\n"
3986  "InnoDB: creating an InnoDB table with"
3987  " the same name in another\n"
3988  "InnoDB: database and copying the .frm file"
3989  " to the current database.\n"
3990  "InnoDB: Then MySQL thinks the table exists,"
3991  " and DROP TABLE will\n"
3992  "InnoDB: succeed.\n", stderr);
3993  }
3994  trx->error_state = DB_SUCCESS;
3995  trx_general_rollback_for_mysql(trx, NULL);
3996  trx->error_state = DB_SUCCESS;
3997  } else {
3998  /* The following call will also rename the .ibd data file if
3999  the table is stored in a single-table tablespace */
4000 
4001  if (!dict_table_rename_in_cache(table, new_name,
4002  !new_is_tmp)) {
4003  trx->error_state = DB_SUCCESS;
4004  trx_general_rollback_for_mysql(trx, NULL);
4005  trx->error_state = DB_SUCCESS;
4006  goto funct_exit;
4007  }
4008 
4009  /* We only want to switch off some of the type checking in
4010  an ALTER, not in a RENAME. */
4011 
4012  err = dict_load_foreigns(
4013  new_name, FALSE, !old_is_tmp || trx->check_foreigns);
4014 
4015  if (err != DB_SUCCESS) {
4016  ut_print_timestamp(stderr);
4017 
4018  if (old_is_tmp) {
4019  fputs(" InnoDB: Error: in ALTER TABLE ",
4020  stderr);
4021  ut_print_name(stderr, trx, TRUE, new_name);
4022  fputs("\n"
4023  "InnoDB: has or is referenced"
4024  " in foreign key constraints\n"
4025  "InnoDB: which are not compatible"
4026  " with the new table definition.\n",
4027  stderr);
4028  } else {
4029  fputs(" InnoDB: Error: in RENAME TABLE"
4030  " table ",
4031  stderr);
4032  ut_print_name(stderr, trx, TRUE, new_name);
4033  fputs("\n"
4034  "InnoDB: is referenced in"
4035  " foreign key constraints\n"
4036  "InnoDB: which are not compatible"
4037  " with the new table definition.\n",
4038  stderr);
4039  }
4040 
4042  old_name, FALSE));
4043  trx->error_state = DB_SUCCESS;
4044  trx_general_rollback_for_mysql(trx, NULL);
4045  trx->error_state = DB_SUCCESS;
4046  }
4047  }
4048 
4049 funct_exit:
4050 
4051  if (commit) {
4052  trx_commit_for_mysql(trx);
4053  }
4054 
4055  if (UNIV_LIKELY_NULL(heap)) {
4056  mem_heap_free(heap);
4057  }
4058 
4059  trx->op_info = "";
4060 
4061  return(err);
4062 }
4063 
4064 /*********************************************************************/
4069 UNIV_INTERN
4070 ibool
4072 /*======================*/
4073  row_prebuilt_t* prebuilt,
4075  const dict_index_t* index,
4076  ulint* n_rows)
4078 {
4079  dtuple_t* prev_entry = NULL;
4080  ulint matched_fields;
4081  ulint matched_bytes;
4082  byte* buf;
4083  ulint ret;
4084  rec_t* rec;
4085  ibool is_ok = TRUE;
4086  int cmp;
4087  ibool contains_null;
4088  ulint i;
4089  ulint cnt;
4090  mem_heap_t* heap = NULL;
4091  ulint n_ext;
4092  ulint offsets_[REC_OFFS_NORMAL_SIZE];
4093  ulint* offsets;
4094  rec_offs_init(offsets_);
4095 
4096  *n_rows = 0;
4097 
4098  buf = static_cast<byte *>(mem_alloc(UNIV_PAGE_SIZE));
4099  heap = mem_heap_create(100);
4100 
4101  cnt = 1000;
4102 
4103  ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0);
4104 loop:
4105  /* Check thd->killed every 1,000 scanned rows */
4106  if (--cnt == 0) {
4107  if (trx_is_interrupted(prebuilt->trx)) {
4108  goto func_exit;
4109  }
4110  cnt = 1000;
4111  }
4112 
4113  switch (ret) {
4114  case DB_SUCCESS:
4115  break;
4116  default:
4117  ut_print_timestamp(stderr);
4118  fputs(" InnoDB: Warning: CHECK TABLE on ", stderr);
4119  dict_index_name_print(stderr, prebuilt->trx, index);
4120  fprintf(stderr, " returned %lu\n", ret);
4121  /* fall through (this error is ignored by CHECK TABLE) */
4122  case DB_END_OF_INDEX:
4123 func_exit:
4124  mem_free(buf);
4125  mem_heap_free(heap);
4126 
4127  return(is_ok);
4128  }
4129 
4130  *n_rows = *n_rows + 1;
4131 
4132  /* row_search... returns the index record in buf, record origin offset
4133  within buf stored in the first 4 bytes, because we have built a dummy
4134  template */
4135 
4136  rec = buf + mach_read_from_4(buf);
4137 
4138  offsets = rec_get_offsets(rec, index, offsets_,
4139  ULINT_UNDEFINED, &heap);
4140 
4141  if (prev_entry != NULL) {
4142  matched_fields = 0;
4143  matched_bytes = 0;
4144 
4145  cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
4146  &matched_fields,
4147  &matched_bytes);
4148  contains_null = FALSE;
4149 
4150  /* In a unique secondary index we allow equal key values if
4151  they contain SQL NULLs */
4152 
4153  for (i = 0;
4155  i++) {
4156  if (UNIV_SQL_NULL == dfield_get_len(
4157  dtuple_get_nth_field(prev_entry, i))) {
4158 
4159  contains_null = TRUE;
4160  }
4161  }
4162 
4163  if (cmp > 0) {
4164  fputs("InnoDB: index records in a wrong order in ",
4165  stderr);
4166 not_ok:
4167  dict_index_name_print(stderr,
4168  prebuilt->trx, index);
4169  fputs("\n"
4170  "InnoDB: prev record ", stderr);
4171  dtuple_print(stderr, prev_entry);
4172  fputs("\n"
4173  "InnoDB: record ", stderr);
4174  rec_print_new(stderr, rec, offsets);
4175  putc('\n', stderr);
4176  is_ok = FALSE;
4177  } else if (dict_index_is_unique(index)
4178  && !contains_null
4179  && matched_fields
4181  index)) {
4182 
4183  fputs("InnoDB: duplicate key in ", stderr);
4184  goto not_ok;
4185  }
4186  }
4187 
4188  {
4189  mem_heap_t* tmp_heap = NULL;
4190 
4191  /* Empty the heap on each round. But preserve offsets[]
4192  for the row_rec_to_index_entry() call, by copying them
4193  into a separate memory heap when needed. */
4194  if (UNIV_UNLIKELY(offsets != offsets_)) {
4195  ulint size = rec_offs_get_n_alloc(offsets)
4196  * sizeof *offsets;
4197 
4198  tmp_heap = mem_heap_create(size);
4199  offsets = static_cast<ulint *>(mem_heap_dup(tmp_heap, offsets, size));
4200  }
4201 
4202  mem_heap_empty(heap);
4203 
4204  prev_entry = row_rec_to_index_entry(ROW_COPY_DATA, rec,
4205  index, offsets,
4206  &n_ext, heap);
4207 
4208  if (UNIV_LIKELY_NULL(tmp_heap)) {
4209  mem_heap_free(tmp_heap);
4210  }
4211  }
4212 
4213  ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, ROW_SEL_NEXT);
4214 
4215  goto loop;
4216 }
4217 
4218 /*********************************************************************/
4221 UNIV_INTERN
4222 ibool
4224 /*=======================*/
4225  const char* table_name)
4227 {
4228  const char* name; /* table_name without database/ */
4229  ulint len;
4230 
4231  name = strchr(table_name, '/');
4232  ut_a(name != NULL);
4233  name++;
4234  len = strlen(name) + 1;
4235 
4236  if (STR_EQ(name, len, S_innodb_monitor)
4237  || STR_EQ(name, len, S_innodb_lock_monitor)
4238  || STR_EQ(name, len, S_innodb_tablespace_monitor)
4239  || STR_EQ(name, len, S_innodb_table_monitor)
4240  || STR_EQ(name, len, S_innodb_mem_validate)) {
4241 
4242  return(TRUE);
4243  }
4244 
4245  return(FALSE);
4246 }
UNIV_INTERN void row_mysql_store_blob_ref(byte *dest, ulint col_len, const void *data, ulint len)
Definition: row0mysql.cc:196
#define UT_LIST_GET_LEN(BASE)
Definition: ut0lst.h:217
dict_table_t * sys_tables
Definition: dict0dict.h:1192
UNIV_INTERN void lock_remove_all_on_table(dict_table_t *table, ibool remove_also_table_sx_locks)
Definition: lock0lock.cc:4212
UNIV_INTERN ins_node_t * ins_node_create(ulint ins_type, dict_table_t *table, mem_heap_t *heap)
Definition: row0ins.cc:69
UNIV_INTERN void que_thr_stop_for_mysql_no_error(que_thr_t *thr, trx_t *trx)
Definition: que0que.cc:1033
UNIV_INTERN ulint row_search_for_mysql(byte *buf, ulint mode, row_prebuilt_t *prebuilt, ulint match_mode, ulint direction)
Definition: row0sel.cc:3346
ibool srv_locks_unsafe_for_binlog
Definition: srv0srv.cc:138
UNIV_INTERN void row_mysql_freeze_data_dictionary_func(trx_t *trx, const char *file, ulint line)
Definition: row0mysql.cc:1735
UNIV_INLINE trx_id_t row_get_rec_trx_id(const rec_t *rec, dict_index_t *index, const ulint *offsets)
UNIV_INTERN void row_prebuild_sel_graph(row_prebuilt_t *prebuilt)
Definition: row0mysql.cc:1234
#define UT_LIST_GET_NEXT(NAME, N)
Definition: ut0lst.h:201
UNIV_INLINE void trx_start_if_not_started(trx_t *trx)
#define FIL_IBD_FILE_INITIAL_SIZE
Definition: fil0fil.h:45
unsigned trx_id_offset
Definition: dict0mem.h:349
ulint fk_cascade_depth
Definition: que0que.h:385
ulint lock_state
Definition: que0que.h:383
dict_table_t * table
Definition: row0mysql.h:592
UNIV_INLINE void dict_table_x_unlock_indexes(dict_table_t *table)
UNIV_INTERN ind_node_t * ind_create_graph_create(dict_index_t *index, mem_heap_t *heap)
Definition: dict0crea.cc:914
ulint stat_modified_counter
Definition: dict0mem.h:587
UNIV_INLINE ibool btr_pcur_is_on_user_rec(const btr_pcur_t *cursor)
UNIV_INLINE void trx_set_dict_operation(trx_t *trx, enum trx_dict_op op)
trx_id_t id
Definition: trx0trx.h:548
char * foreign_table_name_lookup
Definition: dict0mem.h:436
UNIV_INTERN int row_create_table_for_mysql(dict_table_t *table, trx_t *trx)
Definition: row0mysql.cc:1814
UNIV_INTERN que_thr_t * pars_complete_graph_for_exec(que_node_t *node, trx_t *trx, mem_heap_t *heap)
Definition: pars0pars.cc:1909
UNIV_INLINE ulint dict_index_get_n_fields(const dict_index_t *index)
unsigned space
Definition: dict0mem.h:343
char * foreign_table_name
Definition: dict0mem.h:435
UNIV_INTERN ulint lock_table(ulint flags, dict_table_t *table, enum lock_mode mode, que_thr_t *thr)
Definition: lock0lock.cc:3866
UNIV_INTERN void srv_wake_master_thread(void)
Definition: srv0srv.cc:2660
btr_pcur_t * pcur
Definition: row0upd.h:420
table_id_t table_id
Definition: trx0trx.h:556
UT_LIST_NODE_T(row_mysql_drop_t) row_mysql_drop_list
UNIV_INLINE dtuple_t * dtuple_create(mem_heap_t *heap, ulint n_fields)
UNIV_INTERN void dict_table_change_id_in_cache(dict_table_t *table, table_id_t new_id)
Definition: dict0dict.cc:1192
ins_node_t * ins_node
Definition: row0mysql.h:646
unsigned tablespace_discarded
Definition: dict0mem.h:495
#define mem_free(PTR)
Definition: mem0mem.h:249
UNIV_INTERN dict_table_t * dict_load_table(const char *name, ibool cached, dict_err_ignore_t ignore_err)
Definition: dict0load.cc:1710
que_common_t common
Definition: que0que.h:352
UNIV_INTERN ulint dict_truncate_index_tree(dict_table_t *table, ulint space, btr_pcur_t *pcur, mtr_t *mtr)
Definition: dict0crea.cc:744
ibool row_rollback_on_timeout
Definition: row0mysql.cc:58
UNIV_INTERN ibool fil_open_single_table_tablespace(ibool check_space_id, ulint id, ulint flags, const char *name)
Definition: fil0fil.cc:3047
UNIV_INTERN upd_t * row_get_prebuilt_update_vector(row_prebuilt_t *prebuilt)
Definition: row0mysql.cc:1299
dict_table_t * table
Definition: row0upd.h:425
UNIV_INTERN void * mem_heap_dup(mem_heap_t *heap, const void *data, ulint len)
Definition: mem0mem.cc:120
byte * ins_upd_rec_buff
Definition: row0mysql.h:649
UNIV_INTERN void que_run_threads(que_thr_t *thr)
Definition: que0que.cc:1336
UNIV_INTERN ibool dict_tables_have_same_db(const char *name1, const char *name2)
Definition: dict0dict.cc:204
UNIV_INLINE ibool dict_table_is_comp(const dict_table_t *table)
UNIV_INTERN ibool row_mysql_handle_errors(ulint *new_err, trx_t *trx, que_thr_t *thr, trx_savept_t *savept)
Definition: row0mysql.cc:533
UNIV_INLINE void mach_write_to_8(byte *b, ib_uint64_t n)
UNIV_INTERN void rec_print_new(FILE *file, const rec_t *rec, const ulint *offsets)
Definition: rem0rec.cc:1722
que_fork_t * ins_graph
Definition: row0mysql.h:665
UNIV_INTERN ibool row_is_magic_monitor_table(const char *table_name)
Definition: row0mysql.cc:4223
UNIV_INTERN void dict_mem_table_free(dict_table_t *table)
Definition: dict0mem.cc:111
unsigned sql_stat_start
Definition: row0mysql.h:596
unsigned space
Definition: dict0mem.h:486
que_node_t * run_node
Definition: que0que.h:376
UNIV_INTERN void ins_node_set_new_row(ins_node_t *node, dtuple_t *row)
Definition: row0ins.cc:186
UNIV_INTERN int trx_general_rollback_for_mysql(trx_t *trx, trx_savept_t *savept)
Definition: trx0roll.cc:65
dtuple_t * row
Definition: row0ins.h:115
UNIV_INLINE ulint mach_read_from_2_little_endian(const byte *buf) __attribute__((nonnull
#define mem_heap_free(heap)
Definition: mem0mem.h:117
UNIV_INTERN void pars_info_add_int4_literal(pars_info_t *info, const char *name, lint val)
Definition: pars0pars.cc:2027
UNIV_INTERN void row_mysql_prebuilt_free_blob_heap(row_prebuilt_t *prebuilt)
Definition: row0mysql.cc:127
UNIV_INTERN void lock_release_autoinc_locks(trx_t *trx)
Definition: lock0lock.cc:5596
UNIV_INTERN void dict_update_statistics(dict_table_t *table, ibool only_calc_if_missing_stats)
Definition: dict0dict.cc:4268
UNIV_INTERN byte * row_mysql_store_col_in_innobase_format(dfield_t *dfield, byte *buf, ibool row_format_col, const byte *mysql_data, ulint col_len, ulint comp)
Definition: row0mysql.cc:301
UNIV_INTERN ulint trx_commit_for_mysql(trx_t *trx)
Definition: trx0trx.cc:1596
UNIV_INTERN void dtuple_print(FILE *f, const dtuple_t *tuple)
Definition: data0data.cc:532
UNIV_INTERN void row_unlock_table_autoinc_for_mysql(trx_t *trx)
Definition: row0mysql.cc:928
UNIV_INLINE dict_table_t * dict_table_get_low(const char *table_name)
UNIV_INLINE const dict_col_t * dict_index_get_nth_col(const dict_index_t *index, ulint pos)
UNIV_INTERN void dict_index_copy_types(dtuple_t *tuple, const dict_index_t *index, ulint n_fields)
Definition: dict0dict.cc:1932
UNIV_INTERN void trx_free_for_background(trx_t *trx)
Definition: trx0trx.cc:363
UNIV_INTERN trx_savept_t trx_savept_take(trx_t *trx)
Definition: trx0roll.cc:399
UNIV_INTERN void row_mysql_pad_col(ulint mbminlen, byte *pad, ulint len)
Definition: row0mysql.cc:255
UNIV_INTERN ulint dict_get_db_name_len(const char *name)
Definition: dict0dict.cc:246
UNIV_INLINE ib_uint64_t log_get_lsn(void)
UNIV_INLINE void btr_pcur_close(btr_pcur_t *cursor)
UNIV_INTERN void row_mysql_unfreeze_data_dictionary(trx_t *trx)
Definition: row0mysql.cc:1752
UNIV_INTERN void dict_table_copy_types(dtuple_t *tuple, const dict_table_t *table)
Definition: dict0dict.cc:1963
UNIV_INTERN int row_table_add_foreign_constraints(trx_t *trx, const char *sql_string, size_t sql_length, const char *name, ibool reject_fks)
Definition: row0mysql.cc:2096
#define DICT_MAX_INDEX_COL_LEN
DICT_MAX_INDEX_COL_LEN is measured in bytes and is the maximum indexed column length (or indexed pref...
Definition: dict0mem.h:316
UNIV_INTERN char * mem_heap_strdup(mem_heap_t *heap, const char *str)
Definition: mem0mem.cc:107
que_fork_t * sel_graph
Definition: row0mysql.h:673
UNIV_INTERN ibool trx_is_interrupted(trx_t *trx)
Definition: ha_innodb.cc:1882
UNIV_INLINE void rw_lock_s_lock_func(rw_lock_t *lock, ulint pass, const char *file_name, ulint line)
UNIV_INTERN trx_t * trx_allocate_for_background(void)
Definition: trx0trx.cc:226
UNIV_INTERN int row_discard_tablespace_for_mysql(const char *name, trx_t *trx)
Definition: row0mysql.cc:2351
dtuple_t * clust_ref
Definition: row0mysql.h:681
UNIV_INTERN void rw_lock_x_lock_func(rw_lock_t *lock, ulint pass, const char *file_name, ulint line)
Definition: sync0rw.cc:616
UNIV_INLINE ulint dtype_get_mysql_type(const dtype_t *type)
UNIV_INTERN const byte * row_mysql_read_blob_ref(ulint *len, const byte *ref, ulint col_len)
Definition: row0mysql.cc:234
typedef UT_LIST_BASE_NODE_T(mutex_t) ut_list_base_node_t
UNIV_INTERN sel_node_t * sel_node_create(mem_heap_t *heap)
Definition: row0sel.cc:255
que_node_t * parent
Definition: que0types.h:49
UNIV_INLINE ulint rec_get_deleted_flag(const rec_t *rec, ulint comp)
UNIV_INTERN char * dict_get_first_table_name_in_db(const char *name)
Definition: dict0load.cc:84
const trx_t * autoinc_trx
Definition: dict0mem.h:639
UNIV_INTERN char * mem_heap_strcat(mem_heap_t *heap, const char *s1, const char *s2)
Definition: mem0mem.cc:134
UNIV_INTERN void pars_info_add_str_literal(pars_info_t *info, const char *name, const char *str)
Definition: pars0pars.cc:2006
UNIV_INTERN void mtr_commit(mtr_t *mtr) __attribute__((nonnull))
Definition: mtr0mtr.cc:247
#define UT_LIST_REMOVE(NAME, BASE, N)
Definition: ut0lst.h:178
UNIV_INTERN void dict_hdr_get_new_id(table_id_t *table_id, index_id_t *index_id, ulint *space_id)
Definition: dict0boot.cc:68
UNIV_INLINE void dfield_set_data(dfield_t *field, const void *data, ulint len)
dict_table_t * sys_indexes
Definition: dict0dict.h:1194
UNIV_INTERN ulint row_check_index_for_mysql(row_prebuilt_t *prebuilt, const dict_index_t *index, ulint *n_rows)
Definition: row0mysql.cc:4071
UNIV_INLINE ulint dfield_get_len(const dfield_t *field)
mem_heap_t * blob_heap
Definition: row0mysql.h:753
UNIV_INTERN void log_buffer_flush_to_disk(void)
Definition: log0log.cc:1603
UNIV_INLINE ulint dtype_get_len(const dtype_t *type)
const char * op_info
Definition: trx0trx.h:477
UNIV_INTERN ibool dict_table_rename_in_cache(dict_table_t *table, const char *new_name, ibool rename_also_foreigns)
Definition: dict0dict.cc:955
UNIV_INTERN int cmp_dtuple_rec_with_match(const dtuple_t *dtuple, const rec_t *rec, const ulint *offsets, ulint *matched_fields, ulint *matched_bytes)
Definition: rem0cmp.cc:411
UNIV_INTERN void que_graph_free(que_t *graph)
Definition: que0que.cc:679
UNIV_INTERN void row_prebuilt_free(row_prebuilt_t *prebuilt, ibool dict_locked)
Definition: row0mysql.cc:712
UNIV_INTERN void os_event_set(os_event_t event)
Definition: os0sync.cc:434
UNIV_INTERN void os_thread_sleep(ulint tm)
Definition: os0thread.cc:265
table_id_t id
Definition: dict0mem.h:477
UNIV_INLINE char * mem_heap_strdupl(mem_heap_t *heap, const char *str, ulint len)
UNIV_INTERN ulint fil_space_get_flags(ulint id)
Definition: fil0fil.cc:1483
UNIV_INTERN void btr_pcur_copy_stored_position(btr_pcur_t *pcur_receive, btr_pcur_t *pcur_donate)
Definition: btr0pcur.cc:165
UNIV_INTERN ulint row_update_cascade_for_mysql(que_thr_t *thr, upd_node_t *node, dict_table_t *table)
Definition: row0mysql.cc:1634
UNIV_INLINE ulint dict_index_is_clust(const dict_index_t *index) __attribute__((pure))
UNIV_INLINE ulint mach_read_from_n_little_endian(const byte *buf, ulint buf_size) __attribute__((nonnull
#define DICT_FK_MAX_RECURSIVE_LOAD
Definition: dict0mem.h:130
UNIV_INTERN upd_node_t * upd_node_create(mem_heap_t *heap)
Definition: row0upd.cc:310
UNIV_INTERN int row_unlock_for_mysql(row_prebuilt_t *prebuilt, ibool has_latches_on_recs)
Definition: row0mysql.cc:1510
#define FK_MAX_CASCADE_DEL
Definition: dict0mem.h:138
UNIV_INTERN void btr_pcur_store_position(btr_pcur_t *cursor, mtr_t *mtr)
Definition: btr0pcur.cc:89
UNIV_INLINE ulint ut_max(ulint n1, ulint n2)
UNIV_INTERN tab_node_t * tab_create_graph_create(dict_table_t *table, mem_heap_t *heap)
Definition: dict0crea.cc:878
UNIV_INTERN int row_truncate_table_for_mysql(dict_table_t *table, trx_t *trx)
Definition: row0mysql.cc:2679
ulint dict_operation_lock_mode
Definition: trx0trx.h:530
#define ut_a(EXPR)
Definition: ut0dbg.h:105
mysql_row_templ_t * mysql_template
Definition: row0mysql.h:639
UNIV_INLINE ulint dict_index_get_n_ordering_defined_by_user(const dict_index_t *index)
UNIV_INTERN void dict_table_autoinc_initialize(dict_table_t *table, ib_uint64_t value)
Definition: dict0dict.cc:412
UNIV_INTERN void que_graph_free_recursive(que_node_t *node)
Definition: que0que.cc:508
UNIV_INTERN void ut_print_name(FILE *f, struct trx_struct *trx, ibool table_id, const char *name)
Definition: ut0ut.cc:528
UNIV_INTERN upd_node_t * row_create_update_node_for_mysql(dict_table_t *table, mem_heap_t *heap)
Definition: row0mysql.cc:1262
UNIV_INTERN pars_info_t * pars_info_create(void)
Definition: pars0pars.cc:1938
ib_uint64_t autoinc_increment
Definition: row0mysql.h:760
UNIV_INLINE void * mem_heap_alloc(mem_heap_t *heap, ulint n)
#define mem_heap_create(N)
Definition: mem0mem.h:97
#define UT_NOT_USED(A)
Definition: ut0dbg.h:134
UNIV_INTERN ulint que_eval_sql(pars_info_t *info, const char *sql, ibool reserve_dict_mutex, trx_t *trx)
Definition: que0que.cc:1392
UNIV_INLINE ulint dtype_get_mbminlen(const dtype_t *type)
UNIV_INTERN ulint fil_create_new_single_table_tablespace(ulint space_id, const char *tablename, ibool is_temp, ulint flags, ulint size)
Definition: fil0fil.cc:2671
UNIV_INLINE ulint dtype_get_mbmaxlen(const dtype_t *type)
UNIV_INLINE void * mem_heap_zalloc(mem_heap_t *heap, ulint n)
UNIV_INLINE que_thr_t * que_fork_get_first_thr(que_fork_t *fork)
UNIV_INLINE void mach_write_to_1(byte *b, ulint n)
UNIV_INTERN void pars_info_add_ull_literal(pars_info_t *info, const char *name, ib_uint64_t val)
Definition: pars0pars.cc:2050
UNIV_INLINE dict_table_t * dict_table_get_low_ignore_err(const char *table_name, dict_err_ignore_t ignore_err)
ulint n_mysql_handles_opened
Definition: dict0mem.h:527
#define DICT_TF2_SHIFT
Additional table flags.
Definition: dict0mem.h:113
#define UT_LIST_ADD_LAST(NAME, BASE, N)
Definition: ut0lst.h:119
#define UT_LIST_GET_FIRST(BASE)
Definition: ut0lst.h:224
UNIV_INTERN void row_mysql_lock_data_dictionary_func(trx_t *trx, const char *file, ulint line)
Definition: row0mysql.cc:1768
btr_pcur_t * pcur
Definition: row0mysql.h:669
UNIV_INTERN int row_import_tablespace_for_mysql(const char *name, trx_t *trx)
Definition: row0mysql.cc:2542
UNIV_INTERN row_prebuilt_t * row_create_prebuilt(dict_table_t *table)
Definition: row0mysql.cc:650
UNIV_INTERN void que_thr_stop_for_mysql(que_thr_t *thr)
Definition: que0que.cc:955
UNIV_INLINE void mach_write_to_n_little_endian(byte *dest, ulint dest_size, ulint n)
UNIV_INLINE void mem_heap_empty(mem_heap_t *heap)
dict_sys_t * dict_sys
Definition: dict0dict.cc:63
UNIV_INLINE void mach_write_to_2_little_endian(byte *dest, ulint n)
dtuple_t * search_tuple
Definition: row0mysql.h:675
unsigned template_type
Definition: row0mysql.h:619
UNIV_INTERN int row_update_for_mysql(byte *mysql_rec, row_prebuilt_t *prebuilt)
Definition: row0mysql.cc:1333
#define ut_ad(EXPR)
Definition: ut0dbg.h:127
#define DICT_TF_COMPACT
Definition: dict0mem.h:69
UNIV_INTERN int row_lock_table_for_mysql(row_prebuilt_t *prebuilt, dict_table_t *table, ulint mode)
Definition: row0mysql.cc:1026
UNIV_INTERN void srv_suspend_mysql_thread(que_thr_t *thr)
Definition: srv0srv.cc:1610
ib_id_t trx_id_t
Definition: trx0types.h:85
btr_cur_t btr_cur
Definition: btr0pcur.h:459
unsigned ibd_file_missing
Definition: dict0mem.h:490
UNIV_INTERN void que_thr_move_to_run_state_for_mysql(que_thr_t *thr, trx_t *trx)
Definition: que0que.cc:1001
UNIV_INLINE ulint dict_table_get_n_cols(const dict_table_t *table)
ib_uint64_t autoinc_last_value
Definition: row0mysql.h:758
#define UT_LIST_INIT(BASE)
Definition: ut0lst.h:84
#define ut_error
Definition: ut0dbg.h:115
unsigned prtype
Definition: data0type.h:486
UNIV_INLINE trx_id_t trx_read_trx_id(const byte *ptr)
UNIV_INTERN ulint row_drop_tables_for_mysql_in_background(void)
Definition: row0mysql.cc:2203
UNIV_INLINE que_node_t * que_node_get_parent(que_node_t *node)
ulint n_foreign_key_checks_running
Definition: dict0mem.h:539
unsigned flags
Definition: dict0mem.h:489
UNIV_INLINE char * mem_strdup(const char *str)
#define FIL_NULL
Definition: fil0fil.h:48
UNIV_INLINE ulint dict_index_get_n_unique(const dict_index_t *index)
trx_t * trx
Definition: que0que.h:403
dict_index_t * index
Definition: btr0cur.h:688
const char * table_name
Definition: dict0mem.h:340
unsigned n_fields
Definition: dict0mem.h:361
UNIV_INTERN que_thr_t * row_upd_step(que_thr_t *thr)
Definition: row0upd.cc:2354
UNIV_INTERN void dict_table_decrement_handle_count(dict_table_t *table, ibool dict_locked)
Definition: dict0dict.cc:348
UNIV_INTERN int row_create_index_for_mysql(dict_index_t *index, trx_t *trx, const ulint *field_lengths)
Definition: row0mysql.cc:1965
UNIV_INTERN ulint dict_foreign_parse_drop_constraints(mem_heap_t *heap, trx_t *trx, dict_table_t *table, ulint *n, const char ***constraints_to_drop)
Definition: dict0dict.cc:3891
UNIV_INLINE void dfield_set_null(dfield_t *field)
mem_heap_t * old_vers_heap
Definition: row0mysql.h:755
UNIV_INTERN void lock_rec_unlock(trx_t *trx, const buf_block_t *block, const rec_t *rec, enum lock_mode lock_mode)
Definition: lock0lock.cc:4000
UNIV_INLINE ulint mach_read_from_4(const byte *b) __attribute__((nonnull
UNIV_INTERN ibool lock_trx_holds_autoinc_locks(const trx_t *trx)
Definition: lock0lock.cc:5583
upd_t * update
Definition: row0upd.h:426
UNIV_INTERN void ut_print_timestamp(FILE *file)
Definition: ut0ut.cc:247
UNIV_INTERN ibool fil_reset_too_high_lsns(const char *name, ib_uint64_t current_lsn)
Definition: fil0fil.cc:2873
UNIV_INTERN void dict_table_autoinc_lock(dict_table_t *table)
Definition: dict0dict.cc:401
UNIV_INLINE ulint dict_index_is_unique(const dict_index_t *index) __attribute__((pure))
upd_node_t * upd_node
Definition: row0mysql.h:663
UNIV_INTERN ulint row_rename_table_for_mysql(const char *old_name, const char *new_name, trx_t *trx, ibool commit)
Definition: row0mysql.cc:3754
UNIV_INLINE trx_t * thr_get_trx(que_thr_t *thr)
unsigned n_template
Definition: row0mysql.h:623
que_node_t * prev_node
Definition: que0que.h:379
UNIV_INTERN que_thr_t * row_ins_step(que_thr_t *thr)
Definition: row0ins.cc:2414
btr_pcur_t * clust_pcur
Definition: row0mysql.h:671
UNIV_INTERN os_thread_id_t os_thread_get_curr_id(void)
Definition: os0thread.cc:93
UNIV_INTERN ulint dict_create_foreign_constraints(trx_t *trx, const char *sql_string, size_t sql_length, const char *name, ibool reject_fks)
Definition: dict0dict.cc:3846
UNIV_INTERN void mem_analyze_corruption(void *ptr)
Definition: mem0dbg.cc:822
UNIV_INTERN int row_insert_for_mysql(byte *mysql_rec, row_prebuilt_t *prebuilt)
Definition: row0mysql.cc:1103
byte * fetch_cache[MYSQL_FETCH_CACHE_SIZE]
Definition: row0mysql.h:735
UNIV_INLINE void mtr_start(mtr_t *mtr) __attribute__((nonnull))
const char * dir_path_of_temp_table
Definition: dict0mem.h:480
UNIV_INTERN const byte * row_mysql_read_true_varchar(ulint *len, const byte *field, ulint lenlen)
Definition: row0mysql.cc:172
UNIV_INLINE ibool btr_pcur_move_to_next_user_rec(btr_pcur_t *cursor, mtr_t *mtr)
UNIV_INTERN void btr_pcur_free_for_mysql(btr_pcur_t *cursor)
Definition: btr0pcur.cc:58
UNIV_INLINE ulint mach_read_from_1(const byte *b) __attribute__((nonnull
sel_node_t * select
Definition: row0upd.h:417
UNIV_INLINE ulint rec_offs_get_n_alloc(const ulint *offsets)
UNIV_INTERN dtuple_t * row_rec_to_index_entry(ulint type, const rec_t *rec, const dict_index_t *index, ulint *offsets, ulint *n_ext, mem_heap_t *heap)
Definition: row0row.cc:382
UNIV_INTERN void dict_table_autoinc_unlock(dict_table_t *table)
Definition: dict0dict.cc:460
que_fork_t * upd_graph
Definition: row0mysql.h:667
dict_table_t * foreign_table
Definition: dict0mem.h:438
UNIV_INTERN void row_mysql_drop_temp_tables(void)
Definition: row0mysql.cc:3440
UNIV_INTERN void ibuf_delete_for_discarded_space(ulint space)
Definition: ibuf0ibuf.cc:4812
UNIV_INTERN btr_pcur_t * btr_pcur_create_for_mysql(void)
Definition: btr0pcur.cc:41
mem_heap_t * heap
Definition: row0mysql.h:643
UNIV_INTERN byte * row_mysql_store_true_var_len(byte *dest, ulint len, ulint lenlen)
Definition: row0mysql.cc:143
UNIV_INTERN ibool fil_discard_tablespace(ulint id)
Definition: fil0fil.cc:2408
UNIV_INTERN void row_update_prebuilt_trx(row_prebuilt_t *prebuilt, trx_t *trx)
Definition: row0mysql.cc:798
UNIV_INTERN void dict_index_name_print(FILE *file, trx_t *trx, const dict_index_t *index)
Definition: dict0dict.cc:4775
UNIV_INTERN ibool fil_space_for_table_exists_in_mem(ulint id, const char *name, ibool is_temp, ibool mark_space, ibool print_error_if_does_not_exist)
Definition: fil0fil.cc:3709
UNIV_INTERN ulint row_get_background_drop_list_len_low(void)
Definition: row0mysql.cc:2277
UNIV_INLINE void btr_pcur_open_at_index_side(ibool from_left, dict_index_t *index, ulint latch_mode, btr_pcur_t *pcur, ibool do_init, mtr_t *mtr)
ulint error_state
Definition: trx0trx.h:601
ib_int64_t stat_n_rows
Definition: dict0mem.h:579
UNIV_INTERN int row_drop_database_for_mysql(const char *name, trx_t *trx)
Definition: row0mysql.cc:3585
UNIV_INTERN void page_rec_write_index_page_no(rec_t *rec, ulint i, ulint page_no, mtr_t *mtr)
Definition: page0page.cc:1260
UNIV_INTERN que_thr_t * que_fork_start_command(que_fork_t *fork)
Definition: que0que.cc:342
#define DICT_TF2_TEMPORARY
Definition: dict0mem.h:116
UNIV_INTERN void row_mysql_unlock_data_dictionary(trx_t *trx)
Definition: row0mysql.cc:1790
ulint stored_select_lock_type
Definition: row0mysql.h:684
UNIV_INLINE void dict_table_x_lock_indexes(dict_table_t *table)
UNIV_INTERN int row_drop_table_for_mysql(const char *name, trx_t *trx, ibool drop_db)
Definition: row0mysql.cc:3033
UNIV_INTERN ibool fil_delete_tablespace(ulint id)
Definition: fil0fil.cc:2203
rw_lock_t dict_operation_lock
the data dictionary rw-latch protecting dict_sys
Definition: dict0dict.cc:73
UNIV_INTERN int row_lock_table_autoinc_for_mysql(row_prebuilt_t *prebuilt)
Definition: row0mysql.cc:950
UNIV_INTERN void fsp_header_init(ulint space, ulint size, mtr_t *mtr)
Definition: fsp0fsp.cc:951
UNIV_INLINE upd_t * upd_create(ulint n, mem_heap_t *heap)
UNIV_INLINE void btr_pcur_commit_specify_mtr(btr_pcur_t *pcur, mtr_t *mtr)
UNIV_INTERN ibool row_table_got_default_clust_index(const dict_table_t *table)
Definition: row0mysql.cc:1719
UNIV_INLINE int ut_strcmp(const char *str1, const char *str2)
UNIV_INTERN ulint dict_load_foreigns(const char *table_name, ibool check_recursive, ibool check_charsets)
Definition: dict0load.cc:2257
UNIV_INTERN void dict_table_remove_from_cache(dict_table_t *table)
Definition: dict0dict.cc:1216
unsigned mtype
Definition: data0type.h:485