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