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
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22    02110-1301 USA */
23 
24 #include "rpl_gtid.h"
25 
26 #include "rpl_rli.h"                          // Relay_log_info
27 #include "sql_class.h"                        // THD
28 #include "sql_parse.h"                        // stmt_causes_implicit_commit
29 
30 #include "pfs_transaction_provider.h"
31 #include "mysql/psi/mysql_transaction.h"
32 
33 
34 
set_gtid_next(THD * thd,const Gtid_specification & spec)35 bool set_gtid_next(THD *thd, const Gtid_specification &spec)
36 {
37   DBUG_ENTER("set_gtid_next");
38 
39   spec.dbug_print();
40   global_sid_lock->assert_some_lock();
41   int lock_count= 1;
42   bool ret= true;
43 
44   // we may acquire and release locks throughout this function; this
45   // variable tells the error handler how many are left to release
46 
47   // Check that we don't own a GTID or ANONYMOUS.
48   if (thd->owned_gtid.sidno > 0 ||
49       thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS)
50   {
51     char buf[Gtid::MAX_TEXT_LENGTH + 1];
52     if (thd->owned_gtid.sidno > 0)
53     {
54 #ifndef NDEBUG
55       global_sid_lock->unlock();
56       global_sid_lock->wrlock();
57       assert(gtid_state->get_owned_gtids()->
58              thread_owns_anything(thd->thread_id()));
59 #endif
60       thd->owned_gtid.to_string(thd->owned_sid, buf);
61     }
62     else
63     {
64       assert(gtid_state->get_anonymous_ownership_count() > 0);
65       strcpy(buf, "ANONYMOUS");
66     }
67     my_error(ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID, MYF(0), buf);
68     goto err;
69   }
70 
71   // At this point we should not own any GTID.
72   assert(thd->owned_gtid.is_empty());
73 
74   if (spec.type == AUTOMATIC_GROUP)
75   {
76     thd->variables.gtid_next.set_automatic();
77   }
78   else if (spec.type == ANONYMOUS_GROUP)
79   {
80     if (get_gtid_mode(GTID_MODE_LOCK_SID) == GTID_MODE_ON)
81     {
82       my_error(ER_CANT_SET_GTID_NEXT_TO_ANONYMOUS_WHEN_GTID_MODE_IS_ON, MYF(0));
83       goto err;
84     }
85 
86     thd->variables.gtid_next.set_anonymous();
87     thd->owned_gtid.sidno= THD::OWNED_SIDNO_ANONYMOUS;
88     thd->owned_gtid.gno= 0;
89     gtid_state->acquire_anonymous_ownership();
90   }
91   else
92   {
93     assert(spec.type == GTID_GROUP);
94     assert(spec.gtid.sidno >= 1);
95     assert(spec.gtid.gno >= 1);
96     assert(spec.gtid.gno < GNO_END);
97     while (true)
98     {
99       // loop invariant: we should always hold global_sid_lock.rdlock
100       assert(lock_count == 1);
101       global_sid_lock->assert_some_lock();
102 
103       if (get_gtid_mode(GTID_MODE_LOCK_SID) == GTID_MODE_OFF)
104       {
105         my_error(ER_CANT_SET_GTID_NEXT_TO_GTID_WHEN_GTID_MODE_IS_OFF, MYF(0));
106         goto err;
107       }
108 
109       // acquire lock before checking conditions
110       gtid_state->lock_sidno(spec.gtid.sidno);
111       lock_count= 2;
112 
113       // GTID already logged
114       if (gtid_state->is_executed(spec.gtid))
115       {
116         thd->variables.gtid_next= spec;
117         /*
118           Don't skip the statement here, skip it in
119           gtid_pre_statement_checks.
120         */
121         break;
122       }
123 
124       // GTID not owned by anyone: acquire ownership
125       if (!gtid_state->is_owned(spec.gtid))
126       {
127         // acquire_ownership can't fail
128         gtid_state->acquire_ownership(thd, spec.gtid);
129         thd->variables.gtid_next= spec;
130         assert(thd->owned_gtid.sidno >= 1);
131         assert(thd->owned_gtid.gno >= 1);
132         assert(thd->owned_gtid.gno < GNO_END);
133         break;
134       }
135       // GTID owned by someone (other thread)
136       else
137       {
138         // The call below releases the read lock on global_sid_lock and
139         // the mutex lock on SIDNO.
140         gtid_state->wait_for_gtid(thd, spec.gtid);
141 
142         // global_sid_lock and mutex are now released
143         lock_count= 0;
144 
145         // Check if thread was killed.
146         if (thd->killed || abort_loop)
147         {
148           goto err;
149         }
150 #ifdef HAVE_REPLICATION
151         // If this thread is a slave SQL thread or slave SQL worker
152         // thread, we need this additional condition to determine if it
153         // has been stopped by STOP SLAVE [SQL_THREAD].
154         if ((thd->system_thread &
155              (SYSTEM_THREAD_SLAVE_SQL | SYSTEM_THREAD_SLAVE_WORKER)) != 0)
156         {
157           // TODO: error is *not* reported on cancel
158           assert(thd->rli_slave!= NULL);
159           Relay_log_info *c_rli= thd->rli_slave->get_c_rli();
160           if (c_rli->abort_slave)
161           {
162             goto err;
163           }
164         }
165 #endif // HAVE_REPLICATION
166         global_sid_lock->rdlock();
167         lock_count= 1;
168       }
169     }
170   }
171 
172   ret= false;
173 
174 err:
175   if (lock_count == 2)
176     gtid_state->unlock_sidno(spec.gtid.sidno);
177 
178   if (lock_count >= 1)
179     global_sid_lock->unlock();
180 
181   if (!ret)
182     gtid_set_performance_schema_values(thd);
183   thd->owned_gtid.dbug_print(NULL, "Set owned_gtid in set_gtid_next");
184 
185   DBUG_RETURN(ret);
186 }
187 
188 
189 /**
190   Acquire ownership of all groups in a Gtid_set.  This is used to
191   begin a commit-sequence when @@SESSION.GTID_NEXT_LIST != NULL.
192 */
193 #ifdef HAVE_GTID_NEXT_LIST
gtid_acquire_ownership_multiple(THD * thd)194 int gtid_acquire_ownership_multiple(THD *thd)
195 {
196   const Gtid_set *gtid_next_list= thd->get_gtid_next_list_const();
197   rpl_sidno greatest_sidno= 0;
198   DBUG_ENTER("gtid_acquire_ownership_multiple");
199   // first check if we need to wait for any group
200   while (true)
201   {
202     Gtid_set::Gtid_iterator git(gtid_next_list);
203     Gtid g= git.get();
204     my_thread_id owner= 0;
205     rpl_sidno last_sidno= 0;
206     global_sid_lock->rdlock();
207     while (g.sidno != 0)
208     {
209       // lock all SIDNOs in order
210       if (g.sidno != last_sidno)
211         gtid_state->lock_sidno(g.sidno);
212       if (!gtid_state->is_executed(g))
213       {
214         owner= gtid_state->get_owner(g);
215         // break the do-loop and wait for the sid to be updated
216         if (owner != 0)
217         {
218           assert(owner != thd->id);
219           break;
220         }
221       }
222       last_sidno= g.sidno;
223       greatest_sidno= g.sidno;
224       git.next();
225       g= git.get();
226     }
227 
228     // we don't need to wait for any groups, and all SIDNOs in the
229     // set are locked
230     if (g.sidno == 0)
231       break;
232 
233     // unlock all previous sidnos to avoid blocking them
234     // while waiting.  keep lock on g.sidno
235     for (rpl_sidno sidno= 1; sidno < g.sidno; sidno++)
236       if (gtid_next_list->contains_sidno(sidno))
237         gtid_state->unlock_sidno(sidno);
238 
239     // wait. this call releases the read lock on global_sid_lock and
240     // the mutex lock on SIDNO
241     gtid_state->wait_for_gtid(thd, g);
242 
243     // global_sid_lock and mutex are now released
244 
245     // at this point, we don't hold any locks. re-acquire the global
246     // read lock that was held when this function was invoked
247     if (thd->killed || abort_loop)
248       DBUG_RETURN(1);
249 #ifdef HAVE_REPLICATION
250     // If this thread is a slave SQL thread or slave SQL worker
251     // thread, we need this additional condition to determine if it
252     // has been stopped by STOP SLAVE [SQL_THREAD].
253     if ((thd->system_thread &
254          (SYSTEM_THREAD_SLAVE_SQL | SYSTEM_THREAD_SLAVE_WORKER)) != 0)
255     {
256       assert(thd->rli_slave != NULL);
257       Relay_log_info *c_rli= thd->rli_slave->get_c_rli();
258       if (c_rli->abort_slave)
259         DBUG_RETURN(1);
260     }
261 #endif // HAVE_REPLICATION
262   }
263 
264   // global_sid_lock is now held
265   thd->owned_gtid_set.ensure_sidno(greatest_sidno);
266 
267   /*
268     Now the following hold:
269      - None of the GTIDs in GTID_NEXT_LIST is owned by any thread.
270      - We hold a lock on global_sid_lock.
271      - We hold a lock on all SIDNOs in GTID_NEXT_LIST.
272     So we acquire ownership of all groups that we need.
273   */
274   int ret= 0;
275   Gtid_set::Gtid_iterator git(gtid_next_list);
276   Gtid g= git.get();
277   do
278   {
279     if (!gtid_state->is_executed(g))
280     {
281       if (gtid_state->acquire_ownership(thd, g) != RETURN_STATUS_OK)
282       {
283         /// @todo release ownership on error
284         ret= 1;
285         break;
286       }
287       thd->owned_gtid_set._add_gtid(g);
288     }
289     git.next();
290     g= git.get();
291   } while (g.sidno != 0);
292 
293   // unlock all sidnos
294   rpl_sidno max_sidno= gtid_next_list->get_max_sidno();
295   for (rpl_sidno sidno= 1; sidno <= max_sidno; sidno++)
296     if (gtid_next_list->contains_sidno(sidno))
297       gtid_state->unlock_sidno(sidno);
298 
299   global_sid_lock->unlock();
300 
301   /*
302     TODO: If this code is enabled, set the GTID in the Performance Schema,
303     similar to set_gtid_next().
304   */
305 
306   DBUG_RETURN(ret);
307 }
308 #endif
309 
310 
311 /**
312   Check if current transaction should be skipped, that is, if GTID_NEXT
313   was already logged.
314 
315   @param  thd    The calling thread.
316 
317   @retval true   Transaction was already logged.
318   @retval false  Transaction must be executed.
319 */
is_already_logged_transaction(const THD * thd)320 bool is_already_logged_transaction(const THD *thd)
321 {
322   DBUG_ENTER("is_already_logged_transaction");
323 
324   const Gtid_specification *gtid_next= &thd->variables.gtid_next;
325   const Gtid_set *gtid_next_list= thd->get_gtid_next_list_const();
326 
327   if (gtid_next_list == NULL)
328   {
329     if (gtid_next->type == GTID_GROUP)
330     {
331       if (thd->owned_gtid.sidno == 0)
332         DBUG_RETURN(true);
333       else
334         assert(thd->owned_gtid.equals(gtid_next->gtid));
335     }
336     else
337       assert(thd->owned_gtid.sidno == 0 ||
338              thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS);
339   }
340   else
341   {
342 #ifdef HAVE_GTID_NEXT_LIST
343     if (gtid_next->type == GTID_GROUP)
344     {
345       assert(gtid_next_list->contains_gtid(gtid_next->gtid));
346       if (!thd->owned_gtid_set.contains_gtid(gtid_next->gtid))
347         DBUG_RETURN(true);
348     }
349 #else
350     assert(0);/*NOTREACHED*/
351 #endif
352   }
353 
354   DBUG_RETURN(false);
355 }
356 
357 
358 /**
359   Debug code executed when a transaction is skipped.
360 
361   @param  thd     The calling thread.
362 */
skip_statement(const THD * thd)363 static inline void skip_statement(const THD *thd)
364 {
365   DBUG_ENTER("skip_statement");
366 
367   DBUG_PRINT("info", ("skipping statement '%s'. "
368                       "gtid_next->type=%d sql_command=%d "
369                       "thd->thread_id=%u",
370                       thd->query().str,
371                       thd->variables.gtid_next.type,
372                       thd->lex->sql_command,
373                       thd->thread_id()));
374 
375 #ifndef NDEBUG
376   const Gtid_set* executed_gtids= gtid_state->get_executed_gtids();
377   global_sid_lock->rdlock();
378   gtid_state->lock_sidno(thd->variables.gtid_next.gtid.sidno);
379   assert(executed_gtids->contains_gtid(thd->variables.gtid_next.gtid));
380   gtid_state->unlock_sidno(thd->variables.gtid_next.gtid.sidno);
381   global_sid_lock->unlock();
382 #endif
383 
384   DBUG_VOID_RETURN;
385 }
386 
387 
gtid_reacquire_ownership_if_anonymous(THD * thd)388 bool gtid_reacquire_ownership_if_anonymous(THD *thd)
389 {
390   DBUG_ENTER("gtid_reacquire_ownership_if_anonymous(THD *)");
391   Gtid_specification *gtid_next= &thd->variables.gtid_next;
392   /*
393     When the slave applier thread executes a
394     Format_description_log_event originating from a master
395     (corresponding to a new master binary log), it sets gtid_next to
396     NOT_YET_DETERMINED_GROUP.  This allows any following
397     Gtid_log_event to set the GTID appropriately, but if there is no
398     Gtid_log_event, gtid_next will be converted to ANONYMOUS.
399   */
400   DBUG_PRINT("info", ("gtid_next->type=%d gtid_mode=%s",
401                       gtid_next->type,
402                       get_gtid_mode_string(GTID_MODE_LOCK_NONE)));
403   if (gtid_next->type == NOT_YET_DETERMINED_GROUP ||
404       (gtid_next->type == ANONYMOUS_GROUP && thd->owned_gtid.sidno == 0))
405   {
406     Gtid_specification spec;
407     spec.set_anonymous();
408     DBUG_PRINT("info", ("acquiring ANONYMOUS ownership"));
409 
410     global_sid_lock->rdlock();
411     // set_gtid_next releases global_sid_lock
412     if (set_gtid_next(thd, spec))
413       // this can happen if gtid_mode=on
414       DBUG_RETURN(true);
415 
416 #ifdef HAVE_REPLICATION
417     thd->set_currently_executing_gtid_for_slave_thread();
418 #endif
419   }
420   DBUG_RETURN(false);
421 }
422 
423 
424 /**
425   Return true if the statement does not invoke any stored function,
426   and is one of the following:
427   - SET (except SET PASSWORD)
428   - SHOW
429   - SELECT
430   - DO
431   - An empty statement because of a skipped version comment
432   That means it is guaranteed not to cause any changes in the
433   database.
434 */
is_stmt_innocent(const THD * thd)435 static bool is_stmt_innocent(const THD *thd)
436 {
437   LEX *lex= thd->lex;
438   enum_sql_command sql_command= lex->sql_command;
439   bool is_show=
440     (sql_command_flags[sql_command] & CF_STATUS_COMMAND) &&
441     (sql_command != SQLCOM_BINLOG_BASE64_EVENT);
442   bool is_set=
443     (sql_command == SQLCOM_SET_OPTION) && !lex->is_set_password_sql;
444   bool is_select= (sql_command == SQLCOM_SELECT);
445   bool is_do= (sql_command == SQLCOM_DO);
446   bool is_empty= (sql_command == SQLCOM_EMPTY_QUERY);
447   bool is_use= (sql_command == SQLCOM_CHANGE_DB);
448   return
449     (is_set || is_select || is_do || is_show || is_empty ||
450      is_use) &&
451     !lex->uses_stored_routines();
452 }
453 
454 
gtid_pre_statement_checks(THD * thd)455 enum_gtid_statement_status gtid_pre_statement_checks(THD *thd)
456 {
457   DBUG_ENTER("gtid_pre_statement_checks");
458 
459   Gtid_specification *gtid_next= &thd->variables.gtid_next;
460 
461   DBUG_PRINT("info", ("gtid_next->type=%d "
462                       "owned_gtid.{sidno,gno}={%d,%lld}",
463                       gtid_next->type,
464                       thd->owned_gtid.sidno, thd->owned_gtid.gno));
465   assert(gtid_next->type != AUTOMATIC_GROUP ||
466          thd->owned_gtid.is_empty());
467 
468   if ((stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_BEGIN) ||
469        thd->lex->sql_command == SQLCOM_BEGIN) &&
470       thd->in_active_multi_stmt_transaction() &&
471       gtid_next->type == GTID_GROUP)
472   {
473     my_error(ER_CANT_DO_IMPLICIT_COMMIT_IN_TRX_WHEN_GTID_NEXT_IS_SET, MYF(0));
474     DBUG_RETURN(GTID_STATEMENT_CANCEL);
475   }
476 
477   /*
478     Always allow:
479     - BEGIN/COMMIT/ROLLBACK;
480     - innocent statements, i.e., SET/SHOW/DO/SELECT which don't invoke
481       stored functions.
482 
483     @todo: add flag to sql_command_flags to detect if statement
484     controls transactions instead of listing the commands in the
485     condition below
486 
487     @todo: figure out how to handle SQLCOM_XA_*
488   */
489   const enum_sql_command sql_command= thd->lex->sql_command;
490   if (sql_command == SQLCOM_COMMIT || sql_command == SQLCOM_BEGIN ||
491       sql_command == SQLCOM_ROLLBACK || is_stmt_innocent(thd))
492     DBUG_RETURN(GTID_STATEMENT_EXECUTE);
493 
494   /*
495     If a transaction updates both non-transactional and transactional
496     table; or if it updates more than one non-transactional tables;
497     then the transaction must be stopped.  This is the case when on
498     master all updated tables are transactional but on slave at least
499     one is non-transactional, e.g.:
500 
501     On master, tables are transactional:
502       CREATE TABLE t1 (a INT) Engine=InnoDB;
503       CREATE TABLE t2 (a INT) Engine=InnoDB;
504     On slave, one table is non-transactional:
505       CREATE TABLE t1 (a INT) Engine=MyISAM;
506       CREATE TABLE t2 (a INT) Engine=InnoDB;
507     On master, user executes:
508       BEGIN;
509       INSERT INTO t1 VALUES (1);
510       INSERT INTO t2 VALUES (1);
511       COMMIT;
512     On slave, the second statement must error due to a second statement
513     being executed after a statement that updated a non-transactional
514     table.
515   */
516   if (UNDEFINED_GROUP == gtid_next->type)
517   {
518     char buf[Gtid::MAX_TEXT_LENGTH + 1];
519     global_sid_lock->rdlock();
520     gtid_next->to_string(global_sid_map, buf);
521     global_sid_lock->unlock();
522     my_error(ER_GTID_NEXT_TYPE_UNDEFINED_GROUP, MYF(0), buf);
523     DBUG_RETURN(GTID_STATEMENT_CANCEL);
524   }
525 
526   const Gtid_set *gtid_next_list= thd->get_gtid_next_list_const();
527 
528   DBUG_PRINT("info", ("gtid_next_list=%p gtid_next->type=%d "
529                       "thd->owned_gtid.gtid.{sidno,gno}={%d,%lld} "
530                       "thd->thread_id=%u",
531                       gtid_next_list, gtid_next->type,
532                       thd->owned_gtid.sidno,
533                       thd->owned_gtid.gno,
534                       thd->thread_id()));
535 
536   const bool skip_transaction= is_already_logged_transaction(thd);
537   if (gtid_next_list == NULL)
538   {
539     if (skip_transaction)
540     {
541       skip_statement(thd);
542       DBUG_RETURN(GTID_STATEMENT_SKIP);
543     }
544     DBUG_RETURN(GTID_STATEMENT_EXECUTE);
545   }
546   else
547   {
548 #ifdef HAVE_GTID_NEXT_LIST
549     switch (gtid_next->type)
550     {
551     case AUTOMATIC_GROUP:
552       my_error(ER_GTID_NEXT_CANT_BE_AUTOMATIC_IF_GTID_NEXT_LIST_IS_NON_NULL,
553                MYF(0));
554       DBUG_RETURN(GTID_STATEMENT_CANCEL);
555     case GTID_GROUP:
556       if (skip_transaction)
557       {
558         skip_statement(thd);
559         DBUG_RETURN(GTID_STATEMENT_SKIP);
560       }
561       /*FALLTHROUGH*/
562     case ANONYMOUS_GROUP:
563       DBUG_RETURN(GTID_STATEMENT_EXECUTE);
564     case INVALID_GROUP:
565       assert(0);/*NOTREACHED*/
566     }
567 #else
568     assert(0);/*NOTREACHED*/
569 #endif
570   }
571   assert(0);/*NOTREACHED*/
572   DBUG_RETURN(GTID_STATEMENT_CANCEL);
573 }
574 
575 
gtid_pre_statement_post_implicit_commit_checks(THD * thd)576 bool gtid_pre_statement_post_implicit_commit_checks(THD *thd)
577 {
578   DBUG_ENTER("gtid_pre_statement_post_implicit_commit_checks");
579 
580   /*
581     Ensure that we hold anonymous ownership before executing any
582     statement, if gtid_next=anonymous or not_yet_determined.  But do
583     not re-acquire anonymous ownership if the statement is 'innocent'.
584     Innocent commands are those that cannot get written to the binary
585     log and cannot commit any ongoing transaction, i.e., one of the
586     SET/SELECT/DO/SHOW statements, as long as it does not invoke a
587     stored function.
588 
589     It is important that we don't try to reacquire ownership for
590     innocent commands: SET could be used to set GTID_NEXT to
591     UUID:NUMBER; if anonymous was acquired before this then it would
592     result in an error.  SHOW/SELECT/DO can be useful for testing
593     ownership logic, e.g., to read @@session.gtid_owned or to read
594     warnings using SHOW WARNINGS, and to test this properly it is
595     important to not affect the ownership status.
596   */
597   if (!is_stmt_innocent(thd))
598     if (gtid_reacquire_ownership_if_anonymous(thd))
599       // this can happen if gtid_mode is on
600       DBUG_RETURN(true);
601 
602   if (!thd->is_ddl_gtid_compatible())
603     DBUG_RETURN(true);
604 
605   DBUG_RETURN(false);
606 }
607 
608 
gtid_set_performance_schema_values(const THD * thd)609 void gtid_set_performance_schema_values(const THD *thd)
610 {
611   DBUG_ENTER("gtid_set_performance_schema_values");
612 #ifdef HAVE_PSI_TRANSACTION_INTERFACE
613   if (thd->m_transaction_psi != NULL)
614   {
615     Gtid_specification spec;
616 
617     // Thread owns GTID.
618     if (thd->owned_gtid.sidno >= 1)
619     {
620       spec.type= GTID_GROUP;
621       spec.gtid= thd->owned_gtid;
622     }
623 
624     // Thread owns ANONYMOUS.
625     else if (thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS)
626     {
627       spec.type= ANONYMOUS_GROUP;
628     }
629 
630     // Thread does not own anything.
631     else
632     {
633       assert(thd->owned_gtid.sidno == 0);
634       spec.type= AUTOMATIC_GROUP;
635     }
636     MYSQL_SET_TRANSACTION_GTID(thd->m_transaction_psi, &thd->owned_sid, &spec);
637   }
638 #endif
639   DBUG_VOID_RETURN;
640 }
641