Skip to content

File object_representation_sr.c

File List > base > object_representation_sr.c

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_sr.c - Class representation parsing for the server only
 * This is used for updating the catalog manager when class objects are
 * flushed to the server.
 */

#ident "$Id$"

#include "object_representation_sr.h"

#include "btree_load.h"
#include "config.h"
#include "dbtype.h"
#include "deduplicate_key.h"
#include "error_manager.h"
#include "object_primitive.h"
#include "object_representation.h"
#include "set_object.h"

#include <assert.h>
#include <new>
#include <stdio.h>
#include <string.h>
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"

#define DATA_INIT(data, type) memset(data, 0, sizeof(DB_DATA))
#define OR_ARRAY_EXTENT 10

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

#define OR_VAR_TABLE_ELEMENT_OFFSET(table, index)           \
            OR_VAR_TABLE_ELEMENT_OFFSET_INTERNAL(table, index,      \
                                                 BIG_VAR_OFFSET_SIZE)

#define OR_VAR_TABLE_ELEMENT_LENGTH(table, index)           \
            OR_VAR_TABLE_ELEMENT_LENGTH_INTERNAL(table, index,      \
                                                 BIG_VAR_OFFSET_SIZE)

typedef struct or_btree_property OR_BTREE_PROPERTY;
struct or_btree_property
{
  const char *name;
  DB_SEQ *seq;
  BTREE_TYPE type;
  int length;
};

/* move the data inside the record */
#define HEAP_MOVE_INSIDE_RECORD(rec, dest_offset, src_offset) \
  do \
    { \
      assert ((rec) != NULL && (dest_offset) >= 0 && (src_offset) >= 0); \
      assert (((rec)->length - (src_offset)) >= 0); \
      assert (((rec)->area_size <= 0) || ((rec)->area_size >= (rec)->length)); \
      assert (((rec)->area_size <= 0) \
              || (((rec)->length + ((dest_offset) - (src_offset))) \
                  <= (rec)->area_size)); \
      if ((dest_offset) != (src_offset)) \
        { \
          memmove ((rec)->data + (dest_offset), (rec)->data + (src_offset), \
                   (rec)->length - (src_offset)); \
          (rec)->length = (rec)->length + ((dest_offset) - (src_offset)); \
        } \
    } \
  while (0)

static int or_get_hierarchy_helper (THREAD_ENTRY * thread_p, OID * source_class, OID * class_, BTID * btid,
                    OID ** class_oids, HFID ** hfids, int *num_classes, int *max_classes,
                    int *partition_local_index);
static TP_DOMAIN *or_get_domain_internal (char *ptr);
static TP_DOMAIN *or_get_domain_and_cache (char *ptr);
static void or_get_att_index (char *ptr, BTID * btid);
static int or_get_default_value (OR_ATTRIBUTE * attr, char *ptr, int length);
static int or_get_current_default_value (OR_ATTRIBUTE * attr, char *ptr, int length);
static int or_cl_get_prop_nocopy (DB_SEQ * properties, const char *name, DB_VALUE * pvalue);
static void or_install_btids_foreign_key (const char *fkname, DB_SEQ * fk_seq, OR_INDEX * index);
static void or_install_btids_foreign_key_ref (DB_SEQ * fk_container, OR_INDEX * index);
static void or_install_btids_prefix_length (DB_SEQ * prefix_seq, OR_INDEX * index, int num_attrs);
static int or_install_btids_filter_pred (DB_SEQ * pred_seq, OR_INDEX * index);
static void or_install_btids_class (OR_CLASSREP * rep, BTID * id, DB_SEQ * constraint_seq, int seq_size,
                    BTREE_TYPE type, const char *cons_name);
static int or_install_btids_attribute (OR_CLASSREP * rep, int att_id, BTID * id);
static void or_install_btids_constraint (OR_CLASSREP * rep, DB_SEQ * constraint_seq, BTREE_TYPE type,
                     const char *cons_name);
static void or_install_btids_function_info (DB_SEQ * fi_seq, OR_INDEX * index);
static void or_install_btids (OR_CLASSREP * rep, DB_SEQ * props);
static OR_CLASSREP *or_get_current_representation (RECDES * record, int do_indexes);
static OR_CLASSREP *or_get_old_representation (RECDES * record, int repid, int do_indexes);
static const char *or_find_diskattr (RECDES * record, int attr_id);
static int or_get_attr_string (RECDES * record, int attr_id, int attr_index, char **string, int *alloced_string);

static char or_mvcc_get_flag (RECDES * record);
static void or_mvcc_set_flag (RECDES * record, char flags);
static INLINE MVCCID or_mvcc_get_insid (OR_BUF * buf, int mvcc_flags, int *error) __attribute__ ((ALWAYS_INLINE));
static INLINE int or_mvcc_set_insid (OR_BUF * buf, MVCC_REC_HEADER * mvcc_rec_header) __attribute__ ((ALWAYS_INLINE));
static INLINE MVCCID or_mvcc_get_delid (OR_BUF * buf, int mvcc_flags, int *error) __attribute__ ((ALWAYS_INLINE));
static INLINE int or_mvcc_get_chn (OR_BUF * buf, int *error) __attribute__ ((ALWAYS_INLINE));
static INLINE int or_mvcc_set_delid (OR_BUF * buf, MVCC_REC_HEADER * mvcc_rec_header) __attribute__ ((ALWAYS_INLINE));
static INLINE int or_mvcc_set_chn (OR_BUF * buf, MVCC_REC_HEADER * mvcc_rec_header) __attribute__ ((ALWAYS_INLINE));
static INLINE int or_mvcc_set_prev_version_lsa (OR_BUF * buf, MVCC_REC_HEADER * mvcc_rec_header)
  __attribute__ ((ALWAYS_INLINE));
static INLINE int or_mvcc_get_prev_version_lsa (OR_BUF * buf, int mvcc_flags, LOG_LSA * prev_version_lsa)
  __attribute__ ((ALWAYS_INLINE));

#if defined (ENABLE_UNUSED_FUNCTION)
/*
 * orc_class_rep_dir () - Extracts the OID of representation
 *                             directory record of a class
 *   return: void
 *   record(in): packed disk record containing class
 *   rep_dir_p(out): OID of representation directory record to be filled in
 */
void
orc_class_rep_dir (RECDES * record, OID * rep_dir_p)
{
  char *ptr;

  ptr = (char *) record->data + OR_FIXED_ATTRIBUTES_OFFSET (record->data, ORC_CLASS_VAR_ATT_COUNT) + ORC_REP_DIR_OFFSET;

  OR_GET_OID (ptr, rep_dir_p);
}

/*
 * orc_class_hfid_from_record () - Extracts just the HFID from the disk
 *                                 representation of a class
 *   return: void
 *   record(in): packed disk record containing class
 *   hfid(out): pointer to HFID structure to be filled in
 *
 * Note: It is used by the catalog manager to update the class information
 *       structure when the HFID is assigned.  Since HFID's are assigned only
 *       when instances are created, a class may be entered into the catalog
 *       before the HFID is known.
 */
void
orc_class_hfid_from_record (RECDES * record, HFID * hfid)
{
  char *ptr;

  ptr = record->data + OR_FIXED_ATTRIBUTES_OFFSET (record->data, ORC_CLASS_VAR_ATT_COUNT);
  hfid->vfid.fileid = OR_GET_INT (ptr + ORC_HFID_FILEID_OFFSET);
  hfid->vfid.volid = OR_GET_INT (ptr + ORC_HFID_VOLID_OFFSET);
  hfid->hpgid = OR_GET_INT (ptr + ORC_HFID_PAGEID_OFFSET);
}
#endif

/*
 * orc_diskrep_from_record () - Calculate the corresponding DISK_REPR structure
 *                              for the catalog
 *   return: disk representation structure
 *   record(in): disk record
 */
DISK_REPR *
orc_diskrep_from_record (THREAD_ENTRY * thread_p, RECDES * record)
{
  DISK_ATTR *att, *att_fixed, *att_variable;
  OR_ATTRIBUTE *or_att;
  int i, j, k, n_attributes, n_btstats;
  BTREE_STATS *bt_statsp;

  DISK_REPR *rep = NULL;
  OR_CLASSREP *or_rep = NULL;
  OR_INDEX *or_idx = NULL;

  VPID root_vpid;
  PAGE_PTR root;
  BTREE_ROOT_HEADER *root_header = NULL;
  BTID_INT btid_int;

  or_rep = or_get_classrep (record, NULL_REPRID);
  if (or_rep == NULL)
    {
      goto error;
    }

  rep = (DISK_REPR *) malloc (sizeof (DISK_REPR));
  if (rep == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (DISK_REPR));
      goto error;
    }

  rep->id = or_rep->id;
  rep->n_fixed = 0;
  rep->n_variable = 0;
  rep->fixed_length = or_rep->fixed_length;
#if 0               /* reserved for future use */
  rep->repr_reserved_1 = 0;
#endif
  rep->fixed = NULL;
  rep->variable = NULL;

  /* Calculate the number of fixed and variable length attributes */
  n_attributes = or_rep->n_attributes;
  or_att = or_rep->attributes;
  for (i = 0; i < n_attributes; i++, or_att++)
    {
      if (or_att->is_fixed)
    {
      (rep->n_fixed)++;
    }
      else
    {
      (rep->n_variable)++;
    }
    }

  if (rep->n_fixed)
    {
      rep->fixed = (DISK_ATTR *) malloc (sizeof (DISK_ATTR) * rep->n_fixed);
      if (rep->fixed == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (DISK_ATTR) * rep->n_fixed);
      goto error;
    }
      memset (rep->fixed, 0x0, sizeof (DISK_ATTR) * rep->n_fixed);
    }

  if (rep->n_variable)
    {
      rep->variable = (DISK_ATTR *) malloc (sizeof (DISK_ATTR) * rep->n_variable);
      if (rep->variable == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (DISK_ATTR) * rep->n_variable);
      goto error;
    }
      memset (rep->variable, 0x0, sizeof (DISK_ATTR) * rep->n_variable);
    }

  /* Copy the attribute information */
  att_fixed = rep->fixed;
  att_variable = rep->variable;
  or_att = or_rep->attributes;

  for (i = 0; i < n_attributes; i++, or_att++)
    {
      if (or_att->is_fixed)
    {
      att = att_fixed;
      att_fixed++;
    }
      else
    {
      att = att_variable;
      att_variable++;
    }

      if (att == NULL)
    {
      goto error;
    }

      att->type = or_att->type;
      att->id = or_att->id;
      assert (!IS_DEDUPLICATE_KEY_ATTR_ID (att->id));
      att->location = or_att->location;
      att->position = or_att->position;
      att->val_length = or_att->default_value.val_length;
      att->value = or_att->default_value.value;
      or_att->default_value.value = NULL;
      att->classoid = or_att->classoid;

      /* initialize B+tree statistics information */

      n_btstats = att->n_btstats = or_att->n_btids;
      if (n_btstats > 0)
    {
      att->bt_stats = (BTREE_STATS *) malloc (sizeof (BTREE_STATS) * n_btstats);
      if (att->bt_stats == NULL)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (BTREE_STATS) * n_btstats);
          goto error;
        }
      memset (att->bt_stats, 0, sizeof (BTREE_STATS) * n_btstats);

      for (j = 0, bt_statsp = att->bt_stats; j < n_btstats; j++, bt_statsp++)
        {
          bt_statsp->btid = or_att->btids[j];

          bt_statsp->leafs = 0;
          bt_statsp->pages = 0;
          bt_statsp->height = 0;
          bt_statsp->keys = 0;
          bt_statsp->has_function = 0;
          for (k = 0; k < or_rep->n_indexes; k++)
        {
          or_idx = &or_rep->indexes[k];
          if (or_idx && BTID_IS_EQUAL (&or_idx->btid, &bt_statsp->btid) && or_idx->func_index_info
              && or_idx->func_index_info->col_id == 0)
            {
              bt_statsp->has_function = 1;
              break;
            }
        }

          bt_statsp->key_type = NULL;
          bt_statsp->pkeys_size = 0;
          bt_statsp->pkeys = NULL;
          bt_statsp->dedup_idx = -1;

#if 0               /* reserved for future use */
          for (k = 0; k < BTREE_STATS_RESERVED_NUM; k++)
        {
          bt_statsp->reserved[k] = 0;
        }
#endif

          /* read B+tree Root page header info */
          root_vpid.pageid = bt_statsp->btid.root_pageid;
          root_vpid.volid = bt_statsp->btid.vfid.volid;

          if (VPID_ISNULL (&root_vpid))
        {
          /* after create the catalog record of the class, and before create the catalog record of the
           * constraints for the class currently, does not know BTID */
          continue;
        }

          root = pgbuf_fix (thread_p, &root_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH);
          if (root == NULL)
        {
          goto error;
        }

#if !defined (NDEBUG)
          (void) pgbuf_check_page_ptype (thread_p, root, PAGE_BTREE);
#endif /* !NDEBUG */

          root_header = btree_get_root_header (thread_p, root);
          if (root_header == NULL)
        {
          pgbuf_unfix_and_init (thread_p, root);
          goto error;
        }

          /* construct BTID_INT structure */
          btid_int.sys_btid = &bt_statsp->btid;
          if (btree_glean_root_header_info (thread_p, root_header, &btid_int, true) != NO_ERROR)
        {
          pgbuf_unfix_and_init (thread_p, root);
          goto error;
        }

          pgbuf_unfix_and_init (thread_p, root);

          bt_statsp->key_type = btid_int.key_type;
          if (TP_DOMAIN_TYPE (bt_statsp->key_type) == DB_TYPE_MIDXKEY)
        {
          bt_statsp->pkeys_size = tp_domain_size (bt_statsp->key_type->setdomain);
          bt_statsp->dedup_idx = btid_int.deduplicate_key_idx;
        }
          else
        {
          bt_statsp->pkeys_size = 1;
        }

          /* cut-off to stats */
          if (bt_statsp->pkeys_size > BTREE_STATS_PKEYS_NUM)
        {
          bt_statsp->pkeys_size = BTREE_STATS_PKEYS_NUM;
        }

          bt_statsp->pkeys = (int *) malloc (bt_statsp->pkeys_size * sizeof (int));
          if (bt_statsp->pkeys == NULL)
        {
          bt_statsp->pkeys_size = 0;
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
              bt_statsp->pkeys_size * sizeof (int));
          goto error;
        }

          assert (bt_statsp->pkeys_size <= BTREE_STATS_PKEYS_NUM);
          for (k = 0; k < bt_statsp->pkeys_size; k++)
        {
          bt_statsp->pkeys[k] = 0;
        }
        }           /* for (j = 0, ...) */
    }
      else
    {
      att->bt_stats = NULL;
    }
    }

  or_free_classrep (or_rep);
  return (rep);

error:
  if (rep != NULL)
    {
      orc_free_diskrep (rep);
    }

  if (or_rep != NULL)
    {
      or_free_classrep (or_rep);
    }

  return (NULL);
}

/*
 * orc_free_diskrep () - Frees a DISK_REPR structure that was built with
 *                       orc_diskrep_from_record
 *   return: void
 *   rep(in): representation structure
 */
void
orc_free_diskrep (DISK_REPR * rep)
{
  int i, j;

  if (rep != NULL)
    {
      if (rep->fixed != NULL)
    {
      for (i = 0; i < rep->n_fixed; i++)
        {
          if (rep->fixed[i].value != NULL)
        {
          free_and_init (rep->fixed[i].value);
        }

          if (rep->fixed[i].bt_stats != NULL)
        {
          for (j = 0; j < rep->fixed[i].n_btstats; j++)
            {
              if (rep->fixed[i].bt_stats[j].pkeys)
            {
              free_and_init (rep->fixed[i].bt_stats[j].pkeys);
            }
            }

          free_and_init (rep->fixed[i].bt_stats);
          rep->fixed[i].bt_stats = NULL;
        }
        }

      free_and_init (rep->fixed);
    }

      if (rep->variable != NULL)
    {
      for (i = 0; i < rep->n_variable; i++)
        {
          if (rep->variable[i].value != NULL)
        {
          free_and_init (rep->variable[i].value);
        }

          if (rep->variable[i].bt_stats != NULL)
        {
          for (j = 0; j < rep->variable[i].n_btstats; j++)
            {
              if (rep->variable[i].bt_stats[j].pkeys)
            {
              free_and_init (rep->variable[i].bt_stats[j].pkeys);
            }
            }

          free_and_init (rep->variable[i].bt_stats);
          rep->variable[i].bt_stats = NULL;
        }
        }

      free_and_init (rep->variable);
    }

      free_and_init (rep);
    }
}

/*
 * orc_class_info_from_record () - Extract the information necessary to build
 *                                 a CLS_INFO structure for the catalog
 *   return: class info structure
 *   record(in): disk record with class
 */
CLS_INFO *
orc_class_info_from_record (RECDES * record)
{
  CLS_INFO *class_info_p;

  class_info_p = (CLS_INFO *) malloc (sizeof (CLS_INFO));
  if (class_info_p == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (CLS_INFO));
      return NULL;
    }

  or_class_hfid (record, &(class_info_p->ci_hfid));

  class_info_p->ci_tot_pages = 0;
  class_info_p->ci_tot_objects = 0;
  class_info_p->ci_time_stamp = 0;

  or_class_rep_dir (record, &(class_info_p->ci_rep_dir));

  return class_info_p;
}

/*
 * orc_free_class_info () - Frees a CLS_INFO structure that was allocated by
 *                          orc_class_info_from_record
 *   return: void
 *   info(in): class info structure
 */
void
orc_free_class_info (CLS_INFO * info)
{
  free_and_init (info);
}

/*
 * orc_subclasses_from_record () - Extracts the OID's of the immediate
 *                                 subclasses
 *   return: error code
 *   record(in): record containing a class
 *   array_size(out): pointer to int containing max size of array
 *   array_ptr(out): pointer to OID array
 *
 * Note: The array is maintained as an array of OID's, the last element in the
 *       array will satisfy the OID_ISNULL() test.  The array_size has
 *       the number of actual elements allocated in the array which may be more
 *       than the number of slots that have non-NULL OIDs.
 *       The function adds the subclass oids to the existing array.  If the
 *       array is not large enough, it is reallocated using realloc.
 */
