Skip to content

File db_class.c

File List > compat > db_class.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.
 *
 */

/*
 * db_class.c - API functions for schema definition.
 */

#ident "$Id$"

#include "config.h"

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

#include "authenticate.h"
#include "system_parameter.h"
#include "storage_common.h"
#include "db.h"
#include "class_object.h"
#include "object_print.h"
#include "server_interface.h"
#include "boot_cl.h"
#include "locator_cl.h"
#include "schema_manager.h"
#include "schema_template.h"
#include "object_accessor.h"
#include "set_object.h"
#include "virtual_object.h"
#include "parser.h"
#include "execute_schema.h"

/* Error signaling macros */
static int drop_internal (MOP class_, const char *name, SM_NAME_SPACE name_space);

static int add_method_internal (MOP class_, const char *name, const char *implementation, SM_NAME_SPACE name_space);

static int add_arg_domain (DB_OBJECT * class_, const char *name, int class_method, int index, int initial_domain,
               const char *domain);
/*
 * CLASS DEFINITION
 */

/*
 * db_create_class() - This function creates a new class.
 *    Returns NULL on error with error status left in global error.
 *    The most common reason for returning NULL was that a class with
 *    the given name could not be found.
 * return  : new class object pointer.
 * name(in): the name of a class
 */
DB_OBJECT *
db_create_class (const char *name)
{
  SM_TEMPLATE *def;
  MOP class_;
  OID class_oid = OID_INITIALIZER;

  CHECK_CONNECT_NULL ();
  CHECK_1ARG_NULL (name);
  CHECK_MODIFICATION_NULL ();

  class_ = NULL;
  def = smt_def_class (name);
  if (def != NULL)
    {
      /* Reserve class name. We don't expect failures. */
      if (locator_reserve_class_name (def->name, &class_oid) != LC_CLASSNAME_RESERVED)
    {
      assert_release (false);
      smt_quit (def);
      return NULL;
    }

      if (sm_update_class (def, &class_) != NO_ERROR)
    {
      smt_quit (def);
    }
    }
  return (class_);
}

/*
 * db_drop_class() - This function is used to completely remove a class and
 *    all of its instances from the database.  Obviously this should be used
 *    with care. Returns non-zero error status if the operation could not be
 *    performed. The most common reason for error is that the current user was
 *    not authorized to delete the specified class.
 * return   : error code
 * class(in): class object
 */
int
db_drop_class (MOP class_)
{
  return db_drop_class_ex (class_, false);
}

/*
 * db_drop_class_ex() - Implement to remove class.
 * return   : error code
 * class(in): class object
 * is_cascade_constraints(in): whether drop ralative FK constrants
 */
int
db_drop_class_ex (MOP class_, bool is_cascade_constraints)
{
  int retval;

  CHECK_CONNECT_ERROR ();
  CHECK_1ARG_ERROR (class_);
  CHECK_MODIFICATION_ERROR ();

  retval = do_check_partitioned_class (class_, CHECK_PARTITION_SUBS, NULL);

  if (!retval)
    {
      retval = sm_delete_class_mop (class_, is_cascade_constraints);
    }

  return (retval);
}

/*
 * db_rename_class() - This function changes the name of a class in the
 *    database. Returns non-zero error if the operation could not be
 *    performed. The most common reason for rename failure is that another
 *    class with the desired name existed.  The current user may also not
 *    have ALTER class authorization.
 * return : error code
 * classop(in/out): class object
 * new_name(in)   : the new name
 */
int
db_rename_class (MOP classop, const char *new_name)
{
  int retval;

  CHECK_CONNECT_ERROR ();
  CHECK_2ARGS_ERROR (classop, new_name);
  CHECK_MODIFICATION_ERROR ();

  retval = do_check_partitioned_class (classop, CHECK_PARTITION_SUBS, NULL);
  if (!retval)
    {
      retval = sm_rename_class (classop, new_name);
    }

  return (retval);
}

/*
 * ATTRIBUTES
 */

/*
 * db_add_attribute_internal() - This is a generic work function for adding
 *    attributes of the various types.  It saves redundant error checking code
 *    in each of the type specific attribute routines.
 * return : error code
 * class(in/out) : class object
 * name(in)      : attribute name
 * domain(in)    : domain string
 * default_value(in): default_value
 * namespace(in) : namespace identifier
 */
