MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
archive_reader.c
1 /* Copyright (c) 2007, 2010, 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 "azlib.h"
17 #include <string.h>
18 #include <assert.h>
19 #include <stdio.h>
20 #include <stdarg.h>
21 #include <m_ctype.h>
22 #include <m_string.h>
23 #include <my_getopt.h>
24 #include <mysql_version.h>
25 
26 #define BUFFER_LEN 1024
27 #define ARCHIVE_ROW_HEADER_SIZE 4
28 
29 #define SHOW_VERSION "0.1"
30 
31 static void get_options(int *argc,char * * *argv);
32 static void print_version(void);
33 static void usage(void);
34 static const char *opt_tmpdir;
35 static const char *new_auto_increment;
36 unsigned long long new_auto_increment_value;
37 static const char *load_default_groups[]= { "archive_reader", 0 };
38 static char **default_argv;
39 int opt_check, opt_force, opt_quiet, opt_backup= 0, opt_extract_frm;
40 int opt_autoincrement;
41 
42 int main(int argc, char *argv[])
43 {
44  unsigned int ret;
45  azio_stream reader_handle;
46 
47  MY_INIT(argv[0]);
48  get_options(&argc, &argv);
49 
50  if (argc < 1)
51  {
52  printf("No file specified. \n");
53  return 0;
54  }
55 
56  if (!(ret= azopen(&reader_handle, argv[0], O_RDONLY|O_BINARY)))
57  {
58  printf("Could not open Archive file\n");
59  return 0;
60  }
61 
62  if (opt_autoincrement)
63  {
64  azio_stream writer_handle;
65 
66  if (new_auto_increment_value)
67  {
68  if (reader_handle.auto_increment >= new_auto_increment_value)
69  {
70  printf("Value is lower then current value\n");
71  goto end;
72  }
73  }
74  else
75  {
76  new_auto_increment_value= reader_handle.auto_increment + 1;
77  }
78 
79  if (!(ret= azopen(&writer_handle, argv[0], O_CREAT|O_RDWR|O_BINARY)))
80  {
81  printf("Could not open file for update: %s\n", argv[0]);
82  goto end;
83  }
84 
85  writer_handle.auto_increment= new_auto_increment_value;
86 
87  azclose(&writer_handle);
88  azflush(&reader_handle, Z_SYNC_FLUSH);
89  }
90 
91  printf("Version %u\n", reader_handle.version);
92  if (reader_handle.version > 2)
93  {
94  printf("\tMinor version %u\n", reader_handle.minor_version);
95  printf("\tStart position %llu\n", (unsigned long long)reader_handle.start);
96  printf("\tBlock size %u\n", reader_handle.block_size);
97  printf("\tRows %llu\n", reader_handle.rows);
98  printf("\tAutoincrement %llu\n", reader_handle.auto_increment);
99  printf("\tCheck Point %llu\n", reader_handle.check_point);
100  printf("\tForced Flushes %llu\n", reader_handle.forced_flushes);
101  printf("\tLongest Row %u\n", reader_handle.longest_row);
102  printf("\tShortest Row %u\n", reader_handle.shortest_row);
103  printf("\tState %s\n", ( reader_handle.dirty ? "dirty" : "clean"));
104  printf("\tFRM stored at %u\n", reader_handle.frm_start_pos);
105  printf("\tComment stored at %u\n", reader_handle.comment_start_pos);
106  printf("\tData starts at %u\n", (unsigned int)reader_handle.start);
107  if (reader_handle.frm_start_pos)
108  printf("\tFRM length %u\n", reader_handle.frm_length);
109  if (reader_handle.comment_start_pos)
110  {
111  char *comment =
112  (char *) malloc(sizeof(char) * reader_handle.comment_length);
113  azread_comment(&reader_handle, comment);
114  printf("\tComment length %u\n\t\t%.*s\n", reader_handle.comment_length,
115  reader_handle.comment_length, comment);
116  free(comment);
117  }
118  }
119  else
120  {
121  goto end;
122  }
123 
124  printf("\n");
125 
126  if (opt_check)
127  {
128  uchar size_buffer[ARCHIVE_ROW_HEADER_SIZE];
129  int error;
130  unsigned int x;
131  unsigned int read;
132  unsigned int row_len;
133  unsigned long long row_count= 0;
134  char buffer;
135 
136  while ((read= azread(&reader_handle, (uchar *)size_buffer,
137  ARCHIVE_ROW_HEADER_SIZE, &error)))
138  {
139  if (error == Z_STREAM_ERROR || (read && read < ARCHIVE_ROW_HEADER_SIZE))
140  {
141  printf("Table is damaged\n");
142  goto end;
143  }
144 
145  /* If we read nothing we are at the end of the file */
146  if (read == 0 || read != ARCHIVE_ROW_HEADER_SIZE)
147  break;
148 
149  row_len= uint4korr(size_buffer);
150  row_count++;
151 
152  if (row_len > reader_handle.longest_row)
153  {
154  printf("Table is damaged, row %llu is invalid\n",
155  row_count);
156  goto end;
157  }
158 
159 
160  for (read= x= 0; x < row_len ; x++)
161  {
162  read+= (unsigned int)azread(&reader_handle, &buffer, sizeof(char), &error);
163  if (!read)
164  break;
165  }
166 
167 
168  if (row_len != read)
169  {
170  printf("Row length did not match row (at %llu). %u != %u \n",
171  row_count, row_len, read);
172  goto end;
173  }
174  }
175 
176  if (0)
177  {
178  printf("Table is damaged\n");
179  goto end;
180  }
181  else
182  {
183  printf("Found %llu rows\n", row_count);
184  }
185  }
186 
187  if (opt_backup)
188  {
189  uchar size_buffer[ARCHIVE_ROW_HEADER_SIZE];
190  int error;
191  unsigned int read;
192  unsigned int row_len;
193  unsigned long long row_count= 0;
194  char *buffer;
195 
196  azio_stream writer_handle;
197 
198  buffer= (char *)malloc(reader_handle.longest_row);
199  if (buffer == NULL)
200  {
201  printf("Could not allocate memory for row %llu\n", row_count);
202  goto end;
203  }
204 
205 
206  if (!(ret= azopen(&writer_handle, argv[1], O_CREAT|O_RDWR|O_BINARY)))
207  {
208  printf("Could not open file for backup: %s\n", argv[1]);
209  goto end;
210  }
211 
212  writer_handle.auto_increment= reader_handle.auto_increment;
213  if (reader_handle.frm_length)
214  {
215  char *ptr;
216  ptr= (char *)my_malloc(sizeof(char) * reader_handle.frm_length, MYF(0));
217  azread_frm(&reader_handle, ptr);
218  azwrite_frm(&writer_handle, ptr, reader_handle.frm_length);
219  my_free(ptr);
220  }
221 
222  if (reader_handle.comment_length)
223  {
224  char *ptr;
225  ptr= (char *)my_malloc(sizeof(char) * reader_handle.comment_length, MYF(0));
226  azread_comment(&reader_handle, ptr);
227  azwrite_comment(&writer_handle, ptr, reader_handle.comment_length);
228  my_free(ptr);
229  }
230 
231  while ((read= azread(&reader_handle, (uchar *)size_buffer,
232  ARCHIVE_ROW_HEADER_SIZE, &error)))
233  {
234  if (error == Z_STREAM_ERROR || (read && read < ARCHIVE_ROW_HEADER_SIZE))
235  {
236  printf("Table is damaged\n");
237  goto end;
238  }
239 
240  /* If we read nothing we are at the end of the file */
241  if (read == 0 || read != ARCHIVE_ROW_HEADER_SIZE)
242  break;
243 
244  row_len= uint4korr(size_buffer);
245 
246  row_count++;
247 
248  memcpy(buffer, size_buffer, ARCHIVE_ROW_HEADER_SIZE);
249 
250  read= (unsigned int)azread(&reader_handle, buffer + ARCHIVE_ROW_HEADER_SIZE,
251  row_len, &error);
252 
253  DBUG_ASSERT(read == row_len);
254 
255  azwrite(&writer_handle, buffer, row_len + ARCHIVE_ROW_HEADER_SIZE);
256 
257 
258  if (row_len != read)
259  {
260  printf("Row length did not match row (at %llu). %u != %u \n",
261  row_count, row_len, read);
262  goto end;
263  }
264 
265  if (reader_handle.rows == writer_handle.rows)
266  break;
267  }
268 
269  free(buffer);
270 
271  azclose(&writer_handle);
272  }
273 
274  if (opt_extract_frm)
275  {
276  File frm_file;
277  char *ptr;
278  frm_file= my_open(argv[1], O_CREAT|O_RDWR|O_BINARY, MYF(0));
279  ptr= (char *)my_malloc(sizeof(char) * reader_handle.frm_length, MYF(0));
280  azread_frm(&reader_handle, ptr);
281  my_write(frm_file, (uchar*) ptr, reader_handle.frm_length, MYF(0));
282  my_close(frm_file, MYF(0));
283  my_free(ptr);
284  }
285 
286 end:
287  printf("\n");
288  azclose(&reader_handle);
289 
290  return 0;
291 }
292 
293 static my_bool
294 get_one_option(int optid,
295  const struct my_option *opt __attribute__((unused)),
296  char *argument)
297 {
298  switch (optid) {
299  case 'b':
300  opt_backup= 1;
301  break;
302  case 'c':
303  opt_check= 1;
304  break;
305  case 'e':
306  opt_extract_frm= 1;
307  break;
308  case 'f':
309  opt_force= 1;
310  printf("Not implemented yet\n");
311  break;
312  case 'q':
313  opt_quiet= 1;
314  printf("Not implemented yet\n");
315  break;
316  case 'V':
317  print_version();
318  exit(0);
319  case 't':
320  printf("Not implemented yet\n");
321  break;
322  case 'A':
323  opt_autoincrement= 1;
324  if (argument)
325  new_auto_increment_value= strtoull(argument, NULL, 0);
326  else
327  new_auto_increment_value= 0;
328  break;
329  case '?':
330  usage();
331  exit(0);
332  case '#':
333  if (argument == disabled_my_option)
334  {
335  DBUG_POP();
336  }
337  else
338  {
339  DBUG_PUSH(argument ? argument : "d:t:o,/tmp/archive_reader.trace");
340  }
341  break;
342  }
343  return 0;
344 }
345 
346 static struct my_option my_long_options[] =
347 {
348  {"backup", 'b',
349  "Make a backup of an archive table.",
350  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
351  {"check", 'c', "Check table for errors.",
352  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
353 #ifndef DBUG_OFF
354  {"debug", '#',
355  "Output debug log. Often this is 'd:t:o,filename'.",
356  0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
357 #endif
358  {"extract-frm", 'e',
359  "Extract the frm file.",
360  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
361  {"force", 'f',
362  "Restart with -r if there are any errors in the table.",
363  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
364  {"help", '?',
365  "Display this help and exit.",
366  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
367  {"quick", 'q', "Faster repair by not modifying the data file.",
368  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
369  {"repair", 'r', "Repair a damaged Archive version 3 or above file.",
370  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
371  {"set-auto-increment", 'A',
372  "Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1.",
373  &new_auto_increment, &new_auto_increment,
374  0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0},
375  {"silent", 's',
376  "Only print errors. One can use two -s to make archive_reader very silent.",
377  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
378  {"tmpdir", 't',
379  "Path for temporary files.",
380  &opt_tmpdir,
381  0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
382  {"version", 'V',
383  "Print version and exit.",
384  0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
385  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
386 };
387 
388 static void usage(void)
389 {
390  print_version();
391  puts("Copyright 2007-2008 MySQL AB, 2008 Sun Microsystems, Inc.");
392  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n");
393  puts("Read and modify Archive files directly\n");
394  printf("Usage: %s [OPTIONS] file_to_be_looked_at [file_for_backup]\n", my_progname);
395  print_defaults("my", load_default_groups);
396  my_print_help(my_long_options);
397 }
398 
399 static void print_version(void)
400 {
401  printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, SHOW_VERSION,
402  MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
403 }
404 
405 static void get_options(int *argc, char ***argv)
406 {
407  if (load_defaults("my", load_default_groups, argc, argv))
408  exit(1);
409  default_argv= *argv;
410 
411  handle_options(argc, argv, my_long_options, get_one_option);
412 
413  if (*argc == 0)
414  {
415  usage();
416  exit(-1);
417  }
418 
419  return;
420 } /* get options */