Skip to content

File storage_common.h

File List > cubrid > src > storage > storage_common.h

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */


/*
 * storage_common.h - Definitions and data types of disk related stuffs
 *          such as pages, file structures, and so on.
 */

#ifndef _STORAGE_COMMON_H_
#define _STORAGE_COMMON_H_

#ident "$Id$"

#include "config.h"

#include <limits.h>
#include <time.h>
#include <stdio.h>
#include <assert.h>

#include "porting.h"
#include "porting_inline.hpp"
#include "dbtype_def.h"
#include "sha1.h"
#include "cache_time.h"

  /* LIMITS AND NULL VALUES ON DISK RELATED DATATYPES */

#define NULL_VOLID  (-1)    /* Value of an invalid volume identifier */
#define NULL_SECTID (-1)    /* Value of an invalid sector identifier */
#define NULL_PAGEID (-1)    /* Value of an invalid page identifier */
#define NULL_SLOTID (-1)    /* Value of an invalid slot identifier */
#define NULL_OFFSET (-1)    /* Value of an invalid offset */
#define NULL_FILEID (-1)    /* Value of an invalid file identifier */

#define VOLID_MAX       SHRT_MAX
#define PAGEID_MAX      INT_MAX
#define SECTID_MAX      INT_MAX
#define PGLENGTH_MAX    SHRT_MAX
#define VOL_MAX_NPAGES(page_size) \
  ((sizeof(off_t) == 4) ? (INT_MAX / (page_size)) : INT_MAX)

#define LOGPAGEID_MAX   0x7fffffffffffLL    /* 6 bytes length */

/* NULL_CHN is a special value for an unspecified cache coherency number.
 * It should only be used in error conditions.  This should never be
 * found as a stored chn in a disk or memory object.
 */
enum
{ NULL_CHN = -1, CHN_UNKNOWN_ATCLIENT = -2 };

/* Type definitions related to disk information */

typedef INT16 VOLID;        /* Volume identifier */
typedef VOLID DKNVOLS;      /* Number of volumes */

typedef INT32 PAGEID;       /* Data page identifier */
typedef PAGEID DKNPAGES;    /* Number of disk pages */

typedef INT64 LOG_PAGEID;   /* Log page identifier */
typedef PAGEID LOG_PHY_PAGEID;  /* physical log page identifier */

typedef INT32 SECTID;
typedef SECTID DKNSECTS;

typedef INT16 PGSLOTID;     /* Page slot identifier */
typedef PGSLOTID PGNSLOTS;  /* Number of slots on a page */
typedef INT16 PGLENGTH;     /* Page length */

typedef PAGEID FILEID;      /* File identifier */
typedef INT32 LOLENGTH;     /* Length for a large object */

/* BOTH IO_PAGESIZE AND DB_PAGESIZE MUST BE MULTIPLE OF sizeof(int) */

#define IO_DEFAULT_PAGE_SIZE    (16 * ONE_K)
#define IO_MIN_PAGE_SIZE        (4 * ONE_K)
#define IO_MAX_PAGE_SIZE        (16 * ONE_K)

extern PGLENGTH db_Io_page_size;
extern PGLENGTH db_Log_page_size;
extern PGLENGTH db_User_page_size;

#define LOG_PAGESIZE            db_Log_page_size
#define IO_PAGESIZE             db_Io_page_size
#define DB_PAGESIZE             db_User_page_size

#define IS_POWER_OF_2(x)        (((x) & ((x) - 1)) == 0)

/*
 * Sector
 */
/* Number of pages in a sector. Careful about changing this size. The whole file manager depends on this size. */
#define DISK_SECTOR_NPAGES 64
#define IO_SECTORSIZE           (DISK_SECTOR_NPAGES * IO_PAGESIZE)
#define DB_SECTORSIZE       (DISK_SECTOR_NPAGES * DB_PAGESIZE)

#define VOL_MAX_NSECTS(page_size)  (VOL_MAX_NPAGES(page_size) / DISK_SECTOR_NPAGES)

#define SECTOR_FIRST_PAGEID(sid) ((sid) * DISK_SECTOR_NPAGES)
#define SECTOR_LAST_PAGEID(sid) ((((sid) + 1) * DISK_SECTOR_NPAGES) - 1)
#define SECTOR_FROM_PAGEID(pageid) ((pageid) / DISK_SECTOR_NPAGES)

#define VSID_FROM_VPID(vsid, vpid) (vsid)->volid = (vpid)->volid; (vsid)->sectid = SECTOR_FROM_PAGEID ((vpid)->pageid)
#define VSID_IS_SECTOR_OF_VPID(vsid, vpid) \
  ((vsid)->volid == (vpid)->volid && (vsid)->sectid == SECTOR_FROM_PAGEID ((vpid)->pageid))

#define DB_MAX_PATH_LENGTH      PATH_MAX

#define DISK_VFID_SIZE (OR_INT_SIZE + OR_SHORT_SIZE)
#define DISK_VPID_SIZE (OR_INT_SIZE + OR_SHORT_SIZE)

#define DISK_VFID_ALIGNED_SIZE (DISK_VFID_SIZE + OR_SHORT_SIZE)
#define DISK_VPID_ALIGNED_SIZE (DISK_VPID_SIZE + OR_SHORT_SIZE)

/* BTREE definitions */

/* Non_Leaf Node Record Size */
#define NON_LEAF_RECORD_SIZE (DISK_VPID_ALIGNED_SIZE)
/* Leaf Node Record Size */
#define LEAF_RECORD_SIZE (0)
#define SPLIT_INFO_SIZE (OR_FLOAT_SIZE + OR_INT_SIZE)

typedef struct btree_node_split_info BTREE_NODE_SPLIT_INFO;
struct btree_node_split_info
{
  float pivot;          /* pivot = split_slot_id / num_keys */
  int index;            /* number of key insert after node split */
};

typedef char *PAGE_PTR;     /* Pointer to a page */

