Skip to content

File authenticate_access_auth.cpp

File List > cubrid > src > object > authenticate_access_auth.cpp

Go to the documentation of this file

/*
 *
 * 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.
 *
 */

#include "authenticate_access_auth.hpp"

//
#include "authenticate.h"
#include "authenticate_grant.hpp"
#include "set_object.h"
#include "dbtype.h"
#include "error_manager.h"
#include "object_accessor.h"
#include "object_primitive.h"

#include "db.h"
#include "dbi.h"
#include "schema_manager.h"
#include "schema_system_catalog_constants.h"

#include "jsp_cl.h"

static int update_authorization_for_new_owner (DB_OBJECT_TYPE obj_type, MOP old_owner_mop, MOP new_owner_mop,
    const char *unique_name,
    int *row_count);
static int update_auth_for_new_owner (DB_OBJECT_TYPE obj_type, MOP old_owner_mop, MOP new_owner_mop,
                      const char *unique_name);

using AuthorizationKey = std::tuple<MOP, MOP, MOP>;
using AuthKey = std::tuple<MOP, MOP, MOP, DB_AUTH>;

inline void hash_combine (std::size_t &seed, std::size_t hash)
{
  /* referenced boost::hash_combine. */
  seed ^= hash + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

template <typename Tuple, std::size_t Index>
struct TupleHashHelper
{
  static std::size_t hash (const Tuple &t)
  {
    std::size_t seed = TupleHashHelper<Tuple, Index - 1>::hash (t);
    std::size_t element_hash = std::hash<typename std::tuple_element<Index - 1, Tuple>::type>() (std::get<Index - 1> (t));

    hash_combine (seed, element_hash);
    return seed;
  }
};

template <typename Tuple>
struct TupleHashHelper<Tuple, 0>
{
  static std::size_t hash (const Tuple &)
  {
    return 0;
  }
};

template<typename Tuple>
struct tuple_hash
{
  std::size_t operator() (const Tuple &t) const
  {
    return TupleHashHelper<Tuple, std::tuple_size<Tuple>::value>::hash (t);
  }
};

template <typename Tuple>
struct tuple_equal
{
  bool operator() (const Tuple &lhs, const Tuple &rhs) const
  {
    return lhs == rhs;
  }
};

const char *AU_TYPE_SET[] =
{
  "SELECT",         /* DB_AUTH_SELECT */
  "INSERT",         /* DB_AUTH_INSERT */
  "UPDATE",         /* DB_AUTH_UPDATE */
  "DELETE",         /* DB_AUTH_DELETE */
  "ALTER",          /* DB_AUTH_ALTER */
  "INDEX",          /* DB_AUTH_INDEX */
  "EXECUTE"         /* DB_AUTH_EXECUTE */
};

constexpr int AU_TYPE_SET_LEN[] =
{
  sizeof ("SELECT") - 1,        /* DB_AUTH_SELECT */
  sizeof ("INSERT") - 1,        /* DB_AUTH_INSERT */
  sizeof ("UPDATE") - 1,        /* DB_AUTH_UPDATE */
  sizeof ("DELETE") - 1,        /* DB_AUTH_DELETE */
  sizeof ("ALTER") - 1,     /* DB_AUTH_ALTER */
  sizeof ("INDEX") - 1,     /* DB_AUTH_INDEX */
  sizeof ("EXECUTE") - 1        /* DB_AUTH_EXECUTE */
};

au_auth_accessor::au_auth_accessor ()
  : m_au_class_mop (nullptr)
  , m_au_obj (nullptr)
{}

int
au_auth_accessor::create_new_auth ()
{
  if (m_au_class_mop == nullptr)
    {
      m_au_class_mop = sm_find_class (CT_CLASSAUTH_NAME);
      if (m_au_class_mop == nullptr)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_AU_MISSING_CLASS, 1, CT_CLASSAUTH_NAME);
    }
    }

  m_au_obj = db_create_internal (m_au_class_mop);
  if (m_au_obj == NULL)
    {
      assert (er_errid () != NO_ERROR);
    }
  return er_errid ();
}

int
au_auth_accessor::set_new_auth (DB_OBJECT_TYPE obj_type, MOP au_obj, MOP grantor, MOP user, MOP obj_mop,
                DB_AUTH auth_type, bool grant_option)
{
  DB_VALUE value;
  MOP db_class = nullptr, inst_mop = nullptr;
  DB_AUTH type;
  int i;
  int error = NO_ERROR;
  char unique_name[DB_MAX_IDENTIFIER_LENGTH + 1];
  unique_name[0] = '\0';

  m_au_obj = au_obj;
  if (m_au_obj == nullptr)
    {
      error = create_new_auth ();
    }

  db_make_object (&value, grantor);
  obj_set (m_au_obj, AU_AUTH_ATTR_GRANTOR, &value);

  db_make_object (&value, user);
  obj_set (m_au_obj, AU_AUTH_ATTR_GRANTEE, &value);

  if (obj_type == DB_OBJECT_CLASS)
    {
      inst_mop = obj_mop;
    }
  else
    {
      // TODO: CBRD-24912
      if (jsp_get_unique_name (obj_mop, unique_name, DB_MAX_IDENTIFIER_LENGTH) == NULL)
    {
      assert (er_errid () != NO_ERROR);
      pr_clear_value (&value);
      return er_errid ();
    }

      inst_mop = jsp_find_stored_procedure (unique_name, DB_AUTH_NONE);
      if (inst_mop == NULL)
    {
      assert (er_errid () != NO_ERROR);
      pr_clear_value (&value);
      return er_errid ();
    }
    }

  db_make_int (&value, (int) obj_type);
  obj_set (m_au_obj, "object_type", &value);

  db_make_object (&value, inst_mop);
  obj_set (m_au_obj, "object_of", &value);

  for (type = DB_AUTH_SELECT, i = 0; type != auth_type; type = (DB_AUTH) (type << 1), i++);

  db_make_varchar (&value, 7, AU_TYPE_SET[i], AU_TYPE_SET_LEN[i], LANG_SYS_CODESET, LANG_SYS_COLLATION);
  obj_set (m_au_obj, "auth_type", &value);

  db_make_int (&value, (int) grant_option);
  obj_set (m_au_obj, "is_grantable", &value);

  pr_clear_value (&value);
  return NO_ERROR;
}

