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