List:Commits« Previous MessageNext Message »
From:rsomla Date:November 21 2007 10:19am
Subject:bk commit into 6.0 tree (rafal:1.2667) WL#4060
View as plain text  
Below is the list of changes that have just been committed into a local
6.0 repository of rafal. When rafal does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-11-21 11:18:56+01:00, rafal@quant.(none) +11 -0
  WL#4060 (backup kernel updates for beta release)
  
  File renames in preparation for the kernel updates:
  
  archive.{h,cc}     -> catalog.{h,cc}
  meta_backup.{h,cc} -> meta_data.{h,cc}
  sql_backup.{h,cc}  -> kernel.{h,cc}
  
  The patch also introduces uniform spacing in the makefile.

  sql/backup/CMakeLists.txt@stripped, 2007-11-21 11:18:49+01:00, rafal@quant.(none) +2 -2
    Source file renames.

  sql/backup/Makefile.am@stripped, 2007-11-21 11:18:49+01:00, rafal@quant.(none) +39 -39
    Fixing spaces and including file renames.

  sql/backup/backup_kernel.h@stripped, 2007-11-21 11:18:49+01:00, rafal@quant.(none) +1 -1
    Header file rename.

  sql/backup/be_default.h@stripped, 2007-11-21 11:18:49+01:00, rafal@quant.(none) +1 -2
    Header file rename.

  sql/backup/be_snapshot.h@stripped, 2007-11-21 11:18:49+01:00, rafal@quant.(none) +1 -1
    Header file rename.

  sql/backup/be_thread.h@stripped, 2007-11-21 11:18:49+01:00, rafal@quant.(none) +1 -1
    Header file rename.

  sql/backup/catalog.cc@stripped, 2007-11-21 11:18:49+01:00, rafal@quant.(none) +1 -1
    Header file rename.

  sql/backup/catalog.cc@stripped, 2007-11-21 10:57:47+01:00, rafal@quant.(none) +0 -0
    Rename: sql/backup/archive.cc -> sql/backup/catalog.cc

  sql/backup/catalog.h@stripped, 2007-11-21 11:18:50+01:00, rafal@quant.(none) +1 -1
    Header file rename.

  sql/backup/catalog.h@stripped, 2007-11-21 10:57:37+01:00, rafal@quant.(none) +0 -0
    Rename: sql/backup/archive.h -> sql/backup/catalog.h

  sql/backup/kernel.cc@stripped, 2007-11-21 11:18:50+01:00, rafal@quant.(none) +2 -2
    Header file rename.

  sql/backup/kernel.cc@stripped, 2007-11-21 10:58:05+01:00, rafal@quant.(none) +0 -0
    Rename: sql/backup/sql_backup.cc -> sql/backup/kernel.cc

  sql/backup/meta_data.cc@stripped, 2007-11-21 11:18:50+01:00, rafal@quant.(none) +1 -1
    Header file rename.

  sql/backup/meta_data.cc@stripped, 2007-11-21 10:58:25+01:00, rafal@quant.(none) +0 -0
    Rename: sql/backup/meta_backup.cc -> sql/backup/meta_data.cc

  sql/backup/meta_data.h@stripped, 2007-11-21 10:58:17+01:00, rafal@quant.(none) +0 -0
    Rename: sql/backup/meta_backup.h -> sql/backup/meta_data.h

diff -Nrup a/sql/backup/CMakeLists.txt b/sql/backup/CMakeLists.txt
--- a/sql/backup/CMakeLists.txt	2007-11-16 11:05:55 +01:00
+++ b/sql/backup/CMakeLists.txt	2007-11-21 11:18:49 +01:00
@@ -23,8 +23,8 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/
                     ${CMAKE_SOURCE_DIR}/extra/yassl/include)
 
 SET(BACKUP_SOURCES stream.cc logger.cc string_pool.cc
-               archive.cc meta_backup.cc data_backup.cc
-               sql_backup.cc be_default.cc buffer_iterator.cc
+               catalog.cc meta_data.cc data_backup.cc
+               kernel.cc be_default.cc buffer_iterator.cc
                be_snapshot.cc be_thread.cc)
 
 IF(NOT SOURCE_SUBLIBS)
diff -Nrup a/sql/backup/Makefile.am b/sql/backup/Makefile.am
--- a/sql/backup/Makefile.am	2007-11-16 11:10:35 +01:00
+++ b/sql/backup/Makefile.am	2007-11-21 11:18:49 +01:00
@@ -20,55 +20,55 @@
 noinst_LTLIBRARIES = libbackup.la libbackupstream.la
 
 INCLUDES = \
-	-I$(top_builddir)/include \
-	-I$(top_srcdir)/include \
-	-I$(top_srcdir)/sql \
-	-I$(top_srcdir)/regex
+  -I$(top_builddir)/include \
+  -I$(top_srcdir)/include \
+  -I$(top_srcdir)/sql \
+  -I$(top_srcdir)/regex
 
 libbackup_la_SOURCES = \
-	stream.cc \
-	logger.cc \
-	string_pool.cc \
-	archive.cc \
-	meta_backup.cc \
-	data_backup.cc \
-	sql_backup.cc \
-      be_default.cc \
-      be_snapshot.cc \
-      buffer_iterator.cc \
-      be_thread.cc
+  stream.cc \
+  logger.cc \
+  string_pool.cc \
+  catalog.cc \
+  meta_data.cc \
+  data_backup.cc \
+  kernel.cc \
+  be_default.cc \
+  be_snapshot.cc \
+  buffer_iterator.cc \
+  be_thread.cc
 
 libbackupstream_la_SOURCES= \
   stream_v1_transport.c \
   stream_v1.c
 
 noinst_HEADERS = \
-	api_types.h \
-	backup_engine.h \
-	backup_kernel.h \
-    debug.h \
-    error.h \
-    stream.h \
-    backup_aux.h \
-    logger.h \
-    map.h \
-    string_pool.h \
-    archive.h \
-    meta_backup.h \
-      be_default.h \
-      be_snapshot.h \
-      buffer_iterator.h \
-      be_thread.h \
-	stream_v1.h \
-	stream_v1_services.h
+  api_types.h \
+  backup_engine.h \
+  backup_kernel.h \
+  debug.h \
+  error.h \
+  stream.h \
+  backup_aux.h \
+  logger.h \
+  map.h \
+  string_pool.h \
+  catalog.h \
+  meta_data.h \
+  be_default.h \
+  be_snapshot.h \
+  buffer_iterator.h \
+  be_thread.h \
+  stream_v1.h \
+  stream_v1_services.h
 
 DEFS = \
-	-DMYSQL_SERVER \
-	-DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
-	-DDATADIR="\"$(MYSQLDATAdir)\"" \
-	-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
-	-DLIBDIR="\"$(MYSQLLIBdir)\"" \
-	@DEFS@
+  -DMYSQL_SERVER \
+  -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
+  -DDATADIR="\"$(MYSQLDATAdir)\"" \
+  -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
+  -DLIBDIR="\"$(MYSQLLIBdir)\"" \
+  @DEFS@
 
 EXTRA_DIST =	CMakeLists.txt 
 	
