1/*****************************************************************************
2
3Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
4Copyright (c) 2017, 2020, MariaDB Corporation.
5
6This program is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free Software
8Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program; if not, write to the Free Software Foundation, Inc.,
1651 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
17
18*****************************************************************************/
19
20/********************************************************************//**
21@file include/data0data.ic
22SQL data field and tuple
23
24Created 5/30/1994 Heikki Tuuri
25*************************************************************************/
26
27#include "ut0rnd.h"
28
29/*********************************************************************//**
30Sets the type struct of SQL data field. */
31UNIV_INLINE
32void
33dfield_set_type(
34/*============*/
35	dfield_t*	field,	/*!< in: SQL data field */
36	const dtype_t*	type)	/*!< in: pointer to data type struct */
37{
38	ut_ad(field != NULL);
39	ut_ad(type != NULL);
40
41	field->type = *type;
42}
43
44/*********************************************************************//**
45Sets length in a field. */
46UNIV_INLINE
47void
48dfield_set_len(
49/*===========*/
50	dfield_t*	field,	/*!< in: field */
51	ulint		len)	/*!< in: length or UNIV_SQL_NULL */
52{
53	ut_ad(len != UNIV_SQL_DEFAULT);
54	field->ext = 0;
55	field->len = static_cast<unsigned int>(len);
56}
57
58/** Gets spatial status for "external storage"
59@param[in,out]	field		field */
60UNIV_INLINE
61spatial_status_t
62dfield_get_spatial_status(
63	const dfield_t*	field)
64{
65	ut_ad(field);
66	ut_ad(dfield_is_ext(field));
67
68	return(static_cast<spatial_status_t>(field->spatial_status));
69}
70
71/** Sets spatial status for "external storage"
72@param[in,out]	field		field
73@param[in]	spatial_status	spatial status */
74UNIV_INLINE
75void
76dfield_set_spatial_status(
77	dfield_t*		field,
78	spatial_status_t	spatial_status)
79{
80	ut_ad(field);
81	ut_ad(dfield_is_ext(field));
82
83	field->spatial_status = spatial_status;
84}
85
86/*********************************************************************//**
87Sets pointer to the data and length in a field. */
88UNIV_INLINE
89void
90dfield_set_data(
91/*============*/
92	dfield_t*	field,	/*!< in: field */
93	const void*	data,	/*!< in: data */
94	ulint		len)	/*!< in: length or UNIV_SQL_NULL */
95{
96	field->data = (void*) data;
97	field->ext = 0;
98	field->len = static_cast<unsigned int>(len);
99}
100
101/*********************************************************************//**
102Sets pointer to the data and length in a field. */
103UNIV_INLINE
104void
105dfield_write_mbr(
106/*=============*/
107	dfield_t*	field,	/*!< in: field */
108	const double*	mbr)	/*!< in: data */
109{
110	MEM_CHECK_DEFINED(mbr, sizeof *mbr);
111	field->ext = 0;
112
113	for (unsigned i = 0; i < SPDIMS * 2; i++) {
114		mach_double_write(static_cast<byte*>(field->data)
115				  + i * sizeof(double), mbr[i]);
116	}
117
118	field->len = DATA_MBR_LEN;
119}
120
121/*********************************************************************//**
122Sets a data field to SQL NULL. */
123UNIV_INLINE
124void
125dfield_set_null(
126/*============*/
127	dfield_t*	field)	/*!< in/out: field */
128{
129	dfield_set_data(field, NULL, UNIV_SQL_NULL);
130}
131
132/*********************************************************************//**
133Copies the data and len fields. */
134UNIV_INLINE
135void
136dfield_copy_data(
137/*=============*/
138	dfield_t*	field1,	/*!< out: field to copy to */
139	const dfield_t*	field2)	/*!< in: field to copy from */
140{
141	ut_ad(field1 != NULL);
142	ut_ad(field2 != NULL);
143
144	field1->data = field2->data;
145	field1->len = field2->len;
146	field1->ext = field2->ext;
147	field1->spatial_status = field2->spatial_status;
148}
149
150/*********************************************************************//**
151Copies a data field to another. */
152UNIV_INLINE
153void
154dfield_copy(
155/*========*/
156	dfield_t*	field1,	/*!< out: field to copy to */
157	const dfield_t*	field2)	/*!< in: field to copy from */
158{
159	*field1 = *field2;
160}
161
162/*********************************************************************//**
163Copies the data pointed to by a data field. */
164UNIV_INLINE
165void
166dfield_dup(
167/*=======*/
168	dfield_t*	field,	/*!< in/out: data field */
169	mem_heap_t*	heap)	/*!< in: memory heap where allocated */
170{
171	if (!dfield_is_null(field)) {
172		MEM_CHECK_DEFINED(field->data, field->len);
173		field->data = mem_heap_dup(heap, field->data, field->len);
174	}
175}
176
177/*********************************************************************//**
178Tests if two data fields are equal.
179If len==0, tests the data length and content for equality.
180If len>0, tests the first len bytes of the content for equality.
181@return TRUE if both fields are NULL or if they are equal */
182UNIV_INLINE
183ibool
184dfield_datas_are_binary_equal(
185/*==========================*/
186	const dfield_t*	field1,	/*!< in: field */
187	const dfield_t*	field2,	/*!< in: field */
188	ulint		len)	/*!< in: maximum prefix to compare,
189				or 0 to compare the whole field length */
190{
191	ulint	len2 = len;
192
193	if (field1->len == UNIV_SQL_NULL || len == 0 || field1->len < len) {
194		len = field1->len;
195	}
196
197	if (field2->len == UNIV_SQL_NULL || len2 == 0 || field2->len < len2) {
198		len2 = field2->len;
199	}
200
201	return(len == len2
202	       && (len == UNIV_SQL_NULL
203		   || !memcmp(field1->data, field2->data, len)));
204}
205
206/*********************************************************************//**
207Tests if dfield data length and content is equal to the given.
208@return TRUE if equal */
209UNIV_INLINE
210ibool
211dfield_data_is_binary_equal(
212/*========================*/
213	const dfield_t*	field,	/*!< in: field */
214	ulint		len,	/*!< in: data length or UNIV_SQL_NULL */
215	const byte*	data)	/*!< in: data */
216{
217	ut_ad(len != UNIV_SQL_DEFAULT);
218	return(len == dfield_get_len(field)
219	       && (!len || len == UNIV_SQL_NULL
220		   || !memcmp(dfield_get_data(field), data, len)));
221}
222
223/*********************************************************************//**
224Gets info bits in a data tuple.
225@return info bits */
226UNIV_INLINE
227ulint
228dtuple_get_info_bits(
229/*=================*/
230	const dtuple_t*	tuple)	/*!< in: tuple */
231{
232	return(tuple->info_bits);
233}
234
235/*********************************************************************//**
236Sets info bits in a data tuple. */
237UNIV_INLINE
238void
239dtuple_set_info_bits(
240/*=================*/
241	dtuple_t*	tuple,		/*!< in: tuple */
242	ulint		info_bits)	/*!< in: info bits */
243{
244	tuple->info_bits = info_bits;
245}
246
247/*********************************************************************//**
248Gets number of fields used in record comparisons.
249@return number of fields used in comparisons in rem0cmp.* */
250UNIV_INLINE
251ulint
252dtuple_get_n_fields_cmp(
253/*====================*/
254	const dtuple_t*	tuple)	/*!< in: tuple */
255{
256	return(tuple->n_fields_cmp);
257}
258
259/*********************************************************************//**
260Sets number of fields used in record comparisons. */
261UNIV_INLINE
262void
263dtuple_set_n_fields_cmp(
264/*====================*/
265	dtuple_t*	tuple,		/*!< in: tuple */
266	ulint		n_fields_cmp)	/*!< in: number of fields used in
267					comparisons in rem0cmp.* */
268{
269	ut_ad(n_fields_cmp <= tuple->n_fields);
270	tuple->n_fields_cmp = n_fields_cmp;
271}
272
273/** Creates a data tuple from an already allocated chunk of memory.
274The size of the chunk must be at least DTUPLE_EST_ALLOC(n_fields).
275The default value for number of fields used in record comparisons
276for this tuple is n_fields.
277@param[in,out]	buf		buffer to use
278@param[in]	buf_size	buffer size
279@param[in]	n_fields	number of field
280@param[in]	n_v_fields	number of fields on virtual columns
281@return created tuple (inside buf) */
282UNIV_INLINE
283dtuple_t*
284dtuple_create_from_mem(
285	void*	buf,
286	ulint	buf_size,
287	ulint	n_fields,
288	ulint	n_v_fields)
289{
290	dtuple_t*	tuple;
291	ulint		n_t_fields = n_fields + n_v_fields;
292
293	ut_a(buf_size >= DTUPLE_EST_ALLOC(n_t_fields));
294
295	tuple = (dtuple_t*) buf;
296	tuple->info_bits = 0;
297	tuple->n_fields = n_fields;
298	tuple->n_v_fields = n_v_fields;
299	tuple->n_fields_cmp = n_fields;
300	tuple->fields = (dfield_t*) &tuple[1];
301	if (n_v_fields > 0) {
302		tuple->v_fields = &tuple->fields[n_fields];
303	} else {
304		tuple->v_fields = NULL;
305	}
306
307#ifdef UNIV_DEBUG
308	tuple->magic_n = DATA_TUPLE_MAGIC_N;
309
310	{	/* In the debug version, initialize fields to an error value */
311		ulint	i;
312
313		for (i = 0; i < n_t_fields; i++) {
314			dfield_t*       field;
315
316			if (i >= n_fields) {
317				field = dtuple_get_nth_v_field(
318					tuple, i - n_fields);
319			} else {
320				field = dtuple_get_nth_field(tuple, i);
321			}
322
323			dfield_set_len(field, UNIV_SQL_NULL);
324			field->data = &data_error;
325			dfield_get_type(field)->mtype = DATA_ERROR;
326			dfield_get_type(field)->prtype = DATA_ERROR;
327		}
328	}
329#endif
330	MEM_CHECK_ADDRESSABLE(tuple->fields, n_t_fields
331			      * sizeof *tuple->fields);
332	MEM_UNDEFINED(tuple->fields, n_t_fields * sizeof *tuple->fields);
333	return(tuple);
334}
335
336/** Duplicate the virtual field data in a dtuple_t
337@param[in,out]		vrow	dtuple contains the virtual fields
338@param[in,out]		heap	heap memory to use */
339UNIV_INLINE
340void
341dtuple_dup_v_fld(dtuple_t* vrow, mem_heap_t* heap)
342{
343	for (ulint i = 0; i < vrow->n_v_fields; i++) {
344		dfield_t*       dfield = dtuple_get_nth_v_field(vrow, i);
345		dfield_dup(dfield, heap);
346	}
347}
348
349/** Initialize the virtual field data in a dtuple_t
350@param[in,out]		vrow	dtuple contains the virtual fields */
351UNIV_INLINE
352void
353dtuple_init_v_fld(dtuple_t* vrow)
354{
355	for (ulint i = 0; i < vrow->n_v_fields; i++) {
356		dfield_t*       dfield = dtuple_get_nth_v_field(vrow, i);
357		dfield_get_type(dfield)->mtype = DATA_MISSING;
358		dfield_set_len(dfield, UNIV_SQL_NULL);
359	}
360}
361
362/**********************************************************//**
363Creates a data tuple to a memory heap. The default value for number
364of fields used in record comparisons for this tuple is n_fields.
365@return own: created tuple */
366UNIV_INLINE
367dtuple_t*
368dtuple_create(
369/*==========*/
370	mem_heap_t*	heap,	/*!< in: memory heap where the tuple
371				is created, DTUPLE_EST_ALLOC(n_fields)
372				bytes will be allocated from this heap */
373	ulint		n_fields) /*!< in: number of fields */
374{
375	return(dtuple_create_with_vcol(heap, n_fields, 0));
376}
377
378/** Creates a data tuple with virtual columns to a memory heap.
379@param[in]	heap		memory heap where the tuple is created
380@param[in]	n_fields	number of fields
381@param[in]	n_v_fields	number of fields on virtual col
382@return own: created tuple */
383UNIV_INLINE
384dtuple_t*
385dtuple_create_with_vcol(
386	mem_heap_t*	heap,
387	ulint		n_fields,
388	ulint		n_v_fields)
389{
390	void*		buf;
391	ulint		buf_size;
392	dtuple_t*	tuple;
393
394	ut_ad(heap);
395
396	buf_size = DTUPLE_EST_ALLOC(n_fields + n_v_fields);
397	buf = mem_heap_alloc(heap, buf_size);
398
399	tuple = dtuple_create_from_mem(buf, buf_size, n_fields, n_v_fields);
400
401	return(tuple);
402}
403
404/** Copies a data tuple's virtual fields to another. This is a shallow copy;
405@param[in,out]	d_tuple		destination tuple
406@param[in]	s_tuple		source tuple */
407UNIV_INLINE
408void
409dtuple_copy_v_fields(
410	dtuple_t*	d_tuple,
411	const dtuple_t*	s_tuple)
412{
413
414	ulint		n_v_fields	= dtuple_get_n_v_fields(d_tuple);
415	ut_ad(n_v_fields == dtuple_get_n_v_fields(s_tuple));
416
417	for (ulint i = 0; i < n_v_fields; i++) {
418		dfield_copy(dtuple_get_nth_v_field(d_tuple, i),
419			    dtuple_get_nth_v_field(s_tuple, i));
420	}
421}
422
423/*********************************************************************//**
424Copies a data tuple to another.  This is a shallow copy; if a deep copy
425is desired, dfield_dup() will have to be invoked on each field.
426@return own: copy of tuple */
427UNIV_INLINE
428dtuple_t*
429dtuple_copy(
430/*========*/
431	const dtuple_t*	tuple,	/*!< in: tuple to copy from */
432	mem_heap_t*	heap)	/*!< in: memory heap
433				where the tuple is created */
434{
435	ulint		n_fields	= dtuple_get_n_fields(tuple);
436	ulint		n_v_fields	= dtuple_get_n_v_fields(tuple);
437	dtuple_t*	new_tuple	= dtuple_create_with_vcol(
438						heap, n_fields, n_v_fields);
439	ulint		i;
440
441	for (i = 0; i < n_fields; i++) {
442		dfield_copy(dtuple_get_nth_field(new_tuple, i),
443			    dtuple_get_nth_field(tuple, i));
444	}
445
446	for (i = 0; i < n_v_fields; i++) {
447		dfield_copy(dtuple_get_nth_v_field(new_tuple, i),
448			    dtuple_get_nth_v_field(tuple, i));
449	}
450
451	return(new_tuple);
452}
453
454/**********************************************************//**
455The following function returns the sum of data lengths of a tuple. The space
456occupied by the field structs or the tuple struct is not counted. Neither
457is possible space in externally stored parts of the field.
458@return sum of data lengths */
459UNIV_INLINE
460ulint
461dtuple_get_data_size(
462/*=================*/
463	const dtuple_t*	tuple,	/*!< in: typed data tuple */
464	ulint		comp)	/*!< in: nonzero=ROW_FORMAT=COMPACT  */
465{
466	const dfield_t*	field;
467	ulint		n_fields;
468	ulint		len;
469	ulint		i;
470	ulint		sum	= 0;
471
472	ut_ad(dtuple_check_typed(tuple));
473	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
474
475	n_fields = tuple->n_fields;
476
477	for (i = 0; i < n_fields; i++) {
478		field = dtuple_get_nth_field(tuple,  i);
479		len = dfield_get_len(field);
480
481		if (len == UNIV_SQL_NULL) {
482			len = dtype_get_sql_null_size(dfield_get_type(field),
483						      comp);
484		}
485
486		sum += len;
487	}
488
489	return(sum);
490}
491
492/*********************************************************************//**
493Computes the number of externally stored fields in a data tuple.
494@return number of externally stored fields */
495UNIV_INLINE
496ulint
497dtuple_get_n_ext(
498/*=============*/
499	const dtuple_t*	tuple)	/*!< in: tuple */
500{
501	ulint	n_ext		= 0;
502	ulint	n_fields	= tuple->n_fields;
503	ulint	i;
504
505	ut_ad(dtuple_check_typed(tuple));
506	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
507
508	for (i = 0; i < n_fields; i++) {
509		n_ext += dtuple_get_nth_field(tuple, i)->ext;
510	}
511
512	return(n_ext);
513}
514
515/*******************************************************************//**
516Sets types of fields binary in a tuple. */
517UNIV_INLINE
518void
519dtuple_set_types_binary(
520/*====================*/
521	dtuple_t*	tuple,	/*!< in: data tuple */
522	ulint		n)	/*!< in: number of fields to set */
523{
524	dtype_t*	dfield_type;
525	ulint		i;
526
527	for (i = 0; i < n; i++) {
528		dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
529		dtype_set(dfield_type, DATA_BINARY, 0, 0);
530	}
531}
532
533/** Fold a prefix given as the number of fields of a tuple.
534@param[in]	tuple		index record
535@param[in]	n_fields	number of complete fields to fold
536@param[in]	n_bytes		number of bytes to fold in the last field
537@param[in]	index_id	index tree ID
538@return the folded value */
539UNIV_INLINE
540ulint
541dtuple_fold(
542	const dtuple_t*	tuple,
543	ulint		n_fields,
544	ulint		n_bytes,
545	index_id_t	tree_id)
546{
547	const dfield_t*	field;
548	ulint		i;
549	const byte*	data;
550	ulint		len;
551	ulint		fold;
552
553	ut_ad(tuple);
554	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
555	ut_ad(dtuple_check_typed(tuple));
556
557	fold = ut_fold_ull(tree_id);
558
559	for (i = 0; i < n_fields; i++) {
560		field = dtuple_get_nth_field(tuple, i);
561
562		data = (const byte*) dfield_get_data(field);
563		len = dfield_get_len(field);
564
565		if (len != UNIV_SQL_NULL) {
566			fold = ut_fold_ulint_pair(fold,
567						  ut_fold_binary(data, len));
568		}
569	}
570
571	if (n_bytes > 0) {
572		field = dtuple_get_nth_field(tuple, i);
573
574		data = (const byte*) dfield_get_data(field);
575		len = dfield_get_len(field);
576
577		if (len != UNIV_SQL_NULL) {
578			if (len > n_bytes) {
579				len = n_bytes;
580			}
581
582			fold = ut_fold_ulint_pair(fold,
583						  ut_fold_binary(data, len));
584		}
585	}
586
587	return(fold);
588}
589
590/**********************************************************************//**
591Writes an SQL null field full of zeros. */
592UNIV_INLINE
593void
594data_write_sql_null(
595/*================*/
596	byte*	data,	/*!< in: pointer to a buffer of size len */
597	ulint	len)	/*!< in: SQL null size in bytes */
598{
599	memset(data, 0, len);
600}
601
602/**********************************************************************//**
603Checks if a dtuple contains an SQL null value.
604@return TRUE if some field is SQL null */
605UNIV_INLINE
606ibool
607dtuple_contains_null(
608/*=================*/
609	const dtuple_t*	tuple)	/*!< in: dtuple */
610{
611	ulint	n;
612	ulint	i;
613
614	n = dtuple_get_n_fields(tuple);
615
616	for (i = 0; i < n; i++) {
617		if (dfield_is_null(dtuple_get_nth_field(tuple, i))) {
618
619			return(TRUE);
620		}
621	}
622
623	return(FALSE);
624}
625
626/**************************************************************//**
627Frees the memory in a big rec vector. */
628UNIV_INLINE
629void
630dtuple_big_rec_free(
631/*================*/
632	big_rec_t*	vector)	/*!< in, own: big rec vector; it is
633				freed in this function */
634{
635	mem_heap_free(vector->heap);
636}
637