int
db_add_attribute_internal (MOP class_, const char *name, const char *domain, DB_VALUE * default_value,
               SM_NAME_SPACE name_space)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_3ARGS_RETURN_EXPR (class_, name, domain, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_add_attribute_any (def, name, domain, (DB_DOMAIN *) 0, name_space, false, NULL, NULL);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      if (default_value != NULL)
        {
          if (name_space == ID_CLASS || name_space == ID_CLASS_ATTRIBUTE)
        {
          error = smt_set_attribute_default (def, name, 1, default_value, NULL);
        }
          else
        {
          error = smt_set_attribute_default (def, name, 0, default_value, NULL);
        }
        }
      if (error)
        {
          smt_quit (def);
        }
      else
        {
          error = sm_update_class_auto (def, &newmop);
          if (error)
        {
          smt_quit (def);
        }
        }
    }
    }
  return (error);
}

/*
 * db_add_attribute() - This function adds a normal attribute to a class
 *                      definition.
 * return : error code
 * obj(in/out): class or instance (usually a class)
 * name(in)   : attribute name
 * domain(in) : domain specifier
 * default_value(in): optional default value
 */
int
db_add_attribute (MOP obj, const char *name, const char *domain, DB_VALUE * default_value)
{
  int retval = 0;

  retval = db_add_attribute_internal (obj, name, domain, default_value, ID_ATTRIBUTE);

  return (retval);
}

/*
 * db_add_shared_attribute() - This function adds a shared attribute to a class
 *                             definition.
 * return : error code
 * obj(in)    : class or instance (usually a class)
 * name(in)   : attribute name
 * domain(in) : domain specifier
 * default_value(in): optional default value
 *
 */
int
db_add_shared_attribute (MOP obj, const char *name, const char *domain, DB_VALUE * default_value)
{
  int retval;

  retval = (db_add_attribute_internal (obj, name, domain, default_value, ID_SHARED_ATTRIBUTE));

  return (retval);
}

/*
 * db_add_class_attribute() - This function adds a class attribute to a class
 *                            definition.
 * return : error code
 * obj(in): class or instance (usually a class)
 * name(in): attribute name
 * domain(in): domain specifier
 * default_value(in): optional default value
 *
 */
int
db_add_class_attribute (MOP obj, const char *name, const char *domain, DB_VALUE * default_value)
{
  int retval;

  retval = (db_add_attribute_internal (obj, name, domain, default_value, ID_CLASS_ATTRIBUTE));

  return (retval);
}

/*
 * drop_attribute_internal() - This is internal work function for removing
 *    definitions from a class. Can be used to remove any type of attribute
 *    or method. The db_ function layer currently forces the callers to
 *    recognize the difference between normal/shared/class attributes and
 *    normal/class methods when calling the drop routines.  The interpreter
 *    doesn't have this restriction since the smt_ layer offers an interface
 *    similar to this one. Consider offering the same thing at the db_ layer.
 * return : error code
 * class(in)    : class or instance
 * name(in)     : attribute or method name
 * namespace(in): namespace identifier
 */
static int
drop_internal (MOP class_, const char *name, SM_NAME_SPACE name_space)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_2ARGS_RETURN_EXPR (class_, name, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_delete_any (def, name, name_space);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class_auto (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }

  return (error);
}

/*
 * db_drop_attribute() - see the function db_drop_attribute_internal()
 * return : error code
 * class(in): class or instance
 * name(in) : attribute name
 */
int
db_drop_attribute (MOP class_, const char *name)
{
  int error = NO_ERROR;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_2ARGS_ERROR (class_, name);

  error = do_check_partitioned_class (class_, CHECK_PARTITION_SUBS, (char *) name);
  if (!error)
    {
      error = db_drop_attribute_internal (class_, name);
    }

  return error;
}

/*
 * db_drop_attribute_internal() - This function removes both instance & shared
 *    attributes from a class. The attribute is consequently dropped from any
 *    subclasses, as well.
 * return : error code
 * class(in): class or instance
 * name(in) : attribute name
 */
int
db_drop_attribute_internal (MOP class_, const char *name)
{
  int error = NO_ERROR;

  /* kludge, since instance & shared attributes are really supposed to be in the same logical namespace, we should
   * allow shared attributes to be deleted here as well.  Unfortunately, the template function smt_delete_any() doesn't
   * support this.  Instead, we try the operation and if it gets an error, we try again. */
  error = drop_internal (class_, name, ID_ATTRIBUTE);
  if (error == ER_SM_ATTRIBUTE_NOT_FOUND)
    error = drop_internal (class_, name, ID_SHARED_ATTRIBUTE);

  return (error);
}

/*
 * db_drop_shared_attribute - This function Removes the definitino of a
 *    shared attribute.
 * return: error code
 * class(in): class or instance
 * name(in) : attribute name
 *
 * note : Not necessary now that db_drop_attribute handles this.
 */
int
db_drop_shared_attribute (MOP class_, const char *name)
{
  int retval;

  retval = drop_internal (class_, name, ID_SHARED_ATTRIBUTE);

  return (retval);
}