int
orc_subclasses_from_record (RECDES * record, int *array_size, OID ** array_ptr)
{
  int error = NO_ERROR;
  OID *array;
  char *ptr;
  int max, insert, i, newsize, nsubs;
  char *subset = NULL;

  nsubs = 0;

  if (!OR_VAR_IS_NULL (record->data, ORC_SUBCLASSES_INDEX))
    {
      subset = (char *) (record->data) + OR_VAR_OFFSET (record->data, ORC_SUBCLASSES_INDEX);
      nsubs = OR_SET_ELEMENT_COUNT (subset);
    }

  if (nsubs)
    {
      max = *array_size;
      array = *array_ptr;
      if (array == NULL)
    {
      max = 0;
    }

      /* find the last element in the array */
      for (i = 0; i < max && !OID_ISNULL (&array[i]); i++)
    {
      ;
    }
      insert = i;

      /*
       * check for array extension.
       * Add one in the comparison since a NULL_OID is set at the end of the
       * array
       */
      if (array == NULL || (insert + nsubs + 1) > max)
    {
      newsize = insert + nsubs + 10;
      if (array == NULL)
        {
          array = (OID *) malloc (newsize * sizeof (OID));
        }
      else
        {
          array = (OID *) realloc (array, newsize * sizeof (OID));
        }

      if (array == NULL)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, newsize * sizeof (OID));
          return ER_OUT_OF_VIRTUAL_MEMORY;
        }

      for (i = max; i < newsize; i++)
        {
          OID_SET_NULL (&array[i]);
        }

      max = newsize;
    }

      /* Advance past the set header, the domain size, and the "object" domain. Note that this assumes we are not using
       * a bound bit array even though this is a fixed width homogeneous set.  Probably not a good assumption. */
      ptr = subset + OR_SET_HEADER_SIZE + OR_INT_SIZE + OR_INT_SIZE;

      assert (array != NULL);

      /* add the new OIDs */
      for (i = 0; i < nsubs; i++)
    {
      OR_GET_OID (ptr, &array[insert + i]);
      ptr += OR_OID_SIZE;
    }

      OID_SET_NULL (&array[insert + nsubs]);

      /* return these in case there were changes */
      *array_size = max;
      *array_ptr = array;
    }

  return error;
}

/*
 * orc_superclasses_from_record () - Extracts the OID's of the immediate
 *                   superclasses
 *   return: error code
 *   record(in): record containing a class
 *   array_size(out): pointer to int containing max size of array
 *   array_ptr(out): pointer to OID array
 *
 * Note: The array is maintained as an array of OID's, the last element in the
 *       array will satisfy the OID_ISNULL() test.  The array_size has
 *       the number of actual elements allocated in the array which may be
 *   more than the number of slots that have non-NULL OIDs.
 *       The function adds the subclass oids to the existing array.  If the
 *       array is not large enough, it is reallocated using realloc.
 */
int
orc_superclasses_from_record (RECDES * record, int *array_size, OID ** array_ptr)
{
  int error = NO_ERROR;
  OID *oid_array = NULL;
  char *ptr = NULL;
  int nsupers = 0, i = 0;
  char *superset = NULL;

  assert (array_ptr != NULL);
  assert (*array_ptr == NULL);
  assert (array_size != NULL);

  nsupers = 0;
  if (OR_VAR_IS_NULL (record->data, ORC_SUPERCLASSES_INDEX))
    {
      /* no superclasses, just return */
      return NO_ERROR;
    }

  superset = (char *) (record->data) + OR_VAR_OFFSET (record->data, ORC_SUPERCLASSES_INDEX);
  nsupers = OR_SET_ELEMENT_COUNT (superset);
  if (nsupers <= 0)
    {
      /* This is probably an error but there's no point in reporting it here. We just assume that there are no supers */
      assert (false);
      return NO_ERROR;
    }

  oid_array = (OID *) malloc (nsupers * sizeof (OID));

  if (oid_array == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, nsupers * sizeof (OID));
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }

  /* Advance past the set header, the domain size, and the "object" domain. Note that this assumes we are not using a
   * bound bit array even though this is a fixed width homogeneous set.  Probably not a good assumption. */
  ptr = superset + OR_SET_HEADER_SIZE + OR_INT_SIZE + OR_INT_SIZE;

  /* add the new OIDs */
  for (i = 0; i < nsupers; i++)
    {
      OR_GET_OID (ptr, &oid_array[i]);
      ptr += OR_OID_SIZE;
    }

  /* return these in case there were changes */
  *array_size = nsupers;
  *array_ptr = oid_array;

  return error;
}

/*
 * or_class_rep_dir () - Extracts the OID of representation
 *                            directory record of a class
 *   return: void
 *   record(in): packed disk record containing class
 *   rep_dir_p(out): OID of representation directory record to be filled in
 */
void
or_class_rep_dir (RECDES * record, OID * rep_dir_p)
{
  char *ptr;

  assert (OR_GET_OFFSET_SIZE (record->data) == BIG_VAR_OFFSET_SIZE);

  ptr = (char *) record->data + OR_FIXED_ATTRIBUTES_OFFSET (record->data, ORC_CLASS_VAR_ATT_COUNT) + ORC_REP_DIR_OFFSET;

  OR_GET_OID (ptr, rep_dir_p);
}

/*
 * or_class_hfid () - Extracts just the HFID from the disk representation of
 *                    a class
 *   return: void
 *   record(in): packed disk record containing class
 *   hfid(out): pointer to HFID structure to be filled in
 *
 * Note: It is used by the catalog manager to update the class information
 *       structure when the HFID is assigned.  Since HFID's are assigned only
 *       when instances are created, a class may be entered into the catalog
 *       before the HFID is known.
 */
void
or_class_hfid (RECDES * record, HFID * hfid)
{
  char *ptr;

  assert (OR_GET_OFFSET_SIZE (record->data) == BIG_VAR_OFFSET_SIZE);

  ptr = record->data + OR_FIXED_ATTRIBUTES_OFFSET (record->data, ORC_CLASS_VAR_ATT_COUNT);
  hfid->vfid.fileid = OR_GET_INT (ptr + ORC_HFID_FILEID_OFFSET);
  hfid->vfid.volid = OR_GET_INT (ptr + ORC_HFID_VOLID_OFFSET);
  hfid->hpgid = OR_GET_INT (ptr + ORC_HFID_PAGEID_OFFSET);
}

/*
 * or_class_tde_algorithm, () - Extracts the tde algorithm from the disk representation of a class
 *   return: void
 *   record(in): packed disk record containing class
 *   tde_algo (out): pointer to tde_algo to be filled in
 *
 */
void
or_class_tde_algorithm (RECDES * record, TDE_ALGORITHM * tde_algo)
{
  char *ptr;

  assert (OR_GET_OFFSET_SIZE (record->data) == BIG_VAR_OFFSET_SIZE);

  ptr = record->data + OR_FIXED_ATTRIBUTES_OFFSET (record->data, ORC_CLASS_VAR_ATT_COUNT);
  *(int *) tde_algo = OR_GET_INT (ptr + ORC_CLASS_TDE_ALGORITHM);
}

#if defined (ENABLE_UNUSED_FUNCTION)
/*
 * or_class_statistics () - extracts the OID of the statistics instance for
 *                          this class from the disk representation of a class
 *   return: void
 *   record(in): packed disk record containing class
 *   oid(in): pointer to OID structure to be filled in
 */
void
or_class_statistics (RECDES * record, OID * oid)
{
  char *ptr;

  assert (OR_GET_OFFSET_SIZE (record->data) == BIG_VAR_OFFSET_SIZE);

  ptr = record->data + OR_FIXED_ATTRIBUTES_OFFSET (record->data, ORC_CLASS_VAR_ATT_COUNT);

  /* this doesn't exist yet, return NULL */
  OID_SET_NULL (oid);
}

/*
 * or_class_subclasses () - Extracts the OID's of the immediate subclasses
 *   return: error code
 *   record(in): record containing a class
 *   array_size(out): pointer to int containing max size of array
 *   array_ptr(out): pointer to OID array
 *
 * Note: The array is maintained as an array of OID's, the last element in the
 *       array will satisfy the OID_ISNULL() test.  The array_size has
 *       the number of actual elements allocated in the array which may be more
 *       than the number of slots that have non-NULL OIDs.
 *       The function adds the subclass oids to the existing array.  If the
 *       array is not large enough, it is reallocated using realloc.
 */
int
or_class_subclasses (RECDES * record, int *array_size, OID ** array_ptr)
{
  int error = NO_ERROR;
  OID *array;
  char *ptr;
  int max, insert, i, newsize, nsubs;
  char *subset = NULL;
  size_t buf_size;

  nsubs = 0;
  if (!OR_VAR_IS_NULL (record->data, ORC_SUBCLASSES_INDEX))
    {
      subset = (char *) (record->data) + OR_VAR_OFFSET (record->data, ORC_SUBCLASSES_INDEX);
      nsubs = OR_SET_ELEMENT_COUNT (subset);
    }

  if (nsubs)
    {
      max = *array_size;
      array = *array_ptr;
      if (array == NULL)
    {
      max = 0;
    }

      /* find the last element in the array */
      for (i = 0; i < max && !OID_ISNULL (&array[i]); i++)
    {
      ;
    }
      insert = i;

      /*
       * check for array extension.
       * Add one in the comparison since a NULL_OID is set at the end of the
       * array
       */
      if ((insert + nsubs + 1) > max)
    {
      newsize = insert + nsubs + 10;

      buf_size = newsize * sizeof (OID);
      if (array == NULL)
        {
          array = (OID *) malloc (buf_size);
        }
      else
        {
          array = (OID *) realloc (array, buf_size);
        }

      if (array == NULL)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, buf_size);
          return ER_OUT_OF_VIRTUAL_MEMORY;
        }

      for (i = max; i < newsize; i++)
        {
          OID_SET_NULL (&array[i]);
        }
      max = newsize;
    }

      /* Advance past the set header, the domain size, and the "object" domain. Note that this assumes we are not using
       * a bound bit array even though this is a fixed width homogeneous set.  Probably not a good assumption. */
      ptr = subset + OR_SET_HEADER_SIZE + OR_INT_SIZE + OR_INT_SIZE;

      if (array != NULL)
    {
      /* add the new OIDs */
      for (i = 0; i < nsubs; i++)
        {
          OR_GET_OID (ptr, &array[insert + i]);
          ptr += OR_OID_SIZE;
        }
      OID_SET_NULL (&array[insert + nsubs]);

      /* return these in case there were changes */
      *array_size = max;
      *array_ptr = array;
    }
      else
    {
      assert (false);
    }
    }

  return error;
}
#endif /* ENABLE_UNUSED_FUNCTION */

/*
 * or_get_hierarchy_helper () -
 *   return: error code
 *   source_class(in):
 *   class(in):
 *   btid(in):
 *   class_oids(out):
 *   hfids(out):
 *   num_classes(out):
 *   max_classes(out):
 *   partition_local_index(out):
 *
 * Note: This routine gets checks the class to see if it has an attribute named
 *       attr_name, that has a source class equal to source_class.  This would
 *       mean that the given class participates in the hierachy.  We add its
 *       heap and attribute id to the arrays and recurse for any subclasses
 *       that it might have.
 */
static int
or_get_hierarchy_helper (THREAD_ENTRY * thread_p, OID * source_class, OID * class_, BTID * btid, OID ** class_oids,
             HFID ** hfids, int *num_classes, int *max_classes, int *partition_local_index)
{
  char *ptr;
  char *subset = NULL;
  OID sub_class;
  int i, nsubs, found, newsize;
  RECDES record = RECDES_INITIALIZER;
  OR_CLASSREP *or_rep = NULL;
  OR_INDEX *or_index;
  HFID hfid;
  HEAP_SCANCACHE scan_cache;

  (void) heap_scancache_quick_start_root_hfid (thread_p, &scan_cache);

  if (heap_get_class_record (thread_p, class_, &record, &scan_cache, COPY) != S_SUCCESS)
    {
      goto error;
    }

  or_rep = or_get_classrep (&record, NULL_REPRID);
  if (or_rep == NULL)
    {
      goto error;
    }

  found = 0;
  or_index = &(or_rep->indexes[0]);
  for (i = 0; i < or_rep->n_indexes && !found; i++, or_index++)
    {
      if (BTID_IS_EQUAL (&(or_index->btid), btid))
    {
      found = 1;
    }
    }

  if (!found)
    {
      /* check if we are dealing with a partition class in which the unique constraint stands as a local index and each
       * partition has it's own btree */
      if (or_rep->has_partition_info > 0 && partition_local_index != NULL)
    {
      *partition_local_index = 1;
    }
      else
    {
      goto success;
    }
    }

  /*
   *  For each subclass, recurse ...
   *  Unfortunately, this information is not available in the OR_CLASSREP
   *  structure, so we'll digress into the RECDES structure for it.  It
   *  might be a good idea to add subclass information to the OR_CLASSREP
   *  structure.
   */
  nsubs = 0;
  if (!OR_VAR_IS_NULL (record.data, ORC_SUBCLASSES_INDEX))
    {
      subset = (char *) (record.data) + OR_VAR_OFFSET (record.data, ORC_SUBCLASSES_INDEX);
      nsubs = OR_SET_ELEMENT_COUNT (subset);
    }

  if (nsubs)
    {
      /* Advance past the set header, the domain size, and the "object" domain. Note that this assumes we are not using
       * a bound bit array even though this is a fixed width homogeneous set.  Probably not a good assumption. */
      ptr = subset + OR_SET_HEADER_SIZE + OR_INT_SIZE + OR_INT_SIZE;

      for (i = 0; i < nsubs; i++)
    {
      OR_GET_OID (ptr, &sub_class);
      if (or_get_hierarchy_helper
          (thread_p, source_class, &sub_class, btid, class_oids, hfids, num_classes, max_classes,
           partition_local_index) != NO_ERROR)
        {
          goto error;
        }

      ptr += OR_OID_SIZE;
    }
    }

  /* If we have a valid HFID, then add this class to the array */
  or_class_hfid (&record, &hfid);
  if (HFID_IS_NULL (&hfid))
    {
      goto success;
    }

  /* Need to remove duplicates from a multiple inheritance hierarchy */
  for (i = 0; i < *num_classes; i++)
    {
      if (*class_oids != NULL && OID_EQ (class_, &((*class_oids)[i])))
    {
      goto success;
    }
    }

  /* do we need to extend the arrays? */
  if ((*num_classes + 1) > *max_classes)
    {
      newsize = *max_classes + OR_ARRAY_EXTENT;

      if (*class_oids == NULL)
    {
      *class_oids = (OID *) malloc (newsize * sizeof (OID));
    }
      else
    {
      *class_oids = (OID *) realloc (*class_oids, newsize * sizeof (OID));
    }

      if (*class_oids == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, newsize * sizeof (OID));
      goto error;
    }

      if (*hfids == NULL)
    {
      *hfids = (HFID *) malloc (newsize * sizeof (HFID));
    }
      else
    {
      *hfids = (HFID *) realloc (*hfids, newsize * sizeof (HFID));
    }

      if (*hfids == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, newsize * sizeof (HFID));
      goto error;
    }

      *max_classes = newsize;
    }

  if (*class_oids == NULL || *hfids == NULL)
    {
      goto error;
    }

  COPY_OID (&((*class_oids)[*num_classes]), class_);
  (*hfids)[*num_classes] = hfid;
  *num_classes += 1;

success:
  or_free_classrep (or_rep);
  (void) heap_scancache_end (thread_p, &scan_cache);
  return NO_ERROR;

error:
  if (or_rep != NULL)
    {
      or_free_classrep (or_rep);
    }

  (void) heap_scancache_end (thread_p, &scan_cache);

  assert (er_errid () != NO_ERROR);
  return er_errid ();
}

/*
 * or_get_unique_hierarchy () -
 *   return:
 *   record(in): record containing a class
 *   attrid(in): unique attrid (the one we'll get the hierarchy for)
 *   btid(in):
 *   class_oids(out):
 *   hfids(out): pointer to HFID array
 *   num_classes(out):
 *   partition_local_index(out):
 *
 * Note: This function uses the attribute represented by the attrid and finds
 *       the source class for that attribute (where it was defined in the class
 *       hierarchy).  Then the heap files for all the classes that are in the
 *       hierarchy rooted at the source class that contain the (non shadowed)
 *       attribute are returned in the hfids array and their respective attrids
 *       are returned in the attrids array.  num_heaps will indicate how many
 *       positions of the arrays are valid.
 *
 *       it is the callers responsibility to free the hfids and attrids
 *       arrays if this routine returns successfully.
 *
 *       <attrid> is currently used only to find the source class for
 *       the BTID.  The index attributes can be obtained through the
 *       BTID if needed so it might be a good idea to get rid of the
 *       attribute ID parameter since it no longer represents the
 *       index well.
 */
int
or_get_unique_hierarchy (THREAD_ENTRY * thread_p, RECDES * record, int attrid, BTID * btid, OID ** class_oids,
             HFID ** hfids, int *num_classes, int *partition_local_index)
{
  int n_attributes, n_fixed, n_variable, i;
  int id, found, max_classes;
  char *attr_name, *start, *ptr, *attset, *diskatt = NULL;
  OID source_class;

  *num_classes = 0;
  max_classes = 0;
  *class_oids = NULL;
  *hfids = NULL;

  if (partition_local_index != NULL)
    {
      *partition_local_index = 0;
    }

  /* find the source class of the attribute from the record */
  start = record->data;

  assert (OR_GET_OFFSET_SIZE (start) == BIG_VAR_OFFSET_SIZE);

  ptr = start + OR_FIXED_ATTRIBUTES_OFFSET (record->data, ORC_CLASS_VAR_ATT_COUNT);

  n_fixed = OR_GET_INT (ptr + ORC_FIXED_COUNT_OFFSET);
  n_variable = OR_GET_INT (ptr + ORC_VARIABLE_COUNT_OFFSET);
  n_attributes = n_fixed + n_variable;

  /* find the start of the "set_of(attribute)" attribute inside the class */
  attset = start + OR_VAR_OFFSET (start, ORC_ATTRIBUTES_INDEX);

  /* loop over each attribute in the class record to find our attribute */
  for (i = 0, found = 0; i < n_attributes && !found; i++)
    {
      /* diskatt will now be pointing at the offset table for this attribute. this is logically the "start" of this
       * nested object. */

      diskatt = attset + OR_SET_ELEMENT_OFFSET (attset, i);

      /* set ptr to the beginning of the fixed attributes */
      ptr = diskatt + OR_VAR_TABLE_SIZE (ORC_ATT_VAR_ATT_COUNT);

      /* is this the attribute we want? */
      id = OR_GET_INT (ptr + ORC_ATT_ID_OFFSET);
      if (id == attrid)
    {
      found = 1;
      OR_GET_OID (ptr + ORC_ATT_CLASS_OFFSET, &source_class);
    }
    }

  /* diskatt now points to the attribute that we are interested in. Get the attribute name. */
  if (diskatt == NULL)
    {
      goto error;
    }

  attr_name = (diskatt + OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, ORC_ATT_NAME_INDEX));

  if (!found || (OR_VAR_TABLE_ELEMENT_LENGTH (diskatt, ORC_ATT_NAME_INDEX) == 0)
      || (or_get_hierarchy_helper (thread_p, &source_class, &source_class, btid, class_oids, hfids, num_classes,
                   &max_classes, partition_local_index) != NO_ERROR))
    {
      goto error;
    }

  return NO_ERROR;

