MySQL 8.1.0
Source Code Documentation
data0data.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 1994, 2023, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
8
9This program is also distributed with certain software (including but not
10limited to OpenSSL) that is licensed under separate terms, as designated in a
11particular file or component or in included license documentation. The authors
12of MySQL hereby grant you an additional permission to link the program and
13your derivative works with the separately licensed software that they have
14included with MySQL.
15
16This program is distributed in the hope that it will be useful, but WITHOUT
17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19for 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 St, Fifth Floor, Boston, MA 02110-1301 USA
24
25*****************************************************************************/
26
27/** @file include/data0data.h
28 SQL data field and tuple
29
30 Created 5/30/1994 Heikki Tuuri
31 *************************************************************************/
32
33#ifndef data0data_h
34#define data0data_h
35
36#include "univ.i"
37
38#include "data0type.h"
39#include "data0types.h"
40#include "dict0types.h"
41#include "mem0mem.h"
42#include "trx0types.h"
43#include "ut0bitset.h"
44
45#include <ostream>
46
47/** Storage for overflow data in a big record, that is, a clustered
48index record which needs external storage of data fields */
49struct big_rec_t;
50struct upd_t;
51
52#ifdef UNIV_DEBUG
53/** Gets pointer to the type struct of SQL data field.
54 @return pointer to the type struct */
55[[nodiscard]] static inline dtype_t *dfield_get_type(
56 const dfield_t *field); /*!< in: SQL data field */
57/** Gets pointer to the data in a field.
58 @return pointer to data */
59[[nodiscard]] static inline void *dfield_get_data(
60 const dfield_t *field); /*!< in: field */
61#else /* UNIV_DEBUG */
62#define dfield_get_type(field) (&(field)->type)
63#define dfield_get_data(field) ((field)->data)
64#endif /* UNIV_DEBUG */
65
66/** Sets the type struct of SQL data field.
67@param[in] field SQL data field
68@param[in] type pointer to data type struct */
69static inline void dfield_set_type(dfield_t *field, const dtype_t *type);
70
71/** Gets length of field data.
72 @return length of data; UNIV_SQL_NULL if SQL null data */
73[[nodiscard]] static inline uint32_t dfield_get_len(
74 const dfield_t *field); /*!< in: field */
75
76/** Sets length in a field.
77@param[in] field field
78@param[in] len length or UNIV_SQL_NULL */
79static inline void dfield_set_len(dfield_t *field, ulint len);
80
81/** Determines if a field is SQL NULL
82 @return nonzero if SQL null data */
83[[nodiscard]] static inline ulint dfield_is_null(
84 const dfield_t *field); /*!< in: field */
85/** Determines if a field is externally stored
86 @return nonzero if externally stored */
87[[nodiscard]] static inline bool dfield_is_ext(
88 const dfield_t *field); /*!< in: field */
89/** Sets the "external storage" flag */
90static inline void dfield_set_ext(dfield_t *field); /*!< in/out: field */
91
92/** Gets spatial status for "external storage"
93@param[in,out] field field */
95
96/** Sets spatial status for "external storage"
97@param[in,out] field field
98@param[in] spatial_status spatial status */
99static inline void dfield_set_spatial_status(dfield_t *field,
100 spatial_status_t spatial_status);
101
102/** Sets pointer to the data and length in a field.
103@param[in] field field
104@param[in] data data
105@param[in] len length or UNIV_SQL_NULL */
106static inline void dfield_set_data(dfield_t *field, const void *data,
107 ulint len);
108
109/** Sets pointer to the data and length in a field.
110@param[in] field field
111@param[in] mbr data */
112static inline void dfield_write_mbr(dfield_t *field, const double *mbr);
113
114/** Sets a data field to SQL NULL. */
115static inline void dfield_set_null(dfield_t *field); /*!< in/out: field */
116
117/** Writes an SQL null field full of zeros.
118@param[in] data pointer to a buffer of size len
119@param[in] len SQL null size in bytes */
120static inline void data_write_sql_null(byte *data, ulint len);
121
122/** Copies the data and len fields.
123@param[out] field1 field to copy to
124@param[in] field2 field to copy from */
125static inline void dfield_copy_data(dfield_t *field1, const dfield_t *field2);
126
127/** Copies a data field to another.
128@param[out] field1 field to copy to
129@param[in] field2 field to copy from */
130static inline void dfield_copy(dfield_t *field1, const dfield_t *field2);
131
132/** Copies the data pointed to by a data field.
133@param[in,out] field data field
134@param[in] heap memory heap where allocated */
135static inline void dfield_dup(dfield_t *field, mem_heap_t *heap);
136
137/** Copies the data pointed to by a data field.
138This function works for multi-value fields only.
139@param[in,out] field data field
140@param[in] heap memory heap where allocated */
141static inline void dfield_multi_value_dup(dfield_t *field, mem_heap_t *heap);
142
143/** Determine if a field is of multi-value type
144@param[in] field data field
145@return true if multi-value type field, otherwise false */
146static inline bool dfield_is_multi_value(const dfield_t *field);
147
148/** Tests if two data fields are equal.
149If len==0, tests the data length and content for equality.
150If len>0, tests the first len bytes of the content for equality.
151@param[in] field1 first field to compare
152@param[in] field2 second field to compare
153@param[in] len maximum prefix to compare,
154 or 0 to compare the whole field length.
155 This works only if !multi_val
156@return true if both fields are NULL or if they are equal */
157[[nodiscard]] inline bool dfield_datas_are_binary_equal(const dfield_t *field1,
158 const dfield_t *field2,
159 ulint len);
160/** Tests if dfield data length and content is equal to the given.
161@param[in] field Field
162@param[in] len Data length or UNIV_SQL_NULL
163@param[in] data Data
164@return true if equal */
165[[nodiscard]] static inline bool dfield_data_is_binary_equal(
166 const dfield_t *field, ulint len, const byte *data);
167/** Gets number of fields in a data tuple.
168 @return number of fields */
169[[nodiscard]] static inline ulint dtuple_get_n_fields(
170 const dtuple_t *tuple); /*!< in: tuple */
171
172/** Gets number of virtual fields in a data tuple.
173@param[in] tuple dtuple to check
174@return number of fields */
175static inline ulint dtuple_get_n_v_fields(const dtuple_t *tuple);
176
177#ifdef UNIV_DEBUG
178/** Gets nth field of a tuple.
179@param[in] tuple tuple
180@param[in] n index of field
181@return nth field */
182static inline dfield_t *dtuple_get_nth_field(const dtuple_t *tuple, ulint n);
183
184/** Gets nth virtual field of a tuple.
185@param[in] tuple tuple
186@param[in] n the nth field to get
187@return nth field */
188static inline dfield_t *dtuple_get_nth_v_field(const dtuple_t *tuple, ulint n);
189
190#else /* UNIV_DEBUG */
191#define dtuple_get_nth_field(tuple, n) ((tuple)->fields + (n))
192#define dtuple_get_nth_v_field(tuple, n) \
193 ((tuple)->fields + (tuple)->n_fields + (n))
194#endif /* UNIV_DEBUG */
195/** Gets info bits in a data tuple.
196 @return info bits */
197[[nodiscard]] static inline ulint dtuple_get_info_bits(
198 const dtuple_t *tuple); /*!< in: tuple */
199
200/** Sets info bits in a data tuple.
201@param[in] tuple tuple
202@param[in] info_bits info bits */
203static inline void dtuple_set_info_bits(dtuple_t *tuple, ulint info_bits);
204
205/** Gets number of fields used in record comparisons.
206 @return number of fields used in comparisons in rem0cmp.* */
207[[nodiscard]] static inline ulint dtuple_get_n_fields_cmp(
208 const dtuple_t *tuple); /*!< in: tuple */
209
210/** Gets number of fields used in record comparisons.
211@param[in] tuple tuple
212@param[in] n_fields_cmp number of fields used in comparisons in
213 rem0cmp */
214static inline void dtuple_set_n_fields_cmp(dtuple_t *tuple, ulint n_fields_cmp);
215
216/* Estimate the number of bytes that are going to be allocated when
217creating a new dtuple_t object */
218#define DTUPLE_EST_ALLOC(n_fields) \
219 (sizeof(dtuple_t) + (n_fields) * sizeof(dfield_t))
220
221/** Creates a data tuple from an already allocated chunk of memory.
222 The size of the chunk must be at least DTUPLE_EST_ALLOC(n_fields).
223 The default value for number of fields used in record comparisons
224 for this tuple is n_fields.
225 @param[in,out] buf buffer to use
226 @param[in] buf_size buffer size
227 @param[in] n_fields number of field
228 @param[in] n_v_fields number of fields on virtual columns
229 @return created tuple (inside buf) */
230[[nodiscard]] static inline dtuple_t *dtuple_create_from_mem(void *buf,
233 ulint n_v_fields);
234/** Creates a data tuple to a memory heap. The default value for number
235 of fields used in record comparisons for this tuple is n_fields.
236 @return own: created tuple */
237static inline dtuple_t *dtuple_create(
238 mem_heap_t *heap, /*!< in: memory heap where the tuple
239 is created, DTUPLE_EST_ALLOC(n_fields)
240 bytes will be allocated from this heap */
241 ulint n_fields) /*!< in: number of fields */
242 MY_ATTRIBUTE((malloc));
243
244/** Initialize the virtual field data in a dtuple_t
245@param[in,out] vrow dtuple contains the virtual fields */
246static inline void dtuple_init_v_fld(const dtuple_t *vrow);
247
248/** Duplicate the virtual field data in a dtuple_t
249@param[in,out] vrow dtuple contains the virtual fields
250@param[in] heap heap memory to use */
251static inline void dtuple_dup_v_fld(const dtuple_t *vrow, mem_heap_t *heap);
252
253/** Creates a data tuple with possible virtual columns to a memory heap.
254@param[in] heap memory heap where the tuple is created
255@param[in] n_fields number of fields
256@param[in] n_v_fields number of fields on virtual col
257@return own: created tuple */
260 ulint n_v_fields);
261/** Sets number of fields used in a tuple. Normally this is set in
262dtuple_create, but if you want later to set it smaller, you can use this.
263@param[in] tuple Tuple.
264@param[in] n_fields Number of fields. */
266
267/** Copies a data tuple's virtual fields to another. This is a shallow copy;
268@param[in,out] d_tuple destination tuple
269@param[in] s_tuple source tuple */
270static inline void dtuple_copy_v_fields(dtuple_t *d_tuple,
271 const dtuple_t *s_tuple);
272/** Copies a data tuple to another. This is a shallow copy; if a deep copy
273 is desired, dfield_dup() will have to be invoked on each field.
274 @return own: copy of tuple */
275static inline dtuple_t *dtuple_copy(
276 const dtuple_t *tuple, /*!< in: tuple to copy from */
277 mem_heap_t *heap) /*!< in: memory heap
278 where the tuple is created */
279 MY_ATTRIBUTE((malloc));
280
281/** The following function returns the sum of data lengths of a tuple. The space
282occupied by the field structs or the tuple struct is not counted.
283@param[in] tuple typed data tuple
284@param[in] comp nonzero=ROW_FORMAT=COMPACT
285@return sum of data lens */
286static inline ulint dtuple_get_data_size(const dtuple_t *tuple, ulint comp);
287/** Compare two data tuples.
288@param[in] tuple1 first data tuple
289@param[in] tuple2 second data tuple
290@return whether tuple1==tuple2 */
291[[nodiscard]] bool dtuple_coll_eq(const dtuple_t *tuple1,
292 const dtuple_t *tuple2);
293
294/** Compute a hash value of a prefix of an index record.
295@param[in] tuple index record
296@param[in] n_fields number of fields to include
297@param[in] n_bytes number of bytes to hash in the last field
298@param[in] hash_value hash value of the index identifier
299@return the hashed value */
300[[nodiscard]] static inline uint64_t dtuple_hash(const dtuple_t *tuple,
301 ulint n_fields, ulint n_bytes,
302 uint64_t hash_value);
303
304/** Sets types of fields binary in a tuple.
305@param[in] tuple data tuple
306@param[in] n number of fields to set */
307static inline void dtuple_set_types_binary(dtuple_t *tuple, ulint n);
308
309/** Checks if a dtuple contains an SQL null value.
310 @return true if some field is SQL null */
311[[nodiscard]] static inline bool dtuple_contains_null(
312 const dtuple_t *tuple); /*!< in: dtuple */
313/** Checks that a data field is typed. Asserts an error if not.
314 @return true if ok */
315[[nodiscard]] bool dfield_check_typed(
316 const dfield_t *field); /*!< in: data field */
317/** Checks that a data tuple is typed. Asserts an error if not.
318 @return true if ok */
319[[nodiscard]] bool dtuple_check_typed(const dtuple_t *tuple); /*!< in: tuple */
320#ifdef UNIV_DEBUG
321/** Validates the consistency of a tuple which must be complete, i.e,
322 all fields must have been set.
323 @return true if ok */
324[[nodiscard]] bool dtuple_validate(const dtuple_t *tuple); /*!< in: tuple */
325#endif /* UNIV_DEBUG */
326/** Pretty prints a dfield value according to its data type. Also the hex string
327 is printed if a string contains non-printable characters. */
328void dfield_print_also_hex(const dfield_t *dfield); /*!< in: dfield */
329
330/** The following function prints the contents of a tuple.
331@param[in,out] f Output stream.
332@param[in] tuple Tuple to print. */
333void dtuple_print(FILE *f, const dtuple_t *tuple);
334
335/** Print the contents of a tuple.
336@param[out] o output stream
337@param[in] field array of data fields
338@param[in] n number of data fields */
339void dfield_print(std::ostream &o, const dfield_t *field, ulint n);
340
341/** Print the contents of a tuple.
342@param[out] o output stream
343@param[in] tuple data tuple */
344void dtuple_print(std::ostream &o, const dtuple_t *tuple);
345
346/** Print the contents of a tuple.
347@param[out] o output stream
348@param[in] tuple data tuple */
349inline std::ostream &operator<<(std::ostream &o, const dtuple_t &tuple) {
350 dtuple_print(o, &tuple);
351 return (o);
352}
353
354/** Moves parts of long fields in entry to the big record vector so that
355the size of tuple drops below the maximum record size allowed in the
356database. Moves data only from those fields which are not necessary
357to determine uniquely the insertion place of the tuple in the index.
358@param[in,out] index Index that owns the record.
359@param[in,out] upd Update vector.
360@param[in,out] entry Index entry.
361@return own: created big record vector, NULL if we are not able to
362shorten the entry enough, i.e., if there are too many fixed-length or
363short fields in entry or the index is clustered */
364[[nodiscard]] big_rec_t *dtuple_convert_big_rec(dict_index_t *index, upd_t *upd,
366 MY_ATTRIBUTE((malloc));
367
368/** Puts back to entry the data stored in vector. Note that to ensure the
369fields in entry can accommodate the data, vector must have been created
370from entry with dtuple_convert_big_rec.
371@param[in] entry Entry whose data was put to vector.
372@param[in] vector Big rec vector; it is freed in this function*/
374
375/** Frees the memory in a big rec vector. */
376static inline void dtuple_big_rec_free(
377 big_rec_t *vector); /*!< in, own: big rec vector; it is
378 freed in this function */
379
380/*######################################################################*/
381
382/** Structure to hold number of multiple values */
384 public:
385 /** points to different value */
386 const void **datap;
387
388 /** each individual value length */
389 uint32_t *data_len;
390
391 /** convert buffer if the data is an integer */
392 uint64_t *conv_buf;
393
394 /** number of values */
395 uint32_t num_v;
396
397 /** number of pointers allocated */
398 uint32_t num_alc;
399
400 /** Bitset to indicate which data should be handled for current data
401 array. This is mainly used for UPDATE case. UPDATE may not need
402 to delete all old values and insert all new values because there could
403 be some same values in both old and new data array.
404 If current data array is for INSERT and DELETE, this can(should) be
405 nullptr since all values in current array should be handled in these
406 two cases. */
408
409 /** Allocate specified number of elements for all arrays and initialize
410 the structure accordingly
411 @param[in] num number of elements to allocate
412 @param[in] bitset true if memory for bitset should be
413 allocated too
414 @param[in,out] heap memory heap */
415 void alloc(uint32_t num, bool bitset, mem_heap_t *heap);
416
417 /** Allocate the bitset for current data array
418 @param[in,out] heap memory heap
419 @param[in] size size of the bitset, if 0 or default,
420 the size would be num_v */
421 void alloc_bitset(mem_heap_t *heap, uint32_t size = 0);
422
423 /** Check if two multi_value_data are equal or not, regardless of bitset
424 @param[in] multi_value Another multi-value data to be compared
425 @return true if two data structures are equal, otherwise false */
426 bool equal(const multi_value_data *multi_value) const {
427 if (num_v != multi_value->num_v) {
428 return (false);
429 }
430
431 for (uint32_t i = 0; i < num_v; ++i) {
432 if (data_len[i] != multi_value->data_len[i] ||
433 memcmp(datap[i], multi_value->datap[i], data_len[i]) != 0) {
434 return (false);
435 }
436 }
437
438 return (true);
439 }
440
441 /** Copy a multi_value_data structure
442 @param[in] multi_value multi_value structure to copy from
443 @param[in,out] heap memory heap */
444 void copy(const multi_value_data *multi_value, mem_heap_t *heap) {
445 if (num_alc < multi_value->num_v) {
446 alloc(multi_value->num_v, (multi_value->bitset != nullptr), heap);
447 }
448
449 copy_low(multi_value, heap);
450 }
451
452 /** Compare and check if one value from dfield_t is in current data set.
453 Any caller calls this function to check if one field from clustered index
454 is equal to a record on multi-value index should understand that this
455 function can only be used for equality comparison, rather than order
456 comparison
457 @param[in] type type of the data
458 @param[in] data data value to compare
459 @param[in] len length of data
460 @return true if the value exists in current data set, otherwise false */
461 bool has(const dtype_t *type, const byte *data, uint64_t len) const;
462
463 /** Compare and check if one value from dfield_t is in current data set.
464 Any caller calls this function to check if one field from clustered index
465 is equal to a record on multi-value index should understand that this
466 function can only be used for equality comparison, rather than order
467 comparison
468 @param[in] mtype mtype of data
469 @param[in] prtype prtype of data
470 @param[in] data data value to compare
471 @param[in] len length of data
472 @return true if the value exists in current data set, otherwise false */
473 bool has(ulint mtype, ulint prtype, const byte *data, uint64_t len) const;
474
475#ifdef UNIV_DEBUG
476 /* Check if there is any duplicate data in this array.
477 It is safe to assume all the data has been sorted.
478 @return true if duplicate data found, otherwise false */
479 bool duplicate() const {
480 /* Since the array is guaranteed to be sorted, so it is fine to
481 scan it sequentially and only compare current one with previous one
482 if exists. */
483 if (num_v > 1) {
484 for (uint32_t i = 1; i < num_v; ++i) {
485 if (data_len[i] == data_len[i - 1] &&
486 memcmp(datap[i], datap[i - 1], data_len[i]) == 0) {
487 return (true);
488 }
489 }
490 }
491 return (false);
492 }
493#endif /* UNIV_DEBUG */
494
495 private:
496 /** Copy a multi_value_data structure, current one should be bigger
497 or equal to the one to be copied
498 @param[in] multi_value multi_value structure to copy from
499 @param[in,out] heap memory heap */
500 void copy_low(const multi_value_data *multi_value, mem_heap_t *heap) {
501 ut_ad(num_alc >= multi_value->num_v);
502 for (uint32_t i = 0; i < multi_value->num_v; ++i) {
503 datap[i] =
504 mem_heap_dup(heap, multi_value->datap[i], multi_value->data_len[i]);
505 }
506 memcpy(data_len, multi_value->data_len,
507 sizeof(*data_len) * multi_value->num_v);
508 memcpy(conv_buf, multi_value->conv_buf,
509 sizeof(*conv_buf) * multi_value->num_v);
510 if (multi_value->bitset != nullptr) {
511 ut_ad(bitset != nullptr);
512 *bitset = *multi_value->bitset;
513 }
514 num_v = multi_value->num_v;
515 }
516
517 public:
518 /** default number of multiple values */
519 static constexpr uint32_t s_default_allocate_num = 24;
520};
521
522/** Class to log the multi-value data and read it from the log */
524 public:
525 /** Constructor
526 @param[in] mv_data multi-value data structure to log
527 @param[in] field_len multi-value data field length */
528 Multi_value_logger(const multi_value_data *mv_data, uint32_t field_len)
529 : m_mv_data(mv_data), m_field_len(field_len) {}
530
531 /** Get the log length for the multi-value data
532 @param[in] precise true if precise length is needed, false if rough
533 estimation is OK
534 @return the total log length for the multi-value data */
535 uint32_t get_log_len(bool precise) const;
536
537 /** Log the multi-value data to specified memory
538 @param[in,out] ptr the memory to write
539 @return next to the end of the multi-value data log */
540 byte *log(byte **ptr);
541
542 /** Read the log length for the multi-value data log starting from ptr
543 @param[in] ptr log starting from here
544 @return the length of this log */
545 static uint32_t read_log_len(const byte *ptr);
546
547 /** Read the multi-value data from the ptr
548 @param[in] ptr log starting from here
549 @param[in,out] field multi-value data field to store the array
550 @param[in,out] heap memory heap
551 @return next to the end of the multi-value data log */
552 static const byte *read(const byte *ptr, dfield_t *field, mem_heap_t *heap);
553
554 /** Estimate how many multi-value keys at most can be accommodated into the
555 log of specified size.
556 @param[in] log_size max log size
557 @param[in] key_length max multi-value key length, charset considered
558 @param[out] num_keys max possible number of multi-value keys
559 @return the total size of the keys, let's assume all keys are concatenated
560 one by one compactly */
561 static uint32_t get_keys_capacity(uint32_t log_size, uint32_t key_length,
562 uint32_t *num_keys);
563
564 /** Determine if the log starting from ptr is for multi-value data
565 @return true if it is for multi-value data, otherwise false */
566 static bool is_multi_value_log(const byte *ptr) {
568 }
569
570 private:
571 /** Multi-value data */
573
574 /** Multi-value field length */
575 uint32_t m_field_len;
576
577 /** Length of log for NULL value or no indexed value cases */
578 static constexpr uint32_t s_log_length_for_null_or_empty = 2;
579
580 /** Multi-value virtual column length marker. With this length marker,
581 a multi-value virtual column undo log can be identified. Meanwhile, this
582 marker should/will not conflict with any normal compressed written length
583 leading byte */
584 static constexpr uint8_t s_multi_value_virtual_col_length_marker = 0xFF;
585
586 /** Multi-value virtual column length, which indicates that there is
587 no value on the multi-value index. It's mapped to UNIV_NO_INDEX_VALUE */
588 static constexpr uint16_t s_multi_value_no_index_value = 0x0;
589
590 /** Multi-value virtual column length, which indicates that the field
591 is NULL. It's mapped to UNIV_SQL_NULL. Since any not NULL and not no value
592 multi-value data must be longer than 1 byte, so this is safe for this
593 special meaning */
594 static constexpr uint16_t s_multi_value_null = 0x1;
595
596 /** The compressed length for multi-value key length logging.
597 This would not be longer than 2 bytes for now, while 2 bytes can
598 actually support key length of 16384 bytes. And the actual key
599 length would never be longer than this */
600 static constexpr uint8_t s_max_compressed_mv_key_length_size = 2;
601};
602
603/** Structure for an SQL data field */
604struct dfield_t {
605 void *data; /*!< pointer to data */
606 bool ext; /*!< true=externally stored, false=local */
607 unsigned spatial_status : 2;
608 /*!< spatial status of externally stored field
609 in undo log for purge */
610 unsigned len; /*!< data length; UNIV_SQL_NULL if SQL null */
611 dtype_t type; /*!< type of data */
612
613 bool is_virtual() const { return (type.is_virtual()); }
614
615 void reset() {
616 data = nullptr;
617 ext = false;
619 }
620
621 /** Create a deep copy of this object
622 @param[in] heap the memory heap in which the clone will be
623 created.
624 @return the cloned object. */
625 dfield_t *clone(mem_heap_t *heap);
626
627 byte *blobref() const;
628
629 /** Obtain the LOB version number, if this is an externally
630 stored field. */
631 uint32_t lob_version() const;
632
634 : data(nullptr), ext(0), spatial_status(0), len(0), type({0, 0, 0, 0}) {}
635
636 /** Print the dfield_t object into the given output stream.
637 @param[in] out the output stream.
638 @return the output stream. */
639 std::ostream &print(std::ostream &out) const;
640
641 /** Adjust and(or) set virtual column value which is read from undo
642 or online DDL log
643 @param[in] vcol virtual column definition
644 @param[in] comp true if compact format
645 @param[in] field virtual column value
646 @param[in] len value length
647 @param[in,out] heap memory heap to keep value when necessary */
648 void adjust_v_data_mysql(const dict_v_col_t *vcol, bool comp,
649 const byte *field, ulint len, mem_heap_t *heap);
650};
651
652/** Compare a multi-value clustered index field with a secondary index
653field, to see if they are equal. If the clustered index field is the
654array, then equal means it contains the secondary index field
655@param[in] clust_field clustered index field
656@param[in] clust_len clustered index field length
657@param[in] sec_field secondary index field
658@param[in] sec_len secondary index field length
659@param[in] col the column tied to this field
660@return true if they are equal, otherwise false */
661bool is_multi_value_clust_and_sec_equal(const byte *clust_field,
662 uint64_t clust_len,
663 const byte *sec_field, uint64_t sec_len,
664 const dict_col_t *col);
665
666/** Overloading the global output operator to easily print the given dfield_t
667object into the given output stream.
668@param[in] out the output stream
669@param[in] obj the given object to print.
670@return the output stream. */
671inline std::ostream &operator<<(std::ostream &out, const dfield_t &obj) {
672 return (obj.print(out));
673}
674
675#ifdef UNIV_DEBUG
676/** Value of dtuple_t::magic_n */
677constexpr uint32_t DATA_TUPLE_MAGIC_N = 65478679;
678#endif
679
680/** Structure for an SQL data tuple of fields (logical record) */
681struct dtuple_t {
682 /** info bits of an index record: the default is 0; this field is used if an
683 index record is built from a data tuple */
684 uint16_t info_bits;
685
686 /** Number of fields in dtuple */
687 uint16_t n_fields;
688
689 /** number of fields which should be used in comparison services of rem0cmp.*;
690 the index search is performed by comparing only these fields, others are
691 ignored; the default value in dtuple creation is the same value as n_fields */
692 uint16_t n_fields_cmp;
693
694 /** Fields. */
696
697 /** Number of virtual fields. */
698 uint16_t n_v_fields;
699
700 /** Fields on virtual column */
702
703 /** Data tuples can be linked into a list using this field */
705
706#ifdef UNIV_DEBUG
707 /** Memory heap where this tuple is allocated. */
709
710 /** Value of dtuple_t::magic_n */
711 static constexpr size_t MAGIC_N = 614679;
712
713 /** Magic number, used in debug assertions */
715#endif /* UNIV_DEBUG */
716
717 /** Print the tuple to the output stream.
718 @param[in,out] out Stream to output to.
719 @return stream */
720 std::ostream &print(std::ostream &out) const {
721 dtuple_print(out, this);
722 return out;
723 }
724
725 /** Read the trx id from the tuple (DB_TRX_ID)
726 @return transaction id of the tuple. */
727 trx_id_t get_trx_id() const;
728
729 /** Ignore at most n trailing default fields if this is a tuple
730 from instant index
731 @param[in] index clustered index object for this tuple */
732 void ignore_trailing_default(const dict_index_t *index);
733
734 /** Compare a data tuple to a physical record.
735 @param[in] rec record
736 @param[in] index index
737 @param[in] offsets rec_get_offsets(rec)
738 @param[in,out] matched_fields number of completely matched fields
739 @return the comparison result of dtuple and rec
740 @retval 0 if dtuple is equal to rec
741 @retval negative if dtuple is less than rec
742 @retval positive if dtuple is greater than rec */
743 int compare(const rec_t *rec, const dict_index_t *index, const ulint *offsets,
744 ulint *matched_fields) const;
745
746 /** Compare a data tuple to a physical record.
747 @param[in] rec record
748 @param[in] index index
749 @param[in] offsets rec_get_offsets(rec)
750 @return the comparison result of dtuple and rec
751 @retval 0 if dtuple is equal to rec
752 @retval negative if dtuple is less than rec
753 @retval positive if dtuple is greater than rec */
754 inline int compare(const rec_t *rec, const dict_index_t *index,
755 const ulint *offsets) const {
756 ulint matched_fields{};
757
758 return (compare(rec, index, offsets, &matched_fields));
759 }
760
761 /** Get number of externally stored fields.
762 @retval number of externally stored fields. */
763 inline size_t get_n_ext() const {
764 size_t n_ext = 0;
765 for (uint32_t i = 0; i < n_fields; ++i) {
766 if (dfield_is_ext(&fields[i])) {
767 ++n_ext;
768 }
769 }
770 return n_ext;
771 }
772
773 /** Does tuple has externally stored fields.
774 @retval true if there is externally stored fields. */
775 inline bool has_ext() const {
776 for (uint32_t i = 0; i < n_fields; ++i) {
777 if (dfield_is_ext(&fields[i])) {
778 return true;
779 }
780 }
781 return false;
782 }
783};
784
785/** A slot for a field in a big rec vector */
787 /** Constructor.
788 @param[in] field_no_ the field number
789 @param[in] len_ the data length
790 @param[in] data_ the data */
791 big_rec_field_t(ulint field_no_, ulint len_, void *data_)
792 : field_no(field_no_),
793 len(len_),
794 data(data_),
795 ext_in_old(false),
796 ext_in_new(false) {}
797
798 byte *ptr() const { return (static_cast<byte *>(data)); }
799
800 ulint field_no; /*!< field number in record */
801 ulint len; /*!< stored data length, in bytes */
802 void *data; /*!< stored data */
803
804 /** If true, this field was stored externally in the old row.
805 If false, this field was stored inline in the old row.*/
807
808 /** If true, this field is stored externally in the new row.
809 If false, this field is stored inline in the new row.*/
811
812 /** Print the big_rec_field_t object into the given output stream.
813 @param[in] out the output stream.
814 @return the output stream. */
815 std::ostream &print(std::ostream &out) const;
816};
817
818/** Overloading the global output operator to easily print the given
819big_rec_field_t object into the given output stream.
820@param[in] out the output stream
821@param[in] obj the given object to print.
822@return the output stream. */
823inline std::ostream &operator<<(std::ostream &out, const big_rec_field_t &obj) {
824 return (obj.print(out));
825}
826
827/** Storage format for overflow data in a big record, that is, a
828clustered index record which needs external storage of data fields */
829struct big_rec_t {
830 mem_heap_t *heap; /*!< memory heap from which
831 allocated */
832 const ulint capacity; /*!< fields array size */
833 ulint n_fields; /*!< number of stored fields */
834 big_rec_field_t *fields; /*!< stored fields */
835
836 /** Constructor.
837 @param[in] max the capacity of the array of fields. */
838 explicit big_rec_t(const ulint max)
839 : heap(nullptr), capacity(max), n_fields(0), fields(nullptr) {}
840
841 /** Append one big_rec_field_t object to the end of array of fields */
842 void append(const big_rec_field_t &field) {
844 fields[n_fields] = field;
845 n_fields++;
846 }
847
848 /** Allocate a big_rec_t object in the given memory heap, and for
849 storing n_fld number of fields.
850 @param[in] heap memory heap in which this object is allocated
851 @param[in] n_fld maximum number of fields that can be stored in
852 this object
853 @return the allocated object */
854 static big_rec_t *alloc(mem_heap_t *heap, ulint n_fld);
855
856 /** Print the current object into the given output stream.
857 @param[in] out the output stream.
858 @return the output stream. */
859 std::ostream &print(std::ostream &out) const;
860};
861
862/** Overloading the global output operator to easily print the given
863big_rec_t object into the given output stream.
864@param[in] out the output stream
865@param[in] obj the given object to print.
866@return the output stream. */
867inline std::ostream &operator<<(std::ostream &out, const big_rec_t &obj) {
868 return (obj.print(out));
869}
870
871#include "data0data.ic"
872
873#endif
A simple bitset wrapper class, whose size can be specified after the object has been defined.
Definition: ut0bitset.h:38
Class to log the multi-value data and read it from the log.
Definition: data0data.h:523
Multi_value_logger(const multi_value_data *mv_data, uint32_t field_len)
Constructor.
Definition: data0data.h:528
static uint32_t read_log_len(const byte *ptr)
Read the log length for the multi-value data log starting from ptr.
Definition: data0data.cc:968
static constexpr uint16_t s_multi_value_no_index_value
Multi-value virtual column length, which indicates that there is no value on the multi-value index.
Definition: data0data.h:588
static constexpr uint32_t s_log_length_for_null_or_empty
Length of log for NULL value or no indexed value cases.
Definition: data0data.h:578
static bool is_multi_value_log(const byte *ptr)
Determine if the log starting from ptr is for multi-value data.
Definition: data0data.h:566
const multi_value_data * m_mv_data
Multi-value data.
Definition: data0data.h:572
static constexpr uint16_t s_multi_value_null
Multi-value virtual column length, which indicates that the field is NULL.
Definition: data0data.h:594
uint32_t m_field_len
Multi-value field length.
Definition: data0data.h:575
static uint32_t get_keys_capacity(uint32_t log_size, uint32_t key_length, uint32_t *num_keys)
Estimate how many multi-value keys at most can be accommodated into the log of specified size.
Definition: data0data.cc:1027
byte * log(byte **ptr)
Log the multi-value data to specified memory.
Definition: data0data.cc:928
uint32_t get_log_len(bool precise) const
Get the log length for the multi-value data.
Definition: data0data.cc:892
static constexpr uint8_t s_multi_value_virtual_col_length_marker
Multi-value virtual column length marker.
Definition: data0data.h:584
static const byte * read(const byte *ptr, dfield_t *field, mem_heap_t *heap)
Read the multi-value data from the ptr.
Definition: data0data.cc:981
static constexpr uint8_t s_max_compressed_mv_key_length_size
The compressed length for multi-value key length logging.
Definition: data0data.h:600
constexpr DWORD buf_size
Definition: create_def.cc:227
static void dtuple_init_v_fld(const dtuple_t *vrow)
Initialize the virtual field data in a dtuple_t.
bool dfield_datas_are_binary_equal(const dfield_t *field1, const dfield_t *field2, ulint len)
Tests if two data fields are equal.
Definition: data0data.ic:248
static spatial_status_t dfield_get_spatial_status(const dfield_t *field)
Gets spatial status for "external storage".
static uint64_t dtuple_hash(const dtuple_t *tuple, ulint n_fields, ulint n_bytes, uint64_t hash_value)
Compute a hash value of a prefix of an index record.
static void dfield_set_data(dfield_t *field, const void *data, ulint len)
Sets pointer to the data and length in a field.
static void dfield_set_ext(dfield_t *field)
Sets the "external storage" flag.
static void dtuple_set_info_bits(dtuple_t *tuple, ulint info_bits)
Sets info bits in a data tuple.
static void dfield_copy(dfield_t *field1, const dfield_t *field2)
Copies a data field to another.
static ulint dtuple_get_n_fields_cmp(const dtuple_t *tuple)
Gets number of fields used in record comparisons.
void dtuple_print(FILE *f, const dtuple_t *tuple)
The following function prints the contents of a tuple.
Definition: data0data.cc:367
static dtuple_t * dtuple_create(mem_heap_t *heap, ulint n_fields)
Creates a data tuple to a memory heap.
big_rec_t * dtuple_convert_big_rec(dict_index_t *index, upd_t *upd, dtuple_t *entry)
Moves parts of long fields in entry to the big record vector so that the size of tuple drops below th...
Definition: data0data.cc:421
static ulint dtuple_get_data_size(const dtuple_t *tuple, ulint comp)
The following function returns the sum of data lengths of a tuple.
static void dtuple_set_n_fields_cmp(dtuple_t *tuple, ulint n_fields_cmp)
Gets number of fields used in record comparisons.
static void dtuple_dup_v_fld(const dtuple_t *vrow, mem_heap_t *heap)
Duplicate the virtual field data in a dtuple_t.
static void dfield_set_len(dfield_t *field, ulint len)
Sets length in a field.
static void dfield_dup(dfield_t *field, mem_heap_t *heap)
Copies the data pointed to by a data field.
static void dfield_set_type(dfield_t *field, const dtype_t *type)
Sets the type struct of SQL data field.
static void dfield_multi_value_dup(dfield_t *field, mem_heap_t *heap)
Copies the data pointed to by a data field.
static void data_write_sql_null(byte *data, ulint len)
Writes an SQL null field full of zeros.
static void dfield_write_mbr(dfield_t *field, const double *mbr)
Sets pointer to the data and length in a field.
bool dfield_check_typed(const dfield_t *field)
Checks that a data field is typed.
Definition: data0data.cc:146
static dfield_t * dtuple_get_nth_v_field(const dtuple_t *tuple, ulint n)
Gets nth virtual field of a tuple.
bool dtuple_coll_eq(const dtuple_t *tuple1, const dtuple_t *tuple2)
Compare two data tuples.
Definition: data0data.cc:60
static uint32_t dfield_get_len(const dfield_t *field)
Gets length of field data.
void dfield_print_also_hex(const dfield_t *dfield)
Pretty prints a dfield value according to its data type.
Definition: data0data.cc:203
static bool dfield_is_ext(const dfield_t *field)
Determines if a field is externally stored.
static dtuple_t * dtuple_create_with_vcol(mem_heap_t *heap, ulint n_fields, ulint n_v_fields)
Creates a data tuple with possible virtual columns to a memory heap.
static dtuple_t * dtuple_create_from_mem(void *buf, ulint buf_size, ulint n_fields, ulint n_v_fields)
Creates a data tuple from an already allocated chunk of memory.
static void dtuple_big_rec_free(big_rec_t *vector)
Frees the memory in a big rec vector.
Definition: data0data.ic:650
static dtype_t * dfield_get_type(const dfield_t *field)
Gets pointer to the type struct of SQL data field.
static void dfield_set_spatial_status(dfield_t *field, spatial_status_t spatial_status)
Sets spatial status for "external storage".
static void dtuple_set_types_binary(dtuple_t *tuple, ulint n)
Sets types of fields binary in a tuple.
bool is_multi_value_clust_and_sec_equal(const byte *clust_field, uint64_t clust_len, const byte *sec_field, uint64_t sec_len, const dict_col_t *col)
Compare a multi-value clustered index field with a secondary index field, to see if they are equal.
Definition: data0data.cc:826
static dfield_t * dtuple_get_nth_field(const dtuple_t *tuple, ulint n)
Gets nth field of a tuple.
static bool dtuple_contains_null(const dtuple_t *tuple)
Checks if a dtuple contains an SQL null value.
constexpr uint32_t DATA_TUPLE_MAGIC_N
Value of dtuple_t::magic_n.
Definition: data0data.h:677
std::ostream & operator<<(std::ostream &o, const dtuple_t &tuple)
Print the contents of a tuple.
Definition: data0data.h:349
bool dtuple_check_typed(const dtuple_t *tuple)
Checks that a data tuple is typed.
Definition: data0data.cc:157
void dtuple_convert_back_big_rec(dtuple_t *entry, big_rec_t *vector)
Puts back to entry the data stored in vector.
Definition: data0data.cc:620
static bool dfield_is_multi_value(const dfield_t *field)
Determine if a field is of multi-value type.
static void dfield_copy_data(dfield_t *field1, const dfield_t *field2)
Copies the data and len fields.
static ulint dtuple_get_n_fields(const dtuple_t *tuple)
Gets number of fields in a data tuple.
static void dtuple_copy_v_fields(dtuple_t *d_tuple, const dtuple_t *s_tuple)
Copies a data tuple's virtual fields to another.
static dtuple_t * dtuple_copy(const dtuple_t *tuple, mem_heap_t *heap)
Copies a data tuple to another.
bool dtuple_validate(const dtuple_t *tuple)
Validates the consistency of a tuple which must be complete, i.e, all fields must have been set.
Definition: data0data.cc:170
void dfield_print(std::ostream &o, const dfield_t *field, ulint n)
Print the contents of a tuple.
Definition: data0data.cc:384
static ulint dtuple_get_n_v_fields(const dtuple_t *tuple)
Gets number of virtual fields in a data tuple.
void dtuple_set_n_fields(dtuple_t *tuple, ulint n_fields)
Sets number of fields used in a tuple.
Definition: data0data.cc:95
static void * dfield_get_data(const dfield_t *field)
Gets pointer to the data in a field.
static ulint dtuple_get_info_bits(const dtuple_t *tuple)
Gets info bits in a data tuple.
static bool dfield_data_is_binary_equal(const dfield_t *field, ulint len, const byte *data)
Tests if dfield data length and content is equal to the given.
static void dfield_set_null(dfield_t *field)
Sets a data field to SQL NULL.
static ulint dfield_is_null(const dfield_t *field)
Determines if a field is SQL NULL.
SQL data field and tuple.
Data types.
Some type definitions.
Data dictionary global types.
spatial_status_t
whether a col is used in spatial index or regular index Note: the spatial status is part of persisten...
Definition: dict0types.h:331
@ SPATIAL_UNKNOWN
Definition: dict0types.h:333
Fido Client Authentication nullptr
Definition: fido_client_plugin.cc:221
#define malloc(A)
Definition: lexyy.cc:914
The memory management.
void * mem_heap_dup(mem_heap_t *heap, const void *data, ulint len)
Duplicate a block of data, allocated from a memory heap.
Definition: memory.cc:56
Definition: buf0block_hint.cc:29
const std::string FILE("FILE")
std::vector< T, ut::allocator< T > > vector
Specialization of vector which uses allocator.
Definition: ut0new.h:2873
byte rec_t
Definition: rem0types.h:40
required string type
Definition: replication_group_member_actions.proto:33
Definition: completion_hash.h:34
A slot for a field in a big rec vector.
Definition: data0data.h:786
void * data
stored data
Definition: data0data.h:802
bool ext_in_new
If true, this field is stored externally in the new row.
Definition: data0data.h:810
ulint field_no
field number in record
Definition: data0data.h:800
bool ext_in_old
If true, this field was stored externally in the old row.
Definition: data0data.h:806
big_rec_field_t(ulint field_no_, ulint len_, void *data_)
Constructor.
Definition: data0data.h:791
std::ostream & print(std::ostream &out) const
Print the big_rec_field_t object into the given output stream.
Definition: data0data.cc:763
ulint len
stored data length, in bytes
Definition: data0data.h:801
byte * ptr() const
Definition: data0data.h:798
Storage format for overflow data in a big record, that is, a clustered index record which needs exter...
Definition: data0data.h:829
void append(const big_rec_field_t &field)
Append one big_rec_field_t object to the end of array of fields.
Definition: data0data.h:842
const ulint capacity
fields array size
Definition: data0data.h:832
big_rec_field_t * fields
stored fields
Definition: data0data.h:834
big_rec_t(const ulint max)
Constructor.
Definition: data0data.h:838
ulint n_fields
number of stored fields
Definition: data0data.h:833
mem_heap_t * heap
memory heap from which allocated
Definition: data0data.h:830
std::ostream & print(std::ostream &out) const
Print the current object into the given output stream.
Definition: data0data.cc:770
static big_rec_t * alloc(mem_heap_t *heap, ulint n_fld)
Allocate a big_rec_t object in the given memory heap, and for storing n_fld number of fields.
Definition: data0data.cc:647
Structure for an SQL data field.
Definition: data0data.h:604
std::ostream & print(std::ostream &out) const
Print the dfield_t object into the given output stream.
Definition: data0data.cc:747
uint32_t lob_version() const
Obtain the LOB version number, if this is an externally stored field.
Definition: data0data.cc:687
dtype_t type
type of data
Definition: data0data.h:611
unsigned spatial_status
spatial status of externally stored field in undo log for purge
Definition: data0data.h:607
void reset()
Definition: data0data.h:615
byte * blobref() const
Definition: data0data.cc:681
bool ext
true=externally stored, false=local
Definition: data0data.h:606
dfield_t()
Definition: data0data.h:633
unsigned len
data length; UNIV_SQL_NULL if SQL null
Definition: data0data.h:610
dfield_t * clone(mem_heap_t *heap)
Create a deep copy of this object.
Definition: data0data.cc:661
void adjust_v_data_mysql(const dict_v_col_t *vcol, bool comp, const byte *field, ulint len, mem_heap_t *heap)
Adjust and(or) set virtual column value which is read from undo or online DDL log.
Definition: data0data.cc:695
bool is_virtual() const
Definition: data0data.h:613
void * data
pointer to data
Definition: data0data.h:605
Data structure for a column in a table.
Definition: dict0mem.h:488
Data structure for an index.
Definition: dict0mem.h:1045
Data structure for a virtual column in a table.
Definition: dict0mem.h:814
Structure for an SQL data tuple of fields (logical record)
Definition: data0data.h:681
size_t get_n_ext() const
Get number of externally stored fields.
Definition: data0data.h:763
mem_heap_t * m_heap
Memory heap where this tuple is allocated.
Definition: data0data.h:708
uint16_t n_fields
Number of fields in dtuple.
Definition: data0data.h:687
int compare(const rec_t *rec, const dict_index_t *index, const ulint *offsets) const
Compare a data tuple to a physical record.
Definition: data0data.h:754
static constexpr size_t MAGIC_N
Value of dtuple_t::magic_n.
Definition: data0data.h:711
trx_id_t get_trx_id() const
Read the trx id from the tuple (DB_TRX_ID)
Definition: data0data.cc:781
uint16_t n_fields_cmp
number of fields which should be used in comparison services of rem0cmp.
Definition: data0data.h:692
bool has_ext() const
Does tuple has externally stored fields.
Definition: data0data.h:775
dfield_t * fields
Fields.
Definition: data0data.h:695
int compare(const rec_t *rec, const dict_index_t *index, const ulint *offsets, ulint *matched_fields) const
Compare a data tuple to a physical record.
Definition: rem0cmp.cc:1123
uint16_t n_v_fields
Number of virtual fields.
Definition: data0data.h:698
UT_LIST_NODE_T(dtuple_t) tuple_list
Data tuples can be linked into a list using this field.
std::ostream & print(std::ostream &out) const
Print the tuple to the output stream.
Definition: data0data.h:720
void ignore_trailing_default(const dict_index_t *index)
Ignore at most n trailing default fields if this is a tuple from instant index.
Definition: data0data.cc:795
uint16_t info_bits
info bits of an index record: the default is 0; this field is used if an index record is built from a...
Definition: data0data.h:684
dfield_t * v_fields
Fields on virtual column.
Definition: data0data.h:701
size_t magic_n
Magic number, used in debug assertions.
Definition: data0data.h:714
Definition: data0type.h:497
bool is_virtual() const
Definition: data0type.h:523
The info structure stored at the beginning of a heap block.
Definition: mem0mem.h:301
Structure to hold number of multiple values.
Definition: data0data.h:383
const void ** datap
points to different value
Definition: data0data.h:386
static constexpr uint32_t s_default_allocate_num
default number of multiple values
Definition: data0data.h:519
uint64_t * conv_buf
convert buffer if the data is an integer
Definition: data0data.h:392
void copy_low(const multi_value_data *multi_value, mem_heap_t *heap)
Copy a multi_value_data structure, current one should be bigger or equal to the one to be copied.
Definition: data0data.h:500
bool duplicate() const
Definition: data0data.h:479
uint32_t num_alc
number of pointers allocated
Definition: data0data.h:398
uint32_t num_v
number of values
Definition: data0data.h:395
void alloc_bitset(mem_heap_t *heap, uint32_t size=0)
Allocate the bitset for current data array.
Definition: data0data.cc:881
void alloc(uint32_t num, bool bitset, mem_heap_t *heap)
Allocate specified number of elements for all arrays and initialize the structure accordingly.
Definition: data0data.cc:864
bool has(const dtype_t *type, const byte *data, uint64_t len) const
Compare and check if one value from dfield_t is in current data set.
Definition: data0data.cc:844
void copy(const multi_value_data *multi_value, mem_heap_t *heap)
Copy a multi_value_data structure.
Definition: data0data.h:444
Bitset * bitset
Bitset to indicate which data should be handled for current data array.
Definition: data0data.h:407
uint32_t * data_len
each individual value length
Definition: data0data.h:389
bool equal(const multi_value_data *multi_value) const
Check if two multi_value_data are equal or not, regardless of bitset.
Definition: data0data.h:426
Definition: row0upd.h:564
mem_heap_t * heap
Heap from which memory allocated.
Definition: row0upd.h:568
ulint info_bits
New value of info bits to record; default is 0.
Definition: row0upd.h:576
ulint n_fields
Number of update fields.
Definition: row0upd.h:588
Transaction system global type definitions.
ib_id_t trx_id_t
Transaction identifier (DB_TRX_ID, DATA_TRX_ID)
Definition: trx0types.h:137
Version control for database, common definitions, and include files.
unsigned long int ulint
Definition: univ.i:405
Utilities for bitset operations.
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:68
int n
Definition: xcom_base.cc:508