Skip to content

File parse_dbi.c

File List > cubrid > src > parser > parse_dbi.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.
 *
 */

/*
 * parse_dbi.c - a number of auxiliary functions required to convert parse tree
 *            data structures to data structures compatible with DB interface
 *            functions
 */

#ident "$Id$"

#include "config.h"

#include <assert.h>
#include <stdarg.h>
#include <ctype.h>

#include "porting.h"
#include "error_manager.h"
#include "parser.h"
#include "xasl_generation.h"
#include "parser_message.h"
#include "memory_alloc.h"
#include "language_support.h"
#include "db.h"
#include "schema_manager.h"
#include "cnv.h"
#include "string_opfunc.h"
#include "set_object.h"
#include "intl_support.h"
#include "virtual_object.h"
#include "object_primitive.h"
#include "object_template.h"
#include "db_json.hpp"

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

#define SET_PARSER_ERROR_AND_FREE_NODE(parser, result, default_msg_id)        \
  do {                                        \
      if (!pt_has_error(parser))                          \
    {                                     \
      if (er_errid() != NO_ERROR)                         \
        {                                     \
          PT_ERRORc (parser, result, er_msg());               \
        }                                     \
      else                                    \
        {                                     \
          PT_ERRORm (parser, result, MSGCAT_SET_PARSER_RUNTIME,       \
             default_msg_id);                     \
          assert (false);                             \
        }                                     \
    }                                     \
    parser_free_node (parser, result);                    \
    result = NULL;                                \
    } while (0)

#include "dbtype.h"

static PT_NODE *pt_get_object_data_type (PARSER_CONTEXT * parser, const DB_VALUE * val);

static PT_NODE *pt_bind_helper (PARSER_CONTEXT * parser, PT_NODE * node, DB_VALUE * val, int *data_type_added);

static PT_NODE *pt_bind_set_type (PARSER_CONTEXT * parser, PT_NODE * node, DB_VALUE * val, int *data_type_added);
static PT_NODE *pt_set_elements_to_value (PARSER_CONTEXT * parser, const DB_VALUE * val);
static int pt_get_enumeration_from_data_type (PARSER_CONTEXT * parser, PT_NODE * dt, DB_ENUMERATION * enumeration);

/*
 * pt_misc_to_qp_misc_operand() - convert a PT_MISC_TYPE trim qualifier or
 *                         an extract field specifier to a qp MISC_OPERAND
 *   return: MISC_OPERAND, 0 on error
 *   misc_specifier(in):
 */
MISC_OPERAND
pt_misc_to_qp_misc_operand (PT_MISC_TYPE misc_specifier)
{
  MISC_OPERAND operand;

  switch (misc_specifier)
    {
    case PT_LEADING:
      operand = LEADING;
      break;
    case PT_TRAILING:
      operand = TRAILING;
      break;
    case PT_BOTH:
      operand = BOTH;
      break;
    case PT_YEAR:
      operand = YEAR;
      break;
    case PT_MONTH:
      operand = MONTH;
      break;
    case PT_DAY:
      operand = DAY;
      break;
    case PT_HOUR:
      operand = HOUR;
      break;
    case PT_MINUTE:
      operand = MINUTE;
      break;
    case PT_SECOND:
      operand = SECOND;
      break;
    case PT_MILLISECOND:
      operand = MILLISECOND;
      break;
    case PT_SUBSTR_ORG:
      operand = SUBSTRING;
      break;
    case PT_SUBSTR:
      operand = SUBSTR;
      break;
    default:
      operand = (MISC_OPERAND) 0;   /* technically an error */
    }

  return operand;
}

/*
 * pt_is_same_enum_data_type() -  Compares two enum data types
 *   return:  true if exact match, false otherwise
 *   dt1(in): first data type
 *   dt2(in): second data type
 */
bool
pt_is_same_enum_data_type (PT_NODE * dt1, PT_NODE * dt2)
{
  PT_NODE *e1 = NULL, *e2 = NULL;
  PARSER_VARCHAR *pvc1 = NULL, *pvc2 = NULL;
  int l1 = 0, l2 = 0;

  if (dt1 == dt2)
    {
      return true;
    }

  if (dt1 == NULL || dt1->type_enum != PT_TYPE_ENUMERATION || dt2 == NULL || dt2->type_enum != PT_TYPE_ENUMERATION)
    {
      return false;
    }

  e1 = dt1->info.data_type.enumeration;
  e2 = dt2->info.data_type.enumeration;
  for (; e1 != NULL && e2 != NULL; e1 = e1->next, e2 = e2->next)
    {
      assert (e1->node_type == PT_VALUE && e2->node_type == PT_VALUE);

      pvc1 = e1->info.value.data_value.str;
      pvc2 = e2->info.value.data_value.str;
      l1 = pt_get_varchar_length (pvc1);
      l2 = pt_get_varchar_length (pvc2);
      if (l1 != l2 || memcmp (pt_get_varchar_bytes (pvc1), pt_get_varchar_bytes (pvc2), l1))
    {
      break;
    }
    }

  if (e1 == NULL && e2 == NULL)
    {
      return true;
    }

  return false;
}

/*
 * pt_add_type_to_set() -  add a db_value's data_type to a set of data_types
 *   return:  none
 *   parser(in):  handle to parser context
 *   typs(in):  a list of PT_DATA_TYPE nodes to add to the set
 *   set(out): a set of PT_DATA_TYPE nodes
 *
 * Note :
 *  modifies: parser heap, set
 */
void
pt_add_type_to_set (PARSER_CONTEXT * parser, const PT_NODE * typs, PT_NODE ** set)
{
  PT_TYPE_ENUM typ, expected_typ;
  PT_NODE *next_typs, *expected_typs = NULL;
  PT_NODE *s, *ent;
  DB_OBJECT *cls = NULL;
  bool found = false;
  const char *cls_nam = NULL, *e_nam;

  assert (parser != NULL && set != NULL);

  while (typs)
    {
      /* apparently during runtime, type information is not maintained. for instance: insert into bug(history) values
       * ({insert into situation(status) values ('e')}); in this case, when pt_evaluate_tree() performs the situation
       * insert, the resultant object's type is PT_TYPE_NONE.  We ignore this situation, although its not clear why it
       * works. */
      next_typs = typs->next;

      /* if the hostvar node with expected domain */
      if (typs->node_type == PT_HOST_VAR && typs->expected_domain != NULL)
    {
      expected_typ = pt_db_to_type_enum (typs->expected_domain->type->id);

      assert (typs->type_enum == PT_TYPE_MAYBE && PT_IS_CHAR_STRING_TYPE (expected_typ));

      expected_typs = parser_new_node (parser, PT_DATA_TYPE);
      expected_typs->type_enum = expected_typ;
      expected_typs->data_type = pt_domain_to_data_type (parser, typs->expected_domain);

      typs = expected_typs;
    }

      typ = typs->type_enum;
      if (typ != PT_TYPE_NONE && typ != PT_TYPE_MAYBE)
    {
      /* check for system errors */
      if (typ == PT_TYPE_OBJECT)
        {
          if (typs->data_type == NULL)
        {
          PT_INTERNAL_ERROR (parser, "interface");
          goto exit_on_error;
        }

          if (typs->data_type->info.data_type.entity == NULL)
        {
          /* this type is the generic object */
          cls_nam = NULL;
          cls = NULL;
        }
          else
        {
          /* non-generic object. it must have a class name */
          cls = typs->data_type->info.data_type.entity->info.name.db_object;
          cls_nam = db_get_class_name (cls);
          if (cls == NULL || cls_nam == NULL)
            {
              PT_INTERNAL_ERROR (parser, "interface");
              goto exit_on_error;
            }
        }
        }

      /* check if the type is already in the set */
      for (s = *set, found = false; s && s->node_type == PT_DATA_TYPE && !found; s = s->next)
        {
          if (typ == s->type_enum)
        {
          if (typ == PT_TYPE_OBJECT)
            {
              /* for objects, check if the classes are equal */
              ent = s->info.data_type.entity;
              if (ent && (ent->node_type == PT_NAME) && (e_nam = ent->info.name.original))
            {
              /* ent is not the generic object so equality is based on class_name.  But be careful because
               * the type we're looking for may still be the generic object. */
              if (cls != NULL)
                {
                  found = !pt_user_specified_name_compare (cls_nam, e_nam);
                }
            }
              else
            {
              /* ent must be the generic object, the only way it matches is if typs is also the generic
               * object. */
              found = (cls == NULL);
            }
            }
          /* PR) core dumped & deficient character related with CONST CHAR & CHAR in set.  */
          else if (typ == PT_TYPE_CHAR || typ == PT_TYPE_BIT)
            {
              if (s->info.data_type.precision != typs->data_type->info.data_type.precision)
            {
              continue;
            }
              else if (PT_HAS_COLLATION (typ)
                   && s->info.data_type.collation_id != typs->data_type->info.data_type.collation_id)
            {
              continue;
            }

              found = true;
            }
          else if (typ == PT_TYPE_NUMERIC)
            {
              if (s->info.data_type.precision < typs->data_type->info.data_type.precision
              || s->info.data_type.dec_precision < typs->data_type->info.data_type.dec_precision)
            {
              continue;
            }
              found = true;
            }
          else if (typ == PT_TYPE_ENUMERATION)
            {
              found = pt_is_same_enum_data_type (typs->data_type, s);
            }
          else
            {
              /* for simple types, equality of type_enum is enough */
              found = true;
            }
        }
          else
        {
          found = false;
        }
        }

      if (!found)
        {
          /* prepend it to the set of data_types */
          PT_NODE *new_typ = NULL;
          if (typs->data_type == NULL)
        {
          new_typ = parser_new_node (parser, PT_DATA_TYPE);
          new_typ->type_enum = typ;
        }
          else
        {
          /* If the node has been parameterized by its data_type, node, copy ALL pertinent information into
           * this node. Datatype parameterization includes ALL the fields of a data_type node (ie, virt_object,
           * proxy_object, etc). */
          new_typ = parser_copy_tree_list (parser, typs->data_type);
        }
          if (new_typ && PT_IS_COLLECTION_TYPE (typs->type_enum))
        {
          /* In case of a set in a multiset the data type must be of type set and not just simply adding types
           * of the set into the types of multiset */
          s = parser_new_node (parser, PT_DATA_TYPE);
          s->type_enum = typs->type_enum;
          s->data_type = new_typ;
          new_typ = s;
        }
          if (new_typ)
        {
          if ((typ == PT_TYPE_OBJECT) && (cls != NULL))
            {
              PT_NODE *entity = NULL, *t;
              entity = pt_add_class_to_entity_list (parser, cls, entity, typs, (UINTPTR) typs, PT_CLASS);
              if (entity == NULL)
            {
              goto exit_on_error;
            }
              new_typ->info.data_type.virt_type_enum = typ;
              if (new_typ->info.data_type.entity != NULL)
            {
              parser_free_tree (parser, new_typ->info.data_type.entity);
            }
              new_typ->info.data_type.entity = entity;

              /*
               * Make sure that everything on the entity list has the
               * same bloody spec_id.
               */
              for (t = entity; t; t = t->next)
            {
              t->info.name.spec_id = (UINTPTR) entity;
            }
            }
          new_typ->next = *set;
          *set = new_typ;
        }
        }
    }

      if (expected_typs != NULL)
    {
      parser_free_node (parser, expected_typs);
      expected_typs = NULL;
    }

      typs = next_typs;
    }               /* while (typs) */

exit_on_error:
  if (expected_typs != NULL)
    {
      parser_free_node (parser, expected_typs);
      expected_typs = NULL;
    }
}

/*
 * pt_get_object_data_type() -  derive, create, return a DB_OBJECT's data_type
 *                              node from its db_value container
 *   return:  val's PT_DATA_TYPE node
 *   parser(in):  parser context from which to get PT_NODEs
 *   val(in):  a db_value container of type DB_OBJECT
 *
 * Note :
 *   requires: val->type == DB_TYPE_OBJECT
 *   modifies: parser's heap
 *   effects : allocates, initializes, returns a new PT_DATA_TYPE node
 *             describing val's data_type
 */
static PT_NODE *
pt_get_object_data_type (PARSER_CONTEXT * parser, const DB_VALUE * val)
{
  DB_OBJECT *cls;
  PT_NODE *name, *dt;
  const char *class_name = NULL;

  assert (parser != NULL && val != NULL);

  if (db_value_type (val) != DB_TYPE_OBJECT)
    {
      PT_INTERNAL_ERROR (parser, "not object type");
      return NULL;
    }

  cls = (DB_OBJECT *) db_get_class (db_get_object (val));
  if (cls == NULL)
    {
      PT_INTERNAL_ERROR (parser, "unknown class object");
      return NULL;
    }

  class_name = db_get_class_name (cls);
  if (class_name == NULL)
    {
      PT_INTERNAL_ERROR (parser, "unknown class name");
      return NULL;
    }

  name = pt_name (parser, class_name);
  if (name == NULL)
    {
      PT_INTERNAL_ERROR (parser, "allocate new node");
      return NULL;
    }

  dt = parser_new_node (parser, PT_DATA_TYPE);
  if (dt == NULL)
    {
      PT_INTERNAL_ERROR (parser, "allocate new node");
      return NULL;
    }

  name->info.name.db_object = cls;
  name->info.name.spec_id = (UINTPTR) name;
  dt->type_enum = PT_TYPE_OBJECT;
  dt->info.data_type.entity = name;
  dt->info.data_type.virt_type_enum = PT_TYPE_OBJECT;
  if (db_is_vclass (cls) > 0)
    {
      dt->info.data_type.virt_object = cls;
    }

  return dt;
}

/*
 * pt_set_elements_to_value() - allocates, initializes, returns a new PT_VALUE
 *   return:  a PT_VALUE type PT_NODE list
 *   parser(in):  parser context from which to get a new PT_NODE
 *   val(in):  a db_value of a set type
 */
