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-1301 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
32typedef 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
42typedef struct st_extreme_value_number_info
43{
44 ulonglong ullval;
45 longlong llval;
46 double max_dval, min_dval;
47} EV_NUM_INFO;
48
49typedef struct st_tree_info
50{
51 bool found;
52 String *str;
53 Item *item;
54} TREE_INFO;
55
56uint check_ulonglong(const char *str, uint length);
57bool get_ev_num_info(EV_NUM_INFO *ev_info, NUM_INFO *info, const char *num);
58bool test_if_number(NUM_INFO *info, const char *str, uint str_len);
59int compare_double(const double *s, const double *t);
60int compare_double2(void* cmp_arg __attribute__((unused)),
61 const double *s, const double *t);
62int compare_longlong(const longlong *s, const longlong *t);
63int compare_longlong2(void* cmp_arg __attribute__((unused)),
64 const longlong *s, const longlong *t);
65int compare_ulonglong(const ulonglong *s, const ulonglong *t);
66int compare_ulonglong2(void* cmp_arg __attribute__((unused)),
67 const ulonglong *s, const ulonglong *t);
68int compare_decimal2(int* len, const char *s, const char *t);
69Procedure *proc_analyse_init(THD *thd, ORDER *param, select_result *result,
70 List<Item> &field_list);
71int free_string(String*);
72class analyse;
73
74class field_info :public Sql_alloc
75{
76protected:
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
84public:
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
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;
97 virtual uint decimals() { return 0; }
98 friend class analyse;
99};
100
101
102int collect_string(String *element, element_count count,
103 TREE_INFO *info);
104
105int sortcmp2(void* cmp_arg __attribute__((unused)),
106 const String *a,const String *b);
107
108class 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
117public:
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 (tree_element_free) free_string, NULL,
125 MYF(MY_THREAD_SPECIFIC)); };
126
127 void add();
128 void get_opt_type(String*, ha_rows);
129 String *get_min_arg(String *not_used __attribute__((unused)))
130 { return &min_arg; }
131 String *get_max_arg(String *not_used __attribute__((unused)))
132 { return &max_arg; }
133 String *avg(String *s, ha_rows rows)
134 {
135 if (!(rows - nulls))
136 s->set_real((double) 0.0, 1,my_thd_charset);
137 else
138 s->set_real((ulonglong2double(sum) / ulonglong2double(rows - nulls)),
139 DEC_IN_AVG,my_thd_charset);
140 return s;
141 }
142 friend int collect_string(String *element, element_count count,
143 TREE_INFO *info);
144 tree_walk_action collect_enum()
145 { return (tree_walk_action) collect_string; }
146 String *std(String *s __attribute__((unused)),
147 ha_rows rows __attribute__((unused)))
148 { return (String*) 0; }
149};
150
151
152int collect_decimal(uchar *element, element_count count,
153 TREE_INFO *info);
154
155class field_decimal :public field_info
156{
157 my_decimal min_arg, max_arg;
158 my_decimal sum[2], sum_sqr[2];
159 int cur_sum;
160 int bin_size;
161public:
162 field_decimal(Item* a, analyse* b) :field_info(a,b)
163 {
164 bin_size= my_decimal_get_binary_size(a->max_length, a->decimals);
165 init_tree(&tree, 0, 0, bin_size, (qsort_cmp2)compare_decimal2,
166 0, (void *)&bin_size, MYF(MY_THREAD_SPECIFIC));
167 };
168
169 void add();
170 void get_opt_type(String*, ha_rows);
171 String *get_min_arg(String *);
172 String *get_max_arg(String *);
173 String *avg(String *s, ha_rows rows);
174 friend int collect_decimal(uchar *element, element_count count,
175 TREE_INFO *info);
176 tree_walk_action collect_enum()
177 { return (tree_walk_action) collect_decimal; }
178 String *std(String *s, ha_rows rows);
179};
180
181
182int collect_real(double *element, element_count count, TREE_INFO *info);
183
184class field_real: public field_info
185{
186 double min_arg, max_arg;
187 double sum, sum_sqr;
188 uint max_notzero_dec_len;
189
190public:
191 field_real(Item* a, analyse* b) :field_info(a,b),
192 min_arg(0), max_arg(0), sum(0), sum_sqr(0), max_notzero_dec_len(0)
193 { init_tree(&tree, 0, 0, sizeof(double),
194 (qsort_cmp2) compare_double2, NULL, NULL,
195 MYF(MY_THREAD_SPECIFIC)); }
196
197 void add();
198 void get_opt_type(String*, ha_rows);
199 String *get_min_arg(String *s)
200 {
201 s->set_real(min_arg, item->decimals, my_thd_charset);
202 return s;
203 }
204 String *get_max_arg(String *s)
205 {
206 s->set_real(max_arg, item->decimals, my_thd_charset);
207 return s;
208 }
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 }
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 }
230 uint decimals() { return item->decimals; }
231 friend int collect_real(double *element, element_count count,
232 TREE_INFO *info);
233 tree_walk_action collect_enum()
234 { return (tree_walk_action) collect_real;}
235};
236
237int collect_longlong(longlong *element, element_count count,
238 TREE_INFO *info);
239
240class field_longlong: public field_info
241{
242 longlong min_arg, max_arg;
243 longlong sum, sum_sqr;
244
245public:
246 field_longlong(Item* a, 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, NULL, NULL,
250 MYF(MY_THREAD_SPECIFIC)); }
251
252 void add();
253 void get_opt_type(String*, ha_rows);
254 String *get_min_arg(String *s) { s->set(min_arg,my_thd_charset); return s; }
255 String *get_max_arg(String *s) { s->set(max_arg,my_thd_charset); return s; }
256 String *avg(String *s, ha_rows rows)
257 {
258 if (!(rows - nulls))
259 s->set_real((double) 0.0, 1,my_thd_charset);
260 else
261 s->set_real(((double) sum / (double) (rows - nulls)), DEC_IN_AVG,my_thd_charset);
262 return s;
263 }
264 String *std(String *s, ha_rows rows)
265 {
266 double tmp = ulonglong2double(rows);
267 if (!(tmp - nulls))
268 s->set_real((double) 0.0, 1,my_thd_charset);
269 else
270 {
271 double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) /
272 (tmp - nulls));
273 s->set_real(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset);
274 }
275 return s;
276 }
277 friend int collect_longlong(longlong *element, element_count count,
278 TREE_INFO *info);
279 tree_walk_action collect_enum()
280 { return (tree_walk_action) collect_longlong;}
281};
282
283int collect_ulonglong(ulonglong *element, element_count count,
284 TREE_INFO *info);
285
286class field_ulonglong: public field_info
287{
288 ulonglong min_arg, max_arg;
289 ulonglong sum, sum_sqr;
290
291public:
292 field_ulonglong(Item* a, analyse * b) :field_info(a,b),
293 min_arg(0), max_arg(0), sum(0),sum_sqr(0)
294 { init_tree(&tree, 0, 0, sizeof(ulonglong),
295 (qsort_cmp2) compare_ulonglong2, NULL, NULL,
296 MYF(MY_THREAD_SPECIFIC)); }
297 void add();
298 void get_opt_type(String*, ha_rows);
299 String *get_min_arg(String *s) { s->set(min_arg,my_thd_charset); return s; }
300 String *get_max_arg(String *s) { s->set(max_arg,my_thd_charset); return s; }
301 String *avg(String *s, ha_rows rows)
302 {
303 if (!(rows - nulls))
304 s->set_real((double) 0.0, 1,my_thd_charset);
305 else
306 s->set_real((ulonglong2double(sum) / ulonglong2double(rows - nulls)),
307 DEC_IN_AVG,my_thd_charset);
308 return s;
309 }
310 String *std(String *s, ha_rows rows)
311 {
312 double tmp = ulonglong2double(rows);
313 if (!(tmp - nulls))
314 s->set_real((double) 0.0, 1,my_thd_charset);
315 else
316 {
317 double tmp2 = ((ulonglong2double(sum_sqr) -
318 ulonglong2double(sum * sum) / (tmp - nulls)) /
319 (tmp - nulls));
320 s->set_real(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset);
321 }
322 return s;
323 }
324 friend int collect_ulonglong(ulonglong *element, element_count count,
325 TREE_INFO *info);
326 tree_walk_action collect_enum()
327 { return (tree_walk_action) collect_ulonglong; }
328};
329
330
331Procedure *proc_analyse_init(THD *thd, ORDER *param,
332 select_result *result,
333 List<Item> &field_list);
334
335class analyse: public Procedure
336{
337protected:
338 Item_proc *func_items[10];
339 List<Item> fields, result_fields;
340 field_info **f_info, **f_end;
341 ha_rows rows;
342 uint output_str_length;
343
344public:
345 uint max_tree_elements, max_treemem;
346
347 analyse(select_result *res) :Procedure(res, PROC_NO_SORT), f_info(0),
348 rows(0), output_str_length(0) {}
349
350 ~analyse()
351 {
352 if (f_info)
353 {
354 for (field_info **f=f_info; f != f_end; f++)
355 delete (*f);
356 }
357 }
358 virtual void add() {}
359 virtual bool change_columns(THD *thd, List<Item> &fields);
360 virtual int send_row(List<Item> &field_list);
361 virtual void end_group(void) {}
362 virtual int end_of_records(void);
363 friend Procedure *proc_analyse_init(THD *thd, ORDER *param,
364 select_result *result,
365 List<Item> &field_list);
366};
367
368#endif /* SQL_ANALYSE_INCLUDED */
369