Skip to content

File object_representation.h

File List > base > object_representation.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.
 *
 */


/*
 * object_representation.h - Definitions related to the representation of
 *        objects on disk and in memory.
 *        his file is shared by both the client and server.
 */

#ifndef _OBJECT_REPRESENTATION_H_
#define _OBJECT_REPRESENTATION_H_

#ident "$Id$"

#include <setjmp.h>
#include <time.h>
#include <float.h>
#include <limits.h>
#include <assert.h>
#if !defined(WINDOWS)
#include <netinet/in.h>
#endif /* !WINDOWS */

#include "byte_order.h"
#include "db_set.h"
#include "error_manager.h"
#include "memory_alloc.h"
#include "oid.h"
#include "object_representation_constants.h"
#include "porting_inline.hpp"
#include "storage_common.h"
#include "lock_table.h"     // LOCK, lock_conv

// forward declarations
struct log_lsa;
struct setobj;

#define OR_VALUE_ALIGNED_SIZE(value)   \
  (or_db_value_size (value) + MAX_ALIGNMENT)

/* OVERFLOW CHECK MACROS */

#define OR_CHECK_ASSIGN_OVERFLOW(dest, src) \
  (((src) > 0 && (dest) < 0) || ((src) < 0 && (dest) > 0))
#define OR_CHECK_ADD_OVERFLOW(a, b, c) \
  (((a) > 0 && (b) > 0 && (c) < 0) \
   || ((a) < 0 && (b) < 0 && (c) >= 0))
#define OR_CHECK_UNS_ADD_OVERFLOW(a, b, c) \
  (c) < (a) || (c) < (b)
#define OR_CHECK_SUB_UNDERFLOW(a, b, c) \
  (((a) < (b) && (c) > 0) \
   || ((a) > (b) && (c) < 0))
#define OR_CHECK_UNS_SUB_UNDERFLOW(a, b, c) \
  (b) > (a)
#define OR_CHECK_MULT_OVERFLOW(a, b, c) \
  (((b) == 0) ? ((c) != 0) : ((c) / (b) != (a)))
#define OR_CHECK_SHORT_DIV_OVERFLOW(a, b) \
  ((a) == DB_INT16_MIN && (b) == -1)
#define OR_CHECK_INT_DIV_OVERFLOW(a, b) \
  ((a) == DB_INT32_MIN && (b) == -1)
#define OR_CHECK_BIGINT_DIV_OVERFLOW(a, b) \
  ((a) == DB_BIGINT_MIN && (b) == -1)

#define OR_CHECK_SHORT_OVERFLOW(i)  ((i) > DB_INT16_MAX || (i) < DB_INT16_MIN)
#define OR_CHECK_INT_OVERFLOW(i)    ((i) > DB_INT32_MAX || (i) < DB_INT32_MIN)
#define OR_CHECK_BIGINT_OVERFLOW(i) ((i) > DB_BIGINT_MAX || (i) < DB_BIGINT_MIN)
#define OR_CHECK_USHRT_OVERFLOW(i)  ((i) > (int) DB_UINT16_MAX || (i) < 0)
#define OR_CHECK_UINT_OVERFLOW(i)   ((i) > DB_UINT32_MAX || (i) < 0)

#define OR_CHECK_FLOAT_OVERFLOW(i)         ((i) > FLT_MAX || (-(i)) > FLT_MAX)
#define OR_CHECK_DOUBLE_OVERFLOW(i)        ((i) > DBL_MAX || (-(i)) > DBL_MAX)

/* simple macro to calculate minimum bytes to contain given bits */
#define BITS_TO_BYTES(bit_cnt)      (((bit_cnt) + 7) / 8)

/* PACK/UNPACK MACROS */

/* NUMERIC */

#define OR_PUT_BYTE(ptr, val) \
  (*((unsigned char *) (ptr)) = (unsigned char) (val))

#define OR_GET_BYTE(ptr) \
  (*(unsigned char *) ((char *) (ptr)))

#define OR_PUT_SHORT(ptr, val) \
  (*(short *) ((char *) (ptr)) = htons ((short) (val)))

#define OR_GET_SHORT(ptr) \
  ((short) ntohs (*(short *) ((char *) (ptr))))

#define OR_PUT_INT(ptr, val) \
  (*(int *) ((char *) (ptr)) = htonl ((int) (val)))

#define OR_GET_INT(ptr) \
  ((int) ntohl (*(int *) ((char *) (ptr))))

#define OR_PUT_INT64(ptr, val) \
  do { \
    INT64 packed_value; \
    packed_value = ((INT64) swap64 (*(INT64*) val)); \
    memcpy (ptr, &packed_value, OR_INT64_SIZE); \
  } while (0)

#define OR_GET_INT64(ptr, val) \
  do { \
    INT64 packed_value; \
    memcpy (&packed_value, ptr, OR_INT64_SIZE); \
    *((INT64*) (val)) = ((INT64) swap64 (packed_value)); \
  } while (0)

#define OR_PUT_BIGINT(ptr, val) do {  \
     assert (OR_BIGINT_SIZE == OR_INT64_SIZE); \
     INT64* pval =  (INT64*) (val);   \
     OR_PUT_INT64 (ptr, pval);        \
  } while (0)

#define OR_GET_BIGINT(ptr, val) do {  \
     assert (OR_BIGINT_SIZE == OR_INT64_SIZE); \
     INT64* pval =  (INT64*) (val);   \
     OR_GET_INT64 (ptr, pval);        \
  } while (0)

STATIC_INLINE void
OR_PUT_FLOAT (char *ptr, float val)
{
  UINT32 ui = htonf (val);
  memcpy (ptr, &ui, sizeof (ui));
}

#define OR_GET_FLOAT(ptr, value) \
  (*(value) = ntohf (*(UINT32 *) (ptr)))

STATIC_INLINE void
OR_PUT_DOUBLE (char *ptr, double val)
{
  UINT64 ui = htond (val);
  memcpy (ptr, &ui, sizeof (ui));
}

#define OR_GET_DOUBLE(ptr, value) \
  (*(value) = ntohd (*(UINT64 *) (ptr)))

#if __WORDSIZE == 32
#define OR_PUT_PTR(ptr, val)    OR_PUT_INT ((ptr), (val))
#define OR_GET_PTR(ptr)         OR_GET_INT ((ptr))
#else /* __WORDSIZE == 32 */
#define OR_PUT_PTR(ptr, val)    (*(UINTPTR *) ((char *) (ptr)) = swap64 ((UINTPTR) val))
#define OR_GET_PTR(ptr)         ((UINTPTR) swap64 (*(UINTPTR *) ((char *) (ptr))))
#endif /* __WORDSIZE == 64 */

/* EXTENDED TYPE */

#define OR_PUT_TIME(ptr, value) \
  OR_PUT_INT (ptr, *((DB_TIME *) (value)))

#define OR_GET_TIME(ptr, value) \
  *((DB_TIME *) (value)) = OR_GET_INT (ptr)

#define OR_PUT_UTIME(ptr, value) \
  OR_PUT_INT (ptr, *((DB_UTIME *) (value)))

#define OR_GET_UTIME(ptr, value) \
  *((DB_UTIME *) (value)) = OR_GET_INT (ptr)

#define OR_PUT_TIMESTAMPTZ(ptr, ts_tz) \
  do { \
    OR_PUT_INT (((char *) ptr), (ts_tz)->timestamp); \
    OR_PUT_INT (((char *) ptr) + OR_TIMESTAMPTZ_TZID, (ts_tz)->tz_id); \
  } while (0)

#define OR_GET_TIMESTAMPTZ(ptr, ts_tz) \
  do { \
    (ts_tz)->timestamp = OR_GET_INT ((char *) (ptr)); \
    (ts_tz)->tz_id = OR_GET_INT (((char *) (ptr)) + OR_TIMESTAMPTZ_TZID); \
  } while (0)

#define OR_PUT_DATE(ptr, value) \
  OR_PUT_INT (ptr, *((DB_DATE *) (value)))

#define OR_GET_DATE(ptr, value) \
  *((DB_DATE *) (value)) = OR_GET_INT (ptr)

#define OR_PUT_DATETIME(ptr, datetime) \
  do { \
    OR_PUT_INT (((char *)ptr) + OR_DATETIME_DATE, (datetime)->date); \
    OR_PUT_INT (((char *)ptr) + OR_DATETIME_TIME, (datetime)->time); \
  } while (0)

#define OR_GET_DATETIME(ptr, datetime) \
  do { \
    (datetime)->date = OR_GET_INT (((char *) (ptr)) + OR_DATETIME_DATE); \
    (datetime)->time = OR_GET_INT (((char *) (ptr)) + OR_DATETIME_TIME); \
  } while (0)

#define OR_PUT_DATETIMETZ(ptr, datetimetz) \
  do { \
    OR_PUT_DATETIME (((char *) ptr), \
             &((DB_DATETIMETZ *) datetimetz)->datetime); \
    OR_PUT_INT (((char *) ptr) + OR_DATETIMETZ_TZID, (datetimetz)->tz_id); \
  } while (0)

#define OR_GET_DATETIMETZ(ptr, datetimetz) \
  do { \
    OR_GET_DATETIME ((char *) ptr, \
             &((DB_DATETIMETZ *) datetimetz)->datetime); \
    (datetimetz)->tz_id = OR_GET_INT (((char *) (ptr)) + OR_DATETIMETZ_TZID); \
  } while (0)

#define OR_PUT_MONETARY(ptr, value) \
  do { \
    char pack_value[OR_DOUBLE_SIZE]; \
    OR_PUT_INT (((char *) (ptr)) + OR_MONETARY_TYPE, (int) (value)->type); \
    OR_PUT_DOUBLE (pack_value, (value)->amount); \
    memcpy (((char *) (ptr)) + OR_MONETARY_AMOUNT, pack_value, OR_DOUBLE_SIZE); \
  } while (0)

#define OR_GET_MONETARY(ptr, value) \
  do { \
    UINT64 pack_value; \
    (value)->type = (DB_CURRENCY) OR_GET_INT (((char *) (ptr)) + OR_MONETARY_TYPE); \
    memcpy ((char *) (&pack_value), ((char *) (ptr)) + OR_MONETARY_AMOUNT, OR_DOUBLE_SIZE); \
    OR_GET_DOUBLE (&pack_value, &(value)->amount); \
  } while (0)

#define OR_MOVE_MONETARY(src, dst) \
  do { \
    OR_MOVE_DOUBLE (src, dst); \
    ((DB_MONETARY *) dst)->type = ((DB_MONETARY *) src)->type; \
  } while (0)

#define OR_GET_CURRENCY_TYPE(ptr) \
  (DB_CURRENCY) OR_GET_INT (((char *) (ptr)) + OR_MONETARY_TYPE)

#define OR_PUT_SHA1(ptr, value) \
  do { \
    int i = 0; \
    for (; i < 5; i++) \
      { \
    OR_PUT_INT (ptr + i * OR_INT_SIZE, ((SHA1Hash *) (value))->h[i]); \
      } \
  } while (0)

#define OR_GET_SHA1(ptr, value) \
  do { \
    int i = 0; \
    for (; i < 5; i++) \
      { \
    ((SHA1Hash *) (value))->h[i] = (INT32) OR_GET_INT (ptr + i * OR_INT_SIZE); \
      } \
  } while (0)

#define OR_GET_STRING(ptr) \
  ((char *) ((char *) (ptr)))

/* DISK IDENTIFIERS */

#define OR_GET_OID(ptr, oid) \
  do { \
    (oid)->pageid = OR_GET_INT (((char *) (ptr)) + OR_OID_PAGEID); \
    (oid)->slotid = OR_GET_SHORT (((char *) (ptr)) + OR_OID_SLOTID); \
    (oid)->volid  = OR_GET_SHORT (((char *) (ptr)) + OR_OID_VOLID); \
  } while (0)

#define OR_PUT_OID(ptr, oid) \
  do { \
    OR_PUT_INT (((char *) (ptr)) + OR_OID_PAGEID, (oid)->pageid); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_OID_SLOTID, (oid)->slotid); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_OID_VOLID, (oid)->volid); \
  } while (0)

#define OR_GET_VPID(ptr, vpid) \
  do { \
    (vpid)->pageid = OR_GET_INT (((char *) (ptr)) + OR_VPID_PAGEID); \
    (vpid)->volid = OR_GET_SHORT (((char *) (ptr)) + OR_VPID_VOLID); \
  } while (0)

#define OR_PUT_VPID(ptr, vpid) \
  do { \
    OR_PUT_INT (((char *) (ptr)) + OR_VPID_PAGEID, (vpid)->pageid); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_VPID_VOLID, (vpid)->volid); \
  } while (0)

#define OR_PUT_VPID_ALIGNED(ptr, vpid) \
  do { \
    OR_PUT_INT (((char *) (ptr)) + OR_VPID_PAGEID, (vpid)->pageid); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_VPID_VOLID, (vpid)->volid); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_VPID_SIZE, 0); \
  } while (0)

#define OR_PUT_NULL_OID(ptr) \
  do { \
    OR_PUT_INT (((char *) (ptr)) + OR_OID_PAGEID, NULL_PAGEID); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_OID_SLOTID, 0); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_OID_VOLID,  0); \
  } while (0)

#define OR_GET_HFID(ptr, hfid) \
  do { \
    (hfid)->hpgid = OR_GET_INT (((char *) (ptr)) + OR_HFID_PAGEID); \
    (hfid)->vfid.fileid = OR_GET_INT (((char *) (ptr)) + OR_HFID_VFID_FILEID); \
    (hfid)->vfid.volid = OR_GET_INT (((char *) (ptr)) + OR_HFID_VFID_VOLID); \
  } while (0)

#define OR_PUT_HFID(ptr, hfid) \
  do { \
    OR_PUT_INT (((char *) (ptr)) + OR_HFID_PAGEID, (hfid)->hpgid); \
    OR_PUT_INT (((char *) (ptr)) + OR_HFID_VFID_FILEID, (hfid)->vfid.fileid); \
    OR_PUT_INT (((char *) (ptr)) + OR_HFID_VFID_VOLID, (hfid)->vfid.volid); \
  } while (0)

#define OR_PUT_NULL_HFID(ptr) \
  do { \
    OR_PUT_INT (((char *) (ptr)) + OR_HFID_PAGEID, -1); \
    OR_PUT_INT (((char *) (ptr)) + OR_HFID_VFID_FILEID, -1); \
    OR_PUT_INT (((char *) (ptr)) + OR_HFID_VFID_VOLID, -1); \
  } while (0)

#define OR_GET_BTID(ptr, btid) \
  do { \
    (btid)->root_pageid = OR_GET_INT (((char *) (ptr)) + OR_BTID_PAGEID); \
    (btid)->vfid.fileid = OR_GET_INT (((char *) (ptr)) + OR_BTID_VFID_FILEID); \
    (btid)->vfid.volid  = OR_GET_SHORT (((char *) (ptr)) + OR_BTID_VFID_VOLID); \
  } while (0)

#define OR_PUT_BTID(ptr, btid) \
  do { \
    OR_PUT_INT (((char *) (ptr)) + OR_BTID_PAGEID, (btid)->root_pageid); \
    OR_PUT_INT (((char *) (ptr)) + OR_BTID_VFID_FILEID, (btid)->vfid.fileid); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_BTID_VFID_VOLID, (btid)->vfid.volid); \
  } while (0)

#define OR_PUT_NULL_BTID(ptr) \
  do { \
    OR_PUT_INT (((char *) (ptr)) + OR_BTID_PAGEID, NULL_PAGEID); \
    OR_PUT_INT (((char *) (ptr)) + OR_BTID_VFID_FILEID, NULL_FILEID); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_BTID_VFID_VOLID, NULL_VOLID); \
  } while (0)

#define OR_GET_EHID(ptr, ehid) \
  do { \
    (ehid)->vfid.volid = OR_GET_INT (((char *) (ptr)) + OR_EHID_VOLID); \
    (ehid)->vfid.fileid = OR_GET_INT (((char *) (ptr)) + OR_EHID_FILEID); \
    (ehid)->pageid = OR_GET_INT (((char *) (ptr)) + OR_EHID_PAGEID); \
  } while (0)