int
au_auth_accessor::get_new_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type)
{
  int error = NO_ERROR, save, i = 0;
  DB_VALUE val[COUNT_FOR_VARIABLES];
  DB_VALUE grant_value;
  DB_QUERY_RESULT *result = NULL;
  DB_SESSION *session = NULL;
  STATEMENT_ID stmt_id;
  const char *name;
  const char *sql_query =
      "SELECT [au].object FROM [" CT_CLASSAUTH_NAME "] [au]"
      " WHERE [au].[grantee].[name] = ? AND [au].[grantor].[name] = ?"
      " AND [au].[object_of] = (%s) AND [au].[auth_type] = ?";
  char obj_fetch_query[256];
  const char *class_unique_name = NULL;
  char sp_unique_name[DB_MAX_IDENTIFIER_LENGTH + 1];
  char error_msg[ERR_MSG_SIZE];

  for (i = 0; i < COUNT_FOR_VARIABLES; i++)
    {
      db_make_null (&val[i]);
    }

  db_make_null (&grant_value);

  /* Disable the checking for internal authorization object access */
  AU_DISABLE (save);

  switch (obj_type)
    {
    case DB_OBJECT_CLASS:
      class_unique_name = sm_get_ch_name (obj_mop);
      if (class_unique_name == NULL)
    {
      assert (false);
      error = ER_UNEXPECTED;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, "Cannot get class name of mop.");
      goto exit;
    }

      sprintf (obj_fetch_query, sql_query, "SELECT [cl].[class_of] FROM " CT_CLASS_NAME "[cl] WHERE [unique_name] = ?");
      break;
    case DB_OBJECT_PROCEDURE:
      sp_unique_name[0] = '\0';
      if (jsp_get_unique_name (obj_mop, sp_unique_name, DB_MAX_IDENTIFIER_LENGTH) == NULL)
    {
      assert (false);
      error = ER_UNEXPECTED;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, "Cannot get stored procedure name of mop.");
      goto exit;
    }

      sprintf (obj_fetch_query, sql_query, "SELECT [sp] FROM " CT_STORED_PROC_NAME "[sp] WHERE [unique_name] = ?");
      break;
    default:
      assert (false);
      error = ER_UNEXPECTED;
      error_msg[0] = '\0';
      snprintf (error_msg, sizeof (error_msg) - 1, "unknown database object id: %d.", obj_type);
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 1, error_msg);
      goto exit;
    }

  session = db_open_buffer_local (obj_fetch_query);
  if (session == NULL)
    {
      assert (er_errid () != NO_ERROR);
      goto exit;
    }

  error = db_set_system_generated_statement (session);
  if (error != NO_ERROR)
    {
      goto release;
    }

  stmt_id = db_compile_statement_local (session);
  if (stmt_id != 1)
    {
      assert (er_errid () != NO_ERROR);
      goto release;
    }

  /* Prepare DB_VALUEs for host variables */
  error = obj_get (user, "name", &val[INDEX_FOR_GRANTEE_NAME]);
  if (error != NO_ERROR)
    {
      goto release;
    }
  else if (!DB_IS_STRING (&val[INDEX_FOR_GRANTEE_NAME]) || DB_IS_NULL (&val[INDEX_FOR_GRANTEE_NAME])
       || db_get_string (&val[INDEX_FOR_GRANTEE_NAME]) == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_AU_MISSING_OR_INVALID_USER, 0);
      goto release;
    }

  error = obj_get (grantor, "name", &val[INDEX_FOR_GRANTOR_NAME]);
  if (error != NO_ERROR)
    {
      goto release;
    }
  else if (!DB_IS_STRING (&val[INDEX_FOR_GRANTOR_NAME]) || DB_IS_NULL (&val[INDEX_FOR_GRANTOR_NAME])
       || db_get_string (&val[INDEX_FOR_GRANTOR_NAME]) == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_AU_MISSING_OR_INVALID_USER, 0);
      goto release;
    }

  switch (obj_type)
    {
    case DB_OBJECT_CLASS:
      db_make_string (&val[INDEX_FOR_OBJECT_NAME], class_unique_name);
      break;
    case DB_OBJECT_PROCEDURE:
      db_make_string (&val[INDEX_FOR_OBJECT_NAME], sp_unique_name);
      break;
    default:
      assert (false);
      error = ER_FAILED;
      goto release;
    }

  i = 0;
  for (DB_AUTH type = DB_AUTH_SELECT; type != auth_type; type = (DB_AUTH) (type << 1))
    {
      i++;
    }
  db_make_string (&val[INDEX_FOR_AUTH_TYPE], AU_TYPE_SET[i]);

  error = db_push_values (session, COUNT_FOR_VARIABLES, val);
  if (error != NO_ERROR)
    {
      assert (er_errid () != NO_ERROR);
      goto release;
    }

  error = db_execute_statement_local (session, stmt_id, &result);

  /* The error value is row count if it's not negative value. */
  if (error == 0)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      error = ER_GENERIC_ERROR;
      goto release;
    }
  else if (error < 0)
    {
      assert (er_errid () != NO_ERROR);
      goto release;
    }

  error = NO_ERROR;

  if (db_query_first_tuple (result) == DB_CURSOR_SUCCESS)
    {
      if (db_query_get_tuple_value (result, 0, &grant_value) == NO_ERROR)
    {
      m_au_obj = NULL;
      if (!DB_IS_NULL (&grant_value))
        {
          m_au_obj = db_get_object (&grant_value);
        }
    }

      assert (db_query_next_tuple (result) == DB_CURSOR_END);
    }

  assert (m_au_obj != NULL);

release:
  if (result != NULL)
    {
      db_query_end (result);
    }
  if (session != NULL)
    {
      db_close_session (session);
    }