error:
  if (*class_oids)
    {
      free_and_init (*class_oids);
    }

  if (*hfids)
    {
      free_and_init (*hfids);
    }

  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);

  return ER_GENERIC_ERROR;
}

/*
 * or_get_domain_internal () -
 *   return: transient domain
 *   ptr(in): pointer to the beginning of a domain in a class
 */
static TP_DOMAIN *
or_get_domain_internal (char *ptr)
{
  TP_DOMAIN *domain, *last, *new_;
  int n_domains, offset, i, error = NO_ERROR;
  char *dstart, *fixed;
  DB_TYPE typeid_;

  domain = last = NULL;

  /* ptr has the beginning of a substructure set of domains */
  n_domains = OR_SET_ELEMENT_COUNT (ptr);
  for (i = 0; i < n_domains; i++)
    {
      /* find the start of the domain in the set */
      dstart = ptr + OR_SET_ELEMENT_OFFSET (ptr, i);

      /* dstart points to the offset table for this substructure, get the position of the first fixed attribute. */
      fixed = dstart + OR_VAR_TABLE_SIZE (ORC_DOMAIN_VAR_ATT_COUNT);

      typeid_ = (DB_TYPE) OR_GET_INT (fixed + ORC_DOMAIN_TYPE_OFFSET);

      new_ = tp_domain_new (typeid_);
      if (new_ == NULL)
    {
      goto error_cleanup;
    }

      if (last == NULL)
    {
      domain = new_;
    }
      else
    {
      last->next = new_;
    }
      last = new_;

      new_->precision = OR_GET_INT (fixed + ORC_DOMAIN_PRECISION_OFFSET);
      new_->scale = OR_GET_INT (fixed + ORC_DOMAIN_SCALE_OFFSET);
      new_->codeset = OR_GET_INT (fixed + ORC_DOMAIN_CODESET_OFFSET);
      if (typeid_ == DB_TYPE_ENUMERATION && new_->codeset == 0)
    {
      assert (new_->collation_id == LANG_COLL_ISO_BINARY);
      new_->codeset = INTL_CODESET_ISO88591;
    }
      new_->collation_id = OR_GET_INT (fixed + ORC_DOMAIN_COLLATION_ID_OFFSET);

      OR_GET_OID (fixed + ORC_DOMAIN_CLASS_OFFSET, &new_->class_oid);
      /* can't swizzle the pointer on the server */
      new_->class_mop = NULL;

      if (OR_VAR_TABLE_ELEMENT_LENGTH (dstart, ORC_DOMAIN_SETDOMAIN_INDEX) == 0)
    {
      new_->setdomain = NULL;
    }
      else
    {
      offset = OR_VAR_TABLE_ELEMENT_OFFSET (dstart, ORC_DOMAIN_SETDOMAIN_INDEX);
      new_->setdomain = or_get_domain_internal (dstart + offset);
    }

      DOM_SET_ENUM (new_, NULL, 0);
      if (OR_VAR_TABLE_ELEMENT_LENGTH (dstart, ORC_DOMAIN_ENUMERATION_INDEX) != 0)
    {
      OR_BUF buf;

      offset = OR_VAR_TABLE_ELEMENT_OFFSET (dstart, ORC_DOMAIN_ENUMERATION_INDEX);

      or_init (&buf, dstart + offset, 0);

      new_->enumeration.collation_id = new_->collation_id;

      error = or_get_enumeration (&buf, &DOM_GET_ENUMERATION (new_));
      if (error != NO_ERROR)
        {
          goto error_cleanup;
        }
    }

      if (OR_VAR_TABLE_ELEMENT_LENGTH (dstart, ORC_DOMAIN_SCHEMA_JSON_OFFSET) != 0)
    {
      OR_BUF buf;

      offset = OR_VAR_TABLE_ELEMENT_OFFSET (dstart, ORC_DOMAIN_SCHEMA_JSON_OFFSET);
      or_init (&buf, dstart + offset, 0);

      error = or_get_json_validator (&buf, domain->json_validator);
      if (error != NO_ERROR)
        {
          goto error_cleanup;
        }
    }
    }

  return domain;

error_cleanup:
  while (domain != NULL)
    {
      TP_DOMAIN *next = domain->next;
      tp_domain_free (domain);
      domain = next;
    }
  return NULL;
}

/*
 * or_get_domain_and_cache () -
 *   return:
 *   ptr(in):
 */
static TP_DOMAIN *
or_get_domain_and_cache (char *ptr)
{
  TP_DOMAIN *domain;

  domain = or_get_domain_internal (ptr);
  if (domain != NULL)
    {
      domain = tp_domain_cache (domain);
    }

  return domain;
}

/*
 * or_get_att_index () - Extracts a BTID from the disk representation of an
 *                       attribute
 *   return: void
 *   ptr(in): buffer pointer
 *   btid(out): btree identifier
 */
static void
or_get_att_index (char *ptr, BTID * btid)
{
  unsigned int uval;

  btid->vfid.fileid = (FILEID) OR_GET_INT (ptr);
  ptr += OR_INT_SIZE;
  btid->root_pageid = (PAGEID) OR_GET_INT (ptr);
  ptr += OR_INT_SIZE;
  uval = (unsigned int) OR_GET_INT (ptr);
  btid->vfid.volid = (VOLID) (uval & 0xFFFF);
}

/*
 * or_get_default_value () - Copies the default value of an attribute from disk
 *   return: zero to indicate error
 *   attr(in): disk attribute structure
 *   ptr(in): pointer to beginning of value
 *   length(in): length of value on disk
 *
 * Note: The data manipulation for this is a bit odd, owing to the "rich"
 *       and varied history of default value manipulation in the catalog.
 *       The callers expect to be given a value buffer in disk representation
 *       format, which as it turns out they will immediately turn around and
 *       use the "readval" function on to get it into a DB_VALUE.  This prevents
 *       us from actually returning the value in a DB_VALUE here because then
 *       the callers would have to deal with two different value formats,
 *       diskrep for non-default values and DB_VALUE rep for default values.
 *       This might not be hard to do and should be considered at some point.
 *
 *       As it stands, we have to perform some of the same operations as
 *       or_get_value here and return a buffer containing a copy of the disk
 *       representation of the value only (not the domain).
 */
static int
or_get_default_value (OR_ATTRIBUTE * attr, char *ptr, int length)
{
  int success, is_null;
  TP_DOMAIN *domain;
  char *vptr;

  if (length == 0)
    {
      return 1;
    }

  /* skip over the domain tag, check for tagged NULL */
  success = 0;
  domain = NULL;
  vptr = or_unpack_domain (ptr, &domain, &is_null);
  if (domain == NULL)
    {
      return 0;
    }

  /* reduce the expected size by the amount consumed with the domain tag */
  length -= (int) (vptr - ptr);

  if (is_null || length == 0)
    {
      success = 1;
    }
  else
    {
      attr->default_value.val_length = length;
      attr->default_value.value = malloc (length);
      if (attr->default_value.value != NULL)
    {
      memcpy (attr->default_value.value, vptr, length);
      success = 1;
    }
    }

  return success;
}

/*
 * or_get_current_default_value () - Copies the current default value of an
 *                  attribute from disk
 *   return: zero to indicate error
 *   attr(in): disk attribute structure
 *   ptr(in): pointer to beginning of value
 *   length(in): length of value on disk
 */
static int
or_get_current_default_value (OR_ATTRIBUTE * attr, char *ptr, int length)
{
  int success, is_null;
  TP_DOMAIN *domain;
  char *vptr;

  if (length == 0)
    {
      return 1;
    }

  /* skip over the domain tag, check for tagged NULL */
  success = 0;
  domain = NULL;
  vptr = or_unpack_domain (ptr, &domain, &is_null);
  if (domain == NULL)
    {
      return 0;
    }

  /* reduce the expected size by the amount consumed with the domain tag */
  length -= (int) (vptr - ptr);

  if (is_null || length == 0)
    {
      success = 1;
    }
  else
    {
      attr->current_default_value.val_length = length;
      attr->current_default_value.value = malloc (length);
      if (attr->current_default_value.value != NULL)
    {
      memcpy (attr->current_default_value.value, vptr, length);
      success = 1;
    }
    }

  return success;
}

/*
 * or_cl_get_prop_nocopy () - Modified version of classobj_get_prop that tries to
 *                            avoid copying of the values
 *   return: non-zero if the property was found
 *   properties(in):  property sequence
 *   name(in): name of property to find
 *   pvalue(in): property value
 *
 * Note: This was written for object_representation_sr.c but could be used in other cases if
 *       you're careful.
 *       Uses the hacked set_get_element_nocopy function above, this is
 *       probably what we should be doing anyway, it would make property list
 *       operations faster.
 */
static int
or_cl_get_prop_nocopy (DB_SEQ * properties, const char *name, DB_VALUE * pvalue)
{
  int error;
  int found, max, i;
  DB_VALUE value;
  const char *prop_name;

  error = NO_ERROR;
  found = 0;

  if (properties != NULL && name != NULL && pvalue != NULL)
    {
      max = set_size (properties);
      for (i = 0; i < max && !found && error == NO_ERROR; i += 2)
    {
      error = set_get_element_nocopy (properties, i, &value);
      if (error == NO_ERROR)
        {
          if (DB_VALUE_TYPE (&value) != DB_TYPE_STRING || db_get_string (&value) == NULL)
        {
          error = ER_SM_INVALID_PROPERTY;
        }
          else
        {
          prop_name = db_get_string (&value);
          if (strcmp (name, prop_name) == 0)
            {
              if ((i + 1) >= max)
            {
              error = ER_SM_INVALID_PROPERTY;
            }
              else
            {
              error = set_get_element_nocopy (properties, i + 1, pvalue);
              if (error == NO_ERROR)
                found = i + 1;
            }
            }
        }
        }
    }
    }

  if (error)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
    }

  return (found);
}

/*
 * or_install_btids_foreign_key () -
 *   return:
 *   fkname(in):
 *   fk_seq(in):
 *   index(in):
 */
static void
or_install_btids_foreign_key (const char *fkname, DB_SEQ * fk_seq, OR_INDEX * index)
{
  DB_VALUE val;
  int args;
  int pageid, slotid, volid, fileid;

  index->fk = (OR_FOREIGN_KEY *) malloc (sizeof (OR_FOREIGN_KEY));
  if (index->fk == NULL)
    {
      assert (false);       /* TODO */
      return;
    }

  if (set_get_element_nocopy (fk_seq, 0, &val) != NO_ERROR)
    {
      return;
    }

  index->fk->next = NULL;
  index->fk->fkname = strdup (fkname);

  args = classobj_decompose_property_oid (db_get_string (&val), &pageid, &slotid, &volid);
  if (args != 3)
    {
      return;
    }

  index->fk->ref_class_oid.pageid = (PAGEID) pageid;
  index->fk->ref_class_oid.slotid = (PGSLOTID) slotid;
  index->fk->ref_class_oid.volid = (VOLID) volid;

  if (set_get_element_nocopy (fk_seq, 1, &val) != NO_ERROR)
    {
      return;
    }

  args = classobj_decompose_property_oid (db_get_string (&val), &volid, &fileid, &pageid);

  if (args != 3)
    {
      return;
    }

  index->fk->ref_class_pk_btid.vfid.volid = (VOLID) volid;
  index->fk->ref_class_pk_btid.root_pageid = (PAGEID) pageid;
  index->fk->ref_class_pk_btid.vfid.fileid = (FILEID) fileid;

  set_get_element_nocopy (fk_seq, 2, &val);
  index->fk->del_action = db_get_int (&val);

  set_get_element_nocopy (fk_seq, 3, &val);
  index->fk->upd_action = db_get_int (&val);
}

/*
 * or_install_btids_foreign_key_ref () -
 *   return:
 *   fk_container(in):
 *   index(in):
 */
static void
or_install_btids_foreign_key_ref (DB_SEQ * fk_container, OR_INDEX * index)
{
  DB_VALUE val, fkval;
  int args, size, i;
  int pageid, slotid, volid, fileid;
  DB_SEQ *fk_seq;
  OR_FOREIGN_KEY *fk, *p = NULL;
  const char *fkname;

  size = set_size (fk_container);

  for (i = 0; i < size; i++)
    {
      if (set_get_element_nocopy (fk_container, i, &fkval) != NO_ERROR)
    {
      return;
    }

      fk_seq = db_get_set (&fkval);

      fk = (OR_FOREIGN_KEY *) malloc (sizeof (OR_FOREIGN_KEY));
      if (fk == NULL)
    {
      assert (false);   /* TODO */
      return;
    }

      fk->next = NULL;

      if (set_get_element_nocopy (fk_seq, 0, &val) != NO_ERROR)
    {
      free_and_init (fk);
      return;
    }

      args = classobj_decompose_property_oid (db_get_string (&val), &pageid, &slotid, &volid);

      if (args != 3)
    {
      free_and_init (fk);
      return;
    }

      fk->self_oid.pageid = (PAGEID) pageid;
      fk->self_oid.slotid = (PGSLOTID) slotid;
      fk->self_oid.volid = (VOLID) volid;

      if (set_get_element_nocopy (fk_seq, 1, &val) != NO_ERROR)
    {
      free_and_init (fk);
      return;
    }

      args = classobj_decompose_property_oid (db_get_string (&val), &volid, &fileid, &pageid);

      if (args != 3)
    {
      free_and_init (fk);
      return;
    }

      fk->self_btid.vfid.volid = (VOLID) volid;
      fk->self_btid.root_pageid = (PAGEID) pageid;
      fk->self_btid.vfid.fileid = (FILEID) fileid;

      if (set_get_element_nocopy (fk_seq, 2, &val) != NO_ERROR)
    {
      free_and_init (fk);
      return;
    }
      fk->del_action = db_get_int (&val);

      if (set_get_element_nocopy (fk_seq, 3, &val) != NO_ERROR)
    {
      free_and_init (fk);
      return;
    }
      fk->upd_action = db_get_int (&val);

      if (set_get_element_nocopy (fk_seq, 4, &val) != NO_ERROR)
    {
      free_and_init (fk);
      return;
    }
      fkname = db_get_string (&val);
      fk->fkname = strdup (fkname);

      if (i == 0)
    {
      index->fk = fk;
      p = index->fk;
    }
      else
    {
      if (p != NULL)
        {
          p->next = fk;
          p = p->next;
        }
      else
        {
          free_and_init (fk->fkname);
          free_and_init (fk);
        }
    }
    }
}

/*
 * or_install_btids_prefix_length () - Load prefix length information
 *   return:
 *   prefix_seq(in): sequence which contains the prefix length
 *   index(in): index info structure
 *   num_attrs(in): key attribute count
 */
static void
or_install_btids_prefix_length (DB_SEQ * prefix_seq, OR_INDEX * index, int num_attrs)
{
  DB_VALUE val;
  int i;

  assert (prefix_seq != NULL && set_size (prefix_seq) == num_attrs);
  index->attrs_prefix_length = (int *) malloc (sizeof (int) * num_attrs);
  if (index->attrs_prefix_length == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (int) * num_attrs);
      return;
    }

  for (i = 0; i < num_attrs; i++)
    {
      if (set_get_element_nocopy (prefix_seq, i, &val) != NO_ERROR)
    {
      free_and_init (index->attrs_prefix_length);
      return;
    }

      index->attrs_prefix_length[i] = db_get_int (&val);
    }
}

/*
 * or_install_btids_filter_pred () - Load index filter predicate information
 *   return: error code
 *   pred_seq(in): sequence which contains the filter predicate
 *   index(in): index info structure
 */
static int
or_install_btids_filter_pred (DB_SEQ * pred_seq, OR_INDEX * index)
{
  DB_VALUE val1, val2;
  int error = NO_ERROR;
  int buffer_len = 0;
  const char *buffer = NULL;
  OR_PREDICATE *filter_predicate = NULL;

  index->filter_predicate = NULL;
  if (set_get_element_nocopy (pred_seq, 0, &val1) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
      return ER_SM_INVALID_PROPERTY;
    }

  switch (DB_VALUE_TYPE (&val1))
    {
    case DB_TYPE_NULL:
      return NO_ERROR;

    case DB_TYPE_STRING:
      /* continue */
      break;

    default:
      error = ER_SM_INVALID_PROPERTY;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
      return ER_SM_INVALID_PROPERTY;
    }

  if (set_get_element_nocopy (pred_seq, 1, &val2) != NO_ERROR)
    {
      error = ER_SM_INVALID_PROPERTY;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
      return ER_SM_INVALID_PROPERTY;
    }

  switch (DB_VALUE_TYPE (&val2))
    {
    case DB_TYPE_NULL:
      return NO_ERROR;

    case DB_TYPE_CHAR:
      /* continue */
      break;

    default:
      error = ER_SM_INVALID_PROPERTY;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
      return ER_SM_INVALID_PROPERTY;
    }

  /* currently, element 2 from pred_seq is used only on client side */

  filter_predicate = (OR_PREDICATE *) malloc (sizeof (OR_PREDICATE));
  if (filter_predicate == NULL)
    {
      error = ER_OUT_OF_VIRTUAL_MEMORY;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (OR_PREDICATE));
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }

  filter_predicate->pred_string = strdup (db_get_string (&val1));
  if (filter_predicate->pred_string == NULL)
    {
      error = ER_OUT_OF_VIRTUAL_MEMORY;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
          strlen (db_get_string (&val1)) * sizeof (char));
      goto err;
    }

  buffer = db_get_string (&val2);
  buffer_len = db_get_string_size (&val2);
  filter_predicate->pred_stream = (char *) malloc (buffer_len * sizeof (char));
  if (filter_predicate->pred_stream == NULL)
    {
      error = ER_OUT_OF_VIRTUAL_MEMORY;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, buffer_len * sizeof (char));
      goto err;
    }

  memcpy (filter_predicate->pred_stream, buffer, buffer_len);
  filter_predicate->pred_stream_size = buffer_len;
  index->filter_predicate = filter_predicate;
  return NO_ERROR;

