MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rpl_info_table_access.cc
1 /* Copyright (c) 2010, 2013, 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 as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "rpl_info_table_access.h"
17 #include "rpl_utility.h"
18 #include "handler.h"
19 #include "sql_parse.h"
20 
47 bool Rpl_info_table_access::open_table(THD* thd, const LEX_STRING dbstr,
48  const LEX_STRING tbstr,
49  uint max_num_field,
50  enum thr_lock_type lock_type,
51  TABLE** table,
52  Open_tables_backup* backup)
53 {
54  TABLE_LIST tables;
55  Query_tables_list query_tables_list_backup;
56 
57  uint flags= (MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK |
58  MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY |
59  MYSQL_OPEN_IGNORE_FLUSH |
60  MYSQL_LOCK_IGNORE_TIMEOUT |
61  MYSQL_LOCK_RPL_INFO_TABLE);
62 
63  DBUG_ENTER("Rpl_info_table_access::open_table");
64 
65  /*
66  This is equivalent to a new "statement". For that reason, we call both
67  lex_start() and mysql_reset_thd_for_next_command.
68  */
69  if (thd->slave_thread || !current_thd)
70  {
71  lex_start(thd);
73  }
74 
75  /*
76  We need to use new Open_tables_state in order not to be affected
77  by LOCK TABLES/prelocked mode.
78  Also in order not to break execution of current statement we also
79  have to backup/reset/restore Query_tables_list part of LEX, which
80  is accessed and updated in the process of opening and locking
81  tables.
82  */
83  thd->lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
84  thd->reset_n_backup_open_tables_state(backup);
85 
86  tables.init_one_table(dbstr.str, dbstr.length, tbstr.str, tbstr.length,
87  tbstr.str, lock_type);
88 
89  if (!open_n_lock_single_table(thd, &tables, tables.lock_type, flags))
90  {
91  close_thread_tables(thd);
92  thd->restore_backup_open_tables_state(backup);
93  thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
94  my_error(ER_NO_SUCH_TABLE, MYF(0), dbstr.str, tbstr.str);
95  DBUG_RETURN(TRUE);
96  }
97 
98  DBUG_ASSERT(tables.table->s->table_category == TABLE_CATEGORY_RPL_INFO);
99 
100  if (tables.table->s->fields < max_num_field)
101  {
102  /*
103  Safety: this can only happen if someone started the server and then
104  altered the table.
105  */
106  ha_rollback_trans(thd, FALSE);
107  close_thread_tables(thd);
108  thd->restore_backup_open_tables_state(backup);
109  thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
110  my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2, MYF(0),
111  tables.table->s->db.str, tables.table->s->table_name.str,
112  max_num_field, tables.table->s->fields);
113  DBUG_RETURN(TRUE);
114  }
115 
116  thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
117 
118  *table= tables.table;
119  tables.table->use_all_columns();
120  DBUG_RETURN(FALSE);
121 }
122 
146  Open_tables_backup *backup,
147  bool error)
148 {
149  Query_tables_list query_tables_list_backup;
150 
151  DBUG_ENTER("Rpl_info_table_access::close_table");
152 
153  if (table)
154  {
155  if (error)
156  ha_rollback_trans(thd, FALSE);
157  else
158  {
159  /*
160  To make the commit not to block with global read lock set
161  "ignore_global_read_lock" flag to true.
162  */
163  ha_commit_trans(thd, FALSE, TRUE);
164  }
165  if (saved_current_thd != current_thd)
166  {
167  if (error)
168  ha_rollback_trans(thd, TRUE);
169  else
170  {
171  /*
172  To make the commit not to block with global read lock set
173  "ignore_global_read_lock" flag to true.
174  */
175  ha_commit_trans(thd, TRUE, TRUE);
176  }
177  }
178  /*
179  In order not to break execution of current statement we have to
180  backup/reset/restore Query_tables_list part of LEX, which is
181  accessed and updated in the process of closing tables.
182  */
183  thd->lex->reset_n_backup_query_tables_list(&query_tables_list_backup);
184  close_thread_tables(thd);
185  thd->lex->restore_backup_query_tables_list(&query_tables_list_backup);
186  thd->restore_backup_open_tables_state(backup);
187  }
188 
189  DBUG_RETURN(FALSE);
190 }
191 
206 enum enum_return_id Rpl_info_table_access::find_info(Rpl_info_values *field_values,
207  TABLE *table)
208 {
209  KEY* keyinfo= NULL;
210  uchar key[MAX_KEY_LENGTH];
211 
212  DBUG_ENTER("Rpl_info_table_access::find_info");
213 
214  /*
215  Checks if the table has a primary key as expected.
216  */
217  if (table->s->primary_key >= MAX_KEY ||
218  !table->s->keys_in_use.is_set(table->s->primary_key))
219  {
220  /*
221  This is not supposed to happen and means that someone
222  has changed the table or disabled the keys.
223  */
224  DBUG_RETURN(ERROR_ID);
225  }
226 
227  keyinfo= table->s->key_info + (uint) table->s->primary_key;
228  for (uint idx= 0; idx < keyinfo->user_defined_key_parts; idx++)
229  {
230  uint fieldnr= keyinfo->key_part[idx].fieldnr - 1;
231 
232  /*
233  The size of the field must be great to store data.
234  */
235  if (field_values->value[fieldnr].length() >
236  table->field[fieldnr]->field_length)
237  DBUG_RETURN(ERROR_ID);
238 
239  table->field[fieldnr]->store(field_values->value[fieldnr].c_ptr_safe(),
240  field_values->value[fieldnr].length(),
241  &my_charset_bin);
242  }
243  key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
244 
245  if (table->file->ha_index_read_idx_map(table->record[0], 0, key, HA_WHOLE_KEY,
246  HA_READ_KEY_EXACT))
247  DBUG_RETURN(NOT_FOUND_ID);
248 
249  DBUG_RETURN(FOUND_ID);
250 }
251 
270  uint instance)
271 {
272  int error= 0;
273  uint counter= 0;
274  enum enum_return_id ret= NOT_FOUND_ID;
275 
276  DBUG_ENTER("Rpl_info_table_access::scan_info");
277 
278  if ((error= table->file->ha_rnd_init(TRUE)))
279  DBUG_RETURN(ERROR_ID);
280 
281  do
282  {
283  error= table->file->ha_rnd_next(table->record[0]);
284  switch (error)
285  {
286  case 0:
287  counter++;
288  if (counter == instance)
289  {
290  ret= FOUND_ID;
291  error= HA_ERR_END_OF_FILE;
292  }
293  break;
294 
295  case HA_ERR_END_OF_FILE:
296  ret= NOT_FOUND_ID;
297  break;
298 
299  default:
300  DBUG_PRINT("info", ("Failed to get next record"
301  " (ha_rnd_next returns %d)", error));
302  ret= ERROR_ID;
303  break;
304  }
305  }
306  while (!error);
307 
308  table->file->ha_rnd_end();
309 
310  DBUG_RETURN(ret);
311 }
312 
330 {
331  bool end= false;
332  int error= 0;
333 
334  DBUG_ENTER("Rpl_info_table_access::count_info");
335 
336  if ((error= table->file->ha_rnd_init(true)))
337  DBUG_RETURN(true);
338 
339  do
340  {
341  error= table->file->ha_rnd_next(table->record[0]);
342  switch (error)
343  {
344  case 0:
345  (*counter)++;
346  break;
347 
348  case HA_ERR_END_OF_FILE:
349  end= true;
350  break;
351 
352  default:
353  DBUG_PRINT("info", ("Failed to get next record"
354  " (ha_rnd_next returns %d)", error));
355  break;
356  }
357  }
358  while (!error);
359 
360  table->file->ha_rnd_end();
361 
362  DBUG_RETURN(end ? false : true);
363 }
364 
378 bool Rpl_info_table_access::load_info_values(uint max_num_field, Field **fields,
379  Rpl_info_values *field_values)
380 {
381  DBUG_ENTER("Rpl_info_table_access::load_info_values");
382  char buff[MAX_FIELD_WIDTH];
383  String str(buff, sizeof(buff), &my_charset_bin);
384 
385  uint field_idx= 0;
386  while (field_idx < max_num_field)
387  {
388  fields[field_idx]->val_str(&str);
389  field_values->value[field_idx].copy(str.c_ptr_safe(), str.length(),
390  &my_charset_bin);
391  field_idx++;
392  }
393 
394  DBUG_RETURN(FALSE);
395 }
396 
410 bool Rpl_info_table_access::store_info_values(uint max_num_field, Field **fields,
411  Rpl_info_values *field_values)
412 {
413  DBUG_ENTER("Rpl_info_table_access::store_info_values");
414  uint field_idx= 0;
415 
416  while (field_idx < max_num_field)
417  {
418  fields[field_idx]->set_notnull();
419 
420  if (fields[field_idx]->store(field_values->value[field_idx].c_ptr_safe(),
421  field_values->value[field_idx].length(),
422  &my_charset_bin))
423  {
424  my_error(ER_RPL_INFO_DATA_TOO_LONG, MYF(0),
425  fields[field_idx]->field_name);
426  DBUG_RETURN(TRUE);
427  }
428  field_idx++;
429  }
430 
431  DBUG_RETURN(FALSE);
432 }
433 
443 {
444  THD *thd= NULL;
445  saved_current_thd= current_thd;
446 
447  if (!current_thd)
448  {
449  thd= new THD;
450  thd->thread_stack= (char*) &thd;
451  thd->store_globals();
452  thd->security_ctx->skip_grants();
453  thd->system_thread= SYSTEM_THREAD_INFO_REPOSITORY;
454  }
455  else
456  thd= current_thd;
457 
458  return(thd);
459 }
460 
472 {
473  DBUG_ENTER("Rpl_info::drop_thd");
474 
475  if (saved_current_thd != current_thd)
476  {
477  delete thd;
478  my_pthread_setspecific_ptr(THR_THD, NULL);
479  }
480 
481  DBUG_RETURN(FALSE);
482 }