#define OR_PUT_EHID(ptr, ehid) \
  do { \
    OR_PUT_INT (((char *) (ptr)) + OR_EHID_VOLID,  (ehid)->vfid.volid); \
    OR_PUT_INT (((char *) (ptr)) + OR_EHID_FILEID, (ehid)->vfid.fileid); \
    OR_PUT_INT (((char *) (ptr)) + OR_EHID_PAGEID, (ehid)->pageid); \
  } while (0)

#define OR_GET_LOG_LSA(ptr, lsa) \
  do { \
    INT64 value; \
    OR_GET_INT64 (((char *) (ptr)) + OR_LOG_LSA_PAGEID, &value); \
    (lsa)->pageid = value; \
    (lsa)->offset = OR_GET_SHORT (((char *) (ptr)) + OR_LOG_LSA_OFFSET); \
  } while (0)

#define OR_PUT_LOG_LSA(ptr, lsa) \
  do { \
    INT64 pageid = (lsa)->pageid; \
    OR_PUT_INT64 (((char *) (ptr)) + OR_LOG_LSA_PAGEID, &pageid); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_LOG_LSA_OFFSET, (lsa)->offset); \
  } while (0)

#define OR_PUT_NULL_LOG_LSA(ptr) \
  do { \
    INT64 pageid = -1; \
    OR_PUT_INT64 (((char *) (ptr)) + OR_LOG_LSA_PAGEID, &pageid); \
    OR_PUT_SHORT (((char *) (ptr)) + OR_LOG_LSA_OFFSET, -1); \
  } while (0)

/* VARIABLE OFFSET ACCESSORS */

#define OR_PUT_BIG_VAR_OFFSET(ptr, val) \
  OR_PUT_INT ((ptr), (val))

#define OR_GET_BIG_VAR_OFFSET(ptr) \
  OR_GET_INT ((ptr))

#define OR_PUT_OFFSET(ptr, val) \
  OR_PUT_BIG_VAR_OFFSET ((ptr), (val))

#define OR_GET_OFFSET(ptr) \
  OR_GET_BIG_VAR_OFFSET ((ptr))

#define OR_PUT_OFFSET_INTERNAL(ptr, val, offset_size) \
  do { \
    if ((offset_size) == OR_BYTE_SIZE) \
      { \
    OR_PUT_BYTE ((ptr), (val)); \
      } \
    else if ((offset_size) == OR_SHORT_SIZE) \
      { \
    OR_PUT_SHORT ((ptr), (val)); \
      } \
    else \
      { \
    assert ((offset_size) == OR_INT_SIZE); \
    OR_PUT_INT ((ptr), (val)); \
      } \
  } while (0)

#define OR_GET_OFFSET_INTERNAL(ptr, offset_size) \
  ((offset_size) == OR_BYTE_SIZE) \
   ? OR_GET_BYTE ((ptr)) \
   : (((offset_size) == OR_SHORT_SIZE) \
      ? OR_GET_SHORT ((ptr)) : OR_GET_INT ((ptr)))

/*
 * VARIABLE OFFSET TABLE ACCESSORS
 * The variable offset table is present in the headers of objects and sets.
 */

#define OR_VAR_TABLE_SIZE(vars) \
  (OR_VAR_TABLE_SIZE_INTERNAL (vars, BIG_VAR_OFFSET_SIZE))

#define OR_VAR_TABLE_SIZE_INTERNAL(vars, offset_size) \
  (((vars) == 0) ? 0 : DB_ALIGN ((offset_size * ((vars) + 1)), INT_ALIGNMENT))

#define OR_VAR_TABLE_ELEMENT_PTR(table, index, offset_size) \
  ((offset_size == OR_BYTE_SIZE) \
   ? (&((char *) (table))[(index)]) \
   : ((offset_size == OR_SHORT_SIZE) \
      ? ((char *) (&((short *) (table))[(index)])) \
      : ((char *) (&((int *) (table))[(index)]))))

#define OR_VAR_TABLE_ELEMENT_OFFSET_INTERNAL(table, index, offset_size) \
  ((offset_size == OR_BYTE_SIZE) \
   ? (OR_GET_BYTE (OR_VAR_TABLE_ELEMENT_PTR (table, index, offset_size))) \
   : ((offset_size == OR_SHORT_SIZE) \
      ? (OR_GET_SHORT (OR_VAR_TABLE_ELEMENT_PTR (table, index, offset_size))) \
      : (OR_GET_INT (OR_VAR_TABLE_ELEMENT_PTR (table, index, offset_size)))))

#define OR_VAR_TABLE_ELEMENT_LENGTH_INTERNAL(table, index, offset_size) \
  (OR_VAR_TABLE_ELEMENT_OFFSET_INTERNAL (table, (index) + 1, offset_size) \
   - OR_VAR_TABLE_ELEMENT_OFFSET_INTERNAL (table, (index), offset_size))

/* ATTRIBUTE LOCATION */

#define OR_FIXED_ATTRIBUTES_OFFSET(ptr, nvars) \
  (OR_FIXED_ATTRIBUTES_OFFSET_INTERNAL (ptr, nvars, BIG_VAR_OFFSET_SIZE))

#define OR_FIXED_ATTRIBUTES_OFFSET_INTERNAL(ptr, nvars, offset_size) \
  (OR_HEADER_SIZE (ptr) + OR_VAR_TABLE_SIZE_INTERNAL (nvars, offset_size))

/* OBJECT HEADER LAYOUT */
/* header fixed-size in non-MVCC only, in MVCC the header has variable size */
#define OR_HEADER_SIZE(ptr) (or_header_size ((char *) (ptr)))

/* representation offset in MVCC and non-MVCC. In MVCC the representation
 * contains flags that allow to compute header size and CHN offset.
 */

#define OR_REP_OFFSET    0
#define OR_MVCC_REP_SIZE 4

#define OR_MVCC_FLAG_OFFSET OR_REP_OFFSET
#define OR_MVCC_FLAG_SIZE OR_MVCC_REP_SIZE

#define OR_CHN_OFFSET (OR_REP_OFFSET + OR_MVCC_REP_SIZE)
#define OR_CHN_SIZE 4

#define OR_MVCC_INSERT_ID_OFFSET (OR_CHN_OFFSET + OR_CHN_SIZE)
#define OR_MVCC_INSERT_ID_SIZE 8

#define OR_MVCC_DELETE_ID_OFFSET(mvcc_flags) \
  (OR_MVCC_INSERT_ID_OFFSET + (((mvcc_flags) & OR_MVCC_FLAG_VALID_INSID) ? OR_MVCC_INSERT_ID_SIZE : 0))
#define OR_MVCC_DELETE_ID_SIZE 8

#define OR_MVCC_PREV_VERSION_LSA_OFFSET(mvcc_flags) \
  (OR_MVCC_DELETE_ID_OFFSET(mvcc_flags) + (((mvcc_flags) & OR_MVCC_FLAG_VALID_DELID) ? OR_MVCC_DELETE_ID_SIZE : 0))
#define OR_MVCC_PREV_VERSION_LSA_SIZE 8

/* MVCC */
#define OR_MVCCID_SIZE          OR_BIGINT_SIZE
#define OR_PUT_MVCCID           OR_PUT_BIGINT
#define OR_GET_MVCCID           OR_GET_BIGINT

/* In case MVCC is enabled and chn is needed it will be saved instead of
 * delete MVCC id.
 */

/* high bit of the repid word is reserved for the bound bit flag,
   need to keep representations from going negative ! */
#define OR_BOUND_BIT_FLAG   0x80000000

#define BIG_VAR_OFFSET_SIZE OR_INT_SIZE /* 4byte */
#define SHORT_VAR_OFFSET_SIZE OR_SHORT_SIZE /* 2byte */

/* OBJECT HEADER ACCESS MACROS */

#define OR_GET_REPID(ptr) \
  ((OR_GET_INT ((ptr) + OR_REP_OFFSET)) & ~OR_BOUND_BIT_FLAG & ~OR_OFFSET_SIZE_FLAG)

#define OR_GET_BOUND_BIT_FLAG(ptr) \
  ((OR_GET_INT ((ptr) + OR_REP_OFFSET)) & OR_BOUND_BIT_FLAG)

#define OR_GET_OFFSET_SIZE(ptr) \
  ((((OR_GET_INT (((char *) (ptr)) + OR_REP_OFFSET)) & OR_OFFSET_SIZE_FLAG) == OR_OFFSET_SIZE_1BYTE) \
     ? OR_BYTE_SIZE \
     : ((((OR_GET_INT (((char *) (ptr)) + OR_REP_OFFSET)) & OR_OFFSET_SIZE_FLAG) == OR_OFFSET_SIZE_2BYTE) \
          ? OR_SHORT_SIZE : OR_INT_SIZE))

#define OR_SET_VAR_OFFSET_SIZE(val, offset_size) \
  (((offset_size) == OR_BYTE_SIZE) \
   ? ((val) |= OR_OFFSET_SIZE_1BYTE) \
   : (((offset_size) == OR_SHORT_SIZE) \
      ? ((val) |= OR_OFFSET_SIZE_2BYTE) \
      : ((val) |= OR_OFFSET_SIZE_4BYTE)))

/* MVCC OBJECT HEADER ACCESS MACROS */
#define OR_GET_MVCC_INSERT_ID(ptr, mvcc_flags, valp) \
  ((((mvcc_flags) & OR_MVCC_FLAG_VALID_INSID) == 0) \
    ? MVCCID_ALL_VISIBLE \
    : (OR_GET_BIGINT (((char *) (ptr)) + OR_MVCC_INSERT_ID_OFFSET, (valp))))

#define OR_GET_MVCC_DELETE_ID(ptr, mvcc_flags, valp)  \
  ((((mvcc_flags) & OR_MVCC_FLAG_VALID_DELID) == 0) \
    ? MVCCID_NULL \
    : (OR_GET_BIGINT (((char *) (ptr)) + OR_MVCC_DELETE_ID_OFFSET(mvcc_flags), (valp))))

#define OR_GET_MVCC_REPID(ptr)  \
  ((OR_GET_INT(((char *) (ptr)) + OR_REP_OFFSET)) \
   & OR_MVCC_REPID_MASK)

#define OR_GET_MVCC_CHN(ptr) (OR_GET_INT ((char *) (ptr) + OR_CHN_OFFSET))

#define OR_GET_MVCC_FLAG(ptr) \
  (((OR_GET_INT (((char *) (ptr)) + OR_REP_OFFSET)) \
    >> OR_MVCC_FLAG_SHIFT_BITS) & OR_MVCC_FLAG_MASK)

#define OR_GET_MVCC_REPID_AND_FLAG(ptr) \
  (OR_GET_INT (((char *) (ptr)) + OR_REP_OFFSET))

/* VARIABLE OFFSET TABLE ACCESSORS */

#define OR_GET_OBJECT_VAR_TABLE(obj) \
  ((short *) (((char *) (obj)) + OR_HEADER_SIZE ((char *) (obj))))

#define OR_VAR_ELEMENT_PTR(obj, index) \
  (OR_VAR_TABLE_ELEMENT_PTR (OR_GET_OBJECT_VAR_TABLE (obj), index, OR_GET_OFFSET_SIZE (obj)))

#define OR_VAR_OFFSET(obj, index) \
  (OR_HEADER_SIZE (obj) \
   + OR_VAR_TABLE_ELEMENT_OFFSET_INTERNAL (OR_GET_OBJECT_VAR_TABLE (obj), \
                                           index, OR_GET_OFFSET_SIZE (obj)))

#define OR_VAR_IS_NULL(obj, index) \
  ((OR_VAR_TABLE_ELEMENT_LENGTH_INTERNAL (OR_GET_OBJECT_VAR_TABLE (obj), \
                                          index, OR_GET_OFFSET_SIZE (obj))) ? 0 : 1)

#define OR_VAR_LENGTH(length, obj, index, n_variables) \
  do { \
    int _this_offset, _next_offset, _temp_offset, _nth_var; \
    _this_offset = OR_VAR_OFFSET(obj, index); \
    _next_offset = OR_VAR_OFFSET(obj, index + 1); \
    if ((length = _next_offset - _this_offset) != 0) \
      { \
        _next_offset = 0; \
        for (_nth_var = 0; _nth_var <= n_variables; _nth_var++) \
          { \
            _temp_offset = OR_VAR_OFFSET(obj, _nth_var); \
            if (_temp_offset > _this_offset ) \
              { \
                if (_next_offset == 0) \
                  { \
                    _next_offset = _temp_offset; \
                  } \
                else if (_temp_offset < _next_offset) \
                  { \
                    _next_offset = _temp_offset; \
          } \
              } \
          } \
        length = _next_offset - _this_offset; \
      } \
  } while (0)

/*
 * BOUND BIT ACCESSORS.
 * Note that these are assuming 4 byte integers to avoid a divide operation.
 */

#define OR_BOUND_BIT_WORDS(count) (((count) + 31) >> 5)
#define OR_BOUND_BIT_BYTES(count) ((((count) + 31) >> 5) * 4)

#define OR_BOUND_BIT_MASK(element) (1 << ((int) (element) & 7))

#define OR_GET_BOUND_BIT_BYTE(bitptr, element) \
  ((char *) (bitptr) + ((int) (element) >> 3))

#define OR_GET_BOUND_BIT(bitptr, element) \
  ((*OR_GET_BOUND_BIT_BYTE ((bitptr), (element))) & OR_BOUND_BIT_MASK ((element)))

#define OR_GET_BOUND_BITS(obj, nvars, fsize) \
  (char *) (((char *) (obj)) \
            + OR_HEADER_SIZE ((char *) (obj)) \
            + OR_VAR_TABLE_SIZE_INTERNAL ((nvars), OR_GET_OFFSET_SIZE (obj)) + (fsize))

/* These are the most useful ones if we're only testing a single attribute */

#define OR_FIXED_ATT_IS_BOUND(obj, nvars, fsize, position) \
  (!OR_GET_BOUND_BIT_FLAG (obj) || OR_GET_BOUND_BIT (OR_GET_BOUND_BITS (obj, nvars, fsize), position))

#define OR_FIXED_ATT_IS_UNBOUND(obj, nvars, fsize, position) \
  (OR_GET_BOUND_BIT_FLAG (obj) && !OR_GET_BOUND_BIT (OR_GET_BOUND_BITS (obj, nvars, fsize), position))

#define OR_ENABLE_BOUND_BIT(bitptr, element) \
  *OR_GET_BOUND_BIT_BYTE (bitptr, element) = *OR_GET_BOUND_BIT_BYTE (bitptr, element) | OR_BOUND_BIT_MASK (element)

#define OR_CLEAR_BOUND_BIT(bitptr, element) \
  *OR_GET_BOUND_BIT_BYTE (bitptr, element) = *OR_GET_BOUND_BIT_BYTE (bitptr, element) & ~OR_BOUND_BIT_MASK (element)

/* SET HEADER */

#define OR_SET_HEADER_SIZE 8
#define OR_SET_SIZE_OFFSET 4
/* optional header extension if the full domain is present */
#define OR_SET_DOMAIN_SIZE_OFFSET 8

/* Set header fields.
   These constants are used to construct and decompose the set header word. */
#define OR_SET_TYPE_MASK    0xFF
#define OR_SET_ETYPE_MASK   0xFF00
#define OR_SET_ETYPE_SHIFT  8
#define OR_SET_BOUND_BIT    0x10000
#define OR_SET_VARIABLE_BIT     0x20000
#define OR_SET_DOMAIN_BIT   0x40000
#define OR_SET_TAG_BIT      0x80000
#define OR_SET_COMMON_SUB_BIT   0x100000

#define OR_SET_TYPE(setptr) \
  (DB_TYPE) ((OR_GET_INT ((char *) (setptr))) & OR_SET_TYPE_MASK)

#define OR_SET_ELEMENT_TYPE(setptr)  \
  (DB_TYPE) ((OR_GET_INT ((char *) (setptr)) & OR_SET_ETYPE_MASK) >> OR_SET_ETYPE_SHIFT)

#define OR_SET_HAS_BOUND_BITS(setptr) \
  (OR_GET_INT ((char *) (setptr)) & OR_SET_BOUND_BIT)