/*
 * db_drop_class_attribute() - This function removes a class attribute
 *    from a class.
 * return : error code
 * class(in): class or instance
 * name(in) : attribute name
 */
int
db_drop_class_attribute (MOP class_, const char *name)
{
  int retval;

  retval = drop_internal (class_, name, ID_CLASS_ATTRIBUTE);

  return (retval);
}

/*
 * db_add_set_attribute_domain() - This function adds domain information to an
 *    attribute whose basic domain is one of the set types: set, multiset, or
 *    sequence. If the named attribute has one of these set domains, this
 *    function further specifies the allowed domains for the elements of the
 *    set.
 * return : error code
 * class(in): class or instance pointer
 * name(in) : attribute name
 * class_attribute(in) : 0 if this is not a class attribute
 *                       non-zero if this is a class attribute
 * domain(in): domain name
 */
int
db_add_set_attribute_domain (MOP class_, const char *name, int class_attribute, const char *domain)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_3ARGS_RETURN_EXPR (class_, name, domain, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      /* should make sure this is a set attribute */
      error = smt_add_set_attribute_domain (def, name, class_attribute, domain, (DB_DOMAIN *) 0);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }
  return (error);
}

/*
 * db_add_set_attribute_domain() - see the function db_add_set_attribute_domain
 * return : error code
 * class(in): class or instance pointer
 * name(in) : attribute name
 * domain(in): domain name
 *
 * note : This function is provided for backwards compatibility.
 */
int
db_add_element_domain (MOP class_, const char *name, const char *domain)
{
  int retval;

  retval = db_add_set_attribute_domain (class_, name, 0, domain);

  return (retval);
}

/*
 * db_drop_set_attribute_domain() - This function used to remove domain
 *    specifications for attributes whose original domain was "set",
 *    "multi_set", or "sequence". The set valued attributes can be given
 *    further domain information using db_add_element_domain which defines
 *    the allowed types for elements of the set. Use db_drop_element_domain
 *    to remove entries from the set domain list.
 * returns/side-effects: error code
 * class(in) : class or instance
 * name(in)  : attribute name
 * domain(in): domain name
 *
 */
int
db_drop_set_attribute_domain (MOP class_, const char *name, int class_attribute, const char *domain)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_3ARGS_RETURN_EXPR (class_, name, domain, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_delete_set_attribute_domain (def, name, class_attribute, domain, (DB_DOMAIN *) 0);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }

  return (error);
}

/*
 * db_drop_element_domain() - See the function db_drop_set_attribute_domain
 * returns/side-effects: error code
 * class(in) : class or instance
 * name(in)  : attribute name
 * domain(in): domain name
 *
 * note : This function is provided for backwards compatibility.
 */
int
db_drop_element_domain (MOP class_, const char *name, const char *domain)
{
  int retval;

  retval = db_drop_set_attribute_domain (class_, name, 0, domain);

  return (retval);
}

/*
 * db_change_default() - This function changes the default value definition of
 *    an attribute. Default values are normally established when the attribute
 *    is first defined using the db_add_attribute() function. This function
 *    can be used to change the default value after the attribute has been
 *    defined.
 * return : error code
 * class(in): class or instance pointer
 * name(in) : attribute name
 * value(in): value container with value
 *
 * note: Do not use this function to change the values of class attributes.
 *       Instead, the db_put() function is used with the class object as the
 *       first argument.
 */
int
db_change_default (MOP class_, const char *name, DB_VALUE * value)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_3ARGS_RETURN_EXPR (class_, name, value, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_set_attribute_default (def, name, false, value, NULL);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }
  return (error);
}

/*
 * db_rename() - See the db_rename_internal function.
 * return : error code
 * class(in)   : class to alter
 * name(in)    : component name
 * class_namespace(in): class namespace flag
 * newname(in) : new component name
 */
int
db_rename (MOP class_, const char *name, int class_namespace, const char *newname)
{
  int error = NO_ERROR;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();

  error = do_check_partitioned_class (class_, CHECK_PARTITION_SUBS, (char *) name);
  if (!error)
    {
      error = db_rename_internal (class_, name, class_namespace, newname);
    }

  return error;
}

/*
 * db_rename_internal() - This will rename any of the various class components:
 *    attributes, class attributes, methods, class methods.
 * return : error code
 * class(in)   : class to alter
 * name(in)    : component name
 * class_namespace(in): class namespace flag
 * newname(in) : new component name
 */
int
db_rename_internal (MOP class_, const char *name, int class_namespace, const char *newname)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_rename_any (def, name, class_namespace, newname);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class_auto (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }

  return (error);
}

