/* -------------------------------------------------------------------------
 *  This file is part of the oGRAC project.
 * Copyright (c) 2024 Huawei Technologies Co.,Ltd.
 *
 * oGRAC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * -------------------------------------------------------------------------
 *
 * pl_synonym.c
 *
 *
 * IDENTIFICATION
 * src/ogsql/pl/meta/pl_synonym.c
 *
 * -------------------------------------------------------------------------
 */
#include "pl_synonym.h"
#include "pl_lock.h"
#include "ogsql_dependency.h"
#include "pl_logic.h"
#include "pl_common.h"
#include "knl_table.h"

static status_t pl_init_sync_def(knl_synonym_t *synonym, knl_synonym_def_t *def, pl_desc_t *desc)
{
    synonym->uid = desc->uid;
    synonym->id = (uint32)desc->oid;
    synonym->org_scn = desc->org_scn;
    synonym->chg_scn = desc->chg_scn;
    OG_RETURN_IFERR(cm_text2str(&def->name, synonym->name, OG_NAME_BUFFER_SIZE));
    OG_RETURN_IFERR(cm_text2str(&def->table_owner, synonym->table_owner, OG_NAME_BUFFER_SIZE));
    OG_RETURN_IFERR(cm_text2str(&def->table_name, synonym->table_name, OG_NAME_BUFFER_SIZE));
    synonym->flags = OBJ_STATUS_VALID;
    synonym->type = pltype_to_objtype(def->ref_dc_type);
    return OG_SUCCESS;
}

status_t pl_write_pl_synonym(knl_session_t *session, knl_synonym_def_t *def, pl_desc_t *desc)
{
    knl_synonym_t synonym;
    knl_cursor_t *cursor = NULL;

    if (pl_init_sync_def(&synonym, def, desc) != OG_SUCCESS) {
        return OG_ERROR;
    }

    CM_SAVE_STACK(session->stack);

    knl_set_session_scn(session, OG_INVALID_ID64);
    if (sql_push_knl_cursor(session, &cursor) != OG_SUCCESS) {
        OG_THROW_ERROR(ERR_STACK_OVERFLOW);
        CM_RESTORE_STACK(session->stack);
        return OG_ERROR;
    }

    if (db_write_syssyn(session, cursor, &synonym) != OG_SUCCESS) {
        CM_RESTORE_STACK(session->stack);
        return OG_ERROR;
    }

    CM_RESTORE_STACK(session->stack);
    return OG_SUCCESS;
}

status_t pl_write_syn_dep(knl_session_t *session, knl_synonym_def_t *def, pl_desc_t *desc)
{
    knl_cursor_t *cursor = NULL;
    object_address_t obj_addr;
    object_address_t ref;

    obj_addr.uid = desc->uid;
    obj_addr.oid = desc->oid;
    obj_addr.tid = OBJ_TYPE_PL_SYNONYM;
    obj_addr.scn = desc->chg_scn;
    MEMS_RETURN_IFERR(strcpy_s(obj_addr.name, OG_NAME_BUFFER_SIZE, desc->name));

    ref.uid = def->ref_uid;
    ref.oid = def->ref_oid;
    ref.tid = pltype_to_objtype(def->ref_dc_type);
    ref.scn = def->ref_chg_scn;
    MEMS_RETURN_IFERR(strncpy_s(ref.name, OG_NAME_BUFFER_SIZE, def->table_name.str, def->table_name.len));

    CM_SAVE_STACK(session->stack);

    knl_set_session_scn(session, OG_INVALID_ID64);
    if (sql_push_knl_cursor(session, &cursor) != OG_SUCCESS) {
        OG_THROW_ERROR(ERR_STACK_OVERFLOW);
        CM_RESTORE_STACK(session->stack);
        return OG_ERROR;
    }

    if (db_write_sysdep(session, cursor, &obj_addr, &ref, 0) != OG_SUCCESS) {
        CM_RESTORE_STACK(session->stack);
        return OG_ERROR;
    }
    CM_RESTORE_STACK(session->stack);

    return OG_SUCCESS;
}

static status_t pl_process_drop_synonym(knl_session_t *session, pl_entry_info_t *entry_info)
{
    bool32 ret_ok = OG_FALSE;
    pl_entry_t *entry = entry_info->entry;

    if (pl_lock_entry_exclusive(session, entry_info) != OG_SUCCESS) {
        return OG_ERROR;
    }

    obj_info_t obj_addr = { OBJ_TYPE_PL_SYNONYM, entry->desc.uid, entry->desc.oid };
    do {
        OG_BREAK_IF_ERROR(knl_delete_syssyn_by_name(session, entry->desc.uid, entry->desc.name));
        OG_BREAK_IF_ERROR(knl_delete_dependency(session, entry->desc.uid, entry->desc.oid, OBJ_TYPE_PL_SYNONYM));
        OG_BREAK_IF_ERROR(sql_update_depender_status(session, &obj_addr));
        pl_logic_log_put(session, RD_PLM_DROP, entry->desc.uid, entry->desc.oid, entry->desc.type);
        ret_ok = OG_TRUE;
    } while (OG_FALSE);

    if (!ret_ok) {
        knl_rollback(session, NULL);
        pl_unlock_exclusive(session, entry);
        return OG_ERROR;
    }

    knl_commit(session);
    pl_entity_invalidate_by_entry(entry);
    pl_entry_drop(entry);
    pl_unlock_exclusive(session, entry);
    pl_free_entry(entry);
    return OG_SUCCESS;
}

