1/*****************************************************************************
2
3Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2016, 2017, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/**************************************************//**
21@file include/row0row.h
22General row routines
23
24Created 4/20/1996 Heikki Tuuri
25*******************************************************/
26
27#ifndef row0row_h
28#define row0row_h
29
30#include "univ.i"
31#include "data0data.h"
32#include "dict0types.h"
33#include "ibuf0ibuf.h"
34#include "trx0types.h"
35#include "que0types.h"
36#include "mtr0mtr.h"
37#include "rem0types.h"
38#include "row0types.h"
39#include "btr0types.h"
40
41/*********************************************************************//**
42Gets the offset of the DB_TRX_ID field, in bytes relative to the origin of
43a clustered index record.
44@return offset of DATA_TRX_ID */
45UNIV_INLINE
46ulint
47row_get_trx_id_offset(
48/*==================*/
49 const dict_index_t* index, /*!< in: clustered index */
50 const ulint* offsets)/*!< in: record offsets */
51 MY_ATTRIBUTE((nonnull, warn_unused_result));
52/*********************************************************************//**
53Reads the trx id field from a clustered index record.
54@return value of the field */
55UNIV_INLINE
56trx_id_t
57row_get_rec_trx_id(
58/*===============*/
59 const rec_t* rec, /*!< in: record */
60 const dict_index_t* index, /*!< in: clustered index */
61 const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
62 MY_ATTRIBUTE((nonnull, warn_unused_result));
63/*********************************************************************//**
64Reads the roll pointer field from a clustered index record.
65@return value of the field */
66UNIV_INLINE
67roll_ptr_t
68row_get_rec_roll_ptr(
69/*=================*/
70 const rec_t* rec, /*!< in: record */
71 const dict_index_t* index, /*!< in: clustered index */
72 const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
73 MY_ATTRIBUTE((nonnull, warn_unused_result));
74
75/* Flags for row build type. */
76#define ROW_BUILD_NORMAL 0 /*!< build index row */
77#define ROW_BUILD_FOR_PURGE 1 /*!< build row for purge. */
78#define ROW_BUILD_FOR_UNDO 2 /*!< build row for undo. */
79#define ROW_BUILD_FOR_INSERT 3 /*!< build row for insert. */
80/*****************************************************************//**
81When an insert or purge to a table is performed, this function builds
82the entry to be inserted into or purged from an index on the table.
83@return index entry which should be inserted or purged
84@retval NULL if the externally stored columns in the clustered index record
85are unavailable and ext != NULL, or row is missing some needed columns. */
86dtuple_t*
87row_build_index_entry_low(
88/*======================*/
89 const dtuple_t* row, /*!< in: row which should be
90 inserted or purged */
91 const row_ext_t* ext, /*!< in: externally stored column
92 prefixes, or NULL */
93 dict_index_t* index, /*!< in: index on the table */
94 mem_heap_t* heap, /*!< in: memory heap from which
95 the memory for the index entry
96 is allocated */
97 ulint flag) /*!< in: ROW_BUILD_NORMAL,
98 ROW_BUILD_FOR_PURGE
99 or ROW_BUILD_FOR_UNDO */
100 MY_ATTRIBUTE((warn_unused_result, nonnull(1,3,4)));
101/*****************************************************************//**
102When an insert or purge to a table is performed, this function builds
103the entry to be inserted into or purged from an index on the table.
104@return index entry which should be inserted or purged, or NULL if the
105externally stored columns in the clustered index record are
106unavailable and ext != NULL */
107UNIV_INLINE
108dtuple_t*
109row_build_index_entry(
110/*==================*/
111 const dtuple_t* row, /*!< in: row which should be
112 inserted or purged */
113 const row_ext_t* ext, /*!< in: externally stored column
114 prefixes, or NULL */
115 dict_index_t* index, /*!< in: index on the table */
116 mem_heap_t* heap) /*!< in: memory heap from which
117 the memory for the index entry
118 is allocated */
119 MY_ATTRIBUTE((warn_unused_result, nonnull(1,3,4)));
120/*******************************************************************//**
121An inverse function to row_build_index_entry. Builds a row from a
122record in a clustered index.
123@return own: row built; see the NOTE below! */
124dtuple_t*
125row_build(
126/*======*/
127 ulint type, /*!< in: ROW_COPY_POINTERS or
128 ROW_COPY_DATA; the latter
129 copies also the data fields to
130 heap while the first only
131 places pointers to data fields
132 on the index page, and thus is
133 more efficient */
134 const dict_index_t* index, /*!< in: clustered index */
135 const rec_t* rec, /*!< in: record in the clustered
136 index; NOTE: in the case
137 ROW_COPY_POINTERS the data
138 fields in the row will point
139 directly into this record,
140 therefore, the buffer page of
141 this record must be at least
142 s-latched and the latch held
143 as long as the row dtuple is used! */
144 const ulint* offsets,/*!< in: rec_get_offsets(rec,index)
145 or NULL, in which case this function
146 will invoke rec_get_offsets() */
147 const dict_table_t* col_table,
148 /*!< in: table, to check which
149 externally stored columns
150 occur in the ordering columns
151 of an index, or NULL if
152 index->table should be
153 consulted instead; the user
154 columns in this table should be
155 the same columns as in index->table */
156 const dtuple_t* defaults,
157 /*!< in: default values of
158 added, changed columns, or NULL */
159 const ulint* col_map,/*!< in: mapping of old column
160 numbers to new ones, or NULL */
161 row_ext_t** ext, /*!< out, own: cache of
162 externally stored column
163 prefixes, or NULL */
164 mem_heap_t* heap); /*!< in: memory heap from which
165 the memory needed is allocated */
166
167/** An inverse function to row_build_index_entry. Builds a row from a
168record in a clustered index, with possible indexing on ongoing
169addition of new virtual columns.
170@param[in] type ROW_COPY_POINTERS or ROW_COPY_DATA;
171@param[in] index clustered index
172@param[in] rec record in the clustered index
173@param[in] offsets rec_get_offsets(rec,index) or NULL
174@param[in] col_table table, to check which
175 externally stored columns
176 occur in the ordering columns
177 of an index, or NULL if
178 index->table should be
179 consulted instead
180@param[in] defaults default values of added, changed columns, or NULL
181@param[in] add_v new virtual columns added
182 along with new indexes
183@param[in] col_map mapping of old column
184 numbers to new ones, or NULL
185@param[in] ext cache of externally stored column
186 prefixes, or NULL
187@param[in] heap memory heap from which
188 the memory needed is allocated
189@return own: row built */
190dtuple_t*
191row_build_w_add_vcol(
192 ulint type,
193 const dict_index_t* index,
194 const rec_t* rec,
195 const ulint* offsets,
196 const dict_table_t* col_table,
197 const dtuple_t* defaults,
198 const dict_add_v_col_t* add_v,
199 const ulint* col_map,
200 row_ext_t** ext,
201 mem_heap_t* heap);
202
203/*******************************************************************//**
204Converts an index record to a typed data tuple.
205@return index entry built; does not set info_bits, and the data fields
206in the entry will point directly to rec */
207dtuple_t*
208row_rec_to_index_entry_low(
209/*=======================*/
210 const rec_t* rec, /*!< in: record in the index */
211 const dict_index_t* index, /*!< in: index */
212 const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
213 ulint* n_ext, /*!< out: number of externally
214 stored columns */
215 mem_heap_t* heap) /*!< in: memory heap from which
216 the memory needed is allocated */
217 MY_ATTRIBUTE((warn_unused_result));
218/*******************************************************************//**
219Converts an index record to a typed data tuple. NOTE that externally
220stored (often big) fields are NOT copied to heap.
221@return own: index entry built */
222dtuple_t*
223row_rec_to_index_entry(
224/*===================*/
225 const rec_t* rec, /*!< in: record in the index */
226 const dict_index_t* index, /*!< in: index */
227 const ulint* offsets,/*!< in/out: rec_get_offsets(rec) */
228 ulint* n_ext, /*!< out: number of externally
229 stored columns */
230 mem_heap_t* heap) /*!< in: memory heap from which
231 the memory needed is allocated */
232 MY_ATTRIBUTE((warn_unused_result));
233/*******************************************************************//**
234Builds from a secondary index record a row reference with which we can
235search the clustered index record.
236@return own: row reference built; see the NOTE below! */
237dtuple_t*
238row_build_row_ref(
239/*==============*/
240 ulint type, /*!< in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
241 the former copies also the data fields to
242 heap, whereas the latter only places pointers
243 to data fields on the index page */
244 dict_index_t* index, /*!< in: secondary index */
245 const rec_t* rec, /*!< in: record in the index;
246 NOTE: in the case ROW_COPY_POINTERS
247 the data fields in the row will point
248 directly into this record, therefore,
249 the buffer page of this record must be
250 at least s-latched and the latch held
251 as long as the row reference is used! */
252 mem_heap_t* heap) /*!< in: memory heap from which the memory
253 needed is allocated */
254 MY_ATTRIBUTE((warn_unused_result));
255/*******************************************************************//**
256Builds from a secondary index record a row reference with which we can
257search the clustered index record. */
258void
259row_build_row_ref_in_tuple(
260/*=======================*/
261 dtuple_t* ref, /*!< in/out: row reference built;
262 see the NOTE below! */
263 const rec_t* rec, /*!< in: record in the index;
264 NOTE: the data fields in ref
265 will point directly into this
266 record, therefore, the buffer
267 page of this record must be at
268 least s-latched and the latch
269 held as long as the row
270 reference is used! */
271 const dict_index_t* index, /*!< in: secondary index */
272 ulint* offsets)/*!< in: rec_get_offsets(rec, index)
273 or NULL */
274 MY_ATTRIBUTE((nonnull(1,2,3)));
275/*******************************************************************//**
276Builds from a secondary index record a row reference with which we can
277search the clustered index record. */
278UNIV_INLINE
279void
280row_build_row_ref_fast(
281/*===================*/
282 dtuple_t* ref, /*!< in/out: typed data tuple where the
283 reference is built */
284 const ulint* map, /*!< in: array of field numbers in rec
285 telling how ref should be built from
286 the fields of rec */
287 const rec_t* rec, /*!< in: secondary index record;
288 must be preserved while ref is used, as we do
289 not copy field values to heap */
290 const ulint* offsets);/*!< in: array returned by rec_get_offsets() */
291/***************************************************************//**
292Searches the clustered index record for a row, if we have the row
293reference.
294@return TRUE if found */
295ibool
296row_search_on_row_ref(
297/*==================*/
298 btr_pcur_t* pcur, /*!< out: persistent cursor, which must
299 be closed by the caller */
300 ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
301 const dict_table_t* table, /*!< in: table */
302 const dtuple_t* ref, /*!< in: row reference */
303 mtr_t* mtr) /*!< in/out: mtr */
304 MY_ATTRIBUTE((nonnull, warn_unused_result));
305/*********************************************************************//**
306Fetches the clustered index record for a secondary index record. The latches
307on the secondary index record are preserved.
308@return record or NULL, if no record found */
309rec_t*
310row_get_clust_rec(
311/*==============*/
312 ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
313 const rec_t* rec, /*!< in: record in a secondary index */
314 dict_index_t* index, /*!< in: secondary index */
315 dict_index_t** clust_index,/*!< out: clustered index */
316 mtr_t* mtr) /*!< in: mtr */
317 MY_ATTRIBUTE((nonnull, warn_unused_result));
318
319/** Parse the integer data from specified data, which could be
320DATA_INT, DATA_FLOAT or DATA_DOUBLE. If the value is less than 0
321and the type is not unsigned then we reset the value to 0
322@param[in] data data to read
323@param[in] len length of data
324@param[in] mtype mtype of data
325@param[in] unsigned_type if the data is unsigned
326@return the integer value from the data */
327inline
328ib_uint64_t
329row_parse_int(
330 const byte* data,
331 ulint len,
332 ulint mtype,
333 bool unsigned_type);
334
335/** Result of row_search_index_entry */
336enum row_search_result {
337 ROW_FOUND = 0, /*!< the record was found */
338 ROW_NOT_FOUND, /*!< record not found */
339 ROW_BUFFERED, /*!< one of BTR_INSERT, BTR_DELETE, or
340 BTR_DELETE_MARK was specified, the
341 secondary index leaf page was not in
342 the buffer pool, and the operation was
343 enqueued in the insert/delete buffer */
344 ROW_NOT_DELETED_REF /*!< BTR_DELETE was specified, and
345 row_purge_poss_sec() failed */
346};
347
348/***************************************************************//**
349Searches an index record.
350@return whether the record was found or buffered */
351enum row_search_result
352row_search_index_entry(
353/*===================*/
354 dict_index_t* index, /*!< in: index */
355 const dtuple_t* entry, /*!< in: index entry */
356 ulint mode, /*!< in: BTR_MODIFY_LEAF, ... */
357 btr_pcur_t* pcur, /*!< in/out: persistent cursor, which must
358 be closed by the caller */
359 mtr_t* mtr) /*!< in: mtr */
360 MY_ATTRIBUTE((nonnull, warn_unused_result));
361
362#define ROW_COPY_DATA 1
363#define ROW_COPY_POINTERS 2
364
365/* The allowed latching order of index records is the following:
366(1) a secondary index record ->
367(2) the clustered index record ->
368(3) rollback segment data for the clustered index record. */
369
370/*******************************************************************//**
371Formats the raw data in "data" (in InnoDB on-disk format) using
372"dict_field" and writes the result to "buf".
373Not more than "buf_size" bytes are written to "buf".
374The result is always NUL-terminated (provided buf_size is positive) and the
375number of bytes that were written to "buf" is returned (including the
376terminating NUL).
377@return number of bytes that were written */
378ulint
379row_raw_format(
380/*===========*/
381 const char* data, /*!< in: raw data */
382 ulint data_len, /*!< in: raw data length
383 in bytes */
384 const dict_field_t* dict_field, /*!< in: index field */
385 char* buf, /*!< out: output buffer */
386 ulint buf_size) /*!< in: output buffer size
387 in bytes */
388 MY_ATTRIBUTE((nonnull, warn_unused_result));
389
390/** Prepare to start a mini-transaction to modify an index.
391@param[in,out] mtr mini-transaction
392@param[in,out] index possibly secondary index
393@param[in] pessimistic whether this is a pessimistic operation */
394inline
395void
396row_mtr_start(mtr_t* mtr, dict_index_t* index, bool pessimistic)
397{
398 mtr->start();
399
400 switch (index->table->space->id) {
401 case IBUF_SPACE_ID:
402 if (pessimistic
403 && !(index->type & (DICT_UNIQUE | DICT_SPATIAL))) {
404 ibuf_free_excess_pages();
405 }
406 break;
407 case SRV_TMP_SPACE_ID:
408 mtr->set_log_mode(MTR_LOG_NO_REDO);
409 break;
410 default:
411 index->set_modified(*mtr);
412 break;
413 }
414
415 log_free_check();
416}
417
418#include "row0row.ic"
419
420#endif
421