exit:
  AU_ENABLE (save);

  db_value_clear (&grant_value);

  for (i = 0; i < COUNT_FOR_VARIABLES; i++)
    {
      db_value_clear (&val[i]);
    }

  if (m_au_obj == NULL && er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      error = ER_GENERIC_ERROR;
    }

  return (error);
}

int
au_auth_accessor::insert_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type,
                   int grant_option)
{
  int error = NO_ERROR;
  for (int index = DB_AUTH_EXECUTE; index; index >>= 1)
    {
      if (auth_type & index)
    {
      error = set_new_auth (obj_type, NULL, grantor, user, obj_mop, (DB_AUTH) index,
                ((grant_option & index) ? true : false));
      if (error != NO_ERROR)
        {
          break;
        }
    }
    }

  return error;
}

int
au_auth_accessor::update_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type,
                   int grant_option)
{
  int error = NO_ERROR;
  for (int index = DB_AUTH_EXECUTE; index; index >>= 1)
    {
      if (auth_type & index)
    {
      error = get_new_auth (obj_type, grantor, user, obj_mop, (DB_AUTH) index);
      if (error != NO_ERROR)
        {
          return error;
        }

      assert (m_au_obj != NULL);

      error = obj_inst_lock (m_au_obj, 1);
      if (error != NO_ERROR)
        {
          return error;
        }

      error = set_new_auth (obj_type, m_au_obj, grantor, user, obj_mop, (DB_AUTH) index,
                ((grant_option & index) ? true : false));
      if (error != NO_ERROR)
        {
          return error;
        }
    }
    }

  return error;
}

int
au_auth_accessor::delete_auth (DB_OBJECT_TYPE obj_type, MOP grantor, MOP user, MOP obj_mop, DB_AUTH auth_type)
{
  int error = NO_ERROR;
  for (int index = DB_AUTH_EXECUTE; index; index >>= 1)
    {
      if (auth_type & index)
    {
      error = get_new_auth (obj_type, grantor, user, obj_mop, (DB_AUTH) index);
      if (error != NO_ERROR)
        {
          return error;
        }

      assert (m_au_obj != NULL);

      error = obj_inst_lock (m_au_obj, 1);
      if (error != NO_ERROR)
        {
          return error;
        }

      error = obj_delete (m_au_obj);
      if (error != NO_ERROR)
        {
          return error;
        }
    }
    }

  return error;
}


/*
 * au_delete_auth_of_dropping_user - delete _db_auth records refers to the given grantee user.
 *   return: error code
 *   user(in): the grantee user name to be dropped
 */
int
au_delete_auth_of_dropping_user (MOP user)
{
  int error = NO_ERROR, save;
  const char *sql_query = "DELETE FROM [" CT_CLASSAUTH_NAME "] [au] WHERE [au].[grantee] = ?;";
  DB_VALUE val;
  DB_QUERY_RESULT *result = NULL;
  DB_SESSION *session = NULL;
  int stmt_id;

  db_make_null (&val);

  /* Disable the checking for internal authorization object access */
  AU_DISABLE (save);

  assert (user != NULL);

  session = db_open_buffer_local (sql_query);
  if (session == NULL)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  error = db_set_system_generated_statement (session);
  if (error != NO_ERROR)
    {
      goto release;
    }

  stmt_id = db_compile_statement_local (session);
  if (stmt_id < 0)
    {
      ASSERT_ERROR_AND_SET (error);
      goto release;
    }

  db_make_object (&val, user);
  error = db_push_values (session, 1, &val);
  if (error != NO_ERROR)
    {
      goto release;
    }

  error = db_execute_statement_local (session, stmt_id, &result);
  if (error < 0)
    {
      goto release;
    }

  error = db_query_end (result);

release:
  if (session != NULL)
    {
      db_close_session (session);
    }

exit:
  pr_clear_value (&val);

  AU_ENABLE (save);

  return error;
}

/*
 * au_delete_auth_of_dropping_database_object - delete _db_auth records refers to the given database object.
 *   return: error code
 *   obj_type(in): the object type
 *   name(in): the object name to be dropped
 */
int
au_delete_auth_of_dropping_database_object (DB_OBJECT_TYPE obj_type, const char *name)
{
  int error = NO_ERROR, save;
  const char *sql_query = "DELETE FROM [" CT_CLASSAUTH_NAME "] [au]" " WHERE [au].[object_of] IN (%s);";
  DB_VALUE val;
  DB_QUERY_RESULT *result = NULL;
  DB_SESSION *session = NULL;
  int stmt_id;
  char obj_fetch_query[256];

  db_make_null (&val);

  /* Disable the checking for internal authorization object access */
  AU_DISABLE (save);

  assert (name != NULL);

  switch (obj_type)
    {
    case DB_OBJECT_CLASS:
      sprintf (obj_fetch_query, sql_query, "SELECT [cl].[class_of] FROM " CT_CLASS_NAME "[cl] WHERE [unique_name] = ?");
      break;
    case DB_OBJECT_PROCEDURE:
      sprintf (obj_fetch_query, sql_query, "SELECT [sp] FROM " CT_STORED_PROC_NAME "[sp] WHERE [unique_name] = ?");
      break;
    default:
      assert (false);
      error = ER_FAILED;
      goto exit;
    }

  session = db_open_buffer_local (obj_fetch_query);
  if (session == NULL)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  error = db_set_system_generated_statement (session);
  if (error != NO_ERROR)
    {
      goto release;
    }

  stmt_id = db_compile_statement_local (session);
  if (stmt_id < 0)
    {
      ASSERT_ERROR_AND_SET (error);
      goto release;
    }

  db_make_string (&val, name);
  error = db_push_values (session, 1, &val);
  if (error != NO_ERROR)
    {
      goto release;
    }

  error = db_execute_statement_local (session, stmt_id, &result);
  if (error < 0)
    {
      goto release;
    }

  error = db_query_end (result);

release:
  if (session != NULL)
    {
      db_close_session (session);
    }

exit:
  pr_clear_value (&val);

  AU_ENABLE (save);

  return error;
}

/*
 * au_delete_authorizartion_of_dropping_user - delete a db_authorization record refers to the given user.
 *   return: error code
 *   user(in): the user name to be dropped
 */