/* TODO - PAGE_TYPE is used for debugging */
typedef enum
{
  PAGE_UNKNOWN = 0,     /* used for initialized page */
  PAGE_FTAB,            /* file allocset table page */
  PAGE_HEAP,            /* heap page */
  PAGE_VOLHEADER,       /* volume header page */
  PAGE_VOLBITMAP,       /* volume bitmap page */
  PAGE_QRESULT,         /* query result page */
  PAGE_EHASH,           /* ehash bucket/dir page */
  PAGE_OVERFLOW,        /* overflow page (with ovf_keyval) */
  PAGE_AREA,            /* area page */
  PAGE_CATALOG,         /* catalog page */
  PAGE_BTREE,           /* b+tree index page (with ovf_OIDs) */
  PAGE_LOG,         /* NONE - log page (unused) */
  PAGE_DROPPED_FILES,       /* Dropped files page.  */
  PAGE_VACUUM_DATA,     /* Vacuum data. */
  PAGE_LAST = PAGE_VACUUM_DATA
} PAGE_TYPE;

/* Index scan OID buffer size as set by system parameter. */
#define ISCAN_OID_BUFFER_SIZE \
  ((((int) (IO_PAGESIZE * prm_get_float_value (PRM_ID_BT_OID_NBUFFERS))) \
    / OR_OID_SIZE) \
    * OR_OID_SIZE)
#define ISCAN_OID_BUFFER_COUNT \
  (ISCAN_OID_BUFFER_SIZE / OR_OID_SIZE)
/* Minimum capacity of OID buffer.
 * It should include at least one overflow page and on b-tree leaf record.
 * It was set to roughly two pages.
 */
#define ISCAN_OID_BUFFER_MIN_CAPACITY (2 * DB_PAGESIZE)
/* OID buffer capacity. It is the maximum value between the size set by
 * system parameter and the minimum required capacity.
 */
#define ISCAN_OID_BUFFER_CAPACITY \
  (MAX (ISCAN_OID_BUFFER_MIN_CAPACITY, ISCAN_OID_BUFFER_SIZE))

typedef UINT64 MVCCID;      /* MVCC ID */



/* File structure identifiers */

typedef struct hfid HFID;   /* FILE HEAP IDENTIFIER */
struct hfid
{
  VFID vfid;            /* Volume and file identifier */
  INT32 hpgid;          /* First page identifier (the header page) */
};
#define HFID_INITIALIZER \
  { VFID_INITIALIZER, NULL_PAGEID }
#define HFID_AS_ARGS(hfid) (hfid)->hpgid, VFID_AS_ARGS (&(hfid)->vfid)

typedef struct btid BTID;   /* B+tree identifier */
struct btid
{
  VFID vfid;            /* B+tree index volume identifier */
  INT32 root_pageid;        /* Root page identifier */
};
#define BTID_INITIALIZER \
  { VFID_INITIALIZER, NULL_PAGEID }
#define BTID_AS_ARGS(btid) (btid)->root_pageid, VFID_AS_ARGS (&(btid)->vfid)

typedef struct ehid EHID;   /* EXTENDIBLE HASHING IDENTIFIER */
struct ehid
{
  VFID vfid;            /* Volume and Directory file identifier */
  INT32 pageid;         /* The first (root) page of the directory */
};

typedef struct recdes RECDES;   /* RECORD DESCRIPTOR */
struct recdes
{
  int area_size;        /* Length of the allocated area. It includes only the data field. The value is negative
                 * if data is inside buffer. For example, peeking in a slotted page. */
  int length;           /* Length of the data. Does not include the length and type fields */
  INT16 type;           /* Type of record (REC_HOME, REC_NEWHOME,... ) */
  char *data;           /* The data */
};
/* Replace existing data in record at offset_to_data and size old_data_size
 * with new_data of size new_data_size.
 */
#define RECORD_REPLACE_DATA(record, offset_to_data, old_data_size, \
                new_data_size, new_data) \
  do \
    { \
      assert ((record) != NULL); \
      assert ((record)->data != NULL); \
      assert ((offset_to_data) >= 0 && (offset_to_data) <= (record)->length); \
      assert ((old_data_size) >= 0 && (new_data_size) >= 0); \
      assert ((offset_to_data) + (old_data_size) <= (record)->length); \
      if ((old_data_size) != (new_data_size)) \
        { \
      /* We may need to move data inside record. */ \
      if ((offset_to_data) + (old_data_size) < (record)->length) \
        { \
          /* Move data inside record. */ \
          memmove ((record)->data + (offset_to_data) + (new_data_size), \
               (record)->data + (offset_to_data) + (old_data_size), \
               (record)->length - (offset_to_data) - (old_data_size)); \
        } \
      /* Update record length. */ \
      (record)->length += (new_data_size) - (old_data_size); \
    } \
      /* Copy new data (if any). */ \
      if ((new_data_size) > 0) \
       { \
     memcpy ((record)->data + (offset_to_data), new_data, new_data_size); \
       } \
    } \
  while (false)
/* Move the data inside a record */
#define RECORD_MOVE_DATA(rec, dest_offset, src_offset)  \
  do {  \
    assert ((rec) != NULL && (dest_offset) >= 0 && (src_offset) >= 0); \
    assert (((rec)->length - (src_offset)) >= 0);  \
    assert (((rec)->area_size <= 0) || ((rec)->area_size >= (rec)->length));  \
    assert (((rec)->area_size <= 0) \
        || (((rec)->length + ((dest_offset) - (src_offset)))  \
        <= (rec)->area_size));  \
    if ((dest_offset) != (src_offset))  \
      { \
    if ((rec)->length != (src_offset)) \
      { \
        memmove ((rec)->data + (dest_offset), (rec)->data + (src_offset), \
             (rec)->length - (src_offset)); \
        (rec)->length = (rec)->length + ((dest_offset) - (src_offset)); \
      } \
    else \
      { \
        (rec)->length = (dest_offset); \
      } \
      } \
  } while (false)

typedef struct lorecdes LORECDES;   /* Work area descriptor */
struct lorecdes
{
  LOLENGTH length;      /* The length of data in the area */
  LOLENGTH area_size;       /* The size of the area */
  char *data;           /* Pointer to the beginning of the area */
};

