/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifndef NdbDictionary_H
#define NdbDictionary_H

#include <ndb_types.h>

class Ndb;
struct charset_info_st;
typedef struct charset_info_st CHARSET_INFO;

/**
 * @class NdbDictionary
 * @brief Data dictionary class
 * 
 * The preferred and supported way to create and drop tables and indexes
 * in ndb is through the 
 * MySQL Server (see MySQL reference Manual, section MySQL Cluster).
 *
 * Tables and indexes that are created directly through the 
 * NdbDictionary class
 * can not be viewed from the MySQL Server.
 * Dropping indexes directly via the NdbApi will cause inconsistencies
 * if they were originally created from a MySQL Cluster.
 * 
 * This class supports schema data enquiries such as:
 * -# Enquiries about tables
 *    (Dictionary::getTable, Table::getNoOfColumns, 
 *    Table::getPrimaryKey, and Table::getNoOfPrimaryKeys)
 * -# Enquiries about indexes
 *    (Dictionary::getIndex, Index::getNoOfColumns, 
 *    and Index::getColumn)
 *
 * This class supports schema data definition such as:
 * -# Creating tables (Dictionary::createTable) and table columns
 * -# Dropping tables (Dictionary::dropTable)
 * -# Creating secondary indexes (Dictionary::createIndex)
 * -# Dropping secondary indexes (Dictionary::dropIndex)
 *
 * NdbDictionary has several help (inner) classes to support this:
 * -# NdbDictionary::Dictionary the dictionary handling dictionary objects
 * -# NdbDictionary::Table for creating tables
 * -# NdbDictionary::Column for creating table columns
 * -# NdbDictionary::Index for creating secondary indexes
 *
 * See @ref ndbapi_simple_index.cpp for details of usage.
 */
class NdbDictionary {
public:
  NdbDictionary() {}                          /* Remove gcc warning */
  /**
   * @class Object
   * @brief Meta information about a database object (a table, index, etc)
   */
  class Object {
  public:
    Object() {}                               /* Remove gcc warning */
    virtual ~Object() {}                      /* Remove gcc warning */
    /**
     * Status of object
     */
    enum Status {
      New,                    ///< The object only exist in memory and 
                              ///< has not been created in the NDB Kernel
      Changed,                ///< The object has been modified in memory 
                              ///< and has to be commited in NDB Kernel for 
                              ///< changes to take effect
      Retrieved,              ///< The object exist and has been read 
                              ///< into main memory from NDB Kernel
      Invalid,                ///< The object has been invalidated
                              ///< and should not be used
      Altered                 ///< Table has been altered in NDB kernel
                              ///< but is still valid for usage
    };

    /**
     * Get status of object
     */
    virtual Status getObjectStatus() const = 0;

    /**
     * Get version of object
     */
    virtual int getObjectVersion() const = 0;
    
    virtual int getObjectId() const = 0;
    
    /**
     * Object type
     */
    enum Type {
      TypeUndefined = 0,      ///< Undefined
      SystemTable = 1,        ///< System table
      UserTable = 2,          ///< User table (may be temporary)
      UniqueHashIndex = 3,    ///< Unique un-ordered hash index
      OrderedIndex = 6,       ///< Non-unique ordered index
      HashIndexTrigger = 7,   ///< Index maintenance, internal
      IndexTrigger = 8,       ///< Index maintenance, internal
      SubscriptionTrigger = 9,///< Backup or replication, internal
      ReadOnlyConstraint = 10,///< Trigger, internal
      Tablespace = 20,        ///< Tablespace
      LogfileGroup = 21,      ///< Logfile group
      Datafile = 22,          ///< Datafile
      Undofile = 23           ///< Undofile
    };

    /**
     * Object state
     */
    enum State {
      StateUndefined = 0,     ///< Undefined
      StateOffline = 1,       ///< Offline, not usable
      StateBuilding = 2,      ///< Building, not yet usable
      StateDropping = 3,      ///< Offlining or dropping, not usable
      StateOnline = 4,        ///< Online, usable
      StateBackup = 5,        ///< Online, being backuped, usable
      StateBroken = 9         ///< Broken, should be dropped and re-created
    };

    /**
     * Object store
     */
    enum Store {
      StoreUndefined = 0,     ///< Undefined
      StoreTemporary = 1,     ///< Object or data deleted on system restart
      StorePermanent = 2      ///< Permanent. logged to disk
    };

    /**
     * Type of fragmentation.
     *
     * This parameter specifies how data in the table or index will
     * be distributed among the db nodes in the cluster.<br>
     * The bigger the table the more number of fragments should be used.
     * Note that all replicas count as same "fragment".<br>
     * For a table, default is FragAllMedium.  For a unique hash index,
     * default is taken from underlying table and cannot currently
     * be changed.
     */
    enum FragmentType { 
      FragUndefined = 0,      ///< Fragmentation type undefined or default
      FragSingle = 1,         ///< Only one fragment
      FragAllSmall = 2,       ///< One fragment per node, default
      FragAllMedium = 3,      ///< two fragments per node
      FragAllLarge = 4,       ///< Four fragments per node.
      DistrKeyHash = 5,
      DistrKeyLin = 6,
      UserDefined = 7
    };
  };

  class Dictionary; // Forward declaration
  
  class ObjectId : public Object 
  {
  public:
    ObjectId();
    virtual ~ObjectId();
    
    /**
     * Get status of object
     */
    virtual Status getObjectStatus() const;
    
    /**
     * Get version of object
     */
    virtual int getObjectVersion() const;
    
    virtual int getObjectId() const;
    
  private:
    friend class NdbDictObjectImpl;
    class NdbDictObjectImpl & m_impl;
  };
  
  class Table; // forward declaration
  class Tablespace; // forward declaration
//  class NdbEventOperation; // forward declaration

