1/* Copyright (c) 2011, 2017, MariaDB Corporation.
2 Copyright (c) 2011, 2012, Oleksandr Byelkin
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10
11 2. Redistributions in binary form must the following disclaimer in
12 the documentation and/or other materials provided with the
13 distribution.
14
15 THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY
16 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR
19 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
22 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 SUCH DAMAGE.
27*/
28
29/*
30 Numeric format:
31 ===============
32 * Fixed header part
33 1 byte flags:
34 0,1 bits - <offset size> - 1
35 2-7 bits - 0
36 2 bytes column counter
37 * Columns directory sorted by column number, each entry contains of:
38 2 bytes column number
39 <offset size> bytes (1-4) combined offset from beginning of
40 the data segment + 3 bit type
41 * Data of above columns size of data and length depend on type
42
43 Columns with names:
44 ===================
45 * Fixed header part
46 1 byte flags:
47 0,1 bits - <offset size> - 2
48 2 bit - 1 (means format with names)
49 3,4 bits - 00 (means <names offset size> - 2,
50 now 2 is the only supported size)
51 5-7 bits - 0
52 2 bytes column counter
53 * Variable header part (now it is actually fixed part)
54 <names offset size> (2) bytes size of stored names pool
55 * Column directory sorted by names, each consists of
56 <names offset size> (2) bytes offset of name
57 <offset size> bytes (2-5)bytes combined offset from beginning of
58 the data segment + 4 bit type
59 * Names stored one after another
60 * Data of above columns size of data and length depend on type
61*/
62
63#include "mysys_priv.h"
64#include <m_string.h>
65#include <ma_dyncol.h>
66#include <my_time.h>
67
68uint32 copy_and_convert(char *to, uint32 to_length, CHARSET_INFO *to_cs,
69 const char *from, uint32 from_length,
70 CHARSET_INFO *from_cs, uint *errors);
71/*
72 Flag byte bits
73
74 2 bits which determinate size of offset in the header -1
75*/
76/* mask to get above bits */
77#define DYNCOL_FLG_OFFSET (1U|2U)
78#define DYNCOL_FLG_NAMES 4U
79#define DYNCOL_FLG_NMOFFSET (8U|16U)
80/**
81 All known flags mask that could be set.
82
83 @note DYNCOL_FLG_NMOFFSET should be 0 for now.
84*/
85#define DYNCOL_FLG_KNOWN (1U|2U|4U)
86
87/* formats */
88enum enum_dyncol_format
89{
90 dyncol_fmt_num= 0,
91 dyncol_fmt_str= 1
92};
93
94/* dynamic column size reserve */
95#define DYNCOL_SYZERESERVE 80
96
97#define DYNCOL_OFFSET_ERROR 0xffffffff
98
99/* length of fixed string header 1 byte - flags, 2 bytes - columns counter */
100#define FIXED_HEADER_SIZE 3
101/*
102 length of fixed string header with names
103 1 byte - flags, 2 bytes - columns counter, 2 bytes - name pool size
104*/
105#define FIXED_HEADER_SIZE_NM 5
106
107#define COLUMN_NUMBER_SIZE 2
108/* 2 bytes offset from the name pool */
109#define COLUMN_NAMEPTR_SIZE 2
110
111#define MAX_OFFSET_LENGTH 4
112#define MAX_OFFSET_LENGTH_NM 5
113
114#define DYNCOL_NUM_CHAR 6
115
116my_bool mariadb_dyncol_has_names(DYNAMIC_COLUMN *str)
117{
118 if (str->length < 1)
119 return FALSE;
120 return MY_TEST(str->str[0] & DYNCOL_FLG_NAMES);
121}
122
123static enum enum_dyncol_func_result
124dynamic_column_time_store(DYNAMIC_COLUMN *str,
125 MYSQL_TIME *value, enum enum_dyncol_format format);
126static enum enum_dyncol_func_result
127dynamic_column_date_store(DYNAMIC_COLUMN *str,
128 MYSQL_TIME *value);
129static enum enum_dyncol_func_result
130dynamic_column_time_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
131 uchar *data, size_t length);
132static enum enum_dyncol_func_result
133dynamic_column_date_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
134 uchar *data, size_t length);
135static enum enum_dyncol_func_result
136dynamic_column_get_internal(DYNAMIC_COLUMN *str,
137 DYNAMIC_COLUMN_VALUE *store_it_here,
138 uint num_key, LEX_STRING *str_key);
139static enum enum_dyncol_func_result
140dynamic_column_exists_internal(DYNAMIC_COLUMN *str, uint num_key,
141 LEX_STRING *str_key);
142static enum enum_dyncol_func_result
143dynamic_column_update_many_fmt(DYNAMIC_COLUMN *str,
144 uint add_column_count,
145 void *column_keys,
146 DYNAMIC_COLUMN_VALUE *values,
147 my_bool string_keys);
148static int plan_sort_num(const void *a, const void *b);
149static int plan_sort_named(const void *a, const void *b);
150
151/*
152 Structure to hold information about dynamic columns record and
153 iterate through it.
154*/
155
156struct st_dyn_header
157{
158 uchar *header, *nmpool, *dtpool, *data_end;
159 size_t offset_size;
160 size_t entry_size;
161 size_t header_size;
162 size_t nmpool_size;
163 size_t data_size;
164 /* dyncol_fmt_num - numeric columns, dyncol_fmt_str - column names */
165 enum enum_dyncol_format format;
166 uint column_count;
167
168 uchar *entry, *data, *name;
169 size_t offset;
170 size_t length;
171 enum enum_dynamic_column_type type;
172};
173
174typedef struct st_dyn_header DYN_HEADER;
175
176static inline my_bool read_fixed_header(DYN_HEADER *hdr,
177 DYNAMIC_COLUMN *str);
178static void set_fixed_header(DYNAMIC_COLUMN *str,
179 uint offset_size,
180 uint column_count);
181
182/*
183 Calculate entry size (E) and header size (H) by offset size (O) and column
184 count (C) and fixed part of entry size (F).
185*/
186
187#define calc_param(E,H,F,O,C) do { \
188 (*(E))= (O) + F; \
189 (*(H))= (*(E)) * (C); \
190}while(0);
191
192
193/**
194 Name pool size functions, for numeric format it is 0
195*/
196
197static size_t name_size_num(void *keys __attribute__((unused)),
198 uint i __attribute__((unused)))
199{
200 return 0;
201}
202
203
204/**
205 Name pool size functions.
206*/
207static size_t name_size_named(void *keys, uint i)
208{
209 return ((LEX_STRING *) keys)[i].length;
210}
211
212
213/**
214 Comparator function for references on column numbers for qsort
215 (numeric format)
216*/
217
218static int column_sort_num(const void *a, const void *b)
219{
220 return **((uint **)a) - **((uint **)b);
221}
222
223/**
224 Comparator function for references on column numbers for qsort
225 (names format)
226*/
227
228int mariadb_dyncol_column_cmp_named(const LEX_STRING *s1, const LEX_STRING *s2)
229{
230 /*
231 We compare instead of subtraction to avoid data loss in case of huge
232 length difference (more then fit in int).
233 */
234 int rc= (s1->length > s2->length ? 1 :
235 (s1->length < s2->length ? -1 : 0));
236 if (rc == 0)
237 rc= memcmp((void *)s1->str, (void *)s2->str,
238 (size_t) s1->length);
239 return rc;
240}
241
242
243/**
244 Comparator function for references on column numbers for qsort
245 (names format)
246*/
247
248static int column_sort_named(const void *a, const void *b)
249{
250 return mariadb_dyncol_column_cmp_named(*((LEX_STRING **)a),
251 *((LEX_STRING **)b));
252}
253
254
255/**
256 Check limit function (numeric format)
257*/
258
259static my_bool check_limit_num(const void *val)
260{
261 return **((uint **)val) > UINT_MAX16;
262}
263
264
265/**
266 Check limit function (names format)
267*/
268
269static my_bool check_limit_named(const void *val)
270{
271 return (*((LEX_STRING **)val))->length > MAX_NAME_LENGTH;
272}
273
274
275/**
276 Write numeric format static header part.
277*/
278
279static void set_fixed_header_num(DYNAMIC_COLUMN *str, DYN_HEADER *hdr)
280{
281 set_fixed_header(str, (uint)hdr->offset_size, hdr->column_count);
282 hdr->header= (uchar *)str->str + FIXED_HEADER_SIZE;
283 hdr->nmpool= hdr->dtpool= hdr->header + hdr->header_size;
284}
285
286
287/**
288 Write names format static header part.
289*/
290
291static void set_fixed_header_named(DYNAMIC_COLUMN *str, DYN_HEADER *hdr)
292{
293 DBUG_ASSERT(hdr->column_count <= 0xffff);
294 DBUG_ASSERT(hdr->offset_size <= MAX_OFFSET_LENGTH_NM);
295 /* size of data offset, named format flag, size of names offset (0 means 2) */
296 str->str[0]=
297 (char) (((uchar)str->str[0] & ~(DYNCOL_FLG_OFFSET | DYNCOL_FLG_NMOFFSET)) |
298 (hdr->offset_size - 2) | DYNCOL_FLG_NAMES);
299 int2store(str->str + 1, hdr->column_count); /* columns number */
300 int2store(str->str + 3, hdr->nmpool_size);
301 hdr->header= (uchar *)str->str + FIXED_HEADER_SIZE_NM;
302 hdr->nmpool= hdr->header + hdr->header_size;
303 hdr->dtpool= hdr->nmpool + hdr->nmpool_size;
304}
305
306
307/**
308 Store offset and type information in the given place
309
310 @param place Beginning of the index entry
311 @param offset_size Size of offset field in bytes
312 @param type Type to be written
313 @param offset Offset to be written
314*/
315
316static my_bool type_and_offset_store_num(uchar *place, size_t offset_size,
317 DYNAMIC_COLUMN_TYPE type,
318 size_t offset)
319{
320 ulong val = (((ulong) offset) << 3) | (type - 1);
321 DBUG_ASSERT(type != DYN_COL_NULL);
322 DBUG_ASSERT(((type - 1) & (~7U)) == 0); /* fit in 3 bits */
323 DBUG_ASSERT(offset_size >= 1 && offset_size <= 4);
324
325 /* Index entry starts with column number; jump over it */
326 place+= COLUMN_NUMBER_SIZE;
327
328 switch (offset_size) {
329 case 1:
330 if (offset >= 0x1f) /* all 1 value is reserved */
331 return TRUE;
332 place[0]= (uchar)val;
333 break;
334 case 2:
335 if (offset >= 0x1fff) /* all 1 value is reserved */
336 return TRUE;
337 int2store(place, val);
338 break;
339 case 3:
340 if (offset >= 0x1fffff) /* all 1 value is reserved */
341 return TRUE;
342 int3store(place, val);
343 break;
344 case 4:
345 if (offset >= 0x1fffffff) /* all 1 value is reserved */
346 return TRUE;
347 int4store(place, val);
348 break;
349 default:
350 return TRUE;
351 }
352 return FALSE;
353}
354
355
356static my_bool type_and_offset_store_named(uchar *place, size_t offset_size,
357 DYNAMIC_COLUMN_TYPE type,
358 size_t offset)
359{
360 ulonglong val = (((ulong) offset) << 4) | (type - 1);
361 DBUG_ASSERT(type != DYN_COL_NULL);
362 DBUG_ASSERT(((type - 1) & (~0xfU)) == 0); /* fit in 4 bits */
363 DBUG_ASSERT(offset_size >= 2 && offset_size <= 5);
364
365 /* Index entry starts with name offset; jump over it */
366 place+= COLUMN_NAMEPTR_SIZE;
367 switch (offset_size) {
368 case 2:
369 if (offset >= 0xfff) /* all 1 value is reserved */
370 return TRUE;
371 int2store(place, val);
372 break;
373 case 3:
374 if (offset >= 0xfffff) /* all 1 value is reserved */
375 return TRUE;
376 int3store(place, val);
377 break;
378 case 4:
379 if (offset >= 0xfffffff) /* all 1 value is reserved */
380 return TRUE;
381 int4store(place, val);
382 break;
383 case 5:
384#if SIZEOF_SIZE_T > 4
385 if (offset >= 0xfffffffffull) /* all 1 value is reserved */
386 return TRUE;
387#endif
388 int5store(place, val);
389 break;
390 case 1:
391 default:
392 return TRUE;
393 }
394 return FALSE;
395}
396
397/**
398 Write numeric format header entry
399 2 bytes - column number
400 1-4 bytes - data offset combined with type
401
402 @param hdr descriptor of dynamic column record
403 @param column_key pointer to uint (column number)
404 @param value value which will be written (only type used)
405 @param offset offset of the data
406*/
407
408static my_bool put_header_entry_num(DYN_HEADER *hdr,
409 void *column_key,
410 DYNAMIC_COLUMN_VALUE *value,
411 size_t offset)
412{
413 uint *column_number= (uint *)column_key;
414 int2store(hdr->entry, *column_number);
415 DBUG_ASSERT(hdr->nmpool_size == 0);
416 if (type_and_offset_store_num(hdr->entry, hdr->offset_size,
417 value->type,
418 offset))
419 return TRUE;
420 hdr->entry= hdr->entry + hdr->entry_size;
421 return FALSE;
422}
423
424
425/**
426 Write names format header entry
427 1 byte - name length
428 2 bytes - name offset in the name pool
429 1-4 bytes - data offset combined with type
430
431 @param hdr descriptor of dynamic column record
432 @param column_key pointer to LEX_STRING (column name)
433 @param value value which will be written (only type used)
434 @param offset offset of the data
435*/
436
437static my_bool put_header_entry_named(DYN_HEADER *hdr,
438 void *column_key,
439 DYNAMIC_COLUMN_VALUE *value,
440 size_t offset)
441{
442 LEX_STRING *column_name= (LEX_STRING *)column_key;
443 DBUG_ASSERT(column_name->length <= MAX_NAME_LENGTH);
444 DBUG_ASSERT(hdr->name - hdr->nmpool < (long) 0x10000L);
445 int2store(hdr->entry, hdr->name - hdr->nmpool);
446 memcpy(hdr->name, column_name->str, column_name->length);
447 DBUG_ASSERT(hdr->nmpool_size != 0 || column_name->length == 0);
448 if (type_and_offset_store_named(hdr->entry, hdr->offset_size,
449 value->type,
450 offset))
451 return TRUE;
452 hdr->entry+= hdr->entry_size;
453 hdr->name+= column_name->length;
454 return FALSE;
455}
456
457
458/**
459 Calculate length of offset field for given data length
460
461 @param data_length Length of the data segment
462
463 @return number of bytes
464*/
465
466static size_t dynamic_column_offset_bytes_num(size_t data_length)
467{
468 if (data_length < 0x1f) /* all 1 value is reserved */
469 return 1;
470 if (data_length < 0x1fff) /* all 1 value is reserved */
471 return 2;
472 if (data_length < 0x1fffff) /* all 1 value is reserved */
473 return 3;
474 if (data_length < 0x1fffffff) /* all 1 value is reserved */
475 return 4;
476 return MAX_OFFSET_LENGTH + 1; /* For an error generation*/
477}
478
479static size_t dynamic_column_offset_bytes_named(size_t data_length)
480{
481 if (data_length < 0xfff) /* all 1 value is reserved */
482 return 2;
483 if (data_length < 0xfffff) /* all 1 value is reserved */
484 return 3;
485 if (data_length < 0xfffffff) /* all 1 value is reserved */
486 return 4;
487#if SIZEOF_SIZE_T > 4
488 if (data_length < 0xfffffffffull) /* all 1 value is reserved */
489#endif
490 return 5;
491 return MAX_OFFSET_LENGTH_NM + 1; /* For an error generation */
492}
493
494/**
495 Read offset and type information from index entry
496
497 @param type Where to put type info
498 @param offset Where to put offset info
499 @param place beginning of the type and offset
500 @param offset_size Size of offset field in bytes
501*/
502
503static my_bool type_and_offset_read_num(DYNAMIC_COLUMN_TYPE *type,
504 size_t *offset,
505 uchar *place, size_t offset_size)
506{
507 ulong UNINIT_VAR(val);
508 ulong UNINIT_VAR(lim);
509
510 DBUG_ASSERT(offset_size >= 1 && offset_size <= 4);
511
512 switch (offset_size) {
513 case 1:
514 val= (ulong)place[0];
515 lim= 0x1f;
516 break;
517 case 2:
518 val= uint2korr(place);
519 lim= 0x1fff;
520 break;
521 case 3:
522 val= uint3korr(place);
523 lim= 0x1fffff;
524 break;
525 case 4:
526 val= uint4korr(place);
527 lim= 0x1fffffff;
528 break;
529 default:
530 DBUG_ASSERT(0); /* impossible */
531 return 1;
532 }
533 *type= (val & 0x7) + 1;
534 *offset= val >> 3;
535 return (*offset >= lim);
536}
537
538static my_bool type_and_offset_read_named(DYNAMIC_COLUMN_TYPE *type,
539 size_t *offset,
540 uchar *place, size_t offset_size)
541{
542 ulonglong UNINIT_VAR(val);
543 ulonglong UNINIT_VAR(lim);
544 DBUG_ASSERT(offset_size >= 2 && offset_size <= 5);
545
546 switch (offset_size) {
547 case 2:
548 val= uint2korr(place);
549 lim= 0xfff;
550 break;
551 case 3:
552 val= uint3korr(place);
553 lim= 0xfffff;
554 break;
555 case 4:
556 val= uint4korr(place);
557 lim= 0xfffffff;
558 break;
559 case 5:
560 val= uint5korr(place);
561 lim= 0xfffffffffull;
562 break;
563 case 1:
564 default:
565 DBUG_ASSERT(0); /* impossible */
566 return 1;
567 }
568 *type= (val & 0xf) + 1;
569 *offset= (size_t) (val >> 4);
570 return (*offset >= lim);
571}
572
573/**
574 Format descriptor, contain constants and function references for
575 format processing
576*/
577
578struct st_service_funcs
579{
580 /* size of fixed header */
581 uint fixed_hdr;
582 /* size of fixed part of header entry */
583 uint fixed_hdr_entry;
584
585 /*size of array element which stores keys */
586 uint key_size_in_array;
587
588 /* Maximum data offset size in bytes */
589 size_t max_offset_size;
590
591 size_t (*name_size)
592 (void *, uint);
593 int (*column_sort)
594 (const void *a, const void *b);
595 my_bool (*check_limit)
596 (const void *val);
597 void (*set_fixed_hdr)
598 (DYNAMIC_COLUMN *str, DYN_HEADER *hdr);
599 my_bool (*put_header_entry)(DYN_HEADER *hdr,
600 void *column_key,
601 DYNAMIC_COLUMN_VALUE *value,
602 size_t offset);
603 int (*plan_sort)(const void *a, const void *b);
604 size_t (*dynamic_column_offset_bytes)(size_t data_length);
605 my_bool (*type_and_offset_read)(DYNAMIC_COLUMN_TYPE *type,
606 size_t *offset,
607 uchar *place, size_t offset_size);
608
609};
610
611
612/**
613 Actual our 2 format descriptors
614*/
615
616static struct st_service_funcs fmt_data[2]=
617{
618 {
619 FIXED_HEADER_SIZE,
620 COLUMN_NUMBER_SIZE,
621 sizeof(uint),
622 MAX_OFFSET_LENGTH,
623 &name_size_num,
624 &column_sort_num,
625 &check_limit_num,
626 &set_fixed_header_num,
627 &put_header_entry_num,
628 &plan_sort_num,
629 &dynamic_column_offset_bytes_num,
630 &type_and_offset_read_num
631 },
632 {
633 FIXED_HEADER_SIZE_NM,
634 COLUMN_NAMEPTR_SIZE,
635 sizeof(LEX_STRING),
636 MAX_OFFSET_LENGTH_NM,
637 &name_size_named,
638 &column_sort_named,
639 &check_limit_named,
640 &set_fixed_header_named,
641 &put_header_entry_named,
642 &plan_sort_named,
643 &dynamic_column_offset_bytes_named,
644 &type_and_offset_read_named
645 }
646};
647
648
649/**
650 Read dynamic column record header and fill the descriptor
651
652 @param hdr dynamic columns record descriptor to fill
653 @param str dynamic columns record
654
655 @return ER_DYNCOL_* return code
656*/
657
658static enum enum_dyncol_func_result
659init_read_hdr(DYN_HEADER *hdr, DYNAMIC_COLUMN *str)
660{
661 if (read_fixed_header(hdr, str))
662 return ER_DYNCOL_FORMAT;
663 hdr->header= (uchar*)str->str + fmt_data[hdr->format].fixed_hdr;
664 calc_param(&hdr->entry_size, &hdr->header_size,
665 fmt_data[hdr->format].fixed_hdr_entry, hdr->offset_size,
666 hdr->column_count);
667 hdr->nmpool= hdr->header + hdr->header_size;
668 hdr->dtpool= hdr->nmpool + hdr->nmpool_size;
669 hdr->data_size= str->length - fmt_data[hdr->format].fixed_hdr -
670 hdr->header_size - hdr->nmpool_size;
671 hdr->data_end= (uchar*)str->str + str->length;
672 return ER_DYNCOL_OK;
673}
674
675
676/**
677 Initialize dynamic column string with (make it empty but correct format)
678
679 @param str The string to initialize
680 @param size Amount of preallocated memory for the string.
681
682 @retval FALSE OK
683 @retval TRUE error
684*/
685
686static my_bool dynamic_column_init_named(DYNAMIC_COLUMN *str, size_t size)
687{
688 DBUG_ASSERT(size != 0);
689
690 /*
691 Make string with no fields (empty header)
692 - First \0 is flags
693 - other 2 \0 is number of fields
694 */
695 if (init_dynamic_string(str, NULL, size, DYNCOL_SYZERESERVE))
696 return TRUE;
697 return FALSE;
698}
699
700
701/**
702 Calculate how many bytes needed to store val as variable length integer
703 where first bit indicate continuation of the sequence.
704
705 @param val The value for which we are calculating length
706
707 @return number of bytes
708*/
709
710static size_t dynamic_column_var_uint_bytes(ulonglong val)
711{
712 size_t len= 0;
713 do
714 {
715 len++;
716 val>>= 7;
717 } while (val);
718 return len;
719}
720
721
722/**
723 Stores variable length unsigned integer value to a string
724
725 @param str The string where to append the value
726 @param val The value to put in the string
727
728 @return ER_DYNCOL_* return code
729
730 @notes
731 This is used to store a number together with other data in the same
732 object. (Like decimals, length of string etc)
733 (As we don't know the length of this object, we can't store 0 in 0 bytes)
734*/
735
736static enum enum_dyncol_func_result
737dynamic_column_var_uint_store(DYNAMIC_COLUMN *str, ulonglong val)
738{
739 if (dynstr_realloc(str, 10)) /* max what we can use */
740 return ER_DYNCOL_RESOURCE;
741
742 do
743 {
744 ulonglong rest= val >> 7;
745 str->str[str->length++]= ((val & 0x7f) | (rest ? 0x80 : 0x00));
746 val= rest;
747 } while (val);
748 return ER_DYNCOL_OK;
749}
750
751
752/**
753 Reads variable length unsigned integer value from a string
754
755 @param data The string from which the int should be read
756 @param data_length Max length of data
757 @param len Where to put length of the string read in bytes
758
759 @return value of the unsigned integer read from the string
760
761 In case of error, *len is set to 0
762*/
763
764static ulonglong
765dynamic_column_var_uint_get(uchar *data, size_t data_length,
766 size_t *len)
767{
768 ulonglong val= 0;
769 uint length;
770 uchar *end= data + data_length;
771
772 for (length=0; data < end ; data++)
773 {
774 val+= (((ulonglong)((*data) & 0x7f)) << (length * 7));
775 length++;
776 if (!((*data) & 0x80))
777 {
778 /* End of data */
779 *len= length;
780 return val;
781 }
782 }
783 /* Something was wrong with data */
784 *len= 0; /* Mark error */
785 return 0;
786}
787
788
789/**
790 Calculate how many bytes needed to store val as unsigned.
791
792 @param val The value for which we are calculating length
793
794 @return number of bytes (0-8)
795*/
796
797static size_t dynamic_column_uint_bytes(ulonglong val)
798{
799 size_t len;
800
801 for (len= 0; val ; val>>= 8, len++)
802 ;
803 return len;
804}
805
806
807/**
808 Append the string with given unsigned int value.
809
810 @param str The string where to put the value
811 @param val The value to put in the string
812
813 @return ER_DYNCOL_* return code
814*/
815
816static enum enum_dyncol_func_result
817dynamic_column_uint_store(DYNAMIC_COLUMN *str, ulonglong val)
818{
819 if (dynstr_realloc(str, 8)) /* max what we can use */
820 return ER_DYNCOL_RESOURCE;
821
822 for (; val; val>>= 8)
823 str->str[str->length++]= (char) (val & 0xff);
824 return ER_DYNCOL_OK;
825}
826
827
828/**
829 Read unsigned int value of given length from the string
830
831 @param store_it_here The structure to store the value
832 @param data The string which should be read
833 @param length The length (in bytes) of the value in nthe string
834
835 @return ER_DYNCOL_* return code
836*/
837
838static enum enum_dyncol_func_result
839dynamic_column_uint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
840 uchar *data, size_t length)
841{
842 ulonglong value= 0;
843 size_t i;
844
845 for (i= 0; i < length; i++)
846 value+= ((ulonglong)data[i]) << (i*8);
847
848 store_it_here->x.ulong_value= value;
849 return ER_DYNCOL_OK;
850}
851
852/**
853 Calculate how many bytes needed to store val as signed in following encoding:
854 0 -> 0
855 -1 -> 1
856 1 -> 2
857 -2 -> 3
858 2 -> 4
859 ...
860
861 @param val The value for which we are calculating length
862
863 @return number of bytes
864*/
865
866static size_t dynamic_column_sint_bytes(longlong val)
867{
868 return dynamic_column_uint_bytes((val << 1) ^
869 (val < 0 ? 0xffffffffffffffffull : 0));
870}
871
872
873/**
874 Append the string with given signed int value.
875
876 @param str the string where to put the value
877 @param val the value to put in the string
878
879 @return ER_DYNCOL_* return code
880*/
881
882static enum enum_dyncol_func_result
883dynamic_column_sint_store(DYNAMIC_COLUMN *str, longlong val)
884{
885 return dynamic_column_uint_store(str,
886 (val << 1) ^
887 (val < 0 ? 0xffffffffffffffffULL : 0));
888}
889
890
891/**
892 Read signed int value of given length from the string
893
894 @param store_it_here The structure to store the value
895 @param data The string which should be read
896 @param length The length (in bytes) of the value in the string
897
898 @return ER_DYNCOL_* return code
899*/
900
901static enum enum_dyncol_func_result
902dynamic_column_sint_read(DYNAMIC_COLUMN_VALUE *store_it_here,
903 uchar *data, size_t length)
904{
905 ulonglong val;
906 dynamic_column_uint_read(store_it_here, data, length);
907 val= store_it_here->x.ulong_value;
908 if (val & 1)
909 val= (val >> 1) ^ 0xffffffffffffffffULL;
910 else
911 val>>= 1;
912 store_it_here->x.long_value= (longlong) val;
913 return ER_DYNCOL_OK;
914}
915
916
917/**
918 Calculate how many bytes needed to store the value.
919
920 @param value The value for which we are calculating length
921
922 @return
923 Error: (size_t) ~0
924 ok number of bytes
925*/
926
927static size_t
928dynamic_column_value_len(DYNAMIC_COLUMN_VALUE *value,
929 enum enum_dyncol_format format)
930{
931 switch (value->type) {
932 case DYN_COL_NULL:
933 return 0;
934 case DYN_COL_INT:
935 return dynamic_column_sint_bytes(value->x.long_value);
936 case DYN_COL_UINT:
937 return dynamic_column_uint_bytes(value->x.ulong_value);
938 case DYN_COL_DOUBLE:
939 return 8;
940 case DYN_COL_STRING:
941 return (dynamic_column_var_uint_bytes(value->x.string.charset->number) +
942 value->x.string.value.length);
943 case DYN_COL_DECIMAL:
944 {
945 int precision= value->x.decimal.value.intg + value->x.decimal.value.frac;
946 int scale= value->x.decimal.value.frac;
947
948 if (precision == 0 || decimal_is_zero(&value->x.decimal.value))
949 {
950 /* This is here to simplify dynamic_column_decimal_store() */
951 value->x.decimal.value.intg= value->x.decimal.value.frac= 0;
952 return 0;
953 }
954 /*
955 Check if legal decimal; This is needed to not get an assert in
956 decimal_bin_size(). However this should be impossible as all
957 decimals entered here should be valid and we have the special check
958 above to handle the unlikely but possible case that decimal.value.intg
959 and decimal.frac is 0.
960 */
961 if (scale < 0 || precision <= 0)
962 {
963 DBUG_ASSERT(0); /* Impossible */
964 return (size_t) ~0;
965 }
966 return (dynamic_column_var_uint_bytes(value->x.decimal.value.intg) +
967 dynamic_column_var_uint_bytes(value->x.decimal.value.frac) +
968 decimal_bin_size(precision, scale));
969 }
970 case DYN_COL_DATETIME:
971 if (format == dyncol_fmt_num || value->x.time_value.second_part)
972 /* date+time in bits: 14 + 4 + 5 + 10 + 6 + 6 + 20 + 1 66bits ~= 9 bytes*/
973 return 9;
974 else
975 return 6;
976 case DYN_COL_DATE:
977 /* date in dits: 14 + 4 + 5 = 23bits ~= 3bytes*/
978 return 3;
979 case DYN_COL_TIME:
980 if (format == dyncol_fmt_num || value->x.time_value.second_part)
981 /* time in bits: 10 + 6 + 6 + 20 + 1 = 43bits ~= 6bytes*/
982 return 6;
983 else
984 return 3;
985 case DYN_COL_DYNCOL:
986 return value->x.string.value.length;
987 }
988 DBUG_ASSERT(0);
989 return 0;
990}
991
992
993/**
994 Append double value to a string
995
996 @param str the string where to put the value
997 @param val the value to put in the string
998
999 @return ER_DYNCOL_* return code
1000*/
1001
1002static enum enum_dyncol_func_result
1003dynamic_column_double_store(DYNAMIC_COLUMN *str, double val)
1004{
1005 if (dynstr_realloc(str, 8))
1006 return ER_DYNCOL_RESOURCE;
1007 float8store(str->str + str->length, val);
1008 str->length+= 8;
1009 return ER_DYNCOL_OK;
1010}
1011
1012
1013/**
1014 Read double value of given length from the string
1015
1016 @param store_it_here The structure to store the value
1017 @param data The string which should be read
1018 @param length The length (in bytes) of the value in nthe string
1019
1020 @return ER_DYNCOL_* return code
1021*/
1022
1023static enum enum_dyncol_func_result
1024dynamic_column_double_read(DYNAMIC_COLUMN_VALUE *store_it_here,
1025 uchar *data, size_t length)
1026{
1027 if (length != 8)
1028 return ER_DYNCOL_FORMAT;
1029 float8get(store_it_here->x.double_value, data);
1030 return ER_DYNCOL_OK;
1031}
1032
1033
1034/**
1035 Append the string with given string value.
1036
1037 @param str the string where to put the value
1038 @param val the value to put in the string
1039
1040 @return ER_DYNCOL_* return code
1041*/
1042
1043static enum enum_dyncol_func_result
1044dynamic_column_string_store(DYNAMIC_COLUMN *str, LEX_STRING *string,
1045 CHARSET_INFO *charset)
1046{
1047 enum enum_dyncol_func_result rc;
1048 if ((rc= dynamic_column_var_uint_store(str, charset->number)))
1049 return rc;
1050 if (dynstr_append_mem(str, string->str, string->length))
1051 return ER_DYNCOL_RESOURCE;
1052 return ER_DYNCOL_OK;
1053}
1054
1055/**
1056 Append the string with given string value.
1057
1058 @param str the string where to put the value
1059 @param val the value to put in the string
1060
1061 @return ER_DYNCOL_* return code
1062*/
1063
1064static enum enum_dyncol_func_result
1065dynamic_column_dyncol_store(DYNAMIC_COLUMN *str, LEX_STRING *string)
1066{
1067 if (dynstr_append_mem(str, string->str, string->length))
1068 return ER_DYNCOL_RESOURCE;
1069 return ER_DYNCOL_OK;
1070}
1071
1072/**
1073 Read string value of given length from the packed string
1074
1075 @param store_it_here The structure to store the value
1076 @param data The packed string which should be read
1077 @param length The length (in bytes) of the value in nthe string
1078
1079 @return ER_DYNCOL_* return code
1080*/
1081
1082static enum enum_dyncol_func_result
1083dynamic_column_string_read(DYNAMIC_COLUMN_VALUE *store_it_here,
1084 uchar *data, size_t length)
1085{
1086 size_t len;
1087 uint charset_nr= (uint)dynamic_column_var_uint_get(data, length, &len);
1088 if (len == 0) /* Wrong packed number */
1089 return ER_DYNCOL_FORMAT;
1090 store_it_here->x.string.charset= get_charset(charset_nr, MYF(MY_WME));
1091 if (store_it_here->x.string.charset == NULL)
1092 return ER_DYNCOL_UNKNOWN_CHARSET;
1093 data+= len;
1094 store_it_here->x.string.value.length= (length-= len);
1095 store_it_here->x.string.value.str= (char*) data;
1096 return ER_DYNCOL_OK;
1097}
1098
1099/**
1100 Read Dynamic columns packet string value of given length
1101 from the packed string
1102
1103 @param store_it_here The structure to store the value
1104 @param data The packed string which should be read
1105 @param length The length (in bytes) of the value in nthe string
1106
1107 @return ER_DYNCOL_* return code
1108*/
1109
1110static enum enum_dyncol_func_result
1111dynamic_column_dyncol_read(DYNAMIC_COLUMN_VALUE *store_it_here,
1112 uchar *data, size_t length)
1113{
1114 store_it_here->x.string.charset= &my_charset_bin;
1115 store_it_here->x.string.value.length= length;
1116 store_it_here->x.string.value.str= (char*) data;
1117 return ER_DYNCOL_OK;
1118}
1119
1120/**
1121 Append the string with given decimal value.
1122
1123 @param str the string where to put the value
1124 @param val the value to put in the string
1125
1126 @return ER_DYNCOL_* return code
1127*/
1128
1129static enum enum_dyncol_func_result
1130dynamic_column_decimal_store(DYNAMIC_COLUMN *str,
1131 decimal_t *value)
1132{
1133 uint bin_size;
1134 int precision= value->intg + value->frac;
1135
1136 /* Store decimal zero as empty string */
1137 if (precision == 0)
1138 return ER_DYNCOL_OK;
1139
1140 bin_size= decimal_bin_size(precision, value->frac);
1141 if (dynstr_realloc(str, bin_size + 20))
1142 return ER_DYNCOL_RESOURCE;
1143
1144 /* The following can't fail as memory is already allocated */
1145 (void) dynamic_column_var_uint_store(str, value->intg);
1146 (void) dynamic_column_var_uint_store(str, value->frac);
1147
1148 decimal2bin(value, (uchar *) str->str + str->length,
1149 precision, value->frac);
1150 str->length+= bin_size;
1151 return ER_DYNCOL_OK;
1152}
1153
1154
1155/**
1156 Prepare the value to be used as decimal.
1157
1158 @param value The value structure which sould be setup.
1159*/
1160
1161void mariadb_dyncol_prepare_decimal(DYNAMIC_COLUMN_VALUE *value)
1162{
1163 value->x.decimal.value.buf= value->x.decimal.buffer;
1164 value->x.decimal.value.len= DECIMAL_BUFF_LENGTH;
1165 /* just to be safe */
1166 value->type= DYN_COL_DECIMAL;
1167 decimal_make_zero(&value->x.decimal.value);
1168}
1169
1170void dynamic_column_prepare_decimal(DYNAMIC_COLUMN_VALUE *value)
1171{
1172 mariadb_dyncol_prepare_decimal(value);
1173}
1174
1175
1176
1177/**
1178 Read decimal value of given length from the string
1179
1180 @param store_it_here The structure to store the value
1181 @param data The string which should be read
1182 @param length The length (in bytes) of the value in nthe string
1183
1184 @return ER_DYNCOL_* return code
1185*/
1186
1187static enum enum_dyncol_func_result
1188dynamic_column_decimal_read(DYNAMIC_COLUMN_VALUE *store_it_here,
1189 uchar *data, size_t length)
1190{
1191 size_t intg_len, frac_len;
1192 int intg, frac, precision, scale;
1193
1194 dynamic_column_prepare_decimal(store_it_here);
1195 /* Decimals 0.0 is stored as a zero length string */
1196 if (length == 0)
1197 return ER_DYNCOL_OK; /* value contains zero */
1198
1199 intg= (int)dynamic_column_var_uint_get(data, length, &intg_len);
1200 data+= intg_len;
1201 frac= (int)dynamic_column_var_uint_get(data, length - intg_len, &frac_len);
1202 data+= frac_len;
1203
1204 /* Check the size of data is correct */
1205 precision= intg + frac;
1206 scale= frac;
1207 if (scale < 0 || precision <= 0 || scale > precision ||
1208 (length - intg_len - frac_len) >
1209 (size_t) (DECIMAL_BUFF_LENGTH*sizeof(decimal_digit_t)) ||
1210 decimal_bin_size(intg + frac, frac) !=
1211 (int) (length - intg_len - frac_len))
1212 return ER_DYNCOL_FORMAT;
1213
1214 if (bin2decimal(data, &store_it_here->x.decimal.value, precision, scale) !=
1215 E_DEC_OK)
1216 return ER_DYNCOL_FORMAT;
1217 return ER_DYNCOL_OK;
1218}
1219
1220
1221/**
1222 Append the string with given datetime value.
1223
1224 @param str the string where to put the value
1225 @param value the value to put in the string
1226
1227 @return ER_DYNCOL_* return code
1228*/
1229
1230static enum enum_dyncol_func_result
1231dynamic_column_date_time_store(DYNAMIC_COLUMN *str, MYSQL_TIME *value,
1232 enum enum_dyncol_format format)
1233{
1234 enum enum_dyncol_func_result rc;
1235 /*
1236 0<----year----><mn><day>00000!<-hours--><min-><sec-><---microseconds--->
1237 12345678901234123412345 1123456789012345612345612345678901234567890
1238 <123456><123456><123456><123456><123456><123456><123456><123456><123456>
1239 */
1240 if ((rc= dynamic_column_date_store(str, value)) ||
1241 (rc= dynamic_column_time_store(str, value, format)))
1242 return rc;
1243 return ER_DYNCOL_OK;
1244}
1245
1246
1247/**
1248 Read datetime value of given length from the packed string
1249
1250 @param store_it_here The structure to store the value
1251 @param data The packed string which should be read
1252 @param length The length (in bytes) of the value in nthe string
1253
1254 @return ER_DYNCOL_* return code
1255*/
1256
1257static enum enum_dyncol_func_result
1258dynamic_column_date_time_read(DYNAMIC_COLUMN_VALUE *store_it_here,
1259 uchar *data, size_t length)
1260{
1261 enum enum_dyncol_func_result rc= ER_DYNCOL_FORMAT;
1262 /*
1263 0<----year----><mn><day>00000!<-hours--><min-><sec-><---microseconds--->
1264 12345678901234123412345 1123456789012345612345612345678901234567890
1265 <123456><123456><123456><123456><123456><123456><123456><123456><123456>
1266 */
1267 if (length != 9 && length != 6)
1268 goto err;
1269 store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_DATETIME;
1270 if ((rc= dynamic_column_date_read_internal(store_it_here, data, 3)) ||
1271 (rc= dynamic_column_time_read_internal(store_it_here, data + 3,
1272 length - 3)))
1273 goto err;
1274 return ER_DYNCOL_OK;
1275
1276err:
1277 store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_ERROR;
1278 return rc;
1279}
1280
1281
1282/**
1283 Append the string with given time value.
1284
1285 @param str the string where to put the value
1286 @param value the value to put in the string
1287
1288 @return ER_DYNCOL_* return code
1289*/
1290
1291static enum enum_dyncol_func_result
1292dynamic_column_time_store(DYNAMIC_COLUMN *str, MYSQL_TIME *value,
1293 enum enum_dyncol_format format)
1294{
1295 uchar *buf;
1296 if (dynstr_realloc(str, 6))
1297 return ER_DYNCOL_RESOURCE;
1298
1299 buf= ((uchar *)str->str) + str->length;
1300
1301 if (value->time_type == MYSQL_TIMESTAMP_NONE ||
1302 value->time_type == MYSQL_TIMESTAMP_ERROR ||
1303 value->time_type == MYSQL_TIMESTAMP_DATE)
1304 {
1305 value->neg= 0;
1306 value->second_part= 0;
1307 value->hour= 0;
1308 value->minute= 0;
1309 value->second= 0;
1310 }
1311 DBUG_ASSERT(value->hour <= 838);
1312 DBUG_ASSERT(value->minute <= 59);
1313 DBUG_ASSERT(value->second <= 59);
1314 DBUG_ASSERT(value->second_part <= 999999);
1315 if (format == dyncol_fmt_num || value->second_part)
1316 {
1317 /*
1318 00000!<-hours--><min-><sec-><---microseconds--->
1319 1123456789012345612345612345678901234567890
1320 <123456><123456><123456><123456><123456><123456>
1321 */
1322 buf[0]= (value->second_part & 0xff);
1323 buf[1]= ((value->second_part & 0xff00) >> 8);
1324 buf[2]= (uchar)(((value->second & 0xf) << 4) |
1325 ((value->second_part & 0xf0000) >> 16));
1326 buf[3]= ((value->minute << 2) | ((value->second & 0x30) >> 4));
1327 buf[4]= (value->hour & 0xff);
1328 buf[5]= ((value->neg ? 0x4 : 0) | (value->hour >> 8));
1329 str->length+= 6;
1330 }
1331 else
1332 {
1333 /*
1334 !<-hours--><min-><sec->
1335 11234567890123456123456
1336 <123456><123456><123456>
1337 */
1338 buf[0]= (value->second) | ((value->minute & 0x3) << 6);
1339 buf[1]= (value->minute >> 2) | ((value->hour & 0xf) << 4);
1340 buf[2]= (value->hour >> 4) | (value->neg ? 0x80 : 0);
1341 str->length+= 3;
1342 }
1343
1344 return ER_DYNCOL_OK;
1345}
1346
1347
1348/**
1349 Read time value of given length from the packed string
1350
1351 @param store_it_here The structure to store the value
1352 @param data The packed string which should be read
1353 @param length The length (in bytes) of the value in nthe string
1354
1355 @return ER_DYNCOL_* return code
1356*/
1357
1358static enum enum_dyncol_func_result
1359dynamic_column_time_read(DYNAMIC_COLUMN_VALUE *store_it_here,
1360 uchar *data, size_t length)
1361{
1362 store_it_here->x.time_value.year= store_it_here->x.time_value.month=
1363 store_it_here->x.time_value.day= 0;
1364 store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_TIME;
1365 return dynamic_column_time_read_internal(store_it_here, data, length);
1366}
1367
1368/**
1369 Internal function for reading time part from the string.
1370
1371 @param store_it_here The structure to store the value
1372 @param data The packed string which should be read
1373 @param length The length (in bytes) of the value in nthe string
1374
1375 @return ER_DYNCOL_* return code
1376*/
1377
1378static enum enum_dyncol_func_result
1379dynamic_column_time_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
1380 uchar *data, size_t length)
1381{
1382 if (length != 6 && length != 3)
1383 goto err;
1384 if (length == 6)
1385 {
1386 /*
1387 00000!<-hours--><min-><sec-><---microseconds--->
1388 1123456789012345612345612345678901234567890
1389 <123456><123456><123456><123456><123456><123456>
1390 */
1391 store_it_here->x.time_value.second_part= (data[0] |
1392 (data[1] << 8) |
1393 ((data[2] & 0xf) << 16));
1394 store_it_here->x.time_value.second= ((data[2] >> 4) |
1395 ((data[3] & 0x3) << 4));
1396 store_it_here->x.time_value.minute= (data[3] >> 2);
1397 store_it_here->x.time_value.hour= (((((uint)data[5]) & 0x3 ) << 8) | data[4]);
1398 store_it_here->x.time_value.neg= ((data[5] & 0x4) ? 1 : 0);
1399 }
1400 else
1401 {
1402 /*
1403 !<-hours--><min-><sec->
1404 11234567890123456123456
1405 <123456><123456><123456>
1406 */
1407 store_it_here->x.time_value.second_part= 0;
1408 store_it_here->x.time_value.second= (data[0] & 0x3f);
1409 store_it_here->x.time_value.minute= (data[0] >> 6) | ((data[1] & 0xf) << 2);
1410 store_it_here->x.time_value.hour= (data[1] >> 4) | ((data[2] & 0x3f) << 4);
1411 store_it_here->x.time_value.neg= ((data[2] & 0x80) ? 1 : 0);
1412 }
1413 if (store_it_here->x.time_value.second > 59 ||
1414 store_it_here->x.time_value.minute > 59 ||
1415 store_it_here->x.time_value.hour > 838 ||
1416 store_it_here->x.time_value.second_part > 999999)
1417 goto err;
1418 return ER_DYNCOL_OK;
1419
1420err:
1421 store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_ERROR;
1422 return ER_DYNCOL_FORMAT;
1423}
1424
1425
1426/**
1427 Append the string with given date value.
1428
1429 @param str the string where to put the value
1430 @param value the value to put in the string
1431
1432 @return ER_DYNCOL_* return code
1433*/
1434
1435static enum enum_dyncol_func_result
1436dynamic_column_date_store(DYNAMIC_COLUMN *str, MYSQL_TIME *value)
1437{
1438 uchar *buf;
1439 if (dynstr_realloc(str, 3))
1440 return ER_DYNCOL_RESOURCE;
1441
1442 buf= ((uchar *)str->str) + str->length;
1443 if (value->time_type == MYSQL_TIMESTAMP_NONE ||
1444 value->time_type == MYSQL_TIMESTAMP_ERROR ||
1445 value->time_type == MYSQL_TIMESTAMP_TIME)
1446 value->year= value->month= value->day = 0;
1447 DBUG_ASSERT(value->year <= 9999);
1448 DBUG_ASSERT(value->month <= 12);
1449 DBUG_ASSERT(value->day <= 31);
1450 /*
1451 0<----year----><mn><day>
1452 012345678901234123412345
1453 <123456><123456><123456>
1454 */
1455 buf[0]= (value->day |
1456 ((value->month & 0x7) << 5));
1457 buf[1]= ((value->month >> 3) | ((value->year & 0x7F) << 1));
1458 buf[2]= (value->year >> 7);
1459 str->length+= 3;
1460 return ER_DYNCOL_OK;
1461}
1462
1463
1464
1465/**
1466 Read date value of given length from the packed string
1467
1468 @param store_it_here The structure to store the value
1469 @param data The packed string which should be read
1470 @param length The length (in bytes) of the value in nthe string
1471
1472 @return ER_DYNCOL_* return code
1473*/
1474
1475static enum enum_dyncol_func_result
1476dynamic_column_date_read(DYNAMIC_COLUMN_VALUE *store_it_here,
1477 uchar *data, size_t length)
1478{
1479 store_it_here->x.time_value.neg= 0;
1480 store_it_here->x.time_value.second_part= 0;
1481 store_it_here->x.time_value.hour= 0;
1482 store_it_here->x.time_value.minute= 0;
1483 store_it_here->x.time_value.second= 0;
1484 store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_DATE;
1485 return dynamic_column_date_read_internal(store_it_here, data, length);
1486}
1487
1488/**
1489 Internal function for reading date part from the string.
1490
1491 @param store_it_here The structure to store the value
1492 @param data The packed string which should be read
1493 @param length The length (in bytes) of the value in nthe string
1494
1495 @return ER_DYNCOL_* return code
1496*/
1497
1498static enum enum_dyncol_func_result
1499dynamic_column_date_read_internal(DYNAMIC_COLUMN_VALUE *store_it_here,
1500 uchar *data,
1501 size_t length)
1502{
1503 if (length != 3)
1504 goto err;
1505 /*
1506 0<----year----><mn><day>
1507 12345678901234123412345
1508 <123456><123456><123456>
1509 */
1510 store_it_here->x.time_value.day= (data[0] & 0x1f);
1511 store_it_here->x.time_value.month= (((data[1] & 0x1) << 3) |
1512 (data[0] >> 5));
1513 store_it_here->x.time_value.year= ((((uint)data[2]) << 7) |
1514 (data[1] >> 1));
1515 if (store_it_here->x.time_value.day > 31 ||
1516 store_it_here->x.time_value.month > 12 ||
1517 store_it_here->x.time_value.year > 9999)
1518 goto err;
1519 return ER_DYNCOL_OK;
1520
1521err:
1522 store_it_here->x.time_value.time_type= MYSQL_TIMESTAMP_ERROR;
1523 return ER_DYNCOL_FORMAT;
1524}
1525
1526
1527/**
1528 Append the string with given value.
1529
1530 @param str the string where to put the value
1531 @param value the value to put in the string
1532
1533 @return ER_DYNCOL_* return code
1534*/
1535
1536static enum enum_dyncol_func_result
1537data_store(DYNAMIC_COLUMN *str, DYNAMIC_COLUMN_VALUE *value,
1538 enum enum_dyncol_format format)
1539{
1540 switch (value->type) {
1541 case DYN_COL_INT:
1542 return dynamic_column_sint_store(str, value->x.long_value);
1543 case DYN_COL_UINT:
1544 return dynamic_column_uint_store(str, value->x.ulong_value);
1545 case DYN_COL_DOUBLE:
1546 return dynamic_column_double_store(str, value->x.double_value);
1547 case DYN_COL_STRING:
1548 return dynamic_column_string_store(str, &value->x.string.value,
1549 value->x.string.charset);
1550 case DYN_COL_DECIMAL:
1551 return dynamic_column_decimal_store(str, &value->x.decimal.value);
1552 case DYN_COL_DATETIME:
1553 /* date+time in bits: 14 + 4 + 5 + 5 + 6 + 6 40bits = 5 bytes */
1554 return dynamic_column_date_time_store(str, &value->x.time_value, format);
1555 case DYN_COL_DATE:
1556 /* date in dits: 14 + 4 + 5 = 23bits ~= 3bytes*/
1557 return dynamic_column_date_store(str, &value->x.time_value);
1558 case DYN_COL_TIME:
1559 /* time in bits: 5 + 6 + 6 = 17bits ~= 3bytes*/
1560 return dynamic_column_time_store(str, &value->x.time_value, format);
1561 case DYN_COL_DYNCOL:
1562 return dynamic_column_dyncol_store(str, &value->x.string.value);
1563 case DYN_COL_NULL:
1564 break; /* Impossible */
1565 }
1566 DBUG_ASSERT(0);
1567 return ER_DYNCOL_OK; /* Impossible */
1568}
1569
1570
1571/**
1572 Write information to the fixed header
1573
1574 @param str String where to write the header
1575 @param offset_size Size of offset field in bytes
1576 @param column_count Number of columns
1577*/
1578
1579static void set_fixed_header(DYNAMIC_COLUMN *str,
1580 uint offset_size,
1581 uint column_count)
1582{
1583 DBUG_ASSERT(column_count <= 0xffff);
1584 DBUG_ASSERT(offset_size <= MAX_OFFSET_LENGTH);
1585 str->str[0]= ((str->str[0] & ~DYNCOL_FLG_OFFSET) |
1586 (offset_size - 1)); /* size of offset */
1587 int2store(str->str + 1, column_count); /* columns number */
1588 DBUG_ASSERT((str->str[0] & (~DYNCOL_FLG_KNOWN)) == 0);
1589}
1590
1591/**
1592 Adds columns into the empty string
1593
1594 @param str String where to write the data (the record)
1595 @param hdr Dynamic columns record descriptor
1596 @param column_count Number of columns in the arrays
1597 @param column_keys Array of columns keys (uint or LEX_STRING)
1598 @param values Array of columns values
1599 @param new_str True if we need to allocate new string
1600
1601 @return ER_DYNCOL_* return code
1602*/
1603
1604static enum enum_dyncol_func_result
1605dynamic_new_column_store(DYNAMIC_COLUMN *str,
1606 DYN_HEADER *hdr,
1607 uint column_count,
1608 void *column_keys,
1609 DYNAMIC_COLUMN_VALUE *values,
1610 my_bool new_str)
1611{
1612 struct st_service_funcs *fmt= fmt_data + hdr->format;
1613 void **UNINIT_VAR(columns_order);
1614 uchar *element;
1615 uint i;
1616 enum enum_dyncol_func_result rc= ER_DYNCOL_RESOURCE;
1617 size_t all_headers_size;
1618
1619 if (column_count && !(columns_order= malloc(sizeof(void*)*column_count)))
1620 return ER_DYNCOL_RESOURCE;
1621 if (new_str || str->str == 0)
1622 {
1623 if (column_count)
1624 {
1625 if (dynamic_column_init_named(str,
1626 fmt->fixed_hdr +
1627 hdr->header_size +
1628 hdr->nmpool_size +
1629 hdr->data_size +
1630 DYNCOL_SYZERESERVE))
1631 goto err;
1632 }
1633 else
1634 {
1635 mariadb_dyncol_init(str);
1636 }
1637 }
1638 else
1639 {
1640 str->length= 0;
1641 if (dynstr_realloc(str,
1642 fmt->fixed_hdr +
1643 hdr->header_size +
1644 hdr->nmpool_size +
1645 hdr->data_size +
1646 DYNCOL_SYZERESERVE))
1647 goto err;
1648 }
1649 if (!column_count)
1650 return ER_DYNCOL_OK;
1651
1652 bzero(str->str, fmt->fixed_hdr);
1653 str->length= fmt->fixed_hdr;
1654
1655 /* sort columns for the header */
1656 for (i= 0, element= (uchar *) column_keys;
1657 i < column_count;
1658 i++, element+= fmt->key_size_in_array)
1659 columns_order[i]= (void *)element;
1660 qsort(columns_order, (size_t)column_count, sizeof(void*), fmt->column_sort);
1661
1662 /*
1663 For now we don't allow creating two columns with the same number
1664 at the time of create. This can be fixed later to just use the later
1665 by comparing the pointers.
1666 */
1667 for (i= 0; i < column_count - 1; i++)
1668 {
1669 if ((*fmt->check_limit)(&columns_order[i]) ||
1670 (*fmt->column_sort)(&columns_order[i], &columns_order[i + 1]) == 0)
1671 {
1672 rc= ER_DYNCOL_DATA;
1673 goto err;
1674 }
1675 }
1676 if ((*fmt->check_limit)(&columns_order[i]))
1677 {
1678 rc= ER_DYNCOL_DATA;
1679 goto err;
1680 }
1681
1682 (*fmt->set_fixed_hdr)(str, hdr);
1683 /* reserve place for header and name pool */
1684 str->length+= hdr->header_size + hdr->nmpool_size;
1685
1686 hdr->entry= hdr->header;
1687 hdr->name= hdr->nmpool;
1688 all_headers_size= fmt->fixed_hdr + hdr->header_size + hdr->nmpool_size;
1689 for (i= 0; i < column_count; i++)
1690 {
1691 uint ord= (uint)(((uchar*)columns_order[i] - (uchar*)column_keys) /
1692 fmt->key_size_in_array);
1693 if (values[ord].type != DYN_COL_NULL)
1694 {
1695 /* Store header first in the str */
1696 if ((*fmt->put_header_entry)(hdr, columns_order[i], values + ord,
1697 str->length - all_headers_size))
1698 {
1699 rc= ER_DYNCOL_FORMAT;
1700 goto err;
1701 }
1702
1703 /* Store value in 'str + str->length' and increase str->length */
1704 if ((rc= data_store(str, values + ord, hdr->format)))
1705 goto err;
1706 }
1707 }
1708 rc= ER_DYNCOL_OK;
1709err:
1710 free(columns_order);
1711 return rc;
1712}
1713
1714/**
1715 Calculate size of header, name pool and data pool
1716
1717 @param hdr descriptor of dynamic column record
1718 @param column_count number of elements in arrays
1719 @param column_count Number of columns in the arrays
1720 @param column_keys Array of columns keys (uint or LEX_STRING)
1721 @param values Array of columns values
1722
1723 @return ER_DYNCOL_* return code
1724*/
1725
1726static enum enum_dyncol_func_result
1727calc_var_sizes(DYN_HEADER *hdr,
1728 uint column_count,
1729 void *column_keys,
1730 DYNAMIC_COLUMN_VALUE *values)
1731{
1732 struct st_service_funcs *fmt= fmt_data + hdr->format;
1733 uint i;
1734 hdr->nmpool_size= hdr->data_size= 0;
1735 hdr->column_count= 0;
1736 for (i= 0; i < column_count; i++)
1737 {
1738 if (values[i].type != DYN_COL_NULL)
1739 {
1740 size_t tmp;
1741 hdr->column_count++;
1742 hdr->data_size+= (tmp= dynamic_column_value_len(values + i,
1743 hdr->format));
1744 if (tmp == (size_t) ~0)
1745 return ER_DYNCOL_DATA;
1746 hdr->nmpool_size+= (*fmt->name_size)(column_keys, i);
1747 }
1748 }
1749 /*
1750 We can handle data up to 0x1fffffff (old format) and
1751 0xfffffffff (new format) bytes now.
1752 */
1753 if ((hdr->offset_size= fmt->dynamic_column_offset_bytes(hdr->data_size)) >=
1754 fmt->max_offset_size)
1755 return ER_DYNCOL_LIMIT;
1756
1757 /* header entry is column number or string pointer + offset & type */
1758 hdr->entry_size= fmt->fixed_hdr_entry + hdr->offset_size;
1759 hdr->header_size= hdr->column_count * hdr->entry_size;
1760 return ER_DYNCOL_OK;
1761}
1762
1763/**
1764 Create packed string which contains given columns (internal multi format)
1765
1766 @param str String where to write the data
1767 @param column_count Number of columns in the arrays
1768 @param column_keys Array of columns keys (format dependent)
1769 @param values Array of columns values
1770 @param new_str True if we need allocate new string
1771 @param string_keys keys are strings
1772
1773 @return ER_DYNCOL_* return code
1774*/
1775
1776static enum enum_dyncol_func_result
1777dynamic_column_create_many_internal_fmt(DYNAMIC_COLUMN *str,
1778 uint column_count,
1779 void *column_keys,
1780 DYNAMIC_COLUMN_VALUE *values,
1781 my_bool new_str,
1782 my_bool string_keys)
1783{
1784 DYN_HEADER header;
1785 enum enum_dyncol_func_result rc;
1786 bzero(&header, sizeof(header));
1787 header.format= (string_keys ? 1 : 0);
1788
1789 if (new_str)
1790 {
1791 /* to make dynstr_free() working in case of errors */
1792 mariadb_dyncol_init(str);
1793 }
1794
1795 if ((rc= calc_var_sizes(&header, column_count, column_keys, values)) < 0)
1796 return rc;
1797
1798 return dynamic_new_column_store(str, &header,
1799 column_count,
1800 column_keys, values,
1801 new_str);
1802}
1803
1804
1805/**
1806 Create packed string which contains given columns
1807
1808 @param str String where to write the data
1809 @param column_count Number of columns in the arrays
1810 @param column_numbers Array of columns numbers
1811 @param values Array of columns values
1812
1813 @return ER_DYNCOL_* return code
1814*/
1815
1816enum enum_dyncol_func_result
1817dynamic_column_create_many(DYNAMIC_COLUMN *str,
1818 uint column_count,
1819 uint *column_numbers,
1820 DYNAMIC_COLUMN_VALUE *values)
1821{
1822 DBUG_ENTER("dynamic_column_create_many");
1823 DBUG_RETURN(dynamic_column_create_many_internal_fmt(str, column_count,
1824 column_numbers, values,
1825 TRUE, FALSE));
1826}
1827
1828/**
1829 Create packed string which contains given columns
1830
1831 @param str String where to write the data
1832 @param column_count Number of columns in the arrays
1833 @param column_numbers Array of columns numbers
1834 @param values Array of columns values
1835 @param new_string True if we need allocate new string
1836
1837 @return ER_DYNCOL_* return code
1838*/
1839
1840enum enum_dyncol_func_result
1841mariadb_dyncol_create_many_num(DYNAMIC_COLUMN *str,
1842 uint column_count,
1843 uint *column_numbers,
1844 DYNAMIC_COLUMN_VALUE *values,
1845 my_bool new_string)
1846{
1847 DBUG_ENTER("mariadb_dyncol_create_many_num");
1848 DBUG_RETURN(dynamic_column_create_many_internal_fmt(str, column_count,
1849 column_numbers, values,
1850 new_string, FALSE));
1851}
1852
1853/**
1854 Create packed string which contains given columns
1855
1856 @param str String where to write the data
1857 @param column_count Number of columns in the arrays
1858 @param column_keys Array of columns keys
1859 @param values Array of columns value
1860 @param new_string True if we need allocate new string
1861
1862 @return ER_DYNCOL_* return code
1863*/
1864
1865enum enum_dyncol_func_result
1866mariadb_dyncol_create_many_named(DYNAMIC_COLUMN *str,
1867 uint column_count,
1868 LEX_STRING *column_keys,
1869 DYNAMIC_COLUMN_VALUE *values,
1870 my_bool new_string)
1871{
1872 DBUG_ENTER("mariadb_dyncol_create_many_named");
1873 DBUG_RETURN(dynamic_column_create_many_internal_fmt(str, column_count,
1874 column_keys, values,
1875 new_string, TRUE));
1876}
1877
1878/**
1879 Create packed string which contains given column
1880
1881 @param str String where to write the data
1882 @param column_number Column number
1883 @param value The columns value
1884
1885 @return ER_DYNCOL_* return code
1886*/
1887
1888enum enum_dyncol_func_result
1889dynamic_column_create(DYNAMIC_COLUMN *str, uint column_nr,
1890 DYNAMIC_COLUMN_VALUE *value)
1891{
1892 DBUG_ENTER("dynamic_column_create");
1893 DBUG_RETURN(dynamic_column_create_many(str, 1, &column_nr, value));
1894}
1895
1896
1897/**
1898 Calculate length of data between given two header entries
1899
1900 @param entry Pointer to the first entry
1901 @param entry_next Pointer to the last entry
1902 @param header_end Pointer to the header end
1903 @param offset_size Size of offset field in bytes
1904 @param last_offset Size of the data segment
1905
1906 @return number of bytes
1907*/
1908
1909static size_t get_length_interval(uchar *entry, uchar *entry_next,
1910 uchar *header_end, size_t offset_size,
1911 size_t last_offset)
1912{
1913 size_t offset, offset_next;
1914 DYNAMIC_COLUMN_TYPE type, type_next;
1915 DBUG_ASSERT(entry < entry_next);
1916
1917 if (type_and_offset_read_num(&type, &offset, entry + COLUMN_NUMBER_SIZE,
1918 offset_size))
1919 return DYNCOL_OFFSET_ERROR;
1920 if (entry_next >= header_end)
1921 return (last_offset - offset);
1922 if (type_and_offset_read_num(&type_next, &offset_next,
1923 entry_next + COLUMN_NUMBER_SIZE, offset_size) ||
1924 (offset_next > last_offset))
1925 return DYNCOL_OFFSET_ERROR;
1926 return (offset_next - offset);
1927}
1928
1929
1930/**
1931 Calculate length of data between given hdr->entry and next_entry
1932
1933 @param hdr descriptor of dynamic column record
1934 @param next_entry next header entry (can point just after last header
1935 entry)
1936
1937 @return number of bytes
1938*/
1939
1940static size_t hdr_interval_length(DYN_HEADER *hdr, uchar *next_entry)
1941{
1942 struct st_service_funcs *fmt= fmt_data + hdr->format;
1943 size_t next_entry_offset;
1944 DYNAMIC_COLUMN_TYPE next_entry_type;
1945 DBUG_ASSERT(hdr->entry < next_entry);
1946 DBUG_ASSERT(hdr->entry >= hdr->header);
1947 DBUG_ASSERT(next_entry <= hdr->header + hdr->header_size);
1948
1949 if ((*fmt->type_and_offset_read)(&hdr->type, &hdr->offset,
1950 hdr->entry + fmt->fixed_hdr_entry,
1951 hdr->offset_size) ||
1952 hdr->data_size < hdr->offset)
1953 return DYNCOL_OFFSET_ERROR;
1954 if (next_entry == hdr->header + hdr->header_size)
1955 return hdr->data_size - hdr->offset;
1956 if ((*fmt->type_and_offset_read)(&next_entry_type, &next_entry_offset,
1957 next_entry + fmt->fixed_hdr_entry,
1958 hdr->offset_size) ||
1959 hdr->data_size < next_entry_offset)
1960 return DYNCOL_OFFSET_ERROR;
1961 return (next_entry_offset - hdr->offset);
1962}
1963
1964
1965/**
1966 Comparator function for references to header entries for qsort
1967*/
1968
1969static int header_compar_num(const void *a, const void *b)
1970{
1971 uint va= uint2korr((uchar*)a), vb= uint2korr((uchar*)b);
1972 return (va > vb ? 1 : (va < vb ? -1 : 0));
1973}
1974
1975
1976/**
1977 Find entry in the numeric format header by the column number
1978
1979 @param hdr descriptor of dynamic column record
1980 @param key number to find
1981
1982 @return pointer to the entry or NULL
1983*/
1984
1985static uchar *find_entry_num(DYN_HEADER *hdr, uint key)
1986{
1987 uchar header_entry[2+4];
1988 DBUG_ASSERT(hdr->format == dyncol_fmt_num);
1989 int2store(header_entry, key);
1990 return hdr->entry= bsearch(header_entry, hdr->header,
1991 (size_t)hdr->column_count,
1992 hdr->entry_size, &header_compar_num);
1993}
1994
1995
1996/**
1997 Read name from header entry
1998
1999 @param hdr descriptor of dynamic column record
2000 @param entry pointer to the header entry
2001 @param name where to put name
2002
2003 @return 0 ok
2004 @return 1 error in data
2005*/
2006
2007static my_bool read_name(DYN_HEADER *hdr, uchar *entry, LEX_STRING *name)
2008{
2009 size_t nmoffset= uint2korr(entry);
2010 uchar *next_entry= entry + hdr->entry_size;
2011
2012 if (nmoffset > hdr->nmpool_size)
2013 return 1;
2014
2015 name->str= (char *)hdr->nmpool + nmoffset;
2016 if (next_entry == hdr->header + hdr->header_size)
2017 name->length= hdr->nmpool_size - nmoffset;
2018 else
2019 {
2020 size_t next_nmoffset= uint2korr(next_entry);
2021 if (next_nmoffset > hdr->nmpool_size)
2022 return 1;
2023 name->length= next_nmoffset - nmoffset;
2024 }
2025 return 0;
2026}
2027
2028
2029/**
2030 Find entry in the names format header by the column number
2031
2032 @param hdr descriptor of dynamic column record
2033 @param key name to find
2034
2035 @return pointer to the entry or NULL
2036*/
2037static uchar *find_entry_named(DYN_HEADER *hdr, LEX_STRING *key)
2038{
2039 uchar *min= hdr->header;
2040 uchar *max= hdr->header + (hdr->column_count - 1) * hdr->entry_size;
2041 uchar *mid;
2042 DBUG_ASSERT(hdr->format == dyncol_fmt_str);
2043 DBUG_ASSERT(hdr->nmpool != NULL);
2044 while (max >= min)
2045 {
2046 LEX_STRING name;
2047 int cmp;
2048 mid= hdr->header + ((min - hdr->header) +
2049 (max - hdr->header)) /
2050 2 /
2051 hdr->entry_size * hdr->entry_size;
2052 if (read_name(hdr, mid, &name))
2053 return NULL;
2054 cmp= mariadb_dyncol_column_cmp_named(&name, key);
2055 if (cmp < 0)
2056 min= mid + hdr->entry_size;
2057 else if (cmp > 0)
2058 max= mid - hdr->entry_size;
2059 else
2060 return mid;
2061 }
2062 return NULL;
2063}
2064
2065
2066/**
2067 Write number in the buffer (backward direction - starts from the buffer end)
2068
2069 @return pointer on the number beginning
2070*/
2071
2072static char *backwritenum(char *chr, uint numkey)
2073{
2074 if (numkey == 0)
2075 *(--chr)= '0';
2076 else
2077 while (numkey > 0)
2078 {
2079 *(--chr)= '0' + numkey % 10;
2080 numkey/= 10;
2081 }
2082 return chr;
2083}
2084
2085
2086/**
2087 Find column and fill information about it
2088
2089 @param hdr descriptor of dynamic column record
2090 @param numkey Number of the column to fetch (if strkey is NULL)
2091 @param strkey Name of the column to fetch (or NULL)
2092
2093 @return 0 ok
2094 @return 1 error in data
2095*/
2096
2097static my_bool
2098find_column(DYN_HEADER *hdr, uint numkey, LEX_STRING *strkey)
2099{
2100 LEX_STRING nmkey;
2101 char nmkeybuff[DYNCOL_NUM_CHAR]; /* to fit max 2 bytes number */
2102 DBUG_ASSERT(hdr->header != NULL);
2103
2104 if (hdr->header + hdr->header_size > hdr->data_end)
2105 return TRUE;
2106
2107 /* fix key */
2108 if (hdr->format == dyncol_fmt_num && strkey != NULL)
2109 {
2110 char *end;
2111 numkey= (uint) strtoul(strkey->str, &end, 10);
2112 if (end != strkey->str + strkey->length)
2113 {
2114 /* we can't find non-numeric key among numeric ones */
2115 hdr->type= DYN_COL_NULL;
2116 return 0;
2117 }
2118 }
2119 else if (hdr->format == dyncol_fmt_str && strkey == NULL)
2120 {
2121 nmkey.str= backwritenum(nmkeybuff + sizeof(nmkeybuff), numkey);
2122 nmkey.length= (nmkeybuff + sizeof(nmkeybuff)) - nmkey.str;
2123 strkey= &nmkey;
2124 }
2125 if (hdr->format == dyncol_fmt_num)
2126 hdr->entry= find_entry_num(hdr, numkey);
2127 else
2128 hdr->entry= find_entry_named(hdr, strkey);
2129
2130 if (!hdr->entry)
2131 {
2132 /* Column not found */
2133 hdr->type= DYN_COL_NULL;
2134 return 0;
2135 }
2136 hdr->length= hdr_interval_length(hdr, hdr->entry + hdr->entry_size);
2137 hdr->data= hdr->dtpool + hdr->offset;
2138 /*
2139 Check that the found data is within the ranges. This can happen if
2140 we get data with wrong offsets.
2141 */
2142 if (hdr->length == DYNCOL_OFFSET_ERROR ||
2143 hdr->length > INT_MAX || hdr->offset > hdr->data_size)
2144 return 1;
2145
2146 return 0;
2147}
2148
2149
2150/**
2151 Read and check the header of the dynamic string
2152
2153 @param hdr descriptor of dynamic column record
2154 @param str Dynamic string
2155
2156 @retval FALSE OK
2157 @retval TRUE error
2158
2159 Note
2160 We don't check for str->length == 0 as all code that calls this
2161 already have handled this case.
2162*/
2163
2164static inline my_bool read_fixed_header(DYN_HEADER *hdr,
2165 DYNAMIC_COLUMN *str)
2166{
2167 DBUG_ASSERT(str != NULL && str->length != 0);
2168 if ((str->length < 1) ||
2169 (str->str[0] & (~DYNCOL_FLG_KNOWN)))
2170 return 1;
2171 hdr->format= ((str->str[0] & DYNCOL_FLG_NAMES) ?
2172 dyncol_fmt_str:
2173 dyncol_fmt_num);
2174 if ((str->length < fmt_data[hdr->format].fixed_hdr))
2175 return 1; /* Wrong header */
2176 hdr->offset_size= (str->str[0] & DYNCOL_FLG_OFFSET) + 1 +
2177 (hdr->format == dyncol_fmt_str ? 1 : 0);
2178 hdr->column_count= uint2korr(str->str + 1);
2179 if (hdr->format == dyncol_fmt_str)
2180 hdr->nmpool_size= uint2korr(str->str + 3); // only 2 bytes supported for now
2181 else
2182 hdr->nmpool_size= 0;
2183 return 0;
2184}
2185
2186
2187/**
2188 Get dynamic column value by column number
2189
2190 @param str The packed string to extract the column
2191 @param column_nr Number of column to fetch
2192 @param store_it_here Where to store the extracted value
2193
2194 @return ER_DYNCOL_* return code
2195*/
2196
2197enum enum_dyncol_func_result
2198dynamic_column_get(DYNAMIC_COLUMN *str, uint column_nr,
2199 DYNAMIC_COLUMN_VALUE *store_it_here)
2200{
2201 return dynamic_column_get_internal(str, store_it_here, column_nr, NULL);
2202}
2203
2204enum enum_dyncol_func_result
2205mariadb_dyncol_get_num(DYNAMIC_COLUMN *str, uint column_nr,
2206 DYNAMIC_COLUMN_VALUE *store_it_here)
2207{
2208 return dynamic_column_get_internal(str, store_it_here, column_nr, NULL);
2209}
2210
2211
2212/**
2213 Get dynamic column value by name
2214
2215 @param str The packed string to extract the column
2216 @param name Name of column to fetch
2217 @param store_it_here Where to store the extracted value
2218
2219 @return ER_DYNCOL_* return code
2220*/
2221
2222enum enum_dyncol_func_result
2223mariadb_dyncol_get_named(DYNAMIC_COLUMN *str, LEX_STRING *name,
2224 DYNAMIC_COLUMN_VALUE *store_it_here)
2225{
2226 DBUG_ASSERT(name != NULL);
2227 return dynamic_column_get_internal(str, store_it_here, 0, name);
2228}
2229
2230
2231static enum enum_dyncol_func_result
2232dynamic_column_get_value(DYN_HEADER *hdr, DYNAMIC_COLUMN_VALUE *store_it_here)
2233{
2234 static enum enum_dyncol_func_result rc;
2235 switch ((store_it_here->type= hdr->type)) {
2236 case DYN_COL_INT:
2237 rc= dynamic_column_sint_read(store_it_here, hdr->data, hdr->length);
2238 break;
2239 case DYN_COL_UINT:
2240 rc= dynamic_column_uint_read(store_it_here, hdr->data, hdr->length);
2241 break;
2242 case DYN_COL_DOUBLE:
2243 rc= dynamic_column_double_read(store_it_here, hdr->data, hdr->length);
2244 break;
2245 case DYN_COL_STRING:
2246 rc= dynamic_column_string_read(store_it_here, hdr->data, hdr->length);
2247 break;
2248 case DYN_COL_DECIMAL:
2249 rc= dynamic_column_decimal_read(store_it_here, hdr->data, hdr->length);
2250 break;
2251 case DYN_COL_DATETIME:
2252 rc= dynamic_column_date_time_read(store_it_here, hdr->data,
2253 hdr->length);
2254 break;
2255 case DYN_COL_DATE:
2256 rc= dynamic_column_date_read(store_it_here, hdr->data, hdr->length);
2257 break;
2258 case DYN_COL_TIME:
2259 rc= dynamic_column_time_read(store_it_here, hdr->data, hdr->length);
2260 break;
2261 case DYN_COL_NULL:
2262 rc= ER_DYNCOL_OK;
2263 break;
2264 case DYN_COL_DYNCOL:
2265 rc= dynamic_column_dyncol_read(store_it_here, hdr->data, hdr->length);
2266 break;
2267 default:
2268 rc= ER_DYNCOL_FORMAT;
2269 store_it_here->type= DYN_COL_NULL;
2270 break;
2271 }
2272 return rc;
2273}
2274
2275/**
2276 Get dynamic column value by number or name
2277
2278 @param str The packed string to extract the column
2279 @param store_it_here Where to store the extracted value
2280 @param numkey Number of the column to fetch (if strkey is NULL)
2281 @param strkey Name of the column to fetch (or NULL)
2282
2283 @return ER_DYNCOL_* return code
2284*/
2285
2286static enum enum_dyncol_func_result
2287dynamic_column_get_internal(DYNAMIC_COLUMN *str,
2288 DYNAMIC_COLUMN_VALUE *store_it_here,
2289 uint num_key, LEX_STRING *str_key)
2290{
2291 DYN_HEADER header;
2292 enum enum_dyncol_func_result rc= ER_DYNCOL_FORMAT;
2293 bzero(&header, sizeof(header));
2294
2295 if (str->length == 0)
2296 goto null;
2297
2298 if ((rc= init_read_hdr(&header, str)) < 0)
2299 goto err;
2300
2301 if (header.column_count == 0)
2302 goto null;
2303
2304 if (find_column(&header, num_key, str_key))
2305 goto err;
2306
2307 rc= dynamic_column_get_value(&header, store_it_here);
2308 return rc;
2309
2310null:
2311 rc= ER_DYNCOL_OK;
2312err:
2313 store_it_here->type= DYN_COL_NULL;
2314 return rc;
2315}
2316
2317
2318/**
2319 Check existence of the column in the packed string (by number)
2320
2321 @param str The packed string to check the column
2322 @param column_nr Number of column to check
2323
2324 @return ER_DYNCOL_* return code
2325*/
2326
2327enum enum_dyncol_func_result
2328dynamic_column_exists(DYNAMIC_COLUMN *str, uint column_nr)
2329{
2330 return dynamic_column_exists_internal(str, column_nr, NULL);
2331}
2332
2333enum enum_dyncol_func_result
2334mariadb_dyncol_exists_num(DYNAMIC_COLUMN *str, uint column_nr)
2335{
2336 return dynamic_column_exists_internal(str, column_nr, NULL);
2337}
2338
2339/**
2340 Check existence of the column in the packed string (by name)
2341
2342 @param str The packed string to check the column
2343 @param name Name of column to check
2344
2345 @return ER_DYNCOL_* return code
2346*/
2347
2348enum enum_dyncol_func_result
2349mariadb_dyncol_exists_named(DYNAMIC_COLUMN *str, LEX_STRING *name)
2350{
2351 DBUG_ASSERT(name != NULL);
2352 return dynamic_column_exists_internal(str, 0, name);
2353}
2354
2355
2356/**
2357 Check existence of the column in the packed string (by name of number)
2358
2359 @param str The packed string to check the column
2360 @param num_key Number of the column to fetch (if strkey is NULL)
2361 @param str_key Name of the column to fetch (or NULL)
2362
2363 @return ER_DYNCOL_* return code
2364*/
2365
2366static enum enum_dyncol_func_result
2367dynamic_column_exists_internal(DYNAMIC_COLUMN *str, uint num_key,
2368 LEX_STRING *str_key)
2369{
2370 DYN_HEADER header;
2371 enum enum_dyncol_func_result rc;
2372 bzero(&header, sizeof(header));
2373
2374 if (str->length == 0)
2375 return ER_DYNCOL_NO; /* no columns */
2376
2377 if ((rc= init_read_hdr(&header, str)) < 0)
2378 return rc;
2379
2380 if (header.column_count == 0)
2381 return ER_DYNCOL_NO; /* no columns */
2382
2383 if (find_column(&header, num_key, str_key))
2384 return ER_DYNCOL_FORMAT;
2385
2386 return (header.type != DYN_COL_NULL ? ER_DYNCOL_YES : ER_DYNCOL_NO);
2387}
2388
2389
2390/**
2391 List not-null columns in the packed string (only numeric format)
2392
2393 @param str The packed string
2394 @param array_of_uint Where to put reference on created array
2395
2396 @return ER_DYNCOL_* return code
2397*/
2398enum enum_dyncol_func_result
2399dynamic_column_list(DYNAMIC_COLUMN *str, DYNAMIC_ARRAY *array_of_uint)
2400{
2401 DYN_HEADER header;
2402 uchar *read;
2403 uint i;
2404 enum enum_dyncol_func_result rc;
2405
2406 bzero(array_of_uint, sizeof(*array_of_uint)); /* In case of errors */
2407 if (str->length == 0)
2408 return ER_DYNCOL_OK; /* no columns */
2409
2410 if ((rc= init_read_hdr(&header, str)) < 0)
2411 return rc;
2412
2413 if (header.format != dyncol_fmt_num)
2414 return ER_DYNCOL_FORMAT;
2415
2416 if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
2417 str->length)
2418 return ER_DYNCOL_FORMAT;
2419
2420 if (my_init_dynamic_array(array_of_uint, sizeof(uint), header.column_count,
2421 0, MYF(0)))
2422 return ER_DYNCOL_RESOURCE;
2423
2424 for (i= 0, read= header.header;
2425 i < header.column_count;
2426 i++, read+= header.entry_size)
2427 {
2428 uint nm= uint2korr(read);
2429 /* Insert can't never fail as it's pre-allocated above */
2430 (void) insert_dynamic(array_of_uint, (uchar *)&nm);
2431 }
2432 return ER_DYNCOL_OK;
2433}
2434
2435/**
2436 List not-null columns in the packed string (only numeric format)
2437
2438 @param str The packed string
2439 @param array_of_uint Where to put reference on created array
2440
2441 @return ER_DYNCOL_* return code
2442*/
2443enum enum_dyncol_func_result
2444mariadb_dyncol_list_num(DYNAMIC_COLUMN *str, uint *count, uint **nums)
2445{
2446 DYN_HEADER header;
2447 uchar *read;
2448 uint i;
2449 enum enum_dyncol_func_result rc;
2450
2451 (*nums)= 0; (*count)= 0; /* In case of errors */
2452
2453 if (str->length == 0)
2454 return ER_DYNCOL_OK; /* no columns */
2455
2456 if ((rc= init_read_hdr(&header, str)) < 0)
2457 return rc;
2458
2459 if (header.format != dyncol_fmt_num)
2460 return ER_DYNCOL_FORMAT;
2461
2462 if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
2463 str->length)
2464 return ER_DYNCOL_FORMAT;
2465
2466 if (!((*nums)= my_malloc(sizeof(uint) * header.column_count, MYF(0))))
2467 return ER_DYNCOL_RESOURCE;
2468
2469 for (i= 0, read= header.header;
2470 i < header.column_count;
2471 i++, read+= header.entry_size)
2472 {
2473 (*nums)[i]= uint2korr(read);
2474 }
2475 (*count)= header.column_count;
2476 return ER_DYNCOL_OK;
2477}
2478
2479/**
2480 List not-null columns in the packed string (any format)
2481
2482 @param str The packed string
2483 @param count Number of names in the list
2484 @param names Where to put names list (should be freed)
2485
2486 @return ER_DYNCOL_* return code
2487*/
2488
2489enum enum_dyncol_func_result
2490mariadb_dyncol_list_named(DYNAMIC_COLUMN *str, uint *count, LEX_STRING **names)
2491{
2492 DYN_HEADER header;
2493 uchar *read;
2494 char *pool;
2495 struct st_service_funcs *fmt;
2496 uint i;
2497 enum enum_dyncol_func_result rc;
2498
2499 (*names)= 0; (*count)= 0;
2500
2501 if (str->length == 0)
2502 return ER_DYNCOL_OK; /* no columns */
2503
2504 if ((rc= init_read_hdr(&header, str)) < 0)
2505 return rc;
2506
2507 fmt= fmt_data + header.format;
2508
2509 if (header.entry_size * header.column_count + fmt->fixed_hdr >
2510 str->length)
2511 return ER_DYNCOL_FORMAT;
2512
2513 if (header.format == dyncol_fmt_num)
2514 *names= my_malloc(sizeof(LEX_STRING) * header.column_count +
2515 DYNCOL_NUM_CHAR * header.column_count, MYF(0));
2516 else
2517 *names= my_malloc(sizeof(LEX_STRING) * header.column_count +
2518 header.nmpool_size + header.column_count, MYF(0));
2519 if (!(*names))
2520 return ER_DYNCOL_RESOURCE;
2521 pool= ((char *)(*names)) + sizeof(LEX_STRING) * header.column_count;
2522
2523 for (i= 0, read= header.header;
2524 i < header.column_count;
2525 i++, read+= header.entry_size)
2526 {
2527 if (header.format == dyncol_fmt_num)
2528 {
2529 uint nm= uint2korr(read);
2530 (*names)[i].str= pool;
2531 pool+= DYNCOL_NUM_CHAR;
2532 (*names)[i].length=
2533 longlong2str(nm, (*names)[i].str, 10) - (*names)[i].str;
2534 }
2535 else
2536 {
2537 LEX_STRING tmp;
2538 if (read_name(&header, read, &tmp))
2539 return ER_DYNCOL_FORMAT;
2540 (*names)[i].length= tmp.length;
2541 (*names)[i].str= pool;
2542 pool+= tmp.length + 1;
2543 memcpy((*names)[i].str, (const void *)tmp.str, tmp.length);
2544 (*names)[i].str[tmp.length]= '\0'; // just for safety
2545 }
2546 }
2547 (*count)= header.column_count;
2548 return ER_DYNCOL_OK;
2549}
2550
2551/**
2552 Find the place of the column in the header or place where it should be put
2553
2554 @param hdr descriptor of dynamic column record
2555 @param key Name or number of column to fetch
2556 (depends on string_key)
2557 @param string_key True if we gave pointer to LEX_STRING.
2558
2559 @retval TRUE found
2560 @retval FALSE pointer set to the next row
2561*/
2562
2563static my_bool
2564find_place(DYN_HEADER *hdr, void *key, my_bool string_keys)
2565{
2566 uint mid, start, end, val;
2567 int UNINIT_VAR(flag);
2568 LEX_STRING str;
2569 char buff[DYNCOL_NUM_CHAR];
2570 my_bool need_conversion= ((string_keys ? dyncol_fmt_str : dyncol_fmt_num) !=
2571 hdr->format);
2572 /* new format can't be numeric if the old one is names */
2573 DBUG_ASSERT(string_keys ||
2574 hdr->format == dyncol_fmt_num);
2575
2576 start= 0;
2577 end= hdr->column_count -1;
2578 mid= 1;
2579 while (start != end)
2580 {
2581 mid= (start + end) / 2;
2582 hdr->entry= hdr->header + mid * hdr->entry_size;
2583 if (!string_keys)
2584 {
2585 val= uint2korr(hdr->entry);
2586 flag= CMP_NUM(*((uint *)key), val);
2587 }
2588 else
2589 {
2590 if (need_conversion)
2591 {
2592 str.str= backwritenum(buff + sizeof(buff), uint2korr(hdr->entry));
2593 str.length= (buff + sizeof(buff)) - str.str;
2594 }
2595 else
2596 {
2597 DBUG_ASSERT(hdr->format == dyncol_fmt_str);
2598 if (read_name(hdr, hdr->entry, &str))
2599 return 0;
2600 }
2601 flag= mariadb_dyncol_column_cmp_named((LEX_STRING *)key, &str);
2602 }
2603 if (flag <= 0)
2604 end= mid;
2605 else
2606 start= mid + 1;
2607 }
2608 hdr->entry= hdr->header + start * hdr->entry_size;
2609 if (start != mid)
2610 {
2611 if (!string_keys)
2612 {
2613 val= uint2korr(hdr->entry);
2614 flag= CMP_NUM(*((uint *)key), val);
2615 }
2616 else
2617 {
2618 if (need_conversion)
2619 {
2620 str.str= backwritenum(buff + sizeof(buff), uint2korr(hdr->entry));
2621 str.length= (buff + sizeof(buff)) - str.str;
2622 }
2623 else
2624 {
2625 DBUG_ASSERT(hdr->format == dyncol_fmt_str);
2626 if (read_name(hdr, hdr->entry, &str))
2627 return 0;
2628 }
2629 flag= mariadb_dyncol_column_cmp_named((LEX_STRING *)key, &str);
2630 }
2631 }
2632 if (flag > 0)
2633 hdr->entry+= hdr->entry_size; /* Point at next bigger key */
2634 return flag == 0;
2635}
2636
2637
2638/*
2639 It is internal structure which describes a plan of changing the record
2640 of dynamic columns
2641*/
2642
2643typedef enum {PLAN_REPLACE, PLAN_ADD, PLAN_DELETE, PLAN_NOP} PLAN_ACT;
2644
2645struct st_plan {
2646 DYNAMIC_COLUMN_VALUE *val;
2647 void *key;
2648 uchar *place;
2649 size_t length;
2650 long long hdelta, ddelta, ndelta;
2651 long long mv_offset, mv_length;
2652 uint mv_end;
2653 PLAN_ACT act;
2654};
2655typedef struct st_plan PLAN;
2656
2657
2658/**
2659 Sort function for plan by column number
2660*/
2661
2662static int plan_sort_num(const void *a, const void *b)
2663{
2664 return *((uint *)((PLAN *)a)->key) - *((uint *)((PLAN *)b)->key);
2665}
2666
2667
2668/**
2669 Sort function for plan by column name
2670*/
2671
2672static int plan_sort_named(const void *a, const void *b)
2673{
2674 return mariadb_dyncol_column_cmp_named((LEX_STRING *)((PLAN *)a)->key,
2675 (LEX_STRING *)((PLAN *)b)->key);
2676}
2677
2678#define DELTA_CHECK(S, D, C) \
2679 if ((S) == 0) \
2680 (S)= (D); \
2681 else if (((S) > 0 && (D) < 0) || \
2682 ((S) < 0 && (D) > 0)) \
2683 { \
2684 (C)= TRUE; \
2685 }
2686
2687/**
2688 Update dynamic column by copying in a new record (string).
2689
2690 @param str Dynamic column record to change
2691 @param plan Plan of changing the record
2692 @param add_column_count number of records in the plan array.
2693 @param hdr descriptor of old dynamic column record
2694 @param new_hdr descriptor of new dynamic column record
2695 @param convert need conversion from numeric to names format
2696
2697 @return ER_DYNCOL_* return code
2698*/
2699
2700static enum enum_dyncol_func_result
2701dynamic_column_update_copy(DYNAMIC_COLUMN *str, PLAN *plan,
2702 uint add_column_count,
2703 DYN_HEADER *hdr, DYN_HEADER *new_hdr,
2704 my_bool convert)
2705{
2706 DYNAMIC_COLUMN tmp;
2707 struct st_service_funcs *fmt= fmt_data + hdr->format,
2708 *new_fmt= fmt_data + new_hdr->format;
2709 uint i, j, k;
2710 size_t all_headers_size;
2711
2712 if (dynamic_column_init_named(&tmp,
2713 (new_fmt->fixed_hdr + new_hdr->header_size +
2714 new_hdr->nmpool_size +
2715 new_hdr->data_size + DYNCOL_SYZERESERVE)))
2716 {
2717 return ER_DYNCOL_RESOURCE;
2718 }
2719 bzero(tmp.str, new_fmt->fixed_hdr);
2720 (*new_fmt->set_fixed_hdr)(&tmp, new_hdr);
2721 /* Adjust tmp to contain whole the future header */
2722 tmp.length= new_fmt->fixed_hdr + new_hdr->header_size + new_hdr->nmpool_size;
2723
2724
2725 /*
2726 Copy data to the new string
2727 i= index in array of changes
2728 j= index in packed string header index
2729 */
2730 new_hdr->entry= new_hdr->header;
2731 new_hdr->name= new_hdr->nmpool;
2732 all_headers_size= new_fmt->fixed_hdr +
2733 new_hdr->header_size + new_hdr->nmpool_size;
2734 for (i= 0, j= 0; i < add_column_count || j < hdr->column_count; i++)
2735 {
2736 size_t UNINIT_VAR(first_offset);
2737 uint start= j, end;
2738
2739 /*
2740 Search in i and j for the next column to add from i and where to
2741 add.
2742 */
2743
2744 while (i < add_column_count && plan[i].act == PLAN_NOP)
2745 i++; /* skip NOP */
2746
2747 if (i == add_column_count)
2748 j= end= hdr->column_count;
2749 else
2750 {
2751 /*
2752 old data portion. We don't need to check that j < column_count
2753 as plan[i].place is guaranteed to have a pointer inside the
2754 data.
2755 */
2756 while (hdr->header + j * hdr->entry_size < plan[i].place)
2757 j++;
2758 end= j;
2759 if ((plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
2760 j++; /* data at 'j' will be removed */
2761 }
2762
2763 /*
2764 Adjust all headers since last loop.
2765 We have to do this as the offset for data has moved
2766 */
2767 for (k= start; k < end; k++)
2768 {
2769 uchar *read= hdr->header + k * hdr->entry_size;
2770 void *key;
2771 LEX_STRING name;
2772 size_t offs;
2773 uint nm;
2774 DYNAMIC_COLUMN_TYPE tp;
2775 char buff[DYNCOL_NUM_CHAR];
2776
2777 if (hdr->format == dyncol_fmt_num)
2778 {
2779 if (convert)
2780 {
2781 name.str= backwritenum(buff + sizeof(buff), uint2korr(read));
2782 name.length= (buff + sizeof(buff)) - name.str;
2783 key= &name;
2784 }
2785 else
2786 {
2787 nm= uint2korr(read); /* Column nummber */
2788 key= &nm;
2789 }
2790 }
2791 else
2792 {
2793 if (read_name(hdr, read, &name))
2794 goto err;
2795 key= &name;
2796 }
2797 if (fmt->type_and_offset_read(&tp, &offs,
2798 read + fmt->fixed_hdr_entry,
2799 hdr->offset_size))
2800 goto err;
2801 if (k == start)
2802 first_offset= offs;
2803 else if (offs < first_offset)
2804 goto err;
2805
2806 offs+= (size_t) plan[i].ddelta;
2807 {
2808 DYNAMIC_COLUMN_VALUE val;
2809 val.type= tp; // only the type used in the header
2810 if ((*new_fmt->put_header_entry)(new_hdr, key, &val, offs))
2811 goto err;
2812 }
2813 }
2814
2815 /* copy first the data that was not replaced in original packed data */
2816 if (start < end)
2817 {
2818 size_t data_size;
2819 /* Add old data last in 'tmp' */
2820 hdr->entry= hdr->header + start * hdr->entry_size;
2821 data_size=
2822 hdr_interval_length(hdr, hdr->header + end * hdr->entry_size);
2823 if (data_size == DYNCOL_OFFSET_ERROR ||
2824 (long) data_size < 0 ||
2825 data_size > hdr->data_size - first_offset)
2826 goto err;
2827
2828 memcpy(tmp.str + tmp.length, (char *)hdr->dtpool + first_offset,
2829 data_size);
2830 tmp.length+= data_size;
2831 }
2832
2833 /* new data adding */
2834 if (i < add_column_count)
2835 {
2836 if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
2837 {
2838 if ((*new_fmt->put_header_entry)(new_hdr, plan[i].key,
2839 plan[i].val,
2840 tmp.length - all_headers_size))
2841 goto err;
2842 data_store(&tmp, plan[i].val, new_hdr->format); /* Append new data */
2843 }
2844 }
2845 }
2846 mariadb_dyncol_free(str);
2847 *str= tmp;
2848 return ER_DYNCOL_OK;
2849err:
2850 mariadb_dyncol_free(&tmp);
2851 return ER_DYNCOL_FORMAT;
2852}
2853
2854static enum enum_dyncol_func_result
2855dynamic_column_update_move_left(DYNAMIC_COLUMN *str, PLAN *plan,
2856 size_t offset_size,
2857 size_t entry_size,
2858 size_t header_size,
2859 size_t new_offset_size,
2860 size_t new_entry_size,
2861 size_t new_header_size,
2862 uint column_count,
2863 uint new_column_count,
2864 uint add_column_count,
2865 uchar *header_end,
2866 size_t max_offset)
2867{
2868 uchar *write;
2869 uchar *header_base= (uchar *)str->str + FIXED_HEADER_SIZE;
2870 uint i, j, k;
2871 size_t curr_offset;
2872
2873 write= (uchar *)str->str + FIXED_HEADER_SIZE;
2874 set_fixed_header(str, (uint)new_offset_size, new_column_count);
2875
2876 /*
2877 Move headers first.
2878 i= index in array of changes
2879 j= index in packed string header index
2880 */
2881 for (curr_offset= 0, i= 0, j= 0;
2882 i < add_column_count || j < column_count;
2883 i++)
2884 {
2885 size_t UNINIT_VAR(first_offset);
2886 uint start= j, end;
2887
2888 /*
2889 Search in i and j for the next column to add from i and where to
2890 add.
2891 */
2892
2893 while (i < add_column_count && plan[i].act == PLAN_NOP)
2894 i++; /* skip NOP */
2895
2896 if (i == add_column_count)
2897 j= end= column_count;
2898 else
2899 {
2900 /*
2901 old data portion. We don't need to check that j < column_count
2902 as plan[i].place is guaranteed to have a pointer inside the
2903 data.
2904 */
2905 while (header_base + j * entry_size < plan[i].place)
2906 j++;
2907 end= j;
2908 if ((plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
2909 j++; /* data at 'j' will be removed */
2910 }
2911 plan[i].mv_end= end;
2912
2913 {
2914 DYNAMIC_COLUMN_TYPE tp;
2915 if (type_and_offset_read_num(&tp, &first_offset,
2916 header_base + start * entry_size +
2917 COLUMN_NUMBER_SIZE, offset_size))
2918 return ER_DYNCOL_FORMAT;
2919 }
2920 /* find data to be moved */
2921 if (start < end)
2922 {
2923 size_t data_size=
2924 get_length_interval(header_base + start * entry_size,
2925 header_base + end * entry_size,
2926 header_end, offset_size, max_offset);
2927 if (data_size == DYNCOL_OFFSET_ERROR ||
2928 (long) data_size < 0 ||
2929 data_size > max_offset - first_offset)
2930 {
2931 str->length= 0; // just something valid
2932 return ER_DYNCOL_FORMAT;
2933 }
2934 DBUG_ASSERT(curr_offset == first_offset + plan[i].ddelta);
2935 plan[i].mv_offset= first_offset;
2936 plan[i].mv_length= data_size;
2937 curr_offset+= data_size;
2938 }
2939 else
2940 {
2941 plan[i].mv_length= 0;
2942 plan[i].mv_offset= curr_offset;
2943 }
2944
2945 if (plan[i].ddelta == 0 && offset_size == new_offset_size &&
2946 plan[i].act != PLAN_DELETE)
2947 write+= entry_size * (end - start);
2948 else
2949 {
2950 /*
2951 Adjust all headers since last loop.
2952 We have to do this as the offset for data has moved
2953 */
2954 for (k= start; k < end; k++)
2955 {
2956 uchar *read= header_base + k * entry_size;
2957 size_t offs;
2958 uint nm;
2959 DYNAMIC_COLUMN_TYPE tp;
2960
2961 nm= uint2korr(read); /* Column nummber */
2962 if (type_and_offset_read_num(&tp, &offs, read + COLUMN_NUMBER_SIZE,
2963 offset_size))
2964 return ER_DYNCOL_FORMAT;
2965
2966 if (k > start && offs < first_offset)
2967 {
2968 str->length= 0; // just something valid
2969 return ER_DYNCOL_FORMAT;
2970 }
2971
2972 offs+= (size_t) plan[i].ddelta;
2973 int2store(write, nm);
2974 /* write rest of data at write + COLUMN_NUMBER_SIZE */
2975 type_and_offset_store_num(write, new_offset_size, tp, offs);
2976 write+= new_entry_size;
2977 }
2978 }
2979
2980 /* new data adding */
2981 if (i < add_column_count)
2982 {
2983 if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
2984 {
2985 int2store(write, *((uint *)plan[i].key));
2986 type_and_offset_store_num(write, new_offset_size,
2987 plan[i].val[0].type,
2988 curr_offset);
2989 write+= new_entry_size;
2990 curr_offset+= plan[i].length;
2991 }
2992 }
2993 }
2994
2995 /*
2996 Move data.
2997 i= index in array of changes
2998 j= index in packed string header index
2999 */
3000 str->length= (FIXED_HEADER_SIZE + new_header_size);
3001 for (i= 0, j= 0;
3002 i < add_column_count || j < column_count;
3003 i++)
3004 {
3005 uint start= j, end;
3006
3007 /*
3008 Search in i and j for the next column to add from i and where to
3009 add.
3010 */
3011
3012 while (i < add_column_count && plan[i].act == PLAN_NOP)
3013 i++; /* skip NOP */
3014
3015 j= end= plan[i].mv_end;
3016 if (i != add_column_count &&
3017 (plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
3018 j++;
3019
3020 /* copy first the data that was not replaced in original packed data */
3021 if (start < end && plan[i].mv_length)
3022 {
3023 memmove((header_base + new_header_size +
3024 plan[i].mv_offset + plan[i].ddelta),
3025 header_base + header_size + plan[i].mv_offset,
3026 (size_t) plan[i].mv_length);
3027 }
3028 str->length+= (size_t) plan[i].mv_length;
3029
3030 /* new data adding */
3031 if (i < add_column_count)
3032 {
3033 if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
3034 {
3035 data_store(str, plan[i].val, dyncol_fmt_num);/* Append new data */
3036 }
3037 }
3038 }
3039 return ER_DYNCOL_OK;
3040}
3041
3042#ifdef UNUSED
3043static enum enum_dyncol_func_result
3044dynamic_column_update_move_right(DYNAMIC_COLUMN *str, PLAN *plan,
3045 size_t offset_size,
3046 size_t entry_size,
3047 size_t header_size,
3048 size_t new_offset_size,
3049 size_t new_entry_size,
3050 size_t new_header_size,
3051 uint column_count,
3052 uint new_column_count,
3053 uint add_column_count,
3054 uchar *header_end,
3055 size_t max_offset)
3056{
3057 uchar *write;
3058 uchar *header_base= (uchar *)str->str + FIXED_HEADER_SIZE;
3059 uint i, j, k;
3060 size_t curr_offset;
3061
3062 write= (uchar *)str->str + FIXED_HEADER_SIZE;
3063 set_fixed_header(str, new_offset_size, new_column_count);
3064
3065 /*
3066 Move data first.
3067 i= index in array of changes
3068 j= index in packed string header index
3069 */
3070 for (curr_offset= 0, i= 0, j= 0;
3071 i < add_column_count || j < column_count;
3072 i++)
3073 {
3074 size_t UNINIT_VAR(first_offset);
3075 uint start= j, end;
3076
3077 /*
3078 Search in i and j for the next column to add from i and where to
3079 add.
3080 */
3081
3082 while (i < add_column_count && plan[i].act == PLAN_NOP)
3083 i++; /* skip NOP */
3084
3085 if (i == add_column_count)
3086 j= end= column_count;
3087 else
3088 {
3089 /*
3090 old data portion. We don't need to check that j < column_count
3091 as plan[i].place is guaranteed to have a pointer inside the
3092 data.
3093 */
3094 while (header_base + j * entry_size < plan[i].place)
3095 j++;
3096 end= j;
3097 if ((plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
3098 j++; /* data at 'j' will be removed */
3099 }
3100 plan[i].mv_end= end;
3101
3102 {
3103 DYNAMIC_COLUMN_TYPE tp;
3104 type_and_offset_read_num(&tp, &first_offset,
3105 header_base +
3106 start * entry_size + COLUMN_NUMBER_SIZE,
3107 offset_size);
3108 }
3109 /* find data to be moved */
3110 if (start < end)
3111 {
3112 size_t data_size=
3113 get_length_interval(header_base + start * entry_size,
3114 header_base + end * entry_size,
3115 header_end, offset_size, max_offset);
3116 if (data_size == DYNCOL_OFFSET_ERROR ||
3117 (long) data_size < 0 ||
3118 data_size > max_offset - first_offset)
3119 {
3120 str->length= 0; // just something valid
3121 return ER_DYNCOL_FORMAT;
3122 }
3123 DBUG_ASSERT(curr_offset == first_offset + plan[i].ddelta);
3124 plan[i].mv_offset= first_offset;
3125 plan[i].mv_length= data_size;
3126 curr_offset+= data_size;
3127 }
3128 else
3129 {
3130 plan[i].mv_length= 0;
3131 plan[i].mv_offset= curr_offset;
3132 }
3133
3134 if (plan[i].ddelta == 0 && offset_size == new_offset_size &&
3135 plan[i].act != PLAN_DELETE)
3136 write+= entry_size * (end - start);
3137 else
3138 {
3139 /*
3140 Adjust all headers since last loop.
3141 We have to do this as the offset for data has moved
3142 */
3143 for (k= start; k < end; k++)
3144 {
3145 uchar *read= header_base + k * entry_size;
3146 size_t offs;
3147 uint nm;
3148 DYNAMIC_COLUMN_TYPE tp;
3149
3150 nm= uint2korr(read); /* Column nummber */
3151 type_and_offset_read_num(&tp, &offs, read + COLUMN_NUMBER_SIZE,
3152 offset_size);
3153 if (k > start && offs < first_offset)
3154 {
3155 str->length= 0; // just something valid
3156 return ER_DYNCOL_FORMAT;
3157 }
3158
3159 offs+= plan[i].ddelta;
3160 int2store(write, nm);
3161 /* write rest of data at write + COLUMN_NUMBER_SIZE */
3162 if (type_and_offset_store_num(write, new_offset_size, tp, offs))
3163 {
3164 str->length= 0; // just something valid
3165 return ER_DYNCOL_FORMAT;
3166 }
3167 write+= new_entry_size;
3168 }
3169 }
3170
3171 /* new data adding */
3172 if (i < add_column_count)
3173 {
3174 if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
3175 {
3176 int2store(write, *((uint *)plan[i].key));
3177 if (type_and_offset_store_num(write, new_offset_size,
3178 plan[i].val[0].type,
3179 curr_offset))
3180 {
3181 str->length= 0; // just something valid
3182 return ER_DYNCOL_FORMAT;
3183 }
3184 write+= new_entry_size;
3185 curr_offset+= plan[i].length;
3186 }
3187 }
3188 }
3189
3190 /*
3191 Move headers.
3192 i= index in array of changes
3193 j= index in packed string header index
3194 */
3195 str->length= (FIXED_HEADER_SIZE + new_header_size);
3196 for (i= 0, j= 0;
3197 i < add_column_count || j < column_count;
3198 i++)
3199 {
3200 uint start= j, end;
3201
3202 /*
3203 Search in i and j for the next column to add from i and where to
3204 add.
3205 */
3206
3207 while (i < add_column_count && plan[i].act == PLAN_NOP)
3208 i++; /* skip NOP */
3209
3210 j= end= plan[i].mv_end;
3211 if (i != add_column_count &&
3212 (plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
3213 j++;
3214
3215 /* copy first the data that was not replaced in original packed data */
3216 if (start < end && plan[i].mv_length)
3217 {
3218 memmove((header_base + new_header_size +
3219 plan[i].mv_offset + plan[i].ddelta),
3220 header_base + header_size + plan[i].mv_offset,
3221 plan[i].mv_length);
3222 }
3223 str->length+= plan[i].mv_length;
3224
3225 /* new data adding */
3226 if (i < add_column_count)
3227 {
3228 if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
3229 {
3230 data_store(str, plan[i].val, dyncol_fmt_num); /* Append new data */
3231 }
3232 }
3233 }
3234 return ER_DYNCOL_OK;
3235}
3236#endif
3237
3238/**
3239 Update the packed string with the given columns
3240
3241 @param str String where to write the data
3242 @param add_column_count Number of columns in the arrays
3243 @param column_numbers Array of columns numbers
3244 @param values Array of columns values
3245
3246 @return ER_DYNCOL_* return code
3247*/
3248/* plan allocated on the stack */
3249#define IN_PLACE_PLAN 4
3250
3251enum enum_dyncol_func_result
3252dynamic_column_update_many(DYNAMIC_COLUMN *str,
3253 uint add_column_count,
3254 uint *column_numbers,
3255 DYNAMIC_COLUMN_VALUE *values)
3256{
3257 return dynamic_column_update_many_fmt(str, add_column_count, column_numbers,
3258 values, FALSE);
3259}
3260
3261enum enum_dyncol_func_result
3262mariadb_dyncol_update_many_num(DYNAMIC_COLUMN *str,
3263 uint add_column_count,
3264 uint *column_numbers,
3265 DYNAMIC_COLUMN_VALUE *values)
3266{
3267 return dynamic_column_update_many_fmt(str, add_column_count, column_numbers,
3268 values, FALSE);
3269}
3270
3271enum enum_dyncol_func_result
3272mariadb_dyncol_update_many_named(DYNAMIC_COLUMN *str,
3273 uint add_column_count,
3274 LEX_STRING *column_names,
3275 DYNAMIC_COLUMN_VALUE *values)
3276{
3277 return dynamic_column_update_many_fmt(str, add_column_count, column_names,
3278 values, TRUE);
3279}
3280
3281static uint numlen(uint val)
3282{
3283 uint res;
3284 if (val == 0)
3285 return 1;
3286 res= 0;
3287 while(val)
3288 {
3289 res++;
3290 val/=10;
3291 }
3292 return res;
3293}
3294
3295static enum enum_dyncol_func_result
3296dynamic_column_update_many_fmt(DYNAMIC_COLUMN *str,
3297 uint add_column_count,
3298 void *column_keys,
3299 DYNAMIC_COLUMN_VALUE *values,
3300 my_bool string_keys)
3301{
3302 PLAN *plan, *alloc_plan= NULL, in_place_plan[IN_PLACE_PLAN];
3303 uchar *element;
3304 DYN_HEADER header, new_header;
3305 struct st_service_funcs *fmt, *new_fmt;
3306 long long data_delta= 0, name_delta= 0;
3307 uint i;
3308 uint not_null;
3309 long long header_delta= 0;
3310 long long header_delta_sign, data_delta_sign;
3311 int copy= FALSE;
3312 enum enum_dyncol_func_result rc;
3313 my_bool convert;
3314
3315 if (add_column_count == 0)
3316 return ER_DYNCOL_OK;
3317
3318 bzero(&header, sizeof(header));
3319 bzero(&new_header, sizeof(new_header));
3320 new_header.format= (string_keys ? dyncol_fmt_str : dyncol_fmt_num);
3321 new_fmt= fmt_data + new_header.format;
3322
3323 /*
3324 Get columns in column order. As the data in 'str' is already
3325 in column order this allows to replace all columns in one loop.
3326 */
3327 if (IN_PLACE_PLAN > add_column_count)
3328 plan= in_place_plan;
3329 else if (!(alloc_plan= plan=
3330 my_malloc(sizeof(PLAN) * (add_column_count + 1), MYF(0))))
3331 return ER_DYNCOL_RESOURCE;
3332
3333 not_null= add_column_count;
3334 for (i= 0, element= (uchar *) column_keys;
3335 i < add_column_count;
3336 i++, element+= new_fmt->key_size_in_array)
3337 {
3338 if ((*new_fmt->check_limit)(&element))
3339 {
3340 rc= ER_DYNCOL_DATA;
3341 goto end;
3342 }
3343
3344 plan[i].val= values + i;
3345 plan[i].key= element;
3346 if (values[i].type == DYN_COL_NULL)
3347 not_null--;
3348
3349 }
3350
3351 if (str->length == 0)
3352 {
3353 /*
3354 Just add new columns. If there was no columns to add we return
3355 an empty string.
3356 */
3357 goto create_new_string;
3358 }
3359
3360 /* Check that header is ok */
3361 if ((rc= init_read_hdr(&header, str)) < 0)
3362 goto end;
3363 fmt= fmt_data + header.format;
3364 /* new format can't be numeric if the old one is names */
3365 DBUG_ASSERT(new_header.format == dyncol_fmt_str ||
3366 header.format == dyncol_fmt_num);
3367 if (header.column_count == 0)
3368 goto create_new_string;
3369
3370 qsort(plan, (size_t)add_column_count, sizeof(PLAN), new_fmt->plan_sort);
3371
3372 new_header.column_count= header.column_count;
3373 new_header.nmpool_size= header.nmpool_size;
3374 if ((convert= (new_header.format == dyncol_fmt_str &&
3375 header.format == dyncol_fmt_num)))
3376 {
3377 DBUG_ASSERT(new_header.nmpool_size == 0);
3378 for(i= 0, header.entry= header.header;
3379 i < header.column_count;
3380 i++, header.entry+= header.entry_size)
3381 {
3382 new_header.nmpool_size+= numlen(uint2korr(header.entry));
3383 }
3384 }
3385
3386 if (fmt->fixed_hdr + header.header_size + header.nmpool_size > str->length)
3387 {
3388 rc= ER_DYNCOL_FORMAT;
3389 goto end;
3390 }
3391
3392 /*
3393 Calculate how many columns and data is added/deleted and make a 'plan'
3394 for each of them.
3395 */
3396 for (i= 0; i < add_column_count; i++)
3397 {
3398 /*
3399 For now we don't allow creating two columns with the same number
3400 at the time of create. This can be fixed later to just use the later
3401 by comparing the pointers.
3402 */
3403 if (i < add_column_count - 1 &&
3404 new_fmt->column_sort(&plan[i].key, &plan[i + 1].key) == 0)
3405 {
3406 rc= ER_DYNCOL_DATA;
3407 goto end;
3408 }
3409
3410 /* Set common variables for all plans */
3411 plan[i].ddelta= data_delta;
3412 plan[i].ndelta= name_delta;
3413 /* get header delta in entries */
3414 plan[i].hdelta= header_delta;
3415 plan[i].length= 0; /* Length if NULL */
3416
3417 if (find_place(&header, plan[i].key, string_keys))
3418 {
3419 size_t entry_data_size, entry_name_size= 0;
3420
3421 /* Data existed; We have to replace or delete it */
3422
3423 entry_data_size= hdr_interval_length(&header, header.entry +
3424 header.entry_size);
3425 if (entry_data_size == DYNCOL_OFFSET_ERROR ||
3426 (long) entry_data_size < 0)
3427 {
3428 rc= ER_DYNCOL_FORMAT;
3429 goto end;
3430 }
3431
3432 if (new_header.format == dyncol_fmt_str)
3433 {
3434 if (header.format == dyncol_fmt_str)
3435 {
3436 LEX_STRING name;
3437 if (read_name(&header, header.entry, &name))
3438 {
3439 rc= ER_DYNCOL_FORMAT;
3440 goto end;
3441 }
3442 entry_name_size= name.length;
3443 }
3444 else
3445 entry_name_size= numlen(uint2korr(header.entry));
3446 }
3447
3448 if (plan[i].val->type == DYN_COL_NULL)
3449 {
3450 /* Inserting a NULL means delete the old data */
3451
3452 plan[i].act= PLAN_DELETE; /* Remove old value */
3453 header_delta--; /* One row less in header */
3454 data_delta-= entry_data_size; /* Less data to store */
3455 name_delta-= entry_name_size;
3456 }
3457 else
3458 {
3459 /* Replace the value */
3460
3461 plan[i].act= PLAN_REPLACE;
3462 /* get data delta in bytes */
3463 if ((plan[i].length= dynamic_column_value_len(plan[i].val,
3464 new_header.format)) ==
3465 (size_t) ~0)
3466 {
3467 rc= ER_DYNCOL_DATA;
3468 goto end;
3469 }
3470 data_delta+= plan[i].length - entry_data_size;
3471 if (new_header.format == dyncol_fmt_str)
3472 {
3473 name_delta+= ((LEX_STRING *)(plan[i].key))->length - entry_name_size;
3474 }
3475 }
3476 }
3477 else
3478 {
3479 /* Data did not exists. Add if it it's not NULL */
3480
3481 if (plan[i].val->type == DYN_COL_NULL)
3482 {
3483 plan[i].act= PLAN_NOP; /* Mark entry to be skipped */
3484 }
3485 else
3486 {
3487 /* Add new value */
3488
3489 plan[i].act= PLAN_ADD;
3490 header_delta++; /* One more row in header */
3491 /* get data delta in bytes */
3492 if ((plan[i].length= dynamic_column_value_len(plan[i].val,
3493 new_header.format)) ==
3494 (size_t) ~0)
3495 {
3496 rc= ER_DYNCOL_DATA;
3497 goto end;
3498 }
3499 data_delta+= plan[i].length;
3500 if (new_header.format == dyncol_fmt_str)
3501 name_delta+= ((LEX_STRING *)plan[i].key)->length;
3502 }
3503 }
3504 plan[i].place= header.entry;
3505 }
3506 plan[add_column_count].hdelta= header_delta;
3507 plan[add_column_count].ddelta= data_delta;
3508 plan[add_column_count].act= PLAN_NOP;
3509 plan[add_column_count].place= header.dtpool;
3510
3511 new_header.column_count= (uint)(header.column_count + header_delta);
3512
3513 /*
3514 Check if it is only "increasing" or only "decreasing" plan for (header
3515 and data separately).
3516 */
3517 new_header.data_size= (size_t) (header.data_size + data_delta);
3518 new_header.nmpool_size= (size_t) (new_header.nmpool_size + name_delta);
3519 DBUG_ASSERT(new_header.format != dyncol_fmt_num ||
3520 new_header.nmpool_size == 0);
3521 if ((new_header.offset_size=
3522 new_fmt->dynamic_column_offset_bytes(new_header.data_size)) >=
3523 new_fmt->max_offset_size)
3524 {
3525 rc= ER_DYNCOL_LIMIT;
3526 goto end;
3527 }
3528
3529 copy= ((header.format != new_header.format) ||
3530 (new_header.format == dyncol_fmt_str));
3531 /* if (new_header.offset_size!=offset_size) then we have to rewrite header */
3532 header_delta_sign=
3533 ((int)new_header.offset_size + new_fmt->fixed_hdr_entry) -
3534 ((int)header.offset_size + fmt->fixed_hdr_entry);
3535 data_delta_sign= 0;
3536 // plan[add_column_count] contains last deltas.
3537 for (i= 0; i <= add_column_count && !copy; i++)
3538 {
3539 /* This is the check for increasing/decreasing */
3540 DELTA_CHECK(header_delta_sign, plan[i].hdelta, copy);
3541 DELTA_CHECK(data_delta_sign, plan[i].ddelta, copy);
3542 }
3543 calc_param(&new_header.entry_size, &new_header.header_size,
3544 new_fmt->fixed_hdr_entry,
3545 new_header.offset_size, new_header.column_count);
3546
3547 /*
3548 Need copy because:
3549 1, Header/data parts moved in different directions.
3550 2. There is no enough allocated space in the string.
3551 3. Header and data moved in different directions.
3552 */
3553 if (copy || /*1.*/
3554 str->max_length < str->length + header_delta + data_delta || /*2.*/
3555 ((header_delta_sign < 0 && data_delta_sign > 0) ||
3556 (header_delta_sign > 0 && data_delta_sign < 0))) /*3.*/
3557 rc= dynamic_column_update_copy(str, plan, add_column_count,
3558 &header, &new_header,
3559 convert);
3560 else
3561 if (header_delta_sign < 0)
3562 rc= dynamic_column_update_move_left(str, plan, header.offset_size,
3563 header.entry_size,
3564 header.header_size,
3565 new_header.offset_size,
3566 new_header.entry_size,
3567 new_header.header_size,
3568 header.column_count,
3569 new_header.column_count,
3570 add_column_count, header.dtpool,
3571 header.data_size);
3572 else
3573 /*
3574 rc= dynamic_column_update_move_right(str, plan, offset_size,
3575 entry_size, header_size,
3576 new_header.offset_size,
3577 new_header.entry_size,
3578 new_heder.header_size, column_count,
3579 new_header.column_count,
3580 add_column_count, header_end,
3581 header.data_size);
3582 */
3583 rc= dynamic_column_update_copy(str, plan, add_column_count,
3584 &header, &new_header,
3585 convert);
3586end:
3587 my_free(alloc_plan);
3588 return rc;
3589
3590create_new_string:
3591 /* There is no columns from before, so let's just add the new ones */
3592 rc= ER_DYNCOL_OK;
3593 if (not_null != 0)
3594 rc= dynamic_column_create_many_internal_fmt(str, add_column_count,
3595 (uint*)column_keys, values,
3596 str->str == NULL,
3597 string_keys);
3598 goto end;
3599}
3600
3601
3602/**
3603 Update the packed string with the given column
3604
3605 @param str String where to write the data
3606 @param column_number Array of columns number
3607 @param values Array of columns values
3608
3609 @return ER_DYNCOL_* return code
3610*/
3611
3612
3613enum enum_dyncol_func_result
3614dynamic_column_update(DYNAMIC_COLUMN *str, uint column_nr,
3615 DYNAMIC_COLUMN_VALUE *value)
3616{
3617 return dynamic_column_update_many(str, 1, &column_nr, value);
3618}
3619
3620
3621enum enum_dyncol_func_result
3622mariadb_dyncol_check(DYNAMIC_COLUMN *str)
3623{
3624 struct st_service_funcs *fmt;
3625 enum enum_dyncol_func_result rc= ER_DYNCOL_FORMAT;
3626 DYN_HEADER header;
3627 uint i;
3628 size_t data_offset= 0, name_offset= 0;
3629 size_t prev_data_offset= 0, prev_name_offset= 0;
3630 LEX_STRING name= {0,0}, prev_name= {0,0};
3631 uint num= 0, prev_num= 0;
3632 void *key, *prev_key;
3633 enum enum_dynamic_column_type type= DYN_COL_NULL, prev_type= DYN_COL_NULL;
3634
3635 DBUG_ENTER("dynamic_column_check");
3636
3637 if (str->length == 0)
3638 {
3639 DBUG_PRINT("info", ("empty string is OK"));
3640 DBUG_RETURN(ER_DYNCOL_OK);
3641 }
3642
3643 bzero(&header, sizeof(header));
3644
3645 /* Check that header is OK */
3646 if (read_fixed_header(&header, str))
3647 {
3648 DBUG_PRINT("info", ("Reading fixed string header failed"));
3649 goto end;
3650 }
3651 fmt= fmt_data + header.format;
3652 calc_param(&header.entry_size, &header.header_size,
3653 fmt->fixed_hdr_entry, header.offset_size,
3654 header.column_count);
3655 /* headers are out of string length (no space for data and part of headers) */
3656 if (fmt->fixed_hdr + header.header_size + header.nmpool_size > str->length)
3657 {
3658 DBUG_PRINT("info", ("Fixed header: %u Header size: %u "
3659 "Name pool size: %u but Strig length: %u",
3660 (uint)fmt->fixed_hdr,
3661 (uint)header.header_size,
3662 (uint)header.nmpool_size,
3663 (uint)str->length));
3664 goto end;
3665 }
3666 header.header= (uchar*)str->str + fmt->fixed_hdr;
3667 header.nmpool= header.header + header.header_size;
3668 header.dtpool= header.nmpool + header.nmpool_size;
3669 header.data_size= str->length - fmt->fixed_hdr -
3670 header.header_size - header.nmpool_size;
3671
3672 /* read and check headers */
3673 if (header.format == dyncol_fmt_num)
3674 {
3675 key= &num;
3676 prev_key= &prev_num;
3677 }
3678 else
3679 {
3680 key= &name;
3681 prev_key= &prev_name;
3682 }
3683 for (i= 0, header.entry= header.header;
3684 i < header.column_count;
3685 i++, header.entry+= header.entry_size)
3686 {
3687
3688 if (header.format == dyncol_fmt_num)
3689 {
3690 num= uint2korr(header.entry);
3691 }
3692 else
3693 {
3694 DBUG_ASSERT(header.format == dyncol_fmt_str);
3695 if (read_name(&header, header.entry, &name))
3696 {
3697 DBUG_PRINT("info", ("Reading name failed: Field order: %u"
3698 " Name offset: %u"
3699 " Name pool size: %u",
3700 (uint) i,
3701 uint2korr(header.entry),
3702 (uint)header.nmpool_size));
3703 goto end;
3704 }
3705 name_offset= name.str - (char *)header.nmpool;
3706 }
3707 if ((*fmt->type_and_offset_read)(&type, &data_offset,
3708 header.entry + fmt->fixed_hdr_entry,
3709 header.offset_size))
3710 goto end;
3711
3712 DBUG_ASSERT(type != DYN_COL_NULL);
3713 if (data_offset > header.data_size)
3714 {
3715 DBUG_PRINT("info", ("Field order: %u Data offset: %u"
3716 " > Data pool size: %u",
3717 (uint)i,
3718 (uint)data_offset,
3719 (uint)header.data_size));
3720 goto end;
3721 }
3722 if (prev_type != DYN_COL_NULL)
3723 {
3724 /* It is not first entry */
3725 if (prev_data_offset > data_offset ||
3726 ((prev_type != DYN_COL_INT &&
3727 prev_type != DYN_COL_UINT &&
3728 prev_type != DYN_COL_DECIMAL) && prev_data_offset == data_offset))
3729 {
3730 DBUG_PRINT("info", ("Field order: %u Previous data offset: %u"
3731 " >(=) Current data offset: %u",
3732 (uint)i,
3733 (uint)prev_data_offset,
3734 (uint)data_offset));
3735 goto end;
3736 }
3737 if (prev_name_offset > name_offset)
3738 {
3739 DBUG_PRINT("info", ("Field order: %u Previous name offset: %u"
3740 " > Current name offset: %u",
3741 (uint)i,
3742 (uint)prev_data_offset,
3743 (uint)data_offset));
3744 goto end;
3745 }
3746 if ((*fmt->column_sort)(&prev_key, &key) >= 0)
3747 {
3748 DBUG_PRINT("info", ("Field order: %u Previous key >= Current key",
3749 (uint)i));
3750 goto end;
3751 }
3752 }
3753 prev_num= num;
3754 prev_name= name;
3755 prev_data_offset= data_offset;
3756 prev_name_offset= name_offset;
3757 prev_type= type;
3758 }
3759
3760 /* check data, which we can */
3761 for (i= 0, header.entry= header.header;
3762 i < header.column_count;
3763 i++, header.entry+= header.entry_size)
3764 {
3765 DYNAMIC_COLUMN_VALUE store;
3766 // already checked by previouse pass
3767 (*fmt->type_and_offset_read)(&header.type, &header.offset,
3768 header.entry + fmt->fixed_hdr_entry,
3769 header.offset_size);
3770 header.length=
3771 hdr_interval_length(&header, header.entry + header.entry_size);
3772 header.data= header.dtpool + header.offset;
3773 switch ((header.type)) {
3774 case DYN_COL_INT:
3775 rc= dynamic_column_sint_read(&store, header.data, header.length);
3776 break;
3777 case DYN_COL_UINT:
3778 rc= dynamic_column_uint_read(&store, header.data, header.length);
3779 break;
3780 case DYN_COL_DOUBLE:
3781 rc= dynamic_column_double_read(&store, header.data, header.length);
3782 break;
3783 case DYN_COL_STRING:
3784 rc= dynamic_column_string_read(&store, header.data, header.length);
3785 break;
3786 case DYN_COL_DECIMAL:
3787 rc= dynamic_column_decimal_read(&store, header.data, header.length);
3788 break;
3789 case DYN_COL_DATETIME:
3790 rc= dynamic_column_date_time_read(&store, header.data,
3791 header.length);
3792 break;
3793 case DYN_COL_DATE:
3794 rc= dynamic_column_date_read(&store, header.data, header.length);
3795 break;
3796 case DYN_COL_TIME:
3797 rc= dynamic_column_time_read(&store, header.data, header.length);
3798 break;
3799 case DYN_COL_DYNCOL:
3800 rc= dynamic_column_dyncol_read(&store, header.data, header.length);
3801 break;
3802 case DYN_COL_NULL:
3803 default:
3804 rc= ER_DYNCOL_FORMAT;
3805 goto end;
3806 }
3807 if (rc != ER_DYNCOL_OK)
3808 {
3809 DBUG_ASSERT(rc < 0);
3810 DBUG_PRINT("info", ("Field order: %u Can't read data: %i",
3811 (uint)i, (int) rc));
3812 goto end;
3813 }
3814 }
3815
3816 rc= ER_DYNCOL_OK;
3817end:
3818 DBUG_RETURN(rc);
3819}
3820
3821static
3822my_bool dynstr_append_json_quoted(DYNAMIC_STRING *str,
3823 const char *append, size_t len)
3824{
3825 size_t additional= ((str->alloc_increment && str->alloc_increment > 6) ?
3826 str->alloc_increment :
3827 10);
3828 size_t lim= additional;
3829 size_t i;
3830 if (dynstr_realloc(str, len + additional + 2))
3831 return TRUE;
3832 str->str[str->length++]= '"';
3833 for (i= 0; i < len; i++)
3834 {
3835 register char c= append[i];
3836 if (unlikely(((uchar)c) <= 0x1F))
3837 {
3838 if (lim < 5)
3839 {
3840 if (dynstr_realloc(str, additional))
3841 return TRUE;
3842 lim+= additional;
3843 }
3844 lim-= 5;
3845 str->str[str->length++]= '\\';
3846 str->str[str->length++]= 'u';
3847 str->str[str->length++]= '0';
3848 str->str[str->length++]= '0';
3849 str->str[str->length++]= (c < 0x10 ? '0' : '1');
3850 c%= 0x10;
3851 str->str[str->length++]= (c < 0xA ? '0' + c : 'A' + (c - 0xA));
3852 }
3853 else
3854 {
3855 if (c == '"' || c == '\\')
3856 {
3857 if (!lim)
3858 {
3859 if (dynstr_realloc(str, additional))
3860 return TRUE;
3861 lim= additional;
3862 }
3863 lim--;
3864 str->str[str->length++]= '\\';
3865 }
3866 str->str[str->length++]= c;
3867 }
3868 }
3869 str->str[str->length++]= '"';
3870 return FALSE;
3871}
3872
3873
3874enum enum_dyncol_func_result
3875mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
3876 CHARSET_INFO *cs, char quote)
3877{
3878 char buff[40];
3879 size_t len;
3880 switch (val->type) {
3881 case DYN_COL_INT:
3882 len= snprintf(buff, sizeof(buff), "%lld", val->x.long_value);
3883 if (dynstr_append_mem(str, buff, len))
3884 return ER_DYNCOL_RESOURCE;
3885 break;
3886 case DYN_COL_UINT:
3887 len= snprintf(buff, sizeof(buff), "%llu", val->x.ulong_value);
3888 if (dynstr_append_mem(str, buff, len))
3889 return ER_DYNCOL_RESOURCE;
3890 break;
3891 case DYN_COL_DOUBLE:
3892
3893 len= my_gcvt(val->x.double_value, MY_GCVT_ARG_DOUBLE,
3894 sizeof(buff) - 1, buff, NULL);
3895 if (dynstr_realloc(str, len + (quote ? 2 : 0)))
3896 return ER_DYNCOL_RESOURCE;
3897 dynstr_append_mem(str, buff, len);
3898 break;
3899 case DYN_COL_DYNCOL:
3900 case DYN_COL_STRING:
3901 {
3902 char *alloc= NULL;
3903 char *from= val->x.string.value.str;
3904 ulong bufflen;
3905 my_bool conv= !my_charset_same(val->x.string.charset, cs);
3906 my_bool rc;
3907 len= val->x.string.value.length;
3908 bufflen= (ulong)(len * (conv ? cs->mbmaxlen : 1));
3909 if (dynstr_realloc(str, bufflen))
3910 return ER_DYNCOL_RESOURCE;
3911
3912 // guaranty UTF-8 string for value
3913 if (!my_charset_same(val->x.string.charset, cs))
3914 {
3915 uint dummy_errors;
3916 if (!quote)
3917 {
3918 /* convert to the destination */
3919 str->length+= my_convert(str->str, bufflen,
3920 cs,
3921 from, (uint32)len,
3922 val->x.string.charset,
3923 &dummy_errors);
3924 return ER_DYNCOL_OK;
3925 }
3926 if ((alloc= (char *)my_malloc(bufflen, MYF(0))))
3927 {
3928 len= my_convert(alloc, bufflen, cs,
3929 from, (uint32)len,
3930 val->x.string.charset,
3931 &dummy_errors);
3932 from= alloc;
3933 }
3934 else
3935 return ER_DYNCOL_RESOURCE;
3936 }
3937 if (quote)
3938 if (quote == DYNCOL_JSON_ESC)
3939 rc= dynstr_append_json_quoted(str, from, len);
3940 else
3941 rc= dynstr_append_quoted(str, from, len, quote);
3942 else
3943 rc= dynstr_append_mem(str, from, len);
3944 if (alloc)
3945 my_free(alloc);
3946 if (rc)
3947 return ER_DYNCOL_RESOURCE;
3948 break;
3949 }
3950 case DYN_COL_DECIMAL:
3951 {
3952 int tmp_len= sizeof(buff);
3953 decimal2string(&val->x.decimal.value, buff, &tmp_len,
3954 0, val->x.decimal.value.frac,
3955 '0');
3956 if (dynstr_append_mem(str, buff, tmp_len))
3957 return ER_DYNCOL_RESOURCE;
3958 break;
3959 }
3960 case DYN_COL_DATETIME:
3961 case DYN_COL_DATE:
3962 case DYN_COL_TIME:
3963 len= my_TIME_to_str(&val->x.time_value, buff, AUTO_SEC_PART_DIGITS);
3964 if (dynstr_realloc(str, len + (quote ? 2 : 0)))
3965 return ER_DYNCOL_RESOURCE;
3966 if (quote)
3967 str->str[str->length++]= '"';
3968 dynstr_append_mem(str, buff, len);
3969 if (quote)
3970 str->str[str->length++]= '"';
3971 break;
3972 case DYN_COL_NULL:
3973 if (dynstr_append_mem(str, "null", 4))
3974 return ER_DYNCOL_RESOURCE;
3975 break;
3976 default:
3977 return(ER_DYNCOL_FORMAT);
3978 }
3979 return(ER_DYNCOL_OK);
3980}
3981
3982
3983enum enum_dyncol_func_result
3984mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val)
3985{
3986 enum enum_dyncol_func_result rc= ER_DYNCOL_OK;
3987 *ll= 0;
3988 switch (val->type) {
3989 case DYN_COL_INT:
3990 *ll= val->x.long_value;
3991 break;
3992 case DYN_COL_UINT:
3993 *ll= (longlong)val->x.ulong_value;
3994 if (val->x.ulong_value > ULONGLONG_MAX)
3995 rc= ER_DYNCOL_TRUNCATED;
3996 break;
3997 case DYN_COL_DOUBLE:
3998 *ll= (longlong)val->x.double_value;
3999 if (((double) *ll) != val->x.double_value)
4000 rc= ER_DYNCOL_TRUNCATED;
4001 break;
4002 case DYN_COL_STRING:
4003 {
4004 char *src= val->x.string.value.str;
4005 size_t len= val->x.string.value.length;
4006 longlong i= 0, sign= 1;
4007
4008 while (len && my_isspace(&my_charset_latin1, *src)) src++,len--;
4009
4010 if (len)
4011 {
4012 if (*src == '-')
4013 {
4014 sign= -1;
4015 src++;
4016 } else if (*src == '+')
4017 src++;
4018 while(len && my_isdigit(&my_charset_latin1, *src))
4019 {
4020 i= i * 10 + (*src - '0');
4021 src++;
4022 }
4023 }
4024 else
4025 rc= ER_DYNCOL_TRUNCATED;
4026 if (len)
4027 rc= ER_DYNCOL_TRUNCATED;
4028 *ll= i * sign;
4029 break;
4030 }
4031 case DYN_COL_DECIMAL:
4032 if (decimal2longlong(&val->x.decimal.value, ll) != E_DEC_OK)
4033 rc= ER_DYNCOL_TRUNCATED;
4034 break;
4035 case DYN_COL_DATETIME:
4036 *ll= (val->x.time_value.year * 10000000000ull +
4037 val->x.time_value.month * 100000000L +
4038 val->x.time_value.day * 1000000 +
4039 val->x.time_value.hour * 10000 +
4040 val->x.time_value.minute * 100 +
4041 val->x.time_value.second) *
4042 (val->x.time_value.neg ? -1 : 1);
4043 break;
4044 case DYN_COL_DATE:
4045 *ll= (val->x.time_value.year * 10000 +
4046 val->x.time_value.month * 100 +
4047 val->x.time_value.day) *
4048 (val->x.time_value.neg ? -1 : 1);
4049 break;
4050 case DYN_COL_TIME:
4051 *ll= (val->x.time_value.hour * 10000 +
4052 val->x.time_value.minute * 100 +
4053 val->x.time_value.second) *
4054 (val->x.time_value.neg ? -1 : 1);
4055 break;
4056 case DYN_COL_DYNCOL:
4057 case DYN_COL_NULL:
4058 rc= ER_DYNCOL_TRUNCATED;
4059 break;
4060 default:
4061 return(ER_DYNCOL_FORMAT);
4062 }
4063 return(rc);
4064}
4065
4066
4067enum enum_dyncol_func_result
4068mariadb_dyncol_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val)
4069{
4070 enum enum_dyncol_func_result rc= ER_DYNCOL_OK;
4071 *dbl= 0;
4072 switch (val->type) {
4073 case DYN_COL_INT:
4074 *dbl= (double)val->x.long_value;
4075 if (((longlong) *dbl) != val->x.long_value)
4076 rc= ER_DYNCOL_TRUNCATED;
4077 break;
4078 case DYN_COL_UINT:
4079 *dbl= (double)val->x.ulong_value;
4080 if (((ulonglong) *dbl) != val->x.ulong_value)
4081 rc= ER_DYNCOL_TRUNCATED;
4082 break;
4083 case DYN_COL_DOUBLE:
4084 *dbl= val->x.double_value;
4085 break;
4086 case DYN_COL_STRING:
4087 {
4088 char *str, *end;
4089 if (!(str= malloc(val->x.string.value.length + 1)))
4090 return ER_DYNCOL_RESOURCE;
4091 memcpy(str, val->x.string.value.str, val->x.string.value.length);
4092 str[val->x.string.value.length]= '\0';
4093 *dbl= strtod(str, &end);
4094 if (*end != '\0')
4095 rc= ER_DYNCOL_TRUNCATED;
4096 free(str);
4097 break;
4098 }
4099 case DYN_COL_DECIMAL:
4100 if (decimal2double(&val->x.decimal.value, dbl) != E_DEC_OK)
4101 rc= ER_DYNCOL_TRUNCATED;
4102 break;
4103 case DYN_COL_DATETIME:
4104 *dbl= (double)(val->x.time_value.year * 10000000000ull +
4105 val->x.time_value.month * 100000000L +
4106 val->x.time_value.day * 1000000 +
4107 val->x.time_value.hour * 10000 +
4108 val->x.time_value.minute * 100 +
4109 val->x.time_value.second) *
4110 (val->x.time_value.neg ? -1 : 1);
4111 break;
4112 case DYN_COL_DATE:
4113 *dbl= (double)(val->x.time_value.year * 10000 +
4114 val->x.time_value.month * 100 +
4115 val->x.time_value.day) *
4116 (val->x.time_value.neg ? -1 : 1);
4117 break;
4118 case DYN_COL_TIME:
4119 *dbl= (double)(val->x.time_value.hour * 10000 +
4120 val->x.time_value.minute * 100 +
4121 val->x.time_value.second) *
4122 (val->x.time_value.neg ? -1 : 1);
4123 break;
4124 case DYN_COL_DYNCOL:
4125 case DYN_COL_NULL:
4126 rc= ER_DYNCOL_TRUNCATED;
4127 break;
4128 default:
4129 return(ER_DYNCOL_FORMAT);
4130 }
4131 return(rc);
4132}
4133
4134
4135/**
4136 Convert to JSON
4137
4138 @param str The packed string
4139 @param json Where to put json result
4140
4141 @return ER_DYNCOL_* return code
4142*/
4143
4144#define JSON_STACK_PROTECTION 10
4145
4146static enum enum_dyncol_func_result
4147mariadb_dyncol_json_internal(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json,
4148 uint lvl)
4149{
4150 DYN_HEADER header;
4151 uint i;
4152 enum enum_dyncol_func_result rc;
4153
4154 if (lvl >= JSON_STACK_PROTECTION)
4155 {
4156 rc= ER_DYNCOL_RESOURCE;
4157 goto err;
4158 }
4159
4160
4161 if (str->length == 0)
4162 return ER_DYNCOL_OK; /* no columns */
4163
4164 if ((rc= init_read_hdr(&header, str)) < 0)
4165 goto err;
4166
4167 if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
4168 str->length)
4169 {
4170 rc= ER_DYNCOL_FORMAT;
4171 goto err;
4172 }
4173
4174 rc= ER_DYNCOL_RESOURCE;
4175
4176 if (dynstr_append_mem(json, "{", 1))
4177 goto err;
4178 for (i= 0, header.entry= header.header;
4179 i < header.column_count;
4180 i++, header.entry+= header.entry_size)
4181 {
4182 DYNAMIC_COLUMN_VALUE val;
4183 if (i != 0 && dynstr_append_mem(json, ",", 1))
4184 goto err;
4185 header.length=
4186 hdr_interval_length(&header, header.entry + header.entry_size);
4187 header.data= header.dtpool + header.offset;
4188 /*
4189 Check that the found data is within the ranges. This can happen if
4190 we get data with wrong offsets.
4191 */
4192 if (header.length == DYNCOL_OFFSET_ERROR ||
4193 header.length > INT_MAX || header.offset > header.data_size)
4194 {
4195 rc= ER_DYNCOL_FORMAT;
4196 goto err;
4197 }
4198 if ((rc= dynamic_column_get_value(&header, &val)) < 0)
4199 goto err;
4200 if (header.format == dyncol_fmt_num)
4201 {
4202 uint nm= uint2korr(header.entry);
4203 if (dynstr_realloc(json, DYNCOL_NUM_CHAR + 3))
4204 goto err;
4205 json->str[json->length++]= '"';
4206 json->length+= (snprintf(json->str + json->length,
4207 DYNCOL_NUM_CHAR, "%u", nm));
4208 }
4209 else
4210 {
4211 LEX_STRING name;
4212 if (read_name(&header, header.entry, &name))
4213 {
4214 rc= ER_DYNCOL_FORMAT;
4215 goto err;
4216 }
4217 if (dynstr_realloc(json, name.length + 3))
4218 goto err;
4219 json->str[json->length++]= '"';
4220 memcpy(json->str + json->length, name.str, name.length);
4221 json->length+= name.length;
4222 }
4223 json->str[json->length++]= '"';
4224 json->str[json->length++]= ':';
4225 if (val.type == DYN_COL_DYNCOL)
4226 {
4227 /* here we use it only for read so can cheat a bit */
4228 DYNAMIC_COLUMN dc;
4229 bzero(&dc, sizeof(dc));
4230 dc.str= val.x.string.value.str;
4231 dc.length= val.x.string.value.length;
4232 if (mariadb_dyncol_json_internal(&dc, json, lvl + 1) < 0)
4233 {
4234 dc.str= NULL; dc.length= 0;
4235 goto err;
4236 }
4237 dc.str= NULL; dc.length= 0;
4238 }
4239 else
4240 {
4241 if ((rc= mariadb_dyncol_val_str(json, &val, DYNCOL_UTF, DYNCOL_JSON_ESC))
4242 < 0)
4243 goto err;
4244 }
4245 }
4246 if (dynstr_append_mem(json, "}", 1))
4247 {
4248 rc= ER_DYNCOL_RESOURCE;
4249 goto err;
4250 }
4251 return ER_DYNCOL_OK;
4252
4253err:
4254 json->length= 0;
4255 return rc;
4256}
4257
4258enum enum_dyncol_func_result
4259mariadb_dyncol_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json)
4260{
4261
4262 if (init_dynamic_string(json, NULL, str->length * 2, 100))
4263 return ER_DYNCOL_RESOURCE;
4264
4265 return mariadb_dyncol_json_internal(str, json, 1);
4266}
4267
4268
4269/**
4270 Convert to DYNAMIC_COLUMN_VALUE values and names (LEX_STING) dynamic array
4271
4272 @param str The packed string
4273 @param count number of elements in the arrays
4274 @param names Where to put names (should be free by user)
4275 @param vals Where to put values (should be free by user)
4276
4277 @return ER_DYNCOL_* return code
4278*/
4279
4280enum enum_dyncol_func_result
4281mariadb_dyncol_unpack(DYNAMIC_COLUMN *str,
4282 uint *count,
4283 LEX_STRING **names, DYNAMIC_COLUMN_VALUE **vals)
4284{
4285 DYN_HEADER header;
4286 char *nm;
4287 uint i;
4288 enum enum_dyncol_func_result rc;
4289
4290 *count= 0; *names= 0; *vals= 0;
4291
4292 if (str->length == 0)
4293 return ER_DYNCOL_OK; /* no columns */
4294
4295 if ((rc= init_read_hdr(&header, str)) < 0)
4296 return rc;
4297
4298
4299 if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
4300 str->length)
4301 return ER_DYNCOL_FORMAT;
4302
4303 *vals= my_malloc(sizeof(DYNAMIC_COLUMN_VALUE)* header.column_count, MYF(0));
4304 if (header.format == dyncol_fmt_num)
4305 {
4306 *names= my_malloc(sizeof(LEX_STRING) * header.column_count +
4307 DYNCOL_NUM_CHAR * header.column_count, MYF(0));
4308 nm= (char *)((*names) + header.column_count);
4309 }
4310 else
4311 {
4312 *names= my_malloc(sizeof(LEX_STRING) * header.column_count, MYF(0));
4313 nm= 0;
4314 }
4315 if (!(*vals) || !(*names))
4316 {
4317 rc= ER_DYNCOL_RESOURCE;
4318 goto err;
4319 }
4320
4321 for (i= 0, header.entry= header.header;
4322 i < header.column_count;
4323 i++, header.entry+= header.entry_size)
4324 {
4325 header.length=
4326 hdr_interval_length(&header, header.entry + header.entry_size);
4327 header.data= header.dtpool + header.offset;
4328 /*
4329 Check that the found data is within the ranges. This can happen if
4330 we get data with wrong offsets.
4331 */
4332 if (header.length == DYNCOL_OFFSET_ERROR ||
4333 header.length > INT_MAX || header.offset > header.data_size)
4334 {
4335 rc= ER_DYNCOL_FORMAT;
4336 goto err;
4337 }
4338 if ((rc= dynamic_column_get_value(&header, (*vals) + i)) < 0)
4339 goto err;
4340
4341 if (header.format == dyncol_fmt_num)
4342 {
4343 uint num= uint2korr(header.entry);
4344 (*names)[i].str= nm;
4345 (*names)[i].length= snprintf(nm, DYNCOL_NUM_CHAR, "%u", num);
4346 nm+= (*names)[i].length + 1;
4347 }
4348 else
4349 {
4350 if (read_name(&header, header.entry, (*names) + i))
4351 {
4352 rc= ER_DYNCOL_FORMAT;
4353 goto err;
4354 }
4355 }
4356 }
4357
4358 *count= header.column_count;
4359 return ER_DYNCOL_OK;
4360
4361err:
4362 if (*vals)
4363 {
4364 my_free(*vals);
4365 *vals= 0;
4366 }
4367 if (*names)
4368 {
4369 my_free(*names);
4370 *names= 0;
4371 }
4372 return rc;
4373}
4374
4375/**
4376 Free arrays allocated by mariadb_dyncol_unpack()
4377
4378 @param names Where to put names (should be free by user)
4379 @param vals Where to put values (should be free by user)
4380*/
4381void mariadb_dyncol_unpack_free(LEX_STRING *names, DYNAMIC_COLUMN_VALUE *vals)
4382{
4383 my_free(names);
4384 my_free(vals);
4385}
4386
4387/**
4388 Get not NULL column count
4389
4390 @param str The packed string
4391 @param column_count Where to put column count
4392
4393 @return ER_DYNCOL_* return code
4394*/
4395
4396enum enum_dyncol_func_result
4397mariadb_dyncol_column_count(DYNAMIC_COLUMN *str, uint *column_count)
4398{
4399 DYN_HEADER header;
4400 enum enum_dyncol_func_result rc;
4401
4402 *(column_count)= 0;
4403 if (str->length == 0)
4404 return ER_DYNCOL_OK;
4405
4406 if ((rc= init_read_hdr(&header, str)) < 0)
4407 return rc;
4408 *column_count= header.column_count;
4409 return rc;
4410}
4411/**
4412 Free dynamic column
4413
4414 @param str The packed string
4415*/
4416void mariadb_dyncol_free(DYNAMIC_COLUMN *str)
4417{
4418 dynstr_free(str);
4419}
4420