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