  /**
   * @class Column
   * @brief Represents a column in an NDB Cluster table
   *
   * Each column has a type. The type of a column is determined by a number 
   * of type specifiers.
   * The type specifiers are:
   * - Builtin type
   * - Array length or max length
   * - Precision and scale (not used yet)
   * - Character set for string types
   * - Inline and part sizes for blobs
   *
   * Types in general correspond to MySQL types and their variants.
   * Data formats are same as in MySQL.  NDB API provides no support for
   * constructing such formats.  NDB kernel checks them however.
   */
  class Column {
  public:
    /**
     * The builtin column types
     */
    enum Type {
      Undefined = NDB_TYPE_UNDEFINED,   ///< Undefined 
      Tinyint = NDB_TYPE_TINYINT,       ///< 8 bit. 1 byte signed integer, can be used in array
      Tinyunsigned = NDB_TYPE_TINYUNSIGNED,  ///< 8 bit. 1 byte unsigned integer, can be used in array
      Smallint = NDB_TYPE_SMALLINT,      ///< 16 bit. 2 byte signed integer, can be used in array
      Smallunsigned = NDB_TYPE_SMALLUNSIGNED, ///< 16 bit. 2 byte unsigned integer, can be used in array
      Mediumint = NDB_TYPE_MEDIUMINT,     ///< 24 bit. 3 byte signed integer, can be used in array
      Mediumunsigned = NDB_TYPE_MEDIUMUNSIGNED,///< 24 bit. 3 byte unsigned integer, can be used in array
      Int = NDB_TYPE_INT,           ///< 32 bit. 4 byte signed integer, can be used in array
      Unsigned = NDB_TYPE_UNSIGNED,      ///< 32 bit. 4 byte unsigned integer, can be used in array
      Bigint = NDB_TYPE_BIGINT,        ///< 64 bit. 8 byte signed integer, can be used in array
      Bigunsigned = NDB_TYPE_BIGUNSIGNED,   ///< 64 Bit. 8 byte signed integer, can be used in array
      Float = NDB_TYPE_FLOAT,         ///< 32-bit float. 4 bytes float, can be used in array
      Double = NDB_TYPE_DOUBLE,        ///< 64-bit float. 8 byte float, can be used in array
      Olddecimal = NDB_TYPE_OLDDECIMAL,    ///< MySQL < 5.0 signed decimal,  Precision, Scale
      Olddecimalunsigned = NDB_TYPE_OLDDECIMALUNSIGNED,
      Decimal = NDB_TYPE_DECIMAL,    ///< MySQL >= 5.0 signed decimal,  Precision, Scale
      Decimalunsigned = NDB_TYPE_DECIMALUNSIGNED,
      Char = NDB_TYPE_CHAR,          ///< Len. A fixed array of 1-byte chars
      Varchar = NDB_TYPE_VARCHAR,       ///< Length bytes: 1, Max: 255
      Binary = NDB_TYPE_BINARY,        ///< Len
      Varbinary = NDB_TYPE_VARBINARY,     ///< Length bytes: 1, Max: 255
      Datetime = NDB_TYPE_DATETIME,    ///< Precision down to 1 sec (sizeof(Datetime) == 8 bytes )
      Date = NDB_TYPE_DATE,            ///< Precision down to 1 day(sizeof(Date) == 4 bytes )
      Blob = NDB_TYPE_BLOB,        ///< Binary large object (see NdbBlob)
      Text = NDB_TYPE_TEXT,         ///< Text blob
      Bit = NDB_TYPE_BIT,          ///< Bit, length specifies no of bits
      Longvarchar = NDB_TYPE_LONGVARCHAR,  ///< Length bytes: 2, little-endian
      Longvarbinary = NDB_TYPE_LONGVARBINARY, ///< Length bytes: 2, little-endian
      Time = NDB_TYPE_TIME,        ///< Time without date
      Year = NDB_TYPE_YEAR,   ///< Year 1901-2155 (1 byte)
      Timestamp = NDB_TYPE_TIMESTAMP  ///< Unix time
    };

    /*
     * Array type specifies internal attribute format.
     *
     * - ArrayTypeFixed is stored as fixed number of bytes.  This type
     *   is fastest to access but can waste space.
     *
     * - ArrayTypeVar is stored as variable number of bytes with a fixed
     *   overhead of 2 bytes.
     *
     * Default is ArrayTypeVar for Var* types and ArrayTypeFixed for
     * others.  The default is normally ok.
     */
    enum ArrayType {
      ArrayTypeFixed = NDB_ARRAYTYPE_FIXED,          // 0 length bytes
      ArrayTypeShortVar = NDB_ARRAYTYPE_SHORT_VAR,   // 1 length bytes
      ArrayTypeMediumVar = NDB_ARRAYTYPE_MEDIUM_VAR // 2 length bytes
    };

    /*
     * Storage type specifies whether attribute is stored in memory or
     * on disk.  Default is memory.  Disk attributes are potentially
     * much slower to access and cannot be indexed in version 5.1.
     */
    enum StorageType {
      StorageTypeMemory = NDB_STORAGETYPE_MEMORY,
      StorageTypeDisk = NDB_STORAGETYPE_DISK
    };

    /** 
     * @name General 
     * @{
     */
    
    /**
     * Get name of column
     * @return  Name of the column
     */
    const char* getName() const;

    /**
     * Get if the column is nullable or not
     */
    bool getNullable() const;
    
    /**
     * Check if column is part of primary key
     */
    bool getPrimaryKey() const;

    /**
     *  Get number of column (horizontal position within table)
     */
    int getColumnNo() const;

#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    int getAttrId() const;
#endif

    /**
     * Check if column is equal to some other column
     * @param  column  Column to compare with
     * @return  true if column is equal to some other column otherwise false.
     */
    bool equal(const Column& column) const;


    /** @} *******************************************************************/
    /** 
     * @name Get Type Specifiers
     * @{
     */

    /**
     * Get type of column
     */
    Type getType() const;

    /**
     * Get precision of column.
     * @note Only applicable for decimal types
     */
    int getPrecision() const;

    /**
     * Get scale of column.
     * @note Only applicable for decimal types
     */
    int getScale() const;

    /**
     * Get length for column
     * Array length for column or max length for variable length arrays.
     */
    int getLength() const;

    /**
     * For Char or Varchar or Text, get MySQL CHARSET_INFO.  This
     * specifies both character set and collation.  See get_charset()
     * etc in MySQL.  (The cs is not "const" in MySQL).
     */
    CHARSET_INFO* getCharset() const;


