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