Skip to content

File query_result.c

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

/*
 * query_result.c - Helper functions to allocate, initialize query result
 *                  descriptor for select expressions.
 */

#ident "$Id$"

#include "config.h"

#include "authenticate.h"
#include "misc_string.h"
#include "error_manager.h"
#include "parser.h"
#include "parser_message.h"
#include "server_interface.h"
#include "db_query.h"
#include "object_accessor.h"
#include "schema_manager.h"
#include "memory_alloc.h"
#include "execute_statement.h"
#include "xasl_generation.h"
#include "object_primitive.h"
#include "db.h"
#include "network_interface_cl.h"
#include "transaction_cl.h"
#include "dbtype.h"

static int pt_find_size_from_dbtype (const DB_TYPE T_type);
static int pt_arity_of_query_type (const DB_QUERY_TYPE * qt);
static char *pt_get_attr_name (PARSER_CONTEXT * parser, PT_NODE * node);
static DB_COL_TYPE pt_get_col_type (const PARSER_CONTEXT * parser, const PT_NODE * node);
static void pt_set_domain_class (SM_DOMAIN * dom, const PT_NODE * nam, const DB_OBJECT * virt);
static void pt_set_domain_class_list (SM_DOMAIN * dom, const PT_NODE * nam, const DB_OBJECT * virt);
static SM_DOMAIN *pt_get_src_domain (PARSER_CONTEXT * parser, const PT_NODE * s, const PT_NODE * specs);
static DB_QUERY_TYPE *pt_get_node_title (PARSER_CONTEXT * parser, const PT_NODE * col, const PT_NODE * from_list);
static PT_NODE *pt_get_from_list (const PARSER_CONTEXT * parser, const PT_NODE * query);
static void pt_fixup_select_columns_type (PT_NODE * columns);

/*
 * pt_find_size_from_dbtype () -  return bytesize of memory representation of
 *                               a given primitive DB_TYPE
 *   return:  the bytesize of dt's memory representation
 *   T_type(in): a DB_TYPE
 */
static int
pt_find_size_from_dbtype (const DB_TYPE db_type)
{
  int size = 0;

  if (db_type != DB_TYPE_NULL)
    {
      const PR_TYPE *type = pr_type_from_id (db_type);
      if (type && !(type->variable_p))
    {
      size = pr_mem_size (type);
    }
    }

  return size;
}

/*
 * pt_arity_of_query_type () -  return arity (number of columns) of
 *                             a given DB_QUERY_TYPE
 *   return:  the arity (number of columns) of qt
 *   qt(in): a DB_QUERY_TYPE handle
 */

static int
pt_arity_of_query_type (const DB_QUERY_TYPE * qt)
{
  int cnt = 0;

  while (qt)
    {
      cnt++;
      qt = qt->next;
    }

  return cnt;
}

/*
 * pt_get_attr_name () - return the attribute name of a select_list item or NULL
 *   return: the attribute name of s if s is a path expression,
 *          NULL otherwise
 *   parser(in):
 *   node(in): an expression representing a select_list item
 */
static char *
pt_get_attr_name (PARSER_CONTEXT * parser, PT_NODE * node)
{
  const char *name;
  char *res = NULL;
  unsigned int save_custom = parser->custom_print;

  node = pt_get_end_path_node (node);
  if (node == NULL)
    {
      return NULL;
    }
  if (node->node_type != PT_NAME)
    {
      return NULL;
    }

  parser->custom_print = (parser->custom_print | PT_SUPPRESS_RESOLVED | PT_SUPPRESS_SELECTOR);

  name = parser_print_tree (parser, node);
  parser->custom_print = save_custom;

  if (name)
    {
      res = strdup (name);
    }

  return res;
}

/*
 * pt_get_col_type () -
 *   return:
 *   parser(in):
 *   node(in):
 */
static DB_COL_TYPE
pt_get_col_type (const PARSER_CONTEXT * parser, const PT_NODE * node)
{
  if (pt_is_expr_node (node))
    return DB_COL_EXPR;

  if (pt_is_value_node (node))
    return DB_COL_VALUE;

  if (pt_is_oid_name (node))
    return DB_COL_OID;

  if (pt_is_name_node (node))
    return DB_COL_NAME;

  if (pt_is_dot_node (node))
    {
      if (node->info.dot.arg2->node_type == PT_FUNCTION || node->info.dot.arg2->node_type == PT_METHOD_CALL)
    return DB_COL_OTHER;
      else
    return DB_COL_PATH;
    }

  if (pt_is_function (node))
    return DB_COL_FUNC;

  return DB_COL_OTHER;
}


/*
 * pt_set_domain_class() -  set SM_DOMAIN's class field
 *   return:  none
 *   dom(out): an SM_DOMAIN
 *   nam(in): an entity name
 *   virt(in):
 */
static void
pt_set_domain_class (SM_DOMAIN * dom, const PT_NODE * nam, const DB_OBJECT * virt)
{
  if (!dom || !nam || nam->node_type != PT_NAME)
    return;

  dom->type = pr_type_from_id (DB_TYPE_OBJECT);
  if (virt != NULL)
    {
      dom->class_mop = (DB_OBJECT *) virt;
    }
  else
    {
      if (nam->info.name.db_object != NULL)
    {
      dom->class_mop = nam->info.name.db_object;
      COPY_OID (&dom->class_oid, &(dom->class_mop->oid_info.oid));
    }
      else
    {
      dom->class_mop = db_find_class (nam->info.name.original);
      if (dom->class_mop != NULL)
        {
          COPY_OID (&dom->class_oid, &(dom->class_mop->oid_info.oid));
        }
    }
    }
}

