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