#define RECDES_INITIALIZER { 0, -1, REC_UNKNOWN, NULL }

#define HFID_SET_NULL(hfid) \
  do { \
    (hfid)->vfid.fileid = NULL_FILEID; \
    (hfid)->hpgid = NULL_PAGEID; \
  } while(0)

#define HFID_COPY(hfid_ptr1, hfid_ptr2) *(hfid_ptr1) = *(hfid_ptr2)

#define HFID_IS_NULL(hfid)  (((hfid)->vfid.fileid == NULL_FILEID) ? 1 : 0)

#define BTID_SET_NULL(btid) \
  do { \
    (btid)->vfid.fileid = NULL_FILEID; \
    (btid)->vfid.volid = NULL_VOLID; \
    (btid)->root_pageid = NULL_PAGEID; \
  } while(0)

#define BTID_COPY(btid_ptr1, btid_ptr2) *(btid_ptr1) = *(btid_ptr2)

#define BTID_IS_NULL(btid)  (((btid)->vfid.fileid == NULL_FILEID) ? 1 : 0)

#define BTID_IS_EQUAL(b1,b2) \
  (((b1)->vfid.fileid == (b2)->vfid.fileid) && \
   ((b1)->vfid.volid == (b2)->vfid.volid))

#define DISK_VOLPURPOSE DB_VOLPURPOSE

/* Types and defines of transaction management */

typedef int TRANID;     /* Transaction identifier */

#define NULL_TRANID     (-1)
#define NULL_TRAN_INDEX (-1)
#define MVCCID_NULL (0)

#define MVCCID_ALL_VISIBLE    ((MVCCID) 3)  /* visible for all transactions */
#define MVCCID_FIRST          ((MVCCID) 4)

/* is MVCC ID valid? */
#define MVCCID_IS_VALID(id)   ((id) != MVCCID_NULL)
/* is MVCC ID normal? */
#define MVCCID_IS_NORMAL(id)      ((id) >= MVCCID_FIRST)
/* are MVCC IDs equal? */
#define MVCCID_IS_EQUAL(id1,id2)      ((id1) == (id2))
/* are MVCC IDs valid, not all visible? */
#define MVCCID_IS_NOT_ALL_VISIBLE(id) \
  (MVCCID_IS_VALID (id) && ((id) != MVCCID_ALL_VISIBLE))

/* advance MVCC ID */
#define MVCCID_FORWARD(id) \
  do \
    { \
      (id)++; \
      if ((id) < MVCCID_FIRST) \
        (id) = MVCCID_FIRST; \
    } \
  while (0)

#if 0               // not used
/* back up MVCC ID */
#define MVCCID_BACKWARD(id) \
  do \
    { \
      (id)--; \
    } \
  while ((id) < MVCCID_FIRST)
#endif

#define COMPOSITE_LOCK(scan_op_type)    (scan_op_type != S_SELECT)
#define READONLY_SCAN(scan_op_type) (scan_op_type == S_SELECT)

/* CLASSNAME TO OID RETURN VALUES */
typedef enum
{
  LC_CLASSNAME_RESERVED,
  LC_CLASSNAME_DELETED,
  LC_CLASSNAME_EXIST,
  LC_CLASSNAME_ERROR,
  LC_CLASSNAME_RESERVED_RENAME,
  LC_CLASSNAME_DELETED_RENAME
} LC_FIND_CLASSNAME;

#define LC_EXIST              1
#define LC_DOESNOT_EXIST      2
#define LC_ERROR              3

/* Enumeration type for the result of ehash_search function */
typedef enum
{
  EH_KEY_FOUND,
  EH_KEY_NOTFOUND,
  EH_ERROR_OCCURRED
} EH_SEARCH;

/* BTREE_SEARCH - Result for b-tree key or OID search. */
typedef enum
{
  BTREE_KEY_FOUND,      /* Found key (one visible or dirty version). */
  BTREE_KEY_NOTFOUND,       /* Key was not found (or no usable version found in key). */
  BTREE_ERROR_OCCURRED,     /* Error while searching key/OID. */
  BTREE_ACTIVE_KEY_FOUND,   /* Found key but the version inserter/deleter did not commit/abort. */
  BTREE_KEY_SMALLER,        /* Key was not found and it is smaller than all the keys it was compared to. */
  BTREE_KEY_BIGGER,     /* Key was not found and it is bigger than all the keys it was compared to. */
  BTREE_KEY_BETWEEN     /* Key was not found and it's value is between the smallest and the biggest keys it was
                 * compared to. */
} BTREE_SEARCH;

/* Magic default values */
#define CUBRID_MAGIC_MAX_LENGTH                 25
#define CUBRID_MAGIC_PREFIX         "CUBRID/"
#define CUBRID_MAGIC_DATABASE_VOLUME            "CUBRID/Volume"
#define CUBRID_MAGIC_LOG_ACTIVE                 "CUBRID/LogActive"
#define CUBRID_MAGIC_LOG_ARCHIVE                "CUBRID/LogArchive"
#define CUBRID_MAGIC_LOG_INFO                   "CUBRID/LogInfo"
#define CUBRID_MAGIC_DATABASE_BACKUP            "CUBRID/Backup_v2"
#define CUBRID_MAGIC_DATABASE_BACKUP_OLD        "CUBRID/Backup"
#define CUBRID_MAGIC_KEYS                       "CUBRID/Keys"

/*
 * Typedefs related to the scan data structures
 */

typedef enum
{
  S_OPENED = 1,
  S_STARTED,
  S_ENDED,
  S_CLOSED
} SCAN_STATUS;

typedef enum
{
  S_FORWARD = 1,
  S_BACKWARD
} SCAN_DIRECTION;

typedef enum
{
  S_BEFORE = 1,
  S_ON,
  S_GO_BACKWARD,
  S_AFTER
} SCAN_POSITION;

