1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
4 Copyright (c) 2018, 2021, 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, Fifth Floor, Boston, MA 02110-1335 USA
17 
18 *****************************************************************************/
19 
20 /**************************************************//**
21 @file row/row0row.cc
22 General row routines
23 
24 Created 4/20/1996 Heikki Tuuri
25 *******************************************************/
26 
27 #include "row0row.h"
28 #include "data0type.h"
29 #include "dict0dict.h"
30 #include "dict0boot.h"
31 #include "btr0btr.h"
32 #include "mach0data.h"
33 #include "trx0rseg.h"
34 #include "trx0trx.h"
35 #include "trx0roll.h"
36 #include "trx0undo.h"
37 #include "trx0purge.h"
38 #include "trx0rec.h"
39 #include "que0que.h"
40 #include "row0ext.h"
41 #include "row0upd.h"
42 #include "rem0cmp.h"
43 #include "ut0mem.h"
44 #include "gis0geo.h"
45 #include "row0mysql.h"
46 
47 /** Build a spatial index key.
48 @param[in]	index	spatial index
49 @param[in]	ext	externally stored column prefixes, or NULL
50 @param[in,out]	dfield	field of the tuple to be copied
51 @param[in]	dfield2	field of the tuple to copy
52 @param[in]	flag	ROW_BUILD_NORMAL, ROW_BUILD_FOR_PURGE or
53 			ROW_BUILD_FOR_UNDO
54 @param[in,out]	heap	memory heap from which the memory
55 			of the field entry is allocated.
56 @retval false if undo log is logged before spatial index creation. */
row_build_spatial_index_key(const dict_index_t * index,const row_ext_t * ext,dfield_t * dfield,const dfield_t * dfield2,ulint flag,mem_heap_t * heap)57 static bool row_build_spatial_index_key(
58 	const dict_index_t*	index,
59 	const row_ext_t*	ext,
60 	dfield_t*		dfield,
61 	const dfield_t*		dfield2,
62 	ulint			flag,
63 	mem_heap_t*		heap)
64 {
65 	if (dfield2->type.mtype == DATA_MISSING) {
66 		return false;
67 	}
68 
69 	double*			mbr;
70 
71 	dfield_copy(dfield, dfield2);
72 	dfield->type.prtype |= DATA_GIS_MBR;
73 
74 	/* Allocate memory for mbr field */
75 	mbr = static_cast<double*>(mem_heap_alloc(heap, DATA_MBR_LEN));
76 
77 	/* Set mbr field data. */
78 	dfield_set_data(dfield, mbr, DATA_MBR_LEN);
79 
80 	const fil_space_t* space = index->table->space;
81 
82 	if (UNIV_UNLIKELY(!dfield2->data || !space)) {
83 		/* FIXME: dfield contains uninitialized data,
84 		but row_build_index_entry_low() will not return NULL.
85 		This bug is inherited from MySQL 5.7.5
86 		commit b66ad511b61fffe75c58d0a607cdb837c6e6c821. */
87 		return true;
88 	}
89 
90 	const byte* dptr = NULL;
91 	ulint	dlen = 0;
92 	ulint	flen = 0;
93 	double	tmp_mbr[SPDIMS * 2];
94 	mem_heap_t*	temp_heap = NULL;
95 
96 	if (!dfield_is_ext(dfield2)) {
97 		dptr = static_cast<const byte*>(dfield_get_data(dfield2));
98 		dlen = dfield_get_len(dfield2);
99 		ut_ad(dptr != &data_error);
100 		goto write_mbr;
101 	}
102 
103 	if (flag == ROW_BUILD_FOR_PURGE) {
104 		const byte* ptr = static_cast<const byte*>(
105 			dfield_get_data(dfield2));
106 
107 		switch (dfield_get_spatial_status(dfield2)) {
108 		case SPATIAL_ONLY:
109 			ut_ad(dfield_get_len(dfield2) == DATA_MBR_LEN);
110 			break;
111 
112 		case SPATIAL_MIXED:
113 			ptr += dfield_get_len(dfield2);
114 			break;
115 
116 		case SPATIAL_UNKNOWN:
117 			ut_ad(0);
118 			/* fall through */
119 		case SPATIAL_NONE:
120 			/* Undo record is logged before
121 			spatial index is created.*/
122 			return false;
123 		}
124 
125 		memcpy(mbr, ptr, DATA_MBR_LEN);
126 		return true;
127 	}
128 
129 	if (flag == ROW_BUILD_FOR_UNDO
130 	    && dict_table_has_atomic_blobs(index->table)) {
131 		/* For ROW_FORMAT=DYNAMIC or COMPRESSED, a prefix of
132 		off-page records is stored in the undo log record (for
133 		any column prefix indexes). For SPATIAL INDEX, we
134 		must ignore this prefix. The full column value is
135 		stored in the BLOB.  For non-spatial index, we would
136 		have already fetched a necessary prefix of the BLOB,
137 		available in the "ext" parameter.
138 
139 		Here, for SPATIAL INDEX, we are fetching the full
140 		column, which is potentially wasting a lot of I/O,
141 		memory, and possibly involving a concurrency problem,
142 		similar to ones that existed before the introduction
143 		of row_ext_t.
144 
145 		MDEV-11657 FIXME: write the MBR directly to the undo
146 		log record, and avoid recomputing it here! */
147 		flen = BTR_EXTERN_FIELD_REF_SIZE;
148 		ut_ad(dfield_get_len(dfield2) >= BTR_EXTERN_FIELD_REF_SIZE);
149 		dptr = static_cast<const byte*>(dfield_get_data(dfield2))
150 			+ dfield_get_len(dfield2)
151 			- BTR_EXTERN_FIELD_REF_SIZE;
152 	} else {
153 		flen = dfield_get_len(dfield2);
154 		dptr = static_cast<const byte*>(dfield_get_data(dfield2));
155 	}
156 
157 	temp_heap = mem_heap_create(1000);
158 
159 	dptr = btr_copy_externally_stored_field(
160 		&dlen, dptr, ext ? ext->zip_size : space->zip_size(),
161 		flen, temp_heap);
162 
163 write_mbr:
164 	if (dlen <= GEO_DATA_HEADER_SIZE) {
165 		for (uint i = 0; i < SPDIMS; i += 2) {
166 			tmp_mbr[i] = DBL_MAX;
167 			tmp_mbr[i + 1] = -DBL_MAX;
168 		}
169 	} else {
170 		rtree_mbr_from_wkb(dptr + GEO_DATA_HEADER_SIZE,
171 				   uint(dlen - GEO_DATA_HEADER_SIZE),
172 				   SPDIMS, tmp_mbr);
173 	}
174 
175 	dfield_write_mbr(dfield, tmp_mbr);
176 	if (temp_heap) {
177 		mem_heap_free(temp_heap);
178 	}
179 
180 	return true;
181 }
182 
183 /*****************************************************************//**
184 When an insert or purge to a table is performed, this function builds
185 the entry to be inserted into or purged from an index on the table.
186 @return index entry which should be inserted or purged
187 @retval NULL if the externally stored columns in the clustered index record
188 are unavailable and ext != NULL, or row is missing some needed columns. */
189 dtuple_t*
row_build_index_entry_low(const dtuple_t * row,const row_ext_t * ext,const dict_index_t * index,mem_heap_t * heap,ulint flag)190 row_build_index_entry_low(
191 /*======================*/
192 	const dtuple_t*		row,	/*!< in: row which should be
193 					inserted or purged */
194 	const row_ext_t*	ext,	/*!< in: externally stored column
195 					prefixes, or NULL */
196 	const dict_index_t*	index,	/*!< in: index on the table */
197 	mem_heap_t*		heap,	/*!< in,out: memory heap from which
198 					the memory for the index entry
199 					is allocated */
200 	ulint			flag)	/*!< in: ROW_BUILD_NORMAL,
201 					ROW_BUILD_FOR_PURGE
202                                         or ROW_BUILD_FOR_UNDO */
203 {
204 	dtuple_t*	entry;
205 	ulint		entry_len;
206 	ulint		i = 0;
207 	ulint		num_v = 0;
208 
209 	entry_len = dict_index_get_n_fields(index);
210 
211 	if (flag == ROW_BUILD_FOR_INSERT && dict_index_is_clust(index)) {
212 		num_v = dict_table_get_n_v_cols(index->table);
213 		entry = dtuple_create_with_vcol(heap, entry_len, num_v);
214 	} else {
215 		entry = dtuple_create(heap, entry_len);
216 	}
217 
218 	if (dict_index_is_ibuf(index)) {
219 		dtuple_set_n_fields_cmp(entry, entry_len);
220 		/* There may only be externally stored columns
221 		in a clustered index B-tree of a user table. */
222 		ut_a(!ext);
223 	} else {
224 		dtuple_set_n_fields_cmp(
225 			entry, dict_index_get_n_unique_in_tree(index));
226 		if (dict_index_is_spatial(index)) {
227 			/* Set the MBR field */
228 			if (!row_build_spatial_index_key(
229 				    index, ext,
230 				    dtuple_get_nth_field(entry, 0),
231 				    dtuple_get_nth_field(
232 					    row,
233 					    dict_index_get_nth_field(index, i)
234 					    ->col->ind), flag, heap)) {
235 				return NULL;
236 			}
237 
238 			i = 1;
239 		}
240 	}
241 
242 	for (; i < entry_len; i++) {
243 		const dict_field_t& f = index->fields[i];
244 		dfield_t* dfield = dtuple_get_nth_field(entry, i);
245 
246 		if (f.col->is_dropped()) {
247 			ut_ad(index->is_primary());
248 			ut_ad(index->is_instant());
249 			ut_ad(!f.col->is_virtual());
250 			dict_col_copy_type(f.col, &dfield->type);
251 			if (f.col->is_nullable()) {
252 				dfield_set_null(dfield);
253 			} else {
254 				dfield_set_data(dfield, field_ref_zero,
255 						f.fixed_len);
256 			}
257 			continue;
258 		}
259 
260 		const dfield_t* dfield2;
261 
262 		if (f.col->is_virtual()) {
263 			const dict_v_col_t* v_col
264 				= reinterpret_cast<const dict_v_col_t*>(f.col);
265 
266 			ut_ad(v_col->v_pos < dtuple_get_n_v_fields(row));
267 			dfield2 = dtuple_get_nth_v_field(row, v_col->v_pos);
268 
269 			ut_ad(dfield_is_null(dfield2) ||
270 			      dfield_get_len(dfield2) == 0 || dfield2->data);
271 			ut_ad(!dfield_is_ext(dfield2));
272 			if (UNIV_UNLIKELY(dfield2->type.mtype
273 					  == DATA_MISSING)) {
274 				ut_ad(flag == ROW_BUILD_FOR_PURGE);
275 				return(NULL);
276 			}
277 		} else {
278 			dfield2 = dtuple_get_nth_field(row, f.col->ind);
279 			if (UNIV_UNLIKELY(dfield2->type.mtype
280 					  == DATA_MISSING)) {
281 				/* The field has not been initialized in
282 				the row. This should be from
283 				trx_undo_rec_get_partial_row(). */
284 				return(NULL);
285 			}
286 
287 			ut_ad(!(dfield2->type.prtype & DATA_VIRTUAL));
288 		}
289 
290 		compile_time_assert(DATA_MISSING == 0);
291 
292 		*dfield = *dfield2;
293 
294 		if (dfield_is_null(dfield)) {
295 			continue;
296 		}
297 
298 		ut_ad(!(index->type & DICT_FTS));
299 
300 		ulint len = dfield_get_len(dfield);
301 
302 		if (f.prefix_len == 0
303 		    && (!dfield_is_ext(dfield)
304 			|| dict_index_is_clust(index))) {
305 			/* The *dfield = *dfield2 above suffices for
306 			columns that are stored in-page, or for
307 			clustered index record columns that are not
308 			part of a column prefix in the PRIMARY KEY. */
309 			continue;
310 		}
311 
312 		/* If the column is stored externally (off-page) in
313 		the clustered index, it must be an ordering field in
314 		the secondary index. If !atomic_blobs, the only way
315 		we may have a secondary index pointing to a clustered
316 		index record with an off-page column is when it is a
317 		column prefix index. If atomic_blobs, also fully
318 		indexed long columns may be stored off-page. */
319 		ut_ad(f.col->ord_part);
320 
321 		if (ext && !f.col->is_virtual()) {
322 			/* See if the column is stored externally. */
323 			const byte*	buf = row_ext_lookup(ext, f.col->ind,
324 							     &len);
325 			if (UNIV_LIKELY_NULL(buf)) {
326 				if (UNIV_UNLIKELY(buf == field_ref_zero)) {
327 					return(NULL);
328 				}
329 				dfield_set_data(dfield, buf, len);
330 			}
331 
332 			if (f.prefix_len == 0) {
333 				/* If ROW_FORMAT=DYNAMIC or
334 				ROW_FORMAT=COMPRESSED, we can have a
335 				secondary index on an entire column
336 				that is stored off-page in the
337 				clustered index. As this is not a
338 				prefix index (prefix_len == 0),
339 				include the entire off-page column in
340 				the secondary index record. */
341 				continue;
342 			}
343 		} else if (dfield_is_ext(dfield)) {
344 			/* This table is either in
345 			(ROW_FORMAT=REDUNDANT or ROW_FORMAT=COMPACT)
346 			or a purge record where the ordered part of
347 			the field is not external.
348 			In ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT,
349 			the maximum column prefix
350 			index length is 767 bytes, and the clustered
351 			index record contains a 768-byte prefix of
352 			each off-page column. */
353 			ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE);
354 			len -= BTR_EXTERN_FIELD_REF_SIZE;
355 			dfield_set_len(dfield, len);
356 		}
357 
358 		/* If a column prefix index, take only the prefix. */
359 		if (f.prefix_len) {
360 			len = dtype_get_at_most_n_mbchars(
361 				f.col->prtype,
362 				f.col->mbminlen, f.col->mbmaxlen,
363 				f.prefix_len, len,
364 				static_cast<char*>(dfield_get_data(dfield)));
365 			dfield_set_len(dfield, len);
366 		}
367 	}
368 
369 	for (i = num_v; i--; ) {
370 		ut_ad(index->is_primary());
371 		ut_ad(flag == ROW_BUILD_FOR_INSERT);
372 		dfield_t* dfield = dtuple_get_nth_v_field(entry, i);
373 		const dict_v_col_t* v_col = dict_table_get_nth_v_col(
374 			index->table, i);
375 		ut_ad(!v_col->m_col.is_dropped());
376 		ut_ad(v_col->v_pos < dtuple_get_n_v_fields(row));
377 		const dfield_t* dfield2 = dtuple_get_nth_v_field(
378 			row, v_col->v_pos);
379 		ut_ad(dfield_is_null(dfield2) ||
380 		      dfield_get_len(dfield2) == 0 || dfield2->data);
381 		ut_ad(dfield2->type.mtype != DATA_MISSING);
382 		*dfield = *dfield2;
383 	}
384 
385 	return entry;
386 }
387 
388 /** An inverse function to row_build_index_entry. Builds a row from a
389 record in a clustered index, with possible indexing on ongoing
390 addition of new virtual columns.
391 @param[in]	type		ROW_COPY_POINTERS or ROW_COPY_DATA;
392 @param[in]	index		clustered index
393 @param[in]	rec		record in the clustered index
394 @param[in]	offsets		rec_get_offsets(rec,index) or NULL
395 @param[in]	col_table	table, to check which
396 				externally stored columns
397 				occur in the ordering columns
398 				of an index, or NULL if
399 				index->table should be
400 				consulted instead
401 @param[in]	defaults	default values of added/changed columns, or NULL
402 @param[in]	add_v		new virtual columns added
403 				along with new indexes
404 @param[in]	col_map		mapping of old column
405 				numbers to new ones, or NULL
406 @param[in]	ext		cache of externally stored column
407 				prefixes, or NULL
408 @param[in]	heap		memory heap from which
409 				the memory needed is allocated
410 @return own: row built; */
411 static inline
412 dtuple_t*
row_build_low(ulint type,const dict_index_t * index,const rec_t * rec,const rec_offs * offsets,const dict_table_t * col_table,const dtuple_t * defaults,const dict_add_v_col_t * add_v,const ulint * col_map,row_ext_t ** ext,mem_heap_t * heap)413 row_build_low(
414 	ulint			type,
415 	const dict_index_t*	index,
416 	const rec_t*		rec,
417 	const rec_offs*		offsets,
418 	const dict_table_t*	col_table,
419 	const dtuple_t*		defaults,
420 	const dict_add_v_col_t*	add_v,
421 	const ulint*		col_map,
422 	row_ext_t**		ext,
423 	mem_heap_t*		heap)
424 {
425 	const byte*		copy;
426 	dtuple_t*		row;
427 	ulint			n_ext_cols;
428 	ulint*			ext_cols	= NULL; /* remove warning */
429 	ulint			len;
430 	byte*			buf;
431 	ulint			j;
432 	mem_heap_t*		tmp_heap	= NULL;
433 	rec_offs		offsets_[REC_OFFS_NORMAL_SIZE];
434 	rec_offs_init(offsets_);
435 
436 	ut_ad(index != NULL);
437 	ut_ad(rec != NULL);
438 	ut_ad(heap != NULL);
439 	ut_ad(dict_index_is_clust(index));
440 	ut_ad(!col_map || col_table);
441 
442 	if (!offsets) {
443 		offsets = rec_get_offsets(rec, index, offsets_,
444 					  index->n_core_fields,
445 					  ULINT_UNDEFINED, &tmp_heap);
446 	} else {
447 		ut_ad(rec_offs_validate(rec, index, offsets));
448 	}
449 
450 #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
451 	/* Some blob refs can be NULL during crash recovery before
452 	trx_rollback_active() has completed execution, or when a concurrently
453 	executing insert or update has committed the B-tree mini-transaction
454 	but has not yet managed to restore the cursor position for writing
455 	the big_rec. Note that the mini-transaction can be committed multiple
456 	times, and the cursor restore can happen multiple times for single
457 	insert or update statement.  */
458 	ut_a(!rec_offs_any_null_extern(rec, offsets)
459 	     || trx_sys.is_registered(current_trx(),
460 				      row_get_rec_trx_id(rec, index,
461 							 offsets)));
462 #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
463 
464 	if (type != ROW_COPY_POINTERS) {
465 		/* Take a copy of rec to heap */
466 		buf = static_cast<byte*>(
467 			mem_heap_alloc(heap, rec_offs_size(offsets)));
468 
469 		copy = rec_copy(buf, rec, offsets);
470 	} else {
471 		copy = rec;
472 	}
473 
474 	n_ext_cols = rec_offs_n_extern(offsets);
475 	if (n_ext_cols) {
476 		ext_cols = static_cast<ulint*>(
477 			mem_heap_alloc(heap, n_ext_cols * sizeof *ext_cols));
478 	}
479 
480 	/* Avoid a debug assertion in rec_offs_validate(). */
481 	rec_offs_make_valid(copy, index, true, const_cast<rec_offs*>(offsets));
482 
483 	if (!col_table) {
484 		ut_ad(!col_map);
485 		ut_ad(!defaults);
486 		col_table = index->table;
487 	}
488 
489 	if (defaults) {
490 		ut_ad(col_map);
491 		row = dtuple_copy(defaults, heap);
492 		/* dict_table_copy_types() would set the fields to NULL */
493 		for (ulint i = 0; i < dict_table_get_n_cols(col_table); i++) {
494 			dict_col_copy_type(
495 				dict_table_get_nth_col(col_table, i),
496 				dfield_get_type(dtuple_get_nth_field(row, i)));
497 		}
498 	} else if (add_v != NULL) {
499 		row = dtuple_create_with_vcol(
500 			heap, dict_table_get_n_cols(col_table),
501 			dict_table_get_n_v_cols(col_table) + add_v->n_v_col);
502 		dict_table_copy_types(row, col_table);
503 
504 		for (ulint i = 0; i < add_v->n_v_col; i++) {
505 			dict_col_copy_type(
506 				&add_v->v_col[i].m_col,
507 				dfield_get_type(dtuple_get_nth_v_field(
508 					row, i + col_table->n_v_def)));
509 		}
510 	} else {
511 		row = dtuple_create_with_vcol(
512 			heap, dict_table_get_n_cols(col_table),
513 			dict_table_get_n_v_cols(col_table));
514 		dict_table_copy_types(row, col_table);
515 	}
516 
517 	dtuple_set_info_bits(row, rec_get_info_bits(
518 				     copy, rec_offs_comp(offsets)));
519 
520 	j = 0;
521 
522 	const dict_field_t* ind_field = index->fields;
523 
524 	for (ulint i = 0; i < rec_offs_n_fields(offsets); i++) {
525 		if (i == index->first_user_field()
526 		    && rec_is_alter_metadata(rec, *index)) {
527 			ut_ad(rec_offs_nth_extern(offsets, i));
528 			ut_d(ulint len);
529 			ut_d(rec_get_nth_field_offs(offsets, i, &len));
530 			ut_ad(len == FIELD_REF_SIZE);
531 			continue;
532 		}
533 
534 		ut_ad(ind_field < &index->fields[index->n_fields]);
535 
536 		const dict_col_t* col = dict_field_get_col(ind_field);
537 
538 		if ((ind_field++)->prefix_len) {
539 			/* Column prefixes can only occur in key
540 			fields, which cannot be stored externally. For
541 			a column prefix, there should also be the full
542 			field in the clustered index tuple. The row
543 			tuple comprises full fields, not prefixes. */
544 			ut_ad(!rec_offs_nth_extern(offsets, i));
545 			continue;
546 		}
547 
548 		if (col->is_dropped()) {
549 			continue;
550 		}
551 
552 		ulint	col_no = dict_col_get_no(col);
553 
554 		if (col_map) {
555 			col_no = col_map[col_no];
556 
557 			if (col_no == ULINT_UNDEFINED) {
558 				/* dropped column */
559 				continue;
560 			}
561 		}
562 
563 		dfield_t*	dfield = dtuple_get_nth_field(row, col_no);
564 
565 		const void*	field = rec_get_nth_field(
566 			copy, offsets, i, &len);
567 		if (len == UNIV_SQL_DEFAULT) {
568 			field = index->instant_field_value(i, &len);
569 			if (field && type != ROW_COPY_POINTERS) {
570 				field = mem_heap_dup(heap, field, len);
571 			}
572 		}
573 		dfield_set_data(dfield, field, len);
574 
575 		if (rec_offs_nth_extern(offsets, i)) {
576 			dfield_set_ext(dfield);
577 
578 			col = dict_table_get_nth_col(col_table, col_no);
579 
580 			if (col->ord_part) {
581 				/* We will have to fetch prefixes of
582 				externally stored columns that are
583 				referenced by column prefixes. */
584 				ext_cols[j++] = col_no;
585 			}
586 		}
587 	}
588 
589 	rec_offs_make_valid(rec, index, true, const_cast<rec_offs*>(offsets));
590 
591 	ut_ad(dtuple_check_typed(row));
592 
593 	if (!ext) {
594 		/* REDUNDANT and COMPACT formats store a local
595 		768-byte prefix of each externally stored
596 		column. No cache is needed.
597 
598 		During online table rebuild,
599 		row_log_table_apply_delete_low()
600 		may use a cache that was set up by
601 		row_log_table_delete(). */
602 
603 	} else if (j) {
604 		*ext = row_ext_create(j, ext_cols, *index->table, row,
605 				      heap);
606 	} else {
607 		*ext = NULL;
608 	}
609 
610 	if (tmp_heap) {
611 		mem_heap_free(tmp_heap);
612 	}
613 
614 	return(row);
615 }
616 
617 
618 /*******************************************************************//**
619 An inverse function to row_build_index_entry. Builds a row from a
620 record in a clustered index.
621 @return own: row built; see the NOTE below! */
622 dtuple_t*
row_build(ulint type,const dict_index_t * index,const rec_t * rec,const rec_offs * offsets,const dict_table_t * col_table,const dtuple_t * defaults,const ulint * col_map,row_ext_t ** ext,mem_heap_t * heap)623 row_build(
624 /*======*/
625 	ulint			type,	/*!< in: ROW_COPY_POINTERS or
626 					ROW_COPY_DATA; the latter
627 					copies also the data fields to
628 					heap while the first only
629 					places pointers to data fields
630 					on the index page, and thus is
631 					more efficient */
632 	const dict_index_t*	index,	/*!< in: clustered index */
633 	const rec_t*		rec,	/*!< in: record in the clustered
634 					index; NOTE: in the case
635 					ROW_COPY_POINTERS the data
636 					fields in the row will point
637 					directly into this record,
638 					therefore, the buffer page of
639 					this record must be at least
640 					s-latched and the latch held
641 					as long as the row dtuple is used! */
642 	const rec_offs*		offsets,/*!< in: rec_get_offsets(rec,index)
643 					or NULL, in which case this function
644 					will invoke rec_get_offsets() */
645 	const dict_table_t*	col_table,
646 					/*!< in: table, to check which
647 					externally stored columns
648 					occur in the ordering columns
649 					of an index, or NULL if
650 					index->table should be
651 					consulted instead */
652 	const dtuple_t*		defaults,
653 					/*!< in: default values of
654 					added and changed columns, or NULL */
655 	const ulint*		col_map,/*!< in: mapping of old column
656 					numbers to new ones, or NULL */
657 	row_ext_t**		ext,	/*!< out, own: cache of
658 					externally stored column
659 					prefixes, or NULL */
660 	mem_heap_t*		heap)	/*!< in: memory heap from which
661 					 the memory needed is allocated */
662 {
663 	return(row_build_low(type, index, rec, offsets, col_table,
664 			     defaults, NULL, col_map, ext, heap));
665 }
666 
667 /** An inverse function to row_build_index_entry. Builds a row from a
668 record in a clustered index, with possible indexing on ongoing
669 addition of new virtual columns.
670 @param[in]	type		ROW_COPY_POINTERS or ROW_COPY_DATA;
671 @param[in]	index		clustered index
672 @param[in]	rec		record in the clustered index
673 @param[in]	offsets		rec_get_offsets(rec,index) or NULL
674 @param[in]	col_table	table, to check which
675 				externally stored columns
676 				occur in the ordering columns
677 				of an index, or NULL if
678 				index->table should be
679 				consulted instead
680 @param[in]	defaults	default values of added, changed columns, or NULL
681 @param[in]	add_v		new virtual columns added
682 				along with new indexes
683 @param[in]	col_map		mapping of old column
684 				numbers to new ones, or NULL
685 @param[in]	ext		cache of externally stored column
686 				prefixes, or NULL
687 @param[in]	heap		memory heap from which
688 				the memory needed is allocated
689 @return own: row built; */
690 dtuple_t*
row_build_w_add_vcol(ulint type,const dict_index_t * index,const rec_t * rec,const rec_offs * offsets,const dict_table_t * col_table,const dtuple_t * defaults,const dict_add_v_col_t * add_v,const ulint * col_map,row_ext_t ** ext,mem_heap_t * heap)691 row_build_w_add_vcol(
692 	ulint			type,
693 	const dict_index_t*	index,
694 	const rec_t*		rec,
695 	const rec_offs*		offsets,
696 	const dict_table_t*	col_table,
697 	const dtuple_t*		defaults,
698 	const dict_add_v_col_t*	add_v,
699 	const ulint*		col_map,
700 	row_ext_t**		ext,
701 	mem_heap_t*		heap)
702 {
703 	return(row_build_low(type, index, rec, offsets, col_table,
704 			     defaults, add_v, col_map, ext, heap));
705 }
706 
707 /** Convert an index record to a data tuple.
708 @tparam metadata whether the index->instant_field_value() needs to be accessed
709 @tparam mblob 1 if rec_is_alter_metadata();
710 2 if we want converted metadata corresponding to info_bits
711 @param[in]	rec		index record
712 @param[in]	index		index
713 @param[in]	offsets		rec_get_offsets(rec, index)
714 @param[out]	n_ext		number of externally stored columns
715 @param[in,out]	heap		memory heap for allocations
716 @param[in]	info_bits	(only used if mblob=2)
717 @param[in]	pad		(only used if mblob=2)
718 @return index entry built; does not set info_bits, and the data fields
719 in the entry will point directly to rec */
720 template<bool metadata, int mblob = 0>
721 static inline
722 dtuple_t*
row_rec_to_index_entry_impl(const rec_t * rec,const dict_index_t * index,const rec_offs * offsets,mem_heap_t * heap,ulint info_bits=0,bool pad=false)723 row_rec_to_index_entry_impl(
724 	const rec_t*		rec,
725 	const dict_index_t*	index,
726 	const rec_offs*		offsets,
727 	mem_heap_t*		heap,
728 	ulint			info_bits = 0,
729 	bool			pad = false)
730 {
731 	ut_ad(rec != NULL);
732 	ut_ad(heap != NULL);
733 	ut_ad(index != NULL);
734 	ut_ad(!mblob || index->is_primary());
735 	ut_ad(!mblob || !index->table->is_temporary());
736 	ut_ad(!mblob || !dict_index_is_spatial(index));
737 	compile_time_assert(!mblob || metadata);
738 	compile_time_assert(mblob <= 2);
739 	/* Because this function may be invoked by row0merge.cc
740 	on a record whose header is in different format, the check
741 	rec_offs_validate(rec, index, offsets) must be avoided here. */
742 
743 	const bool got = mblob == 2 && rec_is_alter_metadata(rec, *index);
744 	ulint rec_len = rec_offs_n_fields(offsets);
745 	if (mblob == 2) {
746 		ut_ad(info_bits == REC_INFO_METADATA_ALTER
747 		      || info_bits == REC_INFO_METADATA_ADD);
748 		ut_ad(rec_len <= ulint(index->n_fields + got));
749 		if (pad) {
750 			rec_len = ulint(index->n_fields)
751 				+ (info_bits == REC_INFO_METADATA_ALTER);
752 		} else if (!got && info_bits == REC_INFO_METADATA_ALTER) {
753 			rec_len++;
754 		}
755 	} else {
756 		ut_ad(info_bits == 0);
757 		ut_ad(!pad);
758 	}
759 	dtuple_t* entry = dtuple_create(heap, rec_len);
760 	dfield_t* dfield = entry->fields;
761 
762 	dtuple_set_n_fields_cmp(entry,
763 				dict_index_get_n_unique_in_tree(index));
764 	ut_ad(mblob == 2
765 	      || rec_len == dict_index_get_n_fields(index) + uint(mblob == 1)
766 	      /* a record for older SYS_INDEXES table
767 	      (missing merge_threshold column) is acceptable. */
768 	      || (!index->table->is_temporary()
769 		  && index->table->id == DICT_INDEXES_ID
770 		  && rec_len + 1 == dict_index_get_n_fields(index)));
771 
772 	ulint i;
773 	for (i = 0; i < (mblob ? index->first_user_field() : rec_len);
774 	     i++, dfield++) {
775 		dict_col_copy_type(dict_index_get_nth_col(index, i),
776 				   &dfield->type);
777 		if (!mblob
778 		    && dict_index_is_spatial(index)
779 		    && DATA_GEOMETRY_MTYPE(dfield->type.mtype)) {
780 			dfield->type.prtype |= DATA_GIS_MBR;
781 		}
782 
783 		ulint len;
784 		const byte* field = metadata
785 			? rec_get_nth_cfield(rec, index, offsets, i, &len)
786 			: rec_get_nth_field(rec, offsets, i, &len);
787 
788 		dfield_set_data(dfield, field, len);
789 
790 		if (rec_offs_nth_extern(offsets, i)) {
791 			dfield_set_ext(dfield);
792 		}
793 	}
794 
795 	if (mblob) {
796 		ulint len;
797 		const byte* field;
798 		ulint j = i;
799 
800 		if (mblob == 2) {
801 			const bool want = info_bits == REC_INFO_METADATA_ALTER;
802 			if (got == want) {
803 				if (got) {
804 					goto copy_metadata;
805 				}
806 			} else {
807 				if (want) {
808 					/* Allocate a placeholder for
809 					adding metadata in an update. */
810 					len = FIELD_REF_SIZE;
811 					field = static_cast<byte*>(
812 						mem_heap_zalloc(heap, len));
813 					/* In reality there is one fewer
814 					field present in the record. */
815 					rec_len--;
816 					goto init_metadata;
817 				}
818 
819 				/* Skip the undesired metadata blob
820 				(for example, when rolling back an
821 				instant ALTER TABLE). */
822 				i++;
823 			}
824 			goto copy_user_fields;
825 		}
826 copy_metadata:
827 		ut_ad(rec_offs_nth_extern(offsets, i));
828 		field = rec_get_nth_field(rec, offsets, i++, &len);
829 init_metadata:
830 		dfield->type.metadata_blob_init();
831 		ut_ad(len == FIELD_REF_SIZE);
832 		dfield_set_data(dfield, field, len);
833 		dfield_set_ext(dfield++);
834 copy_user_fields:
835 		for (; i < rec_len; i++, dfield++) {
836 			dict_col_copy_type(dict_index_get_nth_col(index, j++),
837 					   &dfield->type);
838 			if (mblob == 2 && pad
839 			    && i >= rec_offs_n_fields(offsets)) {
840 				field = index->instant_field_value(j - 1,
841 								   &len);
842 				dfield_set_data(dfield, field, len);
843 				continue;
844 			}
845 
846 			field = rec_get_nth_field(rec, offsets, i, &len);
847 			dfield_set_data(dfield, field, len);
848 
849 			if (rec_offs_nth_extern(offsets, i)) {
850 				dfield_set_ext(dfield);
851 			}
852 		}
853 	}
854 
855 	if (mblob == 2) {
856 		ulint n_fields = ulint(dfield - entry->fields);
857 		ut_ad(entry->n_fields >= n_fields);
858 		entry->n_fields = n_fields;
859 	}
860 	ut_ad(dfield == entry->fields + entry->n_fields);
861 	ut_ad(dtuple_check_typed(entry));
862 	return entry;
863 }
864 
865 /** Convert an index record to a data tuple.
866 @param[in]	rec	index record
867 @param[in]	index	index
868 @param[in]	offsets	rec_get_offsets(rec, index)
869 @param[in,out]	heap	memory heap for allocations */
870 dtuple_t*
row_rec_to_index_entry_low(const rec_t * rec,const dict_index_t * index,const rec_offs * offsets,mem_heap_t * heap)871 row_rec_to_index_entry_low(
872 	const rec_t*		rec,
873 	const dict_index_t*	index,
874 	const rec_offs*		offsets,
875 	mem_heap_t*		heap)
876 {
877 	return row_rec_to_index_entry_impl<false>(rec, index, offsets, heap);
878 }
879 
880 /*******************************************************************//**
881 Converts an index record to a typed data tuple. NOTE that externally
882 stored (often big) fields are NOT copied to heap.
883 @return own: index entry built */
884 dtuple_t*
row_rec_to_index_entry(const rec_t * rec,const dict_index_t * index,const rec_offs * offsets,mem_heap_t * heap)885 row_rec_to_index_entry(
886 /*===================*/
887 	const rec_t*		rec,	/*!< in: record in the index */
888 	const dict_index_t*	index,	/*!< in: index */
889 	const rec_offs*		offsets,/*!< in: rec_get_offsets(rec) */
890 	mem_heap_t*		heap)	/*!< in: memory heap from which
891 					the memory needed is allocated */
892 {
893 	ut_ad(rec != NULL);
894 	ut_ad(heap != NULL);
895 	ut_ad(index != NULL);
896 	ut_ad(rec_offs_validate(rec, index, offsets));
897 
898 	/* Take a copy of rec to heap */
899 	const rec_t* copy_rec = rec_copy(
900 		static_cast<byte*>(mem_heap_alloc(heap,
901 						  rec_offs_size(offsets))),
902 		rec, offsets);
903 
904 	rec_offs_make_valid(copy_rec, index, true,
905 			    const_cast<rec_offs*>(offsets));
906 
907 	dtuple_t* entry = rec_is_alter_metadata(copy_rec, *index)
908 		? row_rec_to_index_entry_impl<true,1>(
909 			copy_rec, index, offsets, heap)
910 		: row_rec_to_index_entry_impl<true>(
911 			copy_rec, index, offsets, heap);
912 
913 	rec_offs_make_valid(rec, index, true,
914 			    const_cast<rec_offs*>(offsets));
915 
916 	dtuple_set_info_bits(entry,
917 			     rec_get_info_bits(rec, rec_offs_comp(offsets)));
918 
919 	return(entry);
920 }
921 
922 /** Convert a metadata record to a data tuple.
923 @param[in]	rec		metadata record
924 @param[in]	index		clustered index after instant ALTER TABLE
925 @param[in]	offsets		rec_get_offsets(rec)
926 @param[in,out]	heap		memory heap for allocations
927 @param[in]	info_bits	the info_bits after an update
928 @param[in]	pad		whether to pad to index->n_fields */
929 dtuple_t*
row_metadata_to_tuple(const rec_t * rec,const dict_index_t * index,const rec_offs * offsets,mem_heap_t * heap,ulint info_bits,bool pad)930 row_metadata_to_tuple(
931 	const rec_t*		rec,
932 	const dict_index_t*	index,
933 	const rec_offs*		offsets,
934 	mem_heap_t*		heap,
935 	ulint			info_bits,
936 	bool			pad)
937 {
938 	ut_ad(info_bits == REC_INFO_METADATA_ALTER
939 	      || info_bits == REC_INFO_METADATA_ADD);
940 	ut_ad(rec_is_metadata(rec, *index));
941 	ut_ad(rec_offs_validate(rec, index, offsets));
942 
943 	const rec_t* copy_rec = rec_copy(
944 		static_cast<byte*>(mem_heap_alloc(heap,
945 						  rec_offs_size(offsets))),
946 		rec, offsets);
947 
948 	rec_offs_make_valid(copy_rec, index, true,
949 			    const_cast<rec_offs*>(offsets));
950 
951 	dtuple_t* entry = info_bits == REC_INFO_METADATA_ALTER
952 		|| rec_is_alter_metadata(copy_rec, *index)
953 		? row_rec_to_index_entry_impl<true,2>(
954 			copy_rec, index, offsets, heap, info_bits, pad)
955 		: row_rec_to_index_entry_impl<true>(
956 			copy_rec, index, offsets, heap);
957 
958 	rec_offs_make_valid(rec, index, true,
959 			    const_cast<rec_offs*>(offsets));
960 
961 	dtuple_set_info_bits(entry, info_bits);
962 	return entry;
963 }
964 
965 /*******************************************************************//**
966 Builds from a secondary index record a row reference with which we can
967 search the clustered index record.
968 @return own: row reference built; see the NOTE below! */
969 dtuple_t*
row_build_row_ref(ulint type,dict_index_t * index,const rec_t * rec,mem_heap_t * heap)970 row_build_row_ref(
971 /*==============*/
972 	ulint		type,	/*!< in: ROW_COPY_DATA, or ROW_COPY_POINTERS:
973 				the former copies also the data fields to
974 				heap, whereas the latter only places pointers
975 				to data fields on the index page */
976 	dict_index_t*	index,	/*!< in: secondary index */
977 	const rec_t*	rec,	/*!< in: record in the index;
978 				NOTE: in the case ROW_COPY_POINTERS
979 				the data fields in the row will point
980 				directly into this record, therefore,
981 				the buffer page of this record must be
982 				at least s-latched and the latch held
983 				as long as the row reference is used! */
984 	mem_heap_t*	heap)	/*!< in: memory heap from which the memory
985 				needed is allocated */
986 {
987 	dict_table_t*	table;
988 	dict_index_t*	clust_index;
989 	dfield_t*	dfield;
990 	dtuple_t*	ref;
991 	const byte*	field;
992 	ulint		len;
993 	ulint		ref_len;
994 	ulint		pos;
995 	byte*		buf;
996 	ulint		clust_col_prefix_len;
997 	ulint		i;
998 	mem_heap_t*	tmp_heap	= NULL;
999 	rec_offs	offsets_[REC_OFFS_NORMAL_SIZE];
1000 	rec_offs*	offsets		= offsets_;
1001 	rec_offs_init(offsets_);
1002 
1003 	ut_ad(index != NULL);
1004 	ut_ad(rec != NULL);
1005 	ut_ad(heap != NULL);
1006 	ut_ad(!dict_index_is_clust(index));
1007 
1008 	offsets = rec_get_offsets(rec, index, offsets, index->n_core_fields,
1009 				  ULINT_UNDEFINED, &tmp_heap);
1010 	/* Secondary indexes must not contain externally stored columns. */
1011 	ut_ad(!rec_offs_any_extern(offsets));
1012 
1013 	if (type == ROW_COPY_DATA) {
1014 		/* Take a copy of rec to heap */
1015 
1016 		buf = static_cast<byte*>(
1017 			mem_heap_alloc(heap, rec_offs_size(offsets)));
1018 
1019 		rec = rec_copy(buf, rec, offsets);
1020 		rec_offs_make_valid(rec, index, true, offsets);
1021 	}
1022 
1023 	table = index->table;
1024 
1025 	clust_index = dict_table_get_first_index(table);
1026 
1027 	ref_len = dict_index_get_n_unique(clust_index);
1028 
1029 	ref = dtuple_create(heap, ref_len);
1030 
1031 	dict_index_copy_types(ref, clust_index, ref_len);
1032 
1033 	for (i = 0; i < ref_len; i++) {
1034 		dfield = dtuple_get_nth_field(ref, i);
1035 
1036 		pos = dict_index_get_nth_field_pos(index, clust_index, i);
1037 
1038 		ut_a(pos != ULINT_UNDEFINED);
1039 
1040 		ut_ad(!rec_offs_nth_default(offsets, pos));
1041 		field = rec_get_nth_field(rec, offsets, pos, &len);
1042 
1043 		dfield_set_data(dfield, field, len);
1044 
1045 		/* If the primary key contains a column prefix, then the
1046 		secondary index may contain a longer prefix of the same
1047 		column, or the full column, and we must adjust the length
1048 		accordingly. */
1049 
1050 		clust_col_prefix_len = dict_index_get_nth_field(
1051 			clust_index, i)->prefix_len;
1052 
1053 		if (clust_col_prefix_len > 0) {
1054 			if (len != UNIV_SQL_NULL) {
1055 
1056 				const dtype_t*	dtype
1057 					= dfield_get_type(dfield);
1058 
1059 				dfield_set_len(dfield,
1060 					       dtype_get_at_most_n_mbchars(
1061 						       dtype->prtype,
1062 						       dtype->mbminlen,
1063 						       dtype->mbmaxlen,
1064 						       clust_col_prefix_len,
1065 						       len, (char*) field));
1066 			}
1067 		}
1068 	}
1069 
1070 	ut_ad(dtuple_check_typed(ref));
1071 	if (tmp_heap) {
1072 		mem_heap_free(tmp_heap);
1073 	}
1074 
1075 	return(ref);
1076 }
1077 
1078 /*******************************************************************//**
1079 Builds from a secondary index record a row reference with which we can
1080 search the clustered index record. */
1081 void
row_build_row_ref_in_tuple(dtuple_t * ref,const rec_t * rec,const dict_index_t * index,rec_offs * offsets)1082 row_build_row_ref_in_tuple(
1083 /*=======================*/
1084 	dtuple_t*		ref,	/*!< in/out: row reference built;
1085 					see the NOTE below! */
1086 	const rec_t*		rec,	/*!< in: record in the index;
1087 					NOTE: the data fields in ref
1088 					will point directly into this
1089 					record, therefore, the buffer
1090 					page of this record must be at
1091 					least s-latched and the latch
1092 					held as long as the row
1093 					reference is used! */
1094 	const dict_index_t*	index,	/*!< in: secondary index */
1095 	rec_offs*		offsets)/*!< in: rec_get_offsets(rec, index)
1096 					or NULL */
1097 {
1098 	const dict_index_t*	clust_index;
1099 	dfield_t*		dfield;
1100 	const byte*		field;
1101 	ulint			len;
1102 	ulint			ref_len;
1103 	ulint			pos;
1104 	ulint			clust_col_prefix_len;
1105 	ulint			i;
1106 	mem_heap_t*		heap		= NULL;
1107 	rec_offs		offsets_[REC_OFFS_NORMAL_SIZE];
1108 	rec_offs_init(offsets_);
1109 
1110 	ut_ad(!dict_index_is_clust(index));
1111 	ut_a(index->table);
1112 
1113 	clust_index = dict_table_get_first_index(index->table);
1114 	ut_ad(clust_index);
1115 
1116 	if (!offsets) {
1117 		offsets = rec_get_offsets(rec, index, offsets_,
1118 					  index->n_core_fields,
1119 					  ULINT_UNDEFINED, &heap);
1120 	} else {
1121 		ut_ad(rec_offs_validate(rec, index, offsets));
1122 	}
1123 
1124 	/* Secondary indexes must not contain externally stored columns. */
1125 	ut_ad(!rec_offs_any_extern(offsets));
1126 	ref_len = dict_index_get_n_unique(clust_index);
1127 
1128 	ut_ad(ref_len == dtuple_get_n_fields(ref));
1129 
1130 	dict_index_copy_types(ref, clust_index, ref_len);
1131 
1132 	for (i = 0; i < ref_len; i++) {
1133 		dfield = dtuple_get_nth_field(ref, i);
1134 
1135 		pos = dict_index_get_nth_field_pos(index, clust_index, i);
1136 
1137 		ut_a(pos != ULINT_UNDEFINED);
1138 
1139 		ut_ad(!rec_offs_nth_default(offsets, pos));
1140 		field = rec_get_nth_field(rec, offsets, pos, &len);
1141 
1142 		dfield_set_data(dfield, field, len);
1143 
1144 		/* If the primary key contains a column prefix, then the
1145 		secondary index may contain a longer prefix of the same
1146 		column, or the full column, and we must adjust the length
1147 		accordingly. */
1148 
1149 		clust_col_prefix_len = dict_index_get_nth_field(
1150 			clust_index, i)->prefix_len;
1151 
1152 		if (clust_col_prefix_len > 0) {
1153 			if (len != UNIV_SQL_NULL) {
1154 
1155 				const dtype_t*	dtype
1156 					= dfield_get_type(dfield);
1157 
1158 				dfield_set_len(dfield,
1159 					       dtype_get_at_most_n_mbchars(
1160 						       dtype->prtype,
1161 						       dtype->mbminlen,
1162 						       dtype->mbmaxlen,
1163 						       clust_col_prefix_len,
1164 						       len, (char*) field));
1165 			}
1166 		}
1167 	}
1168 
1169 	ut_ad(dtuple_check_typed(ref));
1170 	if (UNIV_LIKELY_NULL(heap)) {
1171 		mem_heap_free(heap);
1172 	}
1173 }
1174 
1175 /***************************************************************//**
1176 Searches the clustered index record for a row, if we have the row reference.
1177 @return TRUE if found */
1178 ibool
row_search_on_row_ref(btr_pcur_t * pcur,ulint mode,const dict_table_t * table,const dtuple_t * ref,mtr_t * mtr)1179 row_search_on_row_ref(
1180 /*==================*/
1181 	btr_pcur_t*		pcur,	/*!< out: persistent cursor, which must
1182 					be closed by the caller */
1183 	ulint			mode,	/*!< in: BTR_MODIFY_LEAF, ... */
1184 	const dict_table_t*	table,	/*!< in: table */
1185 	const dtuple_t*		ref,	/*!< in: row reference */
1186 	mtr_t*			mtr)	/*!< in/out: mtr */
1187 {
1188 	ulint		low_match;
1189 	rec_t*		rec;
1190 	dict_index_t*	index;
1191 
1192 	ut_ad(dtuple_check_typed(ref));
1193 
1194 	index = dict_table_get_first_index(table);
1195 
1196 	if (UNIV_UNLIKELY(ref->info_bits != 0)) {
1197 		ut_ad(ref->is_metadata());
1198 		ut_ad(ref->n_fields <= index->n_uniq);
1199 		if (btr_pcur_open_at_index_side(
1200 			    true, index, mode, pcur, true, 0, mtr)
1201 		    != DB_SUCCESS
1202 		    || !btr_pcur_move_to_next_user_rec(pcur, mtr)) {
1203 			return FALSE;
1204 		}
1205 		/* We do not necessarily have index->is_instant() here,
1206 		because we could be executing a rollback of an
1207 		instant ADD COLUMN operation. The function
1208 		rec_is_metadata() asserts index->is_instant();
1209 		we do not want to call it here. */
1210 		return rec_get_info_bits(btr_pcur_get_rec(pcur),
1211 					 dict_table_is_comp(index->table))
1212 			& REC_INFO_MIN_REC_FLAG;
1213 	} else {
1214 		ut_a(ref->n_fields == index->n_uniq);
1215 		if (btr_pcur_open(index, ref, PAGE_CUR_LE, mode, pcur, mtr)
1216 		    != DB_SUCCESS) {
1217 			return FALSE;
1218 		}
1219 	}
1220 
1221 	low_match = btr_pcur_get_low_match(pcur);
1222 
1223 	rec = btr_pcur_get_rec(pcur);
1224 
1225 	if (page_rec_is_infimum(rec)) {
1226 
1227 		return(FALSE);
1228 	}
1229 
1230 	if (low_match != dtuple_get_n_fields(ref)) {
1231 
1232 		return(FALSE);
1233 	}
1234 
1235 	return(TRUE);
1236 }
1237 
1238 /*********************************************************************//**
1239 Fetches the clustered index record for a secondary index record. The latches
1240 on the secondary index record are preserved.
1241 @return record or NULL, if no record found */
1242 rec_t*
row_get_clust_rec(ulint mode,const rec_t * rec,dict_index_t * index,dict_index_t ** clust_index,mtr_t * mtr)1243 row_get_clust_rec(
1244 /*==============*/
1245 	ulint		mode,	/*!< in: BTR_MODIFY_LEAF, ... */
1246 	const rec_t*	rec,	/*!< in: record in a secondary index */
1247 	dict_index_t*	index,	/*!< in: secondary index */
1248 	dict_index_t**	clust_index,/*!< out: clustered index */
1249 	mtr_t*		mtr)	/*!< in: mtr */
1250 {
1251 	mem_heap_t*	heap;
1252 	dtuple_t*	ref;
1253 	dict_table_t*	table;
1254 	btr_pcur_t	pcur;
1255 	ibool		found;
1256 	rec_t*		clust_rec;
1257 
1258 	ut_ad(!dict_index_is_clust(index));
1259 
1260 	table = index->table;
1261 
1262 	heap = mem_heap_create(256);
1263 
1264 	ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, heap);
1265 
1266 	found = row_search_on_row_ref(&pcur, mode, table, ref, mtr);
1267 
1268 	clust_rec = found ? btr_pcur_get_rec(&pcur) : NULL;
1269 
1270 	mem_heap_free(heap);
1271 
1272 	btr_pcur_close(&pcur);
1273 
1274 	*clust_index = dict_table_get_first_index(table);
1275 
1276 	return(clust_rec);
1277 }
1278 
1279 /***************************************************************//**
1280 Searches an index record.
1281 @return whether the record was found or buffered */
1282 enum row_search_result
row_search_index_entry(dict_index_t * index,const dtuple_t * entry,ulint mode,btr_pcur_t * pcur,mtr_t * mtr)1283 row_search_index_entry(
1284 /*===================*/
1285 	dict_index_t*	index,	/*!< in: index */
1286 	const dtuple_t*	entry,	/*!< in: index entry */
1287 	ulint		mode,	/*!< in: BTR_MODIFY_LEAF, ... */
1288 	btr_pcur_t*	pcur,	/*!< in/out: persistent cursor, which must
1289 				be closed by the caller */
1290 	mtr_t*		mtr)	/*!< in: mtr */
1291 {
1292 	ulint	n_fields;
1293 	ulint	low_match;
1294 	rec_t*	rec;
1295 
1296 	ut_ad(dtuple_check_typed(entry));
1297 
1298 	if (dict_index_is_spatial(index)) {
1299 		ut_ad(mode & BTR_MODIFY_LEAF || mode & BTR_MODIFY_TREE);
1300 		rtr_pcur_open(index, entry, PAGE_CUR_RTREE_LOCATE,
1301 			      mode, pcur, mtr);
1302 	} else {
1303 		btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
1304 	}
1305 
1306 	switch (btr_pcur_get_btr_cur(pcur)->flag) {
1307 	case BTR_CUR_DELETE_REF:
1308 		ut_a(mode & BTR_DELETE && !dict_index_is_spatial(index));
1309 		return(ROW_NOT_DELETED_REF);
1310 
1311 	case BTR_CUR_DEL_MARK_IBUF:
1312 	case BTR_CUR_DELETE_IBUF:
1313 	case BTR_CUR_INSERT_TO_IBUF:
1314 		return(ROW_BUFFERED);
1315 
1316 	case BTR_CUR_HASH:
1317 	case BTR_CUR_HASH_FAIL:
1318 	case BTR_CUR_BINARY:
1319 		break;
1320 	}
1321 
1322 	low_match = btr_pcur_get_low_match(pcur);
1323 
1324 	rec = btr_pcur_get_rec(pcur);
1325 
1326 	n_fields = dtuple_get_n_fields(entry);
1327 
1328 	if (page_rec_is_infimum(rec)) {
1329 
1330 		return(ROW_NOT_FOUND);
1331 	} else if (low_match != n_fields) {
1332 
1333 		return(ROW_NOT_FOUND);
1334 	}
1335 
1336 	return(ROW_FOUND);
1337 }
1338 
1339 /*******************************************************************//**
1340 Formats the raw data in "data" (in InnoDB on-disk format) that is of
1341 type DATA_INT using "prtype" and writes the result to "buf".
1342 If the data is in unknown format, then nothing is written to "buf",
1343 0 is returned and "format_in_hex" is set to TRUE, otherwise
1344 "format_in_hex" is left untouched.
1345 Not more than "buf_size" bytes are written to "buf".
1346 The result is always '\0'-terminated (provided buf_size > 0) and the
1347 number of bytes that were written to "buf" is returned (including the
1348 terminating '\0').
1349 @return number of bytes that were written */
1350 static
1351 ulint
row_raw_format_int(const char * data,ulint data_len,ulint prtype,char * buf,ulint buf_size,ibool * format_in_hex)1352 row_raw_format_int(
1353 /*===============*/
1354 	const char*	data,		/*!< in: raw data */
1355 	ulint		data_len,	/*!< in: raw data length
1356 					in bytes */
1357 	ulint		prtype,		/*!< in: precise type */
1358 	char*		buf,		/*!< out: output buffer */
1359 	ulint		buf_size,	/*!< in: output buffer size
1360 					in bytes */
1361 	ibool*		format_in_hex)	/*!< out: should the data be
1362 					formated in hex */
1363 {
1364 	ulint	ret;
1365 
1366 	if (data_len <= sizeof(ib_uint64_t)) {
1367 
1368 		ib_uint64_t	value;
1369 		ibool		unsigned_type = prtype & DATA_UNSIGNED;
1370 
1371 		value = mach_read_int_type(
1372 			(const byte*) data, data_len, unsigned_type);
1373 
1374 		ret = (ulint) snprintf(
1375 			buf, buf_size,
1376 			unsigned_type ? "%llu" : "%lld", (longlong) value)+1;
1377 	} else {
1378 
1379 		*format_in_hex = TRUE;
1380 		ret = 0;
1381 	}
1382 
1383 	return(ut_min(ret, buf_size));
1384 }
1385 
1386 /*******************************************************************//**
1387 Formats the raw data in "data" (in InnoDB on-disk format) that is of
1388 type DATA_(CHAR|VARCHAR|MYSQL|VARMYSQL) using "prtype" and writes the
1389 result to "buf".
1390 If the data is in binary format, then nothing is written to "buf",
1391 0 is returned and "format_in_hex" is set to TRUE, otherwise
1392 "format_in_hex" is left untouched.
1393 Not more than "buf_size" bytes are written to "buf".
1394 The result is always '\0'-terminated (provided buf_size > 0) and the
1395 number of bytes that were written to "buf" is returned (including the
1396 terminating '\0').
1397 @return number of bytes that were written */
1398 static
1399 ulint
row_raw_format_str(const char * data,ulint data_len,ulint prtype,char * buf,ulint buf_size,ibool * format_in_hex)1400 row_raw_format_str(
1401 /*===============*/
1402 	const char*	data,		/*!< in: raw data */
1403 	ulint		data_len,	/*!< in: raw data length
1404 					in bytes */
1405 	ulint		prtype,		/*!< in: precise type */
1406 	char*		buf,		/*!< out: output buffer */
1407 	ulint		buf_size,	/*!< in: output buffer size
1408 					in bytes */
1409 	ibool*		format_in_hex)	/*!< out: should the data be
1410 					formated in hex */
1411 {
1412 	ulint	charset_coll;
1413 
1414 	if (buf_size == 0) {
1415 
1416 		return(0);
1417 	}
1418 
1419 	/* we assume system_charset_info is UTF-8 */
1420 
1421 	charset_coll = dtype_get_charset_coll(prtype);
1422 
1423 	if (UNIV_LIKELY(dtype_is_utf8(prtype))) {
1424 
1425 		return(ut_str_sql_format(data, data_len, buf, buf_size));
1426 	}
1427 	/* else */
1428 
1429 	if (charset_coll == DATA_MYSQL_BINARY_CHARSET_COLL) {
1430 
1431 		*format_in_hex = TRUE;
1432 		return(0);
1433 	}
1434 	/* else */
1435 
1436 	return(innobase_raw_format(data, data_len, charset_coll,
1437 					  buf, buf_size));
1438 }
1439 
1440 /*******************************************************************//**
1441 Formats the raw data in "data" (in InnoDB on-disk format) using
1442 "dict_field" and writes the result to "buf".
1443 Not more than "buf_size" bytes are written to "buf".
1444 The result is always NUL-terminated (provided buf_size is positive) and the
1445 number of bytes that were written to "buf" is returned (including the
1446 terminating NUL).
1447 @return number of bytes that were written */
1448 ulint
row_raw_format(const char * data,ulint data_len,const dict_field_t * dict_field,char * buf,ulint buf_size)1449 row_raw_format(
1450 /*===========*/
1451 	const char*		data,		/*!< in: raw data */
1452 	ulint			data_len,	/*!< in: raw data length
1453 						in bytes */
1454 	const dict_field_t*	dict_field,	/*!< in: index field */
1455 	char*			buf,		/*!< out: output buffer */
1456 	ulint			buf_size)	/*!< in: output buffer size
1457 						in bytes */
1458 {
1459 	ulint	mtype;
1460 	ulint	prtype;
1461 	ulint	ret;
1462 	ibool	format_in_hex;
1463 
1464 	ut_ad(data_len != UNIV_SQL_DEFAULT);
1465 
1466 	if (buf_size == 0) {
1467 
1468 		return(0);
1469 	}
1470 
1471 	if (data_len == UNIV_SQL_NULL) {
1472 
1473 		ret = snprintf((char*) buf, buf_size, "NULL") + 1;
1474 
1475 		return(ut_min(ret, buf_size));
1476 	}
1477 
1478 	mtype = dict_field->col->mtype;
1479 	prtype = dict_field->col->prtype;
1480 
1481 	format_in_hex = FALSE;
1482 
1483 	switch (mtype) {
1484 	case DATA_INT:
1485 
1486 		ret = row_raw_format_int(data, data_len, prtype,
1487 					 buf, buf_size, &format_in_hex);
1488 		if (format_in_hex) {
1489 
1490 			goto format_in_hex;
1491 		}
1492 		break;
1493 	case DATA_CHAR:
1494 	case DATA_VARCHAR:
1495 	case DATA_MYSQL:
1496 	case DATA_VARMYSQL:
1497 
1498 		ret = row_raw_format_str(data, data_len, prtype,
1499 					 buf, buf_size, &format_in_hex);
1500 		if (format_in_hex) {
1501 
1502 			goto format_in_hex;
1503 		}
1504 
1505 		break;
1506 	/* XXX support more data types */
1507 	default:
1508 	format_in_hex:
1509 
1510 		if (UNIV_LIKELY(buf_size > 2)) {
1511 
1512 			memcpy(buf, "0x", 2);
1513 			buf += 2;
1514 			buf_size -= 2;
1515 			ret = 2 + ut_raw_to_hex(data, data_len,
1516 						buf, buf_size);
1517 		} else {
1518 
1519 			buf[0] = '\0';
1520 			ret = 1;
1521 		}
1522 	}
1523 
1524 	return(ret);
1525 }
1526 
1527 #ifdef UNIV_ENABLE_UNIT_TEST_ROW_RAW_FORMAT_INT
1528 
1529 #ifdef HAVE_UT_CHRONO_T
1530 
1531 void
test_row_raw_format_int()1532 test_row_raw_format_int()
1533 {
1534 	ulint	ret;
1535 	char	buf[128];
1536 	ibool	format_in_hex;
1537 	ulint	i;
1538 
1539 #define CALL_AND_TEST(data, data_len, prtype, buf, buf_size,\
1540 		      ret_expected, buf_expected, format_in_hex_expected)\
1541 	do {\
1542 		ibool	ok = TRUE;\
1543 		ulint	i;\
1544 		memset(buf, 'x', 10);\
1545 		buf[10] = '\0';\
1546 		format_in_hex = FALSE;\
1547 		fprintf(stderr, "TESTING \"\\x");\
1548 		for (i = 0; i < data_len; i++) {\
1549 			fprintf(stderr, "%02hhX", data[i]);\
1550 		}\
1551 		fprintf(stderr, "\", %lu, %lu, %lu\n",\
1552                         (ulint) data_len, (ulint) prtype,\
1553 			(ulint) buf_size);\
1554 		ret = row_raw_format_int(data, data_len, prtype,\
1555 					 buf, buf_size, &format_in_hex);\
1556 		if (ret != ret_expected) {\
1557 			fprintf(stderr, "expected ret %lu, got %lu\n",\
1558 				(ulint) ret_expected, ret);\
1559 			ok = FALSE;\
1560                 }\
1561                 if (strcmp((char*) buf, buf_expected) != 0) {\
1562                         fprintf(stderr, "expected buf \"%s\", got \"%s\"\n",\
1563                                 buf_expected, buf);\
1564                         ok = FALSE;\
1565                 }\
1566                 if (format_in_hex != format_in_hex_expected) {\
1567                         fprintf(stderr, "expected format_in_hex %d, got %d\n",\
1568                                 (int) format_in_hex_expected,\
1569 				(int) format_in_hex);\
1570                         ok = FALSE;\
1571                 }\
1572                 if (ok) {\
1573                         fprintf(stderr, "OK: %lu, \"%s\" %d\n\n",\
1574                                 (ulint) ret, buf, (int) format_in_hex);\
1575                 } else {\
1576                         return;\
1577                 }\
1578         } while (0)
1579 
1580 #if 1
1581 	/* min values for signed 1-8 byte integers */
1582 
1583 	CALL_AND_TEST("\x00", 1, 0,
1584 		      buf, sizeof(buf), 5, "-128", 0);
1585 
1586 	CALL_AND_TEST("\x00\x00", 2, 0,
1587 		      buf, sizeof(buf), 7, "-32768", 0);
1588 
1589 	CALL_AND_TEST("\x00\x00\x00", 3, 0,
1590 		      buf, sizeof(buf), 9, "-8388608", 0);
1591 
1592 	CALL_AND_TEST("\x00\x00\x00\x00", 4, 0,
1593 		      buf, sizeof(buf), 12, "-2147483648", 0);
1594 
1595 	CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, 0,
1596 		      buf, sizeof(buf), 14, "-549755813888", 0);
1597 
1598 	CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, 0,
1599 		      buf, sizeof(buf), 17, "-140737488355328", 0);
1600 
1601 	CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, 0,
1602 		      buf, sizeof(buf), 19, "-36028797018963968", 0);
1603 
1604 	CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, 0,
1605 		      buf, sizeof(buf), 21, "-9223372036854775808", 0);
1606 
1607 	/* min values for unsigned 1-8 byte integers */
1608 
1609 	CALL_AND_TEST("\x00", 1, DATA_UNSIGNED,
1610 		      buf, sizeof(buf), 2, "0", 0);
1611 
1612 	CALL_AND_TEST("\x00\x00", 2, DATA_UNSIGNED,
1613 		      buf, sizeof(buf), 2, "0", 0);
1614 
1615 	CALL_AND_TEST("\x00\x00\x00", 3, DATA_UNSIGNED,
1616 		      buf, sizeof(buf), 2, "0", 0);
1617 
1618 	CALL_AND_TEST("\x00\x00\x00\x00", 4, DATA_UNSIGNED,
1619 		      buf, sizeof(buf), 2, "0", 0);
1620 
1621 	CALL_AND_TEST("\x00\x00\x00\x00\x00", 5, DATA_UNSIGNED,
1622 		      buf, sizeof(buf), 2, "0", 0);
1623 
1624 	CALL_AND_TEST("\x00\x00\x00\x00\x00\x00", 6, DATA_UNSIGNED,
1625 		      buf, sizeof(buf), 2, "0", 0);
1626 
1627 	CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00", 7, DATA_UNSIGNED,
1628 		      buf, sizeof(buf), 2, "0", 0);
1629 
1630 	CALL_AND_TEST("\x00\x00\x00\x00\x00\x00\x00\x00", 8, DATA_UNSIGNED,
1631 		      buf, sizeof(buf), 2, "0", 0);
1632 
1633 	/* max values for signed 1-8 byte integers */
1634 
1635 	CALL_AND_TEST("\xFF", 1, 0,
1636 		      buf, sizeof(buf), 4, "127", 0);
1637 
1638 	CALL_AND_TEST("\xFF\xFF", 2, 0,
1639 		      buf, sizeof(buf), 6, "32767", 0);
1640 
1641 	CALL_AND_TEST("\xFF\xFF\xFF", 3, 0,
1642 		      buf, sizeof(buf), 8, "8388607", 0);
1643 
1644 	CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, 0,
1645 		      buf, sizeof(buf), 11, "2147483647", 0);
1646 
1647 	CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, 0,
1648 		      buf, sizeof(buf), 13, "549755813887", 0);
1649 
1650 	CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, 0,
1651 		      buf, sizeof(buf), 16, "140737488355327", 0);
1652 
1653 	CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, 0,
1654 		      buf, sizeof(buf), 18, "36028797018963967", 0);
1655 
1656 	CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, 0,
1657 		      buf, sizeof(buf), 20, "9223372036854775807", 0);
1658 
1659 	/* max values for unsigned 1-8 byte integers */
1660 
1661 	CALL_AND_TEST("\xFF", 1, DATA_UNSIGNED,
1662 		      buf, sizeof(buf), 4, "255", 0);
1663 
1664 	CALL_AND_TEST("\xFF\xFF", 2, DATA_UNSIGNED,
1665 		      buf, sizeof(buf), 6, "65535", 0);
1666 
1667 	CALL_AND_TEST("\xFF\xFF\xFF", 3, DATA_UNSIGNED,
1668 		      buf, sizeof(buf), 9, "16777215", 0);
1669 
1670 	CALL_AND_TEST("\xFF\xFF\xFF\xFF", 4, DATA_UNSIGNED,
1671 		      buf, sizeof(buf), 11, "4294967295", 0);
1672 
1673 	CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF", 5, DATA_UNSIGNED,
1674 		      buf, sizeof(buf), 14, "1099511627775", 0);
1675 
1676 	CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF", 6, DATA_UNSIGNED,
1677 		      buf, sizeof(buf), 16, "281474976710655", 0);
1678 
1679 	CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 7, DATA_UNSIGNED,
1680 		      buf, sizeof(buf), 18, "72057594037927935", 0);
1681 
1682 	CALL_AND_TEST("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8, DATA_UNSIGNED,
1683 		      buf, sizeof(buf), 21, "18446744073709551615", 0);
1684 
1685 	/* some random values */
1686 
1687 	CALL_AND_TEST("\x52", 1, 0,
1688 		      buf, sizeof(buf), 4, "-46", 0);
1689 
1690 	CALL_AND_TEST("\x0E", 1, DATA_UNSIGNED,
1691 		      buf, sizeof(buf), 3, "14", 0);
1692 
1693 	CALL_AND_TEST("\x62\xCE", 2, 0,
1694 		      buf, sizeof(buf), 6, "-7474", 0);
1695 
1696 	CALL_AND_TEST("\x29\xD6", 2, DATA_UNSIGNED,
1697 		      buf, sizeof(buf), 6, "10710", 0);
1698 
1699 	CALL_AND_TEST("\x7F\xFF\x90", 3, 0,
1700 		      buf, sizeof(buf), 5, "-112", 0);
1701 
1702 	CALL_AND_TEST("\x00\xA1\x16", 3, DATA_UNSIGNED,
1703 		      buf, sizeof(buf), 6, "41238", 0);
1704 
1705 	CALL_AND_TEST("\x7F\xFF\xFF\xF7", 4, 0,
1706 		      buf, sizeof(buf), 3, "-9", 0);
1707 
1708 	CALL_AND_TEST("\x00\x00\x00\x5C", 4, DATA_UNSIGNED,
1709 		      buf, sizeof(buf), 3, "92", 0);
1710 
1711 	CALL_AND_TEST("\x7F\xFF\xFF\xFF\xFF\xFF\xDC\x63", 8, 0,
1712 		      buf, sizeof(buf), 6, "-9117", 0);
1713 
1714 	CALL_AND_TEST("\x00\x00\x00\x00\x00\x01\x64\x62", 8, DATA_UNSIGNED,
1715 		      buf, sizeof(buf), 6, "91234", 0);
1716 #endif
1717 
1718 	/* speed test */
1719 
1720 	ut_chrono_t	ch(__func__);
1721 
1722 	for (i = 0; i < 1000000; i++) {
1723 		row_raw_format_int("\x23", 1,
1724 				   0, buf, sizeof(buf),
1725 				   &format_in_hex);
1726 		row_raw_format_int("\x23", 1,
1727 				   DATA_UNSIGNED, buf, sizeof(buf),
1728 				   &format_in_hex);
1729 
1730 		row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1731 				   0, buf, sizeof(buf),
1732 				   &format_in_hex);
1733 		row_raw_format_int("\x00\x00\x00\x00\x00\x01\x64\x62", 8,
1734 				   DATA_UNSIGNED, buf, sizeof(buf),
1735 				   &format_in_hex);
1736 	}
1737 }
1738 
1739 #endif /* HAVE_UT_CHRONO_T */
1740 
1741 #endif /* UNIV_ENABLE_UNIT_TEST_ROW_RAW_FORMAT_INT */
1742