Skip to content

File unload_schema.c

File List > cubrid > src > executables > unload_schema.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.
 *
 */

/*
 * unload_schema.c: Utility that emits database schema definitions
 *                  in interpreter format
 */

#ident "$Id$"

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#if defined (WINDOWS)
#include <io.h>
#else
#include <unistd.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>

#include "db.h"
#include "extract_schema.hpp"
#include "authenticate.h"
#include "schema_manager.h"
#include "trigger_description.hpp"
#include "unload_object_file.h"
#include "object_primitive.h"
#include "parser.h"
#include "printer.hpp"
#include "message_catalog.h"
#include "utility.h"
#include "unloaddb.h"
#include "execute_schema.h"
#include "parser.h"
#include "set_object.h"
#include "jsp_cl.h"
#include "class_object.h"
#include "object_print.h"
#include "dbtype.h"
#include "tde.h"
#include "sp_catalog.hpp"

#define CLASS_NAME_MAX 80

#define SCHEMA_NAME   "_schema"
#define TRIGGER_NAME      "_trigger"
#define INDEX_NAME    "_indexes"
#define SCHEMA_INFO        "_schema_info"

#define CLASS_SUFFIX          "_class"
#define FK_SUFFIX             "_fk"
#define GRANT_SUFFIX          "_grant"
#define PK_SUFFIX             "_pk"
#define PROCEDURE_SUFFIX      "_procedure"
#define SERIAL_SUFFIX         "_serial"
#define SERVER_SUFFIX         "_server"
#define SYNONYM_SUFFIX        "_synonym"
#define USER_SUFFIX           "_user"
#define VCLASS_SUFFIX         "_vclass"
#define VCLASS_QUERY_SPEC_SUFFIX         "_vclass_query_spec"
#define UK_SUFFIX            "_uk"


#define EX_ERROR_CHECK(c,d,m)                                 \
  do {                                                        \
    if (c) {                                                  \
      if (db_error_code() != NO_ERROR) {                      \
        goto error;                                           \
      }                                                       \
      else {                                                  \
        if (!d) {  /* if it is not db error check only, */    \
          if (m != NULL) {                                    \
            fprintf(stderr, "%s: %s.\n\n",                    \
                            exec_name, m);                    \
          }                                                   \
          else {                                              \
            fprintf(stderr, "%s: Unknown database error occurs but may not be database error.\n\n", \
                            exec_name);                       \
          }                                                   \
          goto error;                                         \
        }                                                     \
      }                                                       \
    }                                                         \
  } while (0)

typedef enum
{
  INSTANCE_ATTRIBUTE,
  SHARED_ATTRIBUTE,
  CLASS_ATTRIBUTE
} ATTRIBUTE_QUALIFIER;

typedef enum
{
  INSTANCE_METHOD,
  CLASS_METHOD
} METHOD_QUALIFIER;

typedef enum
{
  INSTANCE_RESOLUTION,
  CLASS_RESOLUTION
} RESOLUTION_QUALIFIER;

typedef enum
{
  SERIAL_UNIQUE_NAME,
  SERIAL_NAME,
  SERIAL_OWNER_NAME,
  SERIAL_CURRENT_VAL,
  SERIAL_INCREMENT_VAL,
  SERIAL_MAX_VAL,
  SERIAL_MIN_VAL,
  SERIAL_CYCLIC,
  SERIAL_STARTED,
  SERIAL_CACHED_NUM,
  SERIAL_COMMENT,

  SERIAL_VALUE_INDEX_MAX
} SERIAL_VALUE_INDEX;

typedef enum
{
  ALTER_SERIAL_UNIQUE_NAME,
  ALTER_SERIAL_NAME,
  ALTER_SERIAL_OWNER_NAME,
  ALTER_SERIAL_CURRENT_VAL,
  ALTER_SERIAL_INCREMENT_VAL,
  ALTER_SERIAL_MAX_VAL,
  ALTER_SERIAL_MIN_VAL,
  ALTER_SERIAL_CYCLIC,
  ALTER_SERIAL_STARTED,
  ALTER_SERIAL_CACHED_NUM,
  ALTER_SERIAL_CLASS_NAME,
  ALTER_SERIAL_COMMENT,

  ALTER_SERIAL_VALUE_INDEX_MAX
} ALTER_SERIAL_VALUE_INDEX;

typedef enum
{
  SYNONYM_UNIQUE_NAME,
  SYNONYM_OWNER,
  SYNONYM_IS_PUBLIC,
  SYNONYM_TARGET_NAME,
  SYNONYM_TARGET_OWNER_NAME,
  SYNONYM_COMMENT,

  SYNONYM_VALUE_INDEX_MAX
} SYNONYM_VALUE_INDEX;

typedef enum
{
  EXTRACT_CLASS_ALL,
  EXTRACT_CLASS,
  EXTRACT_VCLASS
} EXTRACT_CLASS_TYPE;

static void filter_system_classes (DB_OBJLIST ** class_list);
static void filter_unrequired_classes (DB_OBJLIST ** class_list);
static int is_dependent_class (DB_OBJECT * class_, DB_OBJLIST * unordered, DB_OBJLIST * ordered);
static int check_domain_dependencies (DB_DOMAIN * domain, DB_OBJECT * this_class, DB_OBJLIST * unordered,
                      DB_OBJLIST * ordered);
static int has_dependencies (DB_OBJECT * class_, DB_OBJLIST * unordered, DB_OBJLIST * ordered, int conservative);
static int order_classes (DB_OBJLIST ** class_list, DB_OBJLIST ** order_list, int conservative);
static void emit_cycle_warning (print_output & output_ctx);
static void force_one_class (print_output & output_ctx, DB_OBJLIST ** class_list, DB_OBJLIST ** order_list);
static DB_OBJLIST *get_ordered_classes (print_output & output_ctx, MOP * class_table);
static int export_serial (extract_context & ctxt, print_output & output_ctx);
static int emit_class_alter_serial (extract_context & ctxt, print_output & output_ctx);
static int emit_indexes (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes, int has_indexes,
             DB_OBJLIST * vclass_list_has_using_index);

static void emit_schema (extract_context & ctxt, print_output & output_ctx, EXTRACT_CLASS_TYPE extract_class);
static void emit_class_query_spec (extract_context & ctxt, print_output & output_ctx, EXTRACT_CLASS_TYPE extract_class);
static bool has_vclass_domains (DB_OBJECT * vclass);
static DB_OBJLIST *emit_query_specs (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes);
static int emit_query_specs_has_using_index (extract_context & ctxt, print_output & output_ctx,
                         DB_OBJLIST * vclass_list_has_using_index);
static bool emit_superclasses (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_,
                   const char *class_type);
static bool emit_resolutions (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_,
                  const char *class_type);
static void emit_resolution_def (extract_context & ctxt, print_output & output_ctx, DB_RESOLUTION * resolution,
                 RESOLUTION_QUALIFIER qualifier);
static bool emit_instance_attributes (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_,
                      const char *class_type, int *has_indexes, EMIT_STORAGE_ORDER storage_order);
static bool emit_class_attributes (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_,
                   const char *class_type);
static bool emit_all_attributes (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_,
                 const char *class_type, int *has_indexes, EMIT_STORAGE_ORDER storage_order);
static bool emit_class_meta (print_output & output_ctx, DB_OBJECT * table);
static void emit_method_files (print_output & output_ctx, DB_OBJECT * class_);
static bool emit_methods (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_,
              const char *class_type);
static int ex_contains_object_reference (DB_VALUE * value);
static void emit_attribute_def (extract_context & ctxt, print_output & output_ctx, DB_ATTRIBUTE * attribute,
                ATTRIBUTE_QUALIFIER qualifier);
static void emit_unique_def (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_,
                 const char *class_type);
static void emit_primary_key_def (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_,
                  const char *class_type);
static void emit_primary_and_unique_def (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_,
                     const char *class_type);
static void emit_reverse_unique_def (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_);
static int emit_index_def (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_);
static void emit_domain_def (extract_context & ctxt, print_output & output_ctx, DB_DOMAIN * domains);
static int emit_autoincrement_def (print_output & output_ctx, DB_ATTRIBUTE * attribute);
static void emit_method_def (extract_context & ctxt, print_output & output_ctx, DB_METHOD * method,
                 METHOD_QUALIFIER qualifier);
static void emit_methfile_def (print_output & output_ctx, DB_METHFILE * methfile);
static void emit_partition_parts (print_output & output_ctx, SM_PARTITION * partition_info, int partcnt);
static void emit_partition_info (extract_context & ctxt, print_output & output_ctx, MOP clsobj);

static int emit_stored_procedure_pre (extract_context & ctxt, print_output & output_ctx);
static int emit_stored_procedure_post (extract_context & ctxt, print_output & output_ctx);
static int emit_stored_procedure_args (print_output & output_ctx, int arg_cnt, DB_SET * arg_set);
static int emit_stored_procedure_code (extract_context & ctxt, print_output & output_ctx, const char *code_name,
                       const char *owner_name, DB_VALUE * comment);

static int emit_foreign_key (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes);
static int emit_grant (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes);
static void emit_unique_key (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes);
static int create_filename (const char *output_dirname, const char *output_prefix, const char *suffix,
                char *output_filename_p, const size_t filename_size);
static int create_filename (const char *output_dirname, const char *output_prefix, const char *infix,
                const char *suffix, char *output_filename_p, const size_t filename_size);
static int create_filefullpath (const char *output_dirname, const char *output_filename,
                char *output_filename_p, const size_t filename_size);
static int export_server (extract_context & ctxt, print_output & output_ctx);
static int extract_all_schema_file (extract_context & ctxt, const char *output_filename);
static int extract_split_schema_files (extract_context & ctxt);
static int extract_schema (extract_context & ctxt, print_output & schema_output_ctx);
static int extract_user (extract_context & ctxt);
static int extract_serial (extract_context & ctxt);
static int extract_synonym (extract_context & ctxt);
static int extract_procedure (extract_context & ctxt);
static int extract_server (extract_context & ctxt);
static int extract_class (extract_context & ctxt);
static int extract_vclass (extract_context & ctxt);
static int extract_vclass_query_spec (extract_context & ctxt);
static int extract_pk (extract_context & ctxt);
static int extract_fk (extract_context & ctxt);
static int extract_uk (extract_context & ctxt);
static int extract_grant (extract_context & ctxt);
static int get_classes (extract_context & ctxt, print_output & output_ctx);
static void filter_user_classes (DB_OBJLIST ** class_list, const char *user_name);
static void emit_primary_key (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes);
static int create_schema_info (extract_context & ctxt);
static int create_filename_schema_info (const char *output_dirname, const char *output_prefix, char *output_filename_p,
                    const size_t filename_size);
static void str_tolower (char *str);

static PARSER_VARCHAR *do_recreate_where_clause_or_function_attr (PARSER_CONTEXT ** parser, const char *class_name,
                                  DB_CONSTRAINT * constraint, bool where_clause);

/*
 * CLASS DEPENDENCY ORDERING
 *
 * This section contains code to calculate an ordered list of classes
 * based on subclass dependencies.  The class definitions must be
 * output in order so that they make sense.
 *
 * Algorithm for dependency checking is pretty dumb.  Speed isn't particularly
 * important however since the number of classes is normally well under 1000.
 *
 * Uses workspace ml_ calls for object list maintenance !
 *
 * THOUGHT:  Now that classes are always defined empty and altered later
 * to add attributes & super classes, I don't believe we can get into
 * a situation where the order of definition is important?  Think
 * about this.  If it is the case then we can skip the dependency ordering
 * step.
 *
 */


/*
 * filter_system_classes - Goes through a class list removing system classes.
 *    return: void
 *    class_list(in): class list to filter
 */
static void
filter_system_classes (DB_OBJLIST ** class_list)
{
  DB_OBJLIST *cl, *prev, *next;

  for (cl = *class_list, prev = NULL, next = NULL; cl != NULL; cl = next)
    {
      next = cl->next;
      if (!db_is_system_class (cl->op))
    {
      prev = cl;
    }
      else
    {
      if (prev == NULL)
        {
          *class_list = next;
        }
      else
        {
          prev->next = next;
        }
      /*
       * class_list links were allocated via ml_ext_alloc_link, so we must
       * free them via ml_ext_free_link.  Otherwise, we can crash.
       */
      ml_ext_free_link (cl);
    }
    }
}

/*
 * filter_unrequired_classes - remove unrequired class from list
 *    return: void
 *    class_list(out): class list
 */
static void
filter_unrequired_classes (DB_OBJLIST ** class_list)
{
  DB_OBJLIST *cl, *prev, *next;

  for (cl = *class_list, prev = NULL, next = NULL; cl != NULL; cl = next)
    {
      next = cl->next;
      if (is_req_class (cl->op))
    {
      prev = cl;
    }
      else
    {
      if (prev == NULL)
        {
          *class_list = next;
        }
      else
        {
          prev->next = next;
        }
      ml_ext_free_link (cl);
    }
    }
}


/*
 * is_dependent_class - determines if a particular class results in a
 * dependency.
 *    return: non-zero if a dependency exists
 *    class(in): class to ponder
 *    unordered(in): remaining unordered class list
 *    ordered(in): ordered class list
 * Note:
 *    This is determined by seeint if the class is NOT already on the
 *    ordered list AND the class IS on the unordered list.
 *    If the class is not on the unordered list, then we have to
 *    assume that the user is responsible for defining it at the
 *    appropriate time.  This will also handle the case
 *    where we have dependencies on system defined classes since these
 *    won't be in the original class list.
 */
static int
is_dependent_class (DB_OBJECT * class_, DB_OBJLIST * unordered, DB_OBJLIST * ordered)
{
  return (!ml_find (ordered, class_) && ml_find (unordered, class_));
}


/*
 * check_domain_dependencies - checks for dependencies on the classes that are
 * found in a domain specification.
 *    return: non-zero if there are dependencies
 *    domain(in): domain to ponder
 *    this_class(in): class to ckeck
 *    unordered(in): remaining unordered class list
 *    ordered(in): ordered class list
 */
static int
check_domain_dependencies (DB_DOMAIN * domain, DB_OBJECT * this_class, DB_OBJLIST * unordered, DB_OBJLIST * ordered)
{
  DB_DOMAIN *d, *setdomain;
  DB_OBJECT *class_;
  int dependencies;

  dependencies = 0;
  for (d = domain; d != NULL && !dependencies; d = db_domain_next (d))
    {
      setdomain = db_domain_set (d);
      if (setdomain != NULL)
    {
      dependencies = check_domain_dependencies (setdomain, this_class, unordered, ordered);
    }
      else
    {
      class_ = db_domain_class (d);
      if (class_ != NULL && class_ != this_class)
        {
          dependencies = is_dependent_class (class_, unordered, ordered);
        }
    }
    }
  return (dependencies);
}

/*
 * has_dependencies - checks to see if a class has any remaining dependencnes
 *    return: non zero if there are dependencies remaining
 *    mop(in): class to ponder
 *    unordered(in): remaining unordered list
 *    ordered(in): ordered list being built
 *    conservative(in): if set detect a depencency on any class that is used
 *                      as the domain of an attribute in this class.
 */
static int
has_dependencies (DB_OBJECT * mop, DB_OBJLIST * unordered, DB_OBJLIST * ordered, int conservative)
{
  DB_OBJLIST *supers, *su;
  DB_ATTRIBUTE *att;
  DB_DOMAIN *domain;
  int dependencies;

  dependencies = 0;

  supers = db_get_superclasses (mop);
  for (su = supers; su != NULL && !dependencies; su = su->next)
    {
      dependencies = is_dependent_class (su->op, unordered, ordered);
    }

  /*
   * if we're doing a conservative dependency check, look at the domains
   * of each attribute.
   */
  if (!dependencies && conservative)
    {
      for (att = db_get_attributes (mop); att != NULL && !dependencies; att = db_attribute_next (att))
    {
      domain = db_attribute_domain (att);
      dependencies = check_domain_dependencies (domain, mop, unordered, ordered);
    }
    }

  return (dependencies);
}


/*
 * order_classes - transfers class list to ordered list if they have no
 * dependencies
 *    return: number of classes transfered
 *    class_list(in): remaining unordered list
 *    order_list(out): order list we're building
 *    conservative(in): if set detect a depencency on any class that is used
 *                      as the domain of an attribute in this class.
 * Note:
 *    This makes a pass on the unordered class list transfering
 *    classes to the ordered list if they have no dependencies.
 *    We may make many passes over this list but there will be at least
 *    one class moved on each pass.  If a pass is made and no classes
 *    can be moved, in indicates a circular depenency that cannot be
 *    handled by this algorithm.  For normal classes, this would
 *    be an error condition since it indicates a cycle in the class
 *    hierarcy which isn't allowed.
 *    For proxy classes, it indicates circular references between the
 *    attributes that make up the OBJECT_ID which also isn't allowed.
 *    It can also indicate a bug in the dependency algorithm.
 */
static int
order_classes (DB_OBJLIST ** class_list, DB_OBJLIST ** order_list, int conservative)
{
  DB_OBJLIST *cl, *o, *next, *prev, *last;
  int add_count;

  add_count = 0;

  for (cl = *class_list, prev = NULL, next = NULL; cl != NULL; cl = next)
    {
      next = cl->next;

      if (has_dependencies (cl->op, *class_list, *order_list, conservative))
    {
      prev = cl;
    }
      else
    {
      /* no dependencies, move it to the other list */
      if (prev == NULL)
        {
          *class_list = next;
        }
      else
        {
          prev->next = next;
        }

      /* append it on the order list */
      cl->next = NULL;
      for (o = *order_list, last = NULL; o != NULL; o = o->next)
        {
          last = o;
        }

      if (last == NULL)
        {
          *order_list = cl;
        }
      else
        {
          last->next = cl;
        }

      add_count++;
    }
    }

  return (add_count);
}


/*
 * emit_cycle_warning - emit cyclic dependency warning
 *    return: void
 * Note:
 *    Dump a warning message enclosed in a comment to the output file
 *    indicating that cycles were encountered in the schema that either
 *    represent error conditions or schema we're not prepared
 *    to handle yet.
 */
static void
emit_cycle_warning (print_output & output_ctx)
{
  output_ctx ("/* Error calculating class dependency order.\n");
  output_ctx ("   This indicates one of the following:\n");
  output_ctx ("     - bug in dependency algorithm\n");
  output_ctx ("     - cycle in class hierarchy\n");
  output_ctx ("     - cycle in proxy attribute used as object ids\n");
  output_ctx ("   The next class may not be in the proper definition order.\n");
  output_ctx ("   Hand editing of the schema may be required before loading.\n");
  output_ctx ("   */\n");
}


/*
 * force_one_class - pick the top class off the 'class_list' and append to
 * the 'order_list'
 *    return: void
 *    class_list(out): remaining unordered classes
 *    order_list(out): ordered class list
 * Note:
 *    This is called when a depencency cycle is detected that we can't
 *    figure out.  So we at least get the full schema dumped to the
 *    output file, pick the top class off the list and hopefully this
 *    will break the cycle.
 *    The user will then have to go in and hand edit the output file
 *    so that it can be loaded.
 */
static void
force_one_class (print_output & output_ctx, DB_OBJLIST ** class_list, DB_OBJLIST ** order_list)
{
  DB_OBJLIST *cl, *o, *last;

  emit_cycle_warning (output_ctx);

  cl = *class_list;
  *class_list = cl->next;

  cl->next = NULL;
  for (o = *order_list, last = NULL; o != NULL; o = o->next)
    {
      last = o;
    }

  if (last == NULL)
    {
      *order_list = cl;
    }
  else
    {
      last->next = cl;
    }
}


/*
 * get_ordered_classes - takes a list of classes to dump and returns a list
 * of classes ordered according to their definition dependencies.
 *    return: ordered class list
 *    class_table(in): classes to dump
 */
