* 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_trigger.c
*
*
* IDENTIFICATION
* src/ogsql/pl/meta/pl_trigger.c
*
* -------------------------------------------------------------------------
*/
#include "pl_trigger.h"
#include "base_compiler.h"
#include "pl_compiler.h"
#include "srv_instance.h"
#include "pl_meta_common.h"
#include "pl_logic.h"
#include "trigger_decl_cl.h"
#ifdef OG_RAC_ING
status_t shd_pre_execute_ddl(sql_stmt_t *stmt, bool32 multi_ddl, bool32 need_encrypt);
status_t shd_trigger_check_for_rebalance(sql_stmt_t *stmt, text_t *user, text_t *tab);
#endif
trig_pseudo_column_t g_trig_pseudo_col[] = {
{TRIG_RES_WORD_ROWID, {"rowid", 5}},
{TRIG_RES_WORD_ROWSCN, {"rowscn", 6}}
};
#define TRIG_PSEUDO_COL_NUM ELEMENT_COUNT(g_trig_pseudo_col)
bool32 plc_trigger_verify_row_pesudo(const text_t *name, uint16 *col, text_t *decl_name)
{
for (uint32 loop = 0; loop < TRIG_PSEUDO_COL_NUM; loop++) {
if (cm_compare_text_ins(&g_trig_pseudo_col[loop].name, name) == 0) {
*col = g_trig_pseudo_col[loop].col_id;
cm_text_upper(decl_name);
return OG_TRUE;
}
}
return OG_FALSE;
}
static status_t plm_update_source_fetch_on(lex_t *lex, word_t *word)
{
for (;;) {
OG_RETURN_IFERR(lex_fetch(lex, word));
if (word->type == WORD_TYPE_EOF) {
OG_THROW_ERROR(ERR_PL_SYNTAX_ERROR_FMT, "'on' expected");
return OG_ERROR;
}
OG_BREAK_IF_TRUE(word->id == KEY_WORD_ON);
}
return OG_SUCCESS;
}
static status_t plm_update_source_trig_tab(knl_session_t *session, knl_cursor_t *cursor, knl_column_t *column, text_t *locator,
text_t *old_source, text_t *old_tab, text_t *new_tab)
{
lex_t lex;
sql_text_t sql_text;
text_t write_data;
word_t word;
word_t tab_word;
status_t status = OG_ERROR;
uint32 need_size = old_source->len - old_tab->len + new_tab->len;
if (OG_LARGE_PAGE_SIZE < need_size) {
OG_THROW_ERROR(ERR_SOURCE_SIZE_TOO_LARGE_FMT, need_size, OG_LARGE_PAGE_SIZE);
return OG_ERROR;
}
sql_text.value = *old_source;
lex_init(&lex, &sql_text);
lex.call_version = CS_LOCAL_VERSION;
if (plm_update_source_fetch_on(&lex, &word) != OG_SUCCESS) {
return OG_ERROR;
}
lex.flags = LEX_WITH_OWNER;
do {
OG_BREAK_IF_ERROR(lex_fetch(&lex, &tab_word));
if (tab_word.ex_count > 0) {
tab_word.text = tab_word.ex_words[0].text;
}
if (!cm_text_equal_ins(&tab_word.text.value, old_tab)) {
OG_THROW_ERROR(ERR_UNDEFINED_SYMBOL_FMT, T2S(old_tab));
break;
}
MEMS_RETURN_IFERR(memset_s(locator->str, locator->len, 0xFF, KNL_LOB_LOCATOR_SIZE));
write_data.str = old_source->str;
write_data.len = (uint32)(tab_word.text.str - old_source->str);
OG_BREAK_IF_ERROR(knl_write_lob(session, cursor, locator->str, column, OG_TRUE, &write_data));
OG_BREAK_IF_ERROR(knl_write_lob(session, cursor, locator->str, column, OG_TRUE, new_tab));
write_data.str = tab_word.text.str + tab_word.text.len;
write_data.len = old_source->len - (uint32)(write_data.str - old_source->str);
OG_BREAK_IF_ERROR(knl_write_lob(session, cursor, locator->str, column, OG_TRUE, &write_data));
status = OG_SUCCESS;
} while (0);
return status;
}
static status_t plm_update_tab_from_sysproc(knl_handle_t knl_session, pl_desc_t *desc, text_t *name, text_t *new_name)
{
knl_cursor_t *cursor = NULL;
row_assist_t row_ass;
knl_update_info_t *update_info = NULL;
char *locator = NULL;
uint32 large_page_id;
knl_session_t *session = (knl_session_t *)knl_session;
text_t source = { 0 };
knl_column_t *column = NULL;
char locator_buf[KNL_LOB_LOCATOR_SIZE] = { 0 };
binary_t loc_upt;
text_t locator_text;
status_t status = OG_SUCCESS;
loc_upt.bytes = (uint8 *)locator_buf;
loc_upt.size = KNL_LOB_LOCATOR_SIZE;
locator_text.str = locator_buf;
locator_text.len = KNL_LOB_LOCATOR_SIZE;
CM_SAVE_STACK(session->stack);
if (sql_push_knl_cursor(session, &cursor) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_STACK_OVERFLOW);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_PROC_ID, IX_PROC_003_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &desc->uid, sizeof(int32),
0);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_BIGINT, &desc->oid,
sizeof(desc->oid), 1);
column = knl_get_column(cursor->dc_entity, SYS_PROC_SOURCE_COL);
knl_begin_session_wait(knl_session, LARGE_POOL_ALLOC, OG_FALSE);
if (mpool_alloc_page_wait(&g_instance->sga.large_pool, &large_page_id, CM_MPOOL_ALLOC_WAIT_TIME) != OG_SUCCESS) {
knl_end_session_wait(knl_session, LARGE_POOL_ALLOC);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_end_session_wait(knl_session, LARGE_POOL_ALLOC);
source.str = mpool_page_addr(&g_instance->sga.large_pool, large_page_id);
for (;;) {
if (OG_SUCCESS != knl_fetch(session, cursor)) {
status = OG_ERROR;
break;
}
if (cursor->eof) {
break;
}
locator = CURSOR_COLUMN_DATA(cursor, SYS_PROC_SOURCE_COL);
if (knl_read_lob(session, locator, 0, source.str, OG_LARGE_PAGE_SIZE, &source.len, NULL) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
if (plm_update_source_trig_tab(session, cursor, column, &locator_text, &source, name, new_name) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
update_info = &cursor->update_info;
row_init(&row_ass, update_info->data, OG_MAX_ROW_SIZE, 2);
(void)row_put_bin(&row_ass, &loc_upt);
(void)row_put_text(&row_ass, new_name);
update_info->count = 2;
update_info->columns[0] = SYS_PROC_SOURCE_COL;
update_info->columns[1] = SYS_PROC_TRIG_TABLE_COL;
cm_decode_row(update_info->data, update_info->offsets, update_info->lens, NULL);
if (OG_SUCCESS != knl_internal_update(session, cursor)) {
status = OG_ERROR;
break;
}
}
mpool_free_page(&g_instance->sga.large_pool, large_page_id);
CM_RESTORE_STACK(session->stack);
return status;
}
status_t pl_update_source_for_trigs(knl_handle_t knl_session, knl_dictionary_t *dc, text_t *name, text_t *new_name)
{
dc_entity_t *entity = DC_ENTITY(dc);
trig_set_t *trig_set = &entity->trig_set;
pl_entry_t *entry = NULL;
pl_entry_info_t entry_info;
trig_item_t *trig_item = NULL;
knl_session_t *session = (knl_session_t *)knl_session;
for (uint32 i = 0; i < trig_set->trig_count; i++) {
trig_item = &trig_set->items[i];
pl_find_entry_by_oid(trig_item->oid, PL_TRIGGER, &entry_info);
entry = entry_info.entry;
CM_ASSERT(entry != NULL);
if (pl_lock_entry_exclusive(knl_session, &entry_info) != OG_SUCCESS) {
return OG_ERROR;
}
if (plm_update_tab_from_sysproc(session, &entry->desc, name, new_name) != OG_SUCCESS) {
pl_unlock_exclusive(knl_session, entry);
return OG_ERROR;
}
pl_entity_invalidate_by_entry(entry);
pl_unlock_exclusive(knl_session, entry);
}
return OG_SUCCESS;
}
void pl_free_trig_entity_by_tab(knl_handle_t knl_session, knl_dictionary_t *dc)
{
dc_entity_t *entity = DC_ENTITY(dc);
pl_entry_t *entry = NULL;
trig_item_t *trig_item = NULL;
trig_set_t trig_set = entity->trig_set;
pl_entry_info_t entry_info;
for (uint32 i = 0; i < trig_set.trig_count; i++) {
trig_item = &trig_set.items[i];
pl_find_entry_by_oid(trig_item->oid, PL_TRIGGER, &entry_info);
entry = entry_info.entry;
CM_ASSERT(entry != NULL);
if (pl_lock_entry_exclusive(knl_session, &entry_info) != OG_SUCCESS) {
OG_LOG_RUN_WAR("Don't find the trigger %s, user id = %u", entry->desc.name, entry->desc.uid);
continue;
}
pl_entity_invalidate_by_entry(entry);
pl_logic_log_put(knl_session, RD_PLM_FREE_TRIG_ENTITY, entry->desc.uid, entry->desc.oid, entry->desc.type);
pl_unlock_exclusive(knl_session, entry);
}
return;
}
status_t pl_write_systrigger(knl_session_t *session, uint64 oid, trig_desc_t *trig_desc)
{
uint32 max_size;
row_assist_t row_ass;
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
if (sql_push_knl_cursor(session, &cursor) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_STACK_OVERFLOW);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
max_size = session->kernel->attr.max_row_size;
row_init(&row_ass, cursor->buf, max_size, SYS_TRIGGER_COLUMN_COUNT);
(void)row_put_int64(&row_ass, oid);
(void)row_put_uint32(&row_ass, trig_desc->type);
(void)row_put_uint32(&row_ass, trig_desc->events);
(void)row_put_uint32(&row_ass, trig_desc->obj_uid);
(void)row_put_int64(&row_ass, trig_desc->base_obj);
(void)row_put_null(&row_ass);
(void)row_put_int32(&row_ass, trig_desc->enable);
(void)row_put_uint32(&row_ass, trig_desc->flags);
(void)row_put_uint32(&row_ass, trig_desc->action_line);
(void)row_put_uint32(&row_ass, trig_desc->action_col);
(void)row_put_null(&row_ass);
(void)row_put_null(&row_ass);
(void)row_put_null(&row_ass);
(void)row_put_null(&row_ass);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_TRIGGER_ID, OG_INVALID_ID32);
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t pl_delete_systriger(knl_session_t *session, uint64 oid)
{
knl_cursor_t *cursor = NULL;
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_DELETE, SYS_TRIGGER_ID, IX_SYS_TRIGGER_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_BIGINT, (void *)&oid, sizeof(oid),
IX_SYS_TRIGGER_001_ID_OBJ);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
while (!cursor->eof) {
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t pl_load_sys_trigger(knl_session_t *session, uint64 oid, trig_desc_t *trig)
{
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
if (sql_push_knl_cursor(session, &cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_set_session_scn(session, OG_INVALID_ID64);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_TRIGGER_ID, IX_SYS_TRIGGER_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_BIGINT, (void *)&oid, sizeof(oid),
IX_SYS_TRIGGER_001_ID_OBJ);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
OG_THROW_ERROR(ERR_OBJECT_ID_NOT_EXIST, "trigger", oid);
OG_LOG_RUN_ERR("load trigger failed, oid = %lld", (int64)oid);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
trig->events = (uint16)(*(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_TRIGGER_COL_EVENT));
trig->type = (uint16)(*(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_TRIGGER_COL_TYPE));
trig->enable = (uint16)(*(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_TRIGGER_COL_ENABLE));
trig->flags = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_TRIGGER_COL_FALGS);
trig->obj_uid = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_TRIGGER_COL_OBJECTUID);
trig->base_obj = *(uint64 *)CURSOR_COLUMN_DATA(cursor, SYS_TRIGGER_COL_BASEOBJECT);
trig->action_line = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_TRIGGER_COL_ACTIONLINENO);
trig->action_col = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_TRIGGER_COL_ACTIONCOLNO);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t pl_update_trigger_enable_status(knl_session_t *session, uint64 oid, bool32 enable)
{
status_t status = OG_ERROR;
knl_cursor_t *cursor = NULL;
knl_update_info_t *update_info = NULL;
row_assist_t row_ass;
CM_SAVE_STACK(session->stack);
if (sql_push_knl_cursor(session, &cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_set_session_scn(session, OG_INVALID_ID64);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TRIGGER_ID, IX_SYS_TRIGGER_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_BIGINT, (void *)&oid, sizeof(oid),
IX_SYS_TRIGGER_001_ID_OBJ);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
do {
OG_BREAK_IF_ERROR(knl_fetch(session, cursor));
if (!cursor->eof) {
OG_THROW_ERROR(ERR_OBJECT_ID_NOT_EXIST, "trigger", oid);
break;
}
update_info = &cursor->update_info;
update_info->count = 1;
row_init(&row_ass, update_info->data, OG_MAX_ROW_SIZE, update_info->count);
(void)row_put_int32(&row_ass, enable);
update_info->columns[0] = SYS_TRIGGER_COL_ENABLE;
cm_decode_row(update_info->data, update_info->offsets, update_info->lens, NULL);
OG_BREAK_IF_ERROR(knl_internal_update(session, cursor));
status = OG_SUCCESS;
} while (0);
CM_RESTORE_STACK(session->stack);
return status;
}
status_t pl_get_table_trigger_count(knl_session_t *session, void *trig_def, uint32 *trig_count)
{
knl_session_t *sess = (knl_session_t *)session;
knl_cursor_t *cursor = NULL;
status_t status = OG_SUCCESS;
trig_def_t *trig = (trig_def_t *)trig_def;
CM_SAVE_STACK(sess->stack);
if (sql_push_knl_cursor(session, &cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_set_session_scn(session, OG_INVALID_ID64);
knl_open_sys_cursor(sess, cursor, CURSOR_ACTION_SELECT, SYS_TRIGGER_ID, IX_SYS_TRIGGERS_002_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&trig->obj_uid,
sizeof(uint32), IX_SYS_TRIGGERS_002_ID_OBJUID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, (void *)&trig->obj_uid,
sizeof(uint32), IX_SYS_TRIGGERS_002_ID_OBJUID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_BIGINT, (void *)&trig->obj_oid,
sizeof(uint64), IX_SYS_TRIGGERS_002_ID_BASEOBJ);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_BIGINT, (void *)&trig->obj_oid,
sizeof(uint64), IX_SYS_TRIGGERS_002_ID_BASEOBJ);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_SYS_TRIGGER_002_ID_OBJ);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_SYS_TRIGGER_002_ID_OBJ);
*trig_count = 0;
for (;;) {
if (OG_SUCCESS != knl_fetch(session, cursor)) {
status = OG_ERROR;
break;
}
if (cursor->eof) {
break;
}
(*trig_count)++;
}
return status;
}
status_t pl_load_entity_update_trigger_table(knl_session_t *session, void *desc_in, void *entity_in)
{
pl_desc_t *desc = (pl_desc_t *)desc_in;
pl_entity_t *entity = (pl_entity_t *)entity_in;
object_address_t obj_addr;
pl_entry_t *entry = entity->entry;
OG_RETURN_IFERR(pl_get_desc_objaddr(&obj_addr, desc));
OG_RETURN_IFERR(pl_update_sysproc_status(session, desc));
OG_RETURN_IFERR(pl_delete_dependency(session, &obj_addr));
if (desc->status == OBJ_STATUS_VALID) {
OG_RETURN_IFERR(pl_insert_dependency_list(session, &obj_addr, &entity->ref_list));
}
if (entry->desc.status == OBJ_STATUS_VALID && desc->status != OBJ_STATUS_VALID) {
OG_RETURN_IFERR(pl_update_depender_status(session, &obj_addr));
}
return OG_SUCCESS;
}
status_t pl_update_sysproc_trigger_enable(knl_session_t *knl_session, void *desc_in, bool32 enable)
{
pl_desc_t *desc = (pl_desc_t *)desc_in;
knl_cursor_t *cursor = NULL;
row_assist_t row_ass;
knl_update_info_t *update_info = NULL;
status_t status = OG_ERROR;
CM_SAVE_STACK(knl_session->stack);
if (sql_push_knl_cursor(knl_session, &cursor) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_STACK_OVERFLOW);
CM_RESTORE_STACK(knl_session->stack);
return OG_ERROR;
}
do {
knl_set_session_scn(knl_session, OG_INVALID_ID64);
knl_open_sys_cursor(knl_session, cursor, CURSOR_ACTION_UPDATE, SYS_PROC_ID, IX_PROC_003_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &desc->uid,
sizeof(int32), 0);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_BIGINT, &desc->oid,
sizeof(desc->oid), 1);
OG_BREAK_IF_ERROR(knl_fetch(knl_session, cursor));
if (cursor->eof) {
break;
}
update_info = &cursor->update_info;
update_info->count = 1;
row_init(&row_ass, update_info->data, OG_MAX_ROW_SIZE, update_info->count);
if (enable) {
(void)row_put_str(&row_ass, "ENABLED");
} else {
(void)row_put_str(&row_ass, "DISABLED");
}
update_info->columns[0] = SYS_PROC_TRIG_STATUS_COL;
cm_decode_row(update_info->data, update_info->offsets, update_info->lens, NULL);
OG_BREAK_IF_ERROR(knl_internal_update(knl_session, cursor));
status = OG_SUCCESS;
} while (0);
CM_RESTORE_STACK(knl_session->stack);
return status;
}