status_t pl_execute_drop_synonym_core(sql_stmt_t *stmt, dc_user_t *dc_user)
{
    knl_drop_def_t *drop_def = (knl_drop_def_t *)stmt->context->entry;
    pl_entry_info_t entry_info;
    bool32 found = OG_FALSE;
    status_t status;

    pl_find_entry_for_desc(dc_user, &drop_def->name, PL_SYNONYM, &entry_info, &found);
    if (found) {
        status = pl_process_drop_synonym(KNL_SESSION(stmt), &entry_info);
    } else {
        if (drop_def->options & DROP_IF_EXISTS) {
            status = OG_SUCCESS;
        } else {
            OG_THROW_ERROR(ERR_USER_OBJECT_NOT_EXISTS, "synonym", T2S(&drop_def->owner), T2S_EX(&drop_def->name));
            status = OG_ERROR;
        }
    }

    return status;
}

status_t pl_drop_synonym_by_user(knl_handle_t sess, uint32 uid, text_t *syn_name)
{
    knl_session_t *session = (knl_session_t *)sess;
    dc_user_t *dc_user = NULL;
    pl_entry_info_t entry_info;
    bool32 found = OG_FALSE;

    OG_RETURN_IFERR(dc_open_user_by_id(session, uid, &dc_user));
    pl_find_entry_for_desc(dc_user, syn_name, PL_SYNONYM, &entry_info, &found);
    if (found) {
        return pl_process_drop_synonym(session, &entry_info);
    }

    OG_THROW_ERROR(ERR_USER_OBJECT_NOT_EXISTS, "synonym", dc_user->desc.name, T2S(syn_name));
    return OG_ERROR;
}

status_t pl_load_synonym(knl_handle_t sess, void *desc_in)
{
    knl_session_t *session = (knl_session_t *)sess;
    pl_desc_t *desc = (pl_desc_t *)desc_in;
    knl_cursor_t *cursor = NULL;
    text_t obj_name;

    CM_SAVE_STACK(session->stack);
    if (sql_push_knl_cursor(session, &cursor) != OG_SUCCESS) {
        CM_RESTORE_STACK(session->stack);
        return OG_ERROR;
    }

    knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_SYN_ID, IX_SYS_SYNONYM002_ID);
    knl_init_index_scan(cursor, OG_TRUE);
    knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&desc->uid,
        sizeof(int32), IX_COL_SYS_SYNONYM002_USER);
    knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&desc->oid,
        sizeof(int64), IX_COL_SYS_SYNONYM002_OBJID);

    if (knl_fetch(session, cursor) != OG_SUCCESS) {
        CM_RESTORE_STACK(session->stack);
        return OG_ERROR;
    }

    if (cursor->eof) {
        CM_RESTORE_STACK(session->stack);
        return OG_ERROR;
    }

    desc->org_scn = *(uint64 *)CURSOR_COLUMN_DATA(cursor, SYS_SYN_ORG_SCN);
    desc->chg_scn = *(uint64 *)CURSOR_COLUMN_DATA(cursor, SYS_SYN_CHG_SCN);

    obj_name.str = (char *)CURSOR_COLUMN_DATA(cursor, SYS_SYN_SYNONYM_NAME);
    obj_name.len = (uint32)CURSOR_COLUMN_SIZE(cursor, SYS_SYN_SYNONYM_NAME);
    if (cm_text2str(&obj_name, desc->name, OG_NAME_BUFFER_SIZE) != OG_SUCCESS) {
        CM_RESTORE_STACK(session->stack);
        return OG_ERROR;
    }

    obj_name.str = (char *)CURSOR_COLUMN_DATA(cursor, SYS_SYN_TABLE_OWNER);
    obj_name.len = (uint32)CURSOR_COLUMN_SIZE(cursor, SYS_SYN_TABLE_OWNER);
    if (cm_text2str(&obj_name, desc->link_user, OG_NAME_BUFFER_SIZE) != OG_SUCCESS) {
        CM_RESTORE_STACK(session->stack);
        return OG_ERROR;
    }

    obj_name.str = (char *)CURSOR_COLUMN_DATA(cursor, SYS_SYN_TABLE_NAME);
    obj_name.len = (uint32)CURSOR_COLUMN_SIZE(cursor, SYS_SYN_TABLE_NAME);
    if (cm_text2str(&obj_name, desc->link_name, OG_NAME_BUFFER_SIZE) != OG_SUCCESS) {
        CM_RESTORE_STACK(session->stack);
        return OG_ERROR;
    }

    desc->status = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_SYN_FLAG);
    CM_RESTORE_STACK(session->stack);
    return OG_SUCCESS;
}