static DB_OBJLIST *
get_ordered_classes (print_output & output_ctx, MOP * class_table)
{
  DB_OBJLIST *classes, *ordered;
  int count, i;

  ordered = NULL;

  /*
   * if class_table is passed, use it to initialize the list, otherwise
   * get it from the API.
   */
  if (class_table == NULL)
    {
      classes = sm_fetch_all_classes (1, DB_FETCH_READ);
      if (classes == NULL)
    {
      return NULL;
    }

      filter_system_classes (&classes);
      if (classes == NULL)
    {           /* no user class */
      return NULL;
    }

      if (input_filename && required_class_only)
    {
      filter_unrequired_classes (&classes);
    }
    }
  else
    {
      classes = NULL;
      for (i = 0; class_table[i] != NULL; i++)
    {
      if (ml_ext_add (&classes, class_table[i], NULL))
        {
          /* memory error */
          ml_ext_free (classes);
          return NULL;
        }
    }
    }

  while (classes != NULL)
    {

      count = order_classes (&classes, &ordered, 1);
      if (count == 0)
    {
      /*
       * didn't find any using the conservative ordering, try the
       * more relaxed one.
       */
      count = order_classes (&classes, &ordered, 0);
      if (count == 0)
        {
          force_one_class (output_ctx, &classes, &ordered);
        }
    }
    }
  return (ordered);
}

/*
 * export_serial - export _db_serial
 *    return: NO_ERROR if successful, error code otherwise
 *    output_ctx(in/out): output context
 */
static int
export_serial (extract_context & ctxt, print_output & output_ctx)
{
  int error = NO_ERROR;
  int i;
  DB_QUERY_RESULT *query_result;
  DB_QUERY_ERROR query_error;
  DB_VALUE values[SERIAL_VALUE_INDEX_MAX], diff_value, answer_value;
  char str_buf[NUMERIC_MAX_STRING_SIZE] = { '\0' };
  char *uppercase_user = NULL;
  size_t uppercase_user_size = 0;
  size_t query_size = 0;
  char *query = NULL;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *serial_name = NULL;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };
  int save;

  /*
   * You must check SERIAL_VALUE_INDEX enum defined on the top of this file
   * when changing the following query. Notice the order of the result.
   */
  const char *query_all =
    "select [unique_name], [name], [owner].[name], " "[current_val], " "[increment_val], " "[max_val], " "[min_val], "
    "[cyclic], " "[started], " "[cached_num], " "[comment] "
    "from [_db_serial] where [class_name] is null and [attr_name] is null";

  const char *query_user =
    "select [unique_name], [name], [owner].[name], " "[current_val], " "[increment_val], " "[max_val], " "[min_val], "
    "[cyclic], " "[started], " "[cached_num], " "[comment] "
    "from [_db_serial] where [class_name] is null and [attr_name] is null and owner.name='%s'";

  if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
    {
      uppercase_user_size = intl_identifier_upper_string_size (ctxt.login_user);
      uppercase_user = (char *) malloc (uppercase_user_size + 1);
      if (uppercase_user == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, uppercase_user_size);
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }

      intl_identifier_upper (ctxt.login_user, uppercase_user);

      query_size = strlen (query_user) + strlen (uppercase_user) + 1;
      query = (char *) malloc (query_size);
      if (query_user == NULL)
    {
      if (uppercase_user != NULL)
        {
          free_and_init (uppercase_user);
        }

      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, query_size);
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }

      sprintf (query, query_user, uppercase_user);
    }

  db_make_null (&diff_value);
  db_make_null (&answer_value);

  AU_DISABLE (save);

  error = db_compile_and_execute_local (((query == NULL) ? query_all : query), &query_result, &query_error);
  if (error < 0)
    {
      goto err;
    }

  if (db_query_first_tuple (query_result) == DB_CURSOR_SUCCESS)
    {
      do
    {
      for (i = 0; i < SERIAL_VALUE_INDEX_MAX; i++)
        {
          error = db_query_get_tuple_value (query_result, i, &values[i]);
          if (error != NO_ERROR)
        {
          goto err;
        }

          /* Validation of the result value */
          switch (i)
        {
        case SERIAL_OWNER_NAME:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_STRING)
              {
            db_make_string (&values[i], "PUBLIC");
              }
          }
          break;

        case SERIAL_UNIQUE_NAME:
        case SERIAL_NAME:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_STRING)
              {
            er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
            error = ER_INVALID_SERIAL_VALUE;
            goto err;
              }
          }
          break;

        case SERIAL_CURRENT_VAL:
        case SERIAL_INCREMENT_VAL:
        case SERIAL_MAX_VAL:
        case SERIAL_MIN_VAL:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_NUMERIC)
              {
            er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
            error = ER_INVALID_SERIAL_VALUE;
            goto err;
              }
          }
          break;

        case SERIAL_CYCLIC:
        case SERIAL_STARTED:
        case SERIAL_CACHED_NUM:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_INTEGER)
              {
            er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
            error = ER_INVALID_SERIAL_VALUE;
            goto err;
              }
          }
          break;

        case SERIAL_COMMENT:
          {
            if (DB_IS_NULL (&values[i]) == false && DB_VALUE_TYPE (&values[i]) != DB_TYPE_STRING)
              {
            er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
            error = ER_INVALID_SERIAL_VALUE;
            goto err;
              }
          }
          break;

        default:
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
          error = ER_INVALID_SERIAL_VALUE;
          goto err;
        }
        }

      SPLIT_USER_SPECIFIED_NAME (db_get_string (&values[SERIAL_UNIQUE_NAME]), owner_name, serial_name);
      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

      output_ctx ("\nCREATE SERIAL %s%s%s%s\n", output_owner,
              PRINT_IDENTIFIER (db_get_string (&values[SERIAL_NAME])));
      output_ctx ("\t START WITH %s\n", numeric_db_value_print (&values[SERIAL_CURRENT_VAL], str_buf));
      output_ctx ("\t INCREMENT BY %s\n", numeric_db_value_print (&values[SERIAL_INCREMENT_VAL], str_buf));
      output_ctx ("\t MINVALUE %s\n", numeric_db_value_print (&values[SERIAL_MIN_VAL], str_buf));
      output_ctx ("\t MAXVALUE %s\n", numeric_db_value_print (&values[SERIAL_MAX_VAL], str_buf));
      output_ctx ("\t %sCYCLE\n", (db_get_int (&values[SERIAL_CYCLIC]) == 0 ? "no" : ""));
      if (db_get_int (&values[SERIAL_CACHED_NUM]) <= 1)
        {
          output_ctx ("\t NOCACHE\n");
        }
      else
        {
          output_ctx ("\t CACHE %d\n", db_get_int (&values[SERIAL_CACHED_NUM]));
        }
      if (DB_IS_NULL (&values[SERIAL_COMMENT]) == false)
        {
          output_ctx ("\t COMMENT ");
          desc_value_print (output_ctx, &values[SERIAL_COMMENT]);
        }
      output_ctx (";\n");

      if (db_get_int (&values[SERIAL_STARTED]) == 1)
        {
          output_ctx ("SELECT %s%s%s%s.NEXT_VALUE;\n", output_owner,
              PRINT_IDENTIFIER (db_get_string (&values[SERIAL_NAME])));
        }

      db_value_clear (&diff_value);
      db_value_clear (&answer_value);
      for (i = 0; i < SERIAL_VALUE_INDEX_MAX; i++)
        {
          db_value_clear (&values[i]);
        }
    }
      while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS);
    }

err:
  db_query_end (query_result);

  if (uppercase_user != NULL)
    {
      free_and_init (uppercase_user);
    }

  AU_ENABLE (save);
  return error;
}

static int
emit_class_alter_serial (extract_context & ctxt, print_output & output_ctx)
{
  int error = NO_ERROR;
  int i;
  DB_QUERY_RESULT *query_result;
  DB_QUERY_ERROR query_error;
  DB_VALUE values[ALTER_SERIAL_VALUE_INDEX_MAX], diff_value, answer_value;
  char str_buf[NUMERIC_MAX_STRING_SIZE] = { '\0' };
  char *uppercase_user = NULL;
  size_t uppercase_user_size = 0;
  size_t query_size = 0;
  char *query = NULL;

  DB_OBJLIST *cl = NULL;
  const char *schema_name = NULL;
  char temp_schema[DB_MAX_CLASS_LENGTH] = { '\0' };
  const char *serial_owner_name = NULL;
  const char *serial_class_name = NULL;
  int save;

  /*
   * You must check SERIAL_VALUE_INDEX enum defined on the top of this file
   * when changing the following query. Notice the order of the result.
   */
  const char *query_all =
    "select [unique_name], [name], [owner].[name], [current_val], [increment_val], [max_val], [min_val], "
    "[cyclic], [started], [cached_num], [class_name], [comment] "
    "from [_db_serial] where [class_name] is not null and [attr_name] is not null";

  const char *query_user =
    "select [unique_name], [name], [owner].[name], [current_val], [increment_val], [max_val], [min_val], "
    "[cyclic], [started], [cached_num], [class_name], [comment] "
    "from [_db_serial] where [class_name] is not null and [attr_name] is not null and owner.name='%s'";

  if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
    {
      uppercase_user_size = intl_identifier_upper_string_size (ctxt.login_user);
      uppercase_user = (char *) malloc (uppercase_user_size + 1);
      if (uppercase_user == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, uppercase_user_size);
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }

      intl_identifier_upper (ctxt.login_user, uppercase_user);

      query_size = strlen (query_user) + strlen (uppercase_user) + 1;
      query = (char *) malloc (query_size);
      if (query_user == NULL)
    {
      if (uppercase_user != NULL)
        {
          free_and_init (uppercase_user);
        }

      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, query_size);
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }

      sprintf (query, query_user, uppercase_user);
    }

  db_make_null (&diff_value);
  db_make_null (&answer_value);

  AU_DISABLE (save);

  error = db_compile_and_execute_local (((query == NULL) ? query_all : query), &query_result, &query_error);
  if (error < 0)
    {
      goto err;
    }

  if (db_query_first_tuple (query_result) == DB_CURSOR_SUCCESS)
    {
      do
    {
      for (i = 0; i < ALTER_SERIAL_VALUE_INDEX_MAX; i++)
        {
          error = db_query_get_tuple_value (query_result, i, &values[i]);
          if (error != NO_ERROR)
        {
          goto err;
        }

          /* Validation of the result value */
          switch (i)
        {
        case ALTER_SERIAL_OWNER_NAME:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_STRING)
              {
            db_make_string (&values[i], "PUBLIC");
              }
          }
          break;

        case ALTER_SERIAL_UNIQUE_NAME:
        case ALTER_SERIAL_NAME:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_STRING)
              {
            er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
            error = ER_INVALID_SERIAL_VALUE;
            goto err;
              }
          }
          break;

        case ALTER_SERIAL_CURRENT_VAL:
        case ALTER_SERIAL_INCREMENT_VAL:
        case ALTER_SERIAL_MAX_VAL:
        case ALTER_SERIAL_MIN_VAL:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_NUMERIC)
              {
            er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
            error = ER_INVALID_SERIAL_VALUE;
            goto err;
              }
          }
          break;

        case ALTER_SERIAL_CYCLIC:
        case ALTER_SERIAL_STARTED:
        case ALTER_SERIAL_CACHED_NUM:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_INTEGER)
              {
            er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
            error = ER_INVALID_SERIAL_VALUE;
            goto err;
              }
          }
          break;

        case ALTER_SERIAL_CLASS_NAME:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_STRING)
              {
            er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
            error = ER_INVALID_SERIAL_VALUE;
            goto err;
              }
          }
          break;

        case ALTER_SERIAL_COMMENT:
          {
            if (DB_IS_NULL (&values[i]) == false && DB_VALUE_TYPE (&values[i]) != DB_TYPE_STRING)
              {
            er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
            error = ER_INVALID_SERIAL_VALUE;
            goto err;
              }
          }
          break;

        default:
          er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_INVALID_SERIAL_VALUE, 0);
          error = ER_INVALID_SERIAL_VALUE;
          goto err;
        }
        }

      if (required_class_only == true)
        {
          int same_schema = 0;
          for (cl = ctxt.classes; cl != NULL; cl = cl->next)
        {
          schema_name = db_get_class_name (cl->op);

          serial_owner_name = db_get_string (&values[ALTER_SERIAL_OWNER_NAME]);
          serial_class_name = db_get_string (&values[ALTER_SERIAL_CLASS_NAME]);

          str_tolower ((char *) serial_owner_name);
          snprintf (temp_schema, DB_MAX_CLASS_LENGTH, "%s%s%s", (serial_owner_name), ".", serial_class_name);

          if (strcmp (temp_schema, schema_name) == 0)
            {
              same_schema++;
            }
        }

          if (same_schema == 0)
        {
          continue;
        }
        }

      if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
        {
          output_ctx ("\nALTER SERIAL %s%s%s START WITH %s;\n",
              PRINT_IDENTIFIER (db_get_string (&values[ALTER_SERIAL_NAME])),
              numeric_db_value_print (&values[ALTER_SERIAL_CURRENT_VAL], str_buf));

          if (db_get_int (&values[ALTER_SERIAL_STARTED]) == 1)
        {

          output_ctx ("SELECT %s%s%s.NEXT_VALUE;\n ",
                  PRINT_IDENTIFIER (db_get_string (&values[ALTER_SERIAL_NAME])));
        }
        }
      else
        {
          output_ctx ("\nALTER SERIAL %s%s%s START WITH %s;\n",
              PRINT_IDENTIFIER (db_get_string (&values[ALTER_SERIAL_UNIQUE_NAME])),
              numeric_db_value_print (&values[ALTER_SERIAL_CURRENT_VAL], str_buf));

          if (db_get_int (&values[ALTER_SERIAL_STARTED]) == 1)
        {
          output_ctx ("SELECT %s%s%s.NEXT_VALUE;\n ",
                  PRINT_IDENTIFIER (db_get_string (&values[ALTER_SERIAL_UNIQUE_NAME])));
        }
        }

      db_value_clear (&diff_value);
      db_value_clear (&answer_value);
      for (i = 0; i < ALTER_SERIAL_VALUE_INDEX_MAX; i++)
        {
          db_value_clear (&values[i]);
        }
    }
      while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS);
    }

err:
  db_query_end (query_result);

  if (uppercase_user != NULL)
    {
      free_and_init (uppercase_user);
    }

  AU_ENABLE (save);
  return error;
}


/*
 * export_synonym - export _db_synonym
 *    return: NO_ERROR if successful, error code otherwise
 *    output_ctx(in/out): output context
 */
static int
export_synonym (extract_context & ctxt, print_output & output_ctx)
{
  DB_QUERY_RESULT *query_result;
  DB_QUERY_ERROR query_error;
  DB_VALUE values[SYNONYM_VALUE_INDEX_MAX];
  char *synonym_name = NULL;
  DB_OBJECT *synonym_owner = NULL;
  const char *synonym_unique_name = NULL;
  char synonym_owner_name[DB_MAX_IDENTIFIER_LENGTH];
  synonym_owner_name[0] = '\0';
  int is_public = 0;
  const char *target_name = NULL;
  const char *target_owner_name = NULL;
  const char *comment = NULL;
  bool is_dba_group_member = false;
  int i = 0;
  int save = 0;
  int error = NO_ERROR;
  char *uppercase_user = NULL;
  size_t uppercase_user_size = 0;
  size_t query_size = 0;
  char *query = NULL;
  char synonym_output_owner[DB_MAX_USER_LENGTH + 4];
  synonym_output_owner[0] = '\0';
  DB_OBJLIST *cl = NULL;
  const char *name = NULL;
  char temp_schema[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };

  // *INDENT-OFF*
  const char *query_all = "SELECT [unique_name], "
                             "[owner], "
                 "[is_public], "
                 "[target_name], "
                 "DECODE((SELECT 1 from [_db_class] WHERE [class_name] = [target_name] and [is_system_class] = 1), NULL, LOWER([target_owner].[name]), '') target_owner, "
                 "[comment] "
              "FROM [_db_synonym]";

  const char *query_user = "SELECT [unique_name], "
                             "[owner], "
                 "[is_public], "
                 "[target_name], "
                 "DECODE((SELECT 1 from [_db_class] WHERE [class_name] = [target_name] and [is_system_class] = 1), NULL, LOWER([target_owner].[name]), '') target_owner, "
                 "[comment] "
               "FROM [_db_synonym]";
  // *INDENT-ON*

  query_error.err_lineno = 0;
  query_error.err_posno = 0;

  // TODO: it should be moved to before db_compile_and_execute_local(). It can be returned without AU_ENABLE().
  AU_DISABLE (save);

  if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
    {
      uppercase_user_size = intl_identifier_upper_string_size (ctxt.login_user);
      uppercase_user = (char *) malloc (uppercase_user_size + 1);
      if (uppercase_user == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, uppercase_user_size);
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }

      intl_identifier_upper (ctxt.login_user, uppercase_user);

      query_size = strlen (query_user) + strlen (uppercase_user) + 1;
      query = (char *) malloc (query_size);
      if (query_user == NULL)
    {
      if (uppercase_user != NULL)
        {
          free_and_init (uppercase_user);
        }

      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, query_size);
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }

      sprintf (query, query_user, uppercase_user);
    }

  error = db_compile_and_execute_local (((query == NULL) ? query_all : query), &query_result, &query_error);
  if (error < 0)
    {
      ASSERT_ERROR ();
      goto end;
    }

  is_dba_group_member = au_is_dba_group_member (Au_user);

  if (db_query_first_tuple (query_result) == DB_CURSOR_SUCCESS)
    {
      do
    {
      for (i = 0; i < SYNONYM_VALUE_INDEX_MAX; i++)
        {
          error = db_query_get_tuple_value (query_result, i, &values[i]);
          if (error != NO_ERROR)
        {
          ASSERT_ERROR ();
          goto end;
        }

          /* Validation of the result value */
          switch (i)
        {
        case SYNONYM_UNIQUE_NAME:
        case SYNONYM_TARGET_NAME:
        case SYNONYM_TARGET_OWNER_NAME:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_STRING)
              {
            ERROR_SET_ERROR (error, ER_SYNONYM_INVALID_VALUE);
            goto end;
              }
          }
          break;

        case SYNONYM_OWNER:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_OBJECT)
              {
            ERROR_SET_ERROR (error, ER_SYNONYM_INVALID_VALUE);
            goto end;
              }
          }
          break;

        case SYNONYM_IS_PUBLIC:
          {
            if (DB_IS_NULL (&values[i]) || DB_VALUE_TYPE (&values[i]) != DB_TYPE_INTEGER)
              {
            ERROR_SET_ERROR (error, ER_SYNONYM_INVALID_VALUE);
            goto end;
              }
          }
          break;

        case SYNONYM_COMMENT:
          {
            if (DB_IS_NULL (&values[i]) == false && DB_VALUE_TYPE (&values[i]) != DB_TYPE_STRING)
              {
            ERROR_SET_ERROR (error, ER_SYNONYM_INVALID_VALUE);
            goto end;
              }
          }
          break;

        default:
          ERROR_SET_ERROR (error, ER_SYNONYM_INVALID_VALUE);
          goto end;
        }
        }

      synonym_unique_name = db_get_string (&values[SYNONYM_UNIQUE_NAME]);
      synonym_owner = db_get_object (&values[SYNONYM_OWNER]);
      is_public = db_get_int (&values[SYNONYM_IS_PUBLIC]);
      target_name = db_get_string (&values[SYNONYM_TARGET_NAME]);
      target_owner_name = db_get_string (&values[SYNONYM_TARGET_OWNER_NAME]);

      if (!is_dba_group_member && !ws_is_same_object (Au_user, synonym_owner))
        {
          continue;
        }

      if (required_class_only == true)
        {
          int same_schema = 0;
          for (cl = ctxt.classes; cl != NULL; cl = cl->next)
        {
          name = db_get_class_name (cl->op);

          snprintf (temp_schema, DB_MAX_IDENTIFIER_LENGTH, "%s%s%s", (target_owner_name), ".", target_name);

          if (strcmp (temp_schema, name) == 0)
            {
              same_schema++;
            }
        }

          if (same_schema == 0)
        {
          continue;
        }
        }

      output_ctx ("\n");

      if (is_public == 1)
        {
          output_ctx ("CREATE PUBLIC");
        }
      else
        {
          output_ctx ("CREATE PRIVATE");
        }

      SPLIT_USER_SPECIFIED_NAME (synonym_unique_name, synonym_owner_name, synonym_name);
      PRINT_OWNER_NAME (synonym_owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), synonym_output_owner,
                sizeof (synonym_owner_name));

      output_ctx (" SYNONYM %s%s%s%s FOR ", synonym_output_owner, PRINT_IDENTIFIER (synonym_name));

      if (target_owner_name[0] == 0x00)
        {
          output_ctx ("%s%s%s", PRINT_IDENTIFIER (target_name));
        }
      else
        {
          output_ctx ("%s%s%s.%s%s%s", PRINT_IDENTIFIER (target_owner_name), PRINT_IDENTIFIER (target_name));
        }

      if (DB_IS_NULL (&values[SYNONYM_COMMENT]) == false)
        {
          output_ctx (" COMMENT ");
          desc_value_print (output_ctx, &values[SYNONYM_COMMENT]);
        }
      output_ctx (";\n");

      for (i = 0; i < SYNONYM_VALUE_INDEX_MAX; i++)
        {
          db_value_clear (&values[i]);
        }
    }
      while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS);
    }