static PT_NODE *
pt_set_elements_to_value (PARSER_CONTEXT * parser, const DB_VALUE * val)
{
  PT_NODE result, *elem = NULL;
  DB_VALUE element;
  int error = NO_ERROR;
  int i, size;

  assert (parser != NULL && val != NULL);

  result.next = NULL;

  db_make_null (&element);
  for (i = 0, size = db_set_size (db_get_set (val)); i < size && error >= 0; i++)
    {
      error = db_set_get (db_get_set (val), i, &element);
      if (error >= 0 && (elem = pt_dbval_to_value (parser, &element)))
    {
      parser_append_node (elem, &result);
      db_value_clear (&element);
    }
      else
    {
      result.next = NULL;
      db_value_clear (&element);
      break;
    }
    }

  return result.next;
}

/*
 * pt_sm_default_value_to_node () - returns a PT_NODE equivalent to the info
 *  in the default_value
 *
 *  parser (in):
 *  default_value (in):
 */
PT_NODE *
pt_sm_attribute_default_value_to_node (PARSER_CONTEXT * parser, const SM_ATTRIBUTE * sm_attr)
{
  PT_NODE *result;
  const SM_DEFAULT_VALUE *default_value;
  PT_NODE *data_type;

  if (sm_attr == NULL || &sm_attr->default_value == NULL)
    {
      return NULL;
    }

  default_value = &sm_attr->default_value;

  if (default_value == NULL)
    {
      return NULL;
    }

  if (default_value->default_expr.default_expr_type == DB_DEFAULT_NONE)
    {
      result = pt_dbval_to_value (parser, &default_value->value);
      if (result == NULL)
    {
      return NULL;
    }
    }
  else
    {
      result = parser_new_node (parser, PT_EXPR);
      if (!result)
    {
      PT_INTERNAL_ERROR (parser, "allocate new node");
      return NULL;
    }
      result->info.expr.op = pt_op_type_from_default_expr_type (default_value->default_expr.default_expr_type);
    }

  data_type = parser_new_node (parser, PT_DATA_TYPE);
  if (data_type == NULL)
    {
      PT_INTERNAL_ERROR (parser, "allocate new node");
      parser_free_tree (parser, result);
      return NULL;
    }
  result->type_enum = pt_db_to_type_enum (sm_attr->type->id);
  data_type->type_enum = result->type_enum;
  result->data_type = data_type;

  return result;
}

/*
 * pt_dbval_to_value() -  convert a db_value into a PT_NODE
 *   return:  a PT_VALUE type PT_NODE
 *   parser(in):  parser context from which to get a new PT_NODE
 *   val(in):  a db_value
 */
PT_NODE *
pt_dbval_to_value (PARSER_CONTEXT * parser, const DB_VALUE * val)
{
  PT_NODE *result;
  const char *bytes;
  int size;
  DB_OBJECT *mop;
  DB_TYPE db_type;
  char buf[100];
  char *json_body = NULL;

  assert (parser != NULL && val != NULL);

  result = parser_new_node (parser, PT_VALUE);
  if (result == NULL)
    {
      PT_INTERNAL_ERROR (parser, "allocate new node");
      return NULL;
    }

  /* copy the db_value */
  db_value_clone ((DB_VALUE *) val, &result->info.value.db_value);
  result->info.value.db_value_is_initialized = true;
  result->info.value.db_value_is_in_workspace = true;

  db_type = DB_VALUE_TYPE (val);
  result->type_enum = pt_db_to_type_enum (db_type);

  switch (db_type)
    {
    case DB_TYPE_NULL:
      result->type_enum = PT_TYPE_NULL;
      break;
    case DB_TYPE_SET:
      result->info.value.data_value.set = pt_set_elements_to_value (parser, val);
      pt_add_type_to_set (parser, result->info.value.data_value.set, &result->data_type);
      break;
    case DB_TYPE_MULTISET:
      result->info.value.data_value.set = pt_set_elements_to_value (parser, val);
      pt_add_type_to_set (parser, result->info.value.data_value.set, &result->data_type);
      break;
    case DB_TYPE_SEQUENCE:
      result->info.value.data_value.set = pt_set_elements_to_value (parser, val);
      pt_add_type_to_set (parser, result->info.value.data_value.set, &result->data_type);
      break;

    case DB_TYPE_INTEGER:
      result->info.value.data_value.i = db_get_int (val);
      break;
    case DB_TYPE_BIGINT:
      result->info.value.data_value.bigint = db_get_bigint (val);
      break;
    case DB_TYPE_FLOAT:
      result->info.value.data_value.f = db_get_float (val);
      break;
    case DB_TYPE_DOUBLE:
      result->info.value.data_value.d = db_get_double (val);
      break;
    case DB_TYPE_JSON:
      result->data_type = parser_new_node (parser, PT_DATA_TYPE);
      if (result->data_type == NULL)
    {
      parser_free_node (parser, result);
      result = NULL;
    }
      else
    {
      result->data_type->type_enum = result->type_enum;
      json_body = db_get_json_raw_body (val);
      result->info.value.data_value.str = pt_append_nulstring (parser, (PARSER_VARCHAR *) NULL, json_body);
      db_private_free (NULL, json_body);
      if (db_get_json_schema (val) != NULL)
        {
          /* check valid schema */
          if (db_json_validate_json (db_get_json_schema (val)) != NO_ERROR)
        {
          assert (false);
          parser_free_node (parser, result);
          PT_INTERNAL_ERROR (parser, "invalid json schema");
          result = NULL;
        }
          else
        {
          result->data_type->info.data_type.json_schema =
            pt_append_bytes (parser, NULL, db_get_json_schema (val), strlen (db_get_json_schema (val)));
        }
        }
    }
      break;
    case DB_TYPE_NUMERIC:
      numeric_db_value_print (val, buf);
      result->info.value.data_value.str = pt_append_nulstring (parser, (PARSER_VARCHAR *) NULL, (const char *) buf);
      result->data_type = parser_new_node (parser, PT_DATA_TYPE);
      if (result->data_type == NULL)
    {
      parser_free_node (parser, result);
      result = NULL;
    }
      else
    {
      result->data_type->type_enum = result->type_enum;
      result->data_type->info.data_type.precision = db_value_precision (val);
      result->data_type->info.data_type.dec_precision = db_value_scale (val);
    }
      break;

    case DB_TYPE_VARCHAR:
    case DB_TYPE_CHAR:
      bytes = db_get_string (val);
      size = db_get_string_size (val);
      result->info.value.data_value.str = pt_append_bytes (parser, NULL, bytes, size);
      result->info.value.data_value.str->length = size;
      result->info.value.string_type = ' ';

      result->data_type = parser_new_node (parser, PT_DATA_TYPE);
      if (result->data_type == NULL)
    {
      parser_free_node (parser, result);
      result = NULL;
    }
      else
    {
      result->data_type->type_enum = result->type_enum;
      result->data_type->info.data_type.precision = db_value_precision (val);
      result->data_type->info.data_type.units = db_get_string_codeset (val);
      result->data_type->info.data_type.collation_id = db_get_string_collation (val);
      assert (result->data_type->info.data_type.collation_id >= 0);
    }
      break;
    case DB_TYPE_BIT:
    case DB_TYPE_VARBIT:
      {
    int max_length = 0;
    char *printed_bit = NULL;

    size = 0;
    bytes = db_get_bit (val, &size);
    max_length = ((size + 3) / 4) + 4;
    printed_bit = (char *) db_private_alloc (NULL, max_length);
    if (printed_bit == NULL)
      {
        PT_ERRORm (parser, NULL, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_OUT_OF_MEMORY);
        parser_free_node (parser, result);
        result = NULL;
        break;
      }
    if (db_bit_string (val, "%X", printed_bit, max_length) != NO_ERROR)
      {
        db_private_free_and_init (NULL, printed_bit);
        PT_ERRORmf (parser, NULL, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_DATA_OVERFLOW_ON,
            pt_show_type_enum (PT_TYPE_BIT));
        parser_free_node (parser, result);
        result = NULL;
        break;
      }

    /* get the printed size */
    size = strlen (printed_bit);

    result->info.value.string_type = 'X';
    result->info.value.data_value.str = pt_append_bytes (parser, NULL, printed_bit, size);

    db_private_free_and_init (NULL, printed_bit);

    result->info.value.data_value.str->length = size;

    result->data_type = parser_new_node (parser, PT_DATA_TYPE);
    if (result->data_type == NULL)
      {
        parser_free_node (parser, result);
        result = NULL;
      }
    else
      {
        result->data_type->type_enum = result->type_enum;
        result->data_type->info.data_type.precision = db_value_precision (val);
        result->data_type->info.data_type.units = db_get_string_codeset (val);
      }
    break;
      }
    case DB_TYPE_OBJECT:
      result->info.value.data_value.op = db_get_object (val);
      result->data_type = pt_get_object_data_type (parser, val);
      if (result->data_type == NULL)
    {
      parser_free_node (parser, result);
      result = NULL;
    }
      break;
    case DB_TYPE_TIME:
      if (db_time_to_string (buf, sizeof (buf), db_get_time (val)) == 0)
    {
      SET_PARSER_ERROR_AND_FREE_NODE (parser, result, MSGCAT_RUNTIME_UNDEFINED_CONVERSION);
    }
      else
    {
      result->info.value.data_value.str = pt_append_bytes (parser, NULL, buf, strlen (buf));
    }
      break;
    case DB_TYPE_TIMESTAMP:
      if (db_utime_to_string (buf, sizeof (buf), db_get_timestamp (val)) == 0)
    {
      SET_PARSER_ERROR_AND_FREE_NODE (parser, result, MSGCAT_RUNTIME_UNDEFINED_CONVERSION);
    }
      else
    {
      result->info.value.data_value.str = pt_append_bytes (parser, NULL, buf, strlen (buf));
    }
      break;
    case DB_TYPE_TIMESTAMPLTZ:
      if (db_timestampltz_to_string (buf, sizeof (buf), db_get_timestamp (val)) == 0)
    {
      SET_PARSER_ERROR_AND_FREE_NODE (parser, result, MSGCAT_RUNTIME_UNDEFINED_CONVERSION);
    }
      else
    {
      result->info.value.data_value.str = pt_append_bytes (parser, NULL, buf, strlen (buf));
    }
      break;
    case DB_TYPE_TIMESTAMPTZ:
      {
    DB_TIMESTAMPTZ *ts_tz = db_get_timestamptz (val);

    if (db_timestamptz_to_string (buf, sizeof (buf), &ts_tz->timestamp, &ts_tz->tz_id) == 0)
      {
        SET_PARSER_ERROR_AND_FREE_NODE (parser, result, MSGCAT_RUNTIME_UNDEFINED_CONVERSION);
      }
    else
      {
        result->info.value.data_value.str = pt_append_bytes (parser, NULL, buf, strlen (buf));
      }
      }
      break;
    case DB_TYPE_DATETIME:
      if (db_datetime_to_string (buf, sizeof (buf), db_get_datetime (val)) == 0)
    {
      SET_PARSER_ERROR_AND_FREE_NODE (parser, result, MSGCAT_RUNTIME_UNDEFINED_CONVERSION);
    }
      else
    {
      result->info.value.data_value.str = pt_append_bytes (parser, NULL, buf, strlen (buf));
    }
      break;
    case DB_TYPE_DATETIMELTZ:
      if (db_datetimeltz_to_string (buf, sizeof (buf), db_get_datetime (val)) == 0)
    {
      SET_PARSER_ERROR_AND_FREE_NODE (parser, result, MSGCAT_RUNTIME_UNDEFINED_CONVERSION);
    }
      else
    {
      result->info.value.data_value.str = pt_append_bytes (parser, NULL, buf, strlen (buf));
    }
      break;
    case DB_TYPE_DATETIMETZ:
      {
    DB_DATETIMETZ *dt_tz = db_get_datetimetz (val);

    if (db_datetimetz_to_string (buf, sizeof (buf), &dt_tz->datetime, &(dt_tz->tz_id)) == 0)
      {
        SET_PARSER_ERROR_AND_FREE_NODE (parser, result, MSGCAT_RUNTIME_UNDEFINED_CONVERSION);
      }
    else
      {
        result->info.value.data_value.str = pt_append_bytes (parser, NULL, buf, strlen (buf));
      }
      }
      break;
    case DB_TYPE_DATE:
      if (db_date_to_string (buf, sizeof (buf), db_get_date (val)) == 0)
    {
      SET_PARSER_ERROR_AND_FREE_NODE (parser, result, MSGCAT_RUNTIME_UNDEFINED_CONVERSION);
    }
      else
    {
      result->info.value.data_value.str = pt_append_bytes (parser, NULL, buf, strlen (buf));
    }
      break;
    case DB_TYPE_MONETARY:
      result->info.value.data_value.money.type = (PT_CURRENCY) db_get_monetary (val)->type;
      result->info.value.data_value.money.amount = db_get_monetary (val)->amount;
      result->data_type = parser_new_node (parser, PT_DATA_TYPE);
      if (result->data_type == NULL)
    {
      parser_free_node (parser, result);
      result = NULL;
    }
      else
    {
      result->data_type->type_enum = result->type_enum;
      result->data_type->info.data_type.units = db_value_get_monetary_currency (val);
    }
      break;
    case DB_TYPE_SHORT:
      result->info.value.data_value.i = db_get_short (val);
      break;

    case DB_TYPE_VOBJ:
      if (vid_vobj_to_object (val, &mop) != NO_ERROR)
    {
      parser_free_node (parser, result);
      result = NULL;
    }
      else
    {
      db_make_object (&result->info.value.db_value, mop);
      result->type_enum = PT_TYPE_OBJECT;
      result->data_type = pt_get_object_data_type (parser, &result->info.value.db_value);
      if (result->data_type == NULL)
        {
          parser_free_node (parser, result);
          result = NULL;
        }
    }
      break;

    case DB_TYPE_OID:
      if (vid_oid_to_object (val, &mop) != NO_ERROR)
    {
      parser_free_node (parser, result);
      result = NULL;
    }
      else
    {
      db_make_object (&result->info.value.db_value, mop);
      result->type_enum = PT_TYPE_OBJECT;
      result->data_type = pt_get_object_data_type (parser, &result->info.value.db_value);
      if (result->data_type == NULL)
        {
          parser_free_node (parser, result);
          result = NULL;
        }
    }
      break;

    case DB_TYPE_BLOB:
    case DB_TYPE_CLOB:
      {
    DB_ELO *db_elo;

    db_elo = db_get_elo (val);
    if (db_elo)
      {
        if (db_elo_copy_structure (db_elo, &result->info.value.data_value.elo) != NO_ERROR)
          {
        parser_free_node (parser, result);
        result = NULL;
          }
      }

    result->type_enum = db_type == DB_TYPE_BLOB ? PT_TYPE_BLOB : PT_TYPE_CLOB;
      }
      break;

    case DB_TYPE_ENUMERATION:
      bytes = db_get_enum_string (val);
      size = db_get_enum_string_size (val);
      result->info.value.data_value.enumeration.short_val = db_get_enum_short (val);
      if (db_get_enum_short (val) != 0)
    {
      result->info.value.data_value.enumeration.str_val = pt_append_bytes (parser, NULL, bytes, size);
      result->info.value.text = (const char *) result->info.value.data_value.enumeration.str_val->bytes;
    }
      result->data_type = NULL;
      break;

      /* explicitly treat others as an error condition */
    case DB_TYPE_VARIABLE:
    case DB_TYPE_SUB:
    case DB_TYPE_POINTER:
    case DB_TYPE_ERROR:
    case DB_TYPE_DB_VALUE:
    case DB_TYPE_TABLE:
      parser_free_node (parser, result);
      result = NULL;
      break;
    default:
      /* ALL TYPES MUST HAVE AN EXPLICIT CONVERSION, OR THE CODE IS IN ERROR */
      assert (false);
    }

  return result;
}