#define OR_SET_HAS_OFFSET_TABLE(setptr) \
  (OR_GET_INT ((char *) (setptr)) & OR_SET_VARIABLE_BIT)

#define OR_SET_HAS_DOMAIN(setptr) \
  (OR_GET_INT ((char *) (setptr)) & OR_SET_DOMAIN_BIT)

#define OR_SET_HAS_ELEMENT_TAGS(setptr) \
  (OR_GET_INT ((char *) (setptr)) & OR_SET_TAG_BIT)

#define OR_SET_ELEMENT_COUNT(setptr) \
  ((OR_GET_INT ((char *) (setptr) + OR_SET_SIZE_OFFSET)))

#define OR_SET_DOMAIN_SIZE(setptr) \
  ((OR_GET_INT ((char *) (setptr) + OR_SET_DOMAIN_SIZE_OFFSET)))

/*
 * SET VARIABLE OFFSET TABLE ACCESSORS.
 * Should make sure that the set actually has one before using.
 */
#define OR_GET_SET_VAR_TABLE(setptr) \
  ((int *) ((char *) (setptr) + OR_SET_HEADER_SIZE))

#define OR_SET_ELEMENT_OFFSET(setptr, element) \
  (OR_VAR_TABLE_ELEMENT_OFFSET_INTERNAL (OR_GET_SET_VAR_TABLE (setptr), element, BIG_VAR_OFFSET_SIZE))

/*
 * SET BOUND BIT ACCESSORS
 *
 * Should make sure that the set actually has these before using.
 * Its essentially the same as OR_GET_SET_VAR_TABLE since these will
 * be in the same position and can't both appear at the same time.
 */

#define OR_GET_SET_BOUND_BITS(setptr) \
  (int *) ((char *) (setptr) + OR_SET_HEADER_SIZE)

/*
 * OR_SUB_HEADER_SIZE
 *
 * Used to tag each substructure.  Same as the object header currently.
 *   class oid, repid, flags
 */
#define OR_SUB_HEADER_SIZE  OR_OID_SIZE + OR_INT_SIZE + OR_INT_SIZE

/*
 * OR_SUB_DOMAIN_AND_HEADER_SIZE
 *
 * Hack for the class transformer, since we always currently know what the
 * substructure lists contain, this allows us to skip over the packed domain
 * quickly.  Must match the stuff packed by or_put_sub_domain_and_header().
 */
#define OR_SUB_DOMAIN_SIZE  OR_INT_SIZE

/* VARIABLE HEADER */
#define OR_VARIABLE_HEADER_SIZE 4

#define OR_GET_VARIABLE_TYPE(ptr) (OR_GET_INT ((int *) (ptr)))

/* class */
enum
{
  ORC_REP_DIR_OFFSET = 8,
  ORC_HFID_FILEID_OFFSET = 16,
  ORC_HFID_VOLID_OFFSET = 20,
  ORC_HFID_PAGEID_OFFSET = 24,
  ORC_FIXED_COUNT_OFFSET = 28,
  ORC_VARIABLE_COUNT_OFFSET = 32,
  ORC_FIXED_LENGTH_OFFSET = 36,
  ORC_ATT_COUNT_OFFSET = 40,
  ORC_SHARED_COUNT_OFFSET = 48,
  ORC_CLASS_ATTR_COUNT_OFFSET = 60,
  ORC_CLASS_FLAGS = 64,
  ORC_CLASS_TYPE = 68,
  ORC_CLASS_TDE_ALGORITHM = 84
};

enum
{
  ORC_NAME_INDEX = 0,
  ORC_LOADER_COMMANDS_INDEX = 1,
  ORC_REPRESENTATIONS_INDEX = 2,
  ORC_SUBCLASSES_INDEX = 3,
  ORC_SUPERCLASSES_INDEX = 4,
  ORC_ATTRIBUTES_INDEX = 5,
  ORC_SHARED_ATTRS_INDEX = 6,
  ORC_CLASS_ATTRS_INDEX = 7,
  ORC_METHODS_INDEX = 8,
  ORC_CLASS_METHODS_INDEX = 9,
  ORC_METHOD_FILES_INDEX = 10,
  ORC_RESOLUTIONS_INDEX = 11,
  ORC_QUERY_SPEC_INDEX = 12,
  ORC_TRIGGERS_INDEX = 13,
  ORC_PROPERTIES_INDEX = 14,
  ORC_COMMENT_INDEX = 15,
  ORC_PARTITION_INDEX = 16,

  /* add a new one above */

  ORC_LAST_INDEX,

  ORC_CLASS_VAR_ATT_COUNT = ORC_LAST_INDEX
};

/* attribute */
enum
{
  ORC_ATT_ID_OFFSET = 0,
  ORC_ATT_TYPE_OFFSET = 4,
  ORC_ATT_DEF_ORDER_OFFSET = 12,
  ORC_ATT_CLASS_OFFSET = 16,
  ORC_ATT_FLAG_OFFSET = 24,
  ORC_ATT_INDEX_OFFSET = 28
};

enum
{
  ORC_ATT_NAME_INDEX = 0,
  ORC_ATT_CURRENT_VALUE_INDEX = 1,
  ORC_ATT_ORIGINAL_VALUE_INDEX = 2,
  ORC_ATT_DOMAIN_INDEX = 3,
  ORC_ATT_TRIGGER_INDEX = 4,
  ORC_ATT_PROPERTIES_INDEX = 5,
  ORC_ATT_COMMENT_INDEX = 6,

  /* add a new one above */

  ORC_ATT_LAST_INDEX,

  ORC_ATT_VAR_ATT_COUNT = ORC_ATT_LAST_INDEX
};

/* representation */
enum
{
  ORC_REP_ID_OFFSET = 0,
  ORC_REP_FIXED_COUNT_OFFSET = 4,
  ORC_REP_VARIABLE_COUNT_OFFSET = 8
};

enum
{
  ORC_REP_ATTRIBUTES_INDEX = 0,
  ORC_REP_PROPERTIES_INDEX = 1,

  /* add a new one above */

  ORC_REP_LAST_INDEX,

  ORC_REP_VAR_ATT_COUNT = ORC_REP_LAST_INDEX
};

/* rep_attribute */
enum
{
  ORC_REPATT_ID_OFFSET = 0,
  ORC_REPATT_TYPE_OFFSET = 4
};

enum
{
  ORC_REPATT_DOMAIN_INDEX = 0,

  /* add a new one above */

  ORC_REPATT_LAST_INDEX,

  ORC_REPATT_VAR_ATT_COUNT = ORC_REPATT_LAST_INDEX
};

/* domain */
enum
{
  ORC_DOMAIN_TYPE_OFFSET = 0,
  ORC_DOMAIN_PRECISION_OFFSET = 4,
  ORC_DOMAIN_SCALE_OFFSET = 8,
  ORC_DOMAIN_CODESET_OFFSET = 12,
  ORC_DOMAIN_COLLATION_ID_OFFSET = 16,
  ORC_DOMAIN_CLASS_OFFSET = 20
};

enum
{
  ORC_DOMAIN_SETDOMAIN_INDEX = 0,
  ORC_DOMAIN_ENUMERATION_INDEX = 1,
  ORC_DOMAIN_SCHEMA_JSON_OFFSET = 2,

  /* add a new one above */

  ORC_DOMAIN_LAST_INDEX,

  ORC_DOMAIN_VAR_ATT_COUNT = ORC_DOMAIN_LAST_INDEX
};

/* method */
enum
{
  ORC_METHOD_NAME_INDEX = 0,
  ORC_METHOD_SIGNATURE_INDEX = 1,
  ORC_METHOD_PROPERTIES_INDEX = 2,

  /* add a new one above */

  ORC_METHOD_LAST_INDEX,

  ORC_METHOD_VAR_ATT_COUNT = ORC_METHOD_LAST_INDEX
};

/* method argument */
enum
{
  ORC_METHARG_DOMAIN_INDEX = 0,

  /* add a new one above */

  ORC_METHARG_LAST_INDEX,

  ORC_METHARG_VAR_ATT_COUNT = ORC_METHARG_LAST_INDEX
};

/* method signature */
enum
{
  ORC_METHSIG_FUNCTION_NAME_INDEX = 0,
  ORC_METHSIG_SQL_DEF_INDEX = 1,
  ORC_METHSIG_RETURN_VALUE_INDEX = 2,
  ORC_METHSIG_ARGUMENTS_INDEX = 3,

  /* add a new one above */

  ORC_METHSIG_LAST_INDEX,

  ORC_METHSIG_VAR_ATT_COUNT = ORC_METHSIG_LAST_INDEX
};

/* method file */
enum
{
  ORC_METHFILE_NAME_INDEX = 0,
  ORC_METHFILE_PROPERTIES_INDEX = 1,

  /* add a new one above */

  ORC_METHFILE_LAST_INDEX,

  ORC_METHFILE_VAR_ATT_COUNT = ORC_METHFILE_LAST_INDEX
};

/* query spec */
enum
{
  ORC_QUERY_SPEC_SPEC_INDEX = 0,

  /* add a new one above */

  ORC_QUERY_LAST_INDEX,

  ORC_QUERY_SPEC_VAR_ATT_COUNT = ORC_QUERY_LAST_INDEX
};

/* resolution */
enum
{
  ORC_RES_NAME_INDEX = 0,
  ORC_RES_ALIAS_INDEX = 1,

  /* add a new one above */

  ORC_RES_LAST_INDEX,

  ORC_RES_VAR_ATT_COUNT = ORC_RES_LAST_INDEX
};

/* partition */
enum
{
  ORC_PARTITION_NAME_INDEX = 0,
  ORC_PARTITION_EXPR_INDEX = 1,
  ORC_PARTITION_VALUES_INDEX = 2,
  ORC_PARTITION_COMMENT_INDEX = 3,

  /* add a new one above */
  ORC_PARTITION_LAST_INDEX,

  ORC_PARTITION_VAR_ATT_COUNT = ORC_PARTITION_LAST_INDEX
};

/* MEMORY REPRESENTATION STRUCTURES */

#define OR_BINARY_MAX_LENGTH 65535
#define OR_BINARY_LENGTH_MASK 0xFFFF
#define OR_BINARY_PAD_SHIFT  16

typedef struct db_binary DB_BINARY;
struct db_binary
{
  unsigned char *data;
  unsigned int length;
};

/*
 * DB_REFERENCE
 *    This is a common structure header used by DB_SET and DB_ELO.
 *    It encapsulates ownership information that must be maintained
 *    by these two types.  General routines can be written to maintain
 *    ownership information for both types.
 *
 */
typedef struct db_reference DB_REFERENCE;
struct db_reference
{
  struct db_object *handle;
  struct db_object *owner;
  int attribute;
};

/*
 * SETOBJ
 *    This is the primitive set object header.
 */
typedef struct setobj SETOBJ;

typedef struct db_set SETREF;

#if defined (__cplusplus)
class JSON_VALIDATOR;
#endif

/*
 * OR_VARINFO
 *    Memory representation for a variable offset table.  This is build
 *    from a disk offset table, either in an object header or in a
 *    set header.
 */
typedef struct or_varinfo OR_VARINFO;
struct or_varinfo
{
  int offset;
  int length;
};

#if __WORDSIZE == 32

#define OR_ALIGNED_BUF(size) \
union \
  { \
    double dummy; \
    char buf[(size) + MAX_ALIGNMENT]; \
  }

#define OR_ALIGNED_BUF_START(abuf) (PTR_ALIGN (abuf.buf, MAX_ALIGNMENT))
#define OR_ALIGNED_BUF_SIZE(abuf) (sizeof (abuf.buf) - MAX_ALIGNMENT)

#else /* __WORDSIZE == 32 */

#define OR_ALIGNED_BUF(size) \
union \
  { \
    double dummy; \
    char buf[(size)]; \
  }

#define OR_ALIGNED_BUF_START(abuf) (abuf.buf)
#define OR_ALIGNED_BUF_SIZE(abuf) (sizeof (abuf.buf))

#endif

#define OR_INFINITE_POINTER ((void *) (~((UINTPTR) 0UL)))

typedef struct or_buf OR_BUF;
struct or_buf
{
  char *buffer;
  char *ptr;
  char *endptr;
  struct or_fixup *fixups;
};

/* Need to translate types of DB_TYPE_OBJECT into DB_TYPE_OID in server-side */
#define OR_PACK_DOMAIN_OBJECT_TO_OID(p, d, o, n) \
  or_pack_domain ((p), \
                  TP_DOMAIN_TYPE (d) == DB_TYPE_OBJECT ? &tp_Oid_domain : (d), \
                  (o), (n))

#define ASSERT_ALIGN(ptr, alignment) (assert (PTR_ALIGN (ptr, alignment) == ptr))

#if defined __cplusplus
extern "C"
{
#endif

  extern int db_string_put_cs_and_collation (DB_VALUE * value, const int codeset, const int collation_id);
  extern int db_enum_put_cs_and_collation (DB_VALUE * value, const int codeset, const int collation_id);

  extern int valcnv_convert_value_to_string (DB_VALUE * value);
  extern int valcnv_convert_collection_value_to_string_all_elements (DB_VALUE * value);

#if defined __cplusplus
}
#endif

extern int or_rep_id (RECDES * record);
extern int or_set_rep_id (RECDES * record, int repid);
extern int or_chn (RECDES * record);
extern int or_replace_chn (RECDES * record, int chn);
extern int or_mvcc_get_repid_and_flags (OR_BUF * buf, int *error);
extern int or_mvcc_set_repid_and_flags (OR_BUF * buf, int mvcc_flag, int repid, int bound_bit,
                    int variable_offset_size);
extern char *or_class_name (RECDES * record);

/* Pointer based decoding functions */
extern int or_set_element_offset (char *setptr, int element);

#if defined(ENABLE_UNUSED_FUNCTION)
extern int or_get_bound_bit (char *bound_bits, int element);
extern void or_put_bound_bit (char *bound_bits, int element, int bound);
#endif

/* Data packing functions */
extern char *or_pack_int (char *ptr, int number);
#if defined(ENABLE_UNUSED_FUNCTION)
extern char *or_pack_bigint (char *ptr, DB_BIGINT number);
#endif
extern char *or_pack_int64 (char *ptr, INT64 number);
extern char *or_pack_float (char *ptr, float number);
extern char *or_pack_double (char *ptr, double number);
#if defined(ENABLE_UNUSED_FUNCTION)
extern char *or_pack_time (char *ptr, DB_TIME time);
extern char *or_pack_date (char *ptr, DB_DATE date);
extern char *or_pack_monetary (char *ptr, DB_MONETARY * money);
extern char *or_pack_utime (char *ptr, DB_UTIME utime);
#endif
extern char *or_pack_short (char *ptr, short number);
extern char *or_pack_string_with_null_padding (char *ptr, const char *stream, size_t len);
extern char *or_pack_stream (char *ptr, const char *stream, size_t len);
extern char *or_pack_string (char *ptr, const char *string);
extern char *or_pack_string_with_length (char *ptr, const char *string, int length);
extern char *or_pack_errcode (char *ptr, int error);
extern char *or_pack_oid (char *ptr, const OID * oid);
extern char *or_pack_oid_array (char *ptr, int n, const OID * oids);
extern char *or_pack_hfid (const char *ptr, const HFID * hfid);
extern char *or_pack_btid (char *buf, const BTID * btid);
extern char *or_pack_ehid (char *buf, EHID * btid);
extern char *or_pack_recdes (char *buf, RECDES * recdes);
extern char *or_pack_log_lsa (const char *ptr, const struct log_lsa *lsa);
extern char *or_unpack_log_lsa (char *ptr, struct log_lsa *lsa);
extern char *or_unpack_set (char *ptr, setobj ** set, struct tp_domain *domain);
extern char *or_unpack_setref (char *ptr, DB_SET ** ref);
extern char *or_pack_listid (char *ptr, void *listid);
extern char *or_pack_lock (char *ptr, LOCK lock);
extern char *or_pack_set_header (char *buf, DB_TYPE stype, DB_TYPE etype, int bound_bits, int size);
extern char *or_pack_set_node (char *ptr, void *set_node);
extern char *or_pack_int_array (char *buffer, int count, const int *int_array);
#if defined(ENABLE_UNUSED_FUNCTION)
extern char *or_pack_elo (char *ptr, void *elo);
extern char *or_pack_string_array (char *buffer, int count, const char **string_array);
extern char *or_pack_db_value_array (char *buffer, int count, DB_VALUE * val);
#endif