typedef enum
{
  S_ERROR = -1,
  S_END = 0,
  S_SUCCESS = 1,
  S_SUCCESS_CHN_UPTODATE,   /* only for slotted page */
  S_DOESNT_FIT,         /* used for slotted page, heap attrinfo */
  S_DOESNT_EXIST,       /* only for slotted page */
  S_SNAPSHOT_NOT_SATISFIED
} SCAN_CODE;

typedef enum
{
  S_SELECT,         /* By default MVCC requires no locks for select operations. */
  S_SELECT_WITH_LOCK,       /* Read operation that doesn't plan to modify the object, but has to know the exact
                 * fate of last version. Can be used for foreign key and unique constraint checks. */
  S_DELETE,         /* Delete object operation. */
  S_UPDATE          /* Update object operation. */
} SCAN_OPERATION_TYPE;

#define IS_WRITE_EXCLUSIVE_LOCK(lock) ((lock) == X_LOCK || (lock) == SCH_M_LOCK)


typedef enum
{
  HEAP_RECORD_INFO_INVALID = -1,
  HEAP_RECORD_INFO_T_PAGEID = 0,
  HEAP_RECORD_INFO_T_SLOTID,
  HEAP_RECORD_INFO_T_VOLUMEID,
  HEAP_RECORD_INFO_T_OFFSET,
  HEAP_RECORD_INFO_T_LENGTH,
  HEAP_RECORD_INFO_T_REC_TYPE,
  HEAP_RECORD_INFO_T_REPRID,
  HEAP_RECORD_INFO_T_CHN,
  HEAP_RECORD_INFO_T_MVCC_INSID,
  HEAP_RECORD_INFO_T_MVCC_DELID,
  HEAP_RECORD_INFO_T_MVCC_FLAGS,
  HEAP_RECORD_INFO_T_MVCC_PREV_VERSION,

  /* leave this last */
  HEAP_RECORD_INFO_COUNT,

  HEAP_RECORD_INFO_FIRST = HEAP_RECORD_INFO_T_PAGEID
} HEAP_RECORD_INFO_ID;

typedef enum
{
  HEAP_PAGE_INFO_INVALID = -1,
  HEAP_PAGE_INFO_CLASS_OID = 0,
  HEAP_PAGE_INFO_CUR_VOLUME,
  HEAP_PAGE_INFO_CUR_PAGE,
  HEAP_PAGE_INFO_PREV_PAGE,
  HEAP_PAGE_INFO_NEXT_PAGE,
  HEAP_PAGE_INFO_NUM_SLOTS,
  HEAP_PAGE_INFO_NUM_RECORDS,
  HEAP_PAGE_INFO_ANCHOR_TYPE,
  HEAP_PAGE_INFO_ALIGNMENT,
  HEAP_PAGE_INFO_TOTAL_FREE,
  HEAP_PAGE_INFO_CONT_FREE,
  HEAP_PAGE_INFO_OFFSET_TO_FREE_AREA,
  HEAP_PAGE_INFO_IS_SAVING,
  HEAP_PAGE_INFO_UPDATE_BEST,

  /* leave this last */
  HEAP_PAGE_INFO_COUNT,

  HEAP_PAGE_INFO_FIRST = HEAP_PAGE_INFO_CLASS_OID
} HEAP_PAGE_INFO_ID;

typedef enum
{
  BTREE_KEY_INFO_INVALID = -1,
  BTREE_KEY_INFO_VOLUMEID = 0,
  BTREE_KEY_INFO_PAGEID,
  BTREE_KEY_INFO_SLOTID,
  BTREE_KEY_INFO_KEY,
  BTREE_KEY_INFO_OID_COUNT,
  BTREE_KEY_INFO_FIRST_OID,
  BTREE_KEY_INFO_OVERFLOW_KEY,
  BTREE_KEY_INFO_OVERFLOW_OIDS,

  /* leave this last */
  BTREE_KEY_INFO_COUNT
} BTREE_KEY_INFO_ID;

typedef enum
{
  BTREE_NODE_INFO_INVALID = -1,
  BTREE_NODE_INFO_VOLUMEID = 0,
  BTREE_NODE_INFO_PAGEID,
  BTREE_NODE_INFO_NODE_TYPE,
  BTREE_NODE_INFO_KEY_COUNT,
  BTREE_NODE_INFO_FIRST_KEY,
  BTREE_NODE_INFO_LAST_KEY,

  /* leave this last */
  BTREE_NODE_INFO_COUNT
} BTREE_NODE_INFO_ID;

typedef enum
{
  LOG_ERROR_IF_DELETED,     /* set error when locking deleted objects */
  LOG_WARNING_IF_DELETED    /* set warning when locking deleted objects - the case when it is expected and
                 * accepted to find a deleted object; for example when er_clear() is used afterwards if
                 * ER_HEAP_UNKNOWN_OBJECT is set in er_errid */
} NON_EXISTENT_HANDLING;

/************************************************************************/
/* spacedb                                                              */
/************************************************************************/

/* database space info */
typedef enum
{
  SPACEDB_PERM_PERM_ALL,
  SPACEDB_PERM_TEMP_ALL,
  SPACEDB_TEMP_TEMP_ALL,

  SPACEDB_TOTAL_ALL,
  SPACEDB_ALL_COUNT,
} SPACEDB_ALL_TYPE;

typedef struct spacedb_all SPACEDB_ALL;
struct spacedb_all
{
  DKNVOLS nvols;
  DKNPAGES npage_used;
  DKNPAGES npage_free;
};

typedef struct spacedb_onevol SPACEDB_ONEVOL;
struct spacedb_onevol
{
  VOLID volid;
  DB_VOLTYPE type;
  DB_VOLPURPOSE purpose;
  DKNPAGES npage_used;
  DKNPAGES npage_free;
  char name[DB_MAX_PATH_LENGTH];
};

/* files */
typedef enum
{
  SPACEDB_INDEX_FILE,
  SPACEDB_HEAP_FILE,
  SPACEDB_SYSTEM_FILE,
  SPACEDB_TEMP_FILE,

  SPACEDB_TOTAL_FILE,
  SPACEDB_FILE_COUNT,
} SPACEDB_FILE_TYPE;

