| 1 | /***************************************************************************** |
| 2 | |
| 3 | Copyright (c) 1996, 2015, 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 include/row0upd.ic |
| 22 | Update of a row |
| 23 | |
| 24 | Created 12/27/1996 Heikki Tuuri |
| 25 | *******************************************************/ |
| 26 | |
| 27 | #include "mtr0log.h" |
| 28 | #include "trx0trx.h" |
| 29 | #include "trx0undo.h" |
| 30 | #include "row0row.h" |
| 31 | #include "lock0lock.h" |
| 32 | #include "page0zip.h" |
| 33 | |
| 34 | /*********************************************************************//** |
| 35 | Creates an update vector object. |
| 36 | @return own: update vector object */ |
| 37 | UNIV_INLINE |
| 38 | upd_t* |
| 39 | upd_create( |
| 40 | /*=======*/ |
| 41 | ulint n, /*!< in: number of fields */ |
| 42 | mem_heap_t* heap) /*!< in: heap from which memory allocated */ |
| 43 | { |
| 44 | upd_t* update; |
| 45 | |
| 46 | update = static_cast<upd_t*>(mem_heap_zalloc( |
| 47 | heap, sizeof(upd_t) + sizeof(upd_field_t) * n)); |
| 48 | |
| 49 | update->n_fields = n; |
| 50 | update->fields = reinterpret_cast<upd_field_t*>(&update[1]); |
| 51 | update->heap = heap; |
| 52 | |
| 53 | return(update); |
| 54 | } |
| 55 | |
| 56 | /*********************************************************************//** |
| 57 | Returns the number of fields in the update vector == number of columns |
| 58 | to be updated by an update vector. |
| 59 | @return number of fields */ |
| 60 | UNIV_INLINE |
| 61 | ulint |
| 62 | upd_get_n_fields( |
| 63 | /*=============*/ |
| 64 | const upd_t* update) /*!< in: update vector */ |
| 65 | { |
| 66 | ut_ad(update); |
| 67 | |
| 68 | return(update->n_fields); |
| 69 | } |
| 70 | |
| 71 | #ifdef UNIV_DEBUG |
| 72 | /*********************************************************************//** |
| 73 | Returns the nth field of an update vector. |
| 74 | @return update vector field */ |
| 75 | UNIV_INLINE |
| 76 | upd_field_t* |
| 77 | upd_get_nth_field( |
| 78 | /*==============*/ |
| 79 | const upd_t* update, /*!< in: update vector */ |
| 80 | ulint n) /*!< in: field position in update vector */ |
| 81 | { |
| 82 | ut_ad(update); |
| 83 | ut_ad(n < update->n_fields); |
| 84 | |
| 85 | return((upd_field_t*) update->fields + n); |
| 86 | } |
| 87 | #endif /* UNIV_DEBUG */ |
| 88 | |
| 89 | /*********************************************************************//** |
| 90 | Sets an index field number to be updated by an update vector field. */ |
| 91 | UNIV_INLINE |
| 92 | void |
| 93 | upd_field_set_field_no( |
| 94 | /*===================*/ |
| 95 | upd_field_t* upd_field, /*!< in: update vector field */ |
| 96 | ulint field_no, /*!< in: field number in a clustered |
| 97 | index */ |
| 98 | dict_index_t* index) /*!< in: index */ |
| 99 | { |
| 100 | upd_field->field_no = unsigned(field_no); |
| 101 | upd_field->orig_len = 0; |
| 102 | dict_col_copy_type(dict_index_get_nth_col(index, field_no), |
| 103 | dfield_get_type(&upd_field->new_val)); |
| 104 | } |
| 105 | |
| 106 | /** set field number to a update vector field, marks this field is updated. |
| 107 | @param[in,out] upd_field update vector field |
| 108 | @param[in] field_no virtual column sequence num |
| 109 | @param[in] index index */ |
| 110 | UNIV_INLINE |
| 111 | void |
| 112 | upd_field_set_v_field_no( |
| 113 | upd_field_t* upd_field, |
| 114 | ulint field_no, |
| 115 | dict_index_t* index) |
| 116 | { |
| 117 | ut_a(field_no < dict_table_get_n_v_cols(index->table)); |
| 118 | upd_field->field_no = unsigned(field_no); |
| 119 | upd_field->orig_len = 0; |
| 120 | |
| 121 | dict_col_copy_type(&dict_table_get_nth_v_col( |
| 122 | index->table, field_no)->m_col, |
| 123 | dfield_get_type(&upd_field->new_val)); |
| 124 | } |
| 125 | |
| 126 | /*********************************************************************//** |
| 127 | Returns a field of an update vector by field_no. |
| 128 | @return update vector field, or NULL */ |
| 129 | UNIV_INLINE |
| 130 | const upd_field_t* |
| 131 | upd_get_field_by_field_no( |
| 132 | /*======================*/ |
| 133 | const upd_t* update, /*!< in: update vector */ |
| 134 | ulint no, /*!< in: field_no */ |
| 135 | bool is_virtual) /*!< in: if it is virtual column */ |
| 136 | { |
| 137 | ulint i; |
| 138 | for (i = 0; i < upd_get_n_fields(update); i++) { |
| 139 | const upd_field_t* uf = upd_get_nth_field(update, i); |
| 140 | |
| 141 | /* matches only if the field matches that of is_virtual */ |
| 142 | if ((!is_virtual) != (!upd_fld_is_virtual_col(uf))) { |
| 143 | continue; |
| 144 | } |
| 145 | |
| 146 | if (uf->field_no == no) { |
| 147 | |
| 148 | return(uf); |
| 149 | } |
| 150 | } |
| 151 | |
| 152 | return(NULL); |
| 153 | } |
| 154 | |
| 155 | /*********************************************************************//** |
| 156 | Updates the trx id and roll ptr field in a clustered index record when |
| 157 | a row is updated or marked deleted. */ |
| 158 | UNIV_INLINE |
| 159 | void |
| 160 | row_upd_rec_sys_fields( |
| 161 | /*===================*/ |
| 162 | rec_t* rec, /*!< in/out: record */ |
| 163 | page_zip_des_t* page_zip,/*!< in/out: compressed page whose |
| 164 | uncompressed part will be updated, or NULL */ |
| 165 | dict_index_t* index, /*!< in: clustered index */ |
| 166 | const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ |
| 167 | const trx_t* trx, /*!< in: transaction */ |
| 168 | roll_ptr_t roll_ptr)/*!< in: DB_ROLL_PTR to the undo log */ |
| 169 | { |
| 170 | ut_ad(dict_index_is_clust(index)); |
| 171 | ut_ad(rec_offs_validate(rec, index, offsets)); |
| 172 | |
| 173 | if (page_zip) { |
| 174 | ulint pos = dict_index_get_sys_col_pos(index, DATA_TRX_ID); |
| 175 | page_zip_write_trx_id_and_roll_ptr(page_zip, rec, offsets, |
| 176 | pos, trx->id, roll_ptr); |
| 177 | } else { |
| 178 | ulint offset = index->trx_id_offset; |
| 179 | |
| 180 | if (!offset) { |
| 181 | offset = row_get_trx_id_offset(index, offsets); |
| 182 | } |
| 183 | |
| 184 | compile_time_assert(DATA_TRX_ID + 1 == DATA_ROLL_PTR); |
| 185 | |
| 186 | /* During IMPORT the trx id in the record can be in the |
| 187 | future, if the .ibd file is being imported from another |
| 188 | instance. During IMPORT roll_ptr will be 0. */ |
| 189 | ut_ad(roll_ptr == 0 |
| 190 | || lock_check_trx_id_sanity( |
| 191 | trx_read_trx_id(rec + offset), |
| 192 | rec, index, offsets)); |
| 193 | |
| 194 | trx_write_trx_id(rec + offset, trx->id); |
| 195 | trx_write_roll_ptr(rec + offset + DATA_TRX_ID_LEN, roll_ptr); |
| 196 | } |
| 197 | } |
| 198 | |