int
au_delete_authorizartion_of_dropping_user (MOP user)
{
  int error = NO_ERROR, save;
  const char *sql_query = "DELETE FROM [" CT_AUTHORIZATION_NAME "] [au] WHERE [au].[owner] = ?;";
  DB_VALUE val;
  DB_QUERY_RESULT *result = NULL;
  DB_SESSION *session = NULL;
  int stmt_id;

  db_make_null (&val);

  /* Disable the checking for internal authorization object access */
  AU_DISABLE (save);

  assert (user != NULL);

  session = db_open_buffer_local (sql_query);
  if (session == NULL)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  error = db_set_system_generated_statement (session);
  if (error != NO_ERROR)
    {
      goto release;
    }

  stmt_id = db_compile_statement_local (session);
  if (stmt_id < 0)
    {
      ASSERT_ERROR_AND_SET (error);
      goto release;
    }

  db_make_object (&val, user);
  error = db_push_values (session, 1, &val);
  if (error != NO_ERROR)
    {
      goto release;
    }

  error = db_execute_statement_local (session, stmt_id, &result);
  if (error < 0)
    {
      goto release;
    }

  error = db_query_end (result);

release:
  if (session != NULL)
    {
      db_close_session (session);
    }

exit:
  pr_clear_value (&val);

  AU_ENABLE (save);

  return error;
}

/*
 * au_object_revoke_all_privileges - drop a class, virtual class and procedure all privileges are revoked.
 *   return: error code
 *   obj_type(in) : objcet type
 *   grantor_mop(in): grantor user
 *   unique_name(in): class/stored procedure unique_name
 */
int
au_object_revoke_all_privileges (DB_OBJECT_TYPE obj_type, MOP grantor_mop, const char *unique_name)
{
  int error = NO_ERROR, save, i = 0;
  const char *auth_type_char;
  DB_AUTH db_auth = DB_AUTH_NONE;
  MOP grantee_mop = NULL, object_of_mop = NULL;
  DB_VALUE val[2];
  DB_VALUE grantee_value, object_of_value, auth_type_value;
  DB_QUERY_RESULT *result = NULL;
  DB_SESSION *session = NULL;
  int stmt_id;
  int row_count = -1;
  char obj_fetch_query[256];
  const char *sql_query =
      "SELECT [au].grantee, [au].object_of, [au].auth_type FROM [" CT_CLASSAUTH_NAME "] [au]"
      " WHERE [au].[grantor].[name] = ? AND [au].[object_of] = (%s);";

  assert (grantor_mop != NULL && unique_name != NULL);

  for (i = 0; i < 2; i++)
    {
      db_make_null (&val[i]);
    }

  db_make_null (&grantee_value);
  db_make_null (&object_of_value);
  db_make_null (&auth_type_value);

  /* Disable the checking for internal authorization object access */
  AU_DISABLE (save);

  switch (obj_type)
    {
    case DB_OBJECT_CLASS:
      sprintf (obj_fetch_query, sql_query, "SELECT [cl].[class_of] FROM " CT_CLASS_NAME "[cl] WHERE [unique_name] = ?");
      break;
    case DB_OBJECT_PROCEDURE:
      sprintf (obj_fetch_query, sql_query, "SELECT [sp] FROM " CT_STORED_PROC_NAME "[sp] WHERE [unique_name] = ?");
      break;
    default:
      assert (false);
      error = ER_FAILED;
      goto exit;
    }

  session = db_open_buffer_local (obj_fetch_query);
  if (session == NULL)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  error = db_set_system_generated_statement (session);
  if (error != NO_ERROR)
    {
      goto exit;
    }

  stmt_id = db_compile_statement_local (session);
  if (stmt_id < 0)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  /* Prepare DB_VALUEs for host variables */
  error = obj_get (grantor_mop, "name", &val[0]);
  if (error != NO_ERROR)
    {
      goto exit;
    }
  else if (!DB_IS_STRING (&val[0]) || DB_IS_NULL (&val[0])
       || db_get_string (&val[0]) == NULL)
    {
      error = ER_AU_MISSING_OR_INVALID_USER;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
      goto exit;
    }

  db_make_string (&val[1], unique_name);

  error = db_push_values (session, 2, val);
  if (error != NO_ERROR)
    {
      assert (er_errid () != NO_ERROR);
      goto exit;
    }

  error = db_execute_statement_local (session, stmt_id, &result);

  /* The error value is row count if it's not negative value. */
  if (error == 0)
    {
      row_count = error;
      goto exit;
    }
  else if (error < 0)
    {
      assert (er_errid () != NO_ERROR);
      goto exit;
    }

  row_count = error;
  error = NO_ERROR;

  while (db_query_next_tuple (result) == DB_CURSOR_SUCCESS)
    {
      if (db_query_get_tuple_value (result, 0, &grantee_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&grantee_value))
        {
          goto exit;
        }

      grantee_mop = db_get_object (&grantee_value);
    }

      if (db_query_get_tuple_value (result, 1, &object_of_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&object_of_value))
        {
          goto exit;
        }

      object_of_mop = db_get_object (&object_of_value);
    }

      if (db_query_get_tuple_value (result, 2, &auth_type_value) == NO_ERROR)
    {
      auth_type_char = NULL;

      if (DB_IS_NULL (&auth_type_value))
        {
          goto exit;
        }

      auth_type_char = db_get_char (&auth_type_value);

      switch (auth_type_char[0])
        {
        case 'A':
          db_auth = DB_AUTH_ALTER;
          break;

        case 'D':
          db_auth = DB_AUTH_DELETE;
          break;

        case 'E':
          db_auth = DB_AUTH_EXECUTE;
          break;

        case 'I':
          if (auth_type_char[2] == 'D')
        {
          db_auth = DB_AUTH_INDEX;
        }
          else if (auth_type_char[2] == 'S')
        {
          db_auth = DB_AUTH_INSERT;
        }
          else
        {
          db_auth = DB_AUTH_NONE;
        }
          break;

        case 'S':
          db_auth = DB_AUTH_SELECT;
          break;

        case 'U':
          db_auth = DB_AUTH_UPDATE;
          break;

        default:
          db_auth = DB_AUTH_NONE;
          break;
        }
    }

      assert (grantee_mop != NULL && object_of_mop != NULL && db_auth != DB_AUTH_NONE);

      error = au_revoke (obj_type, grantee_mop, object_of_mop, db_auth, NULL);
      if (error != NO_ERROR)
    {
      goto exit;
    }
    }