end:
  db_query_end (query_result);

  if (uppercase_user != NULL)
    {
      free_and_init (uppercase_user);
    }

  AU_ENABLE (save);

  return error;
}

/*
 * extract_classes_to_file - exports schema to file
 *    return: 0 if successful, error count otherwise
 *    ctxt(in/out): extract context
 */
int
extract_classes_to_file (extract_context & ctxt)
{
  int err_count = 0;

  if (split_schema_files)
    {
      err_count = extract_split_schema_files (ctxt);
    }
  else
    {
      char output_filename_schema[PATH_MAX * 2] = { '\0' };

      if (create_filename_schema (ctxt.output_dirname, ctxt.output_prefix, output_filename_schema,
                  sizeof (output_filename_schema)) == 0)
    {
      err_count = extract_all_schema_file (ctxt, output_filename_schema);
    }
      else
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      err_count = 1;
    }
    }

  return err_count;
}

/*
 * extract_schema - exports schema to output
 *    return: 0 if successful, error count otherwise
 *    ctxt(in/out): extract context
 *    schema_output_ctx(in/out) : output countext
 * Note:
 *    Always output the entire schema.
 */
static int
extract_schema (extract_context & ctxt, print_output & schema_output_ctx)
{
  DB_OBJLIST *classes = NULL;
  DB_OBJLIST *vclass_list_has_using_index = NULL;
  int err_count = 0;

  /*
   * convert the class table into an ordered class list, would be better
   * if we just built the initial list rather than using the table.
   */
  err_count = get_classes (ctxt, schema_output_ctx);

  if (err_count != NO_ERROR)
    {
      return 1;
    }

  /*
   * Schema
   */
  if (required_class_only == false && ctxt.do_auth)
    {
      if (au_export_users (ctxt, schema_output_ctx) < NO_ERROR)
    {
      err_count++;
    }
    }

  if (required_class_only == false && export_serial (ctxt, schema_output_ctx) < NO_ERROR)
    {
      fprintf (stderr, "%s", db_error_string (3));
      if (db_error_code () == ER_INVALID_SERIAL_VALUE)
    {
      fprintf (stderr, " Check the value of _db_serial object.\n");
    }
      err_count++;
    }

  if (required_class_only == false && emit_stored_procedure_pre (ctxt, schema_output_ctx) != NO_ERROR)
    {
      err_count++;
    }

  if (required_class_only == false && export_server (ctxt, schema_output_ctx) < NO_ERROR)
    {
      err_count++;
    }

  if (ctxt.classes != NULL && (emit_schema (ctxt, schema_output_ctx, EXTRACT_CLASS), er_errid () != NO_ERROR))
    {
      err_count++;
    }


  if (ctxt.classes != NULL && (emit_class_query_spec (ctxt, schema_output_ctx, EXTRACT_CLASS), er_errid () != NO_ERROR))
    {
      err_count++;
    }


  if (emit_class_alter_serial (ctxt, schema_output_ctx) < NO_ERROR)
    {
      fprintf (stderr, "%s", db_error_string (3));
      if (db_error_code () == ER_INVALID_SERIAL_VALUE)
    {
      fprintf (stderr, " Check the value of _db_serial object.\n");
    }
      err_count++;
    }

  if (ctxt.classes != NULL && (emit_schema (ctxt, schema_output_ctx, EXTRACT_VCLASS), er_errid () != NO_ERROR))
    {
      err_count++;
    }

  /*
   * If there is a view using synonym, the synonym must be created first.
   * Since a synonym is like an alias, it can be created even if the target does not exist.
   * So, unload the synonym before class/vclass.
   */
  if (export_synonym (ctxt, schema_output_ctx) < NO_ERROR)
    {
      fprintf (stderr, "%s", db_error_string (3));
      if (db_error_code () == ER_SYNONYM_INVALID_VALUE)
    {
      fprintf (stderr, " Check the value of _db_synonym object.\n");
    }
    }

  if (ctxt.classes != NULL
      && (emit_class_query_spec (ctxt, schema_output_ctx, EXTRACT_VCLASS), er_errid () != NO_ERROR))
    {
      err_count++;
    }

  if (required_class_only == false && emit_stored_procedure_post (ctxt, schema_output_ctx) != NO_ERROR)
    {
      err_count++;
    }

  if (ctxt.classes != NULL && (emit_foreign_key (ctxt, schema_output_ctx, ctxt.classes) != NO_ERROR))
    {
      err_count++;
    }

  if (emit_grant (ctxt, schema_output_ctx, ctxt.classes) != NO_ERROR)
    {
      err_count++;
    }

  return err_count;
}

/*
 * extract_triggers_to_file - exports triggers to file
 *    return: 0 if successful, error count otherwise
 *    ctxt(in/out): extract context
 *    output_filename(in/out) : output filename
 */
int
extract_triggers_to_file (extract_context & ctxt, const char *output_filename)
{
  FILE *output_file;
  int error = NO_ERROR;

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return 1;
    }

  file_print_output output_ctx (output_file);

  error = extract_triggers (ctxt, output_ctx);

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no trigger to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (error == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }
      fclose (output_file);
      output_file = NULL;
    }

  return error;
}

/*
 * extract_triggers - exports triggers to output
 *    return: 0 if successful, error count otherwise
 *    ctxt(in/out): extract context
 *    schema_output_ctx(in/out) : output countext
 * Note:
 *    Always output the entire schema.
 */
int
extract_triggers (extract_context & ctxt, print_output & output_ctx)
{
  /*
   * Trigger
   * emit the triggers last, they will have no mutual dependencies so
   * it doesn't really matter what order they're in.
   */
  assert (ctxt.classes != NULL);
  if (tr_dump_selective_triggers (ctxt, output_ctx, ctxt.classes) != NO_ERROR)
    {
      return ER_FAILED;
    }

  return NO_ERROR;
}

/*
 * extract_indexes_to_file - exports indexes to file
 *    return: 0 if successful, error count otherwise
 *    ctxt(in/out): extract context
 *    output_filename(in/out) : output filename
 */
int
extract_indexes_to_file (extract_context & ctxt, const char *output_filename)
{
  FILE *output_file = NULL;
  int err_count = 0;

  if (!ctxt.has_indexes)
    {
      /* remove any indexes file from previous attempt */
      output_file = fopen_ex (output_filename, "r");
      if (output_file != NULL)
    {
      fclose (output_file);
      output_file = NULL;
      if (unlink (output_filename))
        {
          (void) fprintf (stderr, "%s.\n\n", strerror (errno));
          return 1;
        }
    }
      return 0;
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return 1;
    }

  file_print_output output_ctx (output_file);

  err_count = emit_indexes (ctxt, output_ctx, ctxt.classes, ctxt.has_indexes, ctxt.vclass_list_has_using_index);

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no indexes to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {               /* not empty */
      if (err_count == 0)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }
      fclose (output_file);
      output_file = NULL;
    }

  return err_count;
}

/*
 * emit_indexes - Emit SQL statements to define indexes for all attributes
 * that have them.
 *    return:
 *    classes(in):
 *    has_indexes(in):
 *    vclass_list_has_using_index(in):
 */
static int
emit_indexes (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes, int has_indexes,
          DB_OBJLIST * vclass_list_has_using_index)
{
  DB_OBJLIST *cl;
  int err_count = 0;

  for (cl = classes; cl != NULL; cl = cl->next)
    {
      /* if its some sort of vclass then it can't have indexes */
      if (db_is_vclass (cl->op) <= 0)
    {
      if (emit_index_def (ctxt, output_ctx, cl->op) != NO_ERROR)
        {
          err_count++;
        }
    }
    }

  if (vclass_list_has_using_index != NULL)
    {
      emit_query_specs_has_using_index (ctxt, output_ctx, vclass_list_has_using_index);
    }
  if (er_errid () == ER_OBJ_NO_COMPONENTS)
    {
      er_clear ();
    }

  return err_count;
}

/*
 * emit_schema -
 *    return:
 *    classes():
 *    do_auth():
 */
static void
emit_schema (extract_context & ctxt, print_output & output_ctx, EXTRACT_CLASS_TYPE extract_class)
{
  DB_OBJLIST *cl = NULL;
  int is_vclass = 0;
  const char *class_type = NULL;
  const char *name = NULL;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };
  const char *tde_algo_name = NULL;
  int is_partitioned = 0;
  SM_CLASS *class_ = NULL;

  /*
   * First create all the classes
   */
  for (cl = ctxt.classes; cl != NULL; cl = cl->next)
    {
      is_vclass = db_is_vclass (cl->op);

      name = db_get_class_name (cl->op);
      if (do_is_partitioned_subclass (&is_partitioned, name, NULL))
    {
      continue;
    }

      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);
      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
            sizeof (output_owner));

      if (au_fetch_class_force (cl->op, &class_, AU_FETCH_READ) != NO_ERROR)
    {
      class_ = NULL;
    }
      else
    {
      if (extract_class == EXTRACT_CLASS_ALL)
        {
          output_ctx ("\nCREATE %s %s%s%s%s", is_vclass ? "VCLASS" : "CLASS", output_owner,
              PRINT_IDENTIFIER (class_name));
        }
      else
        {
          if (is_vclass == TRUE && extract_class == EXTRACT_VCLASS)
        {
          output_ctx ("\nCREATE VCLASS %s%s%s%s", output_owner, PRINT_IDENTIFIER (class_name));
        }
          else if (is_vclass == FALSE && extract_class == EXTRACT_CLASS)
        {
          output_ctx ("\nCREATE CLASS %s%s%s%s", output_owner, PRINT_IDENTIFIER (class_name));
        }
          else
        {
          continue;
        }
        }
    }

      if (is_vclass > 0)
    {
      if (sm_get_class_flag (cl->op, SM_CLASSFLAG_WITHCHECKOPTION) > 0)
        {
          output_ctx (" WITH CHECK OPTION");
        }
      else if (sm_get_class_flag (cl->op, SM_CLASSFLAG_LOCALCHECKOPTION) > 0)
        {
          output_ctx (" WITH LOCAL CHECK OPTION");
        }
    }
      else
    {
      if (sm_get_class_flag (cl->op, SM_CLASSFLAG_REUSE_OID) > 0)
        {
          output_ctx (" REUSE_OID");
        }
      else
        {
          output_ctx (" DONT_REUSE_OID");
        }

      if (class_ != NULL)
        {
          output_ctx (", COLLATE %s", lang_get_collation_name (class_->collation_id));
        }

      if (class_ != NULL)
        {
          tde_algo_name = tde_get_algorithm_name ((TDE_ALGORITHM) class_->tde_algorithm);
          assert (tde_algo_name != NULL);
          if (strcmp (tde_algo_name, tde_get_algorithm_name (TDE_ALGORITHM_NONE)) != 0)
        {
          output_ctx (" ENCRYPT=%s", tde_algo_name);
        }
        }
    }

      if (class_ != NULL && class_->comment != NULL && class_->comment[0] != '\0')
    {
      output_ctx (" ");
      help_print_describe_comment (output_ctx, class_->comment);
    }

      output_ctx (";\n");
      if (is_vclass <= 0 && ctxt.storage_order == FOLLOW_STORAGE_ORDER)
    {
      emit_class_meta (output_ctx, cl->op);
    }
    }
}

static void
emit_class_query_spec (extract_context & ctxt, print_output & output_ctx, EXTRACT_CLASS_TYPE extract_class)
{
  DB_OBJLIST *cl = NULL;
  int is_vclass = 0;
  const char *class_type = NULL;
  const char *name = NULL;
  int is_partitioned = 0;

  /* emit super classes without resolutions for non-proxies */
  for (cl = ctxt.classes; cl != NULL; cl = cl->next)
    {
      is_vclass = db_is_vclass (cl->op);

      if (extract_class == EXTRACT_CLASS_ALL)
    {
      class_type = (is_vclass > 0) ? "VCLASS" : "CLASS";
    }
      else
    {
      if (is_vclass == TRUE && extract_class == EXTRACT_VCLASS)
        {
          class_type = "VCLASS";
        }
      else if (is_vclass == FALSE && extract_class == EXTRACT_CLASS)
        {
          class_type = "CLASS";
        }
      else
        {
          continue;
        }
    }

      (void) emit_superclasses (ctxt, output_ctx, cl->op, class_type);
    }

  /*
   * Now fill out the class definitions for the non-proxy classes.
   */
  for (cl = ctxt.classes; cl != NULL; cl = cl->next)
    {
      bool found = false;

      is_vclass = db_is_vclass (cl->op);
      if (extract_class == EXTRACT_CLASS_ALL)
    {
      class_type = (is_vclass > 0) ? "VCLASS" : "CLASS";
    }
      else
    {
      if (is_vclass == TRUE && extract_class == EXTRACT_VCLASS)
        {
          class_type = "VCLASS";
        }
      else if (is_vclass == FALSE && extract_class == EXTRACT_CLASS)
        {
          class_type = "CLASS";
        }
      else
        {
          continue;
        }
    }

      name = db_get_class_name (cl->op);
      if (do_is_partitioned_subclass (&is_partitioned, name, NULL))
    {
      continue;
    }

      output_ctx ("\n");

      if (emit_all_attributes (ctxt, output_ctx, cl->op, class_type, &ctxt.has_indexes, ctxt.storage_order))
    {
      found = true;
    }

      if (emit_methods (ctxt, output_ctx, cl->op, class_type))
    {
      found = true;
    }

      if (is_partitioned)
    {
      emit_partition_info (ctxt, output_ctx, cl->op);
    }
    }

  /* emit super class resolutions for non-proxies */
  for (cl = ctxt.classes; cl != NULL; cl = cl->next)
    {
      is_vclass = db_is_vclass (cl->op);
      if (extract_class == EXTRACT_CLASS_ALL)
    {
      class_type = (is_vclass > 0) ? "VCLASS" : "CLASS";
    }
      else
    {
      if (is_vclass == TRUE && extract_class == EXTRACT_VCLASS)
        {
          class_type = "VCLASS";
        }
      else if (is_vclass == FALSE && extract_class == EXTRACT_CLASS)
        {
          class_type = "CLASS";
        }
      else
        {
          continue;
        }
    }

      (void) emit_resolutions (ctxt, output_ctx, cl->op, class_type);
    }

  /*
   * do query specs LAST after we're sure that all potentially
   * referenced classes have their full definitions.
   */
  if (extract_class != EXTRACT_CLASS)
    {
      ctxt.vclass_list_has_using_index = emit_query_specs (ctxt, output_ctx, ctxt.classes);
    }

  if (er_errid () == ER_OBJ_NO_COMPONENTS)
    {
      er_clear ();
    }

}


/*
 * has_vclass_domains -
 *    return: non-zero if the class has vclasses as attribute domains
 *    vclass(in): class MOP
 * Note:
 *    This is a helper function for emit_query_specs().
 *    Look through the attribute list of this class to see if there are
 *    any attributes defined with domsins that are other vclasses.  If so
 *    we have to adjust the way we emit the query spec lists for
 *    this class.
 */
static bool
has_vclass_domains (DB_OBJECT * vclass)
{
  /*
   * Previously, it force two full passes on the query specs of all vclasses,
   * Now, force one pass
   */
  return 0;
}


/*
 * emit_query_specs - Emit the object ids for a virtual class.
 *    return:
 *    classes(in):
 */
static DB_OBJLIST *
emit_query_specs (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes)
{
  DB_QUERY_SPEC *specs, *s;
  DB_OBJLIST *cl;
  DB_OBJLIST *vclass_list_has_using_index = NULL;
  PARSER_CONTEXT *parser;
  PT_NODE **query_ptr;
  const char *name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH];
  owner_name[0] = '\0';
  char *class_name = NULL;
  const char *null_spec;
  bool has_using_index;
  bool change_vclass_spec;
  int i;
  char output_owner[DB_MAX_USER_LENGTH + 4];
  output_owner[0] = '\0';
  char *query_ptr_result;

  /*
   * pass 1, emit NULL spec lists for vclasses that have attribute
   * domains which are other vclasses
   */
  for (cl = classes; cl != NULL; cl = cl->next)
    {
      if (db_is_vclass (cl->op) <= 0)
    {
      continue;
    }

      name = db_get_class_name (cl->op);
      specs = db_get_query_specs (cl->op);
      if (specs == NULL)
    {
      continue;
    }

      if (!has_vclass_domains (cl->op))
    {
      continue;
    }

      has_using_index = false;
      for (s = specs; s && has_using_index == false; s = db_query_spec_next (s))
    {
      /*
       * convert the query spec into one containing NULLs for
       * each column
       */
      parser = parser_create_parser ();
      if (parser == NULL)
        {
          continue;
        }

      query_ptr = parser_parse_string (parser, db_query_spec_string (s));
      if (query_ptr != NULL)
        {
          parser_walk_tree (parser, *query_ptr, pt_has_using_index_clause, &has_using_index, NULL, NULL);

          if (has_using_index == true)
        {
          /* all view specs should be emitted at index file */
          ml_append (&vclass_list_has_using_index, cl->op, NULL);
        }
        }
      parser_free_parser (parser);
    }

      if (has_using_index == false)
    {
      for (s = specs; s; s = db_query_spec_next (s))
        {
          parser = parser_create_parser ();
          if (parser == NULL)
        {
          continue;
        }

          if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
        {
          parser->custom_print |= PT_PRINT_NO_CURRENT_USER_NAME;
        }

          query_ptr = parser_parse_string (parser, db_query_spec_string (s));
          if (query_ptr != NULL)
        {
          null_spec = pt_print_query_spec_no_list (parser, *query_ptr);
          SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

          PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                    sizeof (output_owner));

          output_ctx ("ALTER VCLASS %s%s%s%s ADD QUERY %s ; \n", output_owner,
                  PRINT_IDENTIFIER (class_name), null_spec);
        }
          parser_free_parser (parser);
        }
    }
    }

  /*
   * pass 2, emit full spec lists
   */
  for (cl = classes; cl != NULL; cl = cl->next)
    {
      if (db_is_vclass (cl->op) <= 0)
    {
      continue;
    }

      name = db_get_class_name (cl->op);
      specs = db_get_query_specs (cl->op);
      if (specs == NULL)
    {
      continue;
    }

      if (ml_find (vclass_list_has_using_index, cl->op))
    {
      continue;
    }

      output_ctx ("\n");

      change_vclass_spec = has_vclass_domains (cl->op);

      for (s = specs, i = 1; s != NULL; s = db_query_spec_next (s), i++)
    {
      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      parser = parser_create_parser ();
      if (parser == NULL)
        {
          output_ctx ("/* ERROR : ALTER VCLASS %s%s%s ADD QUERY ... */\n", PRINT_IDENTIFIER (name));
          continue;
        }

      if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
        {
          parser->custom_print |= PT_PRINT_NO_CURRENT_USER_NAME;
        }

      query_ptr = parser_parse_string (parser, db_query_spec_string (s));
      if (query_ptr != NULL)
        {
          query_ptr_result = parser_print_tree_with_quotes (parser, *query_ptr);
          if (change_vclass_spec)
        {       /* change the existing spec lists */
          PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                    sizeof (output_owner));

          output_ctx ("ALTER VCLASS %s%s%s%s CHANGE QUERY %d %s ;\n", output_owner,
                  PRINT_IDENTIFIER (class_name), i, query_ptr_result);
        }
          else
        {       /* emit the usual statements */
          PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                    sizeof (output_owner));

          output_ctx ("ALTER VCLASS %s%s%s%s ADD QUERY %s ;\n", output_owner,
                  PRINT_IDENTIFIER (class_name), query_ptr_result);
        }
        }
      else
        {
          output_ctx ("/* ERROR : ALTER VCLASS %s%s%s ADD QUERY ... */\n", PRINT_IDENTIFIER (name));
        }

      parser_free_parser (parser);
    }
    }

  return vclass_list_has_using_index;
}