err:
  if (filter_predicate)
    {
      if (filter_predicate->pred_string)
    {
      free_and_init (filter_predicate->pred_string);
    }

      if (filter_predicate->pred_stream)
    {
      free_and_init (filter_predicate->pred_stream);
    }

      free_and_init (filter_predicate);
    }
  return error;
}

/*
 * or_install_btids_class () - Install (add) the B-tree ID to the index
 *                             structure of the class representation
 *   return: void
 *   rep(in): Class representation
 *   id(in): B-tree ID
 *   constraint_seq(in): Set which contains the attribute ID's
 *   max(in): Number of elements in the set
 *   type(in):
 *   cons_name(in):
 *
 * Note: The index structure (OR_INDEX) is assumed to
 *       be allocated before this function is called.  We will allocate
 *       room for the attribute pointer array which will be filled with
 *       pointers to attributes (also from the class representation) which
 *       share this B-tree ID (and associated constraint).
 *
 *       The purpose of this function is to provide a list of B-tree IDs at
 *       that belong to the class and to provide a reference to the attributes
 *       that are associated with each B-tree ID.  This complements the other
 *       structures which are in place that provide a list of B-tree IDs
 *       associated with an attribute in each attribute structure
 *       (OR_ATTRIBUTE).
 *       For constraint structure details, see comment on SM_CLASS_CONSTRAINT in class_object.h.
 */
static void
or_install_btids_class (OR_CLASSREP * rep, BTID * id, DB_SEQ * constraint_seq, int seq_size, BTREE_TYPE type,
            const char *cons_name)
{
  DB_VALUE att_val;
  int i, j, e;
  int att_id, att_cnt;
  OR_ATTRIBUTE *att;
  OR_INDEX *index;
  DB_VALUE stat_val;

  db_make_null (&stat_val);

  if (seq_size < 2)
    {
      /* No attributes IDs here */
      return;
    }

  index = &(rep->indexes[rep->n_indexes]);

  att_cnt = get_class_constraint_att_count (seq_size);

  index->atts = (OR_ATTRIBUTE **) malloc (sizeof (OR_ATTRIBUTE *) * att_cnt);
  if (index->atts == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (OR_ATTRIBUTE *) * att_cnt);
      return;
    }

  index->asc_desc = (int *) malloc (sizeof (int) * att_cnt);
  if (index->asc_desc == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (int) * att_cnt);
      return;
    }

  (rep->n_indexes)++;
  index->btid = *id;
  index->n_atts = 0;
  index->type = type;
  index->fk = NULL;
  index->attrs_prefix_length = NULL;
  index->filter_predicate = NULL;
  index->func_index_info = NULL;
  index->index_status = OR_NO_INDEX;

  /*
   * For each attribute ID in the set,
   *   Extract the attribute ID,
   *   Find the matching attribute and insert the pointer into the array.
   */

  /* Remember that the attribute IDs start in the second position. */
  e = 1;

  for (i = 0; i < att_cnt; i++)
    {
      if (set_get_element_nocopy (constraint_seq, e++, &att_val) == NO_ERROR)
    {
      if (DB_VALUE_TYPE (&att_val) == DB_TYPE_SEQUENCE)
        {
          break;
        }

      att_id = db_get_int (&att_val);
      if (IS_DEDUPLICATE_KEY_ATTR_ID (att_id))
        {
          index->atts[index->n_atts] = (OR_ATTRIBUTE *) dk_find_or_deduplicate_key_attribute (att_id);
          (index->n_atts)++;
        }
      else
        {
          for (j = 0, att = rep->attributes; j < rep->n_attributes; j++, att++)
        {
          if (att->id == att_id)
            {
              index->atts[index->n_atts] = att;
              (index->n_atts)++;
              break;
            }
        }
        }
    }

      /* asc_desc info */
      if (set_get_element_nocopy (constraint_seq, e++, &att_val) == NO_ERROR)
    {
      index->asc_desc[i] = db_get_int (&att_val);
    }
    }
  index->btname = strdup (cons_name);

  set_get_element_nocopy (constraint_seq, get_class_constraint_index (seq_size, SM_CONSTRAINT_STATUS_INDEX), &stat_val);
  index->index_status = (OR_INDEX_STATUS) (db_get_int (&stat_val));

  if (type == BTREE_FOREIGN_KEY)
    {
      if (set_get_element_nocopy
      (constraint_seq, get_class_constraint_index (seq_size, SM_CONSTRAINT_OPTIONAL_INFO_INDEX),
       &att_val) == NO_ERROR)
    {
      or_install_btids_foreign_key (cons_name, db_get_set (&att_val), index);
    }
    }
  else if (type == BTREE_PRIMARY_KEY)
    {
      if (set_get_element_nocopy
      (constraint_seq, get_class_constraint_index (seq_size, SM_CONSTRAINT_OPTIONAL_INFO_INDEX),
       &att_val) == NO_ERROR)
    {
      if (DB_VALUE_TYPE (&att_val) == DB_TYPE_SEQUENCE)
        {
          or_install_btids_foreign_key_ref (db_get_set (&att_val), index);
        }
    }
    }
  else
    {
      if (set_get_element_nocopy
      (constraint_seq, get_class_constraint_index (seq_size, SM_CONSTRAINT_OPTIONAL_INFO_INDEX),
       &att_val) == NO_ERROR)
    {
      if (DB_VALUE_TYPE (&att_val) == DB_TYPE_SEQUENCE)
        {
          DB_SEQ *seq = db_get_set (&att_val);
          DB_VALUE val;

          if (set_get_element_nocopy (seq, 0, &val) == NO_ERROR)
        {
          if (DB_VALUE_TYPE (&val) == DB_TYPE_INTEGER)
            {
              or_install_btids_prefix_length (db_get_set (&att_val), index, att_cnt);
            }
          else if (DB_VALUE_TYPE (&val) == DB_TYPE_SEQUENCE)
            {
              DB_VALUE avalue;
              DB_SET *child_seq = db_get_set (&val);
              int seq_size = set_size (seq);
              SM_INDEX_FLAG index_flag;
              const char *index_flag_str;

              j = 0;
              while (true)
            {
              if (set_get_element_nocopy (child_seq, 0, &avalue) != NO_ERROR)
                {
                  goto next_child;
                }

              if (DB_IS_NULL (&avalue) || DB_VALUE_TYPE (&avalue) != DB_TYPE_STRING)
                {
                  goto next_child;
                }

              index_flag_str = db_get_string (&avalue);
              if (strcmp (index_flag_str, SM_FILTER_INDEX_ID) == 0)
                {
                  index_flag = SM_INDEX_FLAG_FILTER;
                }
              else if (strcmp (index_flag_str, SM_FUNCTION_INDEX_ID) == 0)
                {
                  index_flag = SM_INDEX_FLAG_FUNCTION;
                }
              else if (strcmp (index_flag_str, SM_PREFIX_INDEX_ID) == 0)
                {
                  index_flag = SM_INDEX_FLAG_PREFIX;
                }
              else
                {
                  index_flag = SM_INDEX_FLAG_NONE;
                }

              if (set_get_element_nocopy (child_seq, 1, &avalue) != NO_ERROR)
                {
                  goto next_child;
                }

              if (DB_VALUE_TYPE (&avalue) != DB_TYPE_SEQUENCE)
                {
                  goto next_child;
                }

              switch (index_flag)
                {
                case SM_INDEX_FLAG_FILTER:
                  or_install_btids_filter_pred (db_get_set (&avalue), index);
                  break;

                case SM_INDEX_FLAG_FUNCTION:
                  or_install_btids_function_info (db_get_set (&avalue), index);
                  break;

                case SM_INDEX_FLAG_PREFIX:
                  or_install_btids_prefix_length (db_get_set (&avalue), index, att_cnt);
                  break;

                default:
                  break;
                }

            next_child:
              j++;
              if (j >= seq_size)
                {
                  break;
                }

              if (set_get_element_nocopy (seq, j, &val) != NO_ERROR)
                {
                  continue;
                }

              if (DB_VALUE_TYPE (&val) != DB_TYPE_SEQUENCE)
                {
                  continue;
                }

              child_seq = db_get_set (&val);
            }

              if (index->func_index_info)
            {
              /* function index and prefix length not allowed, yet */
              index->attrs_prefix_length = (int *) malloc (sizeof (int) * att_cnt);
              if (index->attrs_prefix_length == NULL)
                {
                  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
                      sizeof (int) * att_cnt);
                  return;
                }
              for (i = 0; i < att_cnt; i++)
                {
                  index->attrs_prefix_length[i] = -1;
                }
            }
            }
          else
            {
              assert (0);
            }
        }
        }
      else
        {
          assert (0);
        }
    }
    }
}

/*
 * or_install_btids_attribute () - Install (add) the B-tree ID to the
 *                                 appropriate attribute in the class
 *                                 representation
 *   return:
 *   rep(in): Class representation
 *   att_id(in): Attribute ID
 *   id(in): B-tree ID
 */
static int
or_install_btids_attribute (OR_CLASSREP * rep, int att_id, BTID * id)
{
  int i;
  OR_ATTRIBUTE *att;
  int success = 1;
  OR_ATTRIBUTE *ptr = NULL;
  int size;

  assert (!IS_DEDUPLICATE_KEY_ATTR_ID (att_id));
  /* Find the attribute with the matching attribute ID */
  for (i = 0, att = rep->attributes; i < rep->n_attributes; i++, att++)
    {
      assert (!IS_DEDUPLICATE_KEY_ATTR_ID (att->id));
      if (att->id == att_id)
    {
      ptr = att;
      break;
    }
    }

  /* Allocate storage for the ID and store it */
  if (ptr != NULL)
    {
      if (ptr->btids == NULL)
    {
      /* we've never had one before, use the local pack */
      ptr->btids = ptr->btid_pack;
      ptr->max_btids = OR_ATT_BTID_PREALLOC;
    }
      else
    {
      /* we've already got one, continue to use the local pack until that runs out and then start mallocing. */
      if (ptr->n_btids >= ptr->max_btids)
        {
          if (ptr->btids == ptr->btid_pack)
        {
          /* allocate a bigger array and copy over our local pack */
          size = ptr->n_btids + OR_ATT_BTID_PREALLOC;
          ptr->btids = (BTID *) malloc (sizeof (BTID) * size);
          if (ptr->btids != NULL)
            {
              memcpy (ptr->btids, ptr->btid_pack, (sizeof (BTID) * ptr->n_btids));
            }
          ptr->max_btids = size;
        }
          else
        {
          /* we already have an externally allocated array, make it bigger */
          size = ptr->n_btids + OR_ATT_BTID_PREALLOC;
          ptr->btids = (BTID *) realloc (ptr->btids, size * sizeof (BTID));
          ptr->max_btids = size;
        }
        }
    }

      if (ptr->btids)
    {
      ptr->btids[ptr->n_btids] = *id;
      ptr->n_btids += 1;
    }
      else
    {
      success = 0;
    }
    }

  return success;
}

/*
 * or_install_btids_constraint () - Install the constraint into the appropriate
 *                                  attributes
 *   return:
 *   rep(in): Class representation
 *   constraint_seq(in): Constraint
 *   type(in):
 *   cons_name(in):
 *
 * Note: The constraint may be associated with multiple attributes.
 *       For constraint structure details, see comment on SM_CLASS_CONSTRAINT in class_object.h.
 */
static void
or_install_btids_constraint (OR_CLASSREP * rep, DB_SEQ * constraint_seq, BTREE_TYPE type, const char *cons_name)
{
  int att_id;
  int i, seq_size, args;
  int volid, fileid, pageid;
  BTID id;
  DB_VALUE id_val, att_val;

  seq_size = set_size (constraint_seq);

  if (set_get_element_nocopy (constraint_seq, 0, &id_val) != NO_ERROR)
    {
      return;
    }

  if (DB_VALUE_TYPE (&id_val) != DB_TYPE_STRING || db_get_string (&id_val) == NULL)
    {
      return;
    }

  args = classobj_decompose_property_oid (db_get_string (&id_val), &volid, &fileid, &pageid);

  if (args != 3)
    {
      return;
    }

  /*
   *  Assign the B-tree ID.
   *  For the first attribute name in the constraint,
   *    cache the constraint in the attribute.
   */
  id.vfid.volid = (VOLID) volid;
  id.root_pageid = (PAGEID) pageid;
  id.vfid.fileid = (FILEID) fileid;

  i = 1;
  if (set_get_element_nocopy (constraint_seq, i, &att_val) == NO_ERROR)
    {
      assert (DB_VALUE_TYPE (&att_val) == DB_TYPE_INTEGER);
      att_id = db_get_int (&att_val);   /* The first attrID */

      if (IS_DEDUPLICATE_KEY_ATTR_ID (att_id))
    {
          // *INDENT-OFF* 
      /* To reach this point, the inside of the set must have at least the following structure.
       *     0         1                2      [  3        4  ] *x         5 + x               6 + x
       * { btid, dedup_key_attrID, asc_desc, [attrID, asc_desc]+, {fk_info} or {prefix length}, ...}
           * For constraint structure details, see comment on SM_CLASS_CONSTRAINT in class_object.h.
       * That is, the size of this constraint_seq set must be 10 or more, and the 3rd position will be attrID.
       * The position 1 is deduplicate_key_attrID, which is virtual information, 
       * the position 3 value must be read to obtain actual column information.           
       */
          // *INDENT-ON*
      assert (seq_size >= 10);
      i = 3;        // index of attrID (for first real column)
      if (set_get_element_nocopy (constraint_seq, i, &att_val) == NO_ERROR)
        {
          assert (DB_VALUE_TYPE (&att_val) == DB_TYPE_INTEGER);
          att_id = db_get_int (&att_val);   /* The first attrID after HIDDEN_INDEX_COL */
        }
    }

      (void) or_install_btids_attribute (rep, att_id, &id);
    }

  /*
   *  Assign the B-tree ID to the class.
   *  Cache the constraint in the class with pointer to the attributes.
   *  This is just a different way to store the BTID's.
   */
  or_install_btids_class (rep, &id, constraint_seq, seq_size, type, cons_name);
}

/*
 * or_install_btids () - Install the constraints found on the property list
 *                       into the class and attribute structures
 *   return: void
 *   rep(in): Class representation
 *   props(in): Class property list
 */
static void
or_install_btids (OR_CLASSREP * rep, DB_SEQ * props)
{
  OR_BTREE_PROPERTY property_vars[SM_PROPERTY_NUM_INDEX_FAMILY] = {
    {SM_PROPERTY_FOREIGN_KEY, NULL, BTREE_FOREIGN_KEY, 0},
    {SM_PROPERTY_PRIMARY_KEY, NULL, BTREE_PRIMARY_KEY, 0},
    {SM_PROPERTY_UNIQUE, NULL, BTREE_UNIQUE, 0},
    {SM_PROPERTY_REVERSE_UNIQUE, NULL, BTREE_REVERSE_UNIQUE, 0},
    {SM_PROPERTY_INDEX, NULL, BTREE_INDEX, 0},
    {SM_PROPERTY_REVERSE_INDEX, NULL, BTREE_REVERSE_INDEX, 0}
  };

  DB_VALUE vals[SM_PROPERTY_NUM_INDEX_FAMILY];
  int i;
  int n_btids;

  /*
   *  The first thing to do is to determine how many unique and index
   *  BTIDs we have.  We need this up front so that we can allocate
   *  the OR_INDEX structure in the class (rep).
   */
  n_btids = 0;
  for (i = 0; i < SM_PROPERTY_NUM_INDEX_FAMILY; i++)
    {
      if (props != NULL && or_cl_get_prop_nocopy (props, property_vars[i].name, &vals[i]))
    {
      if (DB_VALUE_TYPE (&vals[i]) == DB_TYPE_SEQUENCE)
        {
          property_vars[i].seq = db_get_set (&vals[i]);
        }

      if (property_vars[i].seq)
        {
          property_vars[i].length = set_size (property_vars[i].seq);
          n_btids += property_vars[i].length;
        }
    }
    }

  n_btids /= 2;

  if (n_btids > 0)
    {
      rep->indexes = (OR_INDEX *) malloc (sizeof (OR_INDEX) * n_btids);
      if (rep->indexes == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (OR_INDEX) * n_btids);
      return;
    }
      memset (rep->indexes, 0, sizeof (OR_INDEX) * n_btids);
    }

  /* Now extract the unique and index BTIDs from the property list and install them into the class and attribute
   * structures. */
  for (i = 0; i < SM_PROPERTY_NUM_INDEX_FAMILY; i++)
    {
      if (property_vars[i].seq)
    {
      int j;
      DB_VALUE ids_val, cons_name_val;
      DB_SEQ *ids_seq;
      const char *cons_name = NULL;
      int error = NO_ERROR;

      for (j = 0; j < property_vars[i].length && error == NO_ERROR; j += 2)
        {
          error = set_get_element_nocopy (property_vars[i].seq, j, &cons_name_val);
          if (error == NO_ERROR)
        {
          cons_name = db_get_string (&cons_name_val);
        }

          error = set_get_element_nocopy (property_vars[i].seq, j + 1, &ids_val);
          if (error == NO_ERROR && cons_name != NULL)
        {
          if (DB_VALUE_TYPE (&ids_val) == DB_TYPE_SEQUENCE)
            {
              ids_seq = db_get_set (&ids_val);
              or_install_btids_constraint (rep, ids_seq, property_vars[i].type, cons_name);
            }
        }
        }
    }
    }
}

/*
 * or_get_current_representation () - build an OR_CLASSREP structure for the
 *                                    most recent representation
 *   return: disk representation structure
 *   record(in): disk record
 *   do_indexes(in):
 *
 * Note: This is similar to the old function orc_diskrep_from_record, but is
 *       a little simpler now that we don't need to maintain a separate
 *       list for the fixed and variable length attributes.
 *
 *       The logic is different from the logic in get_old_representation
 *       because the structures used to hold the most recent representation
 *       are different than the simplified structures used to hold the old
 *       representations.
 */
