List:Commits« Previous MessageNext Message »
From:Ingo Struewing Date:September 30 2008 9:15am
Subject:bzr commit into mysql-6.0-backup branch (ingo.struewing:2693) WL#4534
View as plain text  
#At file:///home2/mydev/bzrroot/mysql-6.0-wl4534/

 2693 Ingo Struewing	2008-09-30
      WL#4534 - Backup client program
      
      Quick and dirty prototype for early design review.
      
      First attempt is to implement catalog in C++.
      Uncertainty is about whether it may later be necessary to associate
      table numbers from the table data chunks with catalog data. This won't
      work efficiently with the list implementation. If it turns out that we
      need arrays in the catalog, we may not implement this in C++.
      As far as I know, we do not use the standard C++ library for
      portability reasons. And we don't have an equivalent for std::vector.
      So dynamic arrays (mysys/array.c) come to mind. But then mixing of
      C and C++ in the catalog doesn't seem right. An extension of the
      type-inheritance model of the stream library seems more appropriate.
      Especially as one could use these types directly.
      However, IMHO, this would prove that the catalog representation cannot
      be chosen freely when using the stream library.
      
      Open questions:
      
      - Why do we need to bstream_next_chunk() before some bstream_rd_*()
      calls, but not others.
      - Why header.version is not filled with the library's verion.
      - Why snapshot data belong to two tables (in my backup image example)
      while there is just one table.
      - Why snapshot data is read in 512 + 15872 byte chunks instead of 16K.
      - Why Backup-finish time and binlog positions are not available after
      reading summary.
      
      To repeat my test case, please apply this patch to 6.0-backup, run
      backup_myisam2.test (this creates /tmp/wl4534-test-1.bak), and run
      
          client/.libs/mysqlbackup /tmp/wl4534-test-1.bak
      
      To see the 512 + 15872 byte reads, run
      
          client/.libs/mysqlbackup --debug=t:d: /tmp/wl4534-test-1.bak
added:
  client/mysqlbackup.cc
modified:
  .bzrignore
  client/Makefile.am
  mysql-test/t/backup_myisam2.test
  sql/backup/stream_v1.h
  sql/backup/stream_v1_services.h

per-file messages:
  .bzrignore
    WL#4534 - Backup client program
    Added mysqlbackup related files.
  client/Makefile.am
    WL#4534 - Backup client program
    Added mysqlbackup client build requirements.
  client/mysqlbackup.cc
    WL#4534 - Backup client program
    First prototype implementation.
  mysql-test/t/backup_myisam2.test
    WL#4534 - Backup client program
    Temporarily added copy of a backup file to /tmp/wl4534-test-1.bak.
  sql/backup/stream_v1.h
    WL#4534 - Backup client program
    Added extern "C".
  sql/backup/stream_v1_services.h
    WL#4534 - Backup client program
    Added extern "C".