/*
 * pt_set_domain_class_list() -  set SM_DOMAIN's class fields
 *   return:  none
 *   dom(out): an SM_DOMAIN anchor node
 *   nam(in): an entity name list
 *   virt(in):
 */
static void
pt_set_domain_class_list (SM_DOMAIN * dom, const PT_NODE * nam, const DB_OBJECT * virt)
{
  SM_DOMAIN *tail = dom;

  while (nam && nam->node_type == PT_NAME && dom)
    {
      pt_set_domain_class (dom, nam, virt);
      nam = nam->next;

      if (!nam || nam->node_type != PT_NAME)
    break;

      dom = sm_domain_alloc ();
      assert (dom != NULL);
      tp_domain_init (dom, DB_TYPE_INTEGER);
      tail->next = dom;
      tail = dom;
    }
}

/*
 * pt_get_src_domain() -  compute & return the source domain of an expression
 *   return:  source domain of the given expression
 *   parser(in): the parser context
 *   s(in): an expression representing a select_list item
 *   specs(in): the list of specs to which s was resolved
 */
static SM_DOMAIN *
pt_get_src_domain (PARSER_CONTEXT * parser, const PT_NODE * s, const PT_NODE * specs)
{
  SM_DOMAIN *result;
  PT_NODE *spec, *entity_names, *leaf = (PT_NODE *) s;
  UINTPTR spec_id;

  result = sm_domain_alloc ();
  if (result == NULL)
    {
      return result;
    }
  tp_domain_init (result, DB_TYPE_INTEGER);

  /* if s is not a path expression then its source domain is DB_TYPE_NULL */
  result->type = pr_type_from_id (DB_TYPE_NULL);

  /* make leaf point to the last leaf name node */
  if (s->node_type == PT_DOT_)
    {
      leaf = s->info.dot.arg2;
    }

  /* s's source domain is the domain of leaf's resolvent(s) */
  if (leaf->node_type == PT_NAME && (spec_id = leaf->info.name.spec_id)
      && (spec = pt_find_entity (parser, specs, spec_id)) && (entity_names = spec->info.spec.flat_entity_list))
    {
      pt_set_domain_class_list (result, entity_names, entity_names->info.name.virt_object);
    }

  return result;
}

/*
 * pt_report_to_ersys () - report query compilation error by
 *                         setting global ER state
 *   return:
 *   parser(in): handle to parser used to process the query
 *   error_type(in): syntax, semantic, or execution
 */
void
pt_report_to_ersys (const PARSER_CONTEXT * parser, const PT_ERROR_TYPE error_type)
{
  PT_NODE *error_node;
  int err;
  char buf[1000];

  error_node = parser->error_msgs;
  if (error_node && error_node->node_type == PT_ZZ_ERROR_MSG)
    {
#if 0               /* TODO */
      assert (er_errid () != NO_ERROR);
#endif
      err = er_errid ();
      if (!ER_IS_LOCK_TIMEOUT_ERROR (err) && !ER_IS_SERVER_DOWN_ERROR (err))
    {
      switch (error_type)
        {
        case PT_SYNTAX:
          er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, ER_PT_SYNTAX, 2,
              error_node->info.error_msg.error_message, "");
          break;
        case PT_SEMANTIC:
        default:
          er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, ER_PT_SEMANTIC, 2,
              error_node->info.error_msg.error_message, "");
          break;
        case PT_EXECUTION:
          er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, ER_PT_EXECUTE, 2,
              error_node->info.error_msg.error_message, "");
          break;
        }
    }
      return;
    }

  /* a system error reporting error messages */
  sprintf (buf, "Internal error- reporting %s error.",
       (error_type == PT_SYNTAX ? "syntax" : (error_type == PT_SEMANTIC ? "semantic" : "execution")));

  er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, ER_PT_EXECUTE, 2, buf, "");
}

/*
 * pt_report_to_ersys_with_statement () - report query compilation error by
 *                                        setting global ER state
 *   return:
 *   parser(in): handle to parser used to process the query
 *   error_type(in): syntax, semantic, or execution
 *   statement(in): statement tree
 */
void
pt_report_to_ersys_with_statement (PARSER_CONTEXT * parser, const PT_ERROR_TYPE error_type, PT_NODE * statement)
{
  PT_NODE *error_node;
  char buf[1000];
  char *stmt_string = NULL;
  int err;

  if (parser == NULL)
    {
      return;
    }

  error_node = parser->error_msgs;
  if (statement)
    {
      PT_NODE_PRINT_TO_ALIAS (parser, statement, PT_CONVERT_RANGE | PT_SHORT_PRINT);
      stmt_string = (char *) statement->alias_print;
    }
  if (stmt_string == NULL)
    {
      stmt_string = (char *) "";
    }

  if (error_node && error_node->node_type == PT_ZZ_ERROR_MSG)
    {
#if 0               /* TODO */
      assert (er_errid () != NO_ERROR);
#endif
      err = er_errid ();
      if (!ER_IS_LOCK_TIMEOUT_ERROR (err) && !ER_IS_SERVER_DOWN_ERROR (err))
    {
      switch (error_type)
        {
        case PT_SYNTAX:
          er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, ER_PT_SYNTAX, 2,
              error_node->info.error_msg.error_message, stmt_string);
          break;
        case PT_SEMANTIC:
        default:
          er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, ER_PT_SEMANTIC, 2,
              error_node->info.error_msg.error_message, stmt_string);
          break;
        case PT_EXECUTION:
          er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, ER_PT_EXECUTE, 2,
              error_node->info.error_msg.error_message, stmt_string);
          break;
        }
    }
      return;
    }

  /* a system error reporting error messages */
  sprintf (buf, "Internal error- reporting %s error.",
       (error_type == PT_SYNTAX ? "syntax" : (error_type == PT_SEMANTIC ? "semantic" : "execution")));

  er_set (ER_SYNTAX_ERROR_SEVERITY, ARG_FILE_LINE, ER_PT_EXECUTE, 2, buf, stmt_string);
}               /* pt_report_to_ersys_with_statement() */

