1 /*
2 Copyright (c) 2000, 2021, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
23
24
25 /* Analyse database */
26
27 /* TODO: - Check if any character fields can be of any date type
28 ** (date, datetime, year, time, timestamp, newdate)
29 ** - Check if any number field should be a timestamp
30 ** - type set is out of optimization yet
31 */
32
33 #include "sql_analyse.h"
34
35 #include "procedure.h" // Item_proc
36 #include "sql_yacc.h" // DECIMAL_NUM
37
38 #include <algorithm>
39 using std::min;
40 using std::max;
41
sortcmp2(void * cmp_arg MY_ATTRIBUTE ((unused)),const String * a,const String * b)42 int sortcmp2(void* cmp_arg MY_ATTRIBUTE((unused)),
43 const String *a,const String *b)
44 {
45 return sortcmp(a,b,a->charset());
46 }
47
compare_double2(void * cmp_arg MY_ATTRIBUTE ((unused)),const double * s,const double * t)48 int compare_double2(void* cmp_arg MY_ATTRIBUTE((unused)),
49 const double *s, const double *t)
50 {
51 return compare_double(s,t);
52 }
53
compare_longlong2(void * cmp_arg MY_ATTRIBUTE ((unused)),const longlong * s,const longlong * t)54 int compare_longlong2(void* cmp_arg MY_ATTRIBUTE((unused)),
55 const longlong *s, const longlong *t)
56 {
57 return compare_longlong(s,t);
58 }
59
compare_ulonglong2(void * cmp_arg MY_ATTRIBUTE ((unused)),const ulonglong * s,const ulonglong * t)60 int compare_ulonglong2(void* cmp_arg MY_ATTRIBUTE((unused)),
61 const ulonglong *s, const ulonglong *t)
62 {
63 return compare_ulonglong(s,t);
64 }
65
compare_decimal2(int * len,const char * s,const char * t)66 int compare_decimal2(int* len, const char *s, const char *t)
67 {
68 return memcmp(s, t, *len);
69 }
70
71 /**
72 Create column data accumulator structures
73
74 @param field_list Output columns of the original SELECT
75
76 @retval false Success
77 @retval true Failure (OOM)
78 */
79 bool
init(List<Item> & field_list)80 Query_result_analyse::init(List<Item> &field_list)
81 {
82 DBUG_ENTER("proc_analyse_init");
83
84 assert(thd->lex->sql_command == SQLCOM_SELECT);
85
86 if (!(f_info=
87 (field_info**)sql_alloc(sizeof(field_info*)*field_list.elements)))
88 DBUG_RETURN(true);
89
90 f_end= f_info + field_list.elements;
91
92 {
93 List_iterator_fast<Item> it(field_list);
94 field_info **info= f_info;
95 Item *item;
96 while ((item = it++))
97 {
98 field_info *new_field;
99 switch (item->result_type()) {
100 case INT_RESULT:
101 // Check if fieldtype is ulonglong
102 if (item->type() == Item::FIELD_ITEM &&
103 ((Item_field*) item)->field->type() == MYSQL_TYPE_LONGLONG &&
104 ((Field_longlong*) ((Item_field*) item)->field)->unsigned_flag)
105 new_field= new field_ulonglong(item, this);
106 else
107 new_field= new field_longlong(item, this);
108 break;
109 case REAL_RESULT:
110 new_field= new field_real(item, this);
111 break;
112 case DECIMAL_RESULT:
113 new_field= new field_decimal(item, this);
114 break;
115 case STRING_RESULT:
116 new_field= new field_str(item, this);
117 break;
118 default:
119 DBUG_RETURN(true);
120 }
121 if (new_field == NULL)
122 DBUG_RETURN(true);
123 *info++= new_field;
124 }
125 }
126 DBUG_RETURN(false);
127 }
128
129
130 /*
131 Return 1 if number, else return 0
132 store info about found number in info
133 NOTE:It is expected, that elements of 'info' are all zero!
134 */
135
test_if_number(NUM_INFO * info,const char * str,uint str_len)136 bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
137 {
138 const char *begin, *end= str + str_len;
139 DBUG_ENTER("test_if_number");
140
141 /*
142 MySQL removes any endspaces of a string, so we must take care only of
143 spaces in front of a string
144 */
145 for (; str != end && my_isspace(system_charset_info, *str); str++) ;
146 if (str == end)
147 DBUG_RETURN(0);
148
149 if (*str == '-')
150 {
151 info->negative = 1;
152 if (++str == end || *str == '0') // converting -0 to a number
153 DBUG_RETURN(0); // might lose information
154 }
155 else
156 info->negative = 0;
157 begin = str;
158 for (; str != end && my_isdigit(system_charset_info,*str); str++)
159 {
160 if (!info->integers && *str == '0' && (str + 1) != end &&
161 my_isdigit(system_charset_info,*(str + 1)))
162 info->zerofill = 1; // could be a postnumber for example
163 info->integers++;
164 }
165 if (str == end && info->integers)
166 {
167 char *endpos= (char*) end;
168 int error;
169 info->ullval= (ulonglong) my_strtoll10(begin, &endpos, &error);
170 if (info->integers == 1)
171 DBUG_RETURN(0); // single number can't be zerofill
172 info->maybe_zerofill = 1;
173 DBUG_RETURN(1); // a zerofill number, or an integer
174 }
175 if (*str == '.' || *str == 'e' || *str == 'E')
176 {
177 if (info->zerofill) // can't be zerofill anymore
178 DBUG_RETURN(0);
179 if ((str + 1) == end) // number was something like '123[.eE]'
180 {
181 char *endpos= (char*) str;
182 int error;
183 info->ullval= (ulonglong) my_strtoll10(begin, &endpos, &error);
184 DBUG_RETURN(1);
185 }
186 if (*str == 'e' || *str == 'E') // number may be something like '1e+50'
187 {
188 str++;
189 if (*str != '-' && *str != '+')
190 DBUG_RETURN(0);
191 for (str++; str != end && my_isdigit(system_charset_info,*str); str++) ;
192 if (str == end)
193 {
194 info->is_float = 1; // we can't use variable decimals here
195 DBUG_RETURN(1);
196 }
197 DBUG_RETURN(0);
198 }
199 for (str++; *(end - 1) == '0'; end--) ; // jump over zeros at the end
200 if (str == end) // number was something like '123.000'
201 {
202 char *endpos= (char*) str;
203 int error;
204 info->ullval= (ulonglong) my_strtoll10(begin, &endpos, &error);
205 DBUG_RETURN(1);
206 }
207 for (; str != end && my_isdigit(system_charset_info,*str); str++)
208 info->decimals++;
209 if (str == end)
210 {
211 info->dval = my_atof(begin);
212 DBUG_RETURN(1);
213 }
214 }
215 DBUG_RETURN(0);
216 }
217
218
219 /*
220 Stores the biggest and the smallest value from current 'info'
221 to ev_num_info
222 If info contains an ulonglong number, which is bigger than
223 biggest positive number able to be stored in a longlong variable
224 and is marked as negative, function will return 0, else 1.
225 */
226
get_ev_num_info(EV_NUM_INFO * ev_info,NUM_INFO * info,const char * num)227 bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num)
228 {
229 if (info->negative)
230 {
231 if (((longlong) info->ullval) < 0)
232 return 0; // Impossible to store as a negative number
233 ev_info->llval = - max<longlong>((ulonglong) -ev_info->llval,
234 info->ullval);
235 ev_info->min_dval = - max<double>(-ev_info->min_dval, info->dval);
236 }
237 else // ulonglong is as big as bigint in MySQL
238 {
239 if ((check_ulonglong(num, info->integers) == DECIMAL_NUM))
240 return 0;
241 ev_info->ullval = max<ulonglong>(ev_info->ullval, info->ullval);
242 ev_info->max_dval = max<double>(ev_info->max_dval, info->dval);
243 }
244 return 1;
245 } // get_ev_num_info
246
247
free_string(void * s_void,TREE_FREE,const void *)248 void free_string(void *s_void, TREE_FREE, const void*)
249 {
250 String *s= static_cast<String*>(s_void);
251 s->mem_free();
252 }
253
254
add()255 void field_str::add()
256 {
257 char buff[MAX_FIELD_WIDTH], *ptr;
258 String s(buff, sizeof(buff),&my_charset_bin), *res;
259 size_t length;
260
261 if (!(res= item->str_result(&s)))
262 {
263 nulls++;
264 return;
265 }
266
267 if (!(length = res->length()))
268 empty++;
269 else
270 {
271 ptr = (char*) res->ptr();
272 if (*(ptr + (length - 1)) == ' ')
273 must_be_blob = 1;
274 }
275
276 if (can_be_still_num)
277 {
278 memset(&num_info, 0, sizeof(num_info));
279 if (!test_if_number(&num_info, res->ptr(), (uint) length))
280 can_be_still_num = 0;
281 if (!found)
282 {
283 memset(&ev_num_info, 0, sizeof(ev_num_info));
284 was_zero_fill = num_info.zerofill;
285 }
286 else if (num_info.zerofill != was_zero_fill && !was_maybe_zerofill)
287 can_be_still_num = 0; // one more check needed, when length is counted
288 if (can_be_still_num)
289 can_be_still_num = get_ev_num_info(&ev_num_info, &num_info, res->ptr());
290 was_maybe_zerofill = num_info.maybe_zerofill;
291 }
292
293 /* Update min and max arguments */
294 if (!found)
295 {
296 found = 1;
297 min_arg.copy(*res);
298 max_arg.copy(*res);
299 min_length = max_length = length; sum=length;
300 }
301 else if (length)
302 {
303 sum += length;
304 if (length < min_length)
305 min_length = length;
306 if (length > max_length)
307 max_length = length;
308
309 if (sortcmp(res, &min_arg,item->collation.collation) < 0)
310 min_arg.copy(*res);
311 if (sortcmp(res, &max_arg,item->collation.collation) > 0)
312 max_arg.copy(*res);
313 }
314
315 if (room_in_tree)
316 {
317 if (res != &s)
318 s.copy(*res);
319 if (!tree_search(&tree, (void*) &s, tree.custom_arg)) // If not in tree
320 {
321 s.copy(); // slow, when SAFE_MALLOC is in use
322 if (!tree_insert(&tree, (void*) &s, 0, tree.custom_arg))
323 {
324 room_in_tree = 0; // Remove tree, out of RAM ?
325 delete_tree(&tree);
326 }
327 else
328 {
329 ::new (&s) String; // Let tree handle free of this
330 if ((treemem += length) > pc->max_treemem)
331 {
332 room_in_tree = 0; // Remove tree, too big tree
333 delete_tree(&tree);
334 }
335 }
336 }
337 }
338
339 if ((num_info.zerofill && (max_length != min_length)) ||
340 (was_zero_fill && (max_length != min_length)))
341 can_be_still_num = 0; // zerofilled numbers must be of same length
342 } // field_str::add
343
344
add()345 void field_real::add()
346 {
347 char buff[MAX_FIELD_WIDTH], *ptr, *end;
348 double num= item->val_result();
349 size_t length;
350 uint zero_count, decs;
351 TREE_ELEMENT *element;
352
353 if (item->null_value)
354 {
355 nulls++;
356 return;
357 }
358 if (num == 0.0)
359 empty++;
360
361 if ((decs = decimals()) == NOT_FIXED_DEC)
362 {
363 length= sprintf(buff, "%g", num);
364 if (rint(num) != num)
365 max_notzero_dec_len = 1;
366 }
367 else
368 {
369 buff[sizeof(buff)-1]=0; // Safety
370 my_snprintf(buff, sizeof(buff)-1, "%-.*f", (int) decs, num);
371 length= strlen(buff);
372
373 // We never need to check further than this
374 end = buff + length - 1 - decs + max_notzero_dec_len;
375
376 zero_count = 0;
377 for (ptr = buff + length - 1; ptr > end && *ptr == '0'; ptr--)
378 zero_count++;
379
380 if ((decs - zero_count > max_notzero_dec_len))
381 max_notzero_dec_len = decs - zero_count;
382 }
383
384 if (room_in_tree)
385 {
386 if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
387 {
388 room_in_tree = 0; // Remove tree, out of RAM ?
389 delete_tree(&tree);
390 }
391 /*
392 if element->count == 1, this element can be found only once from tree
393 if element->count == 2, or more, this element is already in tree
394 */
395 else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
396 {
397 room_in_tree = 0; // Remove tree, too many elements
398 delete_tree(&tree);
399 }
400 }
401
402 if (!found)
403 {
404 found = 1;
405 min_arg = max_arg = sum = num;
406 sum_sqr = num * num;
407 min_length = max_length = length;
408 }
409 else if (num != 0.0)
410 {
411 sum += num;
412 sum_sqr += num * num;
413 if (length < min_length)
414 min_length = length;
415 if (length > max_length)
416 max_length = length;
417 if (compare_double(&num, &min_arg) < 0)
418 min_arg = num;
419 if (compare_double(&num, &max_arg) > 0)
420 max_arg = num;
421 }
422 } // field_real::add
423
424
add()425 void field_decimal::add()
426 {
427 /*TODO - remove rounding stuff after decimal_div returns proper frac */
428 my_decimal dec_buf, *dec= item->val_decimal_result(&dec_buf);
429 my_decimal rounded;
430 uint length;
431 TREE_ELEMENT *element;
432
433 if (item->null_value)
434 {
435 nulls++;
436 return;
437 }
438
439 my_decimal_round(E_DEC_FATAL_ERROR, dec, item->decimals, FALSE,&rounded);
440 dec= &rounded;
441
442 length= my_decimal_string_length(dec);
443
444 if (decimal_is_zero(dec))
445 empty++;
446
447 if (room_in_tree)
448 {
449 uchar buf[DECIMAL_MAX_FIELD_SIZE];
450 my_decimal2binary(E_DEC_FATAL_ERROR, dec, buf,
451 item->max_length, item->decimals);
452 if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg)))
453 {
454 room_in_tree = 0; // Remove tree, out of RAM ?
455 delete_tree(&tree);
456 }
457 /*
458 if element->count == 1, this element can be found only once from tree
459 if element->count == 2, or more, this element is already in tree
460 */
461 else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
462 {
463 room_in_tree = 0; // Remove tree, too many elements
464 delete_tree(&tree);
465 }
466 }
467
468 if (!found)
469 {
470 found = 1;
471 min_arg = max_arg = sum[0] = *dec;
472 my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, dec, dec);
473 cur_sum= 0;
474 min_length = max_length = length;
475 }
476 else if (!decimal_is_zero(dec))
477 {
478 int next_cur_sum= cur_sum ^ 1;
479 my_decimal sqr_buf;
480
481 my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, dec);
482 my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec);
483 my_decimal_add(E_DEC_FATAL_ERROR,
484 sum_sqr+next_cur_sum, sum_sqr+cur_sum, &sqr_buf);
485 cur_sum= next_cur_sum;
486 if (length < min_length)
487 min_length = length;
488 if (length > max_length)
489 max_length = length;
490 if (my_decimal_cmp(dec, &min_arg) < 0)
491 {
492 min_arg= *dec;
493 }
494 if (my_decimal_cmp(dec, &max_arg) > 0)
495 {
496 max_arg= *dec;
497 }
498 }
499 }
500
501
add()502 void field_longlong::add()
503 {
504 char buff[MAX_FIELD_WIDTH];
505 longlong num= item->val_int_result();
506 uint length= (uint) (longlong10_to_str(num, buff, -10) - buff);
507 TREE_ELEMENT *element;
508
509 if (item->null_value)
510 {
511 nulls++;
512 return;
513 }
514 if (num == 0)
515 empty++;
516
517 if (room_in_tree)
518 {
519 if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
520 {
521 room_in_tree = 0; // Remove tree, out of RAM ?
522 delete_tree(&tree);
523 }
524 /*
525 if element->count == 1, this element can be found only once from tree
526 if element->count == 2, or more, this element is already in tree
527 */
528 else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
529 {
530 room_in_tree = 0; // Remove tree, too many elements
531 delete_tree(&tree);
532 }
533 }
534
535 if (!found)
536 {
537 found = 1;
538 min_arg = max_arg = sum = num;
539 sum_sqr = num * num;
540 min_length = max_length = length;
541 }
542 else if (num != 0)
543 {
544 sum += num;
545 sum_sqr += num * num;
546 if (length < min_length)
547 min_length = length;
548 if (length > max_length)
549 max_length = length;
550 if (compare_longlong(&num, &min_arg) < 0)
551 min_arg = num;
552 if (compare_longlong(&num, &max_arg) > 0)
553 max_arg = num;
554 }
555 } // field_longlong::add
556
557
add()558 void field_ulonglong::add()
559 {
560 char buff[MAX_FIELD_WIDTH];
561 longlong num= item->val_int_result();
562 uint length= (uint) (longlong10_to_str(num, buff, 10) - buff);
563 TREE_ELEMENT *element;
564
565 if (item->null_value)
566 {
567 nulls++;
568 return;
569 }
570 if (num == 0)
571 empty++;
572
573 if (room_in_tree)
574 {
575 if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
576 {
577 room_in_tree = 0; // Remove tree, out of RAM ?
578 delete_tree(&tree);
579 }
580 /*
581 if element->count == 1, this element can be found only once from tree
582 if element->count == 2, or more, this element is already in tree
583 */
584 else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
585 {
586 room_in_tree = 0; // Remove tree, too many elements
587 delete_tree(&tree);
588 }
589 }
590
591 if (!found)
592 {
593 found = 1;
594 min_arg = max_arg = sum = num;
595 sum_sqr = num * num;
596 min_length = max_length = length;
597 }
598 else if (num != 0)
599 {
600 sum += num;
601 sum_sqr += num * num;
602 if (length < min_length)
603 min_length = length;
604 if (length > max_length)
605 max_length = length;
606 if (compare_ulonglong((ulonglong*) &num, &min_arg) < 0)
607 min_arg = num;
608 if (compare_ulonglong((ulonglong*) &num, &max_arg) > 0)
609 max_arg = num;
610 }
611 } // field_ulonglong::add
612
613
send_data(List<Item> &)614 bool Query_result_analyse::send_data(List<Item> & /* field_list */)
615 {
616 field_info **f = f_info;
617
618 rows++;
619
620 for (;f != f_end; f++)
621 {
622 (*f)->add();
623 }
624 return false;
625 }
626
627
send_eof()628 bool Query_result_analyse::send_eof()
629 {
630 field_info **f = f_info;
631 char buff[MAX_FIELD_WIDTH];
632 String *res, s_min(buff, sizeof(buff),&my_charset_bin),
633 s_max(buff, sizeof(buff),&my_charset_bin),
634 ans(buff, sizeof(buff),&my_charset_bin);
635
636 if (rows == 0) // for backward compatibility
637 goto ok;
638
639 for (; f != f_end; f++)
640 {
641 func_items[0]->set((*f)->item->full_name());
642 if (!(*f)->found)
643 {
644 func_items[1]->null_value = 1;
645 func_items[2]->null_value = 1;
646 }
647 else
648 {
649 func_items[1]->null_value = 0;
650 res = (*f)->get_min_arg(&s_min);
651 func_items[1]->set(res->ptr(), res->length(), res->charset());
652 func_items[2]->null_value = 0;
653 res = (*f)->get_max_arg(&s_max);
654 func_items[2]->set(res->ptr(), res->length(), res->charset());
655 }
656 func_items[3]->set((longlong) (*f)->min_length);
657 func_items[4]->set((longlong) (*f)->max_length);
658 func_items[5]->set((longlong) (*f)->empty);
659 func_items[6]->set((longlong) (*f)->nulls);
660 res = (*f)->avg(&s_max, rows);
661 func_items[7]->set(res->ptr(), res->length(), res->charset());
662 func_items[8]->null_value = 0;
663 res = (*f)->std(&s_max, rows);
664 if (!res)
665 func_items[8]->null_value = 1;
666 else
667 func_items[8]->set(res->ptr(), res->length(), res->charset());
668 /*
669 count the dots, quotas, etc. in (ENUM("a","b","c"...))
670 If tree has been removed, don't suggest ENUM.
671 treemem is used to measure the size of tree for strings,
672 tree_elements is used to count the elements
673 max_treemem tells how long the string starting from ENUM("... and
674 ending to ..") shall at maximum be. If case is about numbers,
675 max_tree_elements will tell the length of the above, now
676 every number is considered as length 1
677 */
678 if (((*f)->treemem || (*f)->tree_elements) &&
679 (*f)->tree.elements_in_tree &&
680 (((*f)->treemem ? max_treemem : max_tree_elements) >
681 (((*f)->treemem ? (*f)->treemem : (*f)->tree_elements) +
682 ((*f)->tree.elements_in_tree * 3 - 1 + 6))))
683 {
684 char tmp[331]; //331, because one double prec. num. can be this long
685 String tmp_str(tmp, sizeof(tmp),&my_charset_bin);
686 TREE_INFO tree_info;
687
688 tree_info.str = &tmp_str;
689 tree_info.found = 0;
690 tree_info.item = (*f)->item;
691
692 tmp_str.set(STRING_WITH_LEN("ENUM("),&my_charset_bin);
693 tree_walk(&(*f)->tree, (*f)->collect_enum(), (char*) &tree_info,
694 left_root_right);
695 tmp_str.append(')');
696
697 if (!(*f)->nulls)
698 tmp_str.append(STRING_WITH_LEN(" NOT NULL"));
699 output_str_length = tmp_str.length();
700 func_items[9]->set(tmp_str.ptr(), tmp_str.length(), tmp_str.charset());
701 if (result->send_data(result_fields))
702 goto error;
703 continue;
704 }
705
706 ans.length(0);
707 if (!(*f)->treemem && !(*f)->tree_elements)
708 ans.append(STRING_WITH_LEN("CHAR(0)"));
709 else if ((*f)->item->type() == Item::FIELD_ITEM)
710 {
711 switch (((Item_field*) (*f)->item)->field->real_type())
712 {
713 case MYSQL_TYPE_TIMESTAMP:
714 ans.append(STRING_WITH_LEN("TIMESTAMP"));
715 break;
716 case MYSQL_TYPE_DATETIME:
717 ans.append(STRING_WITH_LEN("DATETIME"));
718 break;
719 case MYSQL_TYPE_DATE:
720 case MYSQL_TYPE_NEWDATE:
721 ans.append(STRING_WITH_LEN("DATE"));
722 break;
723 case MYSQL_TYPE_SET:
724 ans.append(STRING_WITH_LEN("SET"));
725 break;
726 case MYSQL_TYPE_YEAR:
727 ans.append(STRING_WITH_LEN("YEAR"));
728 break;
729 case MYSQL_TYPE_TIME:
730 ans.append(STRING_WITH_LEN("TIME"));
731 break;
732 case MYSQL_TYPE_DECIMAL:
733 ans.append(STRING_WITH_LEN("DECIMAL"));
734 // if item is FIELD_ITEM, it _must_be_ Field_num in this case
735 if (((Field_num*) ((Item_field*) (*f)->item)->field)->zerofill)
736 ans.append(STRING_WITH_LEN(" ZEROFILL"));
737 break;
738 default:
739 (*f)->get_opt_type(&ans, rows);
740 break;
741 }
742 }
743 if (!(*f)->nulls)
744 ans.append(STRING_WITH_LEN(" NOT NULL"));
745 func_items[9]->set(ans.ptr(), ans.length(), ans.charset());
746 if (result->send_data(result_fields))
747 goto error;
748 }
749 ok:
750 return result->send_eof();
751 error:
752 abort_result_set();
753 return true;
754 } // Query_result_analyse::send_eof
755
756
get_opt_type(String * answer,ha_rows total_rows)757 void field_str::get_opt_type(String *answer, ha_rows total_rows)
758 {
759 char buff[MAX_FIELD_WIDTH];
760
761 if (can_be_still_num)
762 {
763 if (num_info.is_float)
764 sprintf(buff, "DOUBLE"); // number was like 1e+50... TODO:
765 else if (num_info.decimals) // DOUBLE(%d,%d) sometime
766 {
767 if (num_info.dval > -FLT_MAX && num_info.dval < FLT_MAX)
768 sprintf(buff, "FLOAT(%d,%d)", (num_info.integers + num_info.decimals), num_info.decimals);
769 else
770 sprintf(buff, "DOUBLE(%d,%d)", (num_info.integers + num_info.decimals), num_info.decimals);
771 }
772 else if (ev_num_info.llval >= -128 &&
773 ev_num_info.ullval <=
774 (ulonglong) (ev_num_info.llval >= 0 ? 255 : 127))
775 sprintf(buff, "TINYINT(%d)", num_info.integers);
776 else if (ev_num_info.llval >= INT_MIN16 &&
777 ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
778 UINT_MAX16 : INT_MAX16))
779 sprintf(buff, "SMALLINT(%d)", num_info.integers);
780 else if (ev_num_info.llval >= INT_MIN24 &&
781 ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
782 UINT_MAX24 : INT_MAX24))
783 sprintf(buff, "MEDIUMINT(%d)", num_info.integers);
784 else if (ev_num_info.llval >= INT_MIN32 &&
785 ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
786 UINT_MAX32 : INT_MAX32))
787 sprintf(buff, "INT(%d)", num_info.integers);
788 else
789 sprintf(buff, "BIGINT(%d)", num_info.integers);
790 answer->append(buff, strlen(buff));
791 if (ev_num_info.llval >= 0 && ev_num_info.min_dval >= 0)
792 answer->append(STRING_WITH_LEN(" UNSIGNED"));
793 if (num_info.zerofill)
794 answer->append(STRING_WITH_LEN(" ZEROFILL"));
795 }
796 else if (max_length < 256)
797 {
798 if (must_be_blob)
799 {
800 if (item->collation.collation == &my_charset_bin)
801 answer->append(STRING_WITH_LEN("TINYBLOB"));
802 else
803 answer->append(STRING_WITH_LEN("TINYTEXT"));
804 }
805 else if ((max_length * (total_rows - nulls)) < (sum + total_rows))
806 {
807 sprintf(buff, "CHAR(%d)", (int) max_length);
808 answer->append(buff, strlen(buff));
809 }
810 else
811 {
812 sprintf(buff, "VARCHAR(%d)", (int) max_length);
813 answer->append(buff, strlen(buff));
814 }
815 }
816 else if (max_length < (1L << 16))
817 {
818 if (item->collation.collation == &my_charset_bin)
819 answer->append(STRING_WITH_LEN("BLOB"));
820 else
821 answer->append(STRING_WITH_LEN("TEXT"));
822 }
823 else if (max_length < (1L << 24))
824 {
825 if (item->collation.collation == &my_charset_bin)
826 answer->append(STRING_WITH_LEN("MEDIUMBLOB"));
827 else
828 answer->append(STRING_WITH_LEN("MEDIUMTEXT"));
829 }
830 else
831 {
832 if (item->collation.collation == &my_charset_bin)
833 answer->append(STRING_WITH_LEN("LONGBLOB"));
834 else
835 answer->append(STRING_WITH_LEN("LONGTEXT"));
836 }
837 } // field_str::get_opt_type
838
839
get_opt_type(String * answer,ha_rows total_rows MY_ATTRIBUTE ((unused)))840 void field_real::get_opt_type(String *answer,
841 ha_rows total_rows MY_ATTRIBUTE((unused)))
842 {
843 char buff[MAX_FIELD_WIDTH];
844
845 if (!max_notzero_dec_len)
846 {
847 int len= (int) max_length - ((item->decimals == NOT_FIXED_DEC) ?
848 0 : (item->decimals + 1));
849
850 if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127))
851 sprintf(buff, "TINYINT(%d)", len);
852 else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ?
853 UINT_MAX16 : INT_MAX16))
854 sprintf(buff, "SMALLINT(%d)", len);
855 else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ?
856 UINT_MAX24 : INT_MAX24))
857 sprintf(buff, "MEDIUMINT(%d)", len);
858 else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ?
859 UINT_MAX32 : INT_MAX32))
860 sprintf(buff, "INT(%d)", len);
861 else
862 sprintf(buff, "BIGINT(%d)", len);
863 answer->append(buff, strlen(buff));
864 if (min_arg >= 0)
865 answer->append(STRING_WITH_LEN(" UNSIGNED"));
866 }
867 else if (item->decimals == NOT_FIXED_DEC)
868 {
869 if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX)
870 answer->append(STRING_WITH_LEN("FLOAT"));
871 else
872 answer->append(STRING_WITH_LEN("DOUBLE"));
873 }
874 else
875 {
876 if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX)
877 sprintf(buff, "FLOAT(%d,%d)", (int) max_length - (item->decimals + 1) + max_notzero_dec_len,
878 max_notzero_dec_len);
879 else
880 sprintf(buff, "DOUBLE(%d,%d)", (int) max_length - (item->decimals + 1) + max_notzero_dec_len,
881 max_notzero_dec_len);
882 answer->append(buff, strlen(buff));
883 }
884 // if item is FIELD_ITEM, it _must_be_ Field_num in this class
885 if (item->type() == Item::FIELD_ITEM &&
886 // a single number shouldn't be zerofill
887 (max_length - (item->decimals + 1)) != 1 &&
888 ((Field_num*) ((Item_field*) item)->field)->zerofill)
889 answer->append(STRING_WITH_LEN(" ZEROFILL"));
890 } // field_real::get_opt_type
891
892
get_opt_type(String * answer,ha_rows total_rows MY_ATTRIBUTE ((unused)))893 void field_longlong::get_opt_type(String *answer,
894 ha_rows total_rows MY_ATTRIBUTE((unused)))
895 {
896 char buff[MAX_FIELD_WIDTH];
897
898 if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127))
899 sprintf(buff, "TINYINT(%d)", (int) max_length);
900 else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ?
901 UINT_MAX16 : INT_MAX16))
902 sprintf(buff, "SMALLINT(%d)", (int) max_length);
903 else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ?
904 UINT_MAX24 : INT_MAX24))
905 sprintf(buff, "MEDIUMINT(%d)", (int) max_length);
906 else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ?
907 UINT_MAX32 : INT_MAX32))
908 sprintf(buff, "INT(%d)", (int) max_length);
909 else
910 sprintf(buff, "BIGINT(%d)", (int) max_length);
911 answer->append(buff, strlen(buff));
912 if (min_arg >= 0)
913 answer->append(STRING_WITH_LEN(" UNSIGNED"));
914
915 // if item is FIELD_ITEM, it _must_be_ Field_num in this class
916 if ((item->type() == Item::FIELD_ITEM) &&
917 // a single number shouldn't be zerofill
918 max_length != 1 &&
919 ((Field_num*) ((Item_field*) item)->field)->zerofill)
920 answer->append(STRING_WITH_LEN(" ZEROFILL"));
921 } // field_longlong::get_opt_type
922
923
get_opt_type(String * answer,ha_rows total_rows MY_ATTRIBUTE ((unused)))924 void field_ulonglong::get_opt_type(String *answer,
925 ha_rows total_rows MY_ATTRIBUTE((unused)))
926 {
927 char buff[MAX_FIELD_WIDTH];
928
929 if (max_arg < 256)
930 sprintf(buff, "TINYINT(%d) UNSIGNED", (int) max_length);
931 else if (max_arg <= ((2 * INT_MAX16) + 1))
932 sprintf(buff, "SMALLINT(%d) UNSIGNED", (int) max_length);
933 else if (max_arg <= ((2 * INT_MAX24) + 1))
934 sprintf(buff, "MEDIUMINT(%d) UNSIGNED", (int) max_length);
935 else if (max_arg < (((ulonglong) 1) << 32))
936 sprintf(buff, "INT(%d) UNSIGNED", (int) max_length);
937 else
938 sprintf(buff, "BIGINT(%d) UNSIGNED", (int) max_length);
939 // if item is FIELD_ITEM, it _must_be_ Field_num in this class
940 answer->append(buff, strlen(buff));
941 if (item->type() == Item::FIELD_ITEM &&
942 // a single number shouldn't be zerofill
943 max_length != 1 &&
944 ((Field_num*) ((Item_field*) item)->field)->zerofill)
945 answer->append(STRING_WITH_LEN(" ZEROFILL"));
946 } //field_ulonglong::get_opt_type
947
948
get_opt_type(String * answer,ha_rows total_rows MY_ATTRIBUTE ((unused)))949 void field_decimal::get_opt_type(String *answer,
950 ha_rows total_rows MY_ATTRIBUTE((unused)))
951 {
952 my_decimal zero;
953 char buff[MAX_FIELD_WIDTH];
954 size_t length;
955
956 my_decimal_set_zero(&zero);
957 my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0);
958
959 length= my_snprintf(buff, sizeof(buff), "DECIMAL(%d, %d)",
960 static_cast<int>(max_length - (item->decimals ? 1 : 0)),
961 static_cast<int>(item->decimals));
962 if (is_unsigned)
963 length= (my_stpcpy(buff+length, " UNSIGNED")- buff);
964 answer->append(buff, length);
965 }
966
967
get_min_arg(String * str)968 String *field_decimal::get_min_arg(String *str)
969 {
970 my_decimal2string(E_DEC_FATAL_ERROR, &min_arg, 0, 0, '0', str);
971 return str;
972 }
973
974
get_max_arg(String * str)975 String *field_decimal::get_max_arg(String *str)
976 {
977 my_decimal2string(E_DEC_FATAL_ERROR, &max_arg, 0, 0, '0', str);
978 return str;
979 }
980
981
avg(String * s,ha_rows rows)982 String *field_decimal::avg(String *s, ha_rows rows)
983 {
984 if (!(rows - nulls))
985 {
986 s->set_real(0.0, 1,my_thd_charset);
987 return s;
988 }
989 my_decimal num, avg_val, rounded_avg;
990 int prec_increment= current_thd->variables.div_precincrement;
991
992 int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
993 my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, prec_increment);
994 /* TODO remove this after decimal_div returns proper frac */
995 my_decimal_round(E_DEC_FATAL_ERROR, &avg_val,
996 min(sum[cur_sum].frac + prec_increment, DECIMAL_MAX_SCALE),
997 FALSE,&rounded_avg);
998 my_decimal2string(E_DEC_FATAL_ERROR, &rounded_avg, 0, 0, '0', s);
999 return s;
1000 }
1001
1002
std(String * s,ha_rows rows)1003 String *field_decimal::std(String *s, ha_rows rows)
1004 {
1005 if (!(rows - nulls))
1006 {
1007 s->set_real(0.0, 1,my_thd_charset);
1008 return s;
1009 }
1010 my_decimal num, tmp, sum2, sum2d;
1011 double std_sqr;
1012 int prec_increment= current_thd->variables.div_precincrement;
1013
1014 int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
1015 my_decimal_mul(E_DEC_FATAL_ERROR, &sum2, sum+cur_sum, sum+cur_sum);
1016 my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment);
1017 my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &tmp);
1018 my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment);
1019 my_decimal2double(E_DEC_FATAL_ERROR, &tmp, &std_sqr);
1020 s->set_real((std_sqr <= 0.0 ? 0.0 : sqrt(std_sqr)),
1021 min(item->decimals + prec_increment, NOT_FIXED_DEC), my_thd_charset);
1022
1023 return s;
1024 }
1025
1026
collect_string(String * element,element_count count MY_ATTRIBUTE ((unused)),TREE_INFO * info)1027 int collect_string(String *element,
1028 element_count count MY_ATTRIBUTE((unused)),
1029 TREE_INFO *info)
1030 {
1031 if (info->found)
1032 info->str->append(',');
1033 else
1034 info->found = 1;
1035 info->str->append('\'');
1036 if (append_escaped(info->str, element))
1037 return 1;
1038 info->str->append('\'');
1039 return 0;
1040 } // collect_string
1041
1042
collect_real(double * element,element_count count MY_ATTRIBUTE ((unused)),TREE_INFO * info)1043 int collect_real(double *element, element_count count MY_ATTRIBUTE((unused)),
1044 TREE_INFO *info)
1045 {
1046 char buff[MAX_FIELD_WIDTH];
1047 String s(buff, sizeof(buff),current_thd->charset());
1048
1049 if (info->found)
1050 info->str->append(',');
1051 else
1052 info->found = 1;
1053 info->str->append('\'');
1054 s.set_real(*element, info->item->decimals, current_thd->charset());
1055 info->str->append(s);
1056 info->str->append('\'');
1057 return 0;
1058 } // collect_real
1059
1060
collect_decimal(uchar * element,element_count count,TREE_INFO * info)1061 int collect_decimal(uchar *element, element_count count,
1062 TREE_INFO *info)
1063 {
1064 char buff[DECIMAL_MAX_STR_LENGTH + 1];
1065 String s(buff, sizeof(buff),&my_charset_bin);
1066
1067 if (info->found)
1068 info->str->append(',');
1069 else
1070 info->found = 1;
1071 my_decimal dec;
1072 binary2my_decimal(E_DEC_FATAL_ERROR, element, &dec,
1073 info->item->max_length, info->item->decimals);
1074
1075 info->str->append('\'');
1076 my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, '0', &s);
1077 info->str->append(s);
1078 info->str->append('\'');
1079 return 0;
1080 }
1081
1082
collect_longlong(longlong * element,element_count count MY_ATTRIBUTE ((unused)),TREE_INFO * info)1083 int collect_longlong(longlong *element,
1084 element_count count MY_ATTRIBUTE((unused)),
1085 TREE_INFO *info)
1086 {
1087 char buff[MAX_FIELD_WIDTH];
1088 String s(buff, sizeof(buff),&my_charset_bin);
1089
1090 if (info->found)
1091 info->str->append(',');
1092 else
1093 info->found = 1;
1094 info->str->append('\'');
1095 s.set(*element, current_thd->charset());
1096 info->str->append(s);
1097 info->str->append('\'');
1098 return 0;
1099 } // collect_longlong
1100
1101
collect_ulonglong(ulonglong * element,element_count count MY_ATTRIBUTE ((unused)),TREE_INFO * info)1102 int collect_ulonglong(ulonglong *element,
1103 element_count count MY_ATTRIBUTE((unused)),
1104 TREE_INFO *info)
1105 {
1106 char buff[MAX_FIELD_WIDTH];
1107 String s(buff, sizeof(buff),&my_charset_bin);
1108
1109 if (info->found)
1110 info->str->append(',');
1111 else
1112 info->found = 1;
1113 info->str->append('\'');
1114 s.set(*element, current_thd->charset());
1115 info->str->append(s);
1116 info->str->append('\'');
1117 return 0;
1118 } // collect_ulonglong
1119
1120
1121 /**
1122 Create items for substituted output columns (both metadata and data)
1123 */
change_columns()1124 bool Query_result_analyse::change_columns()
1125 {
1126 func_items[0] = new Item_proc_string("Field_name", 255);
1127 func_items[1] = new Item_proc_string("Min_value", 255);
1128 func_items[1]->maybe_null = 1;
1129 func_items[2] = new Item_proc_string("Max_value", 255);
1130 func_items[2]->maybe_null = 1;
1131 func_items[3] = new Item_proc_int("Min_length");
1132 func_items[4] = new Item_proc_int("Max_length");
1133 func_items[5] = new Item_proc_int("Empties_or_zeros");
1134 func_items[6] = new Item_proc_int("Nulls");
1135 func_items[7] = new Item_proc_string("Avg_value_or_avg_length", 255);
1136 func_items[8] = new Item_proc_string("Std", 255);
1137 func_items[8]->maybe_null = 1;
1138 func_items[9] = new Item_proc_string("Optimal_fieldtype",
1139 max<size_t>(64U, output_str_length));
1140 result_fields.empty();
1141 for (uint i = 0; i < array_elements(func_items); i++)
1142 {
1143 if (func_items[i] == NULL)
1144 return true;
1145 result_fields.push_back(func_items[i]);
1146 }
1147 return false;
1148 } // Query_result_analyse::change_columns
1149
1150
cleanup()1151 void Query_result_analyse::cleanup()
1152 {
1153 if (f_info)
1154 {
1155 for (field_info **f= f_info; f != f_end; f++)
1156 delete (*f);
1157 f_info= f_end= NULL;
1158 }
1159 rows= 0;
1160 output_str_length= 0;
1161 }
1162
1163
send_result_set_metadata(List<Item> & fields,uint flag)1164 bool Query_result_analyse::send_result_set_metadata(List<Item> &fields,
1165 uint flag)
1166 {
1167 return (init(fields) || change_columns() ||
1168 result->send_result_set_metadata(result_fields, flag));
1169 }
1170
1171
abort_result_set()1172 void Query_result_analyse::abort_result_set()
1173 {
1174 cleanup();
1175 return result->abort_result_set();
1176 }
1177
1178
compare_double(const double * s,const double * t)1179 int compare_double(const double *s, const double *t)
1180 {
1181 return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
1182 } /* compare_double */
1183
compare_longlong(const longlong * s,const longlong * t)1184 int compare_longlong(const longlong *s, const longlong *t)
1185 {
1186 return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
1187 } /* compare_longlong */
1188
compare_ulonglong(const ulonglong * s,const ulonglong * t)1189 int compare_ulonglong(const ulonglong *s, const ulonglong *t)
1190 {
1191 return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
1192 } /* compare_ulonglong */
1193
1194
check_ulonglong(const char * str,uint length)1195 uint check_ulonglong(const char *str, uint length)
1196 {
1197 const char *long_str = "2147483647", *ulonglong_str = "18446744073709551615";
1198 const uint long_len = 10, ulonglong_len = 20;
1199
1200 while (*str == '0' && length)
1201 {
1202 str++; length--;
1203 }
1204 if (length < long_len)
1205 return NUM;
1206
1207 uint smaller, bigger;
1208 const char *cmp;
1209
1210 if (length == long_len)
1211 {
1212 cmp = long_str;
1213 smaller = NUM;
1214 bigger = LONG_NUM;
1215 }
1216 else if (length > ulonglong_len)
1217 return DECIMAL_NUM;
1218 else
1219 {
1220 cmp = ulonglong_str;
1221 smaller = LONG_NUM;
1222 bigger = DECIMAL_NUM;
1223 }
1224 while (*cmp && *cmp++ == *str++) ;
1225 return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
1226 } /* check_ulonlong */
1227
1228
1229 /*
1230 Quote special characters in a string.
1231
1232 SYNOPSIS
1233 append_escaped(to_str, from_str)
1234 to_str (in) A pointer to a String.
1235 from_str (to) A pointer to an allocated string
1236
1237 DESCRIPTION
1238 append_escaped() takes a String type variable, where it appends
1239 escaped the second argument. Only characters that require escaping
1240 will be escaped.
1241
1242 RETURN VALUES
1243 0 Success
1244 1 Out of memory
1245 */
1246
append_escaped(String * to_str,String * from_str)1247 bool append_escaped(String *to_str, String *from_str)
1248 {
1249 char *from, *end, c;
1250
1251 if (to_str->mem_realloc(to_str->length() + from_str->length()))
1252 return 1;
1253
1254 from= (char*) from_str->ptr();
1255 end= from + from_str->length();
1256 for (; from < end; from++)
1257 {
1258 c= *from;
1259 switch (c) {
1260 case '\0':
1261 c= '0';
1262 break;
1263 case '\032':
1264 c= 'Z';
1265 break;
1266 case '\\':
1267 case '\'':
1268 break;
1269 default:
1270 goto normal_character;
1271 }
1272 if (to_str->append('\\'))
1273 return 1;
1274
1275 normal_character:
1276 if (to_str->append(c))
1277 return 1;
1278 }
1279 return 0;
1280 }
1281
1282