=== modified file '.bzrignore'
--- a/.bzrignore	2008-08-26 10:20:41 +0000
+++ b/.bzrignore	2008-09-30 09:14:57 +0000
@@ -1891,3 +1891,6 @@ zlib/*.vcproj
 extra/libevent/event-config.h
 libmysqld/ddl_blocker.cc
 libmysqld/mdl.cc
+client/mysqlbackup
+client/stream_v1.h
+client/stream_v1_services.h

=== modified file 'client/Makefile.am'
--- a/client/Makefile.am	2008-08-20 16:21:14 +0000
+++ b/client/Makefile.am	2008-09-30 09:14:57 +0000
@@ -42,6 +42,7 @@ CLEANFILES =			$(BUILT_SOURCES)
 
 bin_PROGRAMS =			mysql \
 				mysqladmin \
+				mysqlbackup \
 				mysqlbinlog \
 				mysqlcheck \
 				mysqldump \
@@ -57,6 +58,11 @@ mysql_LDADD =			@readline_link@ @TERMCAP
 				$(LDADD) $(CXXLDFLAGS)
 mysqladmin_SOURCES =		mysqladmin.cc
 
+mysqlbackup_SOURCES =		mysqlbackup.cc \
+				$(top_srcdir)/sql/backup/stream_v1.c \
+				$(top_srcdir)/sql/backup/stream_v1_transport.c
+mysqlbackup_LDADD =		$(LDADD) $(CXXLDFLAGS)
+
 mysqlbinlog_SOURCES =		mysqlbinlog.cc \
 				$(top_srcdir)/mysys/mf_tempdir.c \
 				$(top_srcdir)/mysys/my_new.cc \
@@ -109,6 +115,7 @@ sql_src=log_event.h mysql_priv.h rpl_con
 	log_event_old.h log_event_old.cc \
 	rpl_record_old.h rpl_record_old.cc
 strings_src=decimal.c dtoa.c
+backup_src=stream_v1.h stream_v1_services.h
 
 link_sources:
 	for f in $(sql_src) ; do \
@@ -119,6 +126,10 @@ link_sources:
 	  rm -f $(srcdir)/$$f; \
 	  @LN_CP_F@ $(top_srcdir)/strings/$$f $$f; \
 	done; \
+	for f in $(backup_src) ; do \
+	  rm -f $(srcdir)/$$f; \
+	  @LN_CP_F@ $(top_srcdir)/sql/backup/$$f $$f; \
+	done; \
 	rm -f $(srcdir)/my_user.c; \
 	@LN_CP_F@ $(top_srcdir)/sql-common/my_user.c my_user.c;
 	echo timestamp > link_sources;

=== added file 'client/mysqlbackup.cc'
--- a/client/mysqlbackup.cc	1970-01-01 00:00:00 +0000
+++ b/client/mysqlbackup.cc	2008-09-30 09:14:57 +0000
@@ -0,0 +1,1404 @@
+/* Copyright (C) 2001-2004 MySQL AB
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+/*
+  MySQL Backup Utility
+*/
+
+/* Include client related stuff, which includes a lot of common stuff. */
+#include "client_priv.h"
+/* Include special stuff. */
+#include <my_time.h>
+
+/* As long as we don't connect to the server, we are not a MYSQL_CLIENT. */
+#undef MYSQL_CLIENT
+
+/*
+  Include from the low-level stream access functions.
+*/
+#define BSTREAM_USE_MALLOC
+#include "stream_v1.h"
+#include "stream_v1_services.h"
+
+/*
+  Command line options.
+*/
+#ifdef MYSQL_CLIENT
+static const char       *opt_database;
+static const char       *opt_host;
+static char             *opt_pass;
+static int              opt_port;
+static uint             opt_protocol;
+static const char       *opt_sock;
+static const char       *opt_user;
+#endif
+static uint             opt_verbose;
+static ulong            opt_open_files_limit;
+
+#ifndef DBUG_OFF
+static const char *default_dbug_option = "d:t:o,/tmp/mysqlbackup.trace";
+#endif
+static const char *load_default_groups[]= { "mysqlbackup",
+#ifdef MYSQL_CLIENT
+                                            "client",
+#endif
+                                            NULL };
+
+static struct my_option my_long_options[] =
+{
+  {"help", '?', "Display this help and exit.",
+   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#ifdef __NETWARE__
+  {"autoclose", OPT_AUTO_CLOSE, "Auto close the screen on exit for Netware.",
+   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+#ifndef DBUG_OFF
+  {"debug", '#', "Output debug log.", (uchar**) &default_dbug_option,
+   (uchar**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+#endif
+
+#ifdef MYSQL_CLIENT
+  /* Options required by a MySQL client (connecting to a server). */
+  {"database", 'd', "Unused.",
+   (uchar**) &opt_database, (uchar**) &opt_database,
+   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"host", 'h', "Unused.",
+   (uchar**) &opt_host, (uchar**) &opt_host,
+   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"password", 'p', "Unused.",
+   0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+  {"port", 'P', "Unused.",
+   (uchar**) &opt_port, (uchar**) &opt_port, 0, GET_INT, REQUIRED_ARG,
+   0, 0, 0, 0, 0, 0},
+  {"protocol", OPT_MYSQL_PROTOCOL, "Unused.",
+   0, 0, 0, GET_STR,  REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"socket", 'S', "Unused.",
+   (uchar**) &opt_sock, (uchar**) &opt_sock,
+   0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+  {"user", 'u', "Unused.",
+   (uchar**) &opt_user, (uchar**) &opt_user,
+   0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+#endif /*MYSQL_CLIENT*/
+
+  {"verbose", 'v', "Print verbose information.",
+   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
+  {"version", 'V', "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
+   0, 0, 0, 0, 0},
+  {"open_files_limit", OPT_OPEN_FILES_LIMIT,
+   "Used to reserve file descriptors for usage by this program.",
+   (uchar**) &opt_open_files_limit, (uchar**) &opt_open_files_limit,
+   0, GET_ULONG, REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
+  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+#include <help_start.h>
+
+static void print_version()
+{
+  printf("%s Ver 1.0 for %s at %s\n", my_progname, SYSTEM_TYPE, MACHINE_TYPE);
+  NETWARE_SET_SCREEN_MODE(1);
+}
+
+
+static void usage()
+{
+  print_version();
+  puts("By Sun Microsystems, for your professional use\n\
+This software comes with NO WARRANTY:  This is free software,\n\
+and you are welcome to modify and redistribute it under the GPL license\n");
+
+  printf("Displays information from a backup image.\n\n");
+  printf("Usage: %s [options] backup-image-file\n", my_progname);
+  my_print_help(my_long_options);
+  my_print_variables(my_long_options);
+}
+
+#include <help_end.h>
+
+
+/**
+  Treat some options specially.
+
+  Called for each option that appears on the command line.
+*/
+
+extern "C" my_bool
+get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
+               char *argument)
+{
+#ifdef MYSQL_CLIENT
+  bool tty_password=0;
+#endif
+
+  switch (optid) {
+#ifdef __NETWARE__
+  case OPT_AUTO_CLOSE:
+    setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
+    break;
+#endif
+#ifndef DBUG_OFF
+  case '#':
+    DBUG_PUSH(argument ? argument : default_dbug_option);
+    break;
+#endif
+
+#ifdef MYSQL_CLIENT
+  case 'p':
+    if (argument)
+    {
+      my_free(opt_pass,MYF(MY_ALLOW_ZERO_PTR));
+      char *start=argument;
+      opt_pass= my_strdup(argument,MYF(MY_FAE));
+      while (*argument) *argument++= 'x';		/* Destroy argument */
+      if (*start)
+        start[1]=0;				/* Cut length of argument */
+    }
+    else
+      tty_password=1;
+    break;
+  case OPT_MYSQL_PROTOCOL:
+    opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
+                                    opt->name);
+    break;
+#endif /*MYSQL_CLIENT*/
+
+  case 'v':
+    if (argument == disabled_my_option)
+      opt_verbose= 0;
+    else
+      opt_verbose++;
+    break;
+  case 'V':
+    print_version();
+    exit(0);
+  case '?':
+    usage();
+    exit(0);
+  }
+
+#ifdef MYSQL_CLIENT
+  if (tty_password)
+    opt_pass= get_tty_password(NullS);
+#endif /*MYSQL_CLIENT*/
+
+  return 0;
+}
+
+
+/**
+  Auxiliary function used by error() and warning().
+
+  Prints the given text (normally "WARNING: " or "ERROR: ") to stderr,
+  followed by the given vprintf-style string, followed by a newline.
+
+  @param[in]    format          printf-style format string
+  @param[in]    args            list of arguments for the format string
+  @param[in]    msg             text to print before the string
+*/
+
+static void error_or_warning(const char *format, const char *msg, va_list args)
+{
+  fprintf(stderr, "%s: ", msg);
+  vfprintf(stderr, format, args);
+  fprintf(stderr, "\n");
+}
+
+
+/**
+  Print a message to stderr, prefixed with the text "ERROR: " and
+  suffixed with a newline.
+
+  @param[in]    format          printf-style format string
+  @param[in]    ...             printf-style varargs
+*/
+
+static void error(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+static void error(const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  error_or_warning(format, "ERROR", args);
+  va_end(args);
+}
+
+
+#ifdef NOT_YET_USED
+/**
+  Print a message to stderr, prefixed with the text "WARNING: " and
+  suffixed with a newline.
+
+  @param[in]    format          printf-style format string
+  @param[in]    ...             printf-style varargs
+*/
+static void warning(const char *format, ...) ATTRIBUTE_FORMAT(printf, 1, 2);
+static void warning(const char *format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  error_or_warning(format, "WARNING", args);
+  va_end(args);
+}
+#endif
+
+
+/**
+  Print a formatted time string.
+*/
+
+int print_time(bstream_time_t *time)
+{
+  return printf("%02d-%02d-%04d %02d:%02d:%02d",
+    time->mday, time->mon, 1900 + time->year,
+    time->hour, time->min, time->sec);
+}
+
+
+/*
+  ===================================
+  Helper functions for stream access.
+  ===================================
+*/
+
+/*
+  Helper struct for stream access functions.
+
+  The stream access functions do not read the backup image file directly.
+  They call back functions provided in backup_stream by the application.
+  The struct st_stream ties together the backup_stream with the data
+  required by the I/O functions provided by this application.
+*/
+struct st_stream
+{
+  backup_stream         bupstrm;
+  int                   fd;
+};
+
+/**
+  Read from the stream/image.
+*/
+
+int str_read(struct st_stream *strm, bstream_blob *data, bstream_blob envelope)
+{
+  ssize_t howmuch= data->end - data->begin;
+  DBUG_ENTER("str_read");
+
+  howmuch= read(strm->fd, data->begin, howmuch);
+  if (howmuch < 0)
+  {
+    perror("str_read");
+    DBUG_RETURN(BSTREAM_ERROR);
+  }
+  DBUG_PRINT("stream", ("read bytes: %ld", (long) howmuch));
+
+  if (howmuch == 0)
+    DBUG_RETURN(BSTREAM_EOS);
+
+  data->begin+= howmuch;
+
+  DBUG_RETURN(BSTREAM_OK);
+}
+
+
+/**
+  Skip part of the stream/image.
+*/
+
+int str_forward(struct st_stream *strm, size_t *len)
+{
+  off_t cur_pos= lseek(strm->fd, 0, SEEK_CUR);
+  off_t off=     lseek(strm->fd, *len, SEEK_CUR);
+  DBUG_ENTER("str_forward");
+
+  if ((cur_pos < 0) || (off < 0))
+    DBUG_RETURN(BSTREAM_ERROR);
+
+  *len= off - cur_pos;
+  DBUG_RETURN(BSTREAM_OK);
+}
+
+
+/**
+  Open the stream/image for reading.
+*/
+#define IMAGE_START_OFFSET 10
+
+int str_open_rd(struct st_stream *strm, const char *path)
+{
+  int lgt;
+  char buff[IMAGE_START_OFFSET];
+  DBUG_ENTER("str_open_rd");
+
+  /* Open the image file. */
+  strm->fd= open(path, O_RDONLY);
+  if (strm->fd < 0)
+  {
+    perror("str_open_rd");
+    DBUG_RETURN(BSTREAM_ERROR);
+  }
+  DBUG_PRINT("stream", ("opened image file: '%s'", path));
+
+  /* Have to consume some bytes from the image. */
+  /* TODO: Check magic number and image version. */
+  lgt= read(strm->fd, buff, IMAGE_START_OFFSET);
+  if (lgt != IMAGE_START_OFFSET)
+  {
+    if (lgt < 0)
+      perror("str_open_rd");
+    error("Image file has only %d bytes of at least %d\n",
+          lgt, IMAGE_START_OFFSET);
+    DBUG_RETURN(BSTREAM_ERROR);
+  }
+
+  /* Set callback functions in backup_stream. */
+  strm->bupstrm.stream.write=   (as_write_m) NULL;
+  strm->bupstrm.stream.read=    (as_read_m) str_read;
+  strm->bupstrm.stream.forward= (as_forward_m) str_forward;
+
+  /* Open the stream. */
+  DBUG_PRINT("stream", ("opening stream: '%s'", path));
+  DBUG_RETURN(bstream_open_rd(&strm->bupstrm, IMAGE_START_OFFSET));
+}
+
+/**
+  Close the stream/image.
+*/
+
+int str_close(struct st_stream *strm)
+{
+  DBUG_ENTER("str_close");
+
+  /* Close the stream. */
+  int ret= bstream_close(&strm->bupstrm);
+
+  /* Close the image file. */
+  if (close(strm->fd))
+  {
+    perror("str_close");
+    ret= BSTREAM_ERROR;
+  }
+
+  DBUG_RETURN(ret);
+}
+
+
+/*
+  =====================
+  Catalog declarations.
+  =====================
+*/
+
+/*
+  List handling.
+*/
+
+class list_item
+{
+  list_item             *list_item_next;
+  list_item             **list_item_prev_p;
+
+public:
+
+  list_item(void)
+  { list_item_next= NULL; list_item_prev_p= NULL; }
+
+  list_item **item_append(list_item **last_p)
+  {
+    list_item_next= NULL;
+    list_item_prev_p= last_p;
+    return &list_item_next;
+  }
+
+  void item_remove()
+  {
+    DBUG_PRINT("list", ("delete this: 0x%lx  nxt: 0x%lx  prv: 0x%lx",
+                        (long) this, (long) list_item_next,
+                        (long) list_item_prev_p));
+    if (list_item_prev_p)
+      *list_item_prev_p= list_item_next;
+    if (list_item_next)
+      list_item_next->list_item_prev_p= list_item_prev_p;
+  }
+
+  list_item *item_next(void)
+  { return list_item_next; }
+
+};
+
+class list_head
+{
+  list_item             *list_head_first;
+  list_item             **list_head_last_p;
+
+public:
+
+  list_head(void)
+  { list_head_first= NULL; list_head_last_p= &list_head_first; }
+
+  void list_append(list_item *item)
+  {
+    *list_head_last_p= item;
+    list_head_last_p= item->item_append(list_head_last_p);
+  }
+
+  list_item *list_first(void)
+  { return list_head_first; }
+
+};
+
+class list_iterator
+{
+  list_head                     *list_iterator_head;
+  list_item                     *list_iterator_current;
+  enum enum_bstream_item_type   list_iterator_type;
+
+public:
+
+  list_iterator(void)
+  {
+    list_iterator_head= NULL;
+    list_iterator_current= NULL;
+    list_iterator_type= BSTREAM_IT_LAST;
+  }
+
+  void list_init(list_head *head, enum enum_bstream_item_type type)
+  {
+    list_iterator_head= head;
+    list_iterator_current= NULL;
+    list_iterator_type= type;
+  }
+
+  void list_reset(void)
+  { list_iterator_current= NULL; }
+
+  list_item *list_curr(void)
+  { return list_iterator_current; }
+
+  list_item *list_next(void)
+  {
+    if (list_iterator_current)
+      list_iterator_current= list_iterator_current->item_next();
+    else
+      list_iterator_current= list_iterator_head->list_first();
+    return list_iterator_current;
+  }
+
+  enum enum_bstream_item_type list_type(void)
+  { return list_iterator_type; }
+
+};
+
+/*
+  Character set.
+*/
+class backup_charset : public list_item
+{
+  struct st_bstream_item_info   cs_item;
+
+public:
+
+  backup_charset(struct st_bstream_item_info *item)
+  {
+    /* *item contains a pointer to allocated memory. */
+    cs_item= *item;
+  }
+
+  ~backup_charset(void)
+  { bstream_free(cs_item.name.begin); }
+
+  struct st_bstream_item_info *get_cs_item(void)
+  { return &cs_item; }
+
+};
+
+/*
+  Table.
+*/
+class backup_table : public list_item
+{
+  struct st_bstream_table_info  tbl_item;
+
+public:
+
+  backup_table(struct st_bstream_table_info *item)
+  { tbl_item= *item; }
+
+  ~backup_table(void)
+  { bstream_free(tbl_item.base.base.name.begin); }
+
+  struct st_bstream_table_info *get_tbl_item(void)
+  { return &tbl_item; }
+
+};
+
+/*
+  Database.
+*/
+class backup_database : public list_item
+{
+  struct st_bstream_db_info     db_item;
+  list_head                     table_list;
+  list_iterator                 table_it;
+
+public:
+
+  backup_database(struct st_bstream_db_info *item)
+  { db_item= *item; table_it.list_init(&table_list, BSTREAM_IT_TABLE); }
+
+  ~backup_database(void)
+  {
+    backup_table *tbl;
+    while ((tbl= (backup_table*) table_list.list_first()))
+    {
+      tbl->item_remove();
+      delete tbl;
+    }
+    bstream_free(db_item.base.name.begin);
+  }
+
+  struct st_bstream_db_info *get_db_item(void)
+  { return &db_item; }
+
+  /* Tables. */
+
+  list_iterator *get_table_iterator()
+  { return &table_it; }
+
+  void add_table(struct st_bstream_table_info *item)
+  { table_list.list_append(new backup_table(item)); }
+
+};
+
+/*
+  Catalog.
+*/
+class backup_catalog
+{
+  list_head                     charset_list;
+  list_iterator                 charset_it;
+  list_head                     database_list;
+  list_iterator                 database_it;
+
+public:
+
+  backup_catalog(void)
+  {
+    charset_it.list_init(&charset_list, BSTREAM_IT_CHARSET);
+    database_it.list_init(&database_list, BSTREAM_IT_DB);
+  }
+
+  ~backup_catalog(void)
+  {
+    backup_charset *chrset;
+    backup_database *dbase;
+    while ((chrset= (backup_charset*) charset_list.list_first()))
+    {
+      DBUG_PRINT("bup_cat", ("delete chrset 0x%lx", (long) chrset));
+      chrset->item_remove();
+      delete chrset;
+    }
+    while ((dbase= (backup_database*) database_list.list_first()))
+    {
+      DBUG_PRINT("bup_cat", ("delete dbase 0x%lx", (long) dbase));
+      dbase->item_remove();
+      delete dbase;
+    }
+  }
+
+  void catalog_reset(void)
+  {
+    charset_it.list_reset();
+    database_it.list_reset();
+  }
+
+  /* Character sets. */
+
+  list_iterator *get_charset_iterator()
+  { return &charset_it; }
+
+  void add_charset(struct st_bstream_item_info *item)
+  { charset_list.list_append(new backup_charset(item)); }
+
+  /* Databases. */
+
+  list_iterator *get_database_iterator()
+  { return &database_it; }
+
+  void add_database(struct st_bstream_db_info *item)
+  { database_list.list_append(new backup_database(item)); }
+
+  /* Tables belong to databases. */
+
+  list_iterator *get_table_iterator()
+  { return ((backup_database*)
+            database_it.list_curr())->get_table_iterator(); }
+
+  void add_table(struct st_bstream_table_info *item)
+  { ((backup_database*) database_it.list_curr())->add_table(item); }
+
+};
+
+/*
+  Ambassador struct to reference the C++ catalog from the C stream linbrary.
+*/
+struct backup_catalog_ambassador
+{
+  struct st_bstream_image_header        amb_header;
+  backup_catalog                        *amb_catalog;
+};
+
+/*
+  ================================================
+  Helper functions for backup image item handling.
+  ================================================
+*/
+
+/* backup image handling is implemented in C. */
+extern "C" {
+
+/**
+  Clear catalogue and prepare it for populating with items.
+*/
+
+int
+bcat_reset(struct st_bstream_image_header *hdr)
+{
+  struct backup_catalog_ambassador      *bup_cat_amb;
+  backup_catalog                        *bup_catalog;
+  DBUG_ENTER("bcat_reset");
+
+  /* backup_catalog_ambassador starts with st_bstream_image_header. */
+  bup_cat_amb= (struct backup_catalog_ambassador*) hdr;
+  bup_catalog= bup_cat_amb->amb_catalog;
+
+  bup_catalog->catalog_reset();
+
+  DBUG_RETURN(BSTREAM_OK);
+}
+
+
+/**
+  Close catalogue after all items have been added to it.
+*/
+
+int
+bcat_close(struct st_bstream_image_header *hdr)
+{
+  DBUG_ENTER("bcat_close");
+  DBUG_RETURN(BSTREAM_OK);
+}
+
+
+/**
+  Add item to the catalogue.
+
+  The @c item->pos field should be set to indicate position of the item
+  in the catalogue.
+
+  @note
+  Global, per-table and per-database items can have independent address
+  spaces. Thus item belonging to a database is identified by its position inside
+  that database's item list. Similar for items belonging to tables.
+*/
+
+int
+bcat_add_item(struct st_bstream_image_header *hdr,
+              struct st_bstream_item_info *item)
+{
+  struct backup_catalog_ambassador      *bup_cat_amb;
+  backup_catalog                        *bup_catalog;
+  DBUG_ENTER("bcat_add_item");
+  DBUG_PRINT("cat", ("adding item type: %d  pos: %lu",
+                     item->type, item->pos));
+
+  /* backup_catalog_ambassador starts with st_bstream_image_header. */
+  bup_cat_amb= (struct backup_catalog_ambassador*) hdr;
+  bup_catalog= bup_cat_amb->amb_catalog;
+
+  switch (item->type)
+  {
+  case BSTREAM_IT_CHARSET:
+    bup_catalog->add_charset(item);
+    DBUG_PRINT("cat", ("adding charset: '%.*s'",
+                       (int) (item->name.end - item->name.begin),
+                       item->name.begin));
+    break;
+
+  case BSTREAM_IT_USER:
+    DBUG_PRINT("cat", ("adding user: '%.*s'",
+                       (int) (item->name.end - item->name.begin),
+                       item->name.begin));
+    break;
+
+  case BSTREAM_IT_PRIVILEGE:
+    DBUG_PRINT("cat", ("adding privilege: '%.*s'",
+                       (int) (item->name.end - item->name.begin),
+                       item->name.begin));
+    break;
+
+  case BSTREAM_IT_DB:
+    bup_catalog->add_database((struct st_bstream_db_info*) item);
+    DBUG_PRINT("cat", ("adding database: '%.*s'",
+                       (int) (item->name.end - item->name.begin),
+                       item->name.begin));
+    break;
+
+  case BSTREAM_IT_VIEW:
+    DBUG_PRINT("cat", ("adding view: '%.*s'",
+                       (int) (item->name.end - item->name.begin),
+                       item->name.begin));
+    break;
+
+  case BSTREAM_IT_TABLE:
+    bup_catalog->add_table((struct st_bstream_table_info*) item);
+    IF_DBUG({
+        struct st_bstream_table_info *tbl_item;
+        bstream_blob                 *db_name;
+        tbl_item= (struct st_bstream_table_info*) item;
+        db_name= &tbl_item->base.db->base.name;
+        DBUG_PRINT("cat", ("adding table: '%.*s'.'%.*s'",
+                           (int) (db_name->end - db_name->begin),
+                           db_name->begin,
+                           (int) (item->name.end - item->name.begin),
+                           item->name.begin));
+      });
+    break;
+
+  default:
+    DBUG_PRINT("cat", ("adding unknown item type: '%.*s'",
+                       (int) (item->name.end - item->name.begin),
+                       item->name.begin));
+    DBUG_RETURN(BSTREAM_ERROR);
+  }
+
+  DBUG_RETURN(BSTREAM_OK);
+}
+
+
+/**
+  Create global iterator of a given type.
+
+  Possible iterator types.
+
+  - BSTREAM_IT_CHARSET: all charsets
+  - BSTREAM_IT_USER:    all users
+  - BSTREAM_IT_DB:      all databases
+
+  The following types of iterators iterate only over items for which
+  some meta-data should be saved in the image.
+
+  - BSTREAM_IT_GLOBAL: all global items in create-dependency order
+  - BSTREAM_IT_PERDB: all per-db items except tables which are enumerated by
+                      a table iterator (see below)
+  - BSTREAM_IT_PERTABLE: all per-table items in create-dependency orders.
+
+  @return Pointer to the iterator or NULL in case of error.
+*/
+
+void*
+bcat_iterator_get(struct st_bstream_image_header *hdr, unsigned int it_type)
+{
+  struct backup_catalog_ambassador      *bup_cat_amb;
+  backup_catalog                        *bup_catalog;
+  void                                  *iter= NULL;
+  DBUG_ENTER("bcat_iterator_get");
+  DBUG_PRINT("cat", ("getting iterator for type: %u", it_type));
+
+  /* backup_catalog_ambassador starts with st_bstream_image_header. */
+  bup_cat_amb= (struct backup_catalog_ambassador*) hdr;
+  bup_catalog= bup_cat_amb->amb_catalog;
+
+  switch (it_type)
+  {
+  case BSTREAM_IT_CHARSET:
+    iter= bup_catalog->get_charset_iterator();
+    DBUG_PRINT("cat", ("charset"));
+    break;
+
+  case BSTREAM_IT_USER:
+    DBUG_PRINT("cat", ("user"));
+    break;
+
+  case BSTREAM_IT_DB:
+    iter= bup_catalog->get_database_iterator();
+    DBUG_PRINT("cat", ("database"));
+    break;
+
+  case BSTREAM_IT_GLOBAL:
+    DBUG_PRINT("cat", ("global"));
+    break;
+
+  case BSTREAM_IT_PERDB:
+    DBUG_PRINT("cat", ("perdb"));
+    break;
+
+  default:
+    DBUG_PRINT("cat", ("unknown"));
+  }
+
+  DBUG_ASSERT(!iter || (((list_iterator*) iter)->list_type() ==
+                        (enum enum_bstream_item_type) it_type));
+  DBUG_PRINT("cat", ("iterator: 0x%lx", (long) iter));
+  DBUG_RETURN(iter);
+}
+
+
+/**
+  Return next item pointed by iterator.
+
+  @return NULL if there are no more items in the set.
+*/
+
+struct st_bstream_item_info*
+bcat_iterator_next(struct st_bstream_image_header *hdr, void *iter)
+{
+  list_iterator                 *list_it= (list_iterator*) iter;
+  list_item                     *l_item;
+  st_bstream_item_info          *item= NULL;
+  enum enum_bstream_item_type   it_type;
+  DBUG_ENTER("bcat_iterator_next");
+  DBUG_PRINT("cat", ("iter: 0x%lx", (long) iter));
+
+  l_item= list_it->list_next();
+  if (!l_item)
+    goto end;
+
+  it_type= list_it->list_type();
+  DBUG_PRINT("cat", ("next iterator for type: %u", it_type));
+  DBUG_PRINT("cat", ("next list item: 0x%lx", (long) l_item));
+
+  switch (it_type)
+  {
+  case BSTREAM_IT_CHARSET:
+    item= ((backup_charset*) l_item)->get_cs_item();
+    DBUG_PRINT("cat", ("charset"));
+    break;
+
+  case BSTREAM_IT_USER:
+    DBUG_PRINT("cat", ("user"));
+    break;
+
+  case BSTREAM_IT_DB:
+    item= (st_bstream_item_info*) ((backup_database*) l_item)->get_db_item();
+    DBUG_PRINT("cat", ("database"));
+    break;
+
+  case BSTREAM_IT_GLOBAL:
+    DBUG_PRINT("cat", ("global"));
+    break;
+
+  case BSTREAM_IT_PERDB:
+    DBUG_PRINT("cat", ("perdb"));
+    break;
+
+  default:
+    DBUG_PRINT("cat", ("unknown"));
+  }
+
+ end:
+  DBUG_PRINT("cat", ("item: 0x%lx '%.*s'", (long) item,
+                     item ? (int) (item->name.end - item->name.begin) : 0,
+                     item ? (char*) item->name.begin : ""));
+  DBUG_RETURN(item);
+}
+
+
+/**
+  Free iterator resources.
+
+  @note
+  The iterator can not be used after call to this function.
+*/
+
+void
+bcat_iterator_free(struct st_bstream_image_header *hdr, void *iter)
+{
+  DBUG_ENTER("bcat_iterator_free");
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Create iterator for items belonging to a given database.
+*/
+
+void*
+bcat_db_iterator_get(struct st_bstream_image_header *hdr,
+                     struct st_bstream_db_info *db)
+{
+  DBUG_ENTER("bcat_db_iterator_get");
+  DBUG_RETURN(NULL);
+}
+
+
+/**
+  Return next item from database items iterator
+*/
+
+struct st_bstream_dbitem_info*
+bcat_db_iterator_next(struct st_bstream_image_header *cat,
+                      struct st_bstream_db_info *db, void *it)
+{
+  DBUG_ENTER("bcat_db_iterator_next");
+  DBUG_RETURN(NULL);
+}
+
+
+/**
+  Free database items iterator resources
+*/
+
+void
+bcat_db_iterator_free(struct st_bstream_image_header *cat,
+                      struct st_bstream_db_info *db, void *it)
+{
+  DBUG_ENTER("bcat_db_iterator_free");
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Produce CREATE statement for a given item.
+
+  Backup stream library calls that function when saving item's
+  meta-data. If function successfully produces the statement, it becomes
+  part of meta-data.
+
+  @retval BSTREAM_OK    blob @c stmt contains the CREATE query
+  @retval BSTREAM_ERROR no CREATE statement for that item
+*/
+
+int
+bcat_get_item_create_query(struct st_bstream_image_header *cat,
+                           struct st_bstream_item_info *item,
+                           bstream_blob *query)
+{
+  static char buf[128];
+  DBUG_ENTER("bcat_get_item_create_query");
+
+  switch (item->type)
+  {
+    case BSTREAM_IT_DB:
+      sprintf(buf, "CREATE DATABASE %s", item->name.begin);
+      break;
+    case BSTREAM_IT_TABLE:
+      sprintf(buf, "CREATE TABLE %s", item->name.begin);
+      break;
+    case BSTREAM_IT_PRIVILEGE:
+    {
+      struct st_bstream_db_info *db= ((struct st_bstream_dbitem_info*)item)->db;
+      sprintf(buf, "GRANT ALL ON %s.* TO ''", db->base.name.begin);
+      break;
+    }
+    default:
+      DBUG_RETURN(BSTREAM_ERROR);
+  }
+
+  query->begin= (bstream_byte*) buf;
+  query->end= (bstream_byte*) (buf + strlen(buf));
+
+  DBUG_RETURN(BSTREAM_OK);
+}
+
+
+/**
+  Return meta-data (other than CREATE statement) for a given item.
+
+  Backup stream library calls that function when saving item's
+  meta-data. If function returns successfully, the bytes returned become
+  part of meta-data.
+
+  @retval BSTREAM_OK    blob @c data contains the meta-data
+  @retval BSTREAM_ERROR no extra meta-data for that item
+*/
+
+int
+bcat_get_item_create_data(struct st_bstream_image_header *cat,
+                          struct st_bstream_item_info *item,
+                          bstream_blob *data)
+{
+  DBUG_ENTER("bcat_get_item_create_data");
+  DBUG_RETURN(BSTREAM_ERROR);
+}
+
+
+/**
+  Create item from its meta-data.
+
+  When the meta-data section of backup image is read, items are created
+  as their meta-data is read (so that there is no need to store these
+  meta-data). Backup stream library calls this function to create an item.
+
+  @note
+  Either @c create_stmt or @c other_meta_data or both can be empty, depending
+  on what was stored in the image.
+
+  @retval BSTREAM_OK     item created
+  @retval BSTREAM_ERROR  error while creating item
+*/
+
+int
+bcat_create_item(struct st_bstream_image_header *cat,
+                 struct st_bstream_item_info *item,
+                 bstream_blob query,
+                 bstream_blob data)
+{
+  DBUG_ENTER("bcat_create_item");
+  DBUG_PRINT("cat", ("Creating item type: %d  query: '%*s'",
+                     item->type, (int) (query.end - query.begin), query.begin));
+  printf("%*s;\n", (int) (query.end - query.begin), query.begin);
+  DBUG_RETURN(BSTREAM_OK);
+}
+
+/* backup image handling is implemented in C. End of extern "C". */
+}
+
+
+/*
+  =============
+  Main program.
+  =============
+*/
+
+/**
+  Main
+
+  @parameter[in]        argc            argument count
+  @parameter[in]        argv            argument vector
+
+  @return               status
+    @retval             0               ok
+    @retval             != 0            error
+*/
+
+int main(int argc, char** argv)
+{
+  char                                  **defaults_argv;
+  int                                   rc;
+  int                                   idx;
+  struct st_stream                      strm;
+  struct backup_catalog_ambassador      bup_cat_amb;
+  struct st_bstream_image_header        *hdr;
+  backup_catalog                        *bup_catalog;
+  const char                            *image_pos= "begin";
+
+  /* Preparations */
+  MY_INIT(argv[0]);
+  DBUG_ENTER("main");
+  DBUG_PROCESS(argv[0]);
+  my_init_time(); // for time functions
+  load_defaults("my", load_default_groups, &argc, &argv);
+  defaults_argv= argv;
+  rc= handle_options(&argc, &argv, my_long_options, get_one_option);
+  if (rc)
+    goto end;
+  if (argc != 1)
+    goto use_err;
+  my_set_max_open_files(opt_open_files_limit);
+
+  /* Setup catalog data structures. */
+  bup_catalog= new backup_catalog();
+  bzero(&bup_cat_amb, sizeof(bup_cat_amb));
+  bup_cat_amb.amb_catalog= bup_catalog;
+  hdr= &bup_cat_amb.amb_header;
+
+  /*
+    Open backup image stream.
+  */
+  rc= str_open_rd(&strm, argv[0]);
+  if (rc != BSTREAM_OK)
+  {
+    printf("Can't open backup stream (rc=%d)\n", rc);
+    goto end;
+  }
+  image_pos= "magic number";
+
+  /*
+    Read backup image stream header.
+  */
+  rc= bstream_rd_header(&strm.bupstrm, hdr);
+  DBUG_PRINT("cat", ("Read archive header (rc=%d)", rc));
+  if ((rc != BSTREAM_OK) && (rc != BSTREAM_EOC))
+    goto end;
+  image_pos= "header";
+
+  /*
+    Print backup image stream header.
+  */
+  printf("\n");
+  printf("Image  version is %u\n", hdr->version);
+  printf("Server version is %d.%d.%d (%.*s)\n", hdr->server_version.major,
+         hdr->server_version.minor, hdr->server_version.release,
+         (int) (hdr->server_version.extra.end -
+                hdr->server_version.extra.begin),
+         (char*) hdr->server_version.extra.begin);
+  printf("Image options are %u\n", hdr->flags);
+  printf("Creation time  is ");
+  print_time(&hdr->start_time);
+  printf("\n");
+  printf("Validity time  is ");
+  print_time(&hdr->vp_time);
+  printf("\n");
+  printf("Finish   time  is ");
+  print_time(&hdr->end_time);
+  printf("\n");
+  printf("Binlog pos     is %s:%lu\n",
+         hdr->binlog_pos.file, hdr->binlog_pos.pos);
+  printf("Binlog group   is %s:%lu\n",
+         hdr->binlog_group.file, hdr->binlog_group.pos);
+  printf("Snapshot count is %u\n", hdr->snap_count);
+
+  printf("\n");
+
+  printf("Snapshots:\n");
+  printf("\n");
+  for (idx= 0; idx < hdr->snap_count; ++idx)
+  {
+    struct st_bstream_snapshot_info *snapshot= hdr->snapshot + idx;
+    printf("Snapshot version %u\n", snapshot->version);
+    printf("Snapshot type    %d\n", snapshot->type);
+    printf("Snapshot options %u\n", snapshot->options);
+    printf("Snapshot tables  %lu\n", snapshot->table_count);
+    printf("Snapshot engine  '%.*s'  version %u.%u\n",
+           (int) (snapshot->engine.name.end - snapshot->engine.name.begin),
+           snapshot->engine.name.begin,
+           snapshot->engine.major, snapshot->engine.minor);
+    printf("\n");
+  }
+
+  /*
+    Read catalog.
+  */
+  rc= bstream_next_chunk(&strm.bupstrm);
+  DBUG_PRINT("cat", ("Find next chunk (rc=%d)", rc));
+  if (rc != BSTREAM_OK)
+  {
+    if (rc == BSTREAM_EOS)
+    {
+      error("End of stream after %s.\n", image_pos);
+      goto end;
+    }
+    error("Error finding next chunk.\n");
+    goto end;
+  }
+  rc= bstream_rd_catalogue(&strm.bupstrm, hdr);
+  DBUG_PRINT("cat", ("Read archive catalogue (rc=%d)", rc));
+  if ((rc != BSTREAM_OK) && (rc != BSTREAM_EOC))
+  {
+    if (rc == BSTREAM_EOS)
+    {
+      error("End of stream within catalogue.\n");
+      goto end;
+    }
+    error("Error reading catalogue.\n");
+    goto end;
+  }
+  image_pos= "catalog";
+
+  /*
+    Print catalog.
+  */
+  printf("Catalog:\n");
+  /* Charsets. */
+  {
+    backup_charset *chrset;
+    printf("  Character sets:\n");
+    bup_catalog->get_charset_iterator()->list_reset();
+    while ((chrset= (backup_charset*)
+            bup_catalog->get_charset_iterator()->list_next()))
+    {
+      bstream_blob *name= &chrset->get_cs_item()->name;
+      printf("    '%.*s'\n", (int) (name->end - name->begin), name->begin);
+    }
+  }
+  /* Databases. */
+  {
+    backup_database *dbase;
+    printf("  Databases:\n");
+    bup_catalog->get_database_iterator()->list_reset();
+    while ((dbase= (backup_database*)
+            bup_catalog->get_database_iterator()->list_next()))
+    {
+      bstream_blob *name= &dbase->get_db_item()->base.name;
+      printf("    '%.*s'\n", (int) (name->end - name->begin), name->begin);
+
+      /* Tables. */
+      {
+        backup_table *tbl;
+        printf("      Tables:\n");
+        dbase->get_table_iterator()->list_reset();
+        while ((tbl= (backup_table*)
+                dbase->get_table_iterator()->list_next()))
+        {
+          bstream_blob *name= &tbl->get_tbl_item()->base.base.name;
+          printf("        '%.*s'\n", (int) (name->end - name->begin),
+                 name->begin);
+        }
+      }
+    }
+  }
+  printf("\n");
+
+  /*
+    Read and print meta data.
+  */
+  rc= bstream_next_chunk(&strm.bupstrm);
+  DBUG_PRINT("cat", ("Find next chunk (rc=%d)", rc));
+  if (rc != BSTREAM_OK)
+  {
+    if (rc == BSTREAM_EOS)
+    {
+      error("End of stream after %s.\n", image_pos);
+      goto end;
+    }
+    error("Error finding next chunk.\n");
+    goto end;
+  }
+  printf("Meta data:\n");
+  rc= bstream_rd_meta_data(&strm.bupstrm, hdr);
+  DBUG_PRINT("cat", ("Read meta data (rc=%d)", rc));
+  if ((rc != BSTREAM_OK) && (rc != BSTREAM_EOC))
+  {
+    if (rc == BSTREAM_EOS)
+    {
+      error("End of stream within meta data.\n");
+      goto end;
+    }
+    error("Error finding next chunk.\n");
+    goto end;
+  }
+  printf("\n");
+  image_pos= "meta data";
+
+  /*
+    Read table data.
+  */
+  rc= bstream_next_chunk(&strm.bupstrm);
+  DBUG_PRINT("cat", ("Find next chunk (rc=%d)", rc));
+  if (rc != BSTREAM_OK)
+  {
+    if (rc == BSTREAM_EOS)
+    {
+      error("End of stream after %s.\n", image_pos);
+      goto end;
+    }
+    error("Error finding next chunk.\n");
+    goto end;
+  }
+  printf("Snapshot data:\n");
+  do
+  {
+    struct st_bstream_data_chunk chunk;
+
+    chunk.data.begin= NULL;
+    chunk.data.end= NULL;
+
+#ifdef WHY_NOT_HERE
+    rc= bstream_next_chunk(&strm.bupstrm);
+    DBUG_PRINT("cat", ("Find next chunk (rc=%d)", rc));
+    if (rc != BSTREAM_OK)
+    {
+      if (rc == BSTREAM_EOC)
+        break;
+      if (rc == BSTREAM_EOS)
+      {
+        error("End of stream after %s.\n", image_pos);
+        goto end;
+      }
+      error("Error finding next chunk.\n");
+      goto end;
+    }
+#endif
+    rc= bstream_rd_data_chunk(&strm.bupstrm, &chunk);
+    DBUG_PRINT("data", ("Read data chunk (rc=%d)", rc));
+    if (rc != BSTREAM_OK)
+      break;
+    image_pos= "table data";
+
+    printf("  Snapshot %d has %lu bytes for table %lu\n",
+           chunk.snap_num, chunk.data.end - chunk.data.begin, chunk.table_num);
+
+  } while (rc == BSTREAM_OK);
+  DBUG_PRINT("cat", ("Read table data (rc=%d)", rc));
+  printf("\n");
+
+  /* read summary */
+
+#ifdef WHY_NOT_HERE
+  rc= bstream_next_chunk(&strm.bupstrm);
+  DBUG_PRINT("cat", ("Find next chunk (rc=%d)", rc));
+  if (rc != BSTREAM_OK)
+  {
+    if (rc == BSTREAM_EOS)
+    {
+      error("End of stream after %s.\n", image_pos);
+      goto end;
+    }
+    error("Error finding next chunk.\n");
+    goto end;
+  }
+#endif
+  rc= bstream_rd_summary(&strm.bupstrm, hdr);
+  DBUG_PRINT("cat", ("Read summary (rc=%d)", rc));
+  if (rc != BSTREAM_EOS)
+  {
+    if (rc == BSTREAM_ERROR)
+      error("Error reading summary.\n");
+    else
+      error("Stream not at end after reading summary.\n");
+    goto end;
+  }
+  image_pos= "summary";
+
+  printf("Summary:\n");
+  printf("Creation time  is ");
+  print_time(&hdr->start_time);
+  printf("\n");
+  printf("Validity time  is ");
+  print_time(&hdr->vp_time);
+  printf("\n");
+  printf("Finish   time  is ");
+  print_time(&hdr->end_time);
+  printf("\n");
+  printf("Binlog pos     is %s:%lu\n",
+         hdr->binlog_pos.file, hdr->binlog_pos.pos);
+  printf("Binlog group   is %s:%lu\n",
+         hdr->binlog_group.file, hdr->binlog_group.pos);
+
+  goto end;
+
+ use_err:
+  usage();
+  rc= 1;
+
+ end:
+  /* Cleanup. */
+  (void) str_close(&strm);
+  delete bup_catalog;
+  bstream_free(hdr->server_version.extra.begin);
+  for (idx= 0; idx < hdr->snap_count; ++idx)
+    bstream_free(hdr->snapshot[idx].engine.name.begin);
+  free_defaults(defaults_argv);
+  my_free_open_file_info();
+#ifdef MYSQL_CLIENT
+  my_free((char*) opt_database, MYF(MY_ALLOW_ZERO_PTR));
+  my_free((char*) opt_host, MYF(MY_ALLOW_ZERO_PTR));
+  my_free((char*) opt_pass, MYF(MY_ALLOW_ZERO_PTR));
+  my_free((char*) opt_user, MYF(MY_ALLOW_ZERO_PTR));
+#endif
+  /* We cannot free DBUG, it is used in global destructors after exit(). */
+  my_end(MY_DONT_FREE_DBUG);
+  DBUG_RETURN(rc);
+}
+

=== modified file 'mysql-test/t/backup_myisam2.test'
--- a/mysql-test/t/backup_myisam2.test	2008-07-14 15:33:03 +0000
+++ b/mysql-test/t/backup_myisam2.test	2008-09-30 09:14:57 +0000
@@ -78,6 +78,7 @@ SET DEBUG_SYNC= 'now SIGNAL bup_finish';
 --echo
 --echo connection default: cleanup
 connection default;
+--copy_file $MYSQLTEST_VARDIR/master-data/test.ba /tmp/wl4534-test-1.bak
 --remove_file $MYSQLTEST_VARDIR/master-data/test.ba
 SET DEBUG_SYNC= 'RESET';
 

=== modified file 'sql/backup/stream_v1.h'
--- a/sql/backup/stream_v1.h	2008-09-11 09:47:53 +0000
+++ b/sql/backup/stream_v1.h	2008-09-30 09:14:57 +0000
@@ -11,6 +11,11 @@
   stream using version 1 of backup stream format.
 */
 
+/* Let this be usable in C++ files too. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*********************************************************************
  *
  *   BASIC TYPES
@@ -432,4 +437,9 @@ int bstream_open_wr(backup_stream*, unsi
 int bstream_open_rd(backup_stream*, unsigned long int);
 int bstream_close(backup_stream*);
 
+/* Let this be usable in C++ files too. */
+#ifdef __cplusplus
+}
+#endif
+
 #endif /*BACKUP_V1_*/

=== modified file 'sql/backup/stream_v1_services.h'
--- a/sql/backup/stream_v1_services.h	2007-11-29 19:58:12 +0000
+++ b/sql/backup/stream_v1_services.h	2008-09-30 09:14:57 +0000
@@ -14,6 +14,11 @@
   the catalogue of a backup image and perform other tasks.
 */
 
+/* Let this be usable in C++ files too. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /*********************************************************************
  *
  *   CATALOGUE SERVICES
@@ -248,4 +253,9 @@ void bstream_free(bstream_byte *ptr);
 #endif
 
 
+/* Let this be usable in C++ files too. */
+#ifdef __cplusplus
+}
+#endif
+
 #endif /*STREAM_V1_SERVICES_H_*/

Thread
bzr commit into mysql-6.0-backup branch (ingo.struewing:2693) WL#4534Ingo Struewing30 Sep
  • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2693)WL#4534Rafal Somla30 Sep
    • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2693)WL#4534Ingo Strüwing30 Sep
      • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2693)WL#4534Rafal Somla1 Oct
    • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2693)WL#4534Ingo Strüwing30 Sep
      • Re: bzr commit into mysql-6.0-backup branch (ingo.struewing:2693)WL#4534Rafal Somla1 Oct