/*
 * emit_query_specs_has_using_index - Emit the object ids for a virtual class
 *    return:
 *    vclass_list_has_using_index():
 */
static int
emit_query_specs_has_using_index (extract_context & ctxt, print_output & output_ctx,
                  DB_OBJLIST * vclass_list_has_using_index)
{
  DB_QUERY_SPEC *specs, *s;
  DB_OBJLIST *cl;
  PARSER_CONTEXT *parser;
  PT_NODE **query_ptr;
  const char *name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  const char *null_spec;
  bool change_vclass_spec;
  int i;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };
  char *query_ptr_result;

  /*
   * pass 1, emit NULL spec lists for vclasses that have attribute
   * domains which are other vclasses
   */

  for (cl = vclass_list_has_using_index; cl != NULL; cl = cl->next)
    {
      if (db_is_vclass (cl->op) <= 0)
    {
      continue;
    }

      name = db_get_class_name (cl->op);
      specs = db_get_query_specs (cl->op);
      if (specs == NULL)
    {
      continue;
    }

      if (!has_vclass_domains (cl->op))
    {
      continue;
    }

      for (s = specs; s != NULL; s = db_query_spec_next (s))
    {
      /*
       * convert the query spec into one containing NULLs for
       * each column
       */
      parser = parser_create_parser ();
      if (parser == NULL)
        {
          continue;
        }

      if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
        {
          parser->custom_print |= PT_PRINT_NO_CURRENT_USER_NAME;
        }

      query_ptr = parser_parse_string (parser, db_query_spec_string (s));
      if (query_ptr != NULL)
        {
          null_spec = pt_print_query_spec_no_list (parser, *query_ptr);
          SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

          PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

          output_ctx ("ALTER VCLASS %s%s%s%s ADD QUERY %s ; \n", output_owner,
              PRINT_IDENTIFIER (class_name), null_spec);
        }
      parser_free_parser (parser);
    }
    }

  /* pass 2, emit full spec lists */
  for (cl = vclass_list_has_using_index; cl != NULL; cl = cl->next)
    {
      if (db_is_vclass (cl->op) <= 0)
    {
      continue;
    }
      name = db_get_class_name (cl->op);
      specs = db_get_query_specs (cl->op);
      if (specs == NULL)
    {
      continue;
    }

      change_vclass_spec = has_vclass_domains (cl->op);

      for (s = specs, i = 1; s; s = db_query_spec_next (s), i++)
    {
      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      parser = parser_create_parser ();
      if (parser == NULL)
        {
          output_ctx ("/* ERROR : ALTER VCLASS %s%s%s ADD QUERY ... */\n", PRINT_IDENTIFIER (name));
          continue;
        }

      if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
        {
          parser->custom_print |= PT_PRINT_NO_CURRENT_USER_NAME;
        }

      query_ptr = parser_parse_string (parser, db_query_spec_string (s));
      if (query_ptr != NULL)
        {
          query_ptr_result = parser_print_tree_with_quotes (parser, *query_ptr);

          if (change_vclass_spec)
        {       /* change the existing spec lists */
          PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                    sizeof (output_owner));

          output_ctx ("ALTER VCLASS %s%s%s%s CHANGE QUERY %d %s ;\n", output_owner,
                  PRINT_IDENTIFIER (class_name), i, query_ptr_result);
        }
          else
        {       /* emit the usual statements */
          PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                    sizeof (output_owner));

          output_ctx ("ALTER VCLASS %s%s%s%s ADD QUERY %s ;\n", output_owner,
                  PRINT_IDENTIFIER (class_name), query_ptr_result);
        }
        }
      else
        {
          output_ctx ("/* ERROR : ALTER VCLASS %s%s%s ADD QUERY ... */\n", PRINT_IDENTIFIER (name));
        }

      parser_free_parser (parser);
    }
    }

  return NO_ERROR;
}


/*
 * emit_superclasses - emit queries for adding superclass for the class given
 *    return: true if there are any superclasses or conflict resolutions
 *    output_ctx(in/out): output context
 *    class(in): the class to emit the superclasses for
 *    class_type(in): CLASS or VCLASS
 */
static bool
emit_superclasses (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_, const char *class_type)
{
  DB_OBJLIST *supers, *s;
  const char *name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  supers = db_get_superclasses (class_);
  if (supers != NULL)
    {
      /* create class alter string */
      name = db_get_class_name (class_);
      if (do_is_partitioned_subclass (NULL, name, NULL))
    {
      return (supers != NULL);
    }

      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
            sizeof (output_owner));

      output_ctx ("\nALTER %s %s%s%s%s ADD SUPERCLASS ", class_type, output_owner, PRINT_IDENTIFIER (class_name));

      for (s = supers; s != NULL; s = s->next)
    {
      name = db_get_class_name (s->op);
      if (s != supers)
        {
          output_ctx (", ");
        }

      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

      output_ctx ("%s%s%s%s", output_owner, PRINT_IDENTIFIER (class_name));
    }

      output_ctx (";\n");

    }

  return (supers != NULL);
}


/*
 * emit_resolutions - emit queries for the resolutions (instance, shared and
 * class) for the class given
 *    return: true if any resolutions are emitted, false otherwise
 *    class(in): the class to emit resolutions for
 *    class_type(in): CLASS or VCLASS
 * Note:
 *     Calls emit_resolution_def for each resolution.  This function will
 *     only emit those resolutions defined in this class and NOT any of the
 *     inherited resolutions.
 */
static bool
emit_resolutions (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_, const char *class_type)
{
  DB_RESOLUTION *resolution_list;
  bool return_value = false;
  const char *name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  resolution_list = db_get_resolutions (class_);
  if (resolution_list != NULL)
    {
      name = db_get_class_name (class_);
      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
            sizeof (output_owner));

      output_ctx ("\nALTER %s %s%s%s%s INHERIT", class_type, output_owner, PRINT_IDENTIFIER (class_name));

      for (; resolution_list != NULL; resolution_list = db_resolution_next (resolution_list))
    {
      if (return_value == true)
        {
          output_ctx (",\n");
        }
      else
        {
          output_ctx ("\n");
          return_value = true;
        }
      emit_resolution_def (ctxt, output_ctx, resolution_list,
                   (db_resolution_isclass (resolution_list) ? CLASS_RESOLUTION : INSTANCE_RESOLUTION));
    }

      output_ctx (";\n");
    }               /* if */

  return (return_value);
}


/*
 * emit_resolution_def - emit the resolution qualifier
 *    return: void
 *    resolution(in): the resolution
 *    qualifier(in): the qualifier for this resolution (instance or class)
 */
static void
emit_resolution_def (extract_context & ctxt, print_output & output_ctx, DB_RESOLUTION * resolution,
             RESOLUTION_QUALIFIER qualifier)
{
  const char *name, *alias, *class_name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name_p = NULL;
  DB_OBJECT *class_;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  class_ = db_resolution_class (resolution);
  if (class_ == NULL)
    {
      return;
    }

  name = db_resolution_name (resolution);
  if (name == NULL)
    {
      return;
    }

  class_name = db_get_class_name (class_);
  if (class_name == NULL)
    {
      return;
    }
  SPLIT_USER_SPECIFIED_NAME (class_name, owner_name, class_name_p);

  alias = db_resolution_alias (resolution);

  switch (qualifier)
    {
    case INSTANCE_RESOLUTION:
      {
    PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
              sizeof (output_owner));

    output_ctx ("       %s%s%s OF %s%s%s%s", PRINT_IDENTIFIER (name), output_owner,
            PRINT_IDENTIFIER (class_name_p));
    break;
      }
    case CLASS_RESOLUTION:
      {
    PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
              sizeof (output_owner));

    output_ctx ("CLASS  %s%s%s OF %s%s%s%s", PRINT_IDENTIFIER (name), output_owner,
            PRINT_IDENTIFIER (class_name_p));
    break;
      }
    }

  if (alias != NULL)
    {
      output_ctx (" AS %s%s%s", PRINT_IDENTIFIER (alias));
    }

  class_ = NULL;
}


/*
 * emit_instance_attributes - emit quries for adding the attributes (instance,
 * shared and class) for the class given
 *    return: true if any locally defined attributes are found, false
 *            otherwise
 *    output_ctx(in/out): output context
 *    class(in): the class to emit the attributes for
 *    class_type(in):
 *    has_indexes(in):
 * Note:
 *    Calls emit_attribute_def for each attribute.  This function will only
 *    emit those attributes defined in this class and NOT any of the
 *    inherited attributes.
 *
 *    If its a proxy, only dump those attributes whose domains
 *    are other classes, the attributes with primitive type domains will
 *    have been dumped in the main class definition.
 */
static bool
emit_instance_attributes (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_, const char *class_type,
              int *has_indexes, EMIT_STORAGE_ORDER storage_order)
{
  DB_ATTRIBUTE *attribute_list, *first_attribute, *a;
  int unique_flag = 0;
  int reverse_unique_flag = 0;
  int index_flag = 0;
  const char *name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  char *serial_name = NULL;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  attribute_list = db_get_attributes (class_);

  /* see if we have an index or unique defined on any attribute */
  for (a = attribute_list; a != NULL; a = db_attribute_next (a))
    {
      if (db_attribute_class (a) == class_)
    {
      if (db_attribute_is_unique (a))
        {
          unique_flag = 1;
        }
      else if (db_attribute_is_reverse_unique (a))
        {
          reverse_unique_flag = 1;
        }
    }

      if (db_attribute_is_indexed (a))
    {
      index_flag = 1;
    }

      if (unique_flag && reverse_unique_flag && index_flag)
    {
      /* Since we already found all, no need to go further. */
      break;
    }
    }

  /*
   * We call this function many times, so be careful not to clobber
   * (i.e. overwrite) the has_index parameter
   */
  if (has_indexes != NULL)
    {
      *has_indexes |= index_flag;
    }


  /* see if we have any locally defined components on either list */
  first_attribute = NULL;
  for (a = attribute_list; a != NULL && first_attribute == NULL; a = db_attribute_next (a))
    {
      if (db_attribute_class (a) == class_)
    {
      first_attribute = a;
    }
    }

  if (first_attribute == NULL)
    {
      return false;
    }

  name = db_get_class_name (class_);
  if (storage_order == FOLLOW_STORAGE_ORDER)
    {
      DB_ATTRIBUTE **ordered_attributes, **storage_attributes;
      int i, j, max_order, shared_pos;
      const char *option, *old_attribute_name;

      max_order = 0;
      for (a = first_attribute; a != NULL; a = db_attribute_next (a))
    {
      if (db_attribute_class (a) != class_)
        {
          continue;
        }

      if (a->order > max_order)
        {
          max_order = a->order;
        }
    }
      max_order++;

      ordered_attributes = (DB_ATTRIBUTE **) calloc (max_order * 2, sizeof (DB_ATTRIBUTE *));
      if (ordered_attributes == NULL)
    {
      return false;
    }
      storage_attributes = &ordered_attributes[max_order];

      shared_pos = 1;
      for (a = first_attribute; a != NULL; a = db_attribute_next (a))
    {
      if (db_attribute_class (a) != class_)
        {
          continue;
        }

      if (db_attribute_is_shared (a))
        {
          storage_attributes[max_order - shared_pos] = a;
          shared_pos++;
        }
      else
        {
          assert (storage_attributes[a->storage_order] == NULL);
          storage_attributes[a->storage_order] = a;
        }
    }

      for (i = 0; i < max_order; i++)
    {
      a = storage_attributes[i];
      if (a == NULL)
        {
          continue;
        }

      assert (ordered_attributes[a->order] == NULL);
      ordered_attributes[a->order] = a;

      for (j = a->order - 1; j >= 0; j--)
        {
          if (ordered_attributes[j])
        {
          option = "AFTER ";
          old_attribute_name = db_attribute_name (ordered_attributes[j]);
          break;
        }
        }

      if (j < 0)
        {
          option = "FIRST";
          old_attribute_name = "";
        }

      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

      output_ctx ("ALTER %s %s%s%s%s ADD ATTRIBUTE ", class_type, output_owner, PRINT_IDENTIFIER (class_name));

      if (db_attribute_is_shared (a))
        {
          emit_attribute_def (ctxt, output_ctx, a, SHARED_ATTRIBUTE);
        }
      else
        {
          emit_attribute_def (ctxt, output_ctx, a, INSTANCE_ATTRIBUTE);
        }
      output_ctx (" %s", option);
      if (old_attribute_name[0] == '\0')
        {
          output_ctx (";\n");
        }
      else
        {
          output_ctx (" %s%s%s;\n", PRINT_IDENTIFIER (old_attribute_name));
        }
    }

      free (ordered_attributes);
    }
  else
    {
      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
            sizeof (output_owner));

      output_ctx ("ALTER %s %s%s%s%s ADD ATTRIBUTE\n", class_type, output_owner, PRINT_IDENTIFIER (class_name));

      for (a = first_attribute; a != NULL; a = db_attribute_next (a))
    {
      if (db_attribute_class (a) == class_)
        {
          if (a != first_attribute)
        {
          output_ctx (",\n");
        }

          if (db_attribute_is_shared (a))
        {
          emit_attribute_def (ctxt, output_ctx, a, SHARED_ATTRIBUTE);
        }
          else
        {
          emit_attribute_def (ctxt, output_ctx, a, INSTANCE_ATTRIBUTE);
        }
        }
    }

      output_ctx (";\n");
    }

  if (unique_flag)
    {
      if (split_schema_files == false)
    {
      emit_primary_and_unique_def (ctxt, output_ctx, class_, class_type);
    }
    }

  if (reverse_unique_flag)
    {
      if (split_schema_files == false)
    {
      emit_reverse_unique_def (ctxt, output_ctx, class_);
    }
    }

  return true;
}


/*
 * emit_class_attributes - emit ALTER statements for the class attributes
 *    return: non-zero if something was emitted
 *    output_ctx(in/out): output context
 *    class(in): class
 *    class_type(in): class type
 */
static bool
emit_class_attributes (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_, const char *class_type)
{
  DB_ATTRIBUTE *class_attribute_list, *first_class_attribute, *a;
  const char *name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  class_attribute_list = db_get_class_attributes (class_);
  first_class_attribute = NULL;

  for (a = class_attribute_list; a != NULL && first_class_attribute == NULL; a = db_attribute_next (a))
    {
      if (db_attribute_class (a) == class_)
    {
      first_class_attribute = a;
    }
    }

  if (first_class_attribute != NULL)
    {
      name = db_get_class_name (class_);
      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
            sizeof (output_owner));

      output_ctx ("ALTER %s %s%s%s%s ADD CLASS ATTRIBUTE \n", class_type, output_owner, PRINT_IDENTIFIER (class_name));

      for (a = first_class_attribute; a != NULL; a = db_attribute_next (a))
    {
      if (db_attribute_class (a) == class_)
        {
          if (a != first_class_attribute)
        {
          output_ctx (",\n");
        }
          emit_attribute_def (ctxt, output_ctx, a, CLASS_ATTRIBUTE);
        }
    }
      output_ctx (";\n");
    }

  return (first_class_attribute != NULL);
}

static bool
emit_class_meta (print_output & output_ctx, DB_OBJECT * table)
{
  DB_ATTRIBUTE *attribute_list, *a;
  const char *table_name;
  bool first_print = true;

  table_name = db_get_class_name (table);
  output_ctx ("-- !META! %s%s%s:", PRINT_IDENTIFIER (table_name));

  attribute_list = db_get_attributes (table);
  for (a = attribute_list; a != NULL; a = db_attribute_next (a))
    {
      if (db_attribute_class (a) != table)
    {
      continue;
    }
      if (!first_print)
    {
      output_ctx (",");
    }
      output_ctx ("%s%s%s", PRINT_IDENTIFIER (db_attribute_name (a)));
      output_ctx ("(%d)", db_attribute_type (a));
      output_ctx ("(%d)", db_attribute_order (a));
      output_ctx ("(%d)", a->storage_order);
      output_ctx ("(%c)", db_attribute_is_shared (a) ? 'S' : 'I');
      first_print = false;
    }

  output_ctx ("\n");

  return true;
}

/*
 * emit_all_attributes - Emit both the instance and class attributes.
 *    return: non-zero if something was emmitted
 *    output_ctx(in/out): output context
 *    class(in): class to dump
 *    class_type(in): class type string
 *    has_indexes(in):
 */
static bool
emit_all_attributes (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_, const char *class_type,
             int *has_indexes, EMIT_STORAGE_ORDER storage_order)
{
  bool istatus, cstatus;

  istatus = emit_instance_attributes (ctxt, output_ctx, class_, class_type, has_indexes, storage_order);
  cstatus = emit_class_attributes (ctxt, output_ctx, class_, class_type);

  return istatus || cstatus;
}


/*
 * emit_method_files - emit all methods files
 *    return: void
 *    class(in): class object
 */
static void
emit_method_files (print_output & output_ctx, DB_OBJECT * class_mop)
{
  DB_METHFILE *files, *f;
  bool printed_once = false;

  /* should clean this list ! */
  files = db_get_method_files (class_mop);

  if (files != NULL)
    {
      for (f = files; f != NULL; f = db_methfile_next (f))
    {
      if (f->class_mop == class_mop)
        {
          if (printed_once == false)
        {
          printed_once = true;
          output_ctx ("FILE");
        }
          else
        {
          output_ctx (",\n");
          output_ctx ("    ");
        }
          emit_methfile_def (output_ctx, f);
        }
    }
    }
}


/*
 * emit_methods - emit quries for adding the methods (instance, shared and
 * class) for the class given
 *    return: true if any locally defined methods are emitted, false
 *            otherwise
 *    class(in): the class to emit the method definitions for
 *    class_type(in): class type
 * Note:
 *    Calls emit_method_def for each method.  This function will only
 *    emit those methods defined in this class and NOT any of the
 *    inherited methods.
 */
static bool
emit_methods (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_, const char *class_type)
{
  DB_METHOD *method_list, *class_method_list, *m;
  DB_METHOD *first_method, *first_class_method;
  const char *name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  method_list = db_get_methods (class_);
  class_method_list = db_get_class_methods (class_);

  /* see if we have any locally defined components on either list */
  first_method = first_class_method = NULL;
  for (m = method_list; m != NULL && first_method == NULL; m = db_method_next (m))
    {
      if (db_method_class (m) == class_)
    {
      first_method = m;
    }
    }

  for (m = class_method_list; m != NULL && first_class_method == NULL; m = db_method_next (m))
    {
      if (db_method_class (m) == class_)
    {
      first_class_method = m;
    }
    }

  if (first_method != NULL)
    {
      name = db_get_class_name (class_);
      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
            sizeof (output_owner));

      output_ctx ("ALTER %s %s%s%s%s ADD METHOD\n", class_type, output_owner, PRINT_IDENTIFIER (class_name));

      for (m = first_method; m != NULL; m = db_method_next (m))
    {
      if (db_method_class (m) == class_)
        {
          if (m != first_method)
        {
          output_ctx (",\n");
        }
          emit_method_def (ctxt, output_ctx, m, INSTANCE_METHOD);
        }
    }

      output_ctx ("\n");
      emit_method_files (output_ctx, class_);
      output_ctx (";\n");
    }

  /* eventually, this may merge with the statement above */
  if (first_class_method != NULL)
    {
      name = db_get_class_name (class_);
      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
            sizeof (output_owner));

      output_ctx ("ALTER %s %s%s%s%s ADD METHOD\n", class_type, output_owner, PRINT_IDENTIFIER (class_name));

      for (m = first_class_method; m != NULL; m = db_method_next (m))
    {
      if (db_method_class (m) == class_)
        {
          if (m != first_class_method)
        {
          output_ctx (",\n");
        }
          emit_method_def (ctxt, output_ctx, m, CLASS_METHOD);
        }
    }

      if (first_method == NULL)
    {
      emit_method_files (output_ctx, class_);
    }
      output_ctx (";\n");
    }

  return ((first_method != NULL || first_class_method != NULL));
}