/*
 * db_rename_attribute() - This function renames an attribute and propagates
 *    the changes to the affected sub classes.
 * return: error code
 * class(in)   : class or instance
 * name(in)    : current attribute name
 * class_attribute(in): class attribute flag
 * newname(in) : new attribute name
 *
 * note : This function is obsoleted, use db_rename function
 */
int
db_rename_attribute (MOP class_, const char *name, int class_attribute, const char *newname)
{
  int error = NO_ERROR;

  error = do_check_partitioned_class (class_, CHECK_PARTITION_SUBS, (char *) name);
  if (!error)
    {
      error = db_rename_internal (class_, name, class_attribute, newname);
    }

  return error;
}

/*
 * db_rename_method() - This function renames an method and propagates the
 *    changes to the affected sub classes.
 * return: error code
 * class(in)   : class or instance
 * name(in)    : current method name
 * class_method(in): class method flag
 * newname(in) : new method name
 *
 * note : This function is obsoleted, use db_rename function
 */
int
db_rename_method (MOP class_, const char *name, int class_method, const char *newname)
{
  int retval;

  retval = db_rename_internal (class_, name, class_method, newname);

  return (retval);
}

/*
 * METHODS
 */

/*
 * add_method_internal() - This is internal work function to add a method
 *                         definition.
 * return : error code
 * class(in) : class or instance
 * name(in): method name
 * implementation(in): implementation function name
 * namespace(in): attribute or class namespace identifier
 */
static int
add_method_internal (MOP class_, const char *name, const char *implementation, SM_NAME_SPACE name_space)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_2ARGS_RETURN_EXPR (class_, name, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_add_method_any (def, name, implementation, name_space);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class_auto (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }
  return (error);
}

/*
 * db_add_method() - This function Defines a normal (instance) method.
 * return : error code
 * class(in) : class or instance
 * name(in): method name
 * implementation(in): implementation function name
 *
 * note : The implementation name argument can accept a value of NULL.
 *        This means the system uses a default name that is formed by
 *        combining the class name with the method name
 *        (for example, classname_methodname).
 */
int
db_add_method (MOP class_, const char *name, const char *implementation)
{
  int retval;

  retval = add_method_internal (class_, name, implementation, ID_METHOD);

  return (retval);
}

/*
 * db_add_class_method() - This function define a class method.
 * return : error code
 * class(in): class or instance
 * name(in) : method name
 * implementation(in) : function name
 *
 * note : The implementation name argument can accept a value that is NULL.
 *        This means the system uses a default name that is formed by combining
 *        the class name with the method name
 *        (for example, classname_methodname).
 */
int
db_add_class_method (MOP class_, const char *name, const char *implementation)
{
  int retval;

  retval = add_method_internal (class_, name, implementation, ID_CLASS_METHOD);

  return (retval);
}

/*
 * db_drop_method() - This function removes a method from a class.
 * return : error code
 * class(in): class or instance
 * name(in) : method name
 */
int
db_drop_method (MOP class_, const char *name)
{
  int retval;

  retval = drop_internal (class_, name, ID_METHOD);

  return (retval);
}

/*
 * db_drop_class_method() - This function removes a class method from a class.
 * return : error code
 * class(in): class or instance
 * name(in) : class method name
 *
 */
int
db_drop_class_method (MOP class_, const char *name)
{
  int retval;

  retval = drop_internal (class_, name, ID_CLASS_METHOD);

  return (retval);
}

/*
 * db_change_method_implementation() - This function changes the name of C
 *    function that is called when the method is invoked.
 * returns/side-effects: error code
 * class(in)   : class or instance
 * name(in)    : method name
 * class_method(in): class method flag
 * newname(in) : new interface function name
 */
int
db_change_method_implementation (MOP class_, const char *name, int class_method, const char *newname)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_3ARGS_RETURN_EXPR (class_, name, newname, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_change_method_implementation (def, name, class_method, newname);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }
  return (error);
}

/*
 * add_arg_domain() - This function describes the domain of a method argument
 *    used for run time consistency checking by the interpreter. If the index
 *    argument is 0, the domain is used as the domain of the return value of
 *    the method. Otherwise, the index references the arguments of the method
 *    from 1 to n.
 * return : error code
 * class(in): class object
 * name(in): method name
 * class_method(in): class method flag
 * index(in): argument index (zero is return value)
 * initial_domain(in): initialize flag.
 * domain(in): domain descriptor string
 *
 * note : Argument indexes can be specified that do not necessarily increase
 *        by 1, i.e., arg1, arg2, arg5 leaves arg3 and arg4 unspecified and
 *        logically void.
 *        If the supplied index is greater than any of the indexes that were
 *        previously supplied for the arguments, the argument list of the
 *        method is extended.
 */
