1/***************************************************************************** 2 3Copyright (c) 1996, 2019, Oracle and/or its affiliates. All Rights Reserved. 4 5This program is free software; you can redistribute it and/or modify it under 6the terms of the GNU General Public License, version 2.0, as published by the 7Free Software Foundation. 8 9This program is also distributed with certain software (including but not 10limited to OpenSSL) that is licensed under separate terms, as designated in a 11particular file or component or in included license documentation. The authors 12of MySQL hereby grant you an additional permission to link the program and 13your derivative works with the separately licensed software that they have 14included with MySQL. 15 16This program is distributed in the hope that it will be useful, but WITHOUT 17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0, 19for 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 St, Fifth Floor, Boston, MA 02110-1301 USA 24 25*****************************************************************************/ 26 27/** @file include/row0row.ic 28 General row routines 29 30 Created 4/20/1996 Heikki Tuuri 31 *******************************************************/ 32 33#include <cmath> 34#include <cstdint> 35 36#include "dict0dict.h" 37#include "rem0rec.h" 38#include "trx0undo.h" 39 40/** Gets the offset of the DB_TRX_ID field, in bytes relative to the origin of 41 a clustered index record. 42 @return offset of DATA_TRX_ID */ 43UNIV_INLINE 44ulint row_get_trx_id_offset( 45 const dict_index_t *index, /*!< in: clustered index */ 46 const ulint *offsets) /*!< in: record offsets */ 47{ 48 ulint pos; 49 ulint offset; 50 ulint len; 51 52 ut_ad(index->is_clustered()); 53 ut_ad(rec_offs_validate(nullptr, index, offsets)); 54 55 pos = index->get_sys_col_pos(DATA_TRX_ID); 56 57 offset = rec_get_nth_field_offs(offsets, pos, &len); 58 59 ut_ad(len == DATA_TRX_ID_LEN); 60 61 return (offset); 62} 63 64/** Reads the trx id field from a clustered index record. 65 @return value of the field */ 66UNIV_INLINE 67trx_id_t row_get_rec_trx_id( 68 const rec_t *rec, /*!< in: record */ 69 const dict_index_t *index, /*!< in: clustered index */ 70 const ulint *offsets) /*!< in: rec_get_offsets(rec, index) */ 71{ 72 ulint offset; 73 74 ut_ad(index->is_clustered()); 75 ut_ad(rec_offs_validate(rec, index, offsets)); 76 77 offset = index->trx_id_offset; 78 79 if (!offset) { 80 offset = row_get_trx_id_offset(index, offsets); 81 } 82 83 return (trx_read_trx_id(rec + offset)); 84} 85 86/** Reads the roll pointer field from a clustered index record. 87 @return value of the field */ 88UNIV_INLINE 89roll_ptr_t row_get_rec_roll_ptr( 90 const rec_t *rec, /*!< in: record */ 91 const dict_index_t *index, /*!< in: clustered index */ 92 const ulint *offsets) /*!< in: rec_get_offsets(rec, index) */ 93{ 94 ulint offset; 95 96 ut_ad(index->is_clustered()); 97 ut_ad(rec_offs_validate(rec, index, offsets)); 98 99 offset = index->trx_id_offset; 100 101 if (!offset) { 102 offset = row_get_trx_id_offset(index, offsets); 103 } 104 105 return (trx_read_roll_ptr(rec + offset + DATA_TRX_ID_LEN)); 106} 107 108/** When an insert or purge to a table is performed, this function builds 109 the entry to be inserted into or purged from an index on the table. 110 @return index entry which should be inserted or purged, or NULL if the 111 externally stored columns in the clustered index record are 112 unavailable and ext != NULL */ 113UNIV_INLINE 114dtuple_t *row_build_index_entry( 115 const dtuple_t *row, /*!< in: row which should be 116 inserted or purged */ 117 const row_ext_t *ext, /*!< in: externally stored column 118 prefixes, or NULL */ 119 const dict_index_t *index, /*!< in: index on the table */ 120 mem_heap_t *heap) /*!< in: memory heap from which 121 the memory for the index entry 122 is allocated */ 123{ 124 dtuple_t *entry; 125 126 ut_ad(dtuple_check_typed(row)); 127 entry = row_build_index_entry_low(row, ext, index, heap, ROW_BUILD_NORMAL); 128 ut_ad(!entry || dtuple_check_typed(entry)); 129 return (entry); 130} 131 132/** Builds from a secondary index record a row reference with which we can 133 search the clustered index record. */ 134UNIV_INLINE 135void row_build_row_ref_fast( 136 dtuple_t *ref, /*!< in/out: typed data tuple where the 137 reference is built */ 138 const ulint *map, /*!< in: array of field numbers in rec 139 telling how ref should be built from 140 the fields of rec */ 141 const rec_t *rec, /*!< in: record in the index; must be 142 preserved while ref is used, as we do 143 not copy field values to heap */ 144 const ulint *offsets) /*!< in: array returned by rec_get_offsets() */ 145{ 146 dfield_t *dfield; 147 const byte *field; 148 ulint len; 149 ulint ref_len; 150 ulint field_no; 151 ulint i; 152 153 ut_ad(rec_offs_validate(rec, nullptr, offsets)); 154 ut_ad(!rec_offs_any_extern(offsets)); 155 ref_len = dtuple_get_n_fields(ref); 156 157 for (i = 0; i < ref_len; i++) { 158 dfield = dtuple_get_nth_field(ref, i); 159 160 field_no = *(map + i); 161 162 if (field_no != ULINT_UNDEFINED) { 163 field = rec_get_nth_field(rec, offsets, field_no, &len); 164 dfield_set_data(dfield, field, len); 165 } 166 } 167} 168 169/** Parse the integer data from specified data, which could be 170DATA_INT, DATA_FLOAT or DATA_DOUBLE. If the value is less than 0 171and the type is not unsigned then we reset the value to 0 172@param[in] data data to read 173@param[in] len length of data 174@param[in] mtype mtype of data 175@param[in] unsigned_type if the data is unsigned 176@return the integer value from the data */ 177ib_uint64_t row_parse_int(const byte *data, ulint len, ulint mtype, 178 bool unsigned_type) { 179 ib_uint64_t value = 0; 180 181 switch (mtype) { 182 case DATA_INT: 183 184 ut_a(len <= sizeof value); 185 value = mach_read_int_type(data, len, unsigned_type); 186 break; 187 188 case DATA_FLOAT: 189 190 ut_a(len == sizeof(float)); 191 /* Cast float value to int64_t first, before casting to unsigned, 192 to avoid UBSAN warnings. */ 193 value = 194 static_cast<ib_uint64_t>(static_cast<int64_t>(mach_float_read(data))); 195 break; 196 197 case DATA_DOUBLE: { 198 ut_a(len == sizeof(double)); 199 double dblval = mach_double_read(data); 200 value = std::signbit(dblval) ? static_cast<int64_t>(dblval) 201 : static_cast<ib_uint64_t>(dblval); 202 break; 203 } 204 default: 205 ut_error; 206 } 207 208 if (!unsigned_type && static_cast<int64_t>(value) < 0) { 209 value = 0; 210 } 211 212 return (value); 213} 214