/*
 * ex_contains_object_reference - see if a value contains a reference
 * to a database object.
 *    return: non-zero if there is an object reference in the value
 *    value(in): value to examine
 * Note:
 *    This is used during the dumping of the default values for attribute
 *    definitions in the schema file.
 *    When we encounter object references, we don't include them in
 *    the schema file, they must be included in the object file.
 *    This is public so it can be used by unload_object.c to tell when to
 *    dump the values in the object file.
 */
static int
ex_contains_object_reference (DB_VALUE * value)
{
  DB_TYPE type;
  DB_SET *set;
  int error;
  DB_VALUE setval;
  int has_object, size, i;

  has_object = 0;
  if (value != NULL)
    {
      if (DB_VALUE_TYPE (value) == DB_TYPE_OBJECT)
    {
      has_object = db_get_object (value) != NULL;
    }
      else if (TP_IS_SET_TYPE (DB_VALUE_TYPE (value)))
    {
      set = db_get_set (value);
      size = db_set_size (set);
      type = db_set_type (set);

      for (i = 0; i < size && !has_object; i++)
        {
          if (type == DB_TYPE_SEQUENCE)
        {
          error = db_seq_get (set, i, &setval);
        }
          else
        {
          error = db_set_get (set, i, &setval);
        }

          if (error)
        {
          /*
           * shouldn't happen, return 1 so we don't try to dump this
           * value
           */
          has_object = 1;
        }
          else
        {
          has_object = ex_contains_object_reference (&setval);
        }

          db_value_clear (&setval);
        }
    }
    }
  return has_object;
}

/*
 * emit_attribute_def - emit attribute definition
 *    return: void
 *    attribute(in): attribute descriptor
 *    qualifier(in): the qualifier for the attribute (default, class or shared)
 */
static void
emit_attribute_def (extract_context & ctxt, print_output & output_ctx, DB_ATTRIBUTE * attribute,
            ATTRIBUTE_QUALIFIER qualifier)
{
  DB_VALUE *default_value;
  const char *name;

  name = db_attribute_name (attribute);
  switch (qualifier)
    {
    case CLASS_ATTRIBUTE:
      /*
       * NOTE: The parser no longer recognizes a CLASS prefix for class
       * attributes, this will have been encoded in the surrounding
       * "ADD CLASS ATTRIBUTE" clause
       */
    case INSTANCE_ATTRIBUTE:
    case SHARED_ATTRIBUTE:
      {
    if (strchr (name, ']') != NULL)
      {
        output_ctx ("       %s%s%s ", PRINT_IDENTIFIER_WITH_QUOTE (name));
      }
    else
      {
        output_ctx ("       %s%s%s ", PRINT_IDENTIFIER (name));
      }
    break;
      }
    }

  emit_domain_def (ctxt, output_ctx, db_attribute_domain (attribute));

  if (emit_autoincrement_def (output_ctx, attribute) != NO_ERROR)
    {
      ;             /* just continue */
    }

  if (qualifier == SHARED_ATTRIBUTE)
    {
      output_ctx (" SHARED ");
    }

  default_value = db_attribute_default (attribute);
  if ((default_value != NULL && !DB_IS_NULL (default_value))
      || attribute->default_value.default_expr.default_expr_type != DB_DEFAULT_NONE)
    {
      const char *default_expr_type_str;

      if (qualifier != SHARED_ATTRIBUTE)
    {
      output_ctx (" DEFAULT ");
    }

      if (attribute->default_value.default_expr.default_expr_op == T_TO_CHAR)
    {
      output_ctx ("TO_CHAR(");
    }

      default_expr_type_str = db_default_expression_string (attribute->default_value.default_expr.default_expr_type);
      if (default_expr_type_str != NULL)
    {
      output_ctx ("%s", default_expr_type_str);
    }
      else
    {
      /* these are set during the object load phase */
      if (ex_contains_object_reference (default_value))
        {
          output_ctx ("NULL");
        }
      else
        {
          /* use the desc_ printer, need to have this in a better place */
          desc_value_print (output_ctx, default_value);
        }
    }

      if (attribute->default_value.default_expr.default_expr_op == T_TO_CHAR)
    {
      if (attribute->default_value.default_expr.default_expr_format != NULL)
        {
          output_ctx (", \'");
          output_ctx ("%s", attribute->default_value.default_expr.default_expr_format);
          output_ctx ("\'");
        }

      output_ctx (")");
    }
    }

  if (attribute->on_update_default_expr != DB_DEFAULT_NONE)
    {
      const char *default_expr_type_str;

      output_ctx (" ON UPDATE ");

      default_expr_type_str = db_default_expression_string (attribute->on_update_default_expr);
      if (default_expr_type_str != NULL)
    {
      output_ctx ("%s", default_expr_type_str);
    }
    }

  /* emit constraints */
  if (db_attribute_is_non_null (attribute))
    {
      output_ctx (" NOT NULL");
    }

  /* emit comment */
  if (attribute->comment != NULL && attribute->comment[0] != '\0')
    {
      output_ctx (" ");
      help_print_describe_comment (output_ctx, attribute->comment);
    }
}

/*
 * emit_unique_def - emit the unique constraint definitions for this class
 *    return: void
 *    class(in): the class to emit the attributes for
 */