/* should be using the or_pack_value family instead ! */
extern char *or_pack_db_value (char *buffer, DB_VALUE * var);
extern char *or_unpack_db_value (char *buffer, DB_VALUE * val);
extern int or_db_value_size (DB_VALUE * var);

/* Data unpacking functions */
extern char *or_unpack_int (char *ptr, int *number);
#if defined(ENABLE_UNUSED_FUNCTION)
extern char *or_unpack_bigint (char *ptr, DB_BIGINT * number);
#endif
extern char *or_unpack_int64 (char *ptr, INT64 * number);
extern char *or_unpack_int_array (char *ptr, int n, int **number_array);
extern char *or_unpack_longint (char *ptr, int *number);
extern char *or_unpack_short (char *ptr, short *number);
extern char *or_unpack_float (char *ptr, float *number);
extern char *or_unpack_double (char *ptr, double *number);
#if defined(ENABLE_UNUSED_FUNCTION)
extern char *or_unpack_time (char *ptr, DB_TIME * time);
extern char *or_unpack_date (char *ptr, DB_DATE * date);
extern char *or_unpack_monetary (char *ptr, DB_MONETARY * money);
extern char *or_unpack_utime (char *ptr, DB_UTIME * utime);
#endif
extern char *or_unpack_stream (char *ptr, char *stream, size_t len);
extern char *or_unpack_string (char *ptr, char **string);
extern char *or_unpack_string_alloc (char *ptr, char **string);
extern char *or_unpack_string_nocopy (char *ptr, char **string);
extern char *or_unpack_errcode (char *ptr, int *error);
extern char *or_unpack_oid (char *ptr, OID * oid);
extern char *or_unpack_oid_array (char *ptr, int n, OID ** oids);
extern char *or_unpack_hfid (char *ptr, HFID * hfid);
extern char *or_unpack_hfid_array (char *ptr, int n, HFID ** hfids);
extern char *or_unpack_btid (char *buf, BTID * btid);
extern char *or_unpack_ehid (char *buf, EHID * btid);
extern char *or_unpack_recdes (char *buf, RECDES ** recdes);
extern char *or_unpack_listid (char *ptr, void *listid_ptr);
extern char *or_unpack_unbound_listid (char *ptr, void **listid_ptr);
extern char *or_unpack_lock (char *ptr, LOCK * lock);
extern char *or_unpack_set_header (char *buf, DB_TYPE * stype, DB_TYPE * etype, int *bound_bits, int *size);
extern char *or_unpack_method_sig_list (char *ptr, void **method_sig_list_ptr);
extern char *or_unpack_set_node (char *ptr, void *set_node_ptr);
#if defined(ENABLE_UNUSED_FUNCTION)
extern char *or_unpack_string_array (char *buffer, char ***string_array, int *cnt);
extern char *or_unpack_db_value_array (char *buffer, DB_VALUE ** val, int *count);
extern char *or_unpack_elo (char *ptr, void **elo_ptr);
#endif
extern char *or_pack_ptr (char *ptr, UINTPTR ptrval);
extern char *or_unpack_ptr (char *ptr, UINTPTR * ptrval);
extern char *or_pack_key_val_range (char *ptr, const void *key_val_range_ptr);
extern char *or_unpack_key_val_range (char *ptr, void *key_val_range_ptr);

extern char *or_pack_bool_array (char *ptr, const bool * bools, int size);
extern char *or_unpack_bool_array (char *ptr, bool ** bools);
extern int or_packed_bool_array_length (const bool * bools, int size);

/* pack/unpack support functions */
extern int or_packed_stream_length (size_t len);
extern int or_packed_string_length (const char *string, int *strlen);
#if defined(ENABLE_UNUSED_FUNCTION)
extern int or_align_length (int length);
#endif /* ENABLE_UNUSED_FUNCTION */
extern int or_packed_varbit_length (int bitlen);

/*
 * to avoid circular dependencies, don't require the definition of QFILE_LIST_ID in
 * this file (it references DB_TYPE)
 */
extern int or_listid_length (void *listid);
extern int or_set_node_length (void *set_node_ptr);
#if defined(ENABLE_UNUSED_FUNCTION)
extern int or_elo_length (void *elo_ptr);
extern int or_packed_string_array_length (int count, const char **string_array);
extern int or_packed_db_value_array_length (int count, DB_VALUE * val);
#endif

extern void or_encode (char *buffer, const char *source, int size);
extern void or_decode (const char *buffer, char *dest, int size);

STATIC_INLINE void or_init (OR_BUF * buf, char *data, int length) __attribute__ ((ALWAYS_INLINE));

/* Pack/unpack support functions */
STATIC_INLINE int or_advance (OR_BUF * buf, int offset) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_seek (OR_BUF * buf, int psn) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_pad (OR_BUF * buf, int length) __attribute__ ((ALWAYS_INLINE));

STATIC_INLINE int or_put_align32 (OR_BUF * buf) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_align (OR_BUF * buf, int alignment) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_align (OR_BUF * buf, int align) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_align32 (OR_BUF * buf) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_align64 (OR_BUF * buf) __attribute__ ((ALWAYS_INLINE));

/*
 * NUMERIC DATA TRANSFORMS
 *    This set of functions handles the transformation of the
 *    numeric types byte, short, integer, float, and double.
 *
 */

STATIC_INLINE int or_put_byte (OR_BUF * buf, int num) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_short (OR_BUF * buf, int num) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_int (OR_BUF * buf, int num) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_bigint (OR_BUF * buf, DB_BIGINT num) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_float (OR_BUF * buf, float num) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_double (OR_BUF * buf, double num) __attribute__ ((ALWAYS_INLINE));

STATIC_INLINE int or_get_byte (OR_BUF * buf, int *error) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_short (OR_BUF * buf, int *error) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_int (OR_BUF * buf, int *error) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE DB_BIGINT or_get_bigint (OR_BUF * buf, int *error) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE float or_get_float (OR_BUF * buf, int *error) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE double or_get_double (OR_BUF * buf, int *error) __attribute__ ((ALWAYS_INLINE));

/*
 * EXTENDED TYPE TRANSLATORS
 *    This set of functions reads and writes the extended types time,
 *    utime, date, and monetary.
 */

STATIC_INLINE int or_put_time (OR_BUF * buf, DB_TIME * timeval) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_utime (OR_BUF * buf, DB_UTIME * timeval) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_timestamptz (OR_BUF * buf, DB_TIMESTAMPTZ * ts_tz) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_date (OR_BUF * buf, DB_DATE * date) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_datetime (OR_BUF * buf, DB_DATETIME * datetimeval) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_datetimetz (OR_BUF * buf, DB_DATETIMETZ * datetimetz) __attribute__ ((ALWAYS_INLINE));
extern int or_put_monetary (OR_BUF * buf, DB_MONETARY * monetary);

STATIC_INLINE int or_get_time (OR_BUF * buf, DB_TIME * timeval) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_utime (OR_BUF * buf, DB_UTIME * timeval) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_timestamptz (OR_BUF * buf, DB_TIMESTAMPTZ * ts_tz) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_date (OR_BUF * buf, DB_DATE * date) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_datetime (OR_BUF * buf, DB_DATETIME * datetime) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_datetimetz (OR_BUF * buf, DB_DATETIMETZ * datetimetz) __attribute__ ((ALWAYS_INLINE));
extern int or_get_monetary (OR_BUF * buf, DB_MONETARY * monetary);

#if defined(ENABLE_UNUSED_FUNCTION)
extern int or_put_binary (OR_BUF * buf, DB_BINARY * binary);
#endif
STATIC_INLINE int or_put_data (OR_BUF * buf, const char *data, int length) __attribute__ ((ALWAYS_INLINE));
extern int or_put_varbit (OR_BUF * buf, const char *string, int bitlen);
extern int or_put_varchar (OR_BUF * buf, char *string, int size, int length);
STATIC_INLINE int or_put_string_aligned (OR_BUF * buf, char *string) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_string_aligned_with_length (OR_BUF * buf, const char *str) __attribute__ ((ALWAYS_INLINE));

STATIC_INLINE int or_get_data (OR_BUF * buf, char *data, int length) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_varbit_length (OR_BUF * buf, int *intval) __attribute__ ((ALWAYS_INLINE));
/* Get the compressed and the decompressed lengths of a string stored in buffer */
/* Legacy alias for compression-length-only reads. */
#define or_get_varchar_compression_lengths(buf, compressed_size, decompressed_size) \
  or_get_string_header (buf, NULL, decompressed_size, compressed_size)

STATIC_INLINE int or_varbit_length (int bitlen) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_varchar_length (int length, int size, int compressed_size) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_varbit_length_internal (int bitlen, int align) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_varchar_length_internal (int length, int size, int compressed_size, int align)
  __attribute__ ((ALWAYS_INLINE));

STATIC_INLINE int or_skip_varbit (OR_BUF * buf, int align) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_skip_varchar (OR_BUF * buf, int align) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_skip_varbit_remainder (OR_BUF * buf, int bitlen, int align) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_skip_varchar_remainder (OR_BUF * buf, int charlen, int align) __attribute__ ((ALWAYS_INLINE));

#if defined(ENABLE_UNUSED_FUNCTION)
extern int or_length_binary (DB_BINARY * binary);
extern int or_length_string (char *string);
#endif

/*
 * DISK IDENTIFIER TRANSLATORS
 *    Translators for the disk identifiers OID, HFID, BTID, EHID.
 */

STATIC_INLINE int or_put_oid (OR_BUF * buf, const OID * oid) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_mvccid (OR_BUF * buf, MVCCID mvccid) __attribute__ ((ALWAYS_INLINE));

STATIC_INLINE int or_get_oid (OR_BUF * buf, OID * oid) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_mvccid (OR_BUF * buf, MVCCID * mvccid) __attribute__ ((ALWAYS_INLINE));

/* VARIABLE OFFSET TABLE ACCESSORS */

STATIC_INLINE int or_put_big_var_offset (OR_BUF * buf, int num) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_offset (OR_BUF * buf, int num) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_offset_internal (OR_BUF * buf, int num, int offset_size) __attribute__ ((ALWAYS_INLINE));

STATIC_INLINE int or_get_big_var_offset (OR_BUF * buf, int *error) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_offset (OR_BUF * buf, int *error) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_offset_internal (OR_BUF * buf, int *error, int offset_size) __attribute__ ((ALWAYS_INLINE));

/* Data unpacking functions */

extern int or_packed_put_varbit (OR_BUF * buf, const char *string, int bitlen);
extern int or_packed_put_varchar (OR_BUF * buf, char *string, int size, int length);
extern int or_packed_varchar_length (int length, int size, int compressed_size);
extern int or_packed_recdesc_length (int length);

extern char *or_unpack_var_table (char *ptr, int nvars, OR_VARINFO * vars);
extern OR_VARINFO *or_get_var_table (OR_BUF * buf, int nvars, char *(*allocator) (int));
extern OR_VARINFO *or_get_var_table_internal (OR_BUF * buf, int nvars, char *(*allocator) (int), int offset_size);

/* DOMAIN functions */
extern int or_packed_domain_size (struct tp_domain *domain, int include_classoids);
extern char *or_pack_domain (char *ptr, struct tp_domain *domain, int include_classoids, int is_null);
extern char *or_unpack_domain (char *ptr, struct tp_domain **domain_ptr, int *is_null);
extern int or_put_domain (OR_BUF * buf, struct tp_domain *domain, int include_classoids, int is_null);
extern struct tp_domain *or_get_domain (OR_BUF * buf, struct tp_domain *dom, int *is_null);
extern int or_put_sub_domain (OR_BUF * buf);

/* SET functions */
extern void or_packed_set_info (DB_TYPE set_type, struct tp_domain *domain, int include_domain, int *bound_bits,
                int *offset_table, int *element_tags, int *element_size);

extern int or_put_set_header (OR_BUF * buf, DB_TYPE set_type, int size, int domain, int bound_bits, int offset_table,
                  int element_tags, int common_sub_header);

extern int or_get_set_header (OR_BUF * buf, DB_TYPE * set_type, int *size, int *domain, int *bound_bits,
                  int *offset_table, int *element_tags, int *common_sub_header);

extern int or_skip_set_header (OR_BUF * buf);

extern int or_packed_set_length (setobj * set, int include_domain);

extern void or_put_set (OR_BUF * buf, setobj * set, int include_domain);

extern setobj *or_get_set (OR_BUF * buf, struct tp_domain *domain);
extern int or_disk_set_size (OR_BUF * buf, struct tp_domain *domain, DB_TYPE * set_type);

/* DB_VALUE functions */
extern int or_packed_value_size (const DB_VALUE * value, int collapse_null, int include_domain,
                 int include_domain_classoids);

extern int or_put_value (OR_BUF * buf, DB_VALUE * value, int collapse_null, int include_domain,
             int include_domain_classoids);

extern int or_get_value (OR_BUF * buf, DB_VALUE * value, struct tp_domain *domain, int expected, bool copy);

extern char *or_pack_value (char *buf, DB_VALUE * value);
extern char *or_pack_mem_value (char *ptr, DB_VALUE * value, int *packed_len_except_alignment);
extern char *or_unpack_value (const char *buf, DB_VALUE * value);
extern char *or_unpack_mem_value (char *buf, DB_VALUE * value);

extern int or_packed_enumeration_size (const DB_ENUMERATION * e);
extern int or_put_enumeration (OR_BUF * buf, const DB_ENUMERATION * e);
extern int or_get_enumeration (OR_BUF * buf, DB_ENUMERATION * e);
extern int or_header_size (char *ptr);
extern char *or_pack_mvccid (char *ptr, const MVCCID mvccid);
extern char *or_unpack_mvccid (char *ptr, MVCCID * mvccid);

extern char *or_pack_sha1 (char *ptr, const SHA1Hash * sha1);
extern char *or_unpack_sha1 (char *ptr, SHA1Hash * sha1);

extern int or_packed_spacedb_size (const SPACEDB_ALL * all, const SPACEDB_ONEVOL * vols, const SPACEDB_FILES * files);
extern char *or_pack_spacedb (char *ptr, const SPACEDB_ALL * all, const SPACEDB_ONEVOL * vols,
                  const SPACEDB_FILES * files);
extern char *or_unpack_spacedb (char *ptr, SPACEDB_ALL * all, SPACEDB_ONEVOL ** vols, SPACEDB_FILES * files);

/* class object */
extern int classobj_decompose_property_oid (const char *buffer, int *volid, int *fileid, int *pageid);
extern void classobj_initialize_default_expr (DB_DEFAULT_EXPR * default_expr);
extern int classobj_get_prop (DB_SEQ * properties, const char *name, DB_VALUE * pvalue);
#if defined (__cplusplus)
extern int or_get_json_validator (OR_BUF * buf, REFPTR (JSON_VALIDATOR, validator));
extern int or_put_json_validator (OR_BUF * buf, JSON_VALIDATOR * validator);
extern int or_get_json_schema (OR_BUF * buf, REFPTR (char, schema));
extern int or_put_json_schema (OR_BUF * buf, const char *schema);
#endif

/* Because of the STRING encoding, this one could not be changed for over 255, just lower. */
#define OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION 255

#define OR_IS_STRING_LENGTH_COMPRESSABLE(str_length) \
  ((str_length) >= OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION && (str_length) <= LZ4_MAX_INPUT_SIZE)