/*
 * pt_get_select_list () - PT_NODE *, a pointer to query's select list
 *                     NULL if query is a 'SELECT *' query
 *   return:
 *   parser(in): handle to parser used to process & derive query
 *   query(out): abstract syntax tree form of a SELECT expression
 */
PT_NODE *
pt_get_select_list (PARSER_CONTEXT * parser, PT_NODE * query)
{
  PT_NODE *list, *attr;
  PT_NODE *arg1, *arg2, *attr1, *attr2, *select_list, *col, *next;
  int cnt1, cnt2;
  PT_TYPE_ENUM common_type;

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

  switch (query->node_type)
    {
    default:
      return NULL;

    case PT_SELECT:
      list = query->info.query.q.select.list;
      if (list == NULL)
    {
      return NULL;
    }

      /* return the first row of PT_NODE_LIST */
      if (list->node_type == PT_NODE_LIST)
    {
      return list->info.node_list.list;
    }

      if (list->node_type == PT_VALUE && list->type_enum == PT_TYPE_STAR)
    {
      return NULL;
    }

      for (attr = list; attr; attr = attr->next)
    {
      if (attr->node_type == PT_NAME && attr->type_enum == PT_TYPE_STAR)
        {
          /* found "class_name.*" */
          return NULL;
        }
    }

      return list;

    case PT_DIFFERENCE:
    case PT_INTERSECTION:
    case PT_UNION:
      select_list = query->info.query.q.union_.select_list;

      assert (query->parser_id == parser->id);
      if (select_list && select_list->parser_id != parser->id)
    {
      /*
       * Union PT_NODE keeps select_list as reference
       * this case means, this parser copy other parsers tree
       * but union.info.select_list points old reference
       *
       * this function can free & realloc select_list->data_type
       * so, to prevent modifying (other parser's) original
       * tree, deep copy select_list in this parser's context
       */
      select_list = parser_copy_tree_list (parser, select_list);
      query->info.query.q.union_.select_list = select_list;
    }

      arg1 = pt_get_select_list (parser, query->info.query.q.union_.arg1);
      arg2 = pt_get_select_list (parser, query->info.query.q.union_.arg2);

      if (select_list == NULL)
    {
      /* if arg1 or arg2 is null, there need be resolved firstly. */
      if (arg1 == NULL || arg2 == NULL)
        {
          return NULL;
        }

      cnt1 = pt_length_of_select_list (arg1, EXCLUDE_HIDDEN_COLUMNS);
      cnt2 = pt_length_of_select_list (arg2, EXCLUDE_HIDDEN_COLUMNS);

      if (cnt1 != cnt2)
        {
          PT_ERRORmf2 (parser, arg1, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_ARITY_MISMATCH, cnt1, cnt2);
          return NULL;
        }

      select_list = parser_copy_tree_list (parser, arg1);
      if (cnt1 != pt_length_of_select_list (arg1, INCLUDE_HIDDEN_COLUMNS))
        {
          /* hidden column is included. get rid of it */
          for (col = select_list; col && col->next; col = next)
        {
          next = col->next;
          if (next->flag.is_hidden_column)
            {
              parser_free_tree (parser, next);
              col->next = NULL;
              break;
            }
        }
        }
    }

      for (col = select_list, attr1 = arg1, attr2 = arg2; col && attr1 && attr2;
       col = col->next, attr1 = attr1->next, attr2 = attr2->next)
    {
      /* preserve the ENUM type as common type between two ENUMs in UNION, DIFFERENCE and INTERSECTION. The ENUM
       * domains already have been verified and if they are different an error is generated. */
      if (attr1->type_enum == attr2->type_enum && attr1->type_enum == PT_TYPE_ENUMERATION)
        {
          common_type = PT_TYPE_ENUMERATION;
        }
      else
        {
          common_type = pt_common_type (attr1->type_enum, attr2->type_enum);
        }

      if (pt_is_value_node (col) && (col->type_enum == PT_TYPE_NA || col->type_enum == PT_TYPE_NULL))
        {
          db_make_null (&col->info.value.db_value);
        }

      if ((attr2->type_enum == PT_TYPE_NONE) || (attr2->type_enum == PT_TYPE_NA)
          || (attr2->type_enum == PT_TYPE_NULL))
        {
          /* convert type to that of non-null */
          if (col->type_enum == PT_TYPE_NA && col->alias_print == NULL)
        {
          col->alias_print = pt_append_string (parser, NULL, "na");
        }
          else if (col->type_enum == PT_TYPE_NULL && col->alias_print == NULL)
        {
          col->alias_print = pt_append_string (parser, NULL, "null");
        }
          col->type_enum = attr1->type_enum;
          if (col->data_type)
        {
          parser_free_tree (parser, col->data_type);
        }
          col->data_type = parser_copy_tree_list (parser, attr1->data_type);

        }
      else if ((attr1->type_enum == PT_TYPE_NONE) || (attr1->type_enum == PT_TYPE_NA)
           || (attr1->type_enum == PT_TYPE_NULL))
        {
          /* convert type to that of non-null */
          if (col->type_enum == PT_TYPE_NA && col->alias_print == NULL)
        {
          col->alias_print = pt_append_string (parser, NULL, "na");
        }
          else if (col->type_enum == PT_TYPE_NULL && col->alias_print == NULL)
        {
          col->alias_print = pt_append_string (parser, NULL, "null");
        }
          col->type_enum = attr2->type_enum;
          if (col->data_type)
        {
          parser_free_tree (parser, col->data_type);
        }
          col->data_type = parser_copy_tree_list (parser, attr2->data_type);
        }
      else if (PT_IS_PARAMETERIZED_TYPE (common_type)
           || (common_type != PT_TYPE_NONE && col->type_enum != common_type))
        {
          col->type_enum = common_type;

          if (col->data_type)
        {
          parser_free_tree (parser, col->data_type);
          col->data_type = NULL;
        }
          if (PT_IS_COMPLEX_TYPE (common_type))
        {
          col->data_type = parser_copy_tree_list (parser, attr2->data_type);
        }
        }
    }

      if (select_list != query->info.query.q.union_.select_list)
    {
      parser_free_tree (parser, query->info.query.q.union_.select_list);
    }

      query->info.query.q.union_.select_list = select_list;

      return select_list;
    }
}

