/* -------------------------------------------------------------------------
 *  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.
 * -------------------------------------------------------------------------
 *
 * ogsql_replace_verifier.c
 *
 *
 * IDENTIFICATION
 * src/ogsql/verifier/ogsql_replace_verifier.c
 *
 * -------------------------------------------------------------------------
 */
#include "ogsql_replace_verifier.h"
#include "ogsql_insert_verifier.h"
#include "base_compiler.h"
#include "ogsql_hint_verifier.h"

#ifdef __cplusplus
extern "C" {
#endif

static status_t sql_verify_replace_into_values(sql_verifier_t *verif, sql_replace_t *replace_ctx)
{
    column_value_pair_t *pair = NULL;
    sql_insert_t *insert_ctx = &replace_ctx->insert_ctx;
    verif->excl_flags = SQL_EXCL_AGGR | SQL_EXCL_STAR | SQL_EXCL_ROWNUM | SQL_EXCL_ROWID | SQL_EXCL_ROWSCN |
        SQL_EXCL_WIN_SORT | SQL_EXCL_GROUPING;

    for (uint32 i = 0; i < insert_ctx->pairs->count; i++) {
        pair = (column_value_pair_t *)cm_galist_get(insert_ctx->pairs, i);
        if (sql_static_check_dml_pair(verif, pair) != OG_SUCCESS) {
            return OG_ERROR;
        }
    }

    return OG_SUCCESS;
}

static status_t sql_verify_partkeys_if_part_table(sql_verifier_t *verif, sql_insert_t *insert_ctx, knl_dictionary_t *dc,
    uint32 col_count)
{
    uint16 col_id;
    uint16 partkeys;

    if (knl_is_part_table(dc->handle)) {
        OG_RETURN_IFERR(sql_alloc_mem(verif->context, sizeof(uint16) * col_count, (void **)&insert_ctx->part_key_map));
        MEMS_RETURN_IFERR(memset_s(insert_ctx->part_key_map, sizeof(uint16) * col_count, (int)OG_INVALID_ID16,
            sizeof(uint16) * col_count));
        partkeys = knl_part_key_count(dc->handle);
        for (uint16 i = 0; i < partkeys; i++) {
            col_id = knl_part_key_column_id(dc->handle, i);
            insert_ctx->part_key_map[col_id] = i;
        }
    }

    return OG_SUCCESS;
}

static status_t sql_verify_replace_context(sql_verifier_t *verif, sql_replace_t *replace_ctx)
{
    uint32 col_count;
    knl_dictionary_t *dc = NULL;
    knl_column_t *column = NULL;
    sql_insert_t *insert_ctx = &replace_ctx->insert_ctx;

    OG_RETURN_IFERR(sql_verify_insert_tabs(verif->stmt, insert_ctx));
    dc = &insert_ctx->table->entry->dc;
    col_count = knl_get_column_count(dc->handle);
    if (col_count == 0) {
        OG_THROW_ERROR(ERR_INVALID_DC, T2S(&insert_ctx->table->name));
        return OG_ERROR;
    }

    OG_RETURN_IFERR(sql_alloc_mem(verif->context, sizeof(uint32) * col_count, (void **)&insert_ctx->col_map));

    MEMS_RETURN_IFERR(
        memset_s(insert_ctx->col_map, sizeof(uint32) * col_count, (int)OG_INVALID_ID32, sizeof(uint32) * col_count));
    if (!(insert_ctx->flags & INSERT_COLS_SPECIFIED)) {
        OG_RETURN_IFERR(sql_extract_insert_columns(verif, insert_ctx));
    } else {
        OG_RETURN_IFERR(sql_verify_insert_columns(verif, insert_ctx));

        for (uint32 i = 0; i < col_count; ++i) {
            column = knl_get_column(dc->handle, i);
            if (KNL_COLUMN_INVISIBLE(column)) {
                continue;
            }
            if (column->default_text.len != 0) {
                OG_RETURN_IFERR(sql_add_sequence_node(verif->stmt, ((expr_tree_t *)column->default_expr)->root));
            }
        }
    }

    OG_RETURN_IFERR(sql_verify_partkeys_if_part_table(verif, insert_ctx, dc, col_count));

    if (insert_ctx->select_ctx) {
        OG_RETURN_IFERR(sql_verify_select_context(verif, insert_ctx->select_ctx));
        if (verif->has_ddm_col == OG_TRUE) {
            OG_THROW_ERROR(ERR_INVALID_OPERATION, ", the command references a redacted object");
            return OG_ERROR;
        }
        if (insert_ctx->select_ctx->first_query->rs_columns->count != insert_ctx->pairs->count) {
            OG_THROW_ERROR((insert_ctx->select_ctx->first_query->rs_columns->count > insert_ctx->pairs->count) ?
                ERR_TOO_MANY_VALUES :
                ERR_NOT_ENOUGH_VALUES);
            return OG_ERROR;
        }
    } else {
        OG_RETURN_IFERR(sql_verify_replace_into_values(verif, replace_ctx));
    }

    replace_ctx->insert_ctx.hint_info = verif->stmt->context->hint_info;
    og_hint_verify(verif->stmt, OGSQL_TYPE_REPLACE, (void *)insert_ctx);

    return OG_SUCCESS;
}

status_t sql_verify_replace_into(sql_stmt_t *stmt, sql_replace_t *replace_ctx)
{
    sql_verifier_t verif = { 0 };

    verif.stmt = stmt;
    verif.table = replace_ctx->insert_ctx.table;
    verif.context = stmt->context;
    verif.pl_dc_lst = replace_ctx->insert_ctx.pl_dc_lst;
    verif.do_expr_optmz = OG_TRUE;
    plc_get_verify_obj(stmt, &verif);
    return sql_verify_replace_context(&verif, replace_ctx);
}

#ifdef __cplusplus
}
#endif