1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2020, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2012, Facebook Inc.
5 
6 This program is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License, version 2.0, as published by the
8 Free Software Foundation.
9 
10 This program is also distributed with certain software (including but not
11 limited to OpenSSL) that is licensed under separate terms, as designated in a
12 particular file or component or in included license documentation. The authors
13 of MySQL hereby grant you an additional permission to link the program and
14 your derivative works with the separately licensed software that they have
15 included with MySQL.
16 
17 This program is distributed in the hope that it will be useful, but WITHOUT
18 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
20 for more details.
21 
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
25 
26 *****************************************************************************/
27 
28 /** @file include/dict0dict.h
29  Data dictionary system
30 
31  Created 1/8/1996 Heikki Tuuri
32  *******************************************************/
33 
34 #ifndef dict0dict_h
35 #define dict0dict_h
36 
37 #include <set>
38 
39 #include <deque>
40 #include "data0data.h"
41 #include "data0type.h"
42 #include "dict/dict.h"
43 #include "dict0mem.h"
44 #include "dict0types.h"
45 #include "fsp0fsp.h"
46 #include "fsp0sysspace.h"
47 #include "hash0hash.h"
48 #include "mem0mem.h"
49 #include "rem0types.h"
50 #include "row0types.h"
51 #include "sql/dd/object_id.h"
52 #include "sync0rw.h"
53 #include "trx0types.h"
54 #include "univ.i"
55 #include "ut0byte.h"
56 #include "ut0mem.h"
57 #include "ut0new.h"
58 #include "ut0rnd.h"
59 
60 #define DICT_HEAP_SIZE                   \
61   100 /*!< initial memory heap size when \
62       creating a table or index object */
63 
64 /** SDI version. Written on Page 1 & 2 at FIL_PAGE_FILE_FLUSH_LSN offset. */
65 const uint32_t SDI_VERSION = 1;
66 
67 /** Space id of system tablespace */
68 const space_id_t SYSTEM_TABLE_SPACE = TRX_SYS_SPACE;
69 
70 /** Get the database name length in a table name.
71  @return database name length */
72 ulint dict_get_db_name_len(const char *name) /*!< in: table name in the form
73                                              dbname '/' tablename */
74     MY_ATTRIBUTE((warn_unused_result));
75 #ifndef UNIV_HOTBACKUP
76 /** Frees a foreign key struct. */
77 void dict_foreign_free(
78     dict_foreign_t *foreign); /*!< in, own: foreign key struct */
79 /** Finds the highest [number] for foreign key constraints of the table. Looks
80  only at the >= 4.0.18-format id's, which are of the form
81  databasename/tablename_ibfk_[number].
82  @return highest number, 0 if table has no new format foreign key constraints */
83 ulint dict_table_get_highest_foreign_id(
84     dict_table_t *table); /*!< in: table in the dictionary
85                           memory cache */
86 #endif                    /* !UNIV_HOTBACKUP */
87 /** Return the end of table name where we have removed dbname and '/'.
88  @return table name */
89 const char *dict_remove_db_name(const char *name) /*!< in: table name in the
90                                                   form dbname '/' tablename */
91     MY_ATTRIBUTE((warn_unused_result));
92 
93 /** Operation to perform when opening a table */
94 enum dict_table_op_t {
95   /** Expect the tablespace to exist. */
96   DICT_TABLE_OP_NORMAL = 0,
97   /** Drop any orphan indexes after an aborted online index creation */
98   DICT_TABLE_OP_DROP_ORPHAN,
99   /** Silently load the tablespace if it does not exist,
100   and do not load the definitions of incomplete indexes. */
101   DICT_TABLE_OP_LOAD_TABLESPACE
102 };
103 
104 /** Decrements the count of open handles to a table. */
105 void dict_table_close(dict_table_t *table, /*!< in/out: table */
106                       ibool dict_locked, /*!< in: TRUE=data dictionary locked */
107                       ibool try_drop);   /*!< in: TRUE=try to drop any orphan
108                                          indexes after an aborted online
109                                          index creation */
110 /** Closes the only open handle to a table and drops a table while assuring
111  that dict_sys->mutex is held the whole time.  This assures that the table
112  is not evicted after the close when the count of open handles goes to zero.
113  Because dict_sys->mutex is held, we do not need to call
114  dict_table_prevent_eviction().  */
115 void dict_table_close_and_drop(
116     trx_t *trx,           /*!< in: data dictionary transaction */
117     dict_table_t *table); /*!< in/out: table */
118 /** Inits the data dictionary module. */
119 void dict_init(void);
120 
121 /** Closes the data dictionary module. */
122 void dict_close(void);
123 
124 /** Inits the structure for persisting dynamic metadata */
125 void dict_persist_init(void);
126 
127 /** Clear the structure */
128 void dict_persist_close(void);
129 
130 #ifndef UNIV_HOTBACKUP
131 /** Write back the dirty persistent dynamic metadata of the table
132 to DDTableBuffer.
133 @param[in,out]	table	table object */
134 void dict_table_persist_to_dd_table_buffer(dict_table_t *table);
135 
136 /** Read persistent dynamic metadata stored in a buffer
137 @param[in]	buffer		buffer to read
138 @param[in]	size		size of data in buffer
139 @param[in]	metadata	where we store the metadata from buffer */
140 void dict_table_read_dynamic_metadata(const byte *buffer, ulint size,
141                                       PersistentTableMetadata *metadata);
142 
143 /** Determine bytes of column prefix to be stored in the undo log. Please
144  note that if !dict_table_has_atomic_blobs(table), no prefix
145  needs to be stored in the undo log.
146  @return bytes of column prefix to be stored in the undo log */
147 UNIV_INLINE
148 ulint dict_max_field_len_store_undo(
149     dict_table_t *table,   /*!< in: table */
150     const dict_col_t *col) /*!< in: column which index prefix
151                            is based on */
152     MY_ATTRIBUTE((warn_unused_result));
153 
154 /** Determine maximum bytes of a virtual column need to be stored
155 in the undo log.
156 @param[in]	table		dict_table_t for the table
157 @param[in]	col_no		virtual column number
158 @return maximum bytes of virtual column to be stored in the undo log */
159 UNIV_INLINE
160 ulint dict_max_v_field_len_store_undo(dict_table_t *table, ulint col_no);
161 
162 #endif /* !UNIV_HOTBACKUP */
163 /** Gets the column number.
164  @return col->ind, table column position (starting from 0) */
165 UNIV_INLINE
166 ulint dict_col_get_no(const dict_col_t *col) /*!< in: column */
167     MY_ATTRIBUTE((warn_unused_result));
168 /** Gets the column position in the clustered index. */
169 UNIV_INLINE
170 ulint dict_col_get_clust_pos(
171     const dict_col_t *col,           /*!< in: table column */
172     const dict_index_t *clust_index) /*!< in: clustered index */
173     MY_ATTRIBUTE((warn_unused_result));
174 
175 #ifndef UNIV_HOTBACKUP
176 /** Gets the column position in the given index.
177 @param[in]	col	table column
178 @param[in]	index	index to be searched for column
179 @return position of column in the given index. */
180 UNIV_INLINE
181 ulint dict_col_get_index_pos(const dict_col_t *col, const dict_index_t *index)
182     MY_ATTRIBUTE((nonnull, warn_unused_result));
183 
184 /** If the given column name is reserved for InnoDB system columns, return
185  TRUE.
186  @return true if name is reserved */
187 ibool dict_col_name_is_reserved(const char *name) /*!< in: column name */
188     MY_ATTRIBUTE((warn_unused_result));
189 /** Acquire the autoinc lock. */
190 void dict_table_autoinc_lock(dict_table_t *table); /*!< in/out: table */
191 
192 /** Unconditionally set the autoinc counter. */
193 void dict_table_autoinc_initialize(
194     dict_table_t *table, /*!< in/out: table */
195     ib_uint64_t value);  /*!< in: next value to assign to a row */
196 /** Reads the next autoinc value (== autoinc counter value), 0 if not yet
197  initialized.
198  @return value for a new row, or 0 */
199 ib_uint64_t dict_table_autoinc_read(const dict_table_t *table) /*!< in: table */
200     MY_ATTRIBUTE((warn_unused_result));
201 /** Updates the autoinc counter if the value supplied is greater than the
202  current value. */
203 void dict_table_autoinc_update_if_greater(
204 
205     dict_table_t *table, /*!< in/out: table */
206     ib_uint64_t value);  /*!< in: value which was assigned to a row */
207 /** Release the autoinc lock. */
208 void dict_table_autoinc_unlock(dict_table_t *table); /*!< in/out: table */
209 
210 /** Update the persisted autoinc counter to specified one, we should hold
211 autoinc_persisted_mutex.
212 @param[in,out]	table	table
213 @param[in]	autoinc	set autoinc_persisted to this value */
214 UNIV_INLINE
215 void dict_table_autoinc_persisted_update(dict_table_t *table,
216                                          ib_uint64_t autoinc);
217 
218 /** Set the column position of autoinc column in clustered index for a table.
219 @param[in]	table	table
220 @param[in]	pos	column position in table definition */
221 UNIV_INLINE
222 void dict_table_autoinc_set_col_pos(dict_table_t *table, ulint pos);
223 
224 /** Write redo logs for autoinc counter that is to be inserted, or to
225 update some existing smaller one to bigger.
226 @param[in,out]	table	InnoDB table object
227 @param[in]	value	AUTOINC counter to log
228 @param[in,out]	mtr	mini-transaction */
229 void dict_table_autoinc_log(dict_table_t *table, uint64_t value, mtr_t *mtr);
230 
231 /** Check if a table has an autoinc counter column.
232 @param[in]	table	table
233 @return true if there is an autoinc column in the table, otherwise false. */
234 UNIV_INLINE
235 bool dict_table_has_autoinc_col(const dict_table_t *table);
236 
237 #endif /* !UNIV_HOTBACKUP */
238 /** Adds system columns to a table object. */
239 void dict_table_add_system_columns(dict_table_t *table, /*!< in/out: table */
240                                    mem_heap_t *heap); /*!< in: temporary heap */
241 #ifndef UNIV_HOTBACKUP
242 /** Mark if table has big rows.
243 @param[in,out]	table	table handler */
244 void dict_table_set_big_rows(dict_table_t *table) MY_ATTRIBUTE((nonnull));
245 /** Adds a table object to the dictionary cache.
246 @param[in]	table		table
247 @param[in]	can_be_evicted	true if can be evicted
248 @param[in]	heap		temporary heap
249 */
250 void dict_table_add_to_cache(dict_table_t *table, ibool can_be_evicted,
251                              mem_heap_t *heap);
252 
253 /** Removes a table object from the dictionary cache. */
254 void dict_table_remove_from_cache(dict_table_t *table); /*!< in, own: table */
255 
256 /** Try to invalidate an entry from the dict cache, for a partitioned table,
257 if any table found.
258 @param[in]	name	Table name */
259 void dict_partitioned_table_remove_from_cache(const char *name);
260 
261 #ifdef UNIV_DEBUG
262 /** Removes a table object from the dictionary cache, for debug purpose
263 @param[in,out]	table		table object
264 @param[in]	lru_evict	true if table being evicted to make room
265                                 in the table LRU list */
266 void dict_table_remove_from_cache_debug(dict_table_t *table, bool lru_evict);
267 #endif /* UNIV_DEBUG */
268 
269 /** Renames a table object.
270  @return true if success */
271 dberr_t dict_table_rename_in_cache(dict_table_t *table,  /*!< in/out: table */
272                                    const char *new_name, /*!< in: new name */
273                                    ibool rename_also_foreigns)
274     /*!< in: in ALTER TABLE we want
275     to preserve the original table name
276     in constraints which reference it */
277     MY_ATTRIBUTE((warn_unused_result));
278 
279 /** Removes an index from the dictionary cache.
280 @param[in,out]	table	table whose index to remove
281 @param[in,out]	index	index to remove, this object is destroyed and must not
282 be accessed by the caller afterwards */
283 void dict_index_remove_from_cache(dict_table_t *table, dict_index_t *index);
284 
285 /** Change the id of a table object in the dictionary cache. This is used in
286  DISCARD TABLESPACE. */
287 void dict_table_change_id_in_cache(
288     dict_table_t *table, /*!< in/out: table object already in cache */
289     table_id_t new_id);  /*!< in: new id to set */
290 /** Removes a foreign constraint struct from the dictionary cache. */
291 void dict_foreign_remove_from_cache(
292     dict_foreign_t *foreign); /*!< in, own: foreign constraint */
293 /** Adds a foreign key constraint object to the dictionary cache. May free
294  the object if there already is an object with the same identifier in.
295  At least one of foreign table or referenced table must already be in
296  the dictionary cache!
297  @return DB_SUCCESS or error code */
298 dberr_t dict_foreign_add_to_cache(dict_foreign_t *foreign,
299                                   /*!< in, own: foreign key constraint */
300                                   const char **col_names,
301                                   /*!< in: column names, or NULL to use
302                                   foreign->foreign_table->col_names */
303                                   bool check_charsets,
304                                   /*!< in: whether to check charset
305                                   compatibility */
306                                   bool can_free_fk,
307                                   /*!< in: whether free existing FK */
308                                   dict_err_ignore_t ignore_err)
309     /*!< in: error to be ignored */
310     MY_ATTRIBUTE((warn_unused_result));
311 /** Checks if a table is referenced by foreign keys.
312  @return true if table is referenced by a foreign key */
313 ibool dict_table_is_referenced_by_foreign_key(
314     const dict_table_t *table) /*!< in: InnoDB table */
315     MY_ATTRIBUTE((warn_unused_result));
316 /** Replace the index passed in with another equivalent index in the
317  foreign key lists of the table.
318  @return whether all replacements were found */
319 bool dict_foreign_replace_index(
320     dict_table_t *table, /*!< in/out: table */
321     const char **col_names,
322     /*!< in: column names, or NULL
323     to use table->col_names */
324     const dict_index_t *index) /*!< in: index to be replaced */
325     MY_ATTRIBUTE((warn_unused_result));
326 #endif /* !UNIV_HOTBACKUP */
327 /** Returns a table object and increments its open handle count.
328  NOTE! This is a high-level function to be used mainly from outside the
329  'dict' directory. Inside this directory dict_table_get_low
330  is usually the appropriate function.
331  @param[in] table_name Table name
332  @param[in] dict_locked TRUE=data dictionary locked
333  @param[in] try_drop TRUE=try to drop any orphan indexes after
334                                  an aborted online index creation
335  @param[in] ignore_err error to be ignored when loading the table
336  @return table, NULL if does not exist */
337 dict_table_t *dict_table_open_on_name(const char *table_name, ibool dict_locked,
338                                       ibool try_drop,
339                                       dict_err_ignore_t ignore_err)
340     MY_ATTRIBUTE((warn_unused_result));
341 
342 /** Tries to find an index whose first fields are the columns in the array,
343  in the same order and is not marked for deletion and is not the same
344  as types_idx.
345  @return matching index, NULL if not found */
346 dict_index_t *dict_foreign_find_index(
347     const dict_table_t *table, /*!< in: table */
348     const char **col_names,
349     /*!< in: column names, or NULL
350     to use table->col_names */
351     const char **columns, /*!< in: array of column names */
352     ulint n_cols,         /*!< in: number of columns */
353     const dict_index_t *types_idx,
354     /*!< in: NULL or an index
355     whose types the column types
356     must match */
357     bool check_charsets,
358     /*!< in: whether to check
359     charsets.  only has an effect
360     if types_idx != NULL */
361     ulint check_null)
362     /*!< in: nonzero if none of
363     the columns must be declared
364     NOT NULL */
365     MY_ATTRIBUTE((warn_unused_result));
366 
367 /** Returns a virtual column's name.
368 @param[in]	table		table object
369 @param[in]	col_nr		virtual column number(nth virtual column)
370 @return column name. */
371 const char *dict_table_get_v_col_name(const dict_table_t *table, ulint col_nr);
372 
373 /** Check if the table has a given column.
374 @param[in]	table		table object
375 @param[in]	col_name	column name
376 @param[in]	col_nr		column number guessed, 0 as default
377 @return column number if the table has the specified column,
378 otherwise table->n_def */
379 ulint dict_table_has_column(const dict_table_t *table, const char *col_name,
380                             ulint col_nr = 0);
381 
382 /** Outputs info on a foreign key of a table in a format suitable for
383  CREATE TABLE. */
384 void dict_print_info_on_foreign_key_in_create_format(
385     FILE *file,              /*!< in: file where to print */
386     trx_t *trx,              /*!< in: transaction */
387     dict_foreign_t *foreign, /*!< in: foreign key constraint */
388     ibool add_newline);      /*!< in: whether to add a newline */
389 /** Tries to find an index whose first fields are the columns in the array,
390  in the same order and is not marked for deletion and is not the same
391  as types_idx.
392  @return matching index, NULL if not found */
393 bool dict_foreign_qualify_index(
394     const dict_table_t *table, /*!< in: table */
395     const char **col_names,
396     /*!< in: column names, or NULL
397     to use table->col_names */
398     const char **columns,      /*!< in: array of column names */
399     ulint n_cols,              /*!< in: number of columns */
400     const dict_index_t *index, /*!< in: index to check */
401     const dict_index_t *types_idx,
402     /*!< in: NULL or an index
403     whose types the column types
404     must match */
405     bool check_charsets,
406     /*!< in: whether to check
407     charsets.  only has an effect
408     if types_idx != NULL */
409     ulint check_null)
410     /*!< in: nonzero if none of
411     the columns must be declared
412     NOT NULL */
413     MY_ATTRIBUTE((warn_unused_result));
414 
415 /* Skip corrupted index */
416 #define dict_table_skip_corrupt_index(index) \
417   while (index && index->is_corrupted()) {   \
418     index = index->next();                   \
419   }
420 
421 /* Get the next non-corrupt index */
422 #define dict_table_next_uncorrupted_index(index) \
423   do {                                           \
424     index = index->next();                       \
425     dict_table_skip_corrupt_index(index);        \
426   } while (0)
427 
428 /** Check if index is auto-generated clustered index.
429 @param[in]	index	index
430 
431 @return true if index is auto-generated clustered index. */
432 UNIV_INLINE
433 bool dict_index_is_auto_gen_clust(const dict_index_t *index);
434 
435 /** Check whether the index is unique.
436  @return nonzero for unique index, zero for other indexes */
437 UNIV_INLINE
438 ulint dict_index_is_unique(const dict_index_t *index) /*!< in: index */
439     MY_ATTRIBUTE((warn_unused_result));
440 /** Check whether the index is a Spatial Index.
441  @return	nonzero for Spatial Index, zero for other indexes */
442 UNIV_INLINE
443 ulint dict_index_is_spatial(const dict_index_t *index) /*!< in: index */
444     MY_ATTRIBUTE((warn_unused_result));
445 /** Check whether the index contains a virtual column.
446 @param[in]	index	index
447 @return	nonzero for index on virtual column, zero for other indexes */
448 UNIV_INLINE
449 ulint dict_index_has_virtual(const dict_index_t *index);
450 /** Check whether the index is the insert buffer tree.
451  @return nonzero for insert buffer, zero for other indexes */
452 UNIV_INLINE
453 ulint dict_index_is_ibuf(const dict_index_t *index) /*!< in: index */
454     MY_ATTRIBUTE((warn_unused_result));
455 
456 /** Check whether the index consists of descending columns only.
457 @param[in]	index  index tree
458 @retval true if index has any descending column
459 @retval false if index has only ascending columns */
460 UNIV_INLINE
461 bool dict_index_has_desc(const dict_index_t *index)
462     MY_ATTRIBUTE((warn_unused_result));
463 /** Check whether the index is a secondary index or the insert buffer tree.
464  @return nonzero for insert buffer, zero for other indexes */
465 UNIV_INLINE
466 ulint dict_index_is_sec_or_ibuf(const dict_index_t *index) /*!< in: index */
467     MY_ATTRIBUTE((warn_unused_result));
468 
469 /** Get all the FTS indexes on a table.
470 @param[in]	table	table
471 @param[out]	indexes	all FTS indexes on this table
472 @return number of FTS indexes */
473 ulint dict_table_get_all_fts_indexes(dict_table_t *table, ib_vector_t *indexes);
474 
475 UNIV_INLINE
476 ulint dict_table_get_n_tot_u_cols(const dict_table_t *table);
477 
478 /** Gets the number of virtual columns in a table in the dictionary cache.
479 @param[in]	table	the table to check
480 @return number of virtual columns of a table */
481 UNIV_INLINE
482 ulint dict_table_get_n_v_cols(const dict_table_t *table);
483 
484 /** Check if a table has indexed virtual columns
485 @param[in]	table	the table to check
486 @return true is the table has indexed virtual columns */
487 UNIV_INLINE
488 bool dict_table_has_indexed_v_cols(const dict_table_t *table);
489 
490 /** Gets the approximately estimated number of rows in the table.
491  @return estimated number of rows */
492 UNIV_INLINE
493 ib_uint64_t dict_table_get_n_rows(const dict_table_t *table) /*!< in: table */
494     MY_ATTRIBUTE((warn_unused_result));
495 /** Increment the number of rows in the table by one.
496  Notice that this operation is not protected by any latch, the number is
497  approximate. */
498 UNIV_INLINE
499 void dict_table_n_rows_inc(dict_table_t *table); /*!< in/out: table */
500 /** Decrement the number of rows in the table by one.
501  Notice that this operation is not protected by any latch, the number is
502  approximate. */
503 UNIV_INLINE
504 void dict_table_n_rows_dec(dict_table_t *table); /*!< in/out: table */
505 
506 /** Get nth virtual column
507 @param[in]	table	target table
508 @param[in]	col_nr	column number in MySQL Table definition
509 @return dict_v_col_t ptr */
510 dict_v_col_t *dict_table_get_nth_v_col_mysql(const dict_table_t *table,
511                                              ulint col_nr);
512 
513 #ifdef UNIV_DEBUG
514 /** Gets the nth virtual column of a table.
515 @param[in]	table	table
516 @param[in]	pos	position of virtual column
517 @return pointer to virtual column object */
518 UNIV_INLINE
519 dict_v_col_t *dict_table_get_nth_v_col(const dict_table_t *table, ulint pos);
520 
521 #else /* UNIV_DEBUG */
522 /* Get nth virtual columns */
523 #define dict_table_get_nth_v_col(table, pos) ((table)->v_cols + (pos))
524 #endif /* UNIV_DEBUG */
525 /** Gets the given system column number of a table.
526  @return column number */
527 UNIV_INLINE
528 ulint dict_table_get_sys_col_no(const dict_table_t *table, /*!< in: table */
529                                 ulint sys) /*!< in: DATA_ROW_ID, ... */
530     MY_ATTRIBUTE((warn_unused_result));
531 /** Check whether the table uses the compact page format.
532  @return true if table uses the compact page format */
533 UNIV_INLINE
534 ibool dict_table_is_comp(const dict_table_t *table) /*!< in: table */
535     MY_ATTRIBUTE((warn_unused_result));
536 
537 /** Determine if a table uses atomic BLOBs (no locally stored prefix).
538 @param[in]	table	InnoDB table
539 @return whether BLOBs are atomic */
540 UNIV_INLINE
541 bool dict_table_has_atomic_blobs(const dict_table_t *table)
542     MY_ATTRIBUTE((warn_unused_result));
543 
544 #ifndef UNIV_HOTBACKUP
545 /** Set the various values in a dict_table_t::flags pointer.
546 @param[in,out]	flags		Pointer to a 4 byte Table Flags
547 @param[in]	format		File Format
548 @param[in]	zip_ssize	Zip Shift Size
549 @param[in]	use_data_dir	Table uses DATA DIRECTORY
550 @param[in]	shared_space	Table uses a General Shared Tablespace */
551 UNIV_INLINE
552 void dict_tf_set(uint32_t *flags, rec_format_t format, uint32_t zip_ssize,
553                  bool use_data_dir, bool shared_space);
554 
555 /** Initialize a dict_table_t::flags pointer.
556 @param[in]	compact		Table uses Compact or greater
557 @param[in]	zip_ssize	Zip Shift Size (log 2 minus 9)
558 @param[in]	atomic_blobs	Table uses Compressed or Dynamic
559 @param[in]	data_dir	Table uses DATA DIRECTORY
560 @param[in]	shared_space	Table uses a General Shared Tablespace */
561 UNIV_INLINE
562 uint32_t dict_tf_init(bool compact, ulint zip_ssize, bool atomic_blobs,
563                       bool data_dir, bool shared_space);
564 
565 /** Convert a 32 bit integer table flags to the 32 bit FSP Flags.
566 Fsp Flags are written into the tablespace header at the offset
567 FSP_SPACE_FLAGS and are also stored in the fil_space_t::flags field.
568 The following chart shows the translation of the low order bit.
569 Other bits are the same.
570 ========================= Low order bit ==========================
571                     | REDUNDANT | COMPACT | COMPRESSED | DYNAMIC
572 dict_table_t::flags |     0     |    1    |     1      |    1
573 fil_space_t::flags  |     0     |    0    |     1      |    1
574 ==================================================================
575 @param[in]	table_flags	dict_table_t::flags
576 @return tablespace flags (fil_space_t::flags) */
577 uint32_t dict_tf_to_fsp_flags(uint32_t table_flags);
578 
579 /** Extract the page size from table flags.
580 @param[in]	flags	flags
581 @return compressed page size, or 0 if not compressed */
582 UNIV_INLINE
583 const page_size_t dict_tf_get_page_size(uint32_t flags);
584 #endif /* !UNIV_HOTBACKUP */
585 
586 /** Determine the extent size (in pages) for the given table
587 @param[in]	table	the table whose extent size is being
588                         calculated.
589 @return extent size in pages (256, 128 or 64) */
590 page_no_t dict_table_extent_size(const dict_table_t *table);
591 
592 /** Get the table page size.
593 @param[in]	table	table
594 @return compressed page size, or 0 if not compressed */
595 UNIV_INLINE
596 const page_size_t dict_table_page_size(const dict_table_t *table)
597     MY_ATTRIBUTE((warn_unused_result));
598 
599 #ifndef UNIV_HOTBACKUP
600 /** Obtain exclusive locks on all index trees of the table. This is to prevent
601  accessing index trees while InnoDB is updating internal metadata for
602  operations such as FLUSH TABLES. */
603 UNIV_INLINE
604 void dict_table_x_lock_indexes(dict_table_t *table); /*!< in: table */
605 /** Release the exclusive locks on all index tree. */
606 UNIV_INLINE
607 void dict_table_x_unlock_indexes(dict_table_t *table); /*!< in: table */
608 #endif                                                 /* !UNIV_HOTBACKUP */
609 /** Checks if a column is in the ordering columns of the clustered index of a
610  table. Column prefixes are treated like whole columns.
611  @return true if the column, or its prefix, is in the clustered key */
612 ibool dict_table_col_in_clustered_key(
613     const dict_table_t *table, /*!< in: table */
614     ulint n)                   /*!< in: column number */
615     MY_ATTRIBUTE((warn_unused_result));
616 /** Check if the table has an FTS index.
617  @return true if table has an FTS index */
618 UNIV_INLINE
619 ibool dict_table_has_fts_index(dict_table_t *table) /*!< in: table */
620     MY_ATTRIBUTE((warn_unused_result));
621 /** Copies types of virtual columns contained in table to tuple and sets all
622 fields of the tuple to the SQL NULL value.  This function should
623 be called right after dtuple_create().
624 @param[in,out]	tuple	data tuple
625 @param[in]	table	table */
626 void dict_table_copy_v_types(dtuple_t *tuple, const dict_table_t *table);
627 /** Copies types of columns contained in table to tuple and sets all
628  fields of the tuple to the SQL NULL value.  This function should
629  be called right after dtuple_create(). */
630 void dict_table_copy_types(dtuple_t *tuple, /*!< in/out: data tuple */
631                            const dict_table_t *table); /*!< in: table */
632 #ifndef UNIV_HOTBACKUP
633 /********************************************************************
634 Wait until all the background threads of the given table have exited, i.e.,
635 bg_threads == 0. Note: bg_threads_mutex must be reserved when
636 calling this. */
637 void dict_table_wait_for_bg_threads_to_exit(
638     dict_table_t *table, /* in: table */
639     ulint delay);        /* in: time in microseconds to wait between
640                          checks of bg_threads. */
641 /** Look up an index.
642 @param[in]	id	index identifier
643 @return index or NULL if not found */
644 const dict_index_t *dict_index_find(const index_id_t &id)
645     MY_ATTRIBUTE((warn_unused_result));
646 /** Make room in the table cache by evicting an unused table. The unused table
647  should not be part of FK relationship and currently not used in any user
648  transaction. There is no guarantee that it will remove a table.
649  @return number of tables evicted. */
650 ulint dict_make_room_in_cache(
651     ulint max_tables, /*!< in: max tables allowed in cache */
652     ulint pct_check); /*!< in: max percent to check */
653 
654 #define BIG_ROW_SIZE 1024
655 
656 /** Adds an index to the dictionary cache.
657 @param[in]	table	table on which the index is
658 @param[in]	index	index; NOTE! The index memory
659                         object is freed in this function!
660 @param[in]	page_no	root page number of the index
661 @param[in]	strict	TRUE=refuse to create the index
662                         if records could be too big to fit in
663                         an B-tree page
664 @return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */
665 dberr_t dict_index_add_to_cache(
666     dict_table_t *table, /*!< in: table on which the index is */
667     dict_index_t *index, /*!< in, own: index; NOTE! The index memory
668                          object is freed in this function! */
669     page_no_t page_no,   /*!< in: root page number of the index */
670     ibool strict)        /*!< in: TRUE=refuse to create the index
671                          if records could be too big to fit in
672                          an B-tree page */
673     MY_ATTRIBUTE((warn_unused_result));
674 
675 /** Clears the virtual column's index list before index is being freed.
676 @param[in]  index   Index being freed */
677 void dict_index_remove_from_v_col_list(dict_index_t *index);
678 
679 /** Adds an index to the dictionary cache, with possible indexing newly
680 added column.
681 @param[in]	table	table on which the index is
682 @param[in]	index	index; NOTE! The index memory
683                         object is freed in this function!
684 @param[in]	add_v	new virtual column that being added along with
685                         an add index call
686 @param[in]	page_no	root page number of the index
687 @param[in]	strict	TRUE=refuse to create the index
688                         if records could be too big to fit in
689                         an B-tree page
690 @return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */
691 dberr_t dict_index_add_to_cache_w_vcol(dict_table_t *table, dict_index_t *index,
692                                        const dict_add_v_col_t *add_v,
693                                        page_no_t page_no, ibool strict)
694     MY_ATTRIBUTE((warn_unused_result));
695 #endif /* !UNIV_HOTBACKUP */
696 /** Gets the number of fields in the internal representation of an index,
697  including fields added by the dictionary system.
698  @return number of fields */
699 UNIV_INLINE
700 ulint dict_index_get_n_fields(
701     const dict_index_t *index) /*!< in: an internal
702                                representation of index (in
703                                the dictionary cache) */
704     MY_ATTRIBUTE((warn_unused_result));
705 /** Gets the number of fields in the internal representation of an index
706  that uniquely determine the position of an index entry in the index, if
707  we do not take multiversioning into account: in the B-tree use the value
708  returned by dict_index_get_n_unique_in_tree.
709  @return number of fields */
710 UNIV_INLINE
711 ulint dict_index_get_n_unique(
712     const dict_index_t *index) /*!< in: an internal representation
713                                of index (in the dictionary cache) */
714     MY_ATTRIBUTE((warn_unused_result));
715 /** Gets the number of fields in the internal representation of an index
716  which uniquely determine the position of an index entry in the index, if
717  we also take multiversioning into account.
718  @return number of fields */
719 UNIV_INLINE
720 ulint dict_index_get_n_unique_in_tree(
721     const dict_index_t *index) /*!< in: an internal representation
722                                of index (in the dictionary cache) */
723     MY_ATTRIBUTE((warn_unused_result));
724 
725 /** The number of fields in the nonleaf page of spatial index, except
726 the page no field. */
727 #define DICT_INDEX_SPATIAL_NODEPTR_SIZE 1
728 /**
729 Gets the number of fields on nonleaf page level in the internal representation
730 of an index which uniquely determine the position of an index entry in the
731 index, if we also take multiversioning into account. Note, it doesn't
732 include page no field.
733 @param[in]	index	index
734 @return number of fields */
735 UNIV_INLINE
736 uint16_t dict_index_get_n_unique_in_tree_nonleaf(const dict_index_t *index)
737     MY_ATTRIBUTE((warn_unused_result));
738 /** Gets the number of user-defined ordering fields in the index. In the
739  internal representation we add the row id to the ordering fields to make all
740  indexes unique, but this function returns the number of fields the user defined
741  in the index as ordering fields.
742  @return number of fields */
743 UNIV_INLINE
744 ulint dict_index_get_n_ordering_defined_by_user(
745     const dict_index_t *index) /*!< in: an internal representation
746                                of index (in the dictionary cache) */
747     MY_ATTRIBUTE((warn_unused_result));
748 /** Returns TRUE if the index contains a column or a prefix of that column.
749  @return true if contains the column or its prefix */
750 ibool dict_index_contains_col_or_prefix(
751     const dict_index_t *index, /*!< in: index */
752     ulint n,                   /*!< in: column number */
753     bool is_virtual)
754     /*!< in: whether it is a virtual col */
755     MY_ATTRIBUTE((warn_unused_result));
756 /** Looks for a matching field in an index. The column has to be the same. The
757  column in index must be complete, or must contain a prefix longer than the
758  column in index2. That is, we must be able to construct the prefix in index2
759  from the prefix in index.
760  @return position in internal representation of the index;
761  ULINT_UNDEFINED if not contained */
762 ulint dict_index_get_nth_field_pos(
763     const dict_index_t *index,  /*!< in: index from which to search */
764     const dict_index_t *index2, /*!< in: index */
765     ulint n)                    /*!< in: field number in index2 */
766     MY_ATTRIBUTE((warn_unused_result));
767 /** Looks for non-virtual column n position in the clustered index.
768  @return position in internal representation of the clustered index */
769 ulint dict_table_get_nth_col_pos(const dict_table_t *table, /*!< in: table */
770                                  ulint n) /*!< in: column number */
771     MY_ATTRIBUTE((warn_unused_result));
772 
773 /** Get the innodb column position for a non-virtual column according to
774 its original MySQL table position n
775 @param[in]	table	table
776 @param[in]	n	MySQL column position
777 @return column position in InnoDB */
778 ulint dict_table_mysql_pos_to_innodb(const dict_table_t *table, ulint n);
779 
780 /** Copies types of fields contained in index to tuple. */
781 void dict_index_copy_types(dtuple_t *tuple,           /*!< in/out: data tuple */
782                            const dict_index_t *index, /*!< in: index */
783                            ulint n_fields);           /*!< in: number of
784                                                       field types to copy */
785 #ifdef UNIV_DEBUG
786 /** Checks that a tuple has n_fields_cmp value in a sensible range, so that
787  no comparison can occur with the page number field in a node pointer.
788  @return true if ok */
789 ibool dict_index_check_search_tuple(
790     const dict_index_t *index, /*!< in: index tree */
791     const dtuple_t *tuple)     /*!< in: tuple used in a search */
792     MY_ATTRIBUTE((warn_unused_result));
793 /** Whether and when to allow temporary index names */
794 enum check_name {
795   /** Require all indexes to be complete. */
796   CHECK_ALL_COMPLETE,
797   /** Allow aborted online index creation. */
798   CHECK_ABORTED_OK,
799   /** Allow partial indexes to exist. */
800   CHECK_PARTIAL_OK
801 };
802 /** Check for duplicate index entries in a table [using the index name] */
803 void dict_table_check_for_dup_indexes(
804     const dict_table_t *table, /*!< in: Check for dup indexes
805                                in this table */
806     enum check_name check);    /*!< in: whether and when to allow
807                                temporary index names */
808 /** Check if a table is a temporary table with compressed row format,
809 we should always expect false.
810 @param[in]	table	table
811 @return true if it's a compressed temporary table, false otherwise */
812 inline bool dict_table_is_compressed_temporary(const dict_table_t *table);
813 #endif /* UNIV_DEBUG */
814 /** Builds a node pointer out of a physical record and a page number.
815  @return own: node pointer */
816 dtuple_t *dict_index_build_node_ptr(const dict_index_t *index, /*!< in: index */
817                                     const rec_t *rec,  /*!< in: record for which
818                                                        to build node  pointer */
819                                     page_no_t page_no, /*!< in: page number to
820                                                        put in node pointer */
821                                     mem_heap_t *heap, /*!< in: memory heap where
822                                                       pointer created */
823                                     ulint level) /*!< in: level of rec in tree:
824                                                  0 means leaf level */
825     MY_ATTRIBUTE((warn_unused_result));
826 /** Copies an initial segment of a physical record, long enough to specify an
827  index entry uniquely.
828  @return pointer to the prefix record */
829 rec_t *dict_index_copy_rec_order_prefix(
830     const dict_index_t *index, /*!< in: index */
831     const rec_t *rec,          /*!< in: record for which to
832                                copy prefix */
833     ulint *n_fields,           /*!< out: number of fields copied */
834     byte **buf,                /*!< in/out: memory buffer for the
835                                copied prefix, or NULL */
836     size_t *buf_size)          /*!< in/out: buffer size */
837     MY_ATTRIBUTE((warn_unused_result));
838 /** Builds a typed data tuple out of a physical record.
839  @return own: data tuple */
840 dtuple_t *dict_index_build_data_tuple(
841     dict_index_t *index, /*!< in: index */
842     rec_t *rec,          /*!< in: record for which to build data tuple */
843     ulint n_fields,      /*!< in: number of data fields */
844     mem_heap_t *heap)    /*!< in: memory heap where tuple created */
845     MY_ATTRIBUTE((warn_unused_result));
846 /** Gets the space id of the root of the index tree.
847  @return space id */
848 UNIV_INLINE
849 space_id_t dict_index_get_space(const dict_index_t *index) /*!< in: index */
850     MY_ATTRIBUTE((warn_unused_result));
851 
852 /** Sets the space id of the root of the index tree.
853 @param[in,out]	index	index
854 @param[in]	space	space id */
855 UNIV_INLINE
856 void dict_index_set_space(dict_index_t *index, space_id_t space);
857 
858 /** Gets the page number of the root of the index tree.
859  @return page number */
860 UNIV_INLINE
861 page_no_t dict_index_get_page(const dict_index_t *tree) /*!< in: index */
862     MY_ATTRIBUTE((warn_unused_result));
863 /** Gets the read-write lock of the index tree.
864  @return read-write lock */
865 UNIV_INLINE
866 rw_lock_t *dict_index_get_lock(dict_index_t *index) /*!< in: index */
867     MY_ATTRIBUTE((warn_unused_result));
868 /** Returns free space reserved for future updates of records. This is
869  relevant only in the case of many consecutive inserts, as updates
870  which make the records bigger might fragment the index.
871  @return number of free bytes on page, reserved for updates */
872 UNIV_INLINE
873 ulint dict_index_get_space_reserve(void);
874 
875 /* Online index creation @{ */
876 /** Gets the status of online index creation.
877  @return the status */
878 UNIV_INLINE
879 enum online_index_status dict_index_get_online_status(
880     const dict_index_t *index) /*!< in: secondary index */
881     MY_ATTRIBUTE((warn_unused_result));
882 
883 /** Sets the status of online index creation.
884 @param[in,out]	index	index
885 @param[in]	status	status */
886 UNIV_INLINE
887 void dict_index_set_online_status(dict_index_t *index,
888                                   enum online_index_status status);
889 
890 /** Determines if a secondary index is being or has been created online,
891  or if the table is being rebuilt online, allowing concurrent modifications
892  to the table.
893  @retval true if the index is being or has been built online, or
894  if this is a clustered index and the table is being or has been rebuilt online
895  @retval false if the index has been created or the table has been
896  rebuilt completely */
897 UNIV_INLINE
898 bool dict_index_is_online_ddl(const dict_index_t *index) /*!< in: index */
899     MY_ATTRIBUTE((warn_unused_result));
900 /** Calculates the minimum record length in an index. */
901 ulint dict_index_calc_min_rec_len(const dict_index_t *index) /*!< in: index */
902     MY_ATTRIBUTE((warn_unused_result));
903 /** Reserves the dictionary system mutex for MySQL. */
904 void dict_mutex_enter_for_mysql(void);
905 /** Releases the dictionary system mutex for MySQL. */
906 void dict_mutex_exit_for_mysql(void);
907 
908 #ifndef UNIV_HOTBACKUP
909 /** Create a dict_table_t's stats latch or delay for lazy creation.
910 This function is only called from either single threaded environment
911 or from a thread that has not shared the table object with other threads.
912 @param[in,out]	table	table whose stats latch to create
913 @param[in]	enabled	if false then the latch is disabled
914 and dict_table_stats_lock()/unlock() become noop on this table. */
915 void dict_table_stats_latch_create(dict_table_t *table, bool enabled);
916 
917 /** Destroy a dict_table_t's stats latch.
918 This function is only called from either single threaded environment
919 or from a thread that has not shared the table object with other threads.
920 @param[in,out]	table	table whose stats latch to destroy */
921 void dict_table_stats_latch_destroy(dict_table_t *table);
922 
923 /** Lock the appropriate latch to protect a given table's statistics.
924 @param[in]	table		table whose stats to lock
925 @param[in]	latch_mode	RW_S_LATCH or RW_X_LATCH */
926 void dict_table_stats_lock(dict_table_t *table, ulint latch_mode);
927 
928 /** Unlock the latch that has been locked by dict_table_stats_lock().
929 @param[in]	table		table whose stats to unlock
930 @param[in]	latch_mode	RW_S_LATCH or RW_X_LATCH */
931 void dict_table_stats_unlock(dict_table_t *table, ulint latch_mode);
932 
933 /** Checks if the database name in two table names is the same.
934  @return true if same db name */
935 ibool dict_tables_have_same_db(const char *name1, /*!< in: table name in the
936                                                   form dbname '/' tablename */
937                                const char *name2) /*!< in: table name in the
938                                                   form dbname '/' tablename */
939     MY_ATTRIBUTE((warn_unused_result));
940 /** Get an index by name.
941 @param[in]	table		the table where to look for the index
942 @param[in]	name		the index name to look for
943 @param[in]	committed	true=search for committed,
944 false=search for uncommitted
945 @return index, NULL if does not exist */
946 dict_index_t *dict_table_get_index_on_name(dict_table_t *table,
947                                            const char *name,
948                                            bool committed = true)
949     MY_ATTRIBUTE((warn_unused_result));
950 /** Get an index by name.
951 @param[in]	table		the table where to look for the index
952 @param[in]	name		the index name to look for
953 @param[in]	committed	true=search for committed,
954 false=search for uncommitted
955 @return index, NULL if does not exist */
956 inline const dict_index_t *dict_table_get_index_on_name(
957     const dict_table_t *table, const char *name, bool committed = true) {
958   return (dict_table_get_index_on_name(const_cast<dict_table_t *>(table), name,
959                                        committed));
960 }
961 
962 /***************************************************************
963 Check whether a column exists in an FTS index. */
964 UNIV_INLINE
965 ulint dict_table_is_fts_column(
966     /*!< out: ULINT_UNDEFINED if no match else
967     the offset within the vector */
968     ib_vector_t *indexes, /*!< in: vector containing only FTS indexes */
969     ulint col_no,         /*!< in: col number to search for */
970     bool is_virtual)      /*!< in: whether it is a virtual column */
971     MY_ATTRIBUTE((warn_unused_result));
972 /** Prevent table eviction by moving a table to the non-LRU list from the
973  LRU list if it is not already there. */
974 UNIV_INLINE
975 void dict_table_prevent_eviction(
976     dict_table_t *table); /*!< in: table to prevent eviction */
977 
978 /** Allow the table to be evicted by moving a table to the LRU list from
979 the non-LRU list if it is not already there.
980 @param[in]	table	InnoDB table object can be evicted */
981 UNIV_INLINE
982 void dict_table_allow_eviction(dict_table_t *table);
983 
984 /** Move this table to non-LRU list for DDL operations if it's
985 currently not there. This also prevents later opening table via DD objects,
986 when the table name in InnoDB doesn't match with DD object.
987 @param[in,out]	table	Table to put in non-LRU list */
988 UNIV_INLINE
989 void dict_table_ddl_acquire(dict_table_t *table);
990 
991 /** Move this table to LRU list after DDL operations if it was moved
992 to non-LRU list
993 @param[in,out]	table	Table to put in LRU list */
994 UNIV_INLINE
995 void dict_table_ddl_release(dict_table_t *table);
996 
997 /** Move a table to the non LRU end of the LRU list. */
998 void dict_table_move_from_lru_to_non_lru(
999     dict_table_t *table); /*!< in: table to move from LRU to non-LRU */
1000 
1001 /** Move a table to the LRU end from the non LRU list.
1002 @param[in]	table	InnoDB table object */
1003 void dict_table_move_from_non_lru_to_lru(dict_table_t *table);
1004 
1005 /** Move to the most recently used segment of the LRU list. */
1006 void dict_move_to_mru(dict_table_t *table); /*!< in: table to move to MRU */
1007 
1008 /** Maximum number of columns in a foreign key constraint. Please Note MySQL
1009 has a much lower limit on the number of columns allowed in a foreign key
1010 constraint */
1011 #define MAX_NUM_FK_COLUMNS 500
1012 
1013 /* Buffers for storing detailed information about the latest foreign key
1014 and unique key errors */
1015 extern FILE *dict_foreign_err_file;
1016 extern ib_mutex_t dict_foreign_err_mutex; /* mutex protecting the
1017                                           foreign key error messages */
1018 #endif                                    /* !UNIV_HOTBACKUP */
1019 
1020 /** the dictionary system */
1021 extern dict_sys_t *dict_sys;
1022 #ifndef UNIV_HOTBACKUP
1023 /** the data dictionary rw-latch protecting dict_sys */
1024 extern rw_lock_t *dict_operation_lock;
1025 
1026 /** Forward declaration */
1027 class DDTableBuffer;
1028 #endif /* !UNIV_HOTBACKUP */
1029 struct dict_persist_t;
1030 
1031 /** the dictionary persisting structure */
1032 extern dict_persist_t *dict_persist;
1033 
1034 /* Dictionary system struct */
1035 struct dict_sys_t {
1036 #ifndef UNIV_HOTBACKUP
1037   DictSysMutex mutex;          /*!< mutex protecting the data
1038                                dictionary; protects also the
1039                                disk-based dictionary system tables;
1040                                this mutex serializes CREATE TABLE
1041                                and DROP TABLE, as well as reading
1042                                the dictionary data for a table from
1043                                system tables */
1044 #endif                         /* !UNIV_HOTBACKUP */
1045   row_id_t row_id;             /*!< the next row id to assign;
1046                                NOTE that at a checkpoint this
1047                                must be written to the dict system
1048                                header and flushed to a file; in
1049                                recovery this must be derived from
1050                                the log records */
1051   hash_table_t *table_hash;    /*!< hash table of the tables, based
1052                                on name */
1053   hash_table_t *table_id_hash; /*!< hash table of the tables, based
1054                                on id */
1055   lint size;                   /*!< varying space in bytes occupied
1056                                by the data dictionary table and
1057                                index objects */
1058   /** Handler to sys_* tables, they're only for upgrade */
1059   dict_table_t *sys_tables;  /*!< SYS_TABLES table */
1060   dict_table_t *sys_columns; /*!< SYS_COLUMNS table */
1061   dict_table_t *sys_indexes; /*!< SYS_INDEXES table */
1062   dict_table_t *sys_fields;  /*!< SYS_FIELDS table */
1063   dict_table_t *sys_virtual; /*!< SYS_VIRTUAL table */
1064 
1065   /** Permanent handle to mysql.innodb_table_stats */
1066   dict_table_t *table_stats;
1067   /** Permanent handle to mysql.innodb_index_stats */
1068   dict_table_t *index_stats;
1069   /** Permanent handle to mysql.innodb_ddl_log */
1070   dict_table_t *ddl_log;
1071   /** Permanent handle to mysql.innodb_dynamic_metadata */
1072   dict_table_t *dynamic_metadata;
1073 
1074   UT_LIST_BASE_NODE_T(dict_table_t)
1075   table_LRU; /*!< List of tables that can be evicted
1076              from the cache */
1077   UT_LIST_BASE_NODE_T(dict_table_t)
1078   table_non_LRU; /*!< List of tables that can't be
1079                  evicted from the cache */
1080 
1081   /** Iterate each table.
1082   @tparam Functor visitor
1083   @param[in,out]  functor to be invoked on each table */
1084   template <typename Functor>
for_each_tabledict_sys_t1085   void for_each_table(Functor &functor) {
1086     mutex_enter(&mutex);
1087 
1088     hash_table_t *hash = table_id_hash;
1089 
1090     for (ulint i = 0; i < hash->n_cells; i++) {
1091       for (dict_table_t *table =
1092                static_cast<dict_table_t *>(HASH_GET_FIRST(hash, i));
1093            table;
1094            table = static_cast<dict_table_t *>(HASH_GET_NEXT(id_hash, table))) {
1095         functor(table);
1096       }
1097     }
1098 
1099     mutex_exit(&mutex);
1100   }
1101 
1102   /** Check if a tablespace id is a reserved one
1103   @param[in]	space	tablespace id to check
1104   @return true if a reserved tablespace id, otherwise false */
is_reserveddict_sys_t1105   static bool is_reserved(space_id_t space) {
1106     return (space >= dict_sys_t::s_reserved_space_id ||
1107             fsp_is_session_temporary(space));
1108   }
1109 
1110   /** Set of ids of DD tables */
1111   static std::set<dd::Object_id> s_dd_table_ids;
1112 
1113   /** Check if a table is hardcoded. it only includes the dd tables
1114   @param[in]	id	table ID
1115   @retval true	if the table is a persistent hard-coded table
1116                   (dict_table_t::is_temporary() will not hold)
1117   @retval false	if the table is not hard-coded
1118                   (it can be persistent or temporary) */
is_dd_table_iddict_sys_t1119   static bool is_dd_table_id(table_id_t id) {
1120     return (s_dd_table_ids.find(id) != s_dd_table_ids.end());
1121   }
1122 
1123   /** The first ID of the redo log pseudo-tablespace */
1124   static constexpr space_id_t s_log_space_first_id = 0xFFFFFFF0UL;
1125 
1126   /** Use maximum UINT value to indicate invalid space ID. */
1127   static constexpr space_id_t s_invalid_space_id = 0xFFFFFFFF;
1128 
1129   /** The data dictionary tablespace ID. */
1130   static constexpr space_id_t s_space_id = 0xFFFFFFFE;
1131 
1132   /** The innodb_temporary tablespace ID. */
1133   static constexpr space_id_t s_temp_space_id = 0xFFFFFFFD;
1134 
1135   /** The number of space IDs dedicated to each undo tablespace */
1136   static constexpr space_id_t undo_space_id_range = 512;
1137 
1138   /** The lowest undo tablespace ID. */
1139   static constexpr space_id_t s_min_undo_space_id =
1140       s_log_space_first_id - (FSP_MAX_UNDO_TABLESPACES * undo_space_id_range);
1141 
1142   /** The highest undo tablespace ID. */
1143   static constexpr space_id_t s_max_undo_space_id = s_log_space_first_id - 1;
1144 
1145   /** The first reserved tablespace ID */
1146   static constexpr space_id_t s_reserved_space_id = s_min_undo_space_id;
1147 
1148   /** Leave 1K space_ids and start space_ids for temporary
1149   general tablespaces (total 400K space_ids)*/
1150   static constexpr space_id_t s_max_temp_space_id = s_reserved_space_id - 1000;
1151 
1152   /** Lowest temporary general space id */
1153   static constexpr space_id_t s_min_temp_space_id =
1154       s_reserved_space_id - 1000 - 400000;
1155 
1156   /** The dd::Tablespace::id of the dictionary tablespace. */
1157   static constexpr dd::Object_id s_dd_space_id = 1;
1158 
1159   /** The dd::Tablespace::id of innodb_system. */
1160   static constexpr dd::Object_id s_dd_sys_space_id = 2;
1161 
1162   /** The dd::Tablespace::id of innodb_temporary. */
1163   static constexpr dd::Object_id s_dd_temp_space_id = 3;
1164 
1165   /** The name of the data dictionary tablespace. */
1166   static const char *s_dd_space_name;
1167 
1168   /** The file name of the data dictionary tablespace. */
1169   static const char *s_dd_space_file_name;
1170 
1171   /** The name of the hard-coded system tablespace. */
1172   static const char *s_sys_space_name;
1173 
1174   /** The name of the predefined temporary tablespace. */
1175   static const char *s_temp_space_name;
1176 
1177   /** The file name of the predefined temporary tablespace. */
1178   static const char *s_temp_space_file_name;
1179 
1180   /** The hard-coded tablespace name innodb_file_per_table. */
1181   static const char *s_file_per_table_name;
1182 
1183   /** These two undo tablespaces cannot be dropped. */
1184   static const char *s_default_undo_space_name_1;
1185   static const char *s_default_undo_space_name_2;
1186 
1187   /** The table ID of mysql.innodb_dynamic_metadata */
1188   static constexpr table_id_t s_dynamic_meta_table_id = 2;
1189 
1190   /** The clustered index ID of mysql.innodb_dynamic_metadata */
1191   static constexpr space_index_t s_dynamic_meta_index_id = 2;
1192 };
1193 
1194 /** Structure for persisting dynamic metadata of data dictionary */
1195 struct dict_persist_t {
1196   /** Mutex to protect data in this structure, also the
1197   dict_table_t::dirty_status and
1198   dict_table_t::in_dirty_dict_tables_list
1199   This mutex should be low-level one so that it can be used widely
1200   when necessary, so its level had to be above SYNC_LOG. However,
1201   after this mutex, persister may have to access B-tree and require
1202   tree latch, the latch level of this mutex then has to be right
1203   before the SYNC_INDEX_TREE. */
1204   ib_mutex_t mutex;
1205 
1206   /** List of tables whose dirty_status are marked as METADATA_DIRTY,
1207   or METADATA_BUFFERED. It's protected by the mutex */
1208   UT_LIST_BASE_NODE_T(dict_table_t)
1209   dirty_dict_tables;
1210 
1211   /** Number of the tables which are of status METADATA_DIRTY.
1212   It's protected by the mutex */
1213   std::atomic<uint32_t> num_dirty_tables;
1214 
1215 #ifndef UNIV_HOTBACKUP
1216   /** DDTableBuffer table for persistent dynamic metadata */
1217   DDTableBuffer *table_buffer;
1218 #endif /* !UNIV_HOTBACKUP */
1219 
1220   /** Collection of instances to persist dynamic metadata */
1221   Persisters *persisters;
1222 };
1223 
1224 #ifndef UNIV_HOTBACKUP
1225 /** dummy index for ROW_FORMAT=REDUNDANT supremum and infimum records */
1226 extern dict_index_t *dict_ind_redundant;
1227 
1228 /** Inits dict_ind_redundant. */
1229 void dict_ind_init(void);
1230 
1231 /** Converts a database and table name from filesystem encoding (e.g.
1232 "@code d@i1b/a@q1b@1Kc @endcode", same format as used in  dict_table_t::name)
1233 in two strings in UTF8 encoding (e.g. dцb and aюbØc). The output buffers must
1234 be at least MAX_DB_UTF8_LEN and MAX_TABLE_UTF8_LEN bytes.
1235 @param[in]	db_and_table	database and table names,
1236                                 e.g. "@code d@i1b/a@q1b@1Kc @endcode"
1237 @param[out]	db_utf8		database name, e.g. dцb
1238 @param[in]	db_utf8_size	dbname_utf8 size
1239 @param[out]	table_utf8	table name, e.g. aюbØc
1240 @param[in]	table_utf8_size	table_utf8 size */
1241 void dict_fs2utf8(const char *db_and_table, char *db_utf8, size_t db_utf8_size,
1242                   char *table_utf8, size_t table_utf8_size);
1243 
1244 /** Resize the hash tables besed on the current buffer pool size. */
1245 void dict_resize();
1246 
1247 /** Wrapper for the mysql.innodb_dynamic_metadata used to buffer the persistent
1248 dynamic metadata.
1249 This should be a table with only clustered index, no delete-marked records,
1250 no locking, no undo logging, no purge, no adaptive hash index.
1251 We should always use low level btr functions to access and modify the table.
1252 Accessing this table should be protected by dict_sys->mutex */
1253 class DDTableBuffer {
1254  public:
1255   /** Default constructor */
1256   DDTableBuffer();
1257 
1258   /** Destructor */
1259   ~DDTableBuffer();
1260 
1261   /** Replace the dynamic metadata for a specific table
1262   @param[in]	id		table id
1263   @param[in]	version		table dynamic metadata version
1264   @param[in]	metadata	the metadata we want to replace
1265   @param[in]	len		the metadata length
1266   @return DB_SUCCESS or error code */
1267   dberr_t replace(table_id_t id, uint64_t version, const byte *metadata,
1268                   size_t len);
1269 
1270   /** Remove the whole row for a specific table
1271   @param[in]	id	table id
1272   @return DB_SUCCESS or error code */
1273   dberr_t remove(table_id_t id);
1274 
1275   /** Truncate the table. We can call it after all the dynamic
1276   metadata has been written back to DD table */
1277   void truncate(void);
1278 
1279   /** Get the buffered metadata for a specific table, the caller
1280   has to delete the returned std::string object by UT_DELETE
1281   @param[in]	id	table id
1282   @param[out]	version	table dynamic metadata version
1283   @return the metadata saved in a string object, if nothing, the
1284   string would be of length 0 */
1285   std::string *get(table_id_t id, uint64 *version);
1286 
1287  private:
1288   /** Initialize m_index, the in-memory clustered index of the table
1289   and two tuples used in this class */
1290   void init();
1291 
1292   /** Open the mysql.innodb_dynamic_metadata when DD is not fully up */
1293   void open();
1294 
1295   /** Create the search and replace tuples */
1296   void create_tuples();
1297 
1298   /** Initialize the id field of tuple
1299   @param[out]	tuple	the tuple to be initialized
1300   @param[in]	id	table id */
1301   void init_tuple_with_id(dtuple_t *tuple, table_id_t id);
1302 
1303   /** Free the things initialized in init() */
1304   void close();
1305 
1306   /** Prepare for a update on METADATA field
1307   @param[in]	entry	clustered index entry to replace rec
1308   @param[in]	rec	clustered index record
1309   @return update vector of differing fields without system columns,
1310   or NULL if there isn't any different field */
1311   upd_t *update_set_metadata(const dtuple_t *entry, const rec_t *rec);
1312 
1313  private:
1314   /** The clustered index of this system table */
1315   dict_index_t *m_index;
1316 
1317   /** The heap used for dynamic allocations, which should always
1318   be freed before return */
1319   mem_heap_t *m_dynamic_heap;
1320 
1321   /** The heap used during replace() operation, which should always
1322   be freed before return */
1323   mem_heap_t *m_replace_heap;
1324 
1325   /** The heap used to create the search tuple and replace tuple */
1326   mem_heap_t *m_heap;
1327 
1328   /** The tuple used to search for specified table, it's protected
1329   by dict_persist->mutex */
1330   dtuple_t *m_search_tuple;
1331 
1332   /** The tuple used to replace for specified table, it's protected
1333   by dict_persist->mutex */
1334   dtuple_t *m_replace_tuple;
1335 
1336  private:
1337   /** Column number of mysql.innodb_dynamic_metadata.table_id */
1338   static constexpr unsigned TABLE_ID_COL_NO = 0;
1339 
1340   /** Column number of mysql.innodb_dynamic_metadata.version */
1341   static constexpr unsigned VERSION_COL_NO = 1;
1342 
1343   /** Column number of mysql.innodb_dynamic_metadata.metadata */
1344   static constexpr unsigned METADATA_COL_NO = 2;
1345 
1346   /** Number of user columns */
1347   static constexpr unsigned N_USER_COLS = METADATA_COL_NO + 1;
1348 
1349   /** Number of columns */
1350   static constexpr unsigned N_COLS = N_USER_COLS + DATA_N_SYS_COLS;
1351 
1352   /** Clustered index field number of
1353   mysql.innodb_dynamic_metadata.table_id */
1354   static constexpr unsigned TABLE_ID_FIELD_NO = TABLE_ID_COL_NO;
1355 
1356   /** Clustered index field number of
1357   mysql.innodb_dynamic_metadata.version */
1358   static constexpr unsigned VERSION_FIELD_NO = VERSION_COL_NO + 2;
1359 
1360   /** Clustered index field number of
1361   mysql.innodb_dynamic_metadata.metadata
1362   Plusing 2 here skips the DATA_TRX_ID and DATA_ROLL_PTR fields */
1363   static constexpr unsigned METADATA_FIELD_NO = METADATA_COL_NO + 2;
1364 
1365   /** Number of fields in the clustered index */
1366   static constexpr unsigned N_FIELDS = METADATA_FIELD_NO + 1;
1367 };
1368 
1369 /** Mark the dirty_status of a table as METADATA_DIRTY, and add it to the
1370 dirty_dict_tables list if necessary.
1371 @param[in,out]	table		table */
1372 void dict_table_mark_dirty(dict_table_t *table);
1373 #endif /* !UNIV_HOTBACKUP */
1374 
1375 /** Flags an index corrupted in the data dictionary cache only. This
1376 is used to mark a corrupted index when index's own dictionary
1377 is corrupted, and we would force to load such index for repair purpose.
1378 Besides, we have to write a redo log.
1379 We don't want to hold dict_sys->mutex here, so that we can set index as
1380 corrupted in some low-level functions. We would only set the flags from
1381 not corrupted to corrupted when server is running, so it should be safe
1382 to set it directly.
1383 @param[in,out]	index		index, must not be NULL */
1384 void dict_set_corrupted(dict_index_t *index) UNIV_COLD;
1385 
1386 #ifndef UNIV_HOTBACKUP
1387 /** Check if there is any latest persistent dynamic metadata recorded
1388 in DDTableBuffer table of the specific table. If so, read the metadata and
1389 update the table object accordingly
1390 @param[in]	table		table object */
1391 void dict_table_load_dynamic_metadata(dict_table_t *table);
1392 
1393 /** Check if any table has any dirty persistent data, if so
1394 write dirty persistent data of table to mysql.innodb_dynamic_metadata
1395 accordingly. */
1396 void dict_persist_to_dd_table_buffer();
1397 #endif /* !UNIV_HOTBACKUP */
1398 
1399 /** Apply the persistent dynamic metadata read from redo logs or
1400 DDTableBuffer to corresponding table during recovery.
1401 @param[in,out]	table		table
1402 @param[in]	metadata	structure of persistent metadata
1403 @return true if we do apply something to the in-memory table object,
1404 otherwise false */
1405 bool dict_table_apply_dynamic_metadata(dict_table_t *table,
1406                                        const PersistentTableMetadata *metadata);
1407 
1408 #ifndef UNIV_HOTBACKUP
1409 /** Sets merge_threshold in the SYS_INDEXES
1410 @param[in,out]	index		index
1411 @param[in]	merge_threshold	value to set */
1412 void dict_index_set_merge_threshold(dict_index_t *index, ulint merge_threshold);
1413 
1414 #ifdef UNIV_DEBUG
1415 /** Sets merge_threshold for all indexes in dictionary cache for debug.
1416 @param[in]	merge_threshold_all	value to set for all indexes */
1417 void dict_set_merge_threshold_all_debug(uint merge_threshold_all);
1418 #endif /* UNIV_DEBUG */
1419 
1420 /** Validate the table flags.
1421 @param[in]	flags	Table flags
1422 @return true if valid. */
1423 UNIV_INLINE
1424 bool dict_tf_is_valid(uint32_t flags);
1425 
1426 /** Validate both table flags and table flags2 and make sure they
1427 are compatible.
1428 @param[in]	flags	Table flags
1429 @param[in]	flags2	Table flags2
1430 @return true if valid. */
1431 UNIV_INLINE
1432 bool dict_tf2_is_valid(uint32_t flags, uint32_t flags2);
1433 
1434 /** Check if the tablespace for the table has been discarded.
1435  @return true if the tablespace has been discarded. */
1436 UNIV_INLINE
1437 bool dict_table_is_discarded(
1438     const dict_table_t *table) /*!< in: table to check */
1439     MY_ATTRIBUTE((warn_unused_result));
1440 
1441 /** Check whether the table is DDTableBuffer. See class DDTableBuffer
1442 @param[in]	table	table to check
1443 @return true if this is a DDTableBuffer table. */
1444 UNIV_INLINE
1445 bool dict_table_is_table_buffer(const dict_table_t *table);
1446 
1447 /** Check if the table is in a shared tablespace (System or General).
1448 @param[in]	table	table to check
1449 @return true if table is a shared tablespace, false if not. */
1450 UNIV_INLINE
1451 bool dict_table_in_shared_tablespace(const dict_table_t *table)
1452     MY_ATTRIBUTE((warn_unused_result));
1453 
1454 /** Check whether locking is disabled for this table.
1455 Currently this is done for intrinsic table as their visibility is limited
1456 to the connection and the DDTableBuffer as it's protected by
1457 dict_persist->mutex.
1458 
1459 @param[in]	table	table to check
1460 @return true if locking is disabled. */
1461 UNIV_INLINE
1462 bool dict_table_is_locking_disabled(const dict_table_t *table)
1463     MY_ATTRIBUTE((warn_unused_result));
1464 
1465 /** Turn-off redo-logging if temporary table.
1466 @param[in]	table	table to check
1467 @param[out]	mtr	mini-transaction */
1468 UNIV_INLINE
1469 void dict_disable_redo_if_temporary(const dict_table_t *table, mtr_t *mtr);
1470 
1471 /** Get table session row-id and increment the row-id counter for next use.
1472 @param[in,out]	table	table handler
1473 @return next table local row-id. */
1474 UNIV_INLINE
1475 row_id_t dict_table_get_next_table_sess_row_id(dict_table_t *table);
1476 
1477 /** Get table session trx-id and increment the trx-id counter for next use.
1478 @param[in,out]	table	table handler
1479 @return next table local trx-id. */
1480 UNIV_INLINE
1481 trx_id_t dict_table_get_next_table_sess_trx_id(dict_table_t *table);
1482 
1483 /** Get current session trx-id.
1484 @param[in]	table	table handler
1485 @return table local trx-id. */
1486 UNIV_INLINE
1487 trx_id_t dict_table_get_curr_table_sess_trx_id(const dict_table_t *table);
1488 
1489 /** This function should be called whenever a page is successfully
1490  compressed. Updates the compression padding information. */
1491 void dict_index_zip_success(
1492     dict_index_t *index); /*!< in/out: index to be updated. */
1493 /** This function should be called whenever a page compression attempt
1494  fails. Updates the compression padding information. */
1495 void dict_index_zip_failure(
1496     dict_index_t *index); /*!< in/out: index to be updated. */
1497 /** Return the optimal page size, for which page will likely compress.
1498  @return page size beyond which page may not compress*/
1499 ulint dict_index_zip_pad_optimal_page_size(
1500     dict_index_t *index) /*!< in: index for which page size
1501                          is requested */
1502     MY_ATTRIBUTE((warn_unused_result));
1503 /** Convert table flag to row format string.
1504  @return row format name */
1505 const char *dict_tf_to_row_format_string(
1506     uint32_t table_flag); /*!< in: row format setting */
1507 /** Return maximum size of the node pointer record.
1508  @return maximum size of the record in bytes */
1509 ulint dict_index_node_ptr_max_size(const dict_index_t *index) /*!< in: index */
1510     MY_ATTRIBUTE((warn_unused_result));
1511 
1512 /** Get index by first field of the index.
1513 @param[in]	table		table
1514 @param[in]	col_index	position of column in table
1515 @return index which is having first field matches with the field present in
1516 field_index position of table */
1517 UNIV_INLINE
1518 dict_index_t *dict_table_get_index_on_first_col(dict_table_t *table,
1519                                                 ulint col_index);
1520 #endif /* !UNIV_HOTBACKUP */
1521 
1522 /** encode number of columns and number of virtual columns in one
1523 4 bytes value. We could do this because the number of columns in
1524 InnoDB is limited to 1017
1525 @param[in]	n_col	number of non-virtual column
1526 @param[in]	n_v_col	number of virtual column
1527 @return encoded value */
1528 UNIV_INLINE
1529 ulint dict_table_encode_n_col(ulint n_col, ulint n_v_col);
1530 
1531 /** Decode number of virtual and non-virtual columns in one 4 bytes value.
1532 @param[in]	encoded	encoded value
1533 @param[in,out]	n_col	number of non-virtual column
1534 @param[in,out]	n_v_col	number of virtual column */
1535 UNIV_INLINE
1536 void dict_table_decode_n_col(uint32_t encoded, uint32_t *n_col,
1537                              uint32_t *n_v_col);
1538 
1539 /** Free the virtual column template
1540 @param[in,out]	vc_templ	virtual column template */
1541 UNIV_INLINE
1542 void dict_free_vc_templ(dict_vcol_templ_t *vc_templ);
1543 
1544 /** Returns a virtual column's name according to its original
1545 MySQL table position.
1546 @param[in]	table	target table
1547 @param[in]	col_nr	column number (nth column in the table)
1548 @return column name. */
1549 const char *dict_table_get_v_col_name_mysql(const dict_table_t *table,
1550                                             ulint col_nr);
1551 
1552 /** Check whether the table have virtual index.
1553 @param[in]	table	InnoDB table
1554 @return true if the table have virtual index, false otherwise. */
1555 UNIV_INLINE
1556 bool dict_table_have_virtual_index(dict_table_t *table);
1557 
1558 /** Retrieve in-memory index for SDI table.
1559 @param[in]	tablespace_id	innodb tablespace ID
1560 @return dict_index_t structure or NULL*/
1561 dict_index_t *dict_sdi_get_index(space_id_t tablespace_id);
1562 
1563 /** Retrieve in-memory table object for SDI table.
1564 @param[in]	tablespace_id	innodb tablespace ID
1565 @param[in]	dict_locked	true if dict_sys mutex is acquired
1566 @param[in]	is_create	true when creating SDI Index
1567 @return dict_table_t structure */
1568 dict_table_t *dict_sdi_get_table(space_id_t tablespace_id, bool dict_locked,
1569                                  bool is_create);
1570 
1571 /** Remove the SDI table from table cache.
1572 @param[in]	space_id	InnoDB tablespace ID
1573 @param[in]	sdi_table	SDI table
1574 @param[in]	dict_locked	true if dict_sys mutex acquired */
1575 void dict_sdi_remove_from_cache(space_id_t space_id, dict_table_t *sdi_table,
1576                                 bool dict_locked);
1577 
1578 /** Check if the index is SDI index
1579 @param[in]	index	in-memory index structure
1580 @return true if index is SDI index else false */
1581 UNIV_INLINE
1582 bool dict_index_is_sdi(const dict_index_t *index);
1583 
1584 /** Check if an table id belongs SDI table
1585 @param[in]	table_id	dict_table_t id
1586 @return true if table_id is SDI table_id else false */
1587 UNIV_INLINE
1588 bool dict_table_is_sdi(uint64_t table_id);
1589 
1590 /** Close SDI table.
1591 @param[in]	table		the in-meory SDI table object */
1592 void dict_sdi_close_table(dict_table_t *table);
1593 
1594 /** Acquire exclusive MDL on SDI tables. This is acquired to
1595 prevent concurrent DROP table/tablespace when there is purge
1596 happening on SDI table records. Purge will acquired shared
1597 MDL on SDI table.
1598 
1599 Exclusive MDL is transactional(released on trx commit). So
1600 for successful acquistion, there should be valid thd with
1601 trx associated.
1602 
1603 Acquistion order of SDI MDL and SDI table has to be in same
1604 order:
1605 
1606 1. dd_sdi_acquire_exclusive_mdl
1607 2. row_drop_table_from_cache()/innodb_drop_tablespace()
1608    ->dd_sdi_remove_from_cache()->dd_table_open_on_id()
1609 
1610 In purge:
1611 
1612 1. dd_sdi_acquire_shared_mdl
1613 2. dd_table_open_on_id()
1614 
1615 @param[in]	thd		server thread instance
1616 @param[in]	space_id	InnoDB tablespace id
1617 @param[in,out]	sdi_mdl		MDL ticket on SDI table
1618 @retval	DB_SUCESS		on success
1619 @retval	DB_LOCK_WAIT_TIMEOUT	on error */
1620 dberr_t dd_sdi_acquire_exclusive_mdl(THD *thd, space_id_t space_id,
1621                                      MDL_ticket **sdi_mdl);
1622 
1623 /** Acquire shared MDL on SDI tables. This is acquired by purge to
1624 prevent concurrent DROP table/tablespace.
1625 DROP table/tablespace will acquire exclusive MDL on SDI table
1626 
1627 Acquistion order of SDI MDL and SDI table has to be in same
1628 order:
1629 
1630 1. dd_sdi_acquire_exclusive_mdl
1631 2. row_drop_table_from_cache()/innodb_drop_tablespace()
1632    ->dict_sdi_remove_from_cache()->dd_table_open_on_id()
1633 
1634 In purge:
1635 
1636 1. dd_sdi_acquire_shared_mdl
1637 2. dd_table_open_on_id()
1638 
1639 MDL should be released by caller
1640 @param[in]	thd		server thread instance
1641 @param[in]	space_id	InnoDB tablespace id
1642 @param[in,out]	sdi_mdl		MDL ticket on SDI table
1643 @retval	DB_SUCESS		on success
1644 @retval	DB_LOCK_WAIT_TIMEOUT	on error */
1645 dberr_t dd_sdi_acquire_shared_mdl(THD *thd, space_id_t space_id,
1646                                   MDL_ticket **sdi_mdl);
1647 
1648 /** Check whether the dict_table_t is a partition.
1649 A partitioned table on the SQL level is composed of InnoDB tables,
1650 where each InnoDB table is a [sub]partition including its secondary indexes
1651 which belongs to the partition.
1652 @param[in]	table	Table to check.
1653 @return true if the dict_table_t is a partition else false. */
1654 UNIV_INLINE
1655 bool dict_table_is_partition(const dict_table_t *table);
1656 
1657 /** Allocate memory for intrinsic cache elements in the index
1658  * @param[in]      index   index object */
1659 UNIV_INLINE
1660 void dict_allocate_mem_intrinsic_cache(dict_index_t *index);
1661 
1662 /** Evict all tables that are loaded for applying purge.
1663 Since we move the offset of all table ids during upgrade,
1664 these tables cannot exist in cache. Also change table_ids
1665 of SYS_* tables if they are upgraded from earlier versions */
1666 void dict_upgrade_evict_tables_cache();
1667 
1668 /** @return true if table is InnoDB SYS_* table
1669 @param[in]	table_id	table id  */
1670 bool dict_table_is_system(table_id_t table_id);
1671 
1672 /** Build the table_id array of SYS_* tables. This
1673 array is used to determine if a table is InnoDB SYSTEM
1674 table or not.
1675 @return true if successful, false otherwise */
1676 bool dict_sys_table_id_build();
1677 
1678 /** Change the table_id of SYS_* tables if they have been created after
1679 an earlier upgrade. This will update the table_id by adding DICT_MAX_DD_TABLES
1680 */
1681 void dict_table_change_id_sys_tables();
1682 
1683 /** Get the tablespace data directory if set, otherwise empty string.
1684 @return the data directory */
1685 std::string dict_table_get_datadir(const dict_table_t *table)
1686     MY_ATTRIBUTE((warn_unused_result));
1687 
1688 #include "dict0dict.ic"
1689 
1690 #endif
1691