exit:
  if (result != NULL)
    {
      db_query_end (result);
    }
  if (session != NULL)
    {
      db_close_session (session);
    }

  AU_ENABLE (save);

  db_value_clear (&grantee_value);
  db_value_clear (&object_of_value);
  db_value_clear (&auth_type_value);

  for (i = 0; i < 2; i++)
    {
      db_value_clear (&val[i]);
    }

  if (row_count < 0 && er_errid () == NO_ERROR && (grantee_mop == NULL || object_of_mop == NULL
      || db_auth == DB_AUTH_NONE))
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      error = ER_GENERIC_ERROR;
    }

  return (error);
}

/*
 * au_user_revoke_all_privileges - when a user is deleted, all of their privileges are revoked.
 *   return: error code
 *   user_mop(in): a user object
 */
int
au_user_revoke_all_privileges (MOP user_mop)
{
  int error = NO_ERROR, save;
  int object_type = 0;
  DB_OBJECT_TYPE obj_type = DB_OBJECT_UNKNOWN;
  const char *auth_type_char;
  DB_AUTH db_auth = DB_AUTH_NONE;
  MOP grantee_mop = NULL, obj_mop = NULL;
  DB_VALUE name;
  DB_VALUE grantee_value, object_type_value, object_of_value, auth_type_value;
  DB_QUERY_RESULT *result = NULL;
  DB_SESSION *session = NULL;
  int stmt_id;
  int row_count = -1;
  const char *sql_query =
      "SELECT [au].grantee, [au].object_type, [au].object_of, [au].auth_type FROM [" CT_CLASSAUTH_NAME "] [au]"
      " WHERE [au].[grantor].[name] = ?";

  assert (user_mop != NULL);


  db_make_null (&name);
  db_make_null (&grantee_value);
  db_make_null (&object_type_value);
  db_make_null (&object_of_value);
  db_make_null (&auth_type_value);

  /* Disable the checking for internal authorization object access */
  AU_DISABLE (save);

  session = db_open_buffer_local (sql_query);
  if (session == NULL)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  error = db_set_system_generated_statement (session);
  if (error != NO_ERROR)
    {
      goto exit;
    }

  stmt_id = db_compile_statement_local (session);
  if (stmt_id < 0)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  /* Prepare DB_VALUEs for host variables */
  error = obj_get (user_mop, "name", &name);
  if (error != NO_ERROR)
    {
      goto exit;
    }
  else if (!DB_IS_STRING (&name) || DB_IS_NULL (&name)
       || db_get_string (&name) == NULL)
    {
      error = ER_AU_MISSING_OR_INVALID_USER;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
      goto exit;
    }

  error = db_push_values (session, 1, &name);
  if (error != NO_ERROR)
    {
      assert (er_errid () != NO_ERROR);
      goto exit;
    }

  error = db_execute_statement_local (session, stmt_id, &result);

  /* The error value is row count if it's not negative value. */
  if (error == 0)
    {
      row_count = error;
      goto exit;
    }
  else if (error < 0)
    {
      assert (er_errid () != NO_ERROR);
      goto exit;
    }

  row_count = error;
  error = NO_ERROR;

  while (db_query_next_tuple (result) == DB_CURSOR_SUCCESS)
    {
      if (db_query_get_tuple_value (result, 0, &grantee_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&grantee_value))
        {
          goto exit;
        }

      grantee_mop = db_get_object (&grantee_value);
    }

      if (db_query_get_tuple_value (result, 1, &object_type_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&object_type_value))
        {
          goto exit;
        }

      object_type = db_get_int (&object_type_value);
      switch (object_type)
        {
        case 0:
          obj_type = DB_OBJECT_CLASS;
          break;

        case 5:
          obj_type = DB_OBJECT_PROCEDURE;
          break;

        default:
          assert (object_type == 0 || object_type == 5);
          goto exit;
        }
    }

      if (db_query_get_tuple_value (result, 2, &object_of_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&object_of_value))
        {
          goto exit;
        }

      obj_mop = db_get_object (&object_of_value);
    }

      if (db_query_get_tuple_value (result, 3, &auth_type_value) == NO_ERROR)
    {
      auth_type_char = NULL;

      if (DB_IS_NULL (&auth_type_value))
        {
          goto exit;
        }

      auth_type_char = db_get_char (&auth_type_value);

      switch (auth_type_char[0])
        {
        case 'A':
          db_auth = DB_AUTH_ALTER;
          break;

        case 'D':
          db_auth = DB_AUTH_DELETE;
          break;

        case 'E':
          db_auth = DB_AUTH_EXECUTE;
          break;

        case 'I':
          if (auth_type_char[2] == 'D')
        {
          db_auth = DB_AUTH_INDEX;
        }
          else if (auth_type_char[2] == 'S')
        {
          db_auth = DB_AUTH_INSERT;
        }
          else
        {
          db_auth = DB_AUTH_NONE;
        }
          break;

        case 'S':
          db_auth = DB_AUTH_SELECT;
          break;

        case 'U':
          db_auth = DB_AUTH_UPDATE;
          break;

        default:
          db_auth = DB_AUTH_NONE;
          break;
        }
    }

      assert (grantee_mop != NULL && obj_type != DB_OBJECT_UNKNOWN && obj_mop != NULL && db_auth != DB_AUTH_NONE);

      error = au_revoke (obj_type, grantee_mop, obj_mop, db_auth, user_mop);
      if (error != NO_ERROR)
    {
      goto exit;
    }
    }