    /**
     * For blob, get "inline size" i.e. number of initial bytes
     * to store in table's blob attribute.  This part is normally in
     * main memory and can be indexed and interpreted.
     */
    int getInlineSize() const;

    /**
     * For blob, get "part size" i.e. number of bytes to store in
     * each tuple of the "blob table".  Can be set to zero to omit parts
     * and to allow only inline bytes ("tinyblob").
     */
    int getPartSize() const;

    /**
     * For blob, set or get "stripe size" i.e. number of consecutive
     * <em>parts</em> to store in each node group.
     */
    int getStripeSize() const;

    /**
     * Get size of element
     */
    int getSize() const;

    /** 
     * Check if column is part of partition key
     *
     * A <em>partition key</em> is a set of attributes which are used
     * to distribute the tuples onto the NDB nodes.
     * The partition key uses the NDB Cluster hashing function.
     *
     * An example where this is useful is TPC-C where it might be
     * good to use the warehouse id and district id as the partition key. 
     * This would place all data for a specific district and warehouse 
     * in the same database node.
     *
     * Locally in the fragments the full primary key 
     * will still be used with the hashing algorithm.
     *
     * @return  true then the column is part of 
     *                 the partition key.
     */
    bool getPartitionKey() const;
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
    inline bool getDistributionKey() const { return getPartitionKey(); };
#endif

    ArrayType getArrayType() const;
    StorageType getStorageType() const;

    /** @} *******************************************************************/


    /** 
     * @name Column creation
     * @{
     *
     * These operations should normally not be performed in an NbdApi program
     * as results will not be visable in the MySQL Server
     * 
     */

    /**
     * Constructor
     * @param   name   Name of column
     */
    Column(const char * name = "");
    /**
     * Copy constructor
     * @param  column  Column to be copied
     */
    Column(const Column& column); 
    ~Column();

    /**
     * Set name of column
     * @param  name  Name of the column
     */
    void setName(const char * name);

    /**
     * Set whether column is nullable or not
     */
    void setNullable(bool);

    /**
     * Set that column is part of primary key
     */
    void setPrimaryKey(bool);

    /**
     * Set type of column
     * @param  type  Type of column
     *
     * @note setType resets <em>all</em> column attributes
     *       to (type dependent) defaults and should be the first
     *       method to call.  Default type is Unsigned.
     */
    void setType(Type type);

    /**
     * Set precision of column.
     * @note Only applicable for decimal types
     */
    void setPrecision(int);

    /**
     * Set scale of column.
     * @note Only applicable for decimal types
     */
    void setScale(int);

    /**
     * Set length for column
     * Array length for column or max length for variable length arrays.
     */
    void setLength(int length);

    /**
     * For Char or Varchar or Text, get MySQL CHARSET_INFO.  This
     * specifies both character set and collation.  See get_charset()
     * etc in MySQL.  (The cs is not "const" in MySQL).
     */
    void setCharset(CHARSET_INFO* cs);

    /**
     * For blob, get "inline size" i.e. number of initial bytes
     * to store in table's blob attribute.  This part is normally in
     * main memory and can be indexed and interpreted.
     */
    void setInlineSize(int size);

    /**
     * For blob, get "part size" i.e. number of bytes to store in
     * each tuple of the "blob table".  Can be set to zero to omit parts
     * and to allow only inline bytes ("tinyblob").
     */
    void setPartSize(int size);

    /**
     * For blob, get "stripe size" i.e. number of consecutive
     * <em>parts</em> to store in each node group.
     */
    void setStripeSize(int size);

    /** 
     * Set partition key
     * @see getPartitionKey
     *
     * @param  enable  If set to true, then the column will be part of 
     *                 the partition key.
     */
    void setPartitionKey(bool enable);
#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
    inline void setDistributionKey(bool enable)
    { setPartitionKey(enable); };
#endif

    void setArrayType(ArrayType type);
    void setStorageType(StorageType type);

    /** @} *******************************************************************/

#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    const Table * getBlobTable() const;

    void setAutoIncrement(bool);
    bool getAutoIncrement() const;
    void setAutoIncrementInitialValue(Uint64 val);
    void setDefaultValue(const char*);   
    const char* getDefaultValue() const;

    static const Column * FRAGMENT;
    static const Column * FRAGMENT_FIXED_MEMORY;
    static const Column * FRAGMENT_VARSIZED_MEMORY;
    static const Column * ROW_COUNT;
    static const Column * COMMIT_COUNT;
    static const Column * ROW_SIZE;
    static const Column * RANGE_NO;
    static const Column * DISK_REF;
    static const Column * RECORDS_IN_RANGE;
    static const Column * ROWID;
    static const Column * ROW_GCI;
    
    int getSizeInBytes() const;
#endif
    
  private:
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    friend class NdbRecAttr;
    friend class NdbColumnImpl;
#endif
    class NdbColumnImpl & m_impl;
    Column(NdbColumnImpl&);
    Column& operator=(const Column&);
  };

#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
  /**
   * ???
   */
  typedef Column Attribute;
#endif
  
  /**
   * @brief Represents a table in NDB Cluster
   *
   * <em>TableSize</em><br>
   * When calculating the data storage one should add the size of all 
   * attributes (each attributeconsumes at least 4 bytes) and also an overhead
   * of 12 byte. Variable size attributes (not supported yet) will have a 
   * size of 12 bytes plus the actual data storage parts where there is an 
   * additional overhead based on the size of the variable part.<br>
   * An example table with 5 attributes: 
   * one 64 bit attribute, one 32 bit attribute, 
   * two 16 bit attributes and one array of 64 8 bits. 
   * This table will consume 
   * 12 (overhead) + 8 + 4 + 2*4 (4 is minimum) + 64 = 96 bytes per record.
   * Additionally an overhead of about 2 % as page headers and waste should 
   * be allocated. Thus, 1 million records should consume 96 MBytes
   * plus the overhead 2 MByte and rounded up to 100 000 kBytes.<br>
   *
   */
  class Table : public Object {
  public:
    /** 
     * @name General
     * @{
     */

    /**
     * Get table name
     */
    const char * getName() const;