/*
 * pt_seq_value_to_db() -  add elements into a DB_VALUE sequence
 *   return:  db_value if all OK, NULL otherwise.
 *   parser(in):  handle to parser context
 *   values(in):  the elements to be inserted
 *   db_value(out): a sequence value container
 *   el_types(out): the seq's element data_types
 *
 * Note :
 *  requires: db_value is an empty sequence value container
 *            values is a list of elements
 *  modifies: db_value, parser->error_msgs
 *  effects : evaluates and adds the values as elements of the db_value
 */
DB_VALUE *
pt_seq_value_to_db (PARSER_CONTEXT * parser, PT_NODE * values, DB_VALUE * db_value, PT_NODE ** el_types)
{
  PT_NODE *element;
  DB_VALUE e_val;
  int indx;

  assert (parser != NULL);
  db_make_null (&e_val);

  for (element = values, indx = 0; element != NULL; element = element->next, indx++)
    {
      pt_evaluate_tree (parser, element, &e_val, 1);
      if (!pt_has_error (parser))
    {
      if (db_seq_put (db_get_set (db_value), indx, &e_val) != NO_ERROR)
        {
          PT_ERRORc (parser, element, db_error_string (3));
          pr_clear_value (&e_val);
          return NULL;
        }
    }
      else
    {
      /* this is not an error case, but a result of the use of PT_VALUE node to represent non constant expressions
       * Here we are trying to convert a non-constant expression, and failed. NULL is returned, indicating that a
       * db_value cannot be made, because this is not a constant sequence. Yeah, this is a kludge.... */
      pr_clear_value (&e_val);
      return NULL;
    }
      /* db_seq_add() clones the value so we can clear the element value generated by pt_evaluate_tree() */
      pr_clear_value (&e_val);
    }

  pt_add_type_to_set (parser, values, el_types);

  return db_value;
}

/*
 * pt_set_value_to_db() -  add set elements into a DB_VALUE set/multiset
 *   return:  db_value if all OK, NULL otherwise.
 *   parser(in):  handle to parser context
 *   values(in/out):  the set/multiset elements to be inserted
 *   db_value(out): a set or multiset value container
 *   el_types(out): the set's element data_types
 *
 * Note :
 *  requires: db_value is a set or multiset value container
 *            values is a list of set/multiset elements
 *  modifies: db_value, parser->error_msgs, values
 *  effects : evaluates and adds the values as elements of the db_value
 *            set or multiset.
 */
DB_VALUE *
pt_set_value_to_db (PARSER_CONTEXT * parser, PT_NODE ** values, DB_VALUE * db_value, PT_NODE ** el_types)
{
  PT_NODE *element;
  DB_VALUE e_val;

  assert (parser != NULL && values != NULL);
  db_make_null (&e_val);

  for (element = *values; element != NULL; element = element->next)
    {
      pt_evaluate_tree (parser, element, &e_val, 1);
      if (!pt_has_error (parser))
    {
      if (db_set_add (db_get_set (db_value), &e_val) != NO_ERROR)
        {
          PT_ERRORc (parser, element, db_error_string (3));

          if (DB_VALUE_TYPE (&e_val) == DB_TYPE_POINTER)
        {
          obt_quit ((OBJ_TEMPLATE *) db_get_pointer (&e_val));
        }
          return NULL;
        }
    }
      else
    {
      /* this is not an error case, but a result of the use of PT_VALUE node to represent non constant expressions
       * Here we are trying to convert a non-constant expression, and failed. NULL is returned, indicating that a
       * db_value cannot be made, because this is not a constant set. Yeah, this is a kludge.... */
      return NULL;
    }
      /* db_set_add() clones the value so we can clear the element value generated by pt_evaluate_tree() */
      pr_clear_value (&e_val);
    }

  pt_add_type_to_set (parser, *values, el_types);

  return db_value;
}


/*
 * pt_value_to_db() -  converts a PT_VALUE type node into a DB_VALUE
 *   return:  DB_VALUE equivalent of value on successful conversion
 *      NULL otherwise
 *   parser(in): handle to context used to derive PT_VALUE type node,
 *               may also have associated host_variable bound DB_VALUEs
 *   value(in): the PT_VALUE type node to be converted to DB_VALUE
 *
 * Note :
 *  requires: parser is the parser context used to derive value
 *            value  is a PT_VALUE type node
 *  modifies: heap, parser->error_msgs, value->data_type
 */
DB_VALUE *
pt_value_to_db (PARSER_CONTEXT * parser, PT_NODE * value)
{
  DB_VALUE *db_value;
  int more_type_info_needed;

  assert (parser != NULL);

  if (value == NULL || !pt_is_const (value))
    {
      return NULL;
    }

  /*
   * if it is an input host_variable then its associated DB_VALUE is in parser->host_variables[x] */
  if (value->node_type == PT_HOST_VAR && value->info.host_var.var_type == PT_HOST_IN)
    {
      DB_DOMAIN *hv_dom;

      db_value = pt_host_var_db_value (parser, value);

      if (db_value)
    {
      if (value->type_enum != PT_TYPE_NONE && value->type_enum != PT_TYPE_NULL && value->type_enum != PT_TYPE_MAYBE
          && value->type_enum != PT_TYPE_NUMERIC
          && value->type_enum != PT_TYPE_CHAR && value->type_enum != PT_TYPE_VARCHAR
          && value->type_enum != PT_TYPE_BIT && value->type_enum != PT_TYPE_VARBIT
          && (hv_dom = pt_node_to_db_domain (parser, value, NULL)) != NULL)
        {
          /* host_var node "value" has a useful domain for itself so that check compatibility between the "value"
           * and the host variable provided by the user */

          hv_dom = tp_domain_cache (hv_dom);
          if (!hv_dom   /* must be cached before use! */
          || tp_value_cast (db_value, db_value, hv_dom, false) != DOMAIN_COMPATIBLE)
        {
          PT_ERRORmf2 (parser, value, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_CANT_COERCE_TO, "host var",
                   pt_node_to_db_domain_name (value));
          return NULL;
        }

        }
      else
        {
          DB_TYPE expected_db_type, val_type;
          /* host var node "value" has no useful domain, which probably means that it's a so-far untyped host var
           * reference whose type we're trying to deduce from the supplied value itself. Just return the value and
           * continue on... */
          if (value->expected_domain)
        {
          expected_db_type = TP_DOMAIN_TYPE (value->expected_domain);
        }
          else
        {
          expected_db_type = DB_TYPE_NULL;
        }

          val_type = DB_VALUE_DOMAIN_TYPE (db_value);
          /* if "value" has expected domain but its type is different from the supplied value, we need to deduce
           * from the supplied value */
          if ((value->type_enum == PT_TYPE_MAYBE)
          || (expected_db_type != DB_TYPE_NULL && expected_db_type != val_type))
        {

          if (expected_db_type != DB_TYPE_NULL && expected_db_type != val_type)
            {

              if ((expected_db_type == DB_TYPE_CHAR && val_type == DB_TYPE_VARCHAR)
              || (expected_db_type == DB_TYPE_BIT && val_type == DB_TYPE_VARBIT))
            {
              /* to prevent padding, skip these cases */
            }
              /* cast db_value */
              else if (tp_value_cast_preserve_domain (db_value, db_value, value->expected_domain, false, true)
                   != DOMAIN_COMPATIBLE)
            {
              PT_ERRORmf2 (parser, value, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_CANT_COERCE_TO,
                       "host var", pr_type_name (expected_db_type));
              return NULL;
            }
            }

          if (pt_bind_type_from_dbval (parser, value, db_value) == NULL)
            {
              return NULL;
            }

          /* In case of DB_TYPE_ENUMERATION as expected type we need to compute data type from expected_domain
           * of host variable */
          if (value->type_enum == PT_TYPE_ENUMERATION && expected_db_type == DB_TYPE_ENUMERATION)
            {
              value->data_type = pt_domain_to_data_type (parser, value->expected_domain);
            }
          hv_dom = pt_node_to_db_domain (parser, value, NULL);
          hv_dom = tp_domain_cache (hv_dom);
          if (!hv_dom   /* domain must be cached before use! */
              || tp_value_coerce (db_value, db_value, hv_dom) != DOMAIN_COMPATIBLE)
            {
              PT_ERRORmf2 (parser, value, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_CANT_COERCE_TO,
                   "host var", pt_node_to_db_domain_name (value));
              return NULL;
            }
          value->expected_domain = hv_dom;
        }
          else
        {
          if (pt_bind_type_from_dbval (parser, value, db_value) == NULL)
            {
              return NULL;
            }
        }
        }

    }
      else          /* if (db_value) */
    {
      if (parser->flag.set_host_var == 1)
        {
          PT_ERRORmf2 (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_HOSTVAR_INDEX_ERROR,
               value->info.host_var.index, parser->host_var_count);
        }
      return NULL;
    }

      return db_value;
    }
  else if (value->node_type == PT_NAME && value->info.name.meta_class == PT_PARAMETER)
    {
      db_value = pt_find_value_of_label (value->info.name.original);
      if (!db_value)
    {
      PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_PARM_IS_NOT_SET,
              value->info.name.original);
      return (DB_VALUE *) NULL;
    }
      return db_value;
    }

  /* don't reinitialize non-empty DB_VALUE containers */
  db_value = &value->info.value.db_value;
  if (value->info.value.db_value_is_initialized)
    {
      return db_value;
    }

  more_type_info_needed = 0;
  if (pt_db_value_initialize (parser, value, db_value, &more_type_info_needed) == NULL)
    {
      return (DB_VALUE *) NULL;
    }
  else
    {
      value->info.value.db_value_is_initialized = true;
    }

  /*
   * We want to make sure that none of the parameterized types can leave
   * here without the proper DATA_TYPE information tacked onto them.  A
   * common symptom of a screwup here is character strings that are
   * misinterpreted when they are unpacked from list files, caused by the
   * unpacker using a different domain than that used by the packer.
   */
  if (more_type_info_needed)
    {
      pt_bind_type_from_dbval (parser, value, db_value);
    }

  return (db_value);
}

// pt_data_type_init_value - initialize value according to node data type
//
// node      : PT_NODE for which value_out is initialized
// value_out : DB_VALUE initialized according to node data type
//
void
pt_data_type_init_value (const PT_NODE * node, DB_VALUE * value_out)
{
  // init as null
  db_make_null (value_out);

  // make sure we get rid of pointer
  CAST_POINTER_TO_NODE (node);

  if (node->data_type == NULL)
    {
      // init as node->type_enum
      db_value_domain_init_default (value_out, pt_type_enum_to_db (node->type_enum));
      return;
    }
  // node->data_type is not null

  // get data type
  PT_NODE *node_data_type = node->data_type;
  DB_TYPE node_db_type = pt_type_enum_to_db (node_data_type->type_enum);

  if (node_db_type == DB_TYPE_OBJECT && node->data_type->info.data_type.virt_object != NULL)
    {
      // virtual object
      node_db_type = DB_TYPE_VOBJ;
    }

  db_value_domain_init_default (value_out, node_db_type);
  switch (node_db_type)
    {
    case DB_TYPE_VARCHAR:
    case DB_TYPE_CHAR:
    case DB_TYPE_BIT:
    case DB_TYPE_VARBIT:
      value_out->domain.char_info.length = node_data_type->info.data_type.precision;
      break;

    case DB_TYPE_NUMERIC:
      value_out->domain.numeric_info.precision = node_data_type->info.data_type.precision;
      value_out->domain.numeric_info.scale = node_data_type->info.data_type.dec_precision;
      break;
    case DB_TYPE_JSON:
      // we should really move json_schema from value.data
      if (node_data_type->info.data_type.json_schema != NULL)
    {
      value_out->data.json.schema_raw =
        db_private_strdup (NULL, (const char *) node_data_type->info.data_type.json_schema->bytes);
      value_out->need_clear = true;
    }
      else
    {
      value_out->data.json.schema_raw = NULL;
    }
      break;

    default:
      ;             /* Do nothing. This suppresses compiler's warnings. */
    }
}

/*
 * pt_string_to_db_domain() - returns DB_DOMAIN * that matches the string
 *   return:  a DB_DOMAIN
 *   s(in) : a string
 *   class_name(in): name of the class
 */