/*
 * pt_get_from_list () - returns a pointer to query's from list
 *   return:
 *   parser(in): handle to parser used to process & derive query
 *   query(in): abstract syntax tree form of a SELECT expression
 */
static PT_NODE *
pt_get_from_list (const PARSER_CONTEXT * parser, const PT_NODE * query)
{
  if (query == NULL)
    {
      return NULL;
    }

  switch (query->node_type)
    {
    default:
      return NULL;

    case PT_SELECT:
      return query->info.query.q.select.from;

    case PT_DIFFERENCE:
    case PT_INTERSECTION:
    case PT_UNION:
      return pt_get_from_list (parser, query->info.query.q.union_.arg1);
    }
}

static void
pt_fixup_select_columns_type (PT_NODE * columns)
{
  PT_NODE *col = NULL;
  for (col = columns; col != NULL; col = col->next)
    {
      pt_fixup_column_type (col);
    }
}

/*
 * pt_get_titles() - creates, initializes, returns DB_QUERY_TYPE describing the
 *               output columns titles of the given query
 *   return:  DB_QUERY_TYPE*, a descriptor of query's output columns
 *   parser(in/out): handle to parser used to process & derive query
 *   query(out): abstract syntax tree form of a SELECT expression
 */

DB_QUERY_TYPE *
pt_get_titles (PARSER_CONTEXT * parser, PT_NODE * query)
{
  DB_QUERY_TYPE *q, *t, *tail;
  PT_NODE *s, *f;
  unsigned int save_custom;

  s = pt_get_select_list (parser, query);
  if (pt_length_of_select_list (s, EXCLUDE_HIDDEN_COLUMNS) <= 0)
    {
      return NULL;
    }
  f = pt_get_from_list (parser, query);

  for (q = NULL, tail = NULL; s; s = s->next)
    {
      if (s->flag.is_hidden_column)
    {
      continue;
    }
      else
    {
      save_custom = parser->custom_print;
      parser->custom_print |= PT_SUPPRESS_CHARSET_PRINT;
      parser->custom_print |= PT_PRINT_NO_CURRENT_USER_NAME;
      t = pt_get_node_title (parser, s, f);
      parser->custom_print = save_custom;

      if (t == NULL)
        {
          db_free_query_format (q);
          return NULL;
        }

      if (q == NULL)
        {
          q = t;
        }
      else
        {
          tail->next = t;
        }

      t->next = NULL;
      tail = t;
    }
    }

  return q;
}

/*
 * pt_get_node_title() -  allocate and initialize a query_type node.
 *   return:  a fully initialized query type node
 *   parser(in/out): handle to parser used to process & derive query
 *   col(in): column to create the query type node from.
 *   from_list(in):
 *
 */

