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