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 return ER_DYNCOL_OK;
1685
1686 memset(str->str, 0, fmt->fixed_hdr);
1687 str->length= fmt->fixed_hdr;
1688
1689 /* sort columns for the header */
1690 for (i= 0, element= (uchar *) column_keys;
1691 i < column_count;
1692 i++, element+= fmt->key_size_in_array)
1693 columns_order[i]= (void *)element;
1694 qsort(columns_order, (size_t)column_count, sizeof(void*), fmt->column_sort);
1695
1696 /*
1697 For now we don't allow creating two columns with the same number
1698 at the time of create. This can be fixed later to just use the later
1699 by comparing the pointers.
1700 */
1701 for (i= 0; i < column_count - 1; i++)
1702 {
1703 if ((*fmt->check_limit)(&columns_order[i]) ||
1704 (*fmt->column_sort)(&columns_order[i], &columns_order[i + 1]) == 0)
1705 {
1706 rc= ER_DYNCOL_DATA;
1707 goto err;
1708 }
1709 }
1710 if ((*fmt->check_limit)(&columns_order[i]))
1711 {
1712 rc= ER_DYNCOL_DATA;
1713 goto err;
1714 }
1715
1716 (*fmt->set_fixed_hdr)(str, hdr);
1717 /* reserve place for header and name pool */
1718 str->length+= hdr->header_size + hdr->nmpool_size;
1719
1720 hdr->entry= hdr->header;
1721 hdr->name= hdr->nmpool;
1722 all_headers_size= fmt->fixed_hdr + hdr->header_size + hdr->nmpool_size;
1723 for (i= 0; i < column_count; i++)
1724 {
1725 uint ord= (uint)(((uchar*)columns_order[i] - (uchar*)column_keys) /
1726 fmt->key_size_in_array);
1727 if (values[ord].type != DYN_COL_NULL)
1728 {
1729 /* Store header first in the str */
1730 if ((*fmt->put_header_entry)(hdr, columns_order[i], values + ord,
1731 str->length - all_headers_size))
1732 {
1733 rc= ER_DYNCOL_FORMAT;
1734 goto err;
1735 }
1736
1737 /* Store value in 'str + str->length' and increase str->length */
1738 if ((rc= data_store(str, values + ord, hdr->format)))
1739 goto err;
1740 }
1741 }
1742 rc= ER_DYNCOL_OK;
1743err:
1744 free(columns_order);
1745 return rc;
1746}
1747
1748/**
1749 Calculate size of header, name pool and data pool
1750
1751 @param hdr descriptor of dynamic column record
1752 @param column_count number of elements in arrays
1753 @param column_count Number of columns in the arrays
1754 @param column_keys Array of columns keys (uint or LEX_STRING)
1755 @param values Array of columns values
1756
1757 @return ER_DYNCOL_* return code
1758*/
1759
1760static enum enum_dyncol_func_result
1761calc_var_sizes(DYN_HEADER *hdr,
1762 uint column_count,
1763 void *column_keys,
1764 DYNAMIC_COLUMN_VALUE *values)
1765{
1766 struct st_service_funcs *fmt= fmt_data + hdr->format;
1767 uint i;
1768 hdr->nmpool_size= hdr->data_size= 0;
1769 hdr->column_count= 0;
1770 for (i= 0; i < column_count; i++)
1771 {
1772 if (values[i].type != DYN_COL_NULL)
1773 {
1774 size_t tmp;
1775 hdr->column_count++;
1776 hdr->data_size+= (tmp= dynamic_column_value_len(values + i,
1777 hdr->format));
1778 if (tmp == (size_t) ~0)
1779 return ER_DYNCOL_DATA;
1780 hdr->nmpool_size+= (*fmt->name_size)(column_keys, i);
1781 }
1782 }
1783 /*
1784 We can handle data up to 0x1fffffff (old format) and
1785 0xfffffffff (new format) bytes now.
1786 */
1787 if ((hdr->offset_size= fmt->dynamic_column_offset_bytes(hdr->data_size)) >=
1788 fmt->max_offset_size)
1789 return ER_DYNCOL_LIMIT;
1790
1791 /* header entry is column number or string pointer + offset & type */
1792 hdr->entry_size= fmt->fixed_hdr_entry + hdr->offset_size;
1793 hdr->header_size= hdr->column_count * hdr->entry_size;
1794 return ER_DYNCOL_OK;
1795}
1796
1797/**
1798 Create packed string which contains given columns (internal multi format)
1799
1800 @param str String where to write the data
1801 @param column_count Number of columns in the arrays
1802 @param column_keys Array of columns keys (format dependent)
1803 @param values Array of columns values
1804 @param new_str True if we need allocate new string
1805 @param string_keys keys are strings
1806
1807 @return ER_DYNCOL_* return code
1808*/
1809
1810static enum enum_dyncol_func_result
1811dynamic_column_create_many_internal_fmt(DYNAMIC_COLUMN *str,
1812 uint column_count,
1813 void *column_keys,
1814 DYNAMIC_COLUMN_VALUE *values,
1815 my_bool new_str,
1816 my_bool string_keys)
1817{
1818 DYN_HEADER header;
1819 enum enum_dyncol_func_result rc;
1820 memset(&header, 0, sizeof(header));
1821 header.format= (string_keys ? 1 : 0);
1822
1823 if (new_str)
1824 {
1825 /* to make dynstr_free() working in case of errors */
1826 memset(str, 0, sizeof(DYNAMIC_COLUMN));
1827 }
1828
1829 if ((rc= calc_var_sizes(&header, column_count, column_keys, values)) < 0)
1830 return rc;
1831
1832 return dynamic_new_column_store(str, &header,
1833 column_count,
1834 column_keys, values,
1835 new_str);
1836}
1837
1838
1839/**
1840 Create packed string which contains given columns
1841
1842 @param str String where to write the data
1843 @param column_count Number of columns in the arrays
1844 @param column_numbers Array of columns numbers
1845 @param values Array of columns values
1846
1847 @return ER_DYNCOL_* return code
1848*/
1849
1850enum enum_dyncol_func_result
1851dynamic_column_create_many(DYNAMIC_COLUMN *str,
1852 uint column_count,
1853 uint *column_numbers,
1854 DYNAMIC_COLUMN_VALUE *values)
1855{
1856 return(dynamic_column_create_many_internal_fmt(str, column_count,
1857 column_numbers, values,
1858 TRUE, FALSE));
1859}
1860
1861/**
1862 Create packed string which contains given columns
1863
1864 @param str String where to write the data
1865 @param column_count Number of columns in the arrays
1866 @param column_numbers Array of columns numbers
1867 @param values Array of columns values
1868 @param new_string True if we need allocate new string
1869
1870 @return ER_DYNCOL_* return code
1871*/
1872
1873enum enum_dyncol_func_result
1874mariadb_dyncol_create_many_num(DYNAMIC_COLUMN *str,
1875 uint column_count,
1876 uint *column_numbers,
1877 DYNAMIC_COLUMN_VALUE *values,
1878 my_bool new_string)
1879{
1880 return(dynamic_column_create_many_internal_fmt(str, column_count,
1881 column_numbers, values,
1882 new_string, FALSE));
1883}
1884
1885/**
1886 Create packed string which contains given columns
1887
1888 @param str String where to write the data
1889 @param column_count Number of columns in the arrays
1890 @param column_keys Array of columns keys
1891 @param values Array of columns value
1892 @param new_string True if we need allocate new string
1893
1894 @return ER_DYNCOL_* return code
1895*/
1896
1897enum enum_dyncol_func_result
1898mariadb_dyncol_create_many_named(DYNAMIC_COLUMN *str,
1899 uint column_count,
1900 LEX_STRING *column_keys,
1901 DYNAMIC_COLUMN_VALUE *values,
1902 my_bool new_string)
1903{
1904 return(dynamic_column_create_many_internal_fmt(str, column_count,
1905 column_keys, values,
1906 new_string, TRUE));
1907}
1908
1909/**
1910 Create packed string which contains given column
1911
1912 @param str String where to write the data
1913 @param column_number Column number
1914 @param value The columns value
1915
1916 @return ER_DYNCOL_* return code
1917*/
1918
1919enum enum_dyncol_func_result
1920dynamic_column_create(DYNAMIC_COLUMN *str, uint column_nr,
1921 DYNAMIC_COLUMN_VALUE *value)
1922{
1923 return(dynamic_column_create_many(str, 1, &column_nr, value));
1924}
1925
1926
1927/**
1928 Calculate length of data between given two header entries
1929
1930 @param entry Pointer to the first entry
1931 @param entry_next Pointer to the last entry
1932 @param header_end Pointer to the header end
1933 @param offset_size Size of offset field in bytes
1934 @param last_offset Size of the data segment
1935
1936 @return number of bytes
1937*/
1938
1939static size_t get_length_interval(uchar *entry, uchar *entry_next,
1940 uchar *header_end, size_t offset_size,
1941 size_t last_offset)
1942{
1943 size_t offset, offset_next;
1944 DYNAMIC_COLUMN_TYPE type, type_next;
1945 DBUG_ASSERT(entry < entry_next);
1946
1947 if (type_and_offset_read_num(&type, &offset, entry + COLUMN_NUMBER_SIZE,
1948 offset_size))
1949 return DYNCOL_OFFSET_ERROR;
1950 if (entry_next >= header_end)
1951 return (last_offset - offset);
1952 if (type_and_offset_read_num(&type_next, &offset_next,
1953 entry_next + COLUMN_NUMBER_SIZE, offset_size))
1954 return DYNCOL_OFFSET_ERROR;
1955 return (offset_next - offset);
1956}
1957
1958
1959/**
1960 Calculate length of data between given hdr->entry and next_entry
1961
1962 @param hdr descriptor of dynamic column record
1963 @param next_entry next header entry (can point just after last header
1964 entry)
1965
1966 @return number of bytes
1967*/
1968
1969static size_t hdr_interval_length(DYN_HEADER *hdr, uchar *next_entry)
1970{
1971 struct st_service_funcs *fmt= fmt_data + hdr->format;
1972 size_t next_entry_offset;
1973 DYNAMIC_COLUMN_TYPE next_entry_type;
1974 DBUG_ASSERT(hdr->entry < next_entry);
1975 DBUG_ASSERT(hdr->entry >= hdr->header);
1976 DBUG_ASSERT(next_entry <= hdr->header + hdr->header_size);
1977
1978 if ((*fmt->type_and_offset_read)(&hdr->type, &hdr->offset,
1979 hdr->entry + fmt->fixed_hdr_entry,
1980 hdr->offset_size))
1981 return DYNCOL_OFFSET_ERROR;
1982 if (next_entry == hdr->header + hdr->header_size)
1983 return hdr->data_size - hdr->offset;
1984 if ((*fmt->type_and_offset_read)(&next_entry_type, &next_entry_offset,
1985 next_entry + fmt->fixed_hdr_entry,
1986 hdr->offset_size))
1987 return DYNCOL_OFFSET_ERROR;
1988 return (next_entry_offset - hdr->offset);
1989}
1990
1991
1992/**
1993 Comparator function for references to header entries for qsort
1994*/
1995
1996static int header_compar_num(const void *a, const void *b)
1997{
1998 uint va= uint2korr((uchar*)a), vb= uint2korr((uchar*)b);
1999 return (va > vb ? 1 : (va < vb ? -1 : 0));
2000}
2001
2002
2003/**
2004 Find entry in the numeric format header by the column number
2005
2006 @param hdr descriptor of dynamic column record
2007 @param key number to find
2008
2009 @return pointer to the entry or NULL
2010*/
2011
2012static uchar *find_entry_num(DYN_HEADER *hdr, uint key)
2013{
2014 uchar header_entry[2+4];
2015 DBUG_ASSERT(hdr->format == dyncol_fmt_num);
2016 int2store(header_entry, key);
2017 return hdr->entry= bsearch(header_entry, hdr->header,
2018 (size_t)hdr->column_count,
2019 hdr->entry_size, &header_compar_num);
2020}
2021
2022
2023/**
2024 Read name from header entry
2025
2026 @param hdr descriptor of dynamic column record
2027 @param entry pointer to the header entry
2028 @param name where to put name
2029
2030 @return 0 ok
2031 @return 1 error in data
2032*/
2033
2034static my_bool read_name(DYN_HEADER *hdr, uchar *entry, LEX_STRING *name)
2035{
2036 size_t nmoffset= uint2korr(entry);
2037 uchar *next_entry= entry + hdr->entry_size;
2038
2039 if (nmoffset > hdr->nmpool_size)
2040 return 1;
2041
2042 name->str= (char *)hdr->nmpool + nmoffset;
2043 if (next_entry == hdr->header + hdr->header_size)
2044 name->length= hdr->nmpool_size - nmoffset;
2045 else
2046 {
2047 size_t next_nmoffset= uint2korr(next_entry);
2048 if (next_nmoffset > hdr->nmpool_size)
2049 return 1;
2050 name->length= next_nmoffset - nmoffset;
2051 }
2052 return 0;
2053}
2054
2055
2056/**
2057 Find entry in the names format header by the column number
2058
2059 @param hdr descriptor of dynamic column record
2060 @param key name to find
2061
2062 @return pointer to the entry or NULL
2063*/
2064static uchar *find_entry_named(DYN_HEADER *hdr, LEX_STRING *key)
2065{
2066 uchar *min= hdr->header;
2067 uchar *max= hdr->header + (hdr->column_count - 1) * hdr->entry_size;
2068 uchar *mid;
2069 DBUG_ASSERT(hdr->format == dyncol_fmt_str);
2070 DBUG_ASSERT(hdr->nmpool != NULL);
2071 while (max >= min)
2072 {
2073 LEX_STRING name;
2074 int cmp;
2075 mid= hdr->header + ((min - hdr->header) +
2076 (max - hdr->header)) /
2077 2 /
2078 hdr->entry_size * hdr->entry_size;
2079 if (read_name(hdr, mid, &name))
2080 return NULL;
2081 cmp= mariadb_dyncol_column_cmp_named(&name, key);
2082 if (cmp < 0)
2083 min= mid + hdr->entry_size;
2084 else if (cmp > 0)
2085 max= mid - hdr->entry_size;
2086 else
2087 return mid;
2088 }
2089 return NULL;
2090}
2091
2092
2093/**
2094 Write number in the buffer (backward direction - starts from the buffer end)
2095
2096 @return pointer on the number beginning
2097*/
2098
2099static char *backwritenum(char *chr, uint numkey)
2100{
2101 if (numkey == 0)
2102 *(--chr)= '0';
2103 else
2104 while (numkey > 0)
2105 {
2106 *(--chr)= '0' + numkey % 10;
2107 numkey/= 10;
2108 }
2109 return chr;
2110}
2111
2112
2113/**
2114 Find column and fill information about it
2115
2116 @param hdr descriptor of dynamic column record
2117 @param numkey Number of the column to fetch (if strkey is NULL)
2118 @param strkey Name of the column to fetch (or NULL)
2119
2120 @return 0 ok
2121 @return 1 error in data
2122*/
2123
2124static my_bool
2125find_column(DYN_HEADER *hdr, uint numkey, LEX_STRING *strkey)
2126{
2127 LEX_STRING nmkey;
2128 char nmkeybuff[DYNCOL_NUM_CHAR]; /* to fit max 2 bytes number */
2129 DBUG_ASSERT(hdr->header != NULL);
2130
2131 if (hdr->header + hdr->header_size > hdr->data_end)
2132 return TRUE;
2133
2134 /* fix key */
2135 if (hdr->format == dyncol_fmt_num && strkey != NULL)
2136 {
2137 char *end;
2138 numkey= (uint) strtoul(strkey->str, &end, 10);
2139 if (end != strkey->str + strkey->length)
2140 {
2141 /* we can't find non-numeric key among numeric ones */
2142 hdr->type= DYN_COL_NULL;
2143 return 0;
2144 }
2145 }
2146 else if (hdr->format == dyncol_fmt_str && strkey == NULL)
2147 {
2148 nmkey.str= backwritenum(nmkeybuff + sizeof(nmkeybuff), numkey);
2149 nmkey.length= (nmkeybuff + sizeof(nmkeybuff)) - nmkey.str;
2150 strkey= &nmkey;
2151 }
2152 if (hdr->format == dyncol_fmt_num)
2153 hdr->entry= find_entry_num(hdr, numkey);
2154 else
2155 hdr->entry= find_entry_named(hdr, strkey);
2156
2157 if (!hdr->entry)
2158 {
2159 /* Column not found */
2160 hdr->type= DYN_COL_NULL;
2161 return 0;
2162 }
2163 hdr->length= hdr_interval_length(hdr, hdr->entry + hdr->entry_size);
2164 hdr->data= hdr->dtpool + hdr->offset;
2165 /*
2166 Check that the found data is within the ranges. This can happen if
2167 we get data with wrong offsets.
2168 */
2169 if (hdr->length == DYNCOL_OFFSET_ERROR ||
2170 hdr->length > INT_MAX || hdr->offset > hdr->data_size)
2171 return 1;
2172
2173 return 0;
2174}
2175
2176
2177/**
2178 Read and check the header of the dynamic string
2179
2180 @param hdr descriptor of dynamic column record
2181 @param str Dynamic string
2182
2183 @retval FALSE OK
2184 @retval TRUE error
2185
2186 Note
2187 We don't check for str->length == 0 as all code that calls this
2188 already have handled this case.
2189*/
2190
2191static inline my_bool read_fixed_header(DYN_HEADER *hdr,
2192 DYNAMIC_COLUMN *str)
2193{
2194 DBUG_ASSERT(str != NULL && str->length != 0);
2195 if ((str->length < 1) ||
2196 (str->str[0] & (~DYNCOL_FLG_KNOWN)))
2197 return 1;
2198 hdr->format= ((str->str[0] & DYNCOL_FLG_NAMES) ?
2199 dyncol_fmt_str:
2200 dyncol_fmt_num);
2201 if ((str->length < fmt_data[hdr->format].fixed_hdr))
2202 return 1; /* Wrong header */
2203 hdr->offset_size= (str->str[0] & DYNCOL_FLG_OFFSET) + 1 +
2204 (hdr->format == dyncol_fmt_str ? 1 : 0);
2205 hdr->column_count= uint2korr(str->str + 1);
2206 if (hdr->format == dyncol_fmt_str)
2207 hdr->nmpool_size= uint2korr(str->str + 3); // only 2 bytes supported for now
2208 else
2209 hdr->nmpool_size= 0;
2210 return 0;
2211}
2212
2213
2214/**
2215 Get dynamic column value by column number
2216
2217 @param str The packed string to extract the column
2218 @param column_nr Number of column to fetch
2219 @param store_it_here Where to store the extracted value
2220
2221 @return ER_DYNCOL_* return code
2222*/
2223
2224enum enum_dyncol_func_result
2225dynamic_column_get(DYNAMIC_COLUMN *str, uint column_nr,
2226 DYNAMIC_COLUMN_VALUE *store_it_here)
2227{
2228 return dynamic_column_get_internal(str, store_it_here, column_nr, NULL);
2229}
2230
2231enum enum_dyncol_func_result
2232mariadb_dyncol_get_num(DYNAMIC_COLUMN *str, uint column_nr,
2233 DYNAMIC_COLUMN_VALUE *store_it_here)
2234{
2235 return dynamic_column_get_internal(str, store_it_here, column_nr, NULL);
2236}
2237
2238
2239/**
2240 Get dynamic column value by name
2241
2242 @param str The packed string to extract the column
2243 @param name Name of column to fetch
2244 @param store_it_here Where to store the extracted value
2245
2246 @return ER_DYNCOL_* return code
2247*/
2248
2249enum enum_dyncol_func_result
2250mariadb_dyncol_get_named(DYNAMIC_COLUMN *str, LEX_STRING *name,
2251 DYNAMIC_COLUMN_VALUE *store_it_here)
2252{
2253 DBUG_ASSERT(name != NULL);
2254 return dynamic_column_get_internal(str, store_it_here, 0, name);
2255}
2256
2257
2258static enum enum_dyncol_func_result
2259dynamic_column_get_value(DYN_HEADER *hdr, DYNAMIC_COLUMN_VALUE *store_it_here)
2260{
2261 static enum enum_dyncol_func_result rc;
2262 switch ((store_it_here->type= hdr->type)) {
2263 case DYN_COL_INT:
2264 rc= dynamic_column_sint_read(store_it_here, hdr->data, hdr->length);
2265 break;
2266 case DYN_COL_UINT:
2267 rc= dynamic_column_uint_read(store_it_here, hdr->data, hdr->length);
2268 break;
2269 case DYN_COL_DOUBLE:
2270 rc= dynamic_column_double_read(store_it_here, hdr->data, hdr->length);
2271 break;
2272 case DYN_COL_STRING:
2273 rc= dynamic_column_string_read(store_it_here, hdr->data, hdr->length);
2274 break;
2275#ifndef LIBMARIADB
2276 case DYN_COL_DECIMAL:
2277 rc= dynamic_column_decimal_read(store_it_here, hdr->data, hdr->length);
2278 break;
2279#endif
2280 case DYN_COL_DATETIME:
2281 rc= dynamic_column_date_time_read(store_it_here, hdr->data,
2282 hdr->length);
2283 break;
2284 case DYN_COL_DATE:
2285 rc= dynamic_column_date_read(store_it_here, hdr->data, hdr->length);
2286 break;
2287 case DYN_COL_TIME:
2288 rc= dynamic_column_time_read(store_it_here, hdr->data, hdr->length);
2289 break;
2290 case DYN_COL_NULL:
2291 rc= ER_DYNCOL_OK;
2292 break;
2293 case DYN_COL_DYNCOL:
2294 rc= dynamic_column_dyncol_read(store_it_here, hdr->data, hdr->length);
2295 break;
2296 default:
2297 rc= ER_DYNCOL_FORMAT;
2298 store_it_here->type= DYN_COL_NULL;
2299 break;
2300 }
2301 return rc;
2302}
2303
2304/**
2305 Get dynamic column value by number or name
2306
2307 @param str The packed string to extract the column
2308 @param store_it_here Where to store the extracted value
2309 @param numkey Number of the column to fetch (if strkey is NULL)
2310 @param strkey Name of the column to fetch (or NULL)
2311
2312 @return ER_DYNCOL_* return code
2313*/
2314
2315static enum enum_dyncol_func_result
2316dynamic_column_get_internal(DYNAMIC_COLUMN *str,
2317 DYNAMIC_COLUMN_VALUE *store_it_here,
2318 uint num_key, LEX_STRING *str_key)
2319{
2320 DYN_HEADER header;
2321 enum enum_dyncol_func_result rc= ER_DYNCOL_FORMAT;
2322 memset(&header, 0, sizeof(header));
2323
2324 if (str->length == 0)
2325 goto null;
2326
2327 if ((rc= init_read_hdr(&header, str)) < 0)
2328 goto err;
2329
2330 if (header.column_count == 0)
2331 goto null;
2332
2333 if (find_column(&header, num_key, str_key))
2334 goto err;
2335
2336 rc= dynamic_column_get_value(&header, store_it_here);
2337 return rc;
2338
2339null:
2340 rc= ER_DYNCOL_OK;
2341err:
2342 store_it_here->type= DYN_COL_NULL;
2343 return rc;
2344}
2345
2346
2347/**
2348 Check existence of the column in the packed string (by number)
2349
2350 @param str The packed string to check the column
2351 @param column_nr Number of column to check
2352
2353 @return ER_DYNCOL_* return code
2354*/
2355
2356enum enum_dyncol_func_result
2357mariadb_dyncol_exists_num(DYNAMIC_COLUMN *str, uint column_nr)
2358{
2359 return dynamic_column_exists_internal(str, column_nr, NULL);
2360}
2361
2362/**
2363 Check existence of the column in the packed string (by name)
2364
2365 @param str The packed string to check the column
2366 @param name Name of column to check
2367
2368 @return ER_DYNCOL_* return code
2369*/
2370
2371enum enum_dyncol_func_result
2372mariadb_dyncol_exists_named(DYNAMIC_COLUMN *str, LEX_STRING *name)
2373{
2374 DBUG_ASSERT(name != NULL);
2375 return dynamic_column_exists_internal(str, 0, name);
2376}
2377
2378
2379/**
2380 Check existence of the column in the packed string (by name of number)
2381
2382 @param str The packed string to check the column
2383 @param num_key Number of the column to fetch (if strkey is NULL)
2384 @param str_key Name of the column to fetch (or NULL)
2385
2386 @return ER_DYNCOL_* return code
2387*/
2388
2389static enum enum_dyncol_func_result
2390dynamic_column_exists_internal(DYNAMIC_COLUMN *str, uint num_key,
2391 LEX_STRING *str_key)
2392{
2393 DYN_HEADER header;
2394 enum enum_dyncol_func_result rc;
2395 memset(&header, 0, sizeof(header));
2396
2397 if (str->length == 0)
2398 return ER_DYNCOL_NO; /* no columns */
2399
2400 if ((rc= init_read_hdr(&header, str)) < 0)
2401 return rc;
2402
2403 if (header.column_count == 0)
2404 return ER_DYNCOL_NO; /* no columns */
2405
2406 if (find_column(&header, num_key, str_key))
2407 return ER_DYNCOL_FORMAT;
2408
2409 return (header.type != DYN_COL_NULL ? ER_DYNCOL_YES : ER_DYNCOL_NO);
2410}
2411
2412
2413/**
2414 List not-null columns in the packed string (only numeric format)
2415
2416 @param str The packed string
2417 @param array_of_uint Where to put reference on created array
2418
2419 @return ER_DYNCOL_* return code
2420*/
2421enum enum_dyncol_func_result
2422dynamic_column_list(DYNAMIC_COLUMN *str, DYNAMIC_ARRAY *array_of_uint)
2423{
2424 DYN_HEADER header;
2425 uchar *read;
2426 uint i;
2427 enum enum_dyncol_func_result rc;
2428
2429 memset(array_of_uint, 0, sizeof(*array_of_uint)); /* In case of errors */
2430 if (str->length == 0)
2431 return ER_DYNCOL_OK; /* no columns */
2432
2433 if ((rc= init_read_hdr(&header, str)) < 0)
2434 return rc;
2435
2436 if (header.format != dyncol_fmt_num)
2437 return ER_DYNCOL_FORMAT;
2438
2439 if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
2440 str->length)
2441 return ER_DYNCOL_FORMAT;
2442
2443 if (ma_init_dynamic_array(array_of_uint, sizeof(uint), header.column_count, 0))
2444 return ER_DYNCOL_RESOURCE;
2445
2446 for (i= 0, read= header.header;
2447 i < header.column_count;
2448 i++, read+= header.entry_size)
2449 {
2450 uint nm= uint2korr(read);
2451 /* Insert can't never fail as it's pre-allocated above */
2452 (void) ma_insert_dynamic(array_of_uint, (uchar *)&nm);
2453 }
2454 return ER_DYNCOL_OK;
2455}
2456
2457/**
2458 List not-null columns in the packed string (only numeric format)
2459
2460 @param str The packed string
2461 @param array_of_uint Where to put reference on created array
2462
2463 @return ER_DYNCOL_* return code
2464*/
2465enum enum_dyncol_func_result
2466mariadb_dyncol_list_num(DYNAMIC_COLUMN *str, uint *count, uint **nums)
2467{
2468 DYN_HEADER header;
2469 uchar *read;
2470 uint i;
2471 enum enum_dyncol_func_result rc;
2472
2473 (*nums)= 0; (*count)= 0; /* In case of errors */
2474 if (str->length == 0)
2475 return ER_DYNCOL_OK; /* no columns */
2476
2477 if ((rc= init_read_hdr(&header, str)) < 0)
2478 return rc;
2479
2480 if (header.format != dyncol_fmt_num)
2481 return ER_DYNCOL_FORMAT;
2482
2483 if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
2484 str->length)
2485 return ER_DYNCOL_FORMAT;
2486
2487 if (!((*nums)= (uint *)malloc(sizeof(uint) * header.column_count)))
2488 return ER_DYNCOL_RESOURCE;
2489
2490 for (i= 0, read= header.header;
2491 i < header.column_count;
2492 i++, read+= header.entry_size)
2493 {
2494 (*nums)[i]= uint2korr(read);
2495 }
2496 (*count)= header.column_count;
2497 return ER_DYNCOL_OK;
2498}
2499
2500/**
2501 List not-null columns in the packed string (any format)
2502
2503 @param str The packed string
2504 @param count Number of names in the list
2505 @param names Where to put names list (should be freed)
2506
2507 @return ER_DYNCOL_* return code
2508*/
2509
2510enum enum_dyncol_func_result
2511mariadb_dyncol_list_named(DYNAMIC_COLUMN *str, uint *count, LEX_STRING **names)
2512{
2513 DYN_HEADER header;
2514 uchar *read;
2515 char *pool;
2516 struct st_service_funcs *fmt;
2517 uint i;
2518 enum enum_dyncol_func_result rc;
2519
2520 (*names)= 0; (*count)= 0;
2521
2522 if (str->length == 0)
2523 return ER_DYNCOL_OK; /* no columns */
2524
2525 if ((rc= init_read_hdr(&header, str)) < 0)
2526 return rc;
2527
2528 fmt= fmt_data + header.format;
2529
2530 if (header.entry_size * header.column_count + fmt->fixed_hdr >
2531 str->length)
2532 return ER_DYNCOL_FORMAT;
2533
2534 if (header.format == dyncol_fmt_num)
2535 *names= (LEX_STRING *)malloc(sizeof(LEX_STRING) * header.column_count +
2536 DYNCOL_NUM_CHAR * header.column_count);
2537 else
2538 *names= (LEX_STRING *)malloc(sizeof(LEX_STRING) * header.column_count +
2539 header.nmpool_size + header.column_count);
2540 if (!(*names))
2541 return ER_DYNCOL_RESOURCE;
2542 pool= ((char *)(*names)) + sizeof(LEX_STRING) * header.column_count;
2543
2544 for (i= 0, read= header.header;
2545 i < header.column_count;
2546 i++, read+= header.entry_size)
2547 {
2548 if (header.format == dyncol_fmt_num)
2549 {
2550 uint nm= uint2korr(read);
2551 (*names)[i].str= pool;
2552 pool+= DYNCOL_NUM_CHAR;
2553 (*names)[i].length=
2554 ma_ll2str(nm, (*names)[i].str, 10) - (*names)[i].str;
2555 }
2556 else
2557 {
2558 LEX_STRING tmp;
2559 if (read_name(&header, read, &tmp))
2560 return ER_DYNCOL_FORMAT;
2561 (*names)[i].length= tmp.length;
2562 (*names)[i].str= pool;
2563 pool+= tmp.length + 1;
2564 memcpy((*names)[i].str, (const void *)tmp.str, tmp.length);
2565 (*names)[i].str[tmp.length]= '\0'; // just for safety
2566 }
2567 }
2568 (*count)= header.column_count;
2569 return ER_DYNCOL_OK;
2570}
2571
2572/**
2573 Find the place of the column in the header or place where it should be put
2574
2575 @param hdr descriptor of dynamic column record
2576 @param key Name or number of column to fetch
2577 (depends on string_key)
2578 @param string_key True if we gave pointer to LEX_STRING.
2579
2580 @retval TRUE found
2581 @retval FALSE pointer set to the next row
2582*/
2583
2584static my_bool
2585find_place(DYN_HEADER *hdr, void *key, my_bool string_keys)
2586{
2587 uint mid, start, end, val;
2588 int UNINIT_VAR(flag);
2589 LEX_STRING str;
2590 char buff[DYNCOL_NUM_CHAR];
2591 my_bool need_conversion= ((string_keys ? dyncol_fmt_str : dyncol_fmt_num) !=
2592 hdr->format);
2593 /* new format can't be numeric if the old one is names */
2594 DBUG_ASSERT(string_keys ||
2595 hdr->format == dyncol_fmt_num);
2596
2597 start= 0;
2598 end= hdr->column_count -1;
2599 mid= 1;
2600 while (start != end)
2601 {
2602 uint val;
2603 mid= (start + end) / 2;
2604 hdr->entry= hdr->header + mid * hdr->entry_size;
2605 if (!string_keys)
2606 {
2607 val= uint2korr(hdr->entry);
2608 flag= CMP_NUM(*((uint *)key), val);
2609 }
2610 else
2611 {
2612 if (need_conversion)
2613 {
2614 str.str= backwritenum(buff + sizeof(buff), uint2korr(hdr->entry));
2615 str.length= (buff + sizeof(buff)) - str.str;
2616 }
2617 else
2618 {
2619 DBUG_ASSERT(hdr->format == dyncol_fmt_str);
2620 if (read_name(hdr, hdr->entry, &str))
2621 return 0;
2622 }
2623 flag= mariadb_dyncol_column_cmp_named((LEX_STRING *)key, &str);
2624 }
2625 if (flag <= 0)
2626 end= mid;
2627 else
2628 start= mid + 1;
2629 }
2630 hdr->entry= hdr->header + start * hdr->entry_size;
2631 if (start != mid)
2632 {
2633 if (!string_keys)
2634 {
2635 val= uint2korr(hdr->entry);
2636 flag= CMP_NUM(*((uint *)key), val);
2637 }
2638 else
2639 {
2640 if (need_conversion)
2641 {
2642 str.str= backwritenum(buff + sizeof(buff), uint2korr(hdr->entry));
2643 str.length= (buff + sizeof(buff)) - str.str;
2644 }
2645 else
2646 {
2647 DBUG_ASSERT(hdr->format == dyncol_fmt_str);
2648 if (read_name(hdr, hdr->entry, &str))
2649 return 0;
2650 }
2651 flag= mariadb_dyncol_column_cmp_named((LEX_STRING *)key, &str);
2652 }
2653 }
2654 if (flag > 0)
2655 hdr->entry+= hdr->entry_size; /* Point at next bigger key */
2656 return flag == 0;
2657}
2658
2659
2660/*
2661 It is internal structure which describes a plan of changing the record
2662 of dynamic columns
2663*/
2664
2665typedef enum {PLAN_REPLACE, PLAN_ADD, PLAN_DELETE, PLAN_NOP} PLAN_ACT;
2666
2667struct st_plan {
2668 DYNAMIC_COLUMN_VALUE *val;
2669 void *key;
2670 uchar *place;
2671 size_t length;
2672 long long hdelta, ddelta, ndelta;
2673 long long mv_offset, mv_length;
2674 uint mv_end;
2675 PLAN_ACT act;
2676};
2677typedef struct st_plan PLAN;
2678
2679
2680/**
2681 Sort function for plan by column number
2682*/
2683
2684static int plan_sort_num(const void *a, const void *b)
2685{
2686 return *((uint *)((PLAN *)a)->key) - *((uint *)((PLAN *)b)->key);
2687}
2688
2689
2690/**
2691 Sort function for plan by column name
2692*/
2693
2694static int plan_sort_named(const void *a, const void *b)
2695{
2696 return mariadb_dyncol_column_cmp_named((LEX_STRING *)((PLAN *)a)->key,
2697 (LEX_STRING *)((PLAN *)b)->key);
2698}
2699
2700#define DELTA_CHECK(S, D, C) \
2701 if ((S) == 0) \
2702 (S)= (D); \
2703 else if (((S) > 0 && (D) < 0) || \
2704 ((S) < 0 && (D) > 0)) \
2705 { \
2706 (C)= TRUE; \
2707 }
2708
2709/**
2710 Update dynamic column by copying in a new record (string).
2711
2712 @param str Dynamic column record to change
2713 @param plan Plan of changing the record
2714 @param add_column_count number of records in the plan array.
2715 @param hdr descriptor of old dynamic column record
2716 @param new_hdr descriptor of new dynamic column record
2717 @param convert need conversion from numeric to names format
2718
2719 @return ER_DYNCOL_* return code
2720*/
2721
2722static enum enum_dyncol_func_result
2723dynamic_column_update_copy(DYNAMIC_COLUMN *str, PLAN *plan,
2724 uint add_column_count,
2725 DYN_HEADER *hdr, DYN_HEADER *new_hdr,
2726 my_bool convert)
2727{
2728 DYNAMIC_COLUMN tmp;
2729 struct st_service_funcs *fmt= fmt_data + hdr->format,
2730 *new_fmt= fmt_data + new_hdr->format;
2731 uint i, j, k;
2732 size_t all_headers_size;
2733
2734 if (dynamic_column_init_named(&tmp,
2735 (new_fmt->fixed_hdr + new_hdr->header_size +
2736 new_hdr->nmpool_size +
2737 new_hdr->data_size + DYNCOL_SYZERESERVE)))
2738 {
2739 return ER_DYNCOL_RESOURCE;
2740 }
2741 memset(tmp.str, 0, new_fmt->fixed_hdr);
2742 (*new_fmt->set_fixed_hdr)(&tmp, new_hdr);
2743 /* Adjust tmp to contain whole the future header */
2744 tmp.length= new_fmt->fixed_hdr + new_hdr->header_size + new_hdr->nmpool_size;
2745
2746
2747 /*
2748 Copy data to the new string
2749 i= index in array of changes
2750 j= index in packed string header index
2751 */
2752 new_hdr->entry= new_hdr->header;
2753 new_hdr->name= new_hdr->nmpool;
2754 all_headers_size= new_fmt->fixed_hdr +
2755 new_hdr->header_size + new_hdr->nmpool_size;
2756 for (i= 0, j= 0; i < add_column_count || j < hdr->column_count; i++)
2757 {
2758 size_t UNINIT_VAR(first_offset);
2759 uint start= j, end;
2760
2761 /*
2762 Search in i and j for the next column to add from i and where to
2763 add.
2764 */
2765
2766 while (i < add_column_count && plan[i].act == PLAN_NOP)
2767 i++; /* skip NOP */
2768
2769 if (i == add_column_count)
2770 j= end= hdr->column_count;
2771 else
2772 {
2773 /*
2774 old data portion. We don't need to check that j < column_count
2775 as plan[i].place is guaranteed to have a pointer inside the
2776 data.
2777 */
2778 while (hdr->header + j * hdr->entry_size < plan[i].place)
2779 j++;
2780 end= j;
2781 if ((plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
2782 j++; /* data at 'j' will be removed */
2783 }
2784
2785 /*
2786 Adjust all headers since last loop.
2787 We have to do this as the offset for data has moved
2788 */
2789 for (k= start; k < end; k++)
2790 {
2791 uchar *read= hdr->header + k * hdr->entry_size;
2792 void *key;
2793 LEX_STRING name;
2794 size_t offs;
2795 uint nm;
2796 DYNAMIC_COLUMN_TYPE tp;
2797 char buff[DYNCOL_NUM_CHAR];
2798
2799 if (hdr->format == dyncol_fmt_num)
2800 {
2801 if (convert)
2802 {
2803 name.str= backwritenum(buff + sizeof(buff), uint2korr(read));
2804 name.length= (buff + sizeof(buff)) - name.str;
2805 key= &name;
2806 }
2807 else
2808 {
2809 nm= uint2korr(read); /* Column nummber */
2810 key= &nm;
2811 }
2812 }
2813 else
2814 {
2815 if (read_name(hdr, read, &name))
2816 goto err;
2817 key= &name;
2818 }
2819 if (fmt->type_and_offset_read(&tp, &offs,
2820 read + fmt->fixed_hdr_entry,
2821 hdr->offset_size))
2822 goto err;
2823 if (k == start)
2824 first_offset= offs;
2825 else if (offs < first_offset)
2826 goto err;
2827
2828 offs+= (size_t)plan[i].ddelta;
2829 {
2830 DYNAMIC_COLUMN_VALUE val;
2831 val.type= tp; // only the type used in the header
2832 if ((*new_fmt->put_header_entry)(new_hdr, key, &val, offs))
2833 goto err;
2834 }
2835 }
2836
2837 /* copy first the data that was not replaced in original packed data */
2838 if (start < end)
2839 {
2840 size_t data_size;
2841 /* Add old data last in 'tmp' */
2842 hdr->entry= hdr->header + start * hdr->entry_size;
2843 data_size=
2844 hdr_interval_length(hdr, hdr->header + end * hdr->entry_size);
2845 if (data_size == DYNCOL_OFFSET_ERROR ||
2846 (long) data_size < 0 ||
2847 data_size > hdr->data_size - first_offset)
2848 goto err;
2849
2850 memcpy(tmp.str + tmp.length, (char *)hdr->dtpool + first_offset,
2851 data_size);
2852 tmp.length+= data_size;
2853 }
2854
2855 /* new data adding */
2856 if (i < add_column_count)
2857 {
2858 if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
2859 {
2860 if ((*new_fmt->put_header_entry)(new_hdr, plan[i].key,
2861 plan[i].val,
2862 tmp.length - all_headers_size))
2863 goto err;
2864 data_store(&tmp, plan[i].val, new_hdr->format); /* Append new data */
2865 }
2866 }
2867 }
2868 dynamic_column_column_free(str);
2869 *str= tmp;
2870 return ER_DYNCOL_OK;
2871err:
2872 dynamic_column_column_free(&tmp);
2873 return ER_DYNCOL_FORMAT;
2874}
2875
2876static enum enum_dyncol_func_result
2877dynamic_column_update_move_left(DYNAMIC_COLUMN *str, PLAN *plan,
2878 size_t offset_size,
2879 size_t entry_size,
2880 size_t header_size,
2881 size_t new_offset_size,
2882 size_t new_entry_size,
2883 size_t new_header_size,
2884 uint column_count,
2885 uint new_column_count,
2886 uint add_column_count,
2887 uchar *header_end,
2888 size_t max_offset)
2889{
2890 uchar *write;
2891 uchar *header_base= (uchar *)str->str + FIXED_HEADER_SIZE;
2892 uint i, j, k;
2893 size_t curr_offset;
2894
2895 write= (uchar *)str->str + FIXED_HEADER_SIZE;
2896 set_fixed_header(str, (uint)new_offset_size, new_column_count);
2897
2898 /*
2899 Move headers first.
2900 i= index in array of changes
2901 j= index in packed string header index
2902 */
2903 for (curr_offset= 0, i= 0, j= 0;
2904 i < add_column_count || j < column_count;
2905 i++)
2906 {
2907 size_t UNINIT_VAR(first_offset);
2908 uint start= j, end;
2909
2910 /*
2911 Search in i and j for the next column to add from i and where to
2912 add.
2913 */
2914
2915 while (i < add_column_count && plan[i].act == PLAN_NOP)
2916 i++; /* skip NOP */
2917
2918 if (i == add_column_count)
2919 j= end= column_count;
2920 else
2921 {
2922 /*
2923 old data portion. We don't need to check that j < column_count
2924 as plan[i].place is guaranteed to have a pointer inside the
2925 data.
2926 */
2927 while (header_base + j * entry_size < plan[i].place)
2928 j++;
2929 end= j;
2930 if ((plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
2931 j++; /* data at 'j' will be removed */
2932 }
2933 plan[i].mv_end= end;
2934
2935 {
2936 DYNAMIC_COLUMN_TYPE tp;
2937 if (type_and_offset_read_num(&tp, &first_offset,
2938 header_base + start * entry_size +
2939 COLUMN_NUMBER_SIZE, offset_size))
2940 return ER_DYNCOL_FORMAT;
2941 }
2942 /* find data to be moved */
2943 if (start < end)
2944 {
2945 size_t data_size=
2946 get_length_interval(header_base + start * entry_size,
2947 header_base + end * entry_size,
2948 header_end, offset_size, max_offset);
2949 if (data_size == DYNCOL_OFFSET_ERROR ||
2950 (long) data_size < 0 ||
2951 data_size > max_offset - first_offset)
2952 {
2953 str->length= 0; // just something valid
2954 return ER_DYNCOL_FORMAT;
2955 }
2956 DBUG_ASSERT(curr_offset == first_offset + plan[i].ddelta);
2957 plan[i].mv_offset= first_offset;
2958 plan[i].mv_length= data_size;
2959 curr_offset+= data_size;
2960 }
2961 else
2962 {
2963 plan[i].mv_length= 0;
2964 plan[i].mv_offset= curr_offset;
2965 }
2966
2967 if (plan[i].ddelta == 0 && offset_size == new_offset_size &&
2968 plan[i].act != PLAN_DELETE)
2969 write+= entry_size * (end - start);
2970 else
2971 {
2972 /*
2973 Adjust all headers since last loop.
2974 We have to do this as the offset for data has moved
2975 */
2976 for (k= start; k < end; k++)
2977 {
2978 uchar *read= header_base + k * entry_size;
2979 size_t offs;
2980 uint nm;
2981 DYNAMIC_COLUMN_TYPE tp;
2982
2983 nm= uint2korr(read); /* Column nummber */
2984 if (type_and_offset_read_num(&tp, &offs, read + COLUMN_NUMBER_SIZE,
2985 offset_size))
2986 return ER_DYNCOL_FORMAT;
2987
2988 if (k > start && offs < first_offset)
2989 {
2990 str->length= 0; // just something valid
2991 return ER_DYNCOL_FORMAT;
2992 }
2993
2994 offs+= (size_t)plan[i].ddelta;
2995 int2store(write, nm);
2996 /* write rest of data at write + COLUMN_NUMBER_SIZE */
2997 type_and_offset_store_num(write, new_offset_size, tp, offs);
2998 write+= new_entry_size;
2999 }
3000 }
3001
3002 /* new data adding */
3003 if (i < add_column_count)
3004 {
3005 if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
3006 {
3007 int2store(write, *((uint *)plan[i].key));
3008 type_and_offset_store_num(write, new_offset_size,
3009 plan[i].val[0].type,
3010 curr_offset);
3011 write+= new_entry_size;
3012 curr_offset+= plan[i].length;
3013 }
3014 }
3015 }
3016
3017 /*
3018 Move data.
3019 i= index in array of changes
3020 j= index in packed string header index
3021 */
3022 str->length= (FIXED_HEADER_SIZE + new_header_size);
3023 for (i= 0, j= 0;
3024 i < add_column_count || j < column_count;
3025 i++)
3026 {
3027 uint start= j, end;
3028
3029 /*
3030 Search in i and j for the next column to add from i and where to
3031 add.
3032 */
3033
3034 while (i < add_column_count && plan[i].act == PLAN_NOP)
3035 i++; /* skip NOP */
3036
3037 j= end= plan[i].mv_end;
3038 if (i != add_column_count &&
3039 (plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
3040 j++;
3041
3042 /* copy first the data that was not replaced in original packed data */
3043 if (start < end && plan[i].mv_length)
3044 {
3045 memmove((header_base + new_header_size +
3046 (size_t)plan[i].mv_offset + (size_t)plan[i].ddelta),
3047 header_base + header_size + (size_t)plan[i].mv_offset,
3048 (size_t)plan[i].mv_length);
3049 }
3050 str->length+= (size_t)plan[i].mv_length;
3051
3052 /* new data adding */
3053 if (i < add_column_count)
3054 {
3055 if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
3056 {
3057 data_store(str, plan[i].val, dyncol_fmt_num);/* Append new data */
3058 }
3059 }
3060 }
3061 return ER_DYNCOL_OK;
3062}
3063
3064#ifdef UNUSED
3065static enum enum_dyncol_func_result
3066dynamic_column_update_move_right(DYNAMIC_COLUMN *str, PLAN *plan,
3067 size_t offset_size,
3068 size_t entry_size,
3069 size_t header_size,
3070 size_t new_offset_size,
3071 size_t new_entry_size,
3072 size_t new_header_size,
3073 uint column_count,
3074 uint new_column_count,
3075 uint add_column_count,
3076 uchar *header_end,
3077 size_t max_offset)
3078{
3079 uchar *write;
3080 uchar *header_base= (uchar *)str->str + FIXED_HEADER_SIZE;
3081 uint i, j, k;
3082 size_t curr_offset;
3083
3084 write= (uchar *)str->str + FIXED_HEADER_SIZE;
3085 set_fixed_header(str, new_offset_size, new_column_count);
3086
3087 /*
3088 Move data first.
3089 i= index in array of changes
3090 j= index in packed string header index
3091 */
3092 for (curr_offset= 0, i= 0, j= 0;
3093 i < add_column_count || j < column_count;
3094 i++)
3095 {
3096 size_t UNINIT_VAR(first_offset);
3097 uint start= j, end;
3098
3099 /*
3100 Search in i and j for the next column to add from i and where to
3101 add.
3102 */
3103
3104 while (i < add_column_count && plan[i].act == PLAN_NOP)
3105 i++; /* skip NOP */
3106
3107 if (i == add_column_count)
3108 j= end= column_count;
3109 else
3110 {
3111 /*
3112 old data portion. We don't need to check that j < column_count
3113 as plan[i].place is guaranteed to have a pointer inside the
3114 data.
3115 */
3116 while (header_base + j * entry_size < plan[i].place)
3117 j++;
3118 end= j;
3119 if ((plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
3120 j++; /* data at 'j' will be removed */
3121 }
3122 plan[i].mv_end= end;
3123
3124 {
3125 DYNAMIC_COLUMN_TYPE tp;
3126 type_and_offset_read_num(&tp, &first_offset,
3127 header_base +
3128 start * entry_size + COLUMN_NUMBER_SIZE,
3129 offset_size);
3130 }
3131 /* find data to be moved */
3132 if (start < end)
3133 {
3134 size_t data_size=
3135 get_length_interval(header_base + start * entry_size,
3136 header_base + end * entry_size,
3137 header_end, offset_size, max_offset);
3138 if (data_size == DYNCOL_OFFSET_ERROR ||
3139 (long) data_size < 0 ||
3140 data_size > max_offset - first_offset)
3141 {
3142 str->length= 0; // just something valid
3143 return ER_DYNCOL_FORMAT;
3144 }
3145 DBUG_ASSERT(curr_offset == first_offset + plan[i].ddelta);
3146 plan[i].mv_offset= first_offset;
3147 plan[i].mv_length= data_size;
3148 curr_offset+= data_size;
3149 }
3150 else
3151 {
3152 plan[i].mv_length= 0;
3153 plan[i].mv_offset= curr_offset;
3154 }
3155
3156 if (plan[i].ddelta == 0 && offset_size == new_offset_size &&
3157 plan[i].act != PLAN_DELETE)
3158 write+= entry_size * (end - start);
3159 else
3160 {
3161 /*
3162 Adjust all headers since last loop.
3163 We have to do this as the offset for data has moved
3164 */
3165 for (k= start; k < end; k++)
3166 {
3167 uchar *read= header_base + k * entry_size;
3168 size_t offs;
3169 uint nm;
3170 DYNAMIC_COLUMN_TYPE tp;
3171
3172 nm= uint2korr(read); /* Column nummber */
3173 type_and_offset_read_num(&tp, &offs, read + COLUMN_NUMBER_SIZE,
3174 offset_size);
3175 if (k > start && offs < first_offset)
3176 {
3177 str->length= 0; // just something valid
3178 return ER_DYNCOL_FORMAT;
3179 }
3180
3181 offs+= plan[i].ddelta;
3182 int2store(write, nm);
3183 /* write rest of data at write + COLUMN_NUMBER_SIZE */
3184 if (type_and_offset_store_num(write, new_offset_size, tp, offs))
3185 {
3186 str->length= 0; // just something valid
3187 return ER_DYNCOL_FORMAT;
3188 }
3189 write+= new_entry_size;
3190 }
3191 }
3192
3193 /* new data adding */
3194 if (i < add_column_count)
3195 {
3196 if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
3197 {
3198 int2store(write, *((uint *)plan[i].key));
3199 if (type_and_offset_store_num(write, new_offset_size,
3200 plan[i].val[0].type,
3201 curr_offset))
3202 {
3203 str->length= 0; // just something valid
3204 return ER_DYNCOL_FORMAT;
3205 }
3206 write+= new_entry_size;
3207 curr_offset+= plan[i].length;
3208 }
3209 }
3210 }
3211
3212 /*
3213 Move headers.
3214 i= index in array of changes
3215 j= index in packed string header index
3216 */
3217 str->length= (FIXED_HEADER_SIZE + new_header_size);
3218 for (i= 0, j= 0;
3219 i < add_column_count || j < column_count;
3220 i++)
3221 {
3222 uint start= j, end;
3223
3224 /*
3225 Search in i and j for the next column to add from i and where to
3226 add.
3227 */
3228
3229 while (i < add_column_count && plan[i].act == PLAN_NOP)
3230 i++; /* skip NOP */
3231
3232 j= end= plan[i].mv_end;
3233 if (i != add_column_count &&
3234 (plan[i].act == PLAN_REPLACE || plan[i].act == PLAN_DELETE))
3235 j++;
3236
3237 /* copy first the data that was not replaced in original packed data */
3238 if (start < end && plan[i].mv_length)
3239 {
3240 memmove((header_base + new_header_size +
3241 plan[i].mv_offset + plan[i].ddelta),
3242 header_base + header_size + plan[i].mv_offset,
3243 plan[i].mv_length);
3244 }
3245 str->length+= plan[i].mv_length;
3246
3247 /* new data adding */
3248 if (i < add_column_count)
3249 {
3250 if( plan[i].act == PLAN_ADD || plan[i].act == PLAN_REPLACE)
3251 {
3252 data_store(str, plan[i].val, dyncol_fmt_num); /* Append new data */
3253 }
3254 }
3255 }
3256 return ER_DYNCOL_OK;
3257}
3258#endif
3259
3260/**
3261 Update the packed string with the given columns
3262
3263 @param str String where to write the data
3264 @param add_column_count Number of columns in the arrays
3265 @param column_numbers Array of columns numbers
3266 @param values Array of columns values
3267
3268 @return ER_DYNCOL_* return code
3269*/
3270/* plan allocated on the stack */
3271#define IN_PLACE_PLAN 4
3272
3273enum enum_dyncol_func_result
3274dynamic_column_update_many(DYNAMIC_COLUMN *str,
3275 uint add_column_count,
3276 uint *column_numbers,
3277 DYNAMIC_COLUMN_VALUE *values)
3278{
3279 return dynamic_column_update_many_fmt(str, add_column_count, column_numbers,
3280 values, FALSE);
3281}
3282
3283enum enum_dyncol_func_result
3284mariadb_dyncol_update_many_num(DYNAMIC_COLUMN *str,
3285 uint add_column_count,
3286 uint *column_numbers,
3287 DYNAMIC_COLUMN_VALUE *values)
3288{
3289 return dynamic_column_update_many_fmt(str, add_column_count, column_numbers,
3290 values, FALSE);
3291}
3292
3293enum enum_dyncol_func_result
3294mariadb_dyncol_update_many_named(DYNAMIC_COLUMN *str,
3295 uint add_column_count,
3296 LEX_STRING *column_names,
3297 DYNAMIC_COLUMN_VALUE *values)
3298{
3299 return dynamic_column_update_many_fmt(str, add_column_count, column_names,
3300 values, TRUE);
3301}
3302
3303static uint numlen(uint val)
3304{
3305 uint res;
3306 if (val == 0)
3307 return 1;
3308 res= 0;
3309 while(val)
3310 {
3311 res++;
3312 val/=10;
3313 }
3314 return res;
3315}
3316
3317static enum enum_dyncol_func_result
3318dynamic_column_update_many_fmt(DYNAMIC_COLUMN *str,
3319 uint add_column_count,
3320 void *column_keys,
3321 DYNAMIC_COLUMN_VALUE *values,
3322 my_bool string_keys)
3323{
3324 PLAN *plan, *alloc_plan= NULL, in_place_plan[IN_PLACE_PLAN];
3325 uchar *element;
3326 DYN_HEADER header, new_header;
3327 struct st_service_funcs *fmt, *new_fmt;
3328 long long data_delta= 0, name_delta= 0;
3329 uint i;
3330 uint not_null;
3331 long long header_delta= 0;
3332 long long header_delta_sign, data_delta_sign;
3333 int copy= FALSE;
3334 enum enum_dyncol_func_result rc;
3335 my_bool convert;
3336
3337 if (add_column_count == 0)
3338 return ER_DYNCOL_OK;
3339
3340 memset(&header, 0, sizeof(header));
3341 memset(&new_header, 0, sizeof(new_header));
3342 new_header.format= (string_keys ? dyncol_fmt_str : dyncol_fmt_num);
3343 new_fmt= fmt_data + new_header.format;
3344
3345 /*
3346 Get columns in column order. As the data in 'str' is already
3347 in column order this allows to replace all columns in one loop.
3348 */
3349 if (IN_PLACE_PLAN > add_column_count)
3350 plan= in_place_plan;
3351 else if (!(alloc_plan= plan=
3352 (PLAN *)malloc(sizeof(PLAN) * (add_column_count + 1))))
3353 return ER_DYNCOL_RESOURCE;
3354
3355 not_null= add_column_count;
3356 for (i= 0, element= (uchar *) column_keys;
3357 i < add_column_count;
3358 i++, element+= new_fmt->key_size_in_array)
3359 {
3360 if ((*new_fmt->check_limit)(&element))
3361 {
3362 rc= ER_DYNCOL_DATA;
3363 goto end;
3364 }
3365
3366 plan[i].val= values + i;
3367 plan[i].key= element;
3368 if (values[i].type == DYN_COL_NULL)
3369 not_null--;
3370
3371 }
3372
3373 if (str->length == 0)
3374 {
3375 /*
3376 Just add new columns. If there was no columns to add we return
3377 an empty string.
3378 */
3379 goto create_new_string;
3380 }
3381
3382 /* Check that header is ok */
3383 if ((rc= init_read_hdr(&header, str)) < 0)
3384 goto end;
3385 fmt= fmt_data + header.format;
3386 /* new format can't be numeric if the old one is names */
3387 DBUG_ASSERT(new_header.format == dyncol_fmt_str ||
3388 header.format == dyncol_fmt_num);
3389 if (header.column_count == 0)
3390 goto create_new_string;
3391
3392 qsort(plan, (size_t)add_column_count, sizeof(PLAN), new_fmt->plan_sort);
3393
3394 new_header.column_count= header.column_count;
3395 new_header.nmpool_size= header.nmpool_size;
3396 if ((convert= (new_header.format == dyncol_fmt_str &&
3397 header.format == dyncol_fmt_num)))
3398 {
3399 DBUG_ASSERT(new_header.nmpool_size == 0);
3400 for(i= 0, header.entry= header.header;
3401 i < header.column_count;
3402 i++, header.entry+= header.entry_size)
3403 {
3404 new_header.nmpool_size+= numlen(uint2korr(header.entry));
3405 }
3406 }
3407
3408 if (fmt->fixed_hdr + header.header_size + header.nmpool_size > str->length)
3409 {
3410 rc= ER_DYNCOL_FORMAT;
3411 goto end;
3412 }
3413
3414 /*
3415 Calculate how many columns and data is added/deleted and make a 'plan'
3416 for each of them.
3417 */
3418 for (i= 0; i < add_column_count; i++)
3419 {
3420 /*
3421 For now we don't allow creating two columns with the same number
3422 at the time of create. This can be fixed later to just use the later
3423 by comparing the pointers.
3424 */
3425 if (i < add_column_count - 1 &&
3426 new_fmt->column_sort(&plan[i].key, &plan[i + 1].key) == 0)
3427 {
3428 rc= ER_DYNCOL_DATA;
3429 goto end;
3430 }
3431
3432 /* Set common variables for all plans */
3433 plan[i].ddelta= data_delta;
3434 plan[i].ndelta= name_delta;
3435 /* get header delta in entries */
3436 plan[i].hdelta= header_delta;
3437 plan[i].length= 0; /* Length if NULL */
3438
3439 if (find_place(&header, plan[i].key, string_keys))
3440 {
3441 size_t entry_data_size, entry_name_size= 0;
3442
3443 /* Data existed; We have to replace or delete it */
3444
3445 entry_data_size= hdr_interval_length(&header, header.entry +
3446 header.entry_size);
3447 if (entry_data_size == DYNCOL_OFFSET_ERROR ||
3448 (long) entry_data_size < 0)
3449 {
3450 rc= ER_DYNCOL_FORMAT;
3451 goto end;
3452 }
3453
3454 if (new_header.format == dyncol_fmt_str)
3455 {
3456 if (header.format == dyncol_fmt_str)
3457 {
3458 LEX_STRING name;
3459 if (read_name(&header, header.entry, &name))
3460 {
3461 rc= ER_DYNCOL_FORMAT;
3462 goto end;
3463 }
3464 entry_name_size= name.length;
3465 }
3466 else
3467 entry_name_size= numlen(uint2korr(header.entry));
3468 }
3469
3470 if (plan[i].val->type == DYN_COL_NULL)
3471 {
3472 /* Inserting a NULL means delete the old data */
3473
3474 plan[i].act= PLAN_DELETE; /* Remove old value */
3475 header_delta--; /* One row less in header */
3476 data_delta-= entry_data_size; /* Less data to store */
3477 name_delta-= entry_name_size;
3478 }
3479 else
3480 {
3481 /* Replace the value */
3482
3483 plan[i].act= PLAN_REPLACE;
3484 /* get data delta in bytes */
3485 if ((plan[i].length= dynamic_column_value_len(plan[i].val,
3486 new_header.format)) ==
3487 (size_t) ~0)
3488 {
3489 rc= ER_DYNCOL_DATA;
3490 goto end;
3491 }
3492 data_delta+= plan[i].length - entry_data_size;
3493 if (new_header.format == dyncol_fmt_str)
3494 {
3495 name_delta+= ((LEX_STRING *)(plan[i].key))->length - entry_name_size;
3496 }
3497 }
3498 }
3499 else
3500 {
3501 /* Data did not exists. Add if it it's not NULL */
3502
3503 if (plan[i].val->type == DYN_COL_NULL)
3504 {
3505 plan[i].act= PLAN_NOP; /* Mark entry to be skipped */
3506 }
3507 else
3508 {
3509 /* Add new value */
3510
3511 plan[i].act= PLAN_ADD;
3512 header_delta++; /* One more row in header */
3513 /* get data delta in bytes */
3514 if ((plan[i].length= dynamic_column_value_len(plan[i].val,
3515 new_header.format)) ==
3516 (size_t) ~0)
3517 {
3518 rc= ER_DYNCOL_DATA;
3519 goto end;
3520 }
3521 data_delta+= plan[i].length;
3522 if (new_header.format == dyncol_fmt_str)
3523 name_delta+= ((LEX_STRING *)plan[i].key)->length;
3524 }
3525 }
3526 plan[i].place= header.entry;
3527 }
3528 plan[add_column_count].hdelta= header_delta;
3529 plan[add_column_count].ddelta= data_delta;
3530 plan[add_column_count].act= PLAN_NOP;
3531 plan[add_column_count].place= header.dtpool;
3532
3533 new_header.column_count= (uint)(header.column_count + header_delta);
3534
3535 /*
3536 Check if it is only "increasing" or only "decreasing" plan for (header
3537 and data separately).
3538 */
3539 new_header.data_size= header.data_size + (size_t)data_delta;
3540 new_header.nmpool_size= new_header.nmpool_size + (size_t)name_delta;
3541 DBUG_ASSERT(new_header.format != dyncol_fmt_num ||
3542 new_header.nmpool_size == 0);
3543 if ((new_header.offset_size=
3544 new_fmt->dynamic_column_offset_bytes(new_header.data_size)) >=
3545 new_fmt->max_offset_size)
3546 {
3547 rc= ER_DYNCOL_LIMIT;
3548 goto end;
3549 }
3550
3551 copy= ((header.format != new_header.format) ||
3552 (new_header.format == dyncol_fmt_str));
3553 /* if (new_header.offset_size!=offset_size) then we have to rewrite header */
3554 header_delta_sign=
3555 ((int)new_header.offset_size + new_fmt->fixed_hdr_entry) -
3556 ((int)header.offset_size + fmt->fixed_hdr_entry);
3557 data_delta_sign= 0;
3558 // plan[add_column_count] contains last deltas.
3559 for (i= 0; i <= add_column_count && !copy; i++)
3560 {
3561 /* This is the check for increasing/decreasing */
3562 DELTA_CHECK(header_delta_sign, plan[i].hdelta, copy);
3563 DELTA_CHECK(data_delta_sign, plan[i].ddelta, copy);
3564 }
3565 calc_param(&new_header.entry_size, &new_header.header_size,
3566 new_fmt->fixed_hdr_entry,
3567 new_header.offset_size, new_header.column_count);
3568
3569 /*
3570 Need copy because:
3571 1, Header/data parts moved in different directions.
3572 2. There is no enough allocated space in the string.
3573 3. Header and data moved in different directions.
3574 */
3575 if (copy || /*1.*/
3576 str->max_length < str->length + header_delta + data_delta || /*2.*/
3577 ((header_delta_sign < 0 && data_delta_sign > 0) ||
3578 (header_delta_sign > 0 && data_delta_sign < 0))) /*3.*/
3579 rc= dynamic_column_update_copy(str, plan, add_column_count,
3580 &header, &new_header,
3581 convert);
3582 else
3583 if (header_delta_sign < 0)
3584 rc= dynamic_column_update_move_left(str, plan, header.offset_size,
3585 header.entry_size,
3586 header.header_size,
3587 new_header.offset_size,
3588 new_header.entry_size,
3589 new_header.header_size,
3590 header.column_count,
3591 new_header.column_count,
3592 add_column_count, header.dtpool,
3593 header.data_size);
3594 else
3595 /*
3596 rc= dynamic_column_update_move_right(str, plan, offset_size,
3597 entry_size, header_size,
3598 new_header.offset_size,
3599 new_header.entry_size,
3600 new_heder.header_size, column_count,
3601 new_header.column_count,
3602 add_column_count, header_end,
3603 header.data_size);
3604 */
3605 rc= dynamic_column_update_copy(str, plan, add_column_count,
3606 &header, &new_header,
3607 convert);
3608end:
3609 free(alloc_plan);
3610 return rc;
3611
3612create_new_string:
3613 /* There is no columns from before, so let's just add the new ones */
3614 rc= ER_DYNCOL_OK;
3615 free(alloc_plan);
3616 if (not_null != 0)
3617 rc= dynamic_column_create_many_internal_fmt(str, add_column_count,
3618 (uint*)column_keys, values,
3619 str->str == NULL,
3620 string_keys);
3621 goto end;
3622}
3623
3624
3625/**
3626 Update the packed string with the given column
3627
3628 @param str String where to write the data
3629 @param column_number Array of columns number
3630 @param values Array of columns values
3631
3632 @return ER_DYNCOL_* return code
3633*/
3634
3635
3636int dynamic_column_update(DYNAMIC_COLUMN *str, uint column_nr,
3637 DYNAMIC_COLUMN_VALUE *value)
3638{
3639 return dynamic_column_update_many(str, 1, &column_nr, value);
3640}
3641
3642
3643enum enum_dyncol_func_result
3644mariadb_dyncol_check(DYNAMIC_COLUMN *str)
3645{
3646 struct st_service_funcs *fmt;
3647 enum enum_dyncol_func_result rc= ER_DYNCOL_FORMAT;
3648 DYN_HEADER header;
3649 uint i;
3650 size_t data_offset= 0, name_offset= 0;
3651 size_t prev_data_offset= 0, prev_name_offset= 0;
3652 LEX_STRING name= {0,0}, prev_name= {0,0};
3653 uint num= 0, prev_num= 0;
3654 void *key, *prev_key;
3655 enum enum_dynamic_column_type type= DYN_COL_NULL, prev_type= DYN_COL_NULL;
3656
3657 if (str->length == 0)
3658 {
3659 return(ER_DYNCOL_OK);
3660 }
3661
3662 memset(&header, 0, sizeof(header));
3663
3664 /* Check that header is OK */
3665 if (read_fixed_header(&header, str))
3666 {
3667 goto end;
3668 }
3669 fmt= fmt_data + header.format;
3670 calc_param(&header.entry_size, &header.header_size,
3671 fmt->fixed_hdr_entry, header.offset_size,
3672 header.column_count);
3673 /* headers are out of string length (no space for data and part of headers) */
3674 if (fmt->fixed_hdr + header.header_size + header.nmpool_size > str->length)
3675 {
3676 goto end;
3677 }
3678 header.header= (uchar*)str->str + fmt->fixed_hdr;
3679 header.nmpool= header.header + header.header_size;
3680 header.dtpool= header.nmpool + header.nmpool_size;
3681 header.data_size= str->length - fmt->fixed_hdr -
3682 header.header_size - header.nmpool_size;
3683
3684 /* read and check headers */
3685 if (header.format == dyncol_fmt_num)
3686 {
3687 key= &num;
3688 prev_key= &prev_num;
3689 }
3690 else
3691 {
3692 key= &name;
3693 prev_key= &prev_name;
3694 }
3695 for (i= 0, header.entry= header.header;
3696 i < header.column_count;
3697 i++, header.entry+= header.entry_size)
3698 {
3699
3700 if (header.format == dyncol_fmt_num)
3701 {
3702 num= uint2korr(header.entry);
3703 }
3704 else
3705 {
3706 DBUG_ASSERT(header.format == dyncol_fmt_str);
3707 if (read_name(&header, header.entry, &name))
3708 {
3709 goto end;
3710 }
3711 name_offset= name.str - (char *)header.nmpool;
3712 }
3713 if ((*fmt->type_and_offset_read)(&type, &data_offset,
3714 header.entry + fmt->fixed_hdr_entry,
3715 header.offset_size))
3716 goto end;
3717
3718 DBUG_ASSERT(type != DYN_COL_NULL);
3719 if (data_offset > header.data_size)
3720 {
3721 goto end;
3722 }
3723 if (prev_type != DYN_COL_NULL)
3724 {
3725 /* It is not first entry */
3726 if (prev_data_offset >= data_offset)
3727 {
3728 goto end;
3729 }
3730 if (prev_name_offset > name_offset)
3731 {
3732 goto end;
3733 }
3734 if ((*fmt->column_sort)(&prev_key, &key) >= 0)
3735 {
3736 goto end;
3737 }
3738 }
3739 prev_num= num;
3740 prev_name= name;
3741 prev_data_offset= data_offset;
3742 prev_name_offset= name_offset;
3743 prev_type= type;
3744 }
3745
3746 /* check data, which we can */
3747 for (i= 0, header.entry= header.header;
3748 i < header.column_count;
3749 i++, header.entry+= header.entry_size)
3750 {
3751 DYNAMIC_COLUMN_VALUE store;
3752 // already checked by previouse pass
3753 (*fmt->type_and_offset_read)(&header.type, &header.offset,
3754 header.entry + fmt->fixed_hdr_entry,
3755 header.offset_size);
3756 header.length=
3757 hdr_interval_length(&header, header.entry + header.entry_size);
3758 header.data= header.dtpool + header.offset;
3759 switch ((header.type)) {
3760 case DYN_COL_INT:
3761 rc= dynamic_column_sint_read(&store, header.data, header.length);
3762 break;
3763 case DYN_COL_UINT:
3764 rc= dynamic_column_uint_read(&store, header.data, header.length);
3765 break;
3766 case DYN_COL_DOUBLE:
3767 rc= dynamic_column_double_read(&store, header.data, header.length);
3768 break;
3769 case DYN_COL_STRING:
3770 rc= dynamic_column_string_read(&store, header.data, header.length);
3771 break;
3772#ifndef LIBMARIADB
3773 case DYN_COL_DECIMAL:
3774 rc= dynamic_column_decimal_read(&store, header.data, header.length);
3775 break;
3776#endif
3777 case DYN_COL_DATETIME:
3778 rc= dynamic_column_date_time_read(&store, header.data,
3779 header.length);
3780 break;
3781 case DYN_COL_DATE:
3782 rc= dynamic_column_date_read(&store, header.data, header.length);
3783 break;
3784 case DYN_COL_TIME:
3785 rc= dynamic_column_time_read(&store, header.data, header.length);
3786 break;
3787 case DYN_COL_DYNCOL:
3788 rc= dynamic_column_dyncol_read(&store, header.data, header.length);
3789 break;
3790 case DYN_COL_NULL:
3791 default:
3792 rc= ER_DYNCOL_FORMAT;
3793 goto end;
3794 }
3795 if (rc != ER_DYNCOL_OK)
3796 {
3797 DBUG_ASSERT(rc < 0);
3798 goto end;
3799 }
3800 }
3801
3802 rc= ER_DYNCOL_OK;
3803end:
3804 return(rc);
3805}
3806
3807enum enum_dyncol_func_result
3808mariadb_dyncol_val_str(DYNAMIC_STRING *str, DYNAMIC_COLUMN_VALUE *val,
3809 MARIADB_CHARSET_INFO *cs, char quote)
3810{
3811 char buff[40];
3812 size_t len;
3813 switch (val->type) {
3814 case DYN_COL_INT:
3815 len= snprintf(buff, sizeof(buff), "%lld", val->x.long_value);
3816 if (ma_dynstr_append_mem(str, buff, len))
3817 return ER_DYNCOL_RESOURCE;
3818 break;
3819 case DYN_COL_UINT:
3820 len= snprintf(buff, sizeof(buff), "%llu", val->x.ulong_value);
3821 if (ma_dynstr_append_mem(str, buff, len))
3822 return ER_DYNCOL_RESOURCE;
3823 break;
3824 case DYN_COL_DOUBLE:
3825 len= snprintf(buff, sizeof(buff), "%g", val->x.double_value);
3826 if (ma_dynstr_realloc(str, len + (quote ? 2 : 0)))
3827 return ER_DYNCOL_RESOURCE;
3828 if (quote)
3829 str->str[str->length++]= quote;
3830 ma_dynstr_append_mem(str, buff, len);
3831 if (quote)
3832 str->str[str->length++]= quote;
3833 break;
3834 case DYN_COL_DYNCOL:
3835 case DYN_COL_STRING:
3836 {
3837 char *alloc= NULL;
3838 char *from= val->x.string.value.str;
3839 ulong bufflen;
3840 my_bool conv= ((val->x.string.charset == cs) ||
3841 !strcmp(val->x.string.charset->name, cs->name));
3842 my_bool rc;
3843 len= val->x.string.value.length;
3844 bufflen= (ulong)(len * (conv ? cs->char_maxlen : 1));
3845 if (ma_dynstr_realloc(str, bufflen))
3846 return ER_DYNCOL_RESOURCE;
3847
3848 // guaranty UTF-8 string for value
3849 if (!conv)
3850 {
3851#ifndef LIBMARIADB
3852 uint dumma_errors;
3853#else
3854 int dumma_errors;
3855#endif
3856 if (!quote)
3857 {
3858 /* convert to the destination */
3859 str->length+=
3860#ifndef LIBMARIADB
3861 copy_and_convert_extended(str->str, bufflen,
3862 cs,
3863 from, (uint32)len,
3864 val->x.string.charset,
3865 &dumma_errors);
3866#else
3867 mariadb_convert_string(from, &len, val->x.string.charset,
3868 str->str, (size_t *)&bufflen, cs, &dumma_errors);
3869#endif
3870 return ER_DYNCOL_OK;
3871 }
3872 if ((alloc= (char *)malloc(bufflen)))
3873 {
3874 len=
3875#ifndef LIBMARIADB
3876 copy_and_convert_extended(alloc, bufflen, cs,
3877 from, (uint32)len,
3878 val->x.string.charset,
3879 &dumma_errors);
3880#else
3881 mariadb_convert_string(from, &len, val->x.string.charset,
3882 alloc, (size_t *)&bufflen, cs, &dumma_errors);
3883#endif
3884 from= alloc;
3885 }
3886 else
3887 return ER_DYNCOL_RESOURCE;
3888 }
3889 if (quote)
3890 rc= ma_dynstr_append_mem(str, &quote, 1);
3891 rc= ma_dynstr_append_mem(str, from, len);
3892 if (quote)
3893 rc= ma_dynstr_append_mem(str, &quote, 1);
3894 if (alloc)
3895 free(alloc);
3896 if (rc)
3897 return ER_DYNCOL_RESOURCE;
3898 break;
3899 }
3900#ifndef LIBMARIADB
3901 case DYN_COL_DECIMAL:
3902 {
3903 int len= sizeof(buff);
3904 decimal2string(&val->x.decimal.value, buff, &len,
3905 0, val->x.decimal.value.frac,
3906 '0');
3907 if (ma_dynstr_append_mem(str, buff, len))
3908 return ER_DYNCOL_RESOURCE;
3909 break;
3910 }
3911#endif
3912 case DYN_COL_DATETIME:
3913 case DYN_COL_DATE:
3914 case DYN_COL_TIME:
3915#ifndef LIBMARIADB
3916 len= my_TIME_to_str(&val->x.time_value, buff, AUTO_SEC_PART_DIGITS);
3917#else
3918 len= mariadb_time_to_string(&val->x.time_value, buff, 39, AUTO_SEC_PART_DIGITS);
3919#endif
3920 if (ma_dynstr_realloc(str, len + (quote ? 2 : 0)))
3921 return ER_DYNCOL_RESOURCE;
3922 if (quote)
3923 str->str[str->length++]= '"';
3924 ma_dynstr_append_mem(str, buff, len);
3925 if (quote)
3926 str->str[str->length++]= '"';
3927 break;
3928 case DYN_COL_NULL:
3929 if (ma_dynstr_append_mem(str, "null", 4))
3930 return ER_DYNCOL_RESOURCE;
3931 break;
3932 default:
3933 return(ER_DYNCOL_FORMAT);
3934 }
3935 return(ER_DYNCOL_OK);
3936}
3937
3938enum enum_dyncol_func_result
3939mariadb_dyncol_val_long(longlong *ll, DYNAMIC_COLUMN_VALUE *val)
3940{
3941 enum enum_dyncol_func_result rc= ER_DYNCOL_OK;
3942 *ll= 0;
3943 switch (val->type) {
3944 case DYN_COL_INT:
3945 *ll= val->x.long_value;
3946 break;
3947 case DYN_COL_UINT:
3948 *ll= (longlong)val->x.ulong_value;
3949 if (val->x.ulong_value > ULONGLONG_MAX)
3950 rc= ER_DYNCOL_TRUNCATED;
3951 break;
3952 case DYN_COL_DOUBLE:
3953 *ll= (longlong)val->x.double_value;
3954 if (((double) *ll) != val->x.double_value)
3955 rc= ER_DYNCOL_TRUNCATED;
3956 break;
3957 case DYN_COL_STRING:
3958 {
3959 char *src= val->x.string.value.str;
3960 size_t len= val->x.string.value.length;
3961 longlong i= 0, sign= 1;
3962
3963 while (len && isspace(*src)) src++,len--;
3964
3965 if (len)
3966 {
3967 if (*src == '-')
3968 {
3969 sign= -1;
3970 src++;
3971 }
3972 while(len && isdigit(*src))
3973 {
3974 i= i * 10 + (*src - '0');
3975 src++;
3976 }
3977 }
3978 else
3979 rc= ER_DYNCOL_TRUNCATED;
3980 if (len)
3981 rc= ER_DYNCOL_TRUNCATED;
3982 *ll= i * sign;
3983 break;
3984 }
3985#ifndef LIBMARIADB
3986 case DYN_COL_DECIMAL:
3987 if (decimal2longlong(&val->x.decimal.value, ll) != E_DEC_OK)
3988 rc= ER_DYNCOL_TRUNCATED;
3989 break;
3990#endif
3991 case DYN_COL_DATETIME:
3992 *ll= (val->x.time_value.year * 10000000000ull +
3993 val->x.time_value.month * 100000000L +
3994 val->x.time_value.day * 1000000 +
3995 val->x.time_value.hour * 10000 +
3996 val->x.time_value.minute * 100 +
3997 val->x.time_value.second) *
3998 (val->x.time_value.neg ? -1 : 1);
3999 break;
4000 case DYN_COL_DATE:
4001 *ll= (val->x.time_value.year * 10000 +
4002 val->x.time_value.month * 100 +
4003 val->x.time_value.day) *
4004 (val->x.time_value.neg ? -1 : 1);
4005 break;
4006 case DYN_COL_TIME:
4007 *ll= (val->x.time_value.hour * 10000 +
4008 val->x.time_value.minute * 100 +
4009 val->x.time_value.second) *
4010 (val->x.time_value.neg ? -1 : 1);
4011 break;
4012 case DYN_COL_DYNCOL:
4013 case DYN_COL_NULL:
4014 rc= ER_DYNCOL_TRUNCATED;
4015 break;
4016 default:
4017 return(ER_DYNCOL_FORMAT);
4018 }
4019 return(rc);
4020}
4021
4022
4023enum enum_dyncol_func_result
4024mariadb_dyncol_val_double(double *dbl, DYNAMIC_COLUMN_VALUE *val)
4025{
4026 enum enum_dyncol_func_result rc= ER_DYNCOL_OK;
4027 *dbl= 0;
4028 switch (val->type) {
4029 case DYN_COL_INT:
4030 *dbl= (double)val->x.long_value;
4031 if (((longlong) *dbl) != val->x.long_value)
4032 rc= ER_DYNCOL_TRUNCATED;
4033 break;
4034 case DYN_COL_UINT:
4035 *dbl= (double)val->x.ulong_value;
4036 if (((ulonglong) *dbl) != val->x.ulong_value)
4037 rc= ER_DYNCOL_TRUNCATED;
4038 break;
4039 case DYN_COL_DOUBLE:
4040 *dbl= val->x.double_value;
4041 break;
4042 case DYN_COL_STRING:
4043 {
4044 char *str, *end;
4045 if (!(str= malloc(val->x.string.value.length + 1)))
4046 return ER_DYNCOL_RESOURCE;
4047 memcpy(str, val->x.string.value.str, val->x.string.value.length);
4048 str[val->x.string.value.length]= '\0';
4049 *dbl= strtod(str, &end);
4050 if (*end != '\0')
4051 rc= ER_DYNCOL_TRUNCATED;
4052 free(str);
4053 break;
4054 }
4055#ifndef LIBMARIADB
4056 case DYN_COL_DECIMAL:
4057 if (decimal2double(&val->x.decimal.value, dbl) != E_DEC_OK)
4058 rc= ER_DYNCOL_TRUNCATED;
4059 break;
4060#endif
4061 case DYN_COL_DATETIME:
4062 *dbl= (double)(val->x.time_value.year * 10000000000ull +
4063 val->x.time_value.month * 100000000L +
4064 val->x.time_value.day * 1000000 +
4065 val->x.time_value.hour * 10000 +
4066 val->x.time_value.minute * 100 +
4067 val->x.time_value.second) *
4068 (val->x.time_value.neg ? -1 : 1);
4069 break;
4070 case DYN_COL_DATE:
4071 *dbl= (double)(val->x.time_value.year * 10000 +
4072 val->x.time_value.month * 100 +
4073 val->x.time_value.day) *
4074 (val->x.time_value.neg ? -1 : 1);
4075 break;
4076 case DYN_COL_TIME:
4077 *dbl= (double)(val->x.time_value.hour * 10000 +
4078 val->x.time_value.minute * 100 +
4079 val->x.time_value.second) *
4080 (val->x.time_value.neg ? -1 : 1);
4081 break;
4082 case DYN_COL_DYNCOL:
4083 case DYN_COL_NULL:
4084 rc= ER_DYNCOL_TRUNCATED;
4085 break;
4086 default:
4087 return(ER_DYNCOL_FORMAT);
4088 }
4089 return(rc);
4090}
4091
4092
4093/**
4094 Convert to JSON
4095
4096 @param str The packed string
4097 @param json Where to put json result
4098
4099 @return ER_DYNCOL_* return code
4100*/
4101
4102#define JSON_STACK_PROTECTION 10
4103
4104static enum enum_dyncol_func_result
4105mariadb_dyncol_json_internal(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json,
4106 uint lvl)
4107{
4108 DYN_HEADER header;
4109 uint i;
4110 enum enum_dyncol_func_result rc;
4111
4112 if (lvl >= JSON_STACK_PROTECTION)
4113 {
4114 rc= ER_DYNCOL_RESOURCE;
4115 goto err;
4116 }
4117
4118
4119 if (str->length == 0)
4120 return ER_DYNCOL_OK; /* no columns */
4121
4122 if ((rc= init_read_hdr(&header, str)) < 0)
4123 goto err;
4124
4125 if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
4126 str->length)
4127 {
4128 rc= ER_DYNCOL_FORMAT;
4129 goto err;
4130 }
4131
4132 rc= ER_DYNCOL_RESOURCE;
4133
4134 if (ma_dynstr_append_mem(json, "{", 1))
4135 goto err;
4136 for (i= 0, header.entry= header.header;
4137 i < header.column_count;
4138 i++, header.entry+= header.entry_size)
4139 {
4140 DYNAMIC_COLUMN_VALUE val;
4141 if (i != 0 && ma_dynstr_append_mem(json, ",", 1))
4142 goto err;
4143 header.length=
4144 hdr_interval_length(&header, header.entry + header.entry_size);
4145 header.data= header.dtpool + header.offset;
4146 /*
4147 Check that the found data is within the ranges. This can happen if
4148 we get data with wrong offsets.
4149 */
4150 if (header.length == DYNCOL_OFFSET_ERROR ||
4151 header.length > INT_MAX || header.offset > header.data_size)
4152 {
4153 rc= ER_DYNCOL_FORMAT;
4154 goto err;
4155 }
4156 if ((rc= dynamic_column_get_value(&header, &val)) < 0)
4157 goto err;
4158 if (header.format == dyncol_fmt_num)
4159 {
4160 uint nm= uint2korr(header.entry);
4161 if (ma_dynstr_realloc(json, DYNCOL_NUM_CHAR + 3))
4162 goto err;
4163 json->str[json->length++]= '"';
4164 json->length+= snprintf(json->str + json->length,
4165 DYNCOL_NUM_CHAR, "%u", nm);
4166 }
4167 else
4168 {
4169 LEX_STRING name;
4170 if (read_name(&header, header.entry, &name))
4171 {
4172 rc= ER_DYNCOL_FORMAT;
4173 goto err;
4174 }
4175 if (ma_dynstr_realloc(json, name.length + 3))
4176 goto err;
4177 json->str[json->length++]= '"';
4178 memcpy(json->str + json->length, name.str, name.length);
4179 json->length+= name.length;
4180 }
4181 json->str[json->length++]= '"';
4182 json->str[json->length++]= ':';
4183 if (val.type == DYN_COL_DYNCOL)
4184 {
4185 /* here we use it only for read so can cheat a bit */
4186 DYNAMIC_COLUMN dc;
4187 memset(&dc, 0, sizeof(dc));
4188 dc.str= val.x.string.value.str;
4189 dc.length= val.x.string.value.length;
4190 if (mariadb_dyncol_json_internal(&dc, json, lvl + 1) < 0)
4191 {
4192 dc.str= NULL; dc.length= 0;
4193 goto err;
4194 }
4195 dc.str= NULL; dc.length= 0;
4196 }
4197 else
4198 {
4199 if ((rc= mariadb_dyncol_val_str(json, &val,
4200 ma_charset_utf8_general_ci, '"')) < 0)
4201 goto err;
4202 }
4203 }
4204 if (ma_dynstr_append_mem(json, "}", 1))
4205 {
4206 rc= ER_DYNCOL_RESOURCE;
4207 goto err;
4208 }
4209 return ER_DYNCOL_OK;
4210
4211err:
4212 json->length= 0;
4213 return rc;
4214}
4215
4216enum enum_dyncol_func_result
4217mariadb_dyncol_json(DYNAMIC_COLUMN *str, DYNAMIC_STRING *json)
4218{
4219
4220 if (ma_init_dynamic_string(json, NULL, str->length * 2, 100))
4221 return ER_DYNCOL_RESOURCE;
4222
4223 return mariadb_dyncol_json_internal(str, json, 1);
4224}
4225
4226/**
4227 Convert to DYNAMIC_COLUMN_VALUE values and names (LEX_STING) dynamic array
4228
4229 @param str The packed string
4230 @param count number of elements in the arrays
4231 @param names Where to put names (should be free by user)
4232 @param vals Where to put values (should be free by user)
4233
4234 @return ER_DYNCOL_* return code
4235*/
4236
4237enum enum_dyncol_func_result
4238mariadb_dyncol_unpack(DYNAMIC_COLUMN *str,
4239 uint *count,
4240 LEX_STRING **names, DYNAMIC_COLUMN_VALUE **vals)
4241{
4242 DYN_HEADER header;
4243 char *nm;
4244 uint i;
4245 enum enum_dyncol_func_result rc;
4246
4247 *count= 0; *names= 0; *vals= 0;
4248
4249 if (str->length == 0)
4250 return ER_DYNCOL_OK; /* no columns */
4251
4252 if ((rc= init_read_hdr(&header, str)) < 0)
4253 return rc;
4254
4255
4256 if (header.entry_size * header.column_count + FIXED_HEADER_SIZE >
4257 str->length)
4258 return ER_DYNCOL_FORMAT;
4259
4260 *vals= (DYNAMIC_COLUMN_VALUE *)malloc(sizeof(DYNAMIC_COLUMN_VALUE)* header.column_count);
4261 if (header.format == dyncol_fmt_num)
4262 {
4263 *names= (LEX_STRING *)malloc(sizeof(LEX_STRING) * header.column_count +
4264 DYNCOL_NUM_CHAR * header.column_count);
4265 nm= (char *)((*names) + header.column_count);
4266 }
4267 else
4268 {
4269 *names= (LEX_STRING *)malloc(sizeof(LEX_STRING) * header.column_count);
4270 nm= 0;
4271 }
4272 if (!(*vals) || !(*names))
4273 {
4274 rc= ER_DYNCOL_RESOURCE;
4275 goto err;
4276 }
4277
4278 for (i= 0, header.entry= header.header;
4279 i < header.column_count;
4280 i++, header.entry+= header.entry_size)
4281 {
4282 header.length=
4283 hdr_interval_length(&header, header.entry + header.entry_size);
4284 header.data= header.dtpool + header.offset;
4285 /*
4286 Check that the found data is within the ranges. This can happen if
4287 we get data with wrong offsets.
4288 */
4289 if (header.length == DYNCOL_OFFSET_ERROR ||
4290 header.length > INT_MAX || header.offset > header.data_size)
4291 {
4292 rc= ER_DYNCOL_FORMAT;
4293 goto err;
4294 }
4295 if ((rc= dynamic_column_get_value(&header, (*vals) + i)) < 0)
4296 goto err;
4297
4298 if (header.format == dyncol_fmt_num)
4299 {
4300 uint num= uint2korr(header.entry);
4301 (*names)[i].str= nm;
4302 (*names)[i].length= snprintf(nm, DYNCOL_NUM_CHAR, "%u", num);
4303 nm+= (*names)[i].length + 1;
4304 }
4305 else
4306 {
4307 if (read_name(&header, header.entry, (*names) + i))
4308 {
4309 rc= ER_DYNCOL_FORMAT;
4310 goto err;
4311 }
4312 }
4313 }
4314
4315 *count= header.column_count;
4316 return ER_DYNCOL_OK;
4317
4318err:
4319 if (*vals)
4320 {
4321 free(*vals);
4322 *vals= 0;
4323 }
4324 if (*names)
4325 {
4326 free(*names);
4327 *names= 0;
4328 }
4329 return rc;
4330}
4331
4332
4333/**
4334 Get not NULL column count
4335
4336 @param str The packed string
4337 @param column_count Where to put column count
4338
4339 @return ER_DYNCOL_* return code
4340*/
4341
4342enum enum_dyncol_func_result
4343mariadb_dyncol_column_count(DYNAMIC_COLUMN *str, uint *column_count)
4344{
4345 DYN_HEADER header;
4346 enum enum_dyncol_func_result rc;
4347
4348 (*column_count)= 0;
4349 if (str->length == 0)
4350 return ER_DYNCOL_OK;
4351
4352 if ((rc= init_read_hdr(&header, str)) < 0)
4353 return rc;
4354 *column_count= header.column_count;
4355 return rc;
4356}
4357
4358/**
4359 Release dynamic column memory
4360
4361 @param str dynamic column
4362 @return void
4363*/
4364void mariadb_dyncol_free(DYNAMIC_COLUMN *str)
4365{
4366 ma_dynstr_free(str);
4367}
4368