static int
add_arg_domain (DB_OBJECT * class_, const char *name, int class_method, int index, int initial_domain,
        const char *domain)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_2ARGS_RETURN_EXPR (class_, name, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      if (domain == NULL)
    {
      error = smt_assign_argument_domain (def, name, class_method, NULL, index, NULL, (DB_DOMAIN *) 0);
    }
      else
    {
      if (initial_domain)
        {
          error = smt_assign_argument_domain (def, name, class_method, NULL, index, domain, (DB_DOMAIN *) 0);
        }
      else
        {
          error = smt_add_set_argument_domain (def, name, class_method, NULL, index, domain, (DB_DOMAIN *) 0);
        }
    }
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }
  return (error);
}

/*
 * db_add_argument() - see the add_arg_domain function.
 * return : error code
 * class(in): class object
 * name(in): method name
 * class_method(in): class method flag
 * index(in): argument index (zero is return value)
 * domain(in): domain descriptor string
 */
int
db_add_argument (DB_OBJECT * class_, const char *name, int class_method, int index, const char *domain)
{
  int retval;

  retval = (add_arg_domain (class_, name, class_method, index, 1, domain));

  return (retval);
}

/*
 * db_set_method_arg_domain() -
 * return :
 * class(in)  :
 * name(in)   :
 * index(in)  :
 * domain(in) :
 */
int
db_set_method_arg_domain (DB_OBJECT * class_, const char *name, int index, const char *domain)
{
  int retval;

  retval = (add_arg_domain (class_, name, 0, index, 1, domain));

  return (retval);
}

/*
 * db_set_class_method_arg_domain() -
 * return :
 * class(in)  :
 * name(in)   :
 * index(in)  :
 * domain(in) :
 */
int
db_set_class_method_arg_domain (DB_OBJECT * class_, const char *name, int index, const char *domain)
{
  int retval;

  retval = (add_arg_domain (class_, name, 1, index, 1, domain));

  return (retval);
}

/*
 * db_add_set_argument_domain() - This function is used to add additional
 *    domain information to a method argument whose fundamental domain is
 *    set, multiset, or sequence.
 * return : error code
 * class(in)  : class object
 * name(in)   : method name
 * class_method(in): class method flag
 * index(in)  : argument index
 * domain(in) : domain descriptor
 *
 * note : Use the db_add_argument() function first to specify the set type,
 *    then make repeated calls to the db_add_set_argument_domain()function
 *    to further specify the domains of the set elements.
 */
int
db_add_set_argument_domain (DB_OBJECT * class_, const char *name, int class_method, int index, const char *domain)
{
  int retval;

  retval = (add_arg_domain (class_, name, class_method, index, 0, domain));

  return (retval);
}

/*
 * METHOD FILES & LOADER COMMNADS
 */

/*
 * db_set_loader_commands() - This function sets the dynamic linking loader
 *    command string for a class. This is usually a list of library names that
 *    are to be included when linking the methods for a particular class.
 * return : error code
 * class(in): class or instance
 * commands(in): link command string
 *
 * note : The format of this string must be suitable for insertion in the
 *    command line of the UNIX ld command (link editor), such as
 *      "-L /usr/local/lib -l utilities"
 */
int
db_set_loader_commands (MOP class_, const char *commands)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;

  CHECK_CONNECT_ERROR ();
  CHECK_1ARG_ERROR (class_);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_set_loader_commands (def, commands);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class (def, NULL);
      if (error)
        {
          smt_quit (def);
        }
    }
    }

  return (error);
}

/*
 * db_add_method_file() - This function adds a method file to the list of
 *    method files for a class.
 * return : error code
 * class(in): class or instance
 * name(in) : file pathname
 *
 * note : The file does not have to exist at the time it is added, but it must
 *        exist before dynamic linking can occur. Linking normally occurs the
 *        first time a method is called on an instance of the class. There is
 *        no implicit ordering of method files that are added by this function.
 *        If you attempt to add a method file twice, the second addition is
 *        ignored. The name of a method file may contain an environment
 *        variable reference. This environment variable is expanded during
 *        dynamic linking, but it is not expanded at the time the file is
 *        defined.
 */
int
db_add_method_file (MOP class_, const char *name)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_2ARGS_RETURN_EXPR (class_, name, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_add_method_file (def, name);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }
  return (error);
}

/*
 * db_drop_method_file() - This function removes a method file from a class.
 * returns : error code
 * class(in): class or instance
 * name(in): file pathname
 *
 * note : The effects of this function is not seen during the current session.
 *    The next time a database session is started and dynamic linking occurs
 *    for this class, the file is not included.
 *
 */
