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