DB_DOMAIN *
pt_string_to_db_domain (const char *s, const char *class_name)
{
  DB_DOMAIN *retval = (DB_DOMAIN *) 0;
  PARSER_CONTEXT *parser;
  PT_NODE **dtp, *dt;
  char *stmt;
  const char *prefix = "DATA_TYPE___ ";

  if (s == NULL)
    {
      return (DB_DOMAIN *) NULL;
    }

  stmt = (char *) malloc (strlen (prefix) + strlen (s) + 1);
  if (stmt == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
          (size_t) (strlen (prefix) + strlen (s) + 1));
      return (DB_DOMAIN *) NULL;
    }

  sprintf (stmt, "%s%s", prefix, s);
  parser = parser_create_parser ();
  if (parser)
    {
      dtp = parser_parse_string (parser, stmt);
      if (!pt_has_error (parser) && dtp)
    {
      dt = *dtp;
      if (dt && (dt->node_type == PT_DATA_TYPE))
        {
          retval = pt_data_type_to_db_domain (parser, dt, class_name);
        }
    }
      else
    {
      pt_report_to_ersys (parser, PT_SYNTAX);
    }
      parser_free_parser (parser);
    }
  free_and_init (stmt);

  return retval;
}

#if defined(ENABLE_UNUSED_FUNCTION)
/*
 * pt_string_to_data_type() - adorns a PT_NODE with the type that matches
 *                the string
 *   return: none
 *   parser(in):
 *   s(in): domain string
 *   node(out):
 */
void
pt_string_to_data_type (PARSER_CONTEXT * parser, const char *s, PT_NODE * node)
{
  DB_DOMAIN *dom;

  dom = pt_string_to_db_domain (s, NULL);
  if (dom == NULL)
    {
      return;
    }

  node->type_enum = pt_db_to_type_enum (TP_DOMAIN_TYPE (dom));
  switch (node->type_enum)
    {
    case PT_TYPE_OBJECT:
    case PT_TYPE_SET:
    case PT_TYPE_SEQUENCE:
    case PT_TYPE_MULTISET:
    case PT_TYPE_NUMERIC:
    case PT_TYPE_BIT:
    case PT_TYPE_VARBIT:
    case PT_TYPE_CHAR:
    case PT_TYPE_VARCHAR:
      node->data_type = pt_domain_to_data_type (parser, dom);
      break;
    default:
      break;
    }
}
#endif /* ENABLE_UNUSED_FUNCTION */

/*
 * pt_type_enum_to_db_domain_name() - returns string form of t's datatype
 *   return:  character string denoting datatype dt
 *   t(in): a PT_TYPE_ENUM
 */
/* TODO: PT_TYPE_ENUM should be changed to
 * PT_TYPE_NUM by adjusting the order of including header files */
const char *
pt_type_enum_to_db_domain_name (const PT_TYPE_ENUM t)
{
  const char *name;

  switch (t)
    {
    default:
      name = "unknown data_type";
      break;
    case PT_TYPE_NONE:
      name = "none";
      break;

    case PT_TYPE_LOGICAL:
    case PT_TYPE_INTEGER:
      name = "integer";
      break;
    case PT_TYPE_BIGINT:
      name = "bigint";
      break;
    case PT_TYPE_SMALLINT:
      name = "short";
      break;
    case PT_TYPE_NUMERIC:
      name = "numeric";
      break;
    case PT_TYPE_FLOAT:
      name = "float";
      break;
    case PT_TYPE_DOUBLE:
      name = "double";
      break;

    case PT_TYPE_DATE:
      name = "date";
      break;

    case PT_TYPE_TIME:
      return "time";

    case PT_TYPE_TIMESTAMP:
      name = "timestamp";
      break;
    case PT_TYPE_TIMESTAMPLTZ:
      name = "timestampltz";
      break;
    case PT_TYPE_TIMESTAMPTZ:
      name = "timestamptz";
      break;

    case PT_TYPE_DATETIME:
      name = "datetime";
      break;
    case PT_TYPE_DATETIMETZ:
      name = "datetimetz";
      break;
    case PT_TYPE_DATETIMELTZ:
      name = "datetimeltz";
      break;

    case PT_TYPE_MONETARY:
      name = "monetary";
      break;

    case PT_TYPE_VARCHAR:
      name = "char varying";
      break;
    case PT_TYPE_CHAR:
      name = "char";
      break;

    case PT_TYPE_OBJECT:
      name = "object";
      break;

    case PT_TYPE_SET:
      name = "set";
      break;
    case PT_TYPE_MULTISET:
      name = "multiset";
      break;
    case PT_TYPE_SEQUENCE:
      name = "sequence";
      break;

    case PT_TYPE_BIT:
      name = "bit";
      break;
    case PT_TYPE_VARBIT:
      name = "bit varying";
      break;

    case PT_TYPE_BLOB:
      name = "blob";
      break;
    case PT_TYPE_CLOB:
      name = "clob";
      break;

    case PT_TYPE_ENUMERATION:
      name = "enum";
      break;
    case PT_TYPE_JSON:
      name = "json";
      break;
    }

  return name;
}

/*
 * pt_type_enum_to_db_domain() - returns DB_DOMAIN * that matches a simple type
 *   return:  a DB_DOMAIN
 *   t(in): a PT_TYPE_ENUM
 */
DB_DOMAIN *
pt_type_enum_to_db_domain (const PT_TYPE_ENUM t)
{
  DB_DOMAIN *retval = (DB_DOMAIN *) 0;
  DB_TYPE domain_type;

  domain_type = pt_type_enum_to_db (t);
  switch (domain_type)
    {
    case DB_TYPE_INTEGER:
      retval = tp_domain_construct (domain_type, NULL, DB_INTEGER_PRECISION, 0, NULL);
      break;
    case DB_TYPE_SHORT:
      retval = tp_domain_construct (domain_type, NULL, DB_SHORT_PRECISION, 0, NULL);
      break;
    case DB_TYPE_BIGINT:
      retval = tp_domain_construct (domain_type, NULL, DB_BIGINT_PRECISION, 0, NULL);
      break;
    case DB_TYPE_FLOAT:
      retval = tp_domain_construct (domain_type, NULL, DB_FLOAT_DECIMAL_PRECISION, 0, NULL);
      break;
    case DB_TYPE_DOUBLE:
      retval = tp_domain_construct (domain_type, NULL, DB_DOUBLE_DECIMAL_PRECISION, 0, NULL);
      break;
    case DB_TYPE_MONETARY:
      retval = tp_domain_construct (domain_type, NULL, DB_MONETARY_DECIMAL_PRECISION, 0, NULL);
      break;
    case DB_TYPE_TIME:
      retval = tp_domain_construct (domain_type, NULL, DB_TIME_PRECISION, 0, NULL);
      break;
    case DB_TYPE_DATE:
      retval = tp_domain_construct (domain_type, NULL, DB_DATE_PRECISION, 0, NULL);
      break;
    case DB_TYPE_TIMESTAMPLTZ:
    case DB_TYPE_TIMESTAMP:
      retval = tp_domain_construct (domain_type, NULL, DB_TIMESTAMP_PRECISION, 0, NULL);
      break;
    case DB_TYPE_TIMESTAMPTZ:
      retval = tp_domain_construct (domain_type, NULL, DB_TIMESTAMPTZ_PRECISION, 0, NULL);
      break;
    case DB_TYPE_DATETIMELTZ:
    case DB_TYPE_DATETIME:
      retval = tp_domain_construct (domain_type, NULL, DB_DATETIME_PRECISION, DB_DATETIME_DECIMAL_SCALE, NULL);
      break;
    case DB_TYPE_DATETIMETZ:
      retval = tp_domain_construct (domain_type, NULL, DB_DATETIMETZ_PRECISION, DB_DATETIME_DECIMAL_SCALE, NULL);
      break;
    case DB_TYPE_BLOB:
    case DB_TYPE_CLOB:
    case DB_TYPE_SUB:
    case DB_TYPE_POINTER:
    case DB_TYPE_ERROR:
    case DB_TYPE_VOBJ:
    case DB_TYPE_OID:
    case DB_TYPE_OBJECT:
    case DB_TYPE_SET:
    case DB_TYPE_MULTISET:
    case DB_TYPE_SEQUENCE:
    case DB_TYPE_MIDXKEY:
    case DB_TYPE_ENUMERATION:
    case DB_TYPE_JSON:
      retval = tp_domain_construct (domain_type, (DB_OBJECT *) 0, 0, 0, (TP_DOMAIN *) 0);
      break;

    case DB_TYPE_NUMERIC:
      retval = tp_domain_construct (domain_type, NULL, DB_DEFAULT_NUMERIC_PRECISION, DB_DEFAULT_NUMERIC_SCALE, NULL);
      break;

    case DB_TYPE_CHAR:
    case DB_TYPE_BIT:
    case DB_TYPE_VARCHAR:
    case DB_TYPE_VARBIT:
      /* Note that we assume that some other force is going to come in and repair the precision of the destination of
       * this domain is for the schema manager.  Might be a problem . . . */
      retval = tp_domain_construct (domain_type, NULL, TP_FLOATING_PRECISION_VALUE, 0, NULL);
      break;

    case DB_TYPE_NULL:
      retval = &tp_Null_domain;
      break;

    case DB_TYPE_VARIABLE:
      retval = &tp_Variable_domain;
      break;

    case DB_TYPE_DB_VALUE:
    case DB_TYPE_TABLE:
    case DB_TYPE_RESULTSET:
      break;

    case DB_TYPE_ELO:
      /* obsolete. */
      assert (false);
      break;

    default:
      assert (false);
      break;
    }

  return retval;
}

/*
 * pt_data_type_to_db_domain_name() - returns character string of dt's datatype
 *   return:  character string denoting datatype dt
 *   dt(in): a PT_DATA_TYPE node and nothing else.
 */
const char *
pt_data_type_to_db_domain_name (const PT_NODE * dt)
{
  assert (dt != NULL);

  if (dt->node_type != PT_DATA_TYPE)
    {
      return "unknown data_type";
    }

  if (dt->type_enum == PT_TYPE_OBJECT)
    {
      if (dt->info.data_type.entity && dt->info.data_type.entity->node_type == PT_NAME)
    {
      return dt->info.data_type.entity->info.name.original;
    }
      return "object";
    }
  else
    {
      return pt_type_enum_to_db_domain_name (dt->type_enum);
    }
}

/*
 * pt_get_enumeration_from_data_type() - construct a enumeration from data type.
 *   return:  NO_ERROR or error code.
 *   parser(in):
 *   dt(in): enumeration data type.
 *   enumeration(in/out): address of a DB_ENUMERATION structure to fill.
 */
static int
pt_get_enumeration_from_data_type (PARSER_CONTEXT * parser, PT_NODE * dt, DB_ENUMERATION * enumeration)
{
  int err = NO_ERROR;
  PT_NODE *node = NULL;
  DB_ENUM_ELEMENT *db_enum = NULL, *enum_elements = NULL;
  char *str_val = NULL;
  int str_len = 0, enum_elements_cnt = 0, idx;

  if (dt == NULL || dt->type_enum != PT_TYPE_ENUMERATION || enumeration == NULL)
    {
      err = ER_FAILED;
      goto error;
    }

  node = dt->info.data_type.enumeration;
  while (node != NULL)
    {
      enum_elements_cnt++;
      node = node->next;
    }

  if (enum_elements_cnt == 0)
    {
      enumeration->count = 0;
      enumeration->elements = NULL;
      return NO_ERROR;
    }

  enum_elements = (DB_ENUM_ELEMENT *) malloc (enum_elements_cnt * sizeof (DB_ENUM_ELEMENT));
  if (enum_elements == NULL)
    {
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1,
          enum_elements_cnt * sizeof (DB_ENUM_ELEMENT));
      err = ER_OUT_OF_VIRTUAL_MEMORY;
      goto error;
    }

  idx = 0;
  node = dt->info.data_type.enumeration;
  while (node != NULL)
    {
      if (node->node_type != PT_VALUE)
    {
      /* node_type should always be PT_VALUE */
      assert (false);
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);

      err = ER_GENERIC_ERROR;
      goto error;
    }
      db_enum = &enum_elements[idx];
      str_len = pt_get_varchar_length (node->info.value.data_value.str);
      str_val = (char *) malloc (str_len + 1);
      if (str_val == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) (str_len + 1));
      err = ER_OUT_OF_VIRTUAL_MEMORY;
      goto error;
    }

      memcpy (str_val, pt_get_varchar_bytes (node->info.value.data_value.str), str_len);
      str_val[str_len] = 0;

      /* enum values are indexed starting from 1 */
      DB_SET_ENUM_ELEM_SHORT (db_enum, (unsigned short) idx + 1);
      DB_SET_ENUM_ELEM_STRING (db_enum, str_val);
      DB_SET_ENUM_ELEM_STRING_SIZE (db_enum, str_len);
      DB_SET_ENUM_ELEM_CODESET (db_enum, dt->info.data_type.units);

      idx++;
      node = node->next;
    }

  enumeration->count = enum_elements_cnt;
  enumeration->elements = enum_elements;
  enumeration->collation_id = dt->info.data_type.collation_id;

  return NO_ERROR;

error:
  if (enum_elements != NULL)
    {
      for (--idx; idx >= 0; idx--)
    {
      free_and_init (DB_GET_ENUM_ELEM_STRING (&enum_elements[idx]));
    }
      free_and_init (enum_elements);
    }

  return err;
}

/*
 * pt_data_type_to_db_domain() - returns DB_DOMAIN * that matches dt
 *   return:  a DB_DOMAIN
 *   parser(in):
 *   dt(in):  PT_DATA_TYPE PT_NODE
 *   class_name(in):
 *
 * Note :
 *   requires: dt has undergone type binding via pt_semantic_type.
 *   effects : returns DB_DOMAIN * that matches dt
 *        THIS DIFFERS FROM pt_node_data_type_to_db_domain() IN THAT THE
 *        DATA TYPE NODE IS FROM A META DEFINITION OF A TYPE AND IS NOT
 *        FROM A NON-META DATA NODE.  THIS DIFFERENCE PRIMARILY IS SHOWN
 *        BY SETS:
 *          SET DOMAIN DEFINITION IS:
 *             data_type node with type enum SET, MULTISET, or SEQUENCE
 *             and this node has a list of data type nodes (off its
 *             data_type ptr) that define the domains of the element
 *             types.
 *         FULLY RESOLVED NON-META DATA NODE:
 *             the node (not a data type node) has type enum SET, MULTISET,
 *             or SEQUENCE and this node has a list of data type nodes
 *             (off its data_type ptr) that define the domains of the
 *             element types.
 *             Subtle, ain't it?
 */
