Skip to content

File object_primitive.c

File List > cubrid > src > object > object_primitive.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_primitive.c - This file contains code for handling the values of
 *                      primitive types in memory and for conversion between
 *                      the disk representation.
 */

#ident "$Id$"

#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "object_primitive.h"

#include "area_alloc.h"
#include "db_value_printer.hpp"
#include "db_json.hpp"
#include "elo.h"
#include "error_manager.h"
#include "file_io.h"
#include "compressor.hpp"
#include "mem_block.hpp"
#include "object_representation.h"
#include "set_object.h"
#include "string_buffer.hpp"
#include "string_opfunc.h"
#include "system_parameter.h"
#include "tz_support.h"

#include <utility>

#if !defined (SERVER_MODE)
#include "work_space.h"
#include "virtual_object.h"
#include "transform_cl.h"
#include "dbi.h"
#endif /* !defined (SERVER_MODE) */

#include "dbtype.h"
#include "memory_private_allocator.hpp"
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"

#if defined (SUPPRESS_STRLEN_WARNING)
#define strlen(s1)  ((int) strlen(s1))
#endif /* defined (SUPPRESS_STRLEN_WARNING) */

#if !defined(SERVER_MODE)
extern unsigned int db_on_server;
#endif

#define MR_CMP(d1, d2)                                     \
     ((d1) < (d2) ? DB_LT : (d1) > (d2) ? DB_GT : DB_EQ)

#define MR_CMP_RETURN_CODE(c)                              \
     ((c) < 0 ? DB_LT : (c) > 0 ? DB_GT : DB_EQ)

/*
 * MR_OID_SIZE
 * Hack so we don't have to conditionalize the type vector.
 * On the server we don't have the structure definition for this.
 */
#if !defined (SERVER_MODE)
#define MR_OID_SIZE sizeof(WS_MEMOID)
#else
#define MR_OID_SIZE 0
#endif

#define VALUE_AREA_COUNT 1024

/*
 * PR_OID_PROMOTION_DEFAULT
 *
 * It is intended to allow some control over whether or not OIDs read
 * by "readval" are automatically promoted to MOPs or not.  This
 * is used to prevent cluttering up the workspace with MOPs when we
 * don't really need them.  When this is enabled, callers of "readval"
 * had better be prepared to see DB_VALUE structures containing unswizzled
 * OIDs rather than MOPs.  Not intended for use by by real applications.
 * Think about this more, this may also be the mechanism by which the server
 * can control reading of object values.
 *
 * Note that this makes sense only for the "readval" function, the "readmem
 * function must be building a workspace instance memory representation
 * and oid promotion cannot be controlled there.
 *
 */
#if defined (SERVER_MODE)
#define PR_INHIBIT_OID_PROMOTION_DEFAULT 1
#else
#define PR_INHIBIT_OID_PROMOTION_DEFAULT 0
#endif

/*
 * These are currently fixed length widets of length DB_NUMERIC_BUF_SIZE.
 * Ultimately they may be of variable size based on the precision and scale,
 * in antipication of that move, use the followign function for copying.
 */
#define OR_NUMERIC_SIZE(precision) DB_NUMERIC_BUF_SIZE
#define MR_NUMERIC_SIZE(precision) DB_NUMERIC_BUF_SIZE

#define STR_SIZE(prec, codeset)                                             \
     (((codeset) == INTL_CODESET_RAW_BITS) ? ((prec+7)/8) :         \
      INTL_CODESET_MULT (codeset) * (prec))


#define BITS_IN_BYTE            8
#define BITS_TO_BYTES(bit_cnt)      (((bit_cnt) + 7) / 8)

#define DB_DOMAIN_INIT_CHAR(value, precision)            \
  do {                               \
    (value)->domain.general_info.type = DB_TYPE_CHAR;        \
    (value)->domain.general_info.is_null = 1;            \
    (value)->domain.char_info.length =               \
    (precision) == DB_DEFAULT_PRECISION ?            \
    TP_FLOATING_PRECISION_VALUE : (precision);           \
    (value)->need_clear = false;                 \
    (value)->data.ch.info.codeset = LANG_SYS_CODESET;            \
    (value)->domain.char_info.collation_id = LANG_SYS_COLLATION; \
  } while (0)


#define IS_FLOATING_PRECISION(prec) \
  ((prec) == TP_FLOATING_PRECISION_VALUE)

// *INDENT-OFF*
pr_type::pr_type (const char * name_arg, DB_TYPE id_arg, int varp_arg, int size_arg, int disksize_arg, int align_arg,
                  initmem_function_type initmem_f_arg, initval_function_type initval_f_arg,
                  setmem_function_type setmem_f_arg, getmem_function_type getmem_f_arg,
                  setval_function_type setval_f_arg, data_lengthmem_function_type data_lengthmem_f_arg,
                  data_lengthval_function_type data_lengthval_f_arg, data_writemem_function_type data_writemem_f_arg,
                  data_readmem_function_type data_readmem_f_arg, data_writeval_function_type data_writeval_f_arg,
                  data_readval_function_type data_readval_f_arg, index_lengthmem_function_type index_lengthmem_f_arg,
                  index_lengthval_function_type index_lengthval_f_arg,
                  index_writeval_function_type index_writeval_f_arg, index_readval_function_type index_readval_f_arg,
                  index_cmpdisk_function_type index_cmpdisk_f_arg, freemem_function_type freemem_f_arg,
                  data_cmpdisk_function_type data_cmpdisk_f_arg, cmpval_function_type cmpval_f_arg)
  : name {name_arg}
  , id {id_arg}
  , variable_p {varp_arg}
  , size {size_arg}
  , disksize {disksize_arg}
  , alignment {align_arg}
  , f_initmem {initmem_f_arg}
  , f_initval {initval_f_arg}
  , f_setmem {setmem_f_arg}
  , f_getmem {getmem_f_arg}
  , f_setval {setval_f_arg}
  , f_data_lengthmem {data_lengthmem_f_arg}
  , f_data_lengthval {data_lengthval_f_arg}
  , f_data_writemem {data_writemem_f_arg}
  , f_data_readmem {data_readmem_f_arg}
  , f_data_writeval {data_writeval_f_arg}
  , f_data_readval {data_readval_f_arg}
  , f_index_lengthmem {index_lengthmem_f_arg}
  , f_index_lengthval {index_lengthval_f_arg}
  , f_index_writeval {index_writeval_f_arg}
  , f_index_readval {index_readval_f_arg}
  , f_index_cmpdisk {index_cmpdisk_f_arg}
  , f_freemem {freemem_f_arg}
  , f_data_cmpdisk {data_cmpdisk_f_arg}
  , f_cmpval {cmpval_f_arg}
  {
  }

void
pr_type::set_data_cmpdisk_function (data_cmpdisk_function_type data_cmpdisk_arg)
{
  f_data_cmpdisk = data_cmpdisk_arg;
}

pr_type::data_cmpdisk_function_type
pr_type::get_data_cmpdisk_function () const
{
  return f_data_cmpdisk;
}

void
pr_type::set_cmpval_function (cmpval_function_type cmpval_arg)
{
  f_cmpval = cmpval_arg;
}

pr_type::cmpval_function_type
pr_type::get_cmpval_function () const
{
  return f_cmpval;
}
// *INDENT-ON*

static void mr_initmem_string (void *mem, TP_DOMAIN * domain);
static int mr_setmem_string (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_string (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_data_lengthmem_string (void *memptr, TP_DOMAIN * domain, int disk);
static int mr_index_lengthmem_string (void *memptr, TP_DOMAIN * domain);
static void mr_data_writemem_string (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_string (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size);
static void mr_freemem_string (void *memptr);
static void mr_initval_string (DB_VALUE * value, int precision, int scale);
static int mr_setval_string (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthval_string (DB_VALUE * value, int disk);
static int mr_data_writeval_string (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_string (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                   char *copy_buf, int copy_buf_len);
static int mr_index_lengthval_string (DB_VALUE * value);
static int mr_index_writeval_string (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_string (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static int mr_lengthval_string_internal (DB_VALUE * value, int disk, int align);
static int mr_writeval_string_internal (OR_BUF * buf, DB_VALUE * value, int align);
static int mr_readval_string_internal (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                       char *copy_buf, int copy_buf_len, int align);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_string (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_string (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                               int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_string (DB_VALUE * value1, DB_VALUE * value2, int do_coercion,
                         int total_order, int *start_colp, int collation);
#if defined (ENABLE_UNUSED_FUNCTION)
static int mr_cmpval_string2 (DB_VALUE * value1, DB_VALUE * value2, int length, int do_coercion, int total_order,
                  int *start_colp);
#endif
static void mr_initmem_char (void *memptr, TP_DOMAIN * domain);
static int mr_setmem_char (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_char (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_data_lengthmem_char (void *memptr, TP_DOMAIN * domain, int disk);
static int mr_index_lengthmem_char (void *memptr, TP_DOMAIN * domain);
static void mr_data_writemem_char (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_char (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_freemem_char (void *memptr);
static void mr_initval_char (DB_VALUE * value, int precision, int scale);
static int mr_setval_char (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthval_char (DB_VALUE * value, int disk);
static int mr_data_writeval_char (OR_BUF * buf, DB_VALUE * value);
static int mr_writeval_char_internal (OR_BUF * buf, DB_VALUE * value, int align);
static int mr_data_readval_char (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy,
                 char *copy_buf, int copy_buf_len);
static int mr_readval_char_internal (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy,
                     char *copy_buf, int copy_buf_len, int align);
static int mr_index_lengthval_char (DB_VALUE * value);
static int mr_index_writeval_char (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_char (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy,
                  char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_char (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                              int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_char (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_char (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                           int *start_colp, int collation);
static DB_VALUE_COMPARE_RESULT mr_cmpdisk_char_internal (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp, int align);
#if defined (ENABLE_UNUSED_FUNCTION)
static int mr_cmpval_char2 (DB_VALUE * value1, DB_VALUE * value2, int length, int do_coercion, int total_order,
                int *start_colp);
#endif

static void mr_initmem_bit (void *memptr, TP_DOMAIN * domain);
static int mr_setmem_bit (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_bit (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_data_lengthmem_bit (void *memptr, TP_DOMAIN * domain, int disk);
static void mr_data_writemem_bit (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_bit (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_freemem_bit (void *memptr);
static void mr_initval_bit (DB_VALUE * value, int precision, int scale);
static int mr_setval_bit (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthval_bit (DB_VALUE * value, int disk);
static int mr_data_writeval_bit (OR_BUF * buf, DB_VALUE * value);
static int mr_writeval_bit_internal (OR_BUF * buf, DB_VALUE * value, int align);
static int mr_data_readval_bit (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy,
                char *copy_buf, int copy_buf_len);
static int mr_readval_bit_internal (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy,
                    char *copy_buf, int copy_buf_len, int align);
static int mr_index_lengthmem_bit (void *memptr, TP_DOMAIN * domain);
static int mr_index_lengthval_bit (DB_VALUE * value);
static int mr_index_writeval_bit (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_bit (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy,
                 char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_bit (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_bit (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpdisk_bit_internal (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp, int align);
static DB_VALUE_COMPARE_RESULT mr_cmpval_bit (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                          int *start_colp, int collation);
static DB_VALUE_COMPARE_RESULT mr_cmpval_bit2 (DB_VALUE * value1, DB_VALUE * value2, int length, int do_coercion,
                           int total_order, int *start_colp);
static void mr_initmem_varbit (void *mem, TP_DOMAIN * domain);
static int mr_setmem_varbit (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_varbit (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_data_lengthmem_varbit (void *memptr, TP_DOMAIN * domain, int disk);
static int mr_index_lengthmem_varbit (void *memptr, TP_DOMAIN * domain);
static void mr_data_writemem_varbit (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_varbit (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size);
static void mr_freemem_varbit (void *memptr);
static void mr_initval_varbit (DB_VALUE * value, int precision, int scale);
static int mr_setval_varbit (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthval_varbit (DB_VALUE * value, int disk);
static int mr_data_writeval_varbit (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_varbit (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                   char *copy_buf, int copy_buf_len);
static int mr_index_lengthval_varbit (DB_VALUE * value);
static int mr_index_writeval_varbit (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_varbit (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static int mr_lengthval_varbit_internal (DB_VALUE * value, int disk, int align);
static int mr_writeval_varbit_internal (OR_BUF * buf, DB_VALUE * value, int align);
static int mr_readval_varbit_internal (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                       char *copy_buf, int copy_buf_len, int align);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_varbit (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_varbit (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                               int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_varbit (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                         int *start_colp, int collation);
static DB_VALUE_COMPARE_RESULT mr_cmpval_varbit2 (DB_VALUE * value1, DB_VALUE * value2, int length, int do_coercion,
                          int total_order, int *start_colp);

static void mr_initmem_null (void *mem, TP_DOMAIN * domain);
static int mr_setmem_null (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_null (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_null (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_null (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size);
static void mr_initval_null (DB_VALUE * value, int precision, int scale);
static int mr_setval_null (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_null (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_null (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                 char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_null (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_null (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                           int *start_colp, int collation);
static void mr_initmem_int (void *mem, TP_DOMAIN * domain);
static int mr_setmem_int (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_int (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_int (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_int (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_int (DB_VALUE * value, int precision, int scale);
static int mr_setval_int (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_int (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_int (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                int copy_buf_len);
static int mr_index_writeval_int (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_int (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                 char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_int (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_int (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_int (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                          int *start_colp, int collation);
static void mr_initmem_short (void *mem, TP_DOMAIN * domain);
static int mr_setmem_short (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_short (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_short (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_short (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_short (DB_VALUE * value, int precision, int scale);
static int mr_setval_short (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_short (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_short (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                  char *copy_buf, int copy_buf_len);
static int mr_index_writeval_short (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_short (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                   char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_short (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                               int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_short (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                              int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_short (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                        int *start_colp, int collation);
static void mr_initmem_bigint (void *mem, TP_DOMAIN * domain);
static int mr_setmem_bigint (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_bigint (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_bigint (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_bigint (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_bigint (DB_VALUE * value, int precision, int scale);
static int mr_setval_bigint (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_bigint (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_bigint (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                   char *copy_buf, int copy_buf_len);
static int mr_index_writeval_bigint (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_bigint (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_bigint (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_bigint (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                               int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_bigint (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                         int *start_colp, int collation);
static void mr_initmem_float (void *mem, TP_DOMAIN * domain);
static int mr_setmem_float (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_float (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_float (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_float (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_float (DB_VALUE * value, int precision, int scale);
static int mr_setval_float (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_float (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_float (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                  char *copy_buf, int copy_buf_len);
static int mr_index_writeval_float (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_float (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                   char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_float (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                               int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_float (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                              int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_float (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                        int *start_colp, int collation);
static void mr_initmem_double (void *mem, TP_DOMAIN * domain);
static int mr_setmem_double (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_double (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_double (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_double (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_double (DB_VALUE * value, int precision, int scale);
static int mr_setval_double (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_double (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_double (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                   char *copy_buf, int copy_buf_len);
static int mr_index_writeval_double (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_double (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_double (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_double (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                               int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_double (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                         int *start_colp, int collation);
static void mr_initmem_time (void *mem, TP_DOMAIN * domain);
static int mr_setmem_time (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_time (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_time (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_time (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_time (DB_VALUE * value, int precision, int scale);
static int mr_setval_time (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_time (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_time (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                 char *copy_buf, int copy_buf_len);
static int mr_index_writeval_time (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_time (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                  char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_time (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                              int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_time (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_time (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                           int *start_colp, int collation);

static void mr_initmem_utime (void *mem, TP_DOMAIN * domain);
static int mr_setmem_utime (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_utime (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_getmem_timestampltz (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_utime (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_utime (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_utime (DB_VALUE * value, int precision, int scale);
static void mr_initval_timestampltz (DB_VALUE * value, int precision, int scale);
static int mr_setval_utime (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_setval_timestampltz (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_utime (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_utime (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                  char *copy_buf, int copy_buf_len);
static int mr_data_readval_timestampltz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                     char *copy_buf, int copy_buf_len);
static int mr_index_writeval_utime (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_utime (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                   char *copy_buf, int copy_buf_len);
static int mr_index_readval_timestampltz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                      char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_utime (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                               int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_utime (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                              int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_utime (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                        int *start_colp, int collation);

static void mr_initmem_timestamptz (void *mem, TP_DOMAIN * domain);
static int mr_setmem_timestamptz (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_timestamptz (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_timestamptz (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_timestamptz (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_timestamptz (DB_VALUE * value, int precision, int scale);
static int mr_setval_timestamptz (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_timestamptz (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_timestamptz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static int mr_index_writeval_timestamptz (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_timestamptz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                     char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_timestamptz (void *mem1, void *mem2, TP_DOMAIN * domain,
                                 int do_coercion, int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_timestamptz (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                                int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_timestamptz (DB_VALUE * value1, DB_VALUE * value2, int do_coercion,
                              int total_order, int *start_colp, int collation);

static void mr_initmem_datetime (void *memptr, TP_DOMAIN * domain);
static void mr_initval_datetime (DB_VALUE * value, int precision, int scale);
static void mr_initval_datetimeltz (DB_VALUE * value, int precision, int scale);
static int mr_setmem_datetime (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_datetime (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_getmem_datetimeltz (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_datetime (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_setval_datetimeltz (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static void mr_data_writemem_datetime (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_datetime (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static int mr_data_writeval_datetime (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_datetime (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                     char *copy_buf, int copy_buf_len);
static int mr_data_readval_datetimeltz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static int mr_index_writeval_datetime (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_datetime (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                      char *copy_buf, int copy_buf_len);
static int mr_index_readval_datetimeltz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                     char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_datetime (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                              int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_datetime (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_datetime (DB_VALUE * value1, DB_VALUE * value2, int do_coercion,
                           int total_order, int *start_colp, int collation);

static void mr_initmem_datetimetz (void *memptr, TP_DOMAIN * domain);
static void mr_initval_datetimetz (DB_VALUE * value, int precision, int scale);
static int mr_setmem_datetimetz (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_datetimetz (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_datetimetz (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static void mr_data_writemem_datetimetz (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_datetimetz (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static int mr_data_writeval_datetimetz (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_datetimetz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                       char *copy_buf, int copy_buf_len);
static int mr_index_writeval_datetimetz (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_datetimetz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_datetimetz (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                                int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_datetimetz (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                               int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_datetimetz (DB_VALUE * value1, DB_VALUE * value2, int do_coercion,
                             int total_order, int *start_colp, int collation);

static void mr_initmem_money (void *memptr, TP_DOMAIN * domain);
static int mr_setmem_money (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_money (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_money (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_money (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_money (DB_VALUE * value, int precision, int scale);
static int mr_setval_money (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_money (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_money (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                  char *copy_buf, int copy_buf_len);
static int mr_index_writeval_money (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_money (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                   char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_money (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                               int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_money (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                              int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_money (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                        int *start_colp, int collation);
static void mr_initmem_date (void *mem, TP_DOMAIN * domain);
static int mr_setmem_date (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_date (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_date (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_date (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_date (DB_VALUE * value, int precision, int scale);
static int mr_setval_date (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_date (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_date (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                 char *copy_buf, int copy_buf_len);
static int mr_index_writeval_date (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_date (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                  char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_date (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                              int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_date (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_date (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                           int *start_colp, int collation);
static void mr_null_oid (OID * oid);
static void mr_initmem_object (void *mem, TP_DOMAIN * domain);
static void mr_initval_object (DB_VALUE * value, int precision, int scale);
static int mr_setmem_object (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_object (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_object (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthval_object (DB_VALUE * value, int disk);
static void mr_data_writemem_object (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_object (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size);
static int mr_data_writeval_object (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_object (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                   char *copy_buf, int copy_buf_len);
static int mr_index_writeval_object (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_object (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_object (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_object (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                               int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_object (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                         int *start_colp, int collation);
static void mr_initmem_elo (void *memptr, TP_DOMAIN * domain);
static void mr_initval_elo (DB_VALUE * value, int precision, int scale);
static int mr_setmem_elo (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_setval_elo (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthmem_elo (void *memptr, TP_DOMAIN * domain, int disk);
static void mr_data_writemem_elo (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_elo (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size);
static int mr_getmem_elo (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int getmem_elo_with_type (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy, DB_TYPE type);
static void peekmem_elo (OR_BUF * buf, DB_ELO * elo);
static int mr_data_lengthval_elo (DB_VALUE * value, int disk);
static int mr_data_writeval_elo (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_elo (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                int copy_buf_len);
static int setval_elo_with_type (DB_VALUE * dest, const DB_VALUE * src, bool copy, DB_TYPE type);
static int readval_elo_with_type (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                  char *copy_buf, int copy_buf_len, DB_TYPE type);
static void mr_freemem_elo (void *memptr);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_elo (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_elo (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                          int *start_colp, int collation);

static void mr_initval_blob (DB_VALUE * value, int precision, int scale);
static int mr_getmem_blob (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_blob (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_readval_blob (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                 char *copy_buf, int copy_buf_len);

static void mr_initval_clob (DB_VALUE * value, int precision, int scale);
static int mr_getmem_clob (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_clob (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_readval_clob (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                 char *copy_buf, int copy_buf_len);

static void mr_initval_variable (DB_VALUE * value, int precision, int scale);
static int mr_setval_variable (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthval_variable (DB_VALUE * value, int disk);
static int mr_data_writeval_variable (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_variable (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                     char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_variable (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_variable (DB_VALUE * value1, DB_VALUE * value2, int do_coercion,
                           int total_order, int *start_colp, int collation);
static void mr_initmem_sub (void *mem, TP_DOMAIN * domain);
static void mr_initval_sub (DB_VALUE * value, int precision, int scale);
static int mr_setmem_sub (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_sub (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_sub (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthmem_sub (void *mem, TP_DOMAIN * domain, int disk);
static void mr_data_writemem_sub (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_sub (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static int mr_data_lengthval_sub (DB_VALUE * value, int disk);
static int mr_data_writeval_sub (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_sub (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_sub (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_sub (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                          int *start_colp, int collation);
static void mr_initmem_ptr (void *memptr, TP_DOMAIN * domain);
static void mr_initval_ptr (DB_VALUE * value, int precision, int scale);
static int mr_setmem_ptr (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_ptr (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_ptr (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthmem_ptr (void *memptr, TP_DOMAIN * domain, int disk);
static void mr_data_writemem_ptr (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_ptr (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size);
static int mr_data_lengthval_ptr (DB_VALUE * value, int disk);
static int mr_data_writeval_ptr (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_ptr (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_ptr (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_ptr (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                          int *start_colp, int collation);
static void mr_initmem_error (void *memptr, TP_DOMAIN * domain);
static void mr_initval_error (DB_VALUE * value, int precision, int scale);
static int mr_setmem_error (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_error (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_error (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthmem_error (void *memptr, TP_DOMAIN * domain, int disk);
static int mr_data_lengthval_error (DB_VALUE * value, int disk);
static void mr_data_writemem_error (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_error (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size);
static int mr_data_writeval_error (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_error (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                  char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_error (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                              int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_error (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                        int *start_colp, int collation);
static void mr_initmem_oid (void *memptr, TP_DOMAIN * domain);
static void mr_initval_oid (DB_VALUE * value, int precision, int scale);
static int mr_setmem_oid (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_oid (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_oid (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static void mr_data_writemem_oid (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_oid (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size);
static int mr_data_writeval_oid (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_oid (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                int copy_buf_len);
static int mr_index_writeval_oid (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_oid (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                 char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_oid (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_oid (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_oid (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                          int *start_colp, int collation);
static void mr_initmem_set (void *memptr, TP_DOMAIN * domain);
static void mr_initval_set (DB_VALUE * value, int precision, int scale);
static int mr_setmem_set (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_set (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_set_internal (DB_VALUE * dest, const DB_VALUE * src, bool copy, DB_TYPE set_type);
static int mr_setval_set (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthmem_set (void *memptr, TP_DOMAIN * domain, int disk);
static void mr_data_writemem_set (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_set (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size);
static int mr_data_lengthval_set (DB_VALUE * value, int disk);
static int mr_data_writeval_set (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_set (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                int copy_buf_len);
static void mr_freemem_set (void *memptr);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_set (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_set (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                          int *start_colp, int collation);
static void mr_initval_multiset (DB_VALUE * value, int precision, int scale);
static int mr_getmem_multiset (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_multiset (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static void mr_initval_sequence (DB_VALUE * value, int precision, int scale);
static int mr_getmem_sequence (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_sequence (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_sequence (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_sequence (DB_VALUE * value1, DB_VALUE * value2, int do_coercion,
                           int total_order, int *start_colp, int collation);
static void mr_initval_midxkey (DB_VALUE * value, int precision, int scale);
static int mr_setval_midxkey (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthmem_midxkey (void *memptr, TP_DOMAIN * domain, int disk);
static int mr_index_lengthmem_midxkey (void *memptr, TP_DOMAIN * domain);
static int mr_data_lengthval_midxkey (DB_VALUE * value, int disk);
static int mr_index_lengthval_midxkey (DB_VALUE * value);
static int mr_data_writeval_midxkey (OR_BUF * buf, DB_VALUE * value);
static int mr_index_writeval_midxkey (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_midxkey (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static int mr_index_readval_midxkey (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                     char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT pr_midxkey_compare_element (char *mem1, char *mem2, TP_DOMAIN * dom1, TP_DOMAIN * dom2,
                               int do_coercion, int total_order);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_midxkey (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_midxkey (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_midxkey (DB_VALUE * value1, DB_VALUE * value2, int do_coercion,
                          int total_order, int *start_colp, int collation);
static void mr_initval_vobj (DB_VALUE * value, int precision, int scale);
static int mr_setval_vobj (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_readval_vobj (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                 char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_vobj (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_vobj (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                           int *start_colp, int collation);
static void mr_initmem_numeric (void *memptr, TP_DOMAIN * domain);
static int mr_setmem_numeric (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_numeric (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_data_lengthmem_numeric (void *mem, TP_DOMAIN * domain, int disk);
static int mr_index_lengthmem_numeric (void *mem, TP_DOMAIN * domain);
static void mr_data_writemem_numeric (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_numeric (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_numeric (DB_VALUE * value, int precision, int scale);
static int mr_setval_numeric (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthval_numeric (DB_VALUE * value, int disk);
static int mr_data_writeval_numeric (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_numeric (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static int mr_index_lengthval_numeric (DB_VALUE * value);
static int mr_index_writeval_numeric (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_numeric (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                     char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_numeric (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_numeric (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                            int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_numeric (DB_VALUE * value1, DB_VALUE * value2, int do_coercion,
                          int total_order, int *start_colp, int collation);
static void mr_initmem_resultset (void *mem, TP_DOMAIN * domain);
static int mr_setmem_resultset (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_resultset (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static void mr_data_writemem_resultset (OR_BUF * buf, void *mem, TP_DOMAIN * domain);
static void mr_data_readmem_resultset (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static void mr_initval_resultset (DB_VALUE * value, int precision, int scale);
static int mr_setval_resultset (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_writeval_resultset (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_resultset (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                      char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_resultset (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                              int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_resultset (DB_VALUE * value1, DB_VALUE * value2, int do_coercion,
                            int total_order, int *start_colp, int collation);

static int pr_midxkey_get_vals_size (TP_DOMAIN * domains, DB_VALUE * dbvals, int total);
static int pr_midxkey_get_element_internal (const DB_MIDXKEY * midxkey, int index, DB_VALUE * value, bool copy,
                        int *prev_indexp, char **prev_ptrp);
static void mr_initmem_enumeration (void *mem, TP_DOMAIN * domain);
static void mr_initval_enumeration (DB_VALUE * value, int precision, int scale);
static int mr_setmem_enumeration (void *mem, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_enumeration (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_setval_enumeration (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static void mr_data_writemem_enumeration (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_enumeration (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size);
static int mr_setval_enumeration_internal (DB_VALUE * value, TP_DOMAIN * domain, unsigned short index, int size,
                       bool copy, char *copy_buf, int copy_buf_len);
static int mr_data_readval_enumeration (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                    char *copy_buf, int copy_buf_len);
static int mr_data_writeval_enumeration (OR_BUF * buf, DB_VALUE * value);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_enumeration (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                                int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_enumeration (DB_VALUE * value1, DB_VALUE * value2, int do_coercion,
                              int total_order, int *start_colp, int collation);
static DB_VALUE_COMPARE_RESULT mr_index_cmpdisk_enumeration (void *mem1, void *mem2, TP_DOMAIN * domain,
                                 int do_coercion, int total_order, int *start_colp);
static int mr_index_writeval_enumeration (OR_BUF * buf, DB_VALUE * value);
static int mr_index_readval_enumeration (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                     char *copy_buf, int copy_buf_len);

static int pr_write_compressed_string_to_buffer (OR_BUF * buf, const char *compressed_string, int compressed_length,
                         int decompressed_length, int alignment);
static int pr_write_uncompressed_string_to_buffer (OR_BUF * buf, const char *string, int size, int align);

static void mr_initmem_json (void *mem, TP_DOMAIN * domain);
static int mr_setmem_json (void *memptr, TP_DOMAIN * domain, DB_VALUE * value);
static int mr_getmem_json (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy);
static int mr_data_lengthmem_json (void *memptr, TP_DOMAIN * domain, int disk);
static void mr_data_writemem_json (OR_BUF * buf, void *memptr, TP_DOMAIN * domain);
static void mr_data_readmem_json (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size);
static void mr_freemem_json (void *memptr);
static void mr_initval_json (DB_VALUE * value, int precision, int scale);
static int mr_setval_json (DB_VALUE * dest, const DB_VALUE * src, bool copy);
static int mr_data_lengthval_json (DB_VALUE * value, int disk);
static int mr_data_writeval_json (OR_BUF * buf, DB_VALUE * value);
static int mr_data_readval_json (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy,
                 char *copy_buf, int copy_buf_len);
static DB_VALUE_COMPARE_RESULT mr_data_cmpdisk_json (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion,
                             int total_order, int *start_colp);
static DB_VALUE_COMPARE_RESULT mr_cmpval_json (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order,
                           int *start_colp, int collation);
/*
 * Value_area
 *    Area used for allocation of value containers that may be given out
 *    to database applications.
 */
static AREA *Value_area = NULL;

int pr_Inhibit_oid_promotion = PR_INHIBIT_OID_PROMOTION_DEFAULT;

int pr_Enable_string_compression = true;
const PR_TYPE tp_Null = {
  "*NULL*", DB_TYPE_NULL, 0, 0, 0, 0,
  mr_initmem_null,
  mr_initval_null,
  mr_setmem_null,
  mr_getmem_null,
  mr_setval_null,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_null,
  mr_data_readmem_null,
  mr_data_writeval_null,
  mr_data_readval_null,
  NULL,             /* index_lenghmem */
  NULL,             /* index_lenghval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  NULL,             /* freemem */
  mr_data_cmpdisk_null,
  mr_cmpval_null
};

const PR_TYPE *tp_Type_null = &tp_Null;

const PR_TYPE tp_Integer = {
  "integer", DB_TYPE_INTEGER, 0, sizeof (int), sizeof (int), 4,
  mr_initmem_int,
  mr_initval_int,
  mr_setmem_int,
  mr_getmem_int,
  mr_setval_int,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_int,
  mr_data_readmem_int,
  mr_data_writeval_int,
  mr_data_readval_int,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  mr_index_writeval_int,
  mr_index_readval_int,
  mr_index_cmpdisk_int,
  NULL,             /* freemem */
  mr_data_cmpdisk_int,
  mr_cmpval_int
};

const PR_TYPE *tp_Type_integer = &tp_Integer;

const PR_TYPE tp_Short = {
  "smallint", DB_TYPE_SHORT, 0, sizeof (short), sizeof (short), 2,
  mr_initmem_short,
  mr_initval_short,
  mr_setmem_short,
  mr_getmem_short,
  mr_setval_short,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_short,
  mr_data_readmem_short,
  mr_data_writeval_short,
  mr_data_readval_short,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  mr_index_writeval_short,
  mr_index_readval_short,
  mr_index_cmpdisk_short,
  NULL,             /* freemem */
  mr_data_cmpdisk_short,
  mr_cmpval_short
};

const PR_TYPE *tp_Type_short = &tp_Short;

const PR_TYPE tp_Bigint = {
  "bigint", DB_TYPE_BIGINT, 0, sizeof (DB_BIGINT), sizeof (DB_BIGINT), 4,
  mr_initmem_bigint,
  mr_initval_bigint,
  mr_setmem_bigint,
  mr_getmem_bigint,
  mr_setval_bigint,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_bigint,
  mr_data_readmem_bigint,
  mr_data_writeval_bigint,
  mr_data_readval_bigint,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  mr_index_writeval_bigint,
  mr_index_readval_bigint,
  mr_index_cmpdisk_bigint,
  NULL,             /* freemem */
  mr_data_cmpdisk_bigint,
  mr_cmpval_bigint
};

const PR_TYPE *tp_Type_bigint = &tp_Bigint;

const PR_TYPE tp_Float = {
  "float", DB_TYPE_FLOAT, 0, sizeof (float), sizeof (float), 4,
  mr_initmem_float,
  mr_initval_float,
  mr_setmem_float,
  mr_getmem_float,
  mr_setval_float,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_float,
  mr_data_readmem_float,
  mr_data_writeval_float,
  mr_data_readval_float,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  mr_index_writeval_float,
  mr_index_readval_float,
  mr_index_cmpdisk_float,
  NULL,             /* freemem */
  mr_data_cmpdisk_float,
  mr_cmpval_float
};

const PR_TYPE *tp_Type_float = &tp_Float;

const PR_TYPE tp_Double = {
  "double", DB_TYPE_DOUBLE, 0, sizeof (double), sizeof (double), 4,
  mr_initmem_double,
  mr_initval_double,
  mr_setmem_double,
  mr_getmem_double,
  mr_setval_double,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lenghtval */
  mr_data_writemem_double,
  mr_data_readmem_double,
  mr_data_writeval_double,
  mr_data_readval_double,
  NULL,             /* index_lenghtmem */
  NULL,             /* index_lenghtval */
  mr_index_writeval_double,
  mr_index_readval_double,
  mr_index_cmpdisk_double,
  NULL,             /* freemem */
  mr_data_cmpdisk_double,
  mr_cmpval_double
};

const PR_TYPE *tp_Type_double = &tp_Double;

const PR_TYPE tp_Time = {
  "time", DB_TYPE_TIME, 0, sizeof (DB_TIME), OR_TIME_SIZE, 4,
  mr_initmem_time,
  mr_initval_time,
  mr_setmem_time,
  mr_getmem_time,
  mr_setval_time,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_time,
  mr_data_readmem_time,
  mr_data_writeval_time,
  mr_data_readval_time,
  NULL,             /* index_lenghmem */
  NULL,             /* index_lenghval */
  mr_index_writeval_time,
  mr_index_readval_time,
  mr_index_cmpdisk_time,
  NULL,             /* freemem */
  mr_data_cmpdisk_time,
  mr_cmpval_time
};

const PR_TYPE *tp_Type_time = &tp_Time;

const PR_TYPE tp_Utime = {
  "timestamp", DB_TYPE_TIMESTAMP, 0, sizeof (DB_UTIME), OR_UTIME_SIZE, 4,
  mr_initmem_utime,
  mr_initval_utime,
  mr_setmem_utime,
  mr_getmem_utime,
  mr_setval_utime,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_utime,
  mr_data_readmem_utime,
  mr_data_writeval_utime,
  mr_data_readval_utime,
  NULL,             /* index_lenghmem */
  NULL,             /* index_lenghval */
  mr_index_writeval_utime,
  mr_index_readval_utime,
  mr_index_cmpdisk_utime,
  NULL,             /* freemem */
  mr_data_cmpdisk_utime,
  mr_cmpval_utime
};

const PR_TYPE *tp_Type_utime = &tp_Utime;

const PR_TYPE tp_Timestamptz = {
  "timestamptz", DB_TYPE_TIMESTAMPTZ, 0, sizeof (DB_TIMESTAMPTZ), OR_TIMESTAMPTZ_SIZE, 4,
  mr_initmem_timestamptz,
  mr_initval_timestamptz,
  mr_setmem_timestamptz,
  mr_getmem_timestamptz,
  mr_setval_timestamptz,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_timestamptz,
  mr_data_readmem_timestamptz,
  mr_data_writeval_timestamptz,
  mr_data_readval_timestamptz,
  NULL,             /* index_lenghmem */
  NULL,             /* index_lenghval */
  mr_index_writeval_timestamptz,
  mr_index_readval_timestamptz,
  mr_index_cmpdisk_timestamptz,
  NULL,             /* freemem */
  mr_data_cmpdisk_timestamptz,
  mr_cmpval_timestamptz
};

const PR_TYPE *tp_Type_Timestamptz = &tp_Timestamptz;

/* timestamp with locale time zone has the same storage and primitives as
 * (simple) timestamp */
const PR_TYPE tp_Timestampltz = {
  "timestampltz", DB_TYPE_TIMESTAMPLTZ, 0, sizeof (DB_UTIME), OR_UTIME_SIZE, 4,
  mr_initmem_utime,
  mr_initval_timestampltz,
  mr_setmem_utime,
  mr_getmem_timestampltz,
  mr_setval_timestampltz,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_utime,
  mr_data_readmem_utime,
  mr_data_writeval_utime,
  mr_data_readval_timestampltz,
  NULL,             /* index_lenghmem */
  NULL,             /* index_lenghval */
  mr_index_writeval_utime,
  mr_index_readval_timestampltz,
  mr_index_cmpdisk_utime,
  NULL,             /* freemem */
  mr_data_cmpdisk_utime,
  mr_cmpval_utime
};

const PR_TYPE tp_Datetime = {
  "datetime", DB_TYPE_DATETIME, 0, sizeof (DB_DATETIME), OR_DATETIME_SIZE, 4,
  mr_initmem_datetime,
  mr_initval_datetime,
  mr_setmem_datetime,
  mr_getmem_datetime,
  mr_setval_datetime,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_datetime,
  mr_data_readmem_datetime,
  mr_data_writeval_datetime,
  mr_data_readval_datetime,
  NULL,             /* index_lenghmem */
  NULL,             /* index_lenghval */
  mr_index_writeval_datetime,
  mr_index_readval_datetime,
  mr_index_cmpdisk_datetime,
  NULL,             /* freemem */
  mr_data_cmpdisk_datetime,
  mr_cmpval_datetime
};

const PR_TYPE *tp_Type_datetime = &tp_Datetime;

const PR_TYPE tp_Datetimetz = {
  "datetimetz", DB_TYPE_DATETIMETZ, 0, sizeof (DB_DATETIMETZ), OR_DATETIMETZ_SIZE, 4,
  mr_initmem_datetimetz,
  mr_initval_datetimetz,
  mr_setmem_datetimetz,
  mr_getmem_datetimetz,
  mr_setval_datetimetz,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_datetimetz,
  mr_data_readmem_datetimetz,
  mr_data_writeval_datetimetz,
  mr_data_readval_datetimetz,
  NULL,             /* index_lenghmem */
  NULL,             /* index_lenghval */
  mr_index_writeval_datetimetz,
  mr_index_readval_datetimetz,
  mr_index_cmpdisk_datetimetz,
  NULL,             /* freemem */
  mr_data_cmpdisk_datetimetz,
  mr_cmpval_datetimetz
};

const PR_TYPE *tp_Type_Datetimetz = &tp_Datetimetz;

/* datetime with locale time zone has the same storage and primitives as
 * (simple) datetime */
const PR_TYPE tp_Datetimeltz = {
  "datetimeltz", DB_TYPE_DATETIMELTZ, 0, sizeof (DB_DATETIME), OR_DATETIME_SIZE, 4,
  mr_initmem_datetime,
  mr_initval_datetimeltz,
  mr_setmem_datetime,
  mr_getmem_datetimeltz,
  mr_setval_datetimeltz,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_datetime,
  mr_data_readmem_datetime,
  mr_data_writeval_datetime,
  mr_data_readval_datetimeltz,
  NULL,             /* index_lenghmem */
  NULL,             /* index_lenghval */
  mr_index_writeval_datetime,
  mr_index_readval_datetimeltz,
  mr_index_cmpdisk_datetime,
  NULL,             /* freemem */
  mr_data_cmpdisk_datetime,
  mr_cmpval_datetime
};

const PR_TYPE *tp_Type_datetimeltz = &tp_Datetimeltz;

const PR_TYPE tp_Monetary = {
  "monetary", DB_TYPE_MONETARY, 0, sizeof (DB_MONETARY), OR_MONETARY_SIZE, 4,
  mr_initmem_money,
  mr_initval_money,
  mr_setmem_money,
  mr_getmem_money,
  mr_setval_money,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_money,
  mr_data_readmem_money,
  mr_data_writeval_money,
  mr_data_readval_money,
  NULL,             /* index_lenghmem */
  NULL,             /* index_lenghval */
  mr_index_writeval_money,
  mr_index_readval_money,
  mr_index_cmpdisk_money,
  NULL,             /* freemem */
  mr_data_cmpdisk_money,
  mr_cmpval_money
};

const PR_TYPE *tp_Type_monetary = &tp_Monetary;

const PR_TYPE tp_Date = {
  "date", DB_TYPE_DATE, 0, sizeof (DB_DATE), OR_DATE_SIZE, 4,
  mr_initmem_date,
  mr_initval_date,
  mr_setmem_date,
  mr_getmem_date,
  mr_setval_date,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_date,
  mr_data_readmem_date,
  mr_data_writeval_date,
  mr_data_readval_date,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_index_writeval_date,
  mr_index_readval_date,
  mr_index_cmpdisk_date,
  NULL,             /* freemem */
  mr_data_cmpdisk_date,
  mr_cmpval_date
};

const PR_TYPE *tp_Type_date = &tp_Date;

/*
 * tp_Object
 *
 * ALERT!!! We set the alignment for OIDs to 8 even though they only have an
 * int and two shorts.  This is done because the WS_MEMOID has a pointer
 * following the OID and it must be on an 8 byte boundary for the Alpha boxes.
 */

const PR_TYPE tp_Object = {
  "object", DB_TYPE_OBJECT, 0, MR_OID_SIZE, OR_OID_SIZE, 4,
  mr_initmem_object,
  mr_initval_object,
  mr_setmem_object,
  mr_getmem_object,
  mr_setval_object,
  NULL,             /* data_lengthmem */
  mr_data_lengthval_object,
  mr_data_writemem_object,
  mr_data_readmem_object,
  mr_data_writeval_object,
  mr_data_readval_object,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_index_writeval_object,
  mr_index_readval_object,
  mr_index_cmpdisk_object,
  NULL,             /* freemem */
  mr_data_cmpdisk_object,
  mr_cmpval_object
};

const PR_TYPE *tp_Type_object = &tp_Object;

const PR_TYPE tp_Elo = {    /* todo: remove me */
  "*elo*", DB_TYPE_ELO, 1, sizeof (DB_ELO *), 0, 8,
  mr_initmem_elo,
  mr_initval_elo,
  mr_setmem_elo,
  mr_getmem_elo,
  mr_setval_elo,
  mr_data_lengthmem_elo,
  mr_data_lengthval_elo,
  mr_data_writemem_elo,
  mr_data_readmem_elo,
  mr_data_writeval_elo,
  mr_data_readval_elo,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  mr_freemem_elo,
  mr_data_cmpdisk_elo,
  mr_cmpval_elo
};

const PR_TYPE *tp_Type_elo = &tp_Elo;

const PR_TYPE tp_Blob = {
  "blob", DB_TYPE_BLOB, 1, sizeof (DB_ELO *), 0, 8,
  mr_initmem_elo,
  mr_initval_blob,
  mr_setmem_elo,
  mr_getmem_blob,
  mr_setval_blob,
  mr_data_lengthmem_elo,
  mr_data_lengthval_elo,
  mr_data_writemem_elo,
  mr_data_readmem_elo,
  mr_data_writeval_elo,
  mr_data_readval_blob,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  mr_freemem_elo,
  mr_data_cmpdisk_elo,
  mr_cmpval_elo
};

const PR_TYPE *tp_Type_blob = &tp_Blob;

const PR_TYPE tp_Clob = {
  "clob", DB_TYPE_CLOB, 1, sizeof (DB_ELO *), 0, 8,
  mr_initmem_elo,
  mr_initval_clob,
  mr_setmem_elo,
  mr_getmem_clob,
  mr_setval_clob,
  mr_data_lengthmem_elo,
  mr_data_lengthval_elo,
  mr_data_writemem_elo,
  mr_data_readmem_elo,
  mr_data_writeval_elo,
  mr_data_readval_clob,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  mr_freemem_elo,
  mr_data_cmpdisk_elo,
  mr_cmpval_elo
};

const PR_TYPE *tp_Type_clob = &tp_Clob;

const PR_TYPE tp_Variable = {
  "*variable*", DB_TYPE_VARIABLE, 1, sizeof (DB_VALUE), 0, 4,
  NULL,             /* initmem */
  mr_initval_variable,
  NULL,             /* setmem */
  NULL,             /* getmem */
  mr_setval_variable,
  NULL,             /* data_lengthmem */
  mr_data_lengthval_variable,
  NULL,             /* data_writemem */
  NULL,             /* data_readmem */
  mr_data_writeval_variable,
  mr_data_readval_variable,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  NULL,             /* freemem */
  mr_data_cmpdisk_variable,
  mr_cmpval_variable
};

const PR_TYPE *tp_Type_variable = &tp_Variable;

const PR_TYPE tp_Substructure = {
  "*substructure*", DB_TYPE_SUB, 1, sizeof (void *), 0, 8,
  mr_initmem_sub,
  mr_initval_sub,
  mr_setmem_sub,
  mr_getmem_sub,
  mr_setval_sub,
  mr_data_lengthmem_sub,
  mr_data_lengthval_sub,
  mr_data_writemem_sub,
  mr_data_readmem_sub,
  mr_data_writeval_sub,
  mr_data_readval_sub,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  NULL,             /* freemem */
  mr_data_cmpdisk_sub,
  mr_cmpval_sub
};

const PR_TYPE *tp_Type_substructure = &tp_Substructure;

const PR_TYPE tp_Pointer = {
  "*pointer*", DB_TYPE_POINTER, 0, sizeof (void *), 0, 4,
  mr_initmem_ptr,
  mr_initval_ptr,
  mr_setmem_ptr,
  mr_getmem_ptr,
  mr_setval_ptr,
  mr_data_lengthmem_ptr,
  mr_data_lengthval_ptr,
  mr_data_writemem_ptr,
  mr_data_readmem_ptr,
  mr_data_writeval_ptr,
  mr_data_readval_ptr,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  NULL,             /* freeemem */
  mr_data_cmpdisk_ptr,
  mr_cmpval_ptr
};

const PR_TYPE *tp_Type_pointer = &tp_Pointer;

const PR_TYPE tp_Error = {
  "*error*", DB_TYPE_ERROR, 0, sizeof (int), 0, 4,
  mr_initmem_error,
  mr_initval_error,
  mr_setmem_error,
  mr_getmem_error,
  mr_setval_error,
  mr_data_lengthmem_error,
  mr_data_lengthval_error,
  mr_data_writemem_error,
  mr_data_readmem_error,
  mr_data_writeval_error,
  mr_data_readval_error,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  NULL,             /* freemem */
  mr_data_cmpdisk_error,
  mr_cmpval_error
};

const PR_TYPE *tp_Type_error = &tp_Error;

/*
 * tp_Oid
 *
 * ALERT!!! We set the alignment for OIDs to 8 even though they only have an
 * int and two shorts.  This is done because the WS_MEMOID has a pointer
 * following the OID and it must be on an 8 byte boundary for the Alpha boxes.
 */
const PR_TYPE tp_Oid = {
  "*oid*", DB_TYPE_OID, 0, sizeof (OID), OR_OID_SIZE, 4,
  mr_initmem_oid,
  mr_initval_oid,
  mr_setmem_oid,
  mr_getmem_oid,
  mr_setval_oid,
  NULL,             /* lengthmem */
  NULL,             /* lengthval */
  mr_data_writemem_oid,
  mr_data_readmem_oid,
  mr_data_writeval_oid,
  mr_data_readval_oid,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  mr_index_writeval_oid,
  mr_index_readval_oid,
  mr_index_cmpdisk_oid,
  NULL,             /* freemem */
  mr_data_cmpdisk_oid,
  mr_cmpval_oid
};

const PR_TYPE *tp_Type_oid = &tp_Oid;

const PR_TYPE tp_Set = {
  "set", DB_TYPE_SET, 1, sizeof (SETOBJ *), 0, 4,
  mr_initmem_set,
  mr_initval_set,
  mr_setmem_set,
  mr_getmem_set,
  mr_setval_set,
  mr_data_lengthmem_set,
  mr_data_lengthval_set,
  mr_data_writemem_set,
  mr_data_readmem_set,
  mr_data_writeval_set,
  mr_data_readval_set,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  mr_freemem_set,
  mr_data_cmpdisk_set,
  mr_cmpval_set
};

const PR_TYPE *tp_Type_set = &tp_Set;

const PR_TYPE tp_Multiset = {
  "multiset", DB_TYPE_MULTISET, 1, sizeof (SETOBJ *), 0, 4,
  mr_initmem_set,
  mr_initval_multiset,
  mr_setmem_set,
  mr_getmem_multiset,
  mr_setval_multiset,
  mr_data_lengthmem_set,
  mr_data_lengthval_set,
  mr_data_writemem_set,
  mr_data_readmem_set,
  mr_data_writeval_set,
  mr_data_readval_set,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  mr_freemem_set,
  mr_data_cmpdisk_set,
  mr_cmpval_set
};

const PR_TYPE *tp_Type_multiset = &tp_Multiset;

const PR_TYPE tp_Sequence = {
  "sequence", DB_TYPE_SEQUENCE, 1, sizeof (SETOBJ *), 0, 4,
  mr_initmem_set,
  mr_initval_sequence,
  mr_setmem_set,
  mr_getmem_sequence,
  mr_setval_sequence,
  mr_data_lengthmem_set,
  mr_data_lengthval_set,
  mr_data_writemem_set,
  mr_data_readmem_set,
  mr_data_writeval_set,
  mr_data_readval_set,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  mr_freemem_set,
  mr_data_cmpdisk_sequence,
  mr_cmpval_sequence
};

const PR_TYPE *tp_Type_sequence = &tp_Sequence;

const PR_TYPE tp_Midxkey = {
  "midxkey", DB_TYPE_MIDXKEY, 1, 0, 0, 1,
  NULL,             /* initmem */
  mr_initval_midxkey,
  NULL,             /* setmem */
  NULL,             /* getmem_midxkey */
  mr_setval_midxkey,
  mr_data_lengthmem_midxkey,
  mr_data_lengthval_midxkey,
  NULL,             /* data_writemem */
  NULL,             /* data_readmem */
  mr_data_writeval_midxkey,
  mr_data_readval_midxkey,
  mr_index_lengthmem_midxkey,
  mr_index_lengthval_midxkey,
  mr_index_writeval_midxkey,
  mr_index_readval_midxkey,
  mr_index_cmpdisk_midxkey,
  NULL,             /* freemem */
  mr_data_cmpdisk_midxkey,
  mr_cmpval_midxkey
};

const PR_TYPE *tp_Type_midxkey = &tp_Midxkey;

const PR_TYPE tp_Vobj = {
  "*vobj*", DB_TYPE_VOBJ, 1, sizeof (SETOBJ *), 0, 8,
  mr_initmem_set,
  mr_initval_vobj,
  mr_setmem_set,
  mr_getmem_sequence,
  mr_setval_vobj,
  mr_data_lengthmem_set,
  mr_data_lengthval_set,
  mr_data_writemem_set,
  mr_data_readmem_set,
  mr_data_writeval_set,
  mr_data_readval_vobj,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  mr_freemem_set,
  mr_data_cmpdisk_vobj,
  mr_cmpval_vobj
};

const PR_TYPE *tp_Type_vobj = &tp_Vobj;

const PR_TYPE tp_Numeric = {
  "numeric", DB_TYPE_NUMERIC, 0, 0, 0, 1,
  mr_initmem_numeric,
  mr_initval_numeric,
  mr_setmem_numeric,
  mr_getmem_numeric,
  mr_setval_numeric,
  mr_data_lengthmem_numeric,
  mr_data_lengthval_numeric,
  mr_data_writemem_numeric,
  mr_data_readmem_numeric,
  mr_data_writeval_numeric,
  mr_data_readval_numeric,
  mr_index_lengthmem_numeric,
  mr_index_lengthval_numeric,
  mr_index_writeval_numeric,
  mr_index_readval_numeric,
  mr_index_cmpdisk_numeric,
  NULL,             /* freemem */
  mr_data_cmpdisk_numeric,
  mr_cmpval_numeric
};

const PR_TYPE *tp_Type_numeric = &tp_Numeric;

const PR_TYPE tp_Enumeration = {
  "enum", DB_TYPE_ENUMERATION, 0, sizeof (unsigned short), sizeof (unsigned short), sizeof (unsigned short),
  mr_initmem_enumeration,
  mr_initval_enumeration,
  mr_setmem_enumeration,
  mr_getmem_enumeration,
  mr_setval_enumeration,
  NULL,             /* use disksize */
  NULL,             /* use_disksize */
  mr_data_writemem_enumeration,
  mr_data_readmem_enumeration,
  mr_data_writeval_enumeration,
  mr_data_readval_enumeration,
  NULL,             /* use disksize */
  NULL,             /* use disksize */
  mr_index_writeval_enumeration,
  mr_index_readval_enumeration,
  mr_index_cmpdisk_enumeration,
  NULL,             /* free mem not deeded for short */
  mr_data_cmpdisk_enumeration,
  mr_cmpval_enumeration
};

const PR_TYPE *tp_Type_enumeration = &tp_Enumeration;

/*
 * tp_Type_id_map
 *    This quickly maps a type identifier to a type structure.
 *    This is dependent on the ordering of the DB_TYPE union so take
 *    care when modifying either of these.  It would be safer to build
 *    this at run time.
 */

#define tp_NChar    tp_Char
#define tp_VarNChar tp_String
const PR_TYPE *tp_Type_id_map[] = {
  &tp_Null,
  &tp_Integer,
  &tp_Float,
  &tp_Double,
  &tp_String,
  &tp_Object,
  &tp_Set,
  &tp_Multiset,
  &tp_Sequence,
  &tp_Elo,
  &tp_Time,
  &tp_Utime,
  &tp_Date,
  &tp_Monetary,
  &tp_Variable,
  &tp_Substructure,
  &tp_Pointer,
  &tp_Error,
  &tp_Short,
  &tp_Vobj,
  &tp_Oid,
  &tp_Null,         /* place holder for DB_TYPE_DB_VALUE */
  &tp_Numeric,
  &tp_Bit,
  &tp_VarBit,
  &tp_Char,

  /* TODO:
   * DB_TYPE_NCHAR and DB_TYPE_VARNCHAR will no longer be used(NCHAR was deprecated).
   * However, to maintain compatibility with previous versions, the enum list will be preserved.       
   */
  &tp_NChar,
  &tp_VarNChar,

  &tp_ResultSet,
  &tp_Midxkey,
  &tp_Null,
  &tp_Bigint,
  &tp_Datetime,
  &tp_Blob,
  &tp_Clob,
  &tp_Enumeration,
  &tp_Timestamptz,
  &tp_Timestampltz,
  &tp_Datetimetz,
  &tp_Datetimeltz,
  &tp_Json,
};

const PR_TYPE tp_ResultSet = {
  "resultset", DB_TYPE_RESULTSET, 0, sizeof (DB_RESULTSET), sizeof (DB_RESULTSET), 4,
  mr_initmem_resultset,
  mr_initval_resultset,
  mr_setmem_resultset,
  mr_getmem_resultset,
  mr_setval_resultset,
  NULL,             /* data_lengthmem */
  NULL,             /* data_lengthval */
  mr_data_writemem_resultset,
  mr_data_readmem_resultset,
  mr_data_writeval_resultset,
  mr_data_readval_resultset,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  NULL,             /* freemem */
  mr_data_cmpdisk_resultset,
  mr_cmpval_resultset
};

const PR_TYPE *tp_Type_resultset = &tp_ResultSet;

/*
 * DB_VALUE MAINTENANCE
 */


/*
 * pr_area_init - Initialize the area for allocation of value containers.
 *    return: NO_ERROR or error code.
 * Note:
 *    This must be called at a suitable point in system initialization.
 */
int
pr_area_init (void)
{
  Value_area = area_create ("Value containers", sizeof (DB_VALUE), VALUE_AREA_COUNT);
  if (Value_area == NULL)
    {
      assert (er_errid () != NO_ERROR);
      return er_errid ();
    }

  return NO_ERROR;
}

/*
 * pr_area_final - Finalize the area for allocation of value containers.
 *    return: none.
 */
void
pr_area_final (void)
{
  if (Value_area != NULL)
    {
      area_destroy (Value_area);
      Value_area = NULL;
    }
}

/*
 * pr_make_value - create an internal value container
 *    return: new value container
 * Note:
 *    The value is allocated within the main workspace blocks so that
 *    it will not serve as a root for the garbage collector.
 */
DB_VALUE *
pr_make_value (void)
{
  DB_VALUE *value;

  value = (DB_VALUE *) db_private_alloc (NULL, sizeof (DB_VALUE));

  if (value != NULL)
    {
      db_value_domain_init (value, DB_TYPE_NULL, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }

  return value;
}

/*
 * pr_make_ext_value - creates an external value container suitable for
 * passing beyond the interface layer to application programs.
 *    return: new value container
 * Note:
 *    It is allocated in the special Value_area so that it will serve as
 *    a root to the garbage collector if the value contains a MOP.
 */
DB_VALUE *
pr_make_ext_value (void)
{
  DB_VALUE *value;

  value = (DB_VALUE *) area_alloc (Value_area);
  if (value != NULL)
    {
      db_value_domain_init (value, DB_TYPE_NULL, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  return value;
}

/*
 * pr_clear_value - clear an internal or external DB_VALUE and
 *                  initialize it to the NULL state.
 *    return: NO_ERROR
 *    value(in/out): value to initialize
 * Note:
 *    Any external allocations (strings, sets, etc) will be freed.
 *
 *    There is too much type specific stuff in here.  We need to create a
 *    "freeval" type vector function to do this work.
 */
int
pr_clear_value (DB_VALUE * value)
{
  char *midxkey_buf = NULL;
  const char *char_medium_buf = NULL;
  bool need_clear;
  DB_TYPE db_type;

  static bool oracle_style_empty_string = prm_get_bool_value (PRM_ID_ORACLE_STYLE_EMPTY_STRING);

  if (value == NULL)
    {
      return NO_ERROR;      /* do nothing */
    }

  db_type = DB_VALUE_DOMAIN_TYPE (value);

  need_clear = true;

  if (DB_IS_NULL (value))
    {
      need_clear = false;
      if (value->need_clear)
    {
      if (oracle_style_empty_string)
        {           /* need to check */
          if ((QSTR_IS_ANY_CHAR_OR_BIT (db_type) && value->data.ch.medium.buf != NULL)
          || db_type == DB_TYPE_ENUMERATION)
        {
          need_clear = true;    /* need to free Empty-string */
        }
        }
    }
    }

  if (need_clear == false)
    {
      return NO_ERROR;      /* do nothing */
    }

  switch (db_type)
    {
    case DB_TYPE_JSON:
      if (value->need_clear)
    {
      if (value->data.json.document != NULL)
        {
          db_json_delete_doc (value->data.json.document);
          value->data.json.document = NULL;
        }
      if (value->data.json.schema_raw != NULL)
        {
          db_private_free (NULL, const_cast < char *>(value->data.json.schema_raw));
          value->data.json.schema_raw = NULL;
        }
    }
      else
    {
      value->data.json.document = NULL;
      value->data.json.schema_raw = NULL;
    }
      break;

    case DB_TYPE_OBJECT:
      /* we need to be sure to NULL the object pointer so that this db_value does not cause garbage collection problems
       * by retaining an object pointer. */
      value->data.op = NULL;
      break;

    case DB_TYPE_SET:
    case DB_TYPE_MULTISET:
    case DB_TYPE_SEQUENCE:
    case DB_TYPE_VOBJ:
      set_free (db_get_set (value));
      value->data.set = NULL;
      break;

    case DB_TYPE_MIDXKEY:
      midxkey_buf = value->data.midxkey.buf;
      if (midxkey_buf != NULL)
    {
      if (value->need_clear)
        {
          db_private_free_and_init (NULL, midxkey_buf);
        }
      /*
       * Ack, phfffft!!! why should we have to know about the
       * internals here?
       */
      value->data.midxkey.buf = NULL;
    }
      break;

    case DB_TYPE_VARCHAR:
    case DB_TYPE_CHAR:
    case DB_TYPE_BIT:
    case DB_TYPE_VARBIT:
      char_medium_buf = value->data.ch.medium.buf;
      if (char_medium_buf != NULL)
    {
      if (value->need_clear)
        {
          // here is safe to const_cast since the ownership was handed over by setting need_clear flag to true
          char *temp = CONST_CAST (char *, char_medium_buf);
          db_private_free_and_init (NULL, temp);
        }
      /*
       * Ack, phfffft!!! why should we have to know about the
       * internals here?
       */
      value->data.ch.medium.buf = NULL;
    }

      /* Clear the compressed string since we are here for DB_TYPE_VARCHAR. */
      if (db_type == DB_TYPE_VARCHAR)
    {
      char *compressed_str = DB_GET_COMPRESSED_STRING (value);
      if (compressed_str != NULL)
        {
          if (value->data.ch.info.compressed_need_clear != 0)
        {
          // here is safe to const_cast since the ownership was handed over by setting need_clear flag to true
          db_private_free_and_init (NULL, compressed_str);
        }
        }
      db_set_compressed_string (value, NULL, DB_NOT_YET_COMPRESSED, false);
    }
      else if (db_type == DB_TYPE_CHAR)
    {
      assert (value->data.ch.info.compressed_need_clear == 0);
      char *compressed_str = value->data.ch.medium.compressed_buf;
      if (compressed_str != NULL)
        {
          if (value->data.ch.info.compressed_need_clear != 0)
        {
          db_private_free_and_init (NULL, compressed_str);
        }
        }
    }
      break;

    case DB_TYPE_BLOB:
    case DB_TYPE_CLOB:
      if (value->need_clear)
    {
      elo_free_structure (db_get_elo (value));
    }
      break;

    case DB_TYPE_ENUMERATION:
      if (value->need_clear)
    {
      // here is safe to const_cast since the ownership was handed over by setting need_clear flag to true
      char *temp = CONST_CAST (char *, db_get_enum_string (value));
      if (temp != NULL)
        {
          db_private_free_and_init (NULL, temp);
        }
    }
      db_make_enumeration (value, 0, NULL, 0, db_get_enum_codeset (value), db_get_enum_collation (value));
      break;

    default:
      break;
    }

  /* always make sure the value gets cleared */
  PRIM_SET_NULL (value);
  value->need_clear = false;

  return NO_ERROR;
}

/*
 * pr_clear_value_vector - clear a vector of db_values
 * references
 *    return: void
 *    value(in/out): vector of values
 */
/* *INDENT-OFF* */
void
pr_clear_value_vector (std::vector<DB_VALUE> &value_vector)
{
  for (DB_VALUE &dbval : value_vector)
    {
      pr_clear_value (&dbval);
    }
}
/* *INDENT-ON* */

/*
 * pr_free_value - free an internval value container any anything that it
 * references
 *    return: NO_ERROR if successful, error code otherwise
 *    value(in/out): value to clear & free
 */
int
pr_free_value (DB_VALUE * value)
{
  int error = NO_ERROR;

  if (value != NULL)
    {
      /* some redundant checking but I want the semantics isolated */
      error = pr_clear_value (value);
      db_private_free_and_init (NULL, value);
    }
  return error;
}

/*
 * pr_free_ext_value - free an external value container and anything that it
 * references.
 *    return:
 *    value(in/out): external value to clear & free
 * Note:
 *    Identical to pr_free_value except that it frees the value to the
 * Value_area instead of to the workspace.
 */
int
pr_free_ext_value (DB_VALUE * value)
{
  int error = NO_ERROR;

  if (value != NULL)
    {
      /* some redundant checking but I want the semantics isolated */
      error = pr_clear_value (value);
      (void) area_free (Value_area, (void *) value);
    }
  return error;
}

/*
 * pr_clone_value - copy the contents of one value container to another.
 *    return: none
 *    src(in): source value
 *    dest(out): destination value
 * Note:
 *    For types that contain external allocations (like strings).
 *    The contents are copied.
 */
int
pr_clone_value (const DB_VALUE * src, DB_VALUE * dest)
{
  const PR_TYPE *type;
  DB_TYPE src_dbtype;

  if (dest != NULL)
    {
      if (src == NULL)
    {
      db_make_null (dest);
    }
      else
    {
      src_dbtype = DB_VALUE_DOMAIN_TYPE (src);

      if (DB_IS_NULL (src))
        {
          db_value_domain_init (dest, src_dbtype, DB_VALUE_PRECISION (src), DB_VALUE_SCALE (src));
        }
      else if (src != dest)
        {
          type = pr_type_from_id (src_dbtype);
          if (type != NULL)
        {
          /*
           * Formerly called "initval" here but that was removed as
           * "setval" is supposed to properly initialize the
           * destination domain.  No need to do it twice.
           * Make sure the COPY flag is set in the setval call.
           */
          type->setval (dest, src, true);
        }
          else
        {
          /*
           * can only get here in error conditions, initialize to NULL
           */
          db_make_null (dest);
        }
        }
    }
    }

  return NO_ERROR;
}

/*
 * pr_copy_value - This creates a new internal value container with a copy
 * of the contents of the source container.
 *    return: new value
 *    value(in): value to copy
 */
DB_VALUE *
pr_copy_value (DB_VALUE * value)
{
  DB_VALUE *new_ = NULL;

  if (value != NULL)
    {
      new_ = pr_make_value ();
      if (pr_clone_value (value, new_) != NO_ERROR)
    {
      /*
       * oh well, couldn't allocate storage for the clone.
       * Note that pr_free_value can only return errors in the
       * case where the value has been initialized so it won't
       * stomp on the error code if we call it here
       */
      pr_free_value (new_);
      new_ = NULL;
    }
    }
  return new_;
}

/*
 * TYPE NULL
 */

/*
 * This is largely a placeholder type that does nothing except assert
 * that the size of a NULL value is zero.
 * The "mem" functions are no-ops since NULL is not a valid domain type.
 * The "value" functions don't do much, they just make sure the value
 * domain is initialized.
 *
 */

/*
 * mr_initmem_null - dummy function
 *    return:
 *    memptr():
 */
static void
mr_initmem_null (void *memptr, TP_DOMAIN * domain)
{
}

/*
 * mr_setmem_null - dummy function
 *    return:
 *    memptr():
 *    domain():
 *    value():
 */
static int
mr_setmem_null (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  return NO_ERROR;
}

/*
 * mr_getmem_null - dummy function
 *    return:
 *    memptr():
 *    domain():
 *    value():
 *    copy():
 */
static int
mr_getmem_null (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  db_make_null (value);
  return NO_ERROR;
}

/*
 * mr_writemem_null - dummy function
 *    return:
 *    buf():
 *    memptr():
 *    domain():
 */
static void
mr_data_writemem_null (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
}

/*
 * mr_readmem_null - dummy function
 *    return:
 *    buf():
 *    memptr():
 *    domain():
 *    size():
 */
static void
mr_data_readmem_null (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size)
{
}

static void
mr_initval_null (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_NULL, precision, scale);
}

/*
 * mr_setval_null - dummy function
 *    return:
 *    dest():
 *    src():
 *    copy():
 */
static int
mr_setval_null (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  mr_initval_null (dest, 0, 0);
  return NO_ERROR;
}

/*
 * mr_writeval_null - dummy function
 *    return:
 *    buf():
 *    value():
 */
static int
mr_data_writeval_null (OR_BUF * buf, DB_VALUE * value)
{
  return NO_ERROR;
}

/*
 * mr_readval_null - dummy function
 *    return:
 *    buf():
 *    value():
 *    domain():
 *    size():
 *    copy():
 *    copy_buf():
 *    copy_buf_len():
 */
static int
mr_data_readval_null (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  if (value)
    {
      db_make_null (value);
      value->need_clear = false;
    }
  return NO_ERROR;
}

/*
 * mr_cmpdisk_null - dummy function
 *    return:
 *    mem1():
 *    mem2():
 *    domain():
 *    do_coercion():
 *    total_order():
 *    start_colp():
 */
static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_null (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return DB_UNK;
}

/*
 * mr_cmpval_null - dummy function
 *    return:
 *    value1():
 *    value2():
 *    do_coercion():
 *    total_order():
 *    start_colp():
 */
static DB_VALUE_COMPARE_RESULT
mr_cmpval_null (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  return DB_UNK;
}


/*
 * TYPE INTEGER
 *
 * Your basic 32 bit signed integral value.
 * At the storage level, we don't really care whether it is signed or unsigned.
 */

static void
mr_initmem_int (void *mem, TP_DOMAIN * domain)
{
  *(int *) mem = 0;
}

static int
mr_setmem_int (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value != NULL)
    *(int *) mem = db_get_int (value);
  else
    mr_initmem_int (mem, domain);

  return NO_ERROR;
}

static int
mr_getmem_int (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return db_make_int (value, *(int *) mem);
}

static void
mr_data_writemem_int (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_int (buf, *(int *) mem);
}

static void
mr_data_readmem_int (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  int rc = NO_ERROR;

  if (mem == NULL)
    {
      or_advance (buf, tp_Integer.disksize);
    }
  else
    {
      *(int *) mem = or_get_int (buf, &rc);
    }
}

static void
mr_initval_int (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_INTEGER, precision, scale);
  db_make_int (value, 0);
}

static int
mr_setval_int (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  if (src && !DB_IS_NULL (src))
    {
      return db_make_int (dest, db_get_int (src));
    }
  else
    {
      return db_value_domain_init (dest, DB_TYPE_INTEGER, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
}

static int
mr_data_writeval_int (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_int (buf, db_get_int (value));
}

static int
mr_data_readval_int (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  int temp_int, rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Integer.disksize);
    }
  else
    {
      temp_int = or_get_int (buf, &rc);
      if (rc == NO_ERROR)
    {
      db_make_int (value, temp_int);
    }
      value->need_clear = false;
    }
  return rc;
}

static int
mr_index_writeval_int (OR_BUF * buf, DB_VALUE * value)
{
  int i;

  i = db_get_int (value);

  return or_put_data (buf, (char *) (&i), tp_Integer.disksize);
}

static int
mr_index_readval_int (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  int i, rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Integer.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&i), tp_Integer.disksize);
      if (rc == NO_ERROR)
    {
      db_make_int (value, i);
    }
      value->need_clear = false;
    }
  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_int (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  int i1, i2;

  assert (domain != NULL);

  COPYMEM (int, &i1, mem1);
  COPYMEM (int, &i2, mem2);

  return MR_CMP (i1, i2);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_int (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  int i1, i2;

  assert (domain != NULL);

  i1 = OR_GET_INT (mem1);
  i2 = OR_GET_INT (mem2);

  return MR_CMP (i1, i2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_int (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  int i1, i2;

  i1 = db_get_int (value1);
  i2 = db_get_int (value2);

  return MR_CMP (i1, i2);
}

/*
 * TYPE SHORT
 *
 * Your basic 16 bit signed integral value.
 */

static void
mr_initmem_short (void *mem, TP_DOMAIN * domain)
{
  *(short *) mem = 0;
}

static int
mr_setmem_short (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value == NULL)
    mr_initmem_short (mem, domain);
  else
    *(short *) mem = db_get_short (value);

  return NO_ERROR;
}

static int
mr_getmem_short (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return db_make_short (value, *(short *) mem);
}

static void
mr_data_writemem_short (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
  short *mem = (short *) memptr;

  or_put_short (buf, *mem);
}

static void
mr_data_readmem_short (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  int rc = NO_ERROR;

  if (mem == NULL)
    {
      or_advance (buf, tp_Short.disksize);
    }
  else
    {
      *(short *) mem = or_get_short (buf, &rc);
    }
}

static void
mr_initval_short (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_SHORT, precision, scale);
  db_make_short (value, 0);
}

static int
mr_setval_short (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  if (src && !DB_IS_NULL (src))
    {
      return db_make_short (dest, db_get_short (src));
    }
  else
    {
      return db_value_domain_init (dest, DB_TYPE_SHORT, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
}

static int
mr_data_writeval_short (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_short (buf, db_get_short (value));
}

static int
mr_data_readval_short (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
               int copy_buf_len)
{
  int rc = NO_ERROR;
  short s;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Short.disksize);
    }
  else
    {
      s = (short) or_get_short (buf, &rc);
      if (rc == NO_ERROR)
    {
      db_make_short (value, s);
    }
      value->need_clear = false;
    }

  return rc;
}

static int
mr_index_writeval_short (OR_BUF * buf, DB_VALUE * value)
{
  short s;

  s = db_get_short (value);

  return or_put_data (buf, (char *) (&s), tp_Short.disksize);
}

static int
mr_index_readval_short (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
            int copy_buf_len)
{
  int rc = NO_ERROR;
  short s;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Short.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&s), tp_Short.disksize);
      if (rc == NO_ERROR)
    {
      db_make_short (value, s);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_short (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  short s1, s2;

  assert (domain != NULL);

  COPYMEM (short, &s1, mem1);
  COPYMEM (short, &s2, mem2);

  return MR_CMP (s1, s2);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_short (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  short s1, s2;

  assert (domain != NULL);

  s1 = OR_GET_SHORT (mem1);
  s2 = OR_GET_SHORT (mem2);

  return MR_CMP (s1, s2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_short (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  short s1, s2;

  s1 = db_get_short (value1);
  s2 = db_get_short (value2);

  return MR_CMP (s1, s2);
}

/*
 * TYPE BIGINT
 *
 * Your basic 64 bit signed integral value.
 * At the storage level, we don't really care whether it is signed or unsigned.
 */

static void
mr_initmem_bigint (void *mem, TP_DOMAIN * domain)
{
  *(DB_BIGINT *) mem = 0;
}

static int
mr_setmem_bigint (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value != NULL)
    *(DB_BIGINT *) mem = db_get_bigint (value);
  else
    mr_initmem_bigint (mem, domain);

  return NO_ERROR;
}

static int
mr_getmem_bigint (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return db_make_bigint (value, *(DB_BIGINT *) mem);
}

static void
mr_data_writemem_bigint (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_bigint (buf, *(DB_BIGINT *) mem);
}

static void
mr_data_readmem_bigint (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  int rc = NO_ERROR;

  if (mem == NULL)
    {
      or_advance (buf, tp_Bigint.disksize);
    }
  else
    {
      *(DB_BIGINT *) mem = or_get_bigint (buf, &rc);
    }
}

static void
mr_initval_bigint (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_BIGINT, precision, scale);
  db_make_bigint (value, 0);
}

static int
mr_setval_bigint (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  if (src && !DB_IS_NULL (src))
    {
      return db_make_bigint (dest, db_get_bigint (src));
    }
  else
    {
      return db_value_domain_init (dest, DB_TYPE_BIGINT, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
}

static int
mr_data_writeval_bigint (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_bigint (buf, db_get_bigint (value));
}

static int
mr_data_readval_bigint (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
            int copy_buf_len)
{
  int rc = NO_ERROR;
  DB_BIGINT temp_int;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Bigint.disksize);
    }
  else
    {
      temp_int = or_get_bigint (buf, &rc);
      if (rc == NO_ERROR)
    {
      db_make_bigint (value, temp_int);
    }
      value->need_clear = false;
    }
  return rc;
}

static int
mr_index_writeval_bigint (OR_BUF * buf, DB_VALUE * value)
{
  DB_BIGINT bi;

  bi = db_get_bigint (value);

  return or_put_data (buf, (char *) (&bi), tp_Bigint.disksize);
}

static int
mr_index_readval_bigint (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  int rc = NO_ERROR;
  DB_BIGINT bi;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Bigint.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&bi), tp_Bigint.disksize);
      if (rc == NO_ERROR)
    {
      db_make_bigint (value, bi);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_bigint (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_BIGINT i1, i2;

  assert (domain != NULL);

  COPYMEM (DB_BIGINT, &i1, mem1);
  COPYMEM (DB_BIGINT, &i2, mem2);

  return MR_CMP (i1, i2);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_bigint (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_BIGINT i1, i2;

  assert (domain != NULL);

  OR_GET_BIGINT (mem1, &i1);
  OR_GET_BIGINT (mem2, &i2);

  return MR_CMP (i1, i2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_bigint (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
          int collation)
{
  DB_BIGINT i1, i2;

  i1 = db_get_bigint (value1);
  i2 = db_get_bigint (value2);

  return MR_CMP (i1, i2);
}

/*
 * TYPE FLOAT
 *
 * IEEE single precision floating point values.
 */

static void
mr_initmem_float (void *mem, TP_DOMAIN * domain)
{
  *(float *) mem = 0.0;
}

static int
mr_setmem_float (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value == NULL)
    {
      mr_initmem_float (mem, domain);
    }
  else
    {
      *(float *) mem = db_get_float (value);
    }

  return NO_ERROR;
}

static int
mr_getmem_float (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return db_make_float (value, *(float *) mem);
}

static void
mr_data_writemem_float (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_float (buf, *(float *) mem);
}

static void
mr_data_readmem_float (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  int rc = NO_ERROR;

  if (mem == NULL)
    {
      or_advance (buf, tp_Float.disksize);
    }
  else
    {
      *(float *) mem = or_get_float (buf, &rc);
    }
}

static void
mr_initval_float (DB_VALUE * value, int precision, int scale)
{
  db_make_float (value, 0.0);
  value->need_clear = false;
}

static int
mr_setval_float (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  if (src && !DB_IS_NULL (src))
    {
      return db_make_float (dest, db_get_float (src));
    }
  else
    {
      return db_value_domain_init (dest, DB_TYPE_FLOAT, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
}

static int
mr_data_writeval_float (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_float (buf, db_get_float (value));
}

static int
mr_data_readval_float (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
               int copy_buf_len)
{
  float temp;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Float.disksize);
    }
  else
    {
      temp = or_get_float (buf, &rc);
      if (rc == NO_ERROR)
    {
      db_make_float (value, temp);
    }
      value->need_clear = false;
    }
  return rc;
}

static int
mr_index_writeval_float (OR_BUF * buf, DB_VALUE * value)
{
  float f;

  f = db_get_float (value);

  return or_put_data (buf, (char *) (&f), tp_Float.disksize);
}

static int
mr_index_readval_float (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
            int copy_buf_len)
{
  float f;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Float.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&f), tp_Float.disksize);
      if (rc == NO_ERROR)
    {
      db_make_float (value, f);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_float (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  float f1, f2;

  assert (domain != NULL);

  COPYMEM (float, &f1, mem1);
  COPYMEM (float, &f2, mem2);

  return MR_CMP (f1, f2);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_float (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  float f1, f2;

  assert (domain != NULL);

  OR_GET_FLOAT (mem1, &f1);
  OR_GET_FLOAT (mem2, &f2);

  return MR_CMP (f1, f2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_float (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  float f1, f2;

  f1 = db_get_float (value1);
  f2 = db_get_float (value2);

  return MR_CMP (f1, f2);
}

/*
 * TYPE DOUBLE
 *
 * IEEE double precision floating vlaues.
 * Remember the pointer here isn't necessarily valid as a "double*"
 * because the value may be packed into the object such that it
 * doesn't fall on a double word boundary.
 *
 */

static void
mr_initmem_double (void *mem, TP_DOMAIN * domain)
{
  double d = 0.0;

  OR_MOVE_DOUBLE (&d, mem);
}

static int
mr_setmem_double (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  double d;

  if (value == NULL)
    {
      mr_initmem_double (mem, domain);
    }
  else
    {
      d = db_get_double (value);
      OR_MOVE_DOUBLE (&d, mem);
    }
  return NO_ERROR;
}

static int
mr_getmem_double (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  double d = 0;

  OR_MOVE_DOUBLE (mem, &d);
  return db_make_double (value, d);
}

static void
mr_data_writemem_double (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  double d = 0;

  OR_MOVE_DOUBLE (mem, &d);
  or_put_double (buf, d);
}

static void
mr_data_readmem_double (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  double d;
  int rc = NO_ERROR;

  if (mem == NULL)
    {
      or_advance (buf, tp_Double.disksize);
    }
  else
    {
      d = or_get_double (buf, &rc);
      OR_MOVE_DOUBLE (&d, mem);
    }
}

static void
mr_initval_double (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_DOUBLE, precision, scale);
  db_make_double (value, 0.0);
}

static int
mr_setval_double (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  if (src && !DB_IS_NULL (src))
    {
      return db_make_double (dest, db_get_double (src));
    }
  else
    {
      return db_value_domain_init (dest, DB_TYPE_DOUBLE, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
}

static int
mr_data_writeval_double (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_double (buf, db_get_double (value));
}

static int
mr_data_readval_double (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
            int copy_buf_len)
{
  double temp;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Double.disksize);
    }
  else
    {
      temp = or_get_double (buf, &rc);
      if (rc == NO_ERROR)
    {
      db_make_double (value, temp);
    }
      value->need_clear = false;
    }

  return rc;
}

static int
mr_index_writeval_double (OR_BUF * buf, DB_VALUE * value)
{
  double d;

  d = db_get_double (value);

  return or_put_data (buf, (char *) (&d), tp_Double.disksize);
}

static int
mr_index_readval_double (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  double d;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Double.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&d), tp_Double.disksize);
      if (rc == NO_ERROR)
    {
      db_make_double (value, d);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_double (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  double d1, d2;

  assert (domain != NULL);

  COPYMEM (double, &d1, mem1);
  COPYMEM (double, &d2, mem2);

  return MR_CMP (d1, d2);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_double (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  double d1, d2;

  assert (domain != NULL);

  OR_GET_DOUBLE (mem1, &d1);
  OR_GET_DOUBLE (mem2, &d2);

  return MR_CMP (d1, d2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_double (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
          int collation)
{
  double d1, d2;

  d1 = db_get_double (value1);
  d2 = db_get_double (value2);

  return MR_CMP (d1, d2);
}

/*
 * TYPE TIME
 *
 * 32 bit seconds counter.  Interpreted as an offset within a given day.
 * Probably not general enough currently to be used an an interval type?
 *
 */

static void
mr_initmem_time (void *mem, TP_DOMAIN * domain)
{
  *(DB_TIME *) mem = 0;
}

static int
mr_setmem_time (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value == NULL)
    mr_initmem_time (mem, domain);
  else
    *(DB_TIME *) mem = *db_get_time (value);

  return NO_ERROR;
}

static int
mr_getmem_time (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  (void) db_value_put_encoded_time (value, (DB_TIME *) mem);
  value->need_clear = false;
  return NO_ERROR;
}

static void
mr_data_writemem_time (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_time (buf, (DB_TIME *) mem);
}

static void
mr_data_readmem_time (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  if (mem == NULL)
    {
      or_advance (buf, tp_Time.disksize);
    }
  else
    {
      or_get_time (buf, (DB_TIME *) mem);
    }
}

static void
mr_initval_time (DB_VALUE * value, int precision, int scale)
{
  DB_TIME tm = 0;

  db_value_put_encoded_time (value, &tm);
  value->need_clear = false;
}

static int
mr_setval_time (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error;

  if (DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_TIME, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  else
    {
      error = db_value_put_encoded_time (dest, db_get_time (src));
    }
  return error;
}

static int
mr_data_writeval_time (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_time (buf, db_get_time (value));
}

static int
mr_data_readval_time (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  DB_TIME tm;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Time.disksize);
    }
  else
    {
      rc = or_get_time (buf, &tm);
      if (rc == NO_ERROR)
    {
      db_value_put_encoded_time (value, &tm);
    }
      value->need_clear = false;
    }
  return rc;
}

static int
mr_index_writeval_time (OR_BUF * buf, DB_VALUE * value)
{
  DB_TIME *tm;

  tm = db_get_time (value);

  return or_put_data (buf, (char *) tm, tp_Time.disksize);
}

static int
mr_index_readval_time (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
               int copy_buf_len)
{
  DB_TIME tm;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Time.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&tm), tp_Time.disksize);
      if (rc == NO_ERROR)
    {
      db_value_put_encoded_time (value, &tm);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_time (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_TIME t1, t2;

  assert (domain != NULL);

  COPYMEM (DB_TIME, &t1, mem1);
  COPYMEM (DB_TIME, &t2, mem2);

  return MR_CMP (t1, t2);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_time (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_TIME t1, t2;

  assert (domain != NULL);

  OR_GET_TIME (mem1, &t1);
  OR_GET_TIME (mem2, &t2);

  return MR_CMP (t1, t2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_time (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  const DB_TIME *t1, *t2;

  t1 = db_get_time (value1);
  t2 = db_get_time (value2);

  return MR_CMP (*t1, *t2);
}

/*
 * TYPE UTIME
 *
 * "Universal" time, more recently known as a "timestamp".
 * These are 32 bit encoded values that contain both a date and time
 * identification.
 * The encoding is the standard Unix "time_t" format.
 */

static void
mr_initmem_utime (void *mem, TP_DOMAIN * domain)
{
  *(DB_UTIME *) mem = 0;
}

static int
mr_setmem_utime (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value == NULL)
    mr_initmem_utime (mem, domain);
  else
    *(DB_UTIME *) mem = *db_get_timestamp (value);

  return NO_ERROR;
}

static int
mr_getmem_utime (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int error;

  error = db_make_utime (value, *(DB_UTIME *) mem);
  value->need_clear = false;
  return error;
}

static int
mr_getmem_timestampltz (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int error;

  error = db_make_timestampltz (value, *(DB_UTIME *) mem);
  value->need_clear = false;
  return error;
}

static void
mr_data_writemem_utime (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_utime (buf, (DB_UTIME *) mem);
}

static void
mr_data_readmem_utime (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  if (mem == NULL)
    {
      or_advance (buf, tp_Utime.disksize);
    }
  else
    {
      or_get_utime (buf, (DB_UTIME *) mem);
    }
}

static void
mr_initval_utime (DB_VALUE * value, int precision, int scale)
{
  db_make_utime (value, 0);
  value->need_clear = false;
}

static void
mr_initval_timestampltz (DB_VALUE * value, int precision, int scale)
{
  db_make_timestampltz (value, 0);
  value->need_clear = false;
}

static int
mr_setval_utime (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error;

  if (DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_TIMESTAMP, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  else
    {
      error = db_make_utime (dest, *db_get_timestamp (src));
    }
  return error;
}

static int
mr_setval_timestampltz (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error;

  if (DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_TIMESTAMPLTZ, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  else
    {
      error = db_make_timestampltz (dest, *db_get_timestamp (src));
    }
  return error;
}

static int
mr_data_writeval_utime (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_utime (buf, db_get_timestamp (value));
}

static int
mr_data_readval_utime (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
               int copy_buf_len)
{
  DB_UTIME utm;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Utime.disksize);
    }
  else
    {
      rc = or_get_utime (buf, &utm);
      if (rc == NO_ERROR)
    {
      db_make_utime (value, utm);
    }
      value->need_clear = false;
    }
  return rc;
}

static int
mr_data_readval_timestampltz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                  int copy_buf_len)
{
  DB_UTIME utm;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Timestampltz.disksize);
    }
  else
    {
      rc = or_get_utime (buf, &utm);
      db_make_timestampltz (value, utm);
      value->need_clear = false;
    }
  return rc;
}

static int
mr_index_writeval_utime (OR_BUF * buf, DB_VALUE * value)
{
  DB_UTIME *utm;

  utm = db_get_timestamp (value);

  return or_put_data (buf, (char *) utm, tp_Utime.disksize);
}

static int
mr_index_readval_utime (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
            int copy_buf_len)
{
  DB_UTIME utm;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Utime.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&utm), tp_Utime.disksize);
      if (rc == NO_ERROR)
    {
      db_make_utime (value, utm);
    }
      value->need_clear = false;
    }

  return rc;
}

static int
mr_index_readval_timestampltz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                   int copy_buf_len)
{
  DB_UTIME utm;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Timestampltz.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&utm), tp_Timestampltz.disksize);
      if (rc == NO_ERROR)
    {
      db_make_timestampltz (value, utm);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_utime (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_UTIME utm1, utm2;

  assert (domain != NULL);

  COPYMEM (DB_UTIME, &utm1, mem1);
  COPYMEM (DB_UTIME, &utm2, mem2);

  return MR_CMP (utm1, utm2);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_utime (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_TIMESTAMP ts1, ts2;

  assert (domain != NULL);

  OR_GET_UTIME (mem1, &ts1);
  OR_GET_UTIME (mem2, &ts2);

  return MR_CMP (ts1, ts2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_utime (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  const DB_TIMESTAMP *ts1, *ts2;

  ts1 = db_get_timestamp (value1);
  ts2 = db_get_timestamp (value2);

  return MR_CMP (*ts1, *ts2);
}

/*
 * TYPE TIMESTAMPTZ
 *
 * This stores a TIMESTAMP and a zone identifier
 * The requirement is 4 (TIMESTAMP) + 2 bytes (zone id)
 * The encoding of TIMESTAMP is the standard Unix "time_t" format.
 */

static void
mr_initmem_timestamptz (void *mem, TP_DOMAIN * domain)
{
  DB_TIMESTAMPTZ *ts_tz = (DB_TIMESTAMPTZ *) mem;

  ts_tz->timestamp = 0;
  ts_tz->tz_id = 0;
}

static int
mr_setmem_timestamptz (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value == NULL)
    {
      mr_initmem_timestamptz (mem, domain);
    }
  else
    {
      *(DB_TIMESTAMPTZ *) mem = *db_get_timestamptz (value);
    }

  return NO_ERROR;
}

static int
mr_getmem_timestamptz (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int error;

  error = db_make_timestamptz (value, (DB_TIMESTAMPTZ *) mem);
  return error;
}

static void
mr_data_writemem_timestamptz (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_timestamptz (buf, (DB_TIMESTAMPTZ *) mem);
}

static void
mr_data_readmem_timestamptz (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  if (mem == NULL)
    {
      or_advance (buf, tp_Timestamptz.disksize);
    }
  else
    {
      or_get_timestamptz (buf, (DB_TIMESTAMPTZ *) mem);
    }
}

static void
mr_initval_timestamptz (DB_VALUE * value, int precision, int scale)
{
  DB_TIMESTAMPTZ ts_tz;

  mr_initmem_timestamptz (&ts_tz, NULL);
  db_make_timestamptz (value, &ts_tz);
}

static int
mr_setval_timestamptz (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error;

  if (DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_TIMESTAMPTZ, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  else
    {
      error = db_make_timestamptz (dest, db_get_timestamptz (src));
    }
  return error;
}

static int
mr_data_writeval_timestamptz (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_timestamptz (buf, db_get_timestamptz (value));
}

static int
mr_data_readval_timestamptz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                 int copy_buf_len)
{
  DB_TIMESTAMPTZ ts_tz;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Timestamptz.disksize);
    }
  else
    {
      rc = or_get_timestamptz (buf, &ts_tz);
      db_make_timestamptz (value, &ts_tz);
    }
  return rc;
}

static int
mr_index_writeval_timestamptz (OR_BUF * buf, DB_VALUE * value)
{
  DB_TIMESTAMPTZ *ts_tz;
  int rc = NO_ERROR;

  ts_tz = db_get_timestamptz (value);

  assert (tp_Timestamptz.disksize == (tp_Utime.disksize + tp_Integer.disksize));

  rc = or_put_data (buf, (char *) (&ts_tz->timestamp), tp_Utime.disksize);
  if (rc == NO_ERROR)
    {
      rc = or_put_data (buf, (char *) (&ts_tz->tz_id), tp_Integer.disksize);
    }

  return rc;
}

static int
mr_index_readval_timestamptz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                  int copy_buf_len)
{
  DB_TIMESTAMPTZ ts_tz;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Timestamptz.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&ts_tz), tp_Timestamptz.disksize);
      if (rc == NO_ERROR)
    {
      db_make_timestamptz (value, &ts_tz);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_timestamptz (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order,
                  int *start_colp)
{
  DB_UTIME utm1, utm2;

  assert (domain != NULL);

  /* TIMESTAMP with TZ compares the same as TIMESTAMP (zone is not taken into account) */
  COPYMEM (DB_UTIME, &utm1, mem1);
  COPYMEM (DB_UTIME, &utm2, mem2);

  return MR_CMP (utm1, utm2);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_timestamptz (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order,
                 int *start_colp)
{
  DB_TIMESTAMP ts1, ts2;

  assert (domain != NULL);

  /* TIMESTAMP with TZ compares the same as TIMESTAMP (zone is not taken into account) */
  OR_GET_UTIME (mem1, &ts1);
  OR_GET_UTIME (mem2, &ts2);

  return MR_CMP (ts1, ts2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_timestamptz (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
               int collation)
{
  const DB_TIMESTAMPTZ *ts_tz1, *ts_tz2;

  /* TIMESTAMP with TZ compares the same as TIMESTAMP (zone is not taken into account); the first component of
   * TIMESTAMPTZ is a TIMESTAMP, it is safe to use the TIMESTAMP part of DB_DATA union to read it */
  ts_tz1 = db_get_timestamptz (value1);
  ts_tz2 = db_get_timestamptz (value2);

#if defined (SA_MODE)
  if (tz_Compare_timestamptz_tz_id == true && ts_tz1->tz_id != ts_tz2->tz_id)
    {
      return DB_NE;
    }
#endif

  return MR_CMP (ts_tz1->timestamp, ts_tz2->timestamp);
}

/*
 * TYPE DATETIME
 *
 */

static void
mr_initmem_datetime (void *memptr, TP_DOMAIN * domain)
{
  DB_DATETIME *mem = (DB_DATETIME *) memptr;

  mem->date = 0;
  mem->time = 0;
}

static void
mr_initval_datetime (DB_VALUE * value, int precision, int scale)
{
  DB_DATETIME dt;

  mr_initmem_datetime (&dt, NULL);
  db_make_datetime (value, &dt);
  value->need_clear = false;
}

static void
mr_initval_datetimeltz (DB_VALUE * value, int precision, int scale)
{
  DB_DATETIME dt;

  mr_initmem_datetime (&dt, NULL);
  db_make_datetimeltz (value, &dt);
  value->need_clear = false;
}

static int
mr_setmem_datetime (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value == NULL)
    {
      mr_initmem_datetime (mem, domain);
    }
  else
    {
      *(DB_DATETIME *) mem = *db_get_datetime (value);
    }

  return NO_ERROR;
}

static int
mr_getmem_datetime (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return db_make_datetime (value, (DB_DATETIME *) mem);
}

static int
mr_getmem_datetimeltz (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return db_make_datetimeltz (value, (DB_DATETIME *) mem);
}

static int
mr_setval_datetime (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error;

  if (DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_DATETIME, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  else
    {
      error = db_make_datetime (dest, db_get_datetime (src));
    }
  return error;
}

static int
mr_setval_datetimeltz (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error;

  if (DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_DATETIMELTZ, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  else
    {
      error = db_make_datetimeltz (dest, db_get_datetime (src));
    }
  return error;
}

static void
mr_data_writemem_datetime (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_datetime (buf, (DB_DATETIME *) mem);
}

static void
mr_data_readmem_datetime (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  if (mem == NULL)
    {
      or_advance (buf, tp_Datetime.disksize);
    }
  else
    {
      or_get_datetime (buf, (DB_DATETIME *) mem);
    }
}

static int
mr_data_writeval_datetime (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_datetime (buf, db_get_datetime (value));
}

static int
mr_data_readval_datetime (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  DB_DATETIME datetime;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Datetime.disksize);
    }
  else
    {
      rc = or_get_datetime (buf, &datetime);
      if (rc == NO_ERROR)
    {
      if (DATETIME_IS_NULL (&datetime))
        {
          db_make_null (value);
        }
      else
        {
          db_make_datetime (value, &datetime);
        }
    }
      value->need_clear = false;
    }
  return rc;
}

static int
mr_data_readval_datetimeltz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                 int copy_buf_len)
{
  DB_DATETIME datetime;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Datetimeltz.disksize);
    }
  else
    {
      rc = or_get_datetime (buf, &datetime);
      db_make_datetimeltz (value, &datetime);
    }
  return rc;
}

static int
mr_index_writeval_datetime (OR_BUF * buf, DB_VALUE * value)
{
  DB_DATETIME *datetime;
  int rc = NO_ERROR;

  datetime = db_get_datetime (value);

  assert (tp_Datetime.disksize == (tp_Date.disksize + tp_Time.disksize));

  rc = or_put_data (buf, (char *) (&datetime->date), tp_Date.disksize);
  if (rc == NO_ERROR)
    {
      rc = or_put_data (buf, (char *) (&datetime->time), tp_Time.disksize);
    }

  return rc;
}

static int
mr_index_readval_datetime (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
               int copy_buf_len)
{
  DB_DATETIME datetime;
  int rc = NO_ERROR;

  assert (tp_Datetime.disksize == (tp_Date.disksize + tp_Time.disksize));

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Datetime.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&datetime.date), tp_Date.disksize);
      if (rc == NO_ERROR)
    {
      rc = or_get_data (buf, (char *) (&datetime.time), tp_Time.disksize);
    }

      if (rc == NO_ERROR)
    {
      db_make_datetime (value, &datetime);
    }
      value->need_clear = false;
    }

  return rc;
}

static int
mr_index_readval_datetimeltz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                  int copy_buf_len)
{
  DB_DATETIME datetime;
  int rc = NO_ERROR;

  assert (tp_Datetimeltz.disksize == (tp_Date.disksize + tp_Time.disksize));

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Datetimeltz.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&datetime.date), tp_Date.disksize);
      if (rc == NO_ERROR)
    {
      rc = or_get_data (buf, (char *) (&datetime.time), tp_Time.disksize);
    }

      if (rc == NO_ERROR)
    {
      db_make_datetimeltz (value, &datetime);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_datetime (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order,
               int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c;
  DB_DATETIME dt1, dt2;

  assert (domain != NULL);

  if (mem1 == mem2)
    {
      return DB_EQ;
    }

  COPYMEM (unsigned int, &dt1.date, (char *)mem1 + OR_DATETIME_DATE);
  COPYMEM (unsigned int, &dt1.time, (char *) mem1 + OR_DATETIME_TIME);
  COPYMEM (unsigned int, &dt2.date, (char *) mem2 + OR_DATETIME_DATE);
  COPYMEM (unsigned int, &dt2.time, (char *) mem2 + OR_DATETIME_TIME);

  if (dt1.date < dt2.date)
    {
      c = DB_LT;
    }
  else if (dt1.date > dt2.date)
    {
      c = DB_GT;
    }
  else
    {
      if (dt1.time < dt2.time)
    {
      c = DB_LT;
    }
      else if (dt1.time > dt2.time)
    {
      c = DB_GT;
    }
      else
    {
      c = DB_EQ;
    }
    }

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_datetime (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c;
  DB_DATETIME dt1, dt2;

  assert (domain != NULL);

  if (mem1 == mem2)
    {
      return DB_EQ;
    }

  OR_GET_DATETIME (mem1, &dt1);
  OR_GET_DATETIME (mem2, &dt2);

  if (dt1.date < dt2.date)
    {
      c = DB_LT;
    }
  else if (dt1.date > dt2.date)
    {
      c = DB_GT;
    }
  else
    {
      if (dt1.time < dt2.time)
    {
      c = DB_LT;
    }
      else if (dt1.time > dt2.time)
    {
      c = DB_GT;
    }
      else
    {
      c = DB_EQ;
    }
    }

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_datetime (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
            int collation)
{
  const DB_DATETIME *dt1, *dt2;
  DB_VALUE_COMPARE_RESULT c;

  dt1 = db_get_datetime (value1);
  dt2 = db_get_datetime (value2);

  if (dt1->date < dt2->date)
    {
      c = DB_LT;
    }
  else if (dt1->date > dt2->date)
    {
      c = DB_GT;
    }
  else
    {
      if (dt1->time < dt2->time)
    {
      c = DB_LT;
    }
      else if (dt1->time > dt2->time)
    {
      c = DB_GT;
    }
      else
    {
      c = DB_EQ;
    }
    }

  return c;
}

/*
 * TYPE DATETIMETZ
 *
 */

static void
mr_initmem_datetimetz (void *memptr, TP_DOMAIN * domain)
{
  DB_DATETIMETZ *mem = (DB_DATETIMETZ *) memptr;

  mem->datetime.date = 0;
  mem->datetime.time = 0;
  mem->tz_id = 0;
}

static void
mr_initval_datetimetz (DB_VALUE * value, int precision, int scale)
{
  DB_DATETIMETZ dt_tz;

  mr_initmem_datetimetz (&dt_tz, NULL);
  db_make_datetimetz (value, &dt_tz);
}

static int
mr_setmem_datetimetz (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value == NULL)
    {
      mr_initmem_datetimetz (mem, NULL);
    }
  else
    {
      *(DB_DATETIMETZ *) mem = *db_get_datetimetz (value);
    }

  return NO_ERROR;
}

static int
mr_getmem_datetimetz (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return db_make_datetimetz (value, (DB_DATETIMETZ *) mem);
}

static int
mr_setval_datetimetz (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error;

  if (DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_DATETIMETZ, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  else
    {
      error = db_make_datetimetz (dest, db_get_datetimetz (src));
    }
  return error;
}

static void
mr_data_writemem_datetimetz (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_datetimetz (buf, (DB_DATETIMETZ *) mem);
}

static void
mr_data_readmem_datetimetz (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  if (mem == NULL)
    {
      or_advance (buf, tp_Datetimetz.disksize);
    }
  else
    {
      or_get_datetimetz (buf, (DB_DATETIMETZ *) mem);
    }
}

static int
mr_data_writeval_datetimetz (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_datetimetz (buf, db_get_datetimetz (value));
}

static int
mr_data_readval_datetimetz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                int copy_buf_len)
{
  DB_DATETIMETZ datetimetz;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Datetimetz.disksize);
    }
  else
    {
      rc = or_get_datetimetz (buf, &datetimetz);
      db_make_datetimetz (value, &datetimetz);
    }
  return rc;
}

static int
mr_index_writeval_datetimetz (OR_BUF * buf, DB_VALUE * value)
{
  DB_DATETIMETZ *datetimetz;
  int rc = NO_ERROR;

  datetimetz = db_get_datetimetz (value);

  assert (tp_Datetimetz.disksize == (tp_Date.disksize + tp_Time.disksize + tp_Integer.disksize));

  rc = or_put_data (buf, (char *) (&datetimetz->datetime.date), tp_Date.disksize);
  if (rc == NO_ERROR)
    {
      rc = or_put_data (buf, (char *) (&datetimetz->datetime.time), tp_Time.disksize);
      if (rc == NO_ERROR)
    {
      rc = or_put_data (buf, (char *) (&datetimetz->tz_id), tp_Integer.disksize);
    }
    }

  return rc;
}

static int
mr_index_readval_datetimetz (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                 int copy_buf_len)
{
  DB_DATETIMETZ datetimetz;
  int rc = NO_ERROR;

  assert (tp_Datetimetz.disksize == (tp_Date.disksize + tp_Time.disksize + tp_Integer.disksize));

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Datetimetz.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&datetimetz.datetime.date), tp_Date.disksize);
      if (rc == NO_ERROR)
    {
      rc = or_get_data (buf, (char *) (&datetimetz.datetime.time), tp_Time.disksize);
      if (rc == NO_ERROR)
        {
          rc = or_get_data (buf, (char *) (&datetimetz.tz_id), tp_Integer.disksize);
        }
    }

      if (rc == NO_ERROR)
    {
      db_make_datetimetz (value, &datetimetz);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_datetimetz (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order,
                 int *start_colp)
{
  /* DATETIMETZ compares the same as DATETIME (tz_id is ignored) */
  return mr_index_cmpdisk_datetime (mem1, mem2, domain, do_coercion, total_order, start_colp);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_datetimetz (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order,
                int *start_colp)
{
  /* DATETIMETZ compares the same as DATETIME (tz_id is ignored) */
  return mr_data_cmpdisk_datetime (mem1, mem2, domain, do_coercion, total_order, start_colp);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_datetimetz (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
              int collation)
{
  const DB_DATETIMETZ *dt_tz1, *dt_tz2;
  const DB_DATETIME *dt1, *dt2;
  DB_VALUE_COMPARE_RESULT c;

  dt_tz1 = db_get_datetimetz (value1);
  dt_tz2 = db_get_datetimetz (value2);

  dt1 = &(dt_tz1->datetime);
  dt2 = &(dt_tz2->datetime);

#if defined (SA_MODE)
  if (tz_Compare_datetimetz_tz_id == true && dt_tz1->tz_id != dt_tz2->tz_id)
    {
      return DB_NE;
    }
#endif /* SA_MODE */

  if (dt1->date < dt2->date)
    {
      c = DB_LT;
    }
  else if (dt1->date > dt2->date)
    {
      c = DB_GT;
    }
  else
    {
      if (dt1->time < dt2->time)
    {
      c = DB_LT;
    }
      else if (dt1->time > dt2->time)
    {
      c = DB_GT;
    }
      else
    {
      c = DB_EQ;
    }
    }

  return c;
}

/*
 * TYPE MONETARY
 *
 * Practically useless combination of an IEEE double with a currency tag.
 * Should consider re-implementing this using fixed precision numerics
 * now that we have them.
 * Because of double allignment problems, never access the amount field
 * with a structure dereference.
 */

static void
mr_initmem_money (void *memptr, TP_DOMAIN * domain)
{
  DB_MONETARY *mem = (DB_MONETARY *) memptr;

  double d = 0.0;

  mem->type = DB_CURRENCY_DEFAULT;
  OR_MOVE_DOUBLE (&d, &mem->amount);
}

static int
mr_setmem_money (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  DB_MONETARY *mem = (DB_MONETARY *) memptr;
  DB_MONETARY *money;

  if (value == NULL)
    {
      mr_initmem_money (mem, domain);
    }
  else
    {
      money = db_get_monetary (value);
      mem->type = money->type;
      OR_MOVE_DOUBLE (&money->amount, &mem->amount);
    }
  return NO_ERROR;
}

static int
mr_getmem_money (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int error = NO_ERROR;
  DB_MONETARY *mem = (DB_MONETARY *) memptr;
  double amt = 0;

  OR_MOVE_DOUBLE (&mem->amount, &amt);
  error = db_make_monetary (value, mem->type, amt);
  value->need_clear = false;
  return error;
}

static void
mr_data_writemem_money (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_monetary (buf, (DB_MONETARY *) mem);
}

static void
mr_data_readmem_money (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  if (mem == NULL)
    {
      or_advance (buf, tp_Monetary.disksize);
    }
  else
    {
      or_get_monetary (buf, (DB_MONETARY *) mem);
    }
}

static void
mr_initval_money (DB_VALUE * value, int precision, int scale)
{
  db_make_monetary (value, DB_CURRENCY_DEFAULT, 0.0);
  value->need_clear = false;
}

static int
mr_setval_money (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error;
  DB_MONETARY *money;

  if (DB_IS_NULL (src) || ((money = db_get_monetary (src)) == NULL))
    {
      error = db_value_domain_init (dest, DB_TYPE_MONETARY, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  else
    {
      error = db_make_monetary (dest, money->type, money->amount);
    }
  return error;
}

static int
mr_data_writeval_money (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_monetary (buf, db_get_monetary (value));
}

static int
mr_data_readval_money (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
               int copy_buf_len)
{
  DB_MONETARY money;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Monetary.disksize);
    }
  else
    {
      rc = or_get_monetary (buf, &money);
      if (rc == NO_ERROR)
    {
      db_make_monetary (value, money.type, money.amount);
    }
      value->need_clear = false;
    }
  return rc;
}

static int
mr_index_writeval_money (OR_BUF * buf, DB_VALUE * value)
{
  DB_MONETARY *money;
  int rc = NO_ERROR;

  money = db_get_monetary (value);

  rc = or_put_data (buf, (char *) (&money->type), tp_Integer.disksize);
  if (rc == NO_ERROR)
    {
      rc = or_put_data (buf, (char *) (&money->amount), tp_Double.disksize);
    }

  return rc;
}

static int
mr_index_readval_money (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
            int copy_buf_len)
{
  DB_MONETARY money;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Monetary.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&money.type), tp_Integer.disksize);
      if (rc == NO_ERROR)
    {
      rc = or_get_data (buf, (char *) (&money.amount), tp_Double.disksize);
    }

      if (rc == NO_ERROR)
    {
      db_make_monetary (value, money.type, money.amount);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_money (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_MONETARY m1, m2;

  assert (domain != NULL);

  COPYMEM (double, &m1.amount, (char *) mem1 + tp_Integer.disksize);
  COPYMEM (double, &m2.amount, (char *) mem2 + tp_Integer.disksize);

  return MR_CMP (m1.amount, m2.amount);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_money (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_MONETARY m1, m2;

  assert (domain != NULL);

  OR_GET_MONETARY (mem1, &m1);
  OR_GET_MONETARY (mem2, &m2);

  return MR_CMP (m1.amount, m2.amount);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_money (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  const DB_MONETARY *m1, *m2;

  m1 = db_get_monetary (value1);
  m2 = db_get_monetary (value2);

  return MR_CMP (m1->amount, m2->amount);
}

/*
 * TYPE DATE
 *
 * 32 bit day counter, commonly called a "julian" date.
 */

static void
mr_initmem_date (void *mem, TP_DOMAIN * domain)
{
  *(DB_DATE *) mem = 0;
}

static int
mr_setmem_date (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value == NULL)
    mr_initmem_date (mem, domain);
  else
    *(DB_DATE *) mem = *db_get_date (value);

  return NO_ERROR;
}

static int
mr_getmem_date (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return db_value_put_encoded_date (value, (DB_DATE *) mem);
}

static void
mr_data_writemem_date (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_date (buf, (DB_DATE *) mem);
}

static void
mr_data_readmem_date (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  if (mem == NULL)
    {
      or_advance (buf, tp_Date.disksize);
    }
  else
    {
      or_get_date (buf, (DB_DATE *) mem);
    }
}

static void
mr_initval_date (DB_VALUE * value, int precision, int scale)
{
  db_value_put_encoded_date (value, 0);
  value->need_clear = false;
}

static int
mr_setval_date (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error;

  if (DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_DATE, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  else
    {
      error = db_value_put_encoded_date (dest, db_get_date (src));
    }
  return error;
}

static int
mr_data_writeval_date (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_date (buf, db_get_date (value));
}

static int
mr_data_readval_date (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  DB_DATE dt;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Date.disksize);
    }
  else
    {
      rc = or_get_date (buf, &dt);
      if (rc == NO_ERROR)
    {
      db_value_put_encoded_date (value, &dt);
    }
      value->need_clear = false;
    }
  return rc;
}

static int
mr_index_writeval_date (OR_BUF * buf, DB_VALUE * value)
{
  DB_DATE *dt;

  dt = db_get_date (value);

  return or_put_data (buf, (char *) dt, tp_Date.disksize);
}

static int
mr_index_readval_date (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
               int copy_buf_len)
{
  DB_DATE dt;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Date.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&dt), tp_Date.disksize);
      if (rc == NO_ERROR)
    {
      db_value_put_encoded_date (value, &dt);
    }
      value->need_clear = false;
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_date (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_DATE d1, d2;

  assert (domain != NULL);

  COPYMEM (DB_DATE, &d1, mem1);
  COPYMEM (DB_DATE, &d2, mem2);

  return MR_CMP (d1, d2);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_date (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_DATE d1, d2;

  assert (domain != NULL);

  OR_GET_DATE (mem1, &d1);
  OR_GET_DATE (mem2, &d2);

  return MR_CMP (d1, d2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_date (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  const DB_DATE *d1, *d2;

  d1 = db_get_date (value1);
  d2 = db_get_date (value2);

  return MR_CMP (*d1, *d2);
}

/*
 * TYPE OBJECT
 */

/*
 * This is a bit different than the other primitive types in that the memory
 * value and the DB_VALUE representations are not the same.  The memory value
 * will be represented with a WS_MEMOID structure to avoid creating MOPs until
 * they are actually needed.
 *
 * These types are not available on the server since there is no workspace
 * over there.  Although in standalone mode, we could promote OIDs to MOPs
 * on both sides, use the db_on_server flag to control this so we make
 * both sides behave similarly even though we're in standalone mode.
 * The "mem" functions will in general be commented out since they
 * call things that don't exist on the server.  THe "val" functions will
 * exist so that things tagged as DB_TYPE_OBJECT can be read as OID values.
 *
 */


/*
 * mr_null_oid - This is used to set an OID to the NULL state.
 *    return:  void
 *    oid(out): oid to initialize
 * Note:
 *    SET_OID_NULL does the actual work by setting the volid to -1 but it
 *    leaves garbage in the other fields which can be stored on disk and
 *    generally looks alarming when you encounter it later.  Before
 *    calling SET_OID_NULL, initialize the fields to nice zero values.
 *    Should be an inline function.
 */
static void
mr_null_oid (OID * oid)
{
  oid->pageid = 0;
  oid->volid = 0;
  oid->slotid = 0;

  OID_SET_NULL (oid);
}

static void
mr_initmem_object (void *memptr, TP_DOMAIN * domain)
{
  /* there is no use for initmem on the server */
#if !defined (SERVER_MODE)
  WS_MEMOID *mem = (WS_MEMOID *) memptr;

  mr_null_oid (&mem->oid);
  mem->pointer = NULL;
#endif
}

/*
 * Can get here on the server when dispatching from set element domains.
 * Always represent object values as OIDs on the server.
 */

static void
mr_initval_object (DB_VALUE * value, int precision, int scale)
{
  OID oid;

#if !defined (SERVER_MODE)
  if (db_on_server)
    {
      db_value_domain_init (value, DB_TYPE_OID, precision, scale);
      OID_SET_NULL (&oid);
      db_make_oid (value, &oid);
    }
  else
    {
      db_value_domain_init (value, DB_TYPE_OBJECT, precision, scale);
      db_make_object (value, NULL);
    }
#else /* SERVER_MODE */
  db_value_domain_init (value, DB_TYPE_OID, precision, scale);
  OID_SET_NULL (&oid);
  db_make_oid (value, &oid);
#endif /* !SERVER_MODE */
}

static int
mr_setmem_object (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  /* there is no need for setmem on the server */
#if !defined (SERVER_MODE)
  WS_MEMOID *mem = (WS_MEMOID *) memptr;
  OID *oid;
  MOP op;

  if (value == NULL)
    {
      mr_null_oid (&mem->oid);
      mem->pointer = NULL;
    }
  else
    {
      op = db_get_object (value);
      if (op == NULL)
    {
      mr_initmem_object (mem, domain);
    }
      else
    {
      oid = WS_OID (op);
      mem->oid.volid = oid->volid;
      mem->oid.pageid = oid->pageid;
      mem->oid.slotid = oid->slotid;
      if (op->is_temp)
        {
          mem->pointer = NULL;
        }
      else
        {
          mem->pointer = op;
        }
    }
    }
#endif /* !SERVER_MODE */
  return NO_ERROR;
}

static int
mr_getmem_object (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int error = NO_ERROR;

  /* there is no need for getmem on the server */
#if !defined (SERVER_MODE)
  WS_MEMOID *mem = (WS_MEMOID *) memptr;
  MOP op;

  op = mem->pointer;
  if (op == NULL)
    {
      if (!OID_ISNULL (&mem->oid))
    {
      op = ws_mop (&mem->oid, NULL);
      if (op != NULL)
        {
          mem->pointer = op;
          error = db_make_object (value, op);
        }
      else
        {
          assert (er_errid () != NO_ERROR);
          error = er_errid ();
          (void) db_make_object (value, NULL);
        }
    }
    }
  else
    error = db_make_object (value, op);
#endif /* !SERVER_MODE */

  return error;
}


static int
mr_setval_object (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error = NO_ERROR;
  OID *oid;

#if !defined (SERVER_MODE)
  if (DB_IS_NULL (src))
    {
      db_make_null (dest);
    }
  /* can get here on the server when dispatching through set element domains */
  else if (DB_VALUE_TYPE (src) == DB_TYPE_OID)
    {
      /* make sure that the target type is set properly */
      db_value_domain_init (dest, DB_TYPE_OID, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
      oid = (OID *) db_get_oid (src);
      error = db_make_oid (dest, oid);
    }
  else if (DB_VALUE_TYPE (src) == DB_TYPE_OBJECT)
    {
      /* If we're logically on the server, we probably shouldn't have gotten here but if we do, don't continue with the
       * object representation, de-swizzle it back to an OID. */
      if (db_on_server)
    {
      DB_OBJECT *obj;
      /* what should this do for ISVID mops? */
      obj = db_get_object (src);
      db_value_domain_init (dest, DB_TYPE_OID, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
      oid = WS_OID (obj);
      error = db_make_oid (dest, oid);
    }
      else
    {
      db_value_domain_init (dest, DB_TYPE_OBJECT, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
      error = db_make_object (dest, db_get_object (src));
    }
    }
#else /* SERVER_MODE */
  /*
   * If we're really on the server, we can only get here when dispatching
   * through set element domains.  The value must contain an OID.
   */
  if (DB_IS_NULL (src) || DB_VALUE_TYPE (src) != DB_TYPE_OID)
    {
      db_make_null (dest);
    }
  else
    {
      oid = (OID *) db_get_oid (src);
      error = db_make_oid (dest, oid);
    }
#endif /* !SERVER_MODE */

  return error;
}



static int
mr_index_lengthval_object (DB_VALUE * value)
{
  return tp_Oid.disksize;
}

/*
 * mr_lengthval_object - checks if the object is virtual or not. and returns
 * property type size.
 *    return: If it is virtual object returns calculated the DB_TYPE_VOBJ
 *    packed size. returns DB_TYPE_OID otherwise
 *    value(in): value to get length
 *    disk(in): indicator that it is disk object
 */
static int
mr_data_lengthval_object (DB_VALUE * value, int disk)
{
#if !defined (SERVER_MODE)
  MOP mop;
#endif
  int size;

  if (disk)
    {
      size = OR_OID_SIZE;
    }
  else
    {
      size = MR_OID_SIZE;
    }

#if !defined (SERVER_MODE)
  if (DB_VALUE_TYPE (value) == DB_TYPE_OBJECT && disk)
    {
      mop = db_get_object (value);
      if ((mop == NULL) || (WS_IS_DELETED (mop)))
    {
      /* The size of a NULL is OR_OID_SIZE, which is already set (from Jeff L.) */
    }
      else if (WS_ISVID (mop))
    {
      DB_VALUE vmop_seq;
      int error;

      error = vid_object_to_vobj (mop, &vmop_seq);
      if (error >= 0)
        {
          size = mr_data_lengthval_set (&vmop_seq, disk);
          pr_clear_value (&vmop_seq);
        }
    }
    }
#endif

  return size;
}

static void
mr_data_writemem_object (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
#if !defined (SERVER_MODE)  /* there is no need for writemem on the server */
  WS_MEMOID *mem = (WS_MEMOID *) memptr;
  OID *oidp;

  oidp = NULL;
  if (mem != NULL)
    {
      oidp = &mem->oid;
    }

  if (oidp == NULL)
    {
      /* construct an unbound oid */
      oidp = (OID *) (&oid_Null_oid);
    }
  else if (OID_ISTEMP (oidp))
    {
      /* Temporary oid, must get a permanent one. This should only happen if the MOID has a valid MOP. Check for
       * deletion */
      if ((mem->pointer == NULL) || (WS_IS_DELETED (mem->pointer)))
    {
      oidp = (OID *) (&oid_Null_oid);
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_MR_TEMP_OID_WITHOUT_MOP, 0);
    }
      else
    {
      oidp = WS_OID (mem->pointer);
      if (OID_ISTEMP (oidp))
        {
          /* a MOP with a temporary OID, make an entry in the OID fixup table if we have one, otherwise, stop and
           * assign a permanent one. */
          oidp = tf_need_permanent_oid (buf, mem->pointer);
          if (oidp == NULL)
        {
          /* normally would have used or_abort by now */
          oidp = (OID *) (&oid_Null_oid);
        }
        }
    }
    }
  else
    {
      /* normal OID check for deletion */
      if ((mem->pointer != NULL) && (WS_IS_DELETED (mem->pointer)))
    {
      oidp = (OID *) (&oid_Null_oid);
    }
    }

  or_put_oid (buf, oidp);

#else /* SERVER_MODE */
  /* should never get here but in case we do, dump a NULL OID into the buffer. */
  printf ("mr_writemem_object: called on the server !\n");
  or_put_oid (buf, (OID *) (&oid_Null_oid));
#endif /* !SERVER_MODE */
}


static void
mr_data_readmem_object (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size)
{
#if !defined (SERVER_MODE)  /* there is no need for readmem on the server ??? */
  WS_MEMOID *mem = (WS_MEMOID *) memptr;

  if (mem != NULL)
    {
      or_get_oid (buf, &mem->oid);
      mem->pointer = NULL;
    }
  else
    {
      or_advance (buf, tp_Object.disksize);
    }
#else
  /* shouldn't get here but if we do, just skip over it */
  printf ("mr_readmem_object: called on the server !\n");
  or_advance (buf, tp_Object.disksize);
#endif

}

static int
mr_index_writeval_object (OR_BUF * buf, DB_VALUE * value)
{
  return mr_index_writeval_oid (buf, value);
}

static int
mr_data_writeval_object (OR_BUF * buf, DB_VALUE * value)
{
#if !defined (SERVER_MODE)
  MOP mop;
#endif
  OID *oidp = NULL;
  int rc = NO_ERROR;

#if !defined (SERVER_MODE)
  if (db_on_server || pr_Inhibit_oid_promotion)
    {
      if (DB_VALUE_TYPE (value) == DB_TYPE_OID)
    {
      oidp = db_get_oid (value);
      rc = or_put_oid (buf, oidp);
      return rc;
    }
      else
    {
      return ER_FAILED;
    }
    }
  if (DB_VALUE_TYPE (value) == DB_TYPE_OBJECT)
    {
      mop = db_get_object (value);
      if ((mop == NULL) || (WS_IS_DELETED (mop)))
    {
      rc = or_put_oid (buf, (OID *) (&oid_Null_oid));
    }
      else if (WS_ISVID (mop))
    {
      DB_VALUE vmop_seq;
      int error;

      error = vid_object_to_vobj (mop, &vmop_seq);
      if (error >= 0)
        {
          rc = mr_data_writeval_set (buf, &vmop_seq);
          pr_clear_value (&vmop_seq);
        }
      else
        {
          rc = ER_FAILED;
        }
    }
      else
    {
      oidp = WS_OID (mop);
      if (OID_ISTEMP (oidp))
        {
          /* a MOP with a temporary OID, make an entry in the OID fixup table if we have one, otherwise, stop and
           * assign a permanent one. */
          oidp = tf_need_permanent_oid (buf, mop);
          if (oidp == NULL)
        {
          /* normally would have used or_abort by now */
          oidp = (OID *) (&oid_Null_oid);
        }
        }
      rc = or_put_oid (buf, oidp);
    }
    }
  else if (DB_VALUE_TYPE (value) == DB_TYPE_OID)
    {
      oidp = db_get_oid (value);
      rc = or_put_oid (buf, oidp);
    }
  else
    {
      /* should never get here ! */
      rc = or_put_oid (buf, (OID *) (&oid_Null_oid));
    }
#else /* SERVER_MODE */
  /* on the server, the value must contain an OID */
  oidp = db_get_oid (value);
  rc = or_put_oid (buf, oidp);
#endif /* !SERVER_MODE */
  return rc;
}



static int
mr_index_readval_object (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  return mr_index_readval_oid (buf, value, domain, size, copy, copy_buf, copy_buf_len);
}

static int
mr_data_readval_object (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
            int copy_buf_len)
{
  OID oid;
  int rc = NO_ERROR;

#if !defined (SERVER_MODE)
  if (value == NULL)
    {
      rc = or_advance (buf, tp_Object.disksize);
    }
  else
    {
      if (db_on_server || pr_Inhibit_oid_promotion)
    {
      /* basically the same as mr_readval_server_oid, don't promote OIDs */
      db_value_domain_init (value, DB_TYPE_OID, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
      rc = or_get_oid (buf, &oid);
      db_make_oid (value, &oid);
    }
      else
    {
      db_value_domain_init (value, DB_TYPE_OBJECT, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);

      rc = or_get_oid (buf, &oid);
      /*
       * if the OID is NULL, leave the value with the NULL bit set
       * and don't bother to put the OID inside.
       * I added this because it seemed logical, does it break anything ?
       */
      if (!OID_ISNULL (&oid))
        {
          db_make_object (value, ws_mop (&oid, NULL));
          if (db_get_object (value) == NULL)
        {
          return ER_FAILED;
        }
        }
    }
    }
#else /* SERVER_MODE */
  /* on the server, we only read OIDs */
  if (value == NULL)
    {
      rc = or_advance (buf, tp_Object.disksize);
    }
  else
    {
      db_value_domain_init (value, DB_TYPE_OID, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
      rc = or_get_oid (buf, &oid);
      /* should we be checking for the NULL OID here ? */
      db_make_oid (value, &oid);
    }
#endif /* !SERVER_MODE */
  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_object (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return mr_index_cmpdisk_oid (mem1, mem2, domain, do_coercion, total_order, start_colp);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_object (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  OID o1, o2;
  int oidc;

  assert (domain != NULL);

  OR_GET_OID (mem1, &o1);
  OR_GET_OID (mem2, &o2);
  /* if we ever store virtual objects, this will need to be changed. However, since its known the only disk
   * representation of objects is an OID, this is a valid optimization */

  oidc = oid_compare (&o1, &o2);
  return MR_CMP_RETURN_CODE (oidc);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_object (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
          int collation)
{
#if defined (SERVER_MODE)
  const OID *o1, *o2;
  int oidc;

  /*
   * we need to be careful here because even though the domain may
   * say object, it may really be an OID (especially on the server).
   */
  if (DB_VALUE_DOMAIN_TYPE (value1) == DB_TYPE_OID)
    {
      o1 = db_get_oid (value1);
    }
  else
    {
      assert (false);
      o1 = &oid_Null_oid;
    }

  if (DB_VALUE_DOMAIN_TYPE (value2) == DB_TYPE_OID)
    {
      o2 = db_get_oid (value2);
    }
  else
    {
      assert (false);
      o2 = &oid_Null_oid;
    }

  oidc = oid_compare (o1, o2);
  return MR_CMP_RETURN_CODE (oidc);
#else /* !SERVER_MODE */
  /* on the client, we must also handle virtual db_object types */
  DB_VALUE_COMPARE_RESULT c;
  OID *o1 = NULL, *o2 = NULL;
  DB_OBJECT *mop1 = NULL, *mop2 = NULL, *class1, *class2;
  int virtual_ = 0;
  int nonupdate = 0;
  DB_VALUE keys1, keys2;

  /*
   * we need to be careful here because even though the domain may
   * say object, it may really be an OID (especially on the server).
   */
  if (DB_VALUE_DOMAIN_TYPE (value1) == DB_TYPE_OID)
    {
      o1 = db_get_oid (value1);
    }
  else
    {
      mop1 = db_get_object (value1);
      if (WS_ISVID (mop1))
    {
      if (db_is_updatable_object (mop1))
        {
          mop1 = db_real_instance (mop1);
        }
      else
        {
          nonupdate = 1;
        }

      if (mop1 != NULL)
        {
          if (WS_ISVID (mop1))
        {
          /* non updateble object or proxy object */
          virtual_ = 1;
        }
          else
        {
          o1 = WS_OID (mop1);
        }
        }
      else
        {
          o1 = (OID *) (&oid_Null_oid);
        }
    }
      else
    {
      o1 = WS_OID (mop1);
    }
    }

  if (DB_VALUE_DOMAIN_TYPE (value2) == DB_TYPE_OID)
    {
      o2 = db_get_oid (value2);
    }
  else
    {
      mop2 = db_get_object (value2);
      if (WS_ISVID (mop2))
    {
      if (db_is_updatable_object (mop2))
        {
          mop2 = db_real_instance (mop2);
        }
      else
        {
          nonupdate += 2;
        }

      if (mop2 != NULL)
        {
          if (WS_ISVID (mop2))
        {
          /* non updateble object or proxy object */
          virtual_ += 2;
        }
          else
        {
          o2 = WS_OID (mop2);
        }
        }
      else
        {
          o2 = (OID *) (&oid_Null_oid);
        }
    }
      else
    {
      o2 = WS_OID (mop2);
    }
    }

  if (virtual_ == 0)
    {
      int oidc = oid_compare (o1, o2);
      return MR_CMP_RETURN_CODE (oidc);
    }

  if (mop1 == mop2)
    {
      return DB_EQ;     /* an optimization */
    }

  if (virtual_ == 1)
    {
      return DB_LT;     /* consistent comparison of oids and */
    }
  if (virtual_ == 2)
    {
      return DB_GT;     /* non-oid based vobjs, they are never equal */
    }

  /* virtual must be 3, meaning both objects are either proxies or non-updatable objects */

  if (nonupdate == 1)
    {
      return DB_LT;     /* again, a consistent comparison */
    }

  if (nonupdate == 2)
    {
      return DB_GT;     /* for proxy mop and non-updatable mop */
    }

  if (nonupdate == 0)
    {
      int oidc;
      /*
       * comparing two proxy mops, the must both be from the
       * same proxy class. Compare the proxy classes oids.
       * Note class mops are never virtual mops.
       */
      class1 = db_get_class (mop1);
      class2 = db_get_class (mop2);
      o1 = (class1) ? WS_OID (class1) : (OID *) (&oid_Null_oid);
      o2 = (class2) ? WS_OID (class2) : (OID *) (&oid_Null_oid);
      oidc = oid_compare (o1, o2);
      c = MR_CMP_RETURN_CODE (oidc);

      /*
       * as long as the result is not equal, we are done
       * If its equal, we need to continue with a key test below.
       */
      if (c != DB_EQ)
    {
      return c;
    }
    }

  /*
   * here, nonupdate must be 3 or 0 and
   * we must have two non-updatable mops, or two proxy mops
   * from the same proxy. Consequently, their keys are comparable
   * to identify the object.
   */
  vid_get_keys (mop1, &keys1);
  vid_get_keys (mop2, &keys2);
  return tp_value_compare (&keys1, &keys2, do_coercion, total_order);
#endif /* SERVER_MODE */
}




#if !defined (SERVER_MODE)


#endif /* !SERVER_MODE */

static void
mr_initmem_elo (void *memptr, TP_DOMAIN * domain)
{
  if (memptr != NULL)
    {
      *((DB_ELO **) memptr) = NULL;
    }
}

static void
mr_initval_elo (DB_VALUE * value, int precision, int scale)
{
  /* should not be called */
  assert (0);
}

static void
mr_initval_blob (DB_VALUE * value, int precision, int scale)
{
  DB_ELO *null_elo = NULL;
  db_value_domain_init (value, DB_TYPE_BLOB, precision, scale);
  db_make_elo (value, DB_TYPE_BLOB, null_elo);
}

static void
mr_initval_clob (DB_VALUE * value, int precision, int scale)
{
  DB_ELO *null_elo = NULL;
  db_value_domain_init (value, DB_TYPE_CLOB, precision, scale);
  db_make_elo (value, DB_TYPE_CLOB, null_elo);
}

static int
mr_setmem_elo (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  int rc;
  DB_ELO *elo, *e;

  if (memptr != NULL)
    {
      mr_freemem_elo (memptr);
      mr_initmem_elo (memptr, domain);

      if (value != NULL && (e = db_get_elo (value)) != NULL)
    {
      elo = (DB_ELO *) db_private_alloc (NULL, sizeof (DB_ELO));
      if (elo == NULL)
        {
          return ((er_errid () == NO_ERROR) ? ER_FAILED : er_errid ());
        }
      rc = elo_copy_structure (e, elo);
      if (rc != NO_ERROR)
        {
          if (elo != NULL)
        {
          db_private_free_and_init (NULL, elo);
        }
          return rc;
        }

      *((DB_ELO **) memptr) = elo;
    }
    }
  else
    {
      assert_release (0);
    }

  return NO_ERROR;
}

static int
getmem_elo_with_type (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy, DB_TYPE type)
{
  DB_ELO *elo;
  int r = NO_ERROR;

  if (memptr == NULL)
    {
      db_make_null (value);
      return r;
    }

  elo = *((DB_ELO **) memptr);

  if (elo == NULL || elo->size < 0)
    {
      db_make_null (value);
      return r;
    }

  if (copy)
    {
      DB_ELO e;

      r = elo_copy_structure (elo, &e);
      if (r == NO_ERROR)
    {
      db_make_elo (value, type, &e);
      value->need_clear = true;
    }
    }
  else
    {
      db_make_elo (value, type, elo);
    }

  return r;
}

static int
mr_getmem_elo (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  /* should not happen */
  assert (0);
  return ER_FAILED;
}

static int
mr_getmem_blob (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return getmem_elo_with_type (memptr, domain, value, copy, DB_TYPE_BLOB);
}

static int
mr_getmem_clob (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return getmem_elo_with_type (memptr, domain, value, copy, DB_TYPE_CLOB);
}

static int
setval_elo_with_type (DB_VALUE * dest, const DB_VALUE * src, bool copy, DB_TYPE type)
{
  int r = NO_ERROR;

  if (DB_IS_NULL (src) || db_get_elo (src) == NULL)
    {
      db_make_null (dest);
      return NO_ERROR;
    }

  if (copy)
    {
      DB_ELO elo;
      DB_ELO *e = db_get_elo (src);

      r = elo_copy_structure (e, &elo);
      if (r == NO_ERROR)
    {
      db_make_elo (dest, type, &elo);
      dest->need_clear = true;
    }
    }
  else
    {
      db_make_elo (dest, type, db_get_elo (src));
    }

  return r;
}

static int
mr_setval_elo (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  assert (0);
  return ER_FAILED;
}

static int
mr_setval_blob (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  return setval_elo_with_type (dest, src, copy, DB_TYPE_BLOB);
}

static int
mr_setval_clob (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  return setval_elo_with_type (dest, src, copy, DB_TYPE_CLOB);
}

static int
mr_data_lengthmem_elo (void *memptr, TP_DOMAIN * domain, int disk)
{
  int len = 0;

  if (!disk)
    {
      assert (tp_Elo.size == tp_Blob.size);
      assert (tp_Blob.size == tp_Clob.size);
      len = tp_Elo.size;
    }
  else if (memptr != NULL)
    {
      DB_ELO *elo = *((DB_ELO **) memptr);

      if (elo != NULL && elo->type != ELO_NULL)
    {
      len = (OR_BIGINT_SIZE
         + or_packed_string_length (elo->locator, NULL)
         + or_packed_string_length (elo->meta_data, NULL) + OR_INT_SIZE);
    }
    }
  else
    {
      assert_release (0);
    }

  return len;
}

static int
mr_data_lengthval_elo (DB_VALUE * value, int disk)
{
  DB_ELO *elo;

  if (value != NULL)
    {
      elo = db_get_elo (value);
      return mr_data_lengthmem_elo ((void *) &elo, NULL, disk);
    }
  else
    {
      return 0;
    }
}

static void
mr_data_writemem_elo (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
  DB_ELO *elo;

  if (memptr == NULL)
    {
      assert_release (0);
      return;
    }

  elo = *((DB_ELO **) memptr);

  if (elo != NULL && elo->type != ELO_NULL)
    {
      /* size */
      or_put_bigint (buf, elo->size);

      /* locator */
      assert (elo->locator != NULL);
      or_put_int (buf, or_packed_string_length (elo->locator, NULL) - OR_INT_SIZE);
      if (elo->locator != NULL)
    {
      or_put_string_aligned (buf, elo->locator);
    }

      /* meta_data */
      or_put_int (buf, or_packed_string_length (elo->meta_data, NULL) - OR_INT_SIZE);
      if (elo->meta_data != NULL)
    {
      or_put_string_aligned (buf, elo->meta_data);
    }

      /* type */
      or_put_int (buf, elo->type);
    }
}

static void
peekmem_elo (OR_BUF * buf, DB_ELO * elo)
{
  int locator_len, meta_data_len;
  int rc = NO_ERROR;

  /* size */
  elo->size = or_get_bigint (buf, &rc);

  if (rc != NO_ERROR)
    {
      assert (false);
      goto error;
    }

  /* locator */
  locator_len = or_get_int (buf, &rc);
  if (rc != NO_ERROR)
    {
      assert (false);
      goto error;
    }
  if (locator_len > 0)
    {
      elo->locator = buf->ptr;
    }
  else
    {
      assert (false);
      goto error;
    }
  rc = or_advance (buf, locator_len);
  if (rc != NO_ERROR)
    {
      assert (false);
      goto error;
    }

  /* meta_data */
  meta_data_len = or_get_int (buf, &rc);
  if (rc != NO_ERROR)
    {
      assert (false);
      goto error;
    }
  if (meta_data_len > 0)
    {
      elo->meta_data = buf->ptr;
    }
  else
    {
      elo->meta_data = NULL;
    }
  rc = or_advance (buf, meta_data_len);
  if (rc != NO_ERROR)
    {
      assert (false);
      goto error;
    }

  /* type */
  elo->type = (DB_ELO_TYPE) or_get_int (buf, &rc);
  if (rc != NO_ERROR)
    {
      assert (false);
      goto error;
    }

  return;

error:
  elo->locator = NULL;
  elo->meta_data = NULL;
  elo->size = 0;
  elo->type = ELO_NULL;
}

static void
mr_data_readmem_elo (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size)
{
  DB_ELO *elo;
  DB_ELO e;
  int rc = NO_ERROR;

  if (size == 0)
    {
      return;
    }

  if (memptr == NULL)
    {
      or_advance (buf, size);
      return;
    }

  elo = (DB_ELO *) db_private_alloc (NULL, sizeof (DB_ELO));
  if (elo == NULL)
    {
      ASSERT_ERROR ();
      return;
    }
  else
    {
      peekmem_elo (buf, &e);

      rc = elo_copy_structure (&e, elo);
      if (rc != NO_ERROR)
    {
      db_private_free_and_init (NULL, elo);
      return;
    }
    }

  *((DB_ELO **) memptr) = elo;
}

static int
mr_data_writeval_elo (OR_BUF * buf, DB_VALUE * value)
{
  DB_ELO *elo;

  elo = db_get_elo (value);
  mr_data_writemem_elo (buf, (void *) &elo, NULL);
  return NO_ERROR;
}

static int
readval_elo_with_type (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
               int copy_buf_len, DB_TYPE type)
{
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, size);
      return rc;
    }

  if (size != 0)
    {
      if (copy)
    {
      DB_ELO *e = NULL;

      mr_data_readmem_elo (buf, (void *) &e, NULL, size);
      /* structure copy - to value->data.elo */
      rc = db_make_elo (value, type, e);
      if (e != NULL)
        {
          db_private_free_and_init (NULL, e);
        }

      value->need_clear = true;
    }
      else
    {
      DB_ELO elo;

      peekmem_elo (buf, &elo);
      /* structure copy - to value->data.elo */
      rc = db_make_elo (value, type, &elo);
    }
    }

  return rc;
}

static int
mr_data_readval_elo (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  /* should not happen */
  assert (0);
  return ER_FAILED;
}

static int
mr_data_readval_blob (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  return readval_elo_with_type (buf, value, domain, size, copy, copy_buf, copy_buf_len, DB_TYPE_BLOB);
}

static int
mr_data_readval_clob (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  return readval_elo_with_type (buf, value, domain, size, copy, copy_buf, copy_buf_len, DB_TYPE_CLOB);
}

static void
mr_freemem_elo (void *memptr)
{
  DB_ELO *elo;

  if (memptr != NULL)
    {
      elo = *((DB_ELO **) memptr);

      if (elo != NULL)
    {
      elo_free_structure (elo);
      db_private_free_and_init (NULL, elo);
    }
    }
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_elo (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  /*
   * don't know how to do this since elo's should find their way into
   * listfiles and such.
   */
  return DB_UNK;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_elo (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  DB_ELO *elo1, *elo2;

  elo1 = db_get_elo (value1);
  elo2 = db_get_elo (value2);

  /* use address for collating sequence */
  return MR_CMP ((UINTPTR) elo1, (UINTPTR) elo2);
}

/*
 * TYPE VARIABLE
 *
 * Currently this can only be used internally for class objects.  I think
 * this is useful enough to make a general purpose thing.
 * Implemented with the DB_VALUE (like set elements) which means that we
 * will always create MOPs for variable values that are object references.
 * If this gets to be a big deal, will need to define another union
 * like DB_MEMORY_VALUE that has a local OID cache like the attribute
 * values do.
 * These were once just stubs that didn't do anything since the class
 * transformer called the pr_write_va/rtype etc. functions directly.  If
 * they can be regular types for object attributes, we need to support
 * an mr_ interface as well.
 *
 * NOTE: These are still stubs, need to think about other ramifications
 * in the schema level before making these public.
 */

static void
mr_initval_variable (DB_VALUE * value, int precision, int scale)
{
  mr_initval_null (value, precision, scale);
}

static int
mr_setval_variable (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  mr_initval_null (dest, 0, 0);
  return NO_ERROR;
}

static int
mr_data_lengthval_variable (DB_VALUE * value, int disk)
{
  return 0;
}

static int
mr_data_writeval_variable (OR_BUF * buf, DB_VALUE * value)
{
  return NO_ERROR;
}

static int
mr_data_readval_variable (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  return NO_ERROR;
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_variable (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return DB_UNK;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_variable (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
            int collation)
{
  return DB_UNK;
}

/*
 * TYPE SUBSTRUCTURE
 *
 * Only for meta objects.  Might want to extend.
 * This really only serves as a placeholder in the type table.  These
 * functions should never be referenced through the usual channels.
 */

static void
mr_initmem_sub (void *mem, TP_DOMAIN * domain)
{
}

static void
mr_initval_sub (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_SUB, precision, scale);
}

static int
mr_setmem_sub (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  return NO_ERROR;
}

static int
mr_getmem_sub (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return NO_ERROR;
}

static int
mr_setval_sub (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  return NO_ERROR;
}

static int
mr_data_lengthmem_sub (void *mem, TP_DOMAIN * domain, int disk)
{
  return 0;
}

static int
mr_data_lengthval_sub (DB_VALUE * value, int disk)
{
  return 0;
}

static void
mr_data_writemem_sub (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
}

static void
mr_data_readmem_sub (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
}

static int
mr_data_writeval_sub (OR_BUF * buf, DB_VALUE * value)
{
  return NO_ERROR;
}

static int
mr_data_readval_sub (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  return NO_ERROR;
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_sub (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return DB_UNK;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_sub (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  return DB_UNK;
}

/*
 * TYPE POINTER
 *
 * These exist only so that method arguments can have arbitrary pointer
 * values.  You cannot create an attribute that has a pointer value since
 * these are not persistent values.  Pointer values are used internally
 * by the object templates to keep place holders to other templates
 * that need to be expanded into objects.
 *
 */

static void
mr_initmem_ptr (void *memptr, TP_DOMAIN * domain)
{
  void **mem = (void **) memptr;

  *mem = NULL;
}

static void
mr_initval_ptr (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_POINTER, precision, scale);
  db_make_pointer (value, NULL);
}

static int
mr_setmem_ptr (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  void **mem = (void **) memptr;

  if (value == NULL)
    {
      mr_initmem_ptr (mem, domain);
    }
  else
    {
      *mem = db_get_pointer (value);
    }
  return NO_ERROR;
}

static int
mr_getmem_ptr (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  void **mem = (void **) memptr;

  return db_make_pointer (value, *mem);
}

static int
mr_setval_ptr (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  if (DB_IS_NULL (src))
    {
      db_make_null (dest);
      return NO_ERROR;
    }
  else
    {
      return db_make_pointer (dest, db_get_pointer (src));
    }
}

static int
mr_data_lengthmem_ptr (void *memptr, TP_DOMAIN * domain, int disk)
{
  return 0;
}

static int
mr_data_lengthval_ptr (DB_VALUE * value, int disk)
{
  void *ptr;

  if (value != NULL)
    {
      ptr = db_get_pointer (value);
      return mr_data_lengthmem_ptr (&ptr, NULL, disk);
    }
  else
    {
      return NO_ERROR;
    }
}

static void
mr_data_writemem_ptr (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
}

static void
mr_data_readmem_ptr (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size)
{
  void **mem = (void **) memptr;

  *mem = NULL;
}

static int
mr_data_writeval_ptr (OR_BUF * buf, DB_VALUE * value)
{
  return NO_ERROR;
}

static int
mr_data_readval_ptr (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  if (value)
    {
      db_value_domain_init (value, DB_TYPE_POINTER, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  return NO_ERROR;
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_ptr (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  /* don't know how to unpack pointers */
  return DB_UNK;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_ptr (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  void *p1, *p2;

  p1 = db_get_pointer (value1);
  p2 = db_get_pointer (value2);

  /* use address for collating sequence */
  return MR_CMP ((UINTPTR) p1, (UINTPTR) p2);
}

/*
 * TYPE ERROR
 *
 * This is used only for method arguments, they cannot be attribute values.
 */

static void
mr_initmem_error (void *memptr, TP_DOMAIN * domain)
{
  int *mem = (int *) memptr;

  *mem = NO_ERROR;
}

static void
mr_initval_error (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_ERROR, precision, scale);
  db_make_error (value, NO_ERROR);
}

static int
mr_setmem_error (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  int *mem = (int *) memptr;

  if (value == NULL)
    {
      mr_initmem_error (mem, domain);
    }
  else
    {
      *mem = db_get_error (value);
    }
  return NO_ERROR;
}

static int
mr_getmem_error (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int *mem = (int *) memptr;

  return db_make_error (value, *mem);
}

static int
mr_setval_error (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  if (DB_IS_NULL (src))
    {
      db_make_null (dest);
      return NO_ERROR;
    }
  else
    {
      return db_make_error (dest, db_get_error (src));
    }
}

static int
mr_data_lengthmem_error (void *memptr, TP_DOMAIN * domain, int disk)
{
  return 0;
}

static int
mr_data_lengthval_error (DB_VALUE * value, int disk)
{
  int error;

  if (value != NULL)
    {
      error = db_get_error (value);
      return mr_data_lengthmem_error (&error, NULL, disk);
    }
  else
    {
      return NO_ERROR;
    }
}

static void
mr_data_writemem_error (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
}

static void
mr_data_readmem_error (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size)
{
  int *mem = (int *) memptr;

  *mem = NO_ERROR;
}

static int
mr_data_writeval_error (OR_BUF * buf, DB_VALUE * value)
{
  return NO_ERROR;
}

static int
mr_data_readval_error (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
               int copy_buf_len)
{
  if (value)
    {
      db_value_domain_init (value, DB_TYPE_ERROR, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
      db_make_error (value, NO_ERROR);
    }
  return NO_ERROR;
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_error (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  /* don't know how to unpack errors */
  return DB_UNK;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_error (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  int e1, e2;

  e1 = db_get_error (value1);
  e2 = db_get_error (value2);

  return MR_CMP (e1, e2);
}


/*
 * TYPE OID
 *
 * DB_TYPE_OID is not really a "domain" type, it is rather a physical
 * representation of an object domain.  Due to the way we dispatch
 * on DB_TYPE_ codes however, we need a fleshed out type vector
 * for this.
 *
 * This is used by the server where we have no DB_OBJECT handles.
 * It can also be used on the client in places where we defer
 * the "swizzling" of OID references (e.g. inside sets).
 *
 * We don't have to handle the case where values come in with DB_TYPE_OBJECT
 * as we do in the _object handlers, true ?
 *
 */

static void
mr_initmem_oid (void *memptr, TP_DOMAIN * domain)
{
  OID *mem = (OID *) memptr;

  mr_null_oid (mem);
}

static void
mr_initval_oid (DB_VALUE * value, int precision, int scale)
{
  OID oid;

  mr_null_oid (&oid);
  db_value_domain_init (value, DB_TYPE_OID, precision, scale);
  db_make_oid (value, &oid);
}

static int
mr_setmem_oid (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  OID *mem = (OID *) memptr;
  OID *oid;

  if (value == NULL)
    {
      mr_initmem_oid (mem, domain);
    }
  else
    {
      oid = db_get_oid (value);
      if (oid)
    {
      mem->volid = oid->volid;
      mem->pageid = oid->pageid;
      mem->slotid = oid->slotid;
    }
      else
    {
      return ER_FAILED;
    }
    }
  return NO_ERROR;
}

static int
mr_getmem_oid (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  OID *mem = (OID *) memptr;
  OID oid;

  oid.volid = mem->volid;
  oid.pageid = mem->pageid;
  oid.slotid = mem->slotid;
  return db_make_oid (value, &oid);
}

static int
mr_setval_oid (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  OID *oid;

  if (DB_IS_NULL (src))
    {
      db_make_null (dest);
      return NO_ERROR;
    }
  else
    {
      oid = (OID *) db_get_oid (src);
      return db_make_oid (dest, oid);
    }
}

static void
mr_data_writemem_oid (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
  OID *mem = (OID *) memptr;

  or_put_oid (buf, mem);
}

static void
mr_data_readmem_oid (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size)
{
  OID *mem = (OID *) memptr;
  OID oid;

  if (mem != NULL)
    {
      or_get_oid (buf, mem);
    }
  else
    {
      or_get_oid (buf, &oid);   /* skip over it */
    }
}

static int
mr_data_writeval_oid (OR_BUF * buf, DB_VALUE * value)
{
  return (or_put_oid (buf, db_get_oid (value)));
}

static int
mr_data_readval_oid (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  OID oid;
  int rc = NO_ERROR;

  if (value != NULL)
    {
      db_value_domain_init (value, DB_TYPE_OID, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
      rc = or_get_oid (buf, &oid);
      db_make_oid (value, &oid);
    }
  else
    {
      rc = or_advance (buf, tp_Oid.disksize);
    }

  return rc;
}

static int
mr_index_writeval_oid (OR_BUF * buf, DB_VALUE * value)
{
  OID *oidp = NULL;
  int rc = NO_ERROR;

  assert (DB_VALUE_TYPE (value) == DB_TYPE_OID || DB_VALUE_TYPE (value) == DB_TYPE_OBJECT);

  oidp = db_get_oid (value);

  rc = or_put_data (buf, (char *) (&oidp->pageid), tp_Integer.disksize);
  if (rc == NO_ERROR)
    {
      rc = or_put_data (buf, (char *) (&oidp->slotid), tp_Short.disksize);
    }
  if (rc == NO_ERROR)
    {
      rc = or_put_data (buf, (char *) (&oidp->volid), tp_Short.disksize);
    }

  return rc;
}

static int
mr_index_readval_oid (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  OID oid;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Object.disksize);
    }
  else
    {
      rc = or_get_data (buf, (char *) (&oid.pageid), tp_Integer.disksize);
      if (rc == NO_ERROR)
    {
      rc = or_get_data (buf, (char *) (&oid.slotid), tp_Short.disksize);
    }
      if (rc == NO_ERROR)
    {
      rc = or_get_data (buf, (char *) (&oid.volid), tp_Short.disksize);
    }

      if (rc == NO_ERROR)
    {
      db_value_domain_init (value, DB_TYPE_OID, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
      db_make_oid (value, &oid);
    }
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_oid (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  OID o1, o2;
  int oidc;

  assert (domain != NULL);

  COPYMEM (int, &o1.pageid, (char *) mem1 + OR_OID_PAGEID);
  COPYMEM (short, &o1.slotid, (char *) mem1 + OR_OID_SLOTID);
  COPYMEM (short, &o1.volid, (char *) mem1 + OR_OID_VOLID);

  COPYMEM (int, &o2.pageid, (char *) mem2 + OR_OID_PAGEID);
  COPYMEM (short, &o2.slotid, (char *) mem2 + OR_OID_SLOTID);
  COPYMEM (short, &o2.volid, (char *) mem2 + OR_OID_VOLID);

  oidc = oid_compare (&o1, &o2);
  return MR_CMP_RETURN_CODE (oidc);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_oid (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  OID o1, o2;
  int oidc;

  assert (domain != NULL);

  OR_GET_OID (mem1, &o1);
  OR_GET_OID (mem2, &o2);

  oidc = oid_compare (&o1, &o2);
  return MR_CMP_RETURN_CODE (oidc);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_oid (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  OID *oid1, *oid2;
  int oidc;

  oid1 = db_get_oid (value1);
  oid2 = db_get_oid (value2);

  if (oid1 == NULL || oid2 == NULL)
    {
      return DB_UNK;
    }

  oidc = oid_compare (oid1, oid2);
  return MR_CMP_RETURN_CODE (oidc);
}

/*
 * TYPE SET
 *
 * This is easily the most complicated primitive type.
 * Sets are defined to be owned by an object.
 * They may be checked out of an object and accessed directly through the
 * set structure.  We need to move maintenance of set ownership down
 * from the object layer to this layer.  This will avoid a lot of special
 * cases for sets that now exist in the pr_ and obj_ layers.
 */


static void
mr_initmem_set (void *memptr, TP_DOMAIN * domain)
{
  SETOBJ **mem = (SETOBJ **) memptr;

  *mem = NULL;
}

static void
mr_initval_set (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_SET, precision, scale);
  db_make_set (value, NULL);
}

static int
mr_setmem_set (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  SETOBJ **mem = (SETOBJ **) memptr;
  int error = NO_ERROR;
  SETOBJ *set;
  SETREF *ref;

  /*
   * NOTE: assumes ownership info has already been placed
   * in the set reference by the caller
   */
  if ((value != NULL) && ((ref = db_get_set (value)) != NULL))
    {
      set = ref->set;
      if (*mem != set)
    {
      if (*mem != NULL)
        {
          error = setobj_release (*mem);
        }
      *mem = set;
    }
    }
  else
    {
      if (*mem != NULL)
    {
      error = setobj_release (*mem);
    }
      mr_initmem_set (mem, domain);
    }
  return error;
}

static int
mr_getmem_set (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  SETOBJ **mem = (SETOBJ **) memptr;
  int error = NO_ERROR;
  SETOBJ *set;
  SETREF *ref;

  set = *mem;
  if (set == NULL)
    {
      error = db_make_set (value, NULL);
    }
  else
    {
      ref = setobj_get_reference (set);
      if (ref)
    {
      error = db_make_set (value, ref);
    }
      else
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
      (void) db_make_set (value, NULL);
    }
    }
  /*
   * NOTE: assumes that ownership info will already have been set or will
   * be set by the caller
   */

  return error;
}

static int
mr_setval_set_internal (DB_VALUE * dest, const DB_VALUE * src, bool copy, DB_TYPE set_type)
{
  int error = NO_ERROR;
  SETREF *src_ref, *ref;

  if (src != NULL && !DB_IS_NULL (src) && ((src_ref = db_get_set (src)) != NULL))
    {
      if (!copy)
    {
      ref = src_ref;
      /* must increment the reference count */
      ref->ref_count++;
    }
      else
    {
      /* need to check if we have a disk_image, if so we just copy it */
      if (src_ref->disk_set)
        {
          ref = set_make_reference ();
          if (ref == NULL)
        {
          goto err_set;
        }
          else
        {
          /* Copy the bits into a freshly allocated buffer. */
          ref->disk_set = (char *) db_private_alloc (NULL, src_ref->disk_size);
          if (ref->disk_set == NULL)
            {
              goto err_set;
            }
          else
            {
              ref->need_clear = true;
              ref->disk_size = src_ref->disk_size;
              ref->disk_domain = src_ref->disk_domain;
              memcpy (ref->disk_set, src_ref->disk_set, src_ref->disk_size);
            }
        }
        }
      else
        {
          ref = set_copy (src_ref);
          if (ref == NULL)
        {
          goto err_set;
        }
        }
    }

      switch (set_type)
    {
    case DB_TYPE_SET:
      db_make_set (dest, ref);
      break;
    case DB_TYPE_MULTISET:
      db_make_multiset (dest, ref);
      break;
    case DB_TYPE_SEQUENCE:
      db_make_sequence (dest, ref);
      break;
    default:
      break;
    }
    }
  else
    {
      db_value_domain_init (dest, set_type, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  return error;

err_set:
  /* couldn't allocate storage for set */
  assert (er_errid () != NO_ERROR);
  error = er_errid ();
  switch (set_type)
    {
    case DB_TYPE_SET:
      db_make_set (dest, NULL);
      break;
    case DB_TYPE_MULTISET:
      db_make_multiset (dest, NULL);
      break;
    case DB_TYPE_SEQUENCE:
      db_make_sequence (dest, NULL);
      break;
    default:
      break;
    }
  db_make_null (dest);
  return error;
}

static int
mr_setval_set (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  return mr_setval_set_internal (dest, src, copy, DB_TYPE_SET);
}

static int
mr_data_lengthmem_set (void *memptr, TP_DOMAIN * domain, int disk)
{
  int size;

  if (!disk)
    {
      size = tp_Set.size;
    }
  else
    {
      SETOBJ **mem = (SETOBJ **) memptr;

      size = or_packed_set_length (*mem, 0);
    }

  return size;
}

static int
mr_data_lengthval_set (DB_VALUE * value, int disk)
{
  SETREF *ref;
  SETOBJ *set;
  int size;
#if !defined (SERVER_MODE)
  int pin;
#endif

  size = 0;

  if (!disk)
    {
      size = sizeof (DB_SET *);
    }
  else
    {
      ref = db_get_set (value);
      if (ref != NULL)
    {
      /* should have a set_ function for this ! */
      if (ref->disk_set)
        {
          size = ref->disk_size;
        }
      else if (set_get_setobj (ref, &set, 0) == NO_ERROR)
        {
          if (set != NULL)
        {
          /* probably no need to pin here but it can't hurt */
#if !defined (SERVER_MODE)
          pin = ws_pin (ref->owner, 1);
#endif
          size = or_packed_set_length (set, 1);
#if !defined (SERVER_MODE)
          (void) ws_pin (ref->owner, pin);
#endif
        }
        }
    }
    }
  return size;
}

static void
mr_data_writemem_set (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
  SETOBJ **mem = (SETOBJ **) memptr;

  if (*mem != NULL)
    {
      /* note that we don't have to pin the object here since that will have been handled above this leve. */
      or_put_set (buf, *mem, 0);
    }
}

static int
mr_data_writeval_set (OR_BUF * buf, DB_VALUE * value)
{
  SETREF *ref;
  SETOBJ *set;
  int size;
#if !defined (SERVER_MODE)
  int pin;
#endif
  int rc = NO_ERROR;

  ref = db_get_set (value);
  if (ref != NULL)
    {
      /* If we have a disk image of the set, we can just copy those bits here.  This assumes very careful maintenance
       * of the disk and memory images.  Currently, we only have one or the other.  That is, when we transform the disk
       * image to memory, we clear the disk image. */
      if (ref->disk_set)
    {
      /* check for overflow */
      if ((((ptrdiff_t) (buf->endptr - buf->ptr)) < (ptrdiff_t) ref->disk_size))
        {
          return ER_TF_BUFFER_OVERFLOW;
        }
      else
        {
          memcpy (buf->ptr, ref->disk_set, ref->disk_size);
          rc = or_advance (buf, ref->disk_size);
        }
    }
      else if (set_get_setobj (ref, &set, 0) == NO_ERROR)
    {
      if (set != NULL)
        {
          if (ref->owner == NULL)
        {
          or_put_set (buf, set, 1);
        }
          else
        {
#if !defined (SERVER_MODE)
          pin = ws_pin (ref->owner, 1);
#endif
          size = or_packed_set_length (set, 1);
          /* remember the Windows pointer problem ! */
          if (((ptrdiff_t) (buf->endptr - buf->ptr)) < (ptrdiff_t) size)
            {
              /* unpin the owner before we abort ! */
#if !defined (SERVER_MODE)
              (void) ws_pin (ref->owner, pin);
#endif
              return ER_TF_BUFFER_OVERFLOW;
            }
          else
            {
              /* the buffer is ok, do the transformation */
              or_put_set (buf, set, 1);
            }
#if !defined (SERVER_MODE)
          (void) ws_pin (ref->owner, pin);
#endif
        }
        }
    }
    }
  return rc;
}

static void
mr_data_readmem_set (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size)
{
  SETOBJ **mem = (SETOBJ **) memptr;
  SETOBJ *set;

  if (mem == NULL)
    {
      if (size >= 0)
    {
      or_advance (buf, size);
    }
      else
    {
      set = or_get_set (buf, domain);
      if (set != NULL)
        {
          setobj_free (set);
        }
    }
    }
  else
    {
      if (!size)
    {
      *mem = NULL;
    }
      else
    {
      set = or_get_set (buf, domain);
      if (set != NULL)
        {
          *mem = set;
        }
      else
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CORRUPTED, 0);
          assert (false);
          return;
        }
    }
    }
}

static int
mr_data_readval_set (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  SETOBJ *set;
  SETREF *ref;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      if (size == -1)
    {
      /* don't know the true size, must unpack the set and throw it away */
      set = or_get_set (buf, domain);
      if (set != NULL)
        {
          setobj_free (set);
        }
      else
        {
          return ER_FAILED;
        }
    }
      else
    {
      if (size)
        {
          rc = or_advance (buf, size);
        }
    }
    }
  else
    {
      /* In some cases, like VOBJ reading, the domain passed is NULL here so be careful when initializing the value.
       * If it is NULL, it will be read when the set is unpacked. */
      if (!domain)
    {
      db_value_domain_init (value, DB_TYPE_SET, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
      else
    {
      db_value_domain_init (value, TP_DOMAIN_TYPE (domain), domain->precision, domain->scale);
    }

      /* If size is zero, we have nothing to do, if size is -1, just go ahead and unpack the set. */
      if (!size)
    {
      db_make_set (value, NULL);
    }
      else if (copy)
    {
      set = or_get_set (buf, domain);
      if (set == NULL)
        {
          return ER_FAILED;
        }
      else
        {
          ref = setobj_get_reference (set);
          if (ref == NULL)
        {
          return ER_FAILED;
        }
          else
        {
          switch (set_get_type (ref))
            {
            case DB_TYPE_SET:
              db_make_set (value, ref);
              break;
            case DB_TYPE_MULTISET:
              db_make_multiset (value, ref);
              break;
            case DB_TYPE_SEQUENCE:
              db_make_sequence (value, ref);
              break;
            default:
              break;
            }
        }
        }
    }
      else
    {
      /* copy == false, which means don't translate it into memory rep */
      ref = set_make_reference ();
      if (ref == NULL)
        {
          return ER_FAILED;
        }
      else
        {
          int disk_size;
          DB_TYPE set_type;

          if (size != -1)
        {
          char *set_st;
          int num_elements, has_domain, bound_bits, offset_tbl, el_tags;

          disk_size = size;

          /* unfortunately, we still need to look at the header to find out the set type. */
          set_st = buf->ptr;
          or_get_set_header (buf, &set_type, &num_elements, &has_domain, &bound_bits, &offset_tbl, &el_tags,
                     NULL);

          /* reset the OR_BUF */
          buf->ptr = set_st;
        }
          else
        {
          /* we have to go figure the size out */
          disk_size = or_disk_set_size (buf, domain, &set_type);
        }

          /* Record the pointer to the disk bits */
          ref->disk_set = buf->ptr;
          ref->need_clear = false;
          ref->disk_size = disk_size;
          ref->disk_domain = domain;

          /* advance the buffer as if we had read the set */
          rc = or_advance (buf, disk_size);

          switch (set_type)
        {
        case DB_TYPE_SET:
          db_make_set (value, ref);
          break;
        case DB_TYPE_MULTISET:
          db_make_multiset (value, ref);
          break;
        case DB_TYPE_SEQUENCE:
          db_make_sequence (value, ref);
          break;
        default:
          break;
        }
        }
    }
    }
  return rc;
}

static void
mr_freemem_set (void *memptr)
{
  /* since we aren't explicitly setting the set to NULL, we must set up the reference structures so they will get the
   * new set when it is brought back in, this is the only primitive type for which the free function is semantically
   * different than using the setmem function with a NULL value */

  SETOBJ **mem = (SETOBJ **) memptr;

  if (*mem != NULL)
    {
      setobj_free (*mem);   /* free storage, NULL references */
    }
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_set (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c;
  SETOBJ *set1 = NULL, *set2 = NULL;

  assert (domain != NULL);

  /* is not index type */
  assert (!domain->is_desc && !tp_valid_indextype (TP_DOMAIN_TYPE (domain)));

  mem1 = or_unpack_set ((char *) mem1, &set1, domain);
  mem2 = or_unpack_set ((char *) mem2, &set2, domain);

  if (set1 == NULL || set2 == NULL)
    {
      return DB_UNK;
    }

  c = setobj_compare_order (set1, set2, do_coercion, total_order);

  setobj_free (set1);
  setobj_free (set2);

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_set (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  return set_compare_order (db_get_set (value1), db_get_set (value2), do_coercion, total_order);
}

/*
 * TYPE MULTISET
 */

static void
mr_initval_multiset (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_MULTISET, precision, scale);
  db_make_multiset (value, NULL);
}

static int
mr_getmem_multiset (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  SETOBJ **mem = (SETOBJ **) memptr;
  int error = NO_ERROR;
  SETOBJ *set;
  SETREF *ref;

  set = *mem;
  if (set == NULL)
    {
      error = db_make_multiset (value, NULL);
    }
  else
    {
      ref = setobj_get_reference (set);
      if (ref)
    {
      error = db_make_multiset (value, ref);
    }
      else
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
      (void) db_make_multiset (value, NULL);
    }
    }
  /* NOTE: assumes that ownership info will already have been set or will be set by the caller */

  return error;
}

static int
mr_setval_multiset (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  return mr_setval_set_internal (dest, src, copy, DB_TYPE_MULTISET);
}

/*
 * TYPE SEQUENCE
 */

static void
mr_initval_sequence (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_SEQUENCE, precision, scale);
  db_make_sequence (value, NULL);
}

static int
mr_getmem_sequence (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  SETOBJ **mem = (SETOBJ **) memptr;
  int error = NO_ERROR;
  SETOBJ *set;
  SETREF *ref;

  set = *mem;
  if (set == NULL)
    {
      error = db_make_sequence (value, NULL);
    }
  else
    {
      ref = setobj_get_reference (set);
      if (ref)
    {
      error = db_make_sequence (value, ref);
    }
      else
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
      (void) db_make_sequence (value, NULL);
    }
    }
  /*
   * NOTE: assumes that ownership info will already have been set or will
   * be set by the caller
   */

  return error;
}

static int
mr_setval_sequence (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  return mr_setval_set_internal (dest, src, copy, DB_TYPE_SEQUENCE);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_sequence (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c;
  SETOBJ *seq1 = NULL, *seq2 = NULL;

  assert (domain != NULL);

  /* is not index type */
  assert (!domain->is_desc && !tp_valid_indextype (TP_DOMAIN_TYPE (domain)));

  mem1 = or_unpack_set ((char *) mem1, &seq1, domain);
  mem2 = or_unpack_set ((char *) mem2, &seq2, domain);

  if (seq1 == NULL || seq2 == NULL)
    {
      return DB_UNK;
    }

  c = setobj_compare_order (seq1, seq2, do_coercion, total_order);

  setobj_free (seq1);
  setobj_free (seq2);

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_sequence (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
            int collation)
{
  return set_seq_compare (db_get_set (value1), db_get_set (value2), do_coercion, total_order);
}

/*
 * TYPE MIDXKEY
 */

static void
mr_initval_midxkey (DB_VALUE * value, int precision, int scale)
{
  DB_MIDXKEY *midxkey = NULL;
  db_value_domain_init (value, DB_TYPE_MIDXKEY, precision, scale);
  db_make_midxkey (value, midxkey);
}

static int
mr_setval_midxkey (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error = NO_ERROR;
  int src_precision;

  DB_MIDXKEY dst_idx;
  DB_MIDXKEY *src_idx;

  if (DB_IS_NULL (src))
    {
      return db_value_domain_init (dest, DB_TYPE_MIDXKEY, DB_DEFAULT_PRECISION, 0);
    }

  /* Get information from the value. */
  src_idx = db_get_midxkey (src);
  src_precision = db_value_precision (src);
  if (src_idx == NULL)
    {
      return db_value_domain_init (dest, DB_TYPE_MIDXKEY, src_precision, 0);
    }

  if (src_idx->size < 0)
    {
      dst_idx.size = mr_index_lengthmem_midxkey (src_idx->buf, src_idx->domain);
    }
  else
    {
      dst_idx.size = src_idx->size;
    }

  dst_idx.ncolumns = src_idx->ncolumns;

  dst_idx.domain = src_idx->domain;

  dst_idx.min_max_val.position = src_idx->min_max_val.position;
  dst_idx.min_max_val.type = src_idx->min_max_val.type;

  /* should we be paying attention to this? it is extremely dangerous */
  if (!copy)
    {
      dst_idx.buf = src_idx->buf;

      error = db_make_midxkey (dest, &dst_idx);
      dest->need_clear = false;
    }
  else
    {
      dst_idx.buf = (char *) db_private_alloc (NULL, dst_idx.size);
      if (dst_idx.buf == NULL)
    {
      db_value_domain_init (dest, DB_TYPE_MIDXKEY, src_precision, 0);

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

      memcpy (dst_idx.buf, src_idx->buf, dst_idx.size);
      error = db_make_midxkey (dest, &dst_idx);
      dest->need_clear = true;
    }

  return error;
}

static int
mr_data_writeval_midxkey (OR_BUF * buf, DB_VALUE * value)
{
  return mr_index_writeval_midxkey (buf, value);
}

static int
mr_index_writeval_midxkey (OR_BUF * buf, DB_VALUE * value)
{
  DB_MIDXKEY *midxkey;
  int rc;

  midxkey = db_get_midxkey (value);
  if (midxkey == NULL)
    {
      return ER_FAILED;
    }

  rc = or_put_data (buf, (char *) midxkey->buf, midxkey->size);

  return rc;
}

static int
mr_data_readval_midxkey (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  return mr_index_readval_midxkey (buf, value, domain, size, copy, copy_buf, copy_buf_len);
}

static int
mr_index_readval_midxkey (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  char *new_;
  DB_MIDXKEY midxkey;
  int rc = NO_ERROR;
  TP_DOMAIN *dom;

  if (size == -1)
    {               /* unknown size */
      size = mr_index_lengthmem_midxkey (buf->ptr, domain);
    }

  if (size <= 0)
    {
      assert (false);
      return ER_FAILED;
    }

  if (value == NULL)
    {
      return or_advance (buf, size);
    }

  midxkey.size = size;
  midxkey.domain = domain;
  midxkey.min_max_val.position = -1;
  midxkey.min_max_val.type = MIN_COLUMN;
  midxkey.ncolumns = domain->precision;

  if (!copy)
    {
      midxkey.buf = buf->ptr;
      db_make_midxkey (value, &midxkey);
      rc = or_advance (buf, size);
    }
  else
    {
      if (copy_buf && copy_buf_len >= size)
    {
      /* read buf image into the copy_buf */
      new_ = copy_buf;
    }
      else
    {
      /*
       * Allocate storage for the string
       * do not include the kludge NULL terminator
       */
      new_ = (char *) db_private_alloc (NULL, size);
    }

      if (new_ == NULL)
    {
      /* need to be able to return errors ! */
      db_value_domain_init (value, TP_DOMAIN_TYPE (domain), TP_FLOATING_PRECISION_VALUE, 0);
      return ER_FAILED;
    }
      else
    {
      rc = or_get_data (buf, new_, size);
      if (rc == NO_ERROR)
        {
          /* round up to a word boundary */
          /* rc = or_get_align32 (buf); *//* need ?? */
        }
      if (rc != NO_ERROR)
        {
          if (new_ != copy_buf)
        {
          db_private_free_and_init (NULL, new_);
        }
          return rc;
        }
      midxkey.buf = new_;
      db_make_midxkey (value, &midxkey);
      value->need_clear = (new_ != copy_buf) ? true : false;
    }
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
pr_midxkey_compare_element (char *mem1, char *mem2, TP_DOMAIN * dom1, TP_DOMAIN * dom2, int do_coercion,
                int total_order)
{
  DB_VALUE_COMPARE_RESULT c = DB_UNK;
  DB_VALUE val1, val2;
  bool error = false;
  OR_BUF buf_val1, buf_val2;
  bool comparable = true;

  if (dom1->is_desc != dom2->is_desc)
    {
      assert (false);
      return DB_UNK;        /* impossible case */
    }

  or_init (&buf_val1, mem1, -1);
  or_init (&buf_val2, mem2, -1);

  db_make_null (&val1);
  db_make_null (&val2);

  if (dom1->type->index_readval (&buf_val1, &val1, dom1, -1, false, NULL, 0) != NO_ERROR)
    {
      error = true;
      goto clean_up;
    }

  if (dom2->type->index_readval (&buf_val2, &val2, dom2, -1, false, NULL, 0) != NO_ERROR)
    {
      error = true;
      goto clean_up;
    }

  c = tp_value_compare_with_error (&val1, &val2, do_coercion, total_order, &comparable);

clean_up:
  if (DB_NEED_CLEAR (&val1))
    {
      pr_clear_value (&val1);
    }

  if (DB_NEED_CLEAR (&val2))
    {
      pr_clear_value (&val2);
    }

  if (!comparable || error == true)
    {
      return DB_UNK;
    }

  return c;
}

DB_VALUE_COMPARE_RESULT
pr_midxkey_compare (DB_MIDXKEY * mul1, DB_MIDXKEY * mul2, int do_coercion, int total_order, int num_index_term,
            int *start_colp, int *diff_column, bool * dom_is_desc, int *result_size)
{
  DB_VALUE_COMPARE_RESULT c = DB_UNK;
  int i;
  TP_DOMAIN *dom1, *dom2;
  char *nullmap_ptr1, *nullmap_ptr2;
  char *mem1, *mem2;
  int offset1, offset2;
  int last;

  assert (total_order == 1);
  if (total_order == 0)
    {
      /* unknown case */
      return DB_UNK;
    }

  assert (mul1->domain != NULL);
  assert (TP_DOMAIN_TYPE (mul1->domain) == DB_TYPE_MIDXKEY);
  assert (mul1->domain->setdomain != NULL);

  assert (mul2->domain != NULL);
  assert (TP_DOMAIN_TYPE (mul2->domain) == DB_TYPE_MIDXKEY);
  assert (mul2->domain->setdomain != NULL);

  assert (mul1->ncolumns == mul2->ncolumns);
  assert (mul1->domain->precision == mul2->domain->precision);

  /* safe guard */
  if (mul1->domain == NULL || TP_DOMAIN_TYPE (mul1->domain) != DB_TYPE_MIDXKEY || mul1->domain->setdomain == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_MR_NULL_DOMAIN, 0);
      return DB_UNK;
    }

  /* safe guard */
  if (mul2->domain == NULL || TP_DOMAIN_TYPE (mul2->domain) != DB_TYPE_MIDXKEY || mul2->domain->setdomain == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_MR_NULL_DOMAIN, 0);
      return DB_UNK;
    }

  /* safe guard */
  if (mul1->ncolumns != mul2->ncolumns || mul1->domain->precision != mul2->domain->precision)
    {
      return DB_UNK;
    }

#if !defined(NDEBUG)
  {
    int dom_ncols = 0;      /* init */

    for (dom1 = mul1->domain->setdomain; dom1; dom1 = dom1->next)
      {
    dom_ncols++;
      }

    if (dom_ncols <= 0)
      {
    assert (false);
    return DB_UNK;
      }

    assert (dom_ncols == mul1->domain->precision);
  }
#endif /* NDEBUG */

  nullmap_ptr1 = mul1->buf;
  nullmap_ptr2 = mul2->buf;

  last = or_multi_header_size (mul1->domain->precision);

  mem1 = mul1->buf + last;
  mem2 = mul2->buf + last;

  dom1 = mul1->domain->setdomain;
  dom2 = mul2->domain->setdomain;

  last = (num_index_term > 0) ? num_index_term : mul1->ncolumns;

  i = 0;
  if (start_colp && *start_colp > 0)
    {
      offset1 = or_multi_get_element_offset (nullmap_ptr1, mul1->domain->precision, *start_colp);
      offset2 = or_multi_get_element_offset (nullmap_ptr2, mul2->domain->precision, *start_colp);

      /* fallthrough: i, dom1, dom2 */
      if (offset1 > 0)
    {
      if (offset2 > 0)
        {
          mem1 = mul1->buf + offset1;
          mem2 = mul2->buf + offset2;

          for (; i < *start_colp; i++, dom1 = dom1->next, dom2 = dom2->next)
        {
          assert (dom1 != NULL);
          assert (dom2 != NULL);
          assert (dom1->is_desc == dom2->is_desc);
        }
        }
      else
        {
          mem1 = mul1->buf + offset1;

          for (; i < *start_colp; i++, dom1 = dom1->next, dom2 = dom2->next)
        {
          assert (dom1 != NULL);
          assert (dom2 != NULL);
          assert (dom1->is_desc == dom2->is_desc);

          if (or_multi_is_not_null (nullmap_ptr2, i))
            {
              mem2 += pr_midxkey_element_disk_size (mem2, dom2);
            }
        }
        }
    }
      else if (offset2 > 0)
    {
      mem2 = mul2->buf + offset2;

      for (; i < *start_colp; i++, dom1 = dom1->next, dom2 = dom2->next)
        {
          if (or_multi_is_not_null (nullmap_ptr1, i))
        {
          assert (dom1 != NULL);
          assert (dom2 != NULL);
          assert (dom1->is_desc == dom2->is_desc);

          mem1 += pr_midxkey_element_disk_size (mem1, dom1);
        }
        }
    }
      else
    {
      for (; i < *start_colp; i++, dom1 = dom1->next, dom2 = dom2->next)
        {
          assert (dom1 != NULL);
          assert (dom2 != NULL);
          assert (dom1->is_desc == dom2->is_desc);

          if (or_multi_is_not_null (nullmap_ptr1, i))
        {
          mem1 += pr_midxkey_element_disk_size (mem1, dom1);
        }

          if (or_multi_is_not_null (nullmap_ptr2, i))
        {
          mem2 += pr_midxkey_element_disk_size (mem2, dom2);
        }
        }
    }
    }

  /* fallthrough: i, dom1, dom2 */
  for (c = DB_EQ; i < last; i++, dom1 = dom1->next, dom2 = dom2->next)
    {
      if (dom1 == NULL || dom2 == NULL || dom1->is_desc != dom2->is_desc)
    {
      assert (false);
      return DB_UNK;
    }

      if (or_multi_is_not_null (nullmap_ptr1, i))
    {
      if (or_multi_is_not_null (nullmap_ptr2, i))
        {
          /* check for val1 and val2 same domain */
          if (dom1 == dom2 || tp_domain_match (dom1, dom2, TP_EXACT_MATCH))
        {
          c = dom1->type->index_cmpdisk (mem1, mem2, dom1, do_coercion, total_order, NULL);
        }
          else
        {
          /* coercion and comparison
           * val1 and val2 have different domain
           */
          c = pr_midxkey_compare_element (mem1, mem2, dom1, dom2, do_coercion, total_order);
        }

          if (c == DB_EQ)
        {
          mem1 += pr_midxkey_element_disk_size (mem1, dom1);
          mem2 += pr_midxkey_element_disk_size (mem2, dom2);
          continue;
        }
        }
      else
        {
          /* val 1 bound, val 2 unbound */
          if (mul2->min_max_val.position == i)
        {
          /* safeguard */
          assert (mul2->min_max_val.type == MIN_COLUMN || mul2->min_max_val.type == MAX_COLUMN);
          c = (mul2->min_max_val.type == MIN_COLUMN) ? DB_GT : DB_LT;
        }
          else
        {
          c = DB_GT;
        }
        }
    }
      else if (or_multi_is_not_null (nullmap_ptr2, i))
    {
      /* val 1 unbound, val 2 bound */
      if (mul1->min_max_val.position == i)
        {
          /* safeguard */
          assert (mul1->min_max_val.type == MIN_COLUMN || mul1->min_max_val.type == MAX_COLUMN);
          c = (mul1->min_max_val.type == MIN_COLUMN) ? DB_LT : DB_GT;
        }
      else
        {
          c = DB_LT;
        }
    }
      else
    {
      /* val 1 unbound, val 2 unbound */
      /* SPECIAL_COLUMN_MIN > NULL */
      if (mul1->min_max_val.position == i)
        {
          if (mul2->min_max_val.position == i)
        {
          MIN_MAX_COLUMN_TYPE type1 = mul1->min_max_val.type;
          MIN_MAX_COLUMN_TYPE type2 = mul2->min_max_val.type;
          c = (type1 == type2) ? DB_EQ : ((type1 == MIN_COLUMN) ? DB_LT : DB_GT);
        }
          else
        {
          assert (mul1->min_max_val.type == MIN_COLUMN || mul1->min_max_val.type == MAX_COLUMN);
          c = (mul1->min_max_val.type == MIN_COLUMN) ? DB_LT : DB_GT;
        }
        }
      else if (mul2->min_max_val.position == i)
        {
          assert (mul2->min_max_val.type == MIN_COLUMN || mul2->min_max_val.type == MAX_COLUMN);
          c = (mul2->min_max_val.type == MIN_COLUMN) ? DB_GT : DB_LT;
        }
      else
        {
          c = DB_EQ;
          continue;
        }
    }

      break;            /* exit for-loop */
    }

  if (start_colp != NULL)
    {
      if (c != DB_EQ)
    {
      /* save the start position of non-equal-value column */
      *start_colp = i;
    }
    }

  if (result_size)
    {
      result_size[0] = CAST_BUFLEN (mem1 - mul1->buf);
      result_size[1] = CAST_BUFLEN (mem2 - mul2->buf);

      if (c != DB_EQ)
    {
      if (dom1 != NULL && or_multi_is_not_null (nullmap_ptr1, i))
        {
          result_size[0] += pr_midxkey_element_disk_size (mem1, dom1);
        }

      if (dom2 != NULL && or_multi_is_not_null (nullmap_ptr2, i))
        {
          result_size[1] += pr_midxkey_element_disk_size (mem2, dom2);
        }
    }
    }

  *diff_column = i;

  if (dom_is_desc)
    {
      if (dom1)
    {
      dom_is_desc[0] = dom1->is_desc;
      dom_is_desc[1] = dom1->next ? dom1->next->is_desc : false;
    }
      else
    {
      dom_is_desc[0] = dom_is_desc[1] = false;
    }
    }

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_midxkey (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
           int collation)
{
  DB_VALUE_COMPARE_RESULT c = DB_UNK;
  DB_MIDXKEY *midxkey1;
  DB_MIDXKEY *midxkey2;
  int dummy_diff_column;

  midxkey1 = db_get_midxkey (value1);
  midxkey2 = db_get_midxkey (value2);

  if (midxkey1 == NULL || midxkey2 == NULL)
    {
      assert_release (false);   /* error */
      return DB_UNK;
    }

  if (midxkey1 == midxkey2)
    {
      if (total_order)
    {
      return DB_EQ;
    }

      assert_release (false);   /* error */
      return DB_UNK;
    }

  assert_release (midxkey1->domain != NULL);
  assert_release (midxkey1->domain->precision == midxkey1->ncolumns);
  assert_release (midxkey2->domain != NULL);
  assert_release (midxkey2->domain->precision == midxkey2->ncolumns);

  c =
    (DB_VALUE_COMPARE_RESULT) pr_midxkey_compare (midxkey1, midxkey2, do_coercion, total_order, -1, start_colp,
                          &dummy_diff_column, NULL, NULL);

  assert_release (c == DB_UNK || (DB_LT <= c && c <= DB_GT));

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_midxkey (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (false);

  assert (domain != NULL);

  return mr_index_cmpdisk_midxkey (mem1, mem2, domain, do_coercion, total_order, start_colp);
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_midxkey (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c = DB_UNK;
  DB_MIDXKEY midxkey1;
  DB_MIDXKEY midxkey2;
  TP_DOMAIN *cmp_dom;
  int n_atts = 0;
  int dummy_diff_column;

  assert (false);

  assert (domain != NULL && !domain->is_desc);

  assert (mem1 != NULL);
  assert (mem2 != NULL);

  if (mem1 == NULL || mem2 == NULL)
    {
      assert (false);       /* error */
      return DB_UNK;
    }

  if (mem1 == mem2)
    {
      if (total_order)
    {
      return DB_EQ;
    }

      assert (false);       /* error */
      return DB_UNK;
    }

  midxkey1.buf = (char *) mem1;
  midxkey2.buf = (char *) mem2;

  n_atts = 0;
  for (cmp_dom = domain->setdomain; cmp_dom; cmp_dom = cmp_dom->next)
    {
      n_atts++;
    }

  midxkey1.size = midxkey2.size = -1;   /* is dummy */
  midxkey1.ncolumns = midxkey2.ncolumns = n_atts;
  midxkey1.domain = midxkey2.domain = domain;

  c =
    pr_midxkey_compare (&midxkey1, &midxkey2, do_coercion, total_order, -1, start_colp, &dummy_diff_column, NULL, NULL);
  assert (c == DB_UNK || (DB_LT <= c && c <= DB_GT));

  return c;
}

static int
mr_data_lengthmem_midxkey (void *memptr, TP_DOMAIN * domain, int disk)
{
  return mr_index_lengthmem_midxkey (memptr, domain);
}

static int
mr_index_lengthmem_midxkey (void *memptr, TP_DOMAIN * domain)
{
  char *nullmap_ptr, *buf_ptr;
  TP_DOMAIN *dom;
  int idx_ncols = 0, i;
  int offset, advance_size;
  int len;

  idx_ncols = domain->precision;
  if (idx_ncols <= 0)
    {
      assert (false);
      goto exit_on_error;   /* give up */
    }

  /* There is no difference between the disk & memory sizes. */
  nullmap_ptr = (char *) memptr;

#if !defined (NDEBUG)
  {
    buf_ptr = nullmap_ptr + or_multi_header_size (idx_ncols);

    for (i = 0, dom = domain->setdomain; dom; i++, dom = dom->next)
      {
    /* check for val is NULL */
    if (or_multi_is_null (nullmap_ptr, i))
      {
        continue;       /* zero size; go ahead */
      }

    /* at here, val is non-NULL */

    buf_ptr += pr_midxkey_element_disk_size (buf_ptr, dom);
      }

    if (i <= 0)
      {
    assert (false);
    goto exit_on_error;
      }
    assert (i == idx_ncols);
  }
#endif /* NDEBUG */

  offset = or_multi_get_size_offset (nullmap_ptr, idx_ncols);
  if (offset > 0)
    {
      assert (offset == CAST_BUFLEN (buf_ptr - nullmap_ptr));
      return offset;
    }
  else
    {
      buf_ptr = nullmap_ptr + or_multi_header_size (idx_ncols);

      for (i = 0, dom = domain->setdomain; i < idx_ncols; i++, dom = dom->next)
    {
      /* check for val is NULL */
      if (or_multi_is_null (nullmap_ptr, i))
        {
          continue;     /* zero size; go ahead */
        }

      /* at here, val is non-NULL */

      buf_ptr += pr_midxkey_element_disk_size (buf_ptr, dom);
    }
    }

  /* set buf size */
  len = CAST_BUFLEN (buf_ptr - nullmap_ptr);

exit_on_end:

  return len;

exit_on_error:

  len = -1;         /* set error */
  goto exit_on_end;
}

static int
mr_data_lengthval_midxkey (DB_VALUE * value, int disk)
{
  return mr_index_lengthval_midxkey (value);
}

static int
mr_index_lengthval_midxkey (DB_VALUE * value)
{
  int len;

  if (DB_IS_NULL (value))
    {
      return 0;
    }
  len = value->data.midxkey.size;

  return len;
}

/*
 * TYPE VOBJ
 *
 * This is used only for virtual object keys in SQL/M.
 * Internal structures identical to sequences.
 */

static void
mr_initval_vobj (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_VOBJ, precision, scale);
}

static int
mr_setval_vobj (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error;

  error = mr_setval_sequence (dest, src, copy);
  db_value_alter_type (dest, DB_TYPE_VOBJ);

  return error;
}

static int
mr_data_readval_vobj (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  if (mr_data_readval_set (buf, value, &tp_Sequence_domain, size, copy, copy_buf, copy_buf_len) != NO_ERROR)
    {
      return ER_FAILED;
    }

  if (value)
    {
      db_value_alter_type (value, DB_TYPE_VOBJ);
    }
  return NO_ERROR;
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_vobj (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c;
  SETOBJ *seq1 = NULL, *seq2 = NULL;

  assert (domain != NULL);

  /* is not index type */
  assert (!domain->is_desc && !tp_valid_indextype (TP_DOMAIN_TYPE (domain)));

  mem1 = or_unpack_set ((char *) mem1, &seq1, domain);
  mem2 = or_unpack_set ((char *) mem2, &seq2, domain);

  if (seq1 == NULL || seq2 == NULL)
    {
      return DB_UNK;
    }

  c = setvobj_compare (seq1, seq2, do_coercion, total_order);

  setobj_free (seq1);
  setobj_free (seq2);

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_vobj (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  return vobj_compare (db_get_set (value1), db_get_set (value2), do_coercion, total_order);
}

/*
 * TYPE NUMERIC
 */

static void
mr_initmem_numeric (void *memptr, TP_DOMAIN * domain)
{
  assert (!IS_FLOATING_PRECISION (domain->precision));

  memset (memptr, 0, MR_NUMERIC_SIZE (domain->precision));
}

/*
 * Due to the "within tolerance" domain comparison used during attribute
 * assignment validation, we may receive a numeric whose precision is less
 * then the actual precision of the attribute.  In that case we should be doing
 * an on-the-fly coercion here.
 */
static int
mr_setmem_numeric (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  int error = NO_ERROR;
  int src_precision, src_scale, byte_size;
  DB_C_NUMERIC num, src_num;

  if (value == NULL)
    {
      mr_initmem_numeric (mem, domain);
    }
  else
    {
      src_num = db_get_numeric (value);

      src_precision = db_value_precision (value);
      src_scale = db_value_scale (value);

      /* this should have been handled by now */
      if (src_num == NULL || src_precision != domain->precision || src_scale != domain->scale)
    {
      error = ER_OBJ_DOMAIN_CONFLICT;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, "");
    }
      else
    {
      num = (DB_C_NUMERIC) mem;
      byte_size = MR_NUMERIC_SIZE (src_precision);
      memcpy (num, src_num, byte_size);
    }
    }
  return error;
}

static int
mr_getmem_numeric (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int error = NO_ERROR;
  DB_C_NUMERIC num;

  if (value == NULL)
    {
      return error;
    }

  num = (DB_C_NUMERIC) mem;
  error = db_make_numeric (value, num, domain->precision, domain->scale);
  value->need_clear = false;

  return error;
}

static void
mr_data_writemem_numeric (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  int disk_size;

  disk_size = OR_NUMERIC_SIZE (domain->precision);
  or_put_data (buf, (char *) mem, disk_size);
}

static void
mr_data_readmem_numeric (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  /* if stored size is unknown, the domain precision must be set correctly */
  if (size < 0)
    {
      size = OR_NUMERIC_SIZE (domain->precision);
    }

  if (mem == NULL)
    {
      if (size)
    {
      or_advance (buf, size);
    }
    }
  else if (size)
    {
      if (size != OR_NUMERIC_SIZE (domain->precision))
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CORRUPTED, 0);
      assert (false);
      return;
    }
      else
    {
      or_get_data (buf, (char *) mem, size);
    }
    }
}

static int
mr_index_lengthmem_numeric (void *mem, TP_DOMAIN * domain)
{
  return mr_data_lengthmem_numeric (mem, domain, 1);
}

static int
mr_data_lengthmem_numeric (void *mem, TP_DOMAIN * domain, int disk)
{
  int len;

  /* think about caching this in the domain so we don't have to calculate it */
  if (disk)
    {
      len = OR_NUMERIC_SIZE (domain->precision);
    }
  else
    {
      len = MR_NUMERIC_SIZE (domain->precision);
    }

  return len;
}

static void
mr_initval_numeric (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_NUMERIC, precision, scale);
}

static int
mr_setval_numeric (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error = NO_ERROR;
  int src_precision, src_scale;
  DB_C_NUMERIC src_numeric;

  assert (!db_value_is_corrupted (src));
  if (src == NULL || DB_IS_NULL (src))
    {
      db_value_domain_init (dest, DB_TYPE_NUMERIC, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
  else
    {
      src_precision = db_value_precision (src);
      src_scale = db_value_scale (src);
      src_numeric = (DB_C_NUMERIC) db_get_numeric (src);

      if (DB_IS_NULL (src) || src_numeric == NULL)
    {
      db_value_domain_init (dest, DB_TYPE_NUMERIC, src_precision, src_scale);
    }
      else
    {
      /*
       * Because numerics are stored in an inline buffer, there is no
       * difference between the copy and non-copy operations, this may
       * need to change.
       */
      error = db_make_numeric (dest, src_numeric, src_precision, src_scale);
    }
    }
  return error;
}

static int
mr_index_lengthval_numeric (DB_VALUE * value)
{
  return mr_data_lengthval_numeric (value, 1);
}

static int
mr_data_lengthval_numeric (DB_VALUE * value, int disk)
{
  int precision, len;

  len = 0;
  if (value != NULL)
    {
      /* better have a non-NULL value by the time writeval is called ! */
      precision = db_value_precision (value);
      if (disk)
    {
      len = OR_NUMERIC_SIZE (precision);
    }
      else
    {
      len = MR_NUMERIC_SIZE (precision);
    }
    }
  return len;
}

static int
mr_index_writeval_numeric (OR_BUF * buf, DB_VALUE * value)
{
  return mr_data_writeval_numeric (buf, value);
}

static int
mr_data_writeval_numeric (OR_BUF * buf, DB_VALUE * value)
{
  DB_C_NUMERIC numeric;
  int precision, disk_size;
  int rc = NO_ERROR;

  if (value != NULL)
    {
      numeric = db_get_numeric (value);
      if (numeric != NULL)
    {
      precision = db_value_precision (value);
      disk_size = OR_NUMERIC_SIZE (precision);
      rc = or_put_data (buf, (char *) numeric, disk_size);
    }
    }
  return rc;
}

static int
mr_index_readval_numeric (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  return mr_data_readval_numeric (buf, value, domain, size, copy, copy_buf, copy_buf_len);
}

static int
mr_data_readval_numeric (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  int rc = NO_ERROR;

  if (domain == NULL)
    {
      return ER_FAILED;
    }

  /*
   * If size is -1, the caller doesn't know the size and we must determine
   * it from the domain.
   */
  if (size == -1)
    {
      size = OR_NUMERIC_SIZE (domain->precision);
    }

  if (size == 1)
    {
      size = OR_NUMERIC_SIZE (domain->precision);
    }

  if (value == NULL)
    {
      if (size)
    {
      rc = or_advance (buf, size);
    }
    }
  else
    {
      /*
       * the copy and no copy cases are identical because db_make_numeric
       * will copy the bits into its internal buffer.
       */
      (void) db_make_numeric (value, (DB_C_NUMERIC) buf->ptr, domain->precision, domain->scale);
      value->need_clear = false;
      rc = or_advance (buf, size);
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_numeric (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return mr_data_cmpdisk_numeric (mem1, mem2, domain, do_coercion, total_order, start_colp);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_numeric (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c = DB_UNK;
  OR_BUF buf;
  DB_VALUE value1, value2;
  DB_VALUE answer;
  int rc = NO_ERROR;

  assert (domain != NULL);

  or_init (&buf, (char *) mem1, 0);
  rc = mr_data_readval_numeric (&buf, &value1, domain, -1, 0, NULL, 0);
  if (rc != NO_ERROR)
    {
      return DB_UNK;
    }

  or_init (&buf, (char *) mem2, 0);
  rc = mr_data_readval_numeric (&buf, &value2, domain, -1, 0, NULL, 0);
  if (rc != NO_ERROR)
    {
      return DB_UNK;
    }

  rc = numeric_db_value_compare (&value1, &value2, &answer);
  if (rc != NO_ERROR)
    {
      return DB_UNK;
    }

  c = MR_CMP_RETURN_CODE (db_get_int (&answer));

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_numeric (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
           int collation)
{
  DB_VALUE_COMPARE_RESULT c = DB_UNK;
  DB_VALUE answer;

  if (numeric_db_value_compare (value1, value2, &answer) != NO_ERROR)
    {
      return DB_UNK;
    }

  if (db_get_int (&answer) < 0)
    {
      c = DB_LT;
    }
  else
    {
      if (db_get_int (&answer) > 0)
    {
      c = DB_GT;
    }
      else
    {
      c = DB_EQ;
    }
    }

  return c;
}

/*
 * PRIMITIVE TYPE SUPPORT ROUTINES
 */

/*
 * pr_type_from_id - maps a type identifier such as DB_TYPE_INTEGER into its
 * corresponding primitive type descriptor structures.
 *    return: type descriptor
 *    id(in): type identifier constant
 */
const PR_TYPE *
pr_type_from_id (DB_TYPE id)
{
  const PR_TYPE *type = NULL;

  if (id <= DB_TYPE_LAST && id != DB_TYPE_TABLE)
    {
      type = tp_Type_id_map[(int) id];
    }

  return type;
}


/*
 * pr_type_name - Returns the string type name associated with a type constant.
 *    return: type name
 *    id(in): type identifier constant
 * Note:
 *    The string must not be freed after use.
 */
const char *
pr_type_name (DB_TYPE id)
{
  const char *name = NULL;
  const PR_TYPE *type;

  type = pr_type_from_id (id);

  if (type != NULL)
    {
      name = type->name;
    }

  return name;
}

/*
 * pr_is_variable_type - determine whether or not a type is fixed or variable
 * width on disk.
 *    return: non-zero if this is a variable width type
 *    id(in): type id
 * Note:
 *    With the advent of parameterized types like CHAR(n), NUMERIC(p,s) etc.
 *    this doesn't mean that all values of this type will be the same size,
 *    it means that for any particular attribute of a class, they will all be
 *    the same size and the value will be stored in the "fixed" region of the
 *    disk representation.
 */
int
pr_is_variable_type (DB_TYPE id)
{
  const PR_TYPE *type;
  int is_variable = 0;

  type = pr_type_from_id (id);
  if (type != NULL)
    {
      is_variable = type->variable_p;
    }

  return is_variable;
}

/*
 * pr_find_type - Locate a type descriptor given a name.
 *    return: type structure
 *    name(in): type name
 * Note:
 *    Called by the schema manager to map a domain name into a primitive
 *    type.
 *    This now recognizes some alias names for a few of the types.
 *    The aliases should be more centrally defined so the parser can
 *    check for them.
 *
 */
const PR_TYPE *
pr_find_type (const char *name)
{
  const PR_TYPE *type, *found;
  int i;

  if (name == NULL)
    {
      return NULL;
    }

  found = NULL;
  for (i = DB_TYPE_FIRST; i <= DB_TYPE_LAST && found == NULL; i++)
    {
      type = tp_Type_id_map[i];
      if (type->name != NULL)
    {
      if (intl_mbs_casecmp (name, type->name) == 0)
        {
          found = type;
        }
    }
    }

  /* alias kludge */
  if (found == NULL)
    {
      if (intl_mbs_casecmp (name, "int") == 0)
    {
      found = tp_Type_integer;
    }
      else if (intl_mbs_casecmp (name, "multi_set") == 0)
    {
      found = tp_Type_multiset;
    }

      else if (intl_mbs_casecmp (name, "short") == 0)
    {
      found = tp_Type_short;
    }

      else if (intl_mbs_casecmp (name, "string") == 0)
    {
      found = tp_Type_string;
    }
      else if (intl_mbs_casecmp (name, "utime") == 0)
    {
      found = tp_Type_utime;
    }

      else if (intl_mbs_casecmp (name, "list") == 0)
    {
      found = tp_Type_sequence;
    }
    }

  return found;
}

/*
 * SIZE CALCULATORS
 * These operation on the instance memory format of data values.
 */


/*
 * pr_mem_size - Determine the number of bytes required for the memory
 * representation of a particular type.
 *    return: memory size of type
 *    type(in): const PR_TYPE structure
 * Note:
 *    This only determines the size for an attribute value in contiguous
 *    memory storage for an instance.
 *    It does not include the size of any reference memory (like strings.
 *    For strings, it returns the size of the pointer NOT the length
 *    of the string.
 *
 */
int
pr_mem_size (const PR_TYPE * type)
{
  return type->size;
}

/*
 * DB_VALUE TRANSFORMERS
 *
 * Used in the storage of class objects.
 * Need to fully extend this into the variabe type above so these can
 * be used at attribute values as well.
 *
 * Predicate processor must be able to understand these if we can issue
 * queries on these.
 *
 * This needs to be merged with the partially implemented support
 * for tp_Type_variable above.
 *
 * These functions will be called with a DB_DATA union NOT a pointer to
 * the memory representation of an attribute.
 */


/*
 * pr_value_mem_size - Returns the amount of storage necessary to hold the
 * contents of a DB_VALUE.
 *    return: byte size used by contents of DB_VALUE
 *    value(in): value to examine
 * Note:
 *    Does not include the amount of space necessary for the DB_VALUE.
 *    Used by some statistics modules that calculate memory sizes of structures.
 */
int
pr_value_mem_size (const DB_VALUE * value)
{
  const PR_TYPE *type;
  DB_TYPE dbval_type;

  dbval_type = DB_VALUE_DOMAIN_TYPE (value);
  type = pr_type_from_id (dbval_type);
  assert (type != NULL);
  if (type != NULL)
    {
      return type->get_mem_size_of_value (value);
    }
  else
    {
      return 0;
    }
}

/*
 * pr_midxkey_get_vals_size() -
 *      return: int
 *  domains(in) :
 *  dbvals(in) :
 *  total(in) :
 *
 */

static int
pr_midxkey_get_vals_size (TP_DOMAIN * domains, DB_VALUE * dbvals, int total)
{
  TP_DOMAIN *dom;
  int i;

  for (dom = domains, i = 0; dom; dom = dom->next, i++)
    {
      if (DB_IS_NULL (&dbvals[i]))
    {
      continue;
    }

      total += pr_index_writeval_disk_size (&dbvals[i]);
    }

  return total;
}

/*
 * pr_midxkey_get_element_offset - Returns element offset of midxkey
 *    return:
 *    midxkey(in):
 *    index(in):
 */
int
pr_midxkey_get_element_offset (const DB_MIDXKEY * midxkey, int index)
{
  TP_DOMAIN *domain;
  int idx_ncols = 0, i;
  OR_BUF buf;
  char *nullmap_ptr;
  int offset, advance_size;

  idx_ncols = midxkey->domain->precision;
  if (idx_ncols <= 0)
    {
      assert (false);
      goto exit_on_error;
    }

  if (index >= midxkey->ncolumns)
    {
      assert (false);
      goto exit_on_error;
    }

  /* get domain list, attr number */
  domain = midxkey->domain->setdomain;  /* first element's domain */

  or_init (&buf, midxkey->buf, midxkey->size);

  nullmap_ptr = midxkey->buf;

  if (or_advance (&buf, or_multi_header_size (idx_ncols)) != NO_ERROR)
    {
      goto exit_on_error;
    }

  offset = or_multi_get_element_offset (nullmap_ptr, idx_ncols, index);
  if (offset > 0)
    {
      return offset;
    }
  else
    {
      for (i = 0; i < index; i++, domain = domain->next)
    {
      /* check for element is NULL */
      if (or_multi_is_null (nullmap_ptr, i))
        {
          continue;
        }

      advance_size = pr_midxkey_element_disk_size (buf.ptr, domain);
      or_advance (&buf, advance_size);
    }
    }

  if (er_errid () != NO_ERROR)
    {
      goto exit_on_error;
    }

  return CAST_BUFLEN (buf.ptr - buf.buffer);

exit_on_error:

  assert (false);
  return -1;
}

/*
 * pr_midxkey_add_prefix -
 *
 *    return:
 *    prefix(in):
 *    postfix(in):
 *    result(out):
 *    n_prefix(in):
 */
int
pr_midxkey_add_prefix (DB_VALUE * result, DB_VALUE * prefix, DB_VALUE * postfix, int n_prefix)
{
  int i, offset, offset_postfix, offset_prefix;
  DB_MIDXKEY *midx_prefix, *midx_postfix;
  DB_MIDXKEY midx_result;
  int prefix_size;

  assert (DB_VALUE_TYPE (prefix) == DB_TYPE_MIDXKEY);
  assert (DB_VALUE_TYPE (postfix) == DB_TYPE_MIDXKEY);

  midx_prefix = db_get_midxkey (prefix);
  midx_postfix = db_get_midxkey (postfix);

  offset_prefix = pr_midxkey_get_element_offset (midx_prefix, n_prefix);
  offset_postfix = pr_midxkey_get_element_offset (midx_postfix, n_prefix);

  midx_result.size = offset_prefix + (midx_postfix->size - offset_postfix);
  midx_result.buf = (char *) db_private_alloc (NULL, midx_result.size);
  if (midx_result.buf == NULL)
    {
      return ER_FAILED;
    }
  midx_result.domain = midx_postfix->domain;
  midx_result.ncolumns = midx_postfix->ncolumns;

  memcpy (midx_result.buf, midx_prefix->buf, offset_prefix);
  memcpy (midx_result.buf + offset_prefix, midx_postfix->buf + offset_postfix, midx_postfix->size - offset_postfix);

#if !defined(NDEBUG)
  for (i = 0; i < n_prefix; i++)
    {
      /* Compressed columns must be null. */
      assert (or_multi_is_null (midx_postfix->buf, i));
    }
#endif

  i = n_prefix;
  prefix_size = offset_prefix - or_multi_header_size (midx_prefix->domain->precision);

  if (prefix_size < OR_MULTI_MAX_OFFSET)
    {
      /* fallthrough: i */
      for (; i < midx_postfix->domain->precision; i++)
    {
      /* update nullmap */
      if (or_multi_is_not_null (midx_postfix->buf, i))
        {
          or_multi_set_not_null (midx_result.buf, i);
        }
      else
        {
          /* The lower fence key stores from the first column to the columns that begin to differ when compared
           * to the upper fence key of the previous page. The number of columns in which the fence key stores
           * the value is unrelated to whether or not it is compressed. Therefore, even for columns after prefix,
           * it is not guaranteed that the fence key will always store null. */
          or_multi_set_null (midx_result.buf, i);
        }

      /* update offset */
      offset = or_multi_get_next_element_offset (midx_postfix->buf, midx_postfix->domain->precision, i);
      if (offset > 0 && (offset + prefix_size) < OR_MULTI_MAX_OFFSET)
        {
          or_multi_put_next_element_offset (midx_result.buf, midx_result.domain->precision, offset + prefix_size,
                        i);
        }
      else
        {
          break;
        }
    }
    }

  assert (prefix_size >= OR_MULTI_MAX_OFFSET || i == midx_postfix->domain->precision || offset <= 0);

  /* fallthrough: i */
  for (; i < midx_postfix->domain->precision; i++)
    {
      /* update nullmap */
      if (or_multi_is_not_null (midx_postfix->buf, i))
    {
      or_multi_set_not_null (midx_result.buf, i);
    }
      else
    {
      /* The lower fence key stores from the first column to the columns that begin to differ when compared
       * to the upper fence key of the previous page. The number of columns in which the fence key stores
       * the value is unrelated to whether or not it is compressed. Therefore, even for columns after prefix,
       * it is not guaranteed that the fence key will always store null. */
      or_multi_set_null (midx_result.buf, i);
    }

      /* update offset */
      or_multi_put_next_element_offset (midx_result.buf, midx_result.domain->precision, OR_MULTI_MAX_OFFSET, i);
    }

  midx_result.min_max_val.position = -1;
  midx_result.min_max_val.type = MIN_COLUMN;
  db_make_midxkey (result, &midx_result);
  result->need_clear = true;

  assert (midx_result.size == or_multi_get_size_offset (midx_result.buf, midx_result.domain->precision)
      || midx_result.size >= OR_MULTI_MAX_OFFSET);

  return NO_ERROR;
}

/*
 * pr_midxkey_remove_prefix -
 *
 *    return:
 *    key(in):
 *    prefix(in):
 */
int
pr_midxkey_remove_prefix (DB_VALUE * key, int prefix)
{
  DB_MIDXKEY *midx_key;
  TP_DOMAIN *domain;
  char *buf_ptr;
  int i, start, offset;
  int prefix_size, advance_size;

  midx_key = db_get_midxkey (key);

  start = pr_midxkey_get_element_offset (midx_key, 0);
  offset = pr_midxkey_get_element_offset (midx_key, prefix);

  memmove (midx_key->buf + start, midx_key->buf + offset, midx_key->size - offset);

  for (i = 0, domain = midx_key->domain->setdomain; i < prefix; i++, domain = domain->next)
    {
      or_multi_set_null (midx_key->buf, i);
      or_multi_put_next_element_offset (midx_key->buf, midx_key->domain->precision, start, i);
    }

  assert (i == prefix);
  assert (domain != midx_key->domain->setdomain);

  prefix_size = offset - start;

  /* fallthrough: i, domain */
  for (; i < midx_key->domain->precision; i++, domain = domain->next)
    {
      offset = or_multi_get_next_element_offset (midx_key->buf, midx_key->domain->precision, i);
      if (offset > 0)
    {
      or_multi_put_next_element_offset (midx_key->buf, midx_key->domain->precision, offset - prefix_size, i);
    }
      else
    {
      break;
    }
    }

  assert (i == midx_key->domain->precision || offset <= 0);

  if (i < midx_key->domain->precision)
    {
      /* recalculate offset */
      offset = or_multi_get_element_offset (midx_key->buf, midx_key->domain->precision, i);
      assert (offset > 0);
      assert (offset < OR_MULTI_MAX_OFFSET);

      buf_ptr = midx_key->buf + offset;

      /* fallthrough: i, domain */
      for (; i < midx_key->domain->precision; i++, domain = domain->next)
    {
      if (or_multi_is_null (midx_key->buf, i))
        {
          or_multi_put_next_element_offset (midx_key->buf, midx_key->domain->precision, offset, i);
          continue;
        }

      advance_size = pr_midxkey_element_disk_size (buf_ptr, domain);
      if ((offset + advance_size) < OR_MULTI_MAX_OFFSET)
        {
          or_multi_put_next_element_offset (midx_key->buf, midx_key->domain->precision, offset + advance_size, i);
          offset += advance_size;
          buf_ptr += advance_size;
        }
      else
        {
          break;
        }
    }

      /* fallthrough: i, domain */
      for (; i < midx_key->domain->precision; i++, domain = domain->next)
    {
      or_multi_put_next_element_offset (midx_key->buf, midx_key->domain->precision, OR_MULTI_MAX_OFFSET, i);
    }
    }

  midx_key->size -= prefix_size;

  assert (midx_key->size == or_multi_get_size_offset (midx_key->buf, midx_key->domain->precision)
      || midx_key->size >= OR_MULTI_MAX_OFFSET);

  return NO_ERROR;
}

/*
 * pr_midxkey_common_prefix -
 *
 *    return:
 *    key1(in):
 *    key2(in):
 */
int
pr_midxkey_common_prefix (DB_VALUE * key1, DB_VALUE * key2)
{
  int diff_column, ret;
  DB_MIDXKEY *midx_lf_key, *midx_uf_key;

  assert (DB_VALUE_TYPE (key1) == DB_TYPE_MIDXKEY);
  assert (DB_VALUE_TYPE (key2) == DB_TYPE_MIDXKEY);

  diff_column = 0;      /* init */

  midx_lf_key = db_get_midxkey (key1);
  midx_uf_key = db_get_midxkey (key2);

  ret = pr_midxkey_compare (midx_lf_key, midx_uf_key, 0, 1, -1, NULL, &diff_column, NULL, NULL);

  if (ret == DB_UNK)
    {
      assert (false);
      diff_column = 0;
    }

  return diff_column;
}

/*
 * pr_midxkey_get_element_internal()
 *      return:
 *  midxkey(in) :
 *  index(in) :
 *  value(in) :
 *  copy(in) :
 *  prev_indexp(in) :
 *  prev_ptrp(in) :
 */

static int
pr_midxkey_get_element_internal (const DB_MIDXKEY * midxkey, int index, DB_VALUE * value, bool copy, int *prev_indexp,
                 char **prev_ptrp)
{
  TP_DOMAIN *domain;
  int idx_ncols;
  OR_BUF buf;
  char *nullmap_ptr;
  int offset, advance_size;
  int i;
  int error = NO_ERROR;

  idx_ncols = midxkey->domain->precision;
  if (idx_ncols <= 0)
    {
      assert (false);
      goto exit_on_error;
    }

  if (index >= midxkey->ncolumns)
    {
      assert (false);
      goto exit_on_error;
    }

#if !defined (NDEBUG)
  {
    int dom_ncols = 0;

    for (domain = midxkey->domain->setdomain; domain; domain = domain->next)
      {
    dom_ncols++;
      }

    if (dom_ncols <= 0)
      {
    assert (false);
    goto exit_on_error;
      }
    assert (dom_ncols == idx_ncols);
  }
#endif /* NDEBUG */

  /* get bit-mask */
  nullmap_ptr = midxkey->buf;

  /* get domain list, attr number */
  domain = midxkey->domain->setdomain;  /* first element's domain */

  if (or_multi_is_null (nullmap_ptr, index))
    {
      db_make_null (value);
    }
  else
    {
      i = 0;

      or_init (&buf, midxkey->buf, midxkey->size);
      or_advance (&buf, or_multi_header_size (idx_ncols));

      offset = or_multi_get_element_offset (midxkey->buf, idx_ncols, index);
      if (offset > 0)
    {
      or_seek (&buf, offset);

      for (i = 0; i < index; i++, domain = domain->next)
        {
          assert (domain != NULL);
        }
    }
      else
    {
      if (prev_indexp && prev_ptrp)
        {
          offset = CAST_BUFLEN (*prev_ptrp - midxkey->buf);

          if (*prev_indexp <= 0 || *prev_indexp > index || offset <= 0)
        {       /* invalid info */
          /* nop */
        }
          else
        {
          or_seek (&buf, offset);

          for (i = 0; i < *prev_indexp; i++, domain = domain->next)
            {
              assert (domain != NULL);
            }
        }
        }

      for (; i < index; i++, domain = domain->next)
        {
          /* check for element is NULL */
          if (or_multi_is_null (nullmap_ptr, i))
        {
          continue; /* skip and go ahead */
        }

          advance_size = pr_midxkey_element_disk_size (buf.ptr, domain);
          or_advance (&buf, advance_size);
        }
    }

      error = domain->type->index_readval (&buf, value, domain, -1, copy, NULL, 0);
      if (error != NO_ERROR)
    {
      goto exit_on_error;
    }

      /* save the next index info */
      if (prev_indexp && prev_ptrp)
    {
      *prev_indexp = index + 1;
      *prev_ptrp = buf.ptr;
    }
    }

exit_on_end:

  return error;

exit_on_error:

  if (error == NO_ERROR)
    {
      error = -1;       /* set error */
    }

  goto exit_on_end;
}

/*
 * pr_midxkey_unique_prefix () -
 *      return: NO_ERROR or error code.
 *
 *  db_midxkey1(in) : Left side of compare.
 *  db_midxkey2(in) : Right side of compare.
 *  db_result(out) : midxkey such that > midxkey1, and <= midxkey2.
 *                                  or < midxkey1, and >= midxkey2 (desc)
 *
 * Note:
 *
 */
int
pr_midxkey_unique_prefix (const DB_VALUE * db_midxkey1, const DB_VALUE * db_midxkey2, DB_VALUE * db_result)
{
  DB_VALUE_COMPARE_RESULT c = DB_UNK;
  int i, offset;
  int size_buf[2], diff_column;
  bool dom_is_desc[2];
  int result_size = 0;
  char *result_buf;
  DB_MIDXKEY *midxkey1, *midxkey2;
  DB_MIDXKEY result_midxkey;

  /* Assertions */
  assert (db_midxkey1 != (DB_VALUE *) NULL);
  assert (db_midxkey2 != (DB_VALUE *) NULL);
  assert (db_result != (DB_VALUE *) NULL);

  midxkey1 = db_get_midxkey (db_midxkey1);
  midxkey2 = db_get_midxkey (db_midxkey2);

  assert (midxkey1->size != -1);
  assert (midxkey2->size != -1);
  assert (midxkey1->ncolumns == midxkey2->ncolumns);
  assert (midxkey1->domain == midxkey2->domain);
  assert (midxkey1->domain->setdomain == midxkey2->domain->setdomain);

  c = pr_midxkey_compare (midxkey1, midxkey2, 0, 1, -1, NULL, &diff_column, dom_is_desc, size_buf);
  if (dom_is_desc[0])
    {
      c = ((c == DB_GT) ? DB_LT : (c == DB_LT) ? DB_GT : c);
    }

  assert (c == DB_LT);
  if (c != DB_LT)
    {
      return (er_errid () == NO_ERROR) ? ER_FAILED : er_errid ();
    }

  if (size_buf[0] == midxkey1->size || size_buf[1] == midxkey2->size
      || or_multi_is_null (midxkey1->buf, diff_column + 1) || or_multi_is_null (midxkey2->buf, diff_column + 1))
    {
      /* not found separator: give up */
      pr_clone_value (db_midxkey2, db_result);
    }
  else
    {
      assert (size_buf[0] < midxkey1->size);
      assert (size_buf[1] < midxkey2->size);

      if (!dom_is_desc[1])
    {
      result_buf = midxkey2->buf;
      result_size = size_buf[1];
    }
      else
    {
      result_buf = midxkey1->buf;
      result_size = size_buf[0];
    }

      result_midxkey.buf = (char *) db_private_alloc (NULL, result_size);
      if (result_midxkey.buf == NULL)
    {
      /* will already be set by memory mgr */
      assert (er_errid () != NO_ERROR);
      return er_errid ();
    }

      memcpy (result_midxkey.buf, result_buf, result_size);
      result_midxkey.size = result_size;
      result_midxkey.domain = midxkey2->domain;
      result_midxkey.ncolumns = midxkey2->ncolumns;

      offset = or_multi_get_next_element_offset (result_midxkey.buf, result_midxkey.domain->precision, diff_column);
      if (offset < 0)
    {
      offset = OR_MULTI_MAX_OFFSET;
    }

      for (i = diff_column + 1; i < result_midxkey.domain->precision; i++)
    {
      or_multi_set_null (result_midxkey.buf, i);
      or_multi_put_next_element_offset (result_midxkey.buf, result_midxkey.domain->precision, offset, i);
    }

      or_multi_put_size_offset (result_midxkey.buf, result_midxkey.domain->precision, result_midxkey.size);

      result_midxkey.min_max_val.position = -1;
      result_midxkey.min_max_val.type = MIN_COLUMN;
      db_make_midxkey (db_result, &result_midxkey);

      db_result->need_clear = true;

#if !defined(NDEBUG)
      /* midxkey1 < result_midxkey */
      c = pr_midxkey_compare (midxkey1, &result_midxkey, 0, 1, -1, NULL, &diff_column, dom_is_desc, NULL);
      assert (c == DB_UNK || (DB_LT <= c && c <= DB_GT));
      if (dom_is_desc[0])
    {
      c = ((c == DB_GT) ? DB_LT : (c == DB_LT) ? DB_GT : c);
    }
      assert (c == DB_LT);

      /* result_midxkey <= midxkey2 */
      c = pr_midxkey_compare (&result_midxkey, midxkey2, 0, 1, -1, NULL, &diff_column, dom_is_desc, NULL);
      assert (c == DB_UNK || (DB_LT <= c && c <= DB_GT));
      if (dom_is_desc[0])
    {
      c = ((c == DB_GT) ? DB_LT : (c == DB_LT) ? DB_GT : c);
    }

      assert (c == DB_LT || c == DB_EQ);
#endif
    }

  return NO_ERROR;
}

/*
 * pr_midxkey_get_element_nocopy() -
 *      return: error code
 *  midxkey(in) :
 *  index(in) :
 *  value(in) :
 *  prev_indexp(in) :
 *  prev_ptrp(in) :
 */

int
pr_midxkey_get_element_nocopy (const DB_MIDXKEY * midxkey, int index, DB_VALUE * value, int *prev_indexp,
                   char **prev_ptrp)
{
  return pr_midxkey_get_element_internal (midxkey, index, value, false /* not copy */ ,
                      prev_indexp, prev_ptrp);
}

int
pr_midxkey_add_elements (DB_VALUE * keyval, DB_VALUE * dbvals, int num_dbvals, struct tp_domain *dbvals_domain_list)
{
  TP_DOMAIN *dom;
  DB_MIDXKEY *midxkey;
  int i, total_size, header_size;
  char *new_IDXbuf;
  char *nullmap_ptr;
  OR_BUF buf;

  /* phase 1: find old */
  midxkey = db_get_midxkey (keyval);
  if (midxkey == NULL)
    {
      return ER_FAILED;
    }

  if (midxkey->ncolumns > 0 && midxkey->size > 0)
    {
      assert (midxkey->domain->precision == midxkey->ncolumns + num_dbvals);
      header_size = or_multi_header_size (midxkey->domain->precision);
      total_size = midxkey->size;
    }
  else
    {
      header_size = or_multi_header_size (num_dbvals);
      total_size = header_size;
    }

  /* phase 2: calculate how many bytes need */
  total_size = pr_midxkey_get_vals_size (dbvals_domain_list, dbvals, total_size);

  /* phase 3: initialize new_IDXbuf */
  new_IDXbuf = (char *) db_private_alloc (NULL, total_size);
  if (new_IDXbuf == NULL)
    {
      goto error;
    }

  or_init (&buf, new_IDXbuf, -1);

  nullmap_ptr = new_IDXbuf;

  /* phase 4: copy new_IDXbuf from old */
  if (midxkey->ncolumns > 0 && midxkey->size > 0)
    {
      or_put_data (&buf, midxkey->buf, midxkey->size);
    }
  else
    {
      or_multi_clear_header (nullmap_ptr, num_dbvals);
      or_advance (&buf, header_size);
    }

  for (i = 0, dom = dbvals_domain_list; i < num_dbvals; i++, dom = dom->next)
    {
      or_multi_put_element_offset (nullmap_ptr, midxkey->domain->precision, CAST_BUFLEN (buf.ptr - buf.buffer),
                   midxkey->ncolumns + i);

      /* check for added val is NULL */
      if (DB_IS_NULL (&dbvals[i]))
    {
      continue;     /* skip and go ahead */
    }

      dom->type->index_writeval (&buf, &dbvals[i]);

      or_multi_set_not_null (nullmap_ptr, midxkey->ncolumns + i);
    }               /* for (i = 0, ...) */

  assert (total_size == CAST_BUFLEN (buf.ptr - buf.buffer));

  or_multi_put_size_offset (nullmap_ptr, midxkey->domain->precision, total_size);

  /* phase 5: make new multiIDX */
  if (midxkey->size > 0)
    {
      db_private_free_and_init (NULL, midxkey->buf);
      midxkey->buf = NULL;
    }

  midxkey->buf = new_IDXbuf;
  midxkey->size = total_size;
  midxkey->ncolumns += num_dbvals;

  return NO_ERROR;

error:

  if (midxkey->buf)
    {
      db_private_free_and_init (NULL, midxkey->buf);
      midxkey->buf = NULL;
    }
  return ER_FAILED;
}

/* support for SUPPORT_DEDUPLICATE_KEY_MODE */
int
pr_midxkey_add_elements_with_null (DB_VALUE * keyval, DB_VALUE * dbvals, int num_dbvals,
                   struct tp_domain *dbvals_domain_list, int tail_null_cnt)
{
  TP_DOMAIN *dom;
  DB_MIDXKEY *midxkey;
  int i, total_size, header_size, offset;
  char *new_IDXbuf;
  char *nullmap_ptr;
  OR_BUF buf;

  /* phase 1: find old */
  midxkey = db_get_midxkey (keyval);
  if (midxkey == NULL)
    {
      return ER_FAILED;
    }

  assert (midxkey->ncolumns == 0 && midxkey->size == 0);

  header_size = or_multi_header_size (num_dbvals + tail_null_cnt);
  total_size = header_size;

  /* phase 2: calculate how many bytes need */
  total_size = pr_midxkey_get_vals_size (dbvals_domain_list, dbvals, total_size);

  /* phase 3: initialize new_IDXbuf */
  new_IDXbuf = (char *) db_private_alloc (NULL, total_size);
  if (new_IDXbuf == NULL)
    {
      return ER_FAILED;
    }

  or_init (&buf, new_IDXbuf, -1);

  nullmap_ptr = new_IDXbuf;
  or_multi_clear_header (nullmap_ptr, num_dbvals + tail_null_cnt);

  or_advance (&buf, header_size);

  /* phase 4: copy new_IDXbuf from old */
  for (i = 0, dom = dbvals_domain_list; i < num_dbvals; i++, dom = dom->next)
    {
      /* check for added val is NULL */
      if (DB_IS_NULL (&dbvals[i]))
    {
      continue;     /* skip and go ahead */
    }

      dom->type->index_writeval (&buf, &dbvals[i]);

      or_multi_set_not_null (nullmap_ptr, midxkey->ncolumns + i);
    }               /* for (i = 0, ...) */

  assert (total_size == CAST_BUFLEN (buf.ptr - buf.buffer));

  for (i = num_dbvals; i < (num_dbvals + tail_null_cnt); i++)
    {
      assert (or_multi_is_null (nullmap_ptr, i));
      or_multi_put_element_offset (nullmap_ptr, num_dbvals + tail_null_cnt, total_size, i);
    }

  or_multi_put_size_offset (nullmap_ptr, midxkey->ncolumns + num_dbvals + tail_null_cnt, total_size);

  midxkey->buf = new_IDXbuf;
  midxkey->size = total_size;
  midxkey->ncolumns += (num_dbvals + tail_null_cnt);

  return NO_ERROR;
}

/*
 * pr_data_writeval_disk_size - returns the number of bytes that will be
 * written by the "writeval" type function for this value.
 *    return: byte size of disk representation
 *    value(in): db value
 * Note:
 *    It is generally used prior to writing the value to pre-calculate the
 *    required size.
 *    Formerly called pr_value_disk_size.
 *
 *    Note that "writeval" is used for the construction of disk objects,
 *    and it will leave space for fixed width types that are logically
 *    NULL.  If you need a compressed representation for random values,
 *    look at the or_put_value family of functions.
 */
int
pr_data_writeval_disk_size (DB_VALUE * value)
{
  const PR_TYPE *type;
  DB_TYPE dbval_type;

  dbval_type = DB_VALUE_DOMAIN_TYPE (value);
  type = pr_type_from_id (dbval_type);

  assert (type != NULL);

  if (type)
    {
      return type->get_disk_size_of_value (value);
    }

  return 0;
}

/*
 * pr_index_writeval_disk_size - returns the number of bytes that will be
 * written by the "index_write" type function for this value.
 *    return: byte size of disk representation
 *    value(in): db value
 * Note:
 */
int
pr_index_writeval_disk_size (DB_VALUE * value)
{
  const PR_TYPE *type;
  DB_TYPE dbval_type;

  dbval_type = DB_VALUE_DOMAIN_TYPE (value);
  type = pr_type_from_id (dbval_type);

  assert (type != NULL);

  if (type)
    {
      return type->get_index_size_of_value (value);
    }

  return 0;
}

void
pr_data_writeval (struct or_buf *buf, DB_VALUE * value)
{
  const PR_TYPE *type;
  DB_TYPE dbval_type;

  dbval_type = DB_VALUE_DOMAIN_TYPE (value);
  type = pr_type_from_id (dbval_type);
  if (type == NULL)
    {
      type = tp_Type_null;  /* handle strange arguments with NULL */
    }
  type->data_writeval (buf, value);
}

/*
 * MISCELLANEOUS TYPE-RELATED HELPER FUNCTIONS
 */

/*
 * pr_valstring - Take the value and formats it using the sptrfunc member of
 * the pr_type vector for the appropriate type.
 *    return: a freshly db_private_realloc()'ed string with a printed rep of "val" in it
 *    val(in): some DB_VALUE
 * Note:
 *    The caller is responsible for eventually freeing the memory using db_private_free()
 *
 *    This is really just a debugging helper; it probably doesn't do enough
 *    serious formatting for external use.  Use it to get printed DB_VALUE
 *    representations into error messages and the like.
 */
char *
pr_valstring (const DB_VALUE * val)
{
  const size_t BUFFER_SIZE = 1024;
  string_buffer sb (cubmem::PRIVATE_BLOCK_ALLOCATOR, BUFFER_SIZE);

  if (val == NULL || DB_IS_NULL (val))
    {
      /* space with terminating NULL */
      sb ("(null)");
    }
  else
    {
      db_sprint_value (val, sb);
    }

  return sb.release_ptr (); //caller should use db_private_free() to deallocate it
}

/*
 * pr_complete_enum_value - Sets both index and string of a enum value in case
 *    one of them is missing.
 *    return: NO_ERROR or error code.
 *    value(in/out): enumeration value.
 *    domain(in): enumeration domain against which the value is checked.
 */
int
pr_complete_enum_value (DB_VALUE * value, struct tp_domain *domain)
{
  unsigned short short_val;
  const char *str_val;
  int enum_count, str_val_size, idx;
  DB_ENUM_ELEMENT *db_elem = 0;

  if (value == NULL || domain == NULL || DB_IS_NULL (value))
    {
      return NO_ERROR;
    }

  if (value->domain.general_info.type != DB_TYPE_ENUMERATION || domain->type->id != DB_TYPE_ENUMERATION)
    {
      return ER_FAILED;
    }

  short_val = db_get_enum_short (value);
  str_val = db_get_enum_string (value);
  str_val_size = db_get_enum_string_size (value);
  enum_count = DOM_GET_ENUM_ELEMS_COUNT (domain);
  if (short_val > enum_count)
    {
      return ER_FAILED;
    }

  if (short_val > 0)
    {
      db_elem = &DOM_GET_ENUM_ELEM (domain, short_val);
      if (str_val != NULL && DB_GET_ENUM_ELEM_STRING_SIZE (db_elem) == str_val_size
      && !memcmp (str_val, DB_GET_ENUM_ELEM_STRING (db_elem), str_val_size))
    {
      db_make_enumeration (value, short_val, str_val, str_val_size, DB_GET_ENUM_ELEM_CODESET (db_elem),
                   db_get_enum_collation (value));
      return NO_ERROR;
    }
      pr_clear_value (value);

      str_val_size = DB_GET_ENUM_ELEM_STRING_SIZE (db_elem);
      char *str_val_tmp = (char *) db_private_alloc (NULL, str_val_size + 1);
      if (str_val_tmp == NULL)
    {
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }
      memcpy (str_val_tmp, DB_GET_ENUM_ELEM_STRING (db_elem), str_val_size);
      str_val_tmp[str_val_size] = 0;
      str_val = str_val_tmp;

      db_make_enumeration (value, short_val, str_val, str_val_size, DB_GET_ENUM_ELEM_CODESET (db_elem),
               db_get_enum_collation (value));
      value->need_clear = true;

      return NO_ERROR;
    }
  else if (str_val == NULL)
    {
      /* empty string enum value with index 0 */
      return NO_ERROR;
    }

  for (idx = 0; idx < enum_count; idx++)
    {
      db_elem = &DOM_GET_ENUM_ELEM (domain, idx + 1);
      if (DB_GET_ENUM_ELEM_STRING_SIZE (db_elem) == str_val_size
      && !memcmp (DB_GET_ENUM_ELEM_STRING (db_elem), str_val, str_val_size))
    {
      db_make_enumeration (value, DB_GET_ENUM_ELEM_SHORT (db_elem), str_val, str_val_size,
                   DB_GET_ENUM_ELEM_CODESET (db_elem), db_get_enum_collation (value));
      break;
    }
    }

  return NO_ERROR;
}

/*
 * TYPE RESULTSET
 */

static void
mr_initmem_resultset (void *mem, TP_DOMAIN * domain)
{
  *(DB_BIGINT *) mem = 0;
}

static int
mr_setmem_resultset (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value != NULL)
    {
      *(DB_BIGINT *) mem = db_get_resultset (value);
    }
  else
    {
      mr_initmem_resultset (mem, domain);
    }

  return NO_ERROR;
}

static int
mr_getmem_resultset (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  return db_make_resultset (value, *(DB_BIGINT *) mem);
}

static void
mr_data_writemem_resultset (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  or_put_bigint (buf, *(DB_BIGINT *) mem);
}

static void
mr_data_readmem_resultset (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  int rc = NO_ERROR;

  if (mem == NULL)
    {
      or_advance (buf, tp_ResultSet.disksize);
    }
  else
    {
      *(DB_BIGINT *) mem = or_get_bigint (buf, &rc);
    }
}

static void
mr_initval_resultset (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_RESULTSET, precision, scale);
  db_make_resultset (value, 0);
}

static int
mr_setval_resultset (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  if (src && !DB_IS_NULL (src))
    {
      return db_make_resultset (dest, db_get_resultset (src));
    }
  else
    {
      return db_value_domain_init (dest, DB_TYPE_RESULTSET, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }
}

static int
mr_data_writeval_resultset (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_bigint (buf, db_get_resultset (value));
}

static int
mr_data_readval_resultset (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
               int copy_buf_len)
{
  DB_BIGINT temp;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_ResultSet.disksize);
    }
  else
    {
      temp = (DB_BIGINT) or_get_bigint (buf, &rc);
      if (rc == NO_ERROR)
    {
      db_make_resultset (value, temp);
    }
      value->need_clear = false;
    }
  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_resultset (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order,
               int *start_colp)
{
  DB_BIGINT i1, i2;

  assert (domain != NULL);

  /* is not index type */
  assert (!domain->is_desc && !tp_valid_indextype (TP_DOMAIN_TYPE (domain)));

  OR_GET_BIGINT (mem1, &i1);
  OR_GET_BIGINT (mem2, &i2);

  return MR_CMP (i1, i2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_resultset (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
             int collation)
{
  DB_BIGINT i1, i2;

  i1 = db_get_resultset (value1);
  i2 = db_get_resultset (value2);

  return MR_CMP (i1, i2);
}


/*
 * TYPE STRING
 */

static void
mr_initmem_string (void *mem, TP_DOMAIN * domain)
{
  *(char **) mem = NULL;
}


/*
 * The main difference between "memory" strings and "value" strings is that
 * the length tag is stored as an in-line prefix in the memory block allocated
 * to hold the string characters.
 */
static int
mr_setmem_string (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  int error = NO_ERROR;
  const char *src;
  char *cur, *new_, **mem;
  int src_precision, src_length, new_length;

  /* get the current memory contents */
  mem = (char **) memptr;
  cur = *mem;

  if (value == NULL || (src = db_get_string (value)) == NULL)
    {
      /* remove the current value */
      if (cur != NULL)
    {
      db_private_free_and_init (NULL, cur);
      mr_initmem_string (memptr, domain);
    }
    }
  else
    {
      /*
       * Get information from the value.  Ignore precision for the time being
       * since we really only care about the byte size of the value for varchar.
       * Whether or not the value "fits" should have been checked by now.
       */
      src_precision = DB_GET_STRING_PRECISION (value);
      src_length = db_get_string_size (value);  /* size in bytes */

      if (src_length < 0)
    {
      src_length = strlen (src);
    }

      /* Currently we NULL terminate the workspace string. Could try to do the single byte size hack like we have in
       * the disk representation. */
      new_length = src_length + sizeof (int) + 1;
      new_ = (char *) db_private_alloc (NULL, new_length);
      if (new_ == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
      else
    {
      if (cur != NULL)
        {
          db_private_free_and_init (NULL, cur);
        }

      /* pack in the length prefix */
      *(int *) new_ = src_length;
      cur = new_ + sizeof (int);
      /* store the string */
      memcpy (cur, src, src_length);
      /* NULL terminate the stored string for safety */
      cur[src_length] = '\0';
      *mem = new_;
    }
    }

  return error;
}

static int
mr_getmem_string (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int error = NO_ERROR;
  int mem_length;
  char **mem, *cur, *new_;

  /* get to the current value */
  mem = (char **) memptr;
  cur = *mem;

  if (cur == NULL)
    {
      db_value_domain_init (value, DB_TYPE_VARCHAR, domain->precision, 0);
      value->need_clear = false;
    }
  else
    {
      /* extract the length prefix and the pointer to the actual string data */
      mem_length = *(int *) cur;
      cur += sizeof (int);

      if (TP_DOMAIN_COLLATION_FLAG (domain) != TP_DOMAIN_COLL_NORMAL)
    {
      assert (false);
      return ER_FAILED;
    }

      if (!copy)
    {
      db_make_varchar (value, domain->precision, cur, mem_length, TP_DOMAIN_CODESET (domain),
               TP_DOMAIN_COLLATION (domain));
      value->need_clear = false;
    }
      else
    {
      /* return it with a NULL terminator */
      new_ = (char *) db_private_alloc (NULL, mem_length + 1);
      if (new_ == NULL)
        {
          assert (er_errid () != NO_ERROR);
          error = er_errid ();
        }
      else
        {
          memcpy (new_, cur, mem_length);
          new_[mem_length] = '\0';
          db_make_varchar (value, domain->precision, new_, mem_length, TP_DOMAIN_CODESET (domain),
                   TP_DOMAIN_COLLATION (domain));
          value->need_clear = true;
        }
    }
    }
  return error;
}


/*
 * For the disk representation, we may be adding pad bytes to round up to a
 * word boundary.
 *
 * We are currently adding a NULL terminator to the disk representation
 * for some code on the server that still manufactures pointers directly into
 * the disk buffer and assumes it is a NULL terminated string.  This terminator
 * can be removed after the server has been updated.  The logic for maintaining
 * the terminator is actually in the or_put_varchar, family of functions.
 */
static int
mr_data_lengthmem_string (void *memptr, TP_DOMAIN * domain, int disk)
{
  char **mem, *cur;
  int len;

  len = 0;
  if (!disk)
    {
      len = tp_String.size;
    }
  else if (memptr != NULL)
    {
      mem = (char **) memptr;
      cur = *mem;
      if (cur != NULL)
    {
      len = *(int *) cur;
      if (len >= OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION)
        {
          /* Skip the length of the string */
          len = pr_get_compression_length ((cur + sizeof (int)), len) + PRIM_TEMPORARY_DISK_SIZE;
          len = or_packed_varchar_length (len) - PRIM_TEMPORARY_DISK_SIZE;
        }
      else
        {
          len = or_packed_varchar_length (len);
        }
    }
    }

  return len;
}

static int
mr_index_lengthmem_string (void *memptr, TP_DOMAIN * domain)
{
  int charlen;
  OR_BUF buf;
  int rc = NO_ERROR, compressed_length = 0, decompressed_length = 0, length = 0;

  /* generally, index key-value is short enough */
  charlen = OR_GET_BYTE (memptr);
  if (charlen < OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION)
    {
      return or_varchar_length (charlen);
    }

  assert (charlen == OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION);

  or_init (&buf, (char *) memptr, -1);

  rc = or_get_varchar_compression_lengths (&buf, &compressed_length, &decompressed_length);

  if (compressed_length > 0)
    {
      charlen = compressed_length;
    }
  else
    {
      charlen = decompressed_length;
    }
  /* Temporary disk size in case the length of the current buffer is less than 255.
   * Therefore the or_varchar_length will always add the 8 bytes consisting the compressed_length
   * and decompressed_length stored in buffer.
   */

  charlen += PRIM_TEMPORARY_DISK_SIZE;

  length = or_varchar_length (charlen);

  return length - PRIM_TEMPORARY_DISK_SIZE;
}

static void
mr_data_writemem_string (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
  char **mem, *cur;
  int len;

  mem = (char **) memptr;
  cur = *mem;
  if (cur != NULL)
    {
      len = *(int *) cur;
      cur += sizeof (int);
      or_packed_put_varchar (buf, cur, len);
    }
}


/*
 * The amount of memory requested is currently calculated based on the
 * stored size prefix.  If we ever go to a system where we avoid storing the
 * size, then we could use the size argument passed in to this function but
 * that may also include any padding byte that added to bring us up to a word
 * boundary.
 * Might want some way to determine which bytes at the end of a string are
 * padding.
 */
static void
mr_data_readmem_string (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size)
{
  char **mem, *cur, *new_;
  int len;
  int mem_length, pad;
  char *start;
  int rc = NO_ERROR;

  /*
   * we must have an explicit size here as it can't be determined from the
   * domain
   */
  if (size < 0)
    {
      return;
    }

  if (memptr == NULL)
    {
      if (size)
    {
      or_advance (buf, size);
    }
    }
  else
    {
      mem = (char **) memptr;
      cur = *mem;
      /* should we be checking for existing strings ? */
#if 0
      if (cur != NULL)
    db_private_free_and_init (NULL, cur);
#endif

      new_ = NULL;
      if (size)
    {
      int compressed_size;
      start = buf->ptr;

      /* KLUDGE, we have some knowledge of how the thing is stored here in order have some control over the
       * conversion between the packed length prefix and the full word memory length prefix. Might want to put this
       * in another specialized or_ function. */

      /* Get just the length prefix. */
      rc = or_get_varchar_compression_lengths (buf, &compressed_size, &len);
      if (rc != NO_ERROR)
        {
          return;
        }

      /*
       * Allocate storage for this string, including our own full word size
       * prefix and a NULL terminator.
       */
      mem_length = len + sizeof (int) + 1;

      new_ = (char *) db_private_alloc (NULL, mem_length);
      if (new_ == NULL)
        {
          return;
        }
      else
        {
          /* store the length in our memory prefix */
          *(int *) new_ = len;
          cur = new_ + sizeof (int);

          /* decompress buffer (this also writes nul terminator) */
          rc = pr_get_compressed_data_from_buffer (buf, cur, compressed_size, len);
          if (rc != NO_ERROR)
        {
          db_private_free (NULL, new_);
          ASSERT_ERROR ();
          return;
        }
          /* align like or_get_varchar */
          or_get_align32 (buf);
        }

      /* If we were given a size, check to see if for some reason this is larger than the already word aligned
       * string that we have now extracted.  This shouldn't be the case but since we've got a length, we may as
       * well obey it. */
      pad = size - (int) (buf->ptr - start);
      if (pad > 0)
        {
          or_advance (buf, pad);
        }
    }
      *mem = new_;
    }
}

static void
mr_freemem_string (void *memptr)
{
  char *cur;

  if (memptr != NULL)
    {
      cur = *(char **) memptr;
      if (cur != NULL)
    db_private_free_and_init (NULL, cur);
    }
}

static void
mr_initval_string (DB_VALUE * value, int precision, int scale)
{
  db_make_varchar (value, precision, NULL, 0, LANG_SYS_CODESET, LANG_SYS_COLLATION);
  value->need_clear = false;
}

static int
mr_setval_string (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error = NO_ERROR;
  int src_precision, src_length;
  const char *src_str;
  char *new_, *new_compressed_buf;

  assert (!db_value_is_corrupted (src));
  if (src == NULL || DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_VARCHAR, DB_DEFAULT_PRECISION, 0);
    }
  else if ((src_str = db_get_string (src)) == NULL)
    {
      error = db_value_domain_init (dest, DB_TYPE_VARCHAR, db_value_precision (src), 0);
      if (src->data.ch.info.is_max_string)
    {
      dest->data.ch.info.style = MEDIUM_STRING;
      dest->data.ch.info.is_max_string = true;
      dest->domain.general_info.is_null = 0;
      dest->domain.char_info.collation_id = db_get_string_collation (src);
      dest->data.ch.medium.compressed_buf = NULL;
      dest->data.ch.medium.codeset = db_get_string_codeset (src);
      dest->data.ch.medium.compressed_size = DB_UNCOMPRESSABLE;
      dest->data.ch.info.compressed_need_clear = false;
      dest->data.ch.medium.size = 0;
      dest->data.ch.medium.length = -1;
      dest->data.ch.medium.buf = NULL;
    }
    }
  else
    {
      /* Get information from the value. */
      src_precision = db_value_precision (src);
      src_length = db_get_string_size (src);
      if (src_length < 0)
    {
      src_length = strlen (src_str);
    }

      assert (src->data.ch.info.is_max_string == false);

      /* should we be paying attention to this? it is extremely dangerous */
      if (!copy)
    {
      error = db_make_varchar (dest, src_precision, src_str, src_length, db_get_string_codeset (src),
                   db_get_string_collation (src));
      dest->data.ch.medium.compressed_buf = src->data.ch.medium.compressed_buf;
      dest->data.ch.info.compressed_need_clear = false;
    }
      else
    {
      new_ = (char *) db_private_alloc (NULL, src_length + 1);
      if (new_ == NULL)
        {
          db_value_domain_init (dest, DB_TYPE_VARCHAR, src_precision, 0);
          assert (er_errid () != NO_ERROR);
          error = er_errid ();
        }
      else
        {
          memcpy (new_, src_str, src_length);
          new_[src_length] = '\0';
          db_make_varchar (dest, src_precision, new_, src_length, db_get_string_codeset (src),
                   db_get_string_collation (src));
          dest->need_clear = true;
        }

      if (src->data.ch.medium.compressed_buf == NULL)
        {
          dest->data.ch.medium.compressed_buf = NULL;
          dest->data.ch.info.compressed_need_clear = false;
        }
      else
        {
          new_compressed_buf = (char *) db_private_alloc (NULL, src->data.ch.medium.compressed_size + 1);
          if (new_compressed_buf == NULL)
        {
          db_value_domain_init (dest, DB_TYPE_VARCHAR, src_precision, 0);
          assert (er_errid () != NO_ERROR);
          error = er_errid ();
        }
          else
        {
          memcpy (new_compressed_buf, src->data.ch.medium.compressed_buf, src->data.ch.medium.compressed_size);
          new_compressed_buf[src->data.ch.medium.compressed_size] = '\0';
          dest->data.ch.medium.compressed_buf = new_compressed_buf;
          dest->data.ch.info.compressed_need_clear = true;
        }
        }
    }

      dest->data.ch.medium.length = src->data.ch.medium.length;
      dest->data.ch.medium.compressed_size = src->data.ch.medium.compressed_size;
    }

  return error;
}

static int
mr_index_lengthval_string (DB_VALUE * value)
{
  return mr_lengthval_string_internal (value, 1, CHAR_ALIGNMENT);
}

static int
mr_index_writeval_string (OR_BUF * buf, DB_VALUE * value)
{
  return mr_writeval_string_internal (buf, value, CHAR_ALIGNMENT);
}

static int
mr_index_readval_string (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  return mr_readval_string_internal (buf, value, domain, size, copy, copy_buf, copy_buf_len, CHAR_ALIGNMENT);
}

static int
mr_data_lengthval_string (DB_VALUE * value, int disk)
{
  return mr_lengthval_string_internal (value, disk, INT_ALIGNMENT);
}

static int
mr_data_writeval_string (OR_BUF * buf, DB_VALUE * value)
{
  return mr_writeval_string_internal (buf, value, INT_ALIGNMENT);
}

static int
mr_data_readval_string (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
            int copy_buf_len)
{
  return mr_readval_string_internal (buf, value, domain, size, copy, copy_buf, copy_buf_len, INT_ALIGNMENT);
}

/*
 * Ignoring precision as byte size is really the only important thing for
 * varchar.
 */
static int
mr_lengthval_string_internal (DB_VALUE * value, int disk, int align)
{
  int len;
  bool is_temporary_data = false;
  const char *str;
  int rc = NO_ERROR;
  int compressed_size = 0;

  if (DB_IS_NULL (value))
    {
      return 0;
    }
  str = value->data.ch.medium.buf;
  len = value->data.ch.medium.size;
  if (!str)
    {
      return 0;
    }
  if (len < 0)
    {
      len = strlen (str);
    }

  if (disk == 0)
    {
      return len;
    }
  else
    {
      /* Test and try compression. */
      if (!DB_TRIED_COMPRESSION (value))
    {
      /* It means that the value has never passed through a compression process. */
      rc = pr_do_db_value_string_compression (value);
    }
      /* We are now sure that the value has been through the process of compression */
      compressed_size = db_get_compressed_size (value);

      /* If the compression was successful, then we use the compression size value */
      if (compressed_size > 0)
    {
      len = compressed_size + PRIM_TEMPORARY_DISK_SIZE;
      is_temporary_data = true;
    }
      else
    {
      /* Compression failed so we are using the uncompressed size */
      len = value->data.ch.medium.size;
    }

      if (len >= OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION && is_temporary_data == false)
    {
      /* The compression failed but the size of the string calls for the new encoding. */
      len += PRIM_TEMPORARY_DISK_SIZE;
      is_temporary_data = true;
    }

      if (align == INT_ALIGNMENT)
    {
      len = or_packed_varchar_length (len);
    }
      else
    {
      len = or_varchar_length (len);
    }

      if (is_temporary_data == true)
    {
      return len - PRIM_TEMPORARY_DISK_SIZE;
    }
      return len;
    }
}


/*
 * Ignoring precision as byte size is really the only important thing for
 * varchar.
 */
static int
mr_writeval_string_internal (OR_BUF * buf, DB_VALUE * value, int align)
{
  int src_length, compressed_size;
  const char *str, *compressed_string;
  int rc = NO_ERROR;
  const char *string;
  int size;

  if (value != NULL && !db_value_is_null (value))
    {
      str = db_get_string (value);
      src_length = db_get_string_size (value);  /* size in bytes */
      if (src_length <= 0)
    {
      if (src_length == 0)
        {
          return pr_write_uncompressed_string_to_buffer (buf, "", 0, align);
        }
      src_length = strlen (str);
    }

      /* Test for possible compression. */
      if (!DB_TRIED_COMPRESSION (value))
    {
      /* It means that the value has never passed through a compression process. */
      rc = pr_do_db_value_string_compression (value);
    }

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

      compressed_size = db_get_compressed_size (value);
      compressed_string = DB_GET_COMPRESSED_STRING (value);

      if (compressed_size == DB_UNCOMPRESSABLE && src_length < OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION)
    {
      rc = pr_write_uncompressed_string_to_buffer (buf, str, src_length, align);
    }
      else
    {
      /* String has been prompted to compression before. */
      assert (compressed_size != DB_NOT_YET_COMPRESSED);
      if (compressed_string == NULL)
        {
          /* The value passed through a compression process but it failed due to its size. */
          assert (compressed_size == DB_UNCOMPRESSABLE);
          string = value->data.ch.medium.buf;
        }
      else
        {
          /* Compression successful. */
          assert (compressed_size > 0);
          string = compressed_string;
        }
      if (compressed_size == DB_UNCOMPRESSABLE)
        {
          size = 0;
        }
      else
        {
          size = compressed_size;
        }
      rc = pr_write_compressed_string_to_buffer (buf, string, size, src_length, align);
    }
    }
  return rc;
}

static int
mr_readval_string_internal (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                int copy_buf_len, int align)
{
  int precision;
  int rc = NO_ERROR;
  int compressed_size = 0, expected_decompressed_size = 0;
  char *decompressed_string = NULL, *compressed_string = NULL;

  if (value == NULL)
    {
      if (size == -1)
    {
      rc = or_skip_varchar (buf, align);
    }
      else if (size)
    {
      rc = or_advance (buf, size);
    }

      return rc;
    }

  precision = (domain != NULL) ? domain->precision : DB_MAX_VARCHAR_PRECISION;
  if (size == 0)
    {
      /* its NULL */
      db_value_domain_init (value, DB_TYPE_VARCHAR, precision, 0);
      return NO_ERROR;
    }

  if (TP_DOMAIN_COLLATION_FLAG (domain) != TP_DOMAIN_COLL_NORMAL)
    {
      assert (false);
      return ER_FAILED;
    }

  /* Get the compressed size and uncompressed size from the buffer, and point the buf->ptr
   * towards the data stored in the buffer */
  rc = or_get_varchar_compression_lengths (buf, &compressed_size, &expected_decompressed_size);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  if (copy || (compressed_size > 0))
    {
      if (copy_buf && copy_buf_len >= expected_decompressed_size + 1)
    {
      /* read buf image into the copy_buf */
      decompressed_string = copy_buf;
    }
      else
    {
      /* Allocate storage for the string including the kludge NULL terminator */
      decompressed_string = (char *) db_private_alloc (NULL, expected_decompressed_size + 1);
      if (decompressed_string == NULL)
        {
          rc = ER_OUT_OF_VIRTUAL_MEMORY;
          goto cleanup;
        }
    }
    }

  if (compressed_size > 0)
    {
      rc = pr_get_compressed_data_from_buffer (buf, decompressed_string, compressed_size, expected_decompressed_size);
      if (rc != NO_ERROR)
    {
      goto cleanup;
    }

      db_make_varchar (value, precision, decompressed_string, expected_decompressed_size,
               TP_DOMAIN_CODESET (domain), TP_DOMAIN_COLLATION (domain));
      value->need_clear = (decompressed_string != copy_buf) ? true : false;

#if defined(CS_MODE)
      db_set_compressed_string (value, NULL, DB_NOT_YET_COMPRESSED, false);
#else
      compressed_string = (char *) db_private_alloc (NULL, compressed_size + 1);
      if (compressed_string == NULL)
    {
      rc = ER_OUT_OF_VIRTUAL_MEMORY;
      goto cleanup;
    }

      memcpy (compressed_string, buf->ptr, compressed_size);
      compressed_string[compressed_size] = '\0';
      db_set_compressed_string (value, compressed_string, compressed_size, true);
#endif
    }
  else
    {
      assert (compressed_size == 0);
      if (!copy)
    {
      assert (decompressed_string == NULL);
      db_make_varchar (value, precision, buf->ptr, expected_decompressed_size,
               TP_DOMAIN_CODESET (domain), TP_DOMAIN_COLLATION (domain));
      value->need_clear = false;
    }
      else          /* if (!copy) */
    {
      assert (decompressed_string != NULL);
      memcpy (decompressed_string, buf->ptr, expected_decompressed_size);
      decompressed_string[expected_decompressed_size] = '\0';

      db_make_varchar (value, precision, decompressed_string, expected_decompressed_size,
               TP_DOMAIN_CODESET (domain), TP_DOMAIN_COLLATION (domain));
      value->need_clear = (decompressed_string != copy_buf) ? true : false;
    }
      db_set_compressed_string (value, NULL, DB_UNCOMPRESSABLE, false);
    }

  or_skip_varchar_remainder (buf, (compressed_size > 0) ? compressed_size : expected_decompressed_size, align);

cleanup:
  if (rc != NO_ERROR)
    {
      if (decompressed_string != NULL && decompressed_string != copy_buf)
    {
      db_private_free_and_init (NULL, decompressed_string);
    }
      if (compressed_string != NULL)
    {
      db_private_free_and_init (NULL, compressed_string);
    }
    }

  return rc;
}

#if (MAJOR_VERSION >= 11) || (MAJOR_VERSION == 10 && MINOR_VERSION >= 1)
/* data_readval_string() was written separately to read varchar columns 
 * from HEAP records to support unloaddb.
 * TO-DO: After applying [CBRD-25293], decide whether to consolidate and rewrite the function.
 */
int
data_readval_string (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  int precision;
  int align = INT_ALIGNMENT;
  int rc = NO_ERROR;
  int compressed_size = 0, expected_decompressed_size = 0;
  char *decompressed_string = NULL, *compressed_string = NULL;

  if (value == NULL)
    {
      if (size == -1)
    {
      rc = or_skip_varchar (buf, align);
    }
      else if (size)
    {
      rc = or_advance (buf, size);
    }

      return rc;
    }

  precision = (domain != NULL) ? domain->precision : DB_MAX_VARCHAR_PRECISION;
  if (size == 0)
    {
      /* its NULL */
      db_value_domain_init (value, DB_TYPE_VARCHAR, precision, 0);
      return NO_ERROR;
    }

  if (TP_DOMAIN_COLLATION_FLAG (domain) != TP_DOMAIN_COLL_NORMAL)
    {
      assert (false);
      return ER_FAILED;
    }

/* Get the compressed size and uncompressed size from the buffer, and point the buf->ptr
       * towards the data stored in the buffer */
  rc = or_get_varchar_compression_lengths (buf, &compressed_size, &expected_decompressed_size);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  if (!copy)
    {
      if (compressed_size > 0)
    {
      if (copy_buf && copy_buf_len >= expected_decompressed_size + 1)
        {
          /* read buf image into the copy_buf */
          decompressed_string = copy_buf;
        }
      else
        {
          /* Allocate storage for the string including the kludge NULL terminator */
          decompressed_string = (char *) db_private_alloc (NULL, expected_decompressed_size + 1);
          if (decompressed_string == NULL)
        {
          rc = ER_OUT_OF_VIRTUAL_MEMORY;
          goto cleanup;
        }
        }

      rc =
        pr_get_compressed_data_from_buffer (buf, decompressed_string, compressed_size, expected_decompressed_size);
      if (rc != NO_ERROR)
        {
          goto cleanup;
        }

      db_make_varchar (value, precision, decompressed_string, expected_decompressed_size,
               TP_DOMAIN_CODESET (domain), TP_DOMAIN_COLLATION (domain));
      value->need_clear = (decompressed_string != copy_buf) ? true : false;
      db_set_compressed_string (value, NULL, DB_NOT_YET_COMPRESSED, false);
    }
      else
    {
      assert (compressed_size == 0);

      db_make_varchar (value, precision, buf->ptr, expected_decompressed_size, TP_DOMAIN_CODESET (domain),
               TP_DOMAIN_COLLATION (domain));
      value->need_clear = false;
      db_set_compressed_string (value, NULL, DB_UNCOMPRESSABLE, false);
    }
    }
  else              /* if (!copy) */
    {
      bool compressed_need_clear = false;
      int decompressed_size = 0;

      if (copy_buf && copy_buf_len >= expected_decompressed_size + 1)
    {
      /* read buf image into the copy_buf */
      decompressed_string = copy_buf;
    }
      else
    {
      /* Allocate storage for the string including the kludge NULL terminator */
      decompressed_string = (char *) db_private_alloc (NULL, expected_decompressed_size + 1);
      if (decompressed_string == NULL)
        {
          rc = ER_OUT_OF_VIRTUAL_MEMORY;
          goto cleanup;
        }
    }

      if (compressed_size > 0)
    {
      rc =
        pr_get_compressed_data_from_buffer (buf, decompressed_string, compressed_size, expected_decompressed_size);
      if (rc != NO_ERROR)
        {
          goto cleanup;
        }

      db_make_varchar (value, precision, decompressed_string, expected_decompressed_size,
               TP_DOMAIN_CODESET (domain), TP_DOMAIN_COLLATION (domain));
      value->need_clear = (decompressed_string != copy_buf) ? true : false;
      db_set_compressed_string (value, NULL, DB_NOT_YET_COMPRESSED, false);
    }
      else
    {
      assert (compressed_size == 0);

      memcpy (decompressed_string, buf->ptr, expected_decompressed_size);
      decompressed_string[expected_decompressed_size] = '\0';

      db_make_varchar (value, precision, decompressed_string, expected_decompressed_size,
               TP_DOMAIN_CODESET (domain), TP_DOMAIN_COLLATION (domain));
      value->need_clear = (decompressed_string != copy_buf) ? true : false;
      db_set_compressed_string (value, NULL, DB_UNCOMPRESSABLE, false);
    }
    }

  or_skip_varchar_remainder (buf, (compressed_size > 0) ? compressed_size : expected_decompressed_size, align);

cleanup:
  if (rc != NO_ERROR)
    {
      if (decompressed_string != NULL && decompressed_string != copy_buf)
    {
      db_private_free_and_init (NULL, decompressed_string);
    }
      if (compressed_string != NULL)
    {
      db_private_free_and_init (NULL, compressed_string);
    }
    }

  return rc;
}
#endif // #if (MAJOR_VERSION >= 11) || (MAJOR_VERSION == 10 && MINOR_VERSION >= 1)

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_string (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return mr_data_cmpdisk_string (mem1, mem2, domain, do_coercion, total_order, start_colp);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_string (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c = DB_UNK;
  char *str1, *str2;
  int str_length1, str1_compressed_length = 0, str1_decompressed_length = 0;
  int str_length2, str2_compressed_length = 0, str2_decompressed_length = 0;
  OR_BUF buf1, buf2;
  int rc = NO_ERROR;
  char *string1 = NULL, *string2 = NULL;
  bool alloced_string1 = false, alloced_string2 = false;
  int strc;

  bool ti = true;
  static bool ignore_trailing_space = prm_get_bool_value (PRM_ID_IGNORE_TRAILING_SPACE);

  assert (domain != NULL);

  str1 = (char *) mem1;
  str2 = (char *) mem2;

  /* generally, data is short enough */
  str_length1 = OR_GET_BYTE (str1);
  str_length2 = OR_GET_BYTE (str2);
  if (!ignore_trailing_space)
    {
      ti = false;
    }

  if (str_length1 < OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION && str_length2 < OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION)
    {
      str1 += OR_BYTE_SIZE;
      str2 += OR_BYTE_SIZE;
      strc =
    QSTR_COMPARE (domain->collation_id, (unsigned char *) str1, str_length1, (unsigned char *) str2, str_length2,
              ti);
      c = MR_CMP_RETURN_CODE (strc);
      return c;
    }

  assert (str_length1 == OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION
      || str_length2 == OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION);

  /* String 1 */
  or_init (&buf1, str1, 0);
  if (str_length1 == OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION)
    {
      rc = or_get_varchar_compression_lengths (&buf1, &str1_compressed_length, &str1_decompressed_length);
      if (rc != NO_ERROR)
    {
      goto cleanup;
    }

      string1 = (char *) db_private_alloc (NULL, str1_decompressed_length + 1);
      if (string1 == NULL)
    {
      /* Error report */
      goto cleanup;
    }

      alloced_string1 = true;

      rc = pr_get_compressed_data_from_buffer (&buf1, string1, str1_compressed_length, str1_decompressed_length);
      if (rc != NO_ERROR)
    {
      goto cleanup;
    }

      str_length1 = str1_decompressed_length;
      string1[str_length1] = '\0';
    }
  else
    {
      /* Skip the size byte */
      string1 = buf1.ptr + OR_BYTE_SIZE;
    }

  if (rc != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto cleanup;
    }

  /* String 2 */

  or_init (&buf2, str2, 0);

  if (str_length2 == OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION)
    {
      rc = or_get_varchar_compression_lengths (&buf2, &str2_compressed_length, &str2_decompressed_length);
      if (rc != NO_ERROR)
    {
      goto cleanup;
    }

      string2 = (char *) db_private_alloc (NULL, str2_decompressed_length + 1);
      if (string2 == NULL)
    {
      /* Error report */
      goto cleanup;
    }

      alloced_string2 = true;

      rc = pr_get_compressed_data_from_buffer (&buf2, string2, str2_compressed_length, str2_decompressed_length);
      if (rc != NO_ERROR)
    {
      goto cleanup;
    }

      str_length2 = str2_decompressed_length;
      string2[str_length2] = '\0';
    }
  else
    {
      /* Skip the size byte */
      string2 = buf2.ptr + OR_BYTE_SIZE;
    }

  if (rc != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto cleanup;
    }

  /* Compare the strings */
  strc =
    QSTR_COMPARE (domain->collation_id, (unsigned char *) string1, str_length1, (unsigned char *) string2, str_length2,
          ti);
  c = MR_CMP_RETURN_CODE (strc);

  /* Clean up the strings */
  if (string1 != NULL && alloced_string1 == true)
    {
      db_private_free_and_init (NULL, string1);
    }

  if (string2 != NULL && alloced_string2 == true)
    {
      db_private_free_and_init (NULL, string2);
    }

  return c;

cleanup:
  if (string1 != NULL && alloced_string1 == true)
    {
      db_private_free_and_init (NULL, string1);
    }

  if (string2 != NULL && alloced_string2 == true)
    {
      db_private_free_and_init (NULL, string2);
    }

  return DB_UNK;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_string (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
          int collation)
{
  DB_VALUE_COMPARE_RESULT c;
  int size1, size2;
  int strc;

  static bool ti = prm_get_bool_value (PRM_ID_IGNORE_TRAILING_SPACE);

  DB_TYPE type1 = (DB_TYPE) value1->domain.char_info.type;
  DB_TYPE type2 = (DB_TYPE) value2->domain.char_info.type;

  const unsigned char *string1 = REINTERPRET_CAST (const unsigned char *, db_get_string (value1));
  const unsigned char *string2 = REINTERPRET_CAST (const unsigned char *, db_get_string (value2));

  /*
   *  Check if the is_max_string flag set for each DB_VALUE.
   *  If "value1" has the flag set, return 1, meaning that "value2" is Less Than "value1".
   *  If "value2" has the flag set, return -1, meaning that "value1" is Greater Than "value2".
   */

  if (value1->data.ch.info.is_max_string != 0)
    {
      if (value2->data.ch.info.is_max_string != 0)
    {
      /* Both strings are max_string. Therefore equal. Even though this should not happen. */
      assert (false);
      return DB_EQ;
    }
      return DB_GT;
    }
  else
    {
      if (value2->data.ch.info.is_max_string != 0)
    {
      return DB_LT;
    }
    }

  if (string1 == NULL || string2 == NULL || db_get_string_codeset (value1) != db_get_string_codeset (value2))
    {
      return DB_UNK;
    }

  size1 = (int) db_get_string_size (value1);
  size2 = (int) db_get_string_size (value2);

  if (size1 < 0)
    {
      size1 = strlen ((char *) string1);
    }

  if (size2 < 0)
    {
      size2 = strlen ((char *) string2);
    }

  if (collation == -1)
    {
      assert (false);
      return DB_UNK;
    }

  strc = QSTR_COMPARE (collation, string1, size1, string2, size2, ti);
  c = MR_CMP_RETURN_CODE (strc);

  return c;
}

#if defined (ENABLE_UNUSED_FUNCTION)
static int
mr_cmpval_string2 (DB_VALUE * value1, DB_VALUE * value2, int length, int do_coercion, int total_order, int *start_colp)
{
  int c;
  int len1, len2, string_size;

  const unsigned char *string1 = REINTERPRET_CAST (const unsigned char *, db_get_string (value1));
  const unsigned char *string2 = REINTERPRET_CAST (const unsigned char *, db_get_string (value2));

  if (string1 == NULL || string2 == NULL)
    {
      return DB_UNK;
    }

  string_size = (int) db_get_string_size (value1);
  len1 = MIN (string_size, length);
  string_size = (int) db_get_string_size (value2);
  len2 = MIN (string_size, length);

  c = QSTR_COMPARE (string1, len1, string2, len2);
  c = MR_CMP_RETURN_CODE (c);

  return c;
}
#endif

const PR_TYPE tp_String = {
  "character varying", DB_TYPE_STRING, 1, sizeof (const char *), 0, 1,
  mr_initmem_string,
  mr_initval_string,
  mr_setmem_string,
  mr_getmem_string,
  mr_setval_string,
  mr_data_lengthmem_string,
  mr_data_lengthval_string,
  mr_data_writemem_string,
  mr_data_readmem_string,
  mr_data_writeval_string,
  mr_data_readval_string,
  mr_index_lengthmem_string,
  mr_index_lengthval_string,
  mr_index_writeval_string,
  mr_index_readval_string,
  mr_index_cmpdisk_string,
  mr_freemem_string,
  mr_data_cmpdisk_string,
  mr_cmpval_string
};

const PR_TYPE *tp_Type_string = &tp_String;

/*
 * TYPE CHAR
 */

static void
mr_initmem_char (void *memptr, TP_DOMAIN * domain)
{
#if !defined(NDEBUG)
  int mem_length;

  assert (!IS_FLOATING_PRECISION (domain->precision));

  mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));
  memset (memptr, 0, mem_length);
#endif
}


/*
 * Note! Due to the "within tolerance" comparison of domains used for
 * assignment validation, we may get values in here whose precision is
 * less than the precision of the actual attribute.   This prevents
 * having to copy a string just to coerce a value into a larger precision.
 * Note that the precision of the source value may also come in as -1 here
 * which is used to mean a "floating" precision that is assumed to be
 * compatible with the destination domain as long as the associated value
 * is within tolerance.  This case is generally only seen for string
 * literals that have been produced by the parser.  These literals will
 * not contain blank padding and strlen() or db_get_string_size() can be
 * used to determine the number of significant characters.
 *
 */
static int
mr_setmem_char (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  int error = NO_ERROR;
  char *mem;
  const char *src;
  int src_precision, src_length, mem_length, pad;

  assert (!IS_FLOATING_PRECISION (domain->precision));

  if (value == NULL)
    {
      return NO_ERROR;
    }

  /* Get information from the value */
  src = db_get_string (value);
  src_precision = DB_GET_STRING_PRECISION (value);
  src_length = db_get_string_size (value);  /* size in bytes */

  if (src == NULL)
    {
      return NO_ERROR;
    }

  /* Check for special NTS flag.  This may not be necessary any more. */
  if (src_length < 0)
    {
      src_length = strlen (src);
    }


  /* The only thing we really care about at this point, is the byte length of the string.  The precision could be
   * checked here but it really isn't necessary for this operation. Calculate the maximum number of bytes we have
   * available here. The multiplier is dependent on codeset */
  mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));

  if (mem_length < src_length)
    {
      /*
       * should never get here, this is supposed to be caught during domain
       * validation, need a better error message.
       */
      error = ER_OBJ_DOMAIN_CONFLICT;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, "");
    }
  else
    {
      /* copy the value into memory */
      mem = (char *) memptr;
      memcpy (mem, src, src_length);

      /*
       * Check for space padding, if this were a national string, we would
       * need to be padding with the appropriate space character !
       */
      pad = mem_length - src_length;
      if (pad)
    {
      int i;

      for (i = src_length; i < mem_length; i++)
        {
          mem[i] = ' ';
        }
    }
    }
  return error;
}


static int
mr_getmem_char (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int mem_length;
  char *new_;

  assert (!IS_FLOATING_PRECISION (domain->precision));
  if (TP_DOMAIN_COLLATION_FLAG (domain) != TP_DOMAIN_COLL_NORMAL)
    {
      assert (false);
      return ER_FAILED;
    }

  intl_char_size ((unsigned char *) mem, domain->precision, TP_DOMAIN_CODESET (domain), &mem_length);
  if (mem_length == 0)
    {
      mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));
    }

  if (!copy)
    {
      new_ = (char *) mem;
    }
  else
    {
      new_ = (char *) db_private_alloc (NULL, mem_length + 1);
      if (new_ == NULL)
    {
      assert (er_errid () != NO_ERROR);
      return er_errid ();
    }
      memcpy (new_, (char *) mem, mem_length);
      /* make sure that all outgoing strings are NULL terminated */
      new_[mem_length] = '\0';
    }

  db_make_char (value, domain->precision, new_, mem_length, TP_DOMAIN_CODESET (domain), TP_DOMAIN_COLLATION (domain));
  if (copy)
    {
      value->need_clear = true;
    }

  return NO_ERROR;
}

static int
mr_data_lengthmem_char (void *memptr, TP_DOMAIN * domain, int disk)
{
  int mem_length;

  assert (!IS_FLOATING_PRECISION (domain->precision));

  mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));

  return mem_length;
}

static int
mr_index_lengthmem_char (void *memptr, TP_DOMAIN * domain)
{
  int mem_length;

  assert (!(IS_FLOATING_PRECISION (domain->precision) && memptr == NULL));

  if (IS_FLOATING_PRECISION (domain->precision))
    {
      memcpy (&mem_length, memptr, OR_INT_SIZE);
      mem_length += OR_INT_SIZE;
    }
  else
    {
      mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));
    }

  return mem_length;
}

static void
mr_data_writemem_char (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  int mem_length;

  assert (!IS_FLOATING_PRECISION (domain->precision));

  mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));

  /*
   * We simply dump the memory image to disk, it will already have been padded.
   * If this were a national character string, at this point, we'd have to
   * decide now to perform a character set conversion.
   */
  or_put_data (buf, (char *) mem, mem_length);
}

static void
mr_data_readmem_char (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  int mem_length, padding;

  assert (!IS_FLOATING_PRECISION (domain->precision));

  if (mem == NULL)
    {
      /*
       * If we passed in a size, then use it.  Otherwise, determine the
       * size from the domain.
       */
      if (size > 0)
    {
      or_advance (buf, size);
    }
      else
    {
      mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));
      or_advance (buf, mem_length);
    }
    }
  else
    {
      mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));

      if (size != -1 && mem_length > size)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CORRUPTED, 0);
      assert (false);
      return;
    }
      or_get_data (buf, (char *) mem, mem_length);

      /*
       * We should only see padding if the string is contained within a packed
       * value that had extra padding to ensure alignment.  If we see these,
       * just pop them out of the buffer.  This shouldn't ever happen for the
       * "getmem" function, only for the "getval" function.
       */
      if (size != -1)
    {
      padding = size - mem_length;
      if (padding > 0)
        {
          or_advance (buf, padding);
        }
    }
    }
}

static void
mr_freemem_char (void *memptr)
{
}

static void
mr_initval_char (DB_VALUE * value, int precision, int scale)
{
  DB_DOMAIN_INIT_CHAR (value, precision);
}

static int
mr_setval_char (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error = NO_ERROR;
  int src_precision, src_length;
  char *new_;
  const char *src_string;

  assert (!db_value_is_corrupted (src));
  if (DB_IS_NULL (src))
    {
      DB_DOMAIN_INIT_CHAR (dest, TP_FLOATING_PRECISION_VALUE);
    }
  else
    {
      src_precision = DB_GET_STRING_PRECISION (src);
      if (src_precision == 0)
    {
      src_precision = TP_FLOATING_PRECISION_VALUE;
    }
      DB_DOMAIN_INIT_CHAR (dest, src_precision);
      /* Get information from the value */
      src_string = db_get_string (src);
      src_length = db_get_string_size (src);    /* size in bytes */

      /* shouldn't see a NULL string at this point, treat as NULL */
      if (src_string != NULL)
    {
      if (!copy)
        {
          db_make_char (dest, src_precision, src_string, src_length, db_get_string_codeset (src),
                db_get_string_collation (src));
        }
      else
        {
          /* Check for NTS marker, may not need to do this any more */
          if (src_length < 0)
        {
          src_length = strlen (src_string);
        }

          /* make sure the copy gets a NULL terminator */
          new_ = (char *) db_private_alloc (NULL, src_length + 1);
          if (new_ == NULL)
        {
          assert (er_errid () != NO_ERROR);
          error = er_errid ();
        }
          else
        {
          memcpy (new_, src_string, src_length);
          new_[src_length] = '\0';
          db_make_char (dest, src_precision, new_, src_length, db_get_string_codeset (src),
                db_get_string_collation (src));
          dest->need_clear = true;
        }
        }
      dest->data.ch.medium.length = src->data.ch.medium.length;
    }
    }

  return error;
}

static int
mr_index_lengthval_char (DB_VALUE * value)
{
  return mr_data_lengthval_char (value, 1);
}

/*
 */
static int
mr_data_lengthval_char (DB_VALUE * value, int disk)
{
  int packed_length, src_precision;

  const char *src = db_get_string (value);
  if (src == NULL)
    {
      return 0;
    }

  src_precision = db_value_precision (value);
  if (!IS_FLOATING_PRECISION (src_precision))
    {
      packed_length = STR_SIZE (src_precision, db_get_string_codeset (value));
    }
  else
    {
      /*
       * Precision is "floating", calculate the effective precision based on the
       * string length.
       * Should be rounding this up so it is a proper multiple of the charset
       * width ?
       */
      packed_length = db_get_string_size (value);
      if (packed_length < 0)
    {
      packed_length = strlen (src);
    }

      /* add in storage for a size prefix on the packed value. */
      packed_length += OR_INT_SIZE;
    }

  /*
   * NOTE: We do NOT perform padding here, if this is used in the context
   * of a packed value, the or_put_value() family of functions must handle
   * their own padding, this is because "lengthval" and "writeval" can be
   * used to place values into the disk representation of instances and
   * there can be no padding in there.
   */

  return packed_length;
}


static int
mr_index_writeval_char (OR_BUF * buf, DB_VALUE * value)
{
  return mr_writeval_char_internal (buf, value, CHAR_ALIGNMENT);
}

/*
 * See commentary in mr_lengthval_char.
 */
static int
mr_data_writeval_char (OR_BUF * buf, DB_VALUE * value)
{
  return mr_writeval_char_internal (buf, value, INT_ALIGNMENT);
}

static int
mr_writeval_char_internal (OR_BUF * buf, DB_VALUE * value, int align)
{
  int src_precision, src_length, packed_length, pad;
  const char *src;
  int rc = NO_ERROR;

  src = db_get_string (value);
  if (src == NULL)
    {
      return rc;
    }

  src_precision = db_value_precision (value);

  if (!IS_FLOATING_PRECISION (src_precision))
    {
      src_length = db_get_string_size (value);  /* size in bytes */

      if (src_length < 0)
    {
      src_length = strlen (src);
    }

      packed_length = STR_SIZE (src_precision, db_get_string_codeset (value));

      if (packed_length < src_length)
    {
      /* should have caught this by now, truncate silently */
      rc = or_put_data (buf, src, packed_length);
    }
      else
    {
      rc = or_put_data (buf, src, src_length);
      /*
       * Check for space padding, if this were a national string, we
       * would need to be padding with the appropriate space character !
       */
      pad = packed_length - src_length;
      if (pad)
        {
          int i;
          for (i = src_length; i < packed_length; i++)
        {
          rc = or_put_byte (buf, (int) ' ');
        }
        }
    }
      if (rc != NO_ERROR)
    {
      return rc;
    }
    }
  else
    {
      /*
       * This is a "floating" precision value. Pack what we can based on the
       * string size.  Note that for this to work, this can only be packed as
       * part of a domain tagged value and we must include a length prefix
       * after the domain.
       */
      packed_length = db_get_string_size (value);
      if (packed_length < 0)
    {
      packed_length = strlen (src);
    }

      /* store the size prefix */
      if (align == INT_ALIGNMENT)
    {
      rc = or_put_int (buf, packed_length);
    }
      else
    {
      rc = or_put_data (buf, (char *) (&packed_length), OR_INT_SIZE);
    }
      if (rc == NO_ERROR)
    {
      /* store the data */
      rc = or_put_data (buf, src, packed_length);
      /* there is no blank padding in this case */
    }
    }
  return rc;
}

static int
mr_index_readval_char (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy, char *copy_buf,
               int copy_buf_len)
{
  return mr_readval_char_internal (buf, value, domain, disk_size, copy, copy_buf, copy_buf_len, CHAR_ALIGNMENT);
}

static int
mr_data_readval_char (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  return mr_readval_char_internal (buf, value, domain, disk_size, copy, copy_buf, copy_buf_len, INT_ALIGNMENT);
}

static int
mr_readval_char_internal (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy, char *copy_buf,
              int copy_buf_len, int align)
{
  int mem_length, padding;
  int str_length, precision;
  char *new_;
  int rc = NO_ERROR;
  precision = domain->precision;
  if (TP_DOMAIN_COLLATION_FLAG (domain) != TP_DOMAIN_COLL_NORMAL)
    {
      assert (false);
      return ER_FAILED;
    }

  if (IS_FLOATING_PRECISION (domain->precision))
    {
      if (align == INT_ALIGNMENT)
    {
      mem_length = or_get_int (buf, &rc);
    }
      else
    {
      rc = or_get_data (buf, (char *) (&mem_length), OR_INT_SIZE);
    }
      if (rc != NO_ERROR)
    {
      return rc;
    }

      if (value == NULL)
    {
      rc = or_advance (buf, mem_length);
    }
      else if (!copy)
    {
      db_make_char (value, TP_FLOATING_PRECISION_VALUE, buf->ptr, mem_length, TP_DOMAIN_CODESET (domain),
            TP_DOMAIN_COLLATION (domain));
      value->need_clear = false;
      rc = or_advance (buf, mem_length);
    }
      else
    {
      if (copy_buf && copy_buf_len >= mem_length + 1)
        {
          /* read buf image into the copy_buf */
          new_ = copy_buf;
        }
      else
        {
          /* Allocate storage for the string including the kludge NULL terminator */
          new_ = (char *) db_private_alloc (NULL, mem_length + 1);
        }

      if (new_ == NULL)
        {
          /* need to be able to return errors ! */
          db_value_domain_init (value, TP_DOMAIN_TYPE (domain), TP_FLOATING_PRECISION_VALUE, 0);
          return ER_FAILED;
        }
      else
        {
          rc = or_get_data (buf, new_, mem_length);
          if (rc != NO_ERROR)
        {
          if (new_ != copy_buf)
            {
              db_private_free_and_init (NULL, new_);
            }
          return rc;
        }
          new_[mem_length] = '\0';  /* append the kludge NULL terminator */
          db_make_char (value, TP_FLOATING_PRECISION_VALUE, new_, mem_length, TP_DOMAIN_CODESET (domain),
                TP_DOMAIN_COLLATION (domain));
          value->need_clear = (new_ != copy_buf) ? true : false;
        }
    }
    }
  else
    {
      /*
       * Normal fixed width char(n) whose size can be determined by looking at
       * the domain.
       */
      mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));

      if (disk_size != -1 && mem_length > disk_size)
    {
      /*
       * If we're low here, we could just read what we have and make a
       * smaller value.  Still the domain should match at this point.
       */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CORRUPTED, 0);
      assert (false);
      return ER_FAILED;
    }

      if (value == NULL)
    {
      rc = or_advance (buf, mem_length);
    }
      else if (disk_size == 0)
    {
      db_value_domain_init (value, DB_TYPE_CHAR, precision, 0);
    }
      else if (!copy)
    {
      intl_char_size ((unsigned char *) buf->ptr, domain->precision, TP_DOMAIN_CODESET (domain), &str_length);
      if (str_length == 0)
        {
          str_length = mem_length;
        }
      db_make_char (value, precision, buf->ptr, str_length, TP_DOMAIN_CODESET (domain),
            TP_DOMAIN_COLLATION (domain));
      value->need_clear = false;
      rc = or_advance (buf, mem_length);
    }
      else
    {
      if (copy_buf && copy_buf_len >= mem_length + 1)
        {
          /* read buf image into the copy_buf */
          new_ = copy_buf;
        }
      else
        {
          /*
           * Allocate storage for the string including the kludge NULL
           * terminator
           */
          new_ = (char *) db_private_alloc (NULL, mem_length + 1);
        }
      if (new_ == NULL)
        {
          /* need to be able to return errors ! */
          db_value_domain_init (value, TP_DOMAIN_TYPE (domain), domain->precision, 0);
          return ER_FAILED;
        }
      else
        {
          int actual_size = 0;
          rc = or_get_data (buf, new_, mem_length);
          if (rc != NO_ERROR)
        {
          if (new_ != copy_buf)
            {
              db_private_free_and_init (NULL, new_);
            }
          return rc;
        }
          intl_char_size ((unsigned char *) new_, domain->precision, TP_DOMAIN_CODESET (domain), &actual_size);
          if (actual_size == 0)
        {
          actual_size = mem_length;
        }
          new_[actual_size] = '\0'; /* append the kludge NULL terminator */
          db_make_char (value, domain->precision, new_, actual_size, TP_DOMAIN_CODESET (domain),
                TP_DOMAIN_COLLATION (domain));
          value->need_clear = (new_ != copy_buf) ? true : false;
        }
    }

      if (rc == NO_ERROR)
    {
      /*
       * We should only see padding if the string is contained within a
       * packed value that had extra padding to ensure alignment.  If we
       * see these, just pop them out of the buffer.
       */
      if (disk_size != -1)
        {
          padding = disk_size - mem_length;
          if (padding > 0)
        {
          rc = or_advance (buf, padding);
        }
        }
    }
    }
  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_char (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return mr_cmpdisk_char_internal (mem1, mem2, domain, do_coercion, total_order, start_colp, CHAR_ALIGNMENT);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_char (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return mr_cmpdisk_char_internal (mem1, mem2, domain, do_coercion, total_order, start_colp, INT_ALIGNMENT);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpdisk_char_internal (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp,
              int align)
{
  DB_VALUE_COMPARE_RESULT c;
  int mem_length1, mem_length2, strc;

  bool ti = true;
  static bool ignore_trailing_space = prm_get_bool_value (PRM_ID_IGNORE_TRAILING_SPACE);

  if (IS_FLOATING_PRECISION (domain->precision))
    {
      if (align == INT_ALIGNMENT)
    {
      mem_length1 = OR_GET_INT (mem1);
      mem_length2 = OR_GET_INT (mem2);
    }
      else
    {
      memcpy (&mem_length1, mem1, OR_INT_SIZE);
      memcpy (&mem_length2, mem2, OR_INT_SIZE);
    }
      mem1 = (char *) mem1 + OR_INT_SIZE;
      mem2 = (char *) mem2 + OR_INT_SIZE;
    }
  else
    {
      /*
       * Normal fixed width char(n) whose size can be determined by looking at
       * the domain.
       * Needs NCHAR work here to separate the dependencies on disk_size and
       * mem_size.
       */
      mem_length1 = mem_length2 = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));
    }

  if (!ignore_trailing_space)
    {
      ti = (domain->type->id == DB_TYPE_CHAR);
    }

  strc = QSTR_CHAR_COMPARE (domain->collation_id, (unsigned char *) mem1, mem_length1, (unsigned char *) mem2,
                mem_length2, ti);
  c = MR_CMP_RETURN_CODE (strc);

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_char (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  DB_VALUE_COMPARE_RESULT c;
  int strc, size1, size2;

  bool ti = true;
  static bool ignore_trailing_space = prm_get_bool_value (PRM_ID_IGNORE_TRAILING_SPACE);

  DB_TYPE type1 = (DB_TYPE) value1->domain.char_info.type;
  DB_TYPE type2 = (DB_TYPE) value2->domain.char_info.type;

  const unsigned char *string1 = REINTERPRET_CAST (const unsigned char *, db_get_string (value1));
  const unsigned char *string2 = REINTERPRET_CAST (const unsigned char *, db_get_string (value2));

  /*
   *  Check if the is_max_string flag set for each DB_VALUE.
   *  If "value1" has the flag set, return 1, meaning that "value2" is Less Than "value1".
   *  If "value2" has the flag set, return -1, meaning that "value1" is Greater Than "value2".
   */

  if (value1->data.ch.info.is_max_string != 0)
    {
      if (value2->data.ch.info.is_max_string != 0)
    {
      /* Both strings are max_string. Therefore equal. Even though this should not happen. */
      assert (false);
      return DB_EQ;
    }
      return DB_GT;
    }
  else
    {
      if (value2->data.ch.info.is_max_string != 0)
    {
      return DB_LT;
    }
    }

  if (string1 == NULL || string2 == NULL || db_get_string_codeset (value1) != db_get_string_codeset (value2))
    {
      return DB_UNK;
    }

  if (collation == -1)
    {
      assert (false);
      return DB_UNK;
    }

  size1 = db_get_string_size (value1);
  size2 = db_get_string_size (value2);

  if (!ignore_trailing_space)
    {
      if (!TP_IS_FIXED_LEN_CHAR_TYPE (type1) || !TP_IS_FIXED_LEN_CHAR_TYPE (type2))
    {
      ti = false;
    }
    }

  strc = QSTR_CHAR_COMPARE (collation, string1, size1, string2, size2, ti);
  c = MR_CMP_RETURN_CODE (strc);

  return c;
}

#if defined (ENABLE_UNUSED_FUNCTION)
static int
mr_cmpval_char2 (DB_VALUE * value1, DB_VALUE * value2, int length, int do_coercion, int total_order, int *start_colp)
{
  int c;
  int len1, len2, string_size;

  const unsigned char *string1 = REINTERPRET_CAST (const unsigned char *, db_get_string (value1));
  const unsigned char *string2 = REINTERPRET_CAST (const unsigned char *, db_get_string (value2));

  if (string1 == NULL || string2 == NULL)
    {
      return DB_UNK;
    }

  string_size = (int) db_get_string_size (value1);
  len1 = MIN (string_size, length);
  string_size = (int) db_get_string_size (value2);
  len2 = MIN (string_size, length);

  c = QSTR_CHAR_COMPARE (string1, len1, string2, len2);
  c = MR_CMP_RETURN_CODE (c);

  return c;
}
#endif

const PR_TYPE tp_Char = {
  "character", DB_TYPE_CHAR, 0, 0, 0, 1,
  mr_initmem_char,
  mr_initval_char,
  mr_setmem_char,
  mr_getmem_char,
  mr_setval_char,
  mr_data_lengthmem_char,
  mr_data_lengthval_char,
  mr_data_writemem_char,
  mr_data_readmem_char,
  mr_data_writeval_char,
  mr_data_readval_char,
  mr_index_lengthmem_char,
  mr_index_lengthval_char,
  mr_index_writeval_char,
  mr_index_readval_char,
  mr_index_cmpdisk_char,
  mr_freemem_char,
  mr_data_cmpdisk_char,
  mr_cmpval_char
};

const PR_TYPE *tp_Type_char = &tp_Char;

/*
 * TYPE BIT
 */

static void
mr_initmem_bit (void *memptr, TP_DOMAIN * domain)
{
#if !defined(NDEBUG)
  int mem_length;

  assert (!IS_FLOATING_PRECISION (domain->precision));
  assert (TP_DOMAIN_CODESET (domain) == INTL_CODESET_RAW_BITS);

  mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));
  memset (memptr, 0, mem_length);
#endif
}


/*
 * Due to the "within tolerance" comparison of domains used for
 * assignment validation, we may get values in here whose precision is
 * less than the precision of the actual attribute.   This prevents
 * having to copy a string just to coerce a value into a larger precision.
 * Note that the precision of the source value may also come in as -1 here
 * which is used to mean a "floating" precision that is assumed to be
 * compatible with the destination domain as long as the associated value
 * is within tolerance.  This case is generally only seen for string
 * literals that have been produced by the parser.  These literals will
 * not contain blank padding and strlen() or db_get_string_size() can be
 * used to determine the number of significant characters.
 */
static int
mr_setmem_bit (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  int error = NO_ERROR;
  char *mem;
  const char *src;
  int src_precision, src_length, mem_length, pad;

  if (value == NULL)
    {
      return NO_ERROR;
    }

  /* Get information from the value */
  src = db_get_string (value);
  src_precision = db_value_precision (value);
  src_length = db_get_string_size (value);  /* size in bytes */

  if (src == NULL)
    {
      return NO_ERROR;
    }

  /*
   * The only thing we really care about at this point, is the byte
   * length of the string.  The precision could be checked here but it
   * really isn't necessary for this operation.
   * Calculate the maximum number of bytes we have available here.
   */
  assert (TP_DOMAIN_CODESET (domain) == INTL_CODESET_RAW_BITS);
  mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));

  if (mem_length < src_length)
    {
      /*
       * should never get here, this is supposed to be caught during domain
       * validation, need a better error message.
       */
      error = ER_OBJ_DOMAIN_CONFLICT;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, "");
    }
  else
    {
      /* copy the value into memory */
      mem = (char *) memptr;
      memcpy (mem, src, src_length);

      /* Check for padding */
      pad = mem_length - src_length;
      if (pad)
    {
      int i;

      for (i = src_length; i < mem_length; i++)
        {
          mem[i] = '\0';
        }
    }
    }

  return error;
}

static int
mr_getmem_bit (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int mem_length;
  char *new_;

  assert (TP_DOMAIN_CODESET (domain) == INTL_CODESET_RAW_BITS);
  mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));

  if (!copy)
    {
      new_ = (char *) mem;
    }
  else
    {
      new_ = (char *) db_private_alloc (NULL, mem_length + 1);
      if (new_ == NULL)
    {
      assert (er_errid () != NO_ERROR);
      return er_errid ();
    }
      memcpy (new_, (char *) mem, mem_length);
    }

  db_make_bit (value, domain->precision, new_, domain->precision);
  if (copy)
    {
      value->need_clear = true;
    }

  return NO_ERROR;
}

static int
mr_data_lengthmem_bit (void *memptr, TP_DOMAIN * domain, int disk)
{
  assert (!IS_FLOATING_PRECISION (domain->precision));
  assert (TP_DOMAIN_CODESET (domain) == INTL_CODESET_RAW_BITS);

  /* There is no difference between the disk & memory sizes. */
  return STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));
}

static void
mr_data_writemem_bit (OR_BUF * buf, void *mem, TP_DOMAIN * domain)
{
  int mem_length;

  assert (TP_DOMAIN_CODESET (domain) == INTL_CODESET_RAW_BITS);
  mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));

  /*
   * We simply dump the memory image to disk, it will already have been padded.
   * If this were a national character string, at this point, we'd have to
   * decide now to perform a character set conversion.
   */
  or_put_data (buf, (char *) mem, mem_length);
}

static void
mr_data_readmem_bit (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  int mem_length, padding;

  if (mem == NULL)
    {
      /* If we passed in a size, then use it.  Otherwise, determine the size from the domain. */
      if (size > 0)
    {
      or_advance (buf, size);
    }
      else
    {
      assert (TP_DOMAIN_CODESET (domain) == INTL_CODESET_RAW_BITS);
      mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));
      or_advance (buf, mem_length);
    }
    }
  else
    {
      assert (TP_DOMAIN_CODESET (domain) == INTL_CODESET_RAW_BITS);
      mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));
      if (size != -1 && mem_length > size)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CORRUPTED, 0);
      assert (false);
      return;
    }
      or_get_data (buf, (char *) mem, mem_length);

      /*
       * We should only see padding if the string is contained within a packed
       * value that had extra padding to ensure alignment.  If we see these,
       * just pop them out of the buffer.  This shouldn't ever happen for the
       * "getmem" function, only for the "getval" function.
       */
      if (size != -1)
    {
      padding = size - mem_length;
      if (padding > 0)
        {
          or_advance (buf, padding);
        }
    }
    }
}

static void
mr_freemem_bit (void *memptr)
{
}

static void
mr_initval_bit (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_BIT, precision, scale);
}

static int
mr_setval_bit (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error = NO_ERROR;
  int src_precision, src_length, src_number_of_bits = 0;
  char *new_ = NULL;
  const char *src_string = NULL;

  assert (!db_value_is_corrupted (src));
  if (src == NULL || DB_IS_NULL (src))
    {
      db_value_domain_init (dest, DB_TYPE_BIT, DB_DEFAULT_PRECISION, 0);
    }
  else
    {
      /* Get information from the value */
      src_string = db_get_bit (src, &src_number_of_bits);
      src_precision = db_value_precision (src);
      src_length = db_get_string_size (src);    /* size in bytes */

      db_value_domain_init (dest, DB_TYPE_BIT, src_precision, 0);

      /* shouldn't see a NULL string at this point, treat as NULL */
      if (src_string != NULL)
    {
      if (!copy)
        {
          db_make_bit (dest, src_precision, src_string, src_number_of_bits);
        }
      else
        {

          /* make sure the copy gets a NULL terminator */
          new_ = (char *) db_private_alloc (NULL, src_length + 1);
          if (new_ == NULL)
        {
          assert (er_errid () != NO_ERROR);
          error = er_errid ();
        }
          else
        {
          memcpy (new_, src_string, src_length);
          db_make_bit (dest, src_precision, new_, src_number_of_bits);
          dest->need_clear = true;
        }
        }
    }
    }
  return error;
}

static int
mr_index_lengthmem_bit (void *memptr, TP_DOMAIN * domain)
{
  int mem_length;

  assert (!IS_FLOATING_PRECISION (domain->precision) || memptr != NULL);
  assert (TP_DOMAIN_CODESET (domain) == INTL_CODESET_RAW_BITS);

  if (!IS_FLOATING_PRECISION (domain->precision))
    {
      mem_length = domain->precision;

      return STR_SIZE (mem_length, TP_DOMAIN_CODESET (domain));
    }
  else
    {
      memcpy (&mem_length, memptr, OR_INT_SIZE);

      return STR_SIZE (mem_length, TP_DOMAIN_CODESET (domain)) + OR_INT_SIZE;
    }

}

static int
mr_index_lengthval_bit (DB_VALUE * value)
{
  return mr_data_lengthval_bit (value, 1);
}

static int
mr_data_lengthval_bit (DB_VALUE * value, int disk)
{
  int packed_length, src_precision;

  const char *src = db_get_string (value);
  if (src == NULL)
    {
      return 0;
    }

  src_precision = db_value_precision (value);
  if (!IS_FLOATING_PRECISION (src_precision))
    {
      assert (db_get_string_codeset (value) == INTL_CODESET_RAW_BITS);
      packed_length = STR_SIZE (src_precision, db_get_string_codeset (value));
    }
  else
    {
      /*
       * Precision is "floating", calculate the effective precision based on the
       * string length.
       */
      packed_length = db_get_string_size (value);

      /* add in storage for a size prefix on the packed value. */
      packed_length += OR_INT_SIZE;
    }

  /*
   * NOTE: We do NOT perform padding here, if this is used in the context
   * of a packed value, the or_put_value() family of functions must handle
   * their own padding, this is because "lengthval" and "writeval" can be
   * used to place values into the disk representation of instances and
   * there can be no padding in there.
   */

  return packed_length;
}


static int
mr_index_writeval_bit (OR_BUF * buf, DB_VALUE * value)
{
  return mr_writeval_bit_internal (buf, value, CHAR_ALIGNMENT);
}

/*
 * See commentary in mr_data_lengthval_bit.
 */
static int
mr_data_writeval_bit (OR_BUF * buf, DB_VALUE * value)
{
  return mr_writeval_bit_internal (buf, value, INT_ALIGNMENT);
}

static int
mr_writeval_bit_internal (OR_BUF * buf, DB_VALUE * value, int align)
{
  int src_precision, src_length, packed_length, pad;
  const char *src;
  int rc = NO_ERROR;

  src = db_get_string (value);
  if (src == NULL)
    {
      return rc;
    }

  src_precision = db_value_precision (value);
  src_length = db_get_string_size (value);  /* size in bytes */

  if (!IS_FLOATING_PRECISION (src_precision))
    {
      assert (db_get_string_codeset (value) == INTL_CODESET_RAW_BITS);
      packed_length = STR_SIZE (src_precision, db_get_string_codeset (value));

      if (packed_length < src_length)
    {
      /* should have caught this by now, truncate silently */
      or_put_data (buf, src, packed_length);
    }
      else
    {
      rc = or_put_data (buf, src, src_length);
      if (rc == NO_ERROR)
        {
          /* Check for padding */
          pad = packed_length - src_length;
          if (pad)
        {
          int i;

          for (i = src_length; i < packed_length; i++)
            {
              rc = or_put_byte (buf, (int) '\0');
            }
        }
        }
    }
    }
  else
    {
      /*
       * This is a "floating" precision value. Pack what we can based on the
       * string size.  Note that for this to work, this can only be packed
       * as part of a domain tagged value and we must include a length
       * prefix after the domain.
       */
      packed_length = db_get_string_length (value);

      /* store the size prefix */
      if (align == INT_ALIGNMENT)
    {
      rc = or_put_int (buf, packed_length);
    }
      else
    {
      rc = or_put_data (buf, (char *) (&packed_length), OR_INT_SIZE);
    }

      if (rc == NO_ERROR)
    {
      /* store the data */
      rc = or_put_data (buf, src, BITS_TO_BYTES (packed_length));
      /* there is no blank padding in this case */
    }
    }

  return rc;
}

static int
mr_index_readval_bit (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  return mr_readval_bit_internal (buf, value, domain, disk_size, copy, copy_buf, copy_buf_len, CHAR_ALIGNMENT);
}

static int
mr_data_readval_bit (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  return mr_readval_bit_internal (buf, value, domain, disk_size, copy, copy_buf, copy_buf_len, INT_ALIGNMENT);
}

static int
mr_readval_bit_internal (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int disk_size, bool copy, char *copy_buf,
             int copy_buf_len, int align)
{
  int mem_length, padding;
  int bit_length;
  char *new_;
  int rc = NO_ERROR;

  if (IS_FLOATING_PRECISION (domain->precision))
    {
      if (align == INT_ALIGNMENT)
    {
      bit_length = or_get_int (buf, &rc);
    }
      else
    {
      rc = or_get_data (buf, (char *) (&bit_length), OR_INT_SIZE);
    }
      if (rc != NO_ERROR)
    {
      return ER_FAILED;
    }

      mem_length = BITS_TO_BYTES (bit_length);
      if (value == NULL)
    {
      rc = or_advance (buf, mem_length);
    }
      else if (!copy)
    {
      db_make_bit (value, TP_FLOATING_PRECISION_VALUE, buf->ptr, bit_length);
      value->need_clear = false;
      rc = or_advance (buf, mem_length);
    }
      else
    {
      if (copy_buf && copy_buf_len >= mem_length + 1)
        {
          /* read buf image into the copy_buf */
          new_ = copy_buf;
        }
      else
        {
          /*
           * Allocate storage for the string including the kludge NULL
           * terminator
           */
          new_ = (char *) db_private_alloc (NULL, mem_length + 1);
        }

      if (new_ == NULL)
        {
          /* need to be able to return errors ! */
          db_value_domain_init (value, TP_DOMAIN_TYPE (domain), TP_FLOATING_PRECISION_VALUE, 0);
          return ER_FAILED;
        }
      else
        {
          rc = or_get_data (buf, new_, mem_length);
          if (rc != NO_ERROR)
        {
          if (new_ != copy_buf)
            {
              db_private_free_and_init (NULL, new_);
            }

          return rc;
        }
          new_[mem_length] = '\0';  /* append the kludge NULL terminator */
          db_make_bit (value, TP_FLOATING_PRECISION_VALUE, new_, bit_length);
          value->need_clear = (new_ != copy_buf) ? true : false;
        }
    }
    }
  else
    {
      assert (TP_DOMAIN_CODESET (domain) == INTL_CODESET_RAW_BITS);
      mem_length = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));

      if (disk_size != -1 && mem_length > disk_size)
    {
      /*
       * If we're low here, we could just read what we have and make a
       * smaller value.  Still the domain should match at this point.
       */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_CORRUPTED, 0);
      assert (false);

      return ER_FAILED;
    }

      if (value == NULL)
    {
      rc = or_advance (buf, mem_length);
    }
      else if (!copy)
    {
      db_make_bit (value, domain->precision, buf->ptr, domain->precision);
      value->need_clear = false;
      rc = or_advance (buf, mem_length);
    }
      else
    {
      if (copy_buf && copy_buf_len >= mem_length + 1)
        {
          /* read buf image into the copy_buf */
          new_ = copy_buf;
        }
      else
        {
          /*
           * Allocate storage for the string including the kludge NULL
           * terminator
           */
          new_ = (char *) db_private_alloc (NULL, mem_length + 1);
        }

      if (new_ == NULL)
        {
          /* need to be able to return errors ! */
          db_value_domain_init (value, TP_DOMAIN_TYPE (domain), domain->precision, 0);
          return ER_FAILED;
        }
      else
        {
          rc = or_get_data (buf, new_, mem_length);
          if (rc != NO_ERROR)
        {
          if (new_ != copy_buf)
            {
              db_private_free_and_init (NULL, new_);
            }

          return rc;
        }
          new_[mem_length] = '\0';  /* append the kludge NULL terminator */
          db_make_bit (value, domain->precision, new_, domain->precision);
          value->need_clear = (new_ != copy_buf) ? true : false;
        }
    }
      if (rc == NO_ERROR)
    {
      /*
       * We should only see padding if the string is contained within a
       * packed value that had extra padding to ensure alignment.  If we see
       * these, just pop them out of the buffer.
       */
      if (disk_size != -1)
        {
          padding = disk_size - mem_length;
          if (padding > 0)
        {
          rc = or_advance (buf, padding);
        }
        }
    }
    }

  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_bit (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return mr_cmpdisk_bit_internal (mem1, mem2, domain, do_coercion, total_order, start_colp, CHAR_ALIGNMENT);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_bit (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return mr_cmpdisk_bit_internal (mem1, mem2, domain, do_coercion, total_order, start_colp, INT_ALIGNMENT);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpdisk_bit_internal (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp,
             int align)
{
  DB_VALUE_COMPARE_RESULT c;
  int bit_length1, mem_length1, bit_length2, mem_length2, bitc;

  if (IS_FLOATING_PRECISION (domain->precision))
    {
      if (align == INT_ALIGNMENT)
    {
      bit_length1 = OR_GET_INT (mem1);
      bit_length2 = OR_GET_INT (mem2);
    }
      else
    {
      memcpy (&bit_length1, mem1, OR_INT_SIZE);
      memcpy (&bit_length2, mem2, OR_INT_SIZE);
    }
      mem1 = (char *) mem1 + OR_INT_SIZE;
      mem_length1 = BITS_TO_BYTES (bit_length1);
      mem2 = (char *) mem2 + OR_INT_SIZE;
      mem_length2 = BITS_TO_BYTES (bit_length2);
    }
  else
    {
      assert (TP_DOMAIN_CODESET (domain) == INTL_CODESET_RAW_BITS);
      mem_length1 = mem_length2 = STR_SIZE (domain->precision, TP_DOMAIN_CODESET (domain));
    }

  bitc = bit_compare ((unsigned char *) mem1, mem_length1, (unsigned char *) mem2, mem_length2);
  c = MR_CMP_RETURN_CODE (bitc);

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_bit (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  DB_VALUE_COMPARE_RESULT c;
  int bitc;

  const unsigned char *string1 = REINTERPRET_CAST (const unsigned char *, db_get_string (value1));
  const unsigned char *string2 = REINTERPRET_CAST (const unsigned char *, db_get_string (value2));

  if (string1 == NULL || string2 == NULL)
    {
      return DB_UNK;
    }

  bitc = bit_compare (string1, (int) db_get_string_size (value1), string2, (int) db_get_string_size (value2));
  c = MR_CMP_RETURN_CODE (bitc);

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_bit2 (DB_VALUE * value1, DB_VALUE * value2, int length, int do_coercion, int total_order, int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c;
  int len1, len2, string_size;
  int bitc;

  const unsigned char *string1 = REINTERPRET_CAST (const unsigned char *, db_get_string (value1));
  const unsigned char *string2 = REINTERPRET_CAST (const unsigned char *, db_get_string (value2));

  if (string1 == NULL || string2 == NULL)
    {
      return DB_UNK;
    }

  string_size = (int) db_get_string_size (value1);
  len1 = MIN (string_size, length);
  string_size = (int) db_get_string_size (value2);
  len2 = MIN (string_size, length);

  bitc = bit_compare (string1, len1, string2, len2);
  c = MR_CMP_RETURN_CODE (bitc);

  return c;
}


const PR_TYPE tp_Bit = {
  "bit", DB_TYPE_BIT, 0, 0, 0, 1,
  mr_initmem_bit,
  mr_initval_bit,
  mr_setmem_bit,
  mr_getmem_bit,
  mr_setval_bit,
  mr_data_lengthmem_bit,
  mr_data_lengthval_bit,
  mr_data_writemem_bit,
  mr_data_readmem_bit,
  mr_data_writeval_bit,
  mr_data_readval_bit,
  mr_index_lengthmem_bit,
  mr_index_lengthval_bit,
  mr_index_writeval_bit,
  mr_index_readval_bit,
  mr_index_cmpdisk_bit,
  mr_freemem_bit,
  mr_data_cmpdisk_bit,
  mr_cmpval_bit
};

const PR_TYPE *tp_Type_bit = &tp_Bit;

/*
 * TYPE VARBIT
 */

static void
mr_initmem_varbit (void *mem, TP_DOMAIN * domain)
{
  *(char **) mem = NULL;
}


/*
 * The main difference between "memory" strings and "value" strings is that
 * the length tag is stored as an in-line prefix in the memory block allocated
 * to hold the string characters.
 */
static int
mr_setmem_varbit (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  int error = NO_ERROR;
  const char *src;
  char *cur, *new_, **mem;
  int src_precision, src_length, src_length_bits, new_length;

  /* get the current memory contents */
  mem = (char **) memptr;
  cur = *mem;

  if (value == NULL || (src = db_get_string (value)) == NULL)
    {
      /* remove the current value */
      if (cur != NULL)
    {
      db_private_free_and_init (NULL, cur);
      mr_initmem_varbit (memptr, domain);
    }
    }
  else
    {
      /*
       * Get information from the value.  Ignore precision for the time being
       * since we really only care about the byte size of the value for varbit.
       * Whether or not the value "fits" should have been checked by now.
       */
      src_precision = db_value_precision (value);
      src_length = db_get_string_size (value);  /* size in bytes */
      src_length_bits = db_get_string_length (value);   /* size in bits */

      new_length = src_length + sizeof (int);
      new_ = (char *) db_private_alloc (NULL, new_length);
      if (new_ == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
      else
    {
      if (cur != NULL)
        {
          db_private_free_and_init (NULL, cur);
        }

      /* pack in the length prefix */
      *(int *) new_ = src_length_bits;
      cur = new_ + sizeof (int);
      /* store the string */
      memcpy (cur, src, src_length);
      *mem = new_;
    }
    }

  return error;
}

static int
mr_getmem_varbit (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int error = NO_ERROR;
  int mem_bit_length;
  char **mem, *cur, *new_;

  /* get to the current value */
  mem = (char **) memptr;
  cur = *mem;

  if (cur == NULL)
    {
      db_value_domain_init (value, DB_TYPE_VARBIT, domain->precision, 0);
      value->need_clear = false;
    }
  else
    {
      /* extract the length prefix and the pointer to the actual string data */
      mem_bit_length = *(int *) cur;
      cur += sizeof (int);

      if (!copy)
    {
      db_make_varbit (value, domain->precision, cur, mem_bit_length);
      value->need_clear = false;
    }
      else
    {
      /* return it */
      new_ = (char *) db_private_alloc (NULL, BITS_TO_BYTES (mem_bit_length) + 1);
      if (new_ == NULL)
        {
          assert (er_errid () != NO_ERROR);
          error = er_errid ();
        }
      else
        {
          memcpy (new_, cur, BITS_TO_BYTES (mem_bit_length));
          db_make_varbit (value, domain->precision, new_, mem_bit_length);
          value->need_clear = true;
        }
    }
    }

  return error;
}


/*
 * For the disk representation, we may be adding pad bytes
 * to round up to a word boundary.
 */
static int
mr_data_lengthmem_varbit (void *memptr, TP_DOMAIN * domain, int disk)
{
  char **mem, *cur;
  int len;

  len = 0;
  if (!disk)
    {
      len = tp_VarBit.size;
    }
  else if (memptr != NULL)
    {
      mem = (char **) memptr;
      cur = *mem;
      if (cur != NULL)
    {
      len = *(int *) cur;
      len = or_packed_varbit_length (len);
    }
    }

  return len;
}

static int
mr_index_lengthmem_varbit (void *memptr, TP_DOMAIN * domain)
{
  OR_BUF buf;
  int bitlen;
  int rc = NO_ERROR;

  or_init (&buf, (char *) memptr, -1);

  bitlen = or_get_varbit_length (&buf, &rc);

  return or_varbit_length (bitlen);
}

static void
mr_data_writemem_varbit (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
  char **mem, *cur;
  int bitlen;

  mem = (char **) memptr;
  cur = *mem;
  if (cur != NULL)
    {
      bitlen = *(int *) cur;
      cur += sizeof (int);
      or_packed_put_varbit (buf, cur, bitlen);
    }
}


/*
 * The amount of memory requested is currently calculated based on the
 * stored size prefix.  If we ever go to a system where we avoid storing the
 * size, then we could use the size argument passed in to this function but
 * that may also include any padding byte that added to bring us up to a word
 * boundary. Might want some way to determine which bytes at the end of a
 * string are padding.
 */
static void
mr_data_readmem_varbit (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size)
{
  char **mem, *cur, *new_;
  int bit_len;
  int mem_length, pad;
  char *start;
  int rc = NO_ERROR;

  /* Must have an explicit size here - can't be determined from the domain */
  if (size < 0)
    {
      return;
    }

  if (memptr == NULL)
    {
      if (size)
    {
      or_advance (buf, size);
    }
    }
  else
    {
      mem = (char **) memptr;
      cur = *mem;
      /* should we be checking for existing strings ? */
#if 0
      if (cur != NULL)
    db_private_free_and_init (NULL, cur);
#endif

      new_ = NULL;
      if (size)
    {
      start = buf->ptr;

      /* KLUDGE, we have some knowledge of how the thing is stored here in order have some control over the
       * conversion between the packed length prefix and the full word memory length prefix. Might want to put this
       * in another specialized or_ function. */

      /* Get just the length prefix. */
      bit_len = or_get_varbit_length (buf, &rc);

      /*
       * Allocate storage for this string, including our own full word size
       * prefix.
       */
      mem_length = BITS_TO_BYTES (bit_len) + sizeof (int);

      new_ = (char *) db_private_alloc (NULL, mem_length);
      if (new_ == NULL)
        {
          return;
        }
      else
        {
          /* store the length in our memory prefix */
          *(int *) new_ = bit_len;
          cur = new_ + sizeof (int);

          /* read the string */
          or_get_data (buf, cur, BITS_TO_BYTES (bit_len));
          /* align like or_get_varchar */
          or_get_align32 (buf);
        }

      /*
       * If we were given a size, check to see if for some reason this is
       * larger than the already word aligned string that we have now
       * extracted.  This shouldn't be the case but since we've got a
       * length, we may as well obey it.
       */
      pad = size - (int) (buf->ptr - start);
      if (pad > 0)
        {
          or_advance (buf, pad);
        }
    }
      *mem = new_;
    }
}

static void
mr_freemem_varbit (void *memptr)
{
  char *cur;

  if (memptr != NULL)
    {
      cur = *(char **) memptr;
      if (cur != NULL)
    {
      db_private_free_and_init (NULL, cur);
    }
    }
}

static void
mr_initval_varbit (DB_VALUE * value, int precision, int scale)
{
  db_make_varbit (value, precision, NULL, 0);
  value->need_clear = false;
}

static int
mr_setval_varbit (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error = NO_ERROR;
  int src_precision, src_length, src_bit_length;
  char *new_;
  const char *src_str;

  assert (!db_value_is_corrupted (src));
  if (src == NULL || DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_VARBIT, DB_DEFAULT_PRECISION, 0);
    }
  else if ((src_str = db_get_string (src)) == NULL)
    {
      error = db_value_domain_init (dest, DB_TYPE_VARBIT, db_value_precision (src), 0);
    }
  else
    {
      /* Get information from the value. */
      src_precision = db_value_precision (src);
      src_length = db_get_string_size (src);
      src_bit_length = db_get_string_length (src);

      /* should we be paying attention to this? it is extremely dangerous */
      if (!copy)
    {
      error = db_make_varbit (dest, src_precision, src_str, src_bit_length);
    }
      else
    {
      new_ = (char *) db_private_alloc (NULL, src_length + 1);
      if (new_ == NULL)
        {
          db_value_domain_init (dest, DB_TYPE_VARBIT, src_precision, 0);
          assert (er_errid () != NO_ERROR);
          error = er_errid ();
        }
      else
        {
          memcpy (new_, src_str, src_length);
          db_make_varbit (dest, src_precision, new_, src_bit_length);
          dest->need_clear = true;
        }
    }
    }

  return error;
}

static int
mr_index_lengthval_varbit (DB_VALUE * value)
{
  return mr_lengthval_varbit_internal (value, 1, CHAR_ALIGNMENT);
}

static int
mr_index_writeval_varbit (OR_BUF * buf, DB_VALUE * value)
{
  return mr_writeval_varbit_internal (buf, value, CHAR_ALIGNMENT);
}

static int
mr_index_readval_varbit (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
             int copy_buf_len)
{
  return mr_readval_varbit_internal (buf, value, domain, size, copy, copy_buf, copy_buf_len, CHAR_ALIGNMENT);
}

static int
mr_data_lengthval_varbit (DB_VALUE * value, int disk)
{
  return mr_lengthval_varbit_internal (value, disk, INT_ALIGNMENT);
}

static int
mr_data_writeval_varbit (OR_BUF * buf, DB_VALUE * value)
{
  return mr_writeval_varbit_internal (buf, value, INT_ALIGNMENT);
}

static int
mr_data_readval_varbit (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
            int copy_buf_len)
{
  return mr_readval_varbit_internal (buf, value, domain, size, copy, copy_buf, copy_buf_len, INT_ALIGNMENT);
}

static int
mr_lengthval_varbit_internal (DB_VALUE * value, int disk, int align)
{
  int bit_length, len;

  len = 0;
  if (value != NULL && db_get_string (value) != NULL)
    {
      bit_length = db_get_string_length (value);    /* size in bits */

      if (align == INT_ALIGNMENT)
    {
      len = or_packed_varbit_length (bit_length);
    }
      else
    {
      len = or_varbit_length (bit_length);
    }
    }

  return len;
}

static int
mr_writeval_varbit_internal (OR_BUF * buf, DB_VALUE * value, int align)
{
  int src_bit_length;
  const char *str;
  int rc = NO_ERROR;

  if (value != NULL && (str = db_get_string (value)) != NULL)
    {
      src_bit_length = db_get_string_length (value);    /* size in bits */

      if (align == INT_ALIGNMENT)
    {
      rc = or_packed_put_varbit (buf, str, src_bit_length);
    }
      else
    {
      rc = or_put_varbit (buf, str, src_bit_length);
    }
    }

  assert (buf->ptr <= buf->endptr); /* safety check in heap_file.c */
  return rc;
}

/*
 * Size can come in as negative here to create a value with a pointer
 * directly to disk.
 *
 * Note that we have a potential conflict with this as -1 is a valid size
 * to use here when the string has been packed with a domain/length prefix
 * and we can determine the size from there.  In current practice, this
 * isn't a problem because due to word alignment, we'll never get a
 * negative size here that is greater than -4.
 */
static int
mr_readval_varbit_internal (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                int copy_buf_len, int align)
{
  int pad, precision;
  int str_bit_length, str_length;
  char *new_, *start = NULL;
  int rc = NO_ERROR;

  if (value == NULL)
    {
      if (size == -1)
    {
      rc = or_skip_varbit (buf, align);
    }
      else
    {
      if (size)
        rc = or_advance (buf, size);
    }
    }
  else
    {
      if (domain != NULL)
    {
      precision = domain->precision;
    }
      else
    {
      precision = DB_MAX_VARBIT_PRECISION;
    }

      if (size == 0)
    {
      /* its NULL */
      db_value_domain_init (value, DB_TYPE_VARBIT, precision, 0);
    }
      else if (!copy)
    {
      str_bit_length = or_get_varbit_length (buf, &rc);
      if (rc == NO_ERROR)
        {
          db_make_varbit (value, precision, buf->ptr, str_bit_length);
          value->need_clear = false;
          rc = or_skip_varbit_remainder (buf, str_bit_length, align);
        }
    }
      else
    {
      if (size == -1)
        {
          /* Standard packed varbit with a size prefix */
          ;         /* do nothing */
        }
      else
        {           /* size != -1 */
          /* Standard packed varbit within an area of fixed size, usually this means we're looking at the disk
           * representation of an attribute. Just like the -1 case except we advance past the additional
           * padding. */
          start = buf->ptr;
        }           /* size != -1 */

      str_bit_length = or_get_varbit_length (buf, &rc);
      if (rc != NO_ERROR)
        {
          return ER_FAILED;
        }
      /* get the string byte length */
      str_length = BITS_TO_BYTES (str_bit_length);

      if (copy_buf && copy_buf_len >= str_length + 1)
        {
          /* read buf image into the copy_buf */
          new_ = copy_buf;
        }
      else
        {
          /*
           * Allocate storage for the string including the kludge NULL
           * terminator
           */
          new_ = (char *) db_private_alloc (NULL, str_length + 1);
        }

      if (new_ == NULL)
        {
          /* need to be able to return errors ! */
          if (domain)
        {
          db_value_domain_init (value, TP_DOMAIN_TYPE (domain), TP_FLOATING_PRECISION_VALUE, 0);
        }
          return ER_FAILED;
        }
      else
        {
          /* do not read the kludge NULL terminator */
          rc = or_get_data (buf, new_, str_length);
          if (rc == NO_ERROR && align == INT_ALIGNMENT)
        {
          /* round up to a word boundary */
          rc = or_get_align32 (buf);
        }

          if (rc != NO_ERROR)
        {
          if (new_ != copy_buf)
            {
              db_private_free_and_init (NULL, new_);
            }
          return ER_FAILED;
        }

          new_[str_length] = '\0';  /* append the kludge NULL terminator */
          db_make_varbit (value, precision, new_, str_bit_length);
          value->need_clear = (new_ != copy_buf) ? true : false;

          if (size == -1)
        {
          /* Standard packed varbit with a size prefix */
          ;     /* do nothing */
        }
          else
        {       /* size != -1 */
          /* Standard packed varbit within an area of fixed size, usually this means we're looking at the
           * disk representation of an attribute. Just like the -1 case except we advance past the
           * additional padding. */
          pad = size - (int) (buf->ptr - start);
          if (pad > 0)
            {
              rc = or_advance (buf, pad);
            }
        }       /* size != -1 */
        }           /* else */
    }

    }
  return rc;
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_varbit (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  assert (domain != NULL);

  return mr_data_cmpdisk_varbit (mem1, mem2, domain, do_coercion, total_order, start_colp);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_varbit (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c;
  int bit_length1, bit_length2;
  int mem_length1, mem_length2, bitc;
  OR_BUF buf1, buf2;
  int error = NO_ERROR;

  assert (domain != NULL);

  or_init (&buf1, (char *) mem1, 0);
  bit_length1 = or_get_varbit_length (&buf1, &error);
  mem_length1 = BITS_TO_BYTES (bit_length1);
  assert (error == NO_ERROR);

  or_init (&buf2, (char *) mem2, 0);
  bit_length2 = or_get_varbit_length (&buf2, &error);
  mem_length2 = BITS_TO_BYTES (bit_length2);
  assert (error == NO_ERROR);

  bitc = varbit_compare ((unsigned char *) buf1.ptr, mem_length1, (unsigned char *) buf2.ptr, mem_length2);
  c = MR_CMP_RETURN_CODE (bitc);

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_varbit (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
          int collation)
{
  DB_VALUE_COMPARE_RESULT c;
  int bitc;

  const unsigned char *string1 = REINTERPRET_CAST (const unsigned char *, db_get_string (value1));
  const unsigned char *string2 = REINTERPRET_CAST (const unsigned char *, db_get_string (value2));

  if (string1 == NULL || string2 == NULL)
    {
      return DB_UNK;
    }

  bitc = varbit_compare (string1, (int) db_get_string_size (value1), string2, (int) db_get_string_size (value2));
  c = MR_CMP_RETURN_CODE (bitc);

  return c;
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_varbit2 (DB_VALUE * value1, DB_VALUE * value2, int length, int do_coercion, int total_order, int *start_colp)
{
  DB_VALUE_COMPARE_RESULT c;
  int len1, len2, string_size;
  int bitc;

  const unsigned char *string1 = REINTERPRET_CAST (const unsigned char *, db_get_string (value1));
  const unsigned char *string2 = REINTERPRET_CAST (const unsigned char *, db_get_string (value2));

  if (string1 == NULL || string2 == NULL)
    {
      return DB_UNK;
    }

  string_size = (int) db_get_string_size (value1);
  len1 = MIN (string_size, length);
  string_size = (int) db_get_string_size (value2);
  len2 = MIN (string_size, length);

  bitc = varbit_compare (string1, len1, string2, len2);
  c = MR_CMP_RETURN_CODE (bitc);

  return c;
}


const PR_TYPE tp_VarBit = {
  "bit varying", DB_TYPE_VARBIT, 1, sizeof (const char *), 0, 1,
  mr_initmem_varbit,
  mr_initval_varbit,
  mr_setmem_varbit,
  mr_getmem_varbit,
  mr_setval_varbit,
  mr_data_lengthmem_varbit,
  mr_data_lengthval_varbit,
  mr_data_writemem_varbit,
  mr_data_readmem_varbit,
  mr_data_writeval_varbit,
  mr_data_readval_varbit,
  mr_index_lengthmem_varbit,
  mr_index_lengthval_varbit,
  mr_index_writeval_varbit,
  mr_index_readval_varbit,
  mr_index_cmpdisk_varbit,
  mr_freemem_varbit,
  mr_data_cmpdisk_varbit,
  mr_cmpval_varbit
};

const PR_TYPE *tp_Type_varbit = &tp_VarBit;


static void
mr_initmem_enumeration (void *mem, TP_DOMAIN * domain)
{
  *(unsigned short *) mem = 0;
}

static void
mr_initval_enumeration (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_ENUMERATION, precision, scale);
  db_make_enumeration (value, 0, NULL, 0, LANG_SYS_CODESET, LANG_SYS_COLLATION);
}

static int
mr_setmem_enumeration (void *mem, TP_DOMAIN * domain, DB_VALUE * value)
{
  if (value == NULL)
    {
      mr_initmem_enumeration (mem, domain);
    }
  else
    {
      *(unsigned short *) mem = db_get_enum_short (value);
    }

  return NO_ERROR;
}

static int
mr_getmem_enumeration (void *mem, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  unsigned short short_val = 0;

  short_val = *(short *) mem;

  return mr_setval_enumeration_internal (value, domain, short_val, 0, copy, NULL, 0);
}

static int
mr_setval_enumeration (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  const char *str = NULL;
  bool need_clear = false;

  if (src == NULL || DB_IS_NULL (src))
    {
      return db_value_domain_init (dest, DB_TYPE_ENUMERATION, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
    }

  if (db_get_enum_string (src) != NULL)
    {
      if (copy)
    {
      char *str_tmp = (char *) db_private_alloc (NULL, db_get_enum_string_size (src) + 1);
      if (str_tmp == NULL)
        {
          assert (er_errid () != NO_ERROR);
          return er_errid ();
        }
      memcpy (str_tmp, db_get_enum_string (src), db_get_enum_string_size (src));
      str_tmp[db_get_enum_string_size (src)] = 0;
      need_clear = true;
      str = str_tmp;
    }
      else
    {
      str = db_get_enum_string (src);
    }
    }

  /* get proper codeset from src */
  db_make_enumeration (dest, db_get_enum_short (src), str, db_get_enum_string_size (src), db_get_enum_codeset (src),
               db_get_enum_collation (src));
  dest->need_clear = need_clear;

  return NO_ERROR;
}

static void
mr_data_writemem_enumeration (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
  unsigned short *mem = (unsigned short *) memptr;

  or_put_short (buf, *mem);
}

static void
mr_data_readmem_enumeration (OR_BUF * buf, void *mem, TP_DOMAIN * domain, int size)
{
  int rc = NO_ERROR;
  if (mem == NULL)
    {
      or_advance (buf, tp_Enumeration.disksize);
    }
  else
    {
      *(unsigned short *) mem = (unsigned short) or_get_short (buf, &rc);
    }
}

/*
 * mr_setval_enumeration_internal () - make an enumeration value based on
 *  index and domain.
 * return: NO_ERROR or error code.
 * value(in/out):
 * domain(in):
 * index(in): index of enumeration string
 * size(in):
 * copy(in):
 * copy_buf(in):
 * copy_buf_len(in):
 */
static int
mr_setval_enumeration_internal (DB_VALUE * value, TP_DOMAIN * domain, unsigned short index, int size, bool copy,
                char *copy_buf, int copy_buf_len)
{
  bool need_clear = false;
  int str_size;
  const char *str = NULL;
  DB_ENUM_ELEMENT *db_elem = NULL;

  if (domain == NULL || DOM_GET_ENUM_ELEMS_COUNT (domain) == 0 || index == 0 || index == DB_ENUM_OVERFLOW_VAL)
    {
      db_make_enumeration (value, index, NULL, 0, TP_DOMAIN_CODESET (domain), TP_DOMAIN_COLLATION (domain));
      value->need_clear = false;
      return NO_ERROR;
    }

  if (index > DOM_GET_ENUM_ELEMS_COUNT (domain) && DOM_GET_ENUM_ELEMS_COUNT (domain) > 0)
    {
      assert (false);
      return ER_FAILED;
    }

  db_elem = &DOM_GET_ENUM_ELEM (domain, index);
  str_size = DB_GET_ENUM_ELEM_STRING_SIZE (db_elem);
  if (!copy)
    {
      str = DB_GET_ENUM_ELEM_STRING (db_elem);
    }
  else
    {
      char *str_tmp = NULL;
      if (copy_buf && copy_buf_len >= str_size + 1)
    {
      /* read buf image into the copy_buf */
      str_tmp = copy_buf;
      need_clear = false;
    }
      else
    {
      str_tmp = (char *) db_private_alloc (NULL, str_size + 1);
      if (str_tmp == NULL)
        {
          return ER_FAILED;
        }
      need_clear = true;
    }

      memcpy (str_tmp, DB_GET_ENUM_ELEM_STRING (db_elem), str_size);
      str_tmp[str_size] = 0;

      str = str_tmp;
    }

  db_make_enumeration (value, index, str, str_size, TP_DOMAIN_CODESET (domain), TP_DOMAIN_COLLATION (domain));
  value->need_clear = need_clear;

  return NO_ERROR;
}

static int
mr_data_readval_enumeration (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                 int copy_buf_len)
{
  int rc = NO_ERROR;
  unsigned short s;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Enumeration.disksize);
      return rc;
    }

  s = (unsigned short) or_get_short (buf, &rc);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  return mr_setval_enumeration_internal (value, domain, s, size, copy, copy_buf, copy_buf_len);
}

static int
mr_data_writeval_enumeration (OR_BUF * buf, DB_VALUE * value)
{
  return or_put_short (buf, db_get_enum_short (value));
}

static int
mr_index_writeval_enumeration (OR_BUF * buf, DB_VALUE * value)
{
  unsigned short s = db_get_enum_short (value);

  return or_put_data (buf, (char *) (&s), tp_Enumeration.disksize);
}

static int
mr_index_readval_enumeration (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
                  int copy_buf_len)
{
  int rc = NO_ERROR;
  unsigned short s;

  if (value == NULL)
    {
      rc = or_advance (buf, tp_Enumeration.disksize);
      return rc;
    }

  rc = or_get_data (buf, (char *) (&s), tp_Enumeration.disksize);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  return mr_setval_enumeration_internal (value, domain, s, size, copy, copy_buf, copy_buf_len);
}

static DB_VALUE_COMPARE_RESULT
mr_index_cmpdisk_enumeration (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order,
                  int *start_colp)
{
  unsigned short s1, s2;

  assert (domain != NULL);

  COPYMEM (unsigned short, &s1, mem1);
  COPYMEM (unsigned short, &s2, mem2);

  return MR_CMP (s1, s2);
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_enumeration (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order,
                 int *start_colp)
{
  unsigned short s1, s2;

  assert (domain != NULL);

  s1 = (unsigned short) OR_GET_SHORT (mem1);
  s2 = (unsigned short) OR_GET_SHORT (mem2);

  return MR_CMP (s1, s2);
}

static DB_VALUE_COMPARE_RESULT
mr_cmpval_enumeration (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp,
               int collation)
{
  unsigned short s1, s2;

  s1 = db_get_enum_short (value1);
  s2 = db_get_enum_short (value2);

  return MR_CMP (s1, s2);
}

/*
 * pr_get_compressed_data_from_buffer ()      - Uncompresses a data stored in buffer.
 *
 * return()                   : NO_ERROR or error code.
 * buf(in)                    : The buffer from which is needed decompression.
 * data(out)                      : The result of the decompression. !!! Needs to be alloc'ed !!!
 * compressed_size(in)                : The compressed data size.
 * expected_decompressed_sizes(in)        : The expected uncompressed data size.
 */
int
pr_get_compressed_data_from_buffer (struct or_buf *buf, char *data, int compressed_size, int expected_decompressed_size)
{
  int rc = NO_ERROR;

  /* Check if the string needs decompression */
  if (compressed_size > 0)
    {
      int decompressed_size = 0;
      /* Handle decompression */

      /* decompressing the string */
      // *INDENT-OFF*
      decompressed_size =
    cubcompress::decompress<cubcompress::LZ4> (buf->ptr, compressed_size, data, expected_decompressed_size);
      // *INDENT-ON*
      if (decompressed_size < 0)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_LZ4_DECOMPRESS_FAIL, 0);
      return ER_IO_LZ4_DECOMPRESS_FAIL;
    }

      assert (decompressed_size == expected_decompressed_size);

      data[decompressed_size] = '\0';
    }
  else
    {
      /* String is not compressed and buf->ptr is pointing towards an array of chars of length equal to
       * decompressed_size */

      rc = or_get_data (buf, data, expected_decompressed_size);
      data[expected_decompressed_size] = '\0';
    }

  return rc;
}

/*
 * pr_get_compression_length()        - Simulate a compression to find its length to be stored on the disk.
 *
 * return()               : The length of the compression, based on the new encoding of varchar.
 *                      If the compression fails, then it returns charlen.
 * string(in)                 : The string to be compressed.
 * str_length(in)                 : The length of the string to be compressed.
 */
int
pr_get_compression_length (const char *string, int str_length)
{
  char *compressed_string = NULL;
  int compressed_length = 0;
  int rc = NO_ERROR;
  int length = 0, compress_buffer_size;

  assert (str_length >= OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION);
  if (!pr_Enable_string_compression || str_length > LZ4_MAX_INPUT_SIZE) /* compression is not set */
    {
      return str_length;
    }

  /* Alloc memory for the compressed string */
  // *INDENT-OFF*
  compress_buffer_size = cubcompress::bound<cubcompress::LZ4> (str_length);
  // *INDENT-ON*
  compressed_string = (char *) malloc (compress_buffer_size);
  if (compressed_string == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) compress_buffer_size);
      return str_length;
    }

  /* Compress the string */
  // *INDENT-OFF*
  compressed_length =
    cubcompress::compress<cubcompress::LZ4> (string, str_length, compressed_string, compress_buffer_size);
  // *INDENT-ON*
  if (compressed_length <= 0)
    {
      /* We should not be having any kind of errors here. Because if this compression fails, there is not warranty
       * that the compression from putting data into buffer will fail as well. This needs to be checked but for now
       * we leave it as it is.
       */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_LZ4_COMPRESS_FAIL, 4, FILEIO_ZIP_LZ4_METHOD,
          fileio_get_zip_method_string (FILEIO_ZIP_LZ4_METHOD), FILEIO_ZIP_LZ4_DEFAULT_LEVEL,
          fileio_get_zip_level_string (FILEIO_ZIP_LZ4_DEFAULT_LEVEL));
      goto cleanup;
    }
  assert (compressed_length <= compress_buffer_size);

  if (compressed_length < str_length - 8)
    {
      /* Compression successful */
      length = compressed_length;
    }
  else
    {
      /* Compression failed */
      length = str_length;
    }

cleanup:

  if (compressed_string != NULL)
    {
      free_and_init (compressed_string);
    }

  return length;
}

/*
 * pr_get_size_and_write_string_to_buffer ()
 *                : Writes a VARCHAR to buffer and gets the correct size on the disk.
 *
 * buf(out)           : Buffer to be written to.
 * val_p(in)              : Memory area to be written to.
 * value(in)              : DB_VALUE to be written.
 * val_size(out)          : Disk size of the DB_VALUE.
 * align(in)              :
 *
 *  Note:
 *  We use this to avoid double compression when it is required to have the size of the DB_VALUE, previous
 *  to the write of the DB_VALUE in the buffer.
 */
int
pr_get_size_and_write_string_to_buffer (struct or_buf *buf, char *val_p, DB_VALUE * value, int *val_size, int align)
{
  const char *string = NULL, *str = NULL;
  char *compressed_string = NULL;
  int rc = NO_ERROR, str_length = 0, length = 0;
  int compression_length = 0, compress_buffer_size;
  bool compressed = false;

  /* Checks to be sure that we have the correct input */
  assert (DB_VALUE_DOMAIN_TYPE (value) == DB_TYPE_STRING);
  assert (db_get_string_size (value) >= OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION);

  string = db_get_string (value);
  str_length = db_get_string_size (value);
  *val_size = 0;

  if (!pr_Enable_string_compression || db_get_string_size (value) > LZ4_MAX_INPUT_SIZE) /* compression is not set */
    {
      length = str_length;
      compression_length = 0;
      str = string;
      goto after_compression;
    }

  /* Step 1 : Compress, if possible, the dbvalue */
  /* Alloc memory for the compressed string */
  // *INDENT-OFF*
  compress_buffer_size = cubcompress::bound<cubcompress::LZ4> (str_length);
  // *INDENT-ON*
  compressed_string = (char *) malloc (compress_buffer_size);
  if (compressed_string == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, compress_buffer_size);
      rc = ER_OUT_OF_VIRTUAL_MEMORY;
      goto cleanup;
    }

  // *INDENT-OFF*
  compression_length =
    cubcompress::compress<cubcompress::LZ4> (string, str_length, compressed_string, compress_buffer_size);
  // *INDENT-ON*
  if (compression_length <= 0)
    {
      /* We should not be having any kind of errors here. Because if this compression fails, there is not warranty
       * that the compression from putting data into buffer will fail as well. This needs to be checked but for now
       * we leave it as it is.
       */
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_LZ4_COMPRESS_FAIL, 4, FILEIO_ZIP_LZ4_METHOD,
          fileio_get_zip_method_string (FILEIO_ZIP_LZ4_METHOD), FILEIO_ZIP_LZ4_DEFAULT_LEVEL,
          fileio_get_zip_level_string (FILEIO_ZIP_LZ4_DEFAULT_LEVEL));
      rc = ER_IO_LZ4_COMPRESS_FAIL;
      goto cleanup;
    }
  assert (compression_length <= compress_buffer_size);

  if (compression_length < str_length - 8)
    {
      /* Compression successful */
      length = (int) compression_length;
      compressed = true;
      str = compressed_string;
    }
  else
    {
      /* Compression failed */
      length = str_length;
      compression_length = 0;
      str = string;
    }
after_compression:
  /*
   * Step 2 : Compute the disk size of the dbvalue.
   * We are sure that the initial string length is greater than 255, which means that the new encoding applies.
   */

  switch (DB_VALUE_DOMAIN_TYPE (value))
    {
    case DB_TYPE_VARCHAR:
      *val_size = or_packed_varchar_length (length + PRIM_TEMPORARY_DISK_SIZE) - PRIM_TEMPORARY_DISK_SIZE;
      break;

    default:
      /* It should not happen */
      assert (false);
      rc = ER_FAILED;
      goto cleanup;
    }

  /* Step 3 : Insert the disk representation of the dbvalue in the buffer */

  switch (DB_VALUE_DOMAIN_TYPE (value))
    {
    case DB_TYPE_STRING:
      rc = pr_write_compressed_string_to_buffer (buf, str, (int) compression_length, str_length, align);
      break;

    default:
      /* It should not happen. */
      assert (false);
      rc = ER_FAILED;
      goto cleanup;
    }

cleanup:

  if (compressed_string != NULL)
    {
      free_and_init (compressed_string);
    }

  return rc;
}

/* pr_write_compressed_string_to_buffer()     : Similar function to the previous implementation of
 *                          or_put_varchar_internal.
 *
 * buf(in/out)                    : Buffer to be written the string.
 * compressed_string(in)              : The string to be written.
 * compressed_length(in)              : Compressed length of the string. If it is 0, then no
 *                          compression happened.
 * decompressed_length(in)            : Decompressed length of the string.
 * align(in)                      :
 */

static int
pr_write_compressed_string_to_buffer (OR_BUF * buf, const char *compressed_string, int compressed_length,
                      int decompressed_length, int align)
{
  int storage_length = 0;
  int rc = NO_ERROR;

  assert (decompressed_length >= OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION
      && (compressed_length <= 0 || decompressed_length <= LZ4_MAX_INPUT_SIZE));

  /* store the size prefix */
  rc = or_put_byte (buf, 0xFF);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  /* Store the compressed size */
  OR_PUT_INT (&storage_length, compressed_length);
  rc = or_put_data (buf, (char *) &storage_length, OR_INT_SIZE);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  /* Store the decompressed size */
  OR_PUT_INT (&storage_length, decompressed_length);
  rc = or_put_data (buf, (char *) &storage_length, OR_INT_SIZE);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  /* Get the string disk size */
  if (compressed_length > 0)
    {
      storage_length = compressed_length;
    }
  else
    {
      storage_length = decompressed_length;
    }

  /* store the string bytes */
  rc = or_put_data (buf, compressed_string, storage_length);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  if (align == INT_ALIGNMENT)
    {
      /* kludge, temporary NULL terminator */
      rc = or_put_byte (buf, 0);
      if (rc != NO_ERROR)
    {
      return rc;
    }

      /* round up to a word boundary */
      rc = or_put_align32 (buf);
    }

  return rc;
}

/*
 * pr_write_uncompressed_string_to_buffer()   :-  Writes a string with a size less than
 *                        OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION to buffer.
 *
 * return                     :- NO_ERROR or error code.
 * buf(in/out)                    :- Buffer to be written to.
 * string(in)                     :- String to be written.
 * size(in)                   :- Size of the string.
 * align()                    :-
 */

static int
pr_write_uncompressed_string_to_buffer (OR_BUF * buf, const char *string, int size, int align)
{
  int rc = NO_ERROR;

  assert (size < OR_MINIMUM_STRING_LENGTH_FOR_COMPRESSION);

  /* Store the size prefix */
  rc = or_put_byte (buf, size);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  /* store the string bytes */
  rc = or_put_data (buf, string, size);
  if (rc != NO_ERROR)
    {
      return rc;
    }

  if (align == INT_ALIGNMENT)
    {
      /* kludge, temporary NULL terminator */
      rc = or_put_byte (buf, 0);
      if (rc != NO_ERROR)
    {
      return rc;
    }

      /* round up to a word boundary */
      rc = or_put_align32 (buf);
    }

  return rc;
}

/*
 *  pr_data_compress_string() :- Does compression for a string.
 *
 *  return            :- NO_ERROR or error code.
 *  string(in)            :- String to be compressed.
 *  str_length(in)        :- The size of the string.
 *  compressed_string(out)    :- The compressed string. Needs to be alloced!!!!!
 *  compress_buffer_size(in)  :- The compressed string buffer size.
 *  compressed_length(out)    :- The compressed string length.
 *
 */
int
pr_data_compress_string (const char *string, int str_length, char *compressed_string, int compress_buffer_size,
             int *compressed_length)
{
  int compressed_length_local = 0;

  assert (string != NULL && compressed_string != NULL && compressed_length != NULL && str_length >= 0
      && compress_buffer_size >= 0);

  if (!OR_IS_STRING_LENGTH_COMPRESSABLE (str_length))
    {
      *compressed_length = 0;
      return NO_ERROR;
    }

  if (!pr_Enable_string_compression)    /* compression is not set */
    {
      *compressed_length = -1;
      return NO_ERROR;
    }

  /* Compress the string */
  // *INDENT-OFF*
  compressed_length_local =
    cubcompress::compress<cubcompress::LZ4> (string, str_length, compressed_string, compress_buffer_size);
  // *INDENT-ON*
  if (compressed_length_local <= 0)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_IO_LZ4_COMPRESS_FAIL, 4, FILEIO_ZIP_LZ4_METHOD,
          fileio_get_zip_method_string (FILEIO_ZIP_LZ4_METHOD), FILEIO_ZIP_LZ4_DEFAULT_LEVEL,
          fileio_get_zip_level_string (FILEIO_ZIP_LZ4_DEFAULT_LEVEL));
      return ER_IO_LZ4_COMPRESS_FAIL;
    }
  assert (compressed_length_local <= compress_buffer_size);

  if (compressed_length_local >= str_length - 8)
    {
      /* Compression successful but its length exceeds the original length of the string. */
      /* We will also be freeing the compressed_string since we will not need it anymore. */
      *compressed_length = -1;
    }
  else
    {
      /* Compression successful */
      *compressed_length = compressed_length_local;
    }

  return NO_ERROR;
}

/*
 * pr_clear_compressed_string()       :- Clears the compressed string that might have been stored in a DB_VALUE.
 *                   This needs to succeed only for VARCHAR type.
 *
 * return ()                  :- NO_ERROR or error code.
 * value(in/out)              :- The DB_VALUE that needs the clearing.
 */

int
pr_clear_compressed_string (DB_VALUE * value)
{
  char *data = NULL;
  DB_TYPE db_type;

  if (value == NULL || DB_IS_NULL (value))
    {
      return NO_ERROR;      /* do nothing */
    }

  db_type = DB_VALUE_DOMAIN_TYPE (value);

  /* Make sure we clear only for VARCHAR type. */
  if (db_type != DB_TYPE_VARCHAR)
    {
      return NO_ERROR;      /* do nothing */
    }

  if (value->data.ch.info.compressed_need_clear == false)
    {
      return NO_ERROR;
    }

  if (value->data.ch.medium.compressed_size <= 0)
    {
      return NO_ERROR;      /* do nothing */
    }

  data = value->data.ch.medium.compressed_buf;
  if (data != NULL)
    {
      db_private_free_and_init (NULL, data);
    }

  db_set_compressed_string (value, NULL, DB_NOT_YET_COMPRESSED, false);

  return NO_ERROR;
}

/*
 * pr_do_db_value_string_compression()    :- Test a DB_VALUE for VARCHAR type and do string compression
 *                    :- for such types.
 *
 * return()               :- NO_ERROR or error code.
 * value(in/out)              :- The DB_VALUE to be tested.
 */

int
pr_do_db_value_string_compression (DB_VALUE * value)
{
  DB_TYPE db_type;
  const char *string;
  char *compressed_string;
  int rc = NO_ERROR;
  int src_size = 0, compressed_size, compressed_length;

  if (value == NULL || DB_IS_NULL (value))
    {
      return rc;        /* do nothing */
    }

  db_type = DB_VALUE_DOMAIN_TYPE (value);

  /* Make sure we clear only for VARCHAR type. */
  if (db_type != DB_TYPE_VARCHAR)
    {
      return rc;        /* do nothing */
    }

  /* Make sure the value has not been through a compression before */
  if (value->data.ch.medium.compressed_size != DB_NOT_YET_COMPRESSED)
    {
      return rc;
    }

  string = db_get_string (value);
  src_size = db_get_string_size (value);

  if (!pr_Enable_string_compression || !OR_IS_STRING_LENGTH_COMPRESSABLE (src_size))
    {
      /* Either compression was disabled or the source size is less than the compression threshold. */
      value->data.ch.medium.compressed_buf = NULL;
      value->data.ch.medium.compressed_size = DB_UNCOMPRESSABLE;
      return rc;
    }

  /* Alloc memory for compression */
  // *INDENT-OFF*
  compressed_size = cubcompress::bound<cubcompress::LZ4> (src_size);
  // *INDENT-ON*
  compressed_string = (char *) db_private_alloc (NULL, compressed_size);
  if (compressed_string == NULL)
    {
      rc = ER_OUT_OF_VIRTUAL_MEMORY;
      return rc;
    }

  rc = pr_data_compress_string (string, src_size, compressed_string, compressed_size, &compressed_length);
  if (rc != NO_ERROR)
    {
      ASSERT_ERROR ();
      goto error;
    }

  if (compressed_length > 0)
    {
      /* Compression successful */
      db_set_compressed_string (value, compressed_string, compressed_length, true);
      return rc;
    }
  else
    {
      /* Compression failed */
      db_set_compressed_string (value, NULL, DB_UNCOMPRESSABLE, false);
      goto error;
    }

error:
  if (compressed_string != NULL)
    {
      db_private_free_and_init (NULL, compressed_string);
    }

  return rc;
}

const PR_TYPE tp_Json = {
  "json", DB_TYPE_JSON, 1, sizeof (DB_JSON), 0, 1,
  mr_initmem_json,
  mr_initval_json,
  mr_setmem_json,
  mr_getmem_json,
  mr_setval_json,
  mr_data_lengthmem_json,
  mr_data_lengthval_json,
  mr_data_writemem_json,
  mr_data_readmem_json,
  mr_data_writeval_json,
  mr_data_readval_json,
  NULL,             /* index_lengthmem */
  NULL,             /* index_lengthval */
  NULL,             /* index_writeval */
  NULL,             /* index_readval */
  NULL,             /* index_cmpdisk */
  mr_freemem_json,
  mr_data_cmpdisk_json,
  mr_cmpval_json
};

const PR_TYPE *tp_Type_json = &tp_Json;

static void
mr_initmem_json (void *mem, TP_DOMAIN * domain)
{
  DB_JSON *json = (DB_JSON *) mem;

  if (json != NULL)
    {
      json->document = NULL;
      json->schema_raw = NULL;
    }
  else
    {
      assert (false);
    }
}

static int
mr_setmem_json (void *memptr, TP_DOMAIN * domain, DB_VALUE * value)
{
  int error = NO_ERROR;
  DB_JSON *json;
  JSON_DOC *doc;

  json = (DB_JSON *) memptr;
  if (json != NULL)
    {
      mr_freemem_json (memptr);
    }
  else
    {
      assert (false);
    }

  if (value == NULL)
    {
      return NO_ERROR;
    }
  doc = db_get_json_document (value);
  if (doc != NULL)
    {
      error = db_get_deep_copy_of_json (&value->data.json, json);
      if (error != NO_ERROR)
    {
      ASSERT_ERROR ();
      return error;
    }
    }

  return error;
}

static int
mr_getmem_json (void *memptr, TP_DOMAIN * domain, DB_VALUE * value, bool copy)
{
  int error = NO_ERROR;
  const char *json_schema = NULL;
  DB_JSON *json, json_copy;
  JSON_DOC *new_doc = NULL;

  json = (DB_JSON *) memptr;

  if (json == NULL)
    {
      db_make_null (value);
      db_value_domain_init (value, DB_TYPE_JSON, domain->precision, 0);
      value->need_clear = false;
      return NO_ERROR;
    }

  if (!copy)
    {
      json_schema = json->schema_raw;
      new_doc = json->document;
    }
  else
    {
      error = db_init_db_json_pointers (&json_copy);
      if (error != NO_ERROR)
    {
      return error;
    }
      error = db_get_deep_copy_of_json (json, &json_copy);
      if (error != NO_ERROR)
    {
      return error;
    }
      json_schema = json_copy.schema_raw;
      new_doc = json_copy.document;
    }

  db_make_json (value, new_doc, copy);
  db_get_json_schema (value) = json_schema;

  return error;
}

static int
mr_data_lengthmem_json (void *memptr, TP_DOMAIN * domain, int disk)
{
  int len = 0;
  DB_JSON *json;

  if (!disk)
    {
      len = tp_Json.size;
    }
  else
    {
      if (memptr != NULL)
    {
      json = (DB_JSON *) memptr;
      if (json->document == NULL)
        {
          return 0;
        }

      return (int) db_json_serialize_length (*json->document);
    }
    }

  return len;
}

static void
mr_data_writemem_json (OR_BUF * buf, void *memptr, TP_DOMAIN * domain)
{
  DB_JSON *json;
  int rc = NO_ERROR;

  json = (DB_JSON *) memptr;
  if (json == NULL || json->document == NULL)
    {
      return;
    }

  rc = db_json_serialize (*json->document, *buf);
  if (rc != NO_ERROR)
    {
      ASSERT_ERROR ();
    }
}

static void
mr_data_readmem_json (OR_BUF * buf, void *memptr, TP_DOMAIN * domain, int size)
{
  DB_JSON *json;
  int rc = NO_ERROR;

  json = (DB_JSON *) memptr;
  if (json == NULL)
    {
      if (size != 0)
    {
      if (or_advance (buf, size) != NO_ERROR)
        {
          assert (false);
        }
    }
      return;
    }

  if (size < 0)
    {
      assert (false);
      return;
    }

  if (size == 0)
    {
      mr_initmem_json (memptr, domain);
      return;
    }

  rc = db_json_deserialize (buf, json->document);
  if (rc != NO_ERROR)
    {
      ASSERT_ERROR ();
      db_json_delete_doc (json->document);
    }
}

static void
mr_freemem_json (void *memptr)
{
  DB_JSON *cur;

  cur = (DB_JSON *) memptr;

  if (cur != NULL)
    {
      if (cur->schema_raw != NULL)
    {
      db_private_free (NULL, const_cast < char *>(cur->schema_raw));
      cur->schema_raw = NULL;
    }
      if (cur->document != NULL)
    {
      db_json_delete_doc (cur->document);
      cur->document = NULL;
    }
    }
}

static void
mr_initval_json (DB_VALUE * value, int precision, int scale)
{
  db_value_domain_init (value, DB_TYPE_JSON, precision, scale);
  value->need_clear = false;
}

static int
mr_setval_json (DB_VALUE * dest, const DB_VALUE * src, bool copy)
{
  int error = NO_ERROR;

  if (src == NULL || DB_IS_NULL (src))
    {
      error = db_value_domain_init (dest, DB_TYPE_JSON, DB_DEFAULT_PRECISION, 0);
      if (error != NO_ERROR)
    {
      ASSERT_ERROR ();
      return error;
    }
    }
  else
    {
      db_value_domain_init (dest, DB_TYPE_JSON, DB_DEFAULT_PRECISION, 0);
      dest->domain.general_info.is_null = 0;

      if (copy)
    {
      dest->data.json.document = db_json_get_copy_of_doc (src->data.json.document);
      dest->data.json.schema_raw = db_private_strdup (NULL, src->data.json.schema_raw);
      dest->need_clear = true;
    }
      else
    {
      dest->data.json.document = src->data.json.document;
      dest->data.json.schema_raw = src->data.json.schema_raw;
      dest->need_clear = false;
    }
    }

  return error;
}

static int
mr_data_lengthval_json (DB_VALUE * value, int disk)
{
  if (!disk)
    {
      return tp_Json.size;
    }

  if (value->data.json.document != NULL)
    {
      return (int) db_json_serialize_length (*value->data.json.document);
    }
  else
    {
      return 0;
    }
}

static int
mr_data_writeval_json (OR_BUF * buf, DB_VALUE * value)
{
  int rc = NO_ERROR;

  if (value->data.json.document == NULL || DB_IS_NULL (value))
    {
      assert (false);
      return ER_FAILED;
    }

#if !defined(NDEBUG)
  int estimated_length = mr_data_lengthval_json (value, true);
  if (buf->ptr + estimated_length > buf->endptr)
    {
      assert (false);
    }
#endif

  JSON_DOC *json_doc = db_get_json_document (value);
  rc = db_json_serialize (*json_doc, *buf);
  if (rc != NO_ERROR)
    {
      ASSERT_ERROR ();
    }

  return rc;
}

static int
mr_data_readval_json (OR_BUF * buf, DB_VALUE * value, TP_DOMAIN * domain, int size, bool copy, char *copy_buf,
              int copy_buf_len)
{
  JSON_DOC *doc = NULL;
  char *json_raw = NULL;
  int rc = NO_ERROR;

  db_make_null (value);

  if (size == 0)
    {
      /* early out, means json is NULL */
      return NO_ERROR;
    }

  rc = db_json_deserialize (buf, doc);
  if (rc != NO_ERROR)
    {
      ASSERT_ERROR ();
      return rc;
    }

  db_make_json (value, doc, true);
  return NO_ERROR;
}

static DB_VALUE_COMPARE_RESULT
mr_data_cmpdisk_json (void *mem1, void *mem2, TP_DOMAIN * domain, int do_coercion, int total_order, int *start_colp)
{
  char *first, *second;
  OR_BUF first_buf, second_buf;
  DB_VALUE json1, json2;
  JSON_DOC *doc1 = NULL, *doc2 = NULL;
  int rc = NO_ERROR;

  DB_VALUE_COMPARE_RESULT res = DB_UNK;

  first = (char *) mem1;
  second = (char *) mem2;

  or_init (&first_buf, first, 0);
  or_init (&second_buf, second, 0);

  rc = db_json_deserialize (&first_buf, doc1);
  if (rc != NO_ERROR)
    {
      ASSERT_ERROR ();
      return res;
    }

  rc = db_json_deserialize (&second_buf, doc2);
  if (rc != NO_ERROR)
    {
      ASSERT_ERROR ();
      return res;
    }

  db_make_json (&json1, doc1, true);
  db_make_json (&json2, doc2, true);

  res = mr_cmpval_json (&json1, &json2, do_coercion, total_order, 0, 0);
  pr_clear_value (&json1);
  pr_clear_value (&json2);

  return res;
}

/* when total_order is true,
 * we force to string uncomparable types.
 * this is because "order by" uses total_order=true
 * and we don't want to fail. The standard says that
 * only scalar and nulls are comparable.
 *
 * we only return DB_UNK when either one is null and
 * total_order is false
 */
static DB_VALUE_COMPARE_RESULT
mr_cmpval_json (DB_VALUE * value1, DB_VALUE * value2, int do_coercion, int total_order, int *start_colp, int collation)
{
  JSON_DOC *doc1 = NULL, *doc2 = NULL;
  DB_JSON_TYPE type1 = DB_JSON_UNKNOWN;
  DB_JSON_TYPE type2 = DB_JSON_UNKNOWN;
  DB_VALUE scalar_value1, scalar_value2;
  DB_VALUE_COMPARE_RESULT cmp_result;
  bool is_value1_null = true, is_value2_null = true;
  int error_code;

  doc1 = db_get_json_document (value1);
  doc2 = db_get_json_document (value2);

  is_value1_null = DB_IS_NULL (value1) || ((type1 = db_json_get_type (doc1)) == DB_JSON_NULL);
  is_value2_null = DB_IS_NULL (value2) || ((type2 = db_json_get_type (doc2)) == DB_JSON_NULL);

  if (is_value1_null || is_value2_null)
    {
      if (!total_order)
    {
      return DB_UNK;
    }

      if (is_value1_null && is_value2_null)
    {
      return DB_EQ;
    }

      return is_value1_null ? DB_LT : DB_GT;
    }

  /* db_json_get_type shouldn't return DB_JSON_UNKNOWN, this represents a bug */
  assert (type1 != DB_JSON_UNKNOWN && type2 != DB_JSON_UNKNOWN);

  db_make_null (&scalar_value1);
  db_make_null (&scalar_value2);

  if (db_json_doc_is_uncomparable (doc1) || db_json_doc_is_uncomparable (doc2))
    {
      /* force string comp */
      char *str1 = NULL, *str2 = NULL;

      str1 = db_json_get_json_body_from_document (*doc1);
      str2 = db_json_get_json_body_from_document (*doc2);

      db_make_string (&scalar_value1, str1);
      db_make_string (&scalar_value2, str2);

      scalar_value1.need_clear = true;
      scalar_value2.need_clear = true;
    }
  else
    {
      /* This is not according to standard, in SQL/JSON standard
       * different types should not be compared, but rather throw
       * an error. We chose to also compare different scalar types
       * even when total_order is false.
       */
      error_code = db_convert_json_into_scalar (value1, &scalar_value1);
      if (error_code != NO_ERROR)
    {
      /* this shouldn't happen */
      assert (false);
      pr_clear_value (&scalar_value1);
      return DB_UNK;
    }

      error_code = db_convert_json_into_scalar (value2, &scalar_value2);
      if (error_code != NO_ERROR)
    {
      /* this shouldn't happen */
      assert (false);
      pr_clear_value (&scalar_value1);
      pr_clear_value (&scalar_value2);
      return DB_UNK;
    }
    }

  cmp_result = tp_value_compare_with_error (&scalar_value1, &scalar_value2, do_coercion, total_order, NULL);

  pr_clear_value (&scalar_value1);
  pr_clear_value (&scalar_value2);
  return cmp_result;
}