typedef struct spacedb_files SPACEDB_FILES;
struct spacedb_files
{
  int nfile;
  DKNPAGES npage_ftab;
  DKNPAGES npage_user;
  DKNPAGES npage_reserved;
};

/************************************************************************/
/* client & catalog common                                              */
/************************************************************************/

typedef int REPR_ID;        /* representation identifier */
typedef int ATTR_ID;        /* attribute identifier */

#define NULL_REPRID       -1    /* Null Representation Identifier */
#define NULL_ATTRID       -1    /* Null Attribute Identifier */

/************************************************************************/
/* b-tree common                                                        */
/************************************************************************/

typedef enum
{
  BTREE_CONSTRAINT_UNIQUE = 0x01,
  BTREE_CONSTRAINT_PRIMARY_KEY = 0x02
} BTREE_CONSTRAINT_TYPE;

typedef enum
{
  BTREE_UNIQUE,
  BTREE_INDEX,
  BTREE_REVERSE_UNIQUE,
  BTREE_REVERSE_INDEX,
  BTREE_PRIMARY_KEY,
  BTREE_FOREIGN_KEY
} BTREE_TYPE;

/************************************************************************/
/* storage common functions                                             */
/************************************************************************/
extern int db_set_page_size (INT16 io_page_size, INT16 log_page_size);
extern INT16 db_network_page_size (void);
extern void db_print_data (DB_TYPE type, DB_DATA * data, FILE * fd);

extern int recdes_allocate_data_area (RECDES * rec, int size);
extern void recdes_free_data_area (RECDES * rec);
extern void recdes_set_data_area (RECDES * rec, char *data, int size);

extern char *oid_to_string (char *buf, int buf_size, OID * oid);
extern char *vpid_to_string (char *buf, int buf_size, VPID * vpid);
extern char *vfid_to_string (char *buf, int buf_size, VFID * vfid);
extern char *hfid_to_string (char *buf, int buf_size, HFID * hfid);
extern char *btid_to_string (char *buf, int buf_size, BTID * btid);

/************************************************************************/
/* next has nothing to do with storage. however, we lack a clear place  */
/* for global stuff that affect everything. this is closest...          */
/************************************************************************/

typedef enum
{
  T_ADD,
  T_SUB,
  T_MUL,
  T_DIV,
  T_UNPLUS,
  T_UNMINUS,
  T_PRIOR,
  T_CONNECT_BY_ROOT,
  T_QPRIOR,
  T_BIT_NOT,
  T_BIT_AND,
  T_BIT_OR,
  T_BIT_XOR,
  T_BIT_COUNT,
  T_BITSHIFT_LEFT,
  T_BITSHIFT_RIGHT,
  T_INTDIV,
  T_INTMOD,
  T_IF,
  T_IFNULL,
  T_ISNULL,
  T_ACOS,
  T_ASIN,
  T_ATAN,
  T_ATAN2,
  T_COS,
  T_SIN,
  T_TAN,
  T_COT,
  T_PI,
  T_DEGREES,
  T_RADIANS,
  T_FORMAT,
  T_CONCAT,
  T_CONCAT_WS,
  T_FIELD,
  T_LEFT,
  T_RIGHT,
  T_REPEAT,
  T_SPACE,
  T_LOCATE,
  T_MID,
  T_STRCMP,
  T_REVERSE,
  T_DISK_SIZE,
  T_LN,
  T_LOG2,
  T_LOG10,
  T_ADDDATE,
  T_DATE_ADD,
  T_SUBDATE,
  T_DATE_SUB,
  T_DATE_FORMAT,
  T_STR_TO_DATE,
  T_MOD,
  T_POSITION,
  T_SUBSTRING,
  T_SUBSTRING_INDEX,
  T_OCTET_LENGTH,
  T_BIT_LENGTH,
  T_CHAR_LENGTH,
  T_MD5,
  T_LOWER,
  T_UPPER,
  T_LIKE_LOWER_BOUND,
  T_LIKE_UPPER_BOUND,
  T_TRIM,
  T_LTRIM,
  T_RTRIM,
  T_LPAD,
  T_RPAD,
  T_REPLACE,
  T_TRANSLATE,
  T_ADD_MONTHS,
  T_LAST_DAY,
  T_MONTHS_BETWEEN,
  T_SYS_DATE,
  T_SYS_TIME,
  T_SYS_TIMESTAMP,
  T_UTC_TIME,
  T_UTC_DATE,
  T_TIME_FORMAT,
  T_TIMESTAMP,
  T_UNIX_TIMESTAMP,
  T_FROM_UNIXTIME,
  T_SYS_DATETIME,
  T_YEAR,
  T_MONTH,
  T_DAY,
  T_HOUR,
  T_MINUTE,
  T_SECOND,
  T_QUARTER,
  T_WEEKDAY,
  T_DAYOFWEEK,
  T_DAYOFYEAR,
  T_TODAYS,
  T_FROMDAYS,
  T_TIMETOSEC,
  T_SECTOTIME,
  T_MAKEDATE,
  T_MAKETIME,
  T_WEEK,
  T_TO_CHAR,
  T_TO_DATE,
  T_TO_TIME,
  T_TO_TIMESTAMP,
  T_TO_DATETIME,
  T_TO_NUMBER,
  T_CURRENT_VALUE,
  T_NEXT_VALUE,
  T_CAST,
  T_CAST_NOFAIL,
  T_CAST_WRAP,
  T_CASE,
  T_EXTRACT,
  T_LOCAL_TRANSACTION_ID,
  T_FLOOR,
  T_CEIL,
  T_SIGN,
  T_POWER,
  T_ROUND,
  T_LOG,
  T_EXP,
  T_SQRT,
  T_TRUNC,
  T_ABS,
  T_CHR,
  T_INSTR,
  T_LEAST,
  T_GREATEST,
  T_STRCAT,
  T_NULLIF,
  T_COALESCE,
  T_NVL,
  T_NVL2,
  T_DECODE,
  T_RAND,
  T_DRAND,
  T_RANDOM,
  T_DRANDOM,
  T_INCR,
  T_DECR,
  T_SYS_CONNECT_BY_PATH,
  T_DATE,
  T_TIME,
  T_DATEDIFF,
  T_TIMEDIFF,
  T_ROW_COUNT,
  T_LAST_INSERT_ID,
  T_DEFAULT,
  T_LIST_DBS,
  T_BIT_TO_BLOB,
  T_BLOB_TO_BIT,
  T_CHAR_TO_CLOB,
  T_CLOB_TO_CHAR,
  T_LOB_LENGTH,
  T_TYPEOF,
  T_INDEX_CARDINALITY,
  T_EVALUATE_VARIABLE,
  T_DEFINE_VARIABLE,
  T_PREDICATE,
  T_EXEC_STATS,
  T_ADDTIME,
  T_BIN,
  T_FINDINSET,
  T_HEX,
  T_ASCII,
  T_CONV,
  T_INET_ATON,
  T_INET_NTOA,
  T_TO_ENUMERATION_VALUE,
  T_CHARSET,
  T_COLLATION,
  T_WIDTH_BUCKET,
  T_TRACE_STATS,
  T_AES_ENCRYPT,
  T_AES_DECRYPT,
  T_SHA_ONE,
  T_SHA_TWO,
  T_INDEX_PREFIX,
  T_TO_BASE64,
  T_FROM_BASE64,
  T_SYS_GUID,
  T_SLEEP,
  T_DBTIMEZONE,
  T_SESSIONTIMEZONE,
  T_TZ_OFFSET,
  T_NEW_TIME,
  T_FROM_TZ,
  T_TO_DATETIME_TZ,
  T_TO_TIMESTAMP_TZ,
  T_UTC_TIMESTAMP,
  T_CRC32,
  T_CURRENT_DATETIME,
  T_CURRENT_TIMESTAMP,
  T_CURRENT_DATE,
  T_CURRENT_TIME,
  T_CONV_TZ,
} OPERATOR_TYPE;        /* arithmetic operator types */