static DB_QUERY_TYPE *
pt_get_node_title (PARSER_CONTEXT * parser, const PT_NODE * col, const PT_NODE * from_list)
{
  DB_QUERY_TYPE *q;
  char *name;
  unsigned int save_custom;
  PT_NODE *node, *spec, *range_var;
  char *original_name;
  const char *tmp_name = NULL;

  save_custom = parser->custom_print;
  parser->custom_print |= PT_SUPPRESS_QUOTES;

  if ((q = (DB_QUERY_TYPE *) malloc (DB_SIZEOF (DB_QUERY_TYPE))) == NULL)
    {
      goto error;
    }
  q->visible_type = USER_COLUMN;
  q->next = NULL;
  q->db_type = DB_TYPE_NULL;
  q->size = 0;

  if (pt_resolved (col))
    {
      parser->custom_print |= PT_SUPPRESS_RESOLVED;
    }

  original_name = name = pt_print_alias (parser, col);

  if (col->alias_print == NULL)
    {
      switch (col->node_type)
    {
    case PT_NAME:
      if (pt_resolved (col))
        {
          if (col->info.name.meta_class == PT_META_ATTR)
        {
          name = pt_append_string (parser, NULL, "class ");
          if (parser->custom_print & PT_PRINT_NO_SPECIFIED_USER_NAME)
            {
              name = pt_append_string (parser, name,
                           pt_get_name_with_qualifier_removed (col->info.name.resolved));
            }
          else if (parser->custom_print & PT_PRINT_NO_CURRENT_USER_NAME)
            {
              name =
            pt_append_string (parser, name,
                      pt_get_name_without_current_user_name (col->info.name.resolved));
            }
          else
            {
              name = pt_append_string (parser, name, col->info.name.resolved);
            }
          name = pt_append_string (parser, name, ".");
          name = pt_append_string (parser, name, original_name);
          original_name = name;
        }
          else if (PT_NAME_INFO_IS_FLAGED (col, PT_NAME_INFO_DOT_NAME))
        {
          /* PT_NAME comes from PT_DOT_ */
          if (parser->custom_print & PT_PRINT_NO_SPECIFIED_USER_NAME)
            {
              tmp_name =
            pt_append_string (parser, pt_get_name_with_qualifier_removed (col->info.name.resolved), ".");
              original_name = pt_append_string (parser, tmp_name, original_name);
            }
          else if (parser->custom_print & PT_PRINT_NO_CURRENT_USER_NAME)
            {
              tmp_name = pt_append_string (parser,
                           pt_get_name_without_current_user_name (col->info.name.resolved),
                           ".");
              original_name = pt_append_string (parser, tmp_name, original_name);
            }
          else
            {
              original_name =
            pt_append_string (parser, pt_append_string (parser, col->info.name.resolved, "."),
                      original_name);
            }
        }
          else if (PT_NAME_INFO_IS_FLAGED (col, PT_NAME_INFO_DOT_STAR))
        {
          /* PT_NAME comes from classname.* */
          original_name = NULL;
        }
          else if (PT_NAME_INFO_IS_FLAGED (col, PT_NAME_INFO_STAR))
        {
          /* PT_NAME comes from * */
          original_name = NULL;
        }
        }
      break;
    case PT_DOT_:

      /* traverse left node */
      node = (PT_NODE *) col;
      while (node && node->node_type == PT_DOT_)
        {
          node = node->info.dot.arg1;
        }

      if (node && node->node_type == PT_NAME)
        {
          if (pt_resolved (col))
        {
          if (node->info.name.meta_class == PT_META_ATTR)
            {
              tmp_name = pt_append_string (parser,
                           pt_get_name_without_current_user_name (node->info.name.resolved),
                           ".");
              name = pt_append_string (parser, tmp_name, name);
              name = pt_append_string (parser, pt_append_string (parser, NULL, "class "), name);
              original_name = name;
            }
          else if (PT_NAME_INFO_IS_FLAGED (node, PT_NAME_INFO_DOT_NAME))
            {
              /* PT_NAME comes from PT_DOT_ */
              tmp_name = pt_append_string (parser,
                           pt_get_name_without_current_user_name (node->info.name.resolved),
                           ".");
              original_name = pt_append_string (parser, tmp_name, original_name);
            }
        }
          else if (node->info.name.meta_class == PT_NORMAL)
        {
          /* check for classname */
          for (spec = (PT_NODE *) from_list; spec; spec = spec->next)
            {
              /* get spec's range variable if range variable for spec is used, use range_var. otherwise, use
               * entity_name */
              range_var = spec->info.spec.range_var ? spec->info.spec.range_var : spec->info.spec.entity_name;

              if (pt_check_path_eq (parser, range_var, node) == 0)
            {
              if (original_name)
                {
                  /* strip off classname.* */
                  if (strchr (node->info.name.original, '.'))
                {
                  name = strchr (original_name, '.');
                  name++;
                }
                  else
                {
                  name = original_name;
                }

                  name = strchr (name, '.');
                  if (name == NULL || name[0] == '\0')
                {
                  name = original_name;
                }
                  else
                {
                  name++;
                }
                  break;
                }
              else
                {
                  name = NULL;
                }
            }
            }
        }
        }
      break;
    default:
      break;
    }
    }

  if (name)
    {
      q->name = strdup (name);
      if (q->name == NULL)
    {
      goto error;
    }
    }
  else
    {
      q->name = NULL;
    }

  if (original_name)
    {
      q->original_name = strdup (original_name);
      if (q->original_name == NULL)
    {
      if (q->name)
        {
          free_and_init (q->name);
        }

      goto error;
    }
    }
  else
    {
      /* PT_NAME comes from classname.* or * */
      q->original_name = NULL;
    }

  q->attr_name = pt_get_attr_name (parser, (PT_NODE *) col);
  q->spec_name = NULL;      /* fill it at pt_fillin_type_size() */

  /* At this time before query compilation, we cannot differentiate qualified attribute name(DB_COL_NAME) from path
   * expression(DB_COL_PATH). */
  q->col_type = pt_get_col_type (parser, col);
  q->domain = NULL;
  q->src_domain = NULL;

  parser->custom_print = save_custom;
  return q;

error:
  parser->custom_print = save_custom;
  if (q)
    free_and_init (q);
  return NULL;
}               /* pt_get_node_title */