static void
emit_unique_def (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_, const char *class_type)
{
  DB_CONSTRAINT *constraint_list, *constraint;
  DB_ATTRIBUTE **atts, **att;
  bool has_inherited_atts;
  int num_printed = 0;
  const char *name, *class_name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name_p = NULL;
  int not_online = 0;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  class_name = db_get_class_name (class_);

  /* First we must check if there is a unique one without the online index tag. */

  constraint_list = db_get_constraints (class_);
  if (constraint_list == NULL)
    {
      return;
    }

  for (constraint = constraint_list; constraint != NULL && not_online == 0;
       constraint = db_constraint_next (constraint))
    {
      if (db_constraint_type (constraint) != DB_CONSTRAINT_UNIQUE)
    {
      continue;
    }

      if (constraint->index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
    {
      /* Skip the unique index definitions for online indexes. */
      continue;
    }
      not_online++;
    }

  if (not_online == 0)
    {
      /* We need to return and not print anything. */
      return;
    }

  SPLIT_USER_SPECIFIED_NAME (class_name, owner_name, class_name_p);

  PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner, sizeof (output_owner));

  output_ctx ("\nALTER %s %s%s%s%s ADD ATTRIBUTE\n", class_type, output_owner, PRINT_IDENTIFIER (class_name_p));

  for (constraint = constraint_list; constraint != NULL; constraint = db_constraint_next (constraint))
    {
      if (db_constraint_type (constraint) != DB_CONSTRAINT_UNIQUE)
    {
      continue;
    }

      if (constraint->index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
    {
      /* Skip the unique index definitions for online indexes. */
      continue;
    }

      atts = db_constraint_attributes (constraint);
      has_inherited_atts = false;

      for (att = atts; *att != NULL; att++)
    {
      if (db_attribute_class (*att) != class_)
        {
          has_inherited_atts = true;
          break;
        }
    }

      if (!has_inherited_atts)
    {
      if (num_printed > 0)
        {
          output_ctx (",\n");
        }

      if (constraint->type == SM_CONSTRAINT_UNIQUE)
        {
          output_ctx ("       CONSTRAINT [%s] UNIQUE(", constraint->name);

          int i;
          for (att = atts, i = 0; *att != NULL; att++, i++)
        {
          name = db_attribute_name (*att);
          if (att != atts)
            {
              output_ctx (", ");
            }

          output_ctx ("%s%s%s", PRINT_IDENTIFIER (name));

          if (constraint->asc_desc != NULL && constraint->asc_desc[i] != 0)
            {
              output_ctx ("%s", " DESC");
            }
        }
          output_ctx (")");

          if (constraint->comment != NULL && constraint->comment[0] != '\0')
        {
          output_ctx (" ");
          help_print_describe_comment (output_ctx, constraint->comment);
        }
          ++num_printed;
        }
    }
    }
  output_ctx (";\n");
}

/*
 * emit_primary_key_def - emit the primary key constraint definitions for this class
 *    return: void
 *    class(in): the class to emit the attributes for
 */
static void
emit_primary_key_def (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_, const char *class_type)
{
  DB_CONSTRAINT *constraint_list, *constraint;
  DB_ATTRIBUTE **atts, **att;
  bool has_inherited_atts;
  int num_printed = 0;
  const char *name, *class_name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name_p = NULL;
  int not_online = 0;
  int i = 0;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  class_name = db_get_class_name (class_);

  /* First we must check if there is a unique one without the online index tag. */

  constraint_list = db_get_constraints (class_);
  if (constraint_list == NULL)
    {
      return;
    }

  for (constraint = constraint_list; constraint != NULL && not_online == 0;
       constraint = db_constraint_next (constraint))
    {
      if (db_constraint_type (constraint) != DB_CONSTRAINT_PRIMARY_KEY)
    {
      continue;
    }

      if (constraint->index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
    {
      /* Skip the unique index definitions for online indexes. */
      continue;
    }
      not_online++;
    }

  if (not_online == 0)
    {
      /* We need to return and not print anything. */
      return;
    }

  output_ctx ("\n");

  SPLIT_USER_SPECIFIED_NAME (class_name, owner_name, class_name_p);

  PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner, sizeof (output_owner));

  output_ctx ("ALTER %s %s%s%s%s ADD ATTRIBUTE\n", class_type, output_owner, PRINT_IDENTIFIER (class_name_p));

  for (constraint = constraint_list; constraint != NULL; constraint = db_constraint_next (constraint))
    {
      if (db_constraint_type (constraint) != DB_CONSTRAINT_UNIQUE
      && db_constraint_type (constraint) != DB_CONSTRAINT_PRIMARY_KEY)
    {
      continue;
    }

      if (constraint->index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
    {
      /* Skip the unique index definitions for online indexes. */
      continue;
    }

      atts = db_constraint_attributes (constraint);
      has_inherited_atts = false;

      for (att = atts; *att != NULL; att++)
    {
      if (db_attribute_class (*att) != class_)
        {
          has_inherited_atts = true;
          break;
        }
    }

      if (!has_inherited_atts)
    {
      if (constraint->type == SM_CONSTRAINT_PRIMARY_KEY)
        {
          if (num_printed > 0)
        {
          output_ctx (",\n");
        }

          output_ctx ("       CONSTRAINT [%s] PRIMARY KEY(", constraint->name);

          for (att = atts, i = 0; *att != NULL; att++, i++)
        {
          name = db_attribute_name (*att);
          if (att != atts)
            {
              output_ctx (", ");
            }

          output_ctx ("%s%s%s", PRINT_IDENTIFIER (name));

          if (constraint->asc_desc != NULL && constraint->asc_desc[i] != 0)
            {
              output_ctx ("%s", " DESC");
            }
        }
          output_ctx (")");
          if (constraint->comment != NULL && constraint->comment[0] != '\0')
        {
          output_ctx (" ");
          help_print_describe_comment (output_ctx, constraint->comment);
        }
          ++num_printed;
        }
    }
    }
  output_ctx (";\n");
}

/*
 * emit_primary_and_unique_def - emit the primary key and unique constraint definitions for this class
 *    return: void
 *    class(in): the class to emit the attributes for
 */
static void
emit_primary_and_unique_def (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_,
                 const char *class_type)
{
  DB_CONSTRAINT *constraint_list, *constraint;
  DB_ATTRIBUTE **atts, **att;
  bool has_inherited_atts;
  int num_printed = 0;
  const char *name, *class_name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name_p = NULL;
  int not_online = 0;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  class_name = db_get_class_name (class_);

  /* First we must check if there is a unique one without the online index tag. */

  constraint_list = db_get_constraints (class_);
  if (constraint_list == NULL)
    {
      return;
    }

  for (constraint = constraint_list; constraint != NULL && not_online == 0;
       constraint = db_constraint_next (constraint))
    {
      if (db_constraint_type (constraint) != DB_CONSTRAINT_UNIQUE
      && db_constraint_type (constraint) != DB_CONSTRAINT_PRIMARY_KEY)
    {
      continue;
    }

      if (constraint->index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
    {
      /* Skip the unique index definitions for online indexes. */
      continue;
    }
      not_online++;
    }

  if (not_online == 0)
    {
      /* We need to return and not print anything. */
      return;
    }

  SPLIT_USER_SPECIFIED_NAME (class_name, owner_name, class_name_p);

  PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner, sizeof (output_owner));

  output_ctx ("ALTER %s %s%s%s%s ADD ATTRIBUTE\n", class_type, output_owner, PRINT_IDENTIFIER (class_name_p));

  for (constraint = constraint_list; constraint != NULL; constraint = db_constraint_next (constraint))
    {
      if (db_constraint_type (constraint) != DB_CONSTRAINT_UNIQUE
      && db_constraint_type (constraint) != DB_CONSTRAINT_PRIMARY_KEY)
    {
      continue;
    }

      if (constraint->index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
    {
      /* Skip the unique index definitions for online indexes. */
      continue;
    }

      atts = db_constraint_attributes (constraint);
      has_inherited_atts = false;

      for (att = atts; *att != NULL; att++)
    {
      if (db_attribute_class (*att) != class_)
        {
          has_inherited_atts = true;
          break;
        }
    }

      if (!has_inherited_atts)
    {
      if (num_printed > 0)
        {
          output_ctx (",\n");
        }

      if (constraint->type == SM_CONSTRAINT_PRIMARY_KEY)
        {
          output_ctx ("       CONSTRAINT [%s] PRIMARY KEY(", constraint->name);
        }
      else
        {
          output_ctx ("       CONSTRAINT [%s] UNIQUE(", constraint->name);
        }

      int i;
      for (att = atts, i = 0; *att != NULL; att++, i++)
        {
          name = db_attribute_name (*att);
          if (att != atts)
        {
          output_ctx (", ");
        }

          output_ctx ("%s%s%s", PRINT_IDENTIFIER (name));

          if (constraint->asc_desc != NULL && constraint->asc_desc[i] != 0)
        {
          output_ctx ("%s", " DESC");
        }
        }
      output_ctx (")");

      if (constraint->comment != NULL && constraint->comment[0] != '\0')
        {
          output_ctx (" ");
          help_print_describe_comment (output_ctx, constraint->comment);
        }

      ++num_printed;
    }
    }

  output_ctx (";\n");
}

/*
 * emit_reverse_unique_def - emit a reverse unique index definition query part
 *    return: void
 *    class(in): class object
 */
static void
emit_reverse_unique_def (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_)
{
  DB_CONSTRAINT *constraint_list, *constraint;
  DB_ATTRIBUTE **atts, **att;
  bool has_inherited_atts;
  const char *name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  constraint_list = db_get_constraints (class_);
  if (constraint_list == NULL)
    {
      return;
    }

  for (constraint = constraint_list; constraint != NULL; constraint = db_constraint_next (constraint))
    {
      if (db_constraint_type (constraint) != DB_CONSTRAINT_REVERSE_UNIQUE)
    {
      continue;
    }

      if (constraint->index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
    {
      /* We skip definitions for unique indexes during online loading. */
      continue;
    }

      atts = db_constraint_attributes (constraint);
      has_inherited_atts = false;

      for (att = atts; *att != NULL; att++)
    {
      if (db_attribute_class (*att) != class_)
        {
          has_inherited_atts = true;
          break;
        }
    }

      if (!has_inherited_atts)
    {
      name = db_get_class_name (class_);
      SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

      output_ctx ("\nCREATE REVERSE UNIQUE INDEX %s%s%s on %s%s%s%s (", PRINT_IDENTIFIER (constraint->name),
              output_owner, PRINT_IDENTIFIER (class_name));

      for (att = atts; *att != NULL; att++)
        {
          name = db_attribute_name (*att);
          if (att != atts)
        {
          output_ctx (", ");
        }
          output_ctx ("%s%s%s", PRINT_IDENTIFIER (name));

          // reverse unique does not care for direction of the column.
        }

      output_ctx (")");

      if (constraint->comment != NULL && constraint->comment[0] != '\0')
        {
          output_ctx (" ");
          help_print_describe_comment (output_ctx, constraint->comment);
        }
    }
    }
  output_ctx (";\n");
}


/*
 * emit_index_def - emit the index constraint definitions for this class
 *    return: 
 *    class(in): the class to emit the indexes for
 */
static int
emit_index_def (extract_context & ctxt, print_output & output_ctx, DB_OBJECT * class_)
{
  DB_CONSTRAINT *constraint_list, *constraint;
  DB_CONSTRAINT_TYPE ctype;
  DB_ATTRIBUTE **atts, **att;
  const char *cls_name, *att_name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  int partitioned_subclass = 0, au_save;
  SM_CLASS *supclass = NULL;
  const int *asc_desc;
  const int *prefix_length;
  int k, n_attrs = 0;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };
  char reserved_col_buf[RESERVED_INDEX_ATTR_NAME_BUF_SIZE] = { 0x00, };

  PARSER_CONTEXT *parser = NULL;
  PARSER_VARCHAR *res_vstr = NULL;
  int error = NO_ERROR;
  bool is_fail = false;

  constraint_list = db_get_constraints (class_);
  if (constraint_list == NULL)
    {
      return error;
    }

  cls_name = db_get_class_name (class_);
  if (cls_name != NULL)
    {
      partitioned_subclass = do_is_partitioned_subclass (NULL, cls_name, NULL);
    }
  else
    {
      cls_name = "";
    }

  if (partitioned_subclass)
    {
      DB_OBJECT *root_op = NULL;
      AU_DISABLE (au_save);
      if (do_get_partition_parent (class_, &root_op) == NO_ERROR)
    {
      if (au_fetch_class (root_op, &supclass, AU_FETCH_READ, AU_SELECT) != NO_ERROR)
        {
          supclass = NULL;
        }
    }

      AU_ENABLE (au_save);
    }

  for (constraint = constraint_list; constraint != NULL; constraint = db_constraint_next (constraint))
    {
      ctype = db_constraint_type (constraint);
      if ((constraint->index_status != SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
      && (ctype != DB_CONSTRAINT_INDEX && ctype != DB_CONSTRAINT_REVERSE_INDEX))
    {
      continue;
    }

      if (supclass && classobj_find_class_index (supclass, constraint->name) != NULL)
    {
      continue;     /* same index skip */
    }

      SPLIT_USER_SPECIFIED_NAME (cls_name, owner_name, class_name);
      if (constraint->func_index_info)
    {
      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

      output_ctx ("CREATE %s%sINDEX %s%s%s ON %s%s%s%s (",
              (ctype == DB_CONSTRAINT_REVERSE_INDEX
               || ctype == DB_CONSTRAINT_REVERSE_UNIQUE) ? "REVERSE " : "", (ctype == DB_CONSTRAINT_UNIQUE
                                             || ctype ==
                                             DB_CONSTRAINT_REVERSE_UNIQUE) ?
              "UNIQUE " : "", PRINT_FUNCTION_INDEX_NAME (constraint->name), output_owner,
              PRINT_IDENTIFIER (class_name));
    }
      else
    {
      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

      output_ctx ("CREATE %s%sINDEX %s%s%s ON %s%s%s%s (",
              (ctype == DB_CONSTRAINT_REVERSE_INDEX
               || ctype == DB_CONSTRAINT_REVERSE_UNIQUE) ? "REVERSE " : "", (ctype == DB_CONSTRAINT_UNIQUE
                                             || ctype ==
                                             DB_CONSTRAINT_REVERSE_UNIQUE) ?
              "UNIQUE " : "", PRINT_IDENTIFIER (constraint->name), output_owner, PRINT_IDENTIFIER (class_name));
    }

      asc_desc = NULL;      /* init */
      prefix_length = NULL;
      if (ctype == DB_CONSTRAINT_INDEX)
    {           /* is not reverse index */
      /* need to get asc/desc info */
      asc_desc = db_constraint_asc_desc (constraint);
      prefix_length = db_constraint_prefix_length (constraint);
    }
      else if (ctype == DB_CONSTRAINT_UNIQUE)
    {           /* is not reverse unique index */
      /* need to get asc/desc info */
      asc_desc = db_constraint_asc_desc (constraint);
    }

      atts = db_constraint_attributes (constraint);

      if (constraint->func_index_info)
    {
      n_attrs = constraint->func_index_info->attr_index_start + 1;
    }
      else
    {
      n_attrs = 0;
      for (att = atts; *att != NULL; att++)
        {
          n_attrs++;
        }
    }

      reserved_col_buf[0] = '\0';
      if (!DB_IS_CONSTRAINT_UNIQUE_FAMILY (ctype))
    {
      k = dk_sm_deduplicate_key_position (n_attrs, atts, constraint->func_index_info);
      if (k != -1)
        {
          if (constraint->func_index_info && constraint->func_index_info->attr_index_start > 0)
        {
          k--;
        }

          if (IS_DEDUPLICATE_KEY_ATTR_ID (atts[k]->id))
        {
          dk_print_deduplicate_key_info (reserved_col_buf, sizeof (reserved_col_buf),
                         GET_DEDUPLICATE_KEY_ATTR_LEVEL (atts[k]->id));
          n_attrs--;    /* Hidden column should not be displayed. */
        }
        }
    }

      is_fail = false;
      k = 0;
      for (att = atts; k < n_attrs; att++)
    {
      if (constraint->func_index_info)
        {
          if (k == constraint->func_index_info->col_id)
        {
          if (k > 0)
            {
              output_ctx (", ");
            }

          res_vstr = do_recreate_where_clause_or_function_attr (&parser, cls_name, constraint, false);
          if (res_vstr)
            {
              output_ctx ("%s", res_vstr->bytes);
            }
          else
            {
              output_ctx ("%s", constraint->func_index_info->expr_str);
              error = ER_FAILED;
              is_fail = true;
            }
          if (constraint->func_index_info->fi_domain->is_desc)
            {
              output_ctx ("%s", " DESC");
            }

          k++;
          if (k == n_attrs)
            {
              break;
            }
        }
        }
      att_name = db_attribute_name (*att);
      if (k > 0)
        {
          output_ctx (", ");
        }
      output_ctx ("%s%s%s", PRINT_IDENTIFIER (att_name));

      if (prefix_length)
        {
          if (*prefix_length >= 0)
        {
          output_ctx (" (%d)", *prefix_length);
        }
          prefix_length++;
        }

      if (asc_desc)
        {
          if (*asc_desc == 1)
        {
          output_ctx ("%s", " DESC");
        }
          asc_desc++;
        }
      k++;
    }

      if (constraint->filter_predicate)
    {
      if (constraint->filter_predicate->pred_string)
        {

          res_vstr = do_recreate_where_clause_or_function_attr (&parser, cls_name, constraint, true);
          if (res_vstr)
        {
          output_ctx (") where %s", res_vstr->bytes);
        }
          else
        {
          output_ctx (") where %s", constraint->filter_predicate->pred_string);
          error = ER_FAILED;
          is_fail = true;
        }
        }
    }
      else
    {
      output_ctx (")");
    }

      /* Safeguard. */
      /* If it's unique then it must surely be with online flag. */
      assert ((constraint->index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
          || (ctype != DB_CONSTRAINT_UNIQUE && ctype != DB_CONSTRAINT_REVERSE_UNIQUE));

      if ((reserved_col_buf[0] == '\0') && !DB_IS_CONSTRAINT_UNIQUE_FAMILY (ctype))
    {
      dk_print_deduplicate_key_info (reserved_col_buf, sizeof (reserved_col_buf), DEDUPLICATE_KEY_LEVEL_OFF);
    }
      if (reserved_col_buf[0])
    {
      if (constraint->index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
        {
          output_ctx (" WITH %s, ONLINE", reserved_col_buf);
        }
      else
        {
          output_ctx (" WITH %s", reserved_col_buf);
        }
    }
      else if (constraint->index_status == SM_ONLINE_INDEX_BUILDING_IN_PROGRESS)
    {
      output_ctx (" WITH ONLINE");
    }

      if (constraint->index_status == SM_INVISIBLE_INDEX)
    {
      output_ctx (" INVISIBLE ");
    }

      if (constraint->comment != NULL && constraint->comment[0] != '\0')
    {
      output_ctx (" ");
      help_print_describe_comment (output_ctx, constraint->comment);
    }

      if (is_fail == false)
    {
      output_ctx (";\n");
    }
      else
    {
      output_ctx (";%s\n", (parser ? "    /* Failure: Could be an error(Column name may be incorrect) */ "
                : "    /* Notice: Could be an error */ "));
    }
    }

  if (parser)
    {
      parser_free_parser (parser);
    }

  return error;
}


/*
 * emit_domain_def - emit a domain defintion part
 *    return: void
 *    domains(in): domain list
 */
static void
emit_domain_def (extract_context & ctxt, print_output & output_ctx, DB_DOMAIN * domains)
{
  DB_TYPE type;
  const PR_TYPE *prtype;
  DB_DOMAIN *domain;
  DB_OBJECT *class_;
  int precision;
  int has_collation;
  const char *name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  const char *json_schema;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  for (domain = domains; domain != NULL; domain = db_domain_next (domain))
    {
      type = TP_DOMAIN_TYPE (domain);
      prtype = pr_type_from_id (type);
      if (prtype == NULL)
    {
      continue;
    }

      if (type == DB_TYPE_OBJECT)
    {
      class_ = db_domain_class (domain);
      if (class_ == NULL)
        {
          output_ctx ("%s", prtype->name);
        }
      else
        {
          name = db_get_class_name (class_);
          SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

          PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

          output_ctx ("%s%s%s%s", output_owner, PRINT_IDENTIFIER (class_name));
        }
    }
      else
    {
      has_collation = 0;
      output_ctx ("%s", prtype->name);

      switch (type)
        {
        case DB_TYPE_VARCHAR:
        case DB_TYPE_CHAR:
          has_collation = 1;
          [[fallthrough]];
        case DB_TYPE_BIT:
        case DB_TYPE_VARBIT:
          precision = db_domain_precision (domain);
          output_ctx ("(%d)", precision == TP_FLOATING_PRECISION_VALUE ? DB_MAX_STRING_LENGTH : precision);
          break;

        case DB_TYPE_ENUMERATION:
          {
        int i = 0;
        DB_ENUM_ELEMENT *elem = NULL;
        int count = DOM_GET_ENUM_ELEMS_COUNT (domain);

        if (count == 0)
          {
            /* empty enumeration */
            output_ctx ("()");
            break;
          }

        output_ctx ("(");
        for (i = 1; i < count; i++)
          {
            elem = &DOM_GET_ENUM_ELEM (domain, i);
            output_ctx ("'%s', ", DB_GET_ENUM_ELEM_STRING (elem));
          }
        elem = &DOM_GET_ENUM_ELEM (domain, count);
        output_ctx ("'%s')", DB_GET_ENUM_ELEM_STRING (elem));
        has_collation = 1;
        break;
          }

        case DB_TYPE_NUMERIC:
          output_ctx ("(%d,%d)", db_domain_precision (domain), db_domain_scale (domain));
          break;

        case DB_TYPE_SET:
        case DB_TYPE_MULTISET:
        case DB_TYPE_SEQUENCE:
          output_ctx ("(");
          emit_domain_def (ctxt, output_ctx, db_domain_set (domain));
          output_ctx (")");
          break;

        case DB_TYPE_JSON:
          json_schema = db_domain_raw_json_schema (domain);
          if (json_schema != NULL)
        {
          output_ctx ("('%s')", json_schema);
        }
          break;

        default:
          break;
        }

      if (has_collation)
        {
          (void) output_ctx (" COLLATE %s", lang_get_collation_name (domain->collation_id));
        }
    }

      if (db_domain_next (domain) != NULL)
    {
      output_ctx (",");
    }
    }
}

/*
 * emit_autoincrement_def - emit a auto-increment query part
 *    return: void
 *    attribute(in): attribute to add query part for
 */
static int
emit_autoincrement_def (print_output & output_ctx, DB_ATTRIBUTE * attribute)
{
  int error = NO_ERROR;
  DB_VALUE min_val, inc_val;
  char str_buf[NUMERIC_MAX_STRING_SIZE];

  if (attribute->auto_increment != NULL)
    {
      db_make_null (&min_val);
      db_make_null (&inc_val);

      error = db_get (attribute->auto_increment, "min_val", &min_val);
      if (error < 0)
    {
      return error;
    }

      error = db_get (attribute->auto_increment, "increment_val", &inc_val);
      if (error < 0)
    {
      pr_clear_value (&min_val);
      return error;
    }

      output_ctx (" AUTO_INCREMENT(%s", numeric_db_value_print (&min_val, str_buf));
      output_ctx (", %s)", numeric_db_value_print (&inc_val, str_buf));

      pr_clear_value (&min_val);
      pr_clear_value (&inc_val);
    }

  return error;
}


/*
 * emit_method_def - emit method definitnio query
 *    return: void
 *    method(in): method
 *    qualifier(in): the qualifier for this method (default or class)
 */
static void
emit_method_def (extract_context & ctxt, print_output & output_ctx, DB_METHOD * method, METHOD_QUALIFIER qualifier)
{
  int arg_count, i;
  DB_DOMAIN *method_return_domain;
  const char *method_function_name;
  const char *name;

  name = db_method_name (method);

  switch (qualifier)
    {
    case INSTANCE_METHOD:
      {
    if (name != NULL)
      {
        output_ctx ("       %s%s%s(", PRINT_IDENTIFIER (name));
      }
    break;
      }             /* case INSTANCE_METHOD */
    case CLASS_METHOD:
      {
    if (name != NULL)
      {
        output_ctx ("CLASS  %s%s%s(", PRINT_IDENTIFIER (name));
      }
    break;
      }             /* case CLASS_METHOD */
    }

  /*
   * Emit argument type list
   */
  arg_count = db_method_arg_count (method);
  /* recall that arguments are numbered from 1 */
  for (i = 1; i < arg_count; i++)
    {
      emit_domain_def (ctxt, output_ctx, db_method_arg_domain (method, i));
      output_ctx (", ");
    }

  if (arg_count)
    {
      emit_domain_def (ctxt, output_ctx, db_method_arg_domain (method, i));
    }

  output_ctx (") ");

  /*
   * Emit method return domain
   */
  method_return_domain = db_method_return_domain (method);
  if (method_return_domain != NULL)
    {
      emit_domain_def (ctxt, output_ctx, db_method_return_domain (method));
    }

  /*
   * Emit method function implementation
   */
  method_function_name = db_method_function (method);
  if (method_function_name != NULL)
    {
      name = db_method_function (method);
      if (name != NULL)
    {
      output_ctx (" FUNCTION %s%s%s", PRINT_IDENTIFIER (name));
    }
    }
}


/*
 * emit_methfile_def - emit method file name
 *    return: nothing
 *    methfile(in): method file
 */
static void
emit_methfile_def (print_output & output_ctx, DB_METHFILE * methfile)
{
  output_ctx ("   '%s'", db_methfile_name (methfile));
}

/*
 * emit_partition_parts - emit PARTITION query part
 *    return: void
 *    parts(in): part MOP
 *    partcnt(in): relative position of 'parts'
 */
static void
emit_partition_parts (print_output & output_ctx, SM_PARTITION * partition_info, int partcnt)
{
  DB_VALUE ele;
  int setsize, i1;

  if (partition_info == NULL)
    {
      return;
    }

  if (partcnt > 0)
    {
      output_ctx (",\n ");
    }

  output_ctx ("PARTITION %s%s%s ", PRINT_IDENTIFIER (partition_info->pname));

  switch (partition_info->partition_type)
    {
    case PT_PARTITION_RANGE:
      output_ctx (" VALUES LESS THAN ");
      if (!set_get_element_nocopy (partition_info->values, 1, &ele))
    {           /* 0:MIN, 1:MAX */
      if (DB_IS_NULL (&ele))
        {
          output_ctx ("MAXVALUE");
        }
      else
        {
          output_ctx ("(");
          desc_value_print (output_ctx, &ele);
          output_ctx (")");
        }
    }
      break;
    case PT_PARTITION_LIST:
      output_ctx (" VALUES IN (");
      setsize = set_size (partition_info->values);

      for (i1 = 0; i1 < setsize; i1++)
    {
      if (i1 > 0)
        {
          output_ctx (", ");
        }

      if (!set_get_element_nocopy (partition_info->values, i1, &ele))
        {
          desc_value_print (output_ctx, &ele);
        }
    }

      output_ctx (")");
      break;
    }

  if (partition_info->comment != NULL && partition_info->comment[0] != '\0')
    {
      output_ctx (" ");
      help_print_describe_comment (output_ctx, partition_info->comment);
    }
}

/*
 * emit_partition_info - emit PARTINTION query for a class
 *    return: void
 *    clsobj(in): class object
 */
static void
emit_partition_info (extract_context & ctxt, print_output & output_ctx, MOP clsobj)
{
  DB_VALUE ele;
  int partcnt = 0;
  char *ptr, *ptr2;
  const char *name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  SM_CLASS *class_, *subclass;
  DB_OBJLIST *user;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  if (clsobj == NULL)
    {
      return;
    }

  name = db_get_class_name (clsobj);
  if (au_fetch_class (clsobj, &class_, AU_FETCH_READ, AU_SELECT) != NO_ERROR)
    {
      return;
    }

  SPLIT_USER_SPECIFIED_NAME (name, owner_name, class_name);

  PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner, sizeof (output_owner));

  output_ctx ("\nALTER CLASS %s%s%s%s ", output_owner, PRINT_IDENTIFIER (class_name));
  output_ctx ("\nPARTITION BY ");

  if (class_->partition->expr != NULL)
    {
      switch (class_->partition->partition_type)
    {
    case PT_PARTITION_HASH:
      output_ctx ("HASH ( ");
      break;
    case PT_PARTITION_RANGE:
      output_ctx ("RANGE ( ");
      break;
    case PT_PARTITION_LIST:
      output_ctx ("LIST ( ");
      break;
    }

      ptr = (char *) strstr (class_->partition->expr, "SELECT ");
      if (ptr)
    {
      ptr2 = strstr (ptr + 7, " FROM ");
      if (ptr2)
        {
          *ptr2 = 0;
          output_ctx ("%s", ptr + 7);
          output_ctx (" ) \n ");
        }
    }

      if (class_->partition->partition_type == PT_PARTITION_HASH)
    {
      if (!set_get_element_nocopy (class_->partition->values, 1, &ele))
        {
          output_ctx (" PARTITIONS %d", db_get_int (&ele));
        }
    }
      else
    {
      output_ctx (" ( ");
      for (user = class_->users; user != NULL; user = user->next)
        {
          if (au_fetch_class (user->op, &subclass, AU_FETCH_READ, AU_SELECT) == NO_ERROR)
        {
          if (subclass->partition)
            {
              emit_partition_parts (output_ctx, subclass->partition, partcnt);
              partcnt++;
            }
        }
        }
      output_ctx (" ) ");
    }
    }
  else
    {
      /* FIXME */
    }
  output_ctx (";\n");
}

/*
 * emit_stored_procedure_args - emit stored procedure arguments
 *    return: 0 if success, error count otherwise
 *    arg_cnt(in): argument count
 *    arg_set(in): set containg argument DB_VALUE
 */
static int
emit_stored_procedure_args (print_output & output_ctx, int arg_cnt, DB_SET * arg_set)
{
  MOP arg;
  DB_VALUE arg_val, arg_name_val, arg_mode_val, arg_type_val, arg_comment_val;
  int arg_mode, arg_type, i, save;
  int err;
  int err_count = 0;

  AU_DISABLE (save);

  for (i = 0; i < arg_cnt; i++)
    {
      err = set_get_element (arg_set, i, &arg_val);
      if (err != NO_ERROR)
    {
      err_count++;
      continue;
    }

      arg = db_get_object (&arg_val);

      if ((err = db_get (arg, SP_ARG_ATTR_ARG_NAME, &arg_name_val)) != NO_ERROR
      || (err = db_get (arg, SP_ARG_ATTR_MODE, &arg_mode_val)) != NO_ERROR
      || (err = db_get (arg, SP_ARG_ATTR_DATA_TYPE, &arg_type_val)) != NO_ERROR
      || (err = db_get (arg, SP_ARG_ATTR_COMMENT, &arg_comment_val)) != NO_ERROR)
    {
      err_count++;
      continue;
    }

      output_ctx ("%s%s%s ", PRINT_IDENTIFIER (db_get_string (&arg_name_val)));

      arg_mode = db_get_int (&arg_mode_val);
      output_ctx ("%s ", arg_mode == SP_MODE_IN ? "IN" : arg_mode == SP_MODE_OUT ? "OUT" : "INOUT");

      arg_type = db_get_int (&arg_type_val);

      if (arg_type == DB_TYPE_RESULTSET)
    {
      output_ctx ("CURSOR");
    }
      else
    {
      output_ctx ("%s", db_get_type_name ((DB_TYPE) arg_type));
    }

      if (!DB_IS_NULL (&arg_comment_val))
    {
      output_ctx (" COMMENT ");
      desc_value_print (output_ctx, &arg_comment_val);
    }

      if (i < arg_cnt - 1)
    {
      output_ctx (", ");
    }

      pr_clear_value (&arg_val);
    }

  AU_ENABLE (save);
  return err_count;
}

/*
 * emit_stored_procedure_pre - emit stored procedure (Dummy PL/CSQL and Java SP)
 *    return: void
 *    output_ctx(in/out): output context
 */
static int
emit_stored_procedure_pre (extract_context & ctxt, print_output & output_ctx)
{
  MOP cls, obj, owner;
  DB_OBJLIST *sp_list = NULL, *cur_sp;
  DB_VALUE unique_name_val, sp_name_val, pkg_name_val, sp_type_val, arg_cnt_val, lang_val, generated_val, args_val,
    rtn_type_val, class_val, method_val, directive_val, comment_val;
  DB_VALUE owner_val, owner_name_val;
  int sp_type, rtn_type, arg_cnt, directive, save;
  DB_SET *arg_set;
  int err;
  int err_count = 0;
  char owner_name[DB_MAX_USER_LENGTH];
  owner_name[0] = '\0';
  char output_owner[DB_MAX_USER_LENGTH + 4];
  output_owner[0] = '\0';

  AU_DISABLE (save);

  cls = db_find_class (SP_CLASS_NAME);
  if (cls == NULL)
    {
      AU_ENABLE (save);
      return 1;
    }

  sp_list = db_get_all_objects (cls);
  for (cur_sp = sp_list; cur_sp; cur_sp = cur_sp->next)
    {
      obj = cur_sp->op;

      if ((err = db_get (obj, SP_ATTR_IS_SYSTEM_GENERATED, &generated_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_LANG, &lang_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_OWNER, &owner_val)) != NO_ERROR)
    {
      err_count++;
      continue;
    }

      if (db_get_int (&generated_val) == 1)
    {
      continue;
    }

      // owner
      owner = db_get_object (&owner_val);
      err = db_get (owner, "name", &owner_name_val);
      if (err != NO_ERROR)
    {
      err_count++;
      continue;
    }

      if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
    {
      if (strcasecmp (ctxt.login_user, db_get_string (&owner_name_val)) != 0)
        {
          db_value_clear (&owner_name_val);
          continue;
        }
    }

      if ((err = db_get (obj, SP_ATTR_SP_TYPE, &sp_type_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_UNIQUE_NAME, &unique_name_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_SP_NAME, &sp_name_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_PKG_NAME, &pkg_name_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_ARG_COUNT, &arg_cnt_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_ARGS, &args_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_RETURN_TYPE, &rtn_type_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_DIRECTIVE, &directive_val)) != NO_ERROR)
    {
      err_count++;
      continue;
    }

      sp_type = db_get_int (&sp_type_val);

      output_ctx ("\nCREATE %s", sp_type == SP_TYPE_PROCEDURE ? "PROCEDURE" : "FUNCTION");

      // unique_name
      const char *unique_name = db_get_string (&unique_name_val);
      // sp_name
      const char *sp_name = db_get_string (&sp_name_val);
      sm_qualifier_name (unique_name, owner_name, DB_MAX_USER_LENGTH);
      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
            sizeof (output_owner));

      if (!DB_IS_NULL (&pkg_name_val))
    {
      const char *pkg_name = db_get_string (&pkg_name_val);
      output_ctx (" %s%s%s.%s%s%s (", PRINT_IDENTIFIER (pkg_name), PRINT_IDENTIFIER (sp_name));
      db_value_clear (&pkg_name_val);
    }
      else
    {
      output_ctx (" %s%s%s%s (", output_owner, PRINT_IDENTIFIER (sp_name));
    }

      arg_cnt = db_get_int (&arg_cnt_val);
      arg_set = db_get_set (&args_val);
      if (emit_stored_procedure_args (output_ctx, arg_cnt, arg_set) > 0)
    {
      err_count++;
      output_ctx (";\n");
      continue;
    }
      output_ctx (") ");

      if (sp_type == SP_TYPE_FUNCTION)
    {
      rtn_type = db_get_int (&rtn_type_val);

      if (rtn_type == DB_TYPE_RESULTSET)
        {
          output_ctx ("RETURN CURSOR ");
        }
      else
        {
          output_ctx ("RETURN %s ", db_get_type_name ((DB_TYPE) rtn_type));
        }
    }

      // authid
      directive = db_get_int (&directive_val);
      if (directive & SP_DIRECTIVE_ENUM::SP_DIRECTIVE_RIGHTS_CALLER)
    {
      output_ctx ("AUTHID CALLER ");
    }
      else
    {
      output_ctx ("AUTHID OWNER ");
    }

      // dtrm_type
      if (directive & SP_DIRECTIVE_ENUM::SP_DIRECTIVE_DETERMINISTIC)
    {
      output_ctx ("DETERMINISTIC ");
    }

      int sp_lang = db_get_int (&lang_val);
      if (sp_lang == SP_LANG_PLCSQL)
    {
      output_ctx ("AS LANGUAGE PLCSQL BEGIN ");
      output_ctx
        ("RAISE_APPLICATION_ERROR(1001, '%s%s%s%s: incomplete during loaddb'); /* __CUBRID_NO_BODY__ */",
         output_owner, PRINT_IDENTIFIER (sp_name));
      output_ctx (" END;\n");
    }
      else
    {
      if ((err = db_get (obj, SP_ATTR_TARGET_CLASS, &class_val)) != NO_ERROR
          || (err = db_get (obj, SP_ATTR_TARGET_METHOD, &method_val)) != NO_ERROR
          || (err = db_get (obj, SP_ATTR_COMMENT, &comment_val)) != NO_ERROR)
        {
          err_count++;
          continue;
        }

      output_ctx ("AS LANGUAGE JAVA NAME '%s.%s'", db_get_string (&class_val), db_get_string (&method_val));
      db_value_clear (&class_val);
      db_value_clear (&method_val);

      if (!DB_IS_NULL (&comment_val))
        {
          output_ctx (" COMMENT ");
          desc_value_print (output_ctx, &comment_val);
        }

      output_ctx (";\n");
    }
      db_value_clear (&sp_name_val);
      db_value_clear (&unique_name_val);
      db_value_clear (&owner_name_val);
    }

  db_objlist_free (sp_list);
  AU_ENABLE (save);

  return err_count;
}

/*
 * emit_stored_procedure_post - emit stored procedure
 *    return: void
 *    output_ctx(in/out): output context
 */
static int
emit_stored_procedure_post (extract_context & ctxt, print_output & output_ctx)
{
  MOP cls, obj, owner;
  DB_OBJLIST *sp_list = NULL, *cur_sp;
  DB_VALUE lang_val, owner_val, owner_name_val, generated_val, class_val, comment_val;
  int save;
  int err;
  int err_count = 0;
  const char *owner_name;

  AU_DISABLE (save);

  cls = db_find_class (SP_CLASS_NAME);
  if (cls == NULL)
    {
      AU_ENABLE (save);
      return 1;
    }

  sp_list = db_get_all_objects (cls);
  for (cur_sp = sp_list; cur_sp; cur_sp = cur_sp->next)
    {
      obj = cur_sp->op;

      if ((err = db_get (obj, SP_ATTR_IS_SYSTEM_GENERATED, &generated_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_LANG, &lang_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_OWNER, &owner_val)) != NO_ERROR
      || (err = db_get (obj, SP_ATTR_COMMENT, &comment_val)) != NO_ERROR)
    {
      err_count++;
      continue;
    }

      if (db_get_int (&generated_val) == 1)
    {
      continue;
    }

      // owner
      owner = db_get_object (&owner_val);
      err = db_get (owner, "name", &owner_name_val);
      if (err != NO_ERROR)
    {
      err_count++;
      continue;
    }

      owner_name = db_get_string (&owner_name_val);
      if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
    {
      if (strcasecmp (ctxt.login_user, owner_name) != 0)
        {
          db_value_clear (&owner_name_val);
          continue;
        }
    }

      int sp_lang = db_get_int (&lang_val);
      if (sp_lang == SP_LANG_PLCSQL)
    {
      if ((err = db_get (obj, SP_ATTR_TARGET_CLASS, &class_val)) != NO_ERROR)
        {
          err_count++;
          continue;
        }

      const char *target_class = db_get_string (&class_val);
      err = emit_stored_procedure_code (ctxt, output_ctx, target_class, owner_name, &comment_val);
      output_ctx ("\n");

      db_value_clear (&class_val);
      if (err > 0)
        {
          err_count++;
          continue;
        }
    }

      db_value_clear (&owner_name_val);
    }

  db_objlist_free (sp_list);
  AU_ENABLE (save);

  return err_count;
}

/*
 * emit_stored_procedure_code - emit stored procedure code
 *    return: 0 if success, error count otherwise
 *    code_name(in): code name
 *    owner_name(in): owner name
 */
static int
emit_stored_procedure_code (extract_context & ctxt, print_output & output_ctx, const char *code_name,
                const char *owner_name, DB_VALUE * comment)
{
  MOP obj;
  int save, err = NO_ERROR;
  DB_VALUE value, stype_val, scode_val;
  int stype;
  PARSER_CONTEXT *parser = NULL;
  PT_NODE **scode_ptr;
  char *scode_ptr_result = NULL;
  char downcase_owner_name[DB_MAX_USER_LENGTH];
  downcase_owner_name[0] = '\0';

  AU_DISABLE (save);

  db_make_string (&value, code_name);
  obj = db_find_unique (db_find_class (SP_CODE_CLASS_NAME), SP_CODE_ATTR_NAME, &value);
  if (obj == NULL)
    {
      err = ER_FAILED;
      goto exit;
    }


  if ((err = db_get (obj, SP_CODE_ATTR_STYPE, &stype_val)) != NO_ERROR
      || (err = db_get (obj, SP_CODE_ATTR_SCODE, &scode_val)) != NO_ERROR)
    {
      goto exit;
    }

  stype = db_get_int (&stype_val);
  if (stype == SPSC_PLCSQL)
    {
      const char *scode = db_get_string (&scode_val);
      parser = parser_create_parser ();
      if (parser == NULL)
    {
      err = ER_FAILED;
      goto exit;
    }

      scode_ptr = parser_parse_string (parser, scode);
      if (scode_ptr != NULL)
    {
      if ((*scode_ptr)->info.sp.comment)
        {
          assert (false);   // scode does not have the comment: CBRD-26513
          er_log_debug (ARG_FILE_LINE, "emit_stored_procedure_code: unexpected comment node in scode\n");
          (*scode_ptr)->info.sp.comment = NULL;
        }

      if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
        {
          parser->custom_print |= PT_PRINT_NO_CURRENT_USER_NAME;
        }
      else
        {
          PT_NODE *sp_name = (*scode_ptr)->info.sp.name;
          if (sp_name->info.name.resolved == NULL)
        {
          sm_downcase_name (owner_name, downcase_owner_name, DB_MAX_USER_LENGTH);
          sp_name->info.name.resolved = pt_append_string (parser, NULL, downcase_owner_name);
        }
        }

      parser->flag.is_unloading_plcsql_def = 1;
      scode_ptr_result = parser_print_tree_with_quotes (parser, *scode_ptr);
    }

      if (scode_ptr_result)
    {
      output_ctx ("\n%s", scode_ptr_result);
      if (!DB_IS_NULL (comment))
        {
          output_ctx (" COMMENT ");
          desc_value_print (output_ctx, comment);
        }
    }
      else
    {
      output_ctx ("\n/* error occurs: %s \n\n %s; \n*/", parser->error_buffer ? parser->error_buffer : "", scode);
    }
    }
  output_ctx (";");

exit:

  if (parser)
    {
      parser_free_parser (parser);
    }

  db_value_clear (&value);
  db_value_clear (&scode_val);
  AU_ENABLE (save);

  return err;
}

/*
 * emit_foreign_key - emit foreign key
 *    return: NO_ERROR if successful, error code otherwise
 *    output_ctx(in/out): output context
 *    classes(in): MOP list for dump foreign key
 */
static int
emit_foreign_key (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes)
{
  DB_OBJLIST *cl;
  DB_CONSTRAINT *constraint_list, *constraint;
  DB_ATTRIBUTE **atts, **att;
  bool has_inherited_atts;
  const char *cls_name, *att_name;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };
  char *class_name = NULL;
  MOP ref_clsop;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };
  char reserved_col_buf[RESERVED_INDEX_ATTR_NAME_BUF_SIZE] = { 0x00, };

  for (cl = classes; cl != NULL; cl = cl->next)
    {
      constraint_list = db_get_constraints (cl->op);
      cls_name = db_get_class_name (cl->op);

      for (constraint = constraint_list; constraint != NULL; constraint = db_constraint_next (constraint))
    {
      if (db_constraint_type (constraint) != DB_CONSTRAINT_FOREIGN_KEY)
        {
          continue;
        }

      atts = db_constraint_attributes (constraint);
      has_inherited_atts = false;
      for (att = atts; *att != NULL; att++)
        {
          if (db_attribute_class (*att) != cl->op)
        {
          if (IS_DEDUPLICATE_KEY_ATTR_ID ((*att)->id))
            {
              assert (!SM_IS_CONSTRAINT_UNIQUE_FAMILY (constraint->type));
              assert (att[1] == NULL);
              break;
            }
          has_inherited_atts = true;
          break;
        }
        }

      if (has_inherited_atts)
        {
          continue;
        }

      SPLIT_USER_SPECIFIED_NAME (cls_name, owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

      output_ctx ("\nALTER CLASS %s%s%s%s ADD", output_owner, PRINT_IDENTIFIER (class_name));
      output_ctx (" CONSTRAINT [%s] FOREIGN KEY(", constraint->name);

      reserved_col_buf[0] = '\0';
      for (att = atts; *att != NULL; att++)
        {
          if (IS_DEDUPLICATE_KEY_ATTR_ID (att[0]->id))
        {
          assert (att[1] == NULL);
          dk_print_deduplicate_key_info (reserved_col_buf, sizeof (reserved_col_buf),
                         GET_DEDUPLICATE_KEY_ATTR_LEVEL (att[0]->id));
          break;
        }

          att_name = db_attribute_name (*att);
          if (att != atts)
        {
          output_ctx (", %s%s%s", PRINT_IDENTIFIER (att_name));
        }
          else
        {
          output_ctx ("%s%s%s", PRINT_IDENTIFIER (att_name));
        }
        }
      output_ctx (")");

      if (reserved_col_buf[0] == '\0')
        {
          dk_print_deduplicate_key_info (reserved_col_buf, sizeof (reserved_col_buf), DEDUPLICATE_KEY_LEVEL_OFF);
        }
      if (reserved_col_buf[0])
        {
          output_ctx (" WITH %s", reserved_col_buf);
        }

      ref_clsop = ws_mop (&(constraint->fk_info->ref_class_oid), NULL);
      SPLIT_USER_SPECIFIED_NAME (db_get_class_name (ref_clsop), owner_name, class_name);

      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

      output_ctx (" REFERENCES %s%s%s%s ", output_owner, PRINT_IDENTIFIER (class_name));
      output_ctx ("ON DELETE %s ", classobj_describe_foreign_key_action (constraint->fk_info->delete_action));
      output_ctx ("ON UPDATE %s ", classobj_describe_foreign_key_action (constraint->fk_info->update_action));

      if (constraint->comment != NULL && constraint->comment[0] != '\0')
        {
          output_ctx (" ");
          help_print_describe_comment (output_ctx, constraint->comment);
        }

      (void) output_ctx (";\n");
    }
    }

  return NO_ERROR;
}

static int
export_server (extract_context & ctxt, print_output & output_ctx)
{
  int error = NO_ERROR;
  int i;
  DB_QUERY_RESULT *query_result;
  DB_QUERY_ERROR query_error;
#define SERVER_VALUE_INDEX_MAX   (10)
  DB_VALUE values[SERVER_VALUE_INDEX_MAX];
  char *srv_name, *owner_name, *str;
  char *uppercase_user = NULL;
  size_t uppercase_user_size = 0;
  size_t query_size = 0;
  char *query = NULL;
  char output_owner[DB_MAX_USER_LENGTH + 4] = { '\0' };

  const char *attr_names[SERVER_VALUE_INDEX_MAX] = {
    "link_name", "host", "port", "db_name", "user_name", "password", "properties", "comment", "owner_name", "owner_obj"
  };

  const char *query_all =
    "SELECT [link_name], [host], [port], [db_name], [user_name], [password], [properties], [comment],"
    "[owner].[name] [owner_name], [owner] [owner_obj] FROM [_db_server] WHERE [link_name] IS NOT NULL";

  const char *query_user =
    "SELECT [link_name], [host], [port], [db_name], [user_name], [password], [properties], [comment],"
    "[owner].[name] [owner_name], [owner] [owner_obj] FROM [_db_server] WHERE [link_name] IS NOT NULL and [owner].[name]='%s'";

  if (ctxt.is_dba_user == false && ctxt.is_dba_group_member == false)
    {
      uppercase_user_size = intl_identifier_upper_string_size (ctxt.login_user);
      uppercase_user = (char *) malloc (uppercase_user_size + 1);
      if (uppercase_user == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, uppercase_user_size);
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }

      intl_identifier_upper (ctxt.login_user, uppercase_user);

      query_size = strlen (query_user) + strlen (uppercase_user) + 1;
      query = (char *) malloc (query_size);
      if (query_user == NULL)
    {
      if (uppercase_user != NULL)
        {
          free_and_init (uppercase_user);
        }

      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, query_size);
      return ER_OUT_OF_VIRTUAL_MEMORY;
    }

      sprintf (query, query_user, uppercase_user);
    }

  PARSER_CONTEXT *parser = parser_create_parser ();
  if (parser == NULL)
    {
      fprintf (stderr, "Failed to parser_create_parser().\n");
      return ER_FAILED;
    }

  for (i = 0; i < SERVER_VALUE_INDEX_MAX; i++)
    {
      db_make_null (&values[i]);
    }

  int au_save;
  AU_DISABLE (au_save);

  error = db_compile_and_execute_local (((query == NULL) ? query_all : query), &query_result, &query_error);
  if (error <= 0)
    {
      goto err;
    }

  error = db_query_first_tuple (query_result);
  if (error != DB_CURSOR_SUCCESS)
    {
      goto err;
    }

  do
    {
      for (i = 0; i < SERVER_VALUE_INDEX_MAX; i++)
    {
      error = db_query_get_tuple_value_by_name (query_result, (char *) attr_names[i], &values[i]);
      if (error != NO_ERROR)
        {
          goto err;
        }
    }

      if (au_is_server_authorized_user (values + (SERVER_VALUE_INDEX_MAX - 1)))
    {
      srv_name = (char *) db_get_string (values + 0);

      owner_name = (char *) db_get_string (values + 8);
      PRINT_OWNER_NAME (owner_name, (ctxt.is_dba_user || ctxt.is_dba_group_member), output_owner,
                sizeof (output_owner));

      output_ctx ("\nCREATE SERVER %s[%s] (", output_owner, srv_name);
      output_ctx ("\n\t HOST= '%s'", (char *) db_get_string (values + 1));
      output_ctx (",\n\t PORT= %d", db_get_int (values + 2));

      output_ctx (",\n\t DBNAME= ");
      desc_value_print (output_ctx, values + 3);

      output_ctx (",\n\t USER= ");
      desc_value_print (output_ctx, values + 4);

      output_ctx (",\n\t PASSWORD= '%s'", (char *) db_get_string (values + 5));

      str = (char *) db_get_string (values + 6);
      if (str)
        {
          output_ctx (",\n\t PROPERTIES= '%s'", str);
        }

      str = (char *) db_get_string (values + 7);
      if (str)
        {
          output_ctx (",\n\t COMMENT= ");
          desc_value_print (output_ctx, values + 7);
        }
      output_ctx (" );\n");
    }

      for (i = 0; i < SERVER_VALUE_INDEX_MAX; i++)
    {
      db_value_clear (&values[i]);
      db_make_null (&values[i]);
    }
    }
  while (db_query_next_tuple (query_result) == DB_CURSOR_SUCCESS);

  error = NO_ERROR;

err:
  parser_free_parser (parser);
  db_query_end (query_result);

  if (error != NO_ERROR)
    {
      if (er_has_error ())
    {
      fprintf (stderr, "Failed: %s\n", er_msg ());
    }

      for (i = 0; i < SERVER_VALUE_INDEX_MAX; i++)
    {
      db_value_clear (&values[i]);
    }
    }

  if (uppercase_user != NULL)
    {
      free_and_init (uppercase_user);
    }

  AU_ENABLE (au_save);
  return error;
}


int
create_filename_schema (const char *output_dirname, const char *output_prefix,
            char *output_filename_p, const size_t filename_size)
{
  return create_filename (output_dirname, output_prefix, SCHEMA_NAME, output_filename_p, filename_size);
}

int
create_filename_trigger (const char *output_dirname, const char *output_prefix,
             char *output_filename_p, const size_t filename_size)
{
  return create_filename (output_dirname, output_prefix, TRIGGER_NAME, output_filename_p, filename_size);
}

int
create_filename_indexes (const char *output_dirname, const char *output_prefix,
             char *output_filename_p, const size_t filename_size)
{
  return create_filename (output_dirname, output_prefix, INDEX_NAME, output_filename_p, filename_size);
}

static int
create_filename_schema_info (const char *output_dirname, const char *output_prefix,
                 char *output_filename_p, const size_t filename_size)
{
  return create_filename (output_dirname, output_prefix, SCHEMA_INFO, output_filename_p, filename_size);
}

static int
create_filename (const char *output_dirname, const char *output_prefix, const char *suffix,
         char *output_filename_p, const size_t filename_size)
{
  if (output_dirname == NULL)
    {
      output_dirname = ".";
    }

  size_t total = strlen (output_dirname) + strlen (output_prefix) + strlen (suffix) + 8;

  if (total > filename_size)
    {
      return -1;
    }

  snprintf (output_filename_p, filename_size - 1, "%s/%s%s", output_dirname, output_prefix, suffix);

  return 0;
}

static int
create_filename (const char *output_dirname, const char *output_prefix, const char *infix, const char *suffix,
         char *output_filename_p, const size_t filename_size)
{
  if (output_dirname == NULL)
    {
      output_dirname = ".";
    }

  size_t total = strlen (output_dirname) + strlen (output_prefix) + strlen (infix) + strlen (suffix) + 8;

  if (total > filename_size)
    {
      return -1;
    }

  snprintf (output_filename_p, filename_size - 1, "%s/%s%s%s", output_dirname, output_prefix, infix, suffix);

  return 0;
}

static int
create_filefullpath (const char *output_dirname, const char *output_filename,
             char *output_filename_p, const size_t filename_size)
{
  if (output_dirname == NULL)
    {
      output_dirname = ".";
    }

  size_t total = strlen (output_dirname) + strlen (output_filename) + 8;

  if (total > filename_size)
    {
      return -1;
    }

  snprintf (output_filename_p, filename_size - 1, "%s/%s", output_dirname, output_filename);

  return 0;
}

static int
extract_user (extract_context & ctxt)
{
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, USER_SUFFIX, output_filename,
       sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME, USER_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  /* error is row count if not negative. */
  if (required_class_only == false && ctxt.do_auth)
    {
      err = au_export_users (ctxt, output_ctx);
    }

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no user to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }

      fclose (output_file);
      output_file = NULL;
    }

  return (err < 0) ? ER_FAILED : NO_ERROR;
}