/************************************************************************/
/* QUERY                                                                */
/************************************************************************/

#define CACHE_TIME_AS_ARGS(ct)  (ct)->sec, (ct)->usec

#define CACHE_TIME_EQ(T1, T2) \
  (((T1)->sec != 0) && ((T1)->sec == (T2)->sec) && ((T1)->usec == (T2)->usec))

#define CACHE_TIME_RESET(T) \
  do \
    { \
      (T)->sec = 0; \
      (T)->usec = 0; \
    } \
  while (0)

#define CACHE_TIME_MAKE(CT, TV) \
  do \
    { \
      (CT)->sec = (TV)->tv_sec; \
      (CT)->usec = (TV)->tv_usec; \
    } \
  while (0)

#define OR_CACHE_TIME_SIZE (OR_INT_SIZE * 2)

#define OR_PACK_CACHE_TIME(PTR, T) \
  do \
    { \
      if ((CACHE_TIME *) (T) != NULL) \
        { \
          PTR = or_pack_int (PTR, (T)->sec); \
          PTR = or_pack_int (PTR, (T)->usec); \
        } \
    else \
      { \
        PTR = or_pack_int (PTR, 0); \
        PTR = or_pack_int (PTR, 0); \
      } \
    } \
  while (0)

#define OR_UNPACK_CACHE_TIME(PTR, T) \
  do \
    { \
      if ((CACHE_TIME *) (T) != NULL) \
        { \
          PTR = or_unpack_int (PTR, &((T)->sec)); \
          PTR = or_unpack_int (PTR, &((T)->usec)); \
        } \
    } \
  while (0)

/* XASL identifier */
typedef struct xasl_id XASL_ID;
struct xasl_id
{
  SHA1Hash sha1;        /* SHA-1 hash generated from query string. */
  INT32 cache_flag;
  /* Multiple-purpose field used to handle XASL cache. */
  CACHE_TIME time_stored;   /* when this XASL plan stored */
};              /* XASL plan file identifier */

typedef enum
{
  Q_DISTINCT,           /* no duplicate values */
  Q_ALL             /* all values */
} QUERY_OPTIONS;

typedef enum
{
  R_KEY = 1,            /* key value search */
  R_RANGE,          /* range search with the two key values and range spec */
  R_KEYLIST,            /* a list of key value searches */
  R_RANGELIST           /* a list of range searches */
} RANGE_TYPE;

typedef enum
{
  SHOWSTMT_START = 0,
  SHOWSTMT_NULL = SHOWSTMT_START,
  SHOWSTMT_ACCESS_STATUS,
  SHOWSTMT_VOLUME_HEADER,
  SHOWSTMT_ACTIVE_LOG_HEADER,
  SHOWSTMT_ARCHIVE_LOG_HEADER,
  SHOWSTMT_SLOTTED_PAGE_HEADER,
  SHOWSTMT_SLOTTED_PAGE_SLOTS,
  SHOWSTMT_HEAP_HEADER,
  SHOWSTMT_ALL_HEAP_HEADER,
  SHOWSTMT_HEAP_CAPACITY,
  SHOWSTMT_ALL_HEAP_CAPACITY,
  SHOWSTMT_INDEX_HEADER,
  SHOWSTMT_INDEX_CAPACITY,
  SHOWSTMT_ALL_INDEXES_HEADER,
  SHOWSTMT_ALL_INDEXES_CAPACITY,
  SHOWSTMT_GLOBAL_CRITICAL_SECTIONS,
  SHOWSTMT_JOB_QUEUES,
  SHOWSTMT_TIMEZONES,
  SHOWSTMT_FULL_TIMEZONES,
  SHOWSTMT_TRAN_TABLES,
  SHOWSTMT_THREADS,
  SHOWSTMT_PAGE_BUFFER_STATUS,

  /* append the new show statement types in here */

  SHOWSTMT_END
} SHOWSTMT_TYPE;

#define NUM_F_GENERIC_ARGS 32
#define NUM_F_INSERT_SUBSTRING_ARGS 4

extern const int SM_MAX_STRING_LENGTH;

