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