/*
 * VARIABLE-LENGTH STRING HEADER on disk (used by both VARCHAR and CHAR)
 *
 * The header begins with a 2-bit header type field stored in the top
 * 2 bits of the first byte. The header type determines which of the
 * following four header formats is used.
 *
 * Each format is optimized to minimize header overhead for different
 * string size ranges:
 *
 *   TINY   ( 1 byte ) : [ header type(2bit) | length(2bit) | size(4bit) ]
 *   SMALL  ( 4 bytes) : [ header type(2bit) | length(14bit) ][ size(16bit) ]
 *   MEDIUM ( 6 bytes) : [ header type(2bit) | length(14bit) ][ size(16bit) ][ compressed_size(16bit) ]
 *   LARGE  (12 bytes) : [ header type(2bit) | length(30bit) ][ size(32bit) ][ compressed_size(32bit) ]
 *
 * After the header, the string payload follows:
 *   - size bytes when stored in uncompressed form
 *   - compressed_size bytes when stored in compressed form
 *
 * Field meanings:
 * length          : character count
 * size            : decompressed byte count (includes CHAR trailing-space padding)
 * compressed_size : LZ4-compressed byte count;
 *                   0 when stored uncompressed
 */

/*
 * Each header type is selected based on the string payload size.
 *
 * The TINY and SMALL formats are used for payloads smaller than the compression threshold
 * (OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION = 255),
 * while MEDIUM and LARGE support compressed storage.
 *
 * type   | bytes | length range                  | size range
 * -------+-------+-------------------------------+-------------------------------
 * TINY   | 1     | 0 ~ 3                         | 0 ~ 12 (13~15 reserved)
 * SMALL  | 4     | 1 ~ 254 (255~16383 reserved)  | 13 ~ 254 (255~65535 reserved)
 * MEDIUM | 6     | 255 ~ 16383                   | 255 ~ 65535
 * LARGE  | 12    | 16384 ~ 1G                    | 65536 ~ 4G
 */
#define OR_STRING_HEADER_TYPE_TINY                (0x0u)
#define OR_STRING_HEADER_TYPE_SMALL               (0x1u)
#define OR_STRING_HEADER_TYPE_MEDIUM              (0x2u)
#define OR_STRING_HEADER_TYPE_LARGE               (0x3u)

/*
 * Shift amounts used to place or extract the header type field.
 *
 * The header type always occupies the top 2 bits of the first byte,
 * so the shift value is:
 *   shift = (word bit width) - 2
 *
 *   SHIFT_IN_BYTE  (6)  : 8-bit byte
 *                         - used when writing TINY headers
 *                         - used when reading all header types
 *                           (the header type can be read from the first byte alone)
 *
 *   SHIFT_IN_SHORT (14) : 16-bit short
 *                         - used when writing SMALL and MEDIUM headers
 *                           whose first header word is 2 bytes
 *
 *   SHIFT_IN_INT   (30) : 32-bit int
 *                         - used when writing LARGE headers
 *                           whose first header word is 4 bytes
 */
#define OR_STRING_HEADER_TYPE_SHIFT_IN_BYTE        (6)
#define OR_STRING_HEADER_TYPE_SHIFT_IN_SHORT       (14)
#define OR_STRING_HEADER_TYPE_SHIFT_IN_INT         (30)

/*
 * Bit masks used to read or write the length field of each header type
 * by accessors (e.g. OR_DISK_STRING_GET_* / OR_DISK_STRING_PUT_*).
 *
 * TINY additionally requires LENGTH_SHIFT_TINY and SIZE_MASK_TINY
 * because its length and size fields are packed into a single byte.
 */
#define OR_STRING_LENGTH_MASK_LARGE                (0x3FFFFFFFu)    /* 30-bit length (LARGE) */
#define OR_STRING_LENGTH_MASK_MEDIUM               (0x3FFFu)    /* 14-bit length (SMALL/MEDIUM) */
#define OR_STRING_LENGTH_MASK_TINY                 (0x3u)   /* 2-bit length (TINY) */

#define OR_STRING_LENGTH_SHIFT_TINY                (4)  /* TINY: shift length above size bits */
#define OR_STRING_SIZE_MASK_TINY                   (0xFu)   /* TINY: 4-bit size field */

/*
 * Maximum size and length thresholds used by
 * or_string_pick_header_type().
 *
 * Header types are primarily divided by string byte count,
 * with the main split at the compression threshold
 * (OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION = 255).
 *
 * However, TINY and MEDIUM additionally require length checks
 * because their length fields are narrower than their size ranges.
 * If the length exceeds the selected type's length field limit,
 * the next larger header type is used.
 *
 * Example:
 *   ASCII "abcd" has size = 4 (fits TINY size range 0~12),
 *   but length = 4 exceeds TINY's 2-bit length limit (max 3),
 *   so SMALL is selected.
 *
 * SMALL has no MAX_LENGTH because its maximum size (254)
 * always fits within the 14-bit length field.
 *
 * LARGE has no MAX_SIZE or MAX_LENGTH because it is the
 * final header type.
 */
#define OR_DISK_STRING_TINY_MAX_SIZE                (12)    /* 3 chars * up to 4 bytes per UTF-8 char */
#define OR_DISK_STRING_TINY_MAX_LENGTH              (3) /* 2-bit length field limit */
#define OR_DISK_STRING_SMALL_MAX_SIZE               (254)   /* below compression threshold */
#define OR_DISK_STRING_MEDIUM_MAX_SIZE              (65535) /* 16-bit size/csize field limit */
#define OR_DISK_STRING_MEDIUM_MAX_LENGTH            (16383) /* 14-bit length field limit */

/* On-disk byte size of each header type's header. */
#define OR_DISK_STRING_TINY_HEADER_SIZE             (1)
#define OR_DISK_STRING_SMALL_HEADER_SIZE            (4)
#define OR_DISK_STRING_MEDIUM_HEADER_SIZE           (6)
#define OR_DISK_STRING_LARGE_HEADER_SIZE            (12)

/*
 * Disk header field accessors used by or_put_string_header()
 * and or_get_string_header() to read or write individual
 * header fields for each header type.
 *
 * GET_* read length / size / compressed_size from a header buffer.
 * PUT_TINY_HEADER packs the entire 1-byte TINY header (type | length | size).
 * PUT_*_LEAD writes the first header word (header type bits combined with length).
 * PUT_*_SIZE / PUT_*_CSIZE write the corresponding field at a fixed offset.
 */

/* GET — read from buffer */
#define OR_DISK_STRING_GET_TINY_LENGTH(b) \
  ((int) (((unsigned int) (unsigned char) (b) >> OR_STRING_LENGTH_SHIFT_TINY) & OR_STRING_LENGTH_MASK_TINY))
#define OR_DISK_STRING_GET_TINY_SIZE(b) \
  ((int) ((unsigned int) (unsigned char) (b) & OR_STRING_SIZE_MASK_TINY))

#define OR_DISK_STRING_GET_SMALL_LENGTH(buf) \
  ((int) ((unsigned int) (unsigned short) OR_GET_SHORT (buf) & OR_STRING_LENGTH_MASK_MEDIUM))
#define OR_DISK_STRING_GET_SMALL_SIZE(buf) \
  ((int) (unsigned short) OR_GET_SHORT ((char *) (buf) + OR_SHORT_SIZE))

#define OR_DISK_STRING_GET_MEDIUM_LENGTH(buf) \
  ((int) ((unsigned int) (unsigned short) OR_GET_SHORT (buf) & OR_STRING_LENGTH_MASK_MEDIUM))
#define OR_DISK_STRING_GET_MEDIUM_SIZE(buf) \
  ((int) (unsigned short) OR_GET_SHORT ((char *) (buf) + OR_SHORT_SIZE))
#define OR_DISK_STRING_GET_MEDIUM_CSIZE(buf) \
  ((int) (unsigned short) OR_GET_SHORT ((char *) (buf) + OR_SHORT_SIZE * 2))

#define OR_DISK_STRING_GET_LARGE_LENGTH(buf) \
  ((int) ((unsigned int) OR_GET_INT (buf) & OR_STRING_LENGTH_MASK_LARGE))
#define OR_DISK_STRING_GET_LARGE_SIZE(buf) \
  (OR_GET_INT ((char *) (buf) + OR_INT_SIZE))
#define OR_DISK_STRING_GET_LARGE_CSIZE(buf) \
  (OR_GET_INT ((char *) (buf) + OR_INT_SIZE * 2))

/* PUT — write to buffer */
#define OR_DISK_STRING_PUT_TINY_HEADER(buf, length, size) \
  (*(unsigned char *) (buf) = \
   (unsigned char) ((OR_STRING_HEADER_TYPE_TINY << OR_STRING_HEADER_TYPE_SHIFT_IN_BYTE) \
                    | (((unsigned int) (length) & OR_STRING_LENGTH_MASK_TINY) << OR_STRING_LENGTH_SHIFT_TINY) \
                    | ((unsigned int) (size) & OR_STRING_SIZE_MASK_TINY)))

#define OR_DISK_STRING_PUT_SMALL_LEAD(buf, length) \
  (OR_PUT_SHORT (buf, \
                (short) ((OR_STRING_HEADER_TYPE_SMALL << OR_STRING_HEADER_TYPE_SHIFT_IN_SHORT) \
                         | ((unsigned int) (length) & OR_STRING_LENGTH_MASK_MEDIUM))))
#define OR_DISK_STRING_PUT_SMALL_SIZE(buf, size) \
  (OR_PUT_SHORT ((char *) (buf) + OR_SHORT_SIZE, (short) (size)))

#define OR_DISK_STRING_PUT_MEDIUM_LEAD(buf, length) \
  (OR_PUT_SHORT (buf, \
                (short) ((OR_STRING_HEADER_TYPE_MEDIUM << OR_STRING_HEADER_TYPE_SHIFT_IN_SHORT) \
                         | ((unsigned int) (length) & OR_STRING_LENGTH_MASK_MEDIUM))))
#define OR_DISK_STRING_PUT_MEDIUM_SIZE(buf, size) \
  (OR_PUT_SHORT ((char *) (buf) + OR_SHORT_SIZE, (short) (size)))
#define OR_DISK_STRING_PUT_MEDIUM_CSIZE(buf, csize) \
  (OR_PUT_SHORT ((char *) (buf) + OR_SHORT_SIZE * 2, (short) (csize)))

#define OR_DISK_STRING_PUT_LARGE_LEAD(buf, length) \
  (OR_PUT_INT (buf, \
              (int) ((OR_STRING_HEADER_TYPE_LARGE << OR_STRING_HEADER_TYPE_SHIFT_IN_INT) \
                     | ((unsigned int) (length) & OR_STRING_LENGTH_MASK_LARGE))))
#define OR_DISK_STRING_PUT_LARGE_SIZE(buf, size) \
  (OR_PUT_INT ((char *) (buf) + OR_INT_SIZE, (int) (size)))
#define OR_DISK_STRING_PUT_LARGE_CSIZE(buf, csize) \
  (OR_PUT_INT ((char *) (buf) + OR_INT_SIZE * 2, (int) (csize)))

/*
 * CHAR/VARCHAR IN-MEMORY STRING HEADER (NOT CLOB/BLOB)
 *
 * The in-memory layout differs from the on-disk layout in two ways:
 *
 *  1. In-memory strings never store compressed bytes (see mr_setmem_char_type_common()),
 *     so the compressed_size field is removed.
 *
 *  2. Without a compression threshold separating SMALL
 *     and MEDIUM, the in-memory layout uses only three
 *     header types: TINY, SMALL, and LARGE.
 *
 *     SMALL therefore absorbs the uncompressed disk
 *     MEDIUM range (size up to 65535, the 16-bit size field limit).
 *
 * Per-header-type byte layout:
 *   TINY  (1 byte)  : [ type(2) | length(2) | size(4) ]
 *   SMALL (4 bytes) : [ type(2) | length(14) ][ size(16) ]
 *   LARGE (8 bytes) : [ type(2) | length(30) ][ size(32) ]
 *
 * Field meanings:
 *   length : character count
 *   size   : uncompressed byte count
 */

/*
 * Maximum size and length thresholds used by or_mem_string_pick_header_type().
 *
 * Header type selection follows the same rules as the
 * on-disk layout, but without a compression threshold.
 *
 * SMALL therefore covers all sizes up to the 16-bit size field limit (65535).
 *
 * LARGE has no MAX_SIZE or MAX_LENGTH because it is the final header type.
 *
 *   type   | bytes | length range | size range
 *   -------+-------+--------------+--------------------------
 *   TINY   | 1     | 0 ~ 3        | 0 ~ 12 (13~15 reserved)
 *   SMALL  | 4     | up to 16383  | 13 ~ 65535
 *   LARGE  | 8     | up to 30-bit | 65536 ~ UINT32_MAX
 */
#define OR_MEM_STRING_TINY_HEADER_SIZE      (1)
#define OR_MEM_STRING_SMALL_HEADER_SIZE     (4)
#define OR_MEM_STRING_LARGE_HEADER_SIZE     (8)

/*
 * Selection works the same as the on-disk version (see line 1480):
 * size first, length checked as fallback.
 */
#define OR_MEM_STRING_TINY_MAX_SIZE         (12)    /* same as disk TINY */
#define OR_MEM_STRING_TINY_MAX_LENGTH       (3) /* 2-bit length field limit */
#define OR_MEM_STRING_SMALL_MAX_SIZE        (65535) /* 16-bit size field limit */
#define OR_MEM_STRING_SMALL_MAX_LENGTH      (16383) /* 14-bit length field limit */

/*
 * In-memory header field accessors.
 *
 * These follow the same GET/PUT pattern as OR_DISK_STRING_*,
 * but the in-memory layout has no compressed_size field and
 * no MEDIUM header type.
 *
 * TINY and SMALL use the same layout as the on-disk version,
 * so their accessors reuse the disk macros.
 *
 * LARGE uses a different layout size (8 bytes instead of 12, 
 * with no compressed_size field), so it defines separate 
 * GET/PUT accessors.
 */

/* GET — read from buffer */
#define OR_MEM_STRING_GET_TINY_LENGTH(b)          (OR_DISK_STRING_GET_TINY_LENGTH (b))
#define OR_MEM_STRING_GET_TINY_SIZE(b)            (OR_DISK_STRING_GET_TINY_SIZE (b))
#define OR_MEM_STRING_GET_SMALL_LENGTH(buf)       (OR_DISK_STRING_GET_SMALL_LENGTH (buf))
#define OR_MEM_STRING_GET_SMALL_SIZE(buf)         (OR_DISK_STRING_GET_SMALL_SIZE (buf))
#define OR_MEM_STRING_GET_LARGE_LENGTH(buf) \
  ((int) ((unsigned int) OR_GET_INT (buf) & OR_STRING_LENGTH_MASK_LARGE))
#define OR_MEM_STRING_GET_LARGE_SIZE(buf) \
  (OR_GET_INT ((char *) (buf) + OR_INT_SIZE))

/* PUT — write to buffer */
#define OR_MEM_STRING_PUT_TINY_HEADER(buf, length, size)   (OR_DISK_STRING_PUT_TINY_HEADER (buf, length, size))
#define OR_MEM_STRING_PUT_SMALL_LEAD(buf, length)          (OR_DISK_STRING_PUT_SMALL_LEAD (buf, length))
#define OR_MEM_STRING_PUT_SMALL_SIZE(buf, size)            (OR_DISK_STRING_PUT_SMALL_SIZE (buf, size))
#define OR_MEM_STRING_PUT_LARGE_LEAD(buf, length) \
  (OR_PUT_INT (buf, \
              (int) ((OR_STRING_HEADER_TYPE_LARGE << OR_STRING_HEADER_TYPE_SHIFT_IN_INT) \
                     | ((unsigned int) (length) & OR_STRING_LENGTH_MASK_LARGE))))
#define OR_MEM_STRING_PUT_LARGE_SIZE(buf, size) \
  (OR_PUT_INT ((char *) (buf) + OR_INT_SIZE, (int) (size)))

STATIC_INLINE unsigned int or_string_pick_header_type (int length, int size) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_string_header (OR_BUF * buf, int length, int size, int compressed_size)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_string_header (OR_BUF * buf, int *length, int *size, int *compressed_size)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_string_header_size (int length, int size) __attribute__ ((ALWAYS_INLINE));

STATIC_INLINE unsigned int or_mem_string_pick_header_type (int length, int size) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_put_mem_string_header (char *mem, int length, int size) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_get_mem_string_header (char *mem, int *length, int *size) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_mem_string_header_size (int length, int size) __attribute__ ((ALWAYS_INLINE));

/*
 * MIDXKEY HEADER ACCESSORS
 */