int
db_drop_method_file (MOP class_, const char *name)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_2ARGS_RETURN_EXPR (class_, name, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_drop_method_file (def, name);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }
  return (error);
}

/*
 * db_drop_method_files() - This function removes all of the currently defined
 *    method files for a class. This can be used in cases where you want to
 *    completely respecify the file list without making multiple calls to
 *    db_drop_method_file().
 * return : error code.
 * class(in): class or instance.
 */
int
db_drop_method_files (MOP class_)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_1ARG_RETURN_EXPR (class_, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_reset_method_files (def);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }

  return (error);
}

/*
 * CLASS HIERARCHY
 */

/*
 * db_add_super() - This function adds a super class to a class if it did not
 *    already exist. If the class is partitioned, function returns
 *    ER_NOT_ALLOWED_ACCESS_TO_PARTITION
 * return : error code
 * class(in): class or instance
 * super(in): super class
 */
int
db_add_super (MOP class_, MOP super)
{
  int error = NO_ERROR;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();

  error = do_check_partitioned_class (class_, CHECK_PARTITION_SUBS, NULL);
  if (!error)
    {
      error = do_check_partitioned_class (super, CHECK_PARTITION_SUBS, NULL);
      if (!error)
    {
      error = db_add_super_internal (class_, super);
    }
    }

  return error;
}

/*
 * db_add_super_internal() - This function adds a super class to a class if it
 *                  did not already exist.
 * return : error code
 * class(in): class or instance
 * super(in): super class
 */
int
db_add_super_internal (MOP class_, MOP super)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_2ARGS_RETURN_EXPR (class_, super, ER_OBJ_INVALID_ARGUMENTS);

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_add_super (def, super);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class_auto (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }

  return (error);
}

/*
 * db_drop_super() - This function removes a superclass link from a class.
 *    The attributes and methods that were inherited from the superclass are
 *    removed, and the changes are propagated to the subclasses. If the class
 *    is partitioned, function returns ER_NOT_ALLOWED_ACCESS_TO_PARTITION.
 * return : error code
 * class(in): class or instance pointer
 * super(in): class pointer
 *
 * note : Any resulting conflicts are resolved automatically by the system.
 *      If the system's resolution is unsatisfactory, it can be redefined
 *      with the db_add_resolution() function or the db_add_class_resolution()
 *      function, as appropriate.
 */
int
db_drop_super (MOP class_, MOP super)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_2ARGS_RETURN_EXPR (class_, super, ER_OBJ_INVALID_ARGUMENTS);

  error = do_check_partitioned_class (class_, CHECK_PARTITION_SUBS, NULL);
  if (!error)
    {
      def = smt_edit_class_mop (class_, AU_ALTER);
      if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
      else
    {
      error = smt_delete_super (def, super);
      if (error)
        {
          smt_quit (def);
        }
      else
        {
          error = sm_update_class_auto (def, &newmop);
          if (error)
        {
          smt_quit (def);
        }
        }
    }
    }

  return (error);
}

/*
 * db_drop_super_connect() - This function removes a superclass link from a
 *    class.
 * return : error code
 * class(in): class or instance pointer
 * super(in): class pointer
 *
 * note : It behaves somewhat differently from the db_drop_super () function.
 *    When you use the function db_drop_super_connect(), the superclasses of
 *    the superclass that is dropped(the super argument) are reconnected as
 *    superclasses of the class argument.
 */
int
db_drop_super_connect (MOP class_, MOP super)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();
  CHECK_2ARGS_RETURN_EXPR (class_, super, ER_OBJ_INVALID_ARGUMENTS);

  error = do_check_partitioned_class (class_, CHECK_PARTITION_SUBS, NULL);
  if (!error)
    {
      def = smt_edit_class_mop (class_, AU_ALTER);
      if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
      else
    {
      error = smt_delete_super_connect (def, super);
      if (error)
        {
          smt_quit (def);
        }
      else
        {
          error = sm_update_class_auto (def, &newmop);
          if (error)
        {
          smt_quit (def);
        }
        }
    }
    }
  return (error);
}

/*
 * INTEGRITY CONSTRAINTS
 */

/*
 * db_constrain_non_null() - This function sets the state of an attribute's
 *                           NON_NULL constraint.
 * return : error code
 * class(in): class or instance object
 * name(in) : attribute name
 * class_attribute(in): flag indicating class attribute status
 *        (0 if this is not a class attribute,
 *         non-zero if this is a class attribute)
 * on_or_off(in): non-zero if constraint is to be enabled
 *
 */
