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