1 #ifndef SQL_ANALYSE_INCLUDED
2 #define SQL_ANALYSE_INCLUDED
3 
4 /* Copyright (c) 2000, 2010, 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 as published by
8    the Free Software Foundation; version 2 of the License.
9 
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14 
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
18 
19 
20 /* Analyse database */
21 
22 #ifdef USE_PRAGMA_INTERFACE
23 #pragma interface				/* gcc class implementation */
24 #endif
25 
26 #include "procedure.h"                          /* Procedure */
27 
28 #define my_thd_charset	default_charset_info
29 
30 #define DEC_IN_AVG 4
31 
32 typedef struct st_number_info
33 {
34   // if zerofill is true, the number must be zerofill, or string
35   bool	    negative, is_float, zerofill, maybe_zerofill;
36   int8	    integers;
37   int8	    decimals;
38   double    dval;
39   ulonglong ullval;
40 } NUM_INFO;
41 
42 typedef struct st_extreme_value_number_info
43 {
44   ulonglong ullval;
45   longlong  llval;
46   double    max_dval, min_dval;
47 } EV_NUM_INFO;
48 
49 typedef struct st_tree_info
50 {
51   bool	 found;
52   String *str;
53   Item	 *item;
54 } TREE_INFO;
55 
56 uint check_ulonglong(const char *str, uint length);
57 bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num);
58 bool test_if_number(NUM_INFO *info, const char *str, uint str_len);
59 int compare_double(const double *s, const double *t);
60 int compare_double2(void* cmp_arg __attribute__((unused)),
61 		    const double *s, const double *t);
62 int compare_longlong(const longlong *s, const longlong *t);
63 int compare_longlong2(void* cmp_arg __attribute__((unused)),
64 		      const longlong *s, const longlong *t);
65 int compare_ulonglong(const ulonglong *s, const ulonglong *t);
66 int compare_ulonglong2(void* cmp_arg __attribute__((unused)),
67 		       const ulonglong *s, const ulonglong *t);
68 int compare_decimal2(int* len, const char *s, const char *t);
69 Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result,
70 			     List<Item> &field_list);
71 int free_string(void* str, TREE_FREE, void*);
72 class analyse;
73 
74 class field_info :public Sql_alloc
75 {
76 protected:
77   ulong   treemem, tree_elements, empty, nulls, min_length, max_length;
78   uint	  room_in_tree;
79   bool found;
80   TREE	  tree;
81   Item	  *item;
82   analyse *pc;
83 
84 public:
field_info(Item * a,analyse * b)85   field_info(Item* a, analyse* b) : treemem(0), tree_elements(0), empty(0),
86     nulls(0), min_length(0), max_length(0), room_in_tree(1),
87     found(0),item(a), pc(b) {};
88 
~field_info()89   virtual ~field_info() { delete_tree(&tree, 0); }
90   virtual void	 add() = 0;
91   virtual void	 get_opt_type(String*, ha_rows) = 0;
92   virtual String *get_min_arg(String *) = 0;
93   virtual String *get_max_arg(String *) = 0;
94   virtual String *avg(String*, ha_rows) = 0;
95   virtual String *std(String*, ha_rows) = 0;
96   virtual tree_walk_action collect_enum() = 0;
decimals()97   virtual uint decimals() { return 0; }
98   friend  class analyse;
99 };
100 
101 
102 int collect_string(String *element, element_count count,
103 		   TREE_INFO *info);
104 
105 int sortcmp2(void* cmp_arg __attribute__((unused)),
106 	     const String *a,const String *b);
107 
108 class field_str :public field_info
109 {
110   String      min_arg, max_arg;
111   ulonglong   sum;
112   bool	      must_be_blob, was_zero_fill, was_maybe_zerofill,
113 	      can_be_still_num;
114   NUM_INFO    num_info;
115   EV_NUM_INFO ev_num_info;
116 
117 public:
field_str(Item * a,analyse * b)118   field_str(Item* a, analyse* b) :field_info(a,b),
119     min_arg("",default_charset_info),
120     max_arg("",default_charset_info), sum(0),
121     must_be_blob(0), was_zero_fill(0),
122     was_maybe_zerofill(0), can_be_still_num(1)
123     { init_tree(&tree, 0, 0, sizeof(String), (qsort_cmp2) sortcmp2,
124 		free_string, NULL, MYF(MY_THREAD_SPECIFIC)); };
125 
126   void	 add();
127   void	 get_opt_type(String*, ha_rows);
get_min_arg(String * not_used)128   String *get_min_arg(String *not_used __attribute__((unused)))
129   { return &min_arg; }
get_max_arg(String * not_used)130   String *get_max_arg(String *not_used __attribute__((unused)))
131   { return &max_arg; }
avg(String * s,ha_rows rows)132   String *avg(String *s, ha_rows rows)
133   {
134     if (!(rows - nulls))
135       s->set_real((double) 0.0, 1,my_thd_charset);
136     else
137       s->set_real((ulonglong2double(sum) / ulonglong2double(rows - nulls)),
138 	     DEC_IN_AVG,my_thd_charset);
139     return s;
140   }
141   friend int collect_string(String *element, element_count count,
142 			    TREE_INFO *info);
collect_enum()143   tree_walk_action collect_enum()
144   { return (tree_walk_action) collect_string; }
std(String * s,ha_rows rows)145   String *std(String *s __attribute__((unused)),
146 	      ha_rows rows __attribute__((unused)))
147   { return (String*) 0; }
148 };
149 
150 
151 int collect_decimal(uchar *element, element_count count,
152                     TREE_INFO *info);
153 
154 class field_decimal :public field_info
155 {
156   my_decimal min_arg, max_arg;
157   my_decimal sum[2], sum_sqr[2];
158   int cur_sum;
159   int bin_size;
160 public:
field_decimal(Item * a,analyse * b)161   field_decimal(Item* a, analyse* b) :field_info(a,b)
162   {
163     bin_size= my_decimal_get_binary_size(a->max_length, a->decimals);
164     init_tree(&tree, 0, 0, bin_size, (qsort_cmp2)compare_decimal2,
165               0, (void *)&bin_size, MYF(MY_THREAD_SPECIFIC));
166   };
167 
168   void	 add();
169   void	 get_opt_type(String*, ha_rows);
170   String *get_min_arg(String *);
171   String *get_max_arg(String *);
172   String *avg(String *s, ha_rows rows);
173   friend int collect_decimal(uchar *element, element_count count,
174                              TREE_INFO *info);
collect_enum()175   tree_walk_action collect_enum()
176   { return (tree_walk_action) collect_decimal; }
177   String *std(String *s, ha_rows rows);
178 };
179 
180 
181 int collect_real(double *element, element_count count, TREE_INFO *info);
182 
183 class field_real: public field_info
184 {
185   double min_arg, max_arg;
186   double sum, sum_sqr;
187   uint	 max_notzero_dec_len;
188 
189 public:
field_real(Item * a,analyse * b)190   field_real(Item* a, analyse* b) :field_info(a,b),
191     min_arg(0), max_arg(0),  sum(0), sum_sqr(0), max_notzero_dec_len(0)
192     { init_tree(&tree, 0, 0, sizeof(double),
193 		(qsort_cmp2) compare_double2, NULL, NULL,
194                 MYF(MY_THREAD_SPECIFIC)); }
195 
196   void	 add();
197   void	 get_opt_type(String*, ha_rows);
get_min_arg(String * s)198   String *get_min_arg(String *s)
199   {
200     s->set_real(min_arg, item->decimals, my_thd_charset);
201     return s;
202   }
get_max_arg(String * s)203   String *get_max_arg(String *s)
204   {
205     s->set_real(max_arg, item->decimals, my_thd_charset);
206     return s;
207   }
avg(String * s,ha_rows rows)208   String *avg(String *s, ha_rows rows)
209   {
210     if (!(rows - nulls))
211       s->set_real((double) 0.0, 1,my_thd_charset);
212     else
213       s->set_real(((double)sum / (double) (rows - nulls)), item->decimals,my_thd_charset);
214     return s;
215   }
std(String * s,ha_rows rows)216   String *std(String *s, ha_rows rows)
217   {
218     double tmp = ulonglong2double(rows);
219     if (!(tmp - nulls))
220       s->set_real((double) 0.0, 1,my_thd_charset);
221     else
222     {
223       double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) /
224 		     (tmp - nulls));
225       s->set_real(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), item->decimals,my_thd_charset);
226     }
227     return s;
228   }
decimals()229   uint	 decimals() { return item->decimals; }
230   friend int collect_real(double *element, element_count count,
231 			  TREE_INFO *info);
collect_enum()232   tree_walk_action collect_enum()
233   { return (tree_walk_action) collect_real;}
234 };
235 
236 int collect_longlong(longlong *element, element_count count,
237 		     TREE_INFO *info);
238 
239 class field_longlong: public field_info
240 {
241   longlong min_arg, max_arg;
242   longlong sum, sum_sqr;
243 
244 public:
field_longlong(Item * a,analyse * b)245   field_longlong(Item* a, analyse* b) :field_info(a,b),
246     min_arg(0), max_arg(0), sum(0), sum_sqr(0)
247     { init_tree(&tree, 0, 0, sizeof(longlong),
248 		(qsort_cmp2) compare_longlong2, NULL, NULL,
249                 MYF(MY_THREAD_SPECIFIC)); }
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,analyse * b)291   field_ulonglong(Item* a, 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, NULL, NULL,
295                 MYF(MY_THREAD_SPECIFIC)); }
296   void	 add();
297   void	 get_opt_type(String*, ha_rows);
get_min_arg(String * s)298   String *get_min_arg(String *s) { s->set(min_arg,my_thd_charset); return s; }
get_max_arg(String * s)299   String *get_max_arg(String *s) { s->set(max_arg,my_thd_charset); return s; }
avg(String * s,ha_rows rows)300   String *avg(String *s, ha_rows rows)
301   {
302     if (!(rows - nulls))
303       s->set_real((double) 0.0, 1,my_thd_charset);
304     else
305       s->set_real((ulonglong2double(sum) / ulonglong2double(rows - nulls)),
306 	     DEC_IN_AVG,my_thd_charset);
307     return s;
308   }
std(String * s,ha_rows rows)309   String *std(String *s, ha_rows rows)
310   {
311     double tmp = ulonglong2double(rows);
312     if (!(tmp - nulls))
313       s->set_real((double) 0.0, 1,my_thd_charset);
314     else
315     {
316       double tmp2 = ((ulonglong2double(sum_sqr) -
317 		     ulonglong2double(sum * sum) / (tmp - nulls)) /
318 		     (tmp - nulls));
319       s->set_real(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset);
320     }
321     return s;
322   }
323   friend int collect_ulonglong(ulonglong *element, element_count count,
324 			       TREE_INFO *info);
collect_enum()325   tree_walk_action collect_enum()
326   { return (tree_walk_action) collect_ulonglong; }
327 };
328 
329 
330 Procedure *proc_analyse_init(THD *thd, ORDER *param,
331 			     select_result *result,
332 			     List<Item> &field_list);
333 
334 class analyse: public Procedure
335 {
336 protected:
337   Item_proc    *func_items[10];
338   List<Item>   fields, result_fields;
339   field_info   **f_info, **f_end;
340   ha_rows      rows;
341   uint	       output_str_length;
342 
343 public:
344   uint max_tree_elements, max_treemem;
345 
analyse(select_result * res)346   analyse(select_result *res) :Procedure(res, PROC_NO_SORT), f_info(0),
347     rows(0), output_str_length(0) {}
348 
~analyse()349   ~analyse()
350   {
351     if (f_info)
352     {
353       for (field_info **f=f_info; f != f_end; f++)
354 	delete (*f);
355     }
356   }
add()357   virtual void add() {}
358   virtual bool change_columns(THD *thd, List<Item> &fields);
359   virtual int  send_row(List<Item> &field_list);
end_group(void)360   virtual void end_group(void) {}
361   virtual int end_of_records(void);
362   friend Procedure *proc_analyse_init(THD *thd, ORDER *param,
363 				      select_result *result,
364 				      List<Item> &field_list);
365 };
366 
367 #endif /* SQL_ANALYSE_INCLUDED */
368