int
db_constrain_non_null (MOP class_, const char *name, int class_attribute, int on_or_off)
{
  const char *att_names[2];
  int retval;

  att_names[0] = name;
  att_names[1] = NULL;
  if (on_or_off)
    {
      bool has_nulls = false;
      retval = do_check_rows_for_null (class_, name, &has_nulls);
      if (retval != NO_ERROR)
    {
      return retval;
    }

      if (has_nulls)
    {
      retval = ER_SM_ATTR_NOT_NULL;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, retval, 1, name);
      return retval;
    }

      retval = db_add_constraint (class_, DB_CONSTRAINT_NOT_NULL, NULL, att_names, class_attribute);
    }
  else
    {
      retval = db_drop_constraint (class_, DB_CONSTRAINT_NOT_NULL, NULL, att_names, class_attribute);
    }

  return (retval);
}

/*
 * db_constrain_unique() - This function sets the state of an attribute's
 *                         UNIQUE constraint.
 * return : error code
 * class(in): class or instance object
 * name(in): attribute name
 * on_or_off(in): true if constraint is to be enabled
 */
int
db_constrain_unique (MOP class_, const char *name, int on_or_off)
{
  const char *att_names[2];
  int retval;

  att_names[0] = name;
  att_names[1] = NULL;
  if (on_or_off)
    {
      retval = db_add_constraint (class_, DB_CONSTRAINT_UNIQUE, NULL, att_names, false);
    }
  else
    {
      retval = db_drop_constraint (class_, DB_CONSTRAINT_UNIQUE, NULL, att_names, false);
    }

  return (retval);
}

/*
 *  CONFLICT RESOLUTIONS
 */

/*
 * db_add_resolution() - This defines a conflict resolution specification for
 *    a class. Conflict resolutions must be specified BEFORE an operation which
 *    would generate a conflict. Normally, the alias name is not given in which
 *    case this function simply selects the class from which the
 *    attribute/method will be inherited. If the alias name is given, both of
 *    the conflicting entities are inherited, one with a new name.
 * return : error code
 * class(in): class or instance pointer
 * super(in): class pointer
 * name(in) : attribute or method name
 * alias(in): optional alias name
 */
int
db_add_resolution (MOP class_, MOP super, const char *name, const char *alias)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_add_resolution (def, super, name, alias);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class_auto (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }

  return (error);
}

/*
 * db_add_class_resolution() - This function adds a resolution specifier for
 *    the class attributes or class methods of a class. It functions exactly
 *    like the db_add_resolution() function, except that the namespace for
 *    the resolution is the class namespace instead of the instance namespace.
 * return : error code
 * class(in): class or instance pointer
 * super(in): super class pointer
 * name(in) : attribute or method name
 * alias(in): optional alias name
 */
int
db_add_class_resolution (MOP class_, MOP super, const char *name, const char *alias)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_add_class_resolution (def, super, name, alias);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class_auto (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }

  return (error);
}

/*
 * db_drop_resolution() - This function removes a previously specified
 *                        resolution.
 * return : error code
 * class(in): class pointer
 * super(in): class pointer
 * name(in): attribute/method name
 */
int
db_drop_resolution (MOP class_, MOP super, const char *name)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_delete_resolution (def, super, name);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class_auto (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }

  return (error);
}

/*
 * db_drop_class_resolution() - This function removes a class-level resolution.
 * returns : error code
 * class(in): class pointer
 * super(in): class pointer
 * name(in): attribute/method name
 */
int
db_drop_class_resolution (MOP class_, MOP super, const char *name)
{
  int error = NO_ERROR;
  SM_TEMPLATE *def;
  MOP newmop;

  CHECK_CONNECT_ERROR ();
  CHECK_MODIFICATION_ERROR ();

  def = smt_edit_class_mop (class_, AU_ALTER);
  if (def == NULL)
    {
      assert (er_errid () != NO_ERROR);
      error = er_errid ();
    }
  else
    {
      error = smt_delete_class_resolution (def, super, name);
      if (error)
    {
      smt_quit (def);
    }
      else
    {
      error = sm_update_class_auto (def, &newmop);
      if (error)
        {
          smt_quit (def);
        }
    }
    }

  return (error);
}


/*
 *  INDEX CONTROL
 */

/*
 * db_add_index() - This will add an index to an attribute if one doesn't
 *                  already exist.
 * return : error code
 * classmop(in): class (or instance) pointer
 * attname(in) : attribute name
 *
 * note : This may be an expensive operation if there are a lot of previously
 *    created instances in the database since the index attributes for all of
 *    those instances must be added to the b-tree after it is created.
 */
