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