    /**
     * Get table id
     */ 
    int getTableId() const;
    
    /**
     * Get column definition via name.
     * @return null if none existing name
     */
    const Column* getColumn(const char * name) const;
    
    /**
     * Get column definition via index in table.
     * @return null if none existing name
     */
    Column* getColumn(const int attributeId);

    /**
     * Get column definition via name.
     * @return null if none existing name
     */
    Column* getColumn(const char * name);
    
    /**
     * Get column definition via index in table.
     * @return null if none existing name
     */
    const Column* getColumn(const int attributeId) const;
    
    /** @} *******************************************************************/
    /**
     * @name Storage
     * @{
     */

    /**
     * If set to false, then the table is a temporary 
     * table and is not logged to disk.
     *
     * In case of a system restart the table will still
     * be defined and exist but will be empty. 
     * Thus no checkpointing and no logging is performed on the table.
     *
     * The default value is true and indicates a normal table 
     * with full checkpointing and logging activated.
     */
    bool getLogging() const;

    /**
     * Get fragmentation type
     */
    FragmentType getFragmentType() const;
    
    /**
     * Get KValue (Hash parameter.)
     * Only allowed value is 6.
     * Later implementations might add flexibility in this parameter.
     */
    int getKValue() const;

    /**
     * Get MinLoadFactor  (Hash parameter.)
     * This value specifies the load factor when starting to shrink 
     * the hash table. 
     * It must be smaller than MaxLoadFactor.
     * Both these factors are given in percentage.
     */
    int getMinLoadFactor() const;

    /**
     * Get MaxLoadFactor  (Hash parameter.)
     * This value specifies the load factor when starting to split 
     * the containers in the local hash tables. 
     * 100 is the maximum which will optimize memory usage.
     * A lower figure will store less information in each container and thus
     * find the key faster but consume more memory.
     */
    int getMaxLoadFactor() const;

    /** @} *******************************************************************/
    /** 
     * @name Other
     * @{
     */
    
    /**
     * Get number of columns in the table
     */
    int getNoOfColumns() const;
    
    /**
     * Get number of primary keys in the table
     */
    int getNoOfPrimaryKeys() const;

    /**
     * Get name of primary key 
     */
    const char* getPrimaryKey(int no) const;
    
    /**
     * Check if table is equal to some other table
     */
    bool equal(const Table&) const;

    /**
     * Get frm file stored with this table
     */
    const void* getFrmData() const;
    Uint32 getFrmLength() const;

    /**
     * Get Fragment Data (id, state and node group)
     */
    const void *getFragmentData() const;
    Uint32 getFragmentDataLen() const;

    /**
     * Get Range or List Array (value, partition)
     */
    const void *getRangeListData() const;
    Uint32 getRangeListDataLen() const;

    /**
     * Get Tablespace Data (id, version)
     */
    const void *getTablespaceData() const;
    Uint32 getTablespaceDataLen() const;

    /** @} *******************************************************************/

    /** 
     * @name Table creation
     * @{
     *
     * These methods should normally not be used in an application as
     * the result is not accessible from the MySQL Server
     *
     */

    /**
     * Constructor
     * @param  name   Name of table
     */
    Table(const char * name = "");

    /** 
     * Copy constructor 
     * @param  table  Table to be copied
     */
    Table(const Table& table); 
    virtual ~Table();
    
    /**
     * Assignment operator, deep copy
     * @param  table  Table to be copied
     */
    Table& operator=(const Table& table);

    /**
     * Name of table
     * @param  name  Name of table
     */
    void setName(const char * name);

    /**
     * Add a column definition to a table
     * @note creates a copy
     */
    void addColumn(const Column &);
    
    /**
     * @see NdbDictionary::Table::getLogging.
     */
    void setLogging(bool); 
  
    /**
     * Set/Get Linear Hash Flag
     */ 
    void setLinearFlag(Uint32 flag);
    bool getLinearFlag() const;

    /**
     * Set fragment count
     */
    void setFragmentCount(Uint32);

    /**
     * Get fragment count
     */
    Uint32 getFragmentCount() const;

    /**
     * Set fragmentation type
     */
    void setFragmentType(FragmentType);

    /**
     * Set KValue (Hash parameter.)
     * Only allowed value is 6.
     * Later implementations might add flexibility in this parameter.
     */
    void setKValue(int kValue);
    
    /**
     * Set MinLoadFactor  (Hash parameter.)
     * This value specifies the load factor when starting to shrink 
     * the hash table. 
     * It must be smaller than MaxLoadFactor.
     * Both these factors are given in percentage.
     */
    void setMinLoadFactor(int);

    /**
     * Set MaxLoadFactor  (Hash parameter.)
     * This value specifies the load factor when starting to split 
     * the containers in the local hash tables. 
     * 100 is the maximum which will optimize memory usage.
     * A lower figure will store less information in each container and thus
     * find the key faster but consume more memory.
     */
    void setMaxLoadFactor(int);

    void setTablespace(const char * name);
    void setTablespace(const class Tablespace &);
    const char * getTablespace() const;
    bool getTablespace(Uint32 *id= 0, Uint32 *version= 0) const;

    /**
     * Get table object type
     */
    Object::Type getObjectType() const;

    /**
     * Get object status
     */
    virtual Object::Status getObjectStatus() const;
    void setStatusInvalid() const;

    /**
     * Get object version
     */
    virtual int getObjectVersion() const;

    /**
     * Set/Get indicator if default number of partitions is used in table.
     */
    void setDefaultNoPartitionsFlag(Uint32 indicator);
    Uint32 getDefaultNoPartitionsFlag() const;
   
    /**
     * Get object id
     */
    virtual int getObjectId() const;

    /**
     * Set frm file to store with this table
     */ 
    void setFrm(const void* data, Uint32 len);

    /**
     * Set array of fragment information containing
     * Fragment Identity
     * Node group identity
     * Fragment State
     */
    void setFragmentData(const void* data, Uint32 len);

    /**
     * Set/Get tablespace names per fragment
     */
    void setTablespaceNames(const void* data, Uint32 len);
    const void *getTablespaceNames();
    Uint32 getTablespaceNamesLen() const;