STATIC_INLINE int or_multi_nullmap_size (const int n_elements) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_multi_offset_table_size (const int n_elements) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_multi_header_size (const int n_elements) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void or_multi_clear_header (char *nullmap_ptr, const int n_elements) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void or_multi_set_not_null (char *nullmap_ptr, const int index) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void or_multi_set_null (char *nullmap_ptr, const int index) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE bool or_multi_is_not_null (char *nullmap_ptr, const int index) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE bool or_multi_is_null (char *nullmap_ptr, const int index) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE char *or_multi_get_offset_table (char *nullmap_ptr, const int n_elements) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE char *or_multi_get_element_offset_ptr (char *nullmap_ptr, const int n_elements, const int index)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_multi_get_element_offset_internal (char *nullmap_ptr, const int n_elements, const int index)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_multi_get_element_offset (char *nullmap_ptr, const int n_elements, const int index)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_multi_get_next_element_offset (char *nullmap_ptr, const int n_elements, const int index)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int or_multi_get_size_offset (char *nullmap_ptr, const int n_elements) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void or_multi_put_element_offset_internal (char *nullmap_ptr, const int n_elements, const int offset,
                             const int index) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void or_multi_put_element_offset (char *nullmap_ptr, const int n_elements, const int offset,
                        const int index) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void or_multi_put_next_element_offset (char *nullmap_ptr, const int n_elements, const int offset,
                             const int index) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void or_multi_put_size_offset (char *nullmap_ptr, const int n_elements, const int offset)
  __attribute__ ((ALWAYS_INLINE));

/*
 * or_init - initialize the field of an OR_BUF
 *    return: void
 *    buf(in/out): or buffer to initialize
 *    data(in): buffer data
 *    length(in):  buffer data length
 */
STATIC_INLINE void
or_init (OR_BUF * buf, char *data, int length)
{
  buf->buffer = data;
  buf->ptr = data;

  /* TODO: LP64 check DB_INT32_MAX */
  if (length <= 0 || length == DB_INT32_MAX)
    {
      buf->endptr = (char *) OR_INFINITE_POINTER;
    }
  else
    {
      buf->endptr = data + length;
    }

  buf->fixups = NULL;
}

/*
 * OR_BUF PACK/UNPACK FUNCTIONS
 */

/*
 * or_seek - This sets the translation pointer directly to a certain byte in
 * the buffer.
 *    return: ERROR_SUCCESS or error code
 *    buf(in/out): or buffer
 *    psn(in): position within buffer
 */
STATIC_INLINE int
or_seek (OR_BUF * buf, int psn)
{
  assert (buf->buffer + psn <= buf->endptr);
  buf->ptr = buf->buffer + psn;
  return NO_ERROR;
}

/*
 * or_advance - This advances the translation pointer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    offset(in): number of bytes to skip
 */
STATIC_INLINE int
or_advance (OR_BUF * buf, int offset)
{
  assert (buf->ptr + offset <= buf->endptr);
  buf->ptr += offset;
  return NO_ERROR;
}

/*
 * or_pad - This advances the translation pointer and adds bytes of zero.
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    length(in): number of bytes to pad
 *
 * Note:
 *    This advances the translation pointer and adds bytes of zero.
 *    This is used add padding bytes to ensure proper alignment of
 *    some data types.
 */
STATIC_INLINE int
or_pad (OR_BUF * buf, int length)
{
  assert (buf->ptr + length <= buf->endptr);
  (void) memset (buf->ptr, 0, length);
  buf->ptr += length;
  return NO_ERROR;
}

/*
 * or_put_align32 - pad zero bytes round up to 4 byte bound
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 */
STATIC_INLINE int
or_put_align32 (OR_BUF * buf)
{
  unsigned int bits;
  int rc = NO_ERROR;

  bits = (UINTPTR) buf->ptr & 3;
  if (bits)
    {
      assert (buf->ptr + 4 - bits <= buf->endptr);
      rc = or_pad (buf, 4 - bits);
    }

  return rc;
}

/*
 * or_align () - Align current buffer pointer to given alignment.
 *
 * return    : Error code.
 * buf (in/out)  : Buffer.
 * alignment (in) : Desired alignment.
 */
STATIC_INLINE int
or_align (OR_BUF * buf, int alignment)
{
  char *new_ptr = PTR_ALIGN (buf->ptr, alignment);
  assert (new_ptr <= buf->endptr);
  buf->ptr = new_ptr;
  return NO_ERROR;
}

/*
 * or_get_align - adnvance or buf pointer to next alignment position
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    align(in):
 */
STATIC_INLINE int
or_get_align (OR_BUF * buf, int align)
{
  char *ptr;

  ptr = PTR_ALIGN (buf->ptr, align);
  assert (ptr <= buf->endptr);
  buf->ptr = ptr;
  return NO_ERROR;
}

/*
 * or_get_align32 - adnvance or buf pointer to next 4 byte alignment position
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 */
STATIC_INLINE int
or_get_align32 (OR_BUF * buf)
{
  unsigned int bits;
  int rc = NO_ERROR;

  bits = (UINTPTR) (buf->ptr) & 3;
  if (bits)
    {
      rc = or_advance (buf, 4 - bits);
    }

  return rc;
}

/*
 * or_get_align64 - adnvance or buf pointer to next 8 byte alignment position
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 */
STATIC_INLINE int
or_get_align64 (OR_BUF * buf)
{
  unsigned int bits;
  int rc = NO_ERROR;

  bits = (UINTPTR) (buf->ptr) & 7;
  if (bits)
    {
      rc = or_advance (buf, 8 - bits);
    }

  return rc;
}

/*
 * NUMERIC DATA TRANSFORMS
 *    This set of functions handles the transformation of the
 *    numeric types byte, short, integer, float, and double.
 *
 */

/*
 * or_put_byte - put a byte to or buffer
 *    return: NO_ERROR or error code
 *    buf(out/out): or buffer
 *    num(in): byte value
 */
STATIC_INLINE int
or_put_byte (OR_BUF * buf, int num)
{
  assert (buf->ptr + OR_BYTE_SIZE <= buf->endptr);
  OR_PUT_BYTE (buf->ptr, num);
  buf->ptr += OR_BYTE_SIZE;
  return NO_ERROR;
}

/*
 * or_get_byte - read a byte value from or buffer
 *    return: byte value read
 *    buf(in/out): or buffer
 *    error(out): NO_ERROR or error code
 */
STATIC_INLINE int
or_get_byte (OR_BUF * buf, int *error)
{
  int value = 0;

  assert (buf->ptr + OR_BYTE_SIZE <= buf->endptr);
  value = OR_GET_BYTE (buf->ptr);
  buf->ptr += OR_BYTE_SIZE;
  *error = NO_ERROR;

  return value;
}

/*
 * or_put_short - put a short value to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    num(in): short value to put
 */
STATIC_INLINE int
or_put_short (OR_BUF * buf, int num)
{
  ASSERT_ALIGN (buf->ptr, SHORT_ALIGNMENT);

  assert (buf->ptr + OR_SHORT_SIZE <= buf->endptr);
  OR_PUT_SHORT (buf->ptr, num);
  buf->ptr += OR_SHORT_SIZE;
  return NO_ERROR;
}

/*
 * or_get_short - read a short value from or buffer
 *    return: short value read
 *    buf(in/out): or buffer
 *    error(out): NO_ERROR or error code
 */
STATIC_INLINE int
or_get_short (OR_BUF * buf, int *error)
{
  int value = 0;

  ASSERT_ALIGN (buf->ptr, SHORT_ALIGNMENT);

  assert (buf->ptr + OR_SHORT_SIZE <= buf->endptr);
  value = OR_GET_SHORT (buf->ptr);
  buf->ptr += OR_SHORT_SIZE;
  *error = NO_ERROR;
  return value;
}

/*
 * or_put_int - put int value to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    num(in): int value to put
 */
STATIC_INLINE int
or_put_int (OR_BUF * buf, int num)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);
  assert (buf->ptr + OR_INT_SIZE <= buf->endptr);
  OR_PUT_INT (buf->ptr, num);
  buf->ptr += OR_INT_SIZE;
  return NO_ERROR;
}

/*
 * or_get_int - get int value from or buffer
 *    return: int value read
 *    buf(in/out): or buffer
 *    error(out): NO_ERROR or error code
 */
STATIC_INLINE int
or_get_int (OR_BUF * buf, int *error)
{
  int value = 0;

  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_INT_SIZE <= buf->endptr);
  value = OR_GET_INT (buf->ptr);
  buf->ptr += OR_INT_SIZE;
  *error = NO_ERROR;
  return value;
}


/*
 * or_put_bigint - put bigint value to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    num(in): bigint value to put
 */
STATIC_INLINE int
or_put_bigint (OR_BUF * buf, DB_BIGINT num)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_BIGINT_SIZE <= buf->endptr);
  OR_PUT_BIGINT (buf->ptr, &num);
  buf->ptr += OR_BIGINT_SIZE;
  return NO_ERROR;
}

/*
 * or_get_bigint - get bigint value from or buffer
 *    return: bigint value read
 *    buf(in/out): or buffer
 *    error(out): NO_ERROR or error code
 */
STATIC_INLINE DB_BIGINT
or_get_bigint (OR_BUF * buf, int *error)
{
  DB_BIGINT value = 0;

  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_BIGINT_SIZE <= buf->endptr);

  OR_GET_BIGINT (buf->ptr, &value);
  buf->ptr += OR_BIGINT_SIZE;
  *error = NO_ERROR;
  return value;
}

/*
 * or_put_float - put a float value to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    fnum(in): float value to put
 */
STATIC_INLINE int
or_put_float (OR_BUF * buf, float fnum)
{
  ASSERT_ALIGN (buf->ptr, FLOAT_ALIGNMENT);

  assert (buf->ptr + OR_FLOAT_SIZE <= buf->endptr);
  OR_PUT_FLOAT (buf->ptr, fnum);
  buf->ptr += OR_FLOAT_SIZE;
  return NO_ERROR;
}

/*
 * or_get_float - read a float value from or buffer
 *    return: float value read
 *    buf(in/out): or buffer
 *    error(out): NO_ERROR or error code
 */
STATIC_INLINE float
or_get_float (OR_BUF * buf, int *error)
{
  float value = 0.0;

  ASSERT_ALIGN (buf->ptr, FLOAT_ALIGNMENT);

  assert (buf->ptr + OR_FLOAT_SIZE <= buf->endptr);

  OR_GET_FLOAT (buf->ptr, &value);
  buf->ptr += OR_FLOAT_SIZE;
  *error = NO_ERROR;
  return value;
}

/*
 * or_put_double - put a double value to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    dnum(in): double value to put
 */
STATIC_INLINE int
or_put_double (OR_BUF * buf, double dnum)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_DOUBLE_SIZE <= buf->endptr);
  OR_PUT_DOUBLE (buf->ptr, dnum);
  buf->ptr += OR_DOUBLE_SIZE;
  return NO_ERROR;
}

/*
 * or_get_double - read a double value from or buffer
 *    return: double value read
 *    buf(in/out): or buffer
 *    error(out): NO_ERROR or error code
 */
STATIC_INLINE double
or_get_double (OR_BUF * buf, int *error)
{
  double value = 0.0;

  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);
  assert (buf->ptr + OR_DOUBLE_SIZE <= buf->endptr);

  OR_GET_DOUBLE (buf->ptr, &value);
  buf->ptr += OR_DOUBLE_SIZE;
  *error = NO_ERROR;
  return value;
}

/*
 * EXTENDED TYPE TRANSLATORS
 *    This set of functions reads and writes the extended types time,
 *    utime, date, and monetary.
 */

/*
 * or_put_time - write a DB_TIME to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    timeval(in): time value to write
 */
STATIC_INLINE int
or_put_time (OR_BUF * buf, DB_TIME * timeval)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_TIME_SIZE <= buf->endptr);
  OR_PUT_TIME (buf->ptr, timeval);
  buf->ptr += OR_TIME_SIZE;
  return NO_ERROR;
}

/*
 * or_get_time - read a  DB_TIME from or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    timeval(out): pointer to DB_TIME value
 */
STATIC_INLINE int
or_get_time (OR_BUF * buf, DB_TIME * timeval)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);
  assert (buf->ptr + OR_TIME_SIZE <= buf->endptr);
  OR_GET_TIME (buf->ptr, timeval);
  buf->ptr += OR_TIME_SIZE;
  return NO_ERROR;
}

/*
 * or_put_utime - write a timestamp value to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    timeval(in): pointer to timestamp value
 */
STATIC_INLINE int
or_put_utime (OR_BUF * buf, DB_UTIME * timeval)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_UTIME_SIZE <= buf->endptr);
  OR_PUT_UTIME (buf->ptr, timeval);
  buf->ptr += OR_UTIME_SIZE;
  return NO_ERROR;
}

/*
 * or_get_utime - read a timestamp value from or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    timeval(out): pointer to timestamp value
 */
STATIC_INLINE int
or_get_utime (OR_BUF * buf, DB_UTIME * timeval)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);
  assert (buf->ptr + OR_UTIME_SIZE <= buf->endptr);

  OR_GET_UTIME (buf->ptr, timeval);
  buf->ptr += OR_UTIME_SIZE;
  return NO_ERROR;
}

/*
 * or_put_timestamptz - write a timestamp with tz value to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    ts_tz(in): pointer to DB_TIMESTAMPTZ value
 */
STATIC_INLINE int
or_put_timestamptz (OR_BUF * buf, DB_TIMESTAMPTZ * ts_tz)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_TIMESTAMPTZ_SIZE <= buf->endptr);
  OR_PUT_TIMESTAMPTZ (buf->ptr, ts_tz);
  buf->ptr += OR_TIMESTAMPTZ_SIZE;
  return NO_ERROR;
}

/*
 * or_get_timestamptz - read a timestamp with tz value from or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    ts_tz(out): pointer to DB_TIMESTAMPTZ value
 */
STATIC_INLINE int
or_get_timestamptz (OR_BUF * buf, DB_TIMESTAMPTZ * ts_tz)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_TIMESTAMPTZ_SIZE <= buf->endptr);
  OR_GET_TIMESTAMPTZ (buf->ptr, ts_tz);
  buf->ptr += OR_TIMESTAMPTZ_SIZE;
  return NO_ERROR;
}

/*
 * or_put_date - write a DB_DATE value to or_buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    date(in): pointer to DB_DATE value
 */
STATIC_INLINE int
or_put_date (OR_BUF * buf, DB_DATE * date)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_DATE_SIZE <= buf->endptr);
  OR_PUT_DATE (buf->ptr, date);
  buf->ptr += OR_DATE_SIZE;
  return NO_ERROR;
}

/*
 * or_get_date - read a DB_DATE value from or_buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    date(out): pointer to DB_DATE value
 */
STATIC_INLINE int
or_get_date (OR_BUF * buf, DB_DATE * date)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_DATE_SIZE <= buf->endptr);
  OR_GET_DATE (buf->ptr, date);
  buf->ptr += OR_DATE_SIZE;
  return NO_ERROR;
}

/*
 * or_put_datetime - write a datetime value to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    datetimeval(in): pointer to datetime value
 */
STATIC_INLINE int
or_put_datetime (OR_BUF * buf, DB_DATETIME * datetimeval)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_DATETIME_SIZE <= buf->endptr);
  OR_PUT_DATETIME (buf->ptr, datetimeval);
  buf->ptr += OR_DATETIME_SIZE;
  return NO_ERROR;
}

/*
 * or_get_datetime - read a DB_DATETIME value from or_buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    date(out): pointer to DB_DATETIME value
 */
STATIC_INLINE int
or_get_datetime (OR_BUF * buf, DB_DATETIME * datetime)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_DATETIME_SIZE <= buf->endptr);
  OR_GET_DATETIME (buf->ptr, datetime);
  buf->ptr += OR_DATETIME_SIZE;
  return NO_ERROR;
}

/*
 * or_put_datetimetz - write a datetime with tz value to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    datetimetz(in): pointer to DB_DATETIMETZ value
 */
STATIC_INLINE int
or_put_datetimetz (OR_BUF * buf, DB_DATETIMETZ * datetimetz)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_DATETIMETZ_SIZE <= buf->endptr);
  OR_PUT_DATETIMETZ (buf->ptr, datetimetz);
  buf->ptr += OR_DATETIMETZ_SIZE;
  return NO_ERROR;
}