/*
 * These are the names for the system defined properties on classes,
 * attributes and methods.  For the built in properties, try
 * to use short names.  User properties if they are ever allowed
 * should have more descriptive names.
 *
 * Lets adopt the convention that names beginning with a '*' are
 * reserved for system properties.
 */
#define SM_PROPERTY_UNIQUE "*U"
#define SM_PROPERTY_INDEX "*I"
#define SM_PROPERTY_NOT_NULL "*N"
#define SM_PROPERTY_REVERSE_UNIQUE "*RU"
#define SM_PROPERTY_REVERSE_INDEX "*RI"
#define SM_PROPERTY_VID_KEY "*V_KY"
#define SM_PROPERTY_PRIMARY_KEY "*P"
#define SM_PROPERTY_FOREIGN_KEY "*FK"

#define SM_PROPERTY_NUM_INDEX_FAMILY         6

#define SM_FILTER_INDEX_ID "*FP*"
#define SM_FUNCTION_INDEX_ID "*FI*"
#define SM_PREFIX_INDEX_ID "*PLID*"

typedef enum
{
  SM_INDEX_FLAG_NONE = 0,
  SM_INDEX_FLAG_FILTER = 1,
  SM_INDEX_FLAG_FUNCTION = 2,
  SM_INDEX_FLAG_PREFIX = 3
} SM_INDEX_FLAG;

/*
 * Enum values represent reverse indexes from the end of the constraint sequence to optional info:
 * e.g., COMMENT_INDEX == seq_len - 1, OPTIONS_INDEX == seq_len - 2, ...
 * See SM_CLASS_CONSTRAINT in class_object.h for structure details.
*/
typedef enum
{
  SM_CONSTRAINT_COMMENT_INDEX = 1,  // seq_len - 1
  SM_CONSTRAINT_OPTIONS_INDEX = 2,  // seq_len - 2
  SM_CONSTRAINT_INDEX_TYPE_INDEX = 3,   // seq_len - 3
  SM_CONSTRAINT_STATUS_INDEX = 4,   // seq_len - 4
  SM_CONSTRAINT_OPTIONAL_INFO_INDEX = 5,    // seq_len - 5 (optional)
  // [att_name|id, asc_desc]... (forward from here)
  // BTID

  SM_CONSTRAINT_FIXED_FIELD_COUNT = SM_CONSTRAINT_OPTIONAL_INFO_INDEX   // Excludes OPTIONAL_INFO
} SM_CONSTRAINT_FIXED_FIELD_REVERSE_INDEX;


typedef enum
{
  SM_FK_INFO_REF_CLASS_OID_INDEX = 0,
  SM_FK_INFO_REF_CLASS_PK_BTID_INDEX = 1,
  SM_FK_INFO_DELETE_ACTION_INDEX = 2,
  SM_FK_INFO_UPDATE_ACTION_INDEX = 3,
  SM_FK_INFO_INDEX_CATALOG_OF_REF_CLASS_INDEX = 4,
  SM_FK_INFO_REF_MATCH_OPTION_INDEX = 5,

  SM_FK_INFO_SIZE
} SM_FOREIGN_KEY_INFO_INDEX;

/*
 * All fields except [att_name|id, asc_desc] pairs are fixed in number.
 * (See SM_CLASS_CONSTRAINT in class_object.h for structure details)
 * To compute the number of attributes, we subtract the fixed field count
 * and divide the remaining size by 2 (each attribute is represented by 2 fields).
 * Optional info (1 field) is ignored, since it doesn't affect integer division by 2.
*/
static inline int
get_class_constraint_att_count (int size)
{
  assert (((size - SM_CONSTRAINT_FIXED_FIELD_COUNT) / 2) > 0);
  return ((size - SM_CONSTRAINT_FIXED_FIELD_COUNT) / 2);
}

/*
 * Given the total size of a class constraint sequence, this function computes
 * the absolute index of a fixed field (e.g., status, index_type, comment)
 * based on its reverse position from the end of the sequence.
*/
static inline int
get_class_constraint_index (int size, SM_CONSTRAINT_FIXED_FIELD_REVERSE_INDEX index)
{
  return size - index;
}


/*
 *    Bit field identifiers for attribute flags.  These could be defined
 *    with individual unsigned bit fields but this makes it easier
 *    to save them as a single integer.
 *    The "new" flag is used only at run time and shouldn't be here.
 *    Need to re-design the template functions to operate from a different
 *    memory structure during flattening.
 */
typedef enum
{
  SM_ATTFLAG_NONE = 0,
  SM_ATTFLAG_INDEX = 1,     /* attribute has an index 0x01 */
  SM_ATTFLAG_UNIQUE = 2,    /* attribute has UNIQUE constraint 0x02 */
  SM_ATTFLAG_NON_NULL = 4,  /* attribute has NON_NULL constraint 0x04 */
  SM_ATTFLAG_VID = 8,       /* attribute is part of virtual object id 0x08 */
  SM_ATTFLAG_NEW = 16,      /* is a new attribute 0x10 */
  SM_ATTFLAG_REVERSE_INDEX = 32,    /* attribute has a reverse index 0x20 */
  SM_ATTFLAG_REVERSE_UNIQUE = 64,   /* attribute has a reverse unique 0x40 */
  SM_ATTFLAG_PRIMARY_KEY = 128, /* attribute has a primary key 0x80 */
  SM_ATTFLAG_AUTO_INCREMENT = 256,  /* auto increment attribute 0x0100 */
  SM_ATTFLAG_FOREIGN_KEY = 512, /* attribute has a primary key 0x200 */
  SM_ATTFLAG_PARTITION_KEY = 1024   /* attribute is the partitioning key for the class 0x400 */
} SM_ATTRIBUTE_FLAG;

/* delete or update action type for foreign key */
typedef enum
{
  SM_FOREIGN_KEY_CASCADE,
  SM_FOREIGN_KEY_RESTRICT,
  SM_FOREIGN_KEY_NO_ACTION,
  SM_FOREIGN_KEY_SET_NULL
} SM_FOREIGN_KEY_ACTION;