    /**
     * Set tablespace information per fragment
     * Contains a tablespace id and a tablespace version
     */
    void setTablespaceData(const void* data, Uint32 len);

    /**
     * Set array of information mapping range values and list values
     * to fragments. This is essentially a sorted map consisting of
     * pairs of value, fragment identity. For range partitions there is
     * one pair per fragment. For list partitions it could be any number
     * of pairs, at least as many as there are fragments.
     */
    void setRangeListData(const void* data, Uint32 len);

    /**
     * Set table object type
     */
    void setObjectType(Object::Type type);

    /**
     * Set/Get Maximum number of rows in table (only used to calculate
     * number of partitions).
     */
    void setMaxRows(Uint64 maxRows);
    Uint64 getMaxRows() const;

    /**
     * Set/Get Minimum number of rows in table (only used to calculate
     * number of partitions).
     */
    void setMinRows(Uint64 minRows);
    Uint64 getMinRows() const;

    /** @} *******************************************************************/

    /**
     * 
     */
    void setRowGCIIndicator(bool value);
    bool getRowGCIIndicator() const;

    void setRowChecksumIndicator(bool value);
    bool getRowChecksumIndicator() const;
 
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    const char *getMysqlName() const;

    void setStoredTable(bool x) { setLogging(x); }
    bool getStoredTable() const { return getLogging(); }

    int getRowSizeInBytes() const ;
    int createTableInDb(Ndb*, bool existingEqualIsOk = true) const ;

    int getReplicaCount() const ;
#endif

  private:
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    friend class Ndb;
    friend class NdbDictionaryImpl;
    friend class NdbTableImpl;
    friend class NdbEventOperationImpl;
#endif
    class NdbTableImpl & m_impl;
    Table(NdbTableImpl&);
  };
  
  /**
   * @class Index
   * @brief Represents an index in an NDB Cluster
   */
  class Index : public Object {
  public:
    
    /** 
     * @name Getting Index properties
     * @{
     */

    /**
     * Get the name of an index
     */
    const char * getName() const;
    
    /**
     * Get the name of the table being indexed
     */
    const char * getTable() const;
    
    /**
     * Get the number of columns in the index
     */
    unsigned getNoOfColumns() const;

#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
    /**
     * Get the number of columns in the index
     * Depricated, use getNoOfColumns instead.
     */
    int getNoOfIndexColumns() const;
#endif

    /**
     * Get a specific column in the index
     */
    const Column * getColumn(unsigned no) const ;

#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
    /**
     * Get a specific column name in the index
     * Depricated, use getColumn instead.
     */
    const char * getIndexColumn(int no) const ;
#endif

    /**
     * Represents type of index
     */
    enum Type {
      Undefined = 0,          ///< Undefined object type (initial value)
      UniqueHashIndex = 3,    ///< Unique un-ordered hash index 
                              ///< (only one currently supported)
      OrderedIndex = 6        ///< Non-unique ordered index
    };

    /**
     * Get index type of the index
     */
    Type getType() const;
    
    /**
     * Check if index is set to be stored on disk
     *
     * @return if true then logging id enabled
     *
     * @note Non-logged indexes are rebuilt at system restart.
     * @note Ordered index does not currently support logging.
     */
    bool getLogging() const;

    /**
     * Get object status
     */
    virtual Object::Status getObjectStatus() const;

    /**
     * Get object version
     */
    virtual int getObjectVersion() const;

    /**
     * Get object id
     */
    virtual int getObjectId() const;

    /** @} *******************************************************************/

    /** 
     * @name Index creation
     * @{
     *
     * These methods should normally not be used in an application as
     * the result will not be visible from the MySQL Server
     *
     */

    /**
     *  Constructor
     *  @param  name  Name of index
     */
    Index(const char * name = "");
    virtual ~Index();

    /**
     * Set the name of an index
     */
    void setName(const char * name);

    /**
     * Define the name of the table to be indexed
     */
    void setTable(const char * name);

    /**
     * Add a column to the index definition
     * Note that the order of columns will be in
     * the order they are added (only matters for ordered indexes).
     */
    void addColumn(const Column & c);

    /**
     * Add a column name to the index definition
     * Note that the order of indexes will be in
     * the order they are added (only matters for ordered indexes).
     */
    void addColumnName(const char * name);

#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
    /**
     * Add a column name to the index definition
     * Note that the order of indexes will be in
     * the order they are added (only matters for ordered indexes).
     * Depricated, use addColumnName instead.
     */
    void addIndexColumn(const char * name);
#endif

    /**
     * Add several column names to the index definition
     * Note that the order of indexes will be in
     * the order they are added (only matters for ordered indexes).
     */
    void addColumnNames(unsigned noOfNames, const char ** names);

#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
    /**
     * Add several column names to the index definition
     * Note that the order of indexes will be in
     * the order they are added (only matters for ordered indexes).
     * Depricated, use addColumnNames instead.
     */
    void addIndexColumns(int noOfNames, const char ** names);
#endif

    /**
     * Set index type of the index
     */
    void setType(Type type);

    /**
     * Enable/Disable index storage on disk
     *
     * @param enable  If enable is set to true, then logging becomes enabled
     *
     * @see NdbDictionary::Index::getLogging
     */
    void setLogging(bool enable); 

#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
    void setStoredIndex(bool x) { setLogging(x); }
    bool getStoredIndex() const { return getLogging(); }
#endif
    
    /** @} *******************************************************************/

  private:
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    friend class NdbIndexImpl;
    friend class NdbIndexStat;
#endif
    class NdbIndexImpl & m_impl;
    Index(NdbIndexImpl&);
  };

