1/*****************************************************************************
2
3Copyright (c) 1994, 2021, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License, version 2.0,
7as published by the Free Software Foundation.
8
9This program is also distributed with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation.  The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have included with MySQL.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU General Public License, version 2.0, for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25*****************************************************************************/
26
27/********************************************************************//**
28@file include/data0data.ic
29SQL data field and tuple
30
31Created 5/30/1994 Heikki Tuuri
32*************************************************************************/
33
34#include "mem0mem.h"
35#include "ut0rnd.h"
36#include "btr0types.h"
37
38#ifdef UNIV_DEBUG
39/** Dummy variable to catch access to uninitialized fields.  In the
40debug version, dtuple_create() will make all fields of dtuple_t point
41to data_error. */
42extern byte data_error;
43
44/*********************************************************************//**
45Gets pointer to the type struct of SQL data field.
46@return pointer to the type struct */
47UNIV_INLINE
48dtype_t*
49dfield_get_type(
50/*============*/
51	const dfield_t*	field)	/*!< in: SQL data field */
52{
53	ut_ad(field);
54
55	return((dtype_t*) &(field->type));
56}
57#endif /* UNIV_DEBUG */
58
59/*********************************************************************//**
60Sets the type struct of SQL data field. */
61UNIV_INLINE
62void
63dfield_set_type(
64/*============*/
65	dfield_t*	field,	/*!< in: SQL data field */
66	const dtype_t*	type)	/*!< in: pointer to data type struct */
67{
68	ut_ad(field != NULL);
69	ut_ad(type != NULL);
70
71	field->type = *type;
72}
73
74#ifdef UNIV_DEBUG
75/*********************************************************************//**
76Gets pointer to the data in a field.
77@return pointer to data */
78UNIV_INLINE
79void*
80dfield_get_data(
81/*============*/
82	const dfield_t* field)	/*!< in: field */
83{
84	ut_ad(field);
85	ut_ad((field->len == UNIV_SQL_NULL)
86	      || (field->data != &data_error));
87
88	return((void*) field->data);
89}
90#endif /* UNIV_DEBUG */
91
92/*********************************************************************//**
93Gets length of field data.
94@return length of data; UNIV_SQL_NULL if SQL null data */
95UNIV_INLINE
96ulint
97dfield_get_len(
98/*===========*/
99	const dfield_t*	field)	/*!< in: field */
100{
101	ut_ad(field);
102	ut_ad((field->len == UNIV_SQL_NULL)
103	      || (field->data != &data_error));
104
105	return(field->len);
106}
107
108/*********************************************************************//**
109Sets length in a field. */
110UNIV_INLINE
111void
112dfield_set_len(
113/*===========*/
114	dfield_t*	field,	/*!< in: field */
115	ulint		len)	/*!< in: length or UNIV_SQL_NULL */
116{
117	ut_ad(field);
118#ifdef UNIV_VALGRIND_DEBUG
119	if (len != UNIV_SQL_NULL) UNIV_MEM_ASSERT_RW(field->data, len);
120#endif /* UNIV_VALGRIND_DEBUG */
121
122	field->ext = 0;
123	field->len = static_cast<unsigned int>(len);
124}
125
126/*********************************************************************//**
127Determines if a field is SQL NULL
128@return nonzero if SQL null data */
129UNIV_INLINE
130ulint
131dfield_is_null(
132/*===========*/
133	const dfield_t* field)	/*!< in: field */
134{
135	ut_ad(field);
136
137	return(field->len == UNIV_SQL_NULL);
138}
139
140/*********************************************************************//**
141Determines if a field is externally stored
142@return nonzero if externally stored */
143UNIV_INLINE
144ulint
145dfield_is_ext(
146/*==========*/
147	const dfield_t* field)	/*!< in: field */
148{
149	ut_ad(field);
150	ut_ad(!field->ext || field->len >= BTR_EXTERN_FIELD_REF_SIZE);
151
152	return(field->ext);
153}
154
155/*********************************************************************//**
156Sets the "external storage" flag */
157UNIV_INLINE
158void
159dfield_set_ext(
160/*===========*/
161	dfield_t*	field)	/*!< in/out: field */
162{
163	ut_ad(field);
164
165	field->ext = 1;
166}
167
168/** Gets spatial status for "external storage"
169@param[in,out]	field		field */
170UNIV_INLINE
171spatial_status_t
172dfield_get_spatial_status(
173	const dfield_t*	field)
174{
175	ut_ad(field);
176	ut_ad(dfield_is_ext(field));
177
178	return(static_cast<spatial_status_t>(field->spatial_status));
179}
180
181/** Sets spatial status for "external storage"
182@param[in,out]	field		field
183@param[in]	spatial_status	spatial status */
184UNIV_INLINE
185void
186dfield_set_spatial_status(
187	dfield_t*		field,
188	spatial_status_t	spatial_status)
189{
190	ut_ad(field);
191	ut_ad(dfield_is_ext(field));
192
193	field->spatial_status = spatial_status;
194}
195
196/*********************************************************************//**
197Sets pointer to the data and length in a field. */
198UNIV_INLINE
199void
200dfield_set_data(
201/*============*/
202	dfield_t*	field,	/*!< in: field */
203	const void*	data,	/*!< in: data */
204	ulint		len)	/*!< in: length or UNIV_SQL_NULL */
205{
206	ut_ad(field);
207
208#ifdef UNIV_VALGRIND_DEBUG
209	if (len != UNIV_SQL_NULL) UNIV_MEM_ASSERT_RW(data, len);
210#endif /* UNIV_VALGRIND_DEBUG */
211	field->data = (void*) data;
212	field->ext = 0;
213	field->len = static_cast<unsigned int>(len);
214}
215
216/*********************************************************************//**
217Sets pointer to the data and length in a field. */
218UNIV_INLINE
219void
220dfield_write_mbr(
221/*=============*/
222	dfield_t*	field,	/*!< in: field */
223	const double*	mbr)	/*!< in: data */
224{
225	ut_ad(field);
226
227#ifdef UNIV_VALGRIND_DEBUG
228	if (len != UNIV_SQL_NULL) UNIV_MEM_ASSERT_RW(data, len);
229#endif /* UNIV_VALGRIND_DEBUG */
230	field->ext = 0;
231
232	for (int i = 0; i < SPDIMS * 2; i++) {
233		mach_double_write(static_cast<byte*>(field->data)
234				  + i * sizeof(double), mbr[i]);
235	}
236
237	field->len = DATA_MBR_LEN;
238}
239
240/*********************************************************************//**
241Sets a data field to SQL NULL. */
242UNIV_INLINE
243void
244dfield_set_null(
245/*============*/
246	dfield_t*	field)	/*!< in/out: field */
247{
248	dfield_set_data(field, NULL, UNIV_SQL_NULL);
249}
250
251/*********************************************************************//**
252Copies the data and len fields. */
253UNIV_INLINE
254void
255dfield_copy_data(
256/*=============*/
257	dfield_t*	field1,	/*!< out: field to copy to */
258	const dfield_t*	field2)	/*!< in: field to copy from */
259{
260	ut_ad(field1 != NULL);
261	ut_ad(field2 != NULL);
262
263	field1->data = field2->data;
264	field1->len = field2->len;
265	field1->ext = field2->ext;
266	field1->spatial_status = field2->spatial_status;
267}
268
269/*********************************************************************//**
270Copies a data field to another. */
271UNIV_INLINE
272void
273dfield_copy(
274/*========*/
275	dfield_t*	field1,	/*!< out: field to copy to */
276	const dfield_t*	field2)	/*!< in: field to copy from */
277{
278	*field1 = *field2;
279}
280
281/*********************************************************************//**
282Copies the data pointed to by a data field. */
283UNIV_INLINE
284void
285dfield_dup(
286/*=======*/
287	dfield_t*	field,	/*!< in/out: data field */
288	mem_heap_t*	heap)	/*!< in: memory heap where allocated */
289{
290	if (!dfield_is_null(field)) {
291		UNIV_MEM_ASSERT_RW(field->data, field->len);
292		field->data = mem_heap_dup(heap, field->data, field->len);
293	}
294}
295
296#ifndef UNIV_HOTBACKUP
297/*********************************************************************//**
298Tests if two data fields are equal.
299If len==0, tests the data length and content for equality.
300If len>0, tests the first len bytes of the content for equality.
301@return TRUE if both fields are NULL or if they are equal */
302UNIV_INLINE
303ibool
304dfield_datas_are_binary_equal(
305/*==========================*/
306	const dfield_t*	field1,	/*!< in: field */
307	const dfield_t*	field2,	/*!< in: field */
308	ulint		len)	/*!< in: maximum prefix to compare,
309				or 0 to compare the whole field length */
310{
311	ulint	len2 = len;
312
313	if (field1->len == UNIV_SQL_NULL || len == 0 || field1->len < len) {
314		len = field1->len;
315	}
316
317	if (field2->len == UNIV_SQL_NULL || len2 == 0 || field2->len < len2) {
318		len2 = field2->len;
319	}
320
321	return(len == len2
322	       && (len == UNIV_SQL_NULL
323		   || !memcmp(field1->data, field2->data, len)));
324}
325
326/*********************************************************************//**
327Tests if dfield data length and content is equal to the given.
328@return TRUE if equal */
329UNIV_INLINE
330ibool
331dfield_data_is_binary_equal(
332/*========================*/
333	const dfield_t*	field,	/*!< in: field */
334	ulint		len,	/*!< in: data length or UNIV_SQL_NULL */
335	const byte*	data)	/*!< in: data */
336{
337	return(len == dfield_get_len(field)
338	       && (len == UNIV_SQL_NULL
339		   || !memcmp(dfield_get_data(field), data, len)));
340}
341#endif /* !UNIV_HOTBACKUP */
342
343/*********************************************************************//**
344Gets info bits in a data tuple.
345@return info bits */
346UNIV_INLINE
347ulint
348dtuple_get_info_bits(
349/*=================*/
350	const dtuple_t*	tuple)	/*!< in: tuple */
351{
352	ut_ad(tuple);
353
354	return(tuple->info_bits);
355}
356
357/*********************************************************************//**
358Sets info bits in a data tuple. */
359UNIV_INLINE
360void
361dtuple_set_info_bits(
362/*=================*/
363	dtuple_t*	tuple,		/*!< in: tuple */
364	ulint		info_bits)	/*!< in: info bits */
365{
366	ut_ad(tuple);
367
368	tuple->info_bits = info_bits;
369}
370
371/*********************************************************************//**
372Gets number of fields used in record comparisons.
373@return number of fields used in comparisons in rem0cmp.* */
374UNIV_INLINE
375ulint
376dtuple_get_n_fields_cmp(
377/*====================*/
378	const dtuple_t*	tuple)	/*!< in: tuple */
379{
380	ut_ad(tuple);
381
382	return(tuple->n_fields_cmp);
383}
384
385/*********************************************************************//**
386Sets number of fields used in record comparisons. */
387UNIV_INLINE
388void
389dtuple_set_n_fields_cmp(
390/*====================*/
391	dtuple_t*	tuple,		/*!< in: tuple */
392	ulint		n_fields_cmp)	/*!< in: number of fields used in
393					comparisons in rem0cmp.* */
394{
395	ut_ad(tuple);
396	ut_ad(n_fields_cmp <= tuple->n_fields);
397
398	tuple->n_fields_cmp = n_fields_cmp;
399}
400
401/*********************************************************************//**
402Gets number of fields in a data tuple.
403@return number of fields */
404UNIV_INLINE
405ulint
406dtuple_get_n_fields(
407/*================*/
408	const dtuple_t*	tuple)	/*!< in: tuple */
409{
410	ut_ad(tuple);
411
412	return(tuple->n_fields);
413}
414
415/** Gets the number of virtual fields in a data tuple.
416@param[in]	tuple	dtuple to check
417@return number of fields */
418UNIV_INLINE
419ulint
420dtuple_get_n_v_fields(
421	const dtuple_t*	tuple)
422{
423	ut_ad(tuple);
424
425	return(tuple->n_v_fields);
426}
427#ifdef UNIV_DEBUG
428/** Gets nth field of a tuple.
429@param[in]	tuple	tuple
430@param[in]	n	index of field
431@return nth field */
432UNIV_INLINE
433dfield_t*
434dtuple_get_nth_field(
435	const dtuple_t*	tuple,
436	ulint		n)
437{
438	ut_ad(tuple);
439	ut_ad(n < tuple->n_fields);
440
441	return((dfield_t*) tuple->fields + n);
442}
443/** Gets nth virtual field of a tuple.
444@param[in]	tuple	tuple
445@oaran[in]	n	the nth field to get
446@return nth field */
447UNIV_INLINE
448dfield_t*
449dtuple_get_nth_v_field(
450	const dtuple_t*	tuple,
451	ulint		n)
452{
453	ut_ad(tuple);
454	ut_ad(n < tuple->n_v_fields);
455
456	return(static_cast<dfield_t*>(tuple->v_fields + n));
457}
458#endif /* UNIV_DEBUG */
459
460/** Creates a data tuple from an already allocated chunk of memory.
461The size of the chunk must be at least DTUPLE_EST_ALLOC(n_fields).
462The default value for number of fields used in record comparisons
463for this tuple is n_fields.
464@param[in,out]	buf		buffer to use
465@param[in]	buf_size	buffer size
466@param[in]	n_fields	number of field
467@param[in]	n_v_fields	number of fields on virtual columns
468@return created tuple (inside buf) */
469UNIV_INLINE
470dtuple_t*
471dtuple_create_from_mem(
472	void*	buf,
473	ulint	buf_size,
474	ulint	n_fields,
475	ulint	n_v_fields)
476{
477	dtuple_t*	tuple;
478	ulint		n_t_fields = n_fields + n_v_fields;
479
480	ut_ad(buf != NULL);
481	ut_a(buf_size >= DTUPLE_EST_ALLOC(n_t_fields));
482
483	tuple = (dtuple_t*) buf;
484	tuple->info_bits = 0;
485	tuple->n_fields = n_fields;
486	tuple->n_v_fields = n_v_fields;
487	tuple->n_fields_cmp = n_fields;
488	tuple->fields = (dfield_t*) &tuple[1];
489	if (n_v_fields > 0) {
490		tuple->v_fields = &tuple->fields[n_fields];
491	} else {
492		tuple->v_fields = NULL;
493	}
494
495#ifdef UNIV_DEBUG
496	tuple->magic_n = DATA_TUPLE_MAGIC_N;
497
498	{	/* In the debug version, initialize fields to an error value */
499		ulint	i;
500
501		for (i = 0; i < n_t_fields; i++) {
502			dfield_t*       field;
503
504			if (i >= n_fields) {
505				field = dtuple_get_nth_v_field(
506					tuple, i - n_fields);
507			} else {
508				field = dtuple_get_nth_field(tuple, i);
509			}
510
511			dfield_set_len(field, UNIV_SQL_NULL);
512			field->data = &data_error;
513			dfield_get_type(field)->mtype = DATA_ERROR;
514			dfield_get_type(field)->prtype = DATA_ERROR;
515		}
516	}
517#endif
518	UNIV_MEM_ASSERT_W(tuple->fields, n_t_fields * sizeof *tuple->fields);
519	UNIV_MEM_INVALID(tuple->fields, n_t_fields * sizeof *tuple->fields);
520	return(tuple);
521}
522
523/** Duplicate the virtual field data in a dtuple_t
524@param[in,out]		vrow	dtuple contains the virtual fields
525@param[in]		heap	heap memory to use */
526UNIV_INLINE
527void
528dtuple_dup_v_fld(
529	const dtuple_t*	vrow,
530	mem_heap_t*	heap)
531{
532	for (ulint i = 0; i < vrow->n_v_fields; i++) {
533		dfield_t*       dfield = dtuple_get_nth_v_field(vrow, i);
534		dfield_dup(dfield, heap);
535	}
536}
537
538/** Initialize the virtual field data in a dtuple_t
539@param[in,out]		vrow	dtuple contains the virtual fields */
540UNIV_INLINE
541void
542dtuple_init_v_fld(
543	const dtuple_t*	vrow)
544{
545	for (ulint i = 0; i < vrow->n_v_fields; i++) {
546		dfield_t*       dfield = dtuple_get_nth_v_field(vrow, i);
547		dfield_get_type(dfield)->mtype = DATA_MISSING;
548		dfield_set_len(dfield, UNIV_SQL_NULL);
549	}
550}
551
552/**********************************************************//**
553Creates a data tuple to a memory heap. The default value for number
554of fields used in record comparisons for this tuple is n_fields.
555@return own: created tuple */
556UNIV_INLINE
557dtuple_t*
558dtuple_create(
559/*==========*/
560	mem_heap_t*	heap,	/*!< in: memory heap where the tuple
561				is created, DTUPLE_EST_ALLOC(n_fields)
562				bytes will be allocated from this heap */
563	ulint		n_fields) /*!< in: number of fields */
564{
565	return(dtuple_create_with_vcol(heap, n_fields, 0));
566}
567
568/** Creates a data tuple with virtual columns to a memory heap.
569@param[in]	heap		memory heap where the tuple is created
570@param[in]	n_fields	number of fields
571@param[in]	n_v_fields	number of fields on virtual col
572@return own: created tuple */
573UNIV_INLINE
574dtuple_t*
575dtuple_create_with_vcol(
576	mem_heap_t*	heap,
577	ulint		n_fields,
578	ulint		n_v_fields)
579{
580	void*		buf;
581	ulint		buf_size;
582	dtuple_t*	tuple;
583
584	ut_ad(heap);
585
586	buf_size = DTUPLE_EST_ALLOC(n_fields + n_v_fields);
587	buf = mem_heap_alloc(heap, buf_size);
588
589	tuple = dtuple_create_from_mem(buf, buf_size, n_fields, n_v_fields);
590
591#ifdef UNIV_DEBUG
592	tuple->m_heap = heap;
593#endif /* UNIV_DEBUG */
594	return(tuple);
595}
596
597/** Copies a data tuple's virtual fields to another. This is a shallow copy;
598@param[in,out]	d_tuple		destination tuple
599@param[in]	s_tuple		source tuple */
600UNIV_INLINE
601void
602dtuple_copy_v_fields(
603	dtuple_t*	d_tuple,
604	const dtuple_t*	s_tuple)
605{
606
607	ulint		n_v_fields	= dtuple_get_n_v_fields(d_tuple);
608	ut_ad(n_v_fields == dtuple_get_n_v_fields(s_tuple));
609
610	for (ulint i = 0; i < n_v_fields; i++) {
611		dfield_copy(dtuple_get_nth_v_field(d_tuple, i),
612			    dtuple_get_nth_v_field(s_tuple, i));
613	}
614}
615
616/*********************************************************************//**
617Copies a data tuple to another.  This is a shallow copy; if a deep copy
618is desired, dfield_dup() will have to be invoked on each field.
619@return own: copy of tuple */
620UNIV_INLINE
621dtuple_t*
622dtuple_copy(
623/*========*/
624	const dtuple_t*	tuple,	/*!< in: tuple to copy from */
625	mem_heap_t*	heap)	/*!< in: memory heap
626				where the tuple is created */
627{
628	ulint		n_fields	= dtuple_get_n_fields(tuple);
629	ulint		n_v_fields	= dtuple_get_n_v_fields(tuple);
630	dtuple_t*	new_tuple	= dtuple_create_with_vcol(
631						heap, n_fields, n_v_fields);
632	ulint		i;
633
634	for (i = 0; i < n_fields; i++) {
635		dfield_copy(dtuple_get_nth_field(new_tuple, i),
636			    dtuple_get_nth_field(tuple, i));
637	}
638
639	for (i = 0; i < n_v_fields; i++) {
640		dfield_copy(dtuple_get_nth_v_field(new_tuple, i),
641			    dtuple_get_nth_v_field(tuple, i));
642	}
643
644	return(new_tuple);
645}
646
647/**********************************************************//**
648The following function returns the sum of data lengths of a tuple. The space
649occupied by the field structs or the tuple struct is not counted. Neither
650is possible space in externally stored parts of the field.
651@return sum of data lengths */
652UNIV_INLINE
653ulint
654dtuple_get_data_size(
655/*=================*/
656	const dtuple_t*	tuple,	/*!< in: typed data tuple */
657	ulint		comp)	/*!< in: nonzero=ROW_FORMAT=COMPACT  */
658{
659	const dfield_t*	field;
660	ulint		n_fields;
661	ulint		len;
662	ulint		i;
663	ulint		sum	= 0;
664
665	ut_ad(tuple);
666	ut_ad(dtuple_check_typed(tuple));
667	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
668
669	n_fields = tuple->n_fields;
670
671	for (i = 0; i < n_fields; i++) {
672		field = dtuple_get_nth_field(tuple,  i);
673		len = dfield_get_len(field);
674
675		if (len == UNIV_SQL_NULL) {
676			len = dtype_get_sql_null_size(dfield_get_type(field),
677						      comp);
678		}
679
680		sum += len;
681	}
682
683	return(sum);
684}
685
686/*********************************************************************//**
687Computes the number of externally stored fields in a data tuple.
688@return number of externally stored fields */
689UNIV_INLINE
690ulint
691dtuple_get_n_ext(
692/*=============*/
693	const dtuple_t*	tuple)	/*!< in: tuple */
694{
695	ulint	n_ext		= 0;
696	ulint	n_fields	= tuple->n_fields;
697	ulint	i;
698
699	ut_ad(tuple);
700	ut_ad(dtuple_check_typed(tuple));
701	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
702
703	for (i = 0; i < n_fields; i++) {
704		n_ext += dtuple_get_nth_field(tuple, i)->ext;
705	}
706
707	return(n_ext);
708}
709
710/*******************************************************************//**
711Sets types of fields binary in a tuple. */
712UNIV_INLINE
713void
714dtuple_set_types_binary(
715/*====================*/
716	dtuple_t*	tuple,	/*!< in: data tuple */
717	ulint		n)	/*!< in: number of fields to set */
718{
719	dtype_t*	dfield_type;
720	ulint		i;
721
722	for (i = 0; i < n; i++) {
723		dfield_type = dfield_get_type(dtuple_get_nth_field(tuple, i));
724		dtype_set(dfield_type, DATA_BINARY, 0, 0);
725	}
726}
727
728/** Fold a prefix given as the number of fields of a tuple.
729@param[in]	tuple		index record
730@param[in]	n_fields	number of complete fields to fold
731@param[in]	n_bytes		number of bytes to fold in the last field
732@param[in]	index_id	index tree ID
733@return the folded value */
734UNIV_INLINE
735ulint
736dtuple_fold(
737	const dtuple_t*	tuple,
738	ulint		n_fields,
739	ulint		n_bytes,
740	index_id_t	tree_id)
741{
742	const dfield_t*	field;
743	ulint		i;
744	const byte*	data;
745	ulint		len;
746	ulint		fold;
747
748	ut_ad(tuple);
749	ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
750	ut_ad(dtuple_check_typed(tuple));
751
752	fold = ut_fold_ull(tree_id);
753
754	for (i = 0; i < n_fields; i++) {
755		field = dtuple_get_nth_field(tuple, i);
756
757		data = (const byte*) dfield_get_data(field);
758		len = dfield_get_len(field);
759
760		if (len != UNIV_SQL_NULL) {
761			fold = ut_fold_ulint_pair(fold,
762						  ut_fold_binary(data, len));
763		}
764	}
765
766	if (n_bytes > 0) {
767		field = dtuple_get_nth_field(tuple, i);
768
769		data = (const byte*) dfield_get_data(field);
770		len = dfield_get_len(field);
771
772		if (len != UNIV_SQL_NULL) {
773			if (len > n_bytes) {
774				len = n_bytes;
775			}
776
777			fold = ut_fold_ulint_pair(fold,
778						  ut_fold_binary(data, len));
779		}
780	}
781
782	return(fold);
783}
784
785/**********************************************************************//**
786Writes an SQL null field full of zeros. */
787UNIV_INLINE
788void
789data_write_sql_null(
790/*================*/
791	byte*	data,	/*!< in: pointer to a buffer of size len */
792	ulint	len)	/*!< in: SQL null size in bytes */
793{
794	memset(data, 0, len);
795}
796
797/**********************************************************************//**
798Checks if a dtuple contains an SQL null value.
799@return TRUE if some field is SQL null */
800UNIV_INLINE
801ibool
802dtuple_contains_null(
803/*=================*/
804	const dtuple_t*	tuple)	/*!< in: dtuple */
805{
806	ulint	n;
807	ulint	i;
808
809	n = dtuple_get_n_fields(tuple);
810
811	for (i = 0; i < n; i++) {
812		if (dfield_is_null(dtuple_get_nth_field(tuple, i))) {
813
814			return(TRUE);
815		}
816	}
817
818	return(FALSE);
819}
820
821/**************************************************************//**
822Frees the memory in a big rec vector. */
823UNIV_INLINE
824void
825dtuple_big_rec_free(
826/*================*/
827	big_rec_t*	vector)	/*!< in, own: big rec vector; it is
828				freed in this function */
829{
830	mem_heap_free(vector->heap);
831}
832