exit:
  if (result != NULL)
    {
      db_query_end (result);
    }
  if (session != NULL)
    {
      db_close_session (session);
    }

  AU_ENABLE (save);

  db_value_clear (&grantee_value);
  db_value_clear (&object_type_value);
  db_value_clear (&object_of_value);
  db_value_clear (&auth_type_value);
  db_value_clear (&name);

  if (row_count < 0 && er_errid () == NO_ERROR && (grantee_mop == NULL || obj_mop == NULL
      || db_auth == DB_AUTH_NONE || (object_type != 0 && object_type != 5)))
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      error = ER_GENERIC_ERROR;
    }

  return (error);
}

/*
 * au_object_owner_change_privileges
 *   return: error code
 *   obj_type(in): the object type
 *   old_owner_mop(in): class/stored procedure old owner
 *   new_owner_mop(in): class/stored procedure new owner
 *   unique_name(in):
 * NOTE
 * When the owner of a class, virtual class, or procedure is changed, the previous owner's privileges are transferred to the new owner.
 *
 * However, if the new owner already possesses the privileges granted by the previous owner, those privileges are removed.
 * Reason: The REVOKE statement cannot revoke privileges from the owner.
 */
int
au_object_owner_change_privileges (DB_OBJECT_TYPE obj_type, MOP object_mop, MOP old_owner_mop, MOP new_owner_mop,
                   const char *unique_name)
{
  int error = NO_ERROR;
  int update_count_db_authorization = 0;

  assert (old_owner_mop != NULL && new_owner_mop != NULL && unique_name != NULL);

  /* modify db_authorization catalog */
  error = update_authorization_for_new_owner (obj_type, old_owner_mop, new_owner_mop, unique_name,
      &update_count_db_authorization);
  if (error != NO_ERROR)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  /* if there are no results from querying the db authorization catalog, there is no need to check db_auth. */
  if (update_count_db_authorization)
    {
      /* modify db_auth catalog */
      error = update_auth_for_new_owner (obj_type, old_owner_mop, new_owner_mop, unique_name);
      if (error != NO_ERROR)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

      if (obj_type == DB_OBJECT_CLASS)
    {
      SM_CLASS *classobj;
      if ((error = au_fetch_class_force (object_mop, &classobj, AU_FETCH_READ)) == NO_ERROR)
        {
          /*
           * clear the cache for this user/class pair to make sure we
           * recalculate it the next time it is referenced
           */
          Au_cache.reset_cache_for_user_and_class (classobj);
        }
    }

      /*
       * Make sure that we don't keep any parse trees
       * around that rely on obsolete authorization.
       * This may not be necessary.
       */
      sm_bump_local_schema_version ();
    }

exit:
  return (error);
}

static int
update_authorization_for_new_owner (DB_OBJECT_TYPE obj_type, MOP old_owner_mop, MOP new_owner_mop,
                    const char *unique_name, int *row_count)
{
  int error = NO_ERROR, save, current_cache;
  char obj_fetch_query[256];
  const char *sql_query =
      "SELECT [au].grantee, [au].object_of FROM [" CT_CLASSAUTH_NAME "] [au]"
      " WHERE [au].[object_of] = (%s)"
      " GROUP BY [au].grantee";
  DB_VALUE val, element, grantee_value, object_of_value;
  DB_SESSION *session = NULL;
  int stmt_id;
  DB_QUERY_RESULT *result = NULL;
  MOP grantor_mop = NULL, grantee_mop = NULL, object_of_mop = NULL, auth = NULL;
  DB_SET *grants = NULL;
  int gindex, gsize;
  std::unordered_map<AuthorizationKey, int,
      tuple_hash<AuthorizationKey>, tuple_equal<AuthorizationKey>> authorization_unordered_map;
  AuthorizationKey key;

  *row_count = -1;

  assert (old_owner_mop != NULL && new_owner_mop != NULL && unique_name != NULL);

  AU_DISABLE (save);

  db_make_null (&val);
  db_make_null (&element);
  db_make_null (&grantee_value);
  db_make_null (&object_of_value);

  switch (obj_type)
    {
    case DB_OBJECT_CLASS:
      sprintf (obj_fetch_query, sql_query, "SELECT [cl].[class_of] FROM " CT_CLASS_NAME "[cl] WHERE [unique_name] = ?");
      break;
    case DB_OBJECT_PROCEDURE:
      sprintf (obj_fetch_query, sql_query, "SELECT [sp] FROM " CT_STORED_PROC_NAME "[sp] WHERE [unique_name] = ?");
      break;
    default:
      error = ER_FAILED;
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  session = db_open_buffer_local (obj_fetch_query);
  if (session == NULL)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  error = db_set_system_generated_statement (session);
  if (error != NO_ERROR)
    {
      goto exit;
    }

  stmt_id = db_compile_statement_local (session);
  if (stmt_id < 0)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  /* Prepare DB_VALUEs for host variables */
  db_make_string (&val, unique_name);

  error = db_push_values (session, 1, &val);
  if (error != NO_ERROR)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  error = db_execute_statement_local (session, stmt_id, &result);

  /* The error value is row count if it's not negative value. */
  if (error == 0)
    {
      *row_count = error;
      goto exit;
    }
  else if (error < 0)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  *row_count = error;
  error = NO_ERROR;

  while (db_query_next_tuple (result) == DB_CURSOR_SUCCESS)
    {
      if (db_query_get_tuple_value (result, 0, &grantee_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&grantee_value))
        {
          goto exit;
        }

      grantee_mop = db_get_object (&grantee_value);
    }

      if (db_query_get_tuple_value (result, 1, &object_of_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&object_of_value))
        {
          goto exit;
        }

      object_of_mop = db_get_object (&object_of_value);
    }

      assert (grantee_mop != NULL && object_of_mop != NULL);

      if (au_get_object (grantee_mop, "authorization", &auth) != NO_ERROR)
    {
      error = ER_AU_ACCESS_ERROR;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, AU_USER_CLASS_NAME, "authorization");
      goto exit;
    }
      else if (au_fetch_instance (auth, NULL, AU_FETCH_UPDATE, LC_FETCH_MVCC_VERSION, AU_UPDATE) != NO_ERROR)
    {
      error = ER_AU_CANT_UPDATE;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
      goto exit;
    }
      else if ((error = obj_inst_lock (auth, 1)) == NO_ERROR && (error = get_grants (auth, &grants, 1)) == NO_ERROR)
    {
      gsize = set_size (grants);
      for (gindex = 0; gindex < gsize && error == NO_ERROR; gindex += GRANT_ENTRY_LENGTH)
        {
          error = set_get_element (grants, GRANT_ENTRY_CLASS (gindex), &element);
          if (error != NO_ERROR)
        {
          ASSERT_ERROR_AND_SET (error);
          goto exit;
        }

          if (ws_is_same_object (db_get_object (&element), object_of_mop))
        {
          /*
           * when the grantee becomes the new owner, previously granted privileges are removed.
           * reason: privileges of the owner cannot be revoked.
           * grantee_mop : grantee_user
           * new_owner_mop : grnator_user
           *
           * ex) SELECT * FROM db_authorization;
           *   owner            grants
           * ================================
           *   grantee         {..,unique_name, grantor, ..}
           */
          if (ws_is_same_object (grantee_mop, new_owner_mop))
            {
              /* privileges cannot be granted to the owner, so they are removed immediately without being temporarily stored. */
            }
          else
            {
              error = set_get_element (grants, GRANT_ENTRY_SOURCE (gindex), &element);
              if (error != NO_ERROR)
            {
              ASSERT_ERROR_AND_SET (error);
              goto exit;
            }
              grantor_mop = db_get_object (&element);

              error = set_get_element (grants, GRANT_ENTRY_CACHE (gindex), &element);
              if (error != NO_ERROR)
            {
              ASSERT_ERROR_AND_SET (error);
              goto exit;
            }
              current_cache = db_get_int (&element);

              /* before deleting the data in db_authorization, merge the data and temp store it. */
              std::get<0> (key) = ws_is_same_object (grantor_mop, old_owner_mop) ? new_owner_mop : grantor_mop;
              std::get<1> (key) = grantee_mop;
              std::get<2> (key) = object_of_mop;

              if (authorization_unordered_map.find (key) == authorization_unordered_map.end())
            {
              /* storing unique data */
              authorization_unordered_map[key] = current_cache;
            }
              else
            {
              /* update the mask value of duplicated data. */
              authorization_unordered_map[key] |= current_cache;
            }
            }

          drop_grant_entry (grants, gindex);
          gindex -= GRANT_ENTRY_LENGTH;
          gsize -= GRANT_ENTRY_LENGTH;
        }
        }
    }
    }

  /* reinsert the merged temp data */
  for (const auto &entry : authorization_unordered_map)
    {
      const auto &key = entry.first;
      current_cache = entry.second;

      if (au_get_object (std::get<1> (key), "authorization", &auth) != NO_ERROR)
    {
      error = ER_AU_ACCESS_ERROR;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 2, AU_USER_CLASS_NAME, "authorization");
      goto exit;
    }
      else if ((error = obj_inst_lock (auth, 1)) == NO_ERROR
           && (error = get_grants (auth, &grants, 1)) == NO_ERROR)
    {
      gindex = add_grant_entry (grants, obj_type, std::get<2> (key), std::get<0> (key));
      db_make_int (&element, current_cache);
      error = set_put_element (grants, GRANT_ENTRY_CACHE (gindex), &element);

      /* Fail to insert, never change the grant entry set. */
      if (error != NO_ERROR)
        {
          goto exit;
        }
    }
    }