int
db_add_index (MOP classmop, const char *attname)
{
  const char *att_names[2];
  int retval;

  CHECK_CONNECT_ERROR ();
  CHECK_2ARGS_ERROR (classmop, attname);
  CHECK_MODIFICATION_ERROR ();

  att_names[0] = attname;
  att_names[1] = NULL;
  retval = db_add_constraint (classmop, DB_CONSTRAINT_INDEX, NULL, att_names, false);

  return (retval);
}

/*
 * db_drop_index() - This function drops an index for an attribute if one was
 *    defined. Multi-attribute indexes can be dropped with the
 *    db_drop_constraint() function.
 * return : error code
 * classmop(in): class (or instance) pointer
 * attname(in) : attribute name
 */
int
db_drop_index (MOP classmop, const char *attname)
{
  const char *att_names[2];
  int retval;

  CHECK_CONNECT_ERROR ();
  CHECK_2ARGS_ERROR (classmop, attname);
  CHECK_MODIFICATION_ERROR ();

  att_names[0] = attname;
  att_names[1] = NULL;
  retval = db_drop_constraint (classmop, DB_CONSTRAINT_INDEX, NULL, att_names, false);

  return (retval);
}

/*
 * db_add_constraint() - This function is used to add constraints to a class.
 *    The types of constraints are defined by DB_CONSTRAINT_TYPE and currently
 *    include UNIQUE, REVERSE_UNIQUE, NOT NULL, INDEX, REVERSE_INDEX,
 *    PRIMARY_KEY.
 * return : error code
 * classmop(in): class (or instance) pointer
 * constraint_type(in): type of constraint to add(refer to DB_CONSTRAINT_TYPE).
 * constraint_name(in): constraint name.
 * att_names(in): Names of attributes to be constrained
 * class_attributes(in): flag indicating class attribute status
 *                       (0 if this is not a class attribute,
 *                        non-zero if this is a class attribute)
 *
 */
int
db_add_constraint (MOP classmop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name,
           const char **att_names, int class_attributes)
{
  int retval;
  char *name = NULL;

  CHECK_CONNECT_ERROR ();
  CHECK_2ARGS_ERROR (classmop, att_names);
  CHECK_MODIFICATION_ERROR ();

  name = sm_produce_constraint_name_mop (classmop, constraint_type, att_names, NULL, constraint_name);
  if (name == NULL)
    {
      assert (er_errid () != NO_ERROR);
      retval = er_errid ();
    }
  else
    {
      retval =
    sm_add_constraint (classmop, constraint_type, name, att_names, NULL, NULL, class_attributes, NULL, NULL, NULL,
               SM_NORMAL_INDEX);
      free_and_init (name);
    }

  return (retval);
}

/*
 * db_drop_constraint() - This function is used remove constraint from a class.
 *    Please refer to the header information for db_add_constraint() for basic
 *    information on classes and constraints.
 * return : error code
 * classmop: class (or instance) pointer
 * constraint_type: type of constraint to drop
 * constraint_name: constraint name
 * att_names: names of attributes to be constrained
 * class_attributes: flag indicating class attribute status
 *                  (0 if this is not a class attribute,
 *                   non-zero if this is a class attribute)
 *
 * note :
 *    If the name is known, the constraint can be dropped by name, in which
 *    case the <att_names> parameter should be NULL.
 *    If the name is not known, the constraint can be specified by the
 *    combination of class pointer and attribute names.
 *    The order of the attribute names must match the order given when the
 *    constraint was added. In this case, the <constraint_name> should be NULL.
 */
int
db_drop_constraint (MOP classmop, DB_CONSTRAINT_TYPE constraint_type, const char *constraint_name,
            const char **att_names, int class_attributes)
{
  int retval;
  char *name = NULL;

  CHECK_CONNECT_ERROR ();
  CHECK_1ARG_ERROR (classmop);
  CHECK_MODIFICATION_ERROR ();

  name = sm_produce_constraint_name_mop (classmop, constraint_type, att_names, NULL, constraint_name);

  if (name == NULL)
    {
      assert (er_errid () != NO_ERROR);
      retval = er_errid ();
    }
  else
    {
      retval = sm_drop_constraint (classmop, constraint_type, name, att_names, class_attributes ? true : false, false);
      free_and_init (name);
    }

  return (retval);
}

/*
 * db_truncate_class() - This function is used to truncate a class.
 *    Returns non-zero error status if the operation could not be performed.
 * return   : error code
 * class(in): class object
 * is_cascade(in): whether to truncate cascade FK-referring classes
 */
int
db_truncate_class (DB_OBJECT * class_, const bool is_cascade)
{
  int error_code = NO_ERROR;

  CHECK_CONNECT_ERROR ();
  CHECK_1ARG_ERROR (class_);
  CHECK_MODIFICATION_ERROR ();

  error_code = sm_truncate_class (class_, is_cascade);
  return error_code;
}