diff -Nrup a/sql/backup/archive.cc b/sql/backup/archive.cc
--- a/sql/backup/archive.cc	2007-11-06 19:32:07 +01:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,823 +0,0 @@
-#include "../mysql_priv.h"
-
-/**
-  @file
-
-  Implementation of @c Archive_info and related classes.
- */
-
-/*
-  TODO:
-
-  - Add to Archive_info storage for other meta-data items.
-  - Make existing storage solutions more rational (e.g., string pool).
-  - Make reading code resistant to unknown image formats or meta-data types
-    (or, assume it is handled by format version number).
-  - Improve Image_info::Tables implementation (use some existing data structure).
-  - Add more information to backup archive header , for example server's version
-    string.
-  - Handle backward compatibility (new code reads archive with earlier version
-    number)
-  - Add to Archive_info methods for browsing contents of the archive.
- */
-
-#if defined(USE_PRAGMA_IMPLEMENTATION) || defined(__APPLE_CC__)
-/*
-  #pragma implementation is needed on powermac platform as otherwise compiler 
-  doesn't create/export vtable for Image_info::Tables class (if you know a 
-  better way for fixing this issue let me know! /Rafal).
-  
-  Apparently, configuration macro USE_PRAGMA_IMPLEMENTATION is not set by 
-  ./configure on powermac platform - this is why __APPLE_CC__ is also checked.
- */ 
-#pragma implementation
-#endif
-
-#include "backup_engine.h"
-#include "backup_aux.h"
-#include "archive.h"
-#include "be_default.h"
-#include "be_snapshot.h"
-
-
-/***************************************
-
-   Implementation of Archive_info class
-
- ***************************************/
-
-namespace backup {
-
-Archive_info::~Archive_info()
-{
-  for (uint i=0; i<256; ++i)
-   if (images[i])
-   {
-     delete images[i];
-     images[i]= NULL;
-   }
-}
-
-
-/**
-  Write header and catalogue of a backup archive.
-
-  Header forms the first chunk of archive. Currently it contains archive's
-  format version number followed by a list of table data images used in the
-  archive.
-
-  Next chunk contains the pool of database names. After that there is one chunk
-  per image containing list of tables whose data is saved in that image.
-  @verbatim
-  =====================
-   version number        }
-  ---------------------  }  header
-   image descriptions    }
-  =====================
-   db names              }
-  =====================  }
-   tables of image 1     }
-  =====================  }
-                         }  catalogue
-          ...            }
-                         }
-  =====================  }
-   tables of image N     }
-  =====================
-  @endverbatim
-  In the picture "====" denotes chunk boundaries. Number of images is known
-  from the header.
-
-  The format in which image descriptions are saved is determined by
-  @c Image_info::write_description() method.
-
-  For list of databases and tables the format in which they are saved is
-  defined by @c StringPool::save() and @c Archive_info::Tables::save() methods
-  respectively.
- */
-
-result_t Archive_info::save(OStream &s)
-{
-  DBUG_ENTER("Archive_info::save");
-
-  size_t start_bytes= s.bytes;
-  stream_result::value res;
-
-  res= s.write2int(ver);
-  if (res != stream_result::OK)
-  {
-    DBUG_PRINT("backup",("Can't write archive version number (stream_res=%d)",(int)res));
-    DBUG_RETURN(ERROR);
-  }
-
-  // write list of images
-  DBUG_PRINT("backup",(" writing image list"));
-
-  uint ino;
-  Image_info *img;
-
-  for (ino=0; ino < img_count ; ++ino)
-    if ((img= images[ino]))
-    {
-      DBUG_PRINT("backup",(" %2d: %s image",ino,img->name()));
-      if (ERROR == img->write_description(s))
-      {
-        DBUG_PRINT("backup",("Can't write description of %s image (#%d)",
-                             img->name(),ino));
-        DBUG_RETURN(ERROR);
-      }
-    }
-
-  // close the header chunk
-  res= s.end_chunk();
-  if (res != stream_result::OK)
-  {
-    DBUG_PRINT("backup",("Error when closing image list chunk (stream_res=%d)",(int)res));
-    DBUG_RETURN(ERROR);
-  }
-
-
-  // write catalogue
-  DBUG_PRINT("backup",(" writing archive catalogue"));
-
-  // db names (one chunk)
-  if (ERROR == db_names.save(s)) // note: this closes the chunk
-  {
-    DBUG_PRINT("backup",("Error saving pool of db names (stream_res=%d)",(int)res));
-    DBUG_RETURN(ERROR);
-  }
-
-  // table lists (one chunk per image/list)
-  for (ino=0; ino < img_count ; ++ino)
-    if ((img= images[ino]))
-    {
-      DBUG_PRINT("backup",("  saving %s image's tables",img->name()));
-      if (ERROR == img->tables.save(s))
-      {
-        DBUG_PRINT("backup",("Error saving tables (stream_res=%d)",(int)res));
-        DBUG_RETURN(ERROR);
-      }
-    }
-
-  header_size= s.bytes - start_bytes;
-
-  DBUG_RETURN(OK);
-}
-
-/**
-  Fill @c Archive_info structure reading data from backup archive header and
-  catalogue.
-
-  @returns OK or ERROR
- */
-result_t Archive_info::read(IStream &s)
-{
-  DBUG_ENTER("Archive_info::read");
-
-  size_t start_bytes= s.bytes;
-  result_t res;
-  version_t ver;
-
-  /*
-    We read archive's header which starts with archive format version number.
-    If we can't read the version number (end of stream or no data in the chunk)
-    there is something wrong and we signal error.
-   */
-
-  stream_result::value rres= s.read2int(ver);
-  if ( rres != stream_result::OK)
-  {
-    DBUG_PRINT("restore",("Error reading archive version number"
-                          " (stream_res=%d)",(int)rres));
-    DBUG_RETURN(ERROR);
-  }
-
-  if (ver != Archive_info::ver)
-  {
-    DBUG_PRINT("restore",("Backup archive version %d not supported",ver));
-    DBUG_RETURN(ERROR);
-  }
-
-  /*
-    What follows (until the end of the data chunk) is a list of entries
-    describing data images of the archive. It is read using
-    Image_info::create_from_stream() function which returns DONE when end of
-    chunk is reached.
-   */
-
-  DBUG_PRINT("restore",(" reading image list"));
-
-  uint ino= 0;
-
-  do
-  {
-    Image_info *img;
-
-    res= Image_info::create_from_stream(*this,s,img);
-
-    if (res == OK)
-    {
-      DBUG_ASSERT(img);
-      DBUG_PRINT("restore",("  %2d: %s image",ino,img->name()));
-      images[ino++]= img;
-    }
-
-  } while (res == OK && ino < MAX_IMAGES);
-
-  img_count= ino;
-
-  // If res != DONE we haven't reached end of the chunk - something is wrong
-  if (res != DONE)
-  {
-    DBUG_PRINT("restore",("Error when reading image list (%d images read)",
-                          img_count));
-    DBUG_RETURN(ERROR);
-  }
-
-  /*
-    Next chunk starts archive's catalogue. We proceed with reading it.
-    Note that the catalogue should always contain at least one chunk (db names
-    pool) and hence we should not hit end of stream here.
-   */
-
-  table_count= 0;
-
-  if (s.next_chunk() != stream_result::OK)
-  {
-    DBUG_PRINT("restore",("Can't proceed to the catalogue"));
-    DBUG_RETURN(ERROR);
-  }
-
-  DBUG_PRINT("restore",(" reading catalogue (%d images)",img_count));
-
-  /*
-    First chunk of the catalogue contains db names pool - we read it and
-    proceed to the next chunk. We should never hit end of stream here and
-    so the only acceptable result of db.names.read() is OK.
-   */
-  res= db_names.read(s);
-  if (res != OK)
-  {
-    DBUG_PRINT("restore",("Can't read db names pool (res=%d)",(int)res));
-    DBUG_RETURN(ERROR);
-  }
-
-  /*
-    The following chunks contain lists of tables for each image. There are
-    as many lists as there are images (possibly 0) and each list occupies
-    one chunk.
-   */
-  for (uint ino=0; ino < img_count; ++ino)
-  {
-    Image_info *img= images[ino];
-
-    DBUG_PRINT("restore",(" reading %s image's tables (#%d)",img->name(),ino));
-
-    /*
-      There should be as many lists in the stream as there were images in the
-      header. Thus we should never hit end of stream here.
-     */
-    res= img->tables.read(s); // note: proceeds to the next chunk in the stream
-
-    if (res != OK)
-    {
-      DBUG_PRINT("restore",("Can't read table list for %s image (#%d)",
-                            img->name(),ino));
-      DBUG_RETURN(ERROR); // neither stream nor chunk should end here
-    }
-
-    table_count+= img->tables.count();
-
-    DBUG_PRINT("restore",(" finished reading tables"));
-  }
-
-  header_size= s.bytes - start_bytes;
-
-  DBUG_RETURN(OK);
-}
-
-} // backup namespace
-
-
-/**********************************
-
-  Write/read image descriptions
-
- **********************************/
-
-namespace backup {
-
-/**
-  Write entry describing (format of) a backup driver's image.
-
-  Entry has the form:
-  @verbatim
-  | type | version | image description |
-  @endverbatim
-  where type is a byte holding Image_info::image_type value, version is 2 byte
-  integer holding image format version. The format of optional image description
-  is determined by @c X::do_write_description() method where X is a subclass of
-  Image_info corresponding to given image type.
- */
-result_t
-Image_info::write_description(OStream &s)
-{
-  // TODO: to handle unknown description formats, write description length here
-
-  stream_result::value res= s.writebyte(type());
-
-  if (res != stream_result::OK)
-    return ERROR;
-
-  res= s.write2int(ver);
-
-  if (res != stream_result::OK)
-    return ERROR;
-
-  return do_write_description(s);
-}
-
-/**
-  Create @c Image_info instance from a saved entry describing it.
-
-  @retval OK
-  @retval DONE  end of chunk/stream hit
-  @retval ERROR
- */
-result_t
-Image_info::create_from_stream(Archive_info &info, IStream &s, Image_info* &ptr)
-{
-  uint ver;
-  byte t;
-
-  stream_result::value res= s.readbyte(t);
-
-  // if we are at end of data chunk or stream, we should tell the caller
-  if (res != stream_result::OK)
-    return report_stream_result(res);
-
-  res= s.read2int(ver);
-
-  if (res != stream_result::OK)
-    return ERROR;
-
-  switch (image_type(t)) {
-
-  case NATIVE_IMAGE:
-    return Native_image::create_from_stream(ver,info,s,ptr);
-
-  case DEFAULT_IMAGE:
-    return Default_image::create_from_stream(ver,info,s,ptr);
-
-  case SNAPSHOT_IMAGE:
-    return Snapshot_image::create_from_stream(ver,info,s,ptr);
-
-  default:
-    DBUG_PRINT("restore",("Unknown image type %d",t));
-    return ERROR;
-  }
-}
-
-} // backup namespace
-
-
-/*******************
-
-  Serialization of meta-data items
-
- *******************/
-
-namespace backup {
-
-/**
-  Write an entry describing single meta-data item.
-
-  Entry has format:
-  @verbatim
-  | type | id data | create data |
-  @endverbatim
-  Type is a single byte holding meta::Item::enum_type value. Id data is
-  used to determine which item (from the archive catalogue) the entry
-  corresponds to. Create data is used to create the item.
-
-  The format of id data and create data for item of type X is determined
-  by methods @c Archive_info::X_item::save_id() and @c meta::X::save(),
-  respectively.
-
-  @see @c write_meta_data() for information about the format of the meta-data
-  section of backup archive.
-*/
-result_t
-Archive_info::Item::save(THD *thd, OStream &s)
-{
-  byte b= meta().type();
-
-  stream_result::value res=s.writebyte(b);
-
-  if (res != stream_result::OK)
-    return ERROR;
-
-  if (ERROR == save_id(s))
-    return ERROR;
-
-  return meta().save(thd,s);
-}
-
-/**
-  Create meta-data item from a saved entry.
-
-  This function reads the type byte and calls @c create_from_stream method of
-  corresponding class to create the item. It stores pointer to the created
-  item in @c ptr argument.
-
-  @retval OK    if new item was created
-  @retval DONE  if end of chunk/stream was reached
-  @retval ERROR if error has happened
- */
-result_t
-Archive_info::Item::create_from_stream(const Archive_info &info,
-                                       IStream &s, Item* &ptr)
-{
-  byte b;
-
-  stream_result::value res= s.readbyte(b);
-
-  if (res != stream_result::OK)
-    return report_stream_result(res);
-
-  ptr= NULL;
-
-  result_t res1;
-
-  switch (meta::Item::enum_type(b)) {
-
-  case meta::Item::DB:
-    res1= Db_item::create_from_stream(info,s,ptr);
-    break;
-
-  case meta::Item::TABLE:
-    res1= Table_item::create_from_stream(info,s,ptr);
-    break;
-
-  default: return ERROR;
-
-  }
-
-  /*
-    Note that create_from_stream() should return OK - end of data should not
-    happen here.
-   */
-  if (res1 != OK || ptr == NULL)
-    return ERROR;
-
-  return ptr->meta().read(s);
-}
-
-// Db items
-
-result_t Archive_info::Db_item::save_id(OStream &s)
-{
-  uint k= key;
-  DBUG_PRINT("backup",(" saving db-item (%d)",k));
-  return stream_result::OK == s.writeint(k) ? OK : ERROR;
-}
-
-result_t
-Archive_info::Db_item::create_from_stream(const Archive_info &i,
-                                          IStream &s,
-                                          Archive_info::Item* &ptr)
-{
-  uint k;
-  stream_result::value res= s.readint(k);
-
-  if (res != stream_result::OK)
-    return report_stream_result(res);
-
-  return (ptr= new Db_item(i,k)) ? OK : ERROR;
-}
-
-// Table items
-
-result_t Archive_info::Table_item::save_id(OStream &s)
-{
-  DBUG_PRINT("backup",(" saving table-item (%d,%d)",img,pos));
-  stream_result::value res= s.writeint(img);
-
-  if (res != stream_result::OK)
-    return ERROR;
-
-  res= s.writeint(pos);
-
-  if (res != stream_result::OK)
-    return ERROR;
-
-  return OK;
-}
-
-result_t
-Archive_info::Table_item::create_from_stream(const Archive_info &i,
-                                             IStream &s,
-                                             Archive_info::Item* &ptr)
-{
-  uint img,no;
-  stream_result::value res= s.readint(img);
-
-  if (res != stream_result::OK)
-    return report_stream_result(res);
-
-  res= s.readint(no);
-
-  if (res != stream_result::OK)
-    return ERROR;
-
-  return (ptr= new Table_item(i,img,no)) ? OK : ERROR;
-}
-
-} // backup namespace
-
-
-/**********************************
-
-  Implementation of Image_info::Tables
-
- **********************************/
-
-namespace backup {
-
-// TODO: use better implementation (red-black tree from mysys?)
-
-struct Image_info::Tables::node {
-  StringPool::Key db;
-  String          name;
-  node            *next;
-
-  node(const Image_info::Tables&,
-       const StringPool::Key &k,
-       const String &nm): db(k), next(NULL)
-  {
-    name.copy(nm);
-  }
-};
-
-/// Empty the list.
-void Image_info::Tables::clear()
-{
-  for (node *ptr= m_head; ptr;)
-  {
-    node *n=ptr;
-    ptr= n->next;
-    delete n;
-  }
-
-  m_head= m_last= NULL;
-  m_count= 0;
-}
-
-/**
-  Add a table to the list.
-
-  @returns Position of the table or -1 if error
- */
-int Image_info::Tables::add(const backup::Table_ref &t)
-{
-  StringPool::Key k= m_db_names.add(t.db().name());
-
-  if (!k.is_valid())
-    return -1;
-
-  return add(k,t.name());
-}
-
-/// Add table at given position.
-int Image_info::Tables::add(const StringPool::Key &k, const String &name)
-{
-  node *n= new node(*this,k,name);
-
-  if (!n)
-    return -1;
-
-  if (m_head == NULL)
-  {
-    m_count=1;
-    m_head= m_last= n;
-  }
-  else
-  {
-    m_count++;
-    m_last->next= n;
-    m_last= n;
-  };
-
-  return m_count-1;
-}
-
-/**
-  Locate table at given position.
-
-  @returns Pointer to table's list node or NULL if position is not occupied
- */
-Image_info::Tables::node*
-Image_info::Tables::find_table(uint pos) const
-{
-  DBUG_ASSERT(pos < m_count);
-
-  node *ptr;
-
-  for (ptr= m_head; ptr && pos; ptr= ptr->next)
-   pos--;
-
-  //if( !ptr ) ptr= m_last;
-
-  return ptr;
-}
-
-/// Return table at a given position.
-inline
-Table_ref Image_info::Tables::operator[](uint pos) const
-{
-  // Get access to backup::Table_ref protected constructor
-
-  struct Table_ref: public backup::Table_ref
-  {
-    Table_ref(const StringPool &db_names, Image_info::Tables::node &n):
-      backup::Table_ref(db_names[n.db],n.name)
-    {}
-  };
-
-  node *ptr= find_table(pos);
-  DBUG_ASSERT(ptr);
-
-  return Table_ref(m_db_names,*ptr);
-}
-
-/******************
-
-   Serialization for Image_info::Tables class
-
- ******************/
-
-/**
-  Save list of tables in a backup stream.
-
-  The format used assumes that a pool of database names is stored elsewhere.
-  Thus for each table only the key of the database is stored as var-length
-  integer followed by table name. Empty list is saved as single NIL value.
-
-  The list is stored in a single stream chunk which determines its end.
-
-  @returns OK or ERROR
- */
-result_t
-Image_info::Tables::save(OStream &s)
-{
-  DBUG_ENTER("Image_info::Tables::save");
-  stream_result::value res;
-
-  if (count() == 0)
-  {
-    res= s.writenil();
-    if (res != stream_result::OK)
-      DBUG_RETURN(ERROR);
-  }
-  else
-    for (Tables::node *n= m_head ; n ; n= n->next)
-    {
-      res= s.writeint(n->db);
-      if (res != stream_result::OK)
-        DBUG_RETURN(ERROR);
-
-      res= s.writestr(n->name);
-      if (res != stream_result::OK)
-        DBUG_RETURN(ERROR);
-    };
-
-  res= s.end_chunk();
-  DBUG_RETURN(res == stream_result::ERROR ? ERROR : OK);
-}
-
-/**
-  Read a list from a backup stream.
-
-  @pre Stream is positioned at the first entry of the saved list.
-  @post Stream is positioned at the beginning of next chunk or at its end.
-
-  @retval OK
-  @retval DONE  end of stream or chunk hit (nothing has been read)
-  @retval ERROR
- */
-result_t
-Image_info::Tables::read(IStream &s)
-{
-  DBUG_ENTER("Image_info::Tables::read");
-
-  stream_result::value res;
-  uint k,tno=0;
-
-  /*
-    Read first entry - if it is NIL, we have empty list. Otherwise it should
-    be db index of the first table.
-   */
-
-  res= s.readint(k);
-
-  // If unexpected result, report an error or end of stream/chunk
-  if (res != stream_result::OK && res != stream_result::NIL)
-    DBUG_RETURN(report_stream_result(res));
-
-  // empty the list
-  clear();
-
-  if (res == stream_result::OK) // this is non-empty list
-    do
-    {
-      String                name;
-
-      res= s.readstr(name);
-      if (res != stream_result::OK)
-        break;
-
-      tno= add(k,name);
-      DBUG_PRINT("restore",("got next table %s.%s (pos %d, dbkey %d)",
-                             (*this)[tno].db().name().ptr(),
-                             (*this)[tno].name().ptr(),tno,k));
-      res= s.readint(k);
-    }
-    while (res == stream_result::OK);
-  else
-   /*
-     If we have read NIL value, pretend we are at the end of chunk so that
-     no errors are reported below.
-    */
-   res= stream_result::EOC;
-
-  // we should be now at end of chunk/stream
-  if (res != stream_result::EOC && res != stream_result::EOS)
-  {
-    DBUG_PRINT("restore",("Error when reading table no %d in table list",tno));
-    DBUG_RETURN(ERROR);
-  }
-
-  res= s.next_chunk();
-  DBUG_RETURN(res == stream_result::ERROR ? ERROR : OK);
-}
-
-} // backup namespace
-
-/**************************************
-
-     Native image type definition
-
- **************************************/
-
-namespace backup {
-
-/*
-  For native image its format (apart from the version number) is determined
-  by the storage engine whose backup driver created it. Thus we save the name
-  of storage engine.
-
-  TODO: add more information here. E.g. the version number of the storage engine.
- */
-result_t
-Native_image::do_write_description(OStream &s)
-{
-  String name(::ha_resolve_storage_engine_name(m_hton),&::my_charset_bin);
-  return stream_result::OK == s.writestr(name) ? OK : ERROR;
-}
-
-result_t
-Native_image::create_from_stream(version_t ver,
-                                 Archive_info &info,
-                                 IStream &s, Image_info* &img)
-{
-  String name;
-  stream_result::value res= s.readstr(name);
-
-  if (res != stream_result::OK)
-    return report_stream_result(res);
-
-  LEX_STRING name_lex= name;
-
-  
-  ::handlerton *hton= plugin_data(::ha_resolve_by_name(::current_thd,&name_lex),
-                                  handlerton*);
-  if (!hton)
-    return ERROR;
-
-  img= new Native_image(info,hton);
-  if (!img)
-    return ERROR;
-
-  if (ver > img->ver)
-  {
-    DBUG_PRINT("restore",("Restore diver version %d can't read image version %d",
-                          img->ver,ver));
-    return ERROR;
-  }
-
-  img->ver= ver;
-
-  return OK;
-}
-
-} // backup namespace
diff -Nrup a/sql/backup/archive.h b/sql/backup/archive.h
--- a/sql/backup/archive.h	2007-11-09 22:19:38 +01:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,500 +0,0 @@
-#ifndef _BACKUP_ARCHIVE_H
-#define _BACKUP_ARCHIVE_H
-
-/**
-  @file
-
-  Data types used to represent contents of a backup archive and to read/write
-  its description (catalogue)
- */
-
-#if defined(USE_PRAGMA_INTERFACE) || defined(__APPLE_CC__)
-/*
-  #pragma interface is needed on powermac platform as otherwise compiler 
-  doesn't create/export vtable for Image_info::Tables class (if you know a 
-  better way for fixing this issue let me know! /Rafal).
-  
-  Apparently, configuration macro USE_PRAGMA_INTERFACE is not set by ./configure,
-  on powermac platform - this is why __APPLE_CC__ is also checked.
- */ 
-#pragma interface
-#endif
-
-#include <backup/api_types.h>
-#include <backup/string_pool.h>
-#include <backup/stream.h>
-#include <backup/backup_engine.h>
-#include <backup/meta_backup.h>
-
-namespace backup {
-
-// Forward declaration for a class describing an image inside backup archive.
-class Image_info;
-
-#define MAX_IMAGES  256
-typedef Image_info* Img_list[MAX_IMAGES]; ///< List (vector) of image descriptions.
-
-/**
-  Structure to hold information about binary log.
-*/
-struct st_binlog_info
-{
-  char binlog_file_name[FN_REFLEN];  ///< the file name
-  my_off_t position;                 ///< binlog position
-};
-
-/**
-  Describes contents of a backup archive.
-
-  This class stores a catalogue of a backup archive, that is, description of
-  all items stored in the archive (currently only databases and tables). It also
-  determines how to save and read the catalogue to/from a backup stream.
-
-  Only item names are stored in the catalogue. Other item data is stored
-  in the meta-data part of an archive and in case of tables, their data is
-  stored in images created by backup drivers.
-
-  The @c images member stores a list of @c Image_info objects describing the
-  images included in the archive. Each image description contains a list of
-  tables stored in that image (note that no table can be stored in more than
-  one image).
-
-  To save space, we have a separate pool of database names (@c db_names member).
-  In table references, only the key of the database name is stored, not the
-  whole name.
-
-  When reading or writing backup archive, statistics about the size of its parts
-  is stored in the members of this class for later reporting.
- */
-class Archive_info
-{
- public:
- 
-   static const version_t  ver=1;
-   uint  img_count;       ///< number of images in the archive
-   uint  table_count;     ///< total number of tables in the archive
-
-   size_t total_size;   ///< size of processed backup archive
-   size_t header_size;  ///< size of archive's header (after reading or writing an archive)
-   size_t meta_size;    ///< size of archive's meta-data (after reading or writing an archive)
-   size_t data_size;    ///< size of archive's table data images (after reading or writing an archive)
-
-   st_binlog_info binlog_information; ///< stores binlog information for PTR
-   struct tm start_time;              ///< the start datetime of the backup
-   struct tm end_time;                ///< the end datetime of the backup
-   struct tm vp_time;                 ///< time of validation point
-
-   // Classes representing various types of meta-data items.
-
-   class Item;
-   class Db_item;
-   class Table_item;
-
-  /*
-    Classes which might be used to implement contents browsing.
-
-   class Item_iterator;  // for iterating over all meta-data items
-   class Db_iterator;    // iterates over databases in archive
-   class Ditem_iterator; // iterates over per-db items
-  */
-
-   Img_list images;  ///< list of archive's images
-
-   /// Write archive's header and save the catalogue.
-   result_t save(OStream&);
-   /// Read the header and catalogue from a stream.
-   result_t read(IStream&);
-
-   virtual ~Archive_info();
-
- protected:
-
-   Archive_info():
-     img_count(0), table_count(0),
-     total_size(0), header_size(0), meta_size(0), data_size(0)
-   {
-     for (uint i=0; i<256; ++i)
-       images[i]= NULL;
-   }
-
-   // storage for meta-data items
-
-   StringPool      db_names; ///< Pool of database names.
-
- private:
-
-  friend class Image_info;
-  friend class Db_item;
-  friend class Table_item;
-};
-
-/**
-  Describes an image of table data stored in a backup archive.
-
-  An instance of this class:
-  - informs about the type of image,
-  - stores list of tables whose data is kept in the image,
-  - provides methods for creating backup and restore drivers to write/read the
-    image,
-  - determines which tables can be stored in the image,
-  - defines how image's format is described inside backup archive
-    (via @c do_write_description() method)
- */
-class Image_info
-{
- public:
- 
-  enum image_type {NATIVE_IMAGE, DEFAULT_IMAGE, SNAPSHOT_IMAGE};
-
-  virtual image_type type() const =0; ///< Return type of the image.
-  version_t ver;  ///< Image format version.
-
-  /// Check if instance was correctly constructed
-  virtual bool is_valid() =0;
-  /// Create backup driver for the image.
-  virtual result_t get_backup_driver(Backup_driver*&) =0;
-  /// Create restore driver for the image.
-  virtual result_t get_restore_driver(Restore_driver*&) =0;
-
-  size_t init_size; ///< Size of the initial data transfer (estimate). This is
-                    ///< meaningful only after a call to get_backup_driver().
-
-  /// Write header entry describing the image.
-  result_t write_description(OStream&);
-
-  /**
-    Create instance of @c Image_info described by an entry in backup stream.
-
-    @retval OK    entry successfully read
-    @retval DONE  end of chunk or stream has been reached.
-    @retval ERROR an error was detected
-   */
-  static result_t create_from_stream(Archive_info&, IStream&, Image_info*&);
-
-  /// Determine if a table stored in given engine can be saved in this image.
-  virtual bool accept(const Table_ref&, const ::handlerton*) =0;
-
-  /** 
-    Return name identifying the image in debug messages.
-   
-    The name should fit into "%s backup/restore driver" pattern.
-   */
-  virtual const char* name() const
-  { return "<Unknown>"; }
-
-  virtual ~Image_info()
-  {}
-
-   /*
-     Implementation of Table_list interface used to store the
-     list of tables of an image. Database names are stored in
-     external StringPool
-    */
-   class Tables: public Table_list
-   {
-    public:
-
-     Tables(StringPool &db_names):
-       m_db_names(db_names),
-       m_head(NULL),m_last(NULL),m_count(0)
-     {}
-
-     ~Tables() { clear(); }
-
-     int add(const backup::Table_ref&);
-     void clear();
-
-     backup::Table_ref operator[](uint pos) const;
-     //::TABLE_LIST* get_table_ptr(uint pos) const;
-
-     uint count() const
-     { return m_count; }
-
-     result_t save(OStream&);
-     result_t read(IStream&);
-
-    private:
-
-     struct node;
-
-     int add(const StringPool::Key&, const String&);
-     node* find_table(uint pos) const;
-
-     StringPool &m_db_names;
-     node *m_head, *m_last;
-     uint m_count;
-
-     friend class Table_ref;
-     friend class  Archive_info::Table_item;
-   };
-
-  Tables tables; ///< List of tables stored in the image.
-
- protected:
-
-  Image_info(Archive_info &info):
-    init_size(Driver::UNKNOWN_SIZE), tables(info.db_names)
-  {}
-
-  /**
-    Write image specific data describing it.
-
-    Method redefined in subclasses corresponding to different image types.
-   */
-  virtual result_t do_write_description(OStream&) =0;
-};
-
-/**
-  Represents a meta-data item in a backup archive.
-
-  Instances of this class:
-
-  - identify a meta-data item inside backup archive,
-  - provide storage for a corresponding meta::Item instance,
-  - write item identification data to a backup stream.
-
-  For each type of meta-data there is a specialized subclass of
-  @c Archive_info::Item implementing the above tasks. Each subclass has static
-  @c create_from_stream() method which can create class instance using an
-  identity stored in a stream. For examples, see @c Archive_info::Table_item
-  class.
-
-  Class @c Archive_info::Item defines the format of an entry describing a
-  meta-data item inside the meta-data part of an archive. Such entry is created
-  by @c Archive_info::save() method. These entries are read by
-  @c Restore_info::read_item() method.
- */
-
-class Archive_info::Item
-{
- protected:
-
-  /// Pointer to @c Archive_info instance to which this item belongs.
-  const Archive_info *const m_info;
-  Item  *next; ///< Used to create a linked list of all meta-data items.
-
- public:
-
-  virtual ~Item() {}
-
-  /// Returns reference to the corresponding @c meta::Item instance.
-  virtual meta::Item& meta() =0;
-
-  result_t save(THD*,OStream&); ///< Write entry describing the item.
-
-  // Create item from a saved entry.
-  static result_t create_from_stream(const Archive_info&, IStream&, Item*&);
-
-  class Iterator;
-
- protected:
-
-  Item(const Archive_info &i): m_info(&i), next(NULL)
-  {}
-
-  /// Save data identifying the item inside the archive.
-  virtual result_t save_id(OStream&) =0;
-
-  friend class Archive_info;
-  friend class Backup_info;
-  friend class Restore_info;
-  friend class Iterator;
-};
-
-
-/**
-  Used to iterate over meta-data items.
-
-  Usage:
-  @code
-   Item *head;
-   for (Item::Iterator it(head); it ; it++)
-   {
-     it->archive_item_method()
-   }
-  @endcode
-  or
-  @code
-   Item *head, *p;
-   Item::Iterator it(head);
-
-   while ((p=it++))
-   {
-     @<use p here>
-   }
-  @endcode
- */
-class Archive_info::Item::Iterator
-{
-  Item *m_curr;
-  Item *m_prev;
-
- public:
-
-  Iterator(Item *const head): m_curr(head), m_prev(NULL)
-  {}
-
-  operator bool() const
-  { return m_curr != NULL; }
-
-  Item* operator++(int)
-  {
-    m_prev= m_curr;
-
-    if (m_curr)
-     m_curr= m_curr->next;
-
-    return m_prev;
-  }
-
-  Item* operator->()
-  { DBUG_ASSERT(m_curr);
-    return m_curr; }
-};
-
-
-
-/**
-  Specialization of @c Archive_info::Item representing a database.
-
-  A database is identified by a key into Archive_info::db_names string pool.
-  Using the key one can read database name from the pool. The key is saved
-  as a var-length coded integer.
- */
-class Archive_info::Db_item:
-  public Archive_info::Item, public meta::Db, public Db_ref
-{
-  StringPool::Key   key;
-
-  Db_item(const Archive_info &i, const StringPool::Key &key):
-    Archive_info::Item(i), Db_ref(m_info->db_names[key]), key(key)
-  {}
-
-  meta::Item& meta()
-  { return *this; }
-
-  /// Get the name from @c db_names pool.
-  const char* sql_name() const
-  { return m_info->db_names[key].ptr(); }
-
- public:
-
-  result_t save_id(OStream&);
-  /// Create instance reading its identity from a stream.
-  static
-  result_t create_from_stream(const Archive_info&,IStream&, Archive_info::Item*&);
-
-  friend class Archive_info;
-  friend class Backup_info;
-};
-
-
-/**
-  Specialization of @c Archive_info::Item representing a table.
-
-  A table is identified by its position inside the table list of
-  one of archive's images. Its identity is saved as two var-length coded
-  integers: first being the image number and second the table position inside
-  image's table list.
- */
-class Archive_info::Table_item:
-  public Archive_info::Item, public meta::Table, public Table_ref
-{
-  uint  img;  ///< Image in which this table is saved.
-  uint  pos;  ///< Position of the table in image's table list.
-
-  Table_item(const Archive_info &i, uint no, uint tno):
-    Archive_info::Item(i), Table_ref(i.images[no]->tables[tno]),
-    img(no), pos(tno)
-  {}
-
- public:
-
-  meta::Item& meta()
-  { return *this; }
-
-  const char* sql_name() const
-  { return m_info->images[img]->tables[pos].name().ptr(); }
-
-  /// Table is a per-db item -- indicate to which database it belongs.
-  const Db_ref in_db()
-  { return m_info->images[img]->tables[pos].db(); }
-
-  result_t save_id(OStream&);
-  /// Create instance reading its identity from a stream.
-  static
-  result_t create_from_stream(const Archive_info&,IStream&, Archive_info::Item*&);
-
-  friend class Backup_info;
-};
-
-} // backup namespace
-
-
-/************************************************************
-
-   Class describing native backup image
-
- ************************************************************/
-
-namespace backup {
-
-/**
-  Specialization of @c Image_info for images created by native backup drivers.
- */
-class Native_image: public Image_info
-{
-  const ::handlerton  *m_hton; ///< Pointer to storage engine.
-  Engine   *m_be;  ///< Pointer to the native backup engine.
-
-  const char *m_name;  ///< Used to identify image in debug messages.
-
- public:
-
-  Native_image(Archive_info &info, const ::handlerton *hton):
-    Image_info(info), m_hton(hton)
-  {
-    DBUG_ASSERT(hton);
-    DBUG_ASSERT(hton->get_backup_engine);
-
-    hton->get_backup_engine(const_cast< ::handlerton* >(hton),m_be);
-
-    if(m_be)
-    {
-      ver= m_be->version();
-      m_name= ::ha_resolve_storage_engine_name(hton);
-    }
-  }
-
-  bool is_valid()
-  { return m_be != NULL; }
-
-  image_type type() const
-  { return NATIVE_IMAGE; }
-
-  const char* name() const
-  { return m_name; }
-
-  result_t get_backup_driver(Backup_driver* &drv)
-  {
-    DBUG_ASSERT(m_be);
-    return m_be->get_backup(Driver::PARTIAL,tables,drv);
-  }
-
-  result_t get_restore_driver(Restore_driver* &drv)
-  {
-    DBUG_ASSERT(m_be);
-    return m_be->get_restore(ver,Driver::PARTIAL,tables,drv);
-  }
-
-  result_t do_write_description(OStream&);
-  static result_t create_from_stream(version_t,Archive_info&,IStream&,Image_info*&);
-
-  bool accept(const Table_ref&, const ::handlerton *hton)
-  { return hton == m_hton; }; // this assumes handlertons are single instance objects!
-};
-
-} // backup namespace
-
-
-#endif
diff -Nrup a/sql/backup/backup_kernel.h b/sql/backup/backup_kernel.h
--- a/sql/backup/backup_kernel.h	2007-11-06 19:32:09 +01:00
+++ b/sql/backup/backup_kernel.h	2007-11-21 11:18:49 +01:00
@@ -2,7 +2,7 @@
 #define _BACKUP_KERNEL_API_H
 
 #include <backup/api_types.h>
-#include <backup/archive.h>
+#include <backup/catalog.h>
 #include <backup/stream.h>
 #include <backup/logger.h>
 
diff -Nrup a/sql/backup/be_default.h b/sql/backup/be_default.h
--- a/sql/backup/be_default.h	2007-11-14 21:15:13 +01:00
+++ b/sql/backup/be_default.h	2007-11-21 11:18:49 +01:00
@@ -2,8 +2,7 @@
 #define _DEFAULT_BACKUP_H
 
 #include <backup/backup_engine.h>
-#include <backup/archive.h>   // to define default backup image class
-#include "archive.h"
+#include <backup/catalog.h>   // to define default backup image class
 #include "buffer_iterator.h"
 #include "backup_aux.h"
 #include "mysql_priv.h"
diff -Nrup a/sql/backup/be_snapshot.h b/sql/backup/be_snapshot.h
--- a/sql/backup/be_snapshot.h	2007-11-14 21:15:14 +01:00
+++ b/sql/backup/be_snapshot.h	2007-11-21 11:18:49 +01:00
@@ -1,7 +1,7 @@
 #ifndef _SNAPSHOT_BACKUP_H
 #define _SNAPSHOT_BACKUP_H
 
-#include "archive.h"        
+#include "catalog.h"        
 #include "buffer_iterator.h"
 #include "be_default.h"
 
diff -Nrup a/sql/backup/be_thread.h b/sql/backup/be_thread.h
--- a/sql/backup/be_thread.h	2007-11-14 21:15:17 +01:00
+++ b/sql/backup/be_thread.h	2007-11-21 11:18:49 +01:00
@@ -2,7 +2,7 @@
 #define _BACKUP_THREAD_H
 
 #include "../mysql_priv.h"
-#include "archive.h"
+#include "catalog.h"
 #include "api_types.h"
 #include "backup_engine.h"
 
