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