static OR_CLASSREP *
or_get_current_representation (RECDES * record, int do_indexes)
{
  OR_CLASSREP *rep;
  OR_ATTRIBUTE *att;
  OID oid;
  char *start, *ptr, *attset, *diskatt, *original_val_ptr, *dptr, *properties_val_ptr, *current_val_ptr;
  int i, start_offset, offset, original_val_len, n_fixed, n_variable, properties_val_len, current_val_len;
  int n_shared_attrs, n_class_attrs;
  OR_BUF buf;
  DB_VALUE properties_val, def_expr_op, def_expr, def_expr_type, def_expr_format;
  const char *def_expr_format_str = NULL;
  DB_SEQ *att_props = NULL, *def_expr_set = NULL;

  rep = (OR_CLASSREP *) malloc (sizeof (OR_CLASSREP));
  if (rep == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (OR_CLASSREP));
      return NULL;
    }

  start = record->data;

  assert (OR_GET_OFFSET_SIZE (start) == BIG_VAR_OFFSET_SIZE);

  ptr = start + OR_FIXED_ATTRIBUTES_OFFSET (record->data, ORC_CLASS_VAR_ATT_COUNT);

  rep->id = or_rep_id (record);
  rep->fixed_length = OR_GET_INT (ptr + ORC_FIXED_LENGTH_OFFSET);
  rep->attributes = NULL;
  rep->shared_attrs = NULL;
  rep->class_attrs = NULL;
  rep->indexes = NULL;

  n_fixed = OR_GET_INT (ptr + ORC_FIXED_COUNT_OFFSET);
  n_variable = OR_GET_INT (ptr + ORC_VARIABLE_COUNT_OFFSET);
  n_shared_attrs = OR_GET_INT (ptr + ORC_SHARED_COUNT_OFFSET);
  n_class_attrs = OR_GET_INT (ptr + ORC_CLASS_ATTR_COUNT_OFFSET);

  rep->n_attributes = n_fixed + n_variable;
  rep->n_variable = n_variable;
  rep->n_shared_attrs = n_shared_attrs;
  rep->n_class_attrs = n_class_attrs;
  rep->n_indexes = 0;

  if (rep->n_attributes > 0)
    {
      rep->attributes = (OR_ATTRIBUTE *) calloc (rep->n_attributes, sizeof (OR_ATTRIBUTE));
      if (rep->attributes == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
          sizeof (OR_ATTRIBUTE) * rep->n_attributes);
      goto error_cleanup;
    }
    }

  if (rep->n_shared_attrs > 0)
    {
      rep->shared_attrs = (OR_ATTRIBUTE *) calloc (rep->n_shared_attrs, sizeof (OR_ATTRIBUTE));
      if (rep->shared_attrs == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
          sizeof (OR_ATTRIBUTE) * rep->n_shared_attrs);
      goto error_cleanup;
    }
    }

  if (rep->n_class_attrs > 0)
    {
      rep->class_attrs = (OR_ATTRIBUTE *) calloc (rep->n_class_attrs, sizeof (OR_ATTRIBUTE));
      if (rep->class_attrs == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
          sizeof (OR_ATTRIBUTE) * rep->n_class_attrs);
      goto error_cleanup;
    }
    }


  /* find the beginning of the "set_of(attribute)" attribute inside the class */
  attset = start + OR_VAR_OFFSET (start, ORC_ATTRIBUTES_INDEX);

  /* calculate the offset to the first fixed width attribute in instances of this class. */
  start_offset = offset = 0;

  for (i = 0, att = rep->attributes; i < rep->n_attributes; i++, att++)
    {
      /* diskatt will now be pointing at the offset table for this attribute. this is logically the "start" of this
       * nested object. */
      diskatt = attset + OR_SET_ELEMENT_OFFSET (attset, i);

      /* find out where the original default value is kept */
      original_val_ptr = (diskatt + OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, ORC_ATT_ORIGINAL_VALUE_INDEX));
      original_val_len = OR_VAR_TABLE_ELEMENT_LENGTH (diskatt, ORC_ATT_ORIGINAL_VALUE_INDEX);

      current_val_ptr = (diskatt + OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, ORC_ATT_CURRENT_VALUE_INDEX));
      current_val_len = OR_VAR_TABLE_ELEMENT_LENGTH (diskatt, ORC_ATT_CURRENT_VALUE_INDEX);

      properties_val_ptr = (diskatt + OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, ORC_ATT_PROPERTIES_INDEX));
      properties_val_len = OR_VAR_TABLE_ELEMENT_LENGTH (diskatt, ORC_ATT_PROPERTIES_INDEX);

      or_init (&buf, properties_val_ptr, properties_val_len);

      /* set ptr to the beginning of the fixed attributes */
      ptr = diskatt + OR_VAR_TABLE_SIZE (ORC_ATT_VAR_ATT_COUNT);

      if (OR_GET_INT (ptr + ORC_ATT_FLAG_OFFSET) & SM_ATTFLAG_AUTO_INCREMENT)
    {
      att->is_autoincrement = 1;
    }
      else
    {
      att->is_autoincrement = 0;
    }

      if (OR_GET_INT (ptr + ORC_ATT_FLAG_OFFSET) & SM_ATTFLAG_NON_NULL)
    {
      att->is_notnull = 1;
    }
      else
    {
      att->is_notnull = 0;
    }

      att->type = (DB_TYPE) OR_GET_INT (ptr + ORC_ATT_TYPE_OFFSET);
      att->id = OR_GET_INT (ptr + ORC_ATT_ID_OFFSET);
      assert (!IS_DEDUPLICATE_KEY_ATTR_ID (att->id));
      att->def_order = OR_GET_INT (ptr + ORC_ATT_DEF_ORDER_OFFSET);
      att->position = i;
      att->default_value.val_length = 0;
      att->default_value.value = NULL;
      att->current_default_value.val_length = 0;
      att->current_default_value.value = NULL;
      OR_GET_OID (ptr + ORC_ATT_CLASS_OFFSET, &oid);
      att->classoid = oid;

      att->auto_increment.serial_obj = oid_Null_oid;
      /* get the btree index id if an index has been assigned */
      or_get_att_index (ptr + ORC_ATT_INDEX_OFFSET, &att->index);

      /* We won't know if there are any B-tree ID's for unique constraints until we read the class property list later
       * on */
      att->n_btids = 0;
      att->btids = NULL;

      /* Extract the full domain for this attribute, think about caching here it will add some time that may not be
       * necessary. */
      if (OR_VAR_TABLE_ELEMENT_LENGTH (diskatt, ORC_ATT_DOMAIN_INDEX) == 0)
    {
      /* shouldn't happen, fake one up from the type ! */
      att->domain = tp_domain_resolve_default (att->type);
    }
      else
    {
      dptr = (diskatt + OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, ORC_ATT_DOMAIN_INDEX));
      att->domain = or_get_domain_and_cache (dptr);
    }

      if (i < n_fixed)
    {
      att->is_fixed = 1;
      att->location = offset;
      offset += tp_domain_disk_size (att->domain);
    }
      else
    {
      att->is_fixed = 0;
      att->location = i - n_fixed;
    }

      /* get the current default value - constant */
      if (current_val_len > 0)
    {
      if (or_get_current_default_value (att, current_val_ptr, current_val_len) == 0)
        {
          goto error_cleanup;
        }
    }

      /* get the default value - constant, this could be using a new DB_VALUE ? */
      if (original_val_len > 0)
    {
      if (or_get_default_value (att, original_val_ptr, original_val_len) == 0)
        {
          goto error_cleanup;
        }
    }

      /* get the default expression. */
      classobj_initialize_default_expr (&att->current_default_value.default_expr);
      att->on_update_expr = DB_DEFAULT_NONE;
      if (properties_val_len > 0)
    {
      db_make_null (&properties_val);
      db_make_null (&def_expr);
      db_make_null (&def_expr_op);
      db_make_null (&def_expr_format);

      or_get_value (&buf, &properties_val, tp_domain_resolve_default (DB_TYPE_SEQUENCE), properties_val_len, true);
      att_props = db_get_set (&properties_val);

      if (att_props != NULL && classobj_get_prop (att_props, "default_expr", &def_expr) > 0)
        {
          /* We have two cases: simple and complex expression. */
          if (DB_VALUE_TYPE (&def_expr) == DB_TYPE_SEQUENCE)
        {
          /*
           * We can't have an attribute with default expression and default value simultaneously. However,
           * in some situations attr->default_value.value contains the value of default expression. This happens
           * when the client executes the query on broker side and use attr->default_value.value to cache
           * the default expression value. Then the broker can modify the schema and send to server the default
           * expression and its cached value. Another option may be to clear default value on broker side,
           * but may lead to inconsistency.
           */

          /* Currently, we allow only (T_TO_CHAR(int), default_expr(int), default_expr_format(string)) */
          assert (set_size (db_get_set (&def_expr)) == 3);

          def_expr_set = db_get_set (&def_expr);

          /* get and cache default expression operator - op of expr */
          if (set_get_element_nocopy (def_expr_set, 0, &def_expr_op) != NO_ERROR)
            {
              assert (false);
              pr_clear_value (&def_expr);
              pr_clear_value (&properties_val);
              goto error_cleanup;
            }
          assert (DB_VALUE_TYPE (&def_expr_op) == DB_TYPE_INTEGER
              && db_get_int (&def_expr_op) == (int) T_TO_CHAR);
          att->default_value.default_expr.default_expr_op = db_get_int (&def_expr_op);
          att->current_default_value.default_expr.default_expr_op = db_get_int (&def_expr_op);

          /* get and cache default expression type - arg1 of expr */
          if (set_get_element_nocopy (def_expr_set, 1, &def_expr_type) != NO_ERROR)
            {
              assert (false);
              pr_clear_value (&def_expr);
              pr_clear_value (&properties_val);
              goto error_cleanup;
            }
          assert (DB_VALUE_TYPE (&def_expr_type) == DB_TYPE_INTEGER);
          att->default_value.default_expr.default_expr_type =
            (DB_DEFAULT_EXPR_TYPE) db_get_int (&def_expr_type);
          att->current_default_value.default_expr.default_expr_type =
            (DB_DEFAULT_EXPR_TYPE) db_get_int (&def_expr_type);

          /* get and cache default expression format - arg2 of expr */
          if (set_get_element_nocopy (def_expr_set, 2, &def_expr_format) != NO_ERROR)
            {
              assert (false);
              pr_clear_value (&def_expr);
              pr_clear_value (&properties_val);
              goto error_cleanup;
            }

          if (!db_value_is_null (&def_expr_format))
            {
#if !defined (NDEBUG)
              DB_TYPE db_value_type_local = db_value_type (&def_expr_format);
              assert (db_value_type_local == DB_TYPE_NULL || TP_IS_CHAR_TYPE (db_value_type_local));
#endif
              def_expr_format_str = db_get_string (&def_expr_format);
              att->default_value.default_expr.default_expr_format = strdup (def_expr_format_str);
              att->current_default_value.default_expr.default_expr_format = strdup (def_expr_format_str);
            }
        }
          else
        {
          /* simple expressions like SYS_DATE */
          assert (DB_VALUE_TYPE (&def_expr) == DB_TYPE_INTEGER);

          att->default_value.default_expr.default_expr_type = (DB_DEFAULT_EXPR_TYPE) db_get_int (&def_expr);
          att->current_default_value.default_expr.default_expr_type =
            (DB_DEFAULT_EXPR_TYPE) db_get_int (&def_expr);
        }
        }
      pr_clear_value (&def_expr);

      if (att_props != NULL && classobj_get_prop (att_props, "update_default", &def_expr) > 0)
        {
          /* simple expressions like SYS_DATE */
          assert (DB_VALUE_TYPE (&def_expr) == DB_TYPE_INTEGER);
          att->on_update_expr = (DB_DEFAULT_EXPR_TYPE) db_get_int (&def_expr);
        }

      pr_clear_value (&def_expr);
      pr_clear_value (&properties_val);
    }
    }

  /* find the beginning of the "set_of(shared attributes)" attribute inside the class */
  attset = start + OR_VAR_OFFSET (start, ORC_SHARED_ATTRS_INDEX);

  for (i = 0, att = rep->shared_attrs; i < rep->n_shared_attrs; i++, att++)
    {
      /* diskatt will now be pointing at the offset table for this attribute. this is logically the "start" of this
       * nested object. */
      diskatt = attset + OR_SET_ELEMENT_OFFSET (attset, i);

      /* find out where the current default value is kept */
      current_val_ptr = (diskatt + OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, ORC_ATT_CURRENT_VALUE_INDEX));
      current_val_len = OR_VAR_TABLE_ELEMENT_LENGTH (diskatt, ORC_ATT_CURRENT_VALUE_INDEX);

      /* set ptr to the beginning of the fixed attributes */
      ptr = diskatt + OR_VAR_TABLE_SIZE (ORC_ATT_VAR_ATT_COUNT);

      att->is_autoincrement = 0;
      if (OR_GET_INT (ptr + ORC_ATT_FLAG_OFFSET) & SM_ATTFLAG_NON_NULL)
    {
      att->is_notnull = 1;
    }
      else
    {
      att->is_notnull = 0;
    }

      att->type = (DB_TYPE) OR_GET_INT (ptr + ORC_ATT_TYPE_OFFSET);
      att->id = OR_GET_INT (ptr + ORC_ATT_ID_OFFSET);
      assert (!IS_DEDUPLICATE_KEY_ATTR_ID (att->id));
      att->def_order = OR_GET_INT (ptr + ORC_ATT_DEF_ORDER_OFFSET);
      att->position = i;
      att->default_value.val_length = 0;
      att->default_value.value = NULL;
      classobj_initialize_default_expr (&att->default_value.default_expr);
      att->current_default_value.val_length = 0;
      att->current_default_value.value = NULL;
      classobj_initialize_default_expr (&att->current_default_value.default_expr);
      att->on_update_expr = DB_DEFAULT_NONE;

      OR_GET_OID (ptr + ORC_ATT_CLASS_OFFSET, &oid);
      att->classoid = oid;  /* structure copy */

      /* get the btree index id if an index has been assigned */
      or_get_att_index (ptr + ORC_ATT_INDEX_OFFSET, &att->index);

      /* there won't be any indexes or uniques for shared attrs */
      att->n_btids = 0;
      att->btids = NULL;

      /* Extract the full domain for this attribute, think about caching here it will add some time that may not be
       * necessary. */
      if (OR_VAR_TABLE_ELEMENT_LENGTH (diskatt, ORC_ATT_DOMAIN_INDEX) == 0)
    {
      /* shouldn't happen, fake one up from the type ! */
      att->domain = tp_domain_resolve_default (att->type);
    }
      else
    {
      dptr = diskatt + OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, ORC_ATT_DOMAIN_INDEX);
      att->domain = or_get_domain_and_cache (dptr);
    }

      att->is_fixed = 0;
      att->location = 0;

      /* get the default value, it is the container for the shared value */
      if (current_val_len > 0)
    {
      if (or_get_default_value (att, current_val_ptr, current_val_len) == 0)
        {
          goto error_cleanup;
        }

      if (att->default_value.val_length > 0)
        {
          att->current_default_value.value = malloc (att->default_value.val_length);
          if (att->current_default_value.value == NULL)
        {
          goto error_cleanup;
        }

          memcpy (att->current_default_value.value, att->default_value.value, att->default_value.val_length);
          att->current_default_value.val_length = att->default_value.val_length;
        }
    }
    }

  /* find the beginning of the "set_of(class_attrs)" attribute inside the class */
  attset = start + OR_VAR_OFFSET (start, ORC_CLASS_ATTRS_INDEX);

  for (i = 0, att = rep->class_attrs; i < rep->n_class_attrs; i++, att++)
    {
      /* diskatt will now be pointing at the offset table for this attribute. this is logically the "start" of this
       * nested object. */
      diskatt = attset + OR_SET_ELEMENT_OFFSET (attset, i);

      /* find out where the current default value is kept */
      current_val_ptr = (diskatt + OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, ORC_ATT_CURRENT_VALUE_INDEX));
      current_val_len = OR_VAR_TABLE_ELEMENT_LENGTH (diskatt, ORC_ATT_CURRENT_VALUE_INDEX);

      /* set ptr to the beginning of the fixed attributes */
      ptr = diskatt + OR_VAR_TABLE_SIZE (ORC_ATT_VAR_ATT_COUNT);

      att->is_autoincrement = 0;
      att->is_notnull = 0;

      att->type = (DB_TYPE) OR_GET_INT (ptr + ORC_ATT_TYPE_OFFSET);
      att->id = OR_GET_INT (ptr + ORC_ATT_ID_OFFSET);
      assert (!IS_DEDUPLICATE_KEY_ATTR_ID (att->id));
      att->def_order = OR_GET_INT (ptr + ORC_ATT_DEF_ORDER_OFFSET);
      att->position = i;
      att->default_value.val_length = 0;
      att->default_value.value = NULL;
      classobj_initialize_default_expr (&att->default_value.default_expr);
      att->on_update_expr = DB_DEFAULT_NONE;
      att->current_default_value.val_length = 0;
      att->current_default_value.value = NULL;
      classobj_initialize_default_expr (&att->current_default_value.default_expr);
      OR_GET_OID (ptr + ORC_ATT_CLASS_OFFSET, &oid);
      att->classoid = oid;

      /* get the btree index id if an index has been assigned */
      or_get_att_index (ptr + ORC_ATT_INDEX_OFFSET, &att->index);

      /* there won't be any indexes or uniques for shared attrs */
      att->n_btids = 0;
      att->btids = NULL;

      /* Extract the full domain for this attribute, think about caching here it will add some time that may not be
       * necessary. */
      if (OR_VAR_TABLE_ELEMENT_LENGTH (diskatt, ORC_ATT_DOMAIN_INDEX) == 0)
    {
      /* shouldn't happen, fake one up from the type ! */
      att->domain = tp_domain_resolve_default (att->type);
    }
      else
    {
      dptr = diskatt + OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, ORC_ATT_DOMAIN_INDEX);
      att->domain = or_get_domain_and_cache (dptr);
    }

      att->is_fixed = 0;
      att->location = 0;

      /* get the default value, it is the container for the class attr value */
      if (current_val_len > 0)
    {
      if (or_get_default_value (att, current_val_ptr, current_val_len) == 0)
        {
          goto error_cleanup;
        }
      if (att->default_value.val_length > 0)
        {
          att->current_default_value.value = malloc (att->default_value.val_length);
          if (att->current_default_value.value == NULL)
        {
          goto error_cleanup;
        }

          memcpy (att->current_default_value.value, att->default_value.value, att->default_value.val_length);
          att->current_default_value.val_length = att->default_value.val_length;
        }
    }
    }

  /* Read the B-tree IDs from the class property list */
  if (do_indexes)
    {
      char *propptr;
      DB_SET *props;

      if (!OR_VAR_IS_NULL (record->data, ORC_PROPERTIES_INDEX))
    {
      propptr = record->data + OR_VAR_OFFSET (record->data, ORC_PROPERTIES_INDEX);
      (void) or_unpack_setref (propptr, &props);
      or_install_btids (rep, props);
      db_set_free (props);
    }
      rep->needs_indexes = 0;
    }
  else
    {
      rep->needs_indexes = 1;
    }

  if (OR_VAR_IS_NULL (record->data, ORC_PARTITION_INDEX))
    {
      rep->has_partition_info = 0;
    }
  else
    {
      rep->has_partition_info = 1;
    }

  return rep;