/*
 * pt_fillin_type_size() -  set the db_type&size fields of a DB_QUERY_TYPE list
 *   return:  list, a fully initialized descriptor of query's output columns
 *   parser(in): handle to parser used to process & derive query
 *   query(out): abstract syntax tree form of a SELECT expression
 *   list(in/out): a partially initialized DB_QUERY_TYPE list
 *   oids_included(in):
 *   fixup_columns_type(in): whether fixup column type
 */

DB_QUERY_TYPE *
pt_fillin_type_size (PARSER_CONTEXT * parser, PT_NODE * query, DB_QUERY_TYPE * list, const int oids_included,
             bool want_spec_entity_name, bool fixup_columns_type)
{
  DB_QUERY_TYPE *q, *t;
  PT_NODE *s, *from_list;
  const char *spec_name;
  PT_NODE *node, *spec;
  UINTPTR spec_id;
  char *original_name;

  s = pt_get_select_list (parser, query);
  if (s == NULL || list == NULL)
    {
      return list;
    }

  if (fixup_columns_type)
    {
      /* fixup the columns of union statement */
      pt_fixup_select_columns_type (s);
    }
  from_list = pt_get_from_list (parser, query);
  /* from_list is allowed to be NULL for supporting SELECT without references to tables */

  if (oids_included == 1)
    {
      /*
       * prepend single oid column onto the type list
       * the first node of the select list will be the oid column.
       */
      q = pt_get_node_title (parser, s, from_list);

      if (q == NULL)
    {
      db_free_query_format (list);
      return NULL;
    }
      q->visible_type = OID_COLUMN; /* oid columns are NOT user visible */
      q->next = list;
      list = q;
    }

  if (pt_length_of_select_list (s, EXCLUDE_HIDDEN_COLUMNS) != pt_arity_of_query_type (list))
    {
      PT_INTERNAL_ERROR (parser, "query result");
      return list;
    }

  for (t = list; s && t; s = s->next, t = t->next)
    {
      t->col_type = pt_get_col_type (parser, s);
      t->db_type = pt_type_enum_to_db (s->type_enum);
      t->size = pt_find_size_from_dbtype (t->db_type);
      t->domain = pt_xasl_node_to_domain (parser, s);
      t->src_domain = pt_get_src_domain (parser, s, from_list);

      spec_name = NULL;
      /* if it is attribute, find spec name */
      if (pt_is_attr (s))
    {
      node = s;
      while (node->node_type == PT_DOT_)
        {
          node = node->info.dot.arg1;   /* root node for path expression */
        }
      if (node->node_type == PT_NAME && (spec_id = node->info.name.spec_id)
          && (spec = pt_find_entity (parser, from_list, spec_id)))
        {
          if (want_spec_entity_name == true && spec->info.spec.entity_name)
        {
          spec_name = spec->info.spec.entity_name->info.name.original;
        }
          else if (want_spec_entity_name == false && spec->info.spec.range_var)
        {
          spec_name = spec->info.spec.range_var->info.name.original;
        }
        }
    }
      /* if it is method, find spec name */
      if (pt_is_method_call (s))
    {
      node = s;
      while (node->node_type == PT_DOT_)
        {
          node = node->info.dot.arg2;   /* leaf node for qualified method */
        }
      node = node->info.method_call.method_name;
      if (node->node_type == PT_NAME && (spec_id = node->info.name.spec_id)
          && (spec = pt_find_entity (parser, from_list, spec_id)))
        {
          if (want_spec_entity_name == true && spec->info.spec.entity_name)
        {
          spec_name = spec->info.spec.entity_name->info.name.original;
        }
          else if (want_spec_entity_name == false && spec->info.spec.range_var)
        {
          spec_name = spec->info.spec.range_var->info.name.original;
        }
        }
    }

      t->spec_name = (spec_name) ? strdup (spec_name) : NULL;

      if (!t->original_name)
    {
      /* PT_NAME comes from classname.* or build original_name( = spec_name.name) */
      if (pt_length_of_list (from_list) == 1)
        {
          /* there is only one class spec */
          original_name = pt_append_string (parser, NULL, t->name);
          t->original_name = (char *) malloc (strlen (original_name) + 1);
        }
      else
        {
          /* there are plural class specs */
          original_name = pt_append_string (parser, pt_append_string (parser, (char *) t->spec_name, "."), t->name);
          t->original_name = (char *) malloc (strlen (original_name) + 1);
        }
      if (!t->original_name)
        {
          PT_INTERNAL_ERROR (parser, "insufficient memory");
          return list;
        }
      strcpy ((char *) t->original_name, original_name);
    }
    }

  return list;
}

/*
 * pt_new_query_result_descriptor() - allocates, initializes, returns a new
 *      query result descriptor and opens a cursor for the query's results
 *   return:  DB_QUERY_RESULT* with an open cursor
 *   parser(in): handle to parser used to process & derive query
 *   query(out): abstract syntax tree (AST) form of a query statement
 */

