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