exit:
  if (result != NULL)
    {
      db_query_end (result);
    }
  if (session != NULL)
    {
      db_close_session (session);
    }

  pr_clear_value (&val);
  pr_clear_value (&element);
  pr_clear_value (&grantee_value);
  pr_clear_value (&object_of_value);

  if (grants != NULL)
    {
      set_free (grants);
    }

  if (*row_count < 0 && grantor_mop == NULL && grantee_mop == NULL && object_of_mop == NULL
      && er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      error = ER_GENERIC_ERROR;
    }

  AU_ENABLE (save);

  return (error);
}

static int
update_auth_for_new_owner (DB_OBJECT_TYPE obj_type, MOP old_owner_mop, MOP new_owner_mop, const char *unique_name)
{
  int error = NO_ERROR, save;
  char obj_fetch_query[256];
  const char *sql_query =
      "SELECT [au].object, [au].grantor, [au].grantee, [au].object_of, [au].auth_type, [au].is_grantable FROM ["
      CT_CLASSAUTH_NAME "] [au]"
      " WHERE [au].[object_of] = (%s)";
  DB_SESSION *session = NULL;
  int stmt_id;
  DB_QUERY_RESULT *result = NULL;
  DB_VALUE val, db_auth_object_value, grantor_value, grantee_value, object_of_value, auth_type_value, is_grantable_value;
  MOP db_auth_object_mop = NULL, grantor_mop = NULL, grantee_mop = NULL, object_of_mop = NULL;
  const char *auth_type_char;
  DB_AUTH db_auth = DB_AUTH_NONE;
  int is_grantable = -1;
  MOP auth;
  size_t au_db_auth_size;
  au_auth_accessor accessor;
  std::unordered_map<AuthKey, int, tuple_hash<AuthKey>, tuple_equal<AuthKey>> auth_unordered_map;
  AuthKey key;

  assert (old_owner_mop != NULL && new_owner_mop != NULL && unique_name != NULL);

  AU_DISABLE (save);

  db_make_null (&val);
  db_make_null (&db_auth_object_value);
  db_make_null (&grantor_value);
  db_make_null (&grantee_value);
  db_make_null (&object_of_value);
  db_make_null (&auth_type_value);
  db_make_null (&is_grantable_value);

  switch (obj_type)
    {
    case DB_OBJECT_CLASS:
      sprintf (obj_fetch_query, sql_query, "SELECT [c].[class_of] FROM " CT_CLASS_NAME "[c] WHERE [unique_name] = ?");
      break;
    case DB_OBJECT_PROCEDURE:
      sprintf (obj_fetch_query, sql_query, "SELECT [sp] FROM " CT_STORED_PROC_NAME "[sp] WHERE [unique_name] = ?");
      break;
    default:
      error = ER_FAILED;
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  session = db_open_buffer_local (obj_fetch_query);
  if (session == NULL)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  error = db_set_system_generated_statement (session);
  if (error != NO_ERROR)
    {
      goto exit;
    }

  stmt_id = db_compile_statement_local (session);
  if (stmt_id < 0)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  /* Prepare DB_VALUEs for host variables */
  db_make_string (&val, unique_name);

  error = db_push_values (session, 1, &val);
  if (error != NO_ERROR)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  error = db_execute_statement_local (session, stmt_id, &result);

  /* The error value is row count if it's not negative value. */
  if (error == 0)
    {
      error = ER_GENERIC_ERROR;
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
      goto exit;
    }
  else if (error < 0)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

  error = NO_ERROR;
  while (db_query_next_tuple (result) == DB_CURSOR_SUCCESS)
    {
      if (db_query_get_tuple_value (result, 0, &db_auth_object_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&db_auth_object_value))
        {
          goto exit;
        }

      db_auth_object_mop = db_get_object (&db_auth_object_value);
    }

      if (db_query_get_tuple_value (result, 1, &grantor_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&grantor_value))
        {
          goto exit;
        }

      grantor_mop = db_get_object (&grantor_value);
    }

      if (db_query_get_tuple_value (result, 2, &grantee_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&grantee_value))
        {
          goto exit;
        }

      grantee_mop = db_get_object (&grantee_value);
    }

      if (db_query_get_tuple_value (result, 3, &object_of_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&object_of_value))
        {
          goto exit;
        }

      object_of_mop = db_get_object (&object_of_value);
    }

      if (db_query_get_tuple_value (result, 4, &auth_type_value) == NO_ERROR)
    {
      auth_type_char = NULL;

      if (DB_IS_NULL (&auth_type_value))
        {
          error = ER_FAILED;
          ASSERT_ERROR_AND_SET (error);
          goto exit;
        }

      auth_type_char = db_get_char (&auth_type_value);

      switch (auth_type_char[0])
        {
        case 'A':
          db_auth = DB_AUTH_ALTER;
          break;

        case 'D':
          db_auth = DB_AUTH_DELETE;
          break;

        case 'E':
          db_auth = DB_AUTH_EXECUTE;
          break;

        case 'I':
          if (auth_type_char[2] == 'D')
        {
          db_auth = DB_AUTH_INDEX;
        }
          else if (auth_type_char[2] == 'S')
        {
          db_auth = DB_AUTH_INSERT;
        }
          else
        {
          db_auth = DB_AUTH_NONE;
          goto exit;
        }
          break;

        case 'S':
          db_auth = DB_AUTH_SELECT;
          break;

        case 'U':
          db_auth = DB_AUTH_UPDATE;
          break;

        default:
          db_auth = DB_AUTH_NONE;
          goto exit;
          break;
        }
    }

      if (db_query_get_tuple_value (result, 5, &is_grantable_value) == NO_ERROR)
    {
      if (DB_IS_NULL (&is_grantable_value))
        {
          goto exit;
        }

      is_grantable = db_get_int (&is_grantable_value);
    }

      assert (db_auth_object_mop != NULL && grantor_mop != NULL && grantee_mop != NULL && object_of_mop != NULL
          && db_auth != DB_AUTH_NONE && is_grantable != -1);

      /*
       * when the grantee becomes the new owner, previously granted privileges are removed.
       * reason: privileges of the owner cannot be revoked.
       * grantee_mop : grantee_user
       * new_owner_mop : grnator_user
       *
       * ex) SELECT * FROM db_authorization;
       *   owner            grants
       * ================================
       *   grantee         {..,unique_name, grantor, ..}
       */
      if (ws_is_same_object (grantee_mop, new_owner_mop))
    {
      /* privileges cannot be granted to the owner, so they are removed immediately without being temporarily stored. */
    }
      else
    {
      /* before deleting the data in db_auth, merge the data and temp store it. */
      std::get<0> (key) = ws_is_same_object (grantor_mop, old_owner_mop) ? new_owner_mop : grantor_mop;
      std::get<1> (key) = grantee_mop;
      std::get<2> (key) = object_of_mop;
      std::get<3> (key) = db_auth;

      if (auth_unordered_map.find (key) == auth_unordered_map.end() || auth_unordered_map[key] < is_grantable)
        {
          auth_unordered_map[key] = is_grantable;
        }
    }

      error = obj_inst_lock (db_auth_object_mop, 1);
      if (error != NO_ERROR)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }

      error = obj_delete (db_auth_object_mop);
      if (error != NO_ERROR)
    {
      ASSERT_ERROR_AND_SET (error);
      goto exit;
    }
    }

  /* reinsert the merged temp data */
  for (const auto &entry : auth_unordered_map)
    {
      const auto &key = entry.first;
      is_grantable = entry.second;

      error =
          accessor.insert_auth (obj_type, std::get<0> (key), std::get<1> (key), std::get<2> (key), std::get<3> (key),
                    (is_grantable) ? std::get<3> (key) : DB_AUTH_NONE);

      /* Fail to insert, do not add data to the _auth catalog. */
      if (error != NO_ERROR)
    {
      goto exit;
    }
    }


exit:
  if (result != NULL)
    {
      db_query_end (result);
    }
  if (session != NULL)
    {
      db_close_session (session);
    }

  db_value_clear (&val);
  db_value_clear (&db_auth_object_value);
  db_value_clear (&grantor_value);
  db_value_clear (&grantee_value);
  db_value_clear (&object_of_value);
  db_value_clear (&auth_type_value);
  db_value_clear (&is_grantable_value);

  if (db_auth_object_mop == NULL && grantor_mop == NULL && grantee_mop == NULL && object_of_mop == NULL &&
      db_auth == DB_AUTH_NONE && is_grantable == -1 && er_errid () == NO_ERROR)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_GENERIC_ERROR, 0);
      error = ER_GENERIC_ERROR;
    }

  AU_ENABLE (save);

  return (error);
}