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