1 /*
2  * Copyright (c) 2015, 2021, Oracle and/or its affiliates.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License, version 2.0,
6  * as published by the Free Software Foundation.
7  *
8  * This program is also distributed with certain software (including
9  * but not limited to OpenSSL) that is licensed under separate terms,
10  * as designated in a particular file or component or in included license
11  * documentation.  The authors of MySQL hereby grant you an additional
12  * permission to link the program and your derivative works with the
13  * separately licensed software that they have included with MySQL.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License, version 2.0, for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301  USA
24  */
25 
26 #ifndef _XPL_COMMAND_DELEGATE_H_
27 #define _XPL_COMMAND_DELEGATE_H_
28 
29 #include "ngs/protocol_encoder.h"
30 
31 #include "m_ctype.h"
32 #include "decimal.h"
33 #include "mysql/service_command.h"
34 
35 namespace xpl
36 {
37   class Command_delegate
38   {
39   public:
40     struct Field_type
41     {
42       enum_field_types type;
43       unsigned int flags;
44     };
45     typedef std::vector<Field_type> Field_types;
46 
Command_delegate()47     Command_delegate()
48     {
49       reset();
50     }
~Command_delegate()51     virtual ~Command_delegate() {}
52 
get_error()53     ngs::Error_code get_error() const
54     {
55       if (m_sql_errno == 0)
56         return ngs::Error_code();
57       else
58         return ngs::Error_code(m_sql_errno, m_err_msg, m_sqlstate);
59     }
60 
server_status()61     inline uint server_status() const { return m_server_status; }
statement_warn_count()62     inline uint statement_warn_count() const { return m_statement_warn_count; }
affected_rows()63     inline ulonglong affected_rows() const { return m_affected_rows; }
last_insert_id()64     inline ulonglong last_insert_id() const { return m_last_insert_id; }
message()65     inline const std::string &message() const { return m_message; }
get_field_types()66     inline const Field_types &get_field_types() const { return m_field_types; }
67 
killed()68     bool killed() const { return m_killed; }
got_eof()69     bool got_eof() const { return m_got_eof; }
70 
reset()71     virtual void reset()
72     {
73       m_server_status = 0;
74       m_statement_warn_count = 0;
75       m_affected_rows = 0;
76       m_last_insert_id = 0;
77       m_sql_errno = 0;
78       m_killed = false;
79       m_streaming_metadata = false;
80       m_field_types.clear();
81       m_got_eof = false;
82       m_message = "";
83     }
84 
callbacks()85     const st_command_service_cbs *callbacks() const
86     {
87       static st_command_service_cbs cbs = {
88         &Command_delegate::call_start_result_metadata,
89         &Command_delegate::call_field_metadata,
90         &Command_delegate::call_end_result_metadata,
91         &Command_delegate::call_start_row,
92         &Command_delegate::call_end_row,
93         &Command_delegate::call_abort_row,
94         &Command_delegate::call_get_client_capabilities,
95         &Command_delegate::call_get_null,
96         &Command_delegate::call_get_integer,
97         &Command_delegate::call_get_longlong,
98         &Command_delegate::call_get_decimal,
99         &Command_delegate::call_get_double,
100         &Command_delegate::call_get_date,
101         &Command_delegate::call_get_time,
102         &Command_delegate::call_get_datetime,
103         &Command_delegate::call_get_string,
104         &Command_delegate::call_handle_ok,
105         &Command_delegate::call_handle_error,
106         &Command_delegate::call_shutdown
107       };
108       return &cbs;
109     }
110 
111     virtual enum cs_text_or_binary representation() const = 0;
112 
113   protected:
114     uint m_server_status;
115     uint m_statement_warn_count;
116     ulonglong m_affected_rows;
117     ulonglong m_last_insert_id;
118     std::string m_message;
119     Field_types m_field_types;
120 
121     uint m_sql_errno;
122     std::string m_err_msg;
123     std::string m_sqlstate;
124 
125     st_command_service_cbs m_callbacks;
126 
127     bool m_killed;
128     bool m_streaming_metadata;
129     bool m_got_eof;
130 
131   public:
132     /*** Getting metadata ***/
133     /*
134       Indicates beginning of metadata for the result set
135 
136       @param num_cols Number of fields being sent
137       @param flags    Flags to alter the metadata sending
138       @param resultcs Charset of the result set
139 
140       @returns
141       true  an error occured, server will abort the command
142       false ok
143     */
start_result_metadata(uint num_cols,uint flags,const CHARSET_INFO * resultcs)144     virtual int start_result_metadata(uint num_cols, uint flags,
145                                           const CHARSET_INFO *resultcs)
146     {
147       m_field_types.clear();
148       return false;
149     }
150 
151     /*
152       Field metadata is provided via this callback
153 
154       @param field   Field's metadata (see field.h)
155       @param charset Field's charset
156 
157       @returns
158       true  an error occured, server will abort the command
159       false ok
160     */
field_metadata(struct st_send_field * field,const CHARSET_INFO * charset)161     virtual int field_metadata(struct st_send_field *field,
162                                    const CHARSET_INFO *charset)
163     {
164       Field_type type = { field->type, field->flags };
165       m_field_types.push_back(type);
166 
167       return false;
168     }
169 
170     /*
171       Indicates end of metadata for the result set
172 
173       @returns
174       true  an error occured, server will abort the command
175       false ok
176     */
end_result_metadata(uint server_status,uint warn_count)177     virtual int end_result_metadata(uint server_status,
178                                         uint warn_count)
179     {
180       return false;
181     }
182 
183     /*
184       Indicates the beginning of a new row in the result set/metadata
185 
186       @returns
187       true  an error occured, server will abort the command
188       false ok
189     */
start_row()190     virtual int start_row()
191     {
192       return false;
193     }
194 
195     /*
196      Indicates the end of the current row in the result set/metadata
197 
198      @returns
199      true  an error occured, server will abort the command
200      false ok
201     */
end_row()202     virtual int end_row()
203     {
204       return false;
205     }
206 
207     /*
208       An error occured during execution
209 
210       @details This callback indicates that an error occureded during command
211       execution and the partial row should be dropped. Server will raise error
212       and return.
213 
214       @returns
215       true  an error occured, server will abort the command
216       false ok
217     */
abort_row()218     virtual void abort_row()
219     {
220     }
221 
222     /*
223       Return client's capabilities (see mysql_com.h, CLIENT_*)
224 
225       @return Bitmap of client's capabilities
226     */
get_client_capabilities()227     virtual ulong get_client_capabilities()
228     {
229       return 0;
230     }
231 
232     /****** Getting data ******/
233     /*
234       Receive NULL value from server
235 
236       @returns
237       true  an error occured, server will abort the command
238       false ok
239     */
get_null()240     virtual int get_null()
241     {
242       return false;
243     }
244 
245     /*
246       Get TINY/SHORT/LONG value from server
247 
248       @param value         Value received
249 
250       @note In order to know which type exactly was received, the plugin must
251       track the metadata that was sent just prior to the result set.
252 
253       @returns
254       true  an error occured, server will abort the command
255       false ok
256     */
get_integer(longlong value)257     virtual int get_integer(longlong value)
258     {
259       return false;
260     }
261 
262     /*
263       Get LONGLONG value from server
264 
265       @param value         Value received
266       @param unsigned_flag TRUE <=> value is unsigned
267 
268       @returns
269       true  an error occured, server will abort the command
270       false ok
271     */
get_longlong(longlong value,uint unsigned_flag)272     virtual int get_longlong(longlong value, uint unsigned_flag)
273     {
274       return false;
275     }
276 
277     /*
278       Receive DECIMAL value from server
279 
280       @param value Value received
281 
282       @returns
283       true  an error occured, server will abort the command
284       false ok
285     */
get_decimal(const decimal_t * value)286     virtual int get_decimal(const decimal_t * value)
287     {
288       return false;
289     }
290 
291     /*
292       Get FLOAT/DOUBLE from server
293 
294       @param value    Value received
295       @param decimals Number of decimals
296 
297       @note In order to know which type exactly was received, the plugin must
298       track the metadata that was sent just prior to the result set.
299 
300       @returns
301       true  an error occured, server will abort the command
302       false ok
303     */
get_double(double value,uint32 decimals)304     virtual int get_double(double value, uint32 decimals)
305     {
306       return false;
307     }
308 
309     /*
310       Get DATE value from server
311 
312       @param value    Value received
313 
314       @returns
315       true  an error occured during storing, server will abort the command
316       false ok
317     */
get_date(const MYSQL_TIME * value)318     virtual int get_date(const MYSQL_TIME * value)
319     {
320       return false;
321     }
322 
323     /*
324       Get TIME value from server
325 
326       @param value    Value received
327       @param decimals Number of decimals
328 
329       @returns
330       true  an error occured during storing, server will abort the command
331       false ok
332     */
get_time(const MYSQL_TIME * value,uint decimals)333     virtual int get_time(const MYSQL_TIME * value, uint decimals)
334     {
335       return false;
336     }
337 
338     /*
339       Get DATETIME value from server
340 
341       @param value    Value received
342       @param decimals Number of decimals
343 
344       @returns
345       true  an error occured during storing, server will abort the command
346       false ok
347     */
get_datetime(const MYSQL_TIME * value,uint decimals)348     virtual int get_datetime(const MYSQL_TIME * value, uint decimals)
349     {
350       return false;
351     }
352 
353     /*
354       Get STRING value from server
355 
356       @param value   Value received
357       @param length  Value's length
358       @param valuecs Value's charset
359 
360       @returns
361       true  an error occured, server will abort the command
362       false ok
363     */
get_string(const char * const value,size_t length,const CHARSET_INFO * const valuecs)364     virtual int get_string(const char * const value, size_t length,
365                            const CHARSET_INFO * const valuecs)
366     {
367       return false;
368     }
369 
370     /****** Getting execution status ******/
371     /*
372       Command ended with success
373 
374       @param server_status        Status of server (see mysql_com.h,
375       SERVER_STATUS_*)
376       @param statement_warn_count Number of warnings thrown during execution
377       @param affected_rows        Number of rows affected by the command
378       @param last_insert_id       Last insert id being assigned during execution
379       @param message              A message from server
380     */
handle_ok(uint server_status,uint statement_warn_count,ulonglong affected_rows,ulonglong last_insert_id,const char * const message)381     virtual void handle_ok(uint server_status, uint statement_warn_count,
382                            ulonglong affected_rows, ulonglong last_insert_id,
383                            const char * const message)
384     {
385       m_server_status = server_status;
386       m_statement_warn_count = statement_warn_count;
387       m_affected_rows = affected_rows;
388       m_last_insert_id = last_insert_id;
389       m_message = message ? message : "";
390     }
391 
392     /*
393      Command ended with ERROR
394 
395      @param sql_errno Error code
396      @param err_msg   Error message
397      @param sqlstate  SQL state correspongin to the error code
398     */
handle_error(uint sql_errno,const char * const err_msg,const char * const sqlstate)399     virtual void handle_error(uint sql_errno, const char * const err_msg,
400                               const char * const sqlstate)
401     {
402       m_sql_errno = sql_errno;
403       m_err_msg = err_msg ? err_msg : "";
404       m_sqlstate = sqlstate ? sqlstate : "";
405     }
406 
407     /*
408      Session was shutdown while command was running
409 
410     */
shutdown(int flag)411     virtual void shutdown(int flag)
412     {
413       m_killed = true;
414     }
415 
416   private:
417     Command_delegate(const Command_delegate &);
418     Command_delegate &operator=(const Command_delegate &);
419 
call_start_result_metadata(void * ctx,uint num_cols,uint flags,const CHARSET_INFO * resultcs)420     static int call_start_result_metadata(void *ctx, uint num_cols, uint flags,
421                                           const CHARSET_INFO *resultcs)
422     {
423       Command_delegate *self = static_cast<Command_delegate*>(ctx);
424       self->m_streaming_metadata = true;
425       return self->start_result_metadata(num_cols, flags, resultcs);
426     }
427 
call_field_metadata(void * ctx,struct st_send_field * field,const CHARSET_INFO * charset)428     static int call_field_metadata(void *ctx, struct st_send_field *field,
429                                   const CHARSET_INFO *charset)
430     {
431       return static_cast<Command_delegate*>(ctx)->field_metadata(field, charset);
432     }
433 
call_end_result_metadata(void * ctx,uint server_status,uint warn_count)434     static int call_end_result_metadata(void *ctx, uint server_status,
435                                         uint warn_count)
436     {
437       Command_delegate *self = static_cast<Command_delegate*>(ctx);
438       int tmp = self->end_result_metadata(server_status, warn_count);
439       self->m_streaming_metadata = false;
440       return tmp;
441     }
442 
call_start_row(void * ctx)443     static int call_start_row(void *ctx)
444     {
445       Command_delegate *self = static_cast<Command_delegate*>(ctx);
446       if (self->m_streaming_metadata)
447         return false;
448       return self->start_row();
449     }
450 
call_end_row(void * ctx)451     static int call_end_row(void *ctx)
452     {
453       Command_delegate *self = static_cast<Command_delegate*>(ctx);
454       if (self->m_streaming_metadata)
455         return false;
456       return self->end_row();
457     }
458 
call_abort_row(void * ctx)459     static void call_abort_row(void *ctx)
460     {
461       static_cast<Command_delegate*>(ctx)->abort_row();
462     }
463 
call_get_client_capabilities(void * ctx)464     static ulong call_get_client_capabilities(void *ctx)
465     {
466       return static_cast<Command_delegate*>(ctx)->get_client_capabilities();
467     }
468 
call_get_null(void * ctx)469     static int call_get_null(void * ctx)
470     {
471       return static_cast<Command_delegate*>(ctx)->get_null();
472     }
473 
call_get_integer(void * ctx,longlong value)474     static int call_get_integer(void * ctx, longlong value)
475     {
476       return static_cast<Command_delegate*>(ctx)->get_integer(value);
477     }
478 
call_get_longlong(void * ctx,longlong value,uint unsigned_flag)479     static int call_get_longlong(void * ctx, longlong value, uint unsigned_flag)
480     {
481       return static_cast<Command_delegate*>(ctx)->get_longlong(value, unsigned_flag);
482     }
483 
call_get_decimal(void * ctx,const decimal_t * value)484     static int call_get_decimal(void * ctx, const decimal_t * value)
485     {
486       return static_cast<Command_delegate*>(ctx)->get_decimal(value);
487     }
488 
call_get_double(void * ctx,double value,uint32 decimals)489     static int call_get_double(void * ctx, double value, uint32 decimals)
490     {
491       return static_cast<Command_delegate*>(ctx)->get_double(value, decimals);
492     }
493 
call_get_date(void * ctx,const MYSQL_TIME * value)494     static int call_get_date(void * ctx, const MYSQL_TIME * value)
495     {
496       return static_cast<Command_delegate*>(ctx)->get_date(value);
497     }
498 
call_get_time(void * ctx,const MYSQL_TIME * value,uint decimals)499     static int call_get_time(void * ctx, const MYSQL_TIME * value, uint decimals)
500     {
501       return static_cast<Command_delegate*>(ctx)->get_time(value, decimals);
502     }
503 
call_get_datetime(void * ctx,const MYSQL_TIME * value,uint decimals)504     static int call_get_datetime(void * ctx, const MYSQL_TIME * value, uint decimals)
505     {
506       return static_cast<Command_delegate*>(ctx)->get_datetime(value, decimals);
507     }
508 
call_get_string(void * ctx,const char * const value,size_t length,const CHARSET_INFO * const valuecs)509     static int call_get_string(void * ctx,
510                                const char * const value, size_t length,
511                                const CHARSET_INFO * const valuecs)
512     {
513       return static_cast<Command_delegate*>(ctx)->get_string(value, length, valuecs);
514     }
515 
call_handle_ok(void * ctx,uint server_status,uint statement_warn_count,ulonglong affected_rows,ulonglong last_insert_id,const char * const message)516     static void call_handle_ok(void * ctx,
517                                uint server_status, uint statement_warn_count,
518                                ulonglong affected_rows, ulonglong last_insert_id,
519                                const char * const message)
520     {
521       static_cast<Command_delegate*>(ctx)->m_got_eof = (message == NULL);
522 
523       static_cast<Command_delegate*>(ctx)->handle_ok(server_status, statement_warn_count,
524                                                      affected_rows, last_insert_id,
525                                                      message);
526     }
527 
call_handle_error(void * ctx,uint sql_errno,const char * const err_msg,const char * const sqlstate)528     static void call_handle_error(void * ctx, uint sql_errno, const char * const err_msg,
529                                   const char * const sqlstate)
530     {
531       static_cast<Command_delegate*>(ctx)->handle_error(sql_errno, err_msg, sqlstate);
532     }
533 
call_shutdown(void * ctx,int flag)534     static void call_shutdown(void *ctx, int flag)
535     {
536       static_cast<Command_delegate*>(ctx)->shutdown(flag);
537     }
538   };
539 } // namespace xpl
540 
541 #endif // _XPL_COMMAND_DELEGATE_H_
542