1 /* Copyright (c) 2015, 2019, 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 SQL_SERVICE_COMMAND_INCLUDE
24 #define SQL_SERVICE_COMMAND_INCLUDE
25 
26 #include <stddef.h>
27 
28 #include "my_inttypes.h"
29 #include "plugin/group_replication/include/plugin_utils.h"
30 #include "plugin/group_replication/include/sql_service/sql_service_interface.h"
31 
32 #define GR_PLUGIN_SESSION_THREAD_TIMEOUT 10
33 
34 /**
35   What is the policy when creation a new server session for SQL execution.
36 */
37 enum enum_plugin_con_isolation {
38   PSESSION_USE_THREAD,       ///< Use the current thread
39   PSESSION_INIT_THREAD,      ///< Use the current thread but initialize it
40   PSESSION_DEDICATED_THREAD  ///< Use a dedicated thread to open a session
41 };
42 
43 class Sql_service_commands {
44  public:
45   /**
46     Internal method to set the super read only mode.
47 
48     @param sql_interface the server session interface for query execution
49     @param arg a generic argument to give the method info or get a result
50 
51     @return error code during execution of the sql query.
52        @retval 0  - success
53        @retval >0 - failure
54   */
55   long internal_set_super_read_only(Sql_service_interface *sql_interface,
56                                     void *arg = nullptr);
57 
58   /**
59     Internal method to reset the super read only mode.
60 
61     @param sql_interface the server session interface for query execution
62     @param arg a generic argument to give the method info or get a result
63 
64     @return error code during execution of the sql query.
65        @retval 0  - success
66        @retval >0 - failure
67   */
68   long internal_reset_super_read_only(Sql_service_interface *sql_interface,
69                                       void *arg = nullptr);
70 
71   /**
72     Internal method to reset the super read only mode.
73 
74     @param sql_interface the server session interface for query execution
75     @param arg a generic argument to give the method info or get a result
76 
77     @return error code during execution of the sql query.
78        @retval 0  - success
79        @retval >0 - failure
80   */
81   long internal_reset_read_only(Sql_service_interface *sql_interface,
82                                 void *arg = nullptr);
83 
84   /**
85    Internal method to get the super read only mode.
86 
87    @param sql_interface the server session interface for query execution
88    @param arg a generic argument to give the method info or get a result
89 
90    @retval -1  Error reading the value
91    @retval  0  Not in super read mode
92    @retval  1  In read super mode
93   */
94   long internal_get_server_super_read_only(Sql_service_interface *sql_interface,
95                                            void *arg = nullptr);
96 
97   /**
98     Internal method to get the super read only mode.
99 
100     @param sql_interface the server session interface for query execution
101     @param arg a generic argument to give the method info or get a result
102 
103     @retval -1  Error reading the value
104     @retval  0  Not in super read mode
105     @retval  1  In read super mode
106   */
107   long internal_get_server_read_only(Sql_service_interface *sql_interface,
108                                      void *arg = nullptr);
109 
110   /**
111     Method to return the server gtid_executed by executing the corresponding
112     sql query.
113 
114     @param sql_interface        the server session interface for query execution
115     @param [out] gtid_executed  The string where the result will be appended
116 
117     @return the error value returned
118       @retval 0      OK
119       @retval !=0    Error
120   */
121   long internal_get_server_gtid_executed(Sql_service_interface *sql_interface,
122                                          void *gtid_executed);
123 
124   /**
125     Method to return the server gtid_purged by executing the corresponding
126     sql query.
127 
128     @param sql_interface        the server session interface for query execution
129     @param [out] gtid_purged    The string where the result will be appended
130 
131     @return the error value returned
132       @retval 0      OK
133       @retval !=0    Error
134   */
135   long internal_get_server_gtid_purged(Sql_service_interface *sql_interface,
136                                        void *gtid_purged);
137 
138   /**
139     Method to wait for the server gtid_executed to match the given GTID string
140 
141     @param sql_interface the server session interface for query execution
142     @param [in] gtid_executed  The GTID string to check
143     @param [in] timeout        The timeout after which the method should break
144 
145     @return the error value returned
146       @retval 0      OK
147       @retval !=0    Error when executed or timeout.
148   */
149   long internal_wait_for_server_gtid_executed(
150       Sql_service_interface *sql_interface, std::string &gtid_executed,
151       int timeout = 0);
152 
153   /**
154    Method to kill the session identified by the given session id in those
155    cases where the server hangs while executing the sql query.
156 
157    @param sql_interface  the server session interface for query execution
158    @param session_id  id of the session to be killed.
159 
160    @return the error value returned
161     @retval 0  - success
162     @retval >0 - Failure
163   */
164   long internal_kill_session(Sql_service_interface *sql_interface,
165                              void *session_id = nullptr);
166 
167   /**
168    Method to set a variable using SET PERSIST_ONLY
169    @param sql_interface  the server session interface for query execution
170    @param variable_args  arg void pointer, should be pair <string,string>
171    @return the error value returned
172     @retval 0      OK
173     @retval !=0    Error
174   */
175   long internal_set_persist_only_variable(Sql_service_interface *sql_interface,
176                                           void *variable_args = nullptr);
177 
178   /**
179     Method to remotely clone a server
180 
181     @param[in] sql_interface  The connection where to execute the query
182     @param[in] variable_args  Tuple <string,string,string,string,bool,string>
183 
184     @return the error value returned
185       @retval 0      OK
186       @retval !=0    Error on execution
187   */
188   long internal_clone_server(Sql_service_interface *sql_interface,
189                              void *variable_args = nullptr);
190 
191   /**
192     Method to execute a given query
193 
194     @param[in] sql_interface  The connection where to execute the query
195     @param[in] variable_args  Tuple <string, string>
196 
197     @return the error value returned
198       @retval 0      OK
199       @retval !=0    Error on execution
200   */
201   long internal_execute_query(Sql_service_interface *sql_interface,
202                               void *variable_args = nullptr);
203 
204   /**
205     Method to execute a given conditional query
206 
207     @param[in] sql_interface  The connection where to execute the query
208     @param[in] variable_args  Tuple <string, bool, string>
209 
210     @return the error value returned
211       @retval 0      OK
212       @retval !=0    Error on execution
213   */
214   long internal_execute_conditional_query(Sql_service_interface *sql_interface,
215                                           void *variable_args = nullptr);
216 
217   /**
218     Internal method to set the offline mode.
219 
220     @param sql_interface the server session interface for query execution
221     @param arg a generic argument to give the method info or get a result
222 
223     @return error code during execution of the sql query.
224        @retval 0  - success
225        @retval >0 - failure
226   */
227   long internal_set_offline_mode(Sql_service_interface *sql_interface,
228                                  void *arg = nullptr);
229 };
230 
231 struct st_session_method {
232   long (Sql_service_commands::*method)(Sql_service_interface *, void *);
233   bool terminated;
234 };
235 
236 class Session_plugin_thread {
237  public:
238   Session_plugin_thread(Sql_service_commands *command_interface);
239 
240   ~Session_plugin_thread();
241 
242   /**
243     Launch a new thread that will create a new server session.
244 
245     @param plugin_pointer_var the plugin pointer for session creation
246     @param user               the user for the connection
247 
248     @return the operation was successful
249       @retval 0      OK
250       @retval !=0    Error
251   */
252   int launch_session_thread(void *plugin_pointer_var, const char *user);
253 
254   /**
255     Terminate the thread and close the session.
256 
257     @return the operation was successful
258       @retval 0      OK
259       @retval !=0    Error
260   */
261   int terminate_session_thread();
262 
263   /**
264     Thread handler for session creation.
265   */
266   int session_thread_handler();
267 
268   /**
269      Method to submit a new method into execution on the session thread
270      @param method    method to executed
271      @param terminate termination flag to the class
272   */
273   void queue_new_method_for_application(
274       long (Sql_service_commands::*method)(Sql_service_interface *, void *),
275       bool terminate = false);
276 
277   /**
278     Wait for the queued method to return.
279     @return the return value of the submitted method
280   */
281   long wait_for_method_execution();
282 
283   Sql_service_interface *get_service_interface();
284 
285   /**
286     Sets a pointer that the next queued method will use to return a value
287     @param pointer the pointer where the method will store some return value
288   */
set_return_pointer(void * pointer)289   void set_return_pointer(void *pointer) { return_object = pointer; }
290 
291  private:
292   Sql_service_commands *command_interface;
293 
294   Sql_service_interface *m_server_interface;
295 
296   Synchronized_queue<st_session_method *> *incoming_methods;
297 
298   void *m_plugin_pointer;
299 
300   /** The value for returning on methods */
301   void *return_object;
302 
303   /** Session thread handle */
304   my_thread_handle m_plugin_session_pthd;
305   /* run conditions and locks */
306   mysql_mutex_t m_run_lock;
307   mysql_cond_t m_run_cond;
308   /* method completion conditions and locks */
309   mysql_mutex_t m_method_lock;
310   mysql_cond_t m_method_cond;
311 
312   /**The user for the session connection*/
313   const char *session_user;
314   /** Session thread method completion flag */
315   bool m_method_execution_completed;
316   /** The method return value */
317   long m_method_execution_return_value;
318   /** Session thread state */
319   thread_state m_session_thread_state;
320   /** Session termination flag */
321   bool m_session_thread_terminate;
322   /** Session tread error flag */
323   int m_session_thread_error;
324 };
325 
326 class Sql_service_command_interface {
327  public:
328   Sql_service_command_interface();
329   ~Sql_service_command_interface();
330 
331   /**
332     Establishes the connection to the server.
333 
334     @param isolation_param  session creation requirements: use current thread,
335                             use thread but initialize it or create it in a
336                             dedicated thread
337     @param user             the user for the connection
338     @param plugin_pointer   the plugin pointer for threaded connections
339 
340     @return the connection was successful
341       @retval 0      OK
342       @retval !=0    Error
343   */
344   int establish_session_connection(enum_plugin_con_isolation isolation_param,
345                                    const char *user,
346                                    void *plugin_pointer = nullptr);
347 
348   /**
349     Terminates the old connection and creates a new one to the server.
350 
351     @param isolation_param  session creation requirements: use current thread,
352                             use thread but initialize it or create it in a
353                             dedicated thread
354     @param user             the user for the connection
355     @param plugin_pointer   the plugin pointer for threaded connections
356 
357     @return the connection was successful
358       @retval 0      OK
359       @retval !=0    Error
360   */
361   int reestablish_connection(enum_plugin_con_isolation isolation_param,
362                              const char *user, void *plugin_pointer = nullptr);
363   /**
364     Was this session killed?
365 
366     @retval true   session was killed
367     @retval false  session was not killed
368   */
369   bool is_session_killed();
370 
371   /**
372     Stops and deletes all connection related structures
373   */
374   void terminate_connection_fields();
375 
376   /**
377     Returns the SQL service interface associated to this class
378 
379     @return the sql service interface field
380   */
381   Sql_service_interface *get_sql_service_interface();
382 
383   /**
384     Sets the SQL API user to be used on security checks
385 
386     @param user the user to be used
387 
388     @return the operation was successful
389       @retval 0      OK
390       @retval !=0    Error
391   */
392   int set_interface_user(const char *user);
393 
394   /**
395    Method to kill the session identified by the given session id in those
396    cases where the server hangs while executing the sql query.
397 
398    @param session_id  id of the session to be killed.
399 
400    @return the error value returned
401       @retval 0  - success
402       @retval >0 - Failure
403   */
404   long kill_session(unsigned long session_id);
405 
406   /**
407     Checks if there is an existing session
408 
409     @return the error value returned
410       @retval true  valid
411       @retval false some issue prob happened on connection
412   */
413   bool is_session_valid();
414 
415   /**
416     Method to set the super_read_only variable "ON".
417 
418     @return error code during execution of the sql query.
419        @retval 0  - success
420        @retval >0 - failure
421   */
422   long set_super_read_only();
423 
424   /**
425     Method to reset the super_read_only mode back to "OFF" on the
426     server.
427 
428     @return error code during execution of the sql query.
429        @retval 0  - success
430        @retval >0 - failure
431   */
432   long reset_super_read_only();
433 
434   /**
435     Method to reset the read_only mode back to "OFF" on the
436     server.
437 
438     @return error code during execution of the sql query.
439       @retval 0  -  success
440       @retval >0 - failure
441   */
442   long reset_read_only();
443 
444   /**
445     Method to return the server gtid_executed by executing the corresponding
446     sql query.
447 
448     @param [out] gtid_executed The string where the result will be appended
449 
450     @return the error value returned
451       @retval 0      OK
452       @retval !=0    Error
453   */
454   int get_server_gtid_executed(std::string &gtid_executed);
455 
456   /**
457     Method to return the server gtid_purged by executing the corresponding
458     sql query.
459 
460     @param [out] gtid_purged The string where the result will be appended
461 
462     @return the error value returned
463       @retval 0      OK
464       @retval !=0    Error
465   */
466   int get_server_gtid_purged(std::string &gtid_purged);
467 
468   /**
469     Method to wait for the server gtid_executed to match the given GTID string
470 
471     @param [in] gtid_executed  The GTID string to check
472     @param [in] timeout        The timeout after which the method should break
473 
474     @return the error value returned
475       @retval 0    OK
476       @retval -1   Timeout on the GTID wait
477       @retval 1    Error when executed
478   */
479   long wait_for_server_gtid_executed(std::string &gtid_executed,
480                                      int timeout = 0);
481 
482   /**
483     Method to get the value of the super_read_only variable on the server.
484 
485     @retval -1  Error reading the value
486     @retval  0  Not in super read mode
487     @retval  1  In read super mode
488   */
489   long get_server_super_read_only();
490 
491   /**
492     Method to get the value of the read_only variable on the server.
493 
494     @retval -1  Error reading the value
495     @retval  0  Not in super read mode
496     @retval  1  In read super mode
497   */
498   long get_server_read_only();
499 
500   /**
501     Method to set a variable using SET PERSIST_ONLY
502     @param variable the variable name
503     @param value the value for the variable
504     @return the error value returned
505       @retval 0      OK
506       @retval !=0    Error
507   */
508   long set_persist_only_variable(std::string &variable, std::string &value);
509 
510   /**
511     Method to remotely clone a server
512 
513     @param [in] host      The host to clone
514     @param [in] port      The host port
515     @param [in] username  The username to authenticate in the remote server
516     @param [in] password  The password to authenticate in the remote server
517     @param [in] use_ssl   Is ssl configured for the clone process
518     @param [out] error    The error message in case of error
519 
520     @return the error value returned
521       @retval 0      OK
522       @retval !=0    Error on execution
523   */
524   long clone_server(std::string &host, std::string &port, std::string &username,
525                     std::string &password, bool use_ssl, std::string &error);
526 
527   /**
528     Execute a query passed as parameter.
529 
530     @param [in] query      The query to execute
531 
532     @return the error value returned
533       @retval 0      OK
534       @retval !=0    Error on execution
535   */
536   long execute_query(std::string &query);
537 
538   /**
539     Execute a query passed as parameter.
540 
541     @param [in] query      The query to execute
542     @param [out] error     The error message in case of error
543 
544     @return the error value returned
545       @retval 0      OK
546       @retval !=0    Error on execution
547   */
548   long execute_query(std::string &query, std::string &error);
549 
550   /**
551     Execute a conditional query passed as parameter.
552 
553     @param [in] query      The query to execute
554     @param [in] result     The result of the query
555 
556     @return the error value returned
557       @retval 0      OK
558       @retval !=0    Error on execution
559   */
560   long execute_conditional_query(std::string &query, bool *result);
561 
562   /**
563     Execute a conditional query passed as parameter.
564 
565     @param [in] query      The query to execute
566     @param [in] result     The result of the query
567     @param [out] error     The error message in case of error
568 
569     @return the error value returned
570       @retval 0      OK
571       @retval !=0    Error on execution
572   */
573   long execute_conditional_query(std::string &query, bool *result,
574                                  std::string &error);
575 
576   /**
577     Method to set the offline_mode variable "ON".
578 
579     @return error code during execution of the sql query.
580        @retval 0  - success
581        @retval >0 - failure
582   */
583   long set_offline_mode();
584 
585  private:
586   enum_plugin_con_isolation connection_thread_isolation;
587 
588   Sql_service_commands sql_service_commands;
589 
590   /** The internal SQL session service interface to the server */
591   Sql_service_interface *m_server_interface;
592 
593   /* The thread where the connection leaves if isolation is needed*/
594   Session_plugin_thread *m_plugin_session_thread;
595 };
596 
597 #endif  // SQL_SERVICE_COMMAND_INCLUDE
598