1 /***************************************************************************** 2 3 Copyright (c) 1996, 2020, Oracle and/or its affiliates. All Rights Reserved. 4 5 This program is free software; you can redistribute it and/or modify it under 6 the terms of the GNU General Public License, version 2.0, as published by the 7 Free Software Foundation. 8 9 This program is also distributed with certain software (including but not 10 limited to OpenSSL) that is licensed under separate terms, as designated in a 11 particular file or component or in included license documentation. The authors 12 of MySQL hereby grant you an additional permission to link the program and 13 your derivative works with the separately licensed software that they have 14 included with MySQL. 15 16 This program is distributed in the hope that it will be useful, but WITHOUT 17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, 19 for more details. 20 21 You should have received a copy of the GNU General Public License along with 22 this program; if not, write to the Free Software Foundation, Inc., 23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 25 *****************************************************************************/ 26 27 /** @file include/row0upd.h 28 Update of a row 29 30 Created 12/27/1996 Heikki Tuuri 31 *******************************************************/ 32 33 #ifndef row0upd_h 34 #define row0upd_h 35 36 #include <stack> 37 #include "btr0types.h" 38 #include "data0data.h" 39 #include "dict0types.h" 40 #include "lob0lob.h" 41 #include "row0types.h" 42 #include "table.h" 43 #include "trx0types.h" 44 #include "univ.i" 45 46 #include "btr0pcur.h" 47 #ifndef UNIV_HOTBACKUP 48 #include "pars0types.h" 49 #include "que0types.h" 50 #endif /* !UNIV_HOTBACKUP */ 51 52 /** Creates an update vector object. 53 @param[in] n number of fields 54 @param[in] heap heap from which memory allocated 55 @return own: update vector object */ 56 UNIV_INLINE 57 upd_t *upd_create(ulint n, mem_heap_t *heap); 58 59 /** Returns the number of fields in the update vector == number of columns 60 to be updated by an update vector. 61 @return number of fields */ 62 UNIV_INLINE 63 ulint upd_get_n_fields(const upd_t *update); /*!< in: update vector */ 64 65 #ifdef UNIV_DEBUG 66 /** Returns the nth field of an update vector. 67 @param[in] update update vector 68 @param[in] n field position in update vector 69 @return update vector field */ 70 UNIV_INLINE 71 upd_field_t *upd_get_nth_field(const upd_t *update, ulint n); 72 #else 73 #define upd_get_nth_field(update, n) ((update)->fields + (n)) 74 #endif 75 /** Sets an index field number to be updated by an update vector field. 76 @param[in] upd_field update vector field 77 @param[in] field_no field number in a clustered index 78 @param[in] index index 79 @param[in] trx transaction */ 80 UNIV_INLINE 81 void upd_field_set_field_no(upd_field_t *upd_field, ulint field_no, 82 const dict_index_t *index, trx_t *trx); 83 84 /** set field number to a update vector field, marks this field is updated 85 @param[in,out] upd_field update vector field 86 @param[in] field_no virtual column sequence num 87 @param[in] index index */ 88 UNIV_INLINE 89 void upd_field_set_v_field_no(upd_field_t *upd_field, ulint field_no, 90 const dict_index_t *index); 91 /** Returns a field of an update vector by field_no. 92 @return update vector field, or NULL */ 93 UNIV_INLINE 94 const upd_field_t *upd_get_field_by_field_no( 95 const upd_t *update, /*!< in: update vector */ 96 ulint no, /*!< in: field_no */ 97 bool is_virtual) /*!< in: if it is a virtual column */ 98 MY_ATTRIBUTE((warn_unused_result)); 99 /** Writes into the redo log the values of trx id and roll ptr and enough info 100 to determine their positions within a clustered index record. 101 @return new pointer to mlog */ 102 byte *row_upd_write_sys_vals_to_log( 103 dict_index_t *index, /*!< in: clustered index */ 104 trx_id_t trx_id, /*!< in: transaction id */ 105 roll_ptr_t roll_ptr, /*!< in: roll ptr of the undo log record */ 106 byte *log_ptr, /*!< pointer to a buffer of size > 20 opened 107 in mlog */ 108 mtr_t *mtr); /*!< in: mtr */ 109 110 /** Updates the trx id and roll ptr field in a clustered index record when a 111 row is updated or marked deleted. 112 @param[in,out] rec record 113 @param[in,out] page_zip compressed page whose uncompressed part will 114 be updated, or NULL 115 @param[in] index clustered index 116 @param[in] offsets rec_get_offsets(rec, index) 117 @param[in] trx transaction 118 @param[in] roll_ptr roll ptr of the undo log record, can be 0 119 during IMPORT */ 120 UNIV_INLINE 121 void row_upd_rec_sys_fields(rec_t *rec, page_zip_des_t *page_zip, 122 const dict_index_t *index, const ulint *offsets, 123 const trx_t *trx, roll_ptr_t roll_ptr); 124 125 /** Sets the trx id or roll ptr field of a clustered index entry. */ 126 void row_upd_index_entry_sys_field( 127 dtuple_t *entry, /*!< in/out: index entry, where the memory 128 buffers for sys fields are already allocated: 129 the function just copies the new values to 130 them */ 131 dict_index_t *index, /*!< in: clustered index */ 132 ulint type, /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */ 133 ib_uint64_t val); /*!< in: value to write */ 134 /** Creates an update node for a query graph. 135 @return own: update node */ 136 upd_node_t *upd_node_create( 137 mem_heap_t *heap); /*!< in: mem heap where created */ 138 139 /** Writes to the redo log the new values of the fields occurring in the index. 140 @param[in] index index which to be updated 141 @param[in] update update vector 142 @param[in] log_ptr pointer to mlog buffer: must contain at least 143 MLOG_BUF_MARGIN bytes of free space; the buffer 144 is closed within this function 145 @param[in] mtr mtr into whose log to write */ 146 void row_upd_index_write_log(dict_index_t *index, const upd_t *update, 147 byte *log_ptr, mtr_t *mtr); 148 149 /** Returns TRUE if row update changes size of some field in index or if some 150 field to be updated is stored externally in rec or update. 151 @return true if the update changes the size of some field in index or 152 the field is external in rec or update */ 153 ibool row_upd_changes_field_size_or_external( 154 const dict_index_t *index, /*!< in: index */ 155 const ulint *offsets, /*!< in: rec_get_offsets(rec, index) */ 156 const upd_t *update); /*!< in: update vector */ 157 /** Returns true if row update contains disowned external fields. 158 @return true if the update contains disowned external fields. */ 159 bool row_upd_changes_disowned_external( 160 const upd_t *update) /*!< in: update vector */ 161 MY_ATTRIBUTE((warn_unused_result)); 162 /** Replaces the new column values stored in the update vector to the 163 record given. No field size changes are allowed. This function is 164 usually invoked on a clustered index. The only use case for a 165 secondary index is row_ins_sec_index_entry_by_modify() or its 166 counterpart in ibuf_insert_to_index_page(). */ 167 void row_upd_rec_in_place( 168 rec_t *rec, /*!< in/out: record where replaced */ 169 const dict_index_t *index, /*!< in: the index the record belongs to */ 170 const ulint *offsets, /*!< in: array returned by rec_get_offsets() */ 171 const upd_t *update, /*!< in: update vector */ 172 page_zip_des_t *page_zip); /*!< in: compressed page with enough space 173 available, or NULL */ 174 /** Builds an update vector from those fields which in a secondary index entry 175 differ from a record that has the equal ordering fields. NOTE: we compare 176 the fields as binary strings! 177 @return own: update vector of differing fields */ 178 upd_t *row_upd_build_sec_rec_difference_binary( 179 const rec_t *rec, /*!< in: secondary index record */ 180 dict_index_t *index, /*!< in: index */ 181 const ulint *offsets, /*!< in: rec_get_offsets(rec, index) */ 182 const dtuple_t *entry, /*!< in: entry to insert */ 183 mem_heap_t *heap) /*!< in: memory heap from which allocated */ 184 MY_ATTRIBUTE((warn_unused_result)); 185 /** Builds an update vector from those fields, excluding the roll ptr and 186 trx id fields, which in an index entry differ from a record that has 187 the equal ordering fields. NOTE: we compare the fields as binary strings! 188 @param[in] index clustered index 189 @param[in] entry clustered index entry to insert 190 @param[in] rec clustered index record 191 @param[in] offsets rec_get_offsets(rec,index), or NULL 192 @param[in] no_sys skip the system columns 193 DB_TRX_ID and DB_ROLL_PTR 194 @param[in] trx transaction (for diagnostics), 195 or NULL 196 @param[in] heap memory heap from which allocated 197 @param[in] mysql_table NULL, or mysql table object when 198 user thread invokes dml 199 @param[out] error error number in case of failure 200 @return own: update vector of differing fields, excluding roll ptr and 201 trx id */ 202 upd_t *row_upd_build_difference_binary(dict_index_t *index, 203 const dtuple_t *entry, const rec_t *rec, 204 const ulint *offsets, bool no_sys, 205 trx_t *trx, mem_heap_t *heap, 206 TABLE *mysql_table, dberr_t *error) 207 MY_ATTRIBUTE((warn_unused_result)); 208 /** Replaces the new column values stored in the update vector to the index 209 entry given. */ 210 void row_upd_index_replace_new_col_vals_index_pos( 211 dtuple_t *entry, /*!< in/out: index entry where replaced; 212 the clustered index record must be 213 covered by a lock or a page latch to 214 prevent deletion (rollback or purge) */ 215 const dict_index_t *index, /*!< in: index; NOTE that this may also be a 216 non-clustered index */ 217 const upd_t *update, /*!< in: an update vector built for the index so 218 that the field number in an upd_field is the 219 index position */ 220 ibool order_only, 221 /*!< in: if TRUE, limit the replacement to 222 ordering fields of index; note that this 223 does not work for non-clustered indexes. */ 224 mem_heap_t *heap); /*!< in: memory heap for allocating and 225 copying the new values */ 226 /** Replaces the new column values stored in the update vector to the index 227 entry given. */ 228 void row_upd_index_replace_new_col_vals( 229 dtuple_t *entry, /*!< in/out: index entry where replaced; 230 the clustered index record must be 231 covered by a lock or a page latch to 232 prevent deletion (rollback or purge) */ 233 const dict_index_t *index, /*!< in: index; NOTE that this may also be a 234 non-clustered index */ 235 const upd_t *update, /*!< in: an update vector built for the 236 CLUSTERED index so that the field number in 237 an upd_field is the clustered index position */ 238 mem_heap_t *heap); /*!< in: memory heap for allocating and 239 copying the new values */ 240 /** Replaces the new column values stored in the update vector. */ 241 void row_upd_replace(trx_t *trx, /*!< in: current transaction. */ 242 dtuple_t *row, /*!< in/out: row where replaced, 243 indexed by col_no; 244 the clustered index record must be 245 covered by a lock or a page latch to 246 prevent deletion (rollback or purge) */ 247 row_ext_t **ext, /*!< out, own: NULL, or externally 248 stored column prefixes */ 249 const dict_index_t *index, /*!< in: clustered index */ 250 const upd_t *update, /*!< in: an update vector built for 251 the clustered index */ 252 mem_heap_t *heap); /*!< in: memory heap */ 253 /** Replaces the virtual column values stored in a dtuple with that of 254 a update vector. 255 @param[in,out] row dtuple whose column to be updated 256 @param[in] table table 257 @param[in] update an update vector built for the clustered index 258 @param[in] upd_new update to new or old value 259 @param[in,out] undo_row undo row (if needs to be updated) 260 @param[in] ptr remaining part in update undo log */ 261 void row_upd_replace_vcol(dtuple_t *row, const dict_table_t *table, 262 const upd_t *update, bool upd_new, dtuple_t *undo_row, 263 const byte *ptr); 264 265 /** Checks if an update vector changes an ordering field of an index record. 266 It will also help check if any non-multi-value field on the multi-value index 267 gets updated or not. 268 269 This function is fast if the update vector is short or the number of ordering 270 fields in the index is small. Otherwise, this can be quadratic. 271 NOTE: we compare the fields as binary strings! 272 @param[in] index index of the record 273 @param[in] update update vector for the row; NOTE: the 274 field numbers in this MUST be clustered index 275 positions! */ 276 #ifdef UNIV_DEBUG 277 /** 278 @param[in] thr query thread, or NULL */ 279 #endif /* UNIV_DEBUG */ 280 /** 281 @param[in] row old value of row, or NULL if the 282 row and the data values in update are not 283 known when this function is called, e.g., at 284 compile time 285 @param[in] ext NULL, or prefixes of the externally 286 stored columns in the old row 287 @param[in,out] non_mv_upd NULL, or not NULL pointer to get the 288 information about whether any non-multi-value 289 field on the multi-value index gets updated 290 @param[in] flag ROW_BUILD_NORMAL, ROW_BUILD_FOR_PURGE or 291 ROW_BUILD_FOR_UNDO 292 @return true if update vector changes an ordering field in the index record */ 293 bool row_upd_changes_ord_field_binary_func(dict_index_t *index, 294 const upd_t *update, 295 #ifdef UNIV_DEBUG 296 const que_thr_t *thr, 297 #endif /* UNIV_DEBUG */ 298 const dtuple_t *row, 299 const row_ext_t *ext, 300 bool *non_mv_upd, ulint flag) 301 MY_ATTRIBUTE((warn_unused_result)); 302 303 #ifdef UNIV_DEBUG 304 #define row_upd_changes_ord_field_binary(index, update, thr, row, ext, \ 305 non_mv_upd) \ 306 row_upd_changes_ord_field_binary_func(index, update, thr, row, ext, \ 307 non_mv_upd, 0) 308 #else /* UNIV_DEBUG */ 309 #define row_upd_changes_ord_field_binary(index, update, thr, row, ext, \ 310 non_mv_upd) \ 311 row_upd_changes_ord_field_binary_func(index, update, row, ext, non_mv_upd, 0) 312 #endif /* UNIV_DEBUG */ 313 314 /** Checks if an FTS indexed column is affected by an UPDATE. 315 @return offset within fts_t::indexes if FTS indexed column updated else 316 ULINT_UNDEFINED */ 317 ulint row_upd_changes_fts_column( 318 dict_table_t *table, /*!< in: table */ 319 upd_field_t *upd_field); /*!< in: field to check */ 320 /** Checks if an FTS Doc ID column is affected by an UPDATE. 321 @return whether Doc ID column is affected */ 322 bool row_upd_changes_doc_id(dict_table_t *table, /*!< in: table */ 323 upd_field_t *upd_field) /*!< in: field to check */ 324 MY_ATTRIBUTE((warn_unused_result)); 325 /** Checks if an update vector changes an ordering field of an index record. 326 This function is fast if the update vector is short or the number of ordering 327 fields in the index is small. Otherwise, this can be quadratic. 328 NOTE: we compare the fields as binary strings! 329 @return true if update vector may change an ordering field in an index 330 record */ 331 ibool row_upd_changes_some_index_ord_field_binary( 332 const dict_table_t *table, /*!< in: table */ 333 const upd_t *update); /*!< in: update vector for the row */ 334 /** Stores to the heap the row on which the node->pcur is positioned. 335 @param[in] node row update node 336 @param[in] thd mysql thread handle 337 @param[in,out] mysql_table NULL, or mysql table object when 338 user thread invokes dml */ 339 void row_upd_store_row(trx_t *trx, upd_node_t *node, THD *thd, 340 TABLE *mysql_table); 341 /** Updates a row in a table. This is a high-level function used 342 in SQL execution graphs. 343 @return query thread to run next or NULL */ 344 que_thr_t *row_upd_step(que_thr_t *thr); /*!< in: query thread */ 345 /** Parses the log data of system field values. 346 @return log data end or NULL */ 347 byte *row_upd_parse_sys_vals(const byte *ptr, /*!< in: buffer */ 348 const byte *end_ptr, /*!< in: buffer end */ 349 ulint *pos, /*!< out: TRX_ID position in record */ 350 trx_id_t *trx_id, /*!< out: trx id */ 351 roll_ptr_t *roll_ptr); /*!< out: roll ptr */ 352 /** Updates the trx id and roll ptr field in a clustered index record in 353 database recovery. */ 354 void row_upd_rec_sys_fields_in_recovery( 355 rec_t *rec, /*!< in/out: record */ 356 page_zip_des_t *page_zip, /*!< in/out: compressed page, or NULL */ 357 const ulint *offsets, /*!< in: array returned by rec_get_offsets() */ 358 ulint pos, /*!< in: TRX_ID position in rec */ 359 trx_id_t trx_id, /*!< in: transaction id */ 360 roll_ptr_t roll_ptr); /*!< in: roll ptr of the undo log record */ 361 /** Parses the log data written by row_upd_index_write_log. 362 @return log data end or NULL */ 363 byte *row_upd_index_parse(const byte *ptr, /*!< in: buffer */ 364 const byte *end_ptr, /*!< in: buffer end */ 365 mem_heap_t *heap, /*!< in: memory heap where update 366 vector is built */ 367 upd_t **update_out); /*!< out: update vector */ 368 369 /** Get the new autoinc counter from the update vector when there is 370 an autoinc field defined in this table. 371 @param[in] update update vector for the clustered index 372 @param[in] autoinc_field_no autoinc field's order in clustered index 373 @return the new counter if we find it in the update vector, otherwise 0 */ 374 ib_uint64_t row_upd_get_new_autoinc_counter(const upd_t *update, 375 ulint autoinc_field_no); 376 377 /** This structure is used for undo logging of LOB index changes. */ 378 struct lob_index_diff_t { 379 trx_id_t m_modifier_trxid; 380 undo_no_t m_modifier_undo_no; 381 382 /** Print the current object into the given output stream. 383 @param[in,out] out the output stream. 384 @return the output stream. */ printlob_index_diff_t385 std::ostream &print(std::ostream &out) const { 386 out << "[lob_index_diff_t: m_modifier_trxid=" << m_modifier_trxid 387 << ", m_modifier_undo_no=" << m_modifier_undo_no << "]"; 388 return (out); 389 } 390 }; 391 392 using Lob_index_diff_vec = 393 std::vector<lob_index_diff_t, mem_heap_allocator<lob_index_diff_t>>; 394 395 /** Overloading the global output operator to print lob_index_diff_t object. 396 @param[in,out] out the output stream. 397 @param[in] obj the object to be printed. 398 @return the output stream.*/ 399 inline std::ostream &operator<<(std::ostream &out, 400 const lob_index_diff_t &obj) { 401 return (obj.print(out)); 402 } 403 404 /** The modification done to the LOB. */ 405 struct Lob_diff { 406 /** Constructor. 407 @param[in] mem_heap the memory heap in which this object 408 has been created. */ Lob_diffLob_diff409 Lob_diff(mem_heap_t *mem_heap) : heap(mem_heap) { 410 m_idx_diffs = static_cast<Lob_index_diff_vec *>( 411 mem_heap_alloc(heap, sizeof(Lob_index_diff_vec))); 412 new (m_idx_diffs) 413 Lob_index_diff_vec(mem_heap_allocator<lob_index_diff_t>(heap)); 414 } 415 416 /** Read the offset from the undo record. 417 @param[in] undo_ptr pointer into the undo log record. 418 @return pointer into the undo log record after offset. */ read_offsetLob_diff419 const byte *read_offset(const byte *undo_ptr) { 420 /* Read the offset. */ 421 m_offset = mach_read_next_compressed(&undo_ptr); 422 return (undo_ptr); 423 } 424 425 /** Read the length from the undo record. 426 @param[in] undo_ptr pointer into the undo log record. 427 @return pointer into the undo log record after length information. */ read_lengthLob_diff428 const byte *read_length(const byte *undo_ptr) { 429 /* Read the length. */ 430 m_length = mach_read_next_compressed(&undo_ptr); 431 ut_ad(m_length <= lob::ref_t::LOB_SMALL_CHANGE_THRESHOLD); 432 433 return (undo_ptr); 434 } 435 set_old_dataLob_diff436 void set_old_data(const byte *undo_ptr) { m_old_data = undo_ptr; } 437 printLob_diff438 std::ostream &print(std::ostream &out) const { 439 out << "[Lob_diff: offset=" << m_offset << ", length=" << m_length; 440 if (m_old_data == nullptr) { 441 out << ", m_old_data=nullptr"; 442 } else { 443 out << ", m_old_data=" << PrintBuffer(m_old_data, m_length); 444 } 445 446 if (m_idx_diffs != nullptr) { 447 for (auto iter = m_idx_diffs->begin(); iter != m_idx_diffs->end(); 448 ++iter) { 449 out << *iter; 450 } 451 } 452 453 out << "]"; 454 return (out); 455 } 456 457 /** The offset within LOB where partial update happened. */ 458 ulint m_offset = 0; 459 460 /** The length of the modification. */ 461 ulint m_length = 0; 462 463 /** Changes to the LOB data. */ 464 const byte *m_old_data = nullptr; 465 466 /** Changes to the LOB index. */ 467 Lob_index_diff_vec *m_idx_diffs; 468 469 /** Memory heap in which this object is allocated. */ 470 mem_heap_t *heap; 471 }; 472 473 using Lob_diff_vector = std::vector<Lob_diff, mem_heap_allocator<Lob_diff>>; 474 475 inline std::ostream &operator<<(std::ostream &out, const Lob_diff &obj) { 476 return (obj.print(out)); 477 } 478 479 /* Update vector field */ 480 struct upd_field_t { upd_field_tupd_field_t481 upd_field_t() 482 : field_no(0), 483 orig_len(0), 484 exp(nullptr), 485 old_v_val(nullptr), 486 mysql_field(nullptr), 487 ext_in_old(false), 488 lob_diffs(nullptr), 489 lob_first_page_no(FIL_NULL), 490 lob_version(0), 491 last_trx_id(0), 492 last_undo_no(0), 493 heap(nullptr) {} 494 is_virtualupd_field_t495 bool is_virtual() const { return (new_val.is_virtual()); } 496 497 unsigned field_no : 16; /*!< field number in an index, usually 498 the clustered index, but in updating 499 a secondary index record in btr0cur.cc 500 this is the position in the secondary 501 index, also it could be the position 502 in virtual index for virtual column */ 503 unsigned orig_len : 16; /*!< original length of the locally 504 stored part of an externally stored 505 column, or 0 */ 506 que_node_t *exp; /*!< expression for calculating a new 507 value: it refers to column values and 508 constants in the symbol table of the 509 query graph */ 510 dfield_t old_val; /*!< old value for the column */ 511 dfield_t new_val; /*!< new value for the column */ 512 dfield_t *old_v_val; /*!< old value for the virtual column */ 513 514 Field *mysql_field; /*!< the mysql field object. */ 515 516 /** If true, the field was stored externally in the old row. */ 517 bool ext_in_old; 518 push_lob_diffupd_field_t519 void push_lob_diff(const Lob_diff &lob_diff) { 520 if (lob_diffs == nullptr) { 521 lob_diffs = static_cast<Lob_diff_vector *>( 522 mem_heap_alloc(heap, sizeof(Lob_diff_vector))); 523 new (lob_diffs) Lob_diff_vector(mem_heap_allocator<Lob_diff>(heap)); 524 } 525 lob_diffs->push_back(lob_diff); 526 } 527 528 /** List of changes done to this updated field. This is usually 529 populated from the undo log. */ 530 Lob_diff_vector *lob_diffs; 531 532 /** The LOB first page number. This information is read from 533 the undo log. */ 534 page_no_t lob_first_page_no; 535 536 ulint lob_version; 537 538 /** The last trx that modified the LOB. */ 539 trx_id_t last_trx_id; 540 541 /** The last stmt within trx that modified the LOB. */ 542 undo_no_t last_undo_no; 543 544 std::ostream &print(std::ostream &out) const; 545 546 /** Empty the information collected on LOB diffs. */ resetupd_field_t547 void reset() { 548 if (lob_diffs != nullptr) { 549 lob_diffs->clear(); 550 } 551 } 552 553 /** Memory heap in which this object is allocated. */ 554 mem_heap_t *heap; 555 }; 556 557 inline std::ostream &operator<<(std::ostream &out, const upd_field_t &obj) { 558 return (obj.print(out)); 559 } 560 561 /* check whether an update field is on virtual column */ 562 #define upd_fld_is_virtual_col(upd_fld) \ 563 (((upd_fld)->new_val.type.prtype & DATA_VIRTUAL) == DATA_VIRTUAL) 564 565 /* check whether an update field is on multi-value virtual column */ 566 #define upd_fld_is_multi_value_col(upd_fld) \ 567 (dfield_is_multi_value(&((upd_fld)->new_val))) 568 569 /* set DATA_VIRTUAL bit on update field to show it is a virtual column */ 570 #define upd_fld_set_virtual_col(upd_fld) \ 571 ((upd_fld)->new_val.type.prtype |= DATA_VIRTUAL) 572 573 /* Update vector structure */ 574 struct upd_t { 575 mem_heap_t *heap; /*!< heap from which memory allocated */ 576 ulint info_bits; /*!< new value of info bits to record; 577 default is 0 */ 578 dtuple_t *old_vrow; /*!< pointer to old row, used for 579 virtual column update now */ 580 dict_table_t *table; /*!< the table object */ 581 TABLE *mysql_table; /*!< the mysql table object */ 582 583 ulint n_fields; /*!< number of update fields */ 584 upd_field_t *fields; /*!< array of update fields */ 585 586 /** Append an update field to the end of array 587 @param[in] field an update field */ appendupd_t588 void append(const upd_field_t &field) { fields[n_fields++] = field; } 589 590 /** Determine if the given field_no is modified. 591 @return true if modified, false otherwise. */ is_modifiedupd_t592 bool is_modified(const ulint field_no) const { 593 return (get_field_by_field_no(field_no, table->first_index()) != nullptr); 594 } 595 596 /** Reset the update fields. */ resetupd_t597 void reset() { 598 for (ulint i = 0; i < n_fields; ++i) { 599 fields[i].reset(); 600 } 601 } 602 603 #ifdef UNIV_DEBUG validateupd_t604 bool validate() const { 605 for (ulint i = 0; i < n_fields; ++i) { 606 dfield_t *field = &fields[i].new_val; 607 if (dfield_is_ext(field)) { 608 ut_ad(dfield_get_len(field) >= BTR_EXTERN_FIELD_REF_SIZE); 609 } 610 } 611 return (true); 612 } 613 #endif // UNIV_DEBUG 614 615 /** Check if the given field number is partially updated. 616 @param[in] field_no the field number. 617 @return true if partially updated, false otherwise. */ 618 bool is_partially_updated(ulint field_no) const; 619 620 upd_field_t *get_field_by_field_no(ulint field_no, dict_index_t *index) const; 621 622 const Binary_diff_vector *get_binary_diff_by_field_no(ulint field_no) const; 623 624 /** Calculate the total number of bytes modified in one BLOB. 625 @param[in] bdv the binary diff vector containing all the 626 modifications to one BLOB. 627 @return the total modified bytes. */ get_total_modified_bytesupd_t628 static size_t get_total_modified_bytes(const Binary_diff_vector &bdv) { 629 size_t total = 0; 630 for (const Binary_diff &bdiff : bdv) { 631 total += bdiff.length(); 632 } 633 return (total); 634 } 635 636 std::ostream &print(std::ostream &out) const; 637 638 /** Print the partial update vector (puvect) of the given update 639 field. 640 @param[in,out] out the output stream 641 @param[in] uf the updated field. 642 @return the output stream. */ 643 std::ostream &print_puvect(std::ostream &out, upd_field_t *uf) const; 644 }; 645 646 #ifdef UNIV_DEBUG 647 /** Print the given binary diff into the given output stream. 648 @param[in] out the output stream 649 @param[in] bdiff binary diff to be printed. 650 @param[in] table the table dictionary object. 651 @param[in] field mysql field object. 652 @return the output stream */ 653 std::ostream &print_binary_diff(std::ostream &out, const Binary_diff *bdiff, 654 const dict_table_t *table, const Field *field); 655 656 std::ostream &print_binary_diff(std::ostream &out, const Binary_diff *bdiff); 657 658 inline std::ostream &operator<<(std::ostream &out, const upd_t &obj) { 659 return (obj.print(out)); 660 } 661 662 inline std::ostream &operator<<(std::ostream &out, 663 const Binary_diff_vector &obj) { 664 return (out); 665 } 666 #endif /* UNIV_DEBUG */ 667 668 #ifndef UNIV_HOTBACKUP 669 /* Update node structure which also implements the delete operation 670 of a row */ 671 672 struct upd_node_t { 673 que_common_t common; /*!< node type: QUE_NODE_UPDATE */ 674 ibool is_delete; /* TRUE if delete, FALSE if update */ 675 ibool searched_update; 676 /* TRUE if searched update, FALSE if 677 positioned */ 678 ibool in_mysql_interface; 679 /* TRUE if the update node was created 680 for the MySQL interface */ 681 dict_foreign_t *foreign; /* NULL or pointer to a foreign key 682 constraint if this update node is used in 683 doing an ON DELETE or ON UPDATE operation */ 684 upd_node_t *cascade_node; /* NULL or an update node template which 685 is used to implement ON DELETE/UPDATE CASCADE 686 or ... SET NULL for foreign keys */ 687 mem_heap_t *cascade_heap; 688 /*!< NULL or a mem heap where cascade_upd_nodes 689 are created.*/ 690 sel_node_t *select; /*!< query graph subtree implementing a base 691 table cursor: the rows returned will be 692 updated */ 693 btr_pcur_t *pcur; /*!< persistent cursor placed on the clustered 694 index record which should be updated or 695 deleted; the cursor is stored in the graph 696 of 'select' field above, except in the case 697 of the MySQL interface */ 698 dict_table_t *table; /*!< table where updated */ 699 upd_t *update; /*!< update vector for the row */ 700 ulint update_n_fields; 701 /* when this struct is used to implement 702 a cascade operation for foreign keys, we store 703 here the size of the buffer allocated for use 704 as the update vector */ 705 sym_node_list_t columns; /* symbol table nodes for the columns 706 to retrieve from the table */ 707 ibool has_clust_rec_x_lock; 708 /* TRUE if the select which retrieves the 709 records to update already sets an x-lock on 710 the clustered record; note that it must always 711 set at least an s-lock */ 712 ulint cmpl_info; /* information extracted during query 713 compilation; speeds up execution: 714 UPD_NODE_NO_ORD_CHANGE and 715 UPD_NODE_NO_SIZE_CHANGE, ORed */ 716 /*----------------------*/ 717 /* Local storage for this graph node */ 718 ulint state; /*!< node execution state */ 719 dict_index_t *index; /*!< NULL, or the next index whose record should 720 be updated */ 721 dtuple_t *row; /*!< NULL, or a copy (also fields copied to 722 heap) of the row to update; this must be reset 723 to NULL after a successful update */ 724 row_ext_t *ext; /*!< NULL, or prefixes of the externally 725 stored columns in the old row */ 726 dtuple_t *upd_row; /* NULL, or a copy of the updated row */ 727 row_ext_t *upd_ext; /* NULL, or prefixes of the externally 728 stored columns in upd_row */ 729 mem_heap_t *heap; /*!< memory heap used as auxiliary storage; 730 this must be emptied after a successful 731 update */ 732 /*----------------------*/ 733 sym_node_t *table_sym; /* table node in symbol table */ 734 que_node_t *col_assign_list; 735 /* column assignment list */ 736 737 /** When there is a lock wait error, this remembers current position of 738 the multi-value field, before which the values have been deleted. 739 This will be used for both DELETE and the delete phase of UPDATE. */ 740 uint32_t del_multi_val_pos; 741 742 /** When there is a lock wait error, this remembers current position of 743 the multi-value field, before which the values have been updated. */ 744 uint32_t upd_multi_val_pos; 745 746 ulint magic_n; 747 }; 748 749 #define UPD_NODE_MAGIC_N 1579975 750 751 /* Node execution states */ 752 #define UPD_NODE_SET_IX_LOCK \ 753 1 /* execution came to the node from \ 754 a node above and if the field \ 755 has_clust_rec_x_lock is FALSE, we \ 756 should set an intention x-lock on \ 757 the table */ 758 #define UPD_NODE_UPDATE_CLUSTERED \ 759 2 /* clustered index record should be \ 760 updated */ 761 #define UPD_NODE_INSERT_CLUSTERED \ 762 3 /* clustered index record should be \ 763 inserted, old record is already delete \ 764 marked */ 765 #define UPD_NODE_UPDATE_ALL_SEC \ 766 5 /* an ordering field of the clustered \ 767 index record was changed, or this is \ 768 a delete operation: should update \ 769 all the secondary index records */ 770 #define UPD_NODE_UPDATE_SOME_SEC \ 771 6 /* secondary index entries should be \ 772 looked at and updated if an ordering \ 773 field changed */ 774 775 /* Compilation info flags: these must fit within 2 bits; see trx0rec.h */ 776 #define UPD_NODE_NO_ORD_CHANGE \ 777 1 /* no secondary index record will be \ 778 changed in the update and no ordering \ 779 field of the clustered index */ 780 #define UPD_NODE_NO_SIZE_CHANGE \ 781 2 /* no record field size will be \ 782 changed in the update */ 783 #endif /* !UNIV_HOTBACKUP */ 784 785 #include "row0upd.ic" 786 787 #endif 788