1 /* Copyright (c) 2014, 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
22    02110-1301 USA */
23 
24 #include "rpl_table_access.h"
25 
26 #include "handler.h"     // ha_rollback_trans
27 #include "log.h"         // sql_print_warning
28 #include "sql_base.h"    // close_thread_tables
29 #include "sql_class.h"   // THD
30 #include "sql_lex.h"     // Query_tables_list
31 #include "table.h"       // TABLE_LIST
32 
33 
open_table(THD * thd,const LEX_STRING dbstr,const LEX_STRING tbstr,uint max_num_field,enum thr_lock_type lock_type,TABLE ** table,Open_tables_backup * backup)34 bool System_table_access::open_table(THD* thd, const LEX_STRING dbstr,
35                                      const LEX_STRING tbstr,
36                                      uint max_num_field,
37                                      enum thr_lock_type lock_type,
38                                      TABLE** table,
39                                      Open_tables_backup* backup)
40 {
41   TABLE_LIST tables;
42   Query_tables_list query_tables_list_backup;
43 
44   DBUG_ENTER("System_table_access::open_table");
45   before_open(thd);
46 
47   /*
48     We need to use new Open_tables_state in order not to be affected
49     by LOCK TABLES/prelocked mode.
50     Also in order not to break execution of current statement we also
51     have to backup/reset/restore Query_tables_list part of LEX, which
52     is accessed and updated in the process of opening and locking
53     tables.
54   */
55   thd->lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
56   thd->reset_n_backup_open_tables_state(backup);
57 
58   tables.init_one_table(dbstr.str, dbstr.length, tbstr.str, tbstr.length,
59                         tbstr.str, lock_type);
60 
61   tables.open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
62 
63   if (!open_n_lock_single_table(thd, &tables, tables.lock_type, m_flags))
64   {
65     close_thread_tables(thd);
66     thd->restore_backup_open_tables_state(backup);
67     thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
68     if (thd->is_operating_gtid_table_implicitly)
69       sql_print_warning("Gtid table is not ready to be used. Table '%s.%s' "
70                         "cannot be opened.", dbstr.str, tbstr.str);
71     else
72       my_error(ER_NO_SUCH_TABLE, MYF(0), dbstr.str, tbstr.str);
73     DBUG_RETURN(true);
74   }
75 
76   if (tables.table->s->fields < max_num_field)
77   {
78     /*
79       Safety: this can only happen if someone started the server and then
80       altered the table.
81     */
82     ha_rollback_trans(thd, false);
83     close_thread_tables(thd);
84     thd->restore_backup_open_tables_state(backup);
85     thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
86     my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2, MYF(0),
87              tables.table->s->db.str, tables.table->s->table_name.str,
88              max_num_field, tables.table->s->fields);
89     DBUG_RETURN(true);
90   }
91 
92   thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
93 
94   *table= tables.table;
95   tables.table->use_all_columns();
96   DBUG_RETURN(false);
97 }
98 
99 
close_table(THD * thd,TABLE * table,Open_tables_backup * backup,bool error,bool need_commit)100 bool System_table_access::close_table(THD *thd, TABLE* table,
101                                       Open_tables_backup *backup,
102                                       bool error, bool need_commit)
103 {
104   Query_tables_list query_tables_list_backup;
105   bool res= false;
106 
107   DBUG_ENTER("System_table_access::close_table");
108 
109   if (table)
110   {
111     if (error)
112       res= ha_rollback_trans(thd, false);
113     else
114     {
115       /*
116         To make the commit not to block with global read lock set
117         "ignore_global_read_lock" flag to true.
118        */
119       res= ha_commit_trans(thd, false, true);
120     }
121     if (need_commit)
122     {
123       if (error)
124         res= ha_rollback_trans(thd, true) || res;
125       else
126       {
127         /*
128           To make the commit not to block with global read lock set
129           "ignore_global_read_lock" flag to true.
130          */
131         res= ha_commit_trans(thd, true, true) || res;
132       }
133     }
134     /*
135       In order not to break execution of current statement we have to
136       backup/reset/restore Query_tables_list part of LEX, which is
137       accessed and updated in the process of closing tables.
138     */
139     thd->lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
140     close_thread_tables(thd);
141     thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
142     thd->restore_backup_open_tables_state(backup);
143   }
144 
145   DBUG_EXECUTE_IF("simulate_flush_commit_error", {res= true;});
146   DBUG_RETURN(res);
147 }
148 
149 
create_thd()150 THD *System_table_access::create_thd()
151 {
152   THD *thd= NULL;
153   thd= new THD;
154   thd->thread_stack= (char*) &thd;
155   thd->store_globals();
156   thd->security_context()->skip_grants();
157 
158   return(thd);
159 }
160 
161 
drop_thd(THD * thd)162 void System_table_access::drop_thd(THD *thd)
163 {
164   DBUG_ENTER("System_table_access::drop_thd");
165 
166   delete thd;
167   my_thread_set_THR_THD(NULL);
168 
169   DBUG_VOID_RETURN;
170 }
171 
172