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
add()254 void field_str::add()
255 {
256 char buff[MAX_FIELD_WIDTH], *ptr;
257 String s(buff, sizeof(buff),&my_charset_bin), *res;
258 size_t length;
259
260 if (!(res= item->str_result(&s)))
261 {
262 nulls++;
263 return;
264 }
265
266 if (!(length = res->length()))
267 empty++;
268 else
269 {
270 ptr = (char*) res->ptr();
271 if (*(ptr + (length - 1)) == ' ')
272 must_be_blob = 1;
273 }
274
275 if (can_be_still_num)
276 {
277 memset(&num_info, 0, sizeof(num_info));
278 if (!test_if_number(&num_info, res->ptr(), (uint) length))
279 can_be_still_num = 0;
280 if (!found)
281 {
282 memset(&ev_num_info, 0, sizeof(ev_num_info));
283 was_zero_fill = num_info.zerofill;
284 }
285 else if (num_info.zerofill != was_zero_fill && !was_maybe_zerofill)
286 can_be_still_num = 0; // one more check needed, when length is counted
287 if (can_be_still_num)
288 can_be_still_num = get_ev_num_info(&ev_num_info, &num_info, res->ptr());
289 was_maybe_zerofill = num_info.maybe_zerofill;
290 }
291
292 /* Update min and max arguments */
293 if (!found)
294 {
295 found = 1;
296 min_arg.copy(*res);
297 max_arg.copy(*res);
298 min_length = max_length = length; sum=length;
299 }
300 else if (length)
301 {
302 sum += length;
303 if (length < min_length)
304 min_length = length;
305 if (length > max_length)
306 max_length = length;
307
308 if (sortcmp(res, &min_arg,item->collation.collation) < 0)
309 min_arg.copy(*res);
310 if (sortcmp(res, &max_arg,item->collation.collation) > 0)
311 max_arg.copy(*res);
312 }
313
314 if (room_in_tree)
315 {
316 if (res != &s)
317 s.copy(*res);
318 if (!tree_search(&tree, (void*) &s, tree.custom_arg)) // If not in tree
319 {
320 s.copy(); // slow, when SAFE_MALLOC is in use
321 if (!tree_insert(&tree, (void*) &s, 0, tree.custom_arg))
322 {
323 room_in_tree = 0; // Remove tree, out of RAM ?
324 delete_tree(&tree);
325 }
326 else
327 {
328 ::new (&s) String; // Let tree handle free of this
329 if ((treemem += length) > pc->max_treemem)
330 {
331 room_in_tree = 0; // Remove tree, too big tree
332 delete_tree(&tree);
333 }
334 }
335 }
336 }
337
338 if ((num_info.zerofill && (max_length != min_length)) ||
339 (was_zero_fill && (max_length != min_length)))
340 can_be_still_num = 0; // zerofilled numbers must be of same length
341 } // field_str::add
342
343
add()344 void field_real::add()
345 {
346 char buff[MAX_FIELD_WIDTH], *ptr, *end;
347 double num= item->val_result();
348 size_t length;
349 uint zero_count, decs;
350 TREE_ELEMENT *element;
351
352 if (item->null_value)
353 {
354 nulls++;
355 return;
356 }
357 if (num == 0.0)
358 empty++;
359
360 if ((decs = decimals()) == NOT_FIXED_DEC)
361 {
362 length= sprintf(buff, "%g", num);
363 if (rint(num) != num)
364 max_notzero_dec_len = 1;
365 }
366 else
367 {
368 buff[sizeof(buff)-1]=0; // Safety
369 my_snprintf(buff, sizeof(buff)-1, "%-.*f", (int) decs, num);
370 length= strlen(buff);
371
372 // We never need to check further than this
373 end = buff + length - 1 - decs + max_notzero_dec_len;
374
375 zero_count = 0;
376 for (ptr = buff + length - 1; ptr > end && *ptr == '0'; ptr--)
377 zero_count++;
378
379 if ((decs - zero_count > max_notzero_dec_len))
380 max_notzero_dec_len = decs - zero_count;
381 }
382
383 if (room_in_tree)
384 {
385 if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
386 {
387 room_in_tree = 0; // Remove tree, out of RAM ?
388 delete_tree(&tree);
389 }
390 /*
391 if element->count == 1, this element can be found only once from tree
392 if element->count == 2, or more, this element is already in tree
393 */
394 else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
395 {
396 room_in_tree = 0; // Remove tree, too many elements
397 delete_tree(&tree);
398 }
399 }
400
401 if (!found)
402 {
403 found = 1;
404 min_arg = max_arg = sum = num;
405 sum_sqr = num * num;
406 min_length = max_length = length;
407 }
408 else if (num != 0.0)
409 {
410 sum += num;
411 sum_sqr += num * num;
412 if (length < min_length)
413 min_length = length;
414 if (length > max_length)
415 max_length = length;
416 if (compare_double(&num, &min_arg) < 0)
417 min_arg = num;
418 if (compare_double(&num, &max_arg) > 0)
419 max_arg = num;
420 }
421 } // field_real::add
422
423
add()424 void field_decimal::add()
425 {
426 /*TODO - remove rounding stuff after decimal_div returns proper frac */
427 my_decimal dec_buf, *dec= item->val_decimal_result(&dec_buf);
428 my_decimal rounded;
429 uint length;
430 TREE_ELEMENT *element;
431
432 if (item->null_value)
433 {
434 nulls++;
435 return;
436 }
437
438 my_decimal_round(E_DEC_FATAL_ERROR, dec, item->decimals, FALSE,&rounded);
439 dec= &rounded;
440
441 length= my_decimal_string_length(dec);
442
443 if (decimal_is_zero(dec))
444 empty++;
445
446 if (room_in_tree)
447 {
448 uchar buf[DECIMAL_MAX_FIELD_SIZE];
449 my_decimal2binary(E_DEC_FATAL_ERROR, dec, buf,
450 item->max_length, item->decimals);
451 if (!(element = tree_insert(&tree, (void*)buf, 0, tree.custom_arg)))
452 {
453 room_in_tree = 0; // Remove tree, out of RAM ?
454 delete_tree(&tree);
455 }
456 /*
457 if element->count == 1, this element can be found only once from tree
458 if element->count == 2, or more, this element is already in tree
459 */
460 else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
461 {
462 room_in_tree = 0; // Remove tree, too many elements
463 delete_tree(&tree);
464 }
465 }
466
467 if (!found)
468 {
469 found = 1;
470 min_arg = max_arg = sum[0] = *dec;
471 my_decimal_mul(E_DEC_FATAL_ERROR, sum_sqr, dec, dec);
472 cur_sum= 0;
473 min_length = max_length = length;
474 }
475 else if (!decimal_is_zero(dec))
476 {
477 int next_cur_sum= cur_sum ^ 1;
478 my_decimal sqr_buf;
479
480 my_decimal_add(E_DEC_FATAL_ERROR, sum+next_cur_sum, sum+cur_sum, dec);
481 my_decimal_mul(E_DEC_FATAL_ERROR, &sqr_buf, dec, dec);
482 my_decimal_add(E_DEC_FATAL_ERROR,
483 sum_sqr+next_cur_sum, sum_sqr+cur_sum, &sqr_buf);
484 cur_sum= next_cur_sum;
485 if (length < min_length)
486 min_length = length;
487 if (length > max_length)
488 max_length = length;
489 if (my_decimal_cmp(dec, &min_arg) < 0)
490 {
491 min_arg= *dec;
492 }
493 if (my_decimal_cmp(dec, &max_arg) > 0)
494 {
495 max_arg= *dec;
496 }
497 }
498 }
499
500
add()501 void field_longlong::add()
502 {
503 char buff[MAX_FIELD_WIDTH];
504 longlong num= item->val_int_result();
505 uint length= (uint) (longlong10_to_str(num, buff, -10) - buff);
506 TREE_ELEMENT *element;
507
508 if (item->null_value)
509 {
510 nulls++;
511 return;
512 }
513 if (num == 0)
514 empty++;
515
516 if (room_in_tree)
517 {
518 if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
519 {
520 room_in_tree = 0; // Remove tree, out of RAM ?
521 delete_tree(&tree);
522 }
523 /*
524 if element->count == 1, this element can be found only once from tree
525 if element->count == 2, or more, this element is already in tree
526 */
527 else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
528 {
529 room_in_tree = 0; // Remove tree, too many elements
530 delete_tree(&tree);
531 }
532 }
533
534 if (!found)
535 {
536 found = 1;
537 min_arg = max_arg = sum = num;
538 sum_sqr = num * num;
539 min_length = max_length = length;
540 }
541 else if (num != 0)
542 {
543 sum += num;
544 sum_sqr += num * num;
545 if (length < min_length)
546 min_length = length;
547 if (length > max_length)
548 max_length = length;
549 if (compare_longlong(&num, &min_arg) < 0)
550 min_arg = num;
551 if (compare_longlong(&num, &max_arg) > 0)
552 max_arg = num;
553 }
554 } // field_longlong::add
555
556
add()557 void field_ulonglong::add()
558 {
559 char buff[MAX_FIELD_WIDTH];
560 longlong num= item->val_int_result();
561 uint length= (uint) (longlong10_to_str(num, buff, 10) - buff);
562 TREE_ELEMENT *element;
563
564 if (item->null_value)
565 {
566 nulls++;
567 return;
568 }
569 if (num == 0)
570 empty++;
571
572 if (room_in_tree)
573 {
574 if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg)))
575 {
576 room_in_tree = 0; // Remove tree, out of RAM ?
577 delete_tree(&tree);
578 }
579 /*
580 if element->count == 1, this element can be found only once from tree
581 if element->count == 2, or more, this element is already in tree
582 */
583 else if (element->count == 1 && (tree_elements++) >= pc->max_tree_elements)
584 {
585 room_in_tree = 0; // Remove tree, too many elements
586 delete_tree(&tree);
587 }
588 }
589
590 if (!found)
591 {
592 found = 1;
593 min_arg = max_arg = sum = num;
594 sum_sqr = num * num;
595 min_length = max_length = length;
596 }
597 else if (num != 0)
598 {
599 sum += num;
600 sum_sqr += num * num;
601 if (length < min_length)
602 min_length = length;
603 if (length > max_length)
604 max_length = length;
605 if (compare_ulonglong((ulonglong*) &num, &min_arg) < 0)
606 min_arg = num;
607 if (compare_ulonglong((ulonglong*) &num, &max_arg) > 0)
608 max_arg = num;
609 }
610 } // field_ulonglong::add
611
612
send_data(List<Item> &)613 bool Query_result_analyse::send_data(List<Item> & /* field_list */)
614 {
615 field_info **f = f_info;
616
617 rows++;
618
619 for (;f != f_end; f++)
620 {
621 (*f)->add();
622 }
623 return false;
624 }
625
626
send_eof()627 bool Query_result_analyse::send_eof()
628 {
629 field_info **f = f_info;
630 char buff[MAX_FIELD_WIDTH];
631 String *res, s_min(buff, sizeof(buff),&my_charset_bin),
632 s_max(buff, sizeof(buff),&my_charset_bin),
633 ans(buff, sizeof(buff),&my_charset_bin);
634
635 if (rows == 0) // for backward compatibility
636 goto ok;
637
638 for (; f != f_end; f++)
639 {
640 func_items[0]->set((*f)->item->full_name());
641 if (!(*f)->found)
642 {
643 func_items[1]->null_value = 1;
644 func_items[2]->null_value = 1;
645 }
646 else
647 {
648 func_items[1]->null_value = 0;
649 res = (*f)->get_min_arg(&s_min);
650 func_items[1]->set(res->ptr(), res->length(), res->charset());
651 func_items[2]->null_value = 0;
652 res = (*f)->get_max_arg(&s_max);
653 func_items[2]->set(res->ptr(), res->length(), res->charset());
654 }
655 func_items[3]->set((longlong) (*f)->min_length);
656 func_items[4]->set((longlong) (*f)->max_length);
657 func_items[5]->set((longlong) (*f)->empty);
658 func_items[6]->set((longlong) (*f)->nulls);
659 res = (*f)->avg(&s_max, rows);
660 func_items[7]->set(res->ptr(), res->length(), res->charset());
661 func_items[8]->null_value = 0;
662 res = (*f)->std(&s_max, rows);
663 if (!res)
664 func_items[8]->null_value = 1;
665 else
666 func_items[8]->set(res->ptr(), res->length(), res->charset());
667 /*
668 count the dots, quotas, etc. in (ENUM("a","b","c"...))
669 If tree has been removed, don't suggest ENUM.
670 treemem is used to measure the size of tree for strings,
671 tree_elements is used to count the elements
672 max_treemem tells how long the string starting from ENUM("... and
673 ending to ..") shall at maximum be. If case is about numbers,
674 max_tree_elements will tell the length of the above, now
675 every number is considered as length 1
676 */
677 if (((*f)->treemem || (*f)->tree_elements) &&
678 (*f)->tree.elements_in_tree &&
679 (((*f)->treemem ? max_treemem : max_tree_elements) >
680 (((*f)->treemem ? (*f)->treemem : (*f)->tree_elements) +
681 ((*f)->tree.elements_in_tree * 3 - 1 + 6))))
682 {
683 char tmp[331]; //331, because one double prec. num. can be this long
684 String tmp_str(tmp, sizeof(tmp),&my_charset_bin);
685 TREE_INFO tree_info;
686
687 tree_info.str = &tmp_str;
688 tree_info.found = 0;
689 tree_info.item = (*f)->item;
690
691 tmp_str.set(STRING_WITH_LEN("ENUM("),&my_charset_bin);
692 tree_walk(&(*f)->tree, (*f)->collect_enum(), (char*) &tree_info,
693 left_root_right);
694 tmp_str.append(')');
695
696 if (!(*f)->nulls)
697 tmp_str.append(STRING_WITH_LEN(" NOT NULL"));
698 output_str_length = tmp_str.length();
699 func_items[9]->set(tmp_str.ptr(), tmp_str.length(), tmp_str.charset());
700 if (result->send_data(result_fields))
701 goto error;
702 continue;
703 }
704
705 ans.length(0);
706 if (!(*f)->treemem && !(*f)->tree_elements)
707 ans.append(STRING_WITH_LEN("CHAR(0)"));
708 else if ((*f)->item->type() == Item::FIELD_ITEM)
709 {
710 switch (((Item_field*) (*f)->item)->field->real_type())
711 {
712 case MYSQL_TYPE_TIMESTAMP:
713 ans.append(STRING_WITH_LEN("TIMESTAMP"));
714 break;
715 case MYSQL_TYPE_DATETIME:
716 ans.append(STRING_WITH_LEN("DATETIME"));
717 break;
718 case MYSQL_TYPE_DATE:
719 case MYSQL_TYPE_NEWDATE:
720 ans.append(STRING_WITH_LEN("DATE"));
721 break;
722 case MYSQL_TYPE_SET:
723 ans.append(STRING_WITH_LEN("SET"));
724 break;
725 case MYSQL_TYPE_YEAR:
726 ans.append(STRING_WITH_LEN("YEAR"));
727 break;
728 case MYSQL_TYPE_TIME:
729 ans.append(STRING_WITH_LEN("TIME"));
730 break;
731 case MYSQL_TYPE_DECIMAL:
732 ans.append(STRING_WITH_LEN("DECIMAL"));
733 // if item is FIELD_ITEM, it _must_be_ Field_num in this case
734 if (((Field_num*) ((Item_field*) (*f)->item)->field)->zerofill)
735 ans.append(STRING_WITH_LEN(" ZEROFILL"));
736 break;
737 default:
738 (*f)->get_opt_type(&ans, rows);
739 break;
740 }
741 }
742 if (!(*f)->nulls)
743 ans.append(STRING_WITH_LEN(" NOT NULL"));
744 func_items[9]->set(ans.ptr(), ans.length(), ans.charset());
745 if (result->send_data(result_fields))
746 goto error;
747 }
748 ok:
749 return result->send_eof();
750 error:
751 abort_result_set();
752 return true;
753 } // Query_result_analyse::send_eof
754
755
get_opt_type(String * answer,ha_rows total_rows)756 void field_str::get_opt_type(String *answer, ha_rows total_rows)
757 {
758 char buff[MAX_FIELD_WIDTH];
759
760 if (can_be_still_num)
761 {
762 if (num_info.is_float)
763 sprintf(buff, "DOUBLE"); // number was like 1e+50... TODO:
764 else if (num_info.decimals) // DOUBLE(%d,%d) sometime
765 {
766 if (num_info.dval > -FLT_MAX && num_info.dval < FLT_MAX)
767 sprintf(buff, "FLOAT(%d,%d)", (num_info.integers + num_info.decimals), num_info.decimals);
768 else
769 sprintf(buff, "DOUBLE(%d,%d)", (num_info.integers + num_info.decimals), num_info.decimals);
770 }
771 else if (ev_num_info.llval >= -128 &&
772 ev_num_info.ullval <=
773 (ulonglong) (ev_num_info.llval >= 0 ? 255 : 127))
774 sprintf(buff, "TINYINT(%d)", num_info.integers);
775 else if (ev_num_info.llval >= INT_MIN16 &&
776 ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
777 UINT_MAX16 : INT_MAX16))
778 sprintf(buff, "SMALLINT(%d)", num_info.integers);
779 else if (ev_num_info.llval >= INT_MIN24 &&
780 ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
781 UINT_MAX24 : INT_MAX24))
782 sprintf(buff, "MEDIUMINT(%d)", num_info.integers);
783 else if (ev_num_info.llval >= INT_MIN32 &&
784 ev_num_info.ullval <= (ulonglong) (ev_num_info.llval >= 0 ?
785 UINT_MAX32 : INT_MAX32))
786 sprintf(buff, "INT(%d)", num_info.integers);
787 else
788 sprintf(buff, "BIGINT(%d)", num_info.integers);
789 answer->append(buff, strlen(buff));
790 if (ev_num_info.llval >= 0 && ev_num_info.min_dval >= 0)
791 answer->append(STRING_WITH_LEN(" UNSIGNED"));
792 if (num_info.zerofill)
793 answer->append(STRING_WITH_LEN(" ZEROFILL"));
794 }
795 else if (max_length < 256)
796 {
797 if (must_be_blob)
798 {
799 if (item->collation.collation == &my_charset_bin)
800 answer->append(STRING_WITH_LEN("TINYBLOB"));
801 else
802 answer->append(STRING_WITH_LEN("TINYTEXT"));
803 }
804 else if ((max_length * (total_rows - nulls)) < (sum + total_rows))
805 {
806 sprintf(buff, "CHAR(%d)", (int) max_length);
807 answer->append(buff, strlen(buff));
808 }
809 else
810 {
811 sprintf(buff, "VARCHAR(%d)", (int) max_length);
812 answer->append(buff, strlen(buff));
813 }
814 }
815 else if (max_length < (1L << 16))
816 {
817 if (item->collation.collation == &my_charset_bin)
818 answer->append(STRING_WITH_LEN("BLOB"));
819 else
820 answer->append(STRING_WITH_LEN("TEXT"));
821 }
822 else if (max_length < (1L << 24))
823 {
824 if (item->collation.collation == &my_charset_bin)
825 answer->append(STRING_WITH_LEN("MEDIUMBLOB"));
826 else
827 answer->append(STRING_WITH_LEN("MEDIUMTEXT"));
828 }
829 else
830 {
831 if (item->collation.collation == &my_charset_bin)
832 answer->append(STRING_WITH_LEN("LONGBLOB"));
833 else
834 answer->append(STRING_WITH_LEN("LONGTEXT"));
835 }
836 } // field_str::get_opt_type
837
838
get_opt_type(String * answer,ha_rows total_rows MY_ATTRIBUTE ((unused)))839 void field_real::get_opt_type(String *answer,
840 ha_rows total_rows MY_ATTRIBUTE((unused)))
841 {
842 char buff[MAX_FIELD_WIDTH];
843
844 if (!max_notzero_dec_len)
845 {
846 int len= (int) max_length - ((item->decimals == NOT_FIXED_DEC) ?
847 0 : (item->decimals + 1));
848
849 if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127))
850 sprintf(buff, "TINYINT(%d)", len);
851 else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ?
852 UINT_MAX16 : INT_MAX16))
853 sprintf(buff, "SMALLINT(%d)", len);
854 else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ?
855 UINT_MAX24 : INT_MAX24))
856 sprintf(buff, "MEDIUMINT(%d)", len);
857 else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ?
858 UINT_MAX32 : INT_MAX32))
859 sprintf(buff, "INT(%d)", len);
860 else
861 sprintf(buff, "BIGINT(%d)", len);
862 answer->append(buff, strlen(buff));
863 if (min_arg >= 0)
864 answer->append(STRING_WITH_LEN(" UNSIGNED"));
865 }
866 else if (item->decimals == NOT_FIXED_DEC)
867 {
868 if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX)
869 answer->append(STRING_WITH_LEN("FLOAT"));
870 else
871 answer->append(STRING_WITH_LEN("DOUBLE"));
872 }
873 else
874 {
875 if (min_arg >= -FLT_MAX && max_arg <= FLT_MAX)
876 sprintf(buff, "FLOAT(%d,%d)", (int) max_length - (item->decimals + 1) + max_notzero_dec_len,
877 max_notzero_dec_len);
878 else
879 sprintf(buff, "DOUBLE(%d,%d)", (int) max_length - (item->decimals + 1) + max_notzero_dec_len,
880 max_notzero_dec_len);
881 answer->append(buff, strlen(buff));
882 }
883 // if item is FIELD_ITEM, it _must_be_ Field_num in this class
884 if (item->type() == Item::FIELD_ITEM &&
885 // a single number shouldn't be zerofill
886 (max_length - (item->decimals + 1)) != 1 &&
887 ((Field_num*) ((Item_field*) item)->field)->zerofill)
888 answer->append(STRING_WITH_LEN(" ZEROFILL"));
889 } // field_real::get_opt_type
890
891
get_opt_type(String * answer,ha_rows total_rows MY_ATTRIBUTE ((unused)))892 void field_longlong::get_opt_type(String *answer,
893 ha_rows total_rows MY_ATTRIBUTE((unused)))
894 {
895 char buff[MAX_FIELD_WIDTH];
896
897 if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127))
898 sprintf(buff, "TINYINT(%d)", (int) max_length);
899 else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ?
900 UINT_MAX16 : INT_MAX16))
901 sprintf(buff, "SMALLINT(%d)", (int) max_length);
902 else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ?
903 UINT_MAX24 : INT_MAX24))
904 sprintf(buff, "MEDIUMINT(%d)", (int) max_length);
905 else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ?
906 UINT_MAX32 : INT_MAX32))
907 sprintf(buff, "INT(%d)", (int) max_length);
908 else
909 sprintf(buff, "BIGINT(%d)", (int) max_length);
910 answer->append(buff, strlen(buff));
911 if (min_arg >= 0)
912 answer->append(STRING_WITH_LEN(" UNSIGNED"));
913
914 // if item is FIELD_ITEM, it _must_be_ Field_num in this class
915 if ((item->type() == Item::FIELD_ITEM) &&
916 // a single number shouldn't be zerofill
917 max_length != 1 &&
918 ((Field_num*) ((Item_field*) item)->field)->zerofill)
919 answer->append(STRING_WITH_LEN(" ZEROFILL"));
920 } // field_longlong::get_opt_type
921
922
get_opt_type(String * answer,ha_rows total_rows MY_ATTRIBUTE ((unused)))923 void field_ulonglong::get_opt_type(String *answer,
924 ha_rows total_rows MY_ATTRIBUTE((unused)))
925 {
926 char buff[MAX_FIELD_WIDTH];
927
928 if (max_arg < 256)
929 sprintf(buff, "TINYINT(%d) UNSIGNED", (int) max_length);
930 else if (max_arg <= ((2 * INT_MAX16) + 1))
931 sprintf(buff, "SMALLINT(%d) UNSIGNED", (int) max_length);
932 else if (max_arg <= ((2 * INT_MAX24) + 1))
933 sprintf(buff, "MEDIUMINT(%d) UNSIGNED", (int) max_length);
934 else if (max_arg < (((ulonglong) 1) << 32))
935 sprintf(buff, "INT(%d) UNSIGNED", (int) max_length);
936 else
937 sprintf(buff, "BIGINT(%d) UNSIGNED", (int) max_length);
938 // if item is FIELD_ITEM, it _must_be_ Field_num in this class
939 answer->append(buff, strlen(buff));
940 if (item->type() == Item::FIELD_ITEM &&
941 // a single number shouldn't be zerofill
942 max_length != 1 &&
943 ((Field_num*) ((Item_field*) item)->field)->zerofill)
944 answer->append(STRING_WITH_LEN(" ZEROFILL"));
945 } //field_ulonglong::get_opt_type
946
947
get_opt_type(String * answer,ha_rows total_rows MY_ATTRIBUTE ((unused)))948 void field_decimal::get_opt_type(String *answer,
949 ha_rows total_rows MY_ATTRIBUTE((unused)))
950 {
951 my_decimal zero;
952 char buff[MAX_FIELD_WIDTH];
953 size_t length;
954
955 my_decimal_set_zero(&zero);
956 my_bool is_unsigned= (my_decimal_cmp(&zero, &min_arg) >= 0);
957
958 length= my_snprintf(buff, sizeof(buff), "DECIMAL(%d, %d)",
959 static_cast<int>(max_length - (item->decimals ? 1 : 0)),
960 static_cast<int>(item->decimals));
961 if (is_unsigned)
962 length= (my_stpcpy(buff+length, " UNSIGNED")- buff);
963 answer->append(buff, length);
964 }
965
966
get_min_arg(String * str)967 String *field_decimal::get_min_arg(String *str)
968 {
969 my_decimal2string(E_DEC_FATAL_ERROR, &min_arg, 0, 0, '0', str);
970 return str;
971 }
972
973
get_max_arg(String * str)974 String *field_decimal::get_max_arg(String *str)
975 {
976 my_decimal2string(E_DEC_FATAL_ERROR, &max_arg, 0, 0, '0', str);
977 return str;
978 }
979
980
avg(String * s,ha_rows rows)981 String *field_decimal::avg(String *s, ha_rows rows)
982 {
983 if (!(rows - nulls))
984 {
985 s->set_real(0.0, 1,my_thd_charset);
986 return s;
987 }
988 my_decimal num, avg_val, rounded_avg;
989 int prec_increment= current_thd->variables.div_precincrement;
990
991 int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
992 my_decimal_div(E_DEC_FATAL_ERROR, &avg_val, sum+cur_sum, &num, prec_increment);
993 /* TODO remove this after decimal_div returns proper frac */
994 my_decimal_round(E_DEC_FATAL_ERROR, &avg_val,
995 min(sum[cur_sum].frac + prec_increment, DECIMAL_MAX_SCALE),
996 FALSE,&rounded_avg);
997 my_decimal2string(E_DEC_FATAL_ERROR, &rounded_avg, 0, 0, '0', s);
998 return s;
999 }
1000
1001
std(String * s,ha_rows rows)1002 String *field_decimal::std(String *s, ha_rows rows)
1003 {
1004 if (!(rows - nulls))
1005 {
1006 s->set_real(0.0, 1,my_thd_charset);
1007 return s;
1008 }
1009 my_decimal num, tmp, sum2, sum2d;
1010 double std_sqr;
1011 int prec_increment= current_thd->variables.div_precincrement;
1012
1013 int2my_decimal(E_DEC_FATAL_ERROR, rows - nulls, FALSE, &num);
1014 my_decimal_mul(E_DEC_FATAL_ERROR, &sum2, sum+cur_sum, sum+cur_sum);
1015 my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment);
1016 my_decimal_sub(E_DEC_FATAL_ERROR, &sum2, sum_sqr+cur_sum, &tmp);
1017 my_decimal_div(E_DEC_FATAL_ERROR, &tmp, &sum2, &num, prec_increment);
1018 my_decimal2double(E_DEC_FATAL_ERROR, &tmp, &std_sqr);
1019 s->set_real((std_sqr <= 0.0 ? 0.0 : sqrt(std_sqr)),
1020 min(item->decimals + prec_increment, NOT_FIXED_DEC), my_thd_charset);
1021
1022 return s;
1023 }
1024
1025
collect_string(String * element,element_count count MY_ATTRIBUTE ((unused)),TREE_INFO * info)1026 int collect_string(String *element,
1027 element_count count MY_ATTRIBUTE((unused)),
1028 TREE_INFO *info)
1029 {
1030 if (info->found)
1031 info->str->append(',');
1032 else
1033 info->found = 1;
1034 info->str->append('\'');
1035 if (append_escaped(info->str, element))
1036 return 1;
1037 info->str->append('\'');
1038 return 0;
1039 } // collect_string
1040
1041
collect_real(double * element,element_count count MY_ATTRIBUTE ((unused)),TREE_INFO * info)1042 int collect_real(double *element, element_count count MY_ATTRIBUTE((unused)),
1043 TREE_INFO *info)
1044 {
1045 char buff[MAX_FIELD_WIDTH];
1046 String s(buff, sizeof(buff),current_thd->charset());
1047
1048 if (info->found)
1049 info->str->append(',');
1050 else
1051 info->found = 1;
1052 info->str->append('\'');
1053 s.set_real(*element, info->item->decimals, current_thd->charset());
1054 info->str->append(s);
1055 info->str->append('\'');
1056 return 0;
1057 } // collect_real
1058
1059
collect_decimal(uchar * element,element_count count,TREE_INFO * info)1060 int collect_decimal(uchar *element, element_count count,
1061 TREE_INFO *info)
1062 {
1063 char buff[DECIMAL_MAX_STR_LENGTH + 1];
1064 String s(buff, sizeof(buff),&my_charset_bin);
1065
1066 if (info->found)
1067 info->str->append(',');
1068 else
1069 info->found = 1;
1070 my_decimal dec;
1071 binary2my_decimal(E_DEC_FATAL_ERROR, element, &dec,
1072 info->item->max_length, info->item->decimals);
1073
1074 info->str->append('\'');
1075 my_decimal2string(E_DEC_FATAL_ERROR, &dec, 0, 0, '0', &s);
1076 info->str->append(s);
1077 info->str->append('\'');
1078 return 0;
1079 }
1080
1081
collect_longlong(longlong * element,element_count count MY_ATTRIBUTE ((unused)),TREE_INFO * info)1082 int collect_longlong(longlong *element,
1083 element_count count MY_ATTRIBUTE((unused)),
1084 TREE_INFO *info)
1085 {
1086 char buff[MAX_FIELD_WIDTH];
1087 String s(buff, sizeof(buff),&my_charset_bin);
1088
1089 if (info->found)
1090 info->str->append(',');
1091 else
1092 info->found = 1;
1093 info->str->append('\'');
1094 s.set(*element, current_thd->charset());
1095 info->str->append(s);
1096 info->str->append('\'');
1097 return 0;
1098 } // collect_longlong
1099
1100
collect_ulonglong(ulonglong * element,element_count count MY_ATTRIBUTE ((unused)),TREE_INFO * info)1101 int collect_ulonglong(ulonglong *element,
1102 element_count count MY_ATTRIBUTE((unused)),
1103 TREE_INFO *info)
1104 {
1105 char buff[MAX_FIELD_WIDTH];
1106 String s(buff, sizeof(buff),&my_charset_bin);
1107
1108 if (info->found)
1109 info->str->append(',');
1110 else
1111 info->found = 1;
1112 info->str->append('\'');
1113 s.set(*element, current_thd->charset());
1114 info->str->append(s);
1115 info->str->append('\'');
1116 return 0;
1117 } // collect_ulonglong
1118
1119
1120 /**
1121 Create items for substituted output columns (both metadata and data)
1122 */
change_columns()1123 bool Query_result_analyse::change_columns()
1124 {
1125 func_items[0] = new Item_proc_string("Field_name", 255);
1126 func_items[1] = new Item_proc_string("Min_value", 255);
1127 func_items[1]->maybe_null = 1;
1128 func_items[2] = new Item_proc_string("Max_value", 255);
1129 func_items[2]->maybe_null = 1;
1130 func_items[3] = new Item_proc_int("Min_length");
1131 func_items[4] = new Item_proc_int("Max_length");
1132 func_items[5] = new Item_proc_int("Empties_or_zeros");
1133 func_items[6] = new Item_proc_int("Nulls");
1134 func_items[7] = new Item_proc_string("Avg_value_or_avg_length", 255);
1135 func_items[8] = new Item_proc_string("Std", 255);
1136 func_items[8]->maybe_null = 1;
1137 func_items[9] = new Item_proc_string("Optimal_fieldtype",
1138 max<size_t>(64U, output_str_length));
1139 result_fields.empty();
1140 for (uint i = 0; i < array_elements(func_items); i++)
1141 {
1142 if (func_items[i] == NULL)
1143 return true;
1144 result_fields.push_back(func_items[i]);
1145 }
1146 return false;
1147 } // Query_result_analyse::change_columns
1148
1149
cleanup()1150 void Query_result_analyse::cleanup()
1151 {
1152 if (f_info)
1153 {
1154 for (field_info **f= f_info; f != f_end; f++)
1155 delete (*f);
1156 f_info= f_end= NULL;
1157 }
1158 rows= 0;
1159 output_str_length= 0;
1160 }
1161
1162
send_result_set_metadata(List<Item> & fields,uint flag)1163 bool Query_result_analyse::send_result_set_metadata(List<Item> &fields,
1164 uint flag)
1165 {
1166 return (init(fields) || change_columns() ||
1167 result->send_result_set_metadata(result_fields, flag));
1168 }
1169
1170
abort_result_set()1171 void Query_result_analyse::abort_result_set()
1172 {
1173 cleanup();
1174 return result->abort_result_set();
1175 }
1176
1177
compare_double(const double * s,const double * t)1178 int compare_double(const double *s, const double *t)
1179 {
1180 return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
1181 } /* compare_double */
1182
compare_longlong(const longlong * s,const longlong * t)1183 int compare_longlong(const longlong *s, const longlong *t)
1184 {
1185 return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
1186 } /* compare_longlong */
1187
compare_ulonglong(const ulonglong * s,const ulonglong * t)1188 int compare_ulonglong(const ulonglong *s, const ulonglong *t)
1189 {
1190 return ((*s < *t) ? -1 : *s > *t ? 1 : 0);
1191 } /* compare_ulonglong */
1192
1193
check_ulonglong(const char * str,uint length)1194 uint check_ulonglong(const char *str, uint length)
1195 {
1196 const char *long_str = "2147483647", *ulonglong_str = "18446744073709551615";
1197 const uint long_len = 10, ulonglong_len = 20;
1198
1199 while (*str == '0' && length)
1200 {
1201 str++; length--;
1202 }
1203 if (length < long_len)
1204 return NUM;
1205
1206 uint smaller, bigger;
1207 const char *cmp;
1208
1209 if (length == long_len)
1210 {
1211 cmp = long_str;
1212 smaller = NUM;
1213 bigger = LONG_NUM;
1214 }
1215 else if (length > ulonglong_len)
1216 return DECIMAL_NUM;
1217 else
1218 {
1219 cmp = ulonglong_str;
1220 smaller = LONG_NUM;
1221 bigger = DECIMAL_NUM;
1222 }
1223 while (*cmp && *cmp++ == *str++) ;
1224 return ((uchar) str[-1] <= (uchar) cmp[-1]) ? smaller : bigger;
1225 } /* check_ulonlong */
1226
1227
1228 /*
1229 Quote special characters in a string.
1230
1231 SYNOPSIS
1232 append_escaped(to_str, from_str)
1233 to_str (in) A pointer to a String.
1234 from_str (to) A pointer to an allocated string
1235
1236 DESCRIPTION
1237 append_escaped() takes a String type variable, where it appends
1238 escaped the second argument. Only characters that require escaping
1239 will be escaped.
1240
1241 RETURN VALUES
1242 0 Success
1243 1 Out of memory
1244 */
1245
append_escaped(String * to_str,String * from_str)1246 bool append_escaped(String *to_str, String *from_str)
1247 {
1248 char *from, *end, c;
1249
1250 if (to_str->mem_realloc(to_str->length() + from_str->length()))
1251 return 1;
1252
1253 from= (char*) from_str->ptr();
1254 end= from + from_str->length();
1255 for (; from < end; from++)
1256 {
1257 c= *from;
1258 switch (c) {
1259 case '\0':
1260 c= '0';
1261 break;
1262 case '\032':
1263 c= 'Z';
1264 break;
1265 case '\\':
1266 case '\'':
1267 break;
1268 default:
1269 goto normal_character;
1270 }
1271 if (to_str->append('\\'))
1272 return 1;
1273
1274 normal_character:
1275 if (to_str->append(c))
1276 return 1;
1277 }
1278 return 0;
1279 }
1280
1281