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