  /**
   * @brief Represents an Event in NDB Cluster
   *
   */
  class Event : public Object  {
  public:
    /**
     * Specifies the type of database operations an Event listens to
     */
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    /** TableEvent must match 1 << TriggerEvent */
#endif
    enum TableEvent { 
      TE_INSERT      =1<<0, ///< Insert event on table
      TE_DELETE      =1<<1, ///< Delete event on table
      TE_UPDATE      =1<<2, ///< Update event on table
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
      TE_SCAN        =1<<3, ///< Scan event on table
      TE_FIRST_NON_DATA_EVENT =1<<4,
#endif
      TE_DROP        =1<<4, ///< Drop of table
      TE_ALTER       =1<<5, ///< Alter of table
      TE_CREATE      =1<<6, ///< Create of table
      TE_GCP_COMPLETE=1<<7, ///< GCP is complete
      TE_CLUSTER_FAILURE=1<<8, ///< Cluster is unavailable
      TE_STOP        =1<<9, ///< Stop of event operation
      TE_NODE_FAILURE=1<<10, ///< Node failed
      TE_SUBSCRIBE   =1<<11, ///< Node subscribes
      TE_UNSUBSCRIBE =1<<12, ///< Node unsubscribes
      TE_ALL=0xFFFF         ///< Any/all event on table (not relevant when 
                            ///< events are received)
    };
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    enum _TableEvent { 
      _TE_INSERT=0,
      _TE_DELETE=1,
      _TE_UPDATE=2,
      _TE_SCAN=3,
      _TE_FIRST_NON_DATA_EVENT=4,
      _TE_DROP=4,
      _TE_ALTER=5,
      _TE_CREATE=6,
      _TE_GCP_COMPLETE=7,
      _TE_CLUSTER_FAILURE=8,
      _TE_STOP=9,
      _TE_NODE_FAILURE=10,
      _TE_SUBSCRIBE=11,
      _TE_UNSUBSCRIBE=12,
      _TE_NUL=13, // internal (e.g. INS o DEL within same GCI)
      _TE_ACTIVE=14 // internal (node becomes active)
    };
#endif
    /**
     *  Specifies the durability of an event
     * (future version may supply other types)
     */
    enum EventDurability { 
      ED_UNDEFINED
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
      = 0
#endif
#if 0 // not supported
      ,ED_SESSION = 1, 
      // Only this API can use it
      // and it's deleted after api has disconnected or ndb has restarted
      
      ED_TEMPORARY = 2
      // All API's can use it,
      // But's its removed when ndb is restarted
#endif
      ,ED_PERMANENT    ///< All API's can use it.
                       ///< It's still defined after a cluster system restart
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
      = 3
#endif
    };

    /**
     * Specifies reporting options for table events
     */
    enum EventReport {
      ER_UPDATED = 0,
      ER_ALL = 1, // except not-updated blob inlines
      ER_SUBSCRIBE = 2
    };

    /**
     *  Constructor
     *  @param  name  Name of event
     */
    Event(const char *name);
    /**
     *  Constructor
     *  @param  name  Name of event
     *  @param  table Reference retrieved from NdbDictionary
     */
    Event(const char *name, const NdbDictionary::Table& table);
    virtual ~Event();
    /**
     * Set unique identifier for the event
     */
    void setName(const char *name);
    /**
     * Get unique identifier for the event
     */
    const char *getName() const;
    /**
     * Get table that the event is defined on
     *
     * @return pointer to table or NULL if no table has been defined
     */
    const NdbDictionary::Table * getTable() const;
    /**
     * Define table on which events should be detected
     *
     * @note calling this method will default to detection
     *       of events on all columns. Calling subsequent
     *       addEventColumn calls will override this.
     *
     * @param table reference retrieved from NdbDictionary
     */
    void setTable(const NdbDictionary::Table& table);
    /**
     * Set table for which events should be detected
     *
     * @note preferred way is using setTable(const NdbDictionary::Table&)
     *       or constructor with table object parameter
     */
    void setTable(const char *tableName);
    /**
     * Get table name for events
     *
     * @return table name
     */
    const char* getTableName() const;
    /**
     * Add type of event that should be detected
     */
    void addTableEvent(const TableEvent te);
    /**
     * Check if a specific table event will be detected
     */
    bool getTableEvent(const TableEvent te) const;
    /**
     * Set durability of the event
     */
    void setDurability(EventDurability);
    /**
     * Get durability of the event
     */
    EventDurability getDurability() const;
    /**
     * Set report option of the event
     */
    void setReport(EventReport);
    /**
     * Get report option of the event
     */
    EventReport getReport() const;
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    void addColumn(const Column &c);
#endif
    /**
     * Add a column on which events should be detected
     *
     * @param attrId Column id
     *
     * @note errors will mot be detected until createEvent() is called
     */
    void addEventColumn(unsigned attrId);
    /**
     * Add a column on which events should be detected
     *
     * @param columnName Column name
     *
     * @note errors will not be detected until createEvent() is called
     */
    void addEventColumn(const char * columnName);
    /**
     * Add several columns on which events should be detected
     *
     * @param n Number of columns
     * @param columnNames Column names
     *
     * @note errors will mot be detected until 
     *       NdbDictionary::Dictionary::createEvent() is called
     */
    void addEventColumns(int n, const char ** columnNames);

    /**
     * Get no of columns defined in an Event
     *
     * @return Number of columns, -1 on error
     */
    int getNoOfEventColumns() const;

    /**
     * Get a specific column in the event
     */
    const Column * getEventColumn(unsigned no) const;

    /**
     * The merge events flag is false by default.  Setting it true
     * implies that events are merged in following ways:
     *
     * - for given NdbEventOperation associated with this event,
     *   events on same PK within same GCI are merged into single event
     *
     * - a blob table event is created for each blob attribute
     *   and blob events are handled as part of main table events
     *
     * - blob post/pre data from the blob part events can be read
     *   via NdbBlob methods as a single value
     *
     * NOTE: Currently this flag is not inherited by NdbEventOperation
     * and must be set on NdbEventOperation explicitly.
     */
    void mergeEvents(bool flag);

    /**
     * Get object status
     */
    virtual Object::Status getObjectStatus() const;

    /**
     * Get object version
     */
    virtual int getObjectVersion() const;

    /**
     * Get object id
     */
    virtual int getObjectId() const;

#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    void print();
#endif

  private:
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    friend class NdbEventImpl;
    friend class NdbEventOperationImpl;
#endif
    class NdbEventImpl & m_impl;
    Event(NdbEventImpl&);
  };

  struct AutoGrowSpecification {
    Uint32 min_free;
    Uint64 max_size;
    Uint64 file_size;
    const char * filename_pattern;
  };