error_cleanup:

  if (rep->attributes)
    {
      free_and_init (rep->attributes);
    }

  if (rep->shared_attrs)
    {
      free_and_init (rep->shared_attrs);
    }

  if (rep->class_attrs)
    {
      free_and_init (rep->class_attrs);
    }

  free_and_init (rep);

  return NULL;
}

/*
 * or_get_old_representation () - Extracts the description of an old
 *                                representation from the disk image of a
 *                                class
 *   return:
 *   record(in): record with class diskrep
 *   repid(in): representation id to extract
 *   do_indexes(in):
 *
 * Note: It is similar to get_current_representation
 *       except that it must get its information out of the compressed
 *       SM_REPRESENTATION & SM_REPR_ATTRIBUTE structures which are used for
 *       storing the old representations.  The current representation is stored
 *       in top-level SM_ATTRIBUTE structures which are much larger.
 *
 *       If repid is -1 here, it returns the current representation.
 *       It returns NULL on error.  This can happen during memory allocation
 *       failure but is more likely to happen if the repid given was not
 *       found within the class.
 */
static OR_CLASSREP *
or_get_old_representation (RECDES * record, int repid, int do_indexes)
{
  OR_CLASSREP *rep;
  OR_ATTRIBUTE *att;
  char *repset, *disk_rep, *attset, *repatt, *dptr;
  int rep_count, i, n_fixed, n_variable, offset, start, id;
  char *fixed = NULL;

  if (repid == NULL_REPRID)
    {
      return or_get_current_representation (record, do_indexes);
    }

  /* find the beginning of the "set_of(representation)" attribute inside the class. If this attribute is NULL, we're
   * missing the representations, its an error. */
  if (OR_VAR_IS_NULL (record->data, ORC_REPRESENTATIONS_INDEX))
    {
      return NULL;
    }

  assert (OR_GET_OFFSET_SIZE (record->data) == BIG_VAR_OFFSET_SIZE);

  repset = (record->data + OR_VAR_OFFSET (record->data, ORC_REPRESENTATIONS_INDEX));

  /* repset now points to the beginning of a complex set representation, find out how many elements are in the set. */
  rep_count = OR_SET_ELEMENT_COUNT (repset);

  /* locate the beginning of the representation in this set whose id matches the given repid. */
  disk_rep = NULL;
  for (i = 0; i < rep_count; i++)
    {
      /* set disk_rep to the beginning of the i'th set element */
      disk_rep = repset + OR_SET_ELEMENT_OFFSET (repset, i);

      /* move ptr up to the beginning of the fixed width attributes in this object */
      fixed = disk_rep + OR_VAR_TABLE_SIZE (ORC_REP_VAR_ATT_COUNT);

      /* extract the id of this representation */
      id = OR_GET_INT (fixed + ORC_REP_ID_OFFSET);

      if (id == repid)
    {
      break;
    }
      else
    {
      disk_rep = NULL;
    }
    }

  if (disk_rep == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_CT_UNKNOWN_REPRID, 1, repid);
      return NULL;
    }

  /* allocate a new memory structure for this representation */
  rep = (OR_CLASSREP *) malloc (sizeof (OR_CLASSREP));
  if (rep == NULL)
    {
      return NULL;
    }

  rep->attributes = NULL;
  rep->shared_attrs = NULL;
  rep->class_attrs = NULL;
  rep->indexes = NULL;

  /* at this point, disk_rep points to the beginning of the representation object and "fixed" points at the first fixed
   * width attribute. */

  n_fixed = OR_GET_INT (fixed + ORC_REP_FIXED_COUNT_OFFSET);
  n_variable = OR_GET_INT (fixed + ORC_REP_VARIABLE_COUNT_OFFSET);

  rep->id = repid;
  rep->fixed_length = 0;
  rep->n_attributes = n_fixed + n_variable;
  rep->n_variable = n_variable;
  rep->n_indexes = 0;

  if (!rep->n_attributes)
    {
      /* its an empty representation, return it */
      return rep;
    }

  rep->attributes = (OR_ATTRIBUTE *) calloc (rep->n_attributes, sizeof (OR_ATTRIBUTE));
  if (rep->attributes == NULL)
    {
      free_and_init (rep);
      return NULL;
    }
  /* Calculate the beginning of the set_of(rep_attribute) in the representation object. Assume that the start of the
   * disk_rep points directly at the the substructure's variable offset table (which it does) and use
   * OR_VAR_TABLE_ELEMENT_OFFSET. */
  attset = disk_rep + OR_VAR_TABLE_ELEMENT_OFFSET (disk_rep, ORC_REP_ATTRIBUTES_INDEX);

  /* Calculate the offset to the first fixed width attribute in instances of this class.  Save the start of this region
   * so we can calculate the total fixed witdh size. */
  start = offset = 0;

  /* build up the attribute descriptions */
  for (i = 0, att = rep->attributes; i < rep->n_attributes; i++, att++)
    {
      /* set repatt to the beginning of the rep_attribute object in the set */
      repatt = attset + OR_SET_ELEMENT_OFFSET (attset, i);

      /* set fixed to the beginning of the fixed width attributes for this object */
      fixed = repatt + OR_VAR_TABLE_SIZE (ORC_REPATT_VAR_ATT_COUNT);

      att->id = OR_GET_INT (fixed + ORC_REPATT_ID_OFFSET);
      assert (!IS_DEDUPLICATE_KEY_ATTR_ID (att->id));
      att->type = (DB_TYPE) OR_GET_INT (fixed + ORC_REPATT_TYPE_OFFSET);
      att->position = i;
      att->default_value.val_length = 0;
      att->default_value.value = NULL;
      classobj_initialize_default_expr (&att->default_value.default_expr);
      att->current_default_value.val_length = 0;
      att->current_default_value.value = NULL;
      classobj_initialize_default_expr (&att->current_default_value.default_expr);

      /* We won't know if there are any B-tree ID's for unique constraints until we read the class property list later
       * on */
      att->n_btids = 0;
      att->btids = NULL;

      /* not currently available, will this be a problem ? */
      OID_SET_NULL (&(att->classoid));
      BTID_SET_NULL (&(att->index));

      /* Extract the full domain for this attribute, think about caching here it will add some time that may not be
       * necessary. */
      if (OR_VAR_TABLE_ELEMENT_LENGTH (repatt, ORC_REPATT_DOMAIN_INDEX) == 0)
    {
      /* shouldn't happen, fake one up from the type ! */
      att->domain = tp_domain_resolve_default (att->type);
    }
      else
    {
      dptr = repatt + OR_VAR_TABLE_ELEMENT_OFFSET (repatt, ORC_REPATT_DOMAIN_INDEX);
      att->domain = or_get_domain_and_cache (dptr);
    }

      if (i < n_fixed)
    {
      att->is_fixed = 1;
      att->location = offset;
      offset += tp_domain_disk_size (att->domain);
    }
      else
    {
      att->is_fixed = 0;
      att->location = i - n_fixed;
    }
    }

  /* Offset at this point contains the total fixed size of the representation plus the starting offset, remove the
   * starting offset to get the length of just the fixed width attributes. */
  /* must align up to a word boundar ! */
  rep->fixed_length = DB_ATT_ALIGN (offset - start);

  /* Read the B-tree IDs from the class property list */
  if (do_indexes)
    {
      char *propptr;
      DB_SET *props;

      if (!OR_VAR_IS_NULL (record->data, ORC_PROPERTIES_INDEX))
    {
      propptr = record->data + OR_VAR_OFFSET (record->data, ORC_PROPERTIES_INDEX);
      (void) or_unpack_setref (propptr, &props);
      or_install_btids (rep, props);
      db_set_free (props);
    }
      rep->needs_indexes = 0;
    }
  else
    {
      rep->needs_indexes = 1;
    }

  if (OR_VAR_IS_NULL (record->data, ORC_PARTITION_INDEX))
    {
      rep->has_partition_info = 0;
    }
  else
    {
      rep->has_partition_info = 1;
    }

  return rep;
}

/*
 * or_get_all_representation () - Extracts the description of all
 *                                representation from the disk image of a
 *                                class.
 *   return:
 *   record(in): record with class diskrep
 *   count(out): the number of representation to be returned
 *   do_indexes(in):
 */
OR_CLASSREP **
or_get_all_representation (RECDES * record, bool do_indexes, int *count)
{
  OR_ATTRIBUTE *att;
  OR_CLASSREP *rep, **rep_arr = NULL;
  char *repset = NULL, *disk_rep, *attset, *repatt, *dptr, *fixed = NULL;
  int old_rep_count = 0, i, j, offset, start, n_variable, n_fixed;

  if (count)
    {
      *count = 0;
    }

  assert (OR_GET_OFFSET_SIZE (record->data) == BIG_VAR_OFFSET_SIZE);

  if (!OR_VAR_IS_NULL (record->data, ORC_REPRESENTATIONS_INDEX))
    {
      repset = (record->data + OR_VAR_OFFSET (record->data, ORC_REPRESENTATIONS_INDEX));
      old_rep_count = OR_SET_ELEMENT_COUNT (repset);
    }

  /* add one for current representation */
  rep_arr = (OR_CLASSREP **) malloc (sizeof (OR_CLASSREP *) * (old_rep_count + 1));
  if (rep_arr == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
          (sizeof (OR_CLASSREP *) * (old_rep_count + 1)));
      return NULL;
    }

  memset (rep_arr, 0x0, sizeof (OR_CLASSREP *) * (old_rep_count + 1));

  /* current representation */
  rep_arr[0] = or_get_current_representation (record, 1);
  if (rep_arr[0] == NULL)
    {
      goto error;
    }

  disk_rep = NULL;
  for (i = 0; i < old_rep_count && repset != NULL; i++)
    {
      rep_arr[i + 1] = (OR_CLASSREP *) malloc (sizeof (OR_CLASSREP));
      if (rep_arr[i + 1] == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (OR_CLASSREP));
      goto error;
    }
      rep = rep_arr[i + 1];

      /* set disk_rep to the beginning of the i'th set element */
      disk_rep = repset + OR_SET_ELEMENT_OFFSET (repset, i);

      /* move ptr up to the beginning of the fixed width attributes in this object */
      fixed = disk_rep + OR_VAR_TABLE_SIZE (ORC_REP_VAR_ATT_COUNT);

      /* extract the id of this representation */
      rep->id = OR_GET_INT (fixed + ORC_REP_ID_OFFSET);

      n_fixed = OR_GET_INT (fixed + ORC_REP_FIXED_COUNT_OFFSET);
      n_variable = OR_GET_INT (fixed + ORC_REP_VARIABLE_COUNT_OFFSET);

      rep->n_variable = n_variable;
      rep->n_attributes = n_fixed + n_variable;
      rep->n_indexes = 0;
      rep->n_shared_attrs = 0;
      rep->n_class_attrs = 0;
      rep->fixed_length = 0;

      rep->next = NULL;
      rep->attributes = NULL;
      rep->shared_attrs = NULL;
      rep->class_attrs = NULL;
      rep->indexes = NULL;

      if (rep->n_attributes == 0)
    {
      continue;
    }

      rep->attributes = (OR_ATTRIBUTE *) calloc (rep->n_attributes, sizeof (OR_ATTRIBUTE));
      if (rep->attributes == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
          (sizeof (OR_ATTRIBUTE) * rep->n_attributes));
      goto error;
    }
      /* Calculate the beginning of the set_of(rep_attribute) in the representation object. Assume that the start of
       * the disk_rep points directly at the the substructure's variable offset table (which it does) and use
       * OR_VAR_TABLE_ELEMENT_OFFSET. */
      attset = disk_rep + OR_VAR_TABLE_ELEMENT_OFFSET (disk_rep, ORC_REP_ATTRIBUTES_INDEX);

      /* Calculate the offset to the first fixed width attribute in instances of this class.  Save the start of this
       * region so we can calculate the total fixed width size. */
      start = offset = 0;

      /* build up the attribute descriptions */
      for (j = 0, att = rep->attributes; j < rep->n_attributes; j++, att++)
    {
      /* set repatt to the beginning of the rep_attribute object in the set */
      repatt = attset + OR_SET_ELEMENT_OFFSET (attset, j);

      /* set fixed to the beginning of the fixed width attributes for this object */
      fixed = repatt + OR_VAR_TABLE_SIZE (ORC_REPATT_VAR_ATT_COUNT);

      att->id = OR_GET_INT (fixed + ORC_REPATT_ID_OFFSET);
      assert (!IS_DEDUPLICATE_KEY_ATTR_ID (att->id));
      att->type = (DB_TYPE) OR_GET_INT (fixed + ORC_REPATT_TYPE_OFFSET);
      att->position = j;
      att->default_value.val_length = 0;
      att->default_value.value = NULL;
      classobj_initialize_default_expr (&att->default_value.default_expr);
      att->current_default_value.val_length = 0;
      att->current_default_value.value = NULL;
      classobj_initialize_default_expr (&att->current_default_value.default_expr);

      /* We won't know if there are any B-tree ID's for unique constraints until we read the class property list
       * later on */
      att->n_btids = 0;
      att->btids = NULL;

      /* not currently available, will this be a problem ? */
      OID_SET_NULL (&(att->classoid));
      BTID_SET_NULL (&(att->index));

      /* Extract the full domain for this attribute, think about caching here it will add some time that may not be
       * necessary. */
      if (OR_VAR_TABLE_ELEMENT_LENGTH (repatt, ORC_REPATT_DOMAIN_INDEX) == 0)
        {
          /* shouldn't happen, fake one up from the type ! */
          att->domain = tp_domain_resolve_default (att->type);
        }
      else
        {
          dptr = repatt + OR_VAR_TABLE_ELEMENT_OFFSET (repatt, ORC_REPATT_DOMAIN_INDEX);
          att->domain = or_get_domain_and_cache (dptr);
        }

      if (j < n_fixed)
        {
          att->is_fixed = 1;
          att->location = offset;
          offset += tp_domain_disk_size (att->domain);
        }
      else
        {
          att->is_fixed = 0;
          att->location = j - n_fixed;
        }
    }

      /* Offset at this point contains the total fixed size of the representation plus the starting offset, remove the
       * starting offset to get the length of just the fixed width attributes. */
      /* must align up to a word boundar ! */
      rep->fixed_length = DB_ATT_ALIGN (offset - start);

      /* Read the B-tree IDs from the class property list */
      if (do_indexes)
    {
      char *propptr;
      DB_SET *props;

      if (!OR_VAR_IS_NULL (record->data, ORC_PROPERTIES_INDEX))
        {
          propptr = record->data + OR_VAR_OFFSET (record->data, ORC_PROPERTIES_INDEX);
          (void) or_unpack_setref (propptr, &props);
          or_install_btids (rep, props);
          db_set_free (props);
        }
      rep->needs_indexes = 0;
    }
      else
    {
      rep->needs_indexes = 1;
    }

      if (OR_VAR_IS_NULL (record->data, ORC_PARTITION_INDEX))
    {
      rep->has_partition_info = 0;
    }
      else
    {
      rep->has_partition_info = 1;
    }
    }

  if (count)
    {
      *count = old_rep_count + 1;
    }
  return rep_arr;

error:
  for (i = 0; i < old_rep_count + 1; i++)
    {
      or_free_classrep (rep_arr[i]);
    }
  free_and_init (rep_arr);

  return NULL;
}

/*
 * or_get_classrep () - builds an in-memory OR_CLASSREP that describes the
 *                      class
 *   return: OR_CLASSREP structure
 *   record(in): disk record
 *   repid(in): representation of interest (-1) for current
 *
 * Note: This structure is in turn used to navigate over the instances of this
 *       class stored in the heap.
 *       It calls either get_current_representation or get_old_representation
 *       to do the work.
 */
OR_CLASSREP *
or_get_classrep (RECDES * record, int repid)
{
  OR_CLASSREP *rep;
  int current;

  assert (OR_GET_OFFSET_SIZE (record->data) == BIG_VAR_OFFSET_SIZE);

  if (repid == NULL_REPRID)
    {
      rep = or_get_current_representation (record, 1);
    }
  else
    {
      /* find out what the most recent representation is */
      current = or_rep_id (record);

      if (current == repid)
    {
      rep = or_get_current_representation (record, 1);
    }
      else
    {
      rep = or_get_old_representation (record, repid, 1);
    }
    }

  return rep;
}

/*
 * or_get_classrep_noindex () -
 *   return:
 *   record(in):
 *   repid(in):
 */
OR_CLASSREP *
or_get_classrep_noindex (RECDES * record, int repid)
{
  OR_CLASSREP *rep;
  int current;

  assert (OR_GET_OFFSET_SIZE (record->data) == BIG_VAR_OFFSET_SIZE);

  if (repid == NULL_REPRID)
    {
      rep = or_get_current_representation (record, 0);
    }
  else
    {
      /* find out what the most recent representation is */
      current = or_rep_id (record);

      if (current == repid)
    {
      rep = or_get_current_representation (record, 0);
    }
      else
    {
      rep = or_get_old_representation (record, repid, 0);
    }
    }
  return rep;
}

/*
 * or_classrep_load_indexes () -
 *   return:
 *   rep(in):
 *   record(in):
 */
OR_CLASSREP *
or_classrep_load_indexes (OR_CLASSREP * rep, RECDES * record)
{
  REPR_ID id;

  /* eventually could be smarter about trying to reuse the existing structure. */
  if (rep->needs_indexes)
    {
      id = rep->id;
      or_free_classrep (rep);
      rep = or_get_classrep (record, id);
    }

  return rep;
}