DB_DOMAIN *
pt_data_type_to_db_domain (PARSER_CONTEXT * parser, PT_NODE * dt, const char *class_name)
{
  DB_DOMAIN *retval = (DB_DOMAIN *) 0;
  DB_TYPE domain_type;
  DB_OBJECT *class_obj = (DB_OBJECT *) 0;
  int precision = 0, scale = 0, codeset = 0;
  DB_ENUMERATION enumeration;
  int collation_id = 0;
  TP_DOMAIN_COLL_ACTION collation_flag = TP_DOMAIN_COLL_NORMAL;
  JSON_VALIDATOR *validator = NULL;

  if (dt == NULL)
    {
      return NULL;
    }

  enumeration.count = 0;
  enumeration.elements = NULL;

  domain_type = pt_type_enum_to_db (dt->type_enum);
  switch (domain_type)
    {
    case DB_TYPE_INTEGER:
    case DB_TYPE_FLOAT:
    case DB_TYPE_DOUBLE:
    case DB_TYPE_BLOB:
    case DB_TYPE_CLOB:
    case DB_TYPE_TIME:
    case DB_TYPE_TIMESTAMP:
    case DB_TYPE_TIMESTAMPTZ:
    case DB_TYPE_TIMESTAMPLTZ:
    case DB_TYPE_DATETIME:
    case DB_TYPE_DATETIMETZ:
    case DB_TYPE_DATETIMELTZ:
    case DB_TYPE_DATE:
    case DB_TYPE_MONETARY:
    case DB_TYPE_SUB:
    case DB_TYPE_POINTER:
    case DB_TYPE_ERROR:
    case DB_TYPE_SHORT:
    case DB_TYPE_VOBJ:
    case DB_TYPE_OID:
    case DB_TYPE_BIGINT:
      return pt_type_enum_to_db_domain (dt->type_enum);

    case DB_TYPE_JSON:
      if (dt->info.data_type.json_schema)
    {
      int error_code;

      error_code = db_json_load_validator ((const char *) dt->info.data_type.json_schema->bytes, validator);
      if (error_code != NO_ERROR)
        {
          ASSERT_ERROR ();
          return NULL;
        }
      break;
    }
      else
    {
      return pt_type_enum_to_db_domain (dt->type_enum);
    }

    case DB_TYPE_OBJECT:
      /* first check if its a VOBJ */
      if (dt->info.data_type.virt_object)
    {
      return tp_domain_construct (DB_TYPE_VOBJ, class_obj, precision, scale, NULL);
    }

      if (dt->info.data_type.entity && dt->info.data_type.entity->node_type == PT_NAME)
    {
      const char *name;

      name = dt->info.data_type.entity->info.name.original;
      assert (name != NULL);

      if (class_name != NULL && pt_user_specified_name_compare (name, class_name) == 0)
        {
          /* If the attribute domain is the name of the class being created, indicate with a -1. */
          class_obj = (DB_OBJECT *) TP_DOMAIN_SELF_REF;
        }
      else
        {
          class_obj = db_find_class (name);
          if (class_obj == NULL)
        {
          er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_SM_DOMAIN_NOT_A_CLASS, 1, name);
          return NULL;
        }
        }
      assert (class_obj != NULL);
    }
      break;

    case DB_TYPE_VARCHAR:
    case DB_TYPE_CHAR:
      precision = dt->info.data_type.precision;
      codeset = dt->info.data_type.units;
      collation_id = dt->info.data_type.collation_id;
      assert (collation_id >= 0);
      collation_flag = dt->info.data_type.collation_flag;
      break;

    case DB_TYPE_BIT:
    case DB_TYPE_VARBIT:
      precision = dt->info.data_type.precision;
      codeset = dt->info.data_type.units;
      break;

    case DB_TYPE_NUMERIC:
      precision = dt->info.data_type.precision;
      scale = dt->info.data_type.dec_precision;
      break;

    case DB_TYPE_SET:
    case DB_TYPE_MULTISET:
    case DB_TYPE_SEQUENCE:
    case DB_TYPE_MIDXKEY:
      return pt_node_to_db_domain (parser, dt, class_name);

    case DB_TYPE_ENUMERATION:
      if (pt_get_enumeration_from_data_type (parser, dt, &enumeration) != NO_ERROR)
    {
      return NULL;
    }
      codeset = dt->info.data_type.units;
      collation_id = dt->info.data_type.collation_id;
      assert (collation_id >= 0);
      collation_flag = dt->info.data_type.collation_flag;
      break;

    case DB_TYPE_NULL:
    case DB_TYPE_DB_VALUE:
    case DB_TYPE_VARIABLE:
    case DB_TYPE_TABLE:
    case DB_TYPE_RESULTSET:
      break;

    case DB_TYPE_ELO:
    default:
      /* obsolete */
      assert (false);
      break;
    }

  retval = tp_domain_new (domain_type);
  if (retval)
    {
      if (class_obj == (DB_OBJECT *) TP_DOMAIN_SELF_REF)
    {
      retval->class_mop = NULL;
      retval->self_ref = 1;
    }
      else
    {
      retval->class_mop = class_obj;
      retval->self_ref = 0;
      /* For compatibility on the server side, class objects must have the oid in the domain match the oid in the
       * class object. */
      if (class_obj)
        {
          retval->class_oid = class_obj->oid_info.oid;
        }
    }
      if (collation_flag == TP_DOMAIN_COLL_ENFORCE)
    {
      /* need to create a domain which enforces only the collation precision is set to default to keep list of
       * domains to minimum */
      precision = DB_DEFAULT_PRECISION;
    }
      else if (collation_flag == TP_DOMAIN_COLL_LEAVE)
    {
      /* need to create a domain which ignores the collation */
      codeset = LANG_SYS_CODESET;
      collation_id = LANG_SYS_COLLATION;
    }
      retval->precision = precision;
      retval->scale = scale;
      retval->codeset = codeset;
      retval->collation_id = collation_id;
      retval->collation_flag = collation_flag;
      retval->enumeration.collation_id = collation_id;
      DOM_SET_ENUM_ELEMENTS (retval, enumeration.elements);
      DOM_SET_ENUM_ELEMS_COUNT (retval, enumeration.count);
      retval->json_validator = validator;
    }
  else
    {
      tp_domain_clear_enumeration (&enumeration);
    }

  return retval;
}

/*
 * pt_node_data_type_to_db_domain() - creates a domain from a data type node
 *                                    and a type enum
 *   return:  a DB_DOMAIN
 *   parser(in):
 *   dt(in):  PT_DATA_TYPE PT_NODE
 *   type(in):
 *
 * Note :
 *        THIS DIFFERS FROM pt_data_type_to_db_domain() IN THAT THE
 *        DATA TYPE NODE IS FROM A PT_NODE THAT HAS BEEN FULLY RESOLVED
 *        AND IS NOT THE META DEFINITION OF A TYPE.  THIS DIFFERENCE
 *        PRIMARILY IS SHOWN BY SETS:
 *          SET DOMAIN DEFINITION IS:
 *             data_type node with type enum SET, MULTISET, or SEQUENCE
 *             and this node has a list of data type nodes (off its
 *             data_type ptr) that define the domains of the element
 *             types.
 *         FULLY RESOLVED NON-META DATA NODE:
 *             the node (not a data type node) has type enum SET, MULTISET,
 *             or SEQUENCE and this node has a list of data type nodes
 *             (off its data_type ptr) that define the domains of the
 *             element types.
 *             Subtle, ain't it?
 */
/* TODO: PT_TYPE_ENUM should be changed to
 * PT_TYPE_NUM by adjusting the order of including header files */
DB_DOMAIN *
pt_node_data_type_to_db_domain (PARSER_CONTEXT * parser, PT_NODE * dt, PT_TYPE_ENUM type)
{
  DB_TYPE domain_type;
  DB_OBJECT *class_obj = (DB_OBJECT *) 0;
  int precision = 0, scale = 0, codeset = 0, collation_id = 0;
  DB_DOMAIN *retval = (DB_DOMAIN *) 0;
  DB_DOMAIN *domain = (DB_DOMAIN *) 0;
  DB_DOMAIN *setdomain = (DB_DOMAIN *) 0;
  DB_ENUMERATION enumeration;
  int error = NO_ERROR;
  TP_DOMAIN_COLL_ACTION collation_flag;
  char *raw_schema = NULL;
  JSON_VALIDATOR *validator = NULL;

  if (dt == NULL)
    {
      return (DB_DOMAIN *) NULL;
    }

  enumeration.count = 0;
  enumeration.elements = NULL;
  collation_flag = TP_DOMAIN_COLL_NORMAL;

  domain_type = pt_type_enum_to_db ((PT_TYPE_ENUM) type);
  switch (domain_type)
    {
    case DB_TYPE_INTEGER:
    case DB_TYPE_FLOAT:
    case DB_TYPE_DOUBLE:
    case DB_TYPE_BLOB:
    case DB_TYPE_CLOB:
    case DB_TYPE_TIME:
    case DB_TYPE_TIMESTAMP:
    case DB_TYPE_TIMESTAMPTZ:
    case DB_TYPE_TIMESTAMPLTZ:
    case DB_TYPE_DATETIME:
    case DB_TYPE_DATETIMETZ:
    case DB_TYPE_DATETIMELTZ:
    case DB_TYPE_DATE:
    case DB_TYPE_MONETARY:
    case DB_TYPE_SUB:
    case DB_TYPE_POINTER:
    case DB_TYPE_ERROR:
    case DB_TYPE_SHORT:
    case DB_TYPE_VOBJ:
    case DB_TYPE_OID:
    case DB_TYPE_MIDXKEY:
    case DB_TYPE_BIGINT:
      return pt_type_enum_to_db_domain (type);

    case DB_TYPE_JSON:
      if (dt->info.data_type.json_schema)
    {
      int error_code;

      raw_schema = (char *) malloc (dt->info.data_type.json_schema->length + 1);
      if (raw_schema == NULL)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, raw_schema);
          return NULL;
        }

      strcpy (raw_schema, (const char *) dt->info.data_type.json_schema->bytes);
      error_code = db_json_load_validator (raw_schema, validator);
      free (raw_schema);

      if (error_code != NO_ERROR)
        {
          ASSERT_ERROR ();
          return NULL;
        }
      break;
    }
      else
    {
      return pt_type_enum_to_db_domain (dt->type_enum);
    }

    case DB_TYPE_OBJECT:
      /* first check if its a VOBJ */
      if (dt->info.data_type.virt_object)
    {
      return tp_domain_construct (DB_TYPE_VOBJ, class_obj, precision, scale, setdomain);
    }

      if (dt->info.data_type.entity && dt->info.data_type.entity->node_type == PT_NAME)
    {
      class_obj = (DB_OBJECT *) db_find_class (dt->info.data_type.entity->info.name.original);
      if (!class_obj)
        {
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_SM_DOMAIN_NOT_A_CLASS, 1,
              dt->info.data_type.entity->info.name.original);
          return (DB_DOMAIN *) 0;
        }
    }
      break;

    case DB_TYPE_VARCHAR:
    case DB_TYPE_CHAR:
    case DB_TYPE_BIT:
    case DB_TYPE_VARBIT:
      precision = dt->info.data_type.precision;
      codeset = dt->info.data_type.units;
      collation_id = dt->info.data_type.collation_id;
      collation_flag = dt->info.data_type.collation_flag;
      break;

    case DB_TYPE_NUMERIC:
      precision = dt->info.data_type.precision;
      scale = dt->info.data_type.dec_precision;
      break;

    case DB_TYPE_SET:
    case DB_TYPE_MULTISET:
    case DB_TYPE_SEQUENCE:
      while (dt && (error == NO_ERROR))
    {
      domain = pt_data_type_to_db_domain (parser, dt, NULL);
      if (domain)
        {
          error = tp_domain_add (&setdomain, domain);
        }
      dt = dt->next;
    }
      if (error == NO_ERROR)
    {
      retval = tp_domain_construct (domain_type, (DB_OBJECT *) 0, 0, 0, setdomain);
    }
      return retval;

    case DB_TYPE_ENUMERATION:
      if (pt_get_enumeration_from_data_type (parser, dt, &enumeration) != NO_ERROR)
    {
      return NULL;
    }
      codeset = dt->info.data_type.units;
      collation_id = dt->info.data_type.collation_id;
      break;

    case DB_TYPE_NULL:
    case DB_TYPE_DB_VALUE:
    case DB_TYPE_VARIABLE:
    case DB_TYPE_TABLE:
    case DB_TYPE_RESULTSET:
      break;

    case DB_TYPE_ELO:
      /* obsolete */
      assert (false);
      break;
    default:
      assert (false);
      break;
    }

  retval = tp_domain_new (domain_type);
  if (retval)
    {
      retval->class_mop = class_obj;
      retval->self_ref = 0;
      if (collation_flag == TP_DOMAIN_COLL_ENFORCE)
    {
      /* need to create a domain which enforces only the collation precision is set to default to keep list of
       * domains to minimum */
      precision = DB_DEFAULT_PRECISION;
    }
      else if (collation_flag == TP_DOMAIN_COLL_LEAVE)
    {
      /* need to create a domain which ignores the collation */
      codeset = LANG_SYS_CODESET;
      collation_id = LANG_SYS_COLLATION;
    }
      retval->precision = precision;
      retval->scale = scale;
      retval->codeset = codeset;
      retval->collation_id = collation_id;
      retval->collation_flag = collation_flag;
      retval->enumeration.collation_id = collation_id;
      retval->json_validator = validator;
      DOM_SET_ENUM_ELEMENTS (retval, enumeration.elements);
      DOM_SET_ENUM_ELEMS_COUNT (retval, enumeration.count);
    }
  else
    {
      tp_domain_clear_enumeration (&enumeration);
    }

  return retval;
}

