| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. |
| 4 | Copyright (c) 2017, 2018, MariaDB Corporation. |
| 5 | |
| 6 | This program is free software; you can redistribute it and/or modify it under |
| 7 | the terms of the GNU General Public License as published by the Free Software |
| 8 | Foundation; version 2 of the License. |
| 9 | |
| 10 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU General Public License along with |
| 15 | this program; if not, write to the Free Software Foundation, Inc., |
| 16 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
| 17 | |
| 18 | *****************************************************************************/ |
| 19 | |
| 20 | /********************************************************************//** |
| 21 | @file data/data0data.cc |
| 22 | SQL data field and tuple |
| 23 | |
| 24 | Created 5/30/1994 Heikki Tuuri |
| 25 | *************************************************************************/ |
| 26 | |
| 27 | #include "ha_prototypes.h" |
| 28 | |
| 29 | #include "data0data.h" |
| 30 | #include "rem0rec.h" |
| 31 | #include "rem0cmp.h" |
| 32 | #include "page0page.h" |
| 33 | #include "page0zip.h" |
| 34 | #include "dict0dict.h" |
| 35 | #include "btr0cur.h" |
| 36 | #include "row0upd.h" |
| 37 | |
| 38 | #ifdef UNIV_DEBUG |
| 39 | /** Dummy variable to catch access to uninitialized fields. In the |
| 40 | debug version, dtuple_create() will make all fields of dtuple_t point |
| 41 | to data_error. */ |
| 42 | byte data_error; |
| 43 | #endif /* UNIV_DEBUG */ |
| 44 | |
| 45 | /** Trim the tail of an index tuple before insert or update. |
| 46 | After instant ADD COLUMN, if the last fields of a clustered index tuple |
| 47 | match the 'default row', there will be no need to store them. |
| 48 | NOTE: A page latch in the index must be held, so that the index |
| 49 | may not lose 'instantness' before the trimmed tuple has been |
| 50 | inserted or updated. |
| 51 | @param[in] index index possibly with instantly added columns */ |
| 52 | void dtuple_t::trim(const dict_index_t& index) |
| 53 | { |
| 54 | ut_ad(n_fields >= index.n_core_fields); |
| 55 | ut_ad(n_fields <= index.n_fields); |
| 56 | ut_ad(index.is_instant()); |
| 57 | |
| 58 | ulint i = n_fields; |
| 59 | for (; i > index.n_core_fields; i--) { |
| 60 | const dfield_t* dfield = dtuple_get_nth_field(this, i - 1); |
| 61 | const dict_col_t* col = dict_index_get_nth_col(&index, i - 1); |
| 62 | ut_ad(col->is_instant()); |
| 63 | ulint len = dfield_get_len(dfield); |
| 64 | if (len != col->def_val.len) { |
| 65 | break; |
| 66 | } |
| 67 | |
| 68 | if (len != 0 && len != UNIV_SQL_NULL |
| 69 | && dfield->data != col->def_val.data |
| 70 | && memcmp(dfield->data, col->def_val.data, len)) { |
| 71 | break; |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | n_fields = i; |
| 76 | } |
| 77 | |
| 78 | /** Compare two data tuples. |
| 79 | @param[in] tuple1 first data tuple |
| 80 | @param[in] tuple2 second data tuple |
| 81 | @return positive, 0, negative if tuple1 is greater, equal, less, than tuple2, |
| 82 | respectively */ |
| 83 | int |
| 84 | dtuple_coll_cmp( |
| 85 | const dtuple_t* tuple1, |
| 86 | const dtuple_t* tuple2) |
| 87 | { |
| 88 | ulint n_fields; |
| 89 | ulint i; |
| 90 | int cmp; |
| 91 | |
| 92 | ut_ad(tuple1 != NULL); |
| 93 | ut_ad(tuple2 != NULL); |
| 94 | ut_ad(tuple1->magic_n == DATA_TUPLE_MAGIC_N); |
| 95 | ut_ad(tuple2->magic_n == DATA_TUPLE_MAGIC_N); |
| 96 | ut_ad(dtuple_check_typed(tuple1)); |
| 97 | ut_ad(dtuple_check_typed(tuple2)); |
| 98 | |
| 99 | n_fields = dtuple_get_n_fields(tuple1); |
| 100 | |
| 101 | cmp = (int) n_fields - (int) dtuple_get_n_fields(tuple2); |
| 102 | |
| 103 | for (i = 0; cmp == 0 && i < n_fields; i++) { |
| 104 | const dfield_t* field1 = dtuple_get_nth_field(tuple1, i); |
| 105 | const dfield_t* field2 = dtuple_get_nth_field(tuple2, i); |
| 106 | cmp = cmp_dfield_dfield(field1, field2); |
| 107 | } |
| 108 | |
| 109 | return(cmp); |
| 110 | } |
| 111 | |
| 112 | /*********************************************************************//** |
| 113 | Sets number of fields used in a tuple. Normally this is set in |
| 114 | dtuple_create, but if you want later to set it smaller, you can use this. */ |
| 115 | void |
| 116 | dtuple_set_n_fields( |
| 117 | /*================*/ |
| 118 | dtuple_t* tuple, /*!< in: tuple */ |
| 119 | ulint n_fields) /*!< in: number of fields */ |
| 120 | { |
| 121 | ut_ad(tuple); |
| 122 | |
| 123 | tuple->n_fields = n_fields; |
| 124 | tuple->n_fields_cmp = n_fields; |
| 125 | } |
| 126 | |
| 127 | /**********************************************************//** |
| 128 | Checks that a data field is typed. |
| 129 | @return TRUE if ok */ |
| 130 | static |
| 131 | ibool |
| 132 | dfield_check_typed_no_assert( |
| 133 | /*=========================*/ |
| 134 | const dfield_t* field) /*!< in: data field */ |
| 135 | { |
| 136 | if (dfield_get_type(field)->mtype > DATA_MTYPE_CURRENT_MAX |
| 137 | || dfield_get_type(field)->mtype < DATA_MTYPE_CURRENT_MIN) { |
| 138 | |
| 139 | ib::error() << "Data field type " |
| 140 | << dfield_get_type(field)->mtype |
| 141 | << ", len " << dfield_get_len(field); |
| 142 | |
| 143 | return(FALSE); |
| 144 | } |
| 145 | |
| 146 | return(TRUE); |
| 147 | } |
| 148 | |
| 149 | /**********************************************************//** |
| 150 | Checks that a data tuple is typed. |
| 151 | @return TRUE if ok */ |
| 152 | static |
| 153 | ibool |
| 154 | dtuple_check_typed_no_assert( |
| 155 | /*=========================*/ |
| 156 | const dtuple_t* tuple) /*!< in: tuple */ |
| 157 | { |
| 158 | const dfield_t* field; |
| 159 | ulint i; |
| 160 | |
| 161 | if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) { |
| 162 | ib::error() << "Index entry has " |
| 163 | << dtuple_get_n_fields(tuple) << " fields" ; |
| 164 | dump: |
| 165 | fputs("InnoDB: Tuple contents: " , stderr); |
| 166 | dtuple_print(stderr, tuple); |
| 167 | putc('\n', stderr); |
| 168 | |
| 169 | return(FALSE); |
| 170 | } |
| 171 | |
| 172 | for (i = 0; i < dtuple_get_n_fields(tuple); i++) { |
| 173 | |
| 174 | field = dtuple_get_nth_field(tuple, i); |
| 175 | |
| 176 | if (!dfield_check_typed_no_assert(field)) { |
| 177 | goto dump; |
| 178 | } |
| 179 | } |
| 180 | |
| 181 | return(TRUE); |
| 182 | } |
| 183 | |
| 184 | #ifdef UNIV_DEBUG |
| 185 | /**********************************************************//** |
| 186 | Checks that a data field is typed. Asserts an error if not. |
| 187 | @return TRUE if ok */ |
| 188 | ibool |
| 189 | dfield_check_typed( |
| 190 | /*===============*/ |
| 191 | const dfield_t* field) /*!< in: data field */ |
| 192 | { |
| 193 | if (dfield_get_type(field)->mtype > DATA_MTYPE_CURRENT_MAX |
| 194 | || dfield_get_type(field)->mtype < DATA_MTYPE_CURRENT_MIN) { |
| 195 | |
| 196 | ib::fatal() << "Data field type " |
| 197 | << dfield_get_type(field)->mtype |
| 198 | << ", len " << dfield_get_len(field); |
| 199 | } |
| 200 | |
| 201 | return(TRUE); |
| 202 | } |
| 203 | |
| 204 | /**********************************************************//** |
| 205 | Checks that a data tuple is typed. Asserts an error if not. |
| 206 | @return TRUE if ok */ |
| 207 | ibool |
| 208 | dtuple_check_typed( |
| 209 | /*===============*/ |
| 210 | const dtuple_t* tuple) /*!< in: tuple */ |
| 211 | { |
| 212 | const dfield_t* field; |
| 213 | ulint i; |
| 214 | |
| 215 | for (i = 0; i < dtuple_get_n_fields(tuple); i++) { |
| 216 | |
| 217 | field = dtuple_get_nth_field(tuple, i); |
| 218 | |
| 219 | ut_a(dfield_check_typed(field)); |
| 220 | } |
| 221 | |
| 222 | return(TRUE); |
| 223 | } |
| 224 | |
| 225 | /**********************************************************//** |
| 226 | Validates the consistency of a tuple which must be complete, i.e, |
| 227 | all fields must have been set. |
| 228 | @return TRUE if ok */ |
| 229 | ibool |
| 230 | dtuple_validate( |
| 231 | /*============*/ |
| 232 | const dtuple_t* tuple) /*!< in: tuple */ |
| 233 | { |
| 234 | const dfield_t* field; |
| 235 | ulint n_fields; |
| 236 | ulint len; |
| 237 | ulint i; |
| 238 | |
| 239 | ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N); |
| 240 | |
| 241 | n_fields = dtuple_get_n_fields(tuple); |
| 242 | |
| 243 | /* We dereference all the data of each field to test |
| 244 | for memory traps */ |
| 245 | |
| 246 | for (i = 0; i < n_fields; i++) { |
| 247 | |
| 248 | field = dtuple_get_nth_field(tuple, i); |
| 249 | len = dfield_get_len(field); |
| 250 | |
| 251 | if (!dfield_is_null(field)) { |
| 252 | |
| 253 | const byte* data; |
| 254 | |
| 255 | data = static_cast<const byte*>(dfield_get_data(field)); |
| 256 | #ifndef UNIV_DEBUG_VALGRIND |
| 257 | ulint j; |
| 258 | |
| 259 | for (j = 0; j < len; j++) { |
| 260 | data++; |
| 261 | } |
| 262 | #endif /* !UNIV_DEBUG_VALGRIND */ |
| 263 | |
| 264 | UNIV_MEM_ASSERT_RW(data, len); |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | ut_a(dtuple_check_typed(tuple)); |
| 269 | |
| 270 | return(TRUE); |
| 271 | } |
| 272 | #endif /* UNIV_DEBUG */ |
| 273 | |
| 274 | /*************************************************************//** |
| 275 | Pretty prints a dfield value according to its data type. */ |
| 276 | void |
| 277 | dfield_print( |
| 278 | /*=========*/ |
| 279 | const dfield_t* dfield) /*!< in: dfield */ |
| 280 | { |
| 281 | const byte* data; |
| 282 | ulint len; |
| 283 | ulint i; |
| 284 | |
| 285 | len = dfield_get_len(dfield); |
| 286 | data = static_cast<const byte*>(dfield_get_data(dfield)); |
| 287 | |
| 288 | if (dfield_is_null(dfield)) { |
| 289 | fputs("NULL" , stderr); |
| 290 | |
| 291 | return; |
| 292 | } |
| 293 | |
| 294 | switch (dtype_get_mtype(dfield_get_type(dfield))) { |
| 295 | case DATA_CHAR: |
| 296 | case DATA_VARCHAR: |
| 297 | for (i = 0; i < len; i++) { |
| 298 | int c = *data++; |
| 299 | putc(isprint(c) ? c : ' ', stderr); |
| 300 | } |
| 301 | |
| 302 | if (dfield_is_ext(dfield)) { |
| 303 | fputs("(external)" , stderr); |
| 304 | } |
| 305 | break; |
| 306 | case DATA_INT: |
| 307 | ut_a(len == 4); /* only works for 32-bit integers */ |
| 308 | fprintf(stderr, "%d" , (int) mach_read_from_4(data)); |
| 309 | break; |
| 310 | default: |
| 311 | ut_error; |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | /*************************************************************//** |
| 316 | Pretty prints a dfield value according to its data type. Also the hex string |
| 317 | is printed if a string contains non-printable characters. */ |
| 318 | void |
| 319 | dfield_print_also_hex( |
| 320 | /*==================*/ |
| 321 | const dfield_t* dfield) /*!< in: dfield */ |
| 322 | { |
| 323 | const byte* data; |
| 324 | ulint len; |
| 325 | ulint prtype; |
| 326 | ulint i; |
| 327 | ibool print_also_hex; |
| 328 | |
| 329 | len = dfield_get_len(dfield); |
| 330 | data = static_cast<const byte*>(dfield_get_data(dfield)); |
| 331 | |
| 332 | if (dfield_is_null(dfield)) { |
| 333 | fputs("NULL" , stderr); |
| 334 | |
| 335 | return; |
| 336 | } |
| 337 | |
| 338 | prtype = dtype_get_prtype(dfield_get_type(dfield)); |
| 339 | |
| 340 | switch (dtype_get_mtype(dfield_get_type(dfield))) { |
| 341 | ib_id_t id; |
| 342 | case DATA_INT: |
| 343 | switch (len) { |
| 344 | ulint val; |
| 345 | case 1: |
| 346 | val = mach_read_from_1(data); |
| 347 | |
| 348 | if (!(prtype & DATA_UNSIGNED)) { |
| 349 | val &= ~0x80U; |
| 350 | fprintf(stderr, "%ld" , (long) val); |
| 351 | } else { |
| 352 | fprintf(stderr, "%lu" , (ulong) val); |
| 353 | } |
| 354 | break; |
| 355 | |
| 356 | case 2: |
| 357 | val = mach_read_from_2(data); |
| 358 | |
| 359 | if (!(prtype & DATA_UNSIGNED)) { |
| 360 | val &= ~0x8000U; |
| 361 | fprintf(stderr, "%ld" , (long) val); |
| 362 | } else { |
| 363 | fprintf(stderr, "%lu" , (ulong) val); |
| 364 | } |
| 365 | break; |
| 366 | |
| 367 | case 3: |
| 368 | val = mach_read_from_3(data); |
| 369 | |
| 370 | if (!(prtype & DATA_UNSIGNED)) { |
| 371 | val &= ~0x800000U; |
| 372 | fprintf(stderr, "%ld" , (long) val); |
| 373 | } else { |
| 374 | fprintf(stderr, "%lu" , (ulong) val); |
| 375 | } |
| 376 | break; |
| 377 | |
| 378 | case 4: |
| 379 | val = mach_read_from_4(data); |
| 380 | |
| 381 | if (!(prtype & DATA_UNSIGNED)) { |
| 382 | val &= ~0x80000000; |
| 383 | fprintf(stderr, "%ld" , (long) val); |
| 384 | } else { |
| 385 | fprintf(stderr, "%lu" , (ulong) val); |
| 386 | } |
| 387 | break; |
| 388 | |
| 389 | case 6: |
| 390 | id = mach_read_from_6(data); |
| 391 | fprintf(stderr, IB_ID_FMT, id); |
| 392 | break; |
| 393 | |
| 394 | case 7: |
| 395 | id = mach_read_from_7(data); |
| 396 | fprintf(stderr, IB_ID_FMT, id); |
| 397 | break; |
| 398 | case 8: |
| 399 | id = mach_read_from_8(data); |
| 400 | fprintf(stderr, IB_ID_FMT, id); |
| 401 | break; |
| 402 | default: |
| 403 | goto print_hex; |
| 404 | } |
| 405 | break; |
| 406 | |
| 407 | case DATA_SYS: |
| 408 | switch (prtype & DATA_SYS_PRTYPE_MASK) { |
| 409 | case DATA_TRX_ID: |
| 410 | id = mach_read_from_6(data); |
| 411 | |
| 412 | fprintf(stderr, "trx_id " TRX_ID_FMT, id); |
| 413 | break; |
| 414 | |
| 415 | case DATA_ROLL_PTR: |
| 416 | id = mach_read_from_7(data); |
| 417 | |
| 418 | fprintf(stderr, "roll_ptr " TRX_ID_FMT, id); |
| 419 | break; |
| 420 | |
| 421 | case DATA_ROW_ID: |
| 422 | id = mach_read_from_6(data); |
| 423 | |
| 424 | fprintf(stderr, "row_id " TRX_ID_FMT, id); |
| 425 | break; |
| 426 | |
| 427 | default: |
| 428 | goto print_hex; |
| 429 | } |
| 430 | break; |
| 431 | |
| 432 | case DATA_CHAR: |
| 433 | case DATA_VARCHAR: |
| 434 | print_also_hex = FALSE; |
| 435 | |
| 436 | for (i = 0; i < len; i++) { |
| 437 | int c = *data++; |
| 438 | |
| 439 | if (!isprint(c)) { |
| 440 | print_also_hex = TRUE; |
| 441 | |
| 442 | fprintf(stderr, "\\x%02x" , (unsigned char) c); |
| 443 | } else { |
| 444 | putc(c, stderr); |
| 445 | } |
| 446 | } |
| 447 | |
| 448 | if (dfield_is_ext(dfield)) { |
| 449 | fputs("(external)" , stderr); |
| 450 | } |
| 451 | |
| 452 | if (!print_also_hex) { |
| 453 | break; |
| 454 | } |
| 455 | |
| 456 | data = static_cast<byte*>(dfield_get_data(dfield)); |
| 457 | /* fall through */ |
| 458 | |
| 459 | case DATA_BINARY: |
| 460 | default: |
| 461 | print_hex: |
| 462 | fputs(" Hex: " ,stderr); |
| 463 | |
| 464 | for (i = 0; i < len; i++) { |
| 465 | fprintf(stderr, "%02x" , *data++); |
| 466 | } |
| 467 | |
| 468 | if (dfield_is_ext(dfield)) { |
| 469 | fputs("(external)" , stderr); |
| 470 | } |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | /*************************************************************//** |
| 475 | Print a dfield value using ut_print_buf. */ |
| 476 | static |
| 477 | void |
| 478 | dfield_print_raw( |
| 479 | /*=============*/ |
| 480 | FILE* f, /*!< in: output stream */ |
| 481 | const dfield_t* dfield) /*!< in: dfield */ |
| 482 | { |
| 483 | ulint len = dfield_get_len(dfield); |
| 484 | if (!dfield_is_null(dfield)) { |
| 485 | ulint print_len = ut_min(len, static_cast<ulint>(1000)); |
| 486 | ut_print_buf(f, dfield_get_data(dfield), print_len); |
| 487 | if (len != print_len) { |
| 488 | fprintf(f, "(total %lu bytes%s)" , |
| 489 | (ulong) len, |
| 490 | dfield_is_ext(dfield) ? ", external" : "" ); |
| 491 | } |
| 492 | } else { |
| 493 | fputs(" SQL NULL" , f); |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | /**********************************************************//** |
| 498 | The following function prints the contents of a tuple. */ |
| 499 | void |
| 500 | dtuple_print( |
| 501 | /*=========*/ |
| 502 | FILE* f, /*!< in: output stream */ |
| 503 | const dtuple_t* tuple) /*!< in: tuple */ |
| 504 | { |
| 505 | ulint n_fields; |
| 506 | ulint i; |
| 507 | |
| 508 | n_fields = dtuple_get_n_fields(tuple); |
| 509 | |
| 510 | fprintf(f, "DATA TUPLE: %lu fields;\n" , (ulong) n_fields); |
| 511 | |
| 512 | for (i = 0; i < n_fields; i++) { |
| 513 | fprintf(f, " %lu:" , (ulong) i); |
| 514 | |
| 515 | dfield_print_raw(f, dtuple_get_nth_field(tuple, i)); |
| 516 | |
| 517 | putc(';', f); |
| 518 | putc('\n', f); |
| 519 | } |
| 520 | |
| 521 | ut_ad(dtuple_validate(tuple)); |
| 522 | } |
| 523 | |
| 524 | /** Print the contents of a tuple. |
| 525 | @param[out] o output stream |
| 526 | @param[in] field array of data fields |
| 527 | @param[in] n number of data fields */ |
| 528 | void |
| 529 | dfield_print( |
| 530 | std::ostream& o, |
| 531 | const dfield_t* field, |
| 532 | ulint n) |
| 533 | { |
| 534 | for (ulint i = 0; i < n; i++, field++) { |
| 535 | const void* data = dfield_get_data(field); |
| 536 | const ulint len = dfield_get_len(field); |
| 537 | |
| 538 | if (i) { |
| 539 | o << ','; |
| 540 | } |
| 541 | |
| 542 | if (dfield_is_null(field)) { |
| 543 | o << "NULL" ; |
| 544 | } else if (dfield_is_ext(field)) { |
| 545 | ulint local_len = len - BTR_EXTERN_FIELD_REF_SIZE; |
| 546 | ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE); |
| 547 | |
| 548 | o << '[' |
| 549 | << local_len |
| 550 | << '+' << BTR_EXTERN_FIELD_REF_SIZE << ']'; |
| 551 | ut_print_buf(o, data, local_len); |
| 552 | ut_print_buf_hex(o, static_cast<const byte*>(data) |
| 553 | + local_len, |
| 554 | BTR_EXTERN_FIELD_REF_SIZE); |
| 555 | } else { |
| 556 | o << '[' << len << ']'; |
| 557 | ut_print_buf(o, data, len); |
| 558 | } |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | /** Print the contents of a tuple. |
| 563 | @param[out] o output stream |
| 564 | @param[in] tuple data tuple */ |
| 565 | void |
| 566 | dtuple_print( |
| 567 | std::ostream& o, |
| 568 | const dtuple_t* tuple) |
| 569 | { |
| 570 | const ulint n = dtuple_get_n_fields(tuple); |
| 571 | |
| 572 | o << "TUPLE (info_bits=" << dtuple_get_info_bits(tuple) |
| 573 | << ", " << n << " fields): {" ; |
| 574 | |
| 575 | dfield_print(o, tuple->fields, n); |
| 576 | |
| 577 | o << "}" ; |
| 578 | } |
| 579 | |
| 580 | /**************************************************************//** |
| 581 | Moves parts of long fields in entry to the big record vector so that |
| 582 | the size of tuple drops below the maximum record size allowed in the |
| 583 | database. Moves data only from those fields which are not necessary |
| 584 | to determine uniquely the insertion place of the tuple in the index. |
| 585 | @return own: created big record vector, NULL if we are not able to |
| 586 | shorten the entry enough, i.e., if there are too many fixed-length or |
| 587 | short fields in entry or the index is clustered */ |
| 588 | big_rec_t* |
| 589 | dtuple_convert_big_rec( |
| 590 | /*===================*/ |
| 591 | dict_index_t* index, /*!< in: index */ |
| 592 | upd_t* upd, /*!< in/out: update vector */ |
| 593 | dtuple_t* entry, /*!< in/out: index entry */ |
| 594 | ulint* n_ext) /*!< in/out: number of |
| 595 | externally stored columns */ |
| 596 | { |
| 597 | mem_heap_t* heap; |
| 598 | big_rec_t* vector; |
| 599 | dfield_t* dfield; |
| 600 | dict_field_t* ifield; |
| 601 | ulint size; |
| 602 | ulint n_fields; |
| 603 | ulint local_len; |
| 604 | ulint local_prefix_len; |
| 605 | |
| 606 | if (!dict_index_is_clust(index)) { |
| 607 | return(NULL); |
| 608 | } |
| 609 | |
| 610 | if (!dict_table_has_atomic_blobs(index->table)) { |
| 611 | /* up to MySQL 5.1: store a 768-byte prefix locally */ |
| 612 | local_len = BTR_EXTERN_FIELD_REF_SIZE |
| 613 | + DICT_ANTELOPE_MAX_INDEX_COL_LEN; |
| 614 | } else { |
| 615 | /* new-format table: do not store any BLOB prefix locally */ |
| 616 | local_len = BTR_EXTERN_FIELD_REF_SIZE; |
| 617 | } |
| 618 | |
| 619 | ut_a(dtuple_check_typed_no_assert(entry)); |
| 620 | |
| 621 | size = rec_get_converted_size(index, entry, *n_ext); |
| 622 | |
| 623 | if (UNIV_UNLIKELY(size > 1000000000)) { |
| 624 | ib::warn() << "Tuple size is very big: " << size; |
| 625 | fputs("InnoDB: Tuple contents: " , stderr); |
| 626 | dtuple_print(stderr, entry); |
| 627 | putc('\n', stderr); |
| 628 | } |
| 629 | |
| 630 | heap = mem_heap_create(size + dtuple_get_n_fields(entry) |
| 631 | * sizeof(big_rec_field_t) + 1000); |
| 632 | |
| 633 | vector = big_rec_t::alloc(heap, dtuple_get_n_fields(entry)); |
| 634 | |
| 635 | /* Decide which fields to shorten: the algorithm is to look for |
| 636 | a variable-length field that yields the biggest savings when |
| 637 | stored externally */ |
| 638 | |
| 639 | n_fields = 0; |
| 640 | |
| 641 | while (page_zip_rec_needs_ext(rec_get_converted_size(index, entry, |
| 642 | *n_ext), |
| 643 | dict_table_is_comp(index->table), |
| 644 | dict_index_get_n_fields(index), |
| 645 | dict_table_page_size(index->table))) { |
| 646 | |
| 647 | ulint i; |
| 648 | ulint longest = 0; |
| 649 | ulint longest_i = ULINT_MAX; |
| 650 | byte* data; |
| 651 | |
| 652 | for (i = dict_index_get_n_unique_in_tree(index); |
| 653 | i < dtuple_get_n_fields(entry); i++) { |
| 654 | ulint savings; |
| 655 | |
| 656 | dfield = dtuple_get_nth_field(entry, i); |
| 657 | ifield = dict_index_get_nth_field(index, i); |
| 658 | |
| 659 | /* Skip fixed-length, NULL, externally stored, |
| 660 | or short columns */ |
| 661 | |
| 662 | if (ifield->fixed_len |
| 663 | || dfield_is_null(dfield) |
| 664 | || dfield_is_ext(dfield) |
| 665 | || dfield_get_len(dfield) <= local_len |
| 666 | || dfield_get_len(dfield) |
| 667 | <= BTR_EXTERN_LOCAL_STORED_MAX_SIZE) { |
| 668 | goto skip_field; |
| 669 | } |
| 670 | |
| 671 | savings = dfield_get_len(dfield) - local_len; |
| 672 | |
| 673 | /* Check that there would be savings */ |
| 674 | if (longest >= savings) { |
| 675 | goto skip_field; |
| 676 | } |
| 677 | |
| 678 | /* In DYNAMIC and COMPRESSED format, store |
| 679 | locally any non-BLOB columns whose maximum |
| 680 | length does not exceed 256 bytes. This is |
| 681 | because there is no room for the "external |
| 682 | storage" flag when the maximum length is 255 |
| 683 | bytes or less. This restriction trivially |
| 684 | holds in REDUNDANT and COMPACT format, because |
| 685 | there we always store locally columns whose |
| 686 | length is up to local_len == 788 bytes. |
| 687 | @see rec_init_offsets_comp_ordinary */ |
| 688 | if (!DATA_BIG_COL(ifield->col)) { |
| 689 | goto skip_field; |
| 690 | } |
| 691 | |
| 692 | longest_i = i; |
| 693 | longest = savings; |
| 694 | |
| 695 | skip_field: |
| 696 | continue; |
| 697 | } |
| 698 | |
| 699 | if (!longest) { |
| 700 | /* Cannot shorten more */ |
| 701 | |
| 702 | mem_heap_free(heap); |
| 703 | |
| 704 | return(NULL); |
| 705 | } |
| 706 | |
| 707 | /* Move data from field longest_i to big rec vector. |
| 708 | |
| 709 | We store the first bytes locally to the record. Then |
| 710 | we can calculate all ordering fields in all indexes |
| 711 | from locally stored data. */ |
| 712 | |
| 713 | dfield = dtuple_get_nth_field(entry, longest_i); |
| 714 | ifield = dict_index_get_nth_field(index, longest_i); |
| 715 | local_prefix_len = local_len - BTR_EXTERN_FIELD_REF_SIZE; |
| 716 | |
| 717 | vector->append( |
| 718 | big_rec_field_t( |
| 719 | longest_i, |
| 720 | dfield_get_len(dfield) - local_prefix_len, |
| 721 | static_cast<char*>(dfield_get_data(dfield)) |
| 722 | + local_prefix_len)); |
| 723 | |
| 724 | /* Allocate the locally stored part of the column. */ |
| 725 | data = static_cast<byte*>(mem_heap_alloc(heap, local_len)); |
| 726 | |
| 727 | /* Copy the local prefix. */ |
| 728 | memcpy(data, dfield_get_data(dfield), local_prefix_len); |
| 729 | /* Clear the extern field reference (BLOB pointer). */ |
| 730 | memset(data + local_prefix_len, 0, BTR_EXTERN_FIELD_REF_SIZE); |
| 731 | #if 0 |
| 732 | /* The following would fail the Valgrind checks in |
| 733 | page_cur_insert_rec_low() and page_cur_insert_rec_zip(). |
| 734 | The BLOB pointers in the record will be initialized after |
| 735 | the record and the BLOBs have been written. */ |
| 736 | UNIV_MEM_ALLOC(data + local_prefix_len, |
| 737 | BTR_EXTERN_FIELD_REF_SIZE); |
| 738 | #endif |
| 739 | |
| 740 | dfield_set_data(dfield, data, local_len); |
| 741 | dfield_set_ext(dfield); |
| 742 | |
| 743 | n_fields++; |
| 744 | (*n_ext)++; |
| 745 | ut_ad(n_fields < dtuple_get_n_fields(entry)); |
| 746 | |
| 747 | if (upd && !upd->is_modified(longest_i)) { |
| 748 | |
| 749 | DEBUG_SYNC_C("ib_mv_nonupdated_column_offpage" ); |
| 750 | |
| 751 | upd_field_t upd_field; |
| 752 | upd_field.field_no = unsigned(longest_i); |
| 753 | upd_field.orig_len = 0; |
| 754 | upd_field.exp = NULL; |
| 755 | upd_field.old_v_val = NULL; |
| 756 | dfield_copy(&upd_field.new_val, |
| 757 | dfield->clone(upd->heap)); |
| 758 | upd->append(upd_field); |
| 759 | ut_ad(upd->is_modified(longest_i)); |
| 760 | |
| 761 | ut_ad(upd_field.new_val.len |
| 762 | >= BTR_EXTERN_FIELD_REF_SIZE); |
| 763 | ut_ad(upd_field.new_val.len == local_len); |
| 764 | ut_ad(upd_field.new_val.len == dfield_get_len(dfield)); |
| 765 | } |
| 766 | } |
| 767 | |
| 768 | ut_ad(n_fields == vector->n_fields); |
| 769 | |
| 770 | return(vector); |
| 771 | } |
| 772 | |
| 773 | /**************************************************************//** |
| 774 | Puts back to entry the data stored in vector. Note that to ensure the |
| 775 | fields in entry can accommodate the data, vector must have been created |
| 776 | from entry with dtuple_convert_big_rec. */ |
| 777 | void |
| 778 | dtuple_convert_back_big_rec( |
| 779 | /*========================*/ |
| 780 | dict_index_t* index MY_ATTRIBUTE((unused)), /*!< in: index */ |
| 781 | dtuple_t* entry, /*!< in: entry whose data was put to vector */ |
| 782 | big_rec_t* vector) /*!< in, own: big rec vector; it is |
| 783 | freed in this function */ |
| 784 | { |
| 785 | big_rec_field_t* b = vector->fields; |
| 786 | const big_rec_field_t* const end = b + vector->n_fields; |
| 787 | |
| 788 | for (; b < end; b++) { |
| 789 | dfield_t* dfield; |
| 790 | ulint local_len; |
| 791 | |
| 792 | dfield = dtuple_get_nth_field(entry, b->field_no); |
| 793 | local_len = dfield_get_len(dfield); |
| 794 | |
| 795 | ut_ad(dfield_is_ext(dfield)); |
| 796 | ut_ad(local_len >= BTR_EXTERN_FIELD_REF_SIZE); |
| 797 | |
| 798 | local_len -= BTR_EXTERN_FIELD_REF_SIZE; |
| 799 | |
| 800 | /* Only in REDUNDANT and COMPACT format, we store |
| 801 | up to DICT_ANTELOPE_MAX_INDEX_COL_LEN (768) bytes |
| 802 | locally */ |
| 803 | ut_ad(local_len <= DICT_ANTELOPE_MAX_INDEX_COL_LEN); |
| 804 | |
| 805 | dfield_set_data(dfield, |
| 806 | (char*) b->data - local_len, |
| 807 | b->len + local_len); |
| 808 | } |
| 809 | |
| 810 | mem_heap_free(vector->heap); |
| 811 | } |
| 812 | |
| 813 | /** Allocate a big_rec_t object in the given memory heap, and for storing |
| 814 | n_fld number of fields. |
| 815 | @param[in] heap memory heap in which this object is allocated |
| 816 | @param[in] n_fld maximum number of fields that can be stored in |
| 817 | this object |
| 818 | |
| 819 | @return the allocated object */ |
| 820 | big_rec_t* |
| 821 | big_rec_t::alloc( |
| 822 | mem_heap_t* heap, |
| 823 | ulint n_fld) |
| 824 | { |
| 825 | big_rec_t* rec = static_cast<big_rec_t*>( |
| 826 | mem_heap_alloc(heap, sizeof(big_rec_t))); |
| 827 | |
| 828 | new(rec) big_rec_t(n_fld); |
| 829 | |
| 830 | rec->heap = heap; |
| 831 | rec->fields = static_cast<big_rec_field_t*>( |
| 832 | mem_heap_alloc(heap, |
| 833 | n_fld * sizeof(big_rec_field_t))); |
| 834 | |
| 835 | rec->n_fields = 0; |
| 836 | return(rec); |
| 837 | } |
| 838 | |
| 839 | /** Create a deep copy of this object. |
| 840 | @param[in,out] heap memory heap in which the clone will be created |
| 841 | @return the cloned object */ |
| 842 | dfield_t* |
| 843 | dfield_t::clone(mem_heap_t* heap) const |
| 844 | { |
| 845 | const ulint size = len == UNIV_SQL_NULL ? 0 : len; |
| 846 | dfield_t* obj = static_cast<dfield_t*>( |
| 847 | mem_heap_alloc(heap, sizeof(dfield_t) + size)); |
| 848 | |
| 849 | ut_ad(len != UNIV_SQL_DEFAULT); |
| 850 | obj->ext = ext; |
| 851 | obj->len = len; |
| 852 | obj->type = type; |
| 853 | obj->spatial_status = spatial_status; |
| 854 | |
| 855 | if (len != UNIV_SQL_NULL) { |
| 856 | obj->data = obj + 1; |
| 857 | memcpy(obj->data, data, len); |
| 858 | } else { |
| 859 | obj->data = 0; |
| 860 | } |
| 861 | |
| 862 | return(obj); |
| 863 | } |
| 864 | |