  /**
   * @class LogfileGroup
   */
  class LogfileGroup : public Object {
  public:
    LogfileGroup();
    LogfileGroup(const LogfileGroup&);
    virtual ~LogfileGroup();

    void setName(const char * name);
    const char* getName() const;

    void setUndoBufferSize(Uint32 sz);
    Uint32 getUndoBufferSize() const;
    
    void setAutoGrowSpecification(const AutoGrowSpecification&);
    const AutoGrowSpecification& getAutoGrowSpecification() const;

    Uint64 getUndoFreeWords() const;

    /**
     * Get object status
     */
    virtual Object::Status getObjectStatus() const;

    /**
     * Get object version
     */
    virtual int getObjectVersion() const;

    /**
     * Get object id
     */
    virtual int getObjectId() const;

  private:
    friend class NdbDictionaryImpl;
    friend class NdbLogfileGroupImpl;
    class NdbLogfileGroupImpl & m_impl;
    LogfileGroup(NdbLogfileGroupImpl&);
  };

  /**
   * @class Tablespace
   */
  class Tablespace : public Object {
  public:
    Tablespace();
    Tablespace(const Tablespace&);
    virtual ~Tablespace();

    void setName(const char * name);
    const char* getName() const;

    void setExtentSize(Uint32 sz);
    Uint32 getExtentSize() const;

    void setAutoGrowSpecification(const AutoGrowSpecification&);
    const AutoGrowSpecification& getAutoGrowSpecification() const;

    void setDefaultLogfileGroup(const char * name);
    void setDefaultLogfileGroup(const class LogfileGroup&);

    const char * getDefaultLogfileGroup() const;
    Uint32 getDefaultLogfileGroupId() const;
    
    /**
     * Get object status
     */
    virtual Object::Status getObjectStatus() const;

    /**
     * Get object version
     */
    virtual int getObjectVersion() const;

    /**
     * Get object id
     */
    virtual int getObjectId() const;

  private:
    friend class NdbTablespaceImpl;
    class NdbTablespaceImpl & m_impl;
    Tablespace(NdbTablespaceImpl&);
  };

  class Datafile : public Object {
  public:
    Datafile();
    Datafile(const Datafile&);
    virtual ~Datafile();

    void setPath(const char * name);
    const char* getPath() const;
  
    void setSize(Uint64);
    Uint64 getSize() const;
    Uint64 getFree() const;
    
    void setTablespace(const char * name);
    void setTablespace(const class Tablespace &);
    const char * getTablespace() const;
    void getTablespaceId(ObjectId * dst) const;

    void setNode(Uint32 nodeId);
    Uint32 getNode() const;

    Uint32 getFileNo() const;

    /**
     * Get object status
     */
    virtual Object::Status getObjectStatus() const;

    /**
     * Get object version
     */
    virtual int getObjectVersion() const;

    /**
     * Get object id
     */
    virtual int getObjectId() const;

  private:
    friend class NdbDatafileImpl;
    class NdbDatafileImpl & m_impl;
    Datafile(NdbDatafileImpl&);
  };

  class Undofile : public Object {
  public:
    Undofile();
    Undofile(const Undofile&);
    virtual ~Undofile();

    void setPath(const char * path);
    const char* getPath() const;
  
    void setSize(Uint64);
    Uint64 getSize() const;

    void setLogfileGroup(const char * name);
    void setLogfileGroup(const class LogfileGroup &);
    const char * getLogfileGroup() const;
    void getLogfileGroupId(ObjectId * dst) const;

    void setNode(Uint32 nodeId);
    Uint32 getNode() const;

    Uint32 getFileNo() const;

    /**
     * Get object status
     */
    virtual Object::Status getObjectStatus() const;

    /**
     * Get object version
     */
    virtual int getObjectVersion() const;

    /**
     * Get object id
     */
    virtual int getObjectId() const;

  private:
    friend class NdbUndofileImpl;
    class NdbUndofileImpl & m_impl;
    Undofile(NdbUndofileImpl&);
  };

  /**
   * @class Dictionary
   * @brief Dictionary for defining and retreiving meta data
   */
  class Dictionary {
  public:
    /**
     * @class List
     * @brief Structure for retrieving lists of object names
     */
    struct List {
      /**
       * @struct  Element
       * @brief   Object to be stored in an NdbDictionary::Dictionary::List
       */
      struct Element {
	unsigned id;            ///< Id of object
        Object::Type type;      ///< Type of object
        Object::State state;    ///< State of object
        Object::Store store;    ///< How object is stored
	char * database;        ///< In what database the object resides 
	char * schema;          ///< What schema the object is defined in
	char * name;            ///< Name of object
        Element() :
          id(0),
          type(Object::TypeUndefined),
          state(Object::StateUndefined),
          store(Object::StoreUndefined),
	  database(0),
	  schema(0),
          name(0) {
        }
      };
      unsigned count;           ///< Number of elements in list
      Element * elements;       ///< Pointer to array of elements
      List() : count(0), elements(0) {}
      ~List() {
        if (elements != 0) {
          for (unsigned i = 0; i < count; i++) {
            delete[] elements[i].database;
            delete[] elements[i].schema;
            delete[] elements[i].name;
            elements[i].name = 0;
          }
          delete[] elements;
          count = 0;
          elements = 0;
        }
      }
    };

    /** 
     * @name General
     * @{
     */

    /**
     * Fetch list of all objects, optionally restricted to given type.
     *
     * @param list   List of objects returned in the dictionary
     * @param type   Restrict returned list to only contain objects of
     *               this type
     *
     * @return       -1 if error.
     *
     */
    int listObjects(List & list, Object::Type type = Object::TypeUndefined);
    int listObjects(List & list,
		    Object::Type type = Object::TypeUndefined) const;

    /**
     * Get the latest error
     *
     * @return   Error object.
     */			     
    const struct NdbError & getNdbError() const;

    /** @} *******************************************************************/

    /** 
     * @name Retrieving references to Tables and Indexes
     * @{
     */