static int
extract_serial (extract_context & ctxt)
{
  FILE *output_file = NULL;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };
  int err = NO_ERROR;

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, SERIAL_SUFFIX, output_filename,
       sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME,
       SERIAL_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  if (required_class_only == false)
    {
      err = export_serial (ctxt, output_ctx);
      if (err != NO_ERROR)
    {
      fprintf (stderr, "%s", db_error_string (3));
      if (db_error_code () == ER_INVALID_SERIAL_VALUE)
        {
          fprintf (stderr, " Check the value of _db_serial object.\n");
        }
    }
    }

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no serial to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }

      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static int
extract_synonym (extract_context & ctxt)
{
  FILE *output_file = NULL;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };
  int err = NO_ERROR;

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, SYNONYM_SUFFIX, output_filename,
       sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME,
       SYNONYM_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  err = export_synonym (ctxt, output_ctx);
  if (err != NO_ERROR)
    {
      fprintf (stderr, "%s", db_error_string (3));
      if (db_error_code () == ER_SYNONYM_INVALID_VALUE)
    {
      fprintf (stderr, " Check the value of _db_synonym object.\n");
    }
    }

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no synonym to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }

      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static int
extract_procedure (extract_context & ctxt)
{
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, PROCEDURE_SUFFIX, output_filename,
       sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME,
       PROCEDURE_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  if (required_class_only == false)
    {
      err = emit_stored_procedure_pre (ctxt, output_ctx);
    }

  if (required_class_only == false)
    {
      err = emit_stored_procedure_post (ctxt, output_ctx);
    }

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no procedure to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }
      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static int