/*
 * or_get_datetimetz - read a datetime with tz value from or_buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    datetimetz(out): pointer to DB_DATETIMETZ value
 */
STATIC_INLINE int
or_get_datetimetz (OR_BUF * buf, DB_DATETIMETZ * datetimetz)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_DATETIMETZ_SIZE <= buf->endptr);
  OR_GET_DATETIMETZ (buf->ptr, datetimetz);
  buf->ptr += OR_DATETIMETZ_SIZE;
  return NO_ERROR;
}

/*
 * or_put_data - write an array of bytes to or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    data(in): pointer to data
 *    length(in): length in bytes
 */
STATIC_INLINE int
or_put_data (OR_BUF * buf, const char *data, int length)
{
  assert (buf->ptr + length <= buf->endptr);
  (void) memcpy (buf->ptr, data, length);
  buf->ptr += length;
  return NO_ERROR;
}

/*
 * or_get_data - read an array of bytes from or buffer for given length
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    data(in): pointer to buffer to read data into
 *    length(in): length of read data
 */
STATIC_INLINE int
or_get_data (OR_BUF * buf, char *data, int length)
{
  assert (buf->ptr + length <= buf->endptr);
  (void) memcpy (data, buf->ptr, length);
  buf->ptr += length;
  return NO_ERROR;
}

/*
 * or_get_varbit_length - get varbit length from or buffer
 *    return: length of varbit or 0 if error
 *    buf(in/out): or buffer
 *    rc(out): NO_ERROR or error code
 */
STATIC_INLINE int
or_get_varbit_length (OR_BUF * buf, int *rc)
{
  int net_bitlen = 0, bitlen = 0;

  /* unpack the size prefix */
  bitlen = or_get_byte (buf, rc);

  if (*rc != NO_ERROR)
    {
      return bitlen;
    }

  if (bitlen == 0xFF)
    {
      *rc = or_get_data (buf, (char *) &net_bitlen, OR_INT_SIZE);
      bitlen = OR_GET_INT (&net_bitlen);
    }
  return bitlen;
}

/*
 * or_put_string_header() - Write the variable-length string header.
 *
 *   return              : NO_ERROR or error code
 *   buf(in/out)         : or buffer
 *   length(in)          : character count
 *   size(in)            : decompressed byte count
 *   compressed_size(in) : LZ4-compressed byte count; 0 when stored uncompressed
 *                        (only present in MEDIUM and LARGE headers)
 *
 * Note:
 *   See the VARIABLE-LENGTH STRING HEADER comment above for the
 *   on-disk layout and header type selection rule.
 *
 *   Uses byte-level writes (OR_PUT_* + or_put_data) instead of
 *   or_put_int() / or_put_short() because this function may be
 *   called with unaligned buffers from CHAR_ALIGNMENT contexts.
 */
STATIC_INLINE int
or_put_string_header (OR_BUF * buf, int length, int size, int compressed_size)
{
  switch (or_string_pick_header_type (length, size))
    {
    case OR_STRING_HEADER_TYPE_TINY:
      {
    char header_buf[OR_DISK_STRING_TINY_HEADER_SIZE];
    OR_DISK_STRING_PUT_TINY_HEADER (header_buf, length, size);
    return or_put_data (buf, header_buf, OR_DISK_STRING_TINY_HEADER_SIZE);
      }

    case OR_STRING_HEADER_TYPE_SMALL:
      {
    char header_buf[OR_DISK_STRING_SMALL_HEADER_SIZE];
    OR_DISK_STRING_PUT_SMALL_LEAD (header_buf, length);
    OR_DISK_STRING_PUT_SMALL_SIZE (header_buf, size);
    return or_put_data (buf, header_buf, OR_DISK_STRING_SMALL_HEADER_SIZE);
      }

    case OR_STRING_HEADER_TYPE_MEDIUM:
      {
    char header_buf[OR_DISK_STRING_MEDIUM_HEADER_SIZE];
    OR_DISK_STRING_PUT_MEDIUM_LEAD (header_buf, length);
    OR_DISK_STRING_PUT_MEDIUM_SIZE (header_buf, size);
    OR_DISK_STRING_PUT_MEDIUM_CSIZE (header_buf, compressed_size);
    return or_put_data (buf, header_buf, OR_DISK_STRING_MEDIUM_HEADER_SIZE);
      }

    case OR_STRING_HEADER_TYPE_LARGE:
      {
    char header_buf[OR_DISK_STRING_LARGE_HEADER_SIZE];
    OR_DISK_STRING_PUT_LARGE_LEAD (header_buf, length);
    OR_DISK_STRING_PUT_LARGE_SIZE (header_buf, size);
    OR_DISK_STRING_PUT_LARGE_CSIZE (header_buf, compressed_size);
    return or_put_data (buf, header_buf, OR_DISK_STRING_LARGE_HEADER_SIZE);
      }

    default:
      assert (false);
      return ER_FAILED;
    }
}

/*
 * or_get_string_header() - Read the variable-length string header.
 *
 *   return               : NO_ERROR or error code
 *   buf(in/out)          : or buffer
 *   length(out)          : character count   (NULL to skip)
 *   size(out)            : decompressed byte count   (NULL to skip)
 *   compressed_size(out) : LZ4-compressed byte count, 0 when stored uncompressed
 *                          (only present in MEDIUM and LARGE headers; NULL to skip)
 *
 * Note:
 *   See the VARIABLE-LENGTH STRING HEADER comment above for the
 *   on-disk layout.
 *
 *   Byte 0 is peeked to determine the header type from the top
 *   2 bits. For SMALL, MEDIUM, and LARGE the peek does not advance
 *   buf->ptr, so the subsequent read re-includes byte 0.
 *
 *   Uses byte-level reads (or_get_data() + OR_GET_*) instead of
 *   or_get_int() / or_get_short() because this function may be
 *   called with unaligned buffers from CHAR_ALIGNMENT contexts.
 */
STATIC_INLINE int
or_get_string_header (OR_BUF * buf, int *length, int *size, int *compressed_size)
{
  int rc;
  int tmp_length = 0, tmp_size = 0, tmp_csize = 0;
  unsigned int header_type;
  unsigned char peek_byte;

  assert (buf->ptr + OR_BYTE_SIZE <= buf->endptr);
  peek_byte = (unsigned char) OR_GET_BYTE (buf->ptr);
  header_type = (unsigned int) peek_byte >> OR_STRING_HEADER_TYPE_SHIFT_IN_BYTE;

  switch (header_type)
    {
    case OR_STRING_HEADER_TYPE_TINY:
      /* TINY: 1 byte — entire header already in peek_byte */
      tmp_length = OR_DISK_STRING_GET_TINY_LENGTH (peek_byte);
      tmp_size = OR_DISK_STRING_GET_TINY_SIZE (peek_byte);
      buf->ptr += OR_BYTE_SIZE;
      break;

    case OR_STRING_HEADER_TYPE_SMALL:
      {
    char header_buf[OR_DISK_STRING_SMALL_HEADER_SIZE];
    rc = or_get_data (buf, header_buf, OR_DISK_STRING_SMALL_HEADER_SIZE);
    if (rc != NO_ERROR)
      {
        return rc;
      }
    tmp_length = OR_DISK_STRING_GET_SMALL_LENGTH (header_buf);
    tmp_size = OR_DISK_STRING_GET_SMALL_SIZE (header_buf);
    break;
      }

    case OR_STRING_HEADER_TYPE_MEDIUM:
      {
    char header_buf[OR_DISK_STRING_MEDIUM_HEADER_SIZE];
    rc = or_get_data (buf, header_buf, OR_DISK_STRING_MEDIUM_HEADER_SIZE);
    if (rc != NO_ERROR)
      {
        return rc;
      }
    tmp_length = OR_DISK_STRING_GET_MEDIUM_LENGTH (header_buf);
    tmp_size = OR_DISK_STRING_GET_MEDIUM_SIZE (header_buf);
    tmp_csize = OR_DISK_STRING_GET_MEDIUM_CSIZE (header_buf);
    break;
      }

    case OR_STRING_HEADER_TYPE_LARGE:
      {
    char header_buf[OR_DISK_STRING_LARGE_HEADER_SIZE];
    rc = or_get_data (buf, header_buf, OR_DISK_STRING_LARGE_HEADER_SIZE);
    if (rc != NO_ERROR)
      {
        return rc;
      }
    tmp_length = OR_DISK_STRING_GET_LARGE_LENGTH (header_buf);
    tmp_size = OR_DISK_STRING_GET_LARGE_SIZE (header_buf);
    tmp_csize = OR_DISK_STRING_GET_LARGE_CSIZE (header_buf);
    break;
      }

    default:
      assert (false);
      return ER_FAILED;
    }

  if (length != NULL)
    {
      *length = tmp_length;
    }
  if (size != NULL)
    {
      *size = tmp_size;
    }
  if (compressed_size != NULL)
    {
      *compressed_size = tmp_csize;
    }
  return NO_ERROR;
}

/*
 * or_string_pick_header_type() - Select the header type used for a
 *                                string of given length and size.
 *
 *   return     : OR_STRING_HEADER_TYPE_{TINY,SMALL,MEDIUM,LARGE}
 *   length(in) : character count
 *   size(in)   : decompressed byte count
 *
 * Note:
 *   Selects the smallest header type that can represent both
 *   the string size and length.
 *
 *   Shared by or_string_header_size() and
 *   or_put_string_header() so the computed header size
 *   always matches the actual written layout.
 */
STATIC_INLINE unsigned int
or_string_pick_header_type (int length, int size)
{
  if (size <= OR_DISK_STRING_TINY_MAX_SIZE && length <= OR_DISK_STRING_TINY_MAX_LENGTH)
    {
      return OR_STRING_HEADER_TYPE_TINY;
    }
  if (size <= OR_DISK_STRING_SMALL_MAX_SIZE)
    {
      return OR_STRING_HEADER_TYPE_SMALL;
    }
  if (size <= OR_DISK_STRING_MEDIUM_MAX_SIZE && length <= OR_DISK_STRING_MEDIUM_MAX_LENGTH)
    {
      return OR_STRING_HEADER_TYPE_MEDIUM;
    }
  return OR_STRING_HEADER_TYPE_LARGE;
}

/*
 * or_string_header_size() - Variable-length string header byte count.
 *
 *   return              : header byte count (1 / 4 / 6 / 12)
 *   length(in)          : character count
 *   size(in)            : decompressed byte count (caller's data size)
 *
 * Note:
 *   Mirrors or_put_string_header / or_get_string_header — uses the same
 *   or_string_pick_header_type() dispatch so the predicted byte count always
 *   matches what the emitter actually writes.
 */
STATIC_INLINE int
or_string_header_size (int length, int size)
{
  switch (or_string_pick_header_type (length, size))
    {
    case OR_STRING_HEADER_TYPE_TINY:
      return OR_DISK_STRING_TINY_HEADER_SIZE;
    case OR_STRING_HEADER_TYPE_SMALL:
      return OR_DISK_STRING_SMALL_HEADER_SIZE;
    case OR_STRING_HEADER_TYPE_MEDIUM:
      return OR_DISK_STRING_MEDIUM_HEADER_SIZE;
    case OR_STRING_HEADER_TYPE_LARGE:
      return OR_DISK_STRING_LARGE_HEADER_SIZE;
    default:
      assert (false);
      return OR_DISK_STRING_LARGE_HEADER_SIZE;
    }
}

/*
 * or_mem_string_pick_header_type() - Select the header type used for
 *                                    an in-memory string of given
 *                                    length and size.
 *
 *   return     : OR_STRING_HEADER_TYPE_{TINY, SMALL, LARGE} (never MEDIUM)
 *   length(in) : character count
 *   size(in)   : byte count (always uncompressed in memory)
 *
 * Note:
 *   In-memory strings are never compressed, so the
 *   MEDIUM header type is not used.
 *
 *   See the CHAR/VARCHAR IN-MEMORY STRING HEADER comment
 *   above for the layout and selection thresholds.
 *
 *   Shared by or_mem_string_header_size() and
 *   or_put_mem_string_header() so the computed header size
 *   always matches the actual written layout.
 */
STATIC_INLINE unsigned int
or_mem_string_pick_header_type (int length, int size)
{
  if (size <= OR_MEM_STRING_TINY_MAX_SIZE && length <= OR_MEM_STRING_TINY_MAX_LENGTH)
    {
      return OR_STRING_HEADER_TYPE_TINY;
    }
  if (size <= OR_MEM_STRING_SMALL_MAX_SIZE && length <= OR_MEM_STRING_SMALL_MAX_LENGTH)
    {
      return OR_STRING_HEADER_TYPE_SMALL;
    }
  return OR_STRING_HEADER_TYPE_LARGE;
}

/*
 * or_mem_string_header_size() - Mem header byte count for the given (length, size).
 */
STATIC_INLINE int
or_mem_string_header_size (int length, int size)
{
  switch (or_mem_string_pick_header_type (length, size))
    {
    case OR_STRING_HEADER_TYPE_TINY:
      return OR_MEM_STRING_TINY_HEADER_SIZE;
    case OR_STRING_HEADER_TYPE_SMALL:
      return OR_MEM_STRING_SMALL_HEADER_SIZE;
    case OR_STRING_HEADER_TYPE_LARGE:
      return OR_MEM_STRING_LARGE_HEADER_SIZE;
    default:
      assert (false);
      return OR_MEM_STRING_LARGE_HEADER_SIZE;
    }
}

/*
 * or_put_mem_string_header() - Write the in-memory string header
 *                              (no compressed_size field).
 *
 *   return     : NO_ERROR (cannot fail; int return type kept for
 *                API parity with or_get_mem_string_header())
 *   mem(out)   : caller-allocated memory buffer; must have at least
 *                or_mem_string_header_size(length, size) bytes available
 *   length(in) : character count
 *   size(in)   : uncompressed byte count
 *
 * Note:
 *   See the CHAR/VARCHAR IN-MEMORY STRING HEADER comment above
 *   for the layout and selection thresholds.
 *
 *   Unlike or_put_string_header(), this function does not use
 *   OR_BUF, perform bounds checks, or advance any pointer.
 *   The caller owns the destination buffer and its lifetime.
 */
STATIC_INLINE int
or_put_mem_string_header (char *mem, int length, int size)
{
  switch (or_mem_string_pick_header_type (length, size))
    {
    case OR_STRING_HEADER_TYPE_TINY:
      OR_MEM_STRING_PUT_TINY_HEADER (mem, length, size);
      return NO_ERROR;

    case OR_STRING_HEADER_TYPE_SMALL:
      OR_MEM_STRING_PUT_SMALL_LEAD (mem, length);
      OR_MEM_STRING_PUT_SMALL_SIZE (mem, size);
      return NO_ERROR;

    case OR_STRING_HEADER_TYPE_LARGE:
      OR_MEM_STRING_PUT_LARGE_LEAD (mem, length);
      OR_MEM_STRING_PUT_LARGE_SIZE (mem, size);
      return NO_ERROR;

    default:
      assert (false);
      return ER_FAILED;
    }
}

/*
 * or_get_mem_string_header() - Read the in-memory string header.
 *
 *   return    : NO_ERROR or ER_FAILED
 *   mem(in)   : memory pointer at the header start
 *   length(out): character count   (NULL to skip)
 *   size(out)  : byte count        (NULL to skip)
 *
 * Note:
 *   See the CHAR/VARCHAR IN-MEMORY STRING HEADER comment above
 *   for the layout.
 *
 *   Byte 0 is peeked to determine the header type from the top
 *   2 bits. MEDIUM is rejected because in-memory strings never
 *   use that header type.
 *
 *   Unlike or_get_string_header(), this function does not use
 *   OR_BUF or advance any pointer. The caller computes the
 *   payload start as:
 *     mem + or_mem_string_header_size(length, size)
 */