DB_QUERY_RESULT *
pt_new_query_result_descriptor (PARSER_CONTEXT * parser, PT_NODE * query)
{
  int degree;
  DB_QUERY_RESULT *r = NULL;
  QFILE_LIST_ID *list_id;
  int oids_included = 0;
  bool failure = false;

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

  switch (query->node_type)
    {
    default:
      return NULL;
      break;

    case PT_EXECUTE_PREPARE:
      if (query->info.execute.stmt_type != CUBRID_STMT_SELECT)
    {
      return NULL;
    }
      oids_included = query->info.execute.oids_included;
      degree = query->info.execute.column_count;
      break;

    case PT_INSERT:
      oids_included = 0;
      degree = 1;
      break;

    case PT_DIFFERENCE:
    case PT_INTERSECTION:
    case PT_UNION:
    case PT_SELECT:
      oids_included = query->info.query.oids_included;
      degree = 0;
      degree = pt_length_of_select_list (pt_get_select_list (parser, query), EXCLUDE_HIDDEN_COLUMNS);
      break;
    }

  r = db_alloc_query_result (T_SELECT, degree);
  if (r == NULL)
    {
      return NULL;
    }

  db_init_query_result (r, T_SELECT);
  r->type = T_SELECT;
  r->col_cnt = degree;

  r->oid_included = oids_included == 1;
  r->res.s.query_id = parser->query_id;
  r->res.s.stmt_id = 0;
  r->res.s.stmt_type = CUBRID_STMT_SELECT;
  r->res.s.cache_time = query->cache_time;

  /* the following is for clean up when the query fails */
  memset (&r->res.s.cursor_id.list_id, 0, sizeof (QFILE_LIST_ID));
  r->res.s.cursor_id.query_id = parser->query_id;
  r->res.s.cursor_id.buffer = NULL;
  r->res.s.cursor_id.tuple_record.tpl = NULL;
  r->res.s.holdable = parser->flag.is_holdable;

  list_id = (QFILE_LIST_ID *) query->etc;
  r->type_cnt = degree;
  if (list_id)
    {
      failure = !cursor_open (&r->res.s.cursor_id, list_id, false, r->oid_included);
      /* free result, which was copied by open cursor operation! */
      cursor_free_self_list_id (list_id);
    }
  else
    {
      QFILE_LIST_ID empty_list_id;
      QFILE_CLEAR_LIST_ID (&empty_list_id);
      failure = !cursor_open (&r->res.s.cursor_id, &empty_list_id, false, r->oid_included);
    }

  if (failure)
    {
      db_free_query_result (r);
      r = NULL;
    }

  return r;
}

/*
 * pt_make_cache_hit_result_descriptor () -
 *   return:
 */
DB_QUERY_RESULT *
pt_make_cache_hit_result_descriptor (void)
{
  DB_QUERY_RESULT *r;

  r = db_alloc_query_result (T_CACHE_HIT, 0);
  if (r == NULL)
    {
      return NULL;
    }

  db_init_query_result (r, T_CACHE_HIT);

  return r;
}


/*
 * pt_free_query_etc_area () -
 *   return: none
 *   session(in):
 *   query(in): abstract syntax tree (AST) form of a query statement
 */
void
pt_free_query_etc_area (PARSER_CONTEXT * parser, PT_NODE * query)
{
  if (query && query->etc
      && (pt_node_to_cmd_type (query) == CUBRID_STMT_SELECT || pt_node_to_cmd_type (query) == CUBRID_STMT_DO
      || pt_is_server_insert_with_generated_keys (parser, query)))
    {
      cursor_free_self_list_id (query->etc);
    }
}


/*
 * pt_end_query() -
 *   return:
 *   parser(in): parser context
 *   query_id_self(in):
 */
void
pt_end_query (PARSER_CONTEXT * parser, QUERY_ID query_id_self)
{
  assert (parser != NULL);
  assert (query_id_self != 0);
  assert (query_id_self == NULL_QUERY_ID || query_id_self > 0);

  if (parser->query_id > 0)
    {
      if (!tran_was_latest_query_ended () && er_errid () != ER_LK_UNILATERALLY_ABORTED)
    {
      qmgr_end_query (parser->query_id);
    }
    }
  else
    {
      assert (parser->query_id == 0);
    }

  parser->query_id = query_id_self;
}


/*
 * db_object_describe() -  get a DB_QUERY_TYPE descriptor of the named
 *                         attributes of a given object
 *   return:  int (non-zero in case of error)
 *   obj_mop(in): a DB_OBJECT in the workspace
 *   num_attrs(in): number of names in attrs array
 *   attrs(in): an array of null-terminated character strings
 *   col_spec(out): a new DB_QUERY_TYPE structure
 */
int
db_object_describe (DB_OBJECT * obj_mop, int num_attrs, const char **attrs, DB_QUERY_TYPE ** col_spec)
{
  DB_QUERY_TYPE *t;
  int i, attrid, shared, err = NO_ERROR;
  MOP class_mop;
  const char **name;
  SM_DOMAIN *tmp_dom;

  CHECK_CONNECT_ERROR ();

  if (!col_spec)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0);
      return -1;
    }

  *col_spec = NULL;

  class_mop = WS_CLASS_MOP (obj_mop);
  if (class_mop == NULL)
    {
      return -1;
    }

  *col_spec = db_alloc_query_format (num_attrs);
  if (*col_spec == NULL)
    {
      return -1;
    }

  for (i = 0, t = *col_spec, name = attrs; i < num_attrs && t && name && err == NO_ERROR; i++, t = t->next, name++)
    {
      t->db_type = sm_att_type_id (class_mop, *name);
      t->size = pt_find_size_from_dbtype (t->db_type);
      t->name = (char *) malloc (1 + strlen (*name));
      if (t->name)
    {
      strcpy ((char *) t->name, *name);
    }
      else
    {
      db_free_query_format (*col_spec);
      *col_spec = NULL;
      return -1;
    }

      t->attr_name = NULL;
      t->src_domain = NULL;
      err = sm_att_info (class_mop, *name, &attrid, &tmp_dom, &shared, 0);
      t->domain = sm_domain_copy (tmp_dom);
    }

  if (err != NO_ERROR)
    {
      db_free_query_format (*col_spec);
      *col_spec = NULL;
      return -1;
    }

  return 0;
}