extract_server (extract_context & ctxt)
{
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, SERVER_SUFFIX, output_filename,
       sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME,
       SERVER_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  if (required_class_only == false)
    {
      err = export_server (ctxt, output_ctx);
    }

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no server to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }
      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static int
extract_class (extract_context & ctxt)
{
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, CLASS_SUFFIX, output_filename,
       sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME,
       CLASS_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  if (ctxt.classes == NULL)
    {
      err = get_classes (ctxt, output_ctx);
      if (err != NO_ERROR || ctxt.classes == NULL)
    {
      fclose (output_file);
      remove (output_filename);
      return err;
    }
    }

  emit_schema (ctxt, output_ctx, EXTRACT_CLASS);
  if (er_errid () == ER_FAILED)
    {
      err = ER_FAILED;
      goto end_class;
    }

  emit_class_query_spec (ctxt, output_ctx, EXTRACT_CLASS);
  if (er_errid () == ER_FAILED)
    {
      err = ER_FAILED;
      goto end_class;
    }

  if (emit_class_alter_serial (ctxt, output_ctx) < NO_ERROR)
    {
      fprintf (stderr, "%s", db_error_string (3));
      if (db_error_code () == ER_INVALID_SERIAL_VALUE)
    {
      fprintf (stderr, " Check the value of _db_serial object.\n");
    }
      err = ER_FAILED;
      goto end_class;
    }

end_class:
  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no query spec to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }

      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static int
extract_vclass (extract_context & ctxt)
{
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, VCLASS_SUFFIX, output_filename,
       sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME,
       VCLASS_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  if (ctxt.classes == NULL)
    {
      err = get_classes (ctxt, output_ctx);
      if (err != NO_ERROR || ctxt.classes == NULL)
    {
      fclose (output_file);
      remove (output_filename);
      return err;
    }
    }

  emit_schema (ctxt, output_ctx, EXTRACT_VCLASS);
  err = (er_errid () == NO_ERROR) ? NO_ERROR : ER_FAILED;

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no vclass to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }

      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static int
extract_vclass_query_spec (extract_context & ctxt)
{
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, VCLASS_QUERY_SPEC_SUFFIX, output_filename,
       sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME,
       VCLASS_QUERY_SPEC_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  if (ctxt.classes == NULL)
    {
      err = get_classes (ctxt, output_ctx);
      if (err != NO_ERROR || ctxt.classes == NULL)
    {
      fclose (output_file);
      remove (output_filename);
      return err;
    }
    }

  emit_class_query_spec (ctxt, output_ctx, EXTRACT_VCLASS);
  err = (er_errid () == NO_ERROR) ? NO_ERROR : ER_FAILED;

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no query spec to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }

      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static int
extract_pk (extract_context & ctxt)
{
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, PK_SUFFIX, output_filename, sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME, PK_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  if (ctxt.classes == NULL)
    {
      err = get_classes (ctxt, output_ctx);
      if (err != NO_ERROR || ctxt.classes == NULL)
    {
      fclose (output_file);
      remove (output_filename);
      return err;
    }
    }

  emit_primary_key (ctxt, output_ctx, ctxt.classes);
  err = (er_errid () == NO_ERROR) ? NO_ERROR : ER_FAILED;
  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no pk to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }

      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static int
extract_fk (extract_context & ctxt)
{
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, FK_SUFFIX, output_filename, sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME, FK_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  if (ctxt.classes == NULL)
    {
      err = get_classes (ctxt, output_ctx);
      if (err != NO_ERROR || ctxt.classes == NULL)
    {
      fclose (output_file);
      remove (output_filename);
      return err;
    }
    }

  err = emit_foreign_key (ctxt, output_ctx, ctxt.classes);

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no fk to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }

      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static int
extract_uk (extract_context & ctxt)
{
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, UK_SUFFIX, output_filename, sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME, UK_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  if (ctxt.classes == NULL)
    {
      err = get_classes (ctxt, output_ctx);
      if (err != NO_ERROR || ctxt.classes == NULL)
    {
      fclose (output_file);
      remove (output_filename);
      return err;
    }
    }

  emit_unique_key (ctxt, output_ctx, ctxt.classes);
  err = (er_errid () == NO_ERROR) ? NO_ERROR : ER_FAILED;

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no grant to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }

      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static int
extract_grant (extract_context & ctxt)
{
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char output_schema_info[PATH_MAX * 2] = { '\0' };

  if (create_filename
      (ctxt.output_dirname, ctxt.output_prefix, SCHEMA_NAME, GRANT_SUFFIX, output_filename,
       sizeof (output_filename)) != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  if (snprintf
      (output_schema_info, sizeof (output_schema_info) - 1, "%s%s%s", ctxt.output_prefix, SCHEMA_NAME,
       GRANT_SUFFIX) > 0)
    {
      ctxt.schema_file_list.push_back (output_schema_info);
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  err = emit_grant (ctxt, output_ctx, ctxt.classes);

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      /* file is empty (database has no grant to be emitted) */
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
    }
  else
    {
      /* not empty */
      if (err == NO_ERROR)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }

      fclose (output_file);
      output_file = NULL;
    }

  return err;
}

static void
emit_primary_key (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes)
{
  DB_OBJLIST *cl = NULL;
  int is_vclass = 0;
  const char *class_type = NULL;
  char *class_name = NULL;
  DB_ATTRIBUTE *attribute_list = NULL, *a = NULL;
  int pk_flag = 0;

  for (cl = classes; cl != NULL; cl = cl->next)
    {
      pk_flag = 0;
      attribute_list = db_get_attributes (cl->op);

      /* see if we have an unique defined on any attribute */
      for (a = attribute_list; a != NULL; a = db_attribute_next (a))
    {
      if (db_attribute_class (a) == cl->op)
        {
          if (pk_flag == 0 && db_attribute_is_unique (a))
        {
          pk_flag = 1;
          is_vclass = db_is_vclass (cl->op);
          class_type = (is_vclass > 0) ? "VCLASS" : "CLASS";
          emit_primary_key_def (ctxt, output_ctx, cl->op, class_type);
        }
        }
    }
    }

  if (er_errid () == ER_OBJ_NO_COMPONENTS)
    {
      er_clear ();
    }
}

static int
emit_grant (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes)
{
  int err = NO_ERROR;
  DB_OBJLIST *cl, *cls, *sp_list = NULL;
  const char *name;
  MOP sp_owner;
  int is_partitioned = 0;

  if (ctxt.do_auth)
    {
      for (cl = classes; cl != NULL; cl = cl->next)
    {
      name = db_get_class_name (cl->op);
      if (do_is_partitioned_subclass (&is_partitioned, name, NULL))
        {
          continue;
        }
      err = au_export_grants (ctxt, output_ctx, cl->op, DB_OBJECT_CLASS);
    }

      sp_list = db_get_all_objects (db_find_class (SP_CLASS_NAME));
      for (cls = sp_list; cls; cls = cls->next)
    {
      if (!(ctxt.is_dba_user || ctxt.is_dba_group_member))
        {
          sp_owner = jsp_get_owner (cls->op);
          if (!ws_is_same_object (sp_owner, Au_user))
        {
          continue;
        }
        }
      err = au_export_grants (ctxt, output_ctx, cls->op, DB_OBJECT_PROCEDURE);
    }
    }

  return err;
}

static void
emit_unique_key (extract_context & ctxt, print_output & output_ctx, DB_OBJLIST * classes)
{
  DB_OBJLIST *cl = NULL;
  int is_vclass = 0;
  int reverse_unique_flag = 0;
  const char *class_type = "CLASS";
  const char *name = NULL;
  int is_partitioned = 0;
  int unique_flag = 0;
  DB_ATTRIBUTE *attribute_list = NULL;
  DB_ATTRIBUTE *a = NULL;

  for (cl = ctxt.classes; cl != NULL; cl = cl->next)
    {
      is_vclass = db_is_vclass (cl->op);
      if (is_vclass > 0)
    {
      /* VCLASS is skipped. */
      continue;
    }

      name = db_get_class_name (cl->op);
      if (do_is_partitioned_subclass (&is_partitioned, name, NULL))
    {
      continue;
    }

      attribute_list = db_get_attributes (cl->op);

      /* see if we have an index or unique defined on any attribute */
      for (a = attribute_list; a != NULL; a = db_attribute_next (a))
    {
      if (db_attribute_class (a) == cl->op)
        {
          if (db_attribute_is_unique (a))
        {
          unique_flag = 1;
        }
          else if (db_attribute_is_reverse_unique (a))
        {
          reverse_unique_flag = 1;
        }
        }

      if (unique_flag && reverse_unique_flag)
        {
          /* Since we already found all, no need to go further. */
          break;
        }
    }

      if (unique_flag)
    {
      emit_unique_def (ctxt, output_ctx, cl->op, class_type);
    }

      if (reverse_unique_flag)
    {
      emit_reverse_unique_def (ctxt, output_ctx, cl->op);
    }

      unique_flag = 0;
      reverse_unique_flag = 0;
    }

  if (er_errid () == ER_OBJ_NO_COMPONENTS)
    {
      er_clear ();
    }
}

static int
extract_split_schema_files (extract_context & ctxt)
{
  int err_count = 0;

  if (extract_user (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_serial (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_synonym (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_server (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_fk (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_grant (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_vclass (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_vclass_query_spec (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_class (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_procedure (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_pk (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (extract_uk (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  if (create_schema_info (ctxt) != NO_ERROR)
    {
      err_count++;
    }

  return err_count;
}

static int
extract_all_schema_file (extract_context & ctxt, const char *output_filename)
{
  FILE *output_file;
  int err_count = 0;

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", ctxt.exec_name, strerror (errno));
      return 1;
    }

  file_print_output output_ctx (output_file);
  err_count = extract_schema (ctxt, output_ctx);


  if (ftell (output_file) == 0)
    {
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NODATA_TOBE_UNLOADED, 0);
      err_count++;
    }
  else
    {
      /* not empty */
      if (err_count == 0)
    {
      output_ctx ("\n");
      output_ctx ("COMMIT WORK;\n");
    }
      fclose (output_file);
      output_file = NULL;
    }

  return err_count;
}

static int
get_classes (extract_context & ctxt, print_output & output_ctx)
{
  int err = NO_ERROR;
  /*
   * convert the class table into an ordered class list, would be better
   * if we just built the initial list rather than using the table.
   */
  ctxt.classes = get_ordered_classes (output_ctx, NULL);
  if (ctxt.classes == NULL && db_error_code () != NO_ERROR)
    {
      return ER_FAILED;
    }

  if (ctxt.classes != NULL && !ctxt.is_dba_user && !ctxt.is_dba_group_member)
    {
      filter_user_classes (&ctxt.classes, ctxt.login_user);
      if (ctxt.classes == NULL)
    {
      int err_code = db_error_code ();
      if (err_code != NO_ERROR && err_code != ER_AU_SELECT_FAILURE)
        {
          return ER_FAILED;
        }
    }
    }

  er_clear ();
  return err;
}

static void
filter_user_classes (DB_OBJLIST ** class_list, const char *user)
{
  DB_OBJLIST *cl, *prev, *next;
  const char *name = NULL;
  char owner_name[DB_MAX_IDENTIFIER_LENGTH] = { '\0' };

  for (cl = *class_list, prev = NULL, next = NULL; cl != NULL; cl = next)
    {
      next = cl->next;
      name = db_get_class_name (cl->op);
      sm_qualifier_name (name, owner_name, DB_MAX_IDENTIFIER_LENGTH);

      if (owner_name != NULL && strcmp (owner_name, user) == 0)
    {
      prev = cl;
    }
      else
    {
      if (prev == NULL)
        {
          *class_list = next;
        }
      else
        {
          prev->next = next;
        }
      /*
       * class_list links were allocated via ml_ext_alloc_link, so we must
       * free them via ml_ext_free_link.  Otherwise, we can crash.
       */
      ml_ext_free_link (cl);
    }
    }
}

static int
create_schema_info (extract_context & ctxt)
{
  size_t total_len = 0;
  FILE *output_file = NULL;
  int err = NO_ERROR;
  char output_filename[PATH_MAX * 2] = { '\0' };
  char filename_fullpath[PATH_MAX * 2] = { '\0' };
  char order_str[PATH_MAX * 2] = { '\0' };
  const char *loading_order[] =
    { "_schema_user", "_schema_class", "_schema_vclass", "_schema_server", "_schema_synonym",
    "_schema_serial", "_schema_procedure",
    "_schema_pk", "_schema_fk", "_schema_uk", "_schema_grant", "_schema_vclass_query_spec"
  };

  const size_t len = sizeof (loading_order) / sizeof (loading_order[0]);

  if (create_filename_schema_info (ctxt.output_dirname, ctxt.output_prefix, output_filename, sizeof (output_filename))
      != 0)
    {
      util_log_write_errid (MSGCAT_UTIL_GENERIC_INVALID_ARGUMENT);
      return ER_FAILED;
    }

  output_file = fopen_ex (output_filename, "w");
  if (output_file == NULL)
    {
      (void) fprintf (stderr, "%s: %s.\n\n", output_filename, strerror (errno));
      return ER_FAILED;
    }

  file_print_output output_ctx (output_file);

  for (size_t i = 0; i < len; i++)
    {
      total_len = strlen (ctxt.output_prefix) + strlen (loading_order[i]) + 1;
      if (total_len > sizeof (order_str))
    {
      err = ER_FAILED;
      break;
    }

      order_str[0] = '\0';
      strcat (order_str, ctxt.output_prefix);
      strcat (order_str, loading_order[i]);
      order_str[strlen (ctxt.output_prefix) + strlen (loading_order[i]) + 1] = '\0';

      for (std::size_t j = 0; j < ctxt.schema_file_list.size (); j++)
    {
      if (strcmp (order_str, ctxt.schema_file_list[j].c_str ()) == 0)
        {
          if (create_filefullpath
          (ctxt.output_dirname, ctxt.schema_file_list[j].c_str (), filename_fullpath,
           sizeof (filename_fullpath)))
        {
          continue;
        }

          if (access (filename_fullpath, F_OK) != -1)
        {
          output_ctx ("%s\n", ctxt.schema_file_list[j].c_str ());
          break;
        }
        }
    }
    }

  fflush (output_file);

  if (ftell (output_file) == 0)
    {
      fclose (output_file);
      output_file = NULL;
      remove (output_filename);
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_NODATA_TOBE_UNLOADED, 0);
      err = ER_FAILED;
    }
  else
    {
      fclose (output_file);
      output_file = NULL;
    }

  ctxt.schema_file_list.clear ();

  return err;
}

static void
str_tolower (char *str)
{
  char *p;

  if (str == NULL)
    return;

  for (p = str; *p; p++)
    {
      if (*p >= 'A' && *p <= 'Z')
    *p = *p - 'A' + 'a';
    }
}

static PARSER_VARCHAR *
do_recreate_where_clause_or_function_attr (PARSER_CONTEXT ** parser, const char *class_name, DB_CONSTRAINT * constraint,
                       bool where_clause)
{
  PT_NODE **stmt;
  PT_NODE *expr;
  SEMANTIC_CHK_INFO sc_info = { NULL, NULL, 0, 0, 0, false, false };
  PARSER_VARCHAR *res = NULL;
  char qry_buf[4096];
  char *query_str = qry_buf;
  size_t query_str_len = 0;
  char *in_str;
  unsigned int save_custom;

  assert (parser != NULL);
  if (*parser == NULL)
    {
      *parser = parser_create_parser ();
      if (*parser == NULL)
    {
      return NULL;
    }
    }

  assert (class_name != NULL);
  if (where_clause)
    {
      in_str = constraint->filter_predicate->pred_string;
      // SELECT 1 FROM [<class_name>] WHERE <in_str>  
      query_str_len = strlen (in_str) + strlen (class_name) + 26;
    }
  else
    {
      in_str = constraint->func_index_info->expr_str;
      // SELECT <in_str>  FROM [<class_name>]
      query_str_len = strlen (in_str) + strlen (class_name) + 16;
    }

  if (query_str_len > sizeof (qry_buf))
    {
      query_str = (char *) malloc (query_str_len);
      if (query_str == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, query_str_len);
      parser_free_parser (*parser);
      *parser = NULL;
      return NULL;
    }
    }

  if (where_clause)
    {
      snprintf (query_str, query_str_len, "SELECT 1 FROM [%s] WHERE %s", class_name, in_str);
    }
  else
    {
      snprintf (query_str, query_str_len, "SELECT %s FROM [%s]", in_str, class_name);
    }

  stmt = parser_parse_string_use_sys_charset (*parser, query_str);
  if (stmt == NULL || *stmt == NULL || pt_has_error (*parser))
    {
      goto error_exit;
    }

  expr = where_clause ? (*stmt)->info.query.q.select.where : (*stmt)->info.query.q.select.list;

  *stmt = pt_resolve_names (*parser, *stmt, &sc_info);
  if (*stmt == NULL || pt_has_error (*parser))
    {
      goto error_exit;
    }

  *stmt = pt_semantic_type (*parser, *stmt, &sc_info);
  if (*stmt == NULL || pt_has_error (*parser))
    {
      goto error_exit;
    }

  /* make sure paren_type is 0 so parenthesis are not printed */
  expr->info.expr.paren_type = 0;

  save_custom = (*parser)->custom_print;
  (*parser)->custom_print |= PT_CHARSET_COLLATE_FULL;
  (*parser)->custom_print |= PT_PRINT_NO_SPECIFIED_USER_NAME;
  (*parser)->custom_print |= PT_PRINT_NO_CURRENT_USER_NAME;
  (*parser)->custom_print |= PT_SUPPRESS_RESOLVED;

  res = pt_print_bytes (*parser, expr);
  (*parser)->custom_print = save_custom;

error_exit:
  if (query_str != qry_buf)
    {
      free (query_str);
    }

  return res;
}