1 #ifndef SQL_ANALYSE_INCLUDED
2 #define SQL_ANALYSE_INCLUDED
3 
4 /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License, version 2.0,
8    as published by the Free Software Foundation.
9 
10    This program is also distributed with certain software (including
11    but not limited to OpenSSL) that is licensed under separate terms,
12    as designated in a particular file or component or in included license
13    documentation.  The authors of MySQL hereby grant you an additional
14    permission to link the program and your derivative works with the
15    separately licensed software that they have included with MySQL.
16 
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License, version 2.0, for more details.
21 
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software Foundation,
24    51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
25 
26 
27 /* Analyse database */
28 
29 #include "procedure.h"                          /* Procedure */
30 
31 #define my_thd_charset	default_charset_info
32 
33 #define DEC_IN_AVG 4
34 
35 typedef struct st_number_info
36 {
37   // if zerofill is true, the number must be zerofill, or string
38   bool	    negative, is_float, zerofill, maybe_zerofill;
39   int8	    integers;
40   int8	    decimals;
41   double    dval;
42   ulonglong ullval;
43 } NUM_INFO;
44 
45 typedef struct st_extreme_value_number_info
46 {
47   ulonglong ullval;
48   longlong  llval;
49   double    max_dval, min_dval;
50 } EV_NUM_INFO;
51 
52 typedef struct st_tree_info
53 {
54   bool	 found;
55   String *str;
56   Item	 *item;
57 } TREE_INFO;
58 
59 uint check_ulonglong(const char *str, uint length);
60 bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num);
61 bool test_if_number(NUM_INFO *info, const char *str, uint str_len);
62 int compare_double(const double *s, const double *t);
63 int compare_double2(void* cmp_arg MY_ATTRIBUTE((unused)),
64 		    const double *s, const double *t);
65 int compare_longlong(const longlong *s, const longlong *t);
66 int compare_longlong2(void* cmp_arg MY_ATTRIBUTE((unused)),
67 		      const longlong *s, const longlong *t);
68 int compare_ulonglong(const ulonglong *s, const ulonglong *t);
69 int compare_ulonglong2(void* cmp_arg MY_ATTRIBUTE((unused)),
70 		       const ulonglong *s, const ulonglong *t);
71 int compare_decimal2(int* len, const char *s, const char *t);
72 void free_string(String*);
73 class select_analyse;
74 
75 class field_info :public Sql_alloc
76 {
77 protected:
78   ulong   treemem, tree_elements, empty, nulls, min_length, max_length;
79   uint	  room_in_tree;
80   my_bool found;
81   TREE	  tree;
82   Item	  *item;
83   select_analyse *pc;
84 
85 public:
field_info(Item * a,select_analyse * b)86   field_info(Item* a, select_analyse* b)
87   : treemem(0), tree_elements(0), empty(0),
88     nulls(0), min_length(0), max_length(0), room_in_tree(1),
89     found(0),item(a), pc(b) {};
90 
~field_info()91   virtual ~field_info() { delete_tree(&tree); }
92   virtual void	 add() = 0;
93   virtual void	 get_opt_type(String*, ha_rows) = 0;
94   virtual String *get_min_arg(String *) = 0;
95   virtual String *get_max_arg(String *) = 0;
96   virtual String *avg(String*, ha_rows) = 0;
97   virtual String *std(String*, ha_rows) = 0;
98   virtual tree_walk_action collect_enum() = 0;
decimals()99   virtual uint decimals() { return 0; }
100   friend  class select_analyse;
101 };
102 
103 
104 int collect_string(String *element, element_count count,
105 		   TREE_INFO *info);
106 
107 int sortcmp2(void* cmp_arg MY_ATTRIBUTE((unused)),
108 	     const String *a,const String *b);
109 
110 class field_str :public field_info
111 {
112   String      min_arg, max_arg;
113   ulonglong   sum;
114   bool	      must_be_blob, was_zero_fill, was_maybe_zerofill,
115 	      can_be_still_num;
116   NUM_INFO    num_info;
117   EV_NUM_INFO ev_num_info;
118 
119 public:
field_str(Item * a,select_analyse * b)120   field_str(Item* a, select_analyse* b) :field_info(a,b),
121     min_arg("",default_charset_info),
122     max_arg("",default_charset_info), sum(0),
123     must_be_blob(0), was_zero_fill(0),
124     was_maybe_zerofill(0), can_be_still_num(1)
125     { init_tree(&tree, 0, 0, sizeof(String), (qsort_cmp2) sortcmp2,
126 		0, (tree_element_free) free_string, NULL); };
127 
128   void	 add();
129   void	 get_opt_type(String*, ha_rows);
get_min_arg(String * not_used MY_ATTRIBUTE ((unused)))130   String *get_min_arg(String *not_used MY_ATTRIBUTE((unused)))
131   { return &min_arg; }
get_max_arg(String * not_used MY_ATTRIBUTE ((unused)))132   String *get_max_arg(String *not_used MY_ATTRIBUTE((unused)))
133   { return &max_arg; }
avg(String * s,ha_rows rows)134   String *avg(String *s, ha_rows rows)
135   {
136     if (!(rows - nulls))
137       s->set_real((double) 0.0, 1,my_thd_charset);
138     else
139       s->set_real((ulonglong2double(sum) / ulonglong2double(rows - nulls)),
140 	     DEC_IN_AVG,my_thd_charset);
141     return s;
142   }
143   friend int collect_string(String *element, element_count count,
144 			    TREE_INFO *info);
collect_enum()145   tree_walk_action collect_enum()
146   { return (tree_walk_action) collect_string; }
std(String * s MY_ATTRIBUTE ((unused)),ha_rows rows MY_ATTRIBUTE ((unused)))147   String *std(String *s MY_ATTRIBUTE((unused)),
148 	      ha_rows rows MY_ATTRIBUTE((unused)))
149   { return (String*) 0; }
150 };
151 
152 
153 int collect_decimal(uchar *element, element_count count,
154                     TREE_INFO *info);
155 
156 class field_decimal :public field_info
157 {
158   my_decimal min_arg, max_arg;
159   my_decimal sum[2], sum_sqr[2];
160   int cur_sum;
161   int bin_size;
162 public:
field_decimal(Item * a,select_analyse * b)163   field_decimal(Item* a, select_analyse* b) :field_info(a,b)
164   {
165     bin_size= my_decimal_get_binary_size(a->max_length, a->decimals);
166     init_tree(&tree, 0, 0, bin_size, (qsort_cmp2)compare_decimal2,
167               0, 0, (void *)&bin_size);
168   };
169 
170   void	 add();
171   void	 get_opt_type(String*, ha_rows);
172   String *get_min_arg(String *);
173   String *get_max_arg(String *);
174   String *avg(String *s, ha_rows rows);
175   friend int collect_decimal(uchar *element, element_count count,
176                              TREE_INFO *info);
collect_enum()177   tree_walk_action collect_enum()
178   { return (tree_walk_action) collect_decimal; }
179   String *std(String *s, ha_rows rows);
180 };
181 
182 
183 int collect_real(double *element, element_count count, TREE_INFO *info);
184 
185 class field_real: public field_info
186 {
187   double min_arg, max_arg;
188   double sum, sum_sqr;
189   uint	 max_notzero_dec_len;
190 
191 public:
field_real(Item * a,select_analyse * b)192   field_real(Item* a, select_analyse* b) :field_info(a,b),
193     min_arg(0), max_arg(0),  sum(0), sum_sqr(0), max_notzero_dec_len(0)
194     { init_tree(&tree, 0, 0, sizeof(double),
195 		(qsort_cmp2) compare_double2, 0, NULL, NULL); }
196 
197   void	 add();
198   void	 get_opt_type(String*, ha_rows);
get_min_arg(String * s)199   String *get_min_arg(String *s)
200   {
201     s->set_real(min_arg, item->decimals, my_thd_charset);
202     return s;
203   }
get_max_arg(String * s)204   String *get_max_arg(String *s)
205   {
206     s->set_real(max_arg, item->decimals, my_thd_charset);
207     return s;
208   }
avg(String * s,ha_rows rows)209   String *avg(String *s, ha_rows rows)
210   {
211     if (!(rows - nulls))
212       s->set_real((double) 0.0, 1,my_thd_charset);
213     else
214       s->set_real(((double)sum / (double) (rows - nulls)), item->decimals,my_thd_charset);
215     return s;
216   }
std(String * s,ha_rows rows)217   String *std(String *s, ha_rows rows)
218   {
219     double tmp = ulonglong2double(rows);
220     if (!(tmp - nulls))
221       s->set_real((double) 0.0, 1,my_thd_charset);
222     else
223     {
224       double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) /
225 		     (tmp - nulls));
226       s->set_real(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), item->decimals,my_thd_charset);
227     }
228     return s;
229   }
decimals()230   uint	 decimals() { return item->decimals; }
231   friend int collect_real(double *element, element_count count,
232 			  TREE_INFO *info);
collect_enum()233   tree_walk_action collect_enum()
234   { return (tree_walk_action) collect_real;}
235 };
236 
237 int collect_longlong(longlong *element, element_count count,
238 		     TREE_INFO *info);
239 
240 class field_longlong: public field_info
241 {
242   longlong min_arg, max_arg;
243   longlong sum, sum_sqr;
244 
245 public:
field_longlong(Item * a,select_analyse * b)246   field_longlong(Item* a, select_analyse* b) :field_info(a,b),
247     min_arg(0), max_arg(0), sum(0), sum_sqr(0)
248     { init_tree(&tree, 0, 0, sizeof(longlong),
249 		(qsort_cmp2) compare_longlong2, 0, NULL, NULL); }
250 
251   void	 add();
252   void	 get_opt_type(String*, ha_rows);
get_min_arg(String * s)253   String *get_min_arg(String *s) { s->set(min_arg,my_thd_charset); return s; }
get_max_arg(String * s)254   String *get_max_arg(String *s) { s->set(max_arg,my_thd_charset); return s; }
avg(String * s,ha_rows rows)255   String *avg(String *s, ha_rows rows)
256   {
257     if (!(rows - nulls))
258       s->set_real((double) 0.0, 1,my_thd_charset);
259     else
260       s->set_real(((double) sum / (double) (rows - nulls)), DEC_IN_AVG,my_thd_charset);
261     return s;
262   }
std(String * s,ha_rows rows)263   String *std(String *s, ha_rows rows)
264   {
265     double tmp = ulonglong2double(rows);
266     if (!(tmp - nulls))
267       s->set_real((double) 0.0, 1,my_thd_charset);
268     else
269     {
270       double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) /
271 		    (tmp - nulls));
272       s->set_real(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset);
273     }
274     return s;
275   }
276   friend int collect_longlong(longlong *element, element_count count,
277 			      TREE_INFO *info);
collect_enum()278   tree_walk_action collect_enum()
279   { return (tree_walk_action) collect_longlong;}
280 };
281 
282 int collect_ulonglong(ulonglong *element, element_count count,
283 		      TREE_INFO *info);
284 
285 class field_ulonglong: public field_info
286 {
287   ulonglong min_arg, max_arg;
288   ulonglong sum, sum_sqr;
289 
290 public:
field_ulonglong(Item * a,select_analyse * b)291   field_ulonglong(Item* a, select_analyse * b) :field_info(a,b),
292     min_arg(0), max_arg(0), sum(0),sum_sqr(0)
293     { init_tree(&tree, 0, 0, sizeof(ulonglong),
294 		(qsort_cmp2) compare_ulonglong2, 0, NULL, NULL); }
295   void	 add();
296   void	 get_opt_type(String*, ha_rows);
get_min_arg(String * s)297   String *get_min_arg(String *s) { s->set(min_arg,my_thd_charset); return s; }
get_max_arg(String * s)298   String *get_max_arg(String *s) { s->set(max_arg,my_thd_charset); return s; }
avg(String * s,ha_rows rows)299   String *avg(String *s, ha_rows rows)
300   {
301     if (!(rows - nulls))
302       s->set_real((double) 0.0, 1,my_thd_charset);
303     else
304       s->set_real((ulonglong2double(sum) / ulonglong2double(rows - nulls)),
305 	     DEC_IN_AVG,my_thd_charset);
306     return s;
307   }
std(String * s,ha_rows rows)308   String *std(String *s, ha_rows rows)
309   {
310     double tmp = ulonglong2double(rows);
311     if (!(tmp - nulls))
312       s->set_real((double) 0.0, 1,my_thd_charset);
313     else
314     {
315       double tmp2 = ((ulonglong2double(sum_sqr) -
316 		     ulonglong2double(sum * sum) / (tmp - nulls)) /
317 		     (tmp - nulls));
318       s->set_real(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset);
319     }
320     return s;
321   }
322   friend int collect_ulonglong(ulonglong *element, element_count count,
323 			       TREE_INFO *info);
collect_enum()324   tree_walk_action collect_enum()
325   { return (tree_walk_action) collect_ulonglong; }
326 };
327 
328 
329 /**
330   Interceptor class to form SELECT ... PROCEDURE ANALYSE() output rows
331 */
332 
333 class select_analyse : public select_send
334 {
335   select_result *result; //< real output stream
336 
337   Item_proc    *func_items[10]; //< items for output metadata and column data
338   List<Item>   result_fields; //< same as func_items but capable for send_data()
339   field_info   **f_info, **f_end; //< bounds for column data accumulator array
340 
341   ha_rows      rows; //< counter of original SELECT query output rows
342   uint	       output_str_length; //< max.width for the Optimal_fieldtype column
343 
344 public:
345   const uint max_tree_elements; //< maximum number of distinct values per column
346   const uint max_treemem; //< maximum amount of memory to allocate per column
347 
348 public:
select_analyse(select_result * result,const Proc_analyse_params * params)349   select_analyse(select_result *result, const Proc_analyse_params *params)
350   : result(result), f_info(NULL), f_end(NULL), rows(0), output_str_length(0),
351     max_tree_elements(params->max_tree_elements),
352     max_treemem(params->max_treemem)
353   {}
354 
~select_analyse()355   ~select_analyse() { cleanup(); }
356 
357   virtual void cleanup();
field_count(List<Item> &)358   virtual uint field_count(List<Item> &) const
359   { return array_elements(func_items); }
prepare(List<Item> & list,SELECT_LEX_UNIT * u)360   virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u)
361   { return result->prepare(list, u); }
362   virtual bool send_result_set_metadata(List<Item> &fields, uint flag);
363   virtual bool send_data(List<Item> &items);
364   virtual bool send_eof();
365   virtual void abort_result_set();
366 
367 private:
368   bool init(List<Item> &field_list);
369   bool change_columns();
370 };
371 
372 bool append_escaped(String *to_str, String *from_str);
373 
374 #endif /* SQL_ANALYSE_INCLUDED */
375