/*
 * db_object_fetch() -  get the values of the named attributes of the given
 *                      object into a DB_QUERY_RESULT structure
 *   return:  int (non-zero in event of failure)
 *   obj_mop(in): a DB_OBJECT in the workspace
 *   num_attrs(in): number of names in attrs array
 *   attrs(in): an array of null-terminated character strings
 *   result(out): a new DB_QUERY_RESULT structure
 */

int
db_object_fetch (DB_OBJECT * obj_mop, int num_attrs, const char **attrs, DB_QUERY_RESULT ** result)
{
  MOP class_mop;
  DB_QUERY_RESULT *r;
  DB_QUERY_TYPE *t;
  int k;
  const char **name;
  int err = NO_ERROR;
  DB_VALUE **v;
  bool r_inited = false;

  CHECK_CONNECT_ERROR ();

  if (!result)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0);
      return -1;
    }

  *result = NULL;
  class_mop = sm_get_class (obj_mop);
  if (class_mop == NULL)
    {
      goto err_end;
    }

  r = *result = db_alloc_query_result (T_OBJFETCH, num_attrs);
  if (r == NULL)
    {
      goto err_end;
    }
  r_inited = true;

  db_init_query_result (r, T_OBJFETCH);
  r->type = T_OBJFETCH;
  r->col_cnt = num_attrs;
  r->oid_included = false;

  /* allocate and initialize type list */
  r->type_cnt = num_attrs;
  r->query_type = db_alloc_query_format (num_attrs);
  if (!r->query_type)
    {
      goto err_end;
    }

  r->res.o.crs_pos = C_BEFORE;
  for (k = 0, t = r->query_type, name = attrs, v = r->res.o.valptr_list;
       k < num_attrs && t && name && v && err == NO_ERROR; k++, t = t->next, name++, v++)
    {
      t->db_type = sm_att_type_id (class_mop, *name);
      t->size = pt_find_size_from_dbtype (t->db_type);
      t->name = (char *) malloc (1 + strlen (*name));
      if (t->name)
    {
      strcpy ((char *) t->name, *name);
    }
      else
    {
      goto err_end;
    }

      *v = pr_make_ext_value ();
      if (*v == NULL)
    {
      goto err_end;
    }

      err = obj_get (obj_mop, *name, *v);
    }

  if (err != NO_ERROR)
    {
      goto err_end;
    }

  err = 0;
  goto end;

err_end:
  if (r_inited)
    {
      db_free_query_result (r);
    }
  *result = NULL;
  err = -1;

end:
  return err;
}

/*
 * db_get_attribute () -
 *   return:
 *   obj(in):
 *   name(in):
 */
DB_ATTRIBUTE *
db_get_attribute_force (DB_OBJECT * obj, const char *name)
{
  SM_CLASS *class_;
  SM_ATTRIBUTE *att;

  att = NULL;
  if (au_fetch_class_force (obj, &class_, AU_FETCH_READ) == NO_ERROR)
    {
      att = classobj_find_attribute (class_, name, 0);
      if (att == NULL)
    {
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ATTRIBUTE, 1, name);
    }
    }

  return ((DB_ATTRIBUTE *) att);
}

/*
 * db_get_attributes_force () -
 *   return:
 *   obj(in):
 */
DB_ATTRIBUTE *
db_get_attributes_force (DB_OBJECT * obj)
{
  SM_CLASS *class_;
  SM_ATTRIBUTE *atts;

  atts = NULL;
  if (au_fetch_class_force ((DB_OBJECT *) obj, &class_, AU_FETCH_READ) == NO_ERROR)
    {
      atts = class_->ordered_attributes;
      if (atts == NULL)
    {
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_OBJ_NO_COMPONENTS, 0);
    }
    }
  return ((DB_ATTRIBUTE *) atts);
}


/*
 * pt_find_users_class () -
 *   return: class object if found
 *   parser(in):
 *   name(in/out):
 */
DB_OBJECT *
pt_find_users_class (PARSER_CONTEXT * parser, PT_NODE * name)
{
  DB_OBJECT *object;

  object = db_find_class (name->info.name.original);

  if (!object)
    {
      PT_ERRORmf (parser, name, MSGCAT_SET_PARSER_SEMANTIC, MSGCAT_SEMANTIC_CLASS_DOES_NOT_EXIST,
          name->info.name.original);
    }
  name->info.name.db_object = object;

#if defined (ENABLE_UNUSED_FUNCTION)
  /* The code below is no longer needed because it finds objects by unique_name that includes the owner's name. */
  pt_check_user_owns_class (parser, name);
#endif

  return object;
}

/*
 * pt_is_server_insert_with_generated_keys () - check if an insert statement
 *              has been executed on the server and it must
 *              return the autogenerated keys.
 * return:
 * session(in) :
 * statement(in) :
 */
int
pt_is_server_insert_with_generated_keys (PARSER_CONTEXT * parser, PT_NODE * statement)
{
  if (statement && statement->node_type == PT_INSERT && parser && parser->flag.return_generated_keys
      && statement->info.insert.server_allowed == SERVER_INSERT_IS_ALLOWED)
    {
      return 1;
    }

  return 0;
}