1/***************************************************************************** 2 3Copyright (c) 1994, 2016, 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/rem0rec.ic 29Record manager 30 31Created 5/30/1994 Heikki Tuuri 32*************************************************************************/ 33 34#include "mach0data.h" 35#include "ut0byte.h" 36#include "dict0dict.h" 37#include "btr0types.h" 38 39/* Compact flag ORed to the extra size returned by rec_get_offsets() */ 40#define REC_OFFS_COMPACT ((ulint) 1 << 31) 41/* SQL NULL flag in offsets returned by rec_get_offsets() */ 42#define REC_OFFS_SQL_NULL ((ulint) 1 << 31) 43/* External flag in offsets returned by rec_get_offsets() */ 44#define REC_OFFS_EXTERNAL ((ulint) 1 << 30) 45/* Mask for offsets returned by rec_get_offsets() */ 46#define REC_OFFS_MASK (REC_OFFS_EXTERNAL - 1) 47 48/* Offsets of the bit-fields in an old-style record. NOTE! In the table the 49most significant bytes and bits are written below less significant. 50 51 (1) byte offset (2) bit usage within byte 52 downward from 53 origin -> 1 8 bits pointer to next record 54 2 8 bits pointer to next record 55 3 1 bit short flag 56 7 bits number of fields 57 4 3 bits number of fields 58 5 bits heap number 59 5 8 bits heap number 60 6 4 bits n_owned 61 4 bits info bits 62*/ 63 64/* Offsets of the bit-fields in a new-style record. NOTE! In the table the 65most significant bytes and bits are written below less significant. 66 67 (1) byte offset (2) bit usage within byte 68 downward from 69 origin -> 1 8 bits relative offset of next record 70 2 8 bits relative offset of next record 71 the relative offset is an unsigned 16-bit 72 integer: 73 (offset_of_next_record 74 - offset_of_this_record) mod 64Ki, 75 where mod is the modulo as a non-negative 76 number; 77 we can calculate the offset of the next 78 record with the formula: 79 relative_offset + offset_of_this_record 80 mod UNIV_PAGE_SIZE 81 3 3 bits status: 82 000=conventional record 83 001=node pointer record (inside B-tree) 84 010=infimum record 85 011=supremum record 86 1xx=reserved 87 5 bits heap number 88 4 8 bits heap number 89 5 4 bits n_owned 90 4 bits info bits 91*/ 92 93/* We list the byte offsets from the origin of the record, the mask, 94and the shift needed to obtain each bit-field of the record. */ 95 96#define REC_NEXT 2 97#define REC_NEXT_MASK 0xFFFFUL 98#define REC_NEXT_SHIFT 0 99 100#define REC_OLD_SHORT 3 /* This is single byte bit-field */ 101#define REC_OLD_SHORT_MASK 0x1UL 102#define REC_OLD_SHORT_SHIFT 0 103 104#define REC_OLD_N_FIELDS 4 105#define REC_OLD_N_FIELDS_MASK 0x7FEUL 106#define REC_OLD_N_FIELDS_SHIFT 1 107 108#define REC_NEW_STATUS 3 /* This is single byte bit-field */ 109#define REC_NEW_STATUS_MASK 0x7UL 110#define REC_NEW_STATUS_SHIFT 0 111 112#define REC_OLD_HEAP_NO 5 113#define REC_HEAP_NO_MASK 0xFFF8UL 114#if 0 /* defined in rem0rec.h for use of page0zip.cc */ 115#define REC_NEW_HEAP_NO 4 116#define REC_HEAP_NO_SHIFT 3 117#endif 118 119#define REC_OLD_N_OWNED 6 /* This is single byte bit-field */ 120#define REC_NEW_N_OWNED 5 /* This is single byte bit-field */ 121#define REC_N_OWNED_MASK 0xFUL 122#define REC_N_OWNED_SHIFT 0 123 124#define REC_OLD_INFO_BITS 6 /* This is single byte bit-field */ 125#define REC_NEW_INFO_BITS 5 /* This is single byte bit-field */ 126#define REC_INFO_BITS_MASK 0xF0UL 127#define REC_INFO_BITS_SHIFT 0 128 129#if REC_OLD_SHORT_MASK << (8 * (REC_OLD_SHORT - 3)) \ 130 ^ REC_OLD_N_FIELDS_MASK << (8 * (REC_OLD_N_FIELDS - 4)) \ 131 ^ REC_HEAP_NO_MASK << (8 * (REC_OLD_HEAP_NO - 4)) \ 132 ^ REC_N_OWNED_MASK << (8 * (REC_OLD_N_OWNED - 3)) \ 133 ^ REC_INFO_BITS_MASK << (8 * (REC_OLD_INFO_BITS - 3)) \ 134 ^ 0xFFFFFFFFUL 135# error "sum of old-style masks != 0xFFFFFFFFUL" 136#endif 137#if REC_NEW_STATUS_MASK << (8 * (REC_NEW_STATUS - 3)) \ 138 ^ REC_HEAP_NO_MASK << (8 * (REC_NEW_HEAP_NO - 4)) \ 139 ^ REC_N_OWNED_MASK << (8 * (REC_NEW_N_OWNED - 3)) \ 140 ^ REC_INFO_BITS_MASK << (8 * (REC_NEW_INFO_BITS - 3)) \ 141 ^ 0xFFFFFFUL 142# error "sum of new-style masks != 0xFFFFFFUL" 143#endif 144 145/***********************************************************//** 146Sets the value of the ith field SQL null bit of an old-style record. */ 147UNIV_INTERN 148void 149rec_set_nth_field_null_bit( 150/*=======================*/ 151 rec_t* rec, /*!< in: record */ 152 ulint i, /*!< in: ith field */ 153 ibool val); /*!< in: value to set */ 154/***********************************************************//** 155Sets an old-style record field to SQL null. 156The physical size of the field is not changed. */ 157UNIV_INTERN 158void 159rec_set_nth_field_sql_null( 160/*=======================*/ 161 rec_t* rec, /*!< in: record */ 162 ulint n); /*!< in: index of the field */ 163 164/******************************************************//** 165Gets a bit field from within 1 byte. */ 166UNIV_INLINE 167ulint 168rec_get_bit_field_1( 169/*================*/ 170 const rec_t* rec, /*!< in: pointer to record origin */ 171 ulint offs, /*!< in: offset from the origin down */ 172 ulint mask, /*!< in: mask used to filter bits */ 173 ulint shift) /*!< in: shift right applied after masking */ 174{ 175 ut_ad(rec); 176 177 return((mach_read_from_1(rec - offs) & mask) >> shift); 178} 179 180/******************************************************//** 181Sets a bit field within 1 byte. */ 182UNIV_INLINE 183void 184rec_set_bit_field_1( 185/*================*/ 186 rec_t* rec, /*!< in: pointer to record origin */ 187 ulint val, /*!< in: value to set */ 188 ulint offs, /*!< in: offset from the origin down */ 189 ulint mask, /*!< in: mask used to filter bits */ 190 ulint shift) /*!< in: shift right applied after masking */ 191{ 192 ut_ad(rec); 193 ut_ad(offs <= REC_N_OLD_EXTRA_BYTES); 194 ut_ad(mask); 195 ut_ad(mask <= 0xFFUL); 196 ut_ad(((mask >> shift) << shift) == mask); 197 ut_ad(((val << shift) & mask) == (val << shift)); 198 199 mach_write_to_1(rec - offs, 200 (mach_read_from_1(rec - offs) & ~mask) 201 | (val << shift)); 202} 203 204/******************************************************//** 205Gets a bit field from within 2 bytes. */ 206UNIV_INLINE 207ulint 208rec_get_bit_field_2( 209/*================*/ 210 const rec_t* rec, /*!< in: pointer to record origin */ 211 ulint offs, /*!< in: offset from the origin down */ 212 ulint mask, /*!< in: mask used to filter bits */ 213 ulint shift) /*!< in: shift right applied after masking */ 214{ 215 ut_ad(rec); 216 217 return((mach_read_from_2(rec - offs) & mask) >> shift); 218} 219 220/******************************************************//** 221Sets a bit field within 2 bytes. */ 222UNIV_INLINE 223void 224rec_set_bit_field_2( 225/*================*/ 226 rec_t* rec, /*!< in: pointer to record origin */ 227 ulint val, /*!< in: value to set */ 228 ulint offs, /*!< in: offset from the origin down */ 229 ulint mask, /*!< in: mask used to filter bits */ 230 ulint shift) /*!< in: shift right applied after masking */ 231{ 232 ut_ad(rec); 233 ut_ad(offs <= REC_N_OLD_EXTRA_BYTES); 234 ut_ad(mask > 0xFFUL); 235 ut_ad(mask <= 0xFFFFUL); 236 ut_ad((mask >> shift) & 1); 237 ut_ad(0 == ((mask >> shift) & ((mask >> shift) + 1))); 238 ut_ad(((mask >> shift) << shift) == mask); 239 ut_ad(((val << shift) & mask) == (val << shift)); 240 241 mach_write_to_2(rec - offs, 242 (mach_read_from_2(rec - offs) & ~mask) 243 | (val << shift)); 244} 245 246/******************************************************//** 247The following function is used to get the pointer of the next chained record 248on the same page. 249@return pointer to the next chained record, or NULL if none */ 250UNIV_INLINE 251const rec_t* 252rec_get_next_ptr_const( 253/*===================*/ 254 const rec_t* rec, /*!< in: physical record */ 255 ulint comp) /*!< in: nonzero=compact page format */ 256{ 257 ulint field_value; 258 259 ut_ad(REC_NEXT_MASK == 0xFFFFUL); 260 ut_ad(REC_NEXT_SHIFT == 0); 261 262 field_value = mach_read_from_2(rec - REC_NEXT); 263 264 if (field_value == 0) { 265 266 return(NULL); 267 } 268 269 if (comp) { 270#if UNIV_PAGE_SIZE_MAX <= 32768 271 /* Note that for 64 KiB pages, field_value can 'wrap around' 272 and the debug assertion is not valid */ 273 274 /* In the following assertion, field_value is interpreted 275 as signed 16-bit integer in 2's complement arithmetics. 276 If all platforms defined int16_t in the standard headers, 277 the expression could be written simpler as 278 (int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE 279 */ 280 ut_ad((field_value >= 32768 281 ? field_value - 65536 282 : field_value) 283 + ut_align_offset(rec, UNIV_PAGE_SIZE) 284 < UNIV_PAGE_SIZE); 285#endif 286 /* There must be at least REC_N_NEW_EXTRA_BYTES + 1 287 between each record. */ 288 ut_ad((field_value > REC_N_NEW_EXTRA_BYTES 289 && field_value < 32768) 290 || field_value < (uint16) -REC_N_NEW_EXTRA_BYTES); 291 292 return((byte*) ut_align_down(rec, UNIV_PAGE_SIZE) 293 + ut_align_offset(rec + field_value, UNIV_PAGE_SIZE)); 294 } else { 295 ut_ad(field_value < UNIV_PAGE_SIZE); 296 297 return((byte*) ut_align_down(rec, UNIV_PAGE_SIZE) 298 + field_value); 299 } 300} 301 302/******************************************************//** 303The following function is used to get the pointer of the next chained record 304on the same page. 305@return pointer to the next chained record, or NULL if none */ 306UNIV_INLINE 307rec_t* 308rec_get_next_ptr( 309/*=============*/ 310 rec_t* rec, /*!< in: physical record */ 311 ulint comp) /*!< in: nonzero=compact page format */ 312{ 313 return(const_cast<rec_t*>(rec_get_next_ptr_const(rec, comp))); 314} 315 316/******************************************************//** 317The following function is used to get the offset of the next chained record 318on the same page. 319@return the page offset of the next chained record, or 0 if none */ 320UNIV_INLINE 321ulint 322rec_get_next_offs( 323/*==============*/ 324 const rec_t* rec, /*!< in: physical record */ 325 ulint comp) /*!< in: nonzero=compact page format */ 326{ 327 ulint field_value; 328#if REC_NEXT_MASK != 0xFFFFUL 329# error "REC_NEXT_MASK != 0xFFFFUL" 330#endif 331#if REC_NEXT_SHIFT 332# error "REC_NEXT_SHIFT != 0" 333#endif 334 335 field_value = mach_read_from_2(rec - REC_NEXT); 336 337 if (comp) { 338#if UNIV_PAGE_SIZE_MAX <= 32768 339 /* Note that for 64 KiB pages, field_value can 'wrap around' 340 and the debug assertion is not valid */ 341 342 /* In the following assertion, field_value is interpreted 343 as signed 16-bit integer in 2's complement arithmetics. 344 If all platforms defined int16_t in the standard headers, 345 the expression could be written simpler as 346 (int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE 347 */ 348 ut_ad((field_value >= 32768 349 ? field_value - 65536 350 : field_value) 351 + ut_align_offset(rec, UNIV_PAGE_SIZE) 352 < UNIV_PAGE_SIZE); 353#endif 354 if (field_value == 0) { 355 356 return(0); 357 } 358 359 /* There must be at least REC_N_NEW_EXTRA_BYTES + 1 360 between each record. */ 361 ut_ad((field_value > REC_N_NEW_EXTRA_BYTES 362 && field_value < 32768) 363 || field_value < (uint16) -REC_N_NEW_EXTRA_BYTES); 364 365 return(ut_align_offset(rec + field_value, UNIV_PAGE_SIZE)); 366 } else { 367 ut_ad(field_value < UNIV_PAGE_SIZE); 368 369 return(field_value); 370 } 371} 372 373/******************************************************//** 374The following function is used to set the next record offset field 375of an old-style record. */ 376UNIV_INLINE 377void 378rec_set_next_offs_old( 379/*==================*/ 380 rec_t* rec, /*!< in: old-style physical record */ 381 ulint next) /*!< in: offset of the next record */ 382{ 383 ut_ad(rec); 384 ut_ad(UNIV_PAGE_SIZE > next); 385#if REC_NEXT_MASK != 0xFFFFUL 386# error "REC_NEXT_MASK != 0xFFFFUL" 387#endif 388#if REC_NEXT_SHIFT 389# error "REC_NEXT_SHIFT != 0" 390#endif 391 392 mach_write_to_2(rec - REC_NEXT, next); 393} 394 395/******************************************************//** 396The following function is used to set the next record offset field 397of a new-style record. */ 398UNIV_INLINE 399void 400rec_set_next_offs_new( 401/*==================*/ 402 rec_t* rec, /*!< in/out: new-style physical record */ 403 ulint next) /*!< in: offset of the next record */ 404{ 405 ulint field_value; 406 407 ut_ad(rec); 408 ut_ad(UNIV_PAGE_SIZE > next); 409 410 if (!next) { 411 field_value = 0; 412 } else { 413 /* The following two statements calculate 414 next - offset_of_rec mod 64Ki, where mod is the modulo 415 as a non-negative number */ 416 417 field_value = (ulint) 418 ((lint) next 419 - (lint) ut_align_offset(rec, UNIV_PAGE_SIZE)); 420 field_value &= REC_NEXT_MASK; 421 } 422 423 mach_write_to_2(rec - REC_NEXT, field_value); 424} 425 426/******************************************************//** 427The following function is used to get the number of fields 428in an old-style record. 429@return number of data fields */ 430UNIV_INLINE 431ulint 432rec_get_n_fields_old( 433/*=================*/ 434 const rec_t* rec) /*!< in: physical record */ 435{ 436 ulint ret; 437 438 ut_ad(rec); 439 440 ret = rec_get_bit_field_2(rec, REC_OLD_N_FIELDS, 441 REC_OLD_N_FIELDS_MASK, 442 REC_OLD_N_FIELDS_SHIFT); 443 ut_ad(ret <= REC_MAX_N_FIELDS); 444 ut_ad(ret > 0); 445 446 return(ret); 447} 448 449/******************************************************//** 450The following function is used to set the number of fields 451in an old-style record. */ 452UNIV_INLINE 453void 454rec_set_n_fields_old( 455/*=================*/ 456 rec_t* rec, /*!< in: physical record */ 457 ulint n_fields) /*!< in: the number of fields */ 458{ 459 ut_ad(rec); 460 ut_ad(n_fields <= REC_MAX_N_FIELDS); 461 ut_ad(n_fields > 0); 462 463 rec_set_bit_field_2(rec, n_fields, REC_OLD_N_FIELDS, 464 REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT); 465} 466 467/******************************************************//** 468The following function retrieves the status bits of a new-style record. 469@return status bits */ 470UNIV_INLINE 471ulint 472rec_get_status( 473/*===========*/ 474 const rec_t* rec) /*!< in: physical record */ 475{ 476 ulint ret; 477 478 ut_ad(rec); 479 480 ret = rec_get_bit_field_1(rec, REC_NEW_STATUS, 481 REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT); 482 ut_ad((ret & ~REC_NEW_STATUS_MASK) == 0); 483 484 return(ret); 485} 486 487/******************************************************//** 488The following function is used to get the number of fields 489in a record. 490@return number of data fields */ 491UNIV_INLINE 492ulint 493rec_get_n_fields( 494/*=============*/ 495 const rec_t* rec, /*!< in: physical record */ 496 const dict_index_t* index) /*!< in: record descriptor */ 497{ 498 ut_ad(rec); 499 ut_ad(index); 500 501 if (!dict_table_is_comp(index->table)) { 502 return(rec_get_n_fields_old(rec)); 503 } 504 505 switch (rec_get_status(rec)) { 506 case REC_STATUS_ORDINARY: 507 return(dict_index_get_n_fields(index)); 508 case REC_STATUS_NODE_PTR: 509 return(dict_index_get_n_unique_in_tree(index) + 1); 510 case REC_STATUS_INFIMUM: 511 case REC_STATUS_SUPREMUM: 512 return(1); 513 default: 514 ut_error; 515 return(ULINT_UNDEFINED); 516 } 517} 518 519/******************************************************//** 520The following function is used to get the number of records owned by the 521previous directory record. 522@return number of owned records */ 523UNIV_INLINE 524ulint 525rec_get_n_owned_old( 526/*================*/ 527 const rec_t* rec) /*!< in: old-style physical record */ 528{ 529 return(rec_get_bit_field_1(rec, REC_OLD_N_OWNED, 530 REC_N_OWNED_MASK, REC_N_OWNED_SHIFT)); 531} 532 533/******************************************************//** 534The following function is used to set the number of owned records. */ 535UNIV_INLINE 536void 537rec_set_n_owned_old( 538/*================*/ 539 rec_t* rec, /*!< in: old-style physical record */ 540 ulint n_owned) /*!< in: the number of owned */ 541{ 542 rec_set_bit_field_1(rec, n_owned, REC_OLD_N_OWNED, 543 REC_N_OWNED_MASK, REC_N_OWNED_SHIFT); 544} 545 546/******************************************************//** 547The following function is used to get the number of records owned by the 548previous directory record. 549@return number of owned records */ 550UNIV_INLINE 551ulint 552rec_get_n_owned_new( 553/*================*/ 554 const rec_t* rec) /*!< in: new-style physical record */ 555{ 556 return(rec_get_bit_field_1(rec, REC_NEW_N_OWNED, 557 REC_N_OWNED_MASK, REC_N_OWNED_SHIFT)); 558} 559 560/******************************************************//** 561The following function is used to set the number of owned records. */ 562UNIV_INLINE 563void 564rec_set_n_owned_new( 565/*================*/ 566 rec_t* rec, /*!< in/out: new-style physical record */ 567 page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ 568 ulint n_owned)/*!< in: the number of owned */ 569{ 570 rec_set_bit_field_1(rec, n_owned, REC_NEW_N_OWNED, 571 REC_N_OWNED_MASK, REC_N_OWNED_SHIFT); 572 if (page_zip && rec_get_status(rec) != REC_STATUS_SUPREMUM) { 573 page_zip_rec_set_owned(page_zip, rec, n_owned); 574 } 575} 576 577/******************************************************//** 578The following function is used to retrieve the info bits of a record. 579@return info bits */ 580UNIV_INLINE 581ulint 582rec_get_info_bits( 583/*==============*/ 584 const rec_t* rec, /*!< in: physical record */ 585 ulint comp) /*!< in: nonzero=compact page format */ 586{ 587 return(rec_get_bit_field_1( 588 rec, comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS, 589 REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT)); 590} 591 592/******************************************************//** 593The following function is used to set the info bits of a record. */ 594UNIV_INLINE 595void 596rec_set_info_bits_old( 597/*==================*/ 598 rec_t* rec, /*!< in: old-style physical record */ 599 ulint bits) /*!< in: info bits */ 600{ 601 rec_set_bit_field_1(rec, bits, REC_OLD_INFO_BITS, 602 REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT); 603} 604/******************************************************//** 605The following function is used to set the info bits of a record. */ 606UNIV_INLINE 607void 608rec_set_info_bits_new( 609/*==================*/ 610 rec_t* rec, /*!< in/out: new-style physical record */ 611 ulint bits) /*!< in: info bits */ 612{ 613 rec_set_bit_field_1(rec, bits, REC_NEW_INFO_BITS, 614 REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT); 615} 616 617/******************************************************//** 618The following function is used to set the status bits of a new-style record. */ 619UNIV_INLINE 620void 621rec_set_status( 622/*===========*/ 623 rec_t* rec, /*!< in/out: physical record */ 624 ulint bits) /*!< in: info bits */ 625{ 626 rec_set_bit_field_1(rec, bits, REC_NEW_STATUS, 627 REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT); 628} 629 630/******************************************************//** 631The following function is used to retrieve the info and status 632bits of a record. (Only compact records have status bits.) 633@return info bits */ 634UNIV_INLINE 635ulint 636rec_get_info_and_status_bits( 637/*=========================*/ 638 const rec_t* rec, /*!< in: physical record */ 639 ulint comp) /*!< in: nonzero=compact page format */ 640{ 641 ulint bits; 642#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \ 643& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT) 644# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap" 645#endif 646 if (comp) { 647 bits = rec_get_info_bits(rec, TRUE) | rec_get_status(rec); 648 } else { 649 bits = rec_get_info_bits(rec, FALSE); 650 ut_ad(!(bits & ~(REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT))); 651 } 652 return(bits); 653} 654/******************************************************//** 655The following function is used to set the info and status 656bits of a record. (Only compact records have status bits.) */ 657UNIV_INLINE 658void 659rec_set_info_and_status_bits( 660/*=========================*/ 661 rec_t* rec, /*!< in/out: physical record */ 662 ulint bits) /*!< in: info bits */ 663{ 664#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \ 665& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT) 666# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap" 667#endif 668 rec_set_status(rec, bits & REC_NEW_STATUS_MASK); 669 rec_set_info_bits_new(rec, bits & ~REC_NEW_STATUS_MASK); 670} 671 672/******************************************************//** 673The following function tells if record is delete marked. 674@return nonzero if delete marked */ 675UNIV_INLINE 676ulint 677rec_get_deleted_flag( 678/*=================*/ 679 const rec_t* rec, /*!< in: physical record */ 680 ulint comp) /*!< in: nonzero=compact page format */ 681{ 682 if (comp) { 683 return(rec_get_bit_field_1(rec, REC_NEW_INFO_BITS, 684 REC_INFO_DELETED_FLAG, 685 REC_INFO_BITS_SHIFT)); 686 } else { 687 return(rec_get_bit_field_1(rec, REC_OLD_INFO_BITS, 688 REC_INFO_DELETED_FLAG, 689 REC_INFO_BITS_SHIFT)); 690 } 691} 692 693/******************************************************//** 694The following function is used to set the deleted bit. */ 695UNIV_INLINE 696void 697rec_set_deleted_flag_old( 698/*=====================*/ 699 rec_t* rec, /*!< in: old-style physical record */ 700 ulint flag) /*!< in: nonzero if delete marked */ 701{ 702 ulint val; 703 704 val = rec_get_info_bits(rec, FALSE); 705 706 if (flag) { 707 val |= REC_INFO_DELETED_FLAG; 708 } else { 709 val &= ~REC_INFO_DELETED_FLAG; 710 } 711 712 rec_set_info_bits_old(rec, val); 713} 714 715/******************************************************//** 716The following function is used to set the deleted bit. */ 717UNIV_INLINE 718void 719rec_set_deleted_flag_new( 720/*=====================*/ 721 rec_t* rec, /*!< in/out: new-style physical record */ 722 page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */ 723 ulint flag) /*!< in: nonzero if delete marked */ 724{ 725 ulint val; 726 727 val = rec_get_info_bits(rec, TRUE); 728 729 if (flag) { 730 val |= REC_INFO_DELETED_FLAG; 731 } else { 732 val &= ~REC_INFO_DELETED_FLAG; 733 } 734 735 rec_set_info_bits_new(rec, val); 736 737 if (page_zip) { 738 page_zip_rec_set_deleted(page_zip, rec, flag); 739 } 740} 741 742/******************************************************//** 743The following function tells if a new-style record is a node pointer. 744@return TRUE if node pointer */ 745UNIV_INLINE 746ibool 747rec_get_node_ptr_flag( 748/*==================*/ 749 const rec_t* rec) /*!< in: physical record */ 750{ 751 return(REC_STATUS_NODE_PTR == rec_get_status(rec)); 752} 753 754/******************************************************//** 755The following function is used to get the order number 756of an old-style record in the heap of the index page. 757@return heap order number */ 758UNIV_INLINE 759ulint 760rec_get_heap_no_old( 761/*================*/ 762 const rec_t* rec) /*!< in: physical record */ 763{ 764 return(rec_get_bit_field_2(rec, REC_OLD_HEAP_NO, 765 REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT)); 766} 767 768/******************************************************//** 769The following function is used to set the heap number 770field in an old-style record. */ 771UNIV_INLINE 772void 773rec_set_heap_no_old( 774/*================*/ 775 rec_t* rec, /*!< in: physical record */ 776 ulint heap_no)/*!< in: the heap number */ 777{ 778 rec_set_bit_field_2(rec, heap_no, REC_OLD_HEAP_NO, 779 REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT); 780} 781 782/******************************************************//** 783The following function is used to get the order number 784of a new-style record in the heap of the index page. 785@return heap order number */ 786UNIV_INLINE 787ulint 788rec_get_heap_no_new( 789/*================*/ 790 const rec_t* rec) /*!< in: physical record */ 791{ 792 return(rec_get_bit_field_2(rec, REC_NEW_HEAP_NO, 793 REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT)); 794} 795 796/******************************************************//** 797The following function is used to set the heap number 798field in a new-style record. */ 799UNIV_INLINE 800void 801rec_set_heap_no_new( 802/*================*/ 803 rec_t* rec, /*!< in/out: physical record */ 804 ulint heap_no)/*!< in: the heap number */ 805{ 806 rec_set_bit_field_2(rec, heap_no, REC_NEW_HEAP_NO, 807 REC_HEAP_NO_MASK, REC_HEAP_NO_SHIFT); 808} 809 810/******************************************************//** 811The following function is used to test whether the data offsets in the record 812are stored in one-byte or two-byte format. 813@return TRUE if 1-byte form */ 814UNIV_INLINE 815ibool 816rec_get_1byte_offs_flag( 817/*====================*/ 818 const rec_t* rec) /*!< in: physical record */ 819{ 820#if TRUE != 1 821#error "TRUE != 1" 822#endif 823 824 return(rec_get_bit_field_1(rec, REC_OLD_SHORT, REC_OLD_SHORT_MASK, 825 REC_OLD_SHORT_SHIFT)); 826} 827 828/******************************************************//** 829The following function is used to set the 1-byte offsets flag. */ 830UNIV_INLINE 831void 832rec_set_1byte_offs_flag( 833/*====================*/ 834 rec_t* rec, /*!< in: physical record */ 835 ibool flag) /*!< in: TRUE if 1byte form */ 836{ 837#if TRUE != 1 838#error "TRUE != 1" 839#endif 840 ut_ad(flag <= TRUE); 841 842 rec_set_bit_field_1(rec, flag, REC_OLD_SHORT, REC_OLD_SHORT_MASK, 843 REC_OLD_SHORT_SHIFT); 844} 845 846/******************************************************//** 847Returns the offset of nth field end if the record is stored in the 1-byte 848offsets form. If the field is SQL null, the flag is ORed in the returned 849value. 850@return offset of the start of the field, SQL null flag ORed */ 851UNIV_INLINE 852ulint 853rec_1_get_field_end_info( 854/*=====================*/ 855 const rec_t* rec, /*!< in: record */ 856 ulint n) /*!< in: field index */ 857{ 858 ut_ad(rec_get_1byte_offs_flag(rec)); 859 ut_ad(n < rec_get_n_fields_old(rec)); 860 861 return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1))); 862} 863 864/******************************************************//** 865Returns the offset of nth field end if the record is stored in the 2-byte 866offsets form. If the field is SQL null, the flag is ORed in the returned 867value. 868@return offset of the start of the field, SQL null flag and extern 869storage flag ORed */ 870UNIV_INLINE 871ulint 872rec_2_get_field_end_info( 873/*=====================*/ 874 const rec_t* rec, /*!< in: record */ 875 ulint n) /*!< in: field index */ 876{ 877 ut_ad(!rec_get_1byte_offs_flag(rec)); 878 ut_ad(n < rec_get_n_fields_old(rec)); 879 880 return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2))); 881} 882 883/******************************************************//** 884Returns nonzero if the field is stored off-page. 885@retval 0 if the field is stored in-page 886@retval REC_2BYTE_EXTERN_MASK if the field is stored externally */ 887UNIV_INLINE 888ulint 889rec_2_is_field_extern( 890/*==================*/ 891 const rec_t* rec, /*!< in: record */ 892 ulint n) /*!< in: field index */ 893{ 894 return(rec_2_get_field_end_info(rec, n) & REC_2BYTE_EXTERN_MASK); 895} 896 897/* Get the base address of offsets. The extra_size is stored at 898this position, and following positions hold the end offsets of 899the fields. */ 900#define rec_offs_base(offsets) (offsets + REC_OFFS_HEADER_SIZE) 901 902/**********************************************************//** 903The following function returns the number of allocated elements 904for an array of offsets. 905@return number of elements */ 906UNIV_INLINE 907ulint 908rec_offs_get_n_alloc( 909/*=================*/ 910 const ulint* offsets)/*!< in: array for rec_get_offsets() */ 911{ 912 ulint n_alloc; 913 ut_ad(offsets); 914 n_alloc = offsets[0]; 915 ut_ad(n_alloc > REC_OFFS_HEADER_SIZE); 916 UNIV_MEM_ASSERT_W(offsets, n_alloc * sizeof *offsets); 917 return(n_alloc); 918} 919 920/**********************************************************//** 921The following function sets the number of allocated elements 922for an array of offsets. */ 923UNIV_INLINE 924void 925rec_offs_set_n_alloc( 926/*=================*/ 927 ulint* offsets, /*!< out: array for rec_get_offsets(), 928 must be allocated */ 929 ulint n_alloc) /*!< in: number of elements */ 930{ 931 ut_ad(offsets); 932 ut_ad(n_alloc > REC_OFFS_HEADER_SIZE); 933 UNIV_MEM_ASSERT_AND_ALLOC(offsets, n_alloc * sizeof *offsets); 934 offsets[0] = n_alloc; 935} 936 937/**********************************************************//** 938The following function returns the number of fields in a record. 939@return number of fields */ 940UNIV_INLINE 941ulint 942rec_offs_n_fields( 943/*==============*/ 944 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ 945{ 946 ulint n_fields; 947 ut_ad(offsets); 948 n_fields = offsets[1]; 949 ut_ad(n_fields > 0); 950 ut_ad(n_fields <= REC_MAX_N_FIELDS); 951 ut_ad(n_fields + REC_OFFS_HEADER_SIZE 952 <= rec_offs_get_n_alloc(offsets)); 953 return(n_fields); 954} 955 956/************************************************************//** 957Validates offsets returned by rec_get_offsets(). 958@return TRUE if valid */ 959UNIV_INLINE 960ibool 961rec_offs_validate( 962/*==============*/ 963 const rec_t* rec, /*!< in: record or NULL */ 964 const dict_index_t* index, /*!< in: record descriptor or NULL */ 965 const ulint* offsets)/*!< in: array returned by 966 rec_get_offsets() */ 967{ 968 ulint i = rec_offs_n_fields(offsets); 969 ulint last = ULINT_MAX; 970 ulint comp = *rec_offs_base(offsets) & REC_OFFS_COMPACT; 971 972 if (rec) { 973 ut_ad((ulint) rec == offsets[2]); 974 if (!comp) { 975 ut_a(rec_get_n_fields_old(rec) >= i); 976 } 977 } 978 if (index) { 979 ulint max_n_fields; 980 ut_ad((ulint) index == offsets[3]); 981 max_n_fields = ut_max( 982 dict_index_get_n_fields(index), 983 dict_index_get_n_unique_in_tree(index) + 1); 984 if (comp && rec) { 985 switch (rec_get_status(rec)) { 986 case REC_STATUS_ORDINARY: 987 break; 988 case REC_STATUS_NODE_PTR: 989 max_n_fields = dict_index_get_n_unique_in_tree( 990 index) + 1; 991 break; 992 case REC_STATUS_INFIMUM: 993 case REC_STATUS_SUPREMUM: 994 max_n_fields = 1; 995 break; 996 default: 997 ut_error; 998 } 999 } 1000 /* index->n_def == 0 for dummy indexes if !comp */ 1001 ut_a(!comp || index->n_def); 1002 ut_a(!index->n_def || i <= max_n_fields); 1003 } 1004 while (i--) { 1005 ulint curr = rec_offs_base(offsets)[1 + i] & REC_OFFS_MASK; 1006 ut_a(curr <= last); 1007 last = curr; 1008 } 1009 return(TRUE); 1010} 1011#ifdef UNIV_DEBUG 1012/************************************************************//** 1013Updates debug data in offsets, in order to avoid bogus 1014rec_offs_validate() failures. */ 1015UNIV_INLINE 1016void 1017rec_offs_make_valid( 1018/*================*/ 1019 const rec_t* rec, /*!< in: record */ 1020 const dict_index_t* index, /*!< in: record descriptor */ 1021 ulint* offsets)/*!< in: array returned by 1022 rec_get_offsets() */ 1023{ 1024 ut_ad(rec); 1025 ut_ad(index); 1026 ut_ad(offsets); 1027 ut_ad(rec_get_n_fields(rec, index) >= rec_offs_n_fields(offsets)); 1028 offsets[2] = (ulint) rec; 1029 offsets[3] = (ulint) index; 1030} 1031#endif /* UNIV_DEBUG */ 1032 1033/************************************************************//** 1034The following function is used to get an offset to the nth 1035data field in a record. 1036@return offset from the origin of rec */ 1037UNIV_INLINE 1038ulint 1039rec_get_nth_field_offs( 1040/*===================*/ 1041 const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ 1042 ulint n, /*!< in: index of the field */ 1043 ulint* len) /*!< out: length of the field; UNIV_SQL_NULL 1044 if SQL null */ 1045{ 1046 ulint offs; 1047 ulint length; 1048 ut_ad(n < rec_offs_n_fields(offsets)); 1049 ut_ad(len); 1050 1051 if (n == 0) { 1052 offs = 0; 1053 } else { 1054 offs = rec_offs_base(offsets)[n] & REC_OFFS_MASK; 1055 } 1056 1057 length = rec_offs_base(offsets)[1 + n]; 1058 1059 if (length & REC_OFFS_SQL_NULL) { 1060 length = UNIV_SQL_NULL; 1061 } else { 1062 length &= REC_OFFS_MASK; 1063 length -= offs; 1064 } 1065 1066 *len = length; 1067 return(offs); 1068} 1069 1070/******************************************************//** 1071Determine if the offsets are for a record in the new 1072compact format. 1073@return nonzero if compact format */ 1074UNIV_INLINE 1075ulint 1076rec_offs_comp( 1077/*==========*/ 1078 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ 1079{ 1080 ut_ad(rec_offs_validate(NULL, NULL, offsets)); 1081 return(*rec_offs_base(offsets) & REC_OFFS_COMPACT); 1082} 1083 1084/******************************************************//** 1085Determine if the offsets are for a record containing 1086externally stored columns. 1087@return nonzero if externally stored */ 1088UNIV_INLINE 1089ulint 1090rec_offs_any_extern( 1091/*================*/ 1092 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ 1093{ 1094 ut_ad(rec_offs_validate(NULL, NULL, offsets)); 1095 return(*rec_offs_base(offsets) & REC_OFFS_EXTERNAL); 1096} 1097 1098/******************************************************//** 1099Determine if the offsets are for a record containing null BLOB pointers. 1100@return first field containing a null BLOB pointer, or NULL if none found */ 1101UNIV_INLINE 1102const byte* 1103rec_offs_any_null_extern( 1104/*=====================*/ 1105 const rec_t* rec, /*!< in: record */ 1106 const ulint* offsets) /*!< in: rec_get_offsets(rec) */ 1107{ 1108 ulint i; 1109 ut_ad(rec_offs_validate(rec, NULL, offsets)); 1110 1111 if (!rec_offs_any_extern(offsets)) { 1112 return(NULL); 1113 } 1114 1115 for (i = 0; i < rec_offs_n_fields(offsets); i++) { 1116 if (rec_offs_nth_extern(offsets, i)) { 1117 ulint len; 1118 const byte* field 1119 = rec_get_nth_field(rec, offsets, i, &len); 1120 1121 ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); 1122 if (!memcmp(field + len 1123 - BTR_EXTERN_FIELD_REF_SIZE, 1124 field_ref_zero, 1125 BTR_EXTERN_FIELD_REF_SIZE)) { 1126 return(field); 1127 } 1128 } 1129 } 1130 1131 return(NULL); 1132} 1133 1134/******************************************************//** 1135Returns nonzero if the extern bit is set in nth field of rec. 1136@return nonzero if externally stored */ 1137UNIV_INLINE 1138ulint 1139rec_offs_nth_extern( 1140/*================*/ 1141 const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ 1142 ulint n) /*!< in: nth field */ 1143{ 1144 ut_ad(rec_offs_validate(NULL, NULL, offsets)); 1145 ut_ad(n < rec_offs_n_fields(offsets)); 1146 return(rec_offs_base(offsets)[1 + n] & REC_OFFS_EXTERNAL); 1147} 1148 1149/******************************************************//** 1150Returns nonzero if the SQL NULL bit is set in nth field of rec. 1151@return nonzero if SQL NULL */ 1152UNIV_INLINE 1153ulint 1154rec_offs_nth_sql_null( 1155/*==================*/ 1156 const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ 1157 ulint n) /*!< in: nth field */ 1158{ 1159 ut_ad(rec_offs_validate(NULL, NULL, offsets)); 1160 ut_ad(n < rec_offs_n_fields(offsets)); 1161 return(rec_offs_base(offsets)[1 + n] & REC_OFFS_SQL_NULL); 1162} 1163 1164/******************************************************//** 1165Gets the physical size of a field. 1166@return length of field */ 1167UNIV_INLINE 1168ulint 1169rec_offs_nth_size( 1170/*==============*/ 1171 const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ 1172 ulint n) /*!< in: nth field */ 1173{ 1174 ut_ad(rec_offs_validate(NULL, NULL, offsets)); 1175 ut_ad(n < rec_offs_n_fields(offsets)); 1176 if (!n) { 1177 return(rec_offs_base(offsets)[1 + n] & REC_OFFS_MASK); 1178 } 1179 return((rec_offs_base(offsets)[1 + n] - rec_offs_base(offsets)[n]) 1180 & REC_OFFS_MASK); 1181} 1182 1183/******************************************************//** 1184Returns the number of extern bits set in a record. 1185@return number of externally stored fields */ 1186UNIV_INLINE 1187ulint 1188rec_offs_n_extern( 1189/*==============*/ 1190 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ 1191{ 1192 ulint n = 0; 1193 1194 if (rec_offs_any_extern(offsets)) { 1195 ulint i; 1196 1197 for (i = rec_offs_n_fields(offsets); i--; ) { 1198 if (rec_offs_nth_extern(offsets, i)) { 1199 n++; 1200 } 1201 } 1202 } 1203 1204 return(n); 1205} 1206 1207/******************************************************//** 1208Returns the offset of n - 1th field end if the record is stored in the 1-byte 1209offsets form. If the field is SQL null, the flag is ORed in the returned 1210value. This function and the 2-byte counterpart are defined here because the 1211C-compiler was not able to sum negative and positive constant offsets, and 1212warned of constant arithmetic overflow within the compiler. 1213@return offset of the start of the PREVIOUS field, SQL null flag ORed */ 1214UNIV_INLINE 1215ulint 1216rec_1_get_prev_field_end_info( 1217/*==========================*/ 1218 const rec_t* rec, /*!< in: record */ 1219 ulint n) /*!< in: field index */ 1220{ 1221 ut_ad(rec_get_1byte_offs_flag(rec)); 1222 ut_ad(n <= rec_get_n_fields_old(rec)); 1223 1224 return(mach_read_from_1(rec - (REC_N_OLD_EXTRA_BYTES + n))); 1225} 1226 1227/******************************************************//** 1228Returns the offset of n - 1th field end if the record is stored in the 2-byte 1229offsets form. If the field is SQL null, the flag is ORed in the returned 1230value. 1231@return offset of the start of the PREVIOUS field, SQL null flag ORed */ 1232UNIV_INLINE 1233ulint 1234rec_2_get_prev_field_end_info( 1235/*==========================*/ 1236 const rec_t* rec, /*!< in: record */ 1237 ulint n) /*!< in: field index */ 1238{ 1239 ut_ad(!rec_get_1byte_offs_flag(rec)); 1240 ut_ad(n <= rec_get_n_fields_old(rec)); 1241 1242 return(mach_read_from_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n))); 1243} 1244 1245/******************************************************//** 1246Sets the field end info for the nth field if the record is stored in the 12471-byte format. */ 1248UNIV_INLINE 1249void 1250rec_1_set_field_end_info( 1251/*=====================*/ 1252 rec_t* rec, /*!< in: record */ 1253 ulint n, /*!< in: field index */ 1254 ulint info) /*!< in: value to set */ 1255{ 1256 ut_ad(rec_get_1byte_offs_flag(rec)); 1257 ut_ad(n < rec_get_n_fields_old(rec)); 1258 1259 mach_write_to_1(rec - (REC_N_OLD_EXTRA_BYTES + n + 1), info); 1260} 1261 1262/******************************************************//** 1263Sets the field end info for the nth field if the record is stored in the 12642-byte format. */ 1265UNIV_INLINE 1266void 1267rec_2_set_field_end_info( 1268/*=====================*/ 1269 rec_t* rec, /*!< in: record */ 1270 ulint n, /*!< in: field index */ 1271 ulint info) /*!< in: value to set */ 1272{ 1273 ut_ad(!rec_get_1byte_offs_flag(rec)); 1274 ut_ad(n < rec_get_n_fields_old(rec)); 1275 1276 mach_write_to_2(rec - (REC_N_OLD_EXTRA_BYTES + 2 * n + 2), info); 1277} 1278 1279/******************************************************//** 1280Returns the offset of nth field start if the record is stored in the 1-byte 1281offsets form. 1282@return offset of the start of the field */ 1283UNIV_INLINE 1284ulint 1285rec_1_get_field_start_offs( 1286/*=======================*/ 1287 const rec_t* rec, /*!< in: record */ 1288 ulint n) /*!< in: field index */ 1289{ 1290 ut_ad(rec_get_1byte_offs_flag(rec)); 1291 ut_ad(n <= rec_get_n_fields_old(rec)); 1292 1293 if (n == 0) { 1294 1295 return(0); 1296 } 1297 1298 return(rec_1_get_prev_field_end_info(rec, n) 1299 & ~REC_1BYTE_SQL_NULL_MASK); 1300} 1301 1302/******************************************************//** 1303Returns the offset of nth field start if the record is stored in the 2-byte 1304offsets form. 1305@return offset of the start of the field */ 1306UNIV_INLINE 1307ulint 1308rec_2_get_field_start_offs( 1309/*=======================*/ 1310 const rec_t* rec, /*!< in: record */ 1311 ulint n) /*!< in: field index */ 1312{ 1313 ut_ad(!rec_get_1byte_offs_flag(rec)); 1314 ut_ad(n <= rec_get_n_fields_old(rec)); 1315 1316 if (n == 0) { 1317 1318 return(0); 1319 } 1320 1321 return(rec_2_get_prev_field_end_info(rec, n) 1322 & ~(REC_2BYTE_SQL_NULL_MASK | REC_2BYTE_EXTERN_MASK)); 1323} 1324 1325/******************************************************//** 1326The following function is used to read the offset of the start of a data field 1327in the record. The start of an SQL null field is the end offset of the 1328previous non-null field, or 0, if none exists. If n is the number of the last 1329field + 1, then the end offset of the last field is returned. 1330@return offset of the start of the field */ 1331UNIV_INLINE 1332ulint 1333rec_get_field_start_offs( 1334/*=====================*/ 1335 const rec_t* rec, /*!< in: record */ 1336 ulint n) /*!< in: field index */ 1337{ 1338 ut_ad(rec); 1339 ut_ad(n <= rec_get_n_fields_old(rec)); 1340 1341 if (n == 0) { 1342 1343 return(0); 1344 } 1345 1346 if (rec_get_1byte_offs_flag(rec)) { 1347 1348 return(rec_1_get_field_start_offs(rec, n)); 1349 } 1350 1351 return(rec_2_get_field_start_offs(rec, n)); 1352} 1353 1354/************************************************************//** 1355Gets the physical size of an old-style field. 1356Also an SQL null may have a field of size > 0, 1357if the data type is of a fixed size. 1358@return field size in bytes */ 1359UNIV_INLINE 1360ulint 1361rec_get_nth_field_size( 1362/*===================*/ 1363 const rec_t* rec, /*!< in: record */ 1364 ulint n) /*!< in: index of the field */ 1365{ 1366 ulint os; 1367 ulint next_os; 1368 1369 os = rec_get_field_start_offs(rec, n); 1370 next_os = rec_get_field_start_offs(rec, n + 1); 1371 1372 ut_ad(next_os - os < UNIV_PAGE_SIZE); 1373 1374 return(next_os - os); 1375} 1376 1377/***********************************************************//** 1378This is used to modify the value of an already existing field in a record. 1379The previous value must have exactly the same size as the new value. If len 1380is UNIV_SQL_NULL then the field is treated as an SQL null. 1381For records in ROW_FORMAT=COMPACT (new-style records), len must not be 1382UNIV_SQL_NULL unless the field already is SQL null. */ 1383UNIV_INLINE 1384void 1385rec_set_nth_field( 1386/*==============*/ 1387 rec_t* rec, /*!< in: record */ 1388 const ulint* offsets,/*!< in: array returned by rec_get_offsets() */ 1389 ulint n, /*!< in: index number of the field */ 1390 const void* data, /*!< in: pointer to the data 1391 if not SQL null */ 1392 ulint len) /*!< in: length of the data or UNIV_SQL_NULL */ 1393{ 1394 byte* data2; 1395 ulint len2; 1396 1397 ut_ad(rec); 1398 ut_ad(rec_offs_validate(rec, NULL, offsets)); 1399 1400 if (len == UNIV_SQL_NULL) { 1401 if (!rec_offs_nth_sql_null(offsets, n)) { 1402 ut_a(!rec_offs_comp(offsets)); 1403 rec_set_nth_field_sql_null(rec, n); 1404 } 1405 1406 return; 1407 } 1408 1409 data2 = rec_get_nth_field(rec, offsets, n, &len2); 1410 if (len2 == UNIV_SQL_NULL) { 1411 ut_ad(!rec_offs_comp(offsets)); 1412 rec_set_nth_field_null_bit(rec, n, FALSE); 1413 ut_ad(len == rec_get_nth_field_size(rec, n)); 1414 } else { 1415 ut_ad(len2 == len); 1416 } 1417 1418 ut_memcpy(data2, data, len); 1419} 1420 1421/**********************************************************//** 1422The following function returns the data size of an old-style physical 1423record, that is the sum of field lengths. SQL null fields 1424are counted as length 0 fields. The value returned by the function 1425is the distance from record origin to record end in bytes. 1426@return size */ 1427UNIV_INLINE 1428ulint 1429rec_get_data_size_old( 1430/*==================*/ 1431 const rec_t* rec) /*!< in: physical record */ 1432{ 1433 ut_ad(rec); 1434 1435 return(rec_get_field_start_offs(rec, rec_get_n_fields_old(rec))); 1436} 1437 1438/**********************************************************//** 1439The following function sets the number of fields in offsets. */ 1440UNIV_INLINE 1441void 1442rec_offs_set_n_fields( 1443/*==================*/ 1444 ulint* offsets, /*!< in/out: array returned by 1445 rec_get_offsets() */ 1446 ulint n_fields) /*!< in: number of fields */ 1447{ 1448 ut_ad(offsets); 1449 ut_ad(n_fields > 0); 1450 ut_ad(n_fields <= REC_MAX_N_FIELDS); 1451 ut_ad(n_fields + REC_OFFS_HEADER_SIZE 1452 <= rec_offs_get_n_alloc(offsets)); 1453 offsets[1] = n_fields; 1454} 1455 1456/**********************************************************//** 1457The following function returns the data size of a physical 1458record, that is the sum of field lengths. SQL null fields 1459are counted as length 0 fields. The value returned by the function 1460is the distance from record origin to record end in bytes. 1461@return size */ 1462UNIV_INLINE 1463ulint 1464rec_offs_data_size( 1465/*===============*/ 1466 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ 1467{ 1468 ulint size; 1469 1470 ut_ad(rec_offs_validate(NULL, NULL, offsets)); 1471 size = rec_offs_base(offsets)[rec_offs_n_fields(offsets)] 1472 & REC_OFFS_MASK; 1473 ut_ad(size < UNIV_PAGE_SIZE); 1474 return(size); 1475} 1476 1477/**********************************************************//** 1478Returns the total size of record minus data size of record. The value 1479returned by the function is the distance from record start to record origin 1480in bytes. 1481@return size */ 1482UNIV_INLINE 1483ulint 1484rec_offs_extra_size( 1485/*================*/ 1486 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ 1487{ 1488 ulint size; 1489 ut_ad(rec_offs_validate(NULL, NULL, offsets)); 1490 size = *rec_offs_base(offsets) & ~(REC_OFFS_COMPACT | REC_OFFS_EXTERNAL); 1491 ut_ad(size < UNIV_PAGE_SIZE); 1492 return(size); 1493} 1494 1495/**********************************************************//** 1496Returns the total size of a physical record. 1497@return size */ 1498UNIV_INLINE 1499ulint 1500rec_offs_size( 1501/*==========*/ 1502 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ 1503{ 1504 return(rec_offs_data_size(offsets) + rec_offs_extra_size(offsets)); 1505} 1506 1507#ifdef UNIV_DEBUG 1508/**********************************************************//** 1509Returns a pointer to the end of the record. 1510@return pointer to end */ 1511UNIV_INLINE 1512byte* 1513rec_get_end( 1514/*========*/ 1515 const rec_t* rec, /*!< in: pointer to record */ 1516 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ 1517{ 1518 ut_ad(rec_offs_validate(rec, NULL, offsets)); 1519 return(const_cast<rec_t*>(rec + rec_offs_data_size(offsets))); 1520} 1521 1522/**********************************************************//** 1523Returns a pointer to the start of the record. 1524@return pointer to start */ 1525UNIV_INLINE 1526byte* 1527rec_get_start( 1528/*==========*/ 1529 const rec_t* rec, /*!< in: pointer to record */ 1530 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ 1531{ 1532 ut_ad(rec_offs_validate(rec, NULL, offsets)); 1533 return(const_cast<rec_t*>(rec - rec_offs_extra_size(offsets))); 1534} 1535#endif /* UNIV_DEBUG */ 1536 1537/***************************************************************//** 1538Copies a physical record to a buffer. 1539@return pointer to the origin of the copy */ 1540UNIV_INLINE 1541rec_t* 1542rec_copy( 1543/*=====*/ 1544 void* buf, /*!< in: buffer */ 1545 const rec_t* rec, /*!< in: physical record */ 1546 const ulint* offsets)/*!< in: array returned by rec_get_offsets() */ 1547{ 1548 ulint extra_len; 1549 ulint data_len; 1550 1551 ut_ad(rec != NULL); 1552 ut_ad(buf != NULL); 1553 ut_ad(rec_offs_validate(rec, NULL, offsets)); 1554 ut_ad(rec_validate(rec, offsets)); 1555 1556 extra_len = rec_offs_extra_size(offsets); 1557 data_len = rec_offs_data_size(offsets); 1558 1559 ut_memcpy(buf, rec - extra_len, extra_len + data_len); 1560 1561 return((byte*) buf + extra_len); 1562} 1563 1564/**********************************************************//** 1565Returns the extra size of an old-style physical record if we know its 1566data size and number of fields. 1567@return extra size */ 1568UNIV_INLINE 1569ulint 1570rec_get_converted_extra_size( 1571/*=========================*/ 1572 ulint data_size, /*!< in: data size */ 1573 ulint n_fields, /*!< in: number of fields */ 1574 ulint n_ext) /*!< in: number of externally stored columns */ 1575{ 1576 if (!n_ext && data_size <= REC_1BYTE_OFFS_LIMIT) { 1577 1578 return(REC_N_OLD_EXTRA_BYTES + n_fields); 1579 } 1580 1581 return(REC_N_OLD_EXTRA_BYTES + 2 * n_fields); 1582} 1583 1584/**********************************************************//** 1585The following function returns the size of a data tuple when converted to 1586a physical record. 1587@return size */ 1588UNIV_INLINE 1589ulint 1590rec_get_converted_size( 1591/*===================*/ 1592 dict_index_t* index, /*!< in: record descriptor */ 1593 const dtuple_t* dtuple, /*!< in: data tuple */ 1594 ulint n_ext) /*!< in: number of externally stored columns */ 1595{ 1596 ulint data_size; 1597 ulint extra_size; 1598 1599 ut_ad(index); 1600 ut_ad(dtuple); 1601 ut_ad(dtuple_check_typed(dtuple)); 1602 1603 ut_ad(dict_index_is_univ(index) 1604 || dtuple_get_n_fields(dtuple) 1605 == (((dtuple_get_info_bits(dtuple) & REC_NEW_STATUS_MASK) 1606 == REC_STATUS_NODE_PTR) 1607 ? dict_index_get_n_unique_in_tree(index) + 1 1608 : dict_index_get_n_fields(index))); 1609 1610 if (dict_table_is_comp(index->table)) { 1611 return(rec_get_converted_size_comp(index, 1612 dtuple_get_info_bits(dtuple) 1613 & REC_NEW_STATUS_MASK, 1614 dtuple->fields, 1615 dtuple->n_fields, NULL)); 1616 } 1617 1618 data_size = dtuple_get_data_size(dtuple, 0); 1619 1620 extra_size = rec_get_converted_extra_size( 1621 data_size, dtuple_get_n_fields(dtuple), n_ext); 1622 1623#if 0 1624 /* This code is inactive since it may be the wrong place to add 1625 in the size of node pointers used in parent pages AND it is not 1626 currently needed since ha_innobase::max_supported_key_length() 1627 ensures that the key size limit for each page size is well below 1628 the actual limit ((free space on page / 4) - record overhead). 1629 But those limits will need to be raised when InnoDB can 1630 support multiple page sizes. At that time, we will need 1631 to consider the node pointer on these universal btrees. */ 1632 1633 if (dict_index_is_univ(index)) { 1634 /* This is for the insert buffer B-tree. 1635 All fields in the leaf tuple ascend to the 1636 parent node plus the child page pointer. */ 1637 1638 /* ibuf cannot contain externally stored fields */ 1639 ut_ad(n_ext == 0); 1640 1641 /* Add the data pointer and recompute extra_size 1642 based on one more field. */ 1643 data_size += REC_NODE_PTR_SIZE; 1644 extra_size = rec_get_converted_extra_size( 1645 data_size, 1646 dtuple_get_n_fields(dtuple) + 1, 1647 0); 1648 1649 /* Be sure dtuple->n_fields has this node ptr 1650 accounted for. This function should correspond to 1651 what rec_convert_dtuple_to_rec() needs in storage. 1652 In optimistic insert or update-not-in-place, we will 1653 have to ensure that if the record is converted to a 1654 node pointer, it will not become too large.*/ 1655 } 1656#endif 1657 1658 return(data_size + extra_size); 1659} 1660 1661#ifndef UNIV_HOTBACKUP 1662/************************************************************//** 1663Folds a prefix of a physical record to a ulint. Folds only existing fields, 1664that is, checks that we do not run out of the record. 1665@return the folded value */ 1666UNIV_INLINE 1667ulint 1668rec_fold( 1669/*=====*/ 1670 const rec_t* rec, /*!< in: the physical record */ 1671 const ulint* offsets, /*!< in: array returned by 1672 rec_get_offsets() */ 1673 ulint n_fields, /*!< in: number of complete 1674 fields to fold */ 1675 ulint n_bytes, /*!< in: number of bytes to fold 1676 in an incomplete last field */ 1677 index_id_t tree_id) /*!< in: index tree id */ 1678{ 1679 ulint i; 1680 const byte* data; 1681 ulint len; 1682 ulint fold; 1683 ulint n_fields_rec; 1684 1685 ut_ad(rec_offs_validate(rec, NULL, offsets)); 1686 ut_ad(rec_validate(rec, offsets)); 1687 ut_ad(n_fields + n_bytes > 0); 1688 1689 n_fields_rec = rec_offs_n_fields(offsets); 1690 ut_ad(n_fields <= n_fields_rec); 1691 ut_ad(n_fields < n_fields_rec || n_bytes == 0); 1692 1693 if (n_fields > n_fields_rec) { 1694 n_fields = n_fields_rec; 1695 } 1696 1697 if (n_fields == n_fields_rec) { 1698 n_bytes = 0; 1699 } 1700 1701 fold = ut_fold_ull(tree_id); 1702 1703 for (i = 0; i < n_fields; i++) { 1704 data = rec_get_nth_field(rec, offsets, i, &len); 1705 1706 if (len != UNIV_SQL_NULL) { 1707 fold = ut_fold_ulint_pair(fold, 1708 ut_fold_binary(data, len)); 1709 } 1710 } 1711 1712 if (n_bytes > 0) { 1713 data = rec_get_nth_field(rec, offsets, i, &len); 1714 1715 if (len != UNIV_SQL_NULL) { 1716 if (len > n_bytes) { 1717 len = n_bytes; 1718 } 1719 1720 fold = ut_fold_ulint_pair(fold, 1721 ut_fold_binary(data, len)); 1722 } 1723 } 1724 1725 return(fold); 1726} 1727#endif /* !UNIV_HOTBACKUP */ 1728