/*
 * or_class_get_partition_info () - Get partition information from a record
 *                  descriptor of a class record
 * return : error code or NO_ERROR
 * record (in) : record descriptor
 * partition_info (in/out):  partition information
 * repr_id (in/out):  representation id from record
 * has_partition_info (out): whether this class has partition information or not
 *
 * Note: This function extracts the partition information from a class record.
 *
 * If the class is not a partition or is not a partitioned class,
 * has_partition_info will have the value zero.
 */
int
or_class_get_partition_info (RECDES * record, OR_PARTITION * partition_info, REPR_ID * repr_id, int *has_partition_info)
{
  char *partition_ptr = NULL, *ptr = NULL;
  OR_BUF buf;
  DB_VALUE val;

  assert (record != NULL);
  assert (partition_info != NULL);
  assert (repr_id != NULL);
  assert (has_partition_info != NULL);

  *has_partition_info = 0;
  *repr_id = or_rep_id (record);

  if (OR_VAR_IS_NULL (record->data, ORC_PARTITION_INDEX))
    {
      return NO_ERROR;
    }

  partition_ptr = (char *) (record->data) + OR_VAR_OFFSET (record->data, ORC_PARTITION_INDEX);

  partition_ptr += OR_SET_ELEMENT_OFFSET (partition_ptr, 0);

  /* set ptr to the beginning of the fixed attributes */
  ptr = partition_ptr + OR_VAR_TABLE_SIZE (ORC_PARTITION_VAR_ATT_COUNT);

  partition_info->partition_type = OR_GET_INT (ptr);

  or_init (&buf, partition_ptr + OR_VAR_TABLE_ELEMENT_OFFSET (partition_ptr, ORC_PARTITION_VALUES_INDEX),
       OR_VAR_TABLE_ELEMENT_LENGTH (partition_ptr, ORC_PARTITION_VALUES_INDEX));
  if (or_get_value (&buf, &val, NULL, CAST_BUFLEN (buf.endptr - buf.ptr), true) != NO_ERROR)
    {
      return ER_FAILED;
    }
  partition_info->values = db_seq_copy (db_get_set (&val));
  if (partition_info->values == NULL)
    {
      pr_clear_value (&val);
      return ER_FAILED;
    }

  pr_clear_value (&val);

  or_class_hfid (record, &partition_info->class_hfid);
  partition_info->rep_id = *repr_id;
  *has_partition_info = 1;

  return NO_ERROR;
}

/*
 * or_get_constraint_comment () - Get constraint/index comment from a record
 *                                  descriptor of a class record
 * return : comment
 * record(in): record descriptor
 * constraint_name(in): constraint/index name
 *
 * Note: The "comment" returned is a duplicated string containing the comment string.
 *       It's up to the caller to free the returned pointer.
 *       If the given constraint/index name does not exist for current
 *       representation, NULL is returned.
 *       For constraint structure details, see comment on SM_CLASS_CONSTRAINT in class_object.h.
 */
const char *
or_get_constraint_comment (RECDES * record, const char *constraint_name)
{
  int error = NO_ERROR;
  int i, j, len, info_len, num;
  char *subset, *comment = NULL;
  DB_SET *info, *props, *setref;
  DB_VALUE value, uvalue, cvalue;
  bool found = false;

  info = props = setref = NULL;

  if (OR_VAR_IS_NULL (record->data, ORC_PROPERTIES_INDEX))
    {
      return NULL;
    }

  subset = (char *) (record->data) + OR_VAR_OFFSET (record->data, ORC_PROPERTIES_INDEX);

  or_unpack_setref (subset, &setref);
  if (setref == NULL)
    {
      return NULL;
    }

  num = set_size (setref);
  for (i = 0; i < num && found == false; i += 2)
    {
      const char *prop_name = NULL;
      error = set_get_element_nocopy (setref, i, &value);
      if (error != NO_ERROR || DB_VALUE_TYPE (&value) != DB_TYPE_STRING)
    {
      goto error_exit;
    }

      prop_name = db_get_string (&value);
      if (prop_name == NULL)
    {
      goto error_exit;
    }

      if (strcmp (prop_name, SM_PROPERTY_PRIMARY_KEY) != 0 && strcmp (prop_name, SM_PROPERTY_UNIQUE) != 0
      && strcmp (prop_name, SM_PROPERTY_REVERSE_UNIQUE) != 0 && strcmp (prop_name, SM_PROPERTY_INDEX) != 0
      && strcmp (prop_name, SM_PROPERTY_REVERSE_INDEX) != 0 && strcmp (prop_name, SM_PROPERTY_FOREIGN_KEY) != 0)
    {
      continue;
    }

      error = set_get_element_nocopy (setref, i + 1, &value);
      if (error != NO_ERROR || DB_VALUE_TYPE (&value) != DB_TYPE_SEQUENCE)
    {
      goto error_exit;
    }

      props = db_get_set (&value);
      len = set_size (props);
      for (j = 0; j < len; j += 2)
    {
      /* get the name */
      if (set_get_element_nocopy (props, j, &uvalue) || DB_VALUE_TYPE (&uvalue) != DB_TYPE_STRING)
        {
          goto error_exit;
        }

      if (strcmp (constraint_name, db_get_string (&uvalue)) != 0)
        {
          continue;
        }

      found = true;

      if (set_get_element_nocopy (props, j + 1, &uvalue))
        {
          goto error_exit;
        }
      if (DB_VALUE_TYPE (&uvalue) != DB_TYPE_SEQUENCE)
        {
          goto error_exit;
        }

      info = db_get_set (&uvalue);
      info_len = set_size (info);

      if (set_get_element_nocopy
          (info, get_class_constraint_index (info_len, SM_CONSTRAINT_COMMENT_INDEX), &cvalue)
          || DB_IS_NULL (&cvalue))
        {
          /* if not exists, set comment to null */
          comment = NULL;
        }
      else if (DB_VALUE_TYPE (&cvalue) == DB_TYPE_STRING)
        {
          /* strdup, caller shall free it */
          const char *cvalue_string = db_get_string (&cvalue);
          comment = strdup (cvalue_string);
        }
      else
        {
          goto error_exit;
        }
      break;
    }
    }
end:
  set_free (setref);
  return comment;

error_exit:
  assert (false);
  goto end;
}

#if defined (ENABLE_UNUSED_FUNCTION)
/*
 * or_classrep_needs_indexes () -
 *   return:
 *   rep(in):
 */
int
or_classrep_needs_indexes (OR_CLASSREP * rep)
{
  return rep->needs_indexes;
}
#endif /* ENABLE_UNUSED_FUNCTION */

/*
 * or_free_classrep () - Frees an OR_CLASSREP structure returned by
 *                       or_get_classrep
 *   return: void
 *   rep(in): representation structure
 */
void
or_free_classrep (OR_CLASSREP * rep)
{
  int i;
  OR_ATTRIBUTE *att;
  OR_INDEX *index;
  OR_FOREIGN_KEY *fk, *fk_next;

  if (rep == NULL)
    {
      return;
    }

  if (rep->attributes != NULL)
    {
      for (i = 0, att = rep->attributes; i < rep->n_attributes; i++, att++)
    {
      if (att->default_value.value != NULL)
        {
          free_and_init (att->default_value.value);
        }

      if (att->default_value.default_expr.default_expr_format != NULL)
        {
          free_and_init (att->default_value.default_expr.default_expr_format);
        }

      if (att->current_default_value.value != NULL)
        {
          free_and_init (att->current_default_value.value);
        }

      if (att->current_default_value.default_expr.default_expr_format != NULL)
        {
          free_and_init (att->current_default_value.default_expr.default_expr_format);
        }

      if (att->btids != NULL && att->btids != att->btid_pack)
        {
          free_and_init (att->btids);
        }
    }
      free_and_init (rep->attributes);
    }

  if (rep->shared_attrs != NULL)
    {
      for (i = 0, att = rep->shared_attrs; i < rep->n_shared_attrs; i++, att++)
    {
      if (att->default_value.value != NULL)
        {
          free_and_init (att->default_value.value);
        }

      if (att->default_value.default_expr.default_expr_format != NULL)
        {
          free_and_init (att->default_value.default_expr.default_expr_format);
        }

      if (att->current_default_value.value != NULL)
        {
          free_and_init (att->current_default_value.value);
        }

      if (att->current_default_value.default_expr.default_expr_format != NULL)
        {
          free_and_init (att->current_default_value.default_expr.default_expr_format);
        }

      if (att->btids != NULL && att->btids != att->btid_pack)
        {
          free_and_init (att->btids);
        }
    }
      free_and_init (rep->shared_attrs);
    }

  if (rep->class_attrs != NULL)
    {
      for (i = 0, att = rep->class_attrs; i < rep->n_class_attrs; i++, att++)
    {
      if (att->default_value.value != NULL)
        {
          free_and_init (att->default_value.value);
        }

      if (att->current_default_value.value != NULL)
        {
          free_and_init (att->current_default_value.value);
        }

      if (att->btids != NULL && att->btids != att->btid_pack)
        {
          free_and_init (att->btids);
        }
    }
      free_and_init (rep->class_attrs);
    }

  if (rep->indexes != NULL)
    {
      for (i = 0, index = rep->indexes; i < rep->n_indexes; i++, index++)
    {
      if (index->atts != NULL)
        {
          free_and_init (index->atts);
        }

      if (index->btname != NULL)
        {
          free_and_init (index->btname);
        }

      if (index->filter_predicate)
        {
          if (index->filter_predicate->pred_string)
        {
          free_and_init (index->filter_predicate->pred_string);
        }

          if (index->filter_predicate->pred_stream)
        {
          free_and_init (index->filter_predicate->pred_stream);
        }

          free_and_init (index->filter_predicate);
        }

      if (index->asc_desc != NULL)
        {
          free_and_init (index->asc_desc);
        }

      if (index->attrs_prefix_length != NULL)
        {
          free_and_init (index->attrs_prefix_length);
        }

      if (index->fk)
        {
          for (fk = index->fk; fk; fk = fk_next)
        {
          fk_next = fk->next;
          if (fk->fkname)
            {
              free_and_init (fk->fkname);
            }
          free_and_init (fk);
        }
        }
      if (index->func_index_info)
        {
          if (index->func_index_info->expr_string)
        {
          free_and_init (index->func_index_info->expr_string);
        }
          if (index->func_index_info->expr_stream)
        {
          free_and_init (index->func_index_info->expr_stream);
        }
          free_and_init (index->func_index_info);
        }
    }

      free_and_init (rep->indexes);
    }

  free_and_init (rep);
}

/*
 * or_find_diskattr () - Find disk attribute in record by attr_id
 *   return: a pointer to a disk attribute
 *   record(in): disk record
 *   attr_id(in): desired attribute id
 *
 *   If the given attribute identifier does not exist for current
 *   representation, NULL is returned.
 */
static const char *
or_find_diskattr (RECDES * record, int attr_id)
{
  int n_fixed, n_variable, n_shared, n_class;
  int n_attrs;
  int type_attr, i, id;
  bool found;
  char *start, *ptr, *attset, *diskatt = NULL;

  start = record->data;

  assert (OR_GET_OFFSET_SIZE (record->data) == BIG_VAR_OFFSET_SIZE);

  ptr = start + OR_FIXED_ATTRIBUTES_OFFSET (record->data, ORC_CLASS_VAR_ATT_COUNT);

  n_fixed = OR_GET_INT (ptr + ORC_FIXED_COUNT_OFFSET);
  n_variable = OR_GET_INT (ptr + ORC_VARIABLE_COUNT_OFFSET);
  n_shared = OR_GET_INT (ptr + ORC_SHARED_COUNT_OFFSET);
  n_class = OR_GET_INT (ptr + ORC_CLASS_ATTR_COUNT_OFFSET);

  for (type_attr = 0, found = false; type_attr < 3 && found == false; type_attr++)
    {
      if (type_attr == 0)
    {
      /*
       * INSTANCE ATTRIBUTES
       *
       * find the start of the "set_of(attribute)" fix/variable attribute
       * list inside the class
       */
      attset = start + OR_VAR_OFFSET (start, ORC_ATTRIBUTES_INDEX);
      n_attrs = n_fixed + n_variable;
    }
      else if (type_attr == 1)
    {
      /*
       * SHARED ATTRIBUTES
       *
       * find the start of the "set_of(shared attributes)" attribute
       * list inside the class
       */
      attset = start + OR_VAR_OFFSET (start, ORC_SHARED_ATTRS_INDEX);
      n_attrs = n_shared;
    }
      else
    {
      /*
       * CLASS ATTRIBUTES
       *
       * find the start of the "set_of(class attributes)" attribute
       * list inside the class
       */
      attset = start + OR_VAR_OFFSET (start, ORC_CLASS_ATTRS_INDEX);
      n_attrs = n_class;
    }

      for (i = 0, found = false; i < n_attrs && found == false; i++)
    {
      /*
       * diskatt will now be pointing at the offset table for this attribute.
       * this is logically the "start" of this nested object.
       *
       * set ptr to the beginning of the fixed attributes
       */
      diskatt = attset + OR_SET_ELEMENT_OFFSET (attset, i);
      ptr = diskatt + OR_VAR_TABLE_SIZE (ORC_ATT_VAR_ATT_COUNT);
      id = OR_GET_INT (ptr + ORC_ATT_ID_OFFSET);
      if (id == attr_id)
        {
          found = true;
        }
    }
    }

  return found ? diskatt : NULL;
}

/*
 * or_get_attr_string () - Get the string of the given attribute (id,index)
 *   return: NO_ERROR or error code.
 *   record(in): disk record
 *   attr_id(in): desired attribute id
 *   attr_index(in): index to a string among the attribute
 *   string(out) : The pointer towards the desire attribute.
 *   alloced_string(out) : States whether the returned string was alloc'ed due do decompression,
 *             or is just a pointer from the record.
 *
 *   If the given attribute identifier does not exist for current
 *   representation, NULL is returned.
 */
int
or_get_attr_string (RECDES * record, int attr_id, int attr_index, char **string, int *alloced_string)
{
  char *diskatt, *attr = NULL;
  int offset = 0, offset_next = 0;
  unsigned char len = 0;
  OR_BUF buffer;
  int compressed_length = 0, decompressed_length = 0, rc = NO_ERROR;

  assert (*alloced_string == 0);

  assert (attr_index < ORC_ATT_LAST_INDEX);

  diskatt = (char *) or_find_diskattr (record, attr_id);
  if (diskatt != NULL)
    {
      /*
       * diskatt now points to the attribute that we are interested in.
       * Get the attribute name.
       */
      offset = OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, attr_index);
      attr = diskatt + offset;

      /*
       * Get boundary of the attribute, that is, the offset of next attribute.
       * Regardless the next attribute exists or not,
       * the "offset_next" is always retrievable.
       * There is a last offset to denote the end of object. See attribute_to_disk.
       */
      offset_next = OR_VAR_TABLE_ELEMENT_OFFSET (diskatt, attr_index + 1);

      /*
       * kludge kludge kludge
       * This is now an encoded "varchar" string, we need to skip over the
       * length before returning it.  Note that this also depends on the
       * stored string being NULL terminated.
       */
      assert (attr != NULL);
      if (attr != NULL)
    {
      len = *((unsigned char *) attr);
    }

      if (offset == offset_next)
    {
      attr = NULL;
      *string = NULL;
    }
      else if (len < 0xFFU)
    {
      assert (len != 0);
      attr += 1;
      *string = attr;
    }
      else
    {
      or_init (&buffer, attr, -1);

      rc = or_get_varchar_compression_lengths (&buffer, &compressed_length, &decompressed_length);
      if (rc != NO_ERROR)
        {
          ASSERT_ERROR ();
          *string = NULL;
          return rc;
        }

      assert (*string == NULL);
      *string = (char *) db_private_alloc (NULL, decompressed_length + 1);
      if (*string == NULL)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, decompressed_length + 1);
          return ER_OUT_OF_VIRTUAL_MEMORY;
        }
      *alloced_string = 1;

      rc = pr_get_compressed_data_from_buffer (&buffer, *string, compressed_length, decompressed_length);
      if (rc != NO_ERROR)
        {
          ASSERT_ERROR ();
          db_private_free (NULL, *string);
          *alloced_string = 0;
          *string = NULL;
          return rc;
        }
    }
    }
  else
    {
      *alloced_string = 0;
      *string = NULL;
      if (IS_DEDUPLICATE_KEY_ATTR_ID (attr_id) && (attr_index == ORC_ATT_NAME_INDEX))
    {
      *string = dk_get_deduplicate_key_attr_name (GET_DEDUPLICATE_KEY_ATTR_LEVEL (attr_id));
    }
    }

  return rc;
}

/*
 * or_get_attrname () - Find the name of the given attribute
 *   return: the name of the attribute
 *   record(in): disk record
 *   attrid(in): desired attribute
 *   string(out): Desired attribute name
 *   alloced_string(out) : States whether the attribute name was alloc'ed or it is just a pointer.
 *
 *       The name returned is the name of the actual representation.
 *       If the given attribute identifier does not exist for current
 *       representation, NULL is returned.
 */
int
or_get_attrname (RECDES * record, int attrid, char **string, int *alloced_string)
{
  return or_get_attr_string (record, attrid, ORC_ATT_NAME_INDEX, string, alloced_string);
}

/*
 * or_get_attrcomment () - Find the comment of the given attribute
 *   return: NO_ERROR or error code
 *   record(in): disk record
 *   attrid(in): desired attribute
 *   string(out): Desired string
 *   alloced_string(out) : States whether the string was alloc'ed due to decompression or it is just a pointer.
 *
 * Note: The comment returned is an actual pointer to the record structure
 *       If the record is changed, the pointer may be trashed.
 *       If the given attribute identifier does not exist for current
 *       representation, NULL is returned.
 */
int
or_get_attrcomment (RECDES * record, int attrid, char **string, int *alloced_string)
{
  return or_get_attr_string (record, attrid, ORC_ATT_COMMENT_INDEX, string, alloced_string);
}

/*
 * or_install_btids_function_info () - Install (add) function index
 *                    information to the index structure
 *                    of the class representation
 *   return: void
 *   index(in): index structure
 *   fi_seq(in): Set which contains the function index information
 */
