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