    /**
     * Get table with given name, NULL if undefined
     * @param name   Name of table to get
     * @return table if successful otherwise NULL.
     */
    const Table * getTable(const char * name) const;

#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    /**
     * Given main table, get blob table.
     */
    const Table * getBlobTable(const Table *, const char * col_name);
    const Table * getBlobTable(const Table *, Uint32 col_no);

    /*
     * Save a table definition in dictionary cache
     * @param table Object to put into cache
     */
    void putTable(const Table * table);
#endif

    /**
     * Get index with given name, NULL if undefined
     * @param indexName  Name of index to get.
     * @param tableName  Name of table that index belongs to.
     * @return  index if successful, otherwise 0.
     */
    const Index * getIndex(const char * indexName,
			   const char * tableName) const;

    /**
     * Fetch list of indexes of given table.
     * @param list  Reference to list where to store the listed indexes
     * @param tableName  Name of table that index belongs to.
     * @return  0 if successful, otherwise -1
     */
    int listIndexes(List & list, const char * tableName);
    int listIndexes(List & list, const char * tableName) const;

#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    /**
     * Fetch list of indexes of given table.
     * @param list  Reference to list where to store the listed indexes
     * @param table  Reference to table that index belongs to.
     * @return  0 if successful, otherwise -1
     */
    int listIndexes(List & list, const Table &table) const;
#endif

    /** @} *******************************************************************/
    /** 
     * @name Events
     * @{
     */
    
    /**
     * Create event given defined Event instance
     * @param event Event to create
     * @return 0 if successful otherwise -1.
     */
    int createEvent(const Event &event);

    /**
     * Drop event with given name
     * @param eventName  Name of event to drop.
     * @return 0 if successful otherwise -1.
     */
    int dropEvent(const char * eventName);
    
    /**
     * Get event with given name.
     * @param eventName  Name of event to get.
     * @return an Event if successful, otherwise NULL.
     */
    const Event * getEvent(const char * eventName);

    /** @} *******************************************************************/

    /** 
     * @name Table creation
     * @{
     *
     * These methods should normally not be used in an application as
     * the result will not be visible from the MySQL Server
     */

    /**
     * Create defined table given defined Table instance
     * @param table Table to create
     * @return 0 if successful otherwise -1.
     */
    int createTable(const Table &table);

    /**
     * Drop table given retrieved Table instance
     * @param table Table to drop
     * @return 0 if successful otherwise -1.
     */
    int dropTable(Table & table);

    /**
     * Drop table given table name
     * @param name   Name of table to drop 
     * @return 0 if successful otherwise -1.
     */
    int dropTable(const char * name);
    
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    /**
     * Alter defined table given defined Table instance
     * @param table Table to alter
     * @return  -2 (incompatible version) <br>
     *          -1 general error          <br>
     *           0 success                 
     */
    int alterTable(const Table &table);

    /**
     * Invalidate cached table object
     * @param name  Name of table to invalidate
     */
    void invalidateTable(const char * name);
#endif

    /**
     * Remove table from local cache
     */
    void removeCachedTable(const char * table);
    /**
     * Remove index from local cache
     */
    void removeCachedIndex(const char * index, const char * table);

    
    /** @} *******************************************************************/
    /** 
     * @name Index creation
     * @{
     *
     * These methods should normally not be used in an application as
     * the result will not be visible from the MySQL Server
     *
     */
    
    /**
     * Create index given defined Index instance
     * @param index Index to create
     * @return 0 if successful otherwise -1.
     */
    int createIndex(const Index &index);
    int createIndex(const Index &index, const Table &table);

    /**
     * Drop index with given name
     * @param indexName  Name of index to drop.
     * @param tableName  Name of table that index belongs to.
     * @return 0 if successful otherwise -1.
     */
    int dropIndex(const char * indexName,
		  const char * tableName);
    
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    void removeCachedTable(const Table *table);
    void removeCachedIndex(const Index *index);
    void invalidateTable(const Table *table);
    /**
     * Invalidate cached index object
     */
    void invalidateIndex(const char * indexName,
                         const char * tableName);
    void invalidateIndex(const Index *index);
    /**
     * Force gcp and wait for gcp complete
     */
    int forceGCPWait();
#endif

    /** @} *******************************************************************/

    /** @} *******************************************************************/
    /** 
     * @name Disk data objects
     * @{
     */
    
    int createLogfileGroup(const LogfileGroup &, ObjectId* = 0);
    int dropLogfileGroup(const LogfileGroup&);
    LogfileGroup getLogfileGroup(const char * name);

    int createTablespace(const Tablespace &, ObjectId* = 0);
    int dropTablespace(const Tablespace&);
    Tablespace getTablespace(const char * name);
    Tablespace getTablespace(Uint32 tablespaceId);

    int createDatafile(const Datafile &, bool overwrite_existing = false, ObjectId* = 0);
    int dropDatafile(const Datafile&);
    Datafile getDatafile(Uint32 node, const char * path);
    
    int createUndofile(const Undofile &, bool overwrite_existing = false, ObjectId * = 0);
    int dropUndofile(const Undofile&);
    Undofile getUndofile(Uint32 node, const char * path);
    
    /** @} *******************************************************************/
    
  protected:
    Dictionary(Ndb & ndb);
    ~Dictionary();
    
  private:
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    friend class NdbDictionaryImpl;
    friend class UtilTransactions;
    friend class NdbBlob;
#endif
    class NdbDictionaryImpl & m_impl;
    Dictionary(NdbDictionaryImpl&);
    const Table * getIndexTable(const char * indexName, 
				const char * tableName) const;
  public:
#ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
    const Table * getTable(const char * name, void **data) const;
    void set_local_table_data_size(unsigned sz);

    const Index * getIndexGlobal(const char * indexName,
                                 const Table &ndbtab) const;
    const Table * getTableGlobal(const char * tableName) const;
    int alterTableGlobal(const Table &f, const Table &t);
    int dropTableGlobal(const Table &ndbtab);
    int dropIndexGlobal(const Index &index);
    int removeIndexGlobal(const Index &ndbidx, int invalidate) const;
    int removeTableGlobal(const Table &ndbtab, int invalidate) const;
#endif
  };
};

class NdbOut& operator <<(class NdbOut& out, const NdbDictionary::Column& col);

#endif