/*
 * pt_node_to_db_domain_name() -
 *   return:  character string denoting domain name
 *   node(in):  any PT_NODE
 */
const char *
pt_node_to_db_domain_name (PT_NODE * node)
{
  assert (node != NULL);

  if (node->type_enum == PT_TYPE_OBJECT && node->data_type)
    {
      return pt_data_type_to_db_domain_name (node->data_type);
    }

  return pt_type_enum_to_db_domain_name (node->type_enum);
}

/*
 * pt_node_to_db_domain() - returns DB_DOMAIN * that matches node
 *   return:  a DB_DOMAIN
 *   parser(in):
 *   node(in):  any PT_NODE
 *   class_name(in):
 */
DB_DOMAIN *
pt_node_to_db_domain (PARSER_CONTEXT * parser, PT_NODE * node, const char *class_name)
{
  int error = NO_ERROR, natts = 0;
  DB_DOMAIN *retval = (DB_DOMAIN *) 0;
  DB_DOMAIN *domain = (DB_DOMAIN *) 0;
  DB_DOMAIN *setdomain = (DB_DOMAIN *) 0;
  DB_TYPE domain_type;
  PT_NODE *dt;

  CAST_POINTER_TO_NODE (node);

  if (node->data_type)
    {
      domain_type = pt_type_enum_to_db (node->type_enum);
      switch (domain_type)
    {
    case DB_TYPE_SET:
    case DB_TYPE_MULTISET:
    case DB_TYPE_SEQUENCE:
    case DB_TYPE_MIDXKEY:
      /* Recursively build the setdomain */
      dt = node->data_type;
      while (dt && (error == NO_ERROR))
        {
          domain = pt_data_type_to_db_domain (parser, dt, class_name);
          if (domain)
        {
          if (domain_type == DB_TYPE_MIDXKEY)
            {
              error = tp_domain_attach (&setdomain, domain);
              natts++;
            }
          else
            {
              error = tp_domain_add (&setdomain, domain);
            }
        }
          else
        {
          /* given element domain was not found, raise error */
          assert (er_errid () != NO_ERROR);
          error = er_errid ();
        }
          dt = dt->next;
        }
      if (error == NO_ERROR)
        {
          retval = tp_domain_construct (domain_type, (DB_OBJECT *) 0, natts, 0, setdomain);
        }
      break;

    default:
      retval = pt_data_type_to_db_domain (parser, node->data_type, class_name);
      break;
    }
    }
  else
    {
      retval = pt_type_enum_to_db_domain (node->type_enum);
    }

  return retval;
}

/*
 * pt_type_enum_to_db() - return DB_TYPE equivalent of PT_TYPE_ENUM t
 *   return:  DB_TYPE equivalent of t
 *   t(in):  a PT_TYPE_ENUM value
 */
DB_TYPE
pt_type_enum_to_db (const PT_TYPE_ENUM t)
{
  DB_TYPE db_type = DB_TYPE_NULL;

  switch (t)
    {
    case PT_TYPE_NONE:
      db_type = DB_TYPE_NULL;
      break;

    case PT_TYPE_LOGICAL:
    case PT_TYPE_INTEGER:
      db_type = DB_TYPE_INTEGER;
      break;

    case PT_TYPE_BIGINT:
      db_type = DB_TYPE_BIGINT;
      break;

    case PT_TYPE_SMALLINT:
      db_type = DB_TYPE_SHORT;
      break;
    case PT_TYPE_FLOAT:
      db_type = DB_TYPE_FLOAT;
      break;
    case PT_TYPE_DOUBLE:
      db_type = DB_TYPE_DOUBLE;
      break;

    case PT_TYPE_DATE:
      db_type = DB_TYPE_DATE;
      break;
    case PT_TYPE_TIME:
      db_type = DB_TYPE_TIME;
      break;
    case PT_TYPE_TIMESTAMP:
      db_type = DB_TYPE_TIMESTAMP;
      break;
    case PT_TYPE_TIMESTAMPTZ:
      db_type = DB_TYPE_TIMESTAMPTZ;
      break;
    case PT_TYPE_TIMESTAMPLTZ:
      db_type = DB_TYPE_TIMESTAMPLTZ;
      break;

    case PT_TYPE_DATETIME:
      db_type = DB_TYPE_DATETIME;
      break;
    case PT_TYPE_DATETIMETZ:
      db_type = DB_TYPE_DATETIMETZ;
      break;
    case PT_TYPE_DATETIMELTZ:
      db_type = DB_TYPE_DATETIMELTZ;
      break;
    case PT_TYPE_MONETARY:
      db_type = DB_TYPE_MONETARY;
      break;

    case PT_TYPE_CHAR:
      db_type = DB_TYPE_CHAR;
      break;
    case PT_TYPE_VARCHAR:
      db_type = DB_TYPE_VARCHAR;
      break;

    case PT_TYPE_JSON:
      db_type = DB_TYPE_JSON;
      break;

    case PT_TYPE_OBJECT:
      db_type = DB_TYPE_OBJECT;
      break;

    case PT_TYPE_SET:
      db_type = DB_TYPE_SET;
      break;

    case PT_TYPE_MULTISET:
      db_type = DB_TYPE_MULTISET;
      break;

    case PT_TYPE_SEQUENCE:
      db_type = DB_TYPE_SEQUENCE;
      break;

    case PT_TYPE_MIDXKEY:
      db_type = DB_TYPE_MIDXKEY;
      break;

    case PT_TYPE_NUMERIC:
      db_type = DB_TYPE_NUMERIC;
      break;
    case PT_TYPE_BIT:
      db_type = DB_TYPE_BIT;
      break;
    case PT_TYPE_VARBIT:
      db_type = DB_TYPE_VARBIT;
      break;

    case PT_TYPE_RESULTSET:
      db_type = DB_TYPE_RESULTSET;
      break;

    case PT_TYPE_BLOB:
      db_type = DB_TYPE_BLOB;
      break;

    case PT_TYPE_CLOB:
      db_type = DB_TYPE_CLOB;
      break;

    case PT_TYPE_MAYBE:
      db_type = DB_TYPE_VARIABLE;
      break;

    case PT_TYPE_ENUMERATION:
      db_type = DB_TYPE_ENUMERATION;
      break;

    default:
      db_type = DB_TYPE_NULL;
      break;
    }

  return db_type;
}

/*
 * pt_node_to_db_type() - return DB_TYPE equivalent of PT_TYPE_ENUM of node
 *   return:  DB_TYPE equivalent of type_enum of node
 *   node(in):  a PT_NODE
 */
DB_TYPE
pt_node_to_db_type (PT_NODE * node)
{
  DB_TYPE db_type;

  if (!node)
    {
      return DB_TYPE_NULL;
    }

  CAST_POINTER_TO_NODE (node);

  db_type = pt_type_enum_to_db (node->type_enum);

  if (db_type == DB_TYPE_OBJECT && node->data_type && (node->data_type->info.data_type.virt_object))
    {
      db_type = DB_TYPE_VOBJ;
    }

  return db_type;
}

/*
 * pt_sort_in_desc_order() - first builds a linked of integers from the value
 *                       list. then bubble sorts them in descending order.
 *                           finally removes all duplicates
 *   return:  returns a the list of nodes sorted in descending order and with
 *            all the duplicates removed.
 *   vlist(in): a list of value nodes with integer values
 */

PT_NODE *
pt_sort_in_desc_order (PT_NODE * vlist)
{
  PT_NODE *init_list = vlist, *c_addr, *p_addr;
  int t;

  /*
   * bubble sort (yuck!) the linked list of nodes
   * in descending order.
   */
  do
    {
      t = init_list->info.value.data_value.i;
      for (c_addr = init_list->next, p_addr = init_list; c_addr != NULL; c_addr = c_addr->next, p_addr = p_addr->next)
    {
      if (p_addr->info.value.data_value.i < c_addr->info.value.data_value.i)
        {
          t = p_addr->info.value.data_value.i;
          p_addr->info.value.data_value.i = c_addr->info.value.data_value.i;
          c_addr->info.value.data_value.i = t;
        }
    }
    }
  while (t != init_list->info.value.data_value.i);

  /* now remove all the duplicates in the list */
  c_addr = init_list;
  while (c_addr)
    {
      if (c_addr->next == NULL)
    {
      break;
    }

      if (c_addr->info.value.data_value.i == c_addr->next->info.value.data_value.i)
    {
      c_addr->next = c_addr->next->next;
    }
      else
    {
      c_addr = c_addr->next;
    }
    }

  return init_list;
}


/*
 * pt_auth_to_db_auth() - an element of the enum type PT_PRIV_TYPE to its
                          corresponding element in DB_AUTH
 *   return:  returns an enum of type DB_AUTH.
 *   auth(in): a PT_NODE of type PT_AUTH_CMD
 */

DB_AUTH
pt_auth_to_db_auth (const PT_NODE * auth)
{
  PT_PRIV_TYPE pt_auth;
  DB_AUTH db_auth;

  pt_auth = auth->info.auth_cmd.auth_cmd;

  switch (pt_auth)
    {
    case PT_ALL_PRIV:
      db_auth = DB_AUTH_ALL;
      break;

    case PT_ALTER_PRIV:
      db_auth = DB_AUTH_ALTER;
      break;

    case PT_DELETE_PRIV:
      db_auth = DB_AUTH_DELETE;
      break;

    case PT_EXECUTE_PRIV:
      db_auth = DB_AUTH_EXECUTE;
      break;

    case PT_INDEX_PRIV:
      db_auth = DB_AUTH_INDEX;
      break;

    case PT_INSERT_PRIV:
      db_auth = DB_AUTH_INSERT;
      break;

    case PT_SELECT_PRIV:
      db_auth = DB_AUTH_SELECT;
      break;

    case PT_UPDATE_PRIV:
      db_auth = DB_AUTH_UPDATE;
      break;

    case PT_EXECUTE_PROCEDURE_PRIV:
      db_auth = DB_AUTH_EXECUTE;
      break;

    default:
      db_auth = DB_AUTH_NONE;
      break;
    }

  return db_auth;
}

/*
 * pt_db_to_type_enum() - Convert type_enum from DB_TYPE... to PT_...
 *   return: Returns one of the PT_TYPE_ENUMs defined
 *       PT_TYPE_NONE for internal or unknown types
 *   t(in): a data type as defined in dbi.h
 */
PT_TYPE_ENUM
pt_db_to_type_enum (const DB_TYPE t)
{
  PT_TYPE_ENUM pt_type = PT_TYPE_NONE;

  if (t > DB_TYPE_LAST)
    {
      return PT_TYPE_NONE;
    }
  if (t <= DB_TYPE_FIRST)
    {
      return PT_TYPE_NONE;
    }

  switch (t)
    {
    case DB_TYPE_INTEGER:
      pt_type = PT_TYPE_INTEGER;
      break;
    case DB_TYPE_BIGINT:
      pt_type = PT_TYPE_BIGINT;
      break;
    case DB_TYPE_NUMERIC:
      pt_type = PT_TYPE_NUMERIC;
      break;
    case DB_TYPE_SHORT:
      pt_type = PT_TYPE_SMALLINT;
      break;
    case DB_TYPE_FLOAT:
      pt_type = PT_TYPE_FLOAT;
      break;
    case DB_TYPE_DOUBLE:
      pt_type = PT_TYPE_DOUBLE;
      break;

    case DB_TYPE_DATE:
      pt_type = PT_TYPE_DATE;
      break;
    case DB_TYPE_TIME:
      pt_type = PT_TYPE_TIME;
      break;
    case DB_TYPE_TIMESTAMP:
      pt_type = PT_TYPE_TIMESTAMP;
      break;
    case DB_TYPE_TIMESTAMPTZ:
      pt_type = PT_TYPE_TIMESTAMPTZ;
      break;
    case DB_TYPE_TIMESTAMPLTZ:
      pt_type = PT_TYPE_TIMESTAMPLTZ;
      break;
    case DB_TYPE_DATETIME:
      pt_type = PT_TYPE_DATETIME;
      break;
    case DB_TYPE_DATETIMETZ:
      pt_type = PT_TYPE_DATETIMETZ;
      break;
    case DB_TYPE_DATETIMELTZ:
      pt_type = PT_TYPE_DATETIMELTZ;
      break;

    case DB_TYPE_MONETARY:
      pt_type = PT_TYPE_MONETARY;
      break;

    case DB_TYPE_OBJECT:
      pt_type = PT_TYPE_OBJECT;
      break;

    case DB_TYPE_SET:
      pt_type = PT_TYPE_SET;
      break;
    case DB_TYPE_MULTISET:
      pt_type = PT_TYPE_MULTISET;
      break;
    case DB_TYPE_SEQUENCE:
      pt_type = PT_TYPE_SEQUENCE;
      break;

    case DB_TYPE_CHAR:
      pt_type = PT_TYPE_CHAR;
      break;
    case DB_TYPE_STRING:
      pt_type = PT_TYPE_VARCHAR;
      break;
    case DB_TYPE_BIT:
      pt_type = PT_TYPE_BIT;
      break;
    case DB_TYPE_VARBIT:
      pt_type = PT_TYPE_VARBIT;
      break;
    case DB_TYPE_MIDXKEY:
      pt_type = PT_TYPE_MIDXKEY;
      break;
    case DB_TYPE_RESULTSET:
      pt_type = PT_TYPE_RESULTSET;
      break;
    case DB_TYPE_BLOB:
      pt_type = PT_TYPE_BLOB;
      break;
    case DB_TYPE_CLOB:
      pt_type = PT_TYPE_CLOB;
      break;
    case DB_TYPE_ENUMERATION:
      pt_type = PT_TYPE_ENUMERATION;
      break;
    case DB_TYPE_VARIABLE:
      pt_type = PT_TYPE_MAYBE;
      break;
    case DB_TYPE_JSON:
      pt_type = PT_TYPE_JSON;
      break;

      /* these guys should not get encountered */
    case DB_TYPE_OID:
    case DB_TYPE_VOBJ:
    case DB_TYPE_UNKNOWN:
    case DB_TYPE_POINTER:
    case DB_TYPE_SUB:
    case DB_TYPE_ERROR:
    case DB_TYPE_DB_VALUE:
    case DB_TYPE_TABLE:
      pt_type = PT_TYPE_NONE;
      break;
    default:
      /* ALL TYPES MUST GET HANDLED HERE! */
      assert (false);
    }
  return pt_type;
}

