1 /* Copyright (c) 2011, 2021, Oracle and/or its affiliates. 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License, version 2.0, 5 as published by the Free Software Foundation. 6 7 This program is also distributed with certain software (including 8 but not limited to OpenSSL) that is licensed under separate terms, 9 as designated in a particular file or component or in included license 10 documentation. The authors of MySQL hereby grant you an additional 11 permission to link the program and your derivative works with the 12 separately licensed software that they have included with MySQL. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License, version 2.0, for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software Foundation, 21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ 22 23 24 #ifndef OPT_EXPLAIN_INCLUDED 25 #define OPT_EXPLAIN_INCLUDED 26 27 /** @file "EXPLAIN <command>" 28 29 Single table UPDATE/DELETE commands are explained by the 30 explain_single_table_modification() function. 31 32 A query expression (complete SELECT query possibly including 33 subqueries and unions), INSERT...SELECT and multitable UPDATE/DELETE 34 commands are explained like this: 35 36 (1) explain_query_expression() 37 38 Is the entry point. Forwards the job to explain_unit(). 39 40 (2) explain_unit() 41 42 Is for a SELECT_LEX_UNIT, prepares, optimizes, explains one JOIN for 43 each "top-level" SELECT_LEXs of the unit (like: all SELECTs of a 44 UNION; but not subqueries), and one JOIN for the fake SELECT_LEX of 45 UNION); each JOIN explain (JOIN::exec()) calls explain_query_specification() 46 47 (3) explain_query_specification() 48 49 Is for a single SELECT_LEX (fake or not). It needs a prepared and 50 optimized JOIN, for which it builds the EXPLAIN rows. But it also 51 launches the EXPLAIN process for "inner units" (==subqueries of this 52 SELECT_LEX), by calling explain_unit() for each of them. 53 */ 54 55 #include <my_base.h> 56 #include "opt_explain_format.h" 57 58 class JOIN; 59 class Query_result; 60 class Query_result_interceptor; 61 struct TABLE; 62 class THD; 63 typedef class st_select_lex_unit SELECT_LEX_UNIT; 64 typedef class st_select_lex SELECT_LEX; 65 66 extern const char *join_type_str[]; 67 68 /** Table modification plan for JOIN-less statements (update/delete) */ 69 class Modification_plan 70 { 71 public: 72 THD *const thd; ///< Owning thread 73 const enum_mod_type mod_type;///< Modification type - MT_INSERT/MT_UPDATE/etc 74 TABLE *table; ///< Table to modify 75 76 QEP_TAB *tab; ///< QUICK access method + WHERE clause 77 uint key; ///< Key to use 78 ha_rows limit; ///< Limit 79 bool need_tmp_table; ///< Whether tmp table needs to be used 80 bool need_sort; ///< Whether to use filesort 81 bool used_key_is_modified;///< Whether the key used to scan is modified 82 const char *message; ///< Arbitrary message 83 bool zero_result; ///< TRUE <=> plan will not be executed 84 ha_rows examined_rows; ///< # of rows expected to be examined in the table 85 86 Modification_plan(THD *thd_arg, 87 enum_mod_type mt, QEP_TAB *qep_tab, 88 uint key_arg, ha_rows limit_arg, bool need_tmp_table_arg, 89 bool need_sort_arg, bool used_key_is_modified_arg, 90 ha_rows rows); 91 92 Modification_plan(THD *thd_arg, 93 enum_mod_type mt, TABLE *table_arg, 94 const char *message_arg, bool zero_result_arg, 95 ha_rows rows); 96 97 ~Modification_plan(); 98 99 private: 100 void register_in_thd(); 101 }; 102 103 104 /** 105 EXPLAIN functionality for Query_result_insert, Query_result_update and 106 Query_result_delete. 107 108 This class objects substitute Query_result_insert, Query_result_update and 109 Query_result_delete data interceptor objects to implement EXPLAIN for INSERT, 110 REPLACE and multi-table UPDATE and DELETE queries. 111 Query_result_explain class object initializes tables like Query_result_insert, 112 Query_result_update or Query_result_delete data interceptor do, but it suppress 113 table data modification by the underlying interceptor object. 114 Thus, we can use Query_result_explain object in the context of EXPLAIN INSERT/ 115 REPLACE/UPDATE/DELETE query like we use Query_result_send in the context of 116 EXPLAIN SELECT command: 117 1) in presence of lex->describe flag we pass Query_result_explain object to the 118 handle_query() function, 119 2) it call prepare(), prepare2() and initialize_tables() functions to 120 mark modified tables etc. 121 122 */ 123 124 class Query_result_explain : public Query_result_send { 125 protected: 126 /* 127 As far as we use Query_result_explain object in a place of Query_result_send, 128 Query_result_explain have to pass multiple invocation of its prepare(), 129 prepare2() and initialize_tables() functions, since JOIN::exec() of 130 subqueries runs these functions of Query_result_send multiple times by design. 131 Query_result_insert, Query_result_update and Query_result_delete class 132 functions are not intended for multiple invocations, so "prepared", 133 "prepared2" and "initialized" flags guard data interceptor object from 134 function re-invocation. 135 */ 136 bool prepared; ///< prepare() is done 137 bool prepared2; ///< prepare2() is done 138 bool initialized; ///< initialize_tables() is done 139 140 /** 141 Pointer to underlying Query_result_insert, Query_result_update or 142 Query_result_delete object. 143 */ 144 Query_result *interceptor; 145 146 public: Query_result_explain(st_select_lex_unit * unit_arg,Query_result * interceptor_arg)147 Query_result_explain(st_select_lex_unit *unit_arg, Query_result *interceptor_arg) 148 : prepared(false), prepared2(false), initialized(false), 149 interceptor(interceptor_arg) 150 { unit= unit_arg; } 151 152 protected: prepare(List<Item> & list,SELECT_LEX_UNIT * u)153 virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u) 154 { 155 if (prepared) 156 return false; 157 prepared= true; 158 return Query_result_send::prepare(list, u) || interceptor->prepare(list, u); 159 } 160 prepare2(void)161 virtual int prepare2(void) 162 { 163 if (prepared2) 164 return false; 165 prepared2= true; 166 return Query_result_send::prepare2() || interceptor->prepare2(); 167 } 168 initialize_tables(JOIN * join)169 virtual bool initialize_tables(JOIN *join) 170 { 171 if (initialized) 172 return false; 173 initialized= true; 174 return Query_result_send::initialize_tables(join) || 175 interceptor->initialize_tables(join); 176 } 177 cleanup()178 virtual void cleanup() 179 { 180 Query_result_send::cleanup(); 181 interceptor->cleanup(); 182 } 183 }; 184 185 186 bool explain_no_table(THD *thd, SELECT_LEX *select_lex, const char *message, 187 enum_parsing_context ctx); 188 bool explain_single_table_modification(THD *ethd, 189 const Modification_plan *plan, 190 SELECT_LEX *select); 191 bool explain_query(THD *thd, SELECT_LEX_UNIT *unit); 192 bool explain_query_specification(THD *ethd, SELECT_LEX *select_lex, 193 enum_parsing_context ctx); 194 void mysql_explain_other(THD *thd); 195 196 #endif /* OPT_EXPLAIN_INCLUDED */ 197