1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | Copyright (c) 2016, 2017, 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/row0row.h |
22 | General row routines |
23 | |
24 | Created 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 | /*********************************************************************//** |
42 | Gets the offset of the DB_TRX_ID field, in bytes relative to the origin of |
43 | a clustered index record. |
44 | @return offset of DATA_TRX_ID */ |
45 | UNIV_INLINE |
46 | ulint |
47 | row_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 | /*********************************************************************//** |
53 | Reads the trx id field from a clustered index record. |
54 | @return value of the field */ |
55 | UNIV_INLINE |
56 | trx_id_t |
57 | row_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 | /*********************************************************************//** |
64 | Reads the roll pointer field from a clustered index record. |
65 | @return value of the field */ |
66 | UNIV_INLINE |
67 | roll_ptr_t |
68 | row_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 | /*****************************************************************//** |
81 | When an insert or purge to a table is performed, this function builds |
82 | the 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 |
85 | are unavailable and ext != NULL, or row is missing some needed columns. */ |
86 | dtuple_t* |
87 | row_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 | /*****************************************************************//** |
102 | When an insert or purge to a table is performed, this function builds |
103 | the 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 |
105 | externally stored columns in the clustered index record are |
106 | unavailable and ext != NULL */ |
107 | UNIV_INLINE |
108 | dtuple_t* |
109 | row_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 | /*******************************************************************//** |
121 | An inverse function to row_build_index_entry. Builds a row from a |
122 | record in a clustered index. |
123 | @return own: row built; see the NOTE below! */ |
124 | dtuple_t* |
125 | row_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 |
168 | record in a clustered index, with possible indexing on ongoing |
169 | addition 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 */ |
190 | dtuple_t* |
191 | row_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 | /*******************************************************************//** |
204 | Converts an index record to a typed data tuple. |
205 | @return index entry built; does not set info_bits, and the data fields |
206 | in the entry will point directly to rec */ |
207 | dtuple_t* |
208 | row_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 | /*******************************************************************//** |
219 | Converts an index record to a typed data tuple. NOTE that externally |
220 | stored (often big) fields are NOT copied to heap. |
221 | @return own: index entry built */ |
222 | dtuple_t* |
223 | row_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 | /*******************************************************************//** |
234 | Builds from a secondary index record a row reference with which we can |
235 | search the clustered index record. |
236 | @return own: row reference built; see the NOTE below! */ |
237 | dtuple_t* |
238 | row_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 | /*******************************************************************//** |
256 | Builds from a secondary index record a row reference with which we can |
257 | search the clustered index record. */ |
258 | void |
259 | row_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 | /*******************************************************************//** |
276 | Builds from a secondary index record a row reference with which we can |
277 | search the clustered index record. */ |
278 | UNIV_INLINE |
279 | void |
280 | row_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 | /***************************************************************//** |
292 | Searches the clustered index record for a row, if we have the row |
293 | reference. |
294 | @return TRUE if found */ |
295 | ibool |
296 | row_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 | /*********************************************************************//** |
306 | Fetches the clustered index record for a secondary index record. The latches |
307 | on the secondary index record are preserved. |
308 | @return record or NULL, if no record found */ |
309 | rec_t* |
310 | row_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 |
320 | DATA_INT, DATA_FLOAT or DATA_DOUBLE. If the value is less than 0 |
321 | and 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 */ |
327 | inline |
328 | ib_uint64_t |
329 | row_parse_int( |
330 | const byte* data, |
331 | ulint len, |
332 | ulint mtype, |
333 | bool unsigned_type); |
334 | |
335 | /** Result of row_search_index_entry */ |
336 | enum 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 | /***************************************************************//** |
349 | Searches an index record. |
350 | @return whether the record was found or buffered */ |
351 | enum row_search_result |
352 | row_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 | /*******************************************************************//** |
371 | Formats the raw data in "data" (in InnoDB on-disk format) using |
372 | "dict_field" and writes the result to "buf". |
373 | Not more than "buf_size" bytes are written to "buf". |
374 | The result is always NUL-terminated (provided buf_size is positive) and the |
375 | number of bytes that were written to "buf" is returned (including the |
376 | terminating NUL). |
377 | @return number of bytes that were written */ |
378 | ulint |
379 | row_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 */ |
394 | inline |
395 | void |
396 | row_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 | |