diff -Nrup a/sql/backup/catalog.cc b/sql/backup/catalog.cc
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sql/backup/catalog.cc	2007-11-21 11:18:49 +01:00
@@ -0,0 +1,823 @@
+#include "../mysql_priv.h"
+
+/**
+  @file
+
+  Implementation of @c Archive_info and related classes.
+ */
+
+/*
+  TODO:
+
+  - Add to Archive_info storage for other meta-data items.
+  - Make existing storage solutions more rational (e.g., string pool).
+  - Make reading code resistant to unknown image formats or meta-data types
+    (or, assume it is handled by format version number).
+  - Improve Image_info::Tables implementation (use some existing data structure).
+  - Add more information to backup archive header , for example server's version
+    string.
+  - Handle backward compatibility (new code reads archive with earlier version
+    number)
+  - Add to Archive_info methods for browsing contents of the archive.
+ */
+
+#if defined(USE_PRAGMA_IMPLEMENTATION) || defined(__APPLE_CC__)
+/*
+  #pragma implementation is needed on powermac platform as otherwise compiler 
+  doesn't create/export vtable for Image_info::Tables class (if you know a 
+  better way for fixing this issue let me know! /Rafal).
+  
+  Apparently, configuration macro USE_PRAGMA_IMPLEMENTATION is not set by 
+  ./configure on powermac platform - this is why __APPLE_CC__ is also checked.
+ */ 
+#pragma implementation
+#endif
+
+#include "backup_engine.h"
+#include "backup_aux.h"
+#include "catalog.h"
+#include "be_default.h"
+#include "be_snapshot.h"
+
+
+/***************************************
+
+   Implementation of Archive_info class
+
+ ***************************************/
+
+namespace backup {
+
+Archive_info::~Archive_info()
+{
+  for (uint i=0; i<256; ++i)
+   if (images[i])
+   {
+     delete images[i];
+     images[i]= NULL;
+   }
+}
+
+
+/**
+  Write header and catalogue of a backup archive.
+
+  Header forms the first chunk of archive. Currently it contains archive's
+  format version number followed by a list of table data images used in the
+  archive.
+
+  Next chunk contains the pool of database names. After that there is one chunk
+  per image containing list of tables whose data is saved in that image.
+  @verbatim
+  =====================
+   version number        }
+  ---------------------  }  header
+   image descriptions    }
+  =====================
+   db names              }
+  =====================  }
+   tables of image 1     }
+  =====================  }
+                         }  catalogue
+          ...            }
+                         }
+  =====================  }
+   tables of image N     }
+  =====================
+  @endverbatim
+  In the picture "====" denotes chunk boundaries. Number of images is known
+  from the header.
+
+  The format in which image descriptions are saved is determined by
+  @c Image_info::write_description() method.
+
+  For list of databases and tables the format in which they are saved is
+  defined by @c StringPool::save() and @c Archive_info::Tables::save() methods
+  respectively.
+ */
+
+result_t Archive_info::save(OStream &s)
+{
+  DBUG_ENTER("Archive_info::save");
+
+  size_t start_bytes= s.bytes;
+  stream_result::value res;
+
+  res= s.write2int(ver);
+  if (res != stream_result::OK)
+  {
+    DBUG_PRINT("backup",("Can't write archive version number (stream_res=%d)",(int)res));
+    DBUG_RETURN(ERROR);
+  }
+
+  // write list of images
+  DBUG_PRINT("backup",(" writing image list"));
+
+  uint ino;
+  Image_info *img;
+
+  for (ino=0; ino < img_count ; ++ino)
+    if ((img= images[ino]))
+    {
+      DBUG_PRINT("backup",(" %2d: %s image",ino,img->name()));
+      if (ERROR == img->write_description(s))
+      {
+        DBUG_PRINT("backup",("Can't write description of %s image (#%d)",
+                             img->name(),ino));
+        DBUG_RETURN(ERROR);
+      }
+    }
+
+  // close the header chunk
+  res= s.end_chunk();
+  if (res != stream_result::OK)
+  {
+    DBUG_PRINT("backup",("Error when closing image list chunk (stream_res=%d)",(int)res));
+    DBUG_RETURN(ERROR);
+  }
+
+
+  // write catalogue
+  DBUG_PRINT("backup",(" writing archive catalogue"));
+
+  // db names (one chunk)
+  if (ERROR == db_names.save(s)) // note: this closes the chunk
+  {
+    DBUG_PRINT("backup",("Error saving pool of db names (stream_res=%d)",(int)res));
+    DBUG_RETURN(ERROR);
+  }
+
+  // table lists (one chunk per image/list)
+  for (ino=0; ino < img_count ; ++ino)
+    if ((img= images[ino]))
+    {
+      DBUG_PRINT("backup",("  saving %s image's tables",img->name()));
+      if (ERROR == img->tables.save(s))
+      {
+        DBUG_PRINT("backup",("Error saving tables (stream_res=%d)",(int)res));
+        DBUG_RETURN(ERROR);
+      }
+    }
+
+  header_size= s.bytes - start_bytes;
+
+  DBUG_RETURN(OK);
+}
+
+/**
+  Fill @c Archive_info structure reading data from backup archive header and
+  catalogue.
+
+  @returns OK or ERROR
+ */
+result_t Archive_info::read(IStream &s)
+{
+  DBUG_ENTER("Archive_info::read");
+
+  size_t start_bytes= s.bytes;
+  result_t res;
+  version_t ver;
+
+  /*
+    We read archive's header which starts with archive format version number.
+    If we can't read the version number (end of stream or no data in the chunk)
+    there is something wrong and we signal error.
+   */
+
+  stream_result::value rres= s.read2int(ver);
+  if ( rres != stream_result::OK)
+  {
+    DBUG_PRINT("restore",("Error reading archive version number"
+                          " (stream_res=%d)",(int)rres));
+    DBUG_RETURN(ERROR);
+  }
+
+  if (ver != Archive_info::ver)
+  {
+    DBUG_PRINT("restore",("Backup archive version %d not supported",ver));
+    DBUG_RETURN(ERROR);
+  }
+
+  /*
+    What follows (until the end of the data chunk) is a list of entries
+    describing data images of the archive. It is read using
+    Image_info::create_from_stream() function which returns DONE when end of
+    chunk is reached.
+   */
+
+  DBUG_PRINT("restore",(" reading image list"));
+
+  uint ino= 0;
+
+  do
+  {
+    Image_info *img;
+
+    res= Image_info::create_from_stream(*this,s,img);
+
+    if (res == OK)
+    {
+      DBUG_ASSERT(img);
+      DBUG_PRINT("restore",("  %2d: %s image",ino,img->name()));
+      images[ino++]= img;
+    }
+
+  } while (res == OK && ino < MAX_IMAGES);
+
+  img_count= ino;
+
+  // If res != DONE we haven't reached end of the chunk - something is wrong
+  if (res != DONE)
+  {
+    DBUG_PRINT("restore",("Error when reading image list (%d images read)",
+                          img_count));
+    DBUG_RETURN(ERROR);
+  }
+
+  /*
+    Next chunk starts archive's catalogue. We proceed with reading it.
+    Note that the catalogue should always contain at least one chunk (db names
+    pool) and hence we should not hit end of stream here.
+   */
+
+  table_count= 0;
+
+  if (s.next_chunk() != stream_result::OK)
+  {
+    DBUG_PRINT("restore",("Can't proceed to the catalogue"));
+    DBUG_RETURN(ERROR);
+  }
+
+  DBUG_PRINT("restore",(" reading catalogue (%d images)",img_count));
+
+  /*
+    First chunk of the catalogue contains db names pool - we read it and
+    proceed to the next chunk. We should never hit end of stream here and
+    so the only acceptable result of db.names.read() is OK.
+   */
+  res= db_names.read(s);
+  if (res != OK)
+  {
+    DBUG_PRINT("restore",("Can't read db names pool (res=%d)",(int)res));
+    DBUG_RETURN(ERROR);
+  }
+
+  /*
+    The following chunks contain lists of tables for each image. There are
+    as many lists as there are images (possibly 0) and each list occupies
+    one chunk.
+   */
+  for (uint ino=0; ino < img_count; ++ino)
+  {
+    Image_info *img= images[ino];
+
+    DBUG_PRINT("restore",(" reading %s image's tables (#%d)",img->name(),ino));
+
+    /*
+      There should be as many lists in the stream as there were images in the
+      header. Thus we should never hit end of stream here.
+     */
+    res= img->tables.read(s); // note: proceeds to the next chunk in the stream
+
+    if (res != OK)
+    {
+      DBUG_PRINT("restore",("Can't read table list for %s image (#%d)",
+                            img->name(),ino));
+      DBUG_RETURN(ERROR); // neither stream nor chunk should end here
+    }
+
+    table_count+= img->tables.count();
+
+    DBUG_PRINT("restore",(" finished reading tables"));
+  }
+
+  header_size= s.bytes - start_bytes;
+
+  DBUG_RETURN(OK);
+}
+
+} // backup namespace
+
+
+/**********************************
+
+  Write/read image descriptions
+
+ **********************************/
+
+namespace backup {
+
+/**
+  Write entry describing (format of) a backup driver's image.
+
+  Entry has the form:
+  @verbatim
+  | type | version | image description |
+  @endverbatim
+  where type is a byte holding Image_info::image_type value, version is 2 byte
+  integer holding image format version. The format of optional image description
+  is determined by @c X::do_write_description() method where X is a subclass of
+  Image_info corresponding to given image type.
+ */
+result_t
+Image_info::write_description(OStream &s)
+{
+  // TODO: to handle unknown description formats, write description length here
+
+  stream_result::value res= s.writebyte(type());
+
+  if (res != stream_result::OK)
+    return ERROR;
+
+  res= s.write2int(ver);
+
+  if (res != stream_result::OK)
+    return ERROR;
+
+  return do_write_description(s);
+}
+
+/**
+  Create @c Image_info instance from a saved entry describing it.
+
+  @retval OK
+  @retval DONE  end of chunk/stream hit
+  @retval ERROR
+ */
+result_t
+Image_info::create_from_stream(Archive_info &info, IStream &s, Image_info* &ptr)
+{
+  uint ver;
+  byte t;
+
+  stream_result::value res= s.readbyte(t);
+
+  // if we are at end of data chunk or stream, we should tell the caller
+  if (res != stream_result::OK)
+    return report_stream_result(res);
+
+  res= s.read2int(ver);
+
+  if (res != stream_result::OK)
+    return ERROR;
+
+  switch (image_type(t)) {
+
+  case NATIVE_IMAGE:
+    return Native_image::create_from_stream(ver,info,s,ptr);
+
+  case DEFAULT_IMAGE:
+    return Default_image::create_from_stream(ver,info,s,ptr);
+
+  case SNAPSHOT_IMAGE:
+    return Snapshot_image::create_from_stream(ver,info,s,ptr);
+
+  default:
+    DBUG_PRINT("restore",("Unknown image type %d",t));
+    return ERROR;
+  }
+}
+
+} // backup namespace
+
+
+/*******************
+
+  Serialization of meta-data items
+
+ *******************/
+
+namespace backup {
+
+/**
+  Write an entry describing single meta-data item.
+
+  Entry has format:
+  @verbatim
+  | type | id data | create data |
+  @endverbatim
+  Type is a single byte holding meta::Item::enum_type value. Id data is
+  used to determine which item (from the archive catalogue) the entry
+  corresponds to. Create data is used to create the item.
+
+  The format of id data and create data for item of type X is determined
+  by methods @c Archive_info::X_item::save_id() and @c meta::X::save(),
+  respectively.
+
+  @see @c write_meta_data() for information about the format of the meta-data
+  section of backup archive.
+*/
+result_t
+Archive_info::Item::save(THD *thd, OStream &s)
+{
+  byte b= meta().type();
+
+  stream_result::value res=s.writebyte(b);
+
+  if (res != stream_result::OK)
+    return ERROR;
+
+  if (ERROR == save_id(s))
+    return ERROR;
+
+  return meta().save(thd,s);
+}
+
+/**
+  Create meta-data item from a saved entry.
+
+  This function reads the type byte and calls @c create_from_stream method of
+  corresponding class to create the item. It stores pointer to the created
+  item in @c ptr argument.
+
+  @retval OK    if new item was created
+  @retval DONE  if end of chunk/stream was reached
+  @retval ERROR if error has happened
+ */
+result_t
+Archive_info::Item::create_from_stream(const Archive_info &info,
+                                       IStream &s, Item* &ptr)
+{
+  byte b;
+
+  stream_result::value res= s.readbyte(b);
+
+  if (res != stream_result::OK)
+    return report_stream_result(res);
+
+  ptr= NULL;
+
+  result_t res1;
+
+  switch (meta::Item::enum_type(b)) {
+
+  case meta::Item::DB:
+    res1= Db_item::create_from_stream(info,s,ptr);
+    break;
+
+  case meta::Item::TABLE:
+    res1= Table_item::create_from_stream(info,s,ptr);
+    break;
+
+  default: return ERROR;
+
+  }
+
+  /*
+    Note that create_from_stream() should return OK - end of data should not
+    happen here.
+   */
+  if (res1 != OK || ptr == NULL)
+    return ERROR;
+
+  return ptr->meta().read(s);
+}
+
+// Db items
+
+result_t Archive_info::Db_item::save_id(OStream &s)
+{
+  uint k= key;
+  DBUG_PRINT("backup",(" saving db-item (%d)",k));
+  return stream_result::OK == s.writeint(k) ? OK : ERROR;
+}
+
+result_t
+Archive_info::Db_item::create_from_stream(const Archive_info &i,
+                                          IStream &s,
+                                          Archive_info::Item* &ptr)
+{
+  uint k;
+  stream_result::value res= s.readint(k);
+
+  if (res != stream_result::OK)
+    return report_stream_result(res);
+
+  return (ptr= new Db_item(i,k)) ? OK : ERROR;
+}
+
+// Table items
+
+result_t Archive_info::Table_item::save_id(OStream &s)
+{
+  DBUG_PRINT("backup",(" saving table-item (%d,%d)",img,pos));
+  stream_result::value res= s.writeint(img);
+
+  if (res != stream_result::OK)
+    return ERROR;
+
+  res= s.writeint(pos);
+
+  if (res != stream_result::OK)
+    return ERROR;
+
+  return OK;
+}
+
+result_t
+Archive_info::Table_item::create_from_stream(const Archive_info &i,
+                                             IStream &s,
+                                             Archive_info::Item* &ptr)
+{
+  uint img,no;
+  stream_result::value res= s.readint(img);
+
+  if (res != stream_result::OK)
+    return report_stream_result(res);
+
+  res= s.readint(no);
+
+  if (res != stream_result::OK)
+    return ERROR;
+
+  return (ptr= new Table_item(i,img,no)) ? OK : ERROR;
+}
+
+} // backup namespace
+
+
+/**********************************
+
+  Implementation of Image_info::Tables
+
+ **********************************/
+
+namespace backup {
+
+// TODO: use better implementation (red-black tree from mysys?)
+
+struct Image_info::Tables::node {
+  StringPool::Key db;
+  String          name;
+  node            *next;
+
+  node(const Image_info::Tables&,
+       const StringPool::Key &k,
+       const String &nm): db(k), next(NULL)
+  {
+    name.copy(nm);
+  }
+};
+
+/// Empty the list.
+void Image_info::Tables::clear()
+{
+  for (node *ptr= m_head; ptr;)
+  {
+    node *n=ptr;
+    ptr= n->next;
+    delete n;
+  }
+
+  m_head= m_last= NULL;
+  m_count= 0;
+}
+
+/**
+  Add a table to the list.
+
+  @returns Position of the table or -1 if error
+ */
+int Image_info::Tables::add(const backup::Table_ref &t)
+{
+  StringPool::Key k= m_db_names.add(t.db().name());
+
+  if (!k.is_valid())
+    return -1;
+
+  return add(k,t.name());
+}
+
+/// Add table at given position.
+int Image_info::Tables::add(const StringPool::Key &k, const String &name)
+{
+  node *n= new node(*this,k,name);
+
+  if (!n)
+    return -1;
+
+  if (m_head == NULL)
+  {
+    m_count=1;
+    m_head= m_last= n;
+  }
+  else
+  {
+    m_count++;
+    m_last->next= n;
+    m_last= n;
+  };
+
+  return m_count-1;
+}
+
+/**
+  Locate table at given position.
+
+  @returns Pointer to table's list node or NULL if position is not occupied
+ */
+Image_info::Tables::node*
+Image_info::Tables::find_table(uint pos) const
+{
+  DBUG_ASSERT(pos < m_count);
+
+  node *ptr;
+
+  for (ptr= m_head; ptr && pos; ptr= ptr->next)
+   pos--;
+
+  //if( !ptr ) ptr= m_last;
+
+  return ptr;
+}
+
+/// Return table at a given position.
+inline
+Table_ref Image_info::Tables::operator[](uint pos) const
+{
+  // Get access to backup::Table_ref protected constructor
+
+  struct Table_ref: public backup::Table_ref
+  {
+    Table_ref(const StringPool &db_names, Image_info::Tables::node &n):
+      backup::Table_ref(db_names[n.db],n.name)
+    {}
+  };
+
+  node *ptr= find_table(pos);
+  DBUG_ASSERT(ptr);
+
+  return Table_ref(m_db_names,*ptr);
+}
+
+/******************
+
+   Serialization for Image_info::Tables class
+
+ ******************/
+
+/**
+  Save list of tables in a backup stream.
+
+  The format used assumes that a pool of database names is stored elsewhere.
+  Thus for each table only the key of the database is stored as var-length
+  integer followed by table name. Empty list is saved as single NIL value.
+
+  The list is stored in a single stream chunk which determines its end.
+
+  @returns OK or ERROR
+ */
+result_t
+Image_info::Tables::save(OStream &s)
+{
+  DBUG_ENTER("Image_info::Tables::save");
+  stream_result::value res;
+
+  if (count() == 0)
+  {
+    res= s.writenil();
+    if (res != stream_result::OK)
+      DBUG_RETURN(ERROR);
+  }
+  else
+    for (Tables::node *n= m_head ; n ; n= n->next)
+    {
+      res= s.writeint(n->db);
+      if (res != stream_result::OK)
+        DBUG_RETURN(ERROR);
+
+      res= s.writestr(n->name);
+      if (res != stream_result::OK)
+        DBUG_RETURN(ERROR);
+    };
+
+  res= s.end_chunk();
+  DBUG_RETURN(res == stream_result::ERROR ? ERROR : OK);
+}
+
+/**
+  Read a list from a backup stream.
+
+  @pre Stream is positioned at the first entry of the saved list.
+  @post Stream is positioned at the beginning of next chunk or at its end.
+
+  @retval OK
+  @retval DONE  end of stream or chunk hit (nothing has been read)
+  @retval ERROR
+ */
+result_t
+Image_info::Tables::read(IStream &s)
+{
+  DBUG_ENTER("Image_info::Tables::read");
+
+  stream_result::value res;
+  uint k,tno=0;
+
+  /*
+    Read first entry - if it is NIL, we have empty list. Otherwise it should
+    be db index of the first table.
+   */
+
+  res= s.readint(k);
+
+  // If unexpected result, report an error or end of stream/chunk
+  if (res != stream_result::OK && res != stream_result::NIL)
+    DBUG_RETURN(report_stream_result(res));
+
+  // empty the list
+  clear();
+
+  if (res == stream_result::OK) // this is non-empty list
+    do
+    {
+      String                name;
+
+      res= s.readstr(name);
+      if (res != stream_result::OK)
+        break;
+
+      tno= add(k,name);
+      DBUG_PRINT("restore",("got next table %s.%s (pos %d, dbkey %d)",
+                             (*this)[tno].db().name().ptr(),
+                             (*this)[tno].name().ptr(),tno,k));
+      res= s.readint(k);
+    }
+    while (res == stream_result::OK);
+  else
+   /*
+     If we have read NIL value, pretend we are at the end of chunk so that
+     no errors are reported below.
+    */
+   res= stream_result::EOC;
+
+  // we should be now at end of chunk/stream
+  if (res != stream_result::EOC && res != stream_result::EOS)
+  {
+    DBUG_PRINT("restore",("Error when reading table no %d in table list",tno));
+    DBUG_RETURN(ERROR);
+  }
+
+  res= s.next_chunk();
+  DBUG_RETURN(res == stream_result::ERROR ? ERROR : OK);
+}
+
+} // backup namespace
+
+/**************************************
+
+     Native image type definition
+
+ **************************************/
+
+namespace backup {
+
+/*
+  For native image its format (apart from the version number) is determined
+  by the storage engine whose backup driver created it. Thus we save the name
+  of storage engine.
+
+  TODO: add more information here. E.g. the version number of the storage engine.
+ */
+result_t
+Native_image::do_write_description(OStream &s)
+{
+  String name(::ha_resolve_storage_engine_name(m_hton),&::my_charset_bin);
+  return stream_result::OK == s.writestr(name) ? OK : ERROR;
+}
+
+result_t
+Native_image::create_from_stream(version_t ver,
+                                 Archive_info &info,
+                                 IStream &s, Image_info* &img)
+{
+  String name;
+  stream_result::value res= s.readstr(name);
+
+  if (res != stream_result::OK)
+    return report_stream_result(res);
+
+  LEX_STRING name_lex= name;
+
+  
+  ::handlerton *hton= plugin_data(::ha_resolve_by_name(::current_thd,&name_lex),
+                                  handlerton*);
+  if (!hton)
+    return ERROR;
+
+  img= new Native_image(info,hton);
+  if (!img)
+    return ERROR;
+
+  if (ver > img->ver)
+  {
+    DBUG_PRINT("restore",("Restore diver version %d can't read image version %d",
+                          img->ver,ver));
+    return ERROR;
+  }
+
+  img->ver= ver;
+
+  return OK;
+}
+
+} // backup namespace
diff -Nrup a/sql/backup/catalog.h b/sql/backup/catalog.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sql/backup/catalog.h	2007-11-21 11:18:50 +01:00
@@ -0,0 +1,500 @@
+#ifndef _BACKUP_ARCHIVE_H
+#define _BACKUP_ARCHIVE_H
+
+/**
+  @file
+
+  Data types used to represent contents of a backup archive and to read/write
+  its description (catalogue)
+ */
+
+#if defined(USE_PRAGMA_INTERFACE) || defined(__APPLE_CC__)
+/*
+  #pragma interface is needed on powermac platform as otherwise compiler 
+  doesn't create/export vtable for Image_info::Tables class (if you know a 
+  better way for fixing this issue let me know! /Rafal).
+  
+  Apparently, configuration macro USE_PRAGMA_INTERFACE is not set by ./configure,
+  on powermac platform - this is why __APPLE_CC__ is also checked.
+ */ 
+#pragma interface
+#endif
+
+#include <backup/api_types.h>
+#include <backup/string_pool.h>
+#include <backup/stream.h>
+#include <backup/backup_engine.h>
+#include <backup/meta_data.h>
+
+namespace backup {
+
+// Forward declaration for a class describing an image inside backup archive.
+class Image_info;
+
+#define MAX_IMAGES  256
+typedef Image_info* Img_list[MAX_IMAGES]; ///< List (vector) of image descriptions.
+
+/**
+  Structure to hold information about binary log.
+*/
+struct st_binlog_info
+{
+  char binlog_file_name[FN_REFLEN];  ///< the file name
+  my_off_t position;                 ///< binlog position
+};
+
+/**
+  Describes contents of a backup archive.
+
+  This class stores a catalogue of a backup archive, that is, description of
+  all items stored in the archive (currently only databases and tables). It also
+  determines how to save and read the catalogue to/from a backup stream.
+
+  Only item names are stored in the catalogue. Other item data is stored
+  in the meta-data part of an archive and in case of tables, their data is
+  stored in images created by backup drivers.
+
+  The @c images member stores a list of @c Image_info objects describing the
+  images included in the archive. Each image description contains a list of
+  tables stored in that image (note that no table can be stored in more than
+  one image).
+
+  To save space, we have a separate pool of database names (@c db_names member).
+  In table references, only the key of the database name is stored, not the
+  whole name.
+
+  When reading or writing backup archive, statistics about the size of its parts
+  is stored in the members of this class for later reporting.
+ */
+class Archive_info
+{
+ public:
+ 
+   static const version_t  ver=1;
+   uint  img_count;       ///< number of images in the archive
+   uint  table_count;     ///< total number of tables in the archive
+
+   size_t total_size;   ///< size of processed backup archive
+   size_t header_size;  ///< size of archive's header (after reading or writing an archive)
+   size_t meta_size;    ///< size of archive's meta-data (after reading or writing an archive)
+   size_t data_size;    ///< size of archive's table data images (after reading or writing an archive)
+
+   st_binlog_info binlog_information; ///< stores binlog information for PTR
+   struct tm start_time;              ///< the start datetime of the backup
+   struct tm end_time;                ///< the end datetime of the backup
+   struct tm vp_time;                 ///< time of validation point
+
+   // Classes representing various types of meta-data items.
+
+   class Item;
+   class Db_item;
+   class Table_item;
+
+  /*
+    Classes which might be used to implement contents browsing.
+
+   class Item_iterator;  // for iterating over all meta-data items
+   class Db_iterator;    // iterates over databases in archive
+   class Ditem_iterator; // iterates over per-db items
+  */
+
+   Img_list images;  ///< list of archive's images
+
+   /// Write archive's header and save the catalogue.
+   result_t save(OStream&);
+   /// Read the header and catalogue from a stream.
+   result_t read(IStream&);
+
+   virtual ~Archive_info();
+
+ protected:
+
+   Archive_info():
+     img_count(0), table_count(0),
+     total_size(0), header_size(0), meta_size(0), data_size(0)
+   {
+     for (uint i=0; i<256; ++i)
+       images[i]= NULL;
+   }
+
+   // storage for meta-data items
+
+   StringPool      db_names; ///< Pool of database names.
+
+ private:
+
+  friend class Image_info;
+  friend class Db_item;
+  friend class Table_item;
+};
+
+/**
+  Describes an image of table data stored in a backup archive.
+
+  An instance of this class:
+  - informs about the type of image,
+  - stores list of tables whose data is kept in the image,
+  - provides methods for creating backup and restore drivers to write/read the
+    image,
+  - determines which tables can be stored in the image,
+  - defines how image's format is described inside backup archive
+    (via @c do_write_description() method)
+ */
+class Image_info
+{
+ public:
+ 
+  enum image_type {NATIVE_IMAGE, DEFAULT_IMAGE, SNAPSHOT_IMAGE};
+
+  virtual image_type type() const =0; ///< Return type of the image.
+  version_t ver;  ///< Image format version.
+
+  /// Check if instance was correctly constructed
+  virtual bool is_valid() =0;
+  /// Create backup driver for the image.
+  virtual result_t get_backup_driver(Backup_driver*&) =0;
+  /// Create restore driver for the image.
+  virtual result_t get_restore_driver(Restore_driver*&) =0;
+
+  size_t init_size; ///< Size of the initial data transfer (estimate). This is
+                    ///< meaningful only after a call to get_backup_driver().
+
+  /// Write header entry describing the image.
+  result_t write_description(OStream&);
+
+  /**
+    Create instance of @c Image_info described by an entry in backup stream.
+
+    @retval OK    entry successfully read
+    @retval DONE  end of chunk or stream has been reached.
+    @retval ERROR an error was detected
+   */
+  static result_t create_from_stream(Archive_info&, IStream&, Image_info*&);
+
+  /// Determine if a table stored in given engine can be saved in this image.
+  virtual bool accept(const Table_ref&, const ::handlerton*) =0;
+
+  /** 
+    Return name identifying the image in debug messages.
+   
+    The name should fit into "%s backup/restore driver" pattern.
+   */
+  virtual const char* name() const
+  { return "<Unknown>"; }
+
+  virtual ~Image_info()
+  {}
+
+   /*
+     Implementation of Table_list interface used to store the
+     list of tables of an image. Database names are stored in
+     external StringPool
+    */
+   class Tables: public Table_list
+   {
+    public:
+
+     Tables(StringPool &db_names):
+       m_db_names(db_names),
+       m_head(NULL),m_last(NULL),m_count(0)
+     {}
+
+     ~Tables() { clear(); }
+
+     int add(const backup::Table_ref&);
+     void clear();
+
+     backup::Table_ref operator[](uint pos) const;
+     //::TABLE_LIST* get_table_ptr(uint pos) const;
+
+     uint count() const
+     { return m_count; }
+
+     result_t save(OStream&);
+     result_t read(IStream&);
+
+    private:
+
+     struct node;
+
+     int add(const StringPool::Key&, const String&);
+     node* find_table(uint pos) const;
+
+     StringPool &m_db_names;
+     node *m_head, *m_last;
+     uint m_count;
+
+     friend class Table_ref;
+     friend class  Archive_info::Table_item;
+   };
+
+  Tables tables; ///< List of tables stored in the image.
+
+ protected:
+
+  Image_info(Archive_info &info):
+    init_size(Driver::UNKNOWN_SIZE), tables(info.db_names)
+  {}
+
+  /**
+    Write image specific data describing it.
+
+    Method redefined in subclasses corresponding to different image types.
+   */
+  virtual result_t do_write_description(OStream&) =0;
+};
+
+/**
+  Represents a meta-data item in a backup archive.
+
+  Instances of this class:
+
+  - identify a meta-data item inside backup archive,
+  - provide storage for a corresponding meta::Item instance,
+  - write item identification data to a backup stream.
+
+  For each type of meta-data there is a specialized subclass of
+  @c Archive_info::Item implementing the above tasks. Each subclass has static
+  @c create_from_stream() method which can create class instance using an
+  identity stored in a stream. For examples, see @c Archive_info::Table_item
+  class.
+
+  Class @c Archive_info::Item defines the format of an entry describing a
+  meta-data item inside the meta-data part of an archive. Such entry is created
+  by @c Archive_info::save() method. These entries are read by
+  @c Restore_info::read_item() method.
+ */
+
+class Archive_info::Item
+{
+ protected:
+
+  /// Pointer to @c Archive_info instance to which this item belongs.
+  const Archive_info *const m_info;
+  Item  *next; ///< Used to create a linked list of all meta-data items.
+
+ public:
+
+  virtual ~Item() {}
+
+  /// Returns reference to the corresponding @c meta::Item instance.
+  virtual meta::Item& meta() =0;
+
+  result_t save(THD*,OStream&); ///< Write entry describing the item.
+
+  // Create item from a saved entry.
+  static result_t create_from_stream(const Archive_info&, IStream&, Item*&);
+
+  class Iterator;
+
+ protected:
+
+  Item(const Archive_info &i): m_info(&i), next(NULL)
+  {}
+
+  /// Save data identifying the item inside the archive.
+  virtual result_t save_id(OStream&) =0;
+
+  friend class Archive_info;
+  friend class Backup_info;
+  friend class Restore_info;
+  friend class Iterator;
+};
+
+
+/**
+  Used to iterate over meta-data items.
+
+  Usage:
+  @code
+   Item *head;
+   for (Item::Iterator it(head); it ; it++)
+   {
+     it->archive_item_method()
+   }
+  @endcode
+  or
+  @code
+   Item *head, *p;
+   Item::Iterator it(head);
+
+   while ((p=it++))
+   {
+     @<use p here>
+   }
+  @endcode
+ */
+class Archive_info::Item::Iterator
+{
+  Item *m_curr;
+  Item *m_prev;
+
+ public:
+
+  Iterator(Item *const head): m_curr(head), m_prev(NULL)
+  {}
+
+  operator bool() const
+  { return m_curr != NULL; }
+
+  Item* operator++(int)
+  {
+    m_prev= m_curr;
+
+    if (m_curr)
+     m_curr= m_curr->next;
+
+    return m_prev;
+  }
+
+  Item* operator->()
+  { DBUG_ASSERT(m_curr);
+    return m_curr; }
+};
+
+
+
+/**
+  Specialization of @c Archive_info::Item representing a database.
+
+  A database is identified by a key into Archive_info::db_names string pool.
+  Using the key one can read database name from the pool. The key is saved
+  as a var-length coded integer.
+ */
+class Archive_info::Db_item:
+  public Archive_info::Item, public meta::Db, public Db_ref
+{
+  StringPool::Key   key;
+
+  Db_item(const Archive_info &i, const StringPool::Key &key):
+    Archive_info::Item(i), Db_ref(m_info->db_names[key]), key(key)
+  {}
+
+  meta::Item& meta()
+  { return *this; }
+
+  /// Get the name from @c db_names pool.
+  const char* sql_name() const
+  { return m_info->db_names[key].ptr(); }
+
+ public:
+
+  result_t save_id(OStream&);
+  /// Create instance reading its identity from a stream.
+  static
+  result_t create_from_stream(const Archive_info&,IStream&, Archive_info::Item*&);
+
+  friend class Archive_info;
+  friend class Backup_info;
+};
+
+
+/**
+  Specialization of @c Archive_info::Item representing a table.
+
+  A table is identified by its position inside the table list of
+  one of archive's images. Its identity is saved as two var-length coded
+  integers: first being the image number and second the table position inside
+  image's table list.
+ */
+class Archive_info::Table_item:
+  public Archive_info::Item, public meta::Table, public Table_ref
+{
+  uint  img;  ///< Image in which this table is saved.
+  uint  pos;  ///< Position of the table in image's table list.
+
+  Table_item(const Archive_info &i, uint no, uint tno):
+    Archive_info::Item(i), Table_ref(i.images[no]->tables[tno]),
+    img(no), pos(tno)
+  {}
+
+ public:
+
+  meta::Item& meta()
+  { return *this; }
+
+  const char* sql_name() const
+  { return m_info->images[img]->tables[pos].name().ptr(); }
+
+  /// Table is a per-db item -- indicate to which database it belongs.
+  const Db_ref in_db()
+  { return m_info->images[img]->tables[pos].db(); }
+
+  result_t save_id(OStream&);
+  /// Create instance reading its identity from a stream.
+  static
+  result_t create_from_stream(const Archive_info&,IStream&, Archive_info::Item*&);
+
+  friend class Backup_info;
+};
+
+} // backup namespace
+
+
+/************************************************************
+
+   Class describing native backup image
+
+ ************************************************************/
+
+namespace backup {
+
+/**
+  Specialization of @c Image_info for images created by native backup drivers.
+ */
+class Native_image: public Image_info
+{
+  const ::handlerton  *m_hton; ///< Pointer to storage engine.
+  Engine   *m_be;  ///< Pointer to the native backup engine.
+
+  const char *m_name;  ///< Used to identify image in debug messages.
+
+ public:
+
+  Native_image(Archive_info &info, const ::handlerton *hton):
+    Image_info(info), m_hton(hton)
+  {
+    DBUG_ASSERT(hton);
+    DBUG_ASSERT(hton->get_backup_engine);
+
+    hton->get_backup_engine(const_cast< ::handlerton* >(hton),m_be);
+
+    if(m_be)
+    {
+      ver= m_be->version();
+      m_name= ::ha_resolve_storage_engine_name(hton);
+    }
+  }
+
+  bool is_valid()
+  { return m_be != NULL; }
+
+  image_type type() const
+  { return NATIVE_IMAGE; }
+
+  const char* name() const
+  { return m_name; }
+
+  result_t get_backup_driver(Backup_driver* &drv)
+  {
+    DBUG_ASSERT(m_be);
+    return m_be->get_backup(Driver::PARTIAL,tables,drv);
+  }
+
+  result_t get_restore_driver(Restore_driver* &drv)
+  {
+    DBUG_ASSERT(m_be);
+    return m_be->get_restore(ver,Driver::PARTIAL,tables,drv);
+  }
+
+  result_t do_write_description(OStream&);
+  static result_t create_from_stream(version_t,Archive_info&,IStream&,Image_info*&);
+
+  bool accept(const Table_ref&, const ::handlerton *hton)
+  { return hton == m_hton; }; // this assumes handlertons are single instance objects!
+};
+
+} // backup namespace
+
+
+#endif
diff -Nrup a/sql/backup/kernel.cc b/sql/backup/kernel.cc
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sql/backup/kernel.cc	2007-11-21 11:18:50 +01:00
@@ -0,0 +1,1384 @@
+/**
+  @file
+
+  Implementation of the backup kernel API.
+ */
+
+/*
+  TODO:
+
+  - Handle SHOW BACKUP ARCHIVE command.
+  - Add database list to the backup/restore summary.
+  - Implement meta-data freeze during backup/restore.
+  - Improve logic selecting backup driver for a table.
+  - Handle other types of meta-data in Backup_info methods.
+  - Handle item dependencies when adding new items.
+  - Lock I_S tables when reading table list and similar (is it needed?)
+  - When reading table list from I_S tables, use select conditions to
+    limit amount of data read. (check prepare_select_* functions in sql_help.cc)
+  - Handle other kinds of backup locations (far future).
+  - Complete feedback given by BACKUP/RESTORE statements (send_summary function).
+ */
+
+#include "../mysql_priv.h"
+
+#include "backup_aux.h"
+#include "stream.h"
+#include "backup_kernel.h"
+#include "meta_data.h"
+#include "catalog.h"
+#include "debug.h"
+#include "be_default.h"
+#include "be_snapshot.h"
+
+namespace backup {
+
+// Helper functions
+
+static IStream* open_for_read(const Location&);
+static OStream* open_for_write(const Location&);
+
+/*
+  Report errors. The main error code and optional arguments for its description
+  are given plus a logger object which can contain stored errors.
+ */
+static int report_errors(THD*, Logger&, int, ...);
+
+/*
+  Check if info object is valid. If not, report error to client.
+ */
+static int check_info(THD*,Backup_info&);
+static int check_info(THD*,Restore_info&);
+
+static bool send_summary(THD*,const Backup_info&);
+static bool send_summary(THD*,const Restore_info&);
+
+#ifdef DBUG_BACKUP
+// Flag used for testing error reporting
+bool test_error_flag= FALSE;
+#endif
+}
+
+/**
+  Call backup kernel API to execute backup related SQL statement.
+
+  @param lex  results of parsing the statement.
+
+  @note This function sends response to the client (ok, result set or error).
+ */
+
+int
+execute_backup_command(THD *thd, LEX *lex)
+{
+  time_t skr;
+
+  DBUG_ENTER("execute_backup_command");
+  DBUG_ASSERT(thd && lex);
+
+  BACKUP_BREAKPOINT("backup_command");
+
+  /*
+    Check access for SUPER rights. If user does not have SUPER, fail with error.
+  */
+  if (check_global_access(thd, SUPER_ACL))
+    DBUG_RETURN(ER_SPECIFIC_ACCESS_DENIED_ERROR);
+
+  backup::Location *loc= backup::Location::find(lex->backup_dir);
+
+  if (!loc)
+  {
+    my_error(ER_BACKUP_INVALID_LOC,MYF(0),lex->backup_dir.str);
+    DBUG_RETURN(ER_BACKUP_INVALID_LOC);
+  }
+
+  int res= 0;
+
+  switch (lex->sql_command) {
+
+  case SQLCOM_SHOW_ARCHIVE:
+  case SQLCOM_RESTORE:
+  {
+    backup::IStream *stream= backup::open_for_read(*loc);
+
+    if (!stream)
+    {
+      my_error(ER_BACKUP_READ_LOC,MYF(0),loc->describe());
+      goto restore_error;
+    }
+    else
+    {
+      backup::Restore_info info(*stream);
+
+      if (check_info(thd,info))
+        goto restore_error;
+
+      if (lex->sql_command == SQLCOM_SHOW_ARCHIVE)
+      {
+        my_error(ER_NOT_ALLOWED_COMMAND,MYF(0));
+        goto restore_error;
+        /*
+          Uncomment when mysql_show_archive() is implemented
+
+          res= mysql_show_archive(thd,info);
+         */
+      }
+      else
+      {
+        info.report_error(backup::log_level::INFO,ER_BACKUP_RESTORE_START);
+
+        // TODO: freeze all DDL operations here
+
+        info.save_errors();
+        info.restore_all_dbs();
+
+        if (check_info(thd,info))
+          goto restore_error;
+
+        info.clear_saved_errors();
+
+        if (mysql_restore(thd,info,*stream))
+        {
+          report_errors(thd,info,ER_BACKUP_RESTORE);
+          goto restore_error;
+        }
+        else
+        {
+          info.report_error(backup::log_level::INFO,ER_BACKUP_RESTORE_DONE);
+          info.total_size += info.header_size;
+          send_summary(thd,info);
+        }
+
+        // TODO: unfreeze DDL here
+      }
+    } // if (!stream)
+
+    goto finish_restore;
+    
+   restore_error:
+
+    res= res ? res : backup::ERROR;
+    
+   finish_restore:
+
+    if (stream)
+      stream->close();
+
+    break;
+  }
+
+  case SQLCOM_BACKUP:
+  {
+    backup::OStream *stream= backup::open_for_write(*loc);
+
+    if (!stream)
+    {
+      my_error(ER_BACKUP_WRITE_LOC,MYF(0),loc->describe());
+      goto backup_error;
+    }
+    else
+    {
+      backup::Backup_info info(thd);
+
+      if (check_info(thd,info))
+        goto backup_error;
+
+      info.report_error(backup::log_level::INFO,ER_BACKUP_BACKUP_START);
+
+      // TODO: freeze all DDL operations here
+
+      /*
+        Save starting datetime of backup.
+      */
+      skr= my_time(0);
+      gmtime_r(&skr, &info.start_time);
+
+      info.save_errors();
+
+      if (lex->db_list.is_empty())
+      {
+        info.write_message(backup::log_level::INFO,"Backing up all databases");
+        info.add_all_dbs(); // backup all databases
+      }
+      else
+      {
+        info.write_message(backup::log_level::INFO,"Backing up selected databases");
+        info.add_dbs(lex->db_list); // backup databases specified by user
+      }
+
+      if (check_info(thd,info))
+        goto backup_error;
+
+      info.close();
+
+      if (check_info(thd,info))
+        goto backup_error;
+
+      info.clear_saved_errors();
+
+      if (mysql_backup(thd,info,*stream))
+      {
+        report_errors(thd,info,ER_BACKUP_BACKUP);
+        goto backup_error;
+      }
+      else
+      {
+        info.report_error(backup::log_level::INFO,ER_BACKUP_BACKUP_DONE);
+        send_summary(thd,info);
+      }
+
+      /*
+        Save ending datetime of backup.
+      */
+      skr= my_time(0);
+      gmtime_r(&skr, &info.end_time);
+
+      // TODO: unfreeze DDL here
+    } // if (!stream)
+
+    goto finish_backup;
+   
+   backup_error:
+   
+    res= res ? res : backup::ERROR;
+   
+   finish_backup:
+
+    if (stream)
+      stream->close();
+
+#ifdef  DBUG_BACKUP
+    backup::IStream *is= backup::open_for_read(*loc);
+    if (is)
+    {
+      dump_stream(*is);
+      is->close();
+    }
+#endif
+
+    break;
+  }
+
+   default:
+     /*
+       execute_backup_command() should be called with correct command id
+       from the parser. If not, we fail on this assertion.
+      */
+     DBUG_ASSERT(FALSE);
+  }
+
+  loc->free();
+  DBUG_RETURN(res);
+}
+
+
+/*************************************************
+
+                   BACKUP
+
+ *************************************************/
+
+// Declarations for functions used in backup operation
+
+namespace backup {
+
+// defined in meta_backup.cc
+int write_meta_data(THD*, Backup_info&, OStream&);
+
+// defined in data_backup.cc
+int write_table_data(THD*, Backup_info&, OStream&);
+
+} // backup namespace
+
+
+/**
+  Create backup archive.
+*/
+
+int mysql_backup(THD *thd,
+                 backup::Backup_info &info,
+                 backup::OStream &s)
+{
+  DBUG_ENTER("mysql_backup");
+
+  // This function should not be called with invalid backup info.
+  DBUG_ASSERT(info.is_valid());
+
+  size_t start_bytes= s.bytes;
+
+  BACKUP_BREAKPOINT("backup_meta");
+
+  DBUG_PRINT("backup",("Writing image header"));
+
+  if (info.save(s))
+    goto error;
+
+  DBUG_PRINT("backup",("Writing meta-data"));
+
+  if (backup::write_meta_data(thd,info,s))
+    goto error;
+
+  DBUG_PRINT("backup",("Writing table data"));
+
+  BACKUP_BREAKPOINT("backup_data");
+
+  if (backup::write_table_data(thd,info,s))
+    goto error;
+
+  DBUG_PRINT("backup",("Backup done."));
+  BACKUP_BREAKPOINT("backup_done");
+
+  info.total_size= s.bytes - start_bytes;
+
+  DBUG_RETURN(0);
+
+ error:
+
+  DBUG_RETURN(backup::ERROR);
+}
+
+namespace backup {
+
+
+class Backup_info::Table_ref:
+ public backup::Table_ref
+{
+  String  m_db_name;
+  String  m_name;
+  ::TABLE *m_table;
+
+ public:
+
+  Table_ref(const Db_item&, const String&);
+  ~Table_ref()
+  { close(); }
+  
+  ::TABLE* open(THD*);
+  void close();
+  
+  /**
+   Return pointer to @c handlerton structure of table's storage engine.
+   
+   @return @c NULL if table has not been opened or pointer to the @c handlerton
+   structure of table's storage engine.
+   */ 
+  ::handlerton* hton() const
+  { return m_table && m_table->s ? m_table->s->db_type() : NULL; }
+  
+  /// Check if table has been opened.
+  bool is_open() const 
+  { return m_table != NULL; }
+};
+
+/**
+  Find image to which given table can be added and add it.
+
+  Creates new images as needed.
+
+  @returns Position of the image found in @c images[] table or -1 on error.
+ */
+
+/*
+   Logic for selecting image format for a given table location:
+
+   1. If tables from that location have been already stored in one of the
+      sub-images then choose that sub-image.
+
+   2. If location has "native" backup format, put it in a new sub-image with
+      that format.
+
+   3. Otherwise check if one of the existing sub-images would accept table from
+      this location.
+
+   4. If table has no native backup engine, try a consistent snapshot one.
+
+   5. When everything else fails, use default (blocking) backup driver.
+
+   Note: 1 is not implemented yet and hence we start with 3.
+ */
+
+int Backup_info::find_image(const Backup_info::Table_ref &tbl)
+{
+   DBUG_ENTER("Backup_info::find_image");
+   // we assume that table has been opened already
+   DBUG_ASSERT(tbl.is_open());
+   
+   Image_info *img;
+   const ::handlerton *hton= tbl.hton();
+   // If table has no handlerton something is really bad - we crash here
+   DBUG_ASSERT(hton);
+
+   Table_ref::describe_buf buf;
+   
+   DBUG_PRINT("backup",("Adding table %s using storage %s to archive%s",
+                        tbl.describe(buf),
+                        ::ha_resolve_storage_engine_name(hton),
+                        hton->get_backup_engine ? " (has native backup)." : "."));
+
+   // Point 3: try existing images but not the default or snapshot one.
+
+   for (uint no=0; no < img_count && no < MAX_IMAGES ; ++no)
+   {
+     if (default_image_no >= 0 && no == (uint)default_image_no)
+       continue;
+
+     if (snapshot_image_no >= 0 && no == (uint)snapshot_image_no)
+       continue;
+
+     img= images[no];
+
+     // An image object decides if it can handle given table or not
+     if( img && img->accept(tbl,hton) )
+       DBUG_RETURN(no);
+   }
+
+   // Point 2: try native backup of table's storage engine.
+
+   if (hton->get_backup_engine)
+   {
+     uint no= img_count;
+
+     // We handle at most MAX_IMAGES many images
+     DBUG_ASSERT(no<MAX_IMAGES);
+
+     img= images[no]= new Native_image(*this,hton);
+
+     if (!img)
+     {
+       report_error(ER_OUT_OF_RESOURCES);
+       DBUG_RETURN(-1);
+     }
+
+     DBUG_PRINT("backup",("%s image added to archive",img->name()));
+     img_count++;
+
+#ifdef DBUG_OFF 
+     // avoid "unused variable" compilation warning
+     img->accept(tbl,hton);
+#else
+     // native image should accept all tables from its own engine
+     bool res= img->accept(tbl,hton);
+     DBUG_ASSERT(res);
+#endif
+
+     DBUG_RETURN(no);
+   }
+
+   // Points 4 & 5: try consistent snapshot and default drivers..
+
+   // try snapshot driver first
+   int ino= snapshot_image_no;
+   if (hton->start_consistent_snapshot != NULL)
+   {
+     if (snapshot_image_no < 0) //image doesn't exist
+     {
+       ino= img_count;
+       snapshot_image_no= img_count;
+       images[snapshot_image_no]= new Snapshot_image(*this);
+       img_count++;
+       DBUG_PRINT("backup",("Snapshot image added to archive"));
+     }
+   }
+   else
+     ino= default_image_no; //now try default driver
+
+   if (ino < 0) //image doesn't exist
+   {
+     ino= img_count;
+     default_image_no= img_count;
+     images[default_image_no]= new Default_image(*this);
+     img_count++;
+     DBUG_PRINT("backup",("Default image added to archive"));
+   }
+
+   img= images[ino];
+   DBUG_ASSERT(img);
+   if (img->accept(tbl,hton))
+     DBUG_RETURN(ino); // table accepted
+
+   report_error(ER_BACKUP_NO_BACKUP_DRIVER,tbl.describe(buf,sizeof(buf)));
+   DBUG_RETURN(-1);
+}
+
+} // backup namespace
+
+
+/****************************
+
+  Backup_info implementation
+
+ ****************************/
+
+namespace backup {
+
+//  Returns tmp table containing records from a given I_S table
+TABLE* get_schema_table(THD *thd, ST_SCHEMA_TABLE *st);
+
+/* 
+  Backup_info::skip_table pointer is just for indicating that a table
+  added with Backup_info::add_table() was skipped. It should have value not 
+  possible for regular pointers.
+ */
+const Backup_info::Table_item *const 
+Backup_info::skip_table= reinterpret_cast<Backup_info::Table_item*>(1);
+
+/**
+  Create @c Backup_info structure and prepare it for populating with meta-data
+  items.
+
+  When adding a complete database to the archive, all its tables are added.
+  These are found by reading INFORMATION_SCHEMA.TABLES table. The table is
+  opened here so that it is ready for use in @c add_db_items() method. It is
+  closed when the structure is closed with the @c close() method.
+ */
+Backup_info::Backup_info(THD *thd):
+  Logger(Logger::BACKUP),
+  m_state(INIT), default_image_no(-1), snapshot_image_no(-2), 
+  m_thd(thd), i_s_tables(NULL),
+  m_items(NULL), m_last_item(NULL), m_last_db(NULL)
+{
+  i_s_tables= get_schema_table(m_thd, ::get_schema_table(SCH_TABLES));
+  if (!i_s_tables)
+  {
+    report_error(ER_BACKUP_LIST_TABLES);
+    m_state= ERROR;
+  }
+}
+
+Backup_info::~Backup_info()
+{
+  close();
+  m_state= DONE;
+
+  Item_iterator it(*this);
+  Item *i;
+
+  while ((i=it++))
+    delete i;
+
+  m_items= NULL;
+}
+
+/**
+  Close the structure after populating it with items.
+
+  When meta-data is written, we need to open archive's tables to be able
+  to read their definitions. Tables are opened here so that the
+  structure is ready for creation of the archive.
+
+  FIXME: opening all tables at once consumes too much resources when there
+  is a lot of tables (opened file descriptors!). Find a better solution.
+ */
+bool Backup_info::close()
+{
+  bool ok= is_valid();
+
+  if(i_s_tables)
+    ::free_tmp_table(m_thd,i_s_tables);
+  i_s_tables= NULL;
+
+  if (m_state == INIT)
+    m_state= READY;
+
+  return ok;
+}
+
+int Backup_info::save(OStream &s)
+{
+  if (OK != Archive_info::save(s))
+  {
+    report_error(ER_BACKUP_WRITE_HEADER);
+    return ERROR;
+  }
+
+  return 0;
+}
+
+/**
+  Specialization of @c backup::Db_ref with convenient constructors.
+ */
+
+class Backup_info::Db_ref: public backup::Db_ref
+{
+  String m_name;
+
+ public:
+
+  Db_ref(const String &s): backup::Db_ref(m_name), m_name(s)
+  {}
+
+  Db_ref(const LEX_STRING &s):
+    backup::Db_ref(m_name),
+    m_name(s.str,s.length,::system_charset_info)
+  {}
+};
+
+/**
+  Add to archive all databases in the list.
+ */
+int Backup_info::add_dbs(List< ::LEX_STRING > &dbs)
+{
+  List_iterator< ::LEX_STRING > it(dbs);
+  ::LEX_STRING *s;
+  String unknown_dbs; // comma separated list of databases which don't exist
+
+  while ((s= it++))
+  {
+    Db_ref db(*s);
+
+    if (db_exists(db))
+    {
+      if (!unknown_dbs.is_empty()) // we just compose unknown_dbs list
+        continue;
+
+      Db_item *it= add_db(db);
+
+      if (!it)
+        goto error;
+
+      if (add_db_items(*it))
+        goto error;
+    }
+    else
+    {
+      if (!unknown_dbs.is_empty())
+        unknown_dbs.append(",");
+      unknown_dbs.append(db.name());
+    }
+  }
+
+  if (!unknown_dbs.is_empty())
+  {
+    report_error(ER_BAD_DB_ERROR,unknown_dbs.c_ptr());
+    goto error;
+  }
+  
+  return 0;
+  
+ error:
+
+  m_state= ERROR;
+  return backup::ERROR;
+}
+
+/**
+  Add to archive all instance's databases (except the internal ones).
+ */
+
+int Backup_info::add_all_dbs()
+{
+  my_bitmap_map *old_map;
+
+  DBUG_PRINT("backup", ("Reading databases from I_S"));
+
+  ::TABLE *db_table = get_schema_table(m_thd, ::get_schema_table(SCH_SCHEMATA));
+
+  if (!db_table)
+  {
+    report_error(ER_BACKUP_LIST_DBS);
+    return ERROR;
+  }
+
+  ::handler *ha = db_table->file;
+
+  // TODO: locking
+
+  int res= 0;
+
+  old_map= dbug_tmp_use_all_columns(db_table, db_table->read_set);
+
+  if (ha->ha_rnd_init(TRUE))
+  {
+    res= -2;
+    report_error(ER_BACKUP_LIST_DBS);
+    goto finish;
+  }
+
+  while (!ha->rnd_next(db_table->record[0]))
+  {
+    String db_name;
+    
+    db_table->field[1]->val_str(&db_name);
+    
+    // skip internal databases
+    if (db_name == String("information_schema",&::my_charset_bin) 
+        || db_name == String("mysql",&my_charset_bin))
+    {
+      DBUG_PRINT("backup",(" Skipping internal database %s",db_name.ptr()));
+      continue;
+    }
+
+    Db_ref db(db_name);
+
+    DBUG_PRINT("backup", (" Found database %s", db.name().ptr()));
+
+    Db_item *it= add_db(db);
+
+    if (!it)
+    {
+      res= -3;
+      goto finish;
+    }
+
+    if (add_db_items(*it))
+    {
+      res= -4;
+      goto finish;
+    }
+  }
+
+  DBUG_PRINT("backup", ("No more databases in I_S"));
+
+  ha->ha_rnd_end();
+
+ finish:
+
+  if (db_table)
+  {
+    dbug_tmp_restore_column_map(db_table->read_set, old_map);
+    ::free_tmp_table(m_thd, db_table);
+  }
+
+  if (res)
+    m_state= ERROR;
+
+  return res;
+}
+
+/**
+  Insert a @c Db_item into the meta-data items list.
+ */
+Backup_info::Db_item*
+Backup_info::add_db(const backup::Db_ref &db)
+{
+  StringPool::Key key= db_names.add(db.name());
+
+  if (!key.is_valid())
+  {
+    report_error(ER_OUT_OF_RESOURCES);
+    return NULL;
+  }
+
+  Db_item *di= new Db_item(*this,key);
+
+  if (!di)
+  {
+    report_error(ER_OUT_OF_RESOURCES);
+    return NULL;
+  }
+
+  // insert db item before all table items
+
+  if (!m_last_db)
+  {
+    di->next= m_items;
+    m_items= m_last_db= di;
+    if (!m_last_item)
+     m_last_item= m_items;
+  }
+  else
+  {
+    // since m_last_db is not NULL, m_items list can't be empty
+    DBUG_ASSERT(m_items);
+
+    di->next= m_last_db->next;
+    if (m_last_item == m_last_db)
+     m_last_item= di;
+    m_last_db->next= di;
+  }
+
+  return di;
+}
+
+/**
+  Add to archive all items belonging to a given database.
+ */
+int Backup_info::add_db_items(Db_item &db)
+{
+  my_bitmap_map *old_map;
+
+  DBUG_ASSERT(m_state == INIT);  // should be called before structure is closed
+  DBUG_ASSERT(is_valid());       // should be valid
+  DBUG_ASSERT(i_s_tables->file); // i_s_tables should be opened
+
+  // add all tables from db.
+
+  ::handler *ha= i_s_tables->file;
+
+  /*
+    If error debugging is switched on (see debug.h) then I_S.TABLES access
+    error will be triggered when backing up database whose name starts with 'a'.
+   */
+  TEST_ERROR_IF(db.name().ptr()[0]=='a');
+
+  old_map= dbug_tmp_use_all_columns(i_s_tables, i_s_tables->read_set);
+  
+  if (ha->ha_rnd_init(TRUE) || TEST_ERROR)
+  {
+    dbug_tmp_restore_column_map(i_s_tables->read_set, old_map);
+    report_error(ER_BACKUP_LIST_DB_TABLES,db.name().ptr());
+    return ERROR;
+  }
+
+  int res= 0;
+
+  while (!ha->rnd_next(i_s_tables->record[0]))
+  {
+    String db_name;
+    String name;
+    String type;
+    String engine;
+
+    /* 
+      Read info about next table/view
+      
+      Note: this should be synchronized with the definition of 
+      INFORMATION_SCHEMA.TABLES table.
+     */
+    i_s_tables->field[1]->val_str(&db_name);
+    i_s_tables->field[2]->val_str(&name);
+    i_s_tables->field[3]->val_str(&type);
+    i_s_tables->field[4]->val_str(&engine);
+    
+    if (db_name != db.name())
+      continue; // skip tables not from the given database
+    
+    // FIXME: right now, we handle only tables
+    if (type != String("BASE TABLE",&::my_charset_bin))
+    {
+      report_error(log_level::WARNING,ER_BACKUP_SKIP_VIEW,
+                   name.c_ptr(),db_name.c_ptr());
+      continue;
+    }
+
+    Backup_info::Table_ref t(db,name);
+    
+    if (engine.is_empty())
+    {
+      Table_ref::describe_buf buf;
+      report_error(log_level::WARNING,ER_BACKUP_NO_ENGINE,t.describe(buf));
+      continue;                   
+    }
+
+    DBUG_PRINT("backup", ("Found table %s for database %s",
+                           t.name().ptr(), t.db().name().ptr()));
+
+    // We need to open table for add_table() method below
+    if (!t.open(m_thd))
+    {
+      Table_ref::describe_buf buf;
+      report_error(ER_BACKUP_TABLE_OPEN,t.describe(buf));
+      goto error;
+    }
+    // add_table method selects/creates sub-image appropriate for storing given table
+    Table_item *ti= add_table(t);
+    
+    // Close table to free resources
+    t.close();
+    
+    if (!ti)
+      goto error;
+
+    if (ti == skip_table)
+      continue;
+
+    if (add_table_items(*ti))
+      goto error;
+  }
+
+  goto finish;
+  
+ error:
+ 
+  res= res ? res : ERROR;
+ 
+ finish:
+ 
+  ha->ha_rnd_end();
+
+  dbug_tmp_restore_column_map(i_s_tables->read_set, old_map);
+
+  return res;
+}
+
+/* Implementation of Backup_info::Table_ref */
+
+Backup_info::Table_ref::Table_ref(const Db_item &db, const String &name):
+  backup::Table_ref(m_db_name,m_name), m_table(NULL)
+{
+  m_db_name.append(db.name());
+  m_name.append(name);
+}
+
+/**
+ Open table and create corresponding @c TABLE structure.
+ 
+ A pointer to opened @c TABLE structure is stored in @c m_table member. The 
+ structure is owned by @c Table_ref object, to destroy it call @c close() 
+ method. 
+ 
+ This method does nothing if table has been already opened.
+ 
+ @return Pointer to the opened @c TABLE structure or @c NULL if operation was
+ not successful. 
+ */ 
+::TABLE* Backup_info::Table_ref::open(THD *thd)
+{
+  if (is_open())
+    return m_table;
+    
+  char path[FN_REFLEN];
+  const char *db= m_db_name.ptr();
+  const char *name= m_name.ptr();
+  ::build_table_filename(path, sizeof(path), db, name, "", 0);
+  m_table= ::open_temporary_table(
+                thd, path, db, name, 
+                FALSE /* don't link to thd->temporary_tables */,
+                OTM_OPEN);
+  
+  /*
+   Note: If table couldn't be opened (m_table==NULL), open_temporary_table() 
+   doesn't inform us what was the reason. This makes it difficult to give 
+   precise information in the error log. Currently we just say that table 
+   couldn't be opened. When error reporting is improved, we should try to do 
+   better than that.
+   */ 
+  return m_table;
+}
+
+/**
+ Close previously opened table.
+ 
+ Closes table and frees allocated resources. Can be called even when table
+ has not been opened, in which case it does nothing.
+ */ 
+void Backup_info::Table_ref::close()
+{
+  if (m_table)
+  {
+    // TODO: check if ::free_tmp_table() is not better
+    ::intern_close_table(m_table);
+    my_free(m_table, MYF(0));
+  }
+  m_table= NULL;
+  return;
+}
+
+/**
+  Add table to archive's list of meta-data items.
+  
+  @pre Table should be opened.
+ */
+
+Backup_info::Table_item*
+Backup_info::add_table(const Table_ref &t)
+{
+  DBUG_ASSERT(t.is_open());
+    
+  // TODO: skip table if it is a tmp one
+    
+  int no= find_image(t); // Note: find_image reports errors
+
+  /*
+    If error debugging is switched on (see debug.h) then any table whose
+    name starts with 'a' will trigger "no backup driver" error.
+   */
+  TEST_ERROR_IF(t.name().ptr()[0]=='a');
+
+  if (no < 0 || TEST_ERROR)
+    return NULL;
+
+  /*
+    If image was found then images[no] should point at the Image_info
+    object
+   */
+  Image_info *img= images[no];
+  DBUG_ASSERT(img);
+
+  /*
+    If error debugging is switched on (see debug.h) then any table whose
+    name starts with 'b' will trigger error when added to backup image.
+   */
+  TEST_ERROR_IF(t.name().ptr()[0]=='b');
+
+  int tno= img->tables.add(t);
+  if (tno < 0 || TEST_ERROR)
+  {
+    Table_ref::describe_buf buf;
+    report_error(ER_BACKUP_NOT_ACCEPTED,img->name(),t.describe(buf));
+    return NULL;
+  }
+
+  table_count++;
+
+  Table_item *ti= new Table_item(*this,no,tno);
+
+  if (!ti)
+  {
+    report_error(ER_OUT_OF_RESOURCES);
+    return NULL;
+  }
+
+  // add to the end of items list
+
+  ti->next= NULL;
+  if (m_last_item)
+   m_last_item->next= ti;
+  m_last_item= ti;
+  if (!m_items)
+   m_items= ti;
+
+  return ti;
+}
+
+/**
+  Add to archive all items belonging to a given table.
+ */
+int Backup_info::add_table_items(Table_item&)
+{
+  // TODO: Implement when we handle per-table meta-data.
+  return 0;
+}
+
+} // backup namespace
+
+
+/*************************************************
+
+                   RESTORE
+
+ *************************************************/
+
+// Declarations of functions used in restore operation
+
+namespace backup {
+
+// defined in meta_backup.cc
+int restore_meta_data(THD*, Restore_info&, IStream&);
+
+// defined in data_backup.cc
+int restore_table_data(THD*, Restore_info&, IStream&);
+
+} // backup namespace
+
+
+/**
+  Restore items saved in backup archive.
+
+  @pre archive info has been already read and the stream is positioned
+        at archive's meta-data
+*/
+int mysql_restore(THD *thd, backup::Restore_info &info, backup::IStream &s)
+{
+  DBUG_ENTER("mysql_restore");
+
+  size_t start_bytes= s.bytes;
+
+  DBUG_PRINT("restore",("Restoring meta-data"));
+
+  if (backup::restore_meta_data(thd, info, s))
+    DBUG_RETURN(backup::ERROR);
+
+  DBUG_PRINT("restore",("Restoring table data"));
+
+  if (backup::restore_table_data(thd,info,s))
+    DBUG_RETURN(backup::ERROR);
+
+  DBUG_PRINT("restore",("Done."));
+
+  info.total_size= s.bytes - start_bytes;
+
+  DBUG_RETURN(0);
+}
+
+/*************************************************
+
+               BACKUP LOCATIONS
+
+ *************************************************/
+
+namespace backup {
+
+struct File_loc: public Location
+{
+  String path;
+
+  enum_type type() const
+  { return SERVER_FILE; }
+
+  File_loc(const char *p)
+  { path.append(p); }
+
+  const char* describe()
+  { return path.c_ptr(); }
+
+};
+
+
+template<class S>
+S* open_stream(const Location &loc)
+{
+  switch (loc.type()) {
+
+  case Location::SERVER_FILE:
+  {
+    const File_loc &f= static_cast<const File_loc&>(loc);
+    S *s= new S(f.path);
+
+    if (s && s->open())
+      return s;
+
+    delete s;
+    return NULL;
+  }
+
+  default:
+    return NULL;
+
+  }
+}
+
+template IStream* open_stream<IStream>(const Location&);
+template OStream* open_stream<OStream>(const Location&);
+
+IStream* open_for_read(const Location &loc)
+{
+  return open_stream<IStream>(loc);
+}
+
+
+OStream* open_for_write(const Location &loc)
+{
+  return open_stream<OStream>(loc);
+}
+
+/**
+  Find location described by a string.
+
+  The string is taken from the "TO ..." clause of BACKUP/RESTORE commands.
+  This function parses the string and creates instance of @c Location class
+  describing the location or NULL if string doesn't describe any valid location.
+
+  Currently the only supported type of location is a file on the server host.
+  The string is supposed to contain a path to such file.
+
+  @note No checks on the location are made at this stage. In particular the
+  location might not physically exist. In the future methods performing such
+  checks can be added to @Location class.
+ */
+Location*
+Location::find(const LEX_STRING &where)
+{
+  return where.str && where.length ? new File_loc(where.str) : NULL;
+}
+
+} // backup namespace
+
+
+/*************************************************
+
+                 Helper functions
+
+ *************************************************/
+
+TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list); // defined in sql_show.cc
+
+namespace backup {
+
+/**
+  Report errors.
+
+  Current implementation reports the last error saved in the logger if it exist.
+  Otherwise it reports error given by @c error_code.
+ */
+int report_errors(THD *thd, Logger &log, int error_code, ...)
+{
+  MYSQL_ERROR *error= log.last_saved_error();
+
+  if (error && !util::report_mysql_error(thd,error,error_code))
+  {  
+    if (error->code)
+      error_code= error->code;
+  }
+  else // there are no error information in the logger - report error_code
+  {
+    char buf[ERRMSGSIZE + 20];
+    va_list args;
+    va_start(args,error_code);
+
+    my_vsnprintf(buf,sizeof(buf),ER_SAFE(error_code),args);
+    my_printf_error(error_code,buf,MYF(0));
+
+    va_end(args);
+  }
+
+  return error_code;
+}
+
+inline
+int check_info(THD *thd, Backup_info &info)
+{ 
+  return info.is_valid() ? OK : report_errors(thd,info,ER_BACKUP_BACKUP_PREPARE); 
+}
+
+inline
+int check_info(THD *thd, Restore_info &info)
+{ 
+  return info.is_valid() ? OK : report_errors(thd,info,ER_BACKUP_RESTORE_PREPARE); 
+}
+
+/**
+  Send a summary of the backup/restore operation to the client.
+
+  The data about the operation is taken from filled @c Archive_info
+  structure. Parameter @c backup determines if this was backup or
+  restore operation.
+
+  TODO: Add list of databases in the output.
+*/
+
+static
+bool send_summary(THD *thd, const Archive_info &info, bool backup)
+{
+  Protocol   *protocol= ::current_thd->protocol; // client comms
+  List<Item> field_list;                         // list of fields to send
+  Item       *item;                              // field item
+  char       buf[255];                           // buffer for data
+  String     op_str;                             // operations string
+  String     print_str;                          // string to print
+
+  DBUG_ENTER("backup::send_summary");
+
+  DBUG_PRINT(backup?"backup":"restore", ("sending summary"));
+
+  op_str.length(0);
+  if (backup)
+    op_str.append("Backup Summary");
+  else
+    op_str.append("Restore Summary");
+
+
+  field_list.push_back(item= new Item_empty_string(op_str.c_ptr(),255)); // TODO: use varchar field
+  item->maybe_null= TRUE;
+  protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
+
+  my_snprintf(buf,sizeof(buf)," header     = %-8lu bytes",(unsigned long)info.header_size);
+  protocol->prepare_for_resend();
+  protocol->store(buf,system_charset_info);
+  protocol->write();
+
+  my_snprintf(buf,sizeof(buf)," meta-data  = %-8lu bytes",(unsigned long)info.meta_size);
+  protocol->prepare_for_resend();
+  protocol->store(buf,system_charset_info);
+  protocol->write();
+
+  my_snprintf(buf,sizeof(buf)," data       = %-8lu bytes",(unsigned long)info.data_size);
+  protocol->prepare_for_resend();
+  protocol->store(buf,system_charset_info);
+  protocol->write();
+
+  my_snprintf(buf,sizeof(buf),"              --------------");
+  protocol->prepare_for_resend();
+  protocol->store(buf,system_charset_info);
+  protocol->write();
+
+  my_snprintf(buf,sizeof(buf)," total        %-8lu bytes", (unsigned long)info.total_size);
+  protocol->prepare_for_resend();
+  protocol->store(buf,system_charset_info);
+  protocol->write();
+
+  send_eof(thd);
+  DBUG_RETURN(0);
+}
+
+inline
+bool send_summary(THD *thd, const Backup_info &info)
+{ return send_summary(thd,info,TRUE); }
+
+inline
+bool send_summary(THD *thd, const Restore_info &info)
+{ return send_summary(thd,info,FALSE); }
+
+
+/// Open given table in @c INFORMATION_SCHEMA database.
+TABLE* get_schema_table(THD *thd, ST_SCHEMA_TABLE *st)
+{
+  TABLE *t;
+  TABLE_LIST arg;
+  my_bitmap_map *old_map;
+
+  bzero( &arg, sizeof(TABLE_LIST) );
+
+  // set context for create_schema_table call
+  arg.schema_table= st;
+  arg.alias=        NULL;
+  arg.select_lex=   NULL;
+
+  t= ::create_schema_table(thd,&arg); // Note: callers must free t.
+
+  if( !t ) return NULL; // error!
+
+  /*
+   Temporarily set thd->lex->wild to NULL to keep st->fill_table
+   happy.
+  */
+  String *wild= thd->lex->wild;
+  ::enum_sql_command command= thd->lex->sql_command;
+  
+  thd->lex->wild = NULL;
+  thd->lex->sql_command = enum_sql_command(0);
+
+  // context for fill_table
+  arg.table= t;
+
+  old_map= tmp_use_all_columns(t, t->read_set);
+  
+  /*
+    Question: is it correct to fill I_S table each time we use it or should it
+    be filled only once?
+   */
+  st->fill_table(thd,&arg,NULL);  // NULL = no select condition
+
+  tmp_restore_column_map(t->read_set, old_map);
+  
+  // undo changes to thd->lex
+  thd->lex->wild= wild;
+  thd->lex->sql_command= command;
+
+  return t;
+}
+
+/// Build linked @c TABLE_LIST list from a list stored in @c Table_list object.
+
+/*
+  FIXME: build list with the same order as in input
+  Actually, should work fine with reversed list as long as we use the reversed
+  list both in table writing and reading.
+ */
+TABLE_LIST *build_table_list(const Table_list &tables, thr_lock_type lock)
+{
+  TABLE_LIST *tl= NULL;
+
+  for( uint tno=0; tno < tables.count() ; tno++ )
+  {
+    TABLE_LIST *ptr= (TABLE_LIST*)my_malloc(sizeof(TABLE_LIST), MYF(MY_WME));
+    DBUG_ASSERT(ptr);  // FIXME: report error instead
+    bzero(ptr,sizeof(TABLE_LIST));
+
+    Table_ref tbl= tables[tno];
+
+    ptr->alias= ptr->table_name= const_cast<char*>(tbl.name().ptr());
+    ptr->db= const_cast<char*>(tbl.db().name().ptr());
+    ptr->lock_type= lock;
+
+    // and add it to the list
+
+    ptr->next_global= ptr->next_local=
+      ptr->next_name_resolution_table= tl;
+    tl= ptr;
+    tl->table= ptr->table;
+  }
+
+  return tl;
+}
+
+} // backup namespace
diff -Nrup a/sql/backup/meta_backup.cc b/sql/backup/meta_backup.cc
--- a/sql/backup/meta_backup.cc	2007-11-12 21:58:18 +01:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,380 +0,0 @@
-/**
-  @file
-
-  Functions used by kernel to save/restore meta-data
- */
-
-/*
-  TODO:
-
-  - Handle events, routines, triggers and other item types (use Chuck's code).
-
-  - When saving database info, save its default charset and collation.
-    Alternatively, save a complete "CREATE DATABASE ..." statement with all
-    clauses which should work even when new clauses are added in the future.
-
-  - In silent_exec_query() - reset, collect and report errors from statement
-    execution.
-
-  - In the same function: investigate what happens if query triggers error -
-    there were signals that the code might hang in that case (some clean-up
-    needed?)
- */
-
-#include <mysql_priv.h>
-#include <sql_show.h>
-
-#include "backup_aux.h"
-#include "backup_kernel.h"
-#include "meta_backup.h"
-
-
-namespace backup {
-
-/**
-  Write meta-data description to backup stream.
-
-  Meta-data information is stored as a sequence of entries, each describing a
-  single meta-data item. The format of a single entry depends on the type of
-  item (see @c Archive_info::Item::save() method). The entries are saved in a
-  single chunk.
-
-  The order of entries is important. Items on which other items depend should
-  be saved first in the sequence. This order is determined by the implementation
-  of @c Backup_info::Item_iterator class.
-
-  @note Meta-data description is added to the current chunk of the stream which
-  is then closed.
-
-  @returns 0 on success, error code otherwise.
- */
-int write_meta_data(THD *thd, Backup_info &info, OStream &s)
-{
-  DBUG_ENTER("backup::write_meta_data");
-
-  size_t start_bytes= s.bytes;
-
-  for (Backup_info::Item_iterator it(info); it; it++)
-  {
-    result_t res= it->save(thd,s); // this calls Archive_info::Item::save() method
-
-    if (res != OK)
-    {
-      meta::Item::description_buf buf;
-      info.report_error(ER_BACKUP_WRITE_META,
-                         it->meta().describe(buf,sizeof(buf)));
-      DBUG_RETURN(ERROR);
-    }
-  }
-
-  if (stream_result::ERROR == s.end_chunk())
-    DBUG_RETURN(ERROR);
-
-  info.meta_size= s.bytes - start_bytes;
-
-  DBUG_RETURN(0);
-}
-
-
-/**
-  Read meta-data items from a stream and create them if they are selected
-  for restore.
-
-  @pre  Stream is at the beginning of a saved meta-data chunk.
-  @post Stream is at the beginning of the next chunk.
- */
-int restore_meta_data(THD *thd, Restore_info &info, IStream &s)
-{
-  DBUG_ENTER("restore_meta_data");
-  Archive_info::Item *it; // save pointer to item read form the stream
-  Db_ref  curr_db;        // remember the current database
-  result_t res;
-
-  size_t start_bytes= s.bytes;
-
-  // read items from the stream until error or end of data is reached.
-  while (OK == (res= Archive_info::Item::create_from_stream(info,s,it)))
-  {
-    DBUG_PRINT("restore",(" got next meta-item."));
-
-    if (info.selected(*it)) // if the item was selected for restore ...
-    {
-     DBUG_PRINT("restore",("  creating it!"));
-
-     /*
-       change the current database if we are going to create a per-db item
-       and we are not already in the correct one.
-      */
-     const Db_ref db= it->meta().in_db();
-
-     if (db.is_valid() && (!curr_db.is_valid() || db != curr_db))
-     {
-       DBUG_PRINT("restore",("  changing current db to %s",db.name().ptr()));
-       curr_db= db;
-       change_db(thd,db);
-     }
-
-     if (OK != (res= it->meta().create(thd)))
-     {
-       meta::Item::description_buf buf;
-       info.report_error(ER_BACKUP_CREATE_META,
-                          it->meta().describe(buf,sizeof(buf)));
-       DBUG_RETURN(ERROR);
-     }
-
-     delete it;
-    }
-  }
-
-  // We should reach end of chunk now - if not something went wrong
-
-  if (res != DONE)
-  {
-    info.report_error(ER_BACKUP_READ_META);
-    DBUG_RETURN(ERROR);
-  }
-
-  DBUG_ASSERT(res == DONE);
-
-  if (stream_result::ERROR == s.next_chunk())
-  {
-    info.report_error(ER_BACKUP_NEXT_CHUNK);
-    DBUG_RETURN(ERROR);
-  }
-
-  info.meta_size= s.bytes - start_bytes;
-
-  DBUG_RETURN(0);
-}
-
-} // backup namespace
-
-
-/*********************************************
-
-  Save/restore for different meta-data items.
-
- *********************************************/
-
-namespace backup {
-
-int silent_exec_query(THD*, String&);
-
-/**
-  Write data needed to restore an item.
-
-  By default, a complete DDL CREATE statement for the item is saved.
-  This statement is constructed using @c meta::X::build_create_stmt() method
-  where meta::X is the class representing the item. The method stores statement
-  in the @c create_stmt member.
-
-  @returns OK or ERROR
- */
-
-result_t
-meta::Item::save(THD *thd, OStream &s)
-{
-  create_stmt.free();
-
-  if (build_create_stmt(thd))
-    return ERROR;
-
-  return stream_result::OK == s.writestr(create_stmt) ? OK : ERROR;
-}
-
-/**
-  Read data written by @c save().
-
-  By default, the CREATE statement is read and stored in the @c create_stmt
-  member.
-
-  @retval OK    everything went ok
-  @retval DONE  end of data chunk detected
-  @retval ERROR error has happened
- */
-result_t
-meta::Item::read(IStream &s)
-{
-  stream_result::value res= s.readstr(create_stmt);
-
-  // Saved string should not be NIL
-  return res == stream_result::NIL ? ERROR : report_stream_result(res);
-}
-
-/**
-  Create item.
-
-  Default implementation executes the statement stored in the @c create_stmt
-  member.
-
-  @returns OK or ERROR
- */
-result_t
-meta::Item::create(THD *thd)
-{
-  if (create_stmt.is_empty())
-  { return ERROR; }
-
-  if (ERROR == drop(thd))
-    return ERROR;
-
-  return silent_exec_query(thd,create_stmt) ? ERROR : OK;
-}
-
-/**
-  Destroy item if it exists.
-
-  Default implementation executes SQL statement of the form:
-  @verbatim
-     DROP @<object type> IF EXISTS @<name>
-  @endverbatim
-  strings @<object type> and @<name> are returned by @c X::sql_object_name()
-  and @c X::sql_name() methods of the class @c meta::X representing the item.
-  If necessary, method @c drop() can be overwritten in a specialized class
-  corresponding to a given type of meta-data item.
-
-  @returns OK or ERROR
- */
-result_t
-meta::Item::drop(THD *thd)
-{
-  const char *ob= sql_object_name();
-
-  /*
-    An item class should define object name for DROP statement
-    or redefine drop() method.
-   */
-  DBUG_ASSERT(ob);
-
-  String drop_stmt;
-
-  drop_stmt.append("DROP ");
-  drop_stmt.append(ob);
-  drop_stmt.append(" IF EXISTS ");
-  drop_stmt.append(sql_name());
-
-  return silent_exec_query(thd,drop_stmt) ? ERROR : OK;
-}
-
-/**** SAVE/RESTORE DATABASES ***********************************/
-
-/**
-  Save data needed to create a database.
-
-  Currently we don't save anything. A database is always created using
-  "CREATE DATABASE @<name>" statement.
- */
-result_t
-meta::Db::save(THD*,OStream&)
-{
-  return OK;
-}
-
-/**
-  Read data needed to create a database.
-
-  Nothing to read. We just build the "CREATE DATABASE ..." statement in
-  @c create_stmt.
- */
-result_t
-meta::Db::read(IStream&)
-{
-  create_stmt.append("CREATE DATABASE ");
-  create_stmt.append(sql_name());
-  return OK;
-}
-
-
-/**** SAVE/RESTORE TABLES ***************************************/
-
-/**
-  Build a CREATE statement for a table.
-
-  We use @c store_create_info() function defined in the server. For that
-  we need to open the table. After building the statement the table is closed to
-  save resources. Actually, all tables of the thread are closed as we use
-  @c close_thread_tables() function.
- */
-int meta::Table::build_create_stmt(THD *thd)
-{
-  TABLE_LIST t, *tl= &t;
-
-  bzero(&t,sizeof(TABLE_LIST));
-
-  t.db= const_cast<char*>(in_db().name().ptr());
-  t.alias= t.table_name= const_cast<char*>(sql_name());
-
-  uint cnt;
-  int res= ::open_tables(thd,&tl,&cnt,0);
-
-  if (res)
-  {
-    DBUG_PRINT("backup",("Can't open table %s to save its description (error=%d)",
-                         t.alias,res));
-    return res;
-  }
-
-  res= ::store_create_info(thd,&t,&create_stmt,NULL);
-
-  if (res)
-    DBUG_PRINT("backup",("Can't get CREATE statement for table %s (error=%d)",
-                         t.alias,res));
-
-  ::close_thread_tables(thd);
-
-  return res;
-}
-
-} // backup namespace
-
-
-/************************************************
-
-              Helper functions
-
- ************************************************/
-
-namespace backup {
-
-/// Execute SQL query without sending anything to client.
-
-/*
-  Note: the change net.vio idea taken from execute_init_command in
-  sql_parse.cc
- */
-
-int silent_exec_query(THD *thd, String &query)
-{
-  Vio *save_vio= thd->net.vio;
-
-  DBUG_PRINT("restore",("executing query %s",query.c_ptr()));
-
-  thd->net.vio= 0;
-  thd->net.no_send_error= 0;
-
-  thd->query=         query.c_ptr();
-  thd->query_length=  query.length();
-
-  thd->set_time(time(NULL));
-  pthread_mutex_lock(&::LOCK_thread_count);
-  thd->query_id= ::next_query_id();
-  pthread_mutex_unlock(&::LOCK_thread_count);
-
-  const char *ptr;
-  ::mysql_parse(thd,thd->query,thd->query_length,&ptr);
-
-  thd->net.vio= save_vio;
-
-  if (thd->is_slave_error)
-  {
-    DBUG_PRINT("restore",
-              ("error executing query %s!", thd->query));
-    DBUG_PRINT("restore",("last error (%d): %s",thd->net.last_errno
-                                               ,thd->net.last_error));
-    return thd->net.last_errno ? (int)thd->net.last_errno : -1;
-  }
-
-  return 0;
-}
-
-} // backup namespace
diff -Nrup a/sql/backup/meta_backup.h b/sql/backup/meta_backup.h
--- a/sql/backup/meta_backup.h	2007-11-06 19:32:18 +01:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,133 +0,0 @@
-#ifndef _META_BACKUP_H
-#define _META_BACKUP_H
-
-/**
-  @file
-
-  Declarations of classes used to handle meta-data items.
- */
-
-#include <backup/api_types.h>
-#include <backup/stream.h>
-
-#define META_ITEM_DESCRIPTION_LEN 128
-
-namespace backup {
-
-namespace meta {
-
-/**
-  Defines how to backup and restore a meta-data item.
-
-  This class provides @c create() and @c drop() methods used to create and
-  destroy items. The default implementation uses SQL "CREATE ..." and "DROP ..."
-  statements for that purpose. Its instances determine how to save and read data
-  needed for item creation and provide any other item specific data. For each
-  type of meta-data there is a specialized subclass of @c meta::Item which
-  implements these tasks.
- */
-
-class Item
-{
- public:
-
-  /// Possible types of meta-data items.
-  enum enum_type {DB, TABLE};
-
-  virtual ~Item() {}
-
-  /// Return type of the item.
-  virtual const enum_type type() const =0;
-
-  /**
-    For per-db items return the database to which this item belongs.
-    For other items returns an invalid db reference.
-   */
-  virtual const Db_ref in_db()
-  { return Db_ref(); }
-
-  /// Save data needed to create the item.
-  virtual result_t save(THD*,OStream&);
-
-  /// Read data saved by @c save() method.
-  virtual result_t read(IStream&);
-
-  /// Destroy the item if it exists.
-  virtual result_t drop(THD*);
-
-  /// Create the item.
-  virtual result_t create(THD*);
-
-  typedef char description_buf[META_ITEM_DESCRIPTION_LEN+1];
-
-  /// Describe item for log purposes.
-  virtual const char* describe(char *buf, size_t buf_len)
-  {
-    my_snprintf(buf,buf_len,"%s %s",sql_object_name(),sql_name());
-    return buf;
-  }
-
- protected:
-
-  String create_stmt;  /// Storage for a create statement of the item.
-
-  /**
-    Return SQL name of the object represented by this item like TABLE
-    or DATABASE. This is used to construct a "DROP ..." statement for
-    the item.
-   */
-  virtual const char* sql_object_name() const
-  { return NULL; }
-
-  /**
-    Return name under which this item is known to the server. In case of
-    per-db items the name should *not* be qualified by db name.
-   */
-  virtual const char* sql_name() const =0;
-
-  /// Store in @c create_stmt a DDL statement which will create the item.
-  /*
-    We give a default implementation because an item can not use create
-    statements and then it doesn't have to worry about this method.
-  */
-  virtual int build_create_stmt(THD*)
-  { return ERROR; }
-
-};
-
-/**
-  Specialization of @c meta::Item representing a database.
- */
-class Db: public Item
-{
-  const enum_type type() const
-  { return DB; }
-
-  const char* sql_object_name() const
-  { return "DATABASE"; }
-
-  // Overwrite default implementations.
-  result_t save(THD*,OStream&);
-  result_t read(IStream&);
-
-};
-
-/**
-  Specialization of @c meta::Item representing a table.
- */
-class Table: public Item
-{
-  const enum_type type() const
-  { return TABLE; }
-
-  const char* sql_object_name() const
-  { return "TABLE"; }
-
-  int build_create_stmt(THD*);
-};
-
-} // meta namespace
-
-} // backup namespace
-
-#endif
diff -Nrup a/sql/backup/meta_data.cc b/sql/backup/meta_data.cc
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sql/backup/meta_data.cc	2007-11-21 11:18:50 +01:00
@@ -0,0 +1,380 @@
+/**
+  @file
+
+  Functions used by kernel to save/restore meta-data
+ */
+
+/*
+  TODO:
+
+  - Handle events, routines, triggers and other item types (use Chuck's code).
+
+  - When saving database info, save its default charset and collation.
+    Alternatively, save a complete "CREATE DATABASE ..." statement with all
+    clauses which should work even when new clauses are added in the future.
+
+  - In silent_exec_query() - reset, collect and report errors from statement
+    execution.
+
+  - In the same function: investigate what happens if query triggers error -
+    there were signals that the code might hang in that case (some clean-up
+    needed?)
+ */
+
+#include <mysql_priv.h>
+#include <sql_show.h>
+
+#include "backup_aux.h"
+#include "backup_kernel.h"
+#include "meta_data.h"
+
+
+namespace backup {
+
+/**
+  Write meta-data description to backup stream.
+
+  Meta-data information is stored as a sequence of entries, each describing a
+  single meta-data item. The format of a single entry depends on the type of
+  item (see @c Archive_info::Item::save() method). The entries are saved in a
+  single chunk.
+
+  The order of entries is important. Items on which other items depend should
+  be saved first in the sequence. This order is determined by the implementation
+  of @c Backup_info::Item_iterator class.
+
+  @note Meta-data description is added to the current chunk of the stream which
+  is then closed.
+
+  @returns 0 on success, error code otherwise.
+ */
+int write_meta_data(THD *thd, Backup_info &info, OStream &s)
+{
+  DBUG_ENTER("backup::write_meta_data");
+
+  size_t start_bytes= s.bytes;
+
+  for (Backup_info::Item_iterator it(info); it; it++)
+  {
+    result_t res= it->save(thd,s); // this calls Archive_info::Item::save() method
+
+    if (res != OK)
+    {
+      meta::Item::description_buf buf;
+      info.report_error(ER_BACKUP_WRITE_META,
+                         it->meta().describe(buf,sizeof(buf)));
+      DBUG_RETURN(ERROR);
+    }
+  }
+
+  if (stream_result::ERROR == s.end_chunk())
+    DBUG_RETURN(ERROR);
+
+  info.meta_size= s.bytes - start_bytes;
+
+  DBUG_RETURN(0);
+}
+
+
+/**
+  Read meta-data items from a stream and create them if they are selected
+  for restore.
+
+  @pre  Stream is at the beginning of a saved meta-data chunk.
+  @post Stream is at the beginning of the next chunk.
+ */
+int restore_meta_data(THD *thd, Restore_info &info, IStream &s)
+{
+  DBUG_ENTER("restore_meta_data");
+  Archive_info::Item *it; // save pointer to item read form the stream
+  Db_ref  curr_db;        // remember the current database
+  result_t res;
+
+  size_t start_bytes= s.bytes;
+
+  // read items from the stream until error or end of data is reached.
+  while (OK == (res= Archive_info::Item::create_from_stream(info,s,it)))
+  {
+    DBUG_PRINT("restore",(" got next meta-item."));
+
+    if (info.selected(*it)) // if the item was selected for restore ...
+    {
+     DBUG_PRINT("restore",("  creating it!"));
+
+     /*
+       change the current database if we are going to create a per-db item
+       and we are not already in the correct one.
+      */
+     const Db_ref db= it->meta().in_db();
+
+     if (db.is_valid() && (!curr_db.is_valid() || db != curr_db))
+     {
+       DBUG_PRINT("restore",("  changing current db to %s",db.name().ptr()));
+       curr_db= db;
+       change_db(thd,db);
+     }
+
+     if (OK != (res= it->meta().create(thd)))
+     {
+       meta::Item::description_buf buf;
+       info.report_error(ER_BACKUP_CREATE_META,
+                          it->meta().describe(buf,sizeof(buf)));
+       DBUG_RETURN(ERROR);
+     }
+
+     delete it;
+    }
+  }
+
+  // We should reach end of chunk now - if not something went wrong
+
+  if (res != DONE)
+  {
+    info.report_error(ER_BACKUP_READ_META);
+    DBUG_RETURN(ERROR);
+  }
+
+  DBUG_ASSERT(res == DONE);
+
+  if (stream_result::ERROR == s.next_chunk())
+  {
+    info.report_error(ER_BACKUP_NEXT_CHUNK);
+    DBUG_RETURN(ERROR);
+  }
+
+  info.meta_size= s.bytes - start_bytes;
+
+  DBUG_RETURN(0);
+}
+
+} // backup namespace
+
+
+/*********************************************
+
+  Save/restore for different meta-data items.
+
+ *********************************************/
+
+namespace backup {
+
+int silent_exec_query(THD*, String&);
+
+/**
+  Write data needed to restore an item.
+
+  By default, a complete DDL CREATE statement for the item is saved.
+  This statement is constructed using @c meta::X::build_create_stmt() method
+  where meta::X is the class representing the item. The method stores statement
+  in the @c create_stmt member.
+
+  @returns OK or ERROR
+ */
+
+result_t
+meta::Item::save(THD *thd, OStream &s)
+{
+  create_stmt.free();
+
+  if (build_create_stmt(thd))
+    return ERROR;
+
+  return stream_result::OK == s.writestr(create_stmt) ? OK : ERROR;
+}
+
+/**
+  Read data written by @c save().
+
+  By default, the CREATE statement is read and stored in the @c create_stmt
+  member.
+
+  @retval OK    everything went ok
+  @retval DONE  end of data chunk detected
+  @retval ERROR error has happened
+ */
+result_t
+meta::Item::read(IStream &s)
+{
+  stream_result::value res= s.readstr(create_stmt);
+
+  // Saved string should not be NIL
+  return res == stream_result::NIL ? ERROR : report_stream_result(res);
+}
+
+/**
+  Create item.
+
+  Default implementation executes the statement stored in the @c create_stmt
+  member.
+
+  @returns OK or ERROR
+ */
+result_t
+meta::Item::create(THD *thd)
+{
+  if (create_stmt.is_empty())
+  { return ERROR; }
+
+  if (ERROR == drop(thd))
+    return ERROR;
+
+  return silent_exec_query(thd,create_stmt) ? ERROR : OK;
+}
+
+/**
+  Destroy item if it exists.
+
+  Default implementation executes SQL statement of the form:
+  @verbatim
+     DROP @<object type> IF EXISTS @<name>
+  @endverbatim
+  strings @<object type> and @<name> are returned by @c X::sql_object_name()
+  and @c X::sql_name() methods of the class @c meta::X representing the item.
+  If necessary, method @c drop() can be overwritten in a specialized class
+  corresponding to a given type of meta-data item.
+
+  @returns OK or ERROR
+ */
+result_t
+meta::Item::drop(THD *thd)
+{
+  const char *ob= sql_object_name();
+
+  /*
+    An item class should define object name for DROP statement
+    or redefine drop() method.
+   */
+  DBUG_ASSERT(ob);
+
+  String drop_stmt;
+
+  drop_stmt.append("DROP ");
+  drop_stmt.append(ob);
+  drop_stmt.append(" IF EXISTS ");
+  drop_stmt.append(sql_name());
+
+  return silent_exec_query(thd,drop_stmt) ? ERROR : OK;
+}
+
+/**** SAVE/RESTORE DATABASES ***********************************/
+
+/**
+  Save data needed to create a database.
+
+  Currently we don't save anything. A database is always created using
+  "CREATE DATABASE @<name>" statement.
+ */
+result_t
+meta::Db::save(THD*,OStream&)
+{
+  return OK;
+}
+
+/**
+  Read data needed to create a database.
+
+  Nothing to read. We just build the "CREATE DATABASE ..." statement in
+  @c create_stmt.
+ */
+result_t
+meta::Db::read(IStream&)
+{
+  create_stmt.append("CREATE DATABASE ");
+  create_stmt.append(sql_name());
+  return OK;
+}
+
+
+/**** SAVE/RESTORE TABLES ***************************************/
+
+/**
+  Build a CREATE statement for a table.
+
+  We use @c store_create_info() function defined in the server. For that
+  we need to open the table. After building the statement the table is closed to
+  save resources. Actually, all tables of the thread are closed as we use
+  @c close_thread_tables() function.
+ */
+int meta::Table::build_create_stmt(THD *thd)
+{
+  TABLE_LIST t, *tl= &t;
+
+  bzero(&t,sizeof(TABLE_LIST));
+
+  t.db= const_cast<char*>(in_db().name().ptr());
+  t.alias= t.table_name= const_cast<char*>(sql_name());
+
+  uint cnt;
+  int res= ::open_tables(thd,&tl,&cnt,0);
+
+  if (res)
+  {
+    DBUG_PRINT("backup",("Can't open table %s to save its description (error=%d)",
+                         t.alias,res));
+    return res;
+  }
+
+  res= ::store_create_info(thd,&t,&create_stmt,NULL);
+
+  if (res)
+    DBUG_PRINT("backup",("Can't get CREATE statement for table %s (error=%d)",
+                         t.alias,res));
+
+  ::close_thread_tables(thd);
+
+  return res;
+}
+
+} // backup namespace
+
+
+/************************************************
+
+              Helper functions
+
+ ************************************************/
+
+namespace backup {
+
+/// Execute SQL query without sending anything to client.
+
+/*
+  Note: the change net.vio idea taken from execute_init_command in
+  sql_parse.cc
+ */
+
+int silent_exec_query(THD *thd, String &query)
+{
+  Vio *save_vio= thd->net.vio;
+
+  DBUG_PRINT("restore",("executing query %s",query.c_ptr()));
+
+  thd->net.vio= 0;
+  thd->net.no_send_error= 0;
+
+  thd->query=         query.c_ptr();
+  thd->query_length=  query.length();
+
+  thd->set_time(time(NULL));
+  pthread_mutex_lock(&::LOCK_thread_count);
+  thd->query_id= ::next_query_id();
+  pthread_mutex_unlock(&::LOCK_thread_count);
+
+  const char *ptr;
+  ::mysql_parse(thd,thd->query,thd->query_length,&ptr);
+
+  thd->net.vio= save_vio;
+
+  if (thd->is_slave_error)
+  {
+    DBUG_PRINT("restore",
+              ("error executing query %s!", thd->query));
+    DBUG_PRINT("restore",("last error (%d): %s",thd->net.last_errno
+                                               ,thd->net.last_error));
+    return thd->net.last_errno ? (int)thd->net.last_errno : -1;
+  }
+
+  return 0;
+}
+
+} // backup namespace
diff -Nrup a/sql/backup/meta_data.h b/sql/backup/meta_data.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/sql/backup/meta_data.h	2007-11-21 10:58:17 +01:00
@@ -0,0 +1,133 @@
+#ifndef _META_BACKUP_H
+#define _META_BACKUP_H
+
+/**
+  @file
+
+  Declarations of classes used to handle meta-data items.
+ */
+
+#include <backup/api_types.h>
+#include <backup/stream.h>
+
+#define META_ITEM_DESCRIPTION_LEN 128
+
+namespace backup {
+
+namespace meta {
+
+/**
+  Defines how to backup and restore a meta-data item.
+
+  This class provides @c create() and @c drop() methods used to create and
+  destroy items. The default implementation uses SQL "CREATE ..." and "DROP ..."
+  statements for that purpose. Its instances determine how to save and read data
+  needed for item creation and provide any other item specific data. For each
+  type of meta-data there is a specialized subclass of @c meta::Item which
+  implements these tasks.
+ */
+
+class Item
+{
+ public:
+
+  /// Possible types of meta-data items.
+  enum enum_type {DB, TABLE};
+
+  virtual ~Item() {}
+
+  /// Return type of the item.
+  virtual const enum_type type() const =0;
+
+  /**
+    For per-db items return the database to which this item belongs.
+    For other items returns an invalid db reference.
+   */
+  virtual const Db_ref in_db()
+  { return Db_ref(); }
+
+  /// Save data needed to create the item.
+  virtual result_t save(THD*,OStream&);
+
+  /// Read data saved by @c save() method.
+  virtual result_t read(IStream&);
+
+  /// Destroy the item if it exists.
+  virtual result_t drop(THD*);
+
+  /// Create the item.
+  virtual result_t create(THD*);
+
+  typedef char description_buf[META_ITEM_DESCRIPTION_LEN+1];
+
+  /// Describe item for log purposes.
+  virtual const char* describe(char *buf, size_t buf_len)
+  {
+    my_snprintf(buf,buf_len,"%s %s",sql_object_name(),sql_name());
+    return buf;
+  }
+
+ protected:
+
+  String create_stmt;  /// Storage for a create statement of the item.
+
+  /**
+    Return SQL name of the object represented by this item like TABLE
+    or DATABASE. This is used to construct a "DROP ..." statement for
+    the item.
+   */
+  virtual const char* sql_object_name() const
+  { return NULL; }
+
+  /**
+    Return name under which this item is known to the server. In case of
+    per-db items the name should *not* be qualified by db name.
+   */
+  virtual const char* sql_name() const =0;
+
+  /// Store in @c create_stmt a DDL statement which will create the item.
+  /*
+    We give a default implementation because an item can not use create
+    statements and then it doesn't have to worry about this method.
+  */
+  virtual int build_create_stmt(THD*)
+  { return ERROR; }
+
+};
+
+/**
+  Specialization of @c meta::Item representing a database.
+ */
+class Db: public Item
+{
+  const enum_type type() const
+  { return DB; }
+
+  const char* sql_object_name() const
+  { return "DATABASE"; }
+
+  // Overwrite default implementations.
+  result_t save(THD*,OStream&);
+  result_t read(IStream&);
+
+};
+
+/**
+  Specialization of @c meta::Item representing a table.
+ */
+class Table: public Item
+{
+  const enum_type type() const
+  { return TABLE; }
+
+  const char* sql_object_name() const
+  { return "TABLE"; }
+
+  int build_create_stmt(THD*);
+};
+
+} // meta namespace
+
+} // backup namespace
+
+#endif
diff -Nrup a/sql/backup/sql_backup.cc b/sql/backup/sql_backup.cc
--- a/sql/backup/sql_backup.cc	2007-11-09 22:19:39 +01:00
+++ /dev/null	Wed Dec 31 16:00:00 196900
@@ -1,1384 +0,0 @@
-/**
-  @file
-
-  Implementation of the backup kernel API.
- */
-
-/*
-  TODO:
-
-  - Handle SHOW BACKUP ARCHIVE command.
-  - Add database list to the backup/restore summary.
-  - Implement meta-data freeze during backup/restore.
-  - Improve logic selecting backup driver for a table.
-  - Handle other types of meta-data in Backup_info methods.
-  - Handle item dependencies when adding new items.
-  - Lock I_S tables when reading table list and similar (is it needed?)
-  - When reading table list from I_S tables, use select conditions to
-    limit amount of data read. (check prepare_select_* functions in sql_help.cc)
-  - Handle other kinds of backup locations (far future).
-  - Complete feedback given by BACKUP/RESTORE statements (send_summary function).
- */
-
-#include "../mysql_priv.h"
-
-#include "backup_aux.h"
-#include "stream.h"
-#include "backup_kernel.h"
-#include "meta_backup.h"
-#include "archive.h"
-#include "debug.h"
-#include "be_default.h"
-#include "be_snapshot.h"
-
-namespace backup {
-
-// Helper functions
-
-static IStream* open_for_read(const Location&);
-static OStream* open_for_write(const Location&);
-
-/*
-  Report errors. The main error code and optional arguments for its description
-  are given plus a logger object which can contain stored errors.
- */
-static int report_errors(THD*, Logger&, int, ...);
-
-/*
-  Check if info object is valid. If not, report error to client.
- */
-static int check_info(THD*,Backup_info&);
-static int check_info(THD*,Restore_info&);
-
-static bool send_summary(THD*,const Backup_info&);
-static bool send_summary(THD*,const Restore_info&);
-
-#ifdef DBUG_BACKUP
-// Flag used for testing error reporting
-bool test_error_flag= FALSE;
-#endif
-}
-
-/**
-  Call backup kernel API to execute backup related SQL statement.
-
-  @param lex  results of parsing the statement.
-
-  @note This function sends response to the client (ok, result set or error).
- */
-
-int
-execute_backup_command(THD *thd, LEX *lex)
-{
-  time_t skr;
-
-  DBUG_ENTER("execute_backup_command");
-  DBUG_ASSERT(thd && lex);
-
-  BACKUP_BREAKPOINT("backup_command");
-
-  /*
-    Check access for SUPER rights. If user does not have SUPER, fail with error.
-  */
-  if (check_global_access(thd, SUPER_ACL))
-    DBUG_RETURN(ER_SPECIFIC_ACCESS_DENIED_ERROR);
-
-  backup::Location *loc= backup::Location::find(lex->backup_dir);
-
-  if (!loc)
-  {
-    my_error(ER_BACKUP_INVALID_LOC,MYF(0),lex->backup_dir.str);
-    DBUG_RETURN(ER_BACKUP_INVALID_LOC);
-  }
-
-  int res= 0;
-
-  switch (lex->sql_command) {
-
-  case SQLCOM_SHOW_ARCHIVE:
-  case SQLCOM_RESTORE:
-  {
-    backup::IStream *stream= backup::open_for_read(*loc);
-
-    if (!stream)
-    {
-      my_error(ER_BACKUP_READ_LOC,MYF(0),loc->describe());
-      goto restore_error;
-    }
-    else
-    {
-      backup::Restore_info info(*stream);
-
-      if (check_info(thd,info))
-        goto restore_error;
-
-      if (lex->sql_command == SQLCOM_SHOW_ARCHIVE)
-      {
-        my_error(ER_NOT_ALLOWED_COMMAND,MYF(0));
-        goto restore_error;
-        /*
-          Uncomment when mysql_show_archive() is implemented
-
-          res= mysql_show_archive(thd,info);
-         */
-      }
-      else
-      {
-        info.report_error(backup::log_level::INFO,ER_BACKUP_RESTORE_START);
-
-        // TODO: freeze all DDL operations here
-
-        info.save_errors();
-        info.restore_all_dbs();
-
-        if (check_info(thd,info))
-          goto restore_error;
-
-        info.clear_saved_errors();
-
-        if (mysql_restore(thd,info,*stream))
-        {
-          report_errors(thd,info,ER_BACKUP_RESTORE);
-          goto restore_error;
-        }
-        else
-        {
-          info.report_error(backup::log_level::INFO,ER_BACKUP_RESTORE_DONE);
-          info.total_size += info.header_size;
-          send_summary(thd,info);
-        }
-
-        // TODO: unfreeze DDL here
-      }
-    } // if (!stream)
-
-    goto finish_restore;
-    
-   restore_error:
-
-    res= res ? res : backup::ERROR;
-    
-   finish_restore:
-
-    if (stream)
-      stream->close();
-
-    break;
-  }
-
-  case SQLCOM_BACKUP:
-  {
-    backup::OStream *stream= backup::open_for_write(*loc);
-
-    if (!stream)
-    {
-      my_error(ER_BACKUP_WRITE_LOC,MYF(0),loc->describe());
-      goto backup_error;
-    }
-    else
-    {
-      backup::Backup_info info(thd);
-
-      if (check_info(thd,info))
-        goto backup_error;
-
-      info.report_error(backup::log_level::INFO,ER_BACKUP_BACKUP_START);
-
-      // TODO: freeze all DDL operations here
-
-      /*
-        Save starting datetime of backup.
-      */
-      skr= my_time(0);
-      gmtime_r(&skr, &info.start_time);
-
-      info.save_errors();
-
-      if (lex->db_list.is_empty())
-      {
-        info.write_message(backup::log_level::INFO,"Backing up all databases");
-        info.add_all_dbs(); // backup all databases
-      }
-      else
-      {
-        info.write_message(backup::log_level::INFO,"Backing up selected databases");
-        info.add_dbs(lex->db_list); // backup databases specified by user
-      }
-
-      if (check_info(thd,info))
-        goto backup_error;
-
-      info.close();
-
-      if (check_info(thd,info))
-        goto backup_error;
-
-      info.clear_saved_errors();
-
-      if (mysql_backup(thd,info,*stream))
-      {
-        report_errors(thd,info,ER_BACKUP_BACKUP);
-        goto backup_error;
-      }
-      else
-      {
-        info.report_error(backup::log_level::INFO,ER_BACKUP_BACKUP_DONE);
-        send_summary(thd,info);
-      }
-
-      /*
-        Save ending datetime of backup.
-      */
-      skr= my_time(0);
-      gmtime_r(&skr, &info.end_time);
-
-      // TODO: unfreeze DDL here
-    } // if (!stream)
-
-    goto finish_backup;
-   
-   backup_error:
-   
-    res= res ? res : backup::ERROR;
-   
-   finish_backup:
-
-    if (stream)
-      stream->close();
-
-#ifdef  DBUG_BACKUP
-    backup::IStream *is= backup::open_for_read(*loc);
-    if (is)
-    {
-      dump_stream(*is);
-      is->close();
-    }
-#endif
-
-    break;
-  }
-
-   default:
-     /*
-       execute_backup_command() should be called with correct command id
-       from the parser. If not, we fail on this assertion.
-      */
-     DBUG_ASSERT(FALSE);
-  }
-
-  loc->free();
-  DBUG_RETURN(res);
-}
-
-
-/*************************************************
-
-                   BACKUP
-
- *************************************************/
-
-// Declarations for functions used in backup operation
-
-namespace backup {
-
-// defined in meta_backup.cc
-int write_meta_data(THD*, Backup_info&, OStream&);
-
-// defined in data_backup.cc
-int write_table_data(THD*, Backup_info&, OStream&);
-
-} // backup namespace
-
-
-/**
-  Create backup archive.
-*/
-
-int mysql_backup(THD *thd,
-                 backup::Backup_info &info,
-                 backup::OStream &s)
-{
-  DBUG_ENTER("mysql_backup");
-
-  // This function should not be called with invalid backup info.
-  DBUG_ASSERT(info.is_valid());
-
-  size_t start_bytes= s.bytes;
-
-  BACKUP_BREAKPOINT("backup_meta");
-
-  DBUG_PRINT("backup",("Writing image header"));
-
-  if (info.save(s))
-    goto error;
-
-  DBUG_PRINT("backup",("Writing meta-data"));
-
-  if (backup::write_meta_data(thd,info,s))
-    goto error;
-
-  DBUG_PRINT("backup",("Writing table data"));
-
-  BACKUP_BREAKPOINT("backup_data");
-
-  if (backup::write_table_data(thd,info,s))
-    goto error;
-
-  DBUG_PRINT("backup",("Backup done."));
-  BACKUP_BREAKPOINT("backup_done");
-
-  info.total_size= s.bytes - start_bytes;
-
-  DBUG_RETURN(0);
-
- error:
-
-  DBUG_RETURN(backup::ERROR);
-}
-
-namespace backup {
-
-
-class Backup_info::Table_ref:
- public backup::Table_ref
-{
-  String  m_db_name;
-  String  m_name;
-  ::TABLE *m_table;
-
- public:
-
-  Table_ref(const Db_item&, const String&);
-  ~Table_ref()
-  { close(); }
-  
-  ::TABLE* open(THD*);
-  void close();
-  
-  /**
-   Return pointer to @c handlerton structure of table's storage engine.
-   
-   @return @c NULL if table has not been opened or pointer to the @c handlerton
-   structure of table's storage engine.
-   */ 
-  ::handlerton* hton() const
-  { return m_table && m_table->s ? m_table->s->db_type() : NULL; }
-  
-  /// Check if table has been opened.
-  bool is_open() const 
-  { return m_table != NULL; }
-};
-
-/**
-  Find image to which given table can be added and add it.
-
-  Creates new images as needed.
-
-  @returns Position of the image found in @c images[] table or -1 on error.
- */
-
-/*
-   Logic for selecting image format for a given table location:
-
-   1. If tables from that location have been already stored in one of the
-      sub-images then choose that sub-image.
-
-   2. If location has "native" backup format, put it in a new sub-image with
-      that format.
-
-   3. Otherwise check if one of the existing sub-images would accept table from
-      this location.
-
-   4. If table has no native backup engine, try a consistent snapshot one.
-
-   5. When everything else fails, use default (blocking) backup driver.
-
-   Note: 1 is not implemented yet and hence we start with 3.
- */
-
-int Backup_info::find_image(const Backup_info::Table_ref &tbl)
-{
-   DBUG_ENTER("Backup_info::find_image");
-   // we assume that table has been opened already
-   DBUG_ASSERT(tbl.is_open());
-   
-   Image_info *img;
-   const ::handlerton *hton= tbl.hton();
-   // If table has no handlerton something is really bad - we crash here
-   DBUG_ASSERT(hton);
-
-   Table_ref::describe_buf buf;
-   
-   DBUG_PRINT("backup",("Adding table %s using storage %s to archive%s",
-                        tbl.describe(buf),
-                        ::ha_resolve_storage_engine_name(hton),
-                        hton->get_backup_engine ? " (has native backup)." : "."));
-
-   // Point 3: try existing images but not the default or snapshot one.
-
-   for (uint no=0; no < img_count && no < MAX_IMAGES ; ++no)
-   {
-     if (default_image_no >= 0 && no == (uint)default_image_no)
-       continue;
-
-     if (snapshot_image_no >= 0 && no == (uint)snapshot_image_no)
-       continue;
-
-     img= images[no];
-
-     // An image object decides if it can handle given table or not
-     if( img && img->accept(tbl,hton) )
-       DBUG_RETURN(no);
-   }
-
-   // Point 2: try native backup of table's storage engine.
-
-   if (hton->get_backup_engine)
-   {
-     uint no= img_count;
-
-     // We handle at most MAX_IMAGES many images
-     DBUG_ASSERT(no<MAX_IMAGES);
-
-     img= images[no]= new Native_image(*this,hton);
-
-     if (!img)
-     {
-       report_error(ER_OUT_OF_RESOURCES);
-       DBUG_RETURN(-1);
-     }
-
-     DBUG_PRINT("backup",("%s image added to archive",img->name()));
-     img_count++;
-
-#ifdef DBUG_OFF 
-     // avoid "unused variable" compilation warning
-     img->accept(tbl,hton);
-#else
-     // native image should accept all tables from its own engine
-     bool res= img->accept(tbl,hton);
-     DBUG_ASSERT(res);
-#endif
-
-     DBUG_RETURN(no);
-   }
-
-   // Points 4 & 5: try consistent snapshot and default drivers..
-
-   // try snapshot driver first
-   int ino= snapshot_image_no;
-   if (hton->start_consistent_snapshot != NULL)
-   {
-     if (snapshot_image_no < 0) //image doesn't exist
-     {
-       ino= img_count;
-       snapshot_image_no= img_count;
-       images[snapshot_image_no]= new Snapshot_image(*this);
-       img_count++;
-       DBUG_PRINT("backup",("Snapshot image added to archive"));
-     }
-   }
-   else
-     ino= default_image_no; //now try default driver
-
-   if (ino < 0) //image doesn't exist
-   {
-     ino= img_count;
-     default_image_no= img_count;
-     images[default_image_no]= new Default_image(*this);
-     img_count++;
-     DBUG_PRINT("backup",("Default image added to archive"));
-   }
-
-   img= images[ino];
-   DBUG_ASSERT(img);
-   if (img->accept(tbl,hton))
-     DBUG_RETURN(ino); // table accepted
-
-   report_error(ER_BACKUP_NO_BACKUP_DRIVER,tbl.describe(buf,sizeof(buf)));
-   DBUG_RETURN(-1);
-}
-
-} // backup namespace
-
-
-/****************************
-
-  Backup_info implementation
-
- ****************************/
-
-namespace backup {
-
-//  Returns tmp table containing records from a given I_S table
-TABLE* get_schema_table(THD *thd, ST_SCHEMA_TABLE *st);
-
-/* 
-  Backup_info::skip_table pointer is just for indicating that a table
-  added with Backup_info::add_table() was skipped. It should have value not 
-  possible for regular pointers.
- */
-const Backup_info::Table_item *const 
-Backup_info::skip_table= reinterpret_cast<Backup_info::Table_item*>(1);
-
-/**
-  Create @c Backup_info structure and prepare it for populating with meta-data
-  items.
-
-  When adding a complete database to the archive, all its tables are added.
-  These are found by reading INFORMATION_SCHEMA.TABLES table. The table is
-  opened here so that it is ready for use in @c add_db_items() method. It is
-  closed when the structure is closed with the @c close() method.
- */
-Backup_info::Backup_info(THD *thd):
-  Logger(Logger::BACKUP),
-  m_state(INIT), default_image_no(-1), snapshot_image_no(-2), 
-  m_thd(thd), i_s_tables(NULL),
-  m_items(NULL), m_last_item(NULL), m_last_db(NULL)
-{
-  i_s_tables= get_schema_table(m_thd, ::get_schema_table(SCH_TABLES));
-  if (!i_s_tables)
-  {
-    report_error(ER_BACKUP_LIST_TABLES);
-    m_state= ERROR;
-  }
-}
-
-Backup_info::~Backup_info()
-{
-  close();
-  m_state= DONE;
-
-  Item_iterator it(*this);
-  Item *i;
-
-  while ((i=it++))
-    delete i;
-
-  m_items= NULL;
-}
-
-/**
-  Close the structure after populating it with items.
-
-  When meta-data is written, we need to open archive's tables to be able
-  to read their definitions. Tables are opened here so that the
-  structure is ready for creation of the archive.
-
-  FIXME: opening all tables at once consumes too much resources when there
-  is a lot of tables (opened file descriptors!). Find a better solution.
- */
-bool Backup_info::close()
-{
-  bool ok= is_valid();
-
-  if(i_s_tables)
-    ::free_tmp_table(m_thd,i_s_tables);
-  i_s_tables= NULL;
-
-  if (m_state == INIT)
-    m_state= READY;
-
-  return ok;
-}
-
-int Backup_info::save(OStream &s)
-{
-  if (OK != Archive_info::save(s))
-  {
-    report_error(ER_BACKUP_WRITE_HEADER);
-    return ERROR;
-  }
-
-  return 0;
-}
-
-/**
-  Specialization of @c backup::Db_ref with convenient constructors.
- */
-
-class Backup_info::Db_ref: public backup::Db_ref
-{
-  String m_name;
-
- public:
-
-  Db_ref(const String &s): backup::Db_ref(m_name), m_name(s)
-  {}
-
-  Db_ref(const LEX_STRING &s):
-    backup::Db_ref(m_name),
-    m_name(s.str,s.length,::system_charset_info)
-  {}
-};
-
-/**
-  Add to archive all databases in the list.
- */
-int Backup_info::add_dbs(List< ::LEX_STRING > &dbs)
-{
-  List_iterator< ::LEX_STRING > it(dbs);
-  ::LEX_STRING *s;
-  String unknown_dbs; // comma separated list of databases which don't exist
-
-  while ((s= it++))
-  {
-    Db_ref db(*s);
-
-    if (db_exists(db))
-    {
-      if (!unknown_dbs.is_empty()) // we just compose unknown_dbs list
-        continue;
-
-      Db_item *it= add_db(db);
-
-      if (!it)
-        goto error;
-
-      if (add_db_items(*it))
-        goto error;
-    }
-    else
-    {
-      if (!unknown_dbs.is_empty())
-        unknown_dbs.append(",");
-      unknown_dbs.append(db.name());
-    }
-  }
-
-  if (!unknown_dbs.is_empty())
-  {
-    report_error(ER_BAD_DB_ERROR,unknown_dbs.c_ptr());
-    goto error;
-  }
-  
-  return 0;
-  
- error:
-
-  m_state= ERROR;
-  return backup::ERROR;
-}
-
-/**
-  Add to archive all instance's databases (except the internal ones).
- */
-
-int Backup_info::add_all_dbs()
-{
-  my_bitmap_map *old_map;
-
-  DBUG_PRINT("backup", ("Reading databases from I_S"));
-
-  ::TABLE *db_table = get_schema_table(m_thd, ::get_schema_table(SCH_SCHEMATA));
-
-  if (!db_table)
-  {
-    report_error(ER_BACKUP_LIST_DBS);
-    return ERROR;
-  }
-
-  ::handler *ha = db_table->file;
-
-  // TODO: locking
-
-  int res= 0;
-
-  old_map= dbug_tmp_use_all_columns(db_table, db_table->read_set);
-
-  if (ha->ha_rnd_init(TRUE))
-  {
-    res= -2;
-    report_error(ER_BACKUP_LIST_DBS);
-    goto finish;
-  }
-
-  while (!ha->rnd_next(db_table->record[0]))
-  {
-    String db_name;
-    
-    db_table->field[1]->val_str(&db_name);
-    
-    // skip internal databases
-    if (db_name == String("information_schema",&::my_charset_bin) 
-        || db_name == String("mysql",&my_charset_bin))
-    {
-      DBUG_PRINT("backup",(" Skipping internal database %s",db_name.ptr()));
-      continue;
-    }
-
-    Db_ref db(db_name);
-
-    DBUG_PRINT("backup", (" Found database %s", db.name().ptr()));
-
-    Db_item *it= add_db(db);
-
-    if (!it)
-    {
-      res= -3;
-      goto finish;
-    }
-
-    if (add_db_items(*it))
-    {
-      res= -4;
-      goto finish;
-    }
-  }
-
-  DBUG_PRINT("backup", ("No more databases in I_S"));
-
-  ha->ha_rnd_end();
-
- finish:
-
-  if (db_table)
-  {
-    dbug_tmp_restore_column_map(db_table->read_set, old_map);
-    ::free_tmp_table(m_thd, db_table);
-  }
-
-  if (res)
-    m_state= ERROR;
-
-  return res;
-}
-
-/**
-  Insert a @c Db_item into the meta-data items list.
- */
-Backup_info::Db_item*
-Backup_info::add_db(const backup::Db_ref &db)
-{
-  StringPool::Key key= db_names.add(db.name());
-
-  if (!key.is_valid())
-  {
-    report_error(ER_OUT_OF_RESOURCES);
-    return NULL;
-  }
-
-  Db_item *di= new Db_item(*this,key);
-
-  if (!di)
-  {
-    report_error(ER_OUT_OF_RESOURCES);
-    return NULL;
-  }
-
-  // insert db item before all table items
-
-  if (!m_last_db)
-  {
-    di->next= m_items;
-    m_items= m_last_db= di;
-    if (!m_last_item)
-     m_last_item= m_items;
-  }
-  else
-  {
-    // since m_last_db is not NULL, m_items list can't be empty
-    DBUG_ASSERT(m_items);
-
-    di->next= m_last_db->next;
-    if (m_last_item == m_last_db)
-     m_last_item= di;
-    m_last_db->next= di;
-  }
-
-  return di;
-}
-
-/**
-  Add to archive all items belonging to a given database.
- */
-int Backup_info::add_db_items(Db_item &db)
-{
-  my_bitmap_map *old_map;
-
-  DBUG_ASSERT(m_state == INIT);  // should be called before structure is closed
-  DBUG_ASSERT(is_valid());       // should be valid
-  DBUG_ASSERT(i_s_tables->file); // i_s_tables should be opened
-
-  // add all tables from db.
-
-  ::handler *ha= i_s_tables->file;
-
-  /*
-    If error debugging is switched on (see debug.h) then I_S.TABLES access
-    error will be triggered when backing up database whose name starts with 'a'.
-   */
-  TEST_ERROR_IF(db.name().ptr()[0]=='a');
-
-  old_map= dbug_tmp_use_all_columns(i_s_tables, i_s_tables->read_set);
-  
-  if (ha->ha_rnd_init(TRUE) || TEST_ERROR)
-  {
-    dbug_tmp_restore_column_map(i_s_tables->read_set, old_map);
-    report_error(ER_BACKUP_LIST_DB_TABLES,db.name().ptr());
-    return ERROR;
-  }
-
-  int res= 0;
-
-  while (!ha->rnd_next(i_s_tables->record[0]))
-  {
-    String db_name;
-    String name;
-    String type;
-    String engine;
-
-    /* 
-      Read info about next table/view
-      
-      Note: this should be synchronized with the definition of 
-      INFORMATION_SCHEMA.TABLES table.
-     */
-    i_s_tables->field[1]->val_str(&db_name);
-    i_s_tables->field[2]->val_str(&name);
-    i_s_tables->field[3]->val_str(&type);
-    i_s_tables->field[4]->val_str(&engine);
-    
-    if (db_name != db.name())
-      continue; // skip tables not from the given database
-    
-    // FIXME: right now, we handle only tables
-    if (type != String("BASE TABLE",&::my_charset_bin))
-    {
-      report_error(log_level::WARNING,ER_BACKUP_SKIP_VIEW,
-                   name.c_ptr(),db_name.c_ptr());
-      continue;
-    }
-
-    Backup_info::Table_ref t(db,name);
-    
-    if (engine.is_empty())
-    {
-      Table_ref::describe_buf buf;
-      report_error(log_level::WARNING,ER_BACKUP_NO_ENGINE,t.describe(buf));
-      continue;                   
-    }
-
-    DBUG_PRINT("backup", ("Found table %s for database %s",
-                           t.name().ptr(), t.db().name().ptr()));
-
-    // We need to open table for add_table() method below
-    if (!t.open(m_thd))
-    {
-      Table_ref::describe_buf buf;
-      report_error(ER_BACKUP_TABLE_OPEN,t.describe(buf));
-      goto error;
-    }
-    // add_table method selects/creates sub-image appropriate for storing given table
-    Table_item *ti= add_table(t);
-    
-    // Close table to free resources
-    t.close();
-    
-    if (!ti)
-      goto error;
-
-    if (ti == skip_table)
-      continue;
-
-    if (add_table_items(*ti))
-      goto error;
-  }
-
-  goto finish;
-  
- error:
- 
-  res= res ? res : ERROR;
- 
- finish:
- 
-  ha->ha_rnd_end();
-
-  dbug_tmp_restore_column_map(i_s_tables->read_set, old_map);
-
-  return res;
-}
-
-/* Implementation of Backup_info::Table_ref */
-
-Backup_info::Table_ref::Table_ref(const Db_item &db, const String &name):
-  backup::Table_ref(m_db_name,m_name), m_table(NULL)
-{
-  m_db_name.append(db.name());
-  m_name.append(name);
-}
-
-/**
- Open table and create corresponding @c TABLE structure.
- 
- A pointer to opened @c TABLE structure is stored in @c m_table member. The 
- structure is owned by @c Table_ref object, to destroy it call @c close() 
- method. 
- 
- This method does nothing if table has been already opened.
- 
- @return Pointer to the opened @c TABLE structure or @c NULL if operation was
- not successful. 
- */ 
-::TABLE* Backup_info::Table_ref::open(THD *thd)
-{
-  if (is_open())
-    return m_table;
-    
-  char path[FN_REFLEN];
-  const char *db= m_db_name.ptr();
-  const char *name= m_name.ptr();
-  ::build_table_filename(path, sizeof(path), db, name, "", 0);
-  m_table= ::open_temporary_table(
-                thd, path, db, name, 
-                FALSE /* don't link to thd->temporary_tables */,
-                OTM_OPEN);
-  
-  /*
-   Note: If table couldn't be opened (m_table==NULL), open_temporary_table() 
-   doesn't inform us what was the reason. This makes it difficult to give 
-   precise information in the error log. Currently we just say that table 
-   couldn't be opened. When error reporting is improved, we should try to do 
-   better than that.
-   */ 
-  return m_table;
-}
-
-/**
- Close previously opened table.
- 
- Closes table and frees allocated resources. Can be called even when table
- has not been opened, in which case it does nothing.
- */ 
-void Backup_info::Table_ref::close()
-{
-  if (m_table)
-  {
-    // TODO: check if ::free_tmp_table() is not better
-    ::intern_close_table(m_table);
-    my_free(m_table, MYF(0));
-  }
-  m_table= NULL;
-  return;
-}
-
-/**
-  Add table to archive's list of meta-data items.
-  
-  @pre Table should be opened.
- */
-
-Backup_info::Table_item*
-Backup_info::add_table(const Table_ref &t)
-{
-  DBUG_ASSERT(t.is_open());
-    
-  // TODO: skip table if it is a tmp one
-    
-  int no= find_image(t); // Note: find_image reports errors
-
-  /*
-    If error debugging is switched on (see debug.h) then any table whose
-    name starts with 'a' will trigger "no backup driver" error.
-   */
-  TEST_ERROR_IF(t.name().ptr()[0]=='a');
-
-  if (no < 0 || TEST_ERROR)
-    return NULL;
-
-  /*
-    If image was found then images[no] should point at the Image_info
-    object
-   */
-  Image_info *img= images[no];
-  DBUG_ASSERT(img);
-
-  /*
-    If error debugging is switched on (see debug.h) then any table whose
-    name starts with 'b' will trigger error when added to backup image.
-   */
-  TEST_ERROR_IF(t.name().ptr()[0]=='b');
-
-  int tno= img->tables.add(t);
-  if (tno < 0 || TEST_ERROR)
-  {
-    Table_ref::describe_buf buf;
-    report_error(ER_BACKUP_NOT_ACCEPTED,img->name(),t.describe(buf));
-    return NULL;
-  }
-
-  table_count++;
-
-  Table_item *ti= new Table_item(*this,no,tno);
-
-  if (!ti)
-  {
-    report_error(ER_OUT_OF_RESOURCES);
-    return NULL;
-  }
-
-  // add to the end of items list
-
-  ti->next= NULL;
-  if (m_last_item)
-   m_last_item->next= ti;
-  m_last_item= ti;
-  if (!m_items)
-   m_items= ti;
-
-  return ti;
-}
-
-/**
-  Add to archive all items belonging to a given table.
- */
-int Backup_info::add_table_items(Table_item&)
-{
-  // TODO: Implement when we handle per-table meta-data.
-  return 0;
-}
-
-} // backup namespace
-
-
-/*************************************************
-
-                   RESTORE
-
- *************************************************/
-
-// Declarations of functions used in restore operation
-
-namespace backup {
-
-// defined in meta_backup.cc
-int restore_meta_data(THD*, Restore_info&, IStream&);
-
-// defined in data_backup.cc
-int restore_table_data(THD*, Restore_info&, IStream&);
-
-} // backup namespace
-
-
-/**
-  Restore items saved in backup archive.
-
-  @pre archive info has been already read and the stream is positioned
-        at archive's meta-data
-*/
-int mysql_restore(THD *thd, backup::Restore_info &info, backup::IStream &s)
-{
-  DBUG_ENTER("mysql_restore");
-
-  size_t start_bytes= s.bytes;
-
-  DBUG_PRINT("restore",("Restoring meta-data"));
-
-  if (backup::restore_meta_data(thd, info, s))
-    DBUG_RETURN(backup::ERROR);
-
-  DBUG_PRINT("restore",("Restoring table data"));
-
-  if (backup::restore_table_data(thd,info,s))
-    DBUG_RETURN(backup::ERROR);
-
-  DBUG_PRINT("restore",("Done."));
-
-  info.total_size= s.bytes - start_bytes;
-
-  DBUG_RETURN(0);
-}
-
-/*************************************************
-
-               BACKUP LOCATIONS
-
- *************************************************/
-
-namespace backup {
-
-struct File_loc: public Location
-{
-  String path;
-
-  enum_type type() const
-  { return SERVER_FILE; }
-
-  File_loc(const char *p)
-  { path.append(p); }
-
-  const char* describe()
-  { return path.c_ptr(); }
-
-};
-
-
-template<class S>
-S* open_stream(const Location &loc)
-{
-  switch (loc.type()) {
-
-  case Location::SERVER_FILE:
-  {
-    const File_loc &f= static_cast<const File_loc&>(loc);
-    S *s= new S(f.path);
-
-    if (s && s->open())
-      return s;
-
-    delete s;
-    return NULL;
-  }
-
-  default:
-    return NULL;
-
-  }
-}
-
-template IStream* open_stream<IStream>(const Location&);
-template OStream* open_stream<OStream>(const Location&);
-
-IStream* open_for_read(const Location &loc)
-{
-  return open_stream<IStream>(loc);
-}
-
-
-OStream* open_for_write(const Location &loc)
-{
-  return open_stream<OStream>(loc);
-}
-
-/**
-  Find location described by a string.
-
-  The string is taken from the "TO ..." clause of BACKUP/RESTORE commands.
-  This function parses the string and creates instance of @c Location class
-  describing the location or NULL if string doesn't describe any valid location.
-
-  Currently the only supported type of location is a file on the server host.
-  The string is supposed to contain a path to such file.
-
-  @note No checks on the location are made at this stage. In particular the
-  location might not physically exist. In the future methods performing such
-  checks can be added to @Location class.
- */
-Location*
-Location::find(const LEX_STRING &where)
-{
-  return where.str && where.length ? new File_loc(where.str) : NULL;
-}
-
-} // backup namespace
-
-
-/*************************************************
-
-                 Helper functions
-
- *************************************************/
-
-TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list); // defined in sql_show.cc
-
-namespace backup {
-
-/**
-  Report errors.
-
-  Current implementation reports the last error saved in the logger if it exist.
-  Otherwise it reports error given by @c error_code.
- */
-int report_errors(THD *thd, Logger &log, int error_code, ...)
-{
-  MYSQL_ERROR *error= log.last_saved_error();
-
-  if (error && !util::report_mysql_error(thd,error,error_code))
-  {  
-    if (error->code)
-      error_code= error->code;
-  }
-  else // there are no error information in the logger - report error_code
-  {
-    char buf[ERRMSGSIZE + 20];
-    va_list args;
-    va_start(args,error_code);
-
-    my_vsnprintf(buf,sizeof(buf),ER_SAFE(error_code),args);
-    my_printf_error(error_code,buf,MYF(0));
-
-    va_end(args);
-  }
-
-  return error_code;
-}
-
-inline
-int check_info(THD *thd, Backup_info &info)
-{ 
-  return info.is_valid() ? OK : report_errors(thd,info,ER_BACKUP_BACKUP_PREPARE); 
-}
-
-inline
-int check_info(THD *thd, Restore_info &info)
-{ 
-  return info.is_valid() ? OK : report_errors(thd,info,ER_BACKUP_RESTORE_PREPARE); 
-}
-
-/**
-  Send a summary of the backup/restore operation to the client.
-
-  The data about the operation is taken from filled @c Archive_info
-  structure. Parameter @c backup determines if this was backup or
-  restore operation.
-
-  TODO: Add list of databases in the output.
-*/
-
-static
-bool send_summary(THD *thd, const Archive_info &info, bool backup)
-{
-  Protocol   *protocol= ::current_thd->protocol; // client comms
-  List<Item> field_list;                         // list of fields to send
-  Item       *item;                              // field item
-  char       buf[255];                           // buffer for data
-  String     op_str;                             // operations string
-  String     print_str;                          // string to print
-
-  DBUG_ENTER("backup::send_summary");
-
-  DBUG_PRINT(backup?"backup":"restore", ("sending summary"));
-
-  op_str.length(0);
-  if (backup)
-    op_str.append("Backup Summary");
-  else
-    op_str.append("Restore Summary");
-
-
-  field_list.push_back(item= new Item_empty_string(op_str.c_ptr(),255)); // TODO: use varchar field
-  item->maybe_null= TRUE;
-  protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
-
-  my_snprintf(buf,sizeof(buf)," header     = %-8lu bytes",(unsigned long)info.header_size);
-  protocol->prepare_for_resend();
-  protocol->store(buf,system_charset_info);
-  protocol->write();
-
-  my_snprintf(buf,sizeof(buf)," meta-data  = %-8lu bytes",(unsigned long)info.meta_size);
-  protocol->prepare_for_resend();
-  protocol->store(buf,system_charset_info);
-  protocol->write();
-
-  my_snprintf(buf,sizeof(buf)," data       = %-8lu bytes",(unsigned long)info.data_size);
-  protocol->prepare_for_resend();
-  protocol->store(buf,system_charset_info);
-  protocol->write();
-
-  my_snprintf(buf,sizeof(buf),"              --------------");
-  protocol->prepare_for_resend();
-  protocol->store(buf,system_charset_info);
-  protocol->write();
-
-  my_snprintf(buf,sizeof(buf)," total        %-8lu bytes", (unsigned long)info.total_size);
-  protocol->prepare_for_resend();
-  protocol->store(buf,system_charset_info);
-  protocol->write();
-
-  send_eof(thd);
-  DBUG_RETURN(0);
-}
-
-inline
-bool send_summary(THD *thd, const Backup_info &info)
-{ return send_summary(thd,info,TRUE); }
-
-inline
-bool send_summary(THD *thd, const Restore_info &info)
-{ return send_summary(thd,info,FALSE); }
-
-
-/// Open given table in @c INFORMATION_SCHEMA database.
-TABLE* get_schema_table(THD *thd, ST_SCHEMA_TABLE *st)
-{
-  TABLE *t;
-  TABLE_LIST arg;
-  my_bitmap_map *old_map;
-
-  bzero( &arg, sizeof(TABLE_LIST) );
-
-  // set context for create_schema_table call
-  arg.schema_table= st;
-  arg.alias=        NULL;
-  arg.select_lex=   NULL;
-
-  t= ::create_schema_table(thd,&arg); // Note: callers must free t.
-
-  if( !t ) return NULL; // error!
-
-  /*
-   Temporarily set thd->lex->wild to NULL to keep st->fill_table
-   happy.
-  */
-  String *wild= thd->lex->wild;
-  ::enum_sql_command command= thd->lex->sql_command;
-  
-  thd->lex->wild = NULL;
-  thd->lex->sql_command = enum_sql_command(0);
-
-  // context for fill_table
-  arg.table= t;
-
-  old_map= tmp_use_all_columns(t, t->read_set);
-  
-  /*
-    Question: is it correct to fill I_S table each time we use it or should it
-    be filled only once?
-   */
-  st->fill_table(thd,&arg,NULL);  // NULL = no select condition
-
-  tmp_restore_column_map(t->read_set, old_map);
-  
-  // undo changes to thd->lex
-  thd->lex->wild= wild;
-  thd->lex->sql_command= command;
-
-  return t;
-}
-
-/// Build linked @c TABLE_LIST list from a list stored in @c Table_list object.
-
-/*
-  FIXME: build list with the same order as in input
-  Actually, should work fine with reversed list as long as we use the reversed
-  list both in table writing and reading.
- */
-TABLE_LIST *build_table_list(const Table_list &tables, thr_lock_type lock)
-{
-  TABLE_LIST *tl= NULL;
-
-  for( uint tno=0; tno < tables.count() ; tno++ )
-  {
-    TABLE_LIST *ptr= (TABLE_LIST*)my_malloc(sizeof(TABLE_LIST), MYF(MY_WME));
-    DBUG_ASSERT(ptr);  // FIXME: report error instead
-    bzero(ptr,sizeof(TABLE_LIST));
-
-    Table_ref tbl= tables[tno];
-
-    ptr->alias= ptr->table_name= const_cast<char*>(tbl.name().ptr());
-    ptr->db= const_cast<char*>(tbl.db().name().ptr());
-    ptr->lock_type= lock;
-
-    // and add it to the list
-
-    ptr->next_global= ptr->next_local=
-      ptr->next_name_resolution_table= tl;
-    tl= ptr;
-    tl->table= ptr->table;
-  }
-
-  return tl;
-}
-
-} // backup namespace
Thread
bk commit into 6.0 tree (rafal:1.2667) WL#4060rsomla21 Nov
  • RE: bk commit into 6.0 tree (rafal:1.2667) WL#4060Chuck Bell28 Nov
    • Re: bk commit into 6.0 tree (rafal:1.2667) WL#4060Rafal Somla29 Nov
      • RE: bk commit into 6.0 tree (rafal:1.2667) WL#4060Chuck Bell29 Nov