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