static void
or_install_btids_function_info (DB_SEQ * fi_seq, OR_INDEX * index)
{
  OR_FUNCTION_INDEX *fi_info = NULL;
  DB_VALUE val, val1;
  const char *buffer;

  index->func_index_info = NULL;
  if (fi_seq == NULL)
    {
      return;
    }

  if (set_get_element_nocopy (fi_seq, 0, &val1) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
      goto error;
    }

  switch (DB_VALUE_TYPE (&val1))
    {
    case DB_TYPE_NULL:
      return;

    case DB_TYPE_STRING:
      /* continue */
      break;

    default:
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
      return;
    }

  if (set_get_element_nocopy (fi_seq, 1, &val) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
      goto error;
    }

  switch (DB_VALUE_TYPE (&val))
    {
    case DB_TYPE_NULL:
      return;

    case DB_TYPE_CHAR:
      /* continue */
      break;

    default:
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
      return;
    }


  fi_info = (OR_FUNCTION_INDEX *) malloc (sizeof (OR_FUNCTION_INDEX));
  if (fi_info == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (OR_FUNCTION_INDEX));
      goto error;
    }

  fi_info->expr_string = strdup (db_get_string (&val1));
  if (fi_info->expr_string == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
          strlen (db_get_string (&val1)) * sizeof (char));
      goto error;
    }

  buffer = db_get_string (&val);
  fi_info->expr_stream_size = db_get_string_size (&val);
  fi_info->expr_stream = (char *) malloc (fi_info->expr_stream_size);
  if (fi_info->expr_stream == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, fi_info->expr_stream_size * sizeof (char));
      goto error;
    }
  memcpy (fi_info->expr_stream, buffer, fi_info->expr_stream_size);

  if (set_get_element_nocopy (fi_seq, 2, &val) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
      goto error;
    }
  fi_info->col_id = db_get_int (&val);

  if (set_get_element_nocopy (fi_seq, 3, &val) != NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_INVALID_PROPERTY, 0);
      goto error;
    }
  fi_info->attr_index_start = db_get_int (&val);

  index->func_index_info = fi_info;
  return;

error:
  if (fi_info)
    {
      if (fi_info->expr_string)
    {
      free_and_init (fi_info->expr_string);
    }

      if (fi_info->expr_stream)
    {
      free_and_init (fi_info->expr_stream);
    }

      free_and_init (fi_info);
    }

  return;
}

/*
 * or_replace_rep_id () - replace representation id for record
 * return : error code or NO_ERROR
 * record (in/out): record
 * repid (in)     : new representation
 *
 * NOTE: This function is similar to or_set_rep_id but it determines
 * the type of record based on MVCC flag and sets rep_id accordingly.
 */
int
or_replace_rep_id (RECDES * record, int repid)
{
  OR_BUF orep, *buf;
  unsigned int new_bits = 0;
  int offset_size = 0;
  char mvcc_flag;
  bool is_bound_bit = false;

  or_init (&orep, record->data, record->area_size);
  buf = &orep;

  mvcc_flag = or_mvcc_get_flag (record);
  if (mvcc_flag == 0)
    {
      /* non-MVCC record */
      /* read REPR_ID flags */
      if (OR_GET_BOUND_BIT_FLAG (record->data))
    {
      is_bound_bit = true;
    }
      offset_size = OR_GET_OFFSET_SIZE (record->data);

      /* construct new REPR_ID element */
      new_bits = repid;
      if (is_bound_bit)
    {
      new_bits |= OR_BOUND_BIT_FLAG;
    }
      OR_SET_VAR_OFFSET_SIZE (new_bits, offset_size);
      buf->ptr = buf->buffer + OR_REP_OFFSET;
    }
  else
    {
      /* MVCC record */
      new_bits = OR_GET_MVCC_REPID_AND_FLAG (record->data);

      /* Remove old repid */
      new_bits &= ~OR_MVCC_REPID_MASK;

      /* Add new repid */
      new_bits |= (repid & OR_MVCC_REPID_MASK);

      /* Set buffer pointer to the right position */
      buf->ptr = buf->buffer + OR_REP_OFFSET;
    }

  /* write new REPR_ID to the record */
  or_put_int (buf, new_bits);

  return NO_ERROR;
}

/*
 * or_mvcc_get_header () - Get mvcc record header from record data.
 *
 * return       : Void.
 * record (in)      : Record descriptor.
 * mvcc_header (out)    : MVCC Record header.
 */
int
or_mvcc_get_header (RECDES * record, MVCC_REC_HEADER * mvcc_header)
{
  OR_BUF buf;
  int rc = NO_ERROR;
  int repid_and_flag_bits;

  assert (record != NULL && record->data != NULL && record->length >= OR_MVCC_REP_SIZE && mvcc_header != NULL);

  or_init (&buf, record->data, record->length);

  repid_and_flag_bits = or_mvcc_get_repid_and_flags (&buf, &rc);
  if (rc != NO_ERROR)
    {
      goto exit_on_error;
    }
  mvcc_header->repid = repid_and_flag_bits & OR_MVCC_REPID_MASK;
  mvcc_header->mvcc_flag = (char) ((repid_and_flag_bits >> OR_MVCC_FLAG_SHIFT_BITS) & OR_MVCC_FLAG_MASK);

  mvcc_header->chn = or_mvcc_get_chn (&buf, &rc);
  if (rc != NO_ERROR)
    {
      goto exit_on_error;
    }

  mvcc_header->mvcc_ins_id = or_mvcc_get_insid (&buf, mvcc_header->mvcc_flag, &rc);
  if (rc != NO_ERROR)
    {
      goto exit_on_error;
    }

  mvcc_header->mvcc_del_id = or_mvcc_get_delid (&buf, mvcc_header->mvcc_flag, &rc);
  if (rc != NO_ERROR)
    {
      goto exit_on_error;
    }

  rc = or_mvcc_get_prev_version_lsa (&buf, mvcc_header->mvcc_flag, &(mvcc_header->prev_version_lsa));
  if (rc != NO_ERROR)
    {
      goto exit_on_error;
    }

  return NO_ERROR;

exit_on_error:
  return (rc == NO_ERROR && (rc = er_errid ()) == NO_ERROR) ? ER_FAILED : rc;
}

/*
 * or_mvcc_set_header () - Updates record header
 *
 * return       : Void.
 * record (in/out)  : Record descriptor.
 * mvcc_rec_header (in) : MVCC Record header.
 *
 *  Note: This function assume that record area size is sufficiently large
 *    to include additional MVCC data that may come from mvcc_rec_header.
 */
int
or_mvcc_set_header (RECDES * record, MVCC_REC_HEADER * mvcc_rec_header)
{
  OR_BUF orep, *buf;
  int error = NO_ERROR;
  int mvcc_old_flag = 0;
  int repid_and_flag_bits = 0;
  int old_mvcc_size = 0, new_mvcc_size = 0;

  assert (record != NULL && record->data != NULL && record->length != 0 && record->length >= OR_MVCC_MIN_HEADER_SIZE);

  repid_and_flag_bits = OR_GET_MVCC_REPID_AND_FLAG (record->data);

  mvcc_old_flag = (char) ((repid_and_flag_bits >> OR_MVCC_FLAG_SHIFT_BITS) & OR_MVCC_FLAG_MASK);

  old_mvcc_size = mvcc_header_size_lookup[mvcc_old_flag];
  new_mvcc_size = mvcc_header_size_lookup[mvcc_rec_header->mvcc_flag];
  if (old_mvcc_size != new_mvcc_size)
    {
      /* resize MVCC info inside recdes */
      if (record->area_size < (record->length + new_mvcc_size - old_mvcc_size))
    {
      /* TO DO - er_set */
      assert (false);
      goto exit_on_error;
    }

      HEAP_MOVE_INSIDE_RECORD (record, new_mvcc_size, old_mvcc_size);
    }

  or_init (&orep, record->data, record->area_size);
  buf = &orep;

  error =
    or_mvcc_set_repid_and_flags (buf, mvcc_rec_header->mvcc_flag, mvcc_rec_header->repid,
                 repid_and_flag_bits & OR_BOUND_BIT_FLAG, OR_GET_OFFSET_SIZE (record->data));
  if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

  error = or_mvcc_set_chn (buf, mvcc_rec_header);
  if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

  error = or_mvcc_set_insid (buf, mvcc_rec_header);
  if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

  error = or_mvcc_set_delid (buf, mvcc_rec_header);
  if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

  error = or_mvcc_set_prev_version_lsa (buf, mvcc_rec_header);
  if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

  return NO_ERROR;

exit_on_error:
  return (error == NO_ERROR && (error = er_errid ()) == NO_ERROR) ? ER_FAILED : error;
}

/*
 * or_mvcc_add_header () - Add header in record
 *
 * return       : Void.
 * record (in/out)  : Record descriptor.
 * mvcc_rec_header (in) : MVCC Record header.
 *
 *  Note: This function must be called when the record is build by adding
 *    header and then data. This function will add record header only.
 *    Later, record data must be added. Obvious, the caller must be sure that
 *    the record area size is sufficiently large to include header and data.
 *    When called, record->length must be 0. When return, record->length
 *    will contain the header size.
 */
int
or_mvcc_add_header (RECDES * record, MVCC_REC_HEADER * mvcc_rec_header, int bound_bit, int variable_offset_size)
{
  OR_BUF orep, *buf;
  int error = NO_ERROR;

  assert (record != NULL && record->data != NULL && record->length == 0);

  or_init (&orep, record->data, record->area_size);
  buf = &orep;

  error =
    or_mvcc_set_repid_and_flags (buf, mvcc_rec_header->mvcc_flag, mvcc_rec_header->repid, bound_bit,
                 variable_offset_size);
  if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

  error = or_mvcc_set_chn (buf, mvcc_rec_header);
  if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

  error = or_mvcc_set_insid (buf, mvcc_rec_header);
  if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

  error = or_mvcc_set_delid (buf, mvcc_rec_header);
  if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

  error = or_mvcc_set_prev_version_lsa (buf, mvcc_rec_header);
  if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

  record->length = CAST_BUFLEN (buf->ptr - buf->buffer);

  return NO_ERROR;

exit_on_error:
  return (error == NO_ERROR && (error = er_errid ()) == NO_ERROR) ? ER_FAILED : error;
}

/*
 * or_mvcc_set_log_lsa_to_record () - Sets the previus version LSA in record header.
 *              Assumes the previous version lsa is allocated in header
 *
 * return        : error_code
 * record (in/out)   : record
 * lsa (in) : lsa to be set
 */
int
or_mvcc_set_log_lsa_to_record (RECDES * record, LOG_LSA * lsa)
{
  int mvcc_flags = or_mvcc_get_flag (record);
  int lsa_offset = -1;

  if (!(mvcc_flags & OR_MVCC_FLAG_VALID_PREV_VERSION))
    {
      assert (false);
      return ER_FAILED;
    }

  if (record == NULL || lsa == NULL)
    {
      assert (false);
      return ER_FAILED;
    }

  lsa_offset = (OR_REP_OFFSET + OR_MVCC_REP_SIZE + OR_INT_SIZE
        + (((mvcc_flags) & OR_MVCC_FLAG_VALID_INSID) ? OR_MVCCID_SIZE : 0)
        + (((mvcc_flags) & OR_MVCC_FLAG_VALID_DELID) ? OR_MVCCID_SIZE : 0));

  memcpy (record->data + lsa_offset, lsa, OR_MVCC_PREV_VERSION_LSA_SIZE);

  return NO_ERROR;
}

/*
 * or_mvcc_get_flag () - Gets MVCC flags.
 *
 * return      : MVCC flags.
 * record (in)     : Record descriptor.
 */
static char
or_mvcc_get_flag (RECDES * record)
{
  assert (record != NULL && record->data != NULL && record->length >= OR_HEADER_SIZE (record->data));

  return (char) (OR_GET_MVCC_FLAG (record->data));
}

/*
 * or_mvcc_set_flag () - Set mvcc flags to record header.
 *
 * return      : Void.
 * record (in) : Record descriptor.
 * flags (in)  : MVCC flags to set.
 */
static void
or_mvcc_set_flag (RECDES * record, char flags)
{
  OR_BUF orep, *buf;
  int repid_and_flag = 0;

  assert (record != NULL && record->data != NULL && record->length >= OR_MVCC_REP_SIZE);

  repid_and_flag = OR_GET_INT (record->data + OR_REP_OFFSET);

  /* Remove old mvcc flags */
  repid_and_flag &= ~OR_MVCC_FLAG_MASK;
  /* Set new mvcc flags */
  repid_and_flag += ((flags & OR_MVCC_FLAG_MASK) << OR_MVCC_FLAG_SHIFT_BITS);

  or_init (&orep, record->data, record->area_size);
  buf = &orep;
  buf->ptr = buf->buffer + OR_REP_OFFSET;
  or_put_int (buf, repid_and_flag);
}

/*
 * or_mvcc_get_insid () - Get insert MVCCID from record data.
 *
 * return      : Insert MVCCID.
 * buf (in/out)    : or buffer
 * mvcc_falgs(in)  : MVCC flags
 * error(out): NO_ERROR or error code
 */
STATIC_INLINE MVCCID
or_mvcc_get_insid (OR_BUF * buf, int mvcc_flags, int *error)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  if (!(mvcc_flags & OR_MVCC_FLAG_VALID_INSID))
    {
      return MVCCID_ALL_VISIBLE;
    }
  else
    {
      assert (buf->ptr + OR_MVCCID_SIZE <= buf->endptr);
      MVCCID insert_id = 0;
      OR_GET_BIGINT (buf->ptr, &insert_id);
      buf->ptr += OR_MVCCID_SIZE;
      *error = NO_ERROR;
      return insert_id;
    }
}

/*
 * or_mvcc_set_insid () - Set insert MVCCID into record data
 *
 * return      : Insert MVCCID.
 * buf (in/out)    : or buffer
 * mvcc_rec_header(in) : MVCC record header
 */
STATIC_INLINE int
or_mvcc_set_insid (OR_BUF * buf, MVCC_REC_HEADER * mvcc_rec_header)
{
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);
  if (!(mvcc_rec_header->mvcc_flag & OR_MVCC_FLAG_VALID_INSID))
    {
      return NO_ERROR;
    }

  return or_put_bigint (buf, mvcc_rec_header->mvcc_ins_id);
}

/*
 * or_mvcc_get_delid () - Get MVCC delid
 *
 * return      : MVCC delid
 * buf (in/out)    : or buffer
 * mvcc_falgs(in)  : MVCC flags
 * error(out): NO_ERROR or error code
 */
STATIC_INLINE MVCCID
or_mvcc_get_delid (OR_BUF * buf, int mvcc_flags, int *error)
{
  MVCCID delid = MVCCID_NULL;

  assert (buf != NULL && error != NULL);

  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  *error = NO_ERROR;
  if (mvcc_flags & OR_MVCC_FLAG_VALID_DELID)
    {
      /* MVCC DELID is active */
      assert (buf->ptr + OR_MVCCID_SIZE <= buf->endptr);
      OR_GET_BIGINT (buf->ptr, &(delid));
      buf->ptr += OR_MVCCID_SIZE;
    }
  return delid;
}

/*
 * or_mvcc_get_chn () - Get MVCC chn
 *
 * return      : MVCC chn
 * buf (in/out)    : or buffer
 * mvcc_falgs(in)  : MVCC flags
 * error(out): NO_ERROR or error code
 */
STATIC_INLINE int
or_mvcc_get_chn (OR_BUF * buf, int *error)
{
  int chn = NULL_CHN;

  assert (buf != NULL && error != NULL);

  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  *error = NO_ERROR;

  assert (buf->ptr + OR_INT_SIZE <= buf->endptr);
  chn = OR_GET_INT (buf->ptr);
  buf->ptr += OR_INT_SIZE;

  return chn;
}

/*
 * or_mvcc_set_delid () - Set MVCC delete id
 *
 * return         : error code
 * buf (in/out)       : or buffer
 * mvcc_rec_header(in): MVCC record header
 */
STATIC_INLINE int
or_mvcc_set_delid (OR_BUF * buf, MVCC_REC_HEADER * mvcc_rec_header)
{
  assert (buf != NULL);
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  if (!(mvcc_rec_header->mvcc_flag & OR_MVCC_FLAG_VALID_DELID))
    {
      return NO_ERROR;
    }

  return or_put_bigint (buf, mvcc_rec_header->mvcc_del_id);
}

/*
 * or_mvcc_set_chn () - Set MVCC chn
 *
 * return         : error code
 * buf (in/out)       : or buffer
 * mvcc_rec_header(in): MVCC record header
 */
STATIC_INLINE int
or_mvcc_set_chn (OR_BUF * buf, MVCC_REC_HEADER * mvcc_rec_header)
{
  assert (buf != NULL);
  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);

  return or_put_int (buf, mvcc_rec_header->chn);
}

/*
 * or_mvcc_set_prev_version_lsa () - Set MVCC prev version LSA
 *
 * return         : error code
 * buf (in/out)       : or buffer
 * mvcc_rec_header(in): MVCC record header
 */
STATIC_INLINE int
or_mvcc_set_prev_version_lsa (OR_BUF * buf, MVCC_REC_HEADER * mvcc_rec_header)
{
  assert (buf != NULL);

  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);
  if (!(mvcc_rec_header->mvcc_flag & OR_MVCC_FLAG_VALID_PREV_VERSION))
    {
      return NO_ERROR;
    }
  assert (buf->ptr + OR_MVCC_PREV_VERSION_LSA_SIZE <= buf->endptr);
  memcpy (buf->ptr, &mvcc_rec_header->prev_version_lsa, OR_MVCC_PREV_VERSION_LSA_SIZE);
  buf->ptr += OR_MVCC_PREV_VERSION_LSA_SIZE;

  return NO_ERROR;
}

/*
 * or_mvcc_get_prev_version_lsa () - Get MVCC prev version LSA from buffer
 *
 * return           : error code
 * buf (in)         : or buffer
 * mvcc_flags(in)       : header mvcc flags
 * prev_version_lsa(out): the LSA to previous version
 * mvcc_rec_header(in)  : MVCC record header
 */
STATIC_INLINE int
or_mvcc_get_prev_version_lsa (OR_BUF * buf, int mvcc_flags, LOG_LSA * prev_version_lsa)
{
  assert (buf != NULL);

  ASSERT_ALIGN (buf->ptr, INT_ALIGNMENT);
  if (!(mvcc_flags & OR_MVCC_FLAG_VALID_PREV_VERSION))
    {
      LSA_SET_NULL (prev_version_lsa);
      return NO_ERROR;
    }

  assert (buf->ptr + OR_MVCC_PREV_VERSION_LSA_SIZE <= buf->endptr);
  *prev_version_lsa = *(LOG_LSA *) buf->ptr;
  buf->ptr += OR_MVCC_PREV_VERSION_LSA_SIZE;

  return NO_ERROR;
}