| 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 |  | 
| 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(String*); | 
| 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: | 
| 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 |  | 
| 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: | 
| 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 |  | 
| 152 | int collect_decimal(uchar *element, element_count count, | 
| 153 |                     TREE_INFO *info); | 
| 154 |  | 
| 155 | class 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; | 
| 161 | public: | 
| 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 |  | 
| 182 | int collect_real(double *element, element_count count, TREE_INFO *info); | 
| 183 |  | 
| 184 | class field_real: public field_info | 
| 185 | { | 
| 186 |   double min_arg, max_arg; | 
| 187 |   double sum, sum_sqr; | 
| 188 |   uint	 max_notzero_dec_len; | 
| 189 |  | 
| 190 | public: | 
| 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 |  | 
| 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: | 
| 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 |  | 
| 283 | int collect_ulonglong(ulonglong *element, element_count count, | 
| 284 | 		      TREE_INFO *info); | 
| 285 |  | 
| 286 | class field_ulonglong: public field_info | 
| 287 | { | 
| 288 |   ulonglong min_arg, max_arg; | 
| 289 |   ulonglong sum, sum_sqr; | 
| 290 |  | 
| 291 | public: | 
| 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 |  | 
| 331 | Procedure *proc_analyse_init(THD *thd, ORDER *param, | 
| 332 | 			     select_result *result, | 
| 333 | 			     List<Item> &field_list); | 
| 334 |  | 
| 335 | class analyse: public Procedure | 
| 336 | { | 
| 337 | protected: | 
| 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 |  | 
| 344 | public: | 
| 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 |  |