1 /* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
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
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef QUERY_RESULT_INCLUDED
24 #define QUERY_RESULT_INCLUDED
25 
26 #include <stddef.h>
27 #include <sys/types.h>
28 
29 #include "m_ctype.h"
30 #include "my_base.h"
31 #include "my_dbug.h"
32 #include "my_inttypes.h"
33 #include "my_io.h"
34 #include "my_sys.h"
35 #include "mysqld_error.h"  // ER_*
36 #include "sql/sql_list.h"
37 
38 class Item;
39 class Item_subselect;
40 class PT_select_var;
41 class SELECT_LEX_UNIT;
42 class THD;
43 struct TABLE_LIST;
44 
45 /*
46   This is used to get result from a query
47 */
48 
49 class Query_result {
50  protected:
51   SELECT_LEX_UNIT *unit;
52 
53  public:
54   /**
55     Number of records estimated in this result.
56     Valid only for materialized derived tables/views.
57   */
58   ha_rows estimated_rowcount;
59   /**
60     Cost to execute the subquery which produces this result.
61     Valid only for materialized derived tables/views.
62   */
63   double estimated_cost;
64 
Query_result()65   Query_result() : unit(nullptr), estimated_rowcount(0), estimated_cost(0) {}
~Query_result()66   virtual ~Query_result() {}
67 
needs_file_privilege()68   virtual bool needs_file_privilege() const { return false; }
69 
70   /**
71     Change wrapped Query_result.
72 
73     Replace the wrapped query result object with new_result and call
74     prepare() on new_result.
75 
76     This base class implementation doesn't wrap other Query_results.
77 
78     @retval false Success
79     @retval true  Error
80   */
change_query_result(THD *,Query_result *)81   virtual bool change_query_result(THD *, Query_result *) { return false; }
82   /// @return true if an interceptor object is needed for EXPLAIN
need_explain_interceptor()83   virtual bool need_explain_interceptor() const { return false; }
84 
85   /**
86     Perform preparation specific to the query expression or DML statement.
87 
88     @returns false if success, true if error
89   */
prepare(THD *,List<Item> &,SELECT_LEX_UNIT * u)90   virtual bool prepare(THD *, List<Item> &, SELECT_LEX_UNIT *u) {
91     unit = u;
92     return false;
93   }
94 
95   /**
96     Optimize the result processing of a query expression, applicable to
97     data change operation (not simple select queries).
98 
99     @returns false if success, true if error
100   */
optimize()101   virtual bool optimize() { return false; }
102 
103   /**
104     Prepare for execution of the query expression or DML statement.
105 
106     Generally, this will have an implementation only for outer-most
107     SELECT_LEX objects, such as data change statements (for preparation
108     of the target table(s)) or dump statements (for preparation of target file).
109 
110     @returns false if success, true if error
111   */
start_execution(THD *)112   virtual bool start_execution(THD *) { return false; }
113 
114   /*
115     Because of peculiarities of prepared statements protocol
116     we need to know number of columns in the result set (if
117     there is a result set) apart from sending columns metadata.
118   */
field_count(List<Item> & fields)119   virtual uint field_count(List<Item> &fields) const { return fields.elements; }
120   virtual bool send_result_set_metadata(THD *thd, List<Item> &list,
121                                         uint flags) = 0;
122   virtual bool send_data(THD *thd, List<Item> &items) = 0;
send_error(THD *,uint errcode,const char * err)123   virtual void send_error(THD *, uint errcode, const char *err) {
124     my_message(errcode, err, MYF(0));
125   }
126   virtual bool send_eof(THD *thd) = 0;
127   /**
128     Check if this query returns a result set and therefore is allowed in
129     cursors and set an error message if it is not the case.
130 
131     @retval false     success
132     @retval true      error, an error message is set
133   */
check_simple_select()134   virtual bool check_simple_select() const {
135     my_error(ER_SP_BAD_CURSOR_QUERY, MYF(0));
136     return true;
137   }
abort_result_set(THD *)138   virtual void abort_result_set(THD *) {}
139   /**
140     Cleanup after one execution of the unit, to be ready for a next execution
141     inside the same statement.
142     @returns true if error
143   */
reset()144   virtual bool reset() {
145     DBUG_ASSERT(0);
146     return false;
147   }
148   /**
149     Cleanup after this execution. Completes the execution and resets object
150     before next execution of a prepared statement/stored procedure.
151   */
cleanup(THD *)152   virtual void cleanup(THD *) { /* do nothing */
153   }
154 
begin_dataset()155   void begin_dataset() {}
156 
157   /// @returns Pointer to count of rows retained by this result.
row_count()158   virtual const ha_rows *row_count() const /* purecov: inspected */
159   {
160     DBUG_ASSERT(false);
161     return nullptr;
162   } /* purecov: inspected */
163 
164   /**
165     Checks if this Query_result intercepts and transforms the result set.
166 
167     @return true if it is an interceptor, false otherwise
168   */
is_interceptor()169   virtual bool is_interceptor() const { return false; }
170 
171   /**
172     If this Query_result performs modifications to tables: tells if it modifies
173     the given table's row as it's read (a.k.a. "on the fly"), or rather buffers
174     it to a temporary structure and modifies it in a post-all-reads phase.
175     @param t  TABLE to answer for
176     @return   true if "on the fly"
177   */
immediate_update(TABLE_LIST * t MY_ATTRIBUTE ((unused)))178   virtual bool immediate_update(TABLE_LIST *t MY_ATTRIBUTE((unused))) const {
179     DBUG_ASSERT(false);
180     return false;
181   }
182 };
183 
184 /*
185   Base class for Query_result descendands which intercept and
186   transform result set rows. As the rows are not sent to the client,
187   sending of result set metadata should be suppressed as well.
188 */
189 
190 class Query_result_interceptor : public Query_result {
191  public:
Query_result_interceptor()192   Query_result_interceptor() : Query_result() {}
field_count(List<Item> &)193   uint field_count(List<Item> &) const override { return 0; }
send_result_set_metadata(THD *,List<Item> &,uint)194   bool send_result_set_metadata(THD *, List<Item> &, uint) override {
195     return false;
196   }
is_interceptor()197   bool is_interceptor() const override final { return true; }
198 };
199 
200 class Query_result_send : public Query_result {
201   /**
202     True if we have sent result set metadata to the client.
203     In this case the client always expects us to end the result
204     set with an eof or error packet
205   */
206   bool is_result_set_started;
207 
208  public:
Query_result_send()209   Query_result_send() : Query_result(), is_result_set_started(false) {}
210   bool send_result_set_metadata(THD *thd, List<Item> &list,
211                                 uint flags) override;
212   bool send_data(THD *thd, List<Item> &items) override;
213   bool send_eof(THD *thd) override;
check_simple_select()214   bool check_simple_select() const override { return false; }
215   void abort_result_set(THD *thd) override;
cleanup(THD *)216   void cleanup(THD *) override { is_result_set_started = false; }
217 };
218 
219 class sql_exchange;
220 
221 class Query_result_to_file : public Query_result_interceptor {
222  protected:
223   sql_exchange *exchange;
224   File file;
225   IO_CACHE cache;
226   ha_rows row_count;
227   char path[FN_REFLEN];
228 
229  public:
Query_result_to_file(sql_exchange * ex)230   explicit Query_result_to_file(sql_exchange *ex)
231       : Query_result_interceptor(), exchange(ex), file(-1), row_count(0L) {
232     path[0] = 0;
233   }
~Query_result_to_file()234   ~Query_result_to_file() override { DBUG_ASSERT(file < 0); }
235 
needs_file_privilege()236   bool needs_file_privilege() const override { return true; }
237 
238   void send_error(THD *thd, uint errcode, const char *err) override;
239   bool send_eof(THD *thd) override;
240   void cleanup(THD *thd) override;
241 };
242 
243 #define ESCAPE_CHARS "ntrb0ZN"  // keep synchronous with READ_INFO::unescape
244 
245 /*
246  List of all possible characters of a numeric value text representation.
247 */
248 #define NUMERIC_CHARS ".0123456789e+-"
249 
250 class Query_result_export final : public Query_result_to_file {
251   size_t field_term_length;
252   int field_sep_char, escape_char, line_sep_char;
253   int field_term_char;  // first char of FIELDS TERMINATED BY or MAX_INT
254   /*
255     The is_ambiguous_field_sep field is true if a value of the field_sep_char
256     field is one of the 'n', 't', 'r' etc characters
257     (see the READ_INFO::unescape method and the ESCAPE_CHARS constant value).
258   */
259   bool is_ambiguous_field_sep;
260   /*
261      The is_ambiguous_field_term is true if field_sep_char contains the first
262      char of the FIELDS TERMINATED BY (ENCLOSED BY is empty), and items can
263      contain this character.
264   */
265   bool is_ambiguous_field_term;
266   /*
267     The is_unsafe_field_sep field is true if a value of the field_sep_char
268     field is one of the '0'..'9', '+', '-', '.' and 'e' characters
269     (see the NUMERIC_CHARS constant value).
270   */
271   bool is_unsafe_field_sep;
272   bool fixed_row_size;
273   const CHARSET_INFO *write_cs;  // output charset
274  public:
Query_result_export(sql_exchange * ex)275   explicit Query_result_export(sql_exchange *ex) : Query_result_to_file(ex) {}
276   bool prepare(THD *thd, List<Item> &list, SELECT_LEX_UNIT *u) override;
277   bool start_execution(THD *thd) override;
278   bool send_data(THD *thd, List<Item> &items) override;
279   void cleanup(THD *thd) override;
280 };
281 
282 class Query_result_dump : public Query_result_to_file {
283  public:
Query_result_dump(sql_exchange * ex)284   explicit Query_result_dump(sql_exchange *ex) : Query_result_to_file(ex) {}
285   bool prepare(THD *thd, List<Item> &list, SELECT_LEX_UNIT *u) override;
286   bool start_execution(THD *thd) override;
287   bool send_data(THD *thd, List<Item> &items) override;
288 };
289 
290 class Query_dumpvar final : public Query_result_interceptor {
291   ha_rows row_count;
292 
293  public:
294   List<PT_select_var> var_list;
Query_dumpvar()295   Query_dumpvar() : Query_result_interceptor(), row_count(0) {
296     var_list.empty();
297   }
298   bool prepare(THD *thd, List<Item> &list, SELECT_LEX_UNIT *u) override;
299   bool send_data(THD *thd, List<Item> &items) override;
300   bool send_eof(THD *thd) override;
301   bool check_simple_select() const override;
cleanup(THD *)302   void cleanup(THD *) override { row_count = 0; }
303 };
304 
305 /**
306   Base class for result from a subquery.
307 */
308 
309 class Query_result_subquery : public Query_result_interceptor {
310  protected:
311   Item_subselect *item;
312 
313  public:
Query_result_subquery(Item_subselect * item_arg)314   explicit Query_result_subquery(Item_subselect *item_arg)
315       : Query_result_interceptor(), item(item_arg) {}
316   bool send_data(THD *thd, List<Item> &items) override = 0;
send_eof(THD *)317   bool send_eof(THD *) override { return false; }
318 };
319 
320 #endif  // QUERY_RESULT_INCLUDED
321