typedef enum
{
  SM_FK_MATCH_NONE,     // no match check if any FK column is NULL
  SM_FK_MATCH_PARTIAL,      // check non-NULL FK columns
  SM_FK_MATCH_FULL      // all FK columns must be NULL or all valid
} SM_FOREIGN_KEY_MATCH_OPTION;

/*
 *    These identify "namespaces" for class components like attributes
 *    and methods.  A name_space identifier is frequently used
 *    in conjunction with a name so the correct component can be found
 *    in a class definition.  Since the namespaces for classes and
 *    instances can overlap, a name alone is not enough to uniquely
 *    identify a component.
 */
typedef enum
{
  ID_ATTRIBUTE,
  ID_SHARED_ATTRIBUTE,
  ID_CLASS_ATTRIBUTE,
  ID_METHOD,
  ID_CLASS_METHOD,
  ID_INSTANCE,          /* attributes/shared attributes/methods */
  ID_CLASS,         /* class methods/class attributes */
  ID_NULL
} SM_NAME_SPACE;

/*
 *    This constant defines the maximum size in bytes of a class name,
 *    attribute name, method name, or any other named entity in the schema.
 */
#define SM_MAX_IDENTIFIER_LENGTH    DB_MAX_IDENTIFIER_LENGTH
#define SM_MAX_USER_LENGTH          DB_MAX_USER_LENGTH

// TODO: move to serial.c with related with serial
// TODO: refactoring serial authorization check
#define SERIAL_ATTR_UNIQUE_NAME     "unique_name"
#define SERIAL_ATTR_NAME            "name"
#define SERIAL_ATTR_OWNER           "owner"
#define SERIAL_ATTR_CURRENT_VAL     "current_val"
#define SERIAL_ATTR_INCREMENT_VAL   "increment_val"
#define SERIAL_ATTR_MAX_VAL         "max_val"
#define SERIAL_ATTR_MIN_VAL         "min_val"
#define SERIAL_ATTR_START_VAL       "start_val"
#define SERIAL_ATTR_CYCLIC          "cyclic"
#define SERIAL_ATTR_STARTED         "started"
#define SERIAL_ATTR_CLASS_NAME      "class_name"
#define SERIAL_ATTR_ATTR_NAME       "attr_name"
#define SERIAL_ATTR_CACHED_NUM      "cached_num"
#define SERIAL_ATTR_COMMENT         "comment"

static const bool PEEK = true;  /* Peek for a slotted record */
static const bool COPY = false; /* Don't peek, but copy a slotted record */

enum
{
/* Unknown record type */
  REC_UNKNOWN = 0,

/* Record without content, just the address */
  REC_ASSIGN_ADDRESS = 1,

/* Home of record */
  REC_HOME = 2,

/* No the original home of record.  part of relocation process */
  REC_NEWHOME = 3,

/* Record describe new home of record */
  REC_RELOCATION = 4,

/* Record describe location of big record */
  REC_BIGONE = 5,

/* Slot does not describe any record.
 * A record was stored in this slot.  Slot cannot be reused.
 */
  REC_MARKDELETED = 6,

/* Slot does not describe any record.
 * A record was stored in this slot.  Slot will be reused.
 */
  REC_DELETED_WILL_REUSE = 7,

/* unused reserved record type */
  REC_RESERVED_TYPE_8 = 8,
  REC_RESERVED_TYPE_9 = 9,
  REC_RESERVED_TYPE_10 = 10,
  REC_RESERVED_TYPE_11 = 11,
  REC_RESERVED_TYPE_12 = 12,
  REC_RESERVED_TYPE_13 = 13,
  REC_RESERVED_TYPE_14 = 14,
  REC_RESERVED_TYPE_15 = 15,
/* 4bit record type max */
  REC_4BIT_USED_TYPE_MAX = REC_DELETED_WILL_REUSE,
  REC_4BIT_TYPE_MAX = REC_RESERVED_TYPE_15
};

typedef struct dbdef_vol_ext_info DBDEF_VOL_EXT_INFO;
struct dbdef_vol_ext_info
{
  const char *path;     /* Directory where the volume extension is created.  If NULL, is given, it defaults to
                 * the system parameter. */
  const char *name;     /* Name of the volume extension If NULL, system generates one like "db".ext"volid"
                 * where "db" is the database name and "volid" is the volume identifier to be assigned
                 * to the volume extension. */
  const char *comments;     /* Comments which are included in the volume extension header. */
  int max_npages;       /* Maximum pages of this volume */
  int extend_npages;        /* Number of pages to extend - used for generic volume only */
  INT32 nsect_total;        /* DKNSECTS type, number of sectors for volume extension */
  INT32 nsect_max;      /* DKNSECTS type, maximum number of sectors for volume extension */
  int max_writesize_in_sec; /* the amount of volume written per second */
  DB_VOLPURPOSE purpose;    /* The purpose of the volume extension. One of the following: -
                 * DB_PERMANENT_DATA_PURPOSE, DB_TEMPORARY_DATA_PURPOSE */
  DB_VOLTYPE voltype;       /* Permanent of temporary volume type */
  bool overwrite;
};

#define SERVER_SESSION_KEY_SIZE         8

typedef enum
{
  DB_PARTITION_HASH = 0,
  DB_PARTITION_RANGE,
  DB_PARTITION_LIST
} DB_PARTITION_TYPE;

typedef enum
{
  DB_NOT_PARTITIONED_CLASS = 0,
  DB_PARTITIONED_CLASS = 1,
  DB_PARTITION_CLASS = 2
} DB_CLASS_PARTITION_TYPE;

// TODO: move me in a proper place
typedef enum
{
  KILLSTMT_TRAN = 0,
  KILLSTMT_QUERY = 1,
} KILLSTMT_TYPE;

// query module
typedef enum
{
  HS_NONE = 0,          /* no hash aggregation */
  HS_ACCEPT_ALL,        /* accept tuples in hash table */
  HS_REJECT_ALL         /* reject tuples, use normal sort-based aggregation */
} AGGREGATE_HASH_STATE;

#endif /* _STORAGE_COMMON_H_ */