STATIC_INLINE int
or_get_mem_string_header (char *mem, int *length, int *size)
{
  int tmp_length = 0, tmp_size = 0;
  unsigned int header_type;
  unsigned char peek_byte;

  peek_byte = (unsigned char) OR_GET_BYTE (mem);
  header_type = (unsigned int) peek_byte >> OR_STRING_HEADER_TYPE_SHIFT_IN_BYTE;

  /* Parse into locals via OR_MEM_STRING_GET_* accessors; commit at bottom. */
  switch (header_type)
    {
    case OR_STRING_HEADER_TYPE_TINY:
      /* TINY: 1 byte — entire header already in peek_byte */
      tmp_length = OR_MEM_STRING_GET_TINY_LENGTH (peek_byte);
      tmp_size = OR_MEM_STRING_GET_TINY_SIZE (peek_byte);
      break;

    case OR_STRING_HEADER_TYPE_SMALL:
      tmp_length = OR_MEM_STRING_GET_SMALL_LENGTH (mem);
      tmp_size = OR_MEM_STRING_GET_SMALL_SIZE (mem);
      break;

    case OR_STRING_HEADER_TYPE_LARGE:
      tmp_length = OR_MEM_STRING_GET_LARGE_LENGTH (mem);
      tmp_size = OR_MEM_STRING_GET_LARGE_SIZE (mem);
      break;

    case OR_STRING_HEADER_TYPE_MEDIUM:
      assert (false);
      return ER_FAILED;

    default:
      assert (false);
      return ER_FAILED;
    }

  if (length != NULL)
    {
      *length = tmp_length;
    }
  if (size != NULL)
    {
      *size = tmp_size;
    }
  return NO_ERROR;
}

/*
 * or_put_string - write string to or buf
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    str(in): string to write
 *
 * Note:
 *    Does byte padding on strings to bring them up to 4 byte boundary.
 *
 *    There is no or_get_string since this is the same as or_get_data.
 *    Since the workspace allocator (and most other Unix allocators) will
 *    keep track of the size of allocated blocks (and they will be
 *    in word multiples anyway), we can just include the disk padding
 *    bytes with the string when it is brought in from disk even though
 *    the total length may be more than that returned by strlen.
 */
STATIC_INLINE int
or_put_string_aligned (OR_BUF * buf, char *str)
{
  int len, bits, pad;
  int rc = NO_ERROR;

  if (str == NULL)
    {
      return rc;
    }
  len = strlen (str) + 1;
  rc = or_put_data (buf, str, len);
  if (rc == NO_ERROR)
    {
      /* PAD */
      bits = len & 3;
      if (bits)
    {
      pad = 4 - bits;
      rc = or_pad (buf, pad);
    }
    }
  return rc;
}

/*
 *  this function also adds
 *  the length of the string to the buffer
 */
STATIC_INLINE int
or_put_string_aligned_with_length (OR_BUF * buf, const char *str)
{
  int len;
  int rc = NO_ERROR;

  if (str == NULL)
    {
      return rc;
    }
  len = (int) strlen (str) + 1;

  rc = or_put_int (buf, len);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  rc = or_put_data (buf, str, len);
  if (rc == NO_ERROR)
    {
      or_align (buf, OR_INT_SIZE);
    }
  return rc;
}

/*
 * or_packed_varbit_length - returns packed varbit length of or buffer encoding
 *    return: varbit encoding length
 *    bitlen(in): varbit length
 */
STATIC_INLINE int
or_varbit_length (int bitlen)
{
  return or_varbit_length_internal (bitlen, CHAR_ALIGNMENT);
}

/*
 * or_varchar_length - byte count of a packed varchar (header + data).
 *
 *   return              : header bytes + data bytes (CHAR_ALIGNMENT, no NUL/pad)
 *   length(in)          : character count
 *   size(in)            : decompressed byte count
 *   compressed_size(in) : LZ4-compressed byte count; 0 when stored uncompressed
 */
STATIC_INLINE int
or_varchar_length (int length, int size, int compressed_size)
{
  return or_varchar_length_internal (length, size, compressed_size, CHAR_ALIGNMENT);
}

STATIC_INLINE int
or_varbit_length_internal (int bitlen, int align)
{
  int len;

  /* calculate size of length prefix */
  if (bitlen < 0xFF)
    {
      len = 1;
    }
  else
    {
      len = 1 + OR_INT_SIZE;
    }

  /* add in the string length in bytes */
  len += ((bitlen + 7) / 8);

  if (align == INT_ALIGNMENT)
    {
      /* round up to a word boundary */
      len = DB_ALIGN (len, INT_ALIGNMENT);
    }
  return len;
}

STATIC_INLINE int
or_varchar_length_internal (int length, int size, int compressed_size, int align)
{
  int header = or_string_header_size (length, size);
  int data = (compressed_size > 0) ? compressed_size : size;
  int len = header + data;

  if (align == INT_ALIGNMENT)
    {
      len += OR_BYTE_SIZE;  /* trailing NUL */
      len = DB_ALIGN (len, INT_ALIGNMENT);
    }

  return len;
}

/*
 * or_skip_varbit - skip varbit in or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    align(in):
 */
STATIC_INLINE int
or_skip_varbit (OR_BUF * buf, int align)
{
  int bitlen;
  int rc = NO_ERROR;

  bitlen = or_get_varbit_length (buf, &rc);
  if (rc == NO_ERROR)
    {
      return (or_skip_varbit_remainder (buf, bitlen, align));
    }
  return rc;
}

/*
 * or_skip_varchar - skip varchar field (length + data) from or buffer
 *    return: NO_ERROR or error code.
 *    buf(in/out): or buffer
 *    align(in):
 *
 * Note:
 *   Reads the string header via or_get_string_header(), then
 *   advances past the data bytes (compressed_size if present,
 *   otherwise size) and any trailing padding via
 *   or_skip_varchar_remainder().
 */
STATIC_INLINE int
or_skip_varchar (OR_BUF * buf, int align)
{
  int size = 0, compressed_size = 0, rc = NO_ERROR;

  /* length unused for skip — only data byte count matters. */
  rc = or_get_string_header (buf, NULL, &size, &compressed_size);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  return or_skip_varchar_remainder (buf, (compressed_size > 0) ? compressed_size : size, align);
}

/*
 * or_skip_varbit_remainder - skip varbit field of given length in or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    bitlen(in): bitlen to skip
 *    align(in):
 */
STATIC_INLINE int
or_skip_varbit_remainder (OR_BUF * buf, int bitlen, int align)
{
  int rc = NO_ERROR;

  rc = or_advance (buf, BITS_TO_BYTES (bitlen));
  if (rc == NO_ERROR && align == INT_ALIGNMENT)
    {
      rc = or_get_align32 (buf);
    }
  return rc;
}

/*
 * or_skip_varchar_remainder - skip varchar field of given length
 *    return: NO_ERROR if successful, error code otherwise
 *    buf(in/out): or buffer
 *    charlen(in): length of varchar field to skip
 *    align(in):
 */
STATIC_INLINE int
or_skip_varchar_remainder (OR_BUF * buf, int charlen, int align)
{
  int rc = NO_ERROR;

  if (align == INT_ALIGNMENT)
    {
      rc = or_advance (buf, charlen + 1);
      if (rc == NO_ERROR)
    {
      rc = or_get_align32 (buf);
    }
    }
  else
    {
      rc = or_advance (buf, charlen);
    }

  return rc;
}

/*
 * DISK IDENTIFIER TRANSLATORS
 *    Translators for the disk identifiers OID, HFID, BTID, EHID.
 */

/*
 * or_put_oid - write content of an OID structure from or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    oid(in): pointer to OID
 */
STATIC_INLINE int
or_put_oid (OR_BUF * buf, const OID * oid)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_OID_SIZE <= buf->endptr);
  if (oid == NULL)
    {
      OR_PUT_NULL_OID (buf->ptr);
    }
  else
    {
      /* Cannot allow any temp oid's to be written */
      if (OID_ISTEMP (oid))
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      assert (false);
    }
      OR_PUT_OID (buf->ptr, oid);
    }
  buf->ptr += OR_OID_SIZE;
  return NO_ERROR;
}

/*
 * or_get_oid - read content of an OID structure from or buffer
 *    return: NO_ERROR or error code
 *    buf(in/out): or buffer
 *    oid(out): pointer to OID
 */
STATIC_INLINE int
or_get_oid (OR_BUF * buf, OID * oid)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);
  assert (buf->ptr + OR_OID_SIZE <= buf->endptr);
  OR_GET_OID (buf->ptr, oid);
  buf->ptr += OR_OID_SIZE;
  return NO_ERROR;
}

/*
 * or_put_mvccid () - Put an MVCCID to OR Buffer.
 *
 * return      : Error code.
 * buf (in)    : OR Buffer
 * mvccid (in) : MVCCID
 */
STATIC_INLINE int
or_put_mvccid (OR_BUF * buf, MVCCID mvccid)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  assert (buf->ptr + OR_MVCCID_SIZE <= buf->endptr);
  OR_PUT_MVCCID (buf->ptr, &mvccid);
  buf->ptr += OR_MVCCID_SIZE;
  return NO_ERROR;
}

/*
 * or_get_mvccid () - Get an MVCCID from OR Buffer.
 *
 * return   : MVCCID
 * buf (in/out) : OR Buffer.
 * error (out)  : Error code.
 */
STATIC_INLINE int
or_get_mvccid (OR_BUF * buf, MVCCID * mvccid)
{
  assert (mvccid != NULL);
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  *mvccid = MVCCID_NULL;
  assert (buf->ptr + OR_MVCCID_SIZE <= buf->endptr);
  OR_GET_MVCCID (buf->ptr, mvccid);
  buf->ptr += OR_MVCCID_SIZE;
  return NO_ERROR;
}

/* VARIABLE OFFSET TABLE ACCESSORS */

STATIC_INLINE int
or_put_big_var_offset (OR_BUF * buf, int num)
{
  return or_put_int (buf, num);
}

STATIC_INLINE int
or_get_big_var_offset (OR_BUF * buf, int *error)
{
  return or_get_int (buf, error);
}

STATIC_INLINE int
or_put_offset (OR_BUF * buf, int num)
{
  return or_put_big_var_offset (buf, num);
}

STATIC_INLINE int
or_get_offset (OR_BUF * buf, int *error)
{
  return or_get_big_var_offset (buf, error);
}

STATIC_INLINE int
or_put_offset_internal (OR_BUF * buf, int num, int offset_size)
{
  if (offset_size == OR_BYTE_SIZE)
    {
      return or_put_byte (buf, num);
    }
  else if (offset_size == OR_SHORT_SIZE)
    {
      return or_put_short (buf, num);
    }
  else
    {
      assert (offset_size == OR_INT_SIZE);
      return or_put_int (buf, num);
    }
}

STATIC_INLINE int
or_get_offset_internal (OR_BUF * buf, int *error, int offset_size)
{
  if (offset_size == OR_BYTE_SIZE)
    {
      return or_get_byte (buf, error);
    }
  else if (offset_size == OR_SHORT_SIZE)
    {
      return or_get_short (buf, error);
    }
  else
    {
      assert (offset_size == OR_INT_SIZE);
      return or_get_int (buf, error);
    }
}

/*
 * MIDXKEY HEADER ACCESSORS
 */

STATIC_INLINE int
or_multi_nullmap_size (const int n_elements)
{
  int nullmap_size;

  assert (n_elements > 0);

  nullmap_size = ((n_elements + 7) >> 3);
  assert (nullmap_size > 0);

  return nullmap_size;
}

STATIC_INLINE int
or_multi_offset_table_size (const int n_elements)
{
  assert (n_elements > 0);

  return n_elements + 1;
}

STATIC_INLINE int
or_multi_header_size (const int n_elements)
{
  return or_multi_nullmap_size (n_elements) + or_multi_offset_table_size (n_elements);
}

STATIC_INLINE void
or_multi_clear_header (char *nullmap_ptr, const int n_elements)
{
  assert (nullmap_ptr != NULL);

  memset (nullmap_ptr, 0x00, or_multi_header_size (n_elements));
}

STATIC_INLINE void
or_multi_set_not_null (char *nullmap_ptr, const int index)
{
  assert (nullmap_ptr != NULL);
  assert (index >= 0);

  (*(nullmap_ptr + (index >> 3))) |= (1 << (index & 7));
}


STATIC_INLINE void
or_multi_set_null (char *nullmap_ptr, const int index)
{
  assert (nullmap_ptr != NULL);
  assert (index >= 0);

  (*(nullmap_ptr + (index >> 3))) &= (~(1 << (index & 7)));
}

STATIC_INLINE bool
or_multi_is_not_null (char *nullmap_ptr, const int index)
{
  assert (nullmap_ptr != NULL);
  assert (index >= 0);

  if ((*(nullmap_ptr + (index >> 3))) & (1 << (index & 7)))
    {
      return true;
    }

  return false;
}

STATIC_INLINE bool
or_multi_is_null (char *nullmap_ptr, const int index)
{
  return !or_multi_is_not_null (nullmap_ptr, index);
}

STATIC_INLINE char *
or_multi_get_offset_table (char *nullmap_ptr, const int n_elements)
{
  assert (nullmap_ptr != NULL);

  return nullmap_ptr + or_multi_nullmap_size (n_elements);
}

STATIC_INLINE char *
or_multi_get_element_offset_ptr (char *nullmap_ptr, const int n_elements, const int index)
{
  return or_multi_get_offset_table (nullmap_ptr, n_elements) + index;
}

STATIC_INLINE int
or_multi_get_element_offset_internal (char *nullmap_ptr, const int n_elements, const int index)
{
  int offset;

  offset = OR_GET_BYTE (or_multi_get_element_offset_ptr (nullmap_ptr, n_elements, index));
  assert (offset >= or_multi_header_size (n_elements));
  assert (offset <= OR_MULTI_MAX_OFFSET);

  return offset;
}

STATIC_INLINE int
or_multi_get_element_offset (char *nullmap_ptr, const int n_elements, const int index)
{
  int offset;

  offset = or_multi_get_element_offset_internal (nullmap_ptr, n_elements, index);
  if (offset < OR_MULTI_MAX_OFFSET)
    {
      return offset;
    }

  return -1;
}

STATIC_INLINE int
or_multi_get_next_element_offset (char *nullmap_ptr, const int n_elements, const int index)
{
  return or_multi_get_element_offset (nullmap_ptr, n_elements, index + 1);
}

STATIC_INLINE int
or_multi_get_size_offset (char *nullmap_ptr, const int n_elements)
{
  int offset;

  offset = or_multi_get_element_offset_internal (nullmap_ptr, n_elements, n_elements);
  if (offset < OR_MULTI_MAX_OFFSET)
    {
      return offset;
    }

  return -1;
}

STATIC_INLINE void
or_multi_put_element_offset_internal (char *nullmap_ptr, const int n_elements, const int offset, const int index)
{
  assert (nullmap_ptr != NULL);
  assert (n_elements > 0);
  assert (offset >= or_multi_header_size (n_elements));
  assert (offset <= OR_MULTI_MAX_OFFSET);
  assert (index >= 0);

  OR_PUT_BYTE (or_multi_get_element_offset_ptr (nullmap_ptr, n_elements, index), offset);
}

STATIC_INLINE void
or_multi_put_element_offset (char *nullmap_ptr, const int n_elements, const int offset, const int index)
{
  if (offset < OR_MULTI_MAX_OFFSET)
    {
      or_multi_put_element_offset_internal (nullmap_ptr, n_elements, offset, index);
    }
  else
    {
      or_multi_put_element_offset_internal (nullmap_ptr, n_elements, OR_MULTI_MAX_OFFSET, index);
    }
}

STATIC_INLINE void
or_multi_put_next_element_offset (char *nullmap_ptr, const int n_elements, const int offset, const int index)
{
  or_multi_put_element_offset (nullmap_ptr, n_elements, offset, index + 1);
}

STATIC_INLINE void
or_multi_put_size_offset (char *nullmap_ptr, const int n_elements, const int offset)
{
  if (offset < OR_MULTI_MAX_OFFSET)
    {
      or_multi_put_element_offset_internal (nullmap_ptr, n_elements, offset, n_elements);
    }
  else
    {
      or_multi_put_element_offset_internal (nullmap_ptr, n_elements, OR_MULTI_MAX_OFFSET, n_elements);
    }
}

#endif /* _OBJECT_REPRESENTATION_H_ */