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