1 /***************************************************************************** 2 3 Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved. 4 Copyright (c) 2017, 2020, 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, Fifth Floor, Boston, MA 02110-1335 USA 17 18 *****************************************************************************/ 19 20 /**************************************************//** 21 @file include/row0upd.h 22 Update of a row 23 24 Created 12/27/1996 Heikki Tuuri 25 *******************************************************/ 26 27 #ifndef row0upd_h 28 #define row0upd_h 29 30 #include "data0data.h" 31 #include "rem0types.h" 32 #include "row0types.h" 33 #include "btr0types.h" 34 #include "trx0types.h" 35 #include "btr0pcur.h" 36 #include "que0types.h" 37 #include "pars0types.h" 38 39 /*********************************************************************//** 40 Creates an update vector object. 41 @return own: update vector object */ 42 UNIV_INLINE 43 upd_t* 44 upd_create( 45 /*=======*/ 46 ulint n, /*!< in: number of fields */ 47 mem_heap_t* heap); /*!< in: heap from which memory allocated */ 48 /*********************************************************************//** 49 Returns the number of fields in the update vector == number of columns 50 to be updated by an update vector. 51 @return number of fields */ 52 UNIV_INLINE 53 ulint 54 upd_get_n_fields( 55 /*=============*/ 56 const upd_t* update); /*!< in: update vector */ 57 #ifdef UNIV_DEBUG 58 /*********************************************************************//** 59 Returns the nth field of an update vector. 60 @return update vector field */ 61 UNIV_INLINE 62 upd_field_t* 63 upd_get_nth_field( 64 /*==============*/ 65 const upd_t* update, /*!< in: update vector */ 66 ulint n); /*!< in: field position in update vector */ 67 #else 68 # define upd_get_nth_field(update, n) ((update)->fields + (n)) 69 #endif 70 71 /*********************************************************************//** 72 Sets an index field number to be updated by an update vector field. */ 73 UNIV_INLINE 74 void 75 upd_field_set_field_no( 76 /*===================*/ 77 upd_field_t* upd_field, /*!< in: update vector field */ 78 uint16_t field_no, /*!< in: field number in a clustered 79 index */ 80 dict_index_t* index); 81 82 /** set field number to a update vector field, marks this field is updated 83 @param[in,out] upd_field update vector field 84 @param[in] field_no virtual column sequence num 85 @param[in] index index */ 86 UNIV_INLINE 87 void 88 upd_field_set_v_field_no( 89 upd_field_t* upd_field, 90 uint16_t field_no, 91 dict_index_t* index); 92 /*********************************************************************//** 93 Returns a field of an update vector by field_no. 94 @return update vector field, or NULL */ 95 UNIV_INLINE 96 const upd_field_t* 97 upd_get_field_by_field_no( 98 /*======================*/ 99 const upd_t* update, /*!< in: update vector */ 100 uint16_t no, /*!< in: field_no */ 101 bool is_virtual) /*!< in: if it is a virtual column */ 102 MY_ATTRIBUTE((warn_unused_result)); 103 /*********************************************************************//** 104 Creates an update node for a query graph. 105 @return own: update node */ 106 upd_node_t* 107 upd_node_create( 108 /*============*/ 109 mem_heap_t* heap); /*!< in: mem heap where created */ 110 /***********************************************************//** 111 Returns TRUE if row update changes size of some field in index or if some 112 field to be updated is stored externally in rec or update. 113 @return TRUE if the update changes the size of some field in index or 114 the field is external in rec or update */ 115 ibool 116 row_upd_changes_field_size_or_external( 117 /*===================================*/ 118 dict_index_t* index, /*!< in: index */ 119 const rec_offs* offsets,/*!< in: rec_get_offsets(rec, index) */ 120 const upd_t* update);/*!< in: update vector */ 121 /***********************************************************//** 122 Returns true if row update contains disowned external fields. 123 @return true if the update contains disowned external fields. */ 124 bool 125 row_upd_changes_disowned_external( 126 /*==============================*/ 127 const upd_t* update) /*!< in: update vector */ 128 MY_ATTRIBUTE((nonnull, warn_unused_result)); 129 130 /***************************************************************//** 131 Builds an update vector from those fields which in a secondary index entry 132 differ from a record that has the equal ordering fields. NOTE: we compare 133 the fields as binary strings! 134 @return own: update vector of differing fields */ 135 upd_t* 136 row_upd_build_sec_rec_difference_binary( 137 /*====================================*/ 138 const rec_t* rec, /*!< in: secondary index record */ 139 dict_index_t* index, /*!< in: index */ 140 const rec_offs* offsets,/*!< in: rec_get_offsets(rec, index) */ 141 const dtuple_t* entry, /*!< in: entry to insert */ 142 mem_heap_t* heap) /*!< in: memory heap from which allocated */ 143 MY_ATTRIBUTE((warn_unused_result, nonnull)); 144 /** Builds an update vector from those fields, excluding the roll ptr and 145 trx id fields, which in an index entry differ from a record that has 146 the equal ordering fields. NOTE: we compare the fields as binary strings! 147 @param[in] index clustered index 148 @param[in] entry clustered index entry to insert 149 @param[in] rec clustered index record 150 @param[in] offsets rec_get_offsets(rec,index), or NULL 151 @param[in] no_sys skip the system columns 152 DB_TRX_ID and DB_ROLL_PTR 153 @param[in] trx transaction (for diagnostics), 154 or NULL 155 @param[in] heap memory heap from which allocated 156 @param[in,out] mysql_table NULL, or mysql table object when 157 user thread invokes dml 158 @param[out] error error number in case of failure 159 @return own: update vector of differing fields, excluding roll ptr and 160 trx id */ 161 upd_t* 162 row_upd_build_difference_binary( 163 dict_index_t* index, 164 const dtuple_t* entry, 165 const rec_t* rec, 166 const rec_offs* offsets, 167 bool no_sys, 168 trx_t* trx, 169 mem_heap_t* heap, 170 TABLE* mysql_table, 171 dberr_t* error) 172 MY_ATTRIBUTE((nonnull(1,2,3,7,9), warn_unused_result)); 173 /** Apply an update vector to an index entry. 174 @param[in,out] entry index entry to be updated; the clustered index record 175 must be covered by a lock or a page latch to prevent 176 deletion (rollback or purge) 177 @param[in] index index of the entry 178 @param[in] update update vector built for the entry 179 @param[in,out] heap memory heap for copying off-page columns */ 180 void 181 row_upd_index_replace_new_col_vals_index_pos( 182 dtuple_t* entry, 183 const dict_index_t* index, 184 const upd_t* update, 185 mem_heap_t* heap) 186 MY_ATTRIBUTE((nonnull)); 187 /** Replace the new column values stored in the update vector, 188 during trx_undo_prev_version_build(). 189 @param entry clustered index tuple where the values are replaced 190 (the clustered index leaf page latch must be held) 191 @param index clustered index 192 @param update update vector for the clustered index 193 @param heap memory heap for allocating and copying values 194 @return whether the previous version was built successfully */ 195 bool 196 row_upd_index_replace_new_col_vals(dtuple_t *entry, const dict_index_t &index, 197 const upd_t *update, mem_heap_t *heap) 198 MY_ATTRIBUTE((nonnull, warn_unused_result)); 199 /***********************************************************//** 200 Replaces the new column values stored in the update vector. */ 201 void 202 row_upd_replace( 203 /*============*/ 204 dtuple_t* row, /*!< in/out: row where replaced, 205 indexed by col_no; 206 the clustered index record must be 207 covered by a lock or a page latch to 208 prevent deletion (rollback or purge) */ 209 row_ext_t** ext, /*!< out, own: NULL, or externally 210 stored column prefixes */ 211 const dict_index_t* index, /*!< in: clustered index */ 212 const upd_t* update, /*!< in: an update vector built for the 213 clustered index */ 214 mem_heap_t* heap); /*!< in: memory heap */ 215 /** Replaces the virtual column values stored in a dtuple with that of 216 a update vector. 217 @param[in,out] row dtuple whose column to be updated 218 @param[in] table table 219 @param[in] update an update vector built for the clustered index 220 @param[in] upd_new update to new or old value 221 @param[in,out] undo_row undo row (if needs to be updated) 222 @param[in] ptr remaining part in update undo log */ 223 void 224 row_upd_replace_vcol( 225 dtuple_t* row, 226 const dict_table_t* table, 227 const upd_t* update, 228 bool upd_new, 229 dtuple_t* undo_row, 230 const byte* ptr); 231 232 /***********************************************************//** 233 Checks if an update vector changes an ordering field of an index record. 234 235 This function is fast if the update vector is short or the number of ordering 236 fields in the index is small. Otherwise, this can be quadratic. 237 NOTE: we compare the fields as binary strings! 238 @return TRUE if update vector changes an ordering field in the index record */ 239 ibool 240 row_upd_changes_ord_field_binary_func( 241 /*==================================*/ 242 dict_index_t* index, /*!< in: index of the record */ 243 const upd_t* update, /*!< in: update vector for the row; NOTE: the 244 field numbers in this MUST be clustered index 245 positions! */ 246 #ifdef UNIV_DEBUG 247 const que_thr_t*thr, /*!< in: query thread */ 248 #endif /* UNIV_DEBUG */ 249 const dtuple_t* row, /*!< in: old value of row, or NULL if the 250 row and the data values in update are not 251 known when this function is called, e.g., at 252 compile time */ 253 const row_ext_t*ext, /*!< NULL, or prefixes of the externally 254 stored columns in the old row */ 255 ulint flag) /*!< in: ROW_BUILD_NORMAL, 256 ROW_BUILD_FOR_PURGE or ROW_BUILD_FOR_UNDO */ 257 MY_ATTRIBUTE((nonnull(1,2), warn_unused_result)); 258 #ifdef UNIV_DEBUG 259 # define row_upd_changes_ord_field_binary(index,update,thr,row,ext) \ 260 row_upd_changes_ord_field_binary_func(index,update,thr,row,ext,0) 261 #else /* UNIV_DEBUG */ 262 # define row_upd_changes_ord_field_binary(index,update,thr,row,ext) \ 263 row_upd_changes_ord_field_binary_func(index,update,row,ext,0) 264 #endif /* UNIV_DEBUG */ 265 /***********************************************************//** 266 Checks if an FTS indexed column is affected by an UPDATE. 267 @return offset within fts_t::indexes if FTS indexed column updated else 268 ULINT_UNDEFINED */ 269 ulint 270 row_upd_changes_fts_column( 271 /*=======================*/ 272 dict_table_t* table, /*!< in: table */ 273 upd_field_t* upd_field); /*!< in: field to check */ 274 /***********************************************************//** 275 Checks if an FTS Doc ID column is affected by an UPDATE. 276 @return whether Doc ID column is affected */ 277 bool 278 row_upd_changes_doc_id( 279 /*===================*/ 280 dict_table_t* table, /*!< in: table */ 281 upd_field_t* upd_field) /*!< in: field to check */ 282 MY_ATTRIBUTE((nonnull, warn_unused_result)); 283 /***********************************************************//** 284 Checks if an update vector changes an ordering field of an index record. 285 This function is fast if the update vector is short or the number of ordering 286 fields in the index is small. Otherwise, this can be quadratic. 287 NOTE: we compare the fields as binary strings! 288 @return TRUE if update vector may change an ordering field in an index 289 record */ 290 ibool 291 row_upd_changes_some_index_ord_field_binary( 292 /*========================================*/ 293 const dict_table_t* table, /*!< in: table */ 294 const upd_t* update);/*!< in: update vector for the row */ 295 /***********************************************************//** 296 Updates a row in a table. This is a high-level function used 297 in SQL execution graphs. 298 @return query thread to run next or NULL */ 299 que_thr_t* 300 row_upd_step( 301 /*=========*/ 302 que_thr_t* thr); /*!< in: query thread */ 303 304 /* Update vector field */ 305 struct upd_field_t{ 306 uint16_t field_no; /*!< field number in an index, usually 307 the clustered index, but in updating 308 a secondary index record in btr0cur.cc 309 this is the position in the secondary 310 index. If this field is a virtual 311 column, then field_no represents 312 the nth virtual column in the table */ 313 uint16_t orig_len; /*!< original length of the locally 314 stored part of an externally stored 315 column, or 0 */ 316 que_node_t* exp; /*!< expression for calculating a new 317 value: it refers to column values and 318 constants in the symbol table of the 319 query graph */ 320 dfield_t new_val; /*!< new value for the column */ 321 dfield_t* old_v_val; /*!< old value for the virtual column */ 322 }; 323 324 325 /* check whether an update field is on virtual column */ 326 #define upd_fld_is_virtual_col(upd_fld) \ 327 (((upd_fld)->new_val.type.prtype & DATA_VIRTUAL) == DATA_VIRTUAL) 328 329 /* set DATA_VIRTUAL bit on update field to show it is a virtual column */ 330 #define upd_fld_set_virtual_col(upd_fld) \ 331 ((upd_fld)->new_val.type.prtype |= DATA_VIRTUAL) 332 333 /* Update vector structure */ 334 struct upd_t{ 335 mem_heap_t* heap; /*!< heap from which memory allocated */ 336 byte info_bits; /*!< new value of info bits to record; 337 default is 0 */ 338 dtuple_t* old_vrow; /*!< pointer to old row, used for 339 virtual column update now */ 340 ulint n_fields; /*!< number of update fields */ 341 upd_field_t* fields; /*!< array of update fields */ 342 byte vers_sys_value[8]; /*!< buffer for updating system fields */ 343 344 /** Append an update field to the end of array 345 @param[in] field an update field */ appendupd_t346 void append(const upd_field_t& field) 347 { 348 fields[n_fields++] = field; 349 } 350 remove_elementupd_t351 void remove_element(ulint i) 352 { 353 ut_ad(n_fields > 0); 354 ut_ad(i < n_fields); 355 while (i < n_fields - 1) 356 { 357 fields[i]= fields[i + 1]; 358 i++; 359 } 360 n_fields--; 361 } 362 removeupd_t363 bool remove(const ulint field_no) 364 { 365 for (ulint i= 0; i < n_fields; ++i) 366 { 367 if (field_no == fields[i].field_no) 368 { 369 remove_element(i); 370 return true; 371 } 372 } 373 return false; 374 } 375 376 /** Determine if the given field_no is modified. 377 @return true if modified, false otherwise. */ is_modifiedupd_t378 bool is_modified(uint16_t field_no) const 379 { 380 for (ulint i = 0; i < n_fields; ++i) { 381 if (field_no == fields[i].field_no) { 382 return(true); 383 } 384 } 385 return(false); 386 } 387 388 /** Determine if the update affects a system versioned column or row_end. */ affects_versionedupd_t389 bool affects_versioned() const 390 { 391 for (ulint i = 0; i < n_fields; i++) { 392 dtype_t type = fields[i].new_val.type; 393 if (type.is_versioned()) { 394 return true; 395 } 396 // versioned DELETE is UPDATE SET row_end=NOW 397 if (type.vers_sys_end()) { 398 return true; 399 } 400 } 401 return false; 402 } 403 404 /** @return whether this is for a hidden metadata record 405 for instant ALTER TABLE */ is_metadataupd_t406 bool is_metadata() const { return dtuple_t::is_metadata(info_bits); } 407 /** @return whether this is for a hidden metadata record 408 for instant ALTER TABLE (not only ADD COLUMN) */ is_alter_metadataupd_t409 bool is_alter_metadata() const 410 { return dtuple_t::is_alter_metadata(info_bits); } 411 412 #ifdef UNIV_DEBUG validateupd_t413 bool validate() const 414 { 415 for (ulint i = 0; i < n_fields; ++i) { 416 dfield_t* field = &fields[i].new_val; 417 if (dfield_is_ext(field)) { 418 ut_ad(dfield_get_len(field) 419 >= BTR_EXTERN_FIELD_REF_SIZE); 420 } 421 } 422 return(true); 423 } 424 #endif // UNIV_DEBUG 425 }; 426 427 /** Kinds of update operation */ 428 enum delete_mode_t { 429 NO_DELETE = 0, /*!< this operation does not delete */ 430 PLAIN_DELETE, /*!< ordinary delete */ 431 VERSIONED_DELETE /*!< update old and insert a new row */ 432 }; 433 434 /* Update node structure which also implements the delete operation 435 of a row */ 436 437 struct upd_node_t{ 438 que_common_t common; /*!< node type: QUE_NODE_UPDATE */ 439 delete_mode_t is_delete; /*!< kind of DELETE */ 440 ibool searched_update; 441 /* TRUE if searched update, FALSE if 442 positioned */ 443 bool in_mysql_interface; 444 /* whether the update node was created 445 for the MySQL interface */ 446 dict_foreign_t* foreign;/* NULL or pointer to a foreign key 447 constraint if this update node is used in 448 doing an ON DELETE or ON UPDATE operation */ 449 upd_node_t* cascade_node;/* NULL or an update node template which 450 is used to implement ON DELETE/UPDATE CASCADE 451 or ... SET NULL for foreign keys */ 452 mem_heap_t* cascade_heap; 453 /*!< NULL or a mem heap where cascade 454 node is created.*/ 455 sel_node_t* select; /*!< query graph subtree implementing a base 456 table cursor: the rows returned will be 457 updated */ 458 btr_pcur_t* pcur; /*!< persistent cursor placed on the clustered 459 index record which should be updated or 460 deleted; the cursor is stored in the graph 461 of 'select' field above, except in the case 462 of the MySQL interface */ 463 dict_table_t* table; /*!< table where updated */ 464 upd_t* update; /*!< update vector for the row */ 465 ulint update_n_fields; 466 /* when this struct is used to implement 467 a cascade operation for foreign keys, we store 468 here the size of the buffer allocated for use 469 as the update vector */ 470 sym_node_list_t columns;/* symbol table nodes for the columns 471 to retrieve from the table */ 472 ibool has_clust_rec_x_lock; 473 /* TRUE if the select which retrieves the 474 records to update already sets an x-lock on 475 the clustered record; note that it must always 476 set at least an s-lock */ 477 ulint cmpl_info;/* information extracted during query 478 compilation; speeds up execution: 479 UPD_NODE_NO_ORD_CHANGE and 480 UPD_NODE_NO_SIZE_CHANGE, ORed */ 481 /*----------------------*/ 482 /* Local storage for this graph node */ 483 ulint state; /*!< node execution state */ 484 dict_index_t* index; /*!< NULL, or the next index whose record should 485 be updated */ 486 dtuple_t* row; /*!< NULL, or a copy (also fields copied to 487 heap) of the row to update; this must be reset 488 to NULL after a successful update */ 489 dtuple_t* historical_row; /*!< historical row used in 490 CASCADE UPDATE/SET NULL; 491 allocated from historical_heap */ 492 mem_heap_t* historical_heap; /*!< heap for historical row insertion; 493 created when row to update is located; 494 freed right before row update */ 495 row_ext_t* ext; /*!< NULL, or prefixes of the externally 496 stored columns in the old row */ 497 dtuple_t* upd_row;/* NULL, or a copy of the updated row */ 498 row_ext_t* upd_ext;/* NULL, or prefixes of the externally 499 stored columns in upd_row */ 500 mem_heap_t* heap; /*!< memory heap used as auxiliary storage; 501 this must be emptied after a successful 502 update */ 503 /*----------------------*/ 504 sym_node_t* table_sym;/* table node in symbol table */ 505 que_node_t* col_assign_list; 506 /* column assignment list */ 507 ulint magic_n; 508 509 private: 510 /** Appends row_start or row_end field to update vector and sets a 511 CURRENT_TIMESTAMP/trx->id value to it. 512 Supposed to be called only by make_versioned_update() and 513 make_versioned_delete(). 514 @param[in] trx transaction 515 @param[in] vers_sys_idx table->row_start or table->row_end */ 516 void vers_update_fields(const trx_t *trx, ulint idx); 517 518 public: 519 /** Also set row_start = CURRENT_TIMESTAMP/trx->id 520 @param[in] trx transaction */ vers_make_updateupd_node_t521 void vers_make_update(const trx_t *trx) 522 { 523 vers_update_fields(trx, table->vers_start); 524 } 525 526 /** Only set row_end = CURRENT_TIMESTAMP/trx->id. 527 Do not touch other fields at all. 528 @param[in] trx transaction */ vers_make_deleteupd_node_t529 void vers_make_delete(const trx_t *trx) 530 { 531 update->n_fields = 0; 532 is_delete = VERSIONED_DELETE; 533 vers_update_fields(trx, table->vers_end); 534 } 535 }; 536 537 #define UPD_NODE_MAGIC_N 1579975 538 539 /* Node execution states */ 540 #define UPD_NODE_SET_IX_LOCK 1 /* execution came to the node from 541 a node above and if the field 542 has_clust_rec_x_lock is FALSE, we 543 should set an intention x-lock on 544 the table */ 545 #define UPD_NODE_UPDATE_CLUSTERED 2 /* clustered index record should be 546 updated */ 547 #define UPD_NODE_INSERT_CLUSTERED 3 /* clustered index record should be 548 inserted, old record is already delete 549 marked */ 550 #define UPD_NODE_UPDATE_ALL_SEC 5 /* an ordering field of the clustered 551 index record was changed, or this is 552 a delete operation: should update 553 all the secondary index records */ 554 #define UPD_NODE_UPDATE_SOME_SEC 6 /* secondary index entries should be 555 looked at and updated if an ordering 556 field changed */ 557 558 /* Compilation info flags: these must fit within 3 bits; see trx0rec.h */ 559 #define UPD_NODE_NO_ORD_CHANGE 1 /* no secondary index record will be 560 changed in the update and no ordering 561 field of the clustered index */ 562 #define UPD_NODE_NO_SIZE_CHANGE 2 /* no record field size will be 563 changed in the update */ 564 565 566 #include "row0upd.inl" 567 568 #endif 569