1/*****************************************************************************
2
3Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License, version 2.0,
7as published by the Free Software Foundation.
8
9This program is also distributed with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation.  The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have included with MySQL.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU General Public License, version 2.0, for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25*****************************************************************************/
26
27/******************************************************************//**
28@file include/dict0dict.ic
29Data dictionary system
30
31Created 1/8/1996 Heikki Tuuri
32***********************************************************************/
33
34#include "data0type.h"
35#ifndef UNIV_HOTBACKUP
36#include "dict0load.h"
37#include "rem0types.h"
38#include "fsp0fsp.h"
39#include "srv0srv.h"
40#include "sync0rw.h" /* RW_S_LATCH */
41
42/*********************************************************************//**
43Gets the minimum number of bytes per character.
44@return minimum multi-byte char size, in bytes */
45UNIV_INLINE
46ulint
47dict_col_get_mbminlen(
48/*==================*/
49	const dict_col_t*	col)	/*!< in: column */
50{
51	return(DATA_MBMINLEN(col->mbminmaxlen));
52}
53/*********************************************************************//**
54Gets the maximum number of bytes per character.
55@return maximum multi-byte char size, in bytes */
56UNIV_INLINE
57ulint
58dict_col_get_mbmaxlen(
59/*==================*/
60	const dict_col_t*	col)	/*!< in: column */
61{
62	return(DATA_MBMAXLEN(col->mbminmaxlen));
63}
64/*********************************************************************//**
65Sets the minimum and maximum number of bytes per character. */
66UNIV_INLINE
67void
68dict_col_set_mbminmaxlen(
69/*=====================*/
70	dict_col_t*	col,		/*!< in/out: column */
71	ulint		mbminlen,	/*!< in: minimum multi-byte
72					character size, in bytes */
73	ulint		mbmaxlen)	/*!< in: minimum multi-byte
74					character size, in bytes */
75{
76	ut_ad(mbminlen < DATA_MBMAX);
77	ut_ad(mbmaxlen < DATA_MBMAX);
78	ut_ad(mbminlen <= mbmaxlen);
79
80	col->mbminmaxlen = DATA_MBMINMAXLEN(mbminlen, mbmaxlen);
81}
82/*********************************************************************//**
83Gets the column data type. */
84UNIV_INLINE
85void
86dict_col_copy_type(
87/*===============*/
88	const dict_col_t*	col,	/*!< in: column */
89	dtype_t*		type)	/*!< out: data type */
90{
91	ut_ad(col != NULL);
92	ut_ad(type != NULL);
93
94	type->mtype = col->mtype;
95	type->prtype = col->prtype;
96	type->len = col->len;
97	type->mbminmaxlen = col->mbminmaxlen;
98}
99#endif /* !UNIV_HOTBACKUP */
100
101#ifdef UNIV_DEBUG
102/*********************************************************************//**
103Assert that a column and a data type match.
104@return	TRUE */
105UNIV_INLINE
106ibool
107dict_col_type_assert_equal(
108/*=======================*/
109	const dict_col_t*	col,	/*!< in: column */
110	const dtype_t*		type)	/*!< in: data type */
111{
112	ut_ad(col);
113	ut_ad(type);
114
115	ut_ad(col->mtype == type->mtype);
116	ut_ad(col->prtype == type->prtype);
117	//ut_ad(col->len == type->len);
118# ifndef UNIV_HOTBACKUP
119	ut_ad(col->mbminmaxlen == type->mbminmaxlen);
120# endif /* !UNIV_HOTBACKUP */
121
122	return(TRUE);
123}
124#endif /* UNIV_DEBUG */
125
126#ifndef UNIV_HOTBACKUP
127/***********************************************************************//**
128Returns the minimum size of the column.
129@return	minimum size */
130UNIV_INLINE
131ulint
132dict_col_get_min_size(
133/*==================*/
134	const dict_col_t*	col)	/*!< in: column */
135{
136	return(dtype_get_min_size_low(col->mtype, col->prtype, col->len,
137				      col->mbminmaxlen));
138}
139/***********************************************************************//**
140Returns the maximum size of the column.
141@return	maximum size */
142UNIV_INLINE
143ulint
144dict_col_get_max_size(
145/*==================*/
146	const dict_col_t*	col)	/*!< in: column */
147{
148	return(dtype_get_max_size_low(col->mtype, col->len));
149}
150#endif /* !UNIV_HOTBACKUP */
151/***********************************************************************//**
152Returns the size of a fixed size column, 0 if not a fixed size column.
153@return	fixed size, or 0 */
154UNIV_INLINE
155ulint
156dict_col_get_fixed_size(
157/*====================*/
158	const dict_col_t*	col,	/*!< in: column */
159	ulint			comp)	/*!< in: nonzero=ROW_FORMAT=COMPACT */
160{
161	return(dtype_get_fixed_size_low(col->mtype, col->prtype, col->len,
162					col->mbminmaxlen, comp));
163}
164/***********************************************************************//**
165Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column.
166For fixed length types it is the fixed length of the type, otherwise 0.
167@return	SQL null storage size in ROW_FORMAT=REDUNDANT */
168UNIV_INLINE
169ulint
170dict_col_get_sql_null_size(
171/*=======================*/
172	const dict_col_t*	col,	/*!< in: column */
173	ulint			comp)	/*!< in: nonzero=ROW_FORMAT=COMPACT  */
174{
175	return(dict_col_get_fixed_size(col, comp));
176}
177
178/*********************************************************************//**
179Gets the column number.
180@return	col->ind, table column position (starting from 0) */
181UNIV_INLINE
182ulint
183dict_col_get_no(
184/*============*/
185	const dict_col_t*	col)	/*!< in: column */
186{
187	ut_ad(col);
188
189	return(col->ind);
190}
191
192/*********************************************************************//**
193Gets the column position in the clustered index. */
194UNIV_INLINE
195ulint
196dict_col_get_clust_pos(
197/*===================*/
198	const dict_col_t*	col,		/*!< in: table column */
199	const dict_index_t*	clust_index)	/*!< in: clustered index */
200{
201	ulint	i;
202
203	ut_ad(col);
204	ut_ad(clust_index);
205	ut_ad(dict_index_is_clust(clust_index));
206
207	for (i = 0; i < clust_index->n_def; i++) {
208		const dict_field_t*	field = &clust_index->fields[i];
209
210		if (!field->prefix_len && field->col == col) {
211			return(i);
212		}
213	}
214
215	return(ULINT_UNDEFINED);
216}
217
218#ifndef UNIV_HOTBACKUP
219#ifdef UNIV_DEBUG
220/********************************************************************//**
221Gets the first index on the table (the clustered index).
222@return	index, NULL if none exists */
223UNIV_INLINE
224dict_index_t*
225dict_table_get_first_index(
226/*=======================*/
227	const dict_table_t*	table)	/*!< in: table */
228{
229	ut_ad(table);
230	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
231
232	return(UT_LIST_GET_FIRST(((dict_table_t*) table)->indexes));
233}
234
235/********************************************************************//**
236Gets the last index on the table.
237@return	index, NULL if none exists */
238UNIV_INLINE
239dict_index_t*
240dict_table_get_last_index(
241/*=======================*/
242	const dict_table_t*	table)	/*!< in: table */
243{
244	ut_ad(table);
245	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
246
247	return(UT_LIST_GET_LAST((const_cast<dict_table_t*>(table))
248				->indexes));
249}
250
251/********************************************************************//**
252Gets the next index on the table.
253@return	index, NULL if none left */
254UNIV_INLINE
255dict_index_t*
256dict_table_get_next_index(
257/*======================*/
258	const dict_index_t*	index)	/*!< in: index */
259{
260	ut_ad(index);
261	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
262
263	return(UT_LIST_GET_NEXT(indexes, (dict_index_t*) index));
264}
265#endif /* UNIV_DEBUG */
266#endif /* !UNIV_HOTBACKUP */
267
268/********************************************************************//**
269Check whether the index is the clustered index.
270@return	nonzero for clustered index, zero for other indexes */
271UNIV_INLINE
272ulint
273dict_index_is_clust(
274/*================*/
275	const dict_index_t*	index)	/*!< in: index */
276{
277	ut_ad(index);
278	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
279
280	return(index->type & DICT_CLUSTERED);
281}
282/********************************************************************//**
283Check whether the index is unique.
284@return	nonzero for unique index, zero for other indexes */
285UNIV_INLINE
286ulint
287dict_index_is_unique(
288/*=================*/
289	const dict_index_t*	index)	/*!< in: index */
290{
291	ut_ad(index);
292	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
293
294	return(index->type & DICT_UNIQUE);
295}
296
297/********************************************************************//**
298Check whether the index is the insert buffer tree.
299@return	nonzero for insert buffer, zero for other indexes */
300UNIV_INLINE
301ulint
302dict_index_is_ibuf(
303/*===============*/
304	const dict_index_t*	index)	/*!< in: index */
305{
306	ut_ad(index);
307	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
308
309	return(index->type & DICT_IBUF);
310}
311
312/********************************************************************//**
313Check whether the index is an universal index tree.
314@return	nonzero for universal tree, zero for other indexes */
315UNIV_INLINE
316ulint
317dict_index_is_univ(
318/*===============*/
319	const dict_index_t*	index)	/*!< in: index */
320{
321	ut_ad(index);
322	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
323
324	return(index->type & DICT_UNIVERSAL);
325}
326
327/********************************************************************//**
328Check whether the index is a secondary index or the insert buffer tree.
329@return	nonzero for insert buffer, zero for other indexes */
330UNIV_INLINE
331ulint
332dict_index_is_sec_or_ibuf(
333/*======================*/
334	const dict_index_t*	index)	/*!< in: index */
335{
336	ulint	type;
337
338	ut_ad(index);
339	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
340
341	type = index->type;
342
343	return(!(type & DICT_CLUSTERED) || (type & DICT_IBUF));
344}
345
346/********************************************************************//**
347Gets the number of user-defined columns in a table in the dictionary
348cache.
349@return	number of user-defined (e.g., not ROW_ID) columns of a table */
350UNIV_INLINE
351ulint
352dict_table_get_n_user_cols(
353/*=======================*/
354	const dict_table_t*	table)	/*!< in: table */
355{
356	ut_ad(table);
357	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
358
359	return(table->n_cols - DATA_N_SYS_COLS);
360}
361
362/********************************************************************//**
363Gets the number of system columns in a table in the dictionary cache.
364@return	number of system (e.g., ROW_ID) columns of a table */
365UNIV_INLINE
366ulint
367dict_table_get_n_sys_cols(
368/*======================*/
369	const dict_table_t*	table MY_ATTRIBUTE((unused)))	/*!< in: table */
370{
371	ut_ad(table);
372	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
373	ut_ad(table->cached);
374
375	return(DATA_N_SYS_COLS);
376}
377
378/********************************************************************//**
379Gets the number of all columns (also system) in a table in the dictionary
380cache.
381@return	number of columns of a table */
382UNIV_INLINE
383ulint
384dict_table_get_n_cols(
385/*==================*/
386	const dict_table_t*	table)	/*!< in: table */
387{
388	ut_ad(table);
389	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
390
391	return(table->n_cols);
392}
393
394/********************************************************************//**
395Gets the approximately estimated number of rows in the table.
396@return	estimated number of rows */
397UNIV_INLINE
398ib_uint64_t
399dict_table_get_n_rows(
400/*==================*/
401	const dict_table_t*	table)	/*!< in: table */
402{
403	ut_ad(table->stat_initialized);
404
405	return(table->stat_n_rows);
406}
407
408/********************************************************************//**
409Increment the number of rows in the table by one.
410Notice that this operation is not protected by any latch, the number is
411approximate. */
412UNIV_INLINE
413void
414dict_table_n_rows_inc(
415/*==================*/
416	dict_table_t*	table)	/*!< in/out: table */
417{
418	if (table->stat_initialized) {
419		ib_uint64_t	n_rows = table->stat_n_rows;
420		if (n_rows < 0xFFFFFFFFFFFFFFFFULL) {
421			table->stat_n_rows = n_rows + 1;
422		}
423	}
424}
425
426/********************************************************************//**
427Decrement the number of rows in the table by one.
428Notice that this operation is not protected by any latch, the number is
429approximate. */
430UNIV_INLINE
431void
432dict_table_n_rows_dec(
433/*==================*/
434	dict_table_t*	table)	/*!< in/out: table */
435{
436	if (table->stat_initialized) {
437		ib_uint64_t	n_rows = table->stat_n_rows;
438		if (n_rows > 0) {
439			table->stat_n_rows = n_rows - 1;
440		}
441	}
442}
443
444#ifdef UNIV_DEBUG
445/********************************************************************//**
446Gets the nth column of a table.
447@return	pointer to column object */
448UNIV_INLINE
449dict_col_t*
450dict_table_get_nth_col(
451/*===================*/
452	const dict_table_t*	table,	/*!< in: table */
453	ulint			pos)	/*!< in: position of column */
454{
455	ut_ad(table);
456	ut_ad(pos < table->n_def);
457	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
458
459	return((dict_col_t*) (table->cols) + pos);
460}
461
462/********************************************************************//**
463Gets the given system column of a table.
464@return	pointer to column object */
465UNIV_INLINE
466dict_col_t*
467dict_table_get_sys_col(
468/*===================*/
469	const dict_table_t*	table,	/*!< in: table */
470	ulint			sys)	/*!< in: DATA_ROW_ID, ... */
471{
472	dict_col_t*	col;
473
474	ut_ad(table);
475	ut_ad(sys < DATA_N_SYS_COLS);
476	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
477
478	col = dict_table_get_nth_col(table, table->n_cols
479				     - DATA_N_SYS_COLS + sys);
480	ut_ad(col->mtype == DATA_SYS);
481	ut_ad(col->prtype == (sys | DATA_NOT_NULL));
482
483	return(col);
484}
485#endif /* UNIV_DEBUG */
486
487/********************************************************************//**
488Gets the given system column number of a table.
489@return	column number */
490UNIV_INLINE
491ulint
492dict_table_get_sys_col_no(
493/*======================*/
494	const dict_table_t*	table,	/*!< in: table */
495	ulint			sys)	/*!< in: DATA_ROW_ID, ... */
496{
497	ut_ad(table);
498	ut_ad(sys < DATA_N_SYS_COLS);
499	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
500
501	return(table->n_cols - DATA_N_SYS_COLS + sys);
502}
503
504/********************************************************************//**
505Check whether the table uses the compact page format.
506@return	TRUE if table uses the compact page format */
507UNIV_INLINE
508ibool
509dict_table_is_comp(
510/*===============*/
511	const dict_table_t*	table)	/*!< in: table */
512{
513	ut_ad(table);
514
515#if DICT_TF_COMPACT != 1
516#error "DICT_TF_COMPACT must be 1"
517#endif
518
519	return(table->flags & DICT_TF_COMPACT);
520}
521
522/************************************************************************
523Check if the table has an FTS index. */
524UNIV_INLINE
525ibool
526dict_table_has_fts_index(
527/*=====================*/
528				/* out: TRUE if table has an FTS index */
529	dict_table_t*   table)  /* in: table */
530{
531	ut_ad(table);
532
533	return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS));
534}
535
536/********************************************************************//**
537Validate the table flags.
538@return	true if valid. */
539UNIV_INLINE
540bool
541dict_tf_is_valid(
542/*=============*/
543	ulint	flags)		/*!< in: table flags */
544{
545	ulint	compact = DICT_TF_GET_COMPACT(flags);
546	ulint	zip_ssize = DICT_TF_GET_ZIP_SSIZE(flags);
547	ulint	atomic_blobs = DICT_TF_HAS_ATOMIC_BLOBS(flags);
548	ulint	unused = DICT_TF_GET_UNUSED(flags);
549
550	/* Make sure there are no bits that we do not know about. */
551	if (unused != 0) {
552
553		return(false);
554
555	} else if (atomic_blobs) {
556		/* Barracuda row formats COMPRESSED and DYNAMIC build on
557		the page structure introduced for the COMPACT row format
558		by allowing keys in secondary indexes to be made from
559		data stored off-page in the clustered index. */
560
561		if (!compact) {
562			return(false);
563		}
564
565	} else if (zip_ssize) {
566
567		/* Antelope does not support COMPRESSED row format. */
568		return(false);
569	}
570
571	if (zip_ssize) {
572
573		/* COMPRESSED row format must have compact and atomic_blobs
574		bits set and validate the number is within allowed range. */
575
576		if (!compact
577		    || !atomic_blobs
578		    || zip_ssize > PAGE_ZIP_SSIZE_MAX) {
579
580			return(false);
581		}
582	}
583
584	/* CREATE TABLE ... DATA DIRECTORY is supported for any row format,
585	so the DATA_DIR flag is compatible with all other table flags. */
586
587	return(true);
588}
589
590/********************************************************************//**
591Validate a SYS_TABLES TYPE field and return it.
592@return	Same as input after validating it as a SYS_TABLES TYPE field.
593If there is an error, return ULINT_UNDEFINED. */
594UNIV_INLINE
595ulint
596dict_sys_tables_type_validate(
597/*==========================*/
598	ulint	type,		/*!< in: SYS_TABLES.TYPE */
599	ulint	n_cols)		/*!< in: SYS_TABLES.N_COLS */
600{
601	ulint	low_order_bit = DICT_TF_GET_COMPACT(type);
602	ulint	redundant = !(n_cols & DICT_N_COLS_COMPACT);
603	ulint	zip_ssize = DICT_TF_GET_ZIP_SSIZE(type);
604	ulint	atomic_blobs = DICT_TF_HAS_ATOMIC_BLOBS(type);
605	ulint	unused = DICT_TF_GET_UNUSED(type);
606
607	/* The low order bit of SYS_TABLES.TYPE is always set to 1.
608	If the format is UNIV_FORMAT_B or higher, this field is the same
609	as dict_table_t::flags. Zero is not allowed here. */
610	if (!low_order_bit) {
611		return(ULINT_UNDEFINED);
612	}
613
614	if (redundant) {
615		if (zip_ssize || atomic_blobs) {
616			return(ULINT_UNDEFINED);
617		}
618	}
619
620	/* Make sure there are no bits that we do not know about. */
621	if (unused) {
622		return(ULINT_UNDEFINED);
623	}
624
625	if (atomic_blobs) {
626		/* Barracuda row formats COMPRESSED and DYNAMIC build on
627		the page structure introduced for the COMPACT row format
628		by allowing keys in secondary indexes to be made from
629		data stored off-page in the clustered index.
630
631		The DICT_N_COLS_COMPACT flag should be in N_COLS,
632		but we already know that. */
633
634	} else if (zip_ssize) {
635		/* Antelope does not support COMPRESSED format. */
636		return(ULINT_UNDEFINED);
637	}
638
639	if (zip_ssize) {
640		/* COMPRESSED row format must have low_order_bit and
641		atomic_blobs bits set and the DICT_N_COLS_COMPACT flag
642		should be in N_COLS, but we already know about the
643		low_order_bit and DICT_N_COLS_COMPACT flags. */
644		if (!atomic_blobs) {
645			return(ULINT_UNDEFINED);
646		}
647
648		/* Validate that the number is within allowed range. */
649		if (zip_ssize > PAGE_ZIP_SSIZE_MAX) {
650			return(ULINT_UNDEFINED);
651		}
652	}
653
654	/* There is nothing to validate for the data_dir field.
655	CREATE TABLE ... DATA DIRECTORY is supported for any row
656	format, so the DATA_DIR flag is compatible with any other
657	table flags. However, it is not used with TEMPORARY tables.*/
658
659	/* Return the validated SYS_TABLES.TYPE. */
660	return(type);
661}
662
663/********************************************************************//**
664Determine the file format from dict_table_t::flags
665The low order bit will be zero for REDUNDANT and 1 for COMPACT. For any
666other row_format, file_format is > 0 and DICT_TF_COMPACT will also be set.
667@return	file format version */
668UNIV_INLINE
669rec_format_t
670dict_tf_get_rec_format(
671/*===================*/
672	ulint		flags)	/*!< in: dict_table_t::flags */
673{
674	ut_a(dict_tf_is_valid(flags));
675
676	if (!DICT_TF_GET_COMPACT(flags)) {
677		return(REC_FORMAT_REDUNDANT);
678	}
679
680	if (!DICT_TF_HAS_ATOMIC_BLOBS(flags)) {
681		return(REC_FORMAT_COMPACT);
682	}
683
684	if (DICT_TF_GET_ZIP_SSIZE(flags)) {
685		return(REC_FORMAT_COMPRESSED);
686	}
687
688	return(REC_FORMAT_DYNAMIC);
689}
690
691/********************************************************************//**
692Determine the file format from a dict_table_t::flags.
693@return	file format version */
694UNIV_INLINE
695ulint
696dict_tf_get_format(
697/*===============*/
698	ulint		flags)	/*!< in: dict_table_t::flags */
699{
700	if (DICT_TF_HAS_ATOMIC_BLOBS(flags)) {
701		return(UNIV_FORMAT_B);
702	}
703
704	return(UNIV_FORMAT_A);
705}
706
707/********************************************************************//**
708Determine the file format of a table.
709@return	file format version */
710UNIV_INLINE
711ulint
712dict_table_get_format(
713/*==================*/
714	const dict_table_t*	table)	/*!< in: table */
715{
716	ut_ad(table);
717
718	return(dict_tf_get_format(table->flags));
719}
720
721/********************************************************************//**
722Set the file format and zip size in a dict_table_t::flags.  If zip size
723is not needed, it should be 0. */
724UNIV_INLINE
725void
726dict_tf_set(
727/*========*/
728	ulint*		flags,		/*!< in/out: table flags */
729	rec_format_t	format,		/*!< in: file format */
730	ulint		zip_ssize,	/*!< in: zip shift size */
731	bool		use_data_dir)	/*!< in: table uses DATA DIRECTORY */
732{
733	switch (format) {
734	case REC_FORMAT_REDUNDANT:
735		*flags = 0;
736		ut_ad(zip_ssize == 0);
737		break;
738	case REC_FORMAT_COMPACT:
739		*flags = DICT_TF_COMPACT;
740		ut_ad(zip_ssize == 0);
741		break;
742	case REC_FORMAT_COMPRESSED:
743		*flags = DICT_TF_COMPACT
744			| (1 << DICT_TF_POS_ATOMIC_BLOBS)
745			| (zip_ssize << DICT_TF_POS_ZIP_SSIZE);
746		break;
747	case REC_FORMAT_DYNAMIC:
748		*flags = DICT_TF_COMPACT
749			| (1 << DICT_TF_POS_ATOMIC_BLOBS);
750		ut_ad(zip_ssize == 0);
751		break;
752	}
753
754	if (use_data_dir) {
755		*flags |= (1 << DICT_TF_POS_DATA_DIR);
756	}
757}
758
759/********************************************************************//**
760Convert a 32 bit integer table flags to the 32 bit integer that is
761written into the tablespace header at the offset FSP_SPACE_FLAGS and is
762also stored in the fil_space_t::flags field.  The following chart shows
763the translation of the low order bit.  Other bits are the same.
764========================= Low order bit ==========================
765                    | REDUNDANT | COMPACT | COMPRESSED | DYNAMIC
766dict_table_t::flags |     0     |    1    |     1      |    1
767fil_space_t::flags  |     0     |    0    |     1      |    1
768==================================================================
769@return	tablespace flags (fil_space_t::flags) */
770UNIV_INLINE
771ulint
772dict_tf_to_fsp_flags(
773/*=================*/
774	ulint	table_flags)	/*!< in: dict_table_t::flags */
775{
776	ulint fsp_flags;
777
778	DBUG_EXECUTE_IF("dict_tf_to_fsp_flags_failure",
779			return(ULINT_UNDEFINED););
780
781	/* Adjust bit zero. */
782	fsp_flags = DICT_TF_HAS_ATOMIC_BLOBS(table_flags) ? 1 : 0;
783
784	/* ZIP_SSIZE and ATOMIC_BLOBS are at the same position. */
785	fsp_flags |= table_flags & DICT_TF_MASK_ZIP_SSIZE;
786	fsp_flags |= table_flags & DICT_TF_MASK_ATOMIC_BLOBS;
787
788	/* In addition, tablespace flags also contain the page size. */
789	fsp_flags |= fsp_flags_set_page_size(fsp_flags, UNIV_PAGE_SIZE);
790
791	/* The DATA_DIR flag is in a different position in fsp_flag */
792	fsp_flags |= DICT_TF_HAS_DATA_DIR(table_flags)
793		     ? FSP_FLAGS_MASK_DATA_DIR : 0;
794
795	ut_a(fsp_flags_is_valid(fsp_flags));
796
797	return(fsp_flags);
798}
799
800/********************************************************************//**
801Convert a 32 bit integer from SYS_TABLES.TYPE to dict_table_t::flags
802The following chart shows the translation of the low order bit.
803Other bits are the same.
804========================= Low order bit ==========================
805                    | REDUNDANT | COMPACT | COMPRESSED and DYNAMIC
806SYS_TABLES.TYPE     |     1     |    1    |     1
807dict_table_t::flags |     0     |    1    |     1
808==================================================================
809@return	ulint containing SYS_TABLES.TYPE */
810UNIV_INLINE
811ulint
812dict_sys_tables_type_to_tf(
813/*=======================*/
814	ulint	type,	/*!< in: SYS_TABLES.TYPE field */
815	ulint	n_cols)	/*!< in: SYS_TABLES.N_COLS field */
816{
817	ulint	flags;
818	ulint	redundant = !(n_cols & DICT_N_COLS_COMPACT);
819
820	/* Adjust bit zero. */
821	flags = redundant ? 0 : 1;
822
823	/* ZIP_SSIZE, ATOMIC_BLOBS & DATA_DIR are the same. */
824	flags |= type & (DICT_TF_MASK_ZIP_SSIZE
825			 | DICT_TF_MASK_ATOMIC_BLOBS
826			 | DICT_TF_MASK_DATA_DIR);
827
828	return(flags);
829}
830
831/********************************************************************//**
832Convert a 32 bit integer table flags to the 32bit integer that is written
833to a SYS_TABLES.TYPE field. The following chart shows the translation of
834the low order bit.  Other bits are the same.
835========================= Low order bit ==========================
836                    | REDUNDANT | COMPACT | COMPRESSED and DYNAMIC
837dict_table_t::flags |     0     |    1    |     1
838SYS_TABLES.TYPE     |     1     |    1    |     1
839==================================================================
840@return	ulint containing SYS_TABLES.TYPE */
841UNIV_INLINE
842ulint
843dict_tf_to_sys_tables_type(
844/*=======================*/
845	ulint	flags)	/*!< in: dict_table_t::flags */
846{
847	ulint type;
848
849	ut_a(dict_tf_is_valid(flags));
850
851	/* Adjust bit zero. It is always 1 in SYS_TABLES.TYPE */
852	type = 1;
853
854	/* ZIP_SSIZE, ATOMIC_BLOBS & DATA_DIR are the same. */
855	type |= flags & (DICT_TF_MASK_ZIP_SSIZE
856			 | DICT_TF_MASK_ATOMIC_BLOBS
857			 | DICT_TF_MASK_DATA_DIR);
858
859	return(type);
860}
861
862/********************************************************************//**
863Extract the compressed page size from dict_table_t::flags.
864These flags are in memory, so assert that they are valid.
865@return	compressed page size, or 0 if not compressed */
866UNIV_INLINE
867ulint
868dict_tf_get_zip_size(
869/*=================*/
870	ulint	flags)	/*!< in: flags */
871{
872	ulint zip_ssize = DICT_TF_GET_ZIP_SSIZE(flags);
873	ulint zip_size = (zip_ssize
874			  ? (UNIV_ZIP_SIZE_MIN >> 1) << zip_ssize
875			  : 0);
876
877	ut_ad(zip_size <= UNIV_ZIP_SIZE_MAX);
878
879	return(zip_size);
880}
881
882/********************************************************************//**
883Check whether the table uses the compressed compact page format.
884@return	compressed page size, or 0 if not compressed */
885UNIV_INLINE
886ulint
887dict_table_zip_size(
888/*================*/
889	const dict_table_t*	table)	/*!< in: table */
890{
891	ut_ad(table);
892
893	return(dict_tf_get_zip_size(table->flags));
894}
895
896#ifndef UNIV_HOTBACKUP
897/*********************************************************************//**
898Obtain exclusive locks on all index trees of the table. This is to prevent
899accessing index trees while InnoDB is updating internal metadata for
900operations such as truncate tables. */
901UNIV_INLINE
902void
903dict_table_x_lock_indexes(
904/*======================*/
905	dict_table_t*	table)	/*!< in: table */
906{
907	dict_index_t*   index;
908
909	ut_a(table);
910	ut_ad(mutex_own(&(dict_sys->mutex)));
911
912	/* Loop through each index of the table and lock them */
913	for (index = dict_table_get_first_index(table);
914	     index != NULL;
915	     index = dict_table_get_next_index(index)) {
916		rw_lock_x_lock(dict_index_get_lock(index));
917	}
918}
919
920/*********************************************************************//**
921Returns true if the particular FTS index in the table is still syncing
922in the background, false otherwise.
923@param [in] table      Table containing FTS index
924@return True if sync of fts index is still going in the background  */
925UNIV_INLINE
926bool
927dict_fts_index_syncing(
928	dict_table_t*   table)
929{
930	 dict_index_t*   index;
931
932	for (index = dict_table_get_first_index(table);
933	    index != NULL;
934	    index = dict_table_get_next_index(index)) {
935		if (index->index_fts_syncing) {
936			 return(true);
937		}
938	}
939	return(false);
940}
941/*********************************************************************//**
942Release the exclusive locks on all index tree. */
943UNIV_INLINE
944void
945dict_table_x_unlock_indexes(
946/*========================*/
947	dict_table_t*	table)	/*!< in: table */
948{
949	dict_index_t*   index;
950
951	ut_a(table);
952	ut_ad(mutex_own(&(dict_sys->mutex)));
953
954	for (index = dict_table_get_first_index(table);
955	     index != NULL;
956	     index = dict_table_get_next_index(index)) {
957		rw_lock_x_unlock(dict_index_get_lock(index));
958	}
959}
960#endif /* !UNIV_HOTBACKUP */
961
962/********************************************************************//**
963Gets the number of fields in the internal representation of an index,
964including fields added by the dictionary system.
965@return	number of fields */
966UNIV_INLINE
967ulint
968dict_index_get_n_fields(
969/*====================*/
970	const dict_index_t*	index)	/*!< in: an internal
971					representation of index (in
972					the dictionary cache) */
973{
974	ut_ad(index);
975	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
976
977	return(index->n_fields);
978}
979
980/********************************************************************//**
981Gets the number of fields in the internal representation of an index
982that uniquely determine the position of an index entry in the index, if
983we do not take multiversioning into account: in the B-tree use the value
984returned by dict_index_get_n_unique_in_tree.
985@return	number of fields */
986UNIV_INLINE
987ulint
988dict_index_get_n_unique(
989/*====================*/
990	const dict_index_t*	index)	/*!< in: an internal representation
991					of index (in the dictionary cache) */
992{
993	ut_ad(index);
994	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
995	ut_ad(index->cached);
996
997	return(index->n_uniq);
998}
999
1000/********************************************************************//**
1001Gets the number of fields in the internal representation of an index
1002which uniquely determine the position of an index entry in the index, if
1003we also take multiversioning into account.
1004@return	number of fields */
1005UNIV_INLINE
1006ulint
1007dict_index_get_n_unique_in_tree(
1008/*============================*/
1009	const dict_index_t*	index)	/*!< in: an internal representation
1010					of index (in the dictionary cache) */
1011{
1012	ut_ad(index);
1013	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1014	ut_ad(index->cached);
1015
1016	if (dict_index_is_clust(index)) {
1017
1018		return(dict_index_get_n_unique(index));
1019	}
1020
1021	return(dict_index_get_n_fields(index));
1022}
1023
1024/********************************************************************//**
1025Gets the number of user-defined ordering fields in the index. In the internal
1026representation of clustered indexes we add the row id to the ordering fields
1027to make a clustered index unique, but this function returns the number of
1028fields the user defined in the index as ordering fields.
1029@return	number of fields */
1030UNIV_INLINE
1031ulint
1032dict_index_get_n_ordering_defined_by_user(
1033/*======================================*/
1034	const dict_index_t*	index)	/*!< in: an internal representation
1035					of index (in the dictionary cache) */
1036{
1037	return(index->n_user_defined_cols);
1038}
1039
1040#ifdef UNIV_DEBUG
1041/********************************************************************//**
1042Gets the nth field of an index.
1043@return	pointer to field object */
1044UNIV_INLINE
1045dict_field_t*
1046dict_index_get_nth_field(
1047/*=====================*/
1048	const dict_index_t*	index,	/*!< in: index */
1049	ulint			pos)	/*!< in: position of field */
1050{
1051	ut_ad(index);
1052	ut_ad(pos < index->n_def);
1053	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1054
1055	return((dict_field_t*) (index->fields) + pos);
1056}
1057#endif /* UNIV_DEBUG */
1058
1059/********************************************************************//**
1060Returns the position of a system column in an index.
1061@return	position, ULINT_UNDEFINED if not contained */
1062UNIV_INLINE
1063ulint
1064dict_index_get_sys_col_pos(
1065/*=======================*/
1066	const dict_index_t*	index,	/*!< in: index */
1067	ulint			type)	/*!< in: DATA_ROW_ID, ... */
1068{
1069	ut_ad(index);
1070	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1071	ut_ad(!dict_index_is_univ(index));
1072
1073	if (dict_index_is_clust(index)) {
1074
1075		return(dict_col_get_clust_pos(
1076			       dict_table_get_sys_col(index->table, type),
1077			       index));
1078	}
1079
1080	return(dict_index_get_nth_col_pos(
1081			index, dict_table_get_sys_col_no(index->table, type),
1082			NULL));
1083}
1084
1085/*********************************************************************//**
1086Gets the field column.
1087@return	field->col, pointer to the table column */
1088UNIV_INLINE
1089const dict_col_t*
1090dict_field_get_col(
1091/*===============*/
1092	const dict_field_t*	field)	/*!< in: index field */
1093{
1094	ut_ad(field);
1095
1096	return(field->col);
1097}
1098
1099/********************************************************************//**
1100Gets pointer to the nth column in an index.
1101@return	column */
1102UNIV_INLINE
1103const dict_col_t*
1104dict_index_get_nth_col(
1105/*===================*/
1106	const dict_index_t*	index,	/*!< in: index */
1107	ulint			pos)	/*!< in: position of the field */
1108{
1109	return(dict_field_get_col(dict_index_get_nth_field(index, pos)));
1110}
1111
1112/********************************************************************//**
1113Gets the column number the nth field in an index.
1114@return	column number */
1115UNIV_INLINE
1116ulint
1117dict_index_get_nth_col_no(
1118/*======================*/
1119	const dict_index_t*	index,	/*!< in: index */
1120	ulint			pos)	/*!< in: position of the field */
1121{
1122	return(dict_col_get_no(dict_index_get_nth_col(index, pos)));
1123}
1124
1125/********************************************************************//**
1126Looks for column n in an index.
1127@return position in internal representation of the index;
1128ULINT_UNDEFINED if not contained */
1129UNIV_INLINE
1130ulint
1131dict_index_get_nth_col_pos(
1132/*=======================*/
1133	const dict_index_t*	index,	/*!< in: index */
1134	ulint			n,	/*!< in: column number */
1135	ulint*			prefix_col_pos) /*!< out: col num if prefix */
1136{
1137	return(dict_index_get_nth_col_or_prefix_pos(index, n, FALSE,
1138						    prefix_col_pos));
1139}
1140
1141#ifndef UNIV_HOTBACKUP
1142/********************************************************************//**
1143Returns the minimum data size of an index record.
1144@return	minimum data size in bytes */
1145UNIV_INLINE
1146ulint
1147dict_index_get_min_size(
1148/*====================*/
1149	const dict_index_t*	index)	/*!< in: index */
1150{
1151	ulint	n	= dict_index_get_n_fields(index);
1152	ulint	size	= 0;
1153
1154	while (n--) {
1155		size += dict_col_get_min_size(dict_index_get_nth_col(index,
1156								     n));
1157	}
1158
1159	return(size);
1160}
1161
1162/*********************************************************************//**
1163Gets the space id of the root of the index tree.
1164@return	space id */
1165UNIV_INLINE
1166ulint
1167dict_index_get_space(
1168/*=================*/
1169	const dict_index_t*	index)	/*!< in: index */
1170{
1171	ut_ad(index);
1172	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1173
1174	return(index->space);
1175}
1176
1177/*********************************************************************//**
1178Sets the space id of the root of the index tree. */
1179UNIV_INLINE
1180void
1181dict_index_set_space(
1182/*=================*/
1183	dict_index_t*	index,	/*!< in/out: index */
1184	ulint		space)	/*!< in: space id */
1185{
1186	ut_ad(index);
1187	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1188
1189	index->space = space;
1190}
1191
1192/*********************************************************************//**
1193Gets the page number of the root of the index tree.
1194@return	page number */
1195UNIV_INLINE
1196ulint
1197dict_index_get_page(
1198/*================*/
1199	const dict_index_t*	index)	/*!< in: index */
1200{
1201	ut_ad(index);
1202	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1203
1204	return(index->page);
1205}
1206
1207/*********************************************************************//**
1208Gets the read-write lock of the index tree.
1209@return	read-write lock */
1210UNIV_INLINE
1211prio_rw_lock_t*
1212dict_index_get_lock(
1213/*================*/
1214	dict_index_t*	index)	/*!< in: index */
1215{
1216	ut_ad(index);
1217	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1218
1219	return(&(index->lock));
1220}
1221
1222/********************************************************************//**
1223Returns free space reserved for future updates of records. This is
1224relevant only in the case of many consecutive inserts, as updates
1225which make the records bigger might fragment the index.
1226@return	number of free bytes on page, reserved for updates */
1227UNIV_INLINE
1228ulint
1229dict_index_get_space_reserve(void)
1230/*==============================*/
1231{
1232	return(UNIV_PAGE_SIZE / 16);
1233}
1234
1235/********************************************************************//**
1236Gets the status of online index creation.
1237@return the status */
1238UNIV_INLINE
1239enum online_index_status
1240dict_index_get_online_status(
1241/*=========================*/
1242	const dict_index_t*	index)	/*!< in: secondary index */
1243{
1244	enum online_index_status	status;
1245
1246	status = (enum online_index_status) index->online_status;
1247
1248	/* Without the index->lock protection, the online
1249	status can change from ONLINE_INDEX_CREATION to
1250	ONLINE_INDEX_COMPLETE (or ONLINE_INDEX_ABORTED) in
1251	row_log_apply() once log application is done. So to make
1252	sure the status is ONLINE_INDEX_CREATION or ONLINE_INDEX_COMPLETE
1253	you should always do the recheck after acquiring index->lock */
1254
1255#ifdef UNIV_DEBUG
1256	switch (status) {
1257	case ONLINE_INDEX_COMPLETE:
1258	case ONLINE_INDEX_CREATION:
1259	case ONLINE_INDEX_ABORTED:
1260	case ONLINE_INDEX_ABORTED_DROPPED:
1261		return(status);
1262	}
1263	ut_error;
1264#endif /* UNIV_DEBUG */
1265	return(status);
1266}
1267
1268/********************************************************************//**
1269Sets the status of online index creation. */
1270UNIV_INLINE
1271void
1272dict_index_set_online_status(
1273/*=========================*/
1274	dict_index_t*			index,	/*!< in/out: index */
1275	enum online_index_status	status)	/*!< in: status */
1276{
1277	ut_ad(!(index->type & DICT_FTS));
1278#ifdef UNIV_SYNC_DEBUG
1279	ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_EX));
1280#endif /* UNIV_SYNC_DEBUG */
1281#ifdef UNIV_DEBUG
1282	switch (dict_index_get_online_status(index)) {
1283	case ONLINE_INDEX_COMPLETE:
1284	case ONLINE_INDEX_CREATION:
1285		break;
1286	case ONLINE_INDEX_ABORTED:
1287		ut_ad(status == ONLINE_INDEX_ABORTED_DROPPED);
1288		break;
1289	case ONLINE_INDEX_ABORTED_DROPPED:
1290		ut_error;
1291	}
1292#endif /* UNIV_DEBUG */
1293
1294	index->online_status = status;
1295	ut_ad(dict_index_get_online_status(index) == status);
1296}
1297
1298/********************************************************************//**
1299Determines if a secondary index is being or has been created online,
1300or if the table is being rebuilt online, allowing concurrent modifications
1301to the table.
1302@retval true if the index is being or has been built online, or
1303if this is a clustered index and the table is being or has been rebuilt online
1304@retval false if the index has been created or the table has been
1305rebuilt completely */
1306UNIV_INLINE
1307bool
1308dict_index_is_online_ddl(
1309/*=====================*/
1310	const dict_index_t*	index)	/*!< in: index */
1311{
1312#ifdef UNIV_DEBUG
1313	if (dict_index_is_clust(index)) {
1314		switch (dict_index_get_online_status(index)) {
1315		case ONLINE_INDEX_CREATION:
1316			return(true);
1317		case ONLINE_INDEX_COMPLETE:
1318			return(false);
1319		case ONLINE_INDEX_ABORTED:
1320		case ONLINE_INDEX_ABORTED_DROPPED:
1321			break;
1322		}
1323		ut_ad(0);
1324		return(false);
1325	}
1326#endif /* UNIV_DEBUG */
1327
1328	return(UNIV_UNLIKELY(dict_index_get_online_status(index)
1329			     != ONLINE_INDEX_COMPLETE));
1330}
1331
1332/**********************************************************************//**
1333Check whether a column exists in an FTS index.
1334@return ULINT_UNDEFINED if no match else the offset within the vector */
1335UNIV_INLINE
1336ulint
1337dict_table_is_fts_column(
1338/*=====================*/
1339	ib_vector_t*	indexes,/*!< in: vector containing only FTS indexes */
1340	ulint		col_no)	/*!< in: col number to search for */
1341
1342{
1343	ulint		i;
1344
1345	for (i = 0; i < ib_vector_size(indexes); ++i) {
1346		dict_index_t*	index;
1347
1348		index = (dict_index_t*) ib_vector_getp(indexes, i);
1349
1350		if (dict_index_contains_col_or_prefix(index, col_no)) {
1351
1352			return(i);
1353		}
1354	}
1355
1356	return(ULINT_UNDEFINED);
1357}
1358
1359/**********************************************************************//**
1360Determine bytes of column prefix to be stored in the undo log. Please
1361note if the table format is UNIV_FORMAT_A (< UNIV_FORMAT_B), no prefix
1362needs to be stored in the undo log.
1363@return bytes of column prefix to be stored in the undo log */
1364UNIV_INLINE
1365ulint
1366dict_max_field_len_store_undo(
1367/*==========================*/
1368	dict_table_t*		table,	/*!< in: table */
1369	const dict_col_t*	col)	/*!< in: column which index prefix
1370					is based on */
1371{
1372	ulint	prefix_len = 0;
1373
1374	if (dict_table_get_format(table) >= UNIV_FORMAT_B)
1375	{
1376		prefix_len = col->max_prefix
1377			? col->max_prefix
1378			: DICT_MAX_FIELD_LEN_BY_FORMAT(table);
1379	}
1380
1381	return(prefix_len);
1382}
1383
1384/********************************************************************//**
1385Check whether the table is corrupted.
1386@return	nonzero for corrupted table, zero for valid tables */
1387UNIV_INLINE
1388ulint
1389dict_table_is_corrupted(
1390/*====================*/
1391	const dict_table_t*	table)	/*!< in: table */
1392{
1393	ut_ad(table);
1394	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1395
1396	return(table->corrupted);
1397}
1398
1399/********************************************************************//**
1400Check whether the index is corrupted.
1401@return	nonzero for corrupted index, zero for valid indexes */
1402UNIV_INLINE
1403ulint
1404dict_index_is_corrupted(
1405/*====================*/
1406	const dict_index_t*	index)	/*!< in: index */
1407{
1408	ut_ad(index);
1409	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
1410
1411	return((index->type & DICT_CORRUPT)
1412	       || (index->table && index->table->corrupted));
1413}
1414
1415/********************************************************************//**
1416Check if the tablespace for the table has been discarded.
1417@return	true if the tablespace has been discarded. */
1418UNIV_INLINE
1419bool
1420dict_table_is_discarded(
1421/*====================*/
1422	const dict_table_t*	table)	/*!< in: table to check */
1423{
1424	return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_DISCARDED));
1425}
1426
1427/********************************************************************//**
1428Check if it is a temporary table.
1429@return	true if temporary table flag is set. */
1430UNIV_INLINE
1431bool
1432dict_table_is_temporary(
1433/*====================*/
1434	const dict_table_t*	table)	/*!< in: table to check */
1435{
1436	return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY));
1437}
1438
1439/**********************************************************************//**
1440Get index by first field of the index
1441@return index which is having first field matches
1442with the field present in field_index position of table */
1443UNIV_INLINE
1444dict_index_t*
1445dict_table_get_index_on_first_col(
1446/*==============================*/
1447	const dict_table_t*	table,		/*!< in: table */
1448	ulint			col_index)	/*!< in: position of column
1449						in table */
1450{
1451	ut_ad(col_index < table->n_cols);
1452
1453	dict_col_t* column = dict_table_get_nth_col(table, col_index);
1454
1455	for (dict_index_t* index = dict_table_get_first_index(table);
1456		index != NULL; index = dict_table_get_next_index(index)) {
1457
1458		if (index->fields[0].col == column) {
1459			return(index);
1460		}
1461	}
1462	ut_error;
1463	return(0);
1464}
1465
1466#endif /* !UNIV_HOTBACKUP */
1467