1/*****************************************************************************
2
3Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2013, 2019, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/******************************************************************//**
21@file include/dict0dict.ic
22Data dictionary system
23
24Created 1/8/1996 Heikki Tuuri
25***********************************************************************/
26
27#include "fsp0sysspace.h"
28#include "dict0pagecompress.h"
29
30/*********************************************************************//**
31Gets the minimum number of bytes per character.
32@return minimum multi-byte char size, in bytes */
33UNIV_INLINE
34ulint
35dict_col_get_mbminlen(
36/*==================*/
37	const dict_col_t*	col)	/*!< in: column */
38{
39	return col->mbminlen;
40}
41/*********************************************************************//**
42Gets the maximum number of bytes per character.
43@return maximum multi-byte char size, in bytes */
44UNIV_INLINE
45ulint
46dict_col_get_mbmaxlen(
47/*==================*/
48	const dict_col_t*	col)	/*!< in: column */
49{
50	return col->mbmaxlen;
51}
52/*********************************************************************//**
53Gets the column data type. */
54UNIV_INLINE
55void
56dict_col_copy_type(
57/*===============*/
58	const dict_col_t*	col,	/*!< in: column */
59	dtype_t*		type)	/*!< out: data type */
60{
61	ut_ad(col != NULL);
62	ut_ad(type != NULL);
63
64	type->mtype = col->mtype;
65	type->prtype = col->prtype;
66	type->len = col->len;
67	type->mbminlen = col->mbminlen;
68	type->mbmaxlen = col->mbmaxlen;
69}
70
71#ifdef UNIV_DEBUG
72/*********************************************************************//**
73Assert that a column and a data type match.
74@return TRUE */
75UNIV_INLINE
76ibool
77dict_col_type_assert_equal(
78/*=======================*/
79	const dict_col_t*	col,	/*!< in: column */
80	const dtype_t*		type)	/*!< in: data type */
81{
82	ut_ad(col->mtype == type->mtype);
83	ut_ad(col->prtype == type->prtype);
84	//ut_ad(col->len == type->len);
85	ut_ad(col->mbminlen == type->mbminlen);
86	ut_ad(col->mbmaxlen == type->mbmaxlen);
87
88	return(TRUE);
89}
90#endif /* UNIV_DEBUG */
91
92/***********************************************************************//**
93Returns the minimum size of the column.
94@return minimum size */
95UNIV_INLINE
96ulint
97dict_col_get_min_size(
98/*==================*/
99	const dict_col_t*	col)	/*!< in: column */
100{
101	return(dtype_get_min_size_low(col->mtype, col->prtype, col->len,
102				      col->mbminlen, col->mbmaxlen));
103}
104/***********************************************************************//**
105Returns the maximum size of the column.
106@return maximum size */
107UNIV_INLINE
108ulint
109dict_col_get_max_size(
110/*==================*/
111	const dict_col_t*	col)	/*!< in: column */
112{
113	return(dtype_get_max_size_low(col->mtype, col->len));
114}
115/***********************************************************************//**
116Returns the size of a fixed size column, 0 if not a fixed size column.
117@return fixed size, or 0 */
118UNIV_INLINE
119ulint
120dict_col_get_fixed_size(
121/*====================*/
122	const dict_col_t*	col,	/*!< in: column */
123	ulint			comp)	/*!< in: nonzero=ROW_FORMAT=COMPACT */
124{
125	return(dtype_get_fixed_size_low(col->mtype, col->prtype, col->len,
126					col->mbminlen, col->mbmaxlen, comp));
127}
128/***********************************************************************//**
129Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column.
130For fixed length types it is the fixed length of the type, otherwise 0.
131@return SQL null storage size in ROW_FORMAT=REDUNDANT */
132UNIV_INLINE
133ulint
134dict_col_get_sql_null_size(
135/*=======================*/
136	const dict_col_t*	col,	/*!< in: column */
137	ulint			comp)	/*!< in: nonzero=ROW_FORMAT=COMPACT  */
138{
139	return(dict_col_get_fixed_size(col, comp));
140}
141
142/*********************************************************************//**
143Gets the column number.
144@return col->ind, table column position (starting from 0) */
145UNIV_INLINE
146ulint
147dict_col_get_no(
148/*============*/
149	const dict_col_t*	col)	/*!< in: column */
150{
151	return(col->ind);
152}
153
154/*********************************************************************//**
155Gets the column position in the clustered index. */
156UNIV_INLINE
157ulint
158dict_col_get_clust_pos(
159/*===================*/
160	const dict_col_t*	col,		/*!< in: table column */
161	const dict_index_t*	clust_index)	/*!< in: clustered index */
162{
163	ulint	i;
164
165	ut_ad(dict_index_is_clust(clust_index));
166
167	for (i = 0; i < clust_index->n_def; i++) {
168		const dict_field_t*	field = &clust_index->fields[i];
169
170		if (!field->prefix_len && field->col == col) {
171			return(i);
172		}
173	}
174
175	return(ULINT_UNDEFINED);
176}
177
178/** Gets the column position in the given index.
179@param[in]	col	table column
180@param[in]	index	index to be searched for column
181@return position of column in the given index. */
182UNIV_INLINE
183ulint
184dict_col_get_index_pos(
185	const dict_col_t*	col,
186	const dict_index_t*	index)
187{
188	ulint	i;
189
190	for (i = 0; i < index->n_def; i++) {
191		const dict_field_t*	field = &index->fields[i];
192
193		if (!field->prefix_len && field->col == col) {
194			return(i);
195		}
196	}
197
198	return(ULINT_UNDEFINED);
199}
200
201#ifdef UNIV_DEBUG
202/********************************************************************//**
203Gets the first index on the table (the clustered index).
204@return index, NULL if none exists */
205UNIV_INLINE
206dict_index_t*
207dict_table_get_first_index(
208/*=======================*/
209	const dict_table_t*	table)	/*!< in: table */
210{
211	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
212
213	return(UT_LIST_GET_FIRST(((dict_table_t*) table)->indexes));
214}
215
216/********************************************************************//**
217Gets the last index on the table.
218@return index, NULL if none exists */
219UNIV_INLINE
220dict_index_t*
221dict_table_get_last_index(
222/*=======================*/
223	const dict_table_t*	table)	/*!< in: table */
224{
225	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
226	return(UT_LIST_GET_LAST((const_cast<dict_table_t*>(table))
227				->indexes));
228}
229
230/********************************************************************//**
231Gets the next index on the table.
232@return index, NULL if none left */
233UNIV_INLINE
234dict_index_t*
235dict_table_get_next_index(
236/*======================*/
237	const dict_index_t*	index)	/*!< in: index */
238{
239	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
240	return(UT_LIST_GET_NEXT(indexes, (dict_index_t*) index));
241}
242#endif /* UNIV_DEBUG */
243
244/********************************************************************//**
245Gets the number of user-defined non-virtual columns in a table in the
246dictionary cache.
247@return number of user-defined (e.g., not ROW_ID) non-virtual
248columns of a table */
249UNIV_INLINE
250ulint
251dict_table_get_n_user_cols(
252/*=======================*/
253	const dict_table_t*	table)	/*!< in: table */
254{
255	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
256	/* n_cols counts stored columns only. A table may contain
257	virtual columns and no user-specified stored columns at all. */
258	ut_ad(table->n_cols >= DATA_N_SYS_COLS);
259	return unsigned(table->n_cols) - DATA_N_SYS_COLS;
260}
261
262/********************************************************************//**
263Gets the number of all non-virtual columns (also system) in a table
264in the dictionary cache.
265@return number of non-virtual columns of a table */
266UNIV_INLINE
267ulint
268dict_table_get_n_cols(
269/*==================*/
270	const dict_table_t*	table)	/*!< in: table */
271{
272	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
273	return(table->n_cols);
274}
275
276/** Gets the number of virtual columns in a table in the dictionary cache.
277@param[in]	table	the table to check
278@return number of virtual columns of a table */
279UNIV_INLINE
280ulint
281dict_table_get_n_v_cols(
282	const dict_table_t*	table)
283{
284	ut_ad(table);
285	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
286
287	return(table->n_v_cols);
288}
289
290/** Check if a table has indexed virtual columns
291@param[in]	table	the table to check
292@return true is the table has indexed virtual columns */
293UNIV_INLINE
294bool
295dict_table_has_indexed_v_cols(
296	const dict_table_t*	table)
297{
298
299	for (ulint i = 0; i < table->n_v_cols; i++) {
300		const dict_v_col_t*     col = dict_table_get_nth_v_col(table, i);
301		if (col->m_col.ord_part) {
302			return(true);
303		}
304	}
305
306	return(false);
307}
308
309/********************************************************************//**
310Gets the approximately estimated number of rows in the table.
311@return estimated number of rows */
312UNIV_INLINE
313ib_uint64_t
314dict_table_get_n_rows(
315/*==================*/
316	const dict_table_t*	table)	/*!< in: table */
317{
318	ut_ad(table->stat_initialized);
319
320	return(table->stat_n_rows);
321}
322
323/********************************************************************//**
324Increment the number of rows in the table by one.
325Notice that this operation is not protected by any latch, the number is
326approximate. */
327UNIV_INLINE
328void
329dict_table_n_rows_inc(
330/*==================*/
331	dict_table_t*	table)	/*!< in/out: table */
332{
333	if (table->stat_initialized) {
334		ib_uint64_t	n_rows = table->stat_n_rows;
335		if (n_rows < 0xFFFFFFFFFFFFFFFFULL) {
336			table->stat_n_rows = n_rows + 1;
337		}
338	}
339}
340
341/********************************************************************//**
342Decrement the number of rows in the table by one.
343Notice that this operation is not protected by any latch, the number is
344approximate. */
345UNIV_INLINE
346void
347dict_table_n_rows_dec(
348/*==================*/
349	dict_table_t*	table)	/*!< in/out: table */
350{
351	if (table->stat_initialized) {
352		ib_uint64_t	n_rows = table->stat_n_rows;
353		if (n_rows > 0) {
354			table->stat_n_rows = n_rows - 1;
355		}
356	}
357}
358
359#ifdef UNIV_DEBUG
360/********************************************************************//**
361Gets the nth column of a table.
362@return pointer to column object */
363UNIV_INLINE
364dict_col_t*
365dict_table_get_nth_col(
366/*===================*/
367	const dict_table_t*	table,	/*!< in: table */
368	ulint			pos)	/*!< in: position of column */
369{
370	ut_ad(pos < table->n_def);
371	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
372
373	return((dict_col_t*) (table->cols) + pos);
374}
375
376/** Gets the nth virtual column of a table.
377@param[in]	table	table
378@param[in]	pos	position of virtual column
379@return pointer to virtual column object */
380UNIV_INLINE
381dict_v_col_t*
382dict_table_get_nth_v_col(
383	const dict_table_t*	table,
384	ulint			pos)
385{
386	ut_ad(table);
387	ut_ad(pos < table->n_v_def);
388	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
389	ut_ad(!table->v_cols[pos].m_col.is_added());
390	ut_ad(!table->v_cols[pos].m_col.is_dropped());
391	return &table->v_cols[pos];
392}
393
394/********************************************************************//**
395Gets the given system column of a table.
396@return pointer to column object */
397UNIV_INLINE
398dict_col_t*
399dict_table_get_sys_col(
400/*===================*/
401	const dict_table_t*	table,	/*!< in: table */
402	ulint			sys)	/*!< in: DATA_ROW_ID, ... */
403{
404	dict_col_t*	col;
405	col = dict_table_get_nth_col(table,
406				     dict_table_get_sys_col_no(table, sys));
407	ut_ad(col->mtype == DATA_SYS);
408	ut_ad(col->prtype == (sys | DATA_NOT_NULL));
409
410	return(col);
411}
412#endif /* UNIV_DEBUG */
413
414/********************************************************************//**
415Gets the given system column number of a table.
416@return column number */
417UNIV_INLINE
418ulint
419dict_table_get_sys_col_no(
420/*======================*/
421	const dict_table_t*	table,	/*!< in: table */
422	ulint			sys)	/*!< in: DATA_ROW_ID, ... */
423{
424	ut_ad(sys < DATA_N_SYS_COLS);
425	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
426	return unsigned(table->n_cols) + (sys - DATA_N_SYS_COLS);
427}
428
429/************************************************************************
430Check if the table has an FTS index. */
431UNIV_INLINE
432ibool
433dict_table_has_fts_index(
434/*=====================*/
435				/* out: TRUE if table has an FTS index */
436	dict_table_t*   table)  /* in: table */
437{
438	return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS));
439}
440
441/** Validate the flags for tables that are not ROW_FORMAT=REDUNDANT.
442@param[in]	flags		table flags
443@return whether the flags are valid */
444inline
445bool
446dict_tf_is_valid_not_redundant(ulint flags)
447{
448	const bool	atomic_blobs = DICT_TF_HAS_ATOMIC_BLOBS(flags);
449
450	ulint	zip_ssize = DICT_TF_GET_ZIP_SSIZE(flags);
451
452	if (!zip_ssize) {
453		/* Not ROW_FORMAT=COMPRESSED */
454	} else if (!atomic_blobs) {
455		/* ROW_FORMAT=COMPRESSED implies ROW_FORMAT=DYNAMIC
456		for the uncompressed page format */
457		return(false);
458	} else if (zip_ssize > PAGE_ZIP_SSIZE_MAX
459		   || zip_ssize > srv_page_size_shift
460		   || srv_page_size_shift > UNIV_ZIP_SIZE_SHIFT_MAX) {
461		/* KEY_BLOCK_SIZE is out of bounds, or
462		ROW_FORMAT=COMPRESSED is not supported with this
463		innodb_page_size (only up to 16KiB) */
464		return(false);
465	}
466
467	switch (DICT_TF_GET_PAGE_COMPRESSION_LEVEL(flags)) {
468	case 0:
469		/* PAGE_COMPRESSION_LEVEL=0 should imply PAGE_COMPRESSED=NO */
470		return(!DICT_TF_GET_PAGE_COMPRESSION(flags));
471	case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9:
472		/* PAGE_COMPRESSION_LEVEL requires
473		ROW_FORMAT=COMPACT or ROW_FORMAT=DYNAMIC
474		(not ROW_FORMAT=COMPRESSED or ROW_FORMAT=REDUNDANT)
475		and PAGE_COMPRESSED=YES */
476		return(!zip_ssize && DICT_TF_GET_PAGE_COMPRESSION(flags));
477	default:
478		/* Invalid PAGE_COMPRESSION_LEVEL value */
479		return(false);
480	}
481}
482
483/** Validate the table flags.
484@param[in]	flags	Table flags
485@return true if valid. */
486UNIV_INLINE
487bool
488dict_tf_is_valid(
489	ulint	flags)
490{
491	ut_ad(flags < 1U << DICT_TF_BITS);
492	/* The DATA_DIRECTORY flag can be assigned fully independently
493	of all other persistent table flags. */
494	flags &= ~DICT_TF_MASK_DATA_DIR;
495	if (!(flags & 1)) {
496		/* Only ROW_FORMAT=REDUNDANT has 0 in the least significant
497		bit. For ROW_FORMAT=REDUNDANT, only the DATA_DIR flag
498		(which we cleared above) can be set. If any other flags
499		are set, the flags are invalid. */
500		return(flags == 0 || flags == DICT_TF_MASK_NO_ROLLBACK);
501	}
502
503	return(dict_tf_is_valid_not_redundant(flags));
504}
505
506/** Validate both table flags and table flags2 and make sure they
507are compatible.
508@param[in]	flags	Table flags
509@param[in]	flags2	Table flags2
510@return true if valid. */
511UNIV_INLINE
512bool
513dict_tf2_is_valid(
514	ulint	flags,
515	ulint	flags2)
516{
517	if (!dict_tf_is_valid(flags)) {
518		return(false);
519	}
520
521	if ((flags2 & DICT_TF2_UNUSED_BIT_MASK) != 0) {
522		return(false);
523	}
524
525	return(true);
526}
527
528/********************************************************************//**
529Determine the file format from dict_table_t::flags
530The low order bit will be zero for REDUNDANT and 1 for COMPACT. For any
531other row_format, file_format is > 0 and DICT_TF_COMPACT will also be set.
532@return file format version */
533UNIV_INLINE
534rec_format_t
535dict_tf_get_rec_format(
536/*===================*/
537	ulint		flags)	/*!< in: dict_table_t::flags */
538{
539	ut_a(dict_tf_is_valid(flags));
540
541	if (!DICT_TF_GET_COMPACT(flags)) {
542		return(REC_FORMAT_REDUNDANT);
543	}
544
545	if (!DICT_TF_HAS_ATOMIC_BLOBS(flags)) {
546		return(REC_FORMAT_COMPACT);
547	}
548
549	if (DICT_TF_GET_ZIP_SSIZE(flags)) {
550		return(REC_FORMAT_COMPRESSED);
551	}
552
553	return(REC_FORMAT_DYNAMIC);
554}
555
556/** Set the various values in a dict_table_t::flags pointer.
557@param[in,out]	flags,		Pointer to a 4 byte Table Flags
558@param[in]	format		File Format
559@param[in]	zip_ssize	Zip Shift Size
560@param[in]	use_data_dir	Table uses DATA DIRECTORY
561@param[in]	page_compressed Table uses page compression
562@param[in]	page_compression_level Page compression level */
563UNIV_INLINE
564void
565dict_tf_set(
566/*========*/
567	ulint*		flags,
568	rec_format_t	format,
569	ulint		zip_ssize,
570	bool		use_data_dir,
571	bool		page_compressed,
572	ulint		page_compression_level)
573{
574	*flags = use_data_dir ? 1 << DICT_TF_POS_DATA_DIR : 0;
575
576	switch (format) {
577	case REC_FORMAT_REDUNDANT:
578		ut_ad(zip_ssize == 0);
579		/* no other options are allowed */
580		ut_ad(!page_compressed);
581		return;
582	case REC_FORMAT_COMPACT:
583		*flags |= DICT_TF_COMPACT;
584		ut_ad(zip_ssize == 0);
585		break;
586	case REC_FORMAT_COMPRESSED:
587		*flags |= DICT_TF_COMPACT
588			| (1 << DICT_TF_POS_ATOMIC_BLOBS)
589			| (zip_ssize << DICT_TF_POS_ZIP_SSIZE);
590		break;
591	case REC_FORMAT_DYNAMIC:
592		*flags |= DICT_TF_COMPACT
593			| (1 << DICT_TF_POS_ATOMIC_BLOBS);
594		ut_ad(zip_ssize == 0);
595		break;
596	}
597
598	if (page_compressed) {
599		*flags |= (1 << DICT_TF_POS_ATOMIC_BLOBS)
600		       | (1 << DICT_TF_POS_PAGE_COMPRESSION)
601		       | (page_compression_level << DICT_TF_POS_PAGE_COMPRESSION_LEVEL);
602
603		ut_ad(zip_ssize == 0);
604		ut_ad(dict_tf_get_page_compression(*flags) == TRUE);
605		ut_ad(dict_tf_get_page_compression_level(*flags) == page_compression_level);
606	}
607}
608
609/** Convert a 32 bit integer table flags to the 32 bit FSP Flags.
610Fsp Flags are written into the tablespace header at the offset
611FSP_SPACE_FLAGS and are also stored in the fil_space_t::flags field.
612The following chart shows the translation of the low order bit.
613Other bits are the same.
614========================= Low order bit ==========================
615                    | REDUNDANT | COMPACT | COMPRESSED | DYNAMIC
616dict_table_t::flags |     0     |    1    |     1      |    1
617fil_space_t::flags  |     0     |    0    |     1      |    1
618==================================================================
619@param[in]	table_flags	dict_table_t::flags
620@return tablespace flags (fil_space_t::flags) */
621UNIV_INLINE
622ulint
623dict_tf_to_fsp_flags(ulint table_flags)
624{
625	ulint fsp_flags;
626	ulint page_compression_level = DICT_TF_GET_PAGE_COMPRESSION_LEVEL(
627		table_flags);
628
629	ut_ad((DICT_TF_GET_PAGE_COMPRESSION(table_flags) == 0)
630	      == (page_compression_level == 0));
631
632	DBUG_EXECUTE_IF("dict_tf_to_fsp_flags_failure",
633			return(ULINT_UNDEFINED););
634
635	/* No ROW_FORMAT=COMPRESSED for innodb_checksum_algorithm=full_crc32 */
636	if ((srv_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_FULL_CRC32
637	     || srv_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_FULL_CRC32)
638	    && !(table_flags & DICT_TF_MASK_ZIP_SSIZE)) {
639
640		fsp_flags = 1U << FSP_FLAGS_FCRC32_POS_MARKER
641			| FSP_FLAGS_FCRC32_PAGE_SSIZE();
642
643		if (page_compression_level) {
644			fsp_flags |= innodb_compression_algorithm
645				<< FSP_FLAGS_FCRC32_POS_COMPRESSED_ALGO;
646		}
647	} else {
648		/* Adjust bit zero. */
649		fsp_flags = DICT_TF_HAS_ATOMIC_BLOBS(table_flags) ? 1 : 0;
650
651		/* ZIP_SSIZE and ATOMIC_BLOBS are at the same position. */
652		fsp_flags |= table_flags
653			& (DICT_TF_MASK_ZIP_SSIZE | DICT_TF_MASK_ATOMIC_BLOBS);
654
655		fsp_flags |= FSP_FLAGS_PAGE_SSIZE();
656
657		if (page_compression_level) {
658			fsp_flags |= FSP_FLAGS_MASK_PAGE_COMPRESSION;
659		}
660	}
661
662	ut_a(fil_space_t::is_valid_flags(fsp_flags, false));
663
664	if (DICT_TF_HAS_DATA_DIR(table_flags)) {
665		fsp_flags |= 1U << FSP_FLAGS_MEM_DATA_DIR;
666	}
667
668	fsp_flags |= page_compression_level << FSP_FLAGS_MEM_COMPRESSION_LEVEL;
669
670	return(fsp_flags);
671}
672
673/********************************************************************//**
674Convert a 32 bit integer table flags to the 32bit integer that is written
675to a SYS_TABLES.TYPE field. The following chart shows the translation of
676the low order bit.  Other bits are the same.
677========================= Low order bit ==========================
678                    | REDUNDANT | COMPACT | COMPRESSED and DYNAMIC
679dict_table_t::flags |     0     |    1    |     1
680SYS_TABLES.TYPE     |     1     |    1    |     1
681==================================================================
682@return ulint containing SYS_TABLES.TYPE */
683UNIV_INLINE
684ulint
685dict_tf_to_sys_tables_type(
686/*=======================*/
687	ulint	flags)	/*!< in: dict_table_t::flags */
688{
689	ulint type;
690
691	ut_a(dict_tf_is_valid(flags));
692
693	/* Adjust bit zero. It is always 1 in SYS_TABLES.TYPE */
694	type = 1;
695
696	/* ZIP_SSIZE, ATOMIC_BLOBS, DATA_DIR, PAGE_COMPRESSION,
697	PAGE_COMPRESSION_LEVEL are the same. */
698	type |= flags & (DICT_TF_MASK_ZIP_SSIZE
699			 | DICT_TF_MASK_ATOMIC_BLOBS
700			 | DICT_TF_MASK_DATA_DIR
701			 | DICT_TF_MASK_PAGE_COMPRESSION
702			 | DICT_TF_MASK_PAGE_COMPRESSION_LEVEL
703			 | DICT_TF_MASK_NO_ROLLBACK);
704
705	return(type);
706}
707
708/*********************************************************************//**
709Returns true if the particular FTS index in the table is still syncing
710in the background, false otherwise.
711@param [in] table      Table containing FTS index
712@return True if sync of fts index is still going in the background  */
713UNIV_INLINE
714bool
715dict_fts_index_syncing(
716	dict_table_t*   table)
717{
718	 dict_index_t*   index;
719
720	for (index = dict_table_get_first_index(table);
721	    index != NULL;
722	    index = dict_table_get_next_index(index)) {
723		if (index->index_fts_syncing) {
724			 return(true);
725		}
726	}
727	return(false);
728}
729
730/********************************************************************//**
731Gets the number of fields in the internal representation of an index,
732including fields added by the dictionary system.
733@return number of fields */
734UNIV_INLINE
735ulint
736dict_index_get_n_fields(
737/*====================*/
738	const dict_index_t*	index)	/*!< in: an internal
739					representation of index (in
740					the dictionary cache) */
741{
742	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
743	return(index->n_fields);
744}
745
746/********************************************************************//**
747Gets the number of fields in the internal representation of an index
748that uniquely determine the position of an index entry in the index, if
749we do not take multiversioning into account: in the B-tree use the value
750returned by dict_index_get_n_unique_in_tree.
751@return number of fields */
752UNIV_INLINE
753ulint
754dict_index_get_n_unique(
755/*====================*/
756	const dict_index_t*	index)	/*!< in: an internal representation
757					of index (in the dictionary cache) */
758{
759	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
760	ut_ad(index->cached);
761	return(index->n_uniq);
762}
763
764/********************************************************************//**
765Gets the number of fields in the internal representation of an index
766which uniquely determine the position of an index entry in the index, if
767we also take multiversioning into account.
768@return number of fields */
769UNIV_INLINE
770ulint
771dict_index_get_n_unique_in_tree(
772/*============================*/
773	const dict_index_t*	index)	/*!< in: an internal representation
774					of index (in the dictionary cache) */
775{
776	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
777	ut_ad(index->cached);
778
779	if (dict_index_is_clust(index)) {
780
781		return(dict_index_get_n_unique(index));
782	}
783
784	return(dict_index_get_n_fields(index));
785}
786
787/**
788Gets the number of fields on nonleaf page level in the internal representation
789of an index which uniquely determine the position of an index entry in the
790index, if we also take multiversioning into account. Note, it doesn't
791include page no field.
792@param[in]	index	index
793@return number of fields */
794UNIV_INLINE
795ulint
796dict_index_get_n_unique_in_tree_nonleaf(
797	const dict_index_t*	index)
798{
799	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
800	ut_ad(index->cached);
801
802	if (dict_index_is_spatial(index)) {
803		/* For spatial index, on non-leaf page, we have only
804		2 fields(mbr+page_no). So, except page no field,
805		there's one field there. */
806		return(DICT_INDEX_SPATIAL_NODEPTR_SIZE);
807	} else {
808		return(dict_index_get_n_unique_in_tree(index));
809	}
810}
811
812/********************************************************************//**
813Gets the number of user-defined ordering fields in the index. In the internal
814representation of clustered indexes we add the row id to the ordering fields
815to make a clustered index unique, but this function returns the number of
816fields the user defined in the index as ordering fields.
817@return number of fields */
818UNIV_INLINE
819ulint
820dict_index_get_n_ordering_defined_by_user(
821/*======================================*/
822	const dict_index_t*	index)	/*!< in: an internal representation
823					of index (in the dictionary cache) */
824{
825	return(index->n_user_defined_cols);
826}
827
828#ifdef UNIV_DEBUG
829/********************************************************************//**
830Gets the nth field of an index.
831@return pointer to field object */
832UNIV_INLINE
833dict_field_t*
834dict_index_get_nth_field(
835/*=====================*/
836	const dict_index_t*	index,	/*!< in: index */
837	ulint			pos)	/*!< in: position of field */
838{
839	ut_ad(pos < index->n_def);
840	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
841
842	return((dict_field_t*) (index->fields) + pos);
843}
844#endif /* UNIV_DEBUG */
845
846/*********************************************************************//**
847Gets the field column.
848@return field->col, pointer to the table column */
849UNIV_INLINE
850const dict_col_t*
851dict_field_get_col(
852/*===============*/
853	const dict_field_t*	field)	/*!< in: index field */
854{
855	return(field->col);
856}
857
858/********************************************************************//**
859Gets pointer to the nth column in an index.
860@return column */
861UNIV_INLINE
862const dict_col_t*
863dict_index_get_nth_col(
864/*===================*/
865	const dict_index_t*	index,	/*!< in: index */
866	ulint			pos)	/*!< in: position of the field */
867{
868	return(dict_field_get_col(dict_index_get_nth_field(index, pos)));
869}
870
871/********************************************************************//**
872Gets the column number the nth field in an index.
873@return column number */
874UNIV_INLINE
875ulint
876dict_index_get_nth_col_no(
877/*======================*/
878	const dict_index_t*	index,	/*!< in: index */
879	ulint			pos)	/*!< in: position of the field */
880{
881	return(dict_col_get_no(dict_index_get_nth_col(index, pos)));
882}
883
884/********************************************************************//**
885Looks for column n in an index.
886@return position in internal representation of the index;
887ULINT_UNDEFINED if not contained */
888UNIV_INLINE
889ulint
890dict_index_get_nth_col_pos(
891/*=======================*/
892	const dict_index_t*	index,	/*!< in: index */
893	ulint			n,	/*!< in: column number */
894	ulint*			prefix_col_pos) /*!< out: col num if prefix */
895{
896	return(dict_index_get_nth_col_or_prefix_pos(index, n, false, false,
897						    prefix_col_pos));
898}
899
900/********************************************************************//**
901Returns the minimum data size of an index record.
902@return minimum data size in bytes */
903UNIV_INLINE
904ulint
905dict_index_get_min_size(
906/*====================*/
907	const dict_index_t*	index)	/*!< in: index */
908{
909	ulint	n	= dict_index_get_n_fields(index);
910	ulint	size	= 0;
911
912	while (n--) {
913		size += dict_col_get_min_size(dict_index_get_nth_col(index,
914								     n));
915	}
916
917	return(size);
918}
919
920/*********************************************************************//**
921Gets the page number of the root of the index tree.
922@return page number */
923UNIV_INLINE
924ulint
925dict_index_get_page(
926/*================*/
927	const dict_index_t*	index)	/*!< in: index */
928{
929	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
930
931	return(index->page);
932}
933
934/*********************************************************************//**
935Gets the read-write lock of the index tree.
936@return read-write lock */
937UNIV_INLINE
938rw_lock_t*
939dict_index_get_lock(
940/*================*/
941	const dict_index_t*	index)	/*!< in: index */
942{
943	ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
944
945	return(&(index->lock));
946}
947
948/********************************************************************//**
949Returns free space reserved for future updates of records. This is
950relevant only in the case of many consecutive inserts, as updates
951which make the records bigger might fragment the index.
952@return number of free bytes on page, reserved for updates */
953UNIV_INLINE
954ulint
955dict_index_get_space_reserve(void)
956/*==============================*/
957{
958	return(srv_page_size / 16);
959}
960
961/********************************************************************//**
962Gets the status of online index creation.
963@return the status */
964UNIV_INLINE
965enum online_index_status
966dict_index_get_online_status(
967/*=========================*/
968	const dict_index_t*	index)	/*!< in: secondary index */
969{
970	enum online_index_status	status;
971
972	status = (enum online_index_status) index->online_status;
973
974	/* Without the index->lock protection, the online
975	status can change from ONLINE_INDEX_CREATION to
976	ONLINE_INDEX_COMPLETE (or ONLINE_INDEX_ABORTED) in
977	row_log_apply() once log application is done. So to make
978	sure the status is ONLINE_INDEX_CREATION or ONLINE_INDEX_COMPLETE
979	you should always do the recheck after acquiring index->lock */
980
981#ifdef UNIV_DEBUG
982	switch (status) {
983	case ONLINE_INDEX_COMPLETE:
984	case ONLINE_INDEX_CREATION:
985	case ONLINE_INDEX_ABORTED:
986	case ONLINE_INDEX_ABORTED_DROPPED:
987		return(status);
988	}
989	ut_error;
990#endif /* UNIV_DEBUG */
991	return(status);
992}
993
994/********************************************************************//**
995Sets the status of online index creation. */
996UNIV_INLINE
997void
998dict_index_set_online_status(
999/*=========================*/
1000	dict_index_t*			index,	/*!< in/out: index */
1001	enum online_index_status	status)	/*!< in: status */
1002{
1003	ut_ad(!(index->type & DICT_FTS));
1004	ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_X));
1005
1006#ifdef UNIV_DEBUG
1007	switch (dict_index_get_online_status(index)) {
1008	case ONLINE_INDEX_COMPLETE:
1009	case ONLINE_INDEX_CREATION:
1010		break;
1011	case ONLINE_INDEX_ABORTED:
1012		ut_ad(status == ONLINE_INDEX_ABORTED_DROPPED);
1013		break;
1014	case ONLINE_INDEX_ABORTED_DROPPED:
1015		ut_error;
1016	}
1017#endif /* UNIV_DEBUG */
1018
1019	index->online_status = status;
1020	ut_ad(dict_index_get_online_status(index) == status);
1021}
1022
1023/********************************************************************//**
1024Determines if a secondary index is being or has been created online,
1025or if the table is being rebuilt online, allowing concurrent modifications
1026to the table.
1027@retval true if the index is being or has been built online, or
1028if this is a clustered index and the table is being or has been rebuilt online
1029@retval false if the index has been created or the table has been
1030rebuilt completely */
1031UNIV_INLINE
1032bool
1033dict_index_is_online_ddl(
1034/*=====================*/
1035	const dict_index_t*	index)	/*!< in: index */
1036{
1037#ifdef UNIV_DEBUG
1038	if (dict_index_is_clust(index)) {
1039		switch (dict_index_get_online_status(index)) {
1040		case ONLINE_INDEX_CREATION:
1041			return(true);
1042		case ONLINE_INDEX_COMPLETE:
1043			return(false);
1044		case ONLINE_INDEX_ABORTED:
1045		case ONLINE_INDEX_ABORTED_DROPPED:
1046			break;
1047		}
1048		ut_ad(0);
1049		return(false);
1050	}
1051#endif /* UNIV_DEBUG */
1052
1053	return(UNIV_UNLIKELY(dict_index_get_online_status(index)
1054			     != ONLINE_INDEX_COMPLETE));
1055}
1056
1057/**********************************************************************//**
1058Check whether a column exists in an FTS index.
1059@return ULINT_UNDEFINED if no match else the offset within the vector */
1060UNIV_INLINE
1061ulint
1062dict_table_is_fts_column(
1063/*=====================*/
1064	ib_vector_t*	indexes,/*!< in: vector containing only FTS indexes */
1065	ulint		col_no,	/*!< in: col number to search for */
1066	bool		is_virtual) /*!< in: whether it is a virtual column */
1067
1068{
1069	ulint		i;
1070
1071	for (i = 0; i < ib_vector_size(indexes); ++i) {
1072		dict_index_t*	index;
1073
1074		index = (dict_index_t*) ib_vector_getp(indexes, i);
1075
1076		if (index->contains_col_or_prefix(col_no, is_virtual)) {
1077			return(i);
1078		}
1079	}
1080
1081	return(ULINT_UNDEFINED);
1082}
1083
1084/**********************************************************************//**
1085Determine bytes of column prefix to be stored in the undo log. Please
1086note that if !dict_table_has_atomic_blobs(table), no prefix
1087needs to be stored in the undo log.
1088@return bytes of column prefix to be stored in the undo log */
1089UNIV_INLINE
1090ulint
1091dict_max_field_len_store_undo(
1092/*==========================*/
1093	dict_table_t*		table,	/*!< in: table */
1094	const dict_col_t*	col)	/*!< in: column which index prefix
1095					is based on */
1096{
1097	if (!dict_table_has_atomic_blobs(table)) {
1098		return(0);
1099	}
1100
1101	if (col->max_prefix != 0) {
1102		return(col->max_prefix);
1103	}
1104
1105	return(REC_VERSION_56_MAX_INDEX_COL_LEN);
1106}
1107
1108/** Determine maximum bytes of a virtual column need to be stored
1109in the undo log.
1110@param[in]	table		dict_table_t for the table
1111@param[in]	col_no		virtual column number
1112@return maximum bytes of virtual column to be stored in the undo log */
1113UNIV_INLINE
1114ulint
1115dict_max_v_field_len_store_undo(
1116	dict_table_t*		table,
1117	ulint			col_no)
1118{
1119	const dict_col_t*	col
1120		= &dict_table_get_nth_v_col(table, col_no)->m_col;
1121	ulint			max_log_len;
1122
1123	/* This calculation conforms to the non-virtual column
1124	maximum log length calculation:
1125	1) if No atomic BLOB, upto REC_ANTELOPE_MAX_INDEX_COL_LEN
1126	2) if atomic BLOB, upto col->max_prefix or
1127	REC_VERSION_56_MAX_INDEX_COL_LEN, whichever is less */
1128	if (dict_table_has_atomic_blobs(table)) {
1129		if (DATA_BIG_COL(col) && col->max_prefix > 0) {
1130			max_log_len = col->max_prefix;
1131		} else {
1132			max_log_len = DICT_MAX_FIELD_LEN_BY_FORMAT(table);
1133		}
1134	} else {
1135		max_log_len = REC_ANTELOPE_MAX_INDEX_COL_LEN;
1136	}
1137
1138	return(max_log_len);
1139}
1140
1141/********************************************************************//**
1142Check whether the table is corrupted.
1143@return nonzero for corrupted table, zero for valid tables */
1144UNIV_INLINE
1145ulint
1146dict_table_is_corrupted(
1147/*====================*/
1148	const dict_table_t*	table)	/*!< in: table */
1149{
1150	ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
1151	return(table->corrupted);
1152}
1153
1154/** Check if the table is found is a file_per_table tablespace.
1155This test does not use table flags2 since some REDUNDANT tables in the
1156system tablespace may have garbage in the MIX_LEN field where flags2 is
1157stored. These garbage MIX_LEN fields were written before v3.23.52.
1158A patch was added to v3.23.52 which initializes the MIX_LEN field to 0.
1159Since file-per-table tablespaces were added in 4.1, any SYS_TABLES
1160record with a non-zero space ID will have a reliable MIX_LEN field.
1161However, this test does not use flags2 from SYS_TABLES.MIX_LEN.  Instead,
1162assume that if the tablespace is not a predefined system tablespace,
1163 then it must be file-per-table.
1164Also, during ALTER TABLE, the DICT_TF2_USE_FILE_PER_TABLE flag may not be
1165set on one of the file-per-table tablespaces.
1166This test cannot be done on a table in the process of being created
1167because the space_id will be zero until the tablespace is created.
1168@param[in]	table	An existing open table to check
1169@return true if this table was created as a file-per-table tablespace. */
1170UNIV_INLINE
1171bool
1172dict_table_is_file_per_table(
1173	const dict_table_t*	table)	/*!< in: table to check */
1174{
1175	return table->space != fil_system.sys_space
1176		&& table->space != fil_system.temp_space;
1177}
1178
1179/** Acquire the table handle. */
1180inline
1181void
1182dict_table_t::acquire()
1183{
1184	ut_ad(mutex_own(&dict_sys.mutex));
1185	n_ref_count++;
1186}
1187
1188/** Release the table handle.
1189@return	whether the last handle was released */
1190inline
1191bool
1192dict_table_t::release()
1193{
1194	auto n = n_ref_count--;
1195	ut_ad(n > 0);
1196	return n == 1;
1197}
1198
1199/** Encode the number of columns and number of virtual columns in a
12004 bytes value. We could do this because the number of columns in
1201InnoDB is limited to 1017
1202@param[in]      n_col   number of non-virtual column
1203@param[in]      n_v_col number of virtual column
1204@return encoded value */
1205UNIV_INLINE
1206ulint
1207dict_table_encode_n_col(
1208                ulint   n_col,
1209                ulint   n_v_col)
1210{
1211	return(n_col + (n_v_col<<16));
1212}
1213
1214/** decode number of virtual and non-virtual columns in one 4 bytes value.
1215@param[in]      encoded encoded value
1216@param[in,out]     n_col   number of non-virtual column
1217@param[in,out]     n_v_col number of virtual column */
1218UNIV_INLINE
1219void
1220dict_table_decode_n_col(
1221                ulint   encoded,
1222                ulint*  n_col,
1223                ulint*  n_v_col)
1224{
1225
1226	ulint	num = encoded & ~DICT_N_COLS_COMPACT;
1227	*n_v_col = num >> 16;
1228	*n_col = num & 0xFFFF;
1229}
1230
1231/** Free the virtual column template
1232@param[in,out]	vc_templ	virtual column template */
1233void
1234dict_free_vc_templ(
1235	dict_vcol_templ_t*	vc_templ)
1236{
1237	UT_DELETE_ARRAY(vc_templ->default_rec);
1238	vc_templ->default_rec = NULL;
1239
1240	if (vc_templ->vtempl != NULL) {
1241		ut_ad(vc_templ->n_v_col > 0);
1242		for (ulint i = 0; i < vc_templ->n_col
1243		     + vc_templ->n_v_col; i++) {
1244			if (vc_templ->vtempl[i] != NULL) {
1245				ut_free(vc_templ->vtempl[i]);
1246			}
1247		}
1248		ut_free(vc_templ->vtempl);
1249		vc_templ->vtempl = NULL;
1250	}
1251}
1252
1253/** Check whether the table have virtual index.
1254@param[in]	table	InnoDB table
1255@return true if the table have virtual index, false otherwise. */
1256UNIV_INLINE
1257bool
1258dict_table_have_virtual_index(
1259	dict_table_t*	table)
1260{
1261	for (ulint col_no = 0; col_no < dict_table_get_n_v_cols(table);
1262	     col_no++) {
1263		const dict_v_col_t*	col
1264			= dict_table_get_nth_v_col(table, col_no);
1265
1266		if (col->m_col.ord_part) {
1267			return(true);
1268		}
1269	}
1270
1271	return(false);
1272}
1273