#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_*/