/*
 * pt_node_to_cmd_type() - Convert node to CUBRID_STMT_TYPES
 *   return: one of the CUBRID_STMT_TYPES defined in dbi.h.
 *   node(in):
 */
CUBRID_STMT_TYPE
pt_node_to_cmd_type (PT_NODE * node)
{
  if (node == NULL)
    {
      return CUBRID_STMT_NONE;
    }

  switch (node->node_type)
    {
    case PT_GET_XACTION:
      if (node->info.get_xaction.option == PT_ISOLATION_LEVEL)
    {
      return CUBRID_STMT_GET_ISO_LVL;
    }
      else if (node->info.get_xaction.option == PT_LOCK_TIMEOUT)
    {
      return CUBRID_STMT_GET_TIMEOUT;
    }
      assert (0);       // should not reach here
      return CUBRID_STMT_NONE;

    case PT_DIFFERENCE:
    case PT_INTERSECTION:
    case PT_UNION:
    case PT_SELECT:
      return CUBRID_STMT_SELECT;
    case PT_KILL_STMT:
      return CUBRID_STMT_KILL;
    default:
      /* todo: is this acceptable?? I'll add safe-guard and let's see what happens... */
      assert ((int) node->node_type <= (int) PT_LAST_NODE_NUMBER);
      return (CUBRID_STMT_TYPE) node->node_type;
    }

  return CUBRID_STMT_NONE;
}


/*
 * pt_bind_helper() -  annotate the PT_ type info of a node from a DB_VALUE
 *   return:  PT_NODE
 *   parser(in):  the parser context
 *   node(in):  an input data type node
 *   val(in):  an input dbval
 *   data_type_added(out):  indicates whether an auxiliary node was used
 *
 * Note :
 *   looks at the actual type of the DB_VALUE and constructs an accurate
 *   PT_ data type in "node".  Will traverse all the elements of a set
 *   in order to get an accurate data type, which means that we can find
 *   out exact info about sets of uncertain pedigree.
 */

static PT_NODE *
pt_bind_helper (PARSER_CONTEXT * parser, PT_NODE * node, DB_VALUE * val, int *data_type_added)
{
  PT_NODE *dt;
  DB_TYPE val_type;
  PT_TYPE_ENUM pt_type;
  char *json_body = NULL;

  assert (node != NULL && val != NULL);

  *data_type_added = 0;
  dt = NULL;

  val_type = DB_VALUE_DOMAIN_TYPE (val);
  if (DB_IS_NULL (val) && val_type == DB_TYPE_NULL)
    {
      node->type_enum = PT_TYPE_NULL;
      return node;
    }

  pt_type = pt_db_to_type_enum (val_type);
  if (pt_type == PT_TYPE_NONE)
    {
      PT_INTERNAL_ERROR (parser, "type assignment");
      return NULL;
    }

  node->type_enum = pt_type;

  switch (val_type)
    {
    case DB_TYPE_INTEGER:
      if (node->node_type == PT_DATA_TYPE)
    {
      node->info.data_type.precision = 10;
      node->info.data_type.dec_precision = 0;
      node->info.data_type.units = 0;
    }
      break;

    case DB_TYPE_BIGINT:
      if (node->node_type == PT_DATA_TYPE)
    {
      node->info.data_type.precision = 19;
      node->info.data_type.dec_precision = 0;
      node->info.data_type.units = 0;
    }
      break;

    case DB_TYPE_SHORT:
      if (node->node_type == PT_DATA_TYPE)
    {
      node->info.data_type.precision = 5;
      node->info.data_type.dec_precision = 0;
      node->info.data_type.units = 0;
    }

    case DB_TYPE_NULL:
    case DB_TYPE_FLOAT:
    case DB_TYPE_DOUBLE:
    case DB_TYPE_TIME:
    case DB_TYPE_TIMESTAMP:
    case DB_TYPE_TIMESTAMPTZ:
    case DB_TYPE_TIMESTAMPLTZ:
    case DB_TYPE_DATE:
    case DB_TYPE_DATETIME:
    case DB_TYPE_DATETIMETZ:
    case DB_TYPE_DATETIMELTZ:
    case DB_TYPE_BLOB:
    case DB_TYPE_CLOB:
    case DB_TYPE_RESULTSET:
      /*
       * Nothing more to do for these guys; their type is completely
       * described by the type_enum.  Why don't we care about precision
       * and dec_precision for these, if we care about DB_TYPE_INT?
       */
      break;

    case DB_TYPE_VARIABLE:
    case DB_TYPE_SUB:
    case DB_TYPE_POINTER:
    case DB_TYPE_ERROR:
    case DB_TYPE_OID:
    case DB_TYPE_DB_VALUE:
      PT_INTERNAL_ERROR (parser, "type assignment");
      node = NULL;
      break;

    case DB_TYPE_SET:
    case DB_TYPE_MULTISET:
    case DB_TYPE_SEQUENCE:
      dt = pt_bind_set_type (parser, node, val, data_type_added);
      break;

      /*
       * All of the remaining cases need to tack a new DATA_TYPE node
       * onto the incoming node.  Most of the cases allocate it
       * themselves, but not all.
       */

    case DB_TYPE_MONETARY:
      dt = parser_new_node (parser, PT_DATA_TYPE);
      if (dt)
    {
      dt->type_enum = node->type_enum;
      dt->info.data_type.precision = 0;
      dt->info.data_type.dec_precision = 0;
      dt->info.data_type.units = db_value_get_monetary_currency (val);
    }
      break;

    case DB_TYPE_NUMERIC:
      dt = parser_new_node (parser, PT_DATA_TYPE);
      if (dt)
    {
      dt->type_enum = node->type_enum;
      dt->info.data_type.precision = DB_VALUE_PRECISION (val);
      dt->info.data_type.dec_precision = DB_VALUE_SCALE (val);
    }
      break;

    case DB_TYPE_VARBIT:
    case DB_TYPE_BIT:
    case DB_TYPE_VARCHAR:
    case DB_TYPE_CHAR:
      dt = parser_new_node (parser, PT_DATA_TYPE);
      if (dt)
    {
      dt->type_enum = node->type_enum;
      dt->info.data_type.precision = DB_VALUE_PRECISION (val);
      dt->info.data_type.units = (int) db_get_string_codeset (val);
      dt->info.data_type.collation_id = (int) db_get_string_collation (val);
      assert (!TP_IS_CHAR_TYPE (val_type) || dt->info.data_type.collation_id >= 0);
    }
      break;

    case DB_TYPE_ENUMERATION:
      dt = NULL;
      break;

    case DB_TYPE_OBJECT:
      dt = pt_get_object_data_type (parser, val);
      break;

    case DB_TYPE_JSON:
      dt = parser_new_node (parser, PT_DATA_TYPE);
      if (dt)
    {
      json_body = db_json_get_json_body_from_document (*val->data.json.document);
      if (db_json_validate_json (json_body) != NO_ERROR)
        {
          assert (false);
          parser_free_node (parser, dt);
          /* TODO: set a real error. */
          PT_INTERNAL_ERROR (parser, "json validation failed");
          db_private_free (NULL, json_body);
          return NULL;
        }
      /* valid schema */

      dt->type_enum = node->type_enum;
      db_private_free (NULL, json_body);

      /* save raw schema */
      if (val->data.json.schema_raw != NULL)
        {
          const char *schema_raw = val->data.json.schema_raw;
          dt->info.data_type.json_schema = pt_append_bytes (parser, NULL, schema_raw, strlen (schema_raw));
        }
    }
      break;

    default:
      PT_INTERNAL_ERROR (parser, "type assignment");
      node = NULL;
      break;
    }

  if (dt)
    {
      if (node)
    {
      node->data_type = dt;
      *data_type_added = 1;
    }
      else
    {
      parser_free_node (parser, dt);
    }
    }

  return node;
}


/*
 * pt_bind_set_type() - examine set elements and build up domain of their types
 *   return:  PT_NODE
 *   parser(in):  the parser context
 *   node(in):  an input data type node
 *   val(in):  an input DB_VALUE set
 *   data_type_added(out):  indicator of whether we built an auxiliary node
 */

static PT_NODE *
pt_bind_set_type (PARSER_CONTEXT * parser, PT_NODE * node, DB_VALUE * val, int *data_type_added)
{
  SET_ITERATOR *iterator;
  DB_VALUE *element;
  PT_NODE *set_type;
  PT_NODE tmp;
  int tmp_data_type_added;

  assert (node != NULL && val != NULL);

  iterator = set_iterate (db_get_set (val));
  if (iterator == NULL)
    {
      goto error;
    }
  set_type = NULL;

  parser_init_node (&tmp, PT_DATA_TYPE);
  tmp.line_number = node->line_number;
  tmp.column_number = node->column_number;

  while ((element = set_iterator_value (iterator)))
    {
      if (!pt_bind_helper (parser, &tmp, element, &tmp_data_type_added))
    {
      goto error;
    }

      pt_add_type_to_set (parser, &tmp, &set_type);

      /*
       * pt_add_type_to_set will copy the data type we send it if it
       * needs to keep it, so it's our responsibility to clean up any
       * intermediate stuff that was produced by pt_bind_helper.
       */
      if (tmp_data_type_added)
    {
      parser_free_node (parser, tmp.data_type);
    }
      tmp.data_type = NULL;

      set_iterator_next (iterator);
    }
  set_iterator_free (iterator);
  iterator = NULL;

  *data_type_added = (set_type != NULL);
  return set_type;

error:
  if (iterator)
    {
      set_iterator_free (iterator);
    }
  return NULL;
}


/*
 * pt_bind_type_from_dbval() - Build an accurate pt type for node given
 *                             the actual DB_VALUE val.
 *   return:  PT_NODE
 *   parser(in):  the parser context
 *   node(in):  an input data type node
 *   val(in):  an input DB_VALUE set
 *
 * Note :
 *   This may allocate a PT_DATA_TYPE node for parameterized types, or a whole
 *   slew of them for set types.
 */

PT_NODE *
pt_bind_type_from_dbval (PARSER_CONTEXT * parser, PT_NODE * node, DB_VALUE * val)
{
  int data_type_added;

  return pt_bind_helper (parser, node, val, &data_type_added);
}

/*
 * pt_set_host_variables() - sets parser's host_variables & count
 *   return: none
 *   parser(in):  the parser context
 *   count(in):  an input data type node
 *   values(in):  an input DB_VALUE set
 *
 * Note :
 *  Its purpose is to hide the internal structure for portability and
 *  maintainability of applications.
 */
void
pt_set_host_variables (PARSER_CONTEXT * parser, int count, DB_VALUE * values)
{
  DB_VALUE *val, *hv;
  DB_TYPE typ;
  TP_DOMAIN *hv_dom;
  int i, is_ref = 0;

  if (parser == NULL || count <= 0 || values == NULL)
    {
      return;
    }

  parser->flag.set_host_var = 0;

  if (parser->host_var_count > count)
    {
      /* oh no, an user gave me wrong data ... generate warning! */
      PT_WARNINGmf2 (parser, NULL, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_HOSTVAR_INDEX_ERROR, count,
             parser->host_var_count);
      return;
    }

  /* cast and copy the given values to the place holder */
  for (val = values, hv = parser->host_variables, i = 0; i < parser->host_var_count; val++, hv++, i++)
    {
      is_ref = pt_is_reference_to_reusable_oid (val);
      if (is_ref < 0)
    {
      PT_ERRORc (parser, NULL, er_msg ());
      return;
    }
      if (is_ref > 0)
    {
      PT_ERRORm (parser, NULL, MSGCAT_SET_ERROR, -(ER_REFERENCE_TO_NON_REFERABLE_NOT_ALLOWED));
      return;
    }

      pr_clear_value (hv);
      hv_dom = parser->host_var_expected_domains[i];
      if (TP_DOMAIN_TYPE (hv_dom) == DB_TYPE_UNKNOWN || hv_dom->type->id == DB_TYPE_ENUMERATION)
    {
      pr_clone_value (val, hv);
    }
      else
    {
      DB_TYPE val_type = db_value_type (val);

      if (tp_value_cast_preserve_domain (val, hv, hv_dom, false, true) != DOMAIN_COMPATIBLE)
        {
          typ = TP_DOMAIN_TYPE (hv_dom);
          PT_ERRORmf2 (parser, NULL, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_CANT_COERCE_TO, "host var",
               pt_type_enum_to_db_domain_name (pt_db_to_type_enum (typ)));
          return;
        }
      if (TP_IS_CHAR_TYPE (hv_dom->type->id))
        {
          if (hv_dom->type->id != val_type && (val_type == DB_TYPE_VARCHAR))
        {
          pr_clone_value (val, hv);
        }
        }
    }
    }

  parser->flag.set_host_var = 1;    /* OK */
}

/*
 * pt_host_var_db_value() -
 *   return:
 *   parser(in):
 *   hv(in):
 */
DB_VALUE *
pt_host_var_db_value (PARSER_CONTEXT * parser, PT_NODE * hv)
{
  DB_VALUE *val = NULL;
  int idx;

  if (hv && hv->node_type == PT_HOST_VAR)
    {
      idx = hv->info.host_var.index;
      if (idx >= 0 && idx < parser->host_var_count && parser->flag.set_host_var)
    {
      val = &parser->host_variables[idx];
    }
      else if (idx >= parser->host_var_count && idx < parser->host_var_count + parser->auto_param_count)
    {
      val = &parser->host_variables[idx];
    }
    }

  return val;
}

/*
 * pt_db_value_initialize() -  initialize DB_VALUE
 *   return:  DB_VALUE equivalent of value on successful conversion
 *      NULL otherwise
 *   parser(in): handle to context used to derive PT_VALUE type node,
 *               may also have associated host_variable bound DB_VALUEs
 *   value(in): the PT_VALUE type node to be converted to DB_VALUE
 *   db_value(in): the DB_VALUE
 *   more_type_info_needed(in): flag for need more info
 */
/* TODO fix precision of char and bit constants and then remove the
 *      pt_fixup_column_type function.
 */
DB_VALUE *
pt_db_value_initialize (PARSER_CONTEXT * parser, PT_NODE * value, DB_VALUE * db_value, int *more_type_info_needed)
{
  DB_SET *set;
  DB_MULTISET *multiset;
  DB_SEQ *seq;
  DB_DATE date;
  DB_TIME time;
  DB_UTIME utime;
  DB_TIMESTAMPTZ ts_tz;
  DB_DATETIME datetime;
  DB_DATETIMETZ dt_tz;
  int src_length;
  int dst_length;
  int bits_converted;
  char *bstring;
  int collation_id = LANG_COERCIBLE_COLL;
  INTL_CODESET codeset = LANG_COERCIBLE_CODESET;
  bool has_zone;
  const char *json_body = NULL;

  assert (value->node_type == PT_VALUE);
  if (PT_HAS_COLLATION (value->type_enum) && value->data_type != NULL)
    {
      collation_id = value->data_type->info.data_type.collation_id;
      codeset = (INTL_CODESET) value->data_type->info.data_type.units;
    }

  switch (value->type_enum)
    {
    case PT_TYPE_NA:
    case PT_TYPE_NULL:
      db_make_null (db_value);
      break;

    case PT_TYPE_SET:
      set = db_set_create_basic (NULL, NULL);
      if (set == NULL)
    {
      PT_ERROR (parser, value,
            msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_OUT_OF_MEMORY));
      return (DB_VALUE *) NULL;
    }

      db_make_set (db_value, set);

      if (pt_set_value_to_db (parser, &value->info.value.data_value.set, db_value, &value->data_type) == NULL)
    {
      pr_clear_value (db_value);
      return (DB_VALUE *) NULL;
    }

      value->info.value.db_value_is_in_workspace = true;
      break;

    case PT_TYPE_MULTISET:
      multiset = db_set_create_multi (NULL, NULL);
      if (multiset == NULL)
    {
      PT_ERROR (parser, value,
            msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_OUT_OF_MEMORY));
      return (DB_VALUE *) NULL;
    }

      db_make_multiset (db_value, multiset);

      if (pt_set_value_to_db (parser, &value->info.value.data_value.set, db_value, &value->data_type) == NULL)
    {
      pr_clear_value (db_value);
      return (DB_VALUE *) NULL;
    }

      value->info.value.db_value_is_in_workspace = true;
      break;

    case PT_TYPE_SEQUENCE:
      seq = db_seq_create (NULL, NULL, 0);
      if (seq == NULL)
    {
      PT_ERROR (parser, value,
            msgcat_message (MSGCAT_CATALOG_CUBRID, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_OUT_OF_MEMORY));
      return (DB_VALUE *) NULL;
    }

      db_make_sequence (db_value, seq);

      if (pt_seq_value_to_db (parser, value->info.value.data_value.set, db_value, &value->data_type) == NULL)
    {
      pr_clear_value (db_value);
      return (DB_VALUE *) NULL;
    }

      value->info.value.db_value_is_in_workspace = true;
      break;

    case PT_TYPE_INTEGER:
    case PT_TYPE_LOGICAL:
      db_make_int (db_value, value->info.value.data_value.i);
      break;

    case PT_TYPE_BIGINT:
      db_make_bigint (db_value, value->info.value.data_value.bigint);
      break;

    case PT_TYPE_SMALLINT:
      db_make_short (db_value, (short) value->info.value.data_value.i);
      break;

    case PT_TYPE_FLOAT:
      db_make_float (db_value, value->info.value.data_value.f);
      break;

    case PT_TYPE_NUMERIC:
      if (numeric_coerce_string_to_num ((const char *) value->info.value.data_value.str->bytes,
                    value->info.value.data_value.str->length, codeset, db_value) != NO_ERROR)
    {
      PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_BAD_NUMERIC,
              value->info.value.data_value.str->bytes);
      return (DB_VALUE *) NULL;
    }
      *more_type_info_needed = (value->data_type == NULL);
      break;

    case PT_TYPE_DOUBLE:
      db_make_double (db_value, value->info.value.data_value.d);
      break;

    case PT_TYPE_DATE:
      if (db_string_to_date ((const char *) value->info.value.data_value.str->bytes, &date) != NO_ERROR)
    {
      PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_BAD_DATE,
              value->info.value.data_value.str->bytes);
      return (DB_VALUE *) NULL;
    }
      db_value_domain_init (db_value, DB_TYPE_DATE, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
      db_value_put_encoded_date (db_value, &date);
      break;

    case PT_TYPE_TIME:
      if (db_string_to_time ((const char *) value->info.value.data_value.str->bytes, &time) != NO_ERROR)
    {
      PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_BAD_TIME,
              value->info.value.data_value.str->bytes);
      return (DB_VALUE *) NULL;
    }
      db_value_domain_init (db_value, DB_TYPE_TIME, DB_DEFAULT_PRECISION, DB_DEFAULT_SCALE);
      db_value_put_encoded_time (db_value, &time);
      break;

    case PT_TYPE_TIMESTAMP:
      if (db_string_to_utime ((const char *) value->info.value.data_value.str->bytes, &utime) != NO_ERROR)
    {
      PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_BAD_UTIME,
              value->info.value.data_value.str->bytes);
      return (DB_VALUE *) NULL;
    }
      db_make_timestamp (db_value, utime);
      break;

    case PT_TYPE_TIMESTAMPTZ:
      {
    bool has_zone = false;

    if (db_string_to_timestamptz ((const char *) value->info.value.data_value.str->bytes, &ts_tz, &has_zone) !=
        NO_ERROR)
      {
        PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_BAD_UTIME,
            value->info.value.data_value.str->bytes);
        return (DB_VALUE *) NULL;
      }
    db_make_timestamptz (db_value, &ts_tz);
      }
      break;

    case PT_TYPE_TIMESTAMPLTZ:
      if (db_string_to_timestampltz ((const char *) value->info.value.data_value.str->bytes, &utime) != NO_ERROR)
    {
      PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_BAD_UTIME,
              value->info.value.data_value.str->bytes);
      return (DB_VALUE *) NULL;
    }
      db_make_timestampltz (db_value, utime);
      break;

    case PT_TYPE_DATETIME:
      if (db_string_to_datetime ((const char *) value->info.value.data_value.str->bytes, &datetime) != NO_ERROR)
    {
      PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_BAD_UTIME,
              value->info.value.data_value.str->bytes);
      return (DB_VALUE *) NULL;
    }
      db_make_datetime (db_value, &datetime);
      break;

    case PT_TYPE_DATETIMETZ:
      if (db_string_to_datetimetz ((const char *) value->info.value.data_value.str->bytes, &dt_tz, &has_zone) !=
      NO_ERROR)
    {
      PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_BAD_UTIME,
              value->info.value.data_value.str->bytes);
      return (DB_VALUE *) NULL;
    }
      db_make_datetimetz (db_value, &dt_tz);
      break;

    case PT_TYPE_DATETIMELTZ:
      if (db_string_to_datetimeltz ((const char *) value->info.value.data_value.str->bytes, &datetime) != NO_ERROR)
    {
      PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_BAD_UTIME,
              value->info.value.data_value.str->bytes);
      return (DB_VALUE *) NULL;
    }
      db_make_datetimeltz (db_value, &datetime);
      break;

    case PT_TYPE_MONETARY:
      /*
       * Don't use db_make_monetary here, since it doesn't preserve the
       * currency info.
       */
      db_make_monetary (db_value, (DB_CURRENCY) value->info.value.data_value.money.type,
            value->info.value.data_value.money.amount);
      break;

    case PT_TYPE_BIT:
    case PT_TYPE_VARBIT:
      if (value->info.value.string_type == 'B')
    {
      src_length = value->info.value.data_value.str->length;
      dst_length = (src_length + 7) / 8;
      bits_converted = 0;
      bstring = (char *) db_private_alloc (NULL, dst_length + 1);
      if (!bstring)
        {
          return (DB_VALUE *) NULL;
        }
      bits_converted =
        qstr_bit_to_bin (bstring, dst_length, (char *) value->info.value.data_value.str->bytes, src_length);
      if (bits_converted != src_length)
        {
          db_private_free_and_init (NULL, bstring);
          PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INVALID_BITSTRING,
              pt_short_print (parser, value));
          return (DB_VALUE *) NULL;
        }

      db_make_bit (db_value, TP_FLOATING_PRECISION_VALUE, bstring, src_length);
      db_value->need_clear = true;
      value->info.value.db_value_is_in_workspace = true;
    }
      else if (value->info.value.string_type == 'X')
    {
      src_length = value->info.value.data_value.str->length;
      dst_length = (src_length + 1) / 2;
      bits_converted = 0;
      bstring = (char *) db_private_alloc (NULL, dst_length + 1);
      if (!bstring)
        {
          return (DB_VALUE *) NULL;
        }
      bits_converted =
        qstr_hex_to_bin (bstring, dst_length, (char *) value->info.value.data_value.str->bytes, src_length);
      if (bits_converted != src_length)
        {
          db_private_free_and_init (NULL, bstring);
          PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_INVALID_BITSTRING,
              pt_short_print (parser, value));
          return (DB_VALUE *) NULL;
        }
      db_make_bit (db_value, TP_FLOATING_PRECISION_VALUE, bstring, src_length * 4);
      db_value->need_clear = true;
      value->info.value.db_value_is_in_workspace = true;
    }
      else
    {
      PT_ERRORm (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_UNDEFINED_CONVERSION);
      return (DB_VALUE *) NULL;
    }
      db_value_alter_type (db_value, pt_type_enum_to_db (value->type_enum));
      *more_type_info_needed = (value->data_type == NULL);
      break;

    case PT_TYPE_CHAR:
      /* for constants, set the precision to TP_FLOATING_PRECISION_VALUE */
      db_make_char (db_value, TP_FLOATING_PRECISION_VALUE,
            REINTERPRET_CAST (char *, value->info.value.data_value.str->bytes),
            value->info.value.data_value.str->length, codeset, collation_id);
      value->info.value.db_value_is_in_workspace = false;
      *more_type_info_needed = (value->data_type == NULL);
      break;

    case PT_TYPE_VARCHAR:
      /* for constants, set the precision to TP_FLOATING_PRECISION_VALUE */
      db_make_varchar (db_value, TP_FLOATING_PRECISION_VALUE,
               REINTERPRET_CAST (char *, value->info.value.data_value.str->bytes),
               value->info.value.data_value.str->length, codeset, collation_id);
      value->info.value.db_value_is_in_workspace = false;
      *more_type_info_needed = (value->data_type == NULL);
      break;

    case PT_TYPE_JSON:
      db_value->domain.general_info.type = DB_TYPE_JSON;
      db_value->domain.general_info.is_null = 0;
      json_body = (const char *) value->info.value.data_value.str->bytes;
      if (db_json_get_json_from_str (json_body, db_value->data.json.document,
                     value->info.value.data_value.str->length) != NO_ERROR)
    {
      PT_ERRORmf (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_INVALID_JSON,
              value->info.value.data_value.str->bytes);
      return (DB_VALUE *) NULL;
    }

      value->info.value.db_value_is_in_workspace = true;
      db_value->need_clear = true;
      *more_type_info_needed = (value->data_type == NULL);
      break;

    case PT_TYPE_OBJECT:
      db_make_object (db_value, value->info.value.data_value.op);
      value->info.value.db_value_is_in_workspace = true;
      *more_type_info_needed = (value->data_type == NULL);
      break;

    case PT_TYPE_BLOB:
      /* db_make_blob (db_value, (DB_ELO *)value->info.value.data_value.elo); */
      db_make_elo (db_value, DB_TYPE_BLOB, &value->info.value.data_value.elo);
      db_value->domain.general_info.type = DB_TYPE_BLOB;
      value->info.value.db_value_is_in_workspace = false;
      break;

    case PT_TYPE_CLOB:
      /* db_make_clob (db_value, (DB_ELO *)value->info.value.data_value.elo); */
      db_make_elo (db_value, DB_TYPE_CLOB, &value->info.value.data_value.elo);
      db_value->domain.general_info.type = DB_TYPE_CLOB;
      value->info.value.db_value_is_in_workspace = false;
      break;

    case PT_TYPE_COMPOUND:
      PT_ERRORm (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_UNIMPLEMENTED_CONV);
      return (DB_VALUE *) NULL;

    case PT_TYPE_NONE:
    case PT_TYPE_STAR:
    case PT_TYPE_MAYBE:
    case PT_TYPE_EXPR_SET:
    case PT_TYPE_MAX:
    case PT_TYPE_MIDXKEY:
    case PT_TYPE_RESULTSET:
      PT_ERRORm (parser, value, MSGCAT_SET_PARSER_RUNTIME, MSGCAT_RUNTIME_UNDEFINED_CONVERSION);
      return (DB_VALUE *) NULL;

    default:
      break;
    }

  return db_value;
}

/*
 * db_json_val_from_str() - create JSON value from string
 *   return:  error code
 *   raw_str(in): buffer storing a JSON
 *   str_size(in): size of buffer
 *   json_val(out): output JSON DB_VALUE
 */
int
db_json_val_from_str (const char *raw_str, const int str_size, DB_VALUE * json_val)
{
  JSON_DOC *json_doc = NULL;
  int error_code = NO_ERROR;

  error_code = db_json_get_json_from_str (raw_str, json_doc, str_size);
  if (error_code != NO_ERROR)
    {
      assert (json_doc == NULL);
      return error_code;
    }

  db_make_json (json_val, json_doc, true);

  return error_code;
}