* 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.
* -------------------------------------------------------------------------
*
* knl_table.c
*
*
* IDENTIFICATION
* src/kernel/table/knl_table.c
*
* -------------------------------------------------------------------------
*/
#include "knl_table_module.h"
#include "knl_table.h"
#include "dc_tbl.h"
#include "dc_part.h"
#include "knl_mtrl.h"
#include "knl_database.h"
#include "knl_context.h"
#include "temp_btree.h"
#include "pcr_heap.h"
#include "pcr_heap_scan.h"
#include "pcr_btree.h"
#include "index_common.h"
#include "rcr_btree_scan.h"
#include "knl_comment.h"
#include "knl_external.h"
#include "knl_ctlg.h"
#include "knl_sys_part_defs.h"
#include "index_common.h"
#include "dtc_dls.h"
#include "dtc_dc.h"
#include "srv_instance.h"
#ifdef OG_RAC_ING
static status_t db_insert_distribute_strategy_inner(knl_session_t *session, knl_cursor_t *cursor,
knl_table_desc_t *desc);
status_t db_insert_distribute_strategy(knl_session_t *session, table_t *table);
status_t db_delete_distribute_strategy(knl_session_t *session, table_t *table);
#endif
#define COLUMN_SET_DELETED(col) ((col)->flags |= KNL_COLUMN_FLAG_DELETED)
#define COLUMN_SET_HIDDEN(col) ((col)->flags |= KNL_COLUMN_FLAG_HIDDEN)
#define COLUMN_SET_SERIAL(col) ((col)->flags |= KNL_COLUMN_FLAG_SERIAL)
#define COLUMN_RESET_SERIAL(col) ((col)->flags &= ~KNL_COLUMN_FLAG_SERIAL)
#define COLUMN_SET_UPDATE_DEFAULT(col) ((col)->flags |= KNL_COLUMN_FLAG_UPDATE_DEFAULT)
#define COLUMN_RESET_UPDATE_DEFAULT(col) ((col)->flags &= ~KNL_COLUMN_FLAG_UPDATE_DEFAULT)
#define COLUMN_SET_CHARACTER(col) ((col)->flags |= KNL_COLUMN_FLAG_CHARACTER)
#define COLUMN_SET_QUOTE(col) ((col)->flags |= KNL_COLUMN_FLAG_QUOTE)
#define COLUMN_SET_VIRTUAL(col) ((col)->flags |= KNL_COLUMN_FLAG_VIRTUAL)
#define COLUMN_SET_DESCEND(col) ((col)->flags |= KNL_COLUMN_FLAG_DESCEND)
#define COLUMN_SET_NOCHARACTER(col) ((col)->flags &= ~KNL_COLUMN_FLAG_CHARACTER)
#define COLUMN_SET_DEFAULT_NULL(col) ((col)->flags |= KNL_COLUMN_FLAG_DEFAULT_NULL)
#define COLUMN_SET_ARRAY(col) ((col)->flags |= KNL_COLUMN_FLAG_ARRAY)
#define COLUMN_RESET_ARRAY(col) ((col)->flags &= ~KNL_COLUMN_FLAG_ARRAY)
#define COLUMN_RESET_DEFAULT_NULL(col) ((col)->flags &= ~KNL_COLUMN_FLAG_DEFAULT_NULL)
#define COLUMN_SET_JSONB(col) ((col)->flags |= KNL_COLUMN_FLAG_JSONB)
#define COLUMN_RESET_JSONB(col) ((col)->flags &= ~KNL_COLUMN_FLAG_JSONB)
#define COLUMN_SET_ROWID_TYPE(col) ((col)->flags |= KNL_COLUMN_FLAG_ROWID_TYPE)
#define COLUMN_RESET_ROWID_TYPE(col) ((col)->flags &= ~KNL_COLUMN_FLAG_ROWID_TYPE)
#define MAX_COLUMN_ID_STR_LEN 6
typedef struct st_ptrans_match_cond {
knl_session_t *session;
knl_cursor_t *cursor;
knl_xa_xid_t *xa_xid;
uint64 *ltid;
bool32 only_remained;
}ptrans_match_cond_t;
static status_t db_clean_shadow_index(knl_session_t *session, uint32 user_id, uint32 table_id, bool32 clean_segment);
static inline uint8 db_get_index_col_dir(const knl_index_desc_t *desc, uint32 col_pos)
{
return desc->col_dirs[col_pos] == SORT_MODE_DESC ? SORT_MODE_DESC : SORT_MODE_ASC;
}
status_t db_invalid_cursor_operation(knl_session_t *session, knl_cursor_t *cursor)
{
OG_THROW_ERROR(ERR_CAPABILITY_NOT_SUPPORT, "invalid operation on view or external table");
return OG_ERROR;
}
status_t db_invalid_cursor_operation1(knl_session_t *session, knl_cursor_t *cursor, bool32 *is_found)
{
OG_THROW_ERROR(ERR_CAPABILITY_NOT_SUPPORT, "invalid operation on view or external table");
return OG_ERROR;
}
table_accessor_t g_heap_acsor = {
(knl_cursor_operator_t)heap_fetch,
(knl_cursor_operator_t)heap_rowid_fetch,
(knl_cursor_operator_t)heap_fetch_by_rowid,
(knl_cursor_operator1_t)heap_lock_row,
(knl_cursor_operator_t)heap_insert,
(knl_cursor_operator_t)heap_update,
(knl_cursor_operator_t)heap_delete
};
table_accessor_t g_pcr_heap_acsor = {
(knl_cursor_operator_t)pcrh_fetch_inter,
(knl_cursor_operator_t)pcrh_rowid_scan_fetch,
(knl_cursor_operator_t)pcrh_fetch_by_rid,
(knl_cursor_operator1_t)pcrh_lock_row,
(knl_cursor_operator_t)pcrh_insert,
(knl_cursor_operator_t)pcrh_update,
(knl_cursor_operator_t)pcrh_delete
};
table_accessor_t g_temp_heap_acsor = {
(knl_cursor_operator_t)temp_heap_fetch,
(knl_cursor_operator_t)temp_heap_rowid_fetch,
(knl_cursor_operator_t)temp_heap_fetch_by_rowid,
(knl_cursor_operator1_t)temp_heap_lock_row,
(knl_cursor_operator_t)temp_heap_insert,
(knl_cursor_operator_t)temp_heap_update,
(knl_cursor_operator_t)temp_heap_delete
};
table_accessor_t g_external_table_acsor = {
(knl_cursor_operator_t)external_heap_fetch,
(knl_cursor_operator_t)db_invalid_cursor_operation,
(knl_cursor_operator_t)db_invalid_cursor_operation,
(knl_cursor_operator1_t)db_invalid_cursor_operation,
(knl_cursor_operator_t)db_invalid_cursor_operation,
(knl_cursor_operator_t)db_invalid_cursor_operation,
(knl_cursor_operator_t)db_invalid_cursor_operation,
};
table_accessor_t g_invalid_table_acsor = {
(knl_cursor_operator_t)db_invalid_cursor_operation,
(knl_cursor_operator_t)db_invalid_cursor_operation,
(knl_cursor_operator_t)db_invalid_cursor_operation,
(knl_cursor_operator1_t)db_invalid_cursor_operation1,
(knl_cursor_operator_t)db_invalid_cursor_operation,
(knl_cursor_operator_t)db_invalid_cursor_operation,
(knl_cursor_operator_t)db_invalid_cursor_operation,
};
status_t db_generate_object_id(knl_session_t *session, uint32 *obj_id)
{
uint64 oid;
text_t name;
text_t sys = { .str = SYS_USER_NAME, .len = (uint32)strlen(SYS_USER_NAME) };
cm_str2text("OBJECT_ID$", &name);
if (knl_seq_nextval(session, &sys, &name, (int64 *)&oid) != OG_SUCCESS) {
return OG_ERROR;
}
*obj_id = (uint32)oid;
return OG_SUCCESS;
}
static status_t db_get_table_spaceid(knl_session_t *session, knl_table_def_t *def, knl_table_desc_t *desc)
{
if (def->space.str == NULL) {
if (TABLE_IS_TEMP(def->type)) {
if (dc_get_user_temp_spc(session, desc->uid, &desc->space_id) != OG_SUCCESS) {
return OG_ERROR;
}
} else if (def->type != TABLE_TYPE_NOLOGGING) {
if (dc_get_user_default_spc(session, desc->uid, &desc->space_id) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
desc->space_id = DB_CORE_CTRL(session)->temp_space;
}
} else {
if (spc_get_space_id(session, &def->space, def->is_for_create_db, &desc->space_id) != OG_SUCCESS) {
return OG_ERROR;
}
if (spc_check_by_uid(session, &def->space, desc->space_id, desc->uid) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_check_table_by_spc(knl_session_t *session, space_t *space, knl_table_def_t *def)
{
if (IS_UNDO_SPACE(space)) {
OG_THROW_ERROR(ERR_MISUSE_UNDO_SPACE, T2S(&def->space));
return OG_ERROR;
}
if (SPACE_IS_LOGGING(space) && def->type == TABLE_TYPE_NOLOGGING) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create nologging table", "logging tablespace");
return OG_ERROR;
}
if (SPACE_IS_NOLOGGING(space) && !TABLE_IS_TEMP(def->type)) {
def->type = TABLE_TYPE_NOLOGGING;
}
if (IS_SWAP_SPACE(space) && !TABLE_IS_TEMP(def->type)) {
OG_THROW_ERROR(ERR_PERMANENTOBJ_IN_TEMPSPACE);
return OG_ERROR;
}
if (!IS_SWAP_SPACE(space) && TABLE_IS_TEMP(def->type)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create temporary table", "non-swap tablespace");
return OG_ERROR;
}
if (def->type == TABLE_TYPE_NOLOGGING && DB_ATTR_CLUSTER(session)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create nologging table", "cluster mode");
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_init_table_desc_spc(knl_session_t *session, knl_table_desc_t *desc, knl_table_def_t *def)
{
if (db_get_table_spaceid(session, def, desc) != OG_SUCCESS) {
return OG_ERROR;
}
space_t *space = SPACE_GET(session, desc->space_id);
if (TABLE_IS_TEMP(def->type) && def->parted) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create partition",
IS_LTT_BY_NAME(def->name.str) ? "local temporary table" : "global temporary table");
return OG_ERROR;
}
if (db_check_table_by_spc(session, space, def) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_init_table_desc_by_def(knl_session_t *session, knl_table_desc_t *desc, knl_table_def_t *def)
{
desc->column_count = def->columns.count;
(void)cm_text2str(&def->name, desc->name, OG_NAME_BUFFER_SIZE);
desc->entry = INVALID_PAGID;
desc->type = def->type;
desc->cr_mode = (cr_mode_t)def->cr_mode;
desc->initrans = def->initrans;
desc->pctfree = def->pctfree;
desc->appendonly = def->appendonly;
desc->parted = def->parted;
desc->external_desc = NULL;
desc->serial_start = def->serial_start;
desc->id = def->sysid;
desc->version = TABLE_VERSION_NEW_HASH;
desc->is_csf = def->csf;
space_t *space = SPACE_GET(session, desc->space_id);
desc->compress_algo = COMPRESS_NONE;
if (def->compress_algo > COMPRESS_NONE) {
desc->compress_algo = def->compress_algo;
}
if (desc->compress_algo > COMPRESS_NONE) {
if (!(def->type == TABLE_TYPE_HEAP && IS_SPACE_COMPRESSIBLE(space))) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create compress table",
"non heap table and non user bitmap tablespace");
return OG_ERROR;
}
if (def->part_def != NULL && def->part_def->is_composite) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create compress table",
"subpart table");
return OG_ERROR;
}
} else {
if (session->kernel->attr.default_compress_algo > COMPRESS_NONE) {
if ((def->type == TABLE_TYPE_HEAP && IS_SPACE_COMPRESSIBLE(space) && (def->part_def == NULL ||
!def->part_def->is_composite))) {
desc->compress_algo = session->kernel->attr.default_compress_algo;
}
}
}
desc->compress = (desc->compress_algo > COMPRESS_NONE) ? OG_TRUE : OG_FALSE;
if (TABLE_IS_TEMP(def->type)) {
desc->cr_mode = CR_ROW;
} else if (DB_ATTR_CLUSTER(session)) {
desc->cr_mode = CR_PAGE;
}
#ifdef OG_RAC_ING
desc->distribute_type = def->distribute_type;
desc->distribute_data = def->distribute_data;
desc->distribute_text = def->distribute_text;
desc->distribute_buckets = def->distribute_buckets;
desc->slice_count = def->slice_count;
desc->group_count = def->distribute_groups.count;
#endif
return OG_SUCCESS;
}
static inline status_t db_create_table_def_check(knl_table_def_t *def)
{
if (def->storage_def.initial > 0) {
if (def->type != TABLE_TYPE_HEAP && def->type != TABLE_TYPE_NOLOGGING) {
OG_THROW_ERROR(ERR_CAPABILITY_NOT_SUPPORT, "storage option without heap table");
return OG_ERROR;
}
}
if (def->storage_def.maxsize > 0) {
if (def->type != TABLE_TYPE_HEAP && def->type != TABLE_TYPE_NOLOGGING) {
OG_THROW_ERROR(ERR_CAPABILITY_NOT_SUPPORT, "storage option without heap table");
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_init_table_storage_desc(knl_session_t *session, knl_table_desc_t *desc, knl_table_def_t *def)
{
space_t *space;
space = SPACE_GET(session, desc->space_id);
if (def->storage_def.initial > 0) {
if (!dc_is_reserved_entry(desc->uid, desc->id)) {
desc->storaged = OG_TRUE;
}
desc->storage_desc.initial = CM_CALC_ALIGN((uint64)def->storage_def.initial, space->ctrl->block_size) /
space->ctrl->block_size;
}
if (def->storage_def.maxsize > 0 && !dc_is_reserved_entry(desc->uid, desc->id)) {
desc->storaged = OG_TRUE;
desc->storage_desc.max_pages = CM_CALC_ALIGN((uint64)def->storage_def.maxsize, space->ctrl->block_size) /
space->ctrl->block_size;
}
return OG_SUCCESS;
}
status_t db_init_table_desc(knl_session_t *session, knl_table_desc_t *desc, knl_table_def_t *def)
{
if (!dc_get_user_id(session, &def->schema, &desc->uid)) {
OG_THROW_ERROR(ERR_USER_NOT_EXIST, T2S(&def->schema));
return OG_ERROR;
}
if (def->columns.count > session->kernel->attr.max_column_count - 1) {
OG_THROW_ERROR(ERR_MAX_COLUMN_SIZE, session->kernel->attr.max_column_count - 1);
return OG_ERROR;
}
if (db_init_table_desc_spc(session, desc, def) != OG_SUCCESS) {
return OG_ERROR;
}
if (TABLE_IS_TEMP(def->type)) {
desc->oid = OG_INVALID_ID32;
} else {
if (!dc_is_reserved_entry(desc->uid, desc->id)) {
if (db_generate_object_id(session, &desc->oid) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
desc->oid = def->sysid;
}
}
desc->org_scn = db_inc_scn(session);
desc->chg_scn = desc->org_scn;
if (db_init_table_desc_by_def(session, desc, def) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_init_table_storage_desc(session, desc, def) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_init_view_desc(knl_session_t *session, knl_view_t *view, knl_view_def_t *def)
{
if (!dc_get_user_id(session, &def->user, &view->uid)) {
OG_THROW_ERROR(ERR_USER_NOT_EXIST, T2S(&def->user));
return OG_ERROR;
}
view->org_scn = db_inc_scn(session);
view->chg_scn = view->org_scn;
view->column_count = def->columns.count;
(void)cm_text2str(&def->name, view->name, OG_NAME_BUFFER_SIZE);
view->flags = def->status;
view->sql_type = def->sql_tpye;
view->id = OG_INVALID_ID32;
return OG_SUCCESS;
}
static void db_init_column_flg(knl_column_def_t *def, knl_column_t *column)
{
if (def->is_serial) {
COLUMN_SET_SERIAL(column);
} else {
COLUMN_RESET_SERIAL(column);
}
if (def->is_update_default) {
COLUMN_SET_UPDATE_DEFAULT(column);
} else {
COLUMN_RESET_UPDATE_DEFAULT(column);
}
if (def->has_quote) {
COLUMN_SET_QUOTE(column);
}
if (OG_IS_STRING_TYPE(column->datatype)) {
if (def->typmod.is_char) {
COLUMN_SET_CHARACTER(column);
} else {
COLUMN_SET_NOCHARACTER(column);
}
if (def->typmod.is_rowid_type) {
COLUMN_SET_ROWID_TYPE(column);
} else {
COLUMN_RESET_ROWID_TYPE(column);
}
}
if (!def->is_default_null) {
COLUMN_RESET_DEFAULT_NULL(column);
column->default_text = def->default_text;
} else {
column->default_text.str = NULL;
column->default_text.len = 0;
COLUMN_SET_DEFAULT_NULL(column);
}
if (def->typmod.is_array == OG_TRUE) {
COLUMN_SET_ARRAY(column);
} else {
COLUMN_RESET_ARRAY(column);
}
if (def->is_jsonb == OG_TRUE) {
COLUMN_SET_JSONB(column);
} else {
COLUMN_RESET_JSONB(column);
}
}
* Description : Initialize table description with table definition
* : Note: memory of column->name should allocated outside
* Input : session
* Input : def: table definition
* Output : desc: table description
* Return Value : status_t
* History : 1. 2017/4/26, add description
*/
void db_convert_column_def(knl_column_t *column, uint32 uid, uint32 obj_id, knl_column_def_t *def,
knl_column_t *old_column, uint32 id)
{
column->id = id;
column->uid = uid;
column->table_id = obj_id;
(void)cm_text2str(&def->name, column->name, OG_NAME_BUFFER_SIZE);
column->nullable = old_column ? (def->has_null ? def->nullable : old_column->nullable) : def->nullable;
column->flags = old_column ? old_column->flags : 0;
column->datatype = def->typmod.datatype;
column->size = def->typmod.size;
switch (column->datatype) {
case OG_TYPE_REAL:
case OG_TYPE_FLOAT:
case OG_TYPE_NUMBER:
case OG_TYPE_NUMBER2:
case OG_TYPE_NUMBER3:
case OG_TYPE_DECIMAL:
case OG_TYPE_INTERVAL_DS:
case OG_TYPE_INTERVAL_YM:
case OG_TYPE_TIMESTAMP:
case OG_TYPE_TIMESTAMP_TZ_FAKE:
case OG_TYPE_TIMESTAMP_TZ:
case OG_TYPE_TIMESTAMP_LTZ:
case OG_TYPE_UINT32:
case OG_TYPE_UINT64:
case OG_TYPE_INTEGER:
case OG_TYPE_BIGINT:
column->precision = def->typmod.precision;
column->scale = def->typmod.scale;
break;
default:
column->precision = 0;
column->scale = 0;
break;
}
db_init_column_flg(def, column);
}
status_t db_write_syslob(knl_session_t *session, knl_cursor_t *cursor, knl_lob_desc_t *desc)
{
row_assist_t ra;
table_t *table = NULL;
space_t *space;
status_t status;
space = SPACE_GET(session, desc->space_id);
if (!SPACE_IS_ONLINE(space)) {
OG_THROW_ERROR(ERR_SPACE_OFFLINE, space->ctrl->name, "space offline and write to syslob failed");
return OG_ERROR;
}
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_LOB_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, OG_MAX_ROW_SIZE, table->desc.column_count);
(void)row_put_int32(&ra, desc->uid);
(void)row_put_int32(&ra, desc->table_id);
(void)row_put_int32(&ra, desc->column_id);
(void)row_put_int32(&ra, desc->space_id);
(void)row_put_int64(&ra, *(int64 *)&desc->entry);
(void)row_put_int64(&ra, desc->org_scn);
(void)row_put_int64(&ra, desc->chg_scn);
(void)row_put_int32(&ra, desc->chunk);
(void)row_put_int32(&ra, desc->pctversion);
(void)row_put_int32(&ra, desc->retention);
(void)row_put_int32(&ra, desc->flags);
status = knl_internal_insert(session, cursor);
return status;
}
static status_t db_parse_lob_store(knl_session_t *session, knl_column_t *column,
galist_t *lob_stores, bool32 is_for_create_db, knl_lob_desc_t *lob_desc)
{
knl_lobstor_def_t *store = NULL;
uint32 i = 0;
for (i = 0; i < lob_stores->count; i++) {
store = (knl_lobstor_def_t *)cm_galist_get(lob_stores, i);
if (!cm_text_str_equal(&store->col_name, column->name)) {
continue;
}
if (store->space.len != 0) {
lob_desc->is_stored = OG_TRUE;
if (spc_get_space_id(session, &store->space, is_for_create_db, &lob_desc->space_id) != OG_SUCCESS) {
return OG_ERROR;
}
if (spc_check_by_uid(session, &store->space, lob_desc->space_id, lob_desc->uid) != OG_SUCCESS) {
return OG_ERROR;
}
if (IS_SWAP_SPACE(SPACE_GET(session, lob_desc->space_id))) {
OG_THROW_ERROR(ERR_PERMANENTOBJ_IN_TEMPSPACE);
return OG_ERROR;
}
}
lob_desc->is_inrow = store->in_row;
return OG_SUCCESS;
}
return OG_SUCCESS;
}
status_t db_check_lob_storage_mode(knl_session_t *session, knl_table_def_t *def)
{
knl_column_def_t *column_def = NULL;
knl_lobstor_def_t *store = NULL;
bool32 is_found = OG_FALSE;
char *name = NULL;
if (def->lob_stores.count == 0) {
return OG_SUCCESS;
}
name = (char *)cm_push(session->stack, OG_NAME_BUFFER_SIZE);
for (uint32 i = 0; i < def->lob_stores.count; i++) {
store = (knl_lobstor_def_t *)cm_galist_get(&def->lob_stores, i);
is_found = OG_FALSE;
for (uint32 j = 0; j < def->columns.count; j++) {
column_def = (knl_column_def_t *)cm_galist_get(&def->columns, j);
(void)cm_text2str(&column_def->name, name, OG_NAME_BUFFER_SIZE);
if (cm_text_str_equal(&store->col_name, name)) {
is_found = OG_TRUE;
if (!OG_IS_LOB_TYPE(column_def->typmod.datatype) && !column_def->typmod.is_array) {
cm_pop(session->stack);
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "set no-lob column to mode of storage");
return OG_ERROR;
}
}
}
if (!is_found) {
cm_pop(session->stack);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "column", T2S(&store->col_name));
return OG_ERROR;
}
}
cm_pop(session->stack);
return OG_SUCCESS;
}
static void db_init_lob_desc(knl_session_t *session, table_t *table, knl_column_t *column, knl_lob_desc_t *lob_desc)
{
lob_desc->uid = table->desc.uid;
lob_desc->table_id = table->desc.id;
lob_desc->column_id = column->id;
lob_desc->space_id = table->desc.space_id;
lob_desc->entry = INVALID_PAGID;
lob_desc->org_scn = db_inc_scn(session);
lob_desc->chg_scn = lob_desc->org_scn;
lob_desc->chunk = DEFAULT_LOB_CHUNK_SIZE;
lob_desc->retention = 0;
lob_desc->pctversion = OG_LOB_PCTVISON;
lob_desc->is_compressed = OG_FALSE;
lob_desc->is_encrypted = OG_FALSE;
lob_desc->is_stored = OG_FALSE;
lob_desc->is_inrow = IS_SYS_TABLE(table) ? OG_FALSE : OG_TRUE;
}
status_t db_create_lob(knl_session_t *session, table_t *table, knl_column_t *column, knl_table_def_t *def)
{
lob_t lob;
knl_cursor_t *cursor = NULL;
knl_lob_desc_t *lob_desc = &lob.desc;
errno_t ret = memset_sp(&lob, sizeof(lob_t), 0, sizeof(lob_t));
knl_securec_check(ret);
db_init_lob_desc(session, table, column, lob_desc);
if (def != NULL && def->lob_stores.count > 0) {
if (def->type == TABLE_TYPE_NOLOGGING) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "lob store", "nologging table");
return OG_ERROR;
}
if (db_parse_lob_store(session, column, &def->lob_stores, def->is_for_create_db, lob_desc) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (lob_check_space(session, table, lob_desc->space_id) != OG_SUCCESS) {
return OG_ERROR;
}
if (IS_SYS_TABLE(table)) {
if (lob_create_segment(session, &lob) != OG_SUCCESS) {
return OG_ERROR;
}
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (db_write_syslob(session, cursor, lob_desc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (IS_PART_TABLE(table)) {
if (db_create_part_lob(session, cursor, table, def, &lob) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static bool32 db_reference_cols_match(uint16 *cols, uint32 count, knl_index_desc_t *desc, uint16 *match_id)
{
uint32 i;
uint32 j;
if (count != desc->column_count) {
return OG_FALSE;
}
for (i = 0; i < count; i++) {
for (j = 0; j < count; j++) {
if (cols[j] == desc->columns[i]) {
match_id[i] = j;
break;
}
}
if (j == count) {
return OG_FALSE;
}
}
return OG_TRUE;
}
status_t db_get_fk_part_no(knl_session_t *session, knl_cursor_t *cursor, index_t *index, knl_handle_t dc_entity,
ref_cons_t *cons, uint32 *part_no)
{
uint32 i;
uint32 j;
part_table_t *part_table;
part_key_t *part_key;
dc_entity_t *entity = (dc_entity_t*)dc_entity;
char *data = NULL;
uint32 len;
part_table = entity->table.part_table;
part_key = (part_key_t *)cm_push(session->stack, OG_MAX_COLUMN_SIZE);
errno_t ret = memset_sp(part_key, OG_MAX_COLUMN_SIZE, 0, OG_MAX_COLUMN_SIZE);
knl_securec_check(ret);
part_key_init(part_key, part_table->desc.partkeys);
for (i = 0; i < part_table->desc.partkeys; i++) {
for (j = 0; j < index->desc.column_count; j++) {
if (part_table->keycols[i].column_id != index->desc.columns[j]) {
continue;
}
data = CURSOR_COLUMN_DATA(cursor, cons->cols[j]);
len = CURSOR_COLUMN_SIZE(cursor, cons->cols[j]);
if (len == OG_NULL_VALUE_LEN) {
part_put_null(part_key);
break;
}
og_type_t type = part_table->keycols[i].datatype;
char temp[NUMBER_ZERO_STORAGR_LEN] = {0};
if (CSF_IS_DECIMAL_ZERO(cursor->row->is_csf, len, type)) {
part_get_number_zero(type, temp, NUMBER_ZERO_STORAGR_LEN, &len);
data = temp;
}
if (part_put_data(part_key, data, len, type) != OG_SUCCESS) {
cm_pop(session->stack);
return OG_ERROR;
}
break;
}
if (j == index->desc.column_count) {
break;
}
}
*part_no = knl_locate_part_key(entity, part_key);
cm_pop(session->stack);
return OG_SUCCESS;
}
status_t db_get_fk_subpart_no(knl_session_t *session, knl_cursor_t *cursor, index_t *index, knl_handle_t dc_entity,
ref_cons_t *cons, uint32 compart_no, uint32 *subpart_no)
{
uint32 len;
uint32 j;
char *data = NULL;
dc_entity_t *entity = (dc_entity_t *)dc_entity;
table_t *table = &entity->table;
part_table_t *part_table = table->part_table;
CM_SAVE_STACK(session->stack);
part_key_t *part_key = (part_key_t *)cm_push(session->stack, OG_MAX_COLUMN_SIZE);
errno_t ret = memset_sp(part_key, OG_MAX_COLUMN_SIZE, 0, OG_MAX_COLUMN_SIZE);
knl_securec_check(ret);
part_key_init(part_key, part_table->desc.subpartkeys);
for (uint32 i = 0; i < part_table->desc.subpartkeys; i++) {
for (j = 0; j < index->desc.column_count; j++) {
if (index->desc.columns[j] != part_table->sub_keycols[i].column_id) {
continue;
}
data = CURSOR_COLUMN_DATA(cursor, cons->cols[j]);
len = CURSOR_COLUMN_SIZE(cursor, cons->cols[j]);
if (len == OG_NULL_VALUE_LEN) {
part_put_null(part_key);
break;
}
og_type_t type = part_table->sub_keycols[i].datatype;
char temp[NUMBER_ZERO_STORAGR_LEN] = {0};
if (CSF_IS_DECIMAL_ZERO(cursor->row->is_csf, len, type)) {
part_get_number_zero(type, temp, NUMBER_ZERO_STORAGR_LEN, &len);
data = temp;
}
if (part_put_data(part_key, data, len, part_table->sub_keycols[i].datatype) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
break;
}
if (j == index->desc.column_count) {
break;
}
}
*subpart_no = knl_locate_subpart_key(entity, compart_no, part_key);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_verify_reference_data(knl_session_t *session, knl_dictionary_t *dc, knl_dictionary_t *ref_dc,
ref_cons_t *ref_cons)
{
index_t *index = NULL;
bool32 parent_exist = OG_FALSE;
bool32 has_null = OG_FALSE;
dc_entity_t *ref_entity = NULL;
uint32 i;
uint32 col_id;
knl_cursor_t *cursor = NULL;
char *key = NULL;
char *data = NULL;
uint32 len;
uint32 part_no;
knl_column_t *column = NULL;
table_t *table = NULL;
index_part_t *index_part = NULL;
btree_t *btree = NULL;
status_t status = OG_SUCCESS;
ref_entity = (dc_entity_t *)ref_dc->handle;
table = &ref_entity->table;
for (i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (index->desc.id == ref_cons->ref_ix) {
break;
}
}
if (index->desc.is_invalid) {
OG_THROW_ERROR(ERR_INDEX_NOT_STABLE, index->desc.name);
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
cursor->action = CURSOR_ACTION_SELECT;
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
key = (char *)cm_push(session->stack, OG_KEY_BUF_SIZE);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
while (!cursor->eof) {
parent_exist = OG_FALSE;
has_null = OG_FALSE;
knl_init_key(&index->desc, key, NULL);
for (i = 0; i < index->desc.column_count; i++) {
column = dc_get_column(ref_entity, index->desc.columns[i]);
col_id = ref_cons->cols[i];
data = CURSOR_COLUMN_DATA(cursor, col_id);
len = CURSOR_COLUMN_SIZE(cursor, col_id);
if (len == OG_NULL_VALUE_LEN) {
has_null = OG_TRUE;
break;
}
knl_put_key_data(INDEX_DESC(index), key, column->datatype, data, len, i);
}
if (IS_PART_INDEX(index)) {
if (db_get_fk_part_no(session, cursor, index, ref_entity, ref_cons, &part_no) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (part_no == OG_INVALID_ID32) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_CONSTRAINT_VIOLATED_NO_FOUND, "parent key not found");
return OG_ERROR;
}
index_part = PART_GET_ENTITY(index->part_index, part_no);
if (index_part == NULL) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_CONSTRAINT_VIOLATED_NO_FOUND, "parent key not found");
return OG_ERROR;
}
if (index_part->desc.is_invalid) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_INDEX_PART_UNUSABLE, index_part->desc.name, index->desc.name);
return OG_ERROR;
}
}
if (index->desc.parted) {
btree = &index_part->btree;
} else {
btree = &index->btree;
}
if (btree->segment != NULL && !has_null) {
if (index->desc.cr_mode == CR_PAGE) {
if (pcrb_check_key_exist(session, btree, key, &parent_exist) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
} else {
if (btree_check_key_exist(session, btree, key, &parent_exist) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
}
} else {
parent_exist = has_null ? OG_TRUE : OG_FALSE;
}
if (!parent_exist) {
OG_THROW_ERROR(ERR_CONSTRAINT_VIOLATED_NO_FOUND, "parent key not found");
status = OG_ERROR;
break;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
}
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return status;
}
static bool32 check_column_is_valid_ref(knl_dictionary_t *parent_dc,
uint16 *ref_col_id,
text_t *ref_col_name,
knl_dictionary_t *child_dc,
uint16 *col_id,
text_t *col_name,
uint32 column_idx)
{
knl_column_t *column = NULL;
knl_column_t *ref_column = NULL;
if (col_id[column_idx] == OG_INVALID_ID16) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, DC_ENTRY_NAME(child_dc), T2S(col_name));
return OG_FALSE;
}
if (ref_col_id[column_idx] == OG_INVALID_ID16) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, DC_ENTRY_NAME(parent_dc), T2S(ref_col_name));
return OG_FALSE;
}
column = knl_get_column(DC_ENTITY(child_dc), col_id[column_idx]);
if (KNL_COLUMN_IS_ARRAY(column)) {
OG_THROW_ERROR(ERR_REF_ON_ARRAY_COLUMN);
return OG_FALSE;
}
ref_column = knl_get_column(DC_ENTITY(parent_dc), ref_col_id[column_idx]);
if (ref_column->datatype != column->datatype) {
OG_THROW_ERROR(ERR_COL_TYPE_MISMATCH);
return OG_FALSE;
}
return OG_TRUE;
}
static status_t db_verify_reference_cols(knl_session_t *session, knl_dictionary_t *dc, knl_dictionary_t *ref_dc,
knl_constraint_def_t *def, ref_cons_t *ref_cons)
{
uint32 i;
uint16 *col_id = NULL;
uint16 *ref_col_id = NULL;
uint16 *match_id = NULL;
table_t *ref_table = NULL;
text_t *col_name = NULL;
text_t *ref_col_name = NULL;
knl_reference_def_t *ref = &def->ref;
bool32 match_index = OG_FALSE;
knl_index_desc_t *index = NULL;
col_id = (uint16 *)cm_push(session->stack, sizeof(uint16) * OG_MAX_INDEX_COLUMNS * 3);
ref_col_id = col_id + OG_MAX_INDEX_COLUMNS;
match_id = ref_col_id + OG_MAX_INDEX_COLUMNS;
knl_panic_log(def->columns.count == ref->ref_columns.count, "columns's count is not equal to ref_columns's count, "
"panic info: columns count %u ref_columns count %u", def->columns.count, ref->ref_columns.count);
for (i = 0; i < def->columns.count; i++) {
col_name = (text_t *)cm_galist_get(&def->columns, i);
col_id[i] = knl_get_column_id(dc, col_name);
ref_col_name = (text_t *)cm_galist_get(&ref->ref_columns, i);
ref_col_id[i] = knl_get_column_id(ref_dc, ref_col_name);
if (!check_column_is_valid_ref(ref_dc, ref_col_id, ref_col_name, dc, col_id, col_name, i)) {
cm_pop(session->stack);
return OG_ERROR;
}
}
ref_table = DC_TABLE(ref_dc);
for (i = 0; i < ref_table->index_set.count; i++) {
index = &ref_table->index_set.items[i]->desc;
if (!index->is_enforced) {
continue;
}
knl_panic_log(index->primary || index->unique,
"index is neither primary nor unique, panic info: table %s index %s", ref_table->desc.name, index->name);
if (db_reference_cols_match(ref_col_id, def->columns.count, index, match_id)) {
match_index = OG_TRUE;
ref_cons->ref_ix = index->id;
break;
}
}
if (!match_index) {
cm_pop(session->stack);
OG_THROW_ERROR(ERR_NO_MATCH_CONSTRAINT);
return OG_ERROR;
}
ref_cons->col_count = def->columns.count;
ref_cons->ref_uid = ref_dc->uid;
ref_cons->ref_oid = ref_dc->oid;
for (i = 0; i < ref_cons->col_count; i++) {
ref_cons->cols[i] = col_id[match_id[i]];
}
ref_cons->refactor = ref->refactor;
cm_pop(session->stack);
return OG_SUCCESS;
}
static bool32 db_check_cons_exists(knl_session_t *session, knl_dictionary_t *dc, ref_cons_t *ref_cons)
{
table_t *table;
ref_cons_t *item = NULL;
uint32 i;
uint32 j;
table = DC_TABLE(dc);
for (i = 0; i < table->cons_set.ref_count; i++) {
item = table->cons_set.ref_cons[i];
if (item->ref_uid != ref_cons->ref_uid || item->ref_oid != ref_cons->ref_oid) {
continue;
}
if (item->col_count != ref_cons->col_count) {
continue;
}
for (j = 0; j < ref_cons->col_count; j++) {
if (item->cols[j] != ref_cons->cols[j]) {
break;
}
}
if (j == ref_cons->col_count) {
return OG_TRUE;
}
}
return OG_FALSE;
}
static status_t db_check_ref_dc(knl_session_t *session, knl_dictionary_t *dc, knl_constraint_def_t *def,
knl_dictionary_t *ref_dc, ref_cons_t *ref_cons, bool32 is_same)
{
knl_reference_def_t *ref = &def->ref;
if (ref_dc->type == DICT_TYPE_TEMP_TABLE_TRANS || ref_dc->type == DICT_TYPE_TEMP_TABLE_SESSION) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT,
"attempt to reference in a referential integrity", "temporary table");
return OG_ERROR;
}
if (!is_same) {
uint32 timeout = session->kernel->attr.ddl_lock_timeout;
if (lock_table_directly(session, ref_dc, timeout) != OG_SUCCESS) {
return OG_ERROR;
}
}
table_t *ref_table = DC_TABLE(ref_dc);
if (ref_table->desc.org_scn > ref_dc->org_scn) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, T2S(&ref->ref_user), T2S_EX(&ref->ref_table));
return OG_ERROR;
}
ref_cons->cols = (uint16 *)cm_push(session->stack, sizeof(uint16) * OG_MAX_INDEX_COLUMNS);
if (db_verify_reference_cols(session, dc, ref_dc, def, ref_cons) != OG_SUCCESS) {
return OG_ERROR;
}
if (def->cons_state.is_validate) {
if (db_verify_reference_data(session, dc, ref_dc, ref_cons) != OG_SUCCESS && !ref->no_need_check) {
return OG_ERROR;
}
}
if (db_check_cons_exists(session, dc, ref_cons)) {
OG_THROW_ERROR(ERR_CONS_EXISTS);
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_make_col_list_impl(uint32 column_cnt, text_t *txt_cols, uint16 *column_ids)
{
for (uint32 i = 0; i < column_cnt; i++) {
cm_concat_int32(txt_cols, OG_MAX_INDEX_COLUMNS * MAX_COLUMN_ID_STR_LEN, column_ids[i]);
if (i + 1 < column_cnt) {
if (cm_concat_string(txt_cols, OG_MAX_INDEX_COLUMNS * MAX_COLUMN_ID_STR_LEN, ",") != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static inline status_t db_make_col_list(knl_constraint_def_t *def, ref_cons_t *ref_cons, text_t *txt_cols)
{
return db_make_col_list_impl(def->columns.count, txt_cols, ref_cons->cols);
}
static status_t fill_ref_info_when_reftab_exist(knl_constraint_def_t *def,
row_assist_t *ra,
ref_cons_t *ref_cons)
{
char str_cols[OG_MAX_INDEX_COLUMNS * MAX_COLUMN_ID_STR_LEN];
text_t txt_cols;
txt_cols.str = str_cols;
txt_cols.len = 0;
if (db_make_col_list(def, ref_cons, &txt_cols) != OG_SUCCESS) {
return OG_ERROR;
}
(void)row_put_int32(ra, ref_cons->col_count);
(void)row_put_text(ra, &txt_cols);
row_put_null(ra);
(void)row_put_int32(ra, ref_cons->ref_uid);
(void)row_put_int32(ra, ref_cons->ref_oid);
(void)row_put_int32(ra, ref_cons->ref_ix);
row_put_null(ra);
row_put_null(ra);
(void)row_put_int32(ra, def->cons_state.option);
(void)row_put_int32(ra, (int32)ref_cons->refactor);
return OG_SUCCESS;
}
status_t make_column_name_list_str(text_t *txt_column_name, uint32_t column_cnt, galist_t *columns)
{
text_t *col_name = NULL;
for (int i = 0; i < column_cnt; i++) {
col_name = (text_t *)cm_galist_get(columns, i);
cm_concat_n_string(txt_column_name, OG_MAX_INDEX_COLUMNS * OG_NAME_BUFFER_SIZE,
col_name->str, col_name->len);
if (i + 1 < column_cnt) {
if (cm_concat_string(txt_column_name, OG_MAX_INDEX_COLUMNS * OG_NAME_BUFFER_SIZE, ",") != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
status_t fill_ref_info_when_reftab_not_exist(knl_constraint_def_t *def, row_assist_t *ra)
{
knl_reference_def_t *ref = &def->ref;
char str_col_names[OG_MAX_INDEX_COLUMNS * OG_NAME_BUFFER_SIZE];
text_t ref_txt_col_names;
ref_txt_col_names.len = 0;
ref_txt_col_names.str = str_col_names;
if (make_column_name_list_str(&ref_txt_col_names, def->columns.count, &def->ref.ref_columns) != OG_SUCCESS) {
return OG_ERROR;
}
char col_names[OG_MAX_INDEX_COLUMNS * OG_NAME_BUFFER_SIZE];
text_t txt_col_names;
txt_col_names.len = 0;
txt_col_names.str = col_names;
if (make_column_name_list_str(&txt_col_names, def->columns.count, &def->columns) != OG_SUCCESS) {
return OG_ERROR;
}
(void)row_put_int32(ra, def->columns.count);
(void)row_put_text(ra, &txt_col_names);
row_put_null(ra);
(void)row_put_int32(ra, -1);
(void)row_put_int32(ra, -1);
(void)row_put_int32(ra, -1);
(void)row_put_text(ra, &ref->ref_table);
(void)row_put_text(ra, &ref_txt_col_names);
(void)row_put_int32(ra, def->cons_state.option);
(void)row_put_int32(ra, def->ref.refactor);
return OG_SUCCESS;
}
static bool32 db_compare_ref_cons_cols(ref_cons_t *pre_ref_cons, ref_cons_t *ref_cons)
{
uint32 pre_col_count = pre_ref_cons->col_count;
uint32 ref_col_count = ref_cons->col_count;
for (uint32 i = 0; i < pre_col_count; i++) {
for (uint32 j = 0; j < ref_col_count; j++) {
if (pre_ref_cons->cols[i] == ref_cons->cols[j]) {
return OG_TRUE;
}
}
}
return OG_FALSE;
}
static void db_reset_cons_cascade(knl_dictionary_t *dc, knl_constraint_def_t *def, ref_cons_t *ref_cons)
{
table_t *table = DC_TABLE(dc);
ref_cons_t *pre_ref_cons = NULL;
uint32 ref_count = table->cons_set.ref_count;
for (uint32 i = 0; i < ref_count; i++) {
pre_ref_cons = table->cons_set.ref_cons[i];
if (pre_ref_cons->ref_uid != ref_cons->ref_uid || pre_ref_cons->ref_oid != ref_cons->ref_oid ||
pre_ref_cons->ref_ix != ref_cons->ref_ix) {
continue;
}
if (db_compare_ref_cons_cols(pre_ref_cons, ref_cons)) {
def->cons_state.is_cascade = 0;
return;
}
}
}
static status_t db_build_ref_desc(knl_session_t *session, knl_dictionary_t *dc, knl_constraint_def_t *def,
row_assist_t *ra)
{
knl_reference_def_t *ref = &def->ref;
ref_cons_t ref_cons;
knl_dictionary_t *ref_dc = &ref->ref_dc;
bool32 is_same = OG_FALSE;
dc_entity_t *dc_entity = (dc_entity_t *)dc->handle;
status_t status = OG_SUCCESS;
if (dc->type == DICT_TYPE_TEMP_TABLE_TRANS || dc->type == DICT_TYPE_TEMP_TABLE_SESSION) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT,
"attempt to reference in a referential integrity", "temporary table");
return OG_ERROR;
}
if (cm_text_str_equal(&ref->ref_user, dc_entity->entry->user->desc.name) &&
cm_text_str_equal(&ref->ref_table, dc_entity->table.desc.name)) {
errno_t ret = memcpy_sp(ref_dc, sizeof(knl_dictionary_t), dc, sizeof(knl_dictionary_t));
knl_securec_check(ret);
is_same = OG_TRUE;
}
if (!is_same) {
status = dc_open(session, &ref->ref_user, &ref->ref_table, ref_dc);
if (status != OG_SUCCESS && !ref->no_need_check) {
return OG_ERROR;
}
if (status == OG_SUCCESS && SYNONYM_EXIST(ref_dc)) {
dc_close(ref_dc);
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, T2S(&ref->ref_user), T2S_EX(&ref->ref_table));
return OG_ERROR;
}
}
CM_SAVE_STACK(session->stack);
if (status == OG_SUCCESS && db_check_ref_dc(session, dc, def, ref_dc, &ref_cons, is_same) == OG_ERROR) {
if (!is_same) {
dc_close(ref_dc);
}
ref_dc->handle = NULL;
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (is_same) {
ref_dc->handle = NULL;
}
db_reset_cons_cascade(dc, def, &ref_cons);
if (status == OG_SUCCESS) {
if (fill_ref_info_when_reftab_exist(def, ra, &ref_cons) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
} else {
if (fill_ref_info_when_reftab_not_exist(def, ra) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_verify_check_data(knl_session_t *session, knl_dictionary_t *dc, text_t *cond)
{
bool32 exist = OG_FALSE;
status_t ret;
text_t sql;
dc_entry_t *entry = DC_ENTRY(dc);
dc_user_t *user = entry->user;
char *clause;
uint32 len = 2 * OG_MAX_NAME_LEN + OG_MAX_CHECK_VALUE_LEN + OG_FIX_CHECK_SQL_LEN;
errno_t err;
clause = (char *)cm_push(session->stack, len);
err = snprintf_s(clause, len, len - 1, OG_FIX_CHECK_SQL_FORMAT, user->desc.name, entry->name, T2S(cond));
knl_securec_check_ss(err);
sql.len = (uint32)strlen(clause);
sql.str = clause;
ret = g_knl_callback.exec_check((knl_handle_t)session, &sql, &exist);
cm_pop(session->stack);
if (ret != OG_SUCCESS) {
return OG_ERROR;
}
if (exist) {
OG_THROW_ERROR(ERR_CONSTRAINT_VIOLATED_CHECK_FAILED);
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_build_check_desc(knl_session_t *session, knl_dictionary_t *dc, knl_constraint_def_t *def,
row_assist_t *ra)
{
text_t col_list;
char str_cols[OG_MAX_CHECK_COLUMNS * MAX_COLUMN_ID_STR_LEN];
uint16 col_id;
text_t *column_name = NULL;
knl_check_def_t *check = &def->check;
if (def->columns.count > OG_MAX_CHECK_COLUMNS) {
OG_THROW_ERROR(ERR_TOO_MANY_COLUMNS, "check constraint columns");
return OG_ERROR;
}
if (row_put_int32(ra, def->columns.count) != OG_SUCCESS) {
return OG_ERROR;
}
col_list.str = str_cols;
col_list.len = 0;
for (uint32 i = 0; i < def->columns.count; i++) {
column_name = cm_galist_get(&def->columns, i);
col_id = knl_get_column_id(dc, column_name);
cm_concat_int32(&col_list, OG_MAX_CHECK_COLUMNS * MAX_COLUMN_ID_STR_LEN, (uint32)col_id);
if (i + 1 < def->columns.count) {
if (cm_concat_string(&col_list, OG_MAX_CHECK_COLUMNS * MAX_COLUMN_ID_STR_LEN, ",") != OG_SUCCESS) {
return OG_ERROR;
}
}
}
if (row_put_text(ra, &col_list) != OG_SUCCESS) {
return OG_ERROR;
}
row_put_null(ra);
row_put_null(ra);
row_put_null(ra);
row_put_null(ra);
if (row_put_text(ra, &check->text) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_null(ra) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int32(ra, def->cons_state.option) != OG_SUCCESS) {
return OG_ERROR;
}
row_put_null(ra);
return OG_SUCCESS;
}
static status_t db_build_cons_desc(knl_session_t *session, knl_dictionary_t *dc, knl_constraint_def_t *def,
row_assist_t *ra, knl_cursor_t *cursor)
{
table_t *table = NULL;
knl_table_desc_t *table_desc = NULL;
knl_index_col_def_t *column = NULL;
char str_cols[OG_MAX_INDEX_COLUMNS * MAX_COLUMN_ID_STR_LEN];
text_t col_list;
uint32 i;
uint16 col_id;
table = DC_TABLE(dc);
table_desc = &table->desc;
(void)row_put_int32(ra, table_desc->uid);
(void)row_put_int32(ra, table_desc->id);
(void)row_put_text(ra, &def->name);
(void)row_put_int32(ra, def->type);
if (def->type == CONS_TYPE_REFERENCE && table->cons_set.ref_count >= OG_MAX_CONSTRAINTS) {
OG_THROW_ERROR(ERR_TOO_MANY_OBJECTS, OG_MAX_CONSTRAINTS, "foreign key constraint");
return OG_ERROR;
}
if (def->type == CONS_TYPE_CHECK && table->cons_set.check_count >= OG_MAX_CONSTRAINTS) {
OG_THROW_ERROR(ERR_TOO_MANY_OBJECTS, OG_MAX_CONSTRAINTS, "check constraint");
return OG_ERROR;
}
if (def->type == CONS_TYPE_PRIMARY || def->type == CONS_TYPE_UNIQUE) {
(void)row_put_int32(ra, def->columns.count);
if (def->columns.count > OG_MAX_INDEX_COLUMNS) {
OG_THROW_ERROR(ERR_TOO_MANY_COLUMNS, "unique/primary key columns");
return OG_ERROR;
}
col_list.str = str_cols;
col_list.len = 0;
for (i = 0; i < def->columns.count; i++) {
column = (knl_index_col_def_t *)cm_galist_get(&def->columns, i);
col_id = knl_get_column_id(dc, &column->name);
cm_concat_int32(&col_list, OG_MAX_INDEX_COLUMNS * MAX_COLUMN_ID_STR_LEN, (uint32)col_id);
if (i + 1 < def->columns.count) {
if (cm_concat_string(&col_list, OG_MAX_INDEX_COLUMNS * MAX_COLUMN_ID_STR_LEN, ",") != OG_SUCCESS) {
return OG_ERROR;
}
}
}
(void)row_put_text(ra, &col_list);
(void)row_put_int32(ra, (int32)OG_INVALID_ID32);
row_put_null(ra);
row_put_null(ra);
row_put_null(ra);
row_put_null(ra);
row_put_null(ra);
(void)row_put_int32(ra, def->cons_state.option);
} else if (def->type == CONS_TYPE_REFERENCE) {
if (db_build_ref_desc(session, dc, def, ra) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (db_build_check_desc(session, dc, def, ra) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_fetch_sysconsdef_by_name(knl_session_t *session, knl_cursor_t *cursor,
knl_cursor_action_t cursor_action,
uint32 uid, uint32 oid, text_t *name, bool32 *is_found)
{
*is_found = OG_FALSE;
knl_open_sys_cursor(session, cursor, cursor_action, SYS_CONSDEF_ID, IX_SYS_CONSDEF003_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 *)&uid,
sizeof(uint32), IX_COL_SYS_CONSDEF003_REF_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_VARCHAR, name->str,
name->len, IX_COL_SYS_CONSDEF003_REF_CONS_NAME);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&oid,
sizeof(uint32), IX_COL_SYS_CONSDEF003_REF_TABLE_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (!cursor->eof) {
*is_found = OG_TRUE;
}
return OG_SUCCESS;
}
static status_t db_fetch_sysconsdef_by_table(knl_session_t *session, knl_cursor_t *cursor,
knl_cursor_action_t cursor_action,
uint32 uid, uint32 oid, text_t *def, bool32 *find_flag)
{
knl_scan_key_t *l_key = NULL;
text_t cons_name;
*find_flag = OG_FALSE;
knl_open_sys_cursor(session, cursor, cursor_action, SYS_CONSDEF_ID, IX_SYS_CONSDEF001_ID);
knl_init_index_scan(cursor, OG_TRUE);
l_key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_CONSDEF001_TABLE_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
while (!cursor->eof) {
cons_name.len = CURSOR_COLUMN_SIZE(cursor, CONSDEF_COL_NAME);
cons_name.str = CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_NAME);
if (cm_text_equal(&cons_name, def)) {
*find_flag = OG_TRUE;
return OG_SUCCESS;
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_check_sys_name_exists(knl_session_t *session, knl_cursor_t *cursor,
knl_dictionary_t *dc, text_t *name)
{
bool32 is_found = OG_TRUE;
errno_t ret;
uint32 id = 0;
char *new_name = NULL;
text_t new_sys_name;
if (db_fetch_sysconsdef_by_name(session, cursor, CURSOR_ACTION_SELECT,
dc->uid, dc->oid, name, &is_found) != OG_SUCCESS) {
return OG_ERROR;
}
new_name = (char *)cm_push(session->stack, OG_NAME_BUFFER_SIZE);
while (is_found) {
ret = sprintf_s(new_name, OG_NAME_BUFFER_SIZE, "%s_%u", name->str, id);
knl_securec_check_ss(ret);
cm_str2text_safe(new_name, (uint32)strlen(new_name), &new_sys_name);
if (db_fetch_sysconsdef_by_name(session, cursor, CURSOR_ACTION_SELECT, dc->uid, dc->oid,
&new_sys_name, &is_found) != OG_SUCCESS) {
cm_pop(session->stack);
return OG_ERROR;
}
id++;
}
if (id != 0) {
ret = memcpy_sp(name->str, OG_NAME_BUFFER_SIZE, new_name, OG_NAME_BUFFER_SIZE);
knl_securec_check(ret);
name->len = new_sys_name.len;
}
cm_pop(session->stack);
return OG_SUCCESS;
}
static status_t db_write_cons_def(knl_session_t *session, knl_dictionary_t *dc, knl_constraint_def_t *def)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (def->cons_state.is_anonymous) {
if (db_check_sys_name_exists(session, cursor, dc, &def->name) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_CONSDEF_ID, IX_SYS_CONSDEF001_ID);
row_init(&ra, cursor->buf, OG_MAX_ROW_SIZE, ((table_t *)cursor->table)->desc.column_count);
if (db_build_cons_desc(session, dc, def, &ra, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
int32 code = cm_get_error_code();
if (code == ERR_DUPLICATE_KEY) {
cm_reset_error();
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "constraint", T2S(&def->name));
}
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_update_cons_index(knl_session_t *session, knl_dictionary_t *dc, text_t *cons_name,
uint32 index_id)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
knl_update_info_t *info = NULL;
bool32 is_found;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (db_fetch_sysconsdef_by_name(session, cursor, CURSOR_ACTION_UPDATE, dc->uid, dc->oid,
cons_name, &is_found) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
info = &cursor->update_info;
row_init(&ra, info->data, OG_MAX_ROW_SIZE, 1);
info->count = 1;
info->columns[0] = CONSDEF_COL_INDEX_ID;
(void)row_put_int32(&ra, index_id);
cm_decode_row(info->data, info->offsets, info->lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static bool32 db_constraint_columns_match(galist_t *cols1, galist_t *cols2)
{
uint32 i;
knl_index_col_def_t *col_def1 = NULL;
knl_index_col_def_t *col_def2 = NULL;
if (cols1->count != cols2->count) {
return OG_FALSE;
}
for (i = 0; i < cols1->count; i++) {
col_def1 = (knl_index_col_def_t *)cm_galist_get(cols1, i);
col_def2 = (knl_index_col_def_t *)cm_galist_get(cols2, i);
if (!cm_text_equal(&col_def1->name, &col_def2->name)) {
return OG_FALSE;
}
}
return OG_TRUE;
}
* index include partkeys
* Check current index include all partkeys or not.
* @param index description, partitioned table
*/
static bool32 db_index_include_partkeys(uint32 idx_col_count, uint16 *idx_cols, part_table_t *part_table)
{
uint32 i;
uint32 j;
for (i = 0; i < part_table->desc.partkeys; i++) {
for (j = 0; j < idx_col_count; j++) {
if (part_table->keycols[i].column_id == (uint32)idx_cols[j]) {
break;
}
}
if (j == idx_col_count) {
return OG_FALSE;
}
}
for (i = 0; i < part_table->desc.subpartkeys; i++) {
for (j = 0; j < idx_col_count; j++) {
if (part_table->sub_keycols[i].column_id == (uint32)idx_cols[j]) {
break;
}
}
if (j == idx_col_count) {
return OG_FALSE;
}
}
return OG_TRUE;
}
* Description : allocate id for index
* Input : entity : dc entity of table
* Input : def : index definition
* Output : id : index id
* Return Value : status_t
* History : 1. 2017/4/26, add description
*/
static status_t db_alloc_index_id(dc_entity_t *entity, knl_index_def_t *def, uint32 *id)
{
uint32 i;
index_t *index = NULL;
uint8 map[OG_MAX_TABLE_INDEXES];
uint32 max_indexes;
errno_t err;
max_indexes = OG_MAX_TABLE_INDEXES;
if (entity->table.index_set.total_count >= OG_MAX_TABLE_INDEXES) {
OG_THROW_ERROR(ERR_TOO_MANY_INDEXES, T2S(&def->user), T2S_EX(&def->table));
return OG_ERROR;
}
err = memset_sp(map, max_indexes, 0, max_indexes);
knl_securec_check(err);
for (i = 0; i < entity->table.index_set.total_count; i++) {
index = entity->table.index_set.items[i];
map[index->desc.id] = 1;
}
for (i = 0; i < OG_MAX_TABLE_INDEXES; i++) {
if (map[i] == 0) {
*id = i;
break;
}
}
return OG_SUCCESS;
}
* Description : check if index columns of two index exactly match
* Input : desc1 : description of index1
* Input : desc1 : description of index2
* Output : NA
* Return Value : bool32 : OG_TRUE if matched
* History : 1. 2017/4/26, add description
*/
bool32 db_index_columns_matched(knl_session_t *session, knl_index_desc_t *desc, dc_entity_t *entity,
knl_handle_t def_cols, uint32 col_count, uint16 *columns, bool32 compare_column_mode)
{
uint32 i;
knl_index_col_def_t *index_col = NULL;
knl_column_t *index_col2 = NULL;
galist_t *def_columns = NULL;
if (desc->column_count != col_count) {
return OG_FALSE;
}
for (i = 0; i < desc->column_count; i++) {
if (desc->is_func && desc->columns[i] >= DC_VIRTUAL_COL_START) {
knl_panic_log(def_cols != NULL, "def_cols is NULL, panic info: table %s index %s",
entity->table.desc.name, desc->name);
def_columns = (galist_t *)def_cols;
index_col = (knl_index_col_def_t *)cm_galist_get(def_columns, i);
if (!index_col->is_func) {
return OG_FALSE;
}
index_col2 = dc_get_column(entity, desc->columns[i]);
if (g_knl_callback.compare_index_expr(session, &index_col->func_text,
&index_col2->default_text) == OG_FALSE) {
return OG_FALSE;
}
} else {
if (desc->columns[i] != columns[i]) {
return OG_FALSE;
}
}
if (!compare_column_mode || def_cols == NULL) {
continue;
}
def_columns = (galist_t *)def_cols;
index_col = (knl_index_col_def_t *)cm_galist_get(def_columns, i);
if (db_get_index_col_dir(desc, i) != (index_col->mode == SORT_MODE_DESC ? SORT_MODE_DESC : SORT_MODE_ASC)) {
return OG_FALSE;
}
}
return OG_TRUE;
}
static status_t db_find_exact_index_in_catalog(knl_session_t *session, knl_index_desc_t *desc,
char *matched_name, uint32 matched_name_size, bool32 *found)
{
knl_cursor_t *cursor = NULL;
text_t requested_col_list;
text_t stored_col_list;
text_t index_name;
char requested_col_buf[COLUMN_LIST_BUF_LEN];
*found = OG_FALSE;
if (desc->is_func) {
return OG_SUCCESS;
}
requested_col_list.str = requested_col_buf;
requested_col_list.len = 0;
if (db_encode_index_column_list(&requested_col_list, COLUMN_LIST_BUF_LEN, desc) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_INDEX_ID, IX_SYS_INDEX_001_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (char *)&desc->uid,
sizeof(uint32), IX_COL_SYS_INDEX_001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (char *)&desc->table_id,
sizeof(uint32), IX_COL_SYS_INDEX_001_TABLE);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_INDEX_001_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, (char *)&desc->uid,
sizeof(uint32), IX_COL_SYS_INDEX_001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, (char *)&desc->table_id,
sizeof(uint32), IX_COL_SYS_INDEX_001_TABLE);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_INDEX_001_ID);
for (;;) {
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_SUCCESS;
}
if (*(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_INDEX_COLUMN_ID_COLS) != desc->column_count) {
continue;
}
stored_col_list.str = CURSOR_COLUMN_DATA(cursor, SYS_INDEX_COLUMN_ID_COL_LIST);
stored_col_list.len = CURSOR_COLUMN_SIZE(cursor, SYS_INDEX_COLUMN_ID_COL_LIST);
if (!cm_text_equal(&requested_col_list, &stored_col_list)) {
continue;
}
index_name.str = CURSOR_COLUMN_DATA(cursor, SYS_INDEX_COLUMN_ID_NAME);
index_name.len = CURSOR_COLUMN_SIZE(cursor, SYS_INDEX_COLUMN_ID_NAME);
if (cm_text2str(&index_name, matched_name, matched_name_size) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
*found = OG_TRUE;
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
}
static status_t db_create_virtual_icol(knl_session_t *session, knl_dictionary_t *dc,
knl_index_col_def_t *index_col, uint32 v_col_id, knl_column_t *arg_column)
{
knl_cursor_t *cursor = NULL;
char col_name[OG_NAME_BUFFER_SIZE];
knl_column_t vcolumn = {0};
errno_t ret;
vcolumn.name = col_name;
vcolumn.datatype = index_col->datatype;
vcolumn.uid = dc->uid;
vcolumn.table_id = dc->oid;
vcolumn.id = v_col_id;
vcolumn.size = index_col->size;
vcolumn.nullable = index_col->nullable;
vcolumn.flags = (KNL_COLUMN_FLAG_HIDDEN | KNL_COLUMN_FLAG_VIRTUAL);
if (KNL_COLUMN_IS_CHARACTER(arg_column)) {
COLUMN_SET_CHARACTER(&vcolumn);
}
vcolumn.default_text = index_col->func_text;
ret = snprintf_s(col_name, OG_NAME_BUFFER_SIZE, OG_MAX_NAME_LEN, "SYS_NC%u$_%u", v_col_id, arg_column->id);
knl_securec_check_ss(ret);
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (db_write_syscolumn(session, cursor, &vcolumn) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static void db_alloc_vcol_id(dc_entity_t *entity, uint32 *vcol_id)
{
knl_column_t *column = NULL;
while (*vcol_id < entity->max_virtual_cols + DC_VIRTUAL_COL_START) {
column = dc_get_column(entity, *vcol_id);
if (column == NULL) {
return;
}
(*vcol_id)++;
}
}
static status_t db_prepare_idx_cols(knl_session_t *session, knl_index_def_t *def, knl_dictionary_t *dc,
knl_index_desc_t *desc)
{
knl_column_t *column = NULL;
knl_index_col_def_t *index_col = NULL;
og_type_t type;
uint16 col_size;
dc_entity_t *entity = DC_ENTITY(dc);
uint32 vcol_id = DC_VIRTUAL_COL_START;
bool32 is_pcr = (desc->cr_mode == CR_PAGE);
uint32 key_size = is_pcr ? (sizeof(pcrb_key_t) + sizeof(pcrb_dir_t)) :
(sizeof(btree_key_t) + sizeof(btree_dir_t));
uint16 key_size_limit;
bool32 is_lob = OG_FALSE;
bool32 is_double = OG_FALSE;
db_alloc_vcol_id(entity, &vcol_id);
desc->is_dsc = OG_FALSE;
for (uint32 i = 0; i < desc->column_count; i++) {
index_col = (knl_index_col_def_t *)cm_galist_get(&def->columns, i);
desc->columns[i] = knl_get_column_id(dc, &index_col->name);
desc->col_dirs[i] = (uint8)(index_col->mode == SORT_MODE_DESC ? SORT_MODE_DESC : SORT_MODE_ASC);
if (desc->col_dirs[i] == SORT_MODE_DESC) {
desc->is_dsc = OG_TRUE;
}
if (desc->columns[i] == OG_INVALID_ID16) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, T2S(&def->table), T2S_EX(&index_col->name));
return OG_ERROR;
}
column = dc_get_column(entity, desc->columns[i]);
if (KNL_COLUMN_IS_ARRAY(column)) {
OG_THROW_ERROR(ERR_INDEX_ON_ARRAY_FIELD, column->name);
return OG_ERROR;
}
if (index_col->is_func) {
desc->is_func = OG_TRUE;
desc->columns[i] = vcol_id;
type = index_col->datatype;
col_size = index_col->size;
index_col->nullable = column->nullable;
if (db_create_virtual_icol(session, dc, index_col, vcol_id, column) != OG_SUCCESS) {
return OG_ERROR;
}
vcol_id++;
db_alloc_vcol_id(entity, &vcol_id);
is_lob = OG_IS_LOB_TYPE(type);
is_double = OG_IS_DOUBLE_TYPE(type);
} else {
desc->columns[i] = knl_get_column_id(dc, &index_col->name);
if (desc->columns[i] == OG_INVALID_ID16) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, T2S(&def->table), T2S_EX(&index_col->name));
return OG_ERROR;
}
column = dc_get_column(entity, desc->columns[i]);
type = column->datatype;
col_size = column->size;
is_lob = COLUMN_IS_LOB(column);
is_double = COLUMN_IS_REAL(column);
}
if (is_lob) {
OG_THROW_ERROR(ERR_CREATE_INDEX_ON_TYPE, IS_REVERSE_INDEX(desc) ? "reverse" : "normal",
get_datatype_name_str(type));
return OG_ERROR;
}
if (IS_REVERSE_INDEX(desc) && is_double) {
OG_THROW_ERROR(ERR_CREATE_INDEX_ON_TYPE, "reverse", get_datatype_name_str(type));
return OG_ERROR;
}
key_size += btree_max_column_size(type, col_size, is_pcr);
}
if (session->kernel->attr.enable_idx_key_len_check) {
key_size_limit = btree_max_allowed_size(session, desc);
if (key_size > key_size_limit) {
OG_THROW_ERROR(ERR_MAX_KEYLEN_EXCEEDED, key_size_limit);
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static inline bool32 part_check_index_encrypt_allowed(knl_session_t *session, uint32 table_space_id, space_t *space)
{
bool32 is_encrypt_table = SPACE_IS_ENCRYPT(SPACE_GET(session, table_space_id));
bool32 is_encrypt_index = SPACE_IS_ENCRYPT(space);
if (is_encrypt_table != is_encrypt_index) {
return OG_FALSE;
}
return OG_TRUE;
}
static status_t db_check_spaces_compatable(knl_session_t *session, text_t *space_name,
space_t *parent_space, bool32 is_for_create_db)
{
uint32 space_id;
if (spc_get_space_id(session, space_name, is_for_create_db, &space_id) != OG_SUCCESS) {
return OG_ERROR;
}
space_t *space = SPACE_GET(session, space_id);
if (!IS_SWAP_SPACE(parent_space) && IS_SWAP_SPACE(space)) {
OG_THROW_ERROR(ERR_PERMANENTOBJ_IN_TEMPSPACE);
return OG_ERROR;
}
if (IS_SWAP_SPACE(parent_space) && !IS_SWAP_SPACE(space)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create temporary object", "non-swap object");
return OG_ERROR;
}
if (IS_UNDO_SPACE(space)) {
OG_THROW_ERROR(ERR_MISUSE_UNDO_SPACE, T2S(space_name));
return OG_ERROR;
}
if (SPACE_IS_NOLOGGING(parent_space)) {
if (SPACE_IS_LOGGING(space)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create logging object", "nologging parent object");
return OG_ERROR;
}
} else {
if (SPACE_IS_NOLOGGING(space)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create nologging object", "logging parent object");
return OG_ERROR;
}
}
if (!part_check_index_encrypt_allowed(session, parent_space->ctrl->id, space)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create encrypt object", "non-encrypt parent object \
or create non-encrypt object on encrypt parent object.");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_check_idxpart_space_compatable(knl_session_t *session, knl_index_def_t *def,
knl_index_desc_t *index_desc)
{
uint32 part_count = def->part_def->parts.count;
space_t *index_space = SPACE_GET(session, index_desc->space_id);
for (uint32 i = 0; i < part_count; i++) {
knl_part_def_t *part_def = (knl_part_def_t *)cm_galist_get(&def->part_def->parts, i);
if (part_def->space.len == 0) {
continue;
}
if (db_check_spaces_compatable(session, &part_def->space, index_space, def->is_for_create_db) != OG_SUCCESS) {
return OG_ERROR;
}
if (!def->part_def->is_composite) {
continue;
}
uint32 subpart_count = part_def->subparts.count;
for (uint32 j = 0; j < subpart_count; j++) {
knl_part_def_t *subpart_def = (knl_part_def_t *)cm_galist_get(&part_def->subparts, j);
if (subpart_def->space.len == 0) {
continue;
}
if (db_check_spaces_compatable(session, &subpart_def->space,
index_space, def->is_for_create_db) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_check_index_space(knl_session_t *session, knl_dictionary_t *dc, table_t *table,
knl_index_def_t *def, knl_index_desc_t *desc)
{
if (def->space.len == 0) {
desc->space_id = table->desc.space_id;
if (!def->parted || (def->part_def == NULL)) {
return OG_SUCCESS;
}
if (db_check_idxpart_space_compatable(session, def, desc) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
desc->is_stored = OG_TRUE;
space_t *table_space = SPACE_GET(session, table->desc.space_id);
if (db_check_spaces_compatable(session, &def->space, table_space, def->is_for_create_db) != OG_SUCCESS) {
return OG_ERROR;
}
if (spc_get_space_id(session, &def->space, def->is_for_create_db, &desc->space_id) != OG_SUCCESS) {
return OG_ERROR;
}
if (spc_check_by_uid(session, &def->space, desc->space_id, table->desc.uid) != OG_SUCCESS) {
return OG_ERROR;
}
if (table->desc.parted) {
if (!def->parted || (def->part_def == NULL)) {
return OG_SUCCESS;
}
if (db_check_idxpart_space_compatable(session, def, desc) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_init_idx_desc(knl_session_t *session, knl_dictionary_t *dc, knl_index_def_t *idx_def,
knl_index_desc_t *idx_desc)
{
dc_entity_t *entity = DC_ENTITY(dc);
table_t *table = &entity->table;
errno_t err;
idx_desc->table_id = entity->table.desc.id;
idx_desc->primary = idx_def->primary;
idx_desc->unique = idx_def->unique;
idx_desc->type = idx_def->type;
idx_desc->column_count = idx_def->columns.count;
idx_desc->initrans = idx_def->initrans;
idx_desc->cr_mode = (idx_def->cr_mode == OG_INVALID_ID8) ? table->desc.cr_mode : idx_def->cr_mode;
idx_desc->org_scn = db_inc_scn(session);
idx_desc->entry = INVALID_PAGID;
idx_desc->parted = idx_def->parted;
idx_desc->pctfree = (idx_def->pctfree == OG_INVALID_ID32) ? table->desc.pctfree : idx_def->pctfree;
idx_desc->is_reverse = idx_def->is_reverse;
err = memset_sp(idx_desc->col_dirs, sizeof(idx_desc->col_dirs), SORT_MODE_ASC, sizeof(idx_desc->col_dirs));
if (err != EOK) {
knl_securec_check(err);
return OG_ERROR;
}
if (idx_desc->initrans == 0) {
idx_desc->initrans = cm_text_str_equal_ins(&idx_def->user, "SYS") ? OG_INI_TRANS : session->kernel->attr.initrans;
}
if (dc->type == DICT_TYPE_TEMP_TABLE_SESSION || dc->type == DICT_TYPE_TEMP_TABLE_TRANS) {
idx_desc->cr_mode = CR_ROW;
} else if (DB_ATTR_CLUSTER(session)) {
idx_desc->cr_mode = CR_PAGE;
}
if (IS_NOLOGGING_BY_TABLE_TYPE(table->desc.type) && idx_def->nologging) {
idx_def->nologging = OG_FALSE;
}
if (!dc_get_user_id(session, &idx_def->user, &idx_desc->uid)) {
OG_THROW_ERROR(ERR_USER_NOT_EXIST, T2S(&idx_def->user));
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_chk_idx_def(knl_session_t *session, knl_dictionary_t *dc, table_t *table,
knl_index_def_t *idx_def, knl_index_desc_t *idx_desc)
{
if (db_check_index_space(session, dc, table, idx_def, idx_desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (idx_def->columns.count > OG_MAX_INDEX_COLUMNS) {
OG_THROW_ERROR(ERR_TOO_MANY_COLUMNS, "index columns");
return OG_ERROR;
}
if (idx_def->parted && !table->desc.parted) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "could not create partition index on no partitioned table");
return OG_ERROR;
}
if (!DB_IS_SINGLE(session) && idx_def->nologging) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "creating an index with nologging in HA mode");
return OG_ERROR;
}
if ((dc->type == DICT_TYPE_TEMP_TABLE_SESSION || dc->type == DICT_TYPE_TEMP_TABLE_TRANS) &&
idx_def->cr_mode == CR_PAGE) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "creating a page CR_MODE index on a temporary table");
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_verify_index_def(knl_session_t *session, knl_dictionary_t *dc, knl_index_def_t *def,
knl_index_desc_t *desc)
{
index_t *index = NULL;
dc_entity_t *entity = DC_ENTITY(dc);
table_t *table = &entity->table;
bool32 matched_in_catalog = OG_FALSE;
char matched_index_name[OG_NAME_BUFFER_SIZE];
if (cm_text2str(&def->name, desc->name, OG_NAME_BUFFER_SIZE) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_chk_idx_def(session, dc, table, def, desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_init_idx_desc(session, dc, def, desc)) {
return OG_ERROR;
}
if (db_prepare_idx_cols(session, def, dc, desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (desc->parted && (desc->primary || desc->unique)) {
if (!db_index_include_partkeys(desc->column_count, desc->columns, table->part_table)) {
OG_THROW_ERROR(ERR_LOCAL_UNIQUE_INDEX);
return OG_ERROR;
}
}
for (uint32 i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (desc->primary && index->desc.primary) {
OG_THROW_ERROR(ERR_PRIMRY_KEY_ALREADY_EXISTS);
return OG_ERROR;
}
if (db_index_columns_matched(session, &index->desc,
entity, &def->columns, desc->column_count, desc->columns, OG_TRUE)) {
OG_THROW_ERROR(ERR_COLUMN_ALREADY_INDEXED, index->desc.name);
return OG_ERROR;
}
}
* DDL immediately following another CREATE INDEX may observe an index
* definition that has already been persisted in SYS_INDEX but not fully
* reconstructed with descending metadata in the current DC. Re-check the
* catalog using the encoded COL_LIST so exact duplicates are still blocked.
*/
if (db_find_exact_index_in_catalog(session, desc, matched_index_name,
OG_NAME_BUFFER_SIZE, &matched_in_catalog) != OG_SUCCESS) {
return OG_ERROR;
}
if (matched_in_catalog) {
OG_THROW_ERROR(ERR_COLUMN_ALREADY_INDEXED, matched_index_name);
return OG_ERROR;
}
desc->max_key_size = btree_max_allowed_size(session, desc);
return OG_SUCCESS;
}
static status_t db_check_null_in_idxcols(knl_session_t *session, knl_cursor_t *cursor, knl_index_desc_t desc)
{
uint32 i;
uint32 col_id;
knl_column_t *column = NULL;
dc_entity_t *entity = (dc_entity_t *)cursor->dc_entity;
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
while (!cursor->eof) {
idx_decode_row(session, cursor, cursor->offsets, cursor->lens, &cursor->data_size);
for (i = 0; i < desc.column_count; i++) {
col_id = desc.columns[i];
if (CURSOR_COLUMN_SIZE(cursor, i) == OG_NULL_VALUE_LEN) {
column = dc_get_column(entity, col_id);
OG_THROW_ERROR(ERR_COLUMN_NOT_NULL, column->name);
return OG_ERROR;
}
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t parttable_check_null_in_index(knl_session_t *session, knl_cursor_t *cursor, knl_dictionary_t *dc,
knl_index_desc_t desc)
{
table_t *table = DC_TABLE(dc);
table_part_t *table_part = NULL;
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
cursor->part_loc.part_no = i;
if (!IS_PARENT_TABPART(&table_part->desc)) {
cursor->part_loc.subpart_no = OG_INVALID_ID32;
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
return OG_ERROR;
}
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
if (db_check_null_in_idxcols(session, cursor, desc) != OG_SUCCESS) {
return OG_ERROR;
}
continue;
}
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
cursor->part_loc.subpart_no = j;
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
return OG_ERROR;
}
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
if (db_check_null_in_idxcols(session, cursor, desc) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_check_null_in_index(knl_session_t *session, knl_dictionary_t *dc, knl_index_desc_t desc)
{
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
cursor->action = CURSOR_ACTION_SELECT;
cursor->scan_mode = SCAN_MODE_INDEX;
cursor->index_slot = desc.slot;
cursor->index_only = OG_TRUE;
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
table_t *table = (table_t *)(cursor->table);
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
knl_init_index_scan(cursor, OG_FALSE);
uint32 none_nullable_cnts = 0;
for (uint32 i = 0; i < desc.column_count; i++) {
uint16 col_id = desc.columns[i];
knl_column_t *knl_col = knl_get_column(dc->handle, col_id);
if (!knl_col->nullable) {
none_nullable_cnts++;
}
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, i);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, i);
}
if (none_nullable_cnts == desc.column_count) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
if (!IS_PART_TABLE(table)) {
if (db_check_null_in_idxcols(session, cursor, desc) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
} else {
if (parttable_check_null_in_index(session, cursor, dc, desc) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_enforce_index(knl_session_t *session, knl_dictionary_t *dc, knl_constraint_def_t *def,
index_t *index)
{
knl_alindex_def_t rebuild_def;
table_t *table = DC_TABLE(dc);
if (index->desc.is_func) {
OG_THROW_ERROR(ERR_ENFORCE_INDEX);
return OG_ERROR;
}
if (!IS_REVERSE_INDEX(&index->desc) && def->index.is_reverse) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "add reverse constraint on normal index");
return OG_ERROR;
}
if (index->desc.is_enforced) {
OG_THROW_ERROR(ERR_COLUMN_ALREADY_INDEXED, index->desc.name);
return OG_ERROR;
}
if (index->desc.parted) {
if (!db_index_include_partkeys(index->desc.column_count, index->desc.columns, table->part_table)) {
OG_THROW_ERROR(ERR_LOCAL_UNIQUE_INDEX);
return OG_ERROR;
}
}
if (index->desc.unique) {
return db_check_null_in_index(session, dc, index->desc);
}
rebuild_def.type = ALINDEX_TYPE_REBUILD;
cm_str2text(index->desc.name, &rebuild_def.name);
rebuild_def.rebuild.is_online = OG_FALSE;
rebuild_def.rebuild.parallelism = 0;
rebuild_def.rebuild.specified_parts = 0;
rebuild_def.rebuild.space.len = 0;
rebuild_def.rebuild.space.str = NULL;
rebuild_def.rebuild.pctfree = index->desc.pctfree;
rebuild_def.rebuild.cr_mode = (def->index.cr_mode == OG_INVALID_ID8) ? index->desc.cr_mode : def->index.cr_mode;
rebuild_def.rebuild.lock_timeout = LOCK_INF_WAIT;
if (table->desc.type == TABLE_TYPE_TRANS_TEMP || table->desc.type == TABLE_TYPE_SESSION_TEMP) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "would cause rebuiding index, which", "temporary table");
return OG_ERROR;
}
if (db_alter_index_rebuild(session, &rebuild_def, dc, index) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_set_column_nullable(knl_session_t *session, uint32 uid, uint32 table_id, uint32 col_id,
bool32 nullable)
{
knl_cursor_t *cursor = NULL;
knl_update_info_t *info = NULL;
row_assist_t ra;
bool32 col_nullable = OG_FALSE;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_COLUMN_ID, IX_SYS_COLUMN_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_COLUMN_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &table_id, sizeof(uint32),
IX_COL_SYS_COLUMN_001_TABLE_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &col_id, sizeof(uint32),
IX_COL_SYS_COLUMN_001_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, NULL);
col_nullable = *(bool32 *)CURSOR_COLUMN_DATA(cursor, SYS_COLUMN_COL_NULLABLE);
if (col_nullable == nullable) {
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
info = &cursor->update_info;
row_init(&ra, info->data, HEAP_MAX_ROW_SIZE(session), 1);
info->count = 1;
info->columns[0] = SYS_COLUMN_COL_NULLABLE;
(void)row_put_int32(&ra, nullable);
cm_decode_row(info->data, info->offsets, info->lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_find_matched_index(knl_session_t *session, knl_dictionary_t *dc, knl_constraint_def_t *def,
uint16 *idx_cols, knl_index_def_t *idx_def, index_t **index_ptr, bool32 *matched)
{
uint32 column_count = def->columns.count;
table_t *table;
index_t *index = *index_ptr;
table = DC_TABLE(dc);
if (def->index.use_existed) {
index = dc_find_index_by_name(DC_ENTITY(dc), &idx_def->name);
if (index == NULL) {
OG_THROW_ERROR(ERR_INDEX_NOT_EXIST, T2S(&idx_def->user), T2S_EX(&idx_def->name));
return OG_ERROR;
}
if (!db_index_columns_matched(session, &index->desc, DC_ENTITY(dc), &def->columns,
column_count, idx_cols, OG_FALSE)) {
OG_THROW_ERROR(ERR_INDEX_NOT_SUITABLE);
return OG_ERROR;
}
*matched = OG_TRUE;
*index_ptr = index;
} else {
for (uint32 i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (db_index_columns_matched(session, &index->desc, DC_ENTITY(dc),
&def->columns, column_count, idx_cols, OG_FALSE)) {
*matched = OG_TRUE;
*index_ptr = index;
break;
}
}
}
return OG_SUCCESS;
}
static status_t db_create_index_in_clause(knl_session_t *session, knl_dictionary_t *dc, knl_constraint_def_t *def,
uint16 *idx_cols, uint32 *index_id)
{
uint32 i;
table_t *table;
uint32 column_count;
knl_index_col_def_t *index_col = NULL;
table = DC_TABLE(dc);
column_count = def->columns.count;
if (!cm_text_str_equal(&def->index.table, table->desc.name)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "invalid table name.");
return OG_ERROR;
}
for (i = 0; i < def->index.columns.count; i++) {
index_col = (knl_index_col_def_t *)cm_galist_get(&def->index.columns, i);
if (index_col->is_func) {
OG_THROW_ERROR(ERR_ENFORCE_INDEX);
return OG_ERROR;
}
}
if (!db_constraint_columns_match(&def->index.columns, &def->columns)) {
OG_THROW_ERROR(ERR_INDEX_NOT_SUITABLE);
return OG_ERROR;
}
if (def->index.parted && IS_PART_TABLE(table)) {
if (!db_index_include_partkeys(column_count, idx_cols, table->part_table)) {
OG_THROW_ERROR(ERR_LOCAL_UNIQUE_INDEX);
return OG_ERROR;
}
}
return db_create_index(session, &def->index, dc, OG_FALSE, index_id);
}
static status_t db_create_cons_index(knl_session_t *session, knl_dictionary_t *dc, knl_constraint_def_t *def,
uint32 *index_id)
{
table_t *table = NULL;
uint32 i;
knl_index_col_def_t *col_def = NULL;
uint32 column_count;
index_t *index = NULL;
bool32 matched = OG_FALSE;
knl_index_def_t idx_def;
errno_t err;
uint16 *idx_cols = NULL;
knl_column_t *col_tmp = NULL;
status_t ret;
knl_panic_log(def->type == CONS_TYPE_PRIMARY || def->type == CONS_TYPE_UNIQUE,
"type record on def is neither primary nor unique.");
if (def->index.online) {
OG_THROW_ERROR(ERR_CAPABILITY_NOT_SUPPORT, "create constraint index online");
return OG_ERROR;
}
table = DC_TABLE(dc);
column_count = def->columns.count;
idx_cols = (uint16 *)cm_push(session->stack, column_count * sizeof(uint16));
for (i = 0; i < column_count; i++) {
col_def = (knl_index_col_def_t *)cm_galist_get(&def->columns, i);
if (col_def->is_func) {
OG_THROW_ERROR(ERR_ENFORCE_INDEX);
cm_pop(session->stack);
return OG_ERROR;
}
idx_cols[i] = knl_get_column_id(dc, &col_def->name);
if (idx_cols[i] == OG_INVALID_ID16) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, table->desc.name, T2S(&col_def->name));
cm_pop(session->stack);
return OG_ERROR;
}
col_tmp = knl_get_column(dc->handle, idx_cols[i]);
if (col_tmp->datatype == OG_TYPE_TIMESTAMP_TZ) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR,
"column of datatype TIMESTAMP WITH TIME ZONE cannot be unique or a primary key");
cm_pop(session->stack);
return OG_ERROR;
}
}
if (def->type == CONS_TYPE_PRIMARY) {
for (i = 0; i < column_count; i++) {
if (OG_SUCCESS != db_set_column_nullable(session, table->desc.uid, table->desc.id,
(uint32)idx_cols[i], OG_FALSE)) {
cm_pop(session->stack);
return OG_ERROR;
}
}
}
for (i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (def->type == CONS_TYPE_PRIMARY && index->desc.primary) {
cm_pop(session->stack);
OG_THROW_ERROR(ERR_PRIMRY_KEY_ALREADY_EXISTS);
return OG_ERROR;
}
}
if (def->index.columns.count > 0) {
ret = db_create_index_in_clause(session, dc, def, idx_cols, index_id);
cm_pop(session->stack);
return ret;
} else {
err = memcpy_sp(&idx_def, sizeof(knl_index_def_t), &def->index, sizeof(knl_index_def_t));
knl_securec_check(err);
err = memcpy_sp(&idx_def.columns, sizeof(galist_t), &def->columns, sizeof(galist_t));
knl_securec_check(err);
}
if (db_find_matched_index(session, dc, def, idx_cols, &idx_def, &index, &matched) != OG_SUCCESS) {
cm_pop(session->stack);
return OG_ERROR;
}
if (matched) {
*index_id = index->desc.id;
cm_pop(session->stack);
return db_enforce_index(session, dc, def, index);
}
cm_pop(session->stack);
return db_create_index(session, &idx_def, dc, OG_TRUE, index_id);
}
status_t db_write_syslogicrep(knl_session_t *session, uint32 uid, uint32 tableid, uint32 index_id)
{
row_assist_t ra;
table_t *table = NULL;
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_LOGIC_REP_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, OG_MAX_ROW_SIZE, table->desc.column_count);
(void)row_put_int32(&ra, uid);
(void)row_put_int32(&ra, tableid);
(void)row_put_int32(&ra, LOGICREP_STATUS_ON);
(void)row_put_int32(&ra, index_id);
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_create_cons(knl_session_t *session, knl_dictionary_t *dc, knl_constraint_def_t *def)
{
knl_index_def_t *index = NULL;
dc_user_t *user = NULL;
table_t *table = DC_TABLE(dc);
uint32 index_id = OG_INVALID_ID32;
if (db_write_cons_def(session, dc, def) != OG_SUCCESS) {
return OG_ERROR;
}
if (def->type == CONS_TYPE_PRIMARY || def->type == CONS_TYPE_UNIQUE) {
if (dc_open_user_by_id(session, dc->uid, &user) != OG_SUCCESS) {
return OG_ERROR;
}
index = &def->index;
if (index->user.len == 0) {
cm_str2text(user->desc.name, &index->user);
}
if (index->table.len == 0) {
cm_str2text(table->desc.name, &index->table);
}
if (index->name.len == 0) {
index->name = def->name;
}
if (db_create_cons_index(session, dc, def, &index_id) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (def->type == CONS_TYPE_REFERENCE) {
index_id = DC_TABLE(dc)->cons_set.max_ref_id + 1;
}
return db_update_cons_index(session, dc, &def->name, index_id);
}
static status_t db_create_index_without_cons(knl_session_t *session, knl_table_desc_t *desc, knl_table_def_t *def)
{
uint32 cur_index;
knl_index_def_t *index_def = NULL;
knl_dictionary_t dc;
uint32 index_id = OG_INVALID_ID32;
for (cur_index = 0; cur_index < def->indexs.count; cur_index++) {
if (dc_open_table_private(session, desc->uid, desc->id, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
index_def = (knl_index_def_t *)cm_galist_get(&def->indexs, cur_index);
knl_panic(index_def->name.len != 0);
table_t *table = DC_TABLE(&dc);
uint32 i;
knl_index_col_def_t *col_def = NULL;
knl_column_t *col_tmp = NULL;
index_t *index = NULL;
uint32 column_count = index_def->columns.count;
uint16 *idx_cols = (uint16 *)cm_push(session->stack, column_count * sizeof(uint16));
for (i = 0; i < column_count; i++) {
col_def = (knl_index_col_def_t *)cm_galist_get(&index_def->columns, i);
idx_cols[i] = knl_get_column_id(&dc, &col_def->name);
if (idx_cols[i] == OG_INVALID_ID16) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, table->desc.name, T2S(&col_def->name));
cm_pop(session->stack);
dc_close_table_private(&dc);
return OG_ERROR;
}
col_tmp = knl_get_column(dc.handle, idx_cols[i]);
if (col_tmp->datatype == OG_TYPE_TIMESTAMP_TZ) {
OG_THROW_ERROR(ERR_SQL_SYNTAX_ERROR,
"column of datatype TIMESTAMP WITH TIME ZONE cannot be unique or a primary key");
cm_pop(session->stack);
dc_close_table_private(&dc);
return OG_ERROR;
}
}
if (index_def->primary) {
for (i = 0; i < column_count; i++) {
if (OG_SUCCESS != db_set_column_nullable(session, table->desc.uid, table->desc.id,
(uint32)idx_cols[i], OG_FALSE)) {
cm_pop(session->stack);
dc_close_table_private(&dc);
return OG_ERROR;
}
}
}
for (i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (index_def->primary && index->desc.primary) {
cm_pop(session->stack);
OG_THROW_ERROR(ERR_PRIMRY_KEY_ALREADY_EXISTS);
dc_close_table_private(&dc);
return OG_ERROR;
}
}
if (db_create_index(session, index_def, &dc, OG_FALSE, &index_id) != OG_SUCCESS) {
dc_close_table_private(&dc);
return OG_ERROR;
}
dc_close_table_private(&dc);
}
return OG_SUCCESS;
}
static status_t db_create_constraints(knl_session_t *session, knl_table_desc_t *desc, knl_table_def_t *def)
{
uint32 i;
knl_constraint_def_t *cons_def = NULL;
knl_dictionary_t dc;
for (i = 0; i < def->constraints.count; i++) {
if (dc_open_table_private(session, desc->uid, desc->id, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
cons_def = (knl_constraint_def_t *)cm_galist_get(&def->constraints, i);
knl_panic_log(cons_def->name.len != 0,
"name's len record on cons_def is zero, panic info: table %s", desc->name);
if (cons_def->type == CONS_TYPE_REFERENCE) {
dc_close_table_private(&dc);
continue;
}
cons_def->cons_state.is_contains_vircol = def->contains_vircol;
if (db_create_cons(session, &dc, cons_def) != OG_SUCCESS) {
dc_close_table_private(&dc);
return OG_ERROR;
}
dc_close_table_private(&dc);
}
for (i = 0; i < def->constraints.count; i++) {
if (dc_open_table_private(session, desc->uid, desc->id, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
cons_def = (knl_constraint_def_t *)cm_galist_get(&def->constraints, i);
knl_panic_log(cons_def->name.len != 0,
"name's len record on cons_def is zero, panic info: table %s", desc->name);
if (cons_def->type != CONS_TYPE_REFERENCE) {
dc_close_table_private(&dc);
continue;
}
if (db_create_cons(session, &dc, cons_def) != OG_SUCCESS) {
dc_close_table_private(&dc);
return OG_ERROR;
}
dc_close_table_private(&dc);
}
return OG_SUCCESS;
}
static status_t db_load_sys_dc(knl_session_t *session, knl_table_def_t *def, table_t *table)
{
knl_dictionary_t dc;
dc_ready(session, table->desc.uid, table->desc.id);
if (dc_open(session, &def->schema, &def->name, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (SYNONYM_EXIST(&dc)) {
dc_close(&dc);
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, T2S(&def->schema), T2S_EX(&def->name));
return OG_ERROR;
}
return OG_SUCCESS;
}
#ifdef OG_RAC_ING
status_t db_query_consis_hash_strategy(knl_session_t *session, uint32 *slice_count, uint32 *group_count,
knl_cursor_t *cursor, bool32 *is_found)
{
*is_found = OG_FALSE;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_CONSIS_HASH_STRATEGY_ID,
IX_SYS_CONSISTENT_HASH_STRATEGY001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
slice_count, sizeof(uint32), IX_COL_SYS_CONSIS_HASH_STRATEGY001_SLICE_COUNT);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
group_count, sizeof(uint32), IX_COL_SYS_CONSIS_HASH_STRATEGY001_GROUP_COUNT);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
*is_found = !cursor->eof;
return OG_SUCCESS;
}
status_t db_insert_consis_hash_strategy(knl_session_t *session, table_t *table)
{
knl_table_desc_t *desc = &table->desc;
status_t status;
row_assist_t ra;
knl_column_t *lob_column = NULL;
bool32 is_found = OG_FALSE;
if (IS_SYS_TABLE(table) || desc->slice_count == 0) {
return OG_SUCCESS;
}
CM_SAVE_STACK(session->stack);
do {
knl_cursor_t *cursor = knl_push_cursor(session);
status = db_query_consis_hash_strategy(session, &desc->slice_count, &desc->group_count, cursor, &is_found);
OG_BREAK_IF_ERROR(status);
OG_BREAK_IF_TRUE(is_found);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_CONSIS_HASH_STRATEGY_ID,
IX_SYS_CONSISTENT_HASH_STRATEGY001_ID);
row_init(&ra, cursor->buf, KNL_MAX_ROW_SIZE(session), SYS_CONSIS_HASH_STRATEGY_COLUMN_COUNT);
(void)row_put_int32(&ra, desc->slice_count);
(void)row_put_int32(&ra, desc->group_count);
lob_column = knl_get_column(cursor->dc_entity, SYS_CONSIS_HASH_STRATEGY_COL_BUCKETS);
status = knl_row_put_lob(session, cursor, lob_column, &desc->distribute_buckets, &ra);
OG_BREAK_IF_ERROR(status);
status = knl_internal_insert(session, cursor);
} while (0);
CM_RESTORE_STACK(session->stack);
return status;
}
status_t db_insert_distribute_strategy(knl_session_t *session, table_t *table)
{
knl_cursor_t *cursor = NULL;
status_t status;
knl_table_desc_t *desc = &table->desc;
if (IS_SYS_TABLE(table)) {
return OG_SUCCESS;
}
if (desc->distribute_data.size == 0) {
return OG_SUCCESS;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_DISTRIBUTE_STRATEGY_ID,
IX_SYS_DISTRIBUTE_STRATEGY001_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(uint32), DISTRIBUTED_STRATEGY_COL_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
&desc->id, sizeof(uint32), DISTRIBUTED_STRATEGY_COL_TABLE);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
status = db_insert_distribute_strategy_inner(session, cursor, desc);
} else {
OG_LOG_DEBUG_WAR("distribute strategy table is not empty, user = %d, table_id = %d", desc->uid, desc->id);
if (OG_SUCCESS != db_delete_distribute_strategy(session, table)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
status = db_insert_distribute_strategy_inner(session, cursor, desc);
}
CM_RESTORE_STACK(session->stack);
return status;
}
status_t db_delete_distribute_strategy(knl_session_t *session, table_t *table)
{
knl_cursor_t *cursor = NULL;
knl_table_desc_t *desc = &table->desc;
if (IS_SYS_TABLE(table)) {
return OG_SUCCESS;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_DISTRIBUTE_STRATEGY_ID,
IX_SYS_DISTRIBUTE_STRATEGY001_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(uint32), DISTRIBUTED_STRATEGY_COL_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
&desc->id, sizeof(uint32), DISTRIBUTED_STRATEGY_COL_TABLE);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
CM_RESTORE_STACK(session->stack);
OG_LOG_DEBUG_WAR("cannot find the distribute strategy, user = %d, table_id = %d", desc->uid, desc->id);
return OG_ERROR;
}
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_insert_distribute_strategy_inner(knl_session_t *session, knl_cursor_t *cursor,
knl_table_desc_t *desc)
{
row_assist_t ra;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_DISTRIBUTE_STRATEGY_ID,
IX_SYS_DISTRIBUTE_STRATEGY001_ID);
row_init(&ra, cursor->buf, KNL_MAX_ROW_SIZE(session), DISTRIBUTED_STRATEGY_COLUMN_COUNT);
(void)row_put_int32(&ra, desc->uid);
(void)row_put_int32(&ra, desc->id);
(void)row_put_bin(&ra, &desc->distribute_data);
if (desc->distribute_type == distribute_hash || desc->distribute_type == distribute_hash_basic) {
knl_column_t *lob_column;
lob_column = knl_get_column(cursor->dc_entity, DISTRIBUTED_STRATEGY_COL_BUCKETS);
if (knl_row_put_lob(session, cursor, lob_column, &desc->distribute_buckets, &ra) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
(void)row_put_null(&ra);
}
(void)row_put_int32(&ra, desc->slice_count);
(void)row_put_int32(&ra, 0);
(void)row_put_text(&ra, &desc->distribute_text);
return knl_internal_insert(session, cursor);
}
#endif
static status_t db_write_sys_external(knl_session_t *session, knl_cursor_t *cursor, uint32 uid,
uint32 table_id, knl_table_def_t *def)
{
row_assist_t ra;
table_t *table = NULL;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_EXTERNAL_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
if (def->external_def.directory.len >= OG_FILE_NAME_BUFFER_SIZE) {
OG_THROW_ERROR(ERR_BUFFER_OVERFLOW, def->external_def.directory.len, OG_FILE_NAME_BUFFER_SIZE - 1);
return OG_ERROR;
}
if (def->external_def.location.len >= OG_MAX_NAME_LEN) {
OG_THROW_ERROR(ERR_SQL_TOO_LONG, def->external_def.location.len, OG_MAX_NAME_LEN - 1);
return OG_ERROR;
}
row_init(&ra, cursor->buf, OG_MAX_ROW_SIZE, table->desc.column_count);
row_put_int32(&ra, table_id);
row_put_int32(&ra, def->external_def.external_type);
row_put_text(&ra, &def->external_def.directory);
row_put_text(&ra, &def->external_def.location);
row_put_int32(&ra, def->external_def.records_delimiter);
row_put_int32(&ra, def->external_def.fields_terminator);
row_put_int32(&ra, uid);
return knl_internal_insert(session, cursor);
}
static status_t db_construct_columns(knl_session_t *session, knl_cursor_t *cursor, knl_table_def_t *def, table_t *table)
{
knl_column_def_t *column_def = NULL;
knl_column_t column = {0};
space_t *space = SPACE_GET(session, table->desc.space_id);
bool32 is_encrypt = SPACE_IS_ENCRYPT(space);
column.name = (char *)cm_push(session->stack, OG_NAME_BUFFER_SIZE);
for (uint32 i = 0; i < def->columns.count; i++) {
column_def = (knl_column_def_t *)cm_galist_get(&def->columns, i);
if (is_encrypt && (!OG_IS_LOB_TYPE(column_def->typmod.datatype) && !column_def->typmod.is_array)) {
if (column_def->typmod.size > OG_MAX_COLUMN_SIZE - OG_KMC_MAX_CIPHER_SIZE) {
cm_pop(session->stack);
OG_THROW_ERROR(ERR_ENCRYPTION_NOT_SUPPORT_DDL, "column size should less than",
OG_MAX_COLUMN_SIZE - OG_KMC_MAX_CIPHER_SIZE);
return OG_ERROR;
}
}
db_convert_column_def(&column, table->desc.uid, table->desc.id, column_def, NULL, i);
if (def->type != TABLE_TYPE_HEAP && KNL_COLUMN_IS_ARRAY(&column)) {
OG_THROW_ERROR(ERR_WRONG_TABLE_TYPE);
cm_pop(session->stack);
return OG_ERROR;
}
if (COLUMN_IS_LOB(&column)) {
if (def->type == TABLE_TYPE_EXTERNAL) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "lob type", "external organized table");
cm_pop(session->stack);
return OG_ERROR;
}
if (def->type == TABLE_TYPE_SESSION_TEMP || def->type == TABLE_TYPE_TRANS_TEMP) {
if (column.datatype == OG_TYPE_CLOB || column.datatype == OG_TYPE_IMAGE) {
column.datatype = OG_TYPE_VARCHAR;
column.size = TEMP_LOB_TO_CHAR_LENGTH;
} else {
column.datatype = OG_TYPE_RAW;
column.size = TEMP_LOB_TO_CHAR_LENGTH;
}
} else {
if (db_create_lob(session, table, &column, def) != OG_SUCCESS) {
cm_pop(session->stack);
return OG_ERROR;
}
}
}
if (db_write_syscolumn(session, cursor, &column) != OG_SUCCESS) {
cm_pop(session->stack);
return OG_ERROR;
}
if (column_def->is_comment) {
knl_comment_def_t comment_def;
comment_def.uid = column.uid;
comment_def.id = column.table_id;
comment_def.column_id = column.id;
comment_def.comment = column_def->comment;
comment_def.type = COMMENT_ON_COLUMN;
if (OG_SUCCESS != db_comment_on(session, &comment_def)) {
cm_pop(session->stack);
return OG_ERROR;
}
}
}
cm_pop(session->stack);
return OG_SUCCESS;
}
static status_t db_create_external_table(knl_session_t *session, knl_cursor_t *cursor, knl_table_def_t *def,
table_t *table)
{
bool32 dire_exists = OG_FALSE;
if (db_fetch_directory_path(session, T2S(&def->external_def.directory), NULL, 0, &dire_exists) != OG_SUCCESS) {
return OG_ERROR;
}
if (!dire_exists) {
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "directory", T2S(&def->external_def.directory));
return OG_ERROR;
}
return db_write_sys_external(session, cursor, table->desc.uid, table->desc.id, def);
}
status_t db_create_table(knl_session_t *session, knl_table_def_t *def, table_t *table, bool32 *is_referenced)
{
knl_cursor_t *cursor = NULL;
dc_user_t *user = NULL;
errno_t err;
if (DB_NOT_READY(session)) {
OG_THROW_ERROR(ERR_NO_DB_ACTIVE);
return OG_ERROR;
}
err = memset_sp(table, sizeof(table_t), 0, sizeof(table_t));
knl_securec_check(err);
if (db_init_table_desc(session, &table->desc, def) != OG_SUCCESS) {
return OG_ERROR;
}
table->desc.id = (table->desc.uid == 0) ? def->sysid : OG_INVALID_ID32;
if (dc_open_user_by_id(session, table->desc.uid, &user) != OG_SUCCESS) {
return OG_ERROR;
}
if (dc_create_table_entry(session, user, &table->desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (def->type == TABLE_TYPE_HEAP) {
if (IS_SYS_TABLE(table)) {
if (heap_create_segment(session, table) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
return OG_ERROR;
}
* reset storage initial size to 0 for sys table
* storage parameter will not save to sys_storage for sys tables
*/
table->desc.storage_desc.initial = 0;
}
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->row = (row_head_t *)cursor->buf;
cursor->table = db_sys_table(SYS_TABLE_ID);
cursor->is_valid = OG_TRUE;
if (db_write_systable(session, cursor, &table->desc) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (table->desc.storaged && db_write_sysstorage(session, cursor, table->desc.org_scn,
&table->desc.storage_desc) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (table->desc.compress) {
if (db_write_syscompress(session, cursor, table->desc.space_id, table->desc.org_scn, table->desc.compress_algo,
COMPRESS_OBJ_TYPE_TABLE) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
#ifdef OG_RAC_ING
if (db_insert_consis_hash_strategy(session, table) != OG_SUCCESS ||
db_insert_distribute_strategy(session, table) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
#endif
if (db_check_lob_storage_mode(session, def) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
cursor->table = db_sys_table(SYS_COLUMN_ID);
if (db_construct_columns(session, cursor, def, table) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (def->parted) {
if (db_create_part_table(session, cursor, table, def) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (def->type == TABLE_TYPE_EXTERNAL) {
if (db_create_external_table(session, cursor, def, table) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (def->constraints.count > 0) {
if (db_create_constraints(session, &table->desc, def) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (def->indexs.count > 0) {
if (db_create_index_without_cons(session, &table->desc, def) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
if (def->sysid != OG_INVALID_ID32) {
if (db_load_sys_dc(session, def, table) != OG_SUCCESS) {
dc_free_broken_entry(session, table->desc.uid, table->desc.id);
return OG_ERROR;
}
}
session->stat->table_creates++;
return OG_SUCCESS;
}
static status_t db_init_ltt_column(knl_column_t *column, uint32 uid, uint32 oid, knl_column_def_t *column_def,
int id)
{
errno_t ret;
ret = memset_sp(column, sizeof(knl_column_t), 0, sizeof(knl_column_t));
knl_securec_check(ret);
column->id = id;
column->uid = uid;
column->table_id = oid;
column->nullable = column_def->nullable;
column->datatype = column_def->typmod.datatype;
column->size = column_def->typmod.size;
column->precision = column_def->typmod.precision;
column->scale = column_def->typmod.scale;
column->flags = 0;
if (column->datatype == OG_TYPE_CLOB || column->datatype == OG_TYPE_IMAGE) {
column->datatype = OG_TYPE_VARCHAR;
column->size = TEMP_LOB_TO_CHAR_LENGTH;
} else if (column->datatype == OG_TYPE_BLOB) {
column->datatype = OG_TYPE_RAW;
column->size = TEMP_LOB_TO_CHAR_LENGTH;
}
*/
if (column_def->is_serial) {
COLUMN_SET_SERIAL(column);
} else {
COLUMN_RESET_SERIAL(column);
}
if (column_def->is_update_default) {
COLUMN_SET_UPDATE_DEFAULT(column);
}
if (OG_IS_STRING_TYPE(column->datatype) && column_def->typmod.is_char) {
COLUMN_SET_CHARACTER(column);
}
return OG_SUCCESS;
}
* realloc memory from dc context
*/
static status_t db_convert_ltt_column_def(knl_session_t *session, dc_entity_t *entity, knl_column_t *column,
uint32 uid, uint32 oid, knl_column_def_t *column_def, int id)
{
errno_t ret;
if (dc_copy_text2str(session, entity->memory, &column_def->name, &column->name) != OG_SUCCESS) {
return OG_ERROR;
}
if (column_def->default_text.len == 0) {
column->default_text.len = 0;
column->default_text.str = NULL;
} else {
column->default_text.len = column_def->default_text.len;
if (dc_alloc_mem(&session->kernel->dc_ctx, entity->memory, column->default_text.len,
(void **)&column->default_text.str) != OG_SUCCESS) {
return OG_ERROR;
}
ret = memcpy_sp(column->default_text.str, column->default_text.len, column_def->default_text.str,
column->default_text.len);
knl_securec_check(ret);
}
if (column->default_text.len != 0) {
if (g_knl_callback.parse_default_from_text((knl_handle_t)session,
(knl_handle_t)entity, (knl_handle_t)column, entity->memory,
&column->default_expr, &column->update_default_expr, column->default_text) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static uint32 db_get_valid_llt_file(knl_session_t *session, table_t *table)
{
space_t *space = SPACE_GET(session, table->desc.space_id);
for (uint32 id = 0; id < space->ctrl->file_hwm; id++) {
if (OG_INVALID_ID32 == space->ctrl->files[id]) {
continue;
}
datafile_t *df = DATAFILE_GET(session, space->ctrl->files[id]);
if (!DATAFILE_IS_ONLINE(df)) {
continue;
}
return space->ctrl->files[id];
}
return OG_INVALID_ID32;
}
status_t db_create_ltt_lobs(knl_session_t *session, dc_entity_t *entity, uint32 i)
{
lob_t *lob = NULL;
table_t *table = NULL;
knl_column_t *column = NULL;
errno_t err;
if (!entity->contain_lob) {
return OG_SUCCESS;
}
table = &entity->table;
column = dc_get_column(entity, i);
if (dc_alloc_mem(&session->kernel->dc_ctx, entity->memory, sizeof(lob_t), (void **)&lob) != OG_SUCCESS) {
return OG_ERROR;
}
err = memset_sp(lob, sizeof(lob_t), 0, sizeof(lob_t));
knl_securec_check(err);
db_init_lob_desc(session, table, column, &lob->desc);
lob->lob_entity.entry.file = db_get_valid_llt_file(session, table);
lob->lob_entity.lob = lob;
column->lob = (knl_handle_t)lob;
return OG_SUCCESS;
}
static status_t db_create_ltt_columns(knl_session_t *session, dc_entity_t *entity, knl_table_def_t *def,
uint32 uid, uint32 oid)
{
knl_table_desc_t *desc = &entity->table.desc;
errno_t ret;
entity->column_count = desc->column_count;
if (dc_prepare_load_columns(session, entity) != OG_SUCCESS) {
return OG_ERROR;
}
for (uint32 i = 0; i < def->columns.count; i++) {
knl_column_def_t *column_def = (knl_column_def_t *)cm_galist_get(&def->columns, i);
knl_column_t *column = NULL;
if (dc_alloc_mem(&session->kernel->dc_ctx, entity->memory,
sizeof(knl_column_t), (void **)&column) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_DC_BUFFER_FULL);
return OG_ERROR;
}
ret = memset_sp(column, sizeof(knl_column_t), 0, sizeof(knl_column_t));
knl_securec_check(ret);
if (db_init_ltt_column(column, desc->uid, desc->id, column_def, i) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_convert_ltt_column_def(session, entity, column, desc->uid, desc->id, column_def, i) != OG_SUCCESS) {
return OG_ERROR;
}
entity->column_groups[column->id / DC_COLUMN_GROUP_SIZE].columns[column->id % DC_COLUMN_GROUP_SIZE] = column;
if (KNL_COLUMN_IS_UPDATE_DEFAULT(column)) {
entity->has_udef_col = OG_TRUE;
}
if (COLUMN_IS_LOB(column)) {
entity->contain_lob = OG_TRUE;
if (db_create_ltt_lobs(session, entity, i) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (KNL_COLUMN_IS_SERIAL(column) && !KNL_COLUMN_IS_DELETED(column)) {
entity->has_serial_col = OG_TRUE;
}
estimate_row_len(&entity->table, column);
}
dc_create_column_index(entity);
return OG_SUCCESS;
}
status_t db_create_ltt_index(knl_session_t *session, knl_index_def_t *def, knl_dictionary_t *dc,
bool32 need_fill_index)
{
index_t *index = NULL;
table_t *table;
dc_entity_t *entity;
knl_index_desc_t *desc = NULL;
errno_t ret;
knl_column_t *column = NULL;
knl_cursor_t *cursor = NULL;
entity = DC_ENTITY(dc);
table = &entity->table;
if (table->index_set.total_count >= OG_MAX_TABLE_INDEXES) {
OG_THROW_ERROR(ERR_TOO_MANY_INDEXES, T2S(&def->user), T2S_EX(&def->table));
return OG_ERROR;
}
for (uint32 i = 0; i < def->columns.count; i++) {
knl_index_col_def_t *index_col = (knl_index_col_def_t *)cm_galist_get(&def->columns, i);
if (index_col->is_func) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create function index", "local temp table");
return OG_ERROR;
}
}
index_t check_index;
ret = memset_sp(&check_index, sizeof(index_t), 0, sizeof(index_t));
knl_securec_check(ret);
if (db_alloc_index_id(entity, def, &check_index.desc.id) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_verify_index_def(session, dc, def, &check_index.desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (dc_alloc_mem(&session->kernel->dc_ctx, entity->memory, sizeof(index_t), (void **)&index) != OG_SUCCESS) {
return OG_ERROR;
}
ret = memcpy_sp(index, sizeof(index_t), &check_index, sizeof(index_t));
knl_securec_check(ret);
index->entity = entity;
desc = &index->desc;
desc->is_cons = OG_FALSE;
desc->is_enforced = OG_FALSE;
desc->id = table->index_set.count;
desc->slot = desc->id;
dc_set_index_profile(session, entity, index);
dc_set_index_accessor(table, index);
if (need_fill_index) {
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (temp_db_fill_index(session, cursor, index, def->parallelism) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
}
if (index->desc.primary) {
for (uint32 i = 0; i < index->desc.column_count; i++) {
uint16 id = index->desc.columns[i];
column = dc_get_column(entity, id);
column->nullable = OG_FALSE;
}
}
table->index_set.count++;
table->index_set.total_count++;
table->index_set.items[index->desc.slot] = index;
table->desc.index_count++;
return OG_SUCCESS;
}
static status_t db_create_ltt_indexes(knl_session_t *session, knl_table_def_t *def, knl_dictionary_t *dc)
{
errno_t ret;
for (uint32 i = 0; i < def->constraints.count; i++) {
knl_constraint_def_t *cons = (knl_constraint_def_t *)cm_galist_get(&def->constraints, i);
knl_index_def_t *index_def = &cons->index;
if (cons->type == CONS_TYPE_REFERENCE || cons->type == CONS_TYPE_CHECK) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR,
"local temporary table don't support reference or check constraints");
return OG_ERROR;
}
if (index_def->parted) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR,
"could not create partition index on local temporary table");
return OG_ERROR;
}
if (index_def->use_existed) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR,
"local temporary table don't support use existed index");
return OG_ERROR;
}
if (index_def->columns.count > 0) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR,
"local temporary table don't support this constraint syntax");
return OG_ERROR;
}
if (index_def->user.len == 0) {
index_def->user = def->schema;
}
if (index_def->table.len == 0) {
index_def->table = def->name;
}
if (index_def->name.len == 0) {
index_def->name = cons->name;
}
ret = memcpy_sp(&index_def->columns, sizeof(galist_t), &cons->columns, sizeof(galist_t));
knl_securec_check(ret);
if (db_create_ltt_index(session, index_def, dc, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
}
knl_index_def_t *index_def = NULL;
for (uint32 i = 0; i < def->indexs.count; i++) {
index_def = (knl_index_def_t *)cm_galist_get(&def->indexs, i);
if (index_def->parted) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR,
"could not create partition index on local temporary table");
return OG_ERROR;
}
if (index_def->use_existed) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR,
"local temporary table don't support use existed index");
return OG_ERROR;
}
if (index_def->user.len == 0) {
index_def->user = def->schema;
}
if (index_def->table.len == 0) {
index_def->table = def->name;
}
if (index_def->name.len == 0) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR,
"index name is null on temporary table");
return OG_ERROR;
}
if (db_create_ltt_index(session, index_def, dc, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_create_ltt(knl_session_t *session, knl_table_def_t *def, dc_entity_t *entity)
{
knl_table_desc_t *desc = &entity->table.desc;
knl_dictionary_t dc;
dc.is_sysnonym = OG_FALSE;
dc.handle = (knl_handle_t)entity;
dc.kernel = (knl_handle_t)session->kernel;
dc.uid = desc->uid;
dc.oid = desc->id;
dc.org_scn = desc->org_scn;
dc.chg_scn = desc->chg_scn;
dc.type = desc->type;
dc_set_table_accessor(&entity->table);
if (db_create_ltt_columns(session, entity, def, desc->uid, desc->id) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_create_ltt_indexes(session, def, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_drop_ltt(knl_session_t *session, knl_dictionary_t *dc)
{
table_t *table = DC_TABLE(dc);
knl_temp_cache_t *temp_table = NULL;
cm_spin_lock(&session->temp_cache_lock, NULL);
temp_table = knl_get_temp_cache(session, dc->uid, dc->oid);
if (temp_table != NULL) {
knl_panic_log(temp_table->org_scn == table->desc.org_scn, "temp_table's org_scn is not equal to "
"table's org_scn, panic info: table %s temp_table org_scn %llu table org_scn %llu",
table->desc.name, temp_table->org_scn, table->desc.org_scn);
knl_free_temp_vm(session, temp_table);
}
cm_spin_unlock(&session->temp_cache_lock);
uint32 slot = table->desc.id - OG_LTT_ID_OFFSET;
dc_entity_t *entity = DC_ENTITY(dc);
mctx_destroy(entity->memory);
session->temp_dc->entries[slot] = NULL;
return OG_SUCCESS;
}
static status_t db_delete_from_systable(knl_session_t *session, knl_cursor_t *cursor, uint32 uid, const char *name)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_TABLE_ID, IX_SYS_TABLE_001_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 *)&uid,
sizeof(uint32), IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, (void *)name,
(uint16)strlen(name), IX_COL_SYS_TABLE_001_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_delete_from_sysview(knl_session_t *session, knl_cursor_t *cursor, uint32 uid, char *name)
{
dc_user_t *user = NULL;
if (dc_open_user_by_id(session, uid, &user) != OG_SUCCESS) {
return OG_ERROR;
}
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_VIEW_ID, IX_SYS_VIEW001_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 *)&uid,
sizeof(uint32), IX_COL_SYS_VIEW001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, (void *)name,
(uint16)strlen(name), IX_COL_SYS_VIEW001_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
if (cursor->eof) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, user->desc.name, name);
return OG_ERROR;
} else {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_delete_from_sysstorage(knl_session_t *session, knl_cursor_t *cursor, uint64 orgscn)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_STORAGE_ID, IX_STORAGE_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 *)&orgscn,
sizeof(uint64), IX_COL_SYS_STORAGE_ORGSCN);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
if (cursor->eof) {
return OG_SUCCESS;
}
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_delete_from_sysindex(knl_session_t *session, knl_cursor_t *cursor, uint32 uid, uint32 tid,
uint32 iid)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_INDEX_ID, IX_SYS_INDEX_001_ID);
if (iid == OG_INVALID_ID32) {
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_INDEX_001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &tid, sizeof(uint32),
IX_COL_SYS_INDEX_001_TABLE);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_INDEX_001_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_INDEX_001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &tid, sizeof(uint32),
IX_COL_SYS_INDEX_001_TABLE);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_INDEX_001_ID);
} else {
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_INDEX_001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &tid, sizeof(uint32),
IX_COL_SYS_INDEX_001_TABLE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &iid, sizeof(uint32),
IX_COL_SYS_INDEX_001_ID);
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
while (!cursor->eof) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
return OG_ERROR;
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_delete_columns(knl_session_t *session, knl_cursor_t *cursor, uint32 uid, uint32 oid)
{
knl_scan_key_t *l_key = NULL;
knl_scan_key_t *r_key = NULL;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_COLUMN_ID, IX_SYS_COLUMN_001_ID);
l_key = &cursor->scan_range.l_key;
r_key = &cursor->scan_range.r_key;
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_COLUMN_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_COLUMN_001_TABLE_ID);
knl_set_key_flag(l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_COLUMN_001_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), r_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_COLUMN_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), r_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_COLUMN_001_TABLE_ID);
knl_set_key_flag(r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_COLUMN_001_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
knl_panic_log(oid == *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_COLUMN_COL_TABLE_ID),
"the oid is abnormal, panic info: page %u-%u type %u table %s index %s oid %u", cursor->rowid.file,
cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, ((table_t *)cursor->table)->desc.name,
((index_t *)cursor->index)->desc.name, oid);
while (!cursor->eof) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
return OG_ERROR;
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_delete_viewcolumns(knl_session_t *session, knl_cursor_t *cursor, uint32 uid, uint32 oid)
{
knl_scan_key_t *l_key = NULL;
knl_scan_key_t *r_key = NULL;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_VIEWCOL_ID, IX_SYS_VIEWCOL001_ID);
knl_init_index_scan(cursor, OG_FALSE);
l_key = &cursor->scan_range.l_key;
r_key = &cursor->scan_range.r_key;
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_VIEWCOL001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_VIEWCOL001_VIEW_ID);
knl_set_key_flag(l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_VIEWCOL001_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), r_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_VIEWCOL001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), r_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_VIEWCOL001_VIEW_ID);
knl_set_key_flag(r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_VIEWCOL001_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
while (!cursor->eof) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
return OG_ERROR;
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_delete_from_syslob(knl_session_t *session, knl_cursor_t *cursor, uint32 uid, uint32 oid,
uint32 col_id)
{
knl_scan_key_t *l_key = NULL;
knl_scan_key_t *r_key = NULL;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_LOB_ID, IX_SYS_LOB001_ID);
if (col_id == OG_INVALID_INT32) {
knl_init_index_scan(cursor, OG_FALSE);
l_key = &cursor->scan_range.l_key;
r_key = &cursor->scan_range.r_key;
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_LOB001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_LOB001_TABLE_ID);
knl_set_key_flag(l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_LOB001_COLUMN_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), r_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_LOB001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), r_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_LOB001_TABLE_ID);
knl_set_key_flag(r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_LOB001_COLUMN_ID);
} else {
knl_init_index_scan(cursor, OG_TRUE);
l_key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_LOB001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_LOB001_TABLE_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &col_id, sizeof(uint32),
IX_COL_SYS_LOB001_COLUMN_ID);
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
while (!cursor->eof) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
return OG_ERROR;
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static bool32 db_check_cons_referenced(uint32 idx_id, dc_entity_t *entity, uint32 *type)
{
index_t *index = NULL;
if (*type == CONS_TYPE_PRIMARY || *type == CONS_TYPE_UNIQUE) {
index = dc_find_index_by_id(entity, idx_id);
if (index != NULL && index->dep_set.count != 0) {
OG_THROW_ERROR(ERR_DROP_CONS, "some foreign keys");
return OG_TRUE;
}
if ((entity->lrep_info.status == LOGICREP_STATUS_ON) && (entity->lrep_info.index_id == idx_id)) {
OG_THROW_ERROR(ERR_REFERENCED_BY_LOGICAL_LOG);
return OG_TRUE;
}
}
return OG_FALSE;
}
status_t db_check_cons_auto_increment(dc_entity_t *entity, knl_cursor_t *cursor, uint32 type)
{
text_t col_list;
uint32 col_id;
uint32 cols_num;
knl_column_t *column = NULL;
if (type != CONS_TYPE_PRIMARY && type != CONS_TYPE_UNIQUE) {
return OG_SUCCESS;
}
cols_num = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_COLUMN_COUNT);
if (cols_num != 1) {
return OG_SUCCESS;
}
col_list.str = CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_COLUMN_LIST);
col_list.len = CURSOR_COLUMN_SIZE(cursor, CONSDEF_COL_COLUMN_LIST);
if (cm_text2int(&col_list, (int32 *)&col_id) != OG_SUCCESS) {
return OG_ERROR;
}
column = dc_get_column(entity, col_id);
if (column != NULL && KNL_COLUMN_IS_SERIAL(column)) {
OG_THROW_ERROR(ERR_DUPLICATE_AUTO_COLUMN);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_update_cons_state(knl_session_t *session, knl_dictionary_t *dc, uint32 next_id)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
uint32 fetch_cons_id;
knl_constraint_state_t cons_state;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_CONSDEF_ID, IX_SYS_CONSDEF001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &(cursor->scan_range.l_key), OG_TYPE_INTEGER, &(dc->uid),
sizeof(uint32), IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &(cursor->scan_range.l_key), OG_TYPE_INTEGER, &(dc->oid),
sizeof(uint32), IX_COL_SYS_CONSDEF001_TABLE_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &(cursor->scan_range.r_key), OG_TYPE_INTEGER, &(dc->uid),
sizeof(uint32), IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &(cursor->scan_range.r_key), OG_TYPE_INTEGER, &(dc->oid),
sizeof(uint32), IX_COL_SYS_CONSDEF001_TABLE_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
while (!cursor->eof) {
fetch_cons_id = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_INDEX_ID);
if (fetch_cons_id == next_id) {
cons_state.option = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_FLAGS);
cons_state.is_cascade = 1;
row_init(&ra, cursor->update_info.data, OG_MAX_ROW_SIZE, 1);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = CONSDEF_COL_FLAGS;
(void)row_put_int32(&ra, cons_state.option);
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
break;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_cons_cascade(knl_session_t *session, knl_dictionary_t *dc, uint32 cons_id,
uint32 ref_uid, uint32 ref_oid, uint32 ref_ix)
{
uint32 next_id = OG_INVALID_ID32;
ref_cons_t *del_ref_cons = NULL;
ref_cons_t *ref_cons = NULL;
table_t *table = DC_TABLE(dc);
uint32 ref_count = table->cons_set.ref_count;
for (uint32 i = 0; i < ref_count; i++) {
ref_cons = table->cons_set.ref_cons[i];
if (ref_cons->cons_id == cons_id) {
del_ref_cons = ref_cons;
break;
}
}
for (uint32 i = 0; i < ref_count; i++) {
ref_cons = table->cons_set.ref_cons[i];
if (ref_cons->cons_id == cons_id || ref_cons->ref_uid != ref_uid ||
ref_cons->ref_oid != ref_oid || ref_cons->ref_ix != ref_ix) {
continue;
}
if (db_compare_ref_cons_cols(del_ref_cons, ref_cons) && next_id > ref_cons->cons_id) {
next_id = ref_cons->cons_id;
}
}
if (next_id == OG_INVALID_ID32) {
return OG_SUCCESS;
}
return db_update_cons_state(session, dc, next_id);
}
status_t db_drop_cons(knl_session_t *session, knl_cursor_t *cursor, uint32 uid, uint32 oid,
knl_dictionary_t *dc, knl_altable_def_t *def, bool32 *is_found)
{
uint32 index_id;
uint32 ref_uid;
uint32 ref_tid;
uint32 ref_ix;
knl_dictionary_t ref_dc;
uint32 type;
knl_constraint_state_t cons_state;
dc_entity_t *entity = (dc_entity_t *)dc->handle;
if (db_fetch_sysconsdef_by_table(session, cursor, CURSOR_ACTION_DELETE,
uid, oid, &def->cons_def.name, is_found) != OG_SUCCESS) {
return OG_ERROR;
}
if (!*is_found) {
return OG_SUCCESS;
}
if (CURSOR_COLUMN_SIZE(cursor, CONSDEF_COL_INDEX_ID) == OG_NULL_VALUE_LEN) {
index_id = OG_INVALID_ID32;
} else {
index_id = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_INDEX_ID);
}
type = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_TYPE);
OG_RETURN_IFERR(db_check_cons_auto_increment(entity, cursor, type));
if (type == CONS_TYPE_REFERENCE) {
index_id = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_INDEX_ID);
ref_uid = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_REF_USER);
ref_tid = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_REF_TABLE);
ref_ix = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_REF_INDEX);
cons_state.option = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_FLAGS);
if (cons_state.is_cascade) {
OG_RETURN_IFERR(db_update_cons_cascade(session, dc, index_id, ref_uid, ref_tid, ref_ix));
}
OG_RETURN_IFERR(knl_open_dc_by_id(session, ref_uid, ref_tid, &ref_dc, OG_TRUE));
uint32 timeout = session->kernel->attr.ddl_lock_timeout;
if (lock_table_directly(session, &ref_dc, timeout) != OG_SUCCESS) {
dc_close(&ref_dc);
return OG_ERROR;
}
dc_close(&ref_dc);
} else if (db_check_cons_referenced(index_id, entity, &type)) {
return OG_ERROR;
}
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_drop_cascade_cons(knl_session_t *session, uint32 uid, uint32 oid)
{
knl_scan_key_t *l_key = NULL;
knl_cursor_t *cursor = NULL;
uint32 child_uid;
uint32 child_oid;
knl_dictionary_t child_dc;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_CONSDEF_ID, IX_SYS_CONSDEF002_ID);
knl_init_index_scan(cursor, OG_TRUE);
l_key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_CONSDEF002_REF_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_CONSDEF002_REF_TABLE_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
uint32 timeout = session->kernel->attr.ddl_lock_timeout;
while (!cursor->eof) {
child_uid = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_USER);
child_oid = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_TABLE);
if (knl_open_dc_by_id(session, child_uid, child_oid, &child_dc, OG_TRUE) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (lock_table_directly(session, &child_dc, timeout) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
dc_close(&child_dc);
return OG_ERROR;
}
dc_close(&child_dc);
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_drop_all_cons(knl_session_t *session, uint32 uid, uint32 oid, bool32 only_fk)
{
knl_dictionary_t ref_dc;
knl_cursor_t *cursor = NULL;
uint32 ref_uid;
uint32 ref_tid;
uint32 type;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_CONSDEF_ID, IX_SYS_CONSDEF001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_CONSDEF001_TABLE_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
uint32 timeout = session->kernel->attr.ddl_lock_timeout;
while (!cursor->eof) {
type = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_CONSDEF_COL_CONS_TYPE);
if (type == CONS_TYPE_REFERENCE) {
ref_uid = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_REF_USER);
ref_tid = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_REF_TABLE);
if (knl_open_dc_by_id(session, ref_uid, ref_tid, &ref_dc, OG_TRUE) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (lock_table_directly(session, &ref_dc, timeout) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
dc_close(&ref_dc);
return OG_ERROR;
}
dc_close(&ref_dc);
}
if (type == CONS_TYPE_REFERENCE || !only_fk) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
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 db_delete_from_sys_user(knl_session_t *session, uint32 uid)
{
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_USER_ID, IX_SYS_USER_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_USER_001_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, ppanic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_delete_from_sys_tenant(knl_session_t *session, uint32 tid)
{
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_TENANTS_ID, IX_SYS_TENANTS_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &tid, sizeof(uint32),
IX_SYS_TENANTS_001_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!cursor->eof) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_drop_ref_constraints(knl_session_t *session, uint32 uid, uint32 oid)
{
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->row = (row_head_t *)cursor->buf;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_CONSDEF_ID, IX_SYS_CONSDEF002_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_CONSDEF002_REF_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_CONSDEF002_REF_TABLE_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
while (!cursor->eof) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
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;
}
bool32 db_table_is_referenced(knl_session_t *session, table_t *table, bool32 check_state)
{
uint32 i;
index_t *index = NULL;
cons_dep_t *dep = NULL;
if (table->index_set.total_count == 0 || !table->cons_set.referenced) {
return OG_FALSE;
}
for (i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (index->dep_set.count == 0) {
continue;
}
dep = index->dep_set.first;
while (dep != NULL) {
if (check_state && !dep->cons_state.is_enable) {
dep = dep->next;
continue;
}
if (dep->uid != table->desc.uid || dep->oid != table->desc.id) {
return OG_TRUE;
}
dep = dep->next;
}
}
return OG_FALSE;
}
* un-reside all table segments entry page
* @param kernel session, kernel dictionary
*/
void db_unreside_table_segments(knl_session_t *session, knl_dictionary_t *dc)
{
dc_entity_t *entity;
table_t *table;
index_t *index = NULL;
lob_t *lob = NULL;
knl_column_t *column = NULL;
uint32 i;
space_t *space;
table = DC_TABLE(dc);
entity = DC_ENTITY(dc);
space = SPACE_GET(session, table->desc.space_id);
if (SPACE_IS_ONLINE(space)) {
buf_unreside_page(session, table->desc.entry);
}
for (i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
space = SPACE_GET(session, index->desc.space_id);
if (SPACE_IS_ONLINE(space)) {
buf_unreside_page(session, index->desc.entry);
}
}
for (i = 0; i < entity->column_count; i++) {
column = dc_get_column(entity, i);
if (!COLUMN_IS_LOB(column)) {
continue;
}
if (SPACE_IS_ONLINE(space)) {
lob = (lob_t *)column->lob;
buf_unreside_page(session, lob->desc.entry);
}
}
}
bool32 db_table_has_segment(knl_session_t *session, knl_dictionary_t *dc)
{
table_t *table = DC_TABLE(dc);
if (IS_PART_TABLE(table)) {
table_part_t *table_part = NULL;
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
if (table_part->heap.segment != NULL) {
return OG_TRUE;
}
continue;
}
table_part_t *subpart = NULL;
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
subpart = PART_GET_SUBENTITY(table->part_table, table_part->subparts[j]);
if (subpart->heap.segment != NULL) {
return OG_TRUE;
}
}
}
return OG_FALSE;
} else {
return (table->heap.segment != NULL);
}
}
static status_t db_drop_heap_part_segments(knl_session_t *session, dc_entity_t *entity, table_t *table)
{
table_part_t *table_part = NULL;
table_part_t *table_subpart = NULL;
stats_table_mon_t *table_stats = NULL;
for (uint32 id = 0; id < TOTAL_PARTCNT(&table->part_table->desc); ++id) {
table_part = TABLE_GET_PART(table, id);
if (!IS_READY_PART(table_part)) {
continue;
}
if (IS_PARENT_TABPART(&table_part->desc)) {
for (uint32 i = 0; i < table_part->desc.subpart_cnt; i++) {
table_subpart = PART_GET_SUBENTITY(table->part_table, table_part->subparts[i]);
if (table_subpart == NULL) {
continue;
}
if (heap_part_segment_prepare(session, (table_part_t *)table_subpart, OG_INVALID_ID32,
HEAP_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
if (DB_IS_STATS_ENABLED(((knl_session_t *)session)->kernel)) {
table_stats = &entity->entry->appendix->table_smon;
table_stats->is_change = OG_TRUE;
table_stats->drop_segments++;
table_stats->timestamp = cm_now();
}
}
} else {
if (heap_part_segment_prepare(session, table_part, OG_INVALID_ID32, HEAP_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
if (DB_IS_STATS_ENABLED(((knl_session_t *)session)->kernel)) {
table_stats = &entity->entry->appendix->table_smon;
table_stats->is_change = OG_TRUE;
table_stats->drop_segments++;
table_stats->timestamp = cm_now();
}
}
}
return OG_SUCCESS;
}
static status_t db_drop_heap_segments(knl_session_t *session, dc_entity_t *entity, table_t *table)
{
if (heap_segment_prepare(session, table, OG_INVALID_ID32, HEAP_DROP_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
if (table->desc.parted) {
if (db_drop_heap_part_segments(session, entity, table) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_drop_index_part_segments(knl_session_t *session, index_t *index)
{
index_part_t *index_part = NULL;
index_part_t *index_subpart = NULL;
table_part_t *table_part = NULL;
table_t *table = &index->entity->table;
for (uint32 id = 0; id < TOTAL_PARTCNT(&index->part_index->desc); ++id) {
index_part = INDEX_GET_PART(index, id);
table_part = TABLE_GET_PART(table, id);
if (!IS_READY_PART(table_part) || index_part == NULL) {
continue;
}
if (IS_PARENT_IDXPART(&index_part->desc)) {
for (uint32 i = 0; i < index_part->desc.subpart_cnt; i++) {
index_subpart = PART_GET_SUBENTITY(index->part_index, index_part->subparts[i]);
if (index_subpart == NULL) {
continue;
}
if (btree_part_segment_prepare(session, index_subpart, OG_INVALID_ID32,
BTREE_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
} else {
if (btree_part_segment_prepare(session, index_part, OG_INVALID_ID32,
BTREE_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_drop_index_segments(knl_session_t *session, table_t* table)
{
index_t *index = NULL;
for (uint32 i = 0; i < table->index_set.total_count; ++i) {
index = table->index_set.items[i];
if (btree_segment_prepare(session, index, OG_INVALID_ID32, BTREE_DROP_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
if (index->desc.parted) {
if (db_drop_index_part_segments(session, index) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_drop_lob_part_segments(knl_session_t *session, lob_t *lob, table_t *table)
{
lob_part_t *lob_part = NULL;
lob_part_t *lob_subpart = NULL;
table_part_t *table_part = NULL;
for (uint32 id = 0; id < TOTAL_PARTCNT(&table->part_table->desc); ++id) {
lob_part = LOB_GET_PART(lob, id);
table_part = TABLE_GET_PART(table, id);
if (!IS_READY_PART(table_part) || lob_part == NULL) {
continue;
}
if (IS_PARENT_LOBPART(&lob_part->desc)) {
for (uint32 i = 0; i < lob_part->desc.subpart_cnt; i++) {
lob_subpart = PART_GET_SUBENTITY(lob->part_lob, lob_part->subparts[i]);
if (lob_subpart == NULL) {
continue;
}
if (lob_part_segment_prepare(session, (lob_part_t *)lob_subpart, OG_INVALID_ID32,
LOB_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
} else {
if (lob_part_segment_prepare(session, lob_part, OG_INVALID_ID32, LOB_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_drop_lob_segments(knl_session_t *session, dc_entity_t *entity)
{
lob_t *lob = NULL;
knl_column_t *column = NULL;
table_t *table = &entity->table;
for (uint32 i = 0; i < entity->column_count; i++) {
column = dc_get_column(entity, i);
if (!COLUMN_IS_LOB(column)) {
continue;
}
lob = (lob_t *)column->lob;
if (lob_segment_prepare(session, lob, OG_INVALID_ID32, LOB_DROP_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
if (table->desc.parted) {
if (db_drop_lob_part_segments(session, lob, table) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
* drop all table segments
* @param kernel session, kernel dictionary
* @note heap segment should be drop first to support
* table segment detection after crash.
*/
status_t db_drop_table_segments(knl_session_t *session, knl_dictionary_t *dc)
{
table_t *table = DC_TABLE(dc);
dc_entity_t *entity = DC_ENTITY(dc);
dc_load_all_part_segments(session, entity);
if (db_drop_heap_segments(session, entity, table) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_drop_index_segments(session, table) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_drop_lob_segments(session, entity) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
* db_write_sysdep$
*
* This function is used to insert dependencies to dependency$.
*
*/
status_t db_write_sysdep(knl_session_t *session, knl_cursor_t *cursor, object_address_t *depender,
object_address_t *ref_obj, uint32 order)
{
uint32 max_size;
row_assist_t ra;
table_t *table = NULL;
max_size = session->kernel->attr.max_row_size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_DEPENDENCY_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, max_size, table->desc.column_count);
if (row_put_int32(&ra, depender->uid) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int64(&ra, depender->oid) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int32(&ra, depender->tid) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int64(&ra, depender->scn) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int32(&ra, order) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int32(&ra, ref_obj->uid) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int64(&ra, ref_obj->oid) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int32(&ra, ref_obj->tid) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int64(&ra, ref_obj->scn) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_str(&ra, depender->name) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_str(&ra, ref_obj->name) != OG_SUCCESS) {
return OG_ERROR;
}
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
* db_write_sysdep$_list
*
* This function is used to insert dependencies list to dependency$.
*
*/
status_t db_write_sysdep_list(knl_session_t *knl_session, object_address_t *depender, galist_t *referenced_list)
{
object_address_t *ref_obj = NULL;
knl_cursor_t *cursor = NULL;
uint32 i;
uint32 count;
if (referenced_list == NULL || referenced_list->count == 0) {
return OG_SUCCESS;
}
CM_SAVE_STACK(knl_session->stack);
cursor = knl_push_cursor(knl_session);
for (i = 0, count = 0; i < referenced_list->count; i++) {
ref_obj = (object_address_t *)cm_galist_get((galist_t *)referenced_list, i);
if (depender->uid == ref_obj->uid && depender->oid == ref_obj->oid && depender->tid == ref_obj->tid) {
continue;
}
if (OG_SUCCESS != db_write_sysdep(knl_session, cursor, depender, ref_obj, count)) {
CM_RESTORE_STACK(knl_session->stack);
return OG_ERROR;
}
count++;
}
for (i = referenced_list->count; i > 0; i--) {
cm_galist_delete(referenced_list, i - 1);
}
CM_RESTORE_STACK(knl_session->stack);
return OG_SUCCESS;
}
status_t db_update_sysview(knl_session_t *session, knl_cursor_t *cursor, knl_view_t *view, knl_view_def_t *def,
bool32 *is_found)
{
uint32 max_size;
row_assist_t ra;
knl_column_t *lob_column = NULL;
uint16 size;
max_size = session->kernel->attr.max_row_size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_VIEW_ID, IX_SYS_VIEW001_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 *)&view->uid,
sizeof(uint32), IX_COL_SYS_VIEW001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, (void *)def->name.str,
def->name.len, IX_COL_SYS_VIEW001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (cursor->eof) {
*is_found = OG_FALSE;
return OG_SUCCESS;
}
row_init(&ra, cursor->update_info.data, max_size, 7);
cursor->update_info.count = 7;
cursor->update_info.columns[0] = SYS_VIEW_COLS;
cursor->update_info.columns[1] = SYS_VIEW_FLAG;
cursor->update_info.columns[2] = SYS_VIEW_ORG_SCN;
cursor->update_info.columns[3] = SYS_VIEW_CHG_SCN;
cursor->update_info.columns[4] = SYS_VIEW_TEXT_LENGTH;
cursor->update_info.columns[5] = SYS_VIEW_TEXT_COLUMN;
cursor->update_info.columns[6] = SYS_VIEW_SQL_TYPE;
lob_column = knl_get_column(cursor->dc_entity, SYS_VIEW_TEXT_COLUMN);
(void)row_put_int32(&ra, (int32)view->column_count);
(void)row_put_int32(&ra, (int32)view->flags);
(void)row_put_int64(&ra, (int64)view->org_scn);
(void)row_put_int64(&ra, (int64)view->chg_scn);
(void)row_put_int32(&ra, (int32)def->sub_sql.len);
if (knl_row_put_lob(session, cursor, lob_column, &def->sub_sql, &ra) != OG_SUCCESS) {
return OG_ERROR;
}
(void)row_put_int32(&ra, view->sql_type);
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_replace_view(knl_session_t *session, knl_handle_t stmt, knl_view_def_t *def, knl_dictionary_t *dc)
{
knl_column_t column;
knl_column_def_t *column_def = NULL;
knl_comment_def_t comment_def;
knl_cursor_t *cursor = NULL;
knl_view_t view;
uint32 i;
rd_table_t redo;
object_address_t depender;
bool32 is_found = OG_TRUE;
if (DB_NOT_READY(session)) {
OG_THROW_ERROR(ERR_NO_DB_ACTIVE);
return OG_ERROR;
}
if (db_init_view_desc(session, &view, def) != OG_SUCCESS) {
return OG_ERROR;
}
view.id = dc->oid;
view.uid = dc->uid;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (db_update_sysview(session, cursor, &view, def, &is_found) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!is_found) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, T2S(&def->user), T2S_EX(&def->name));
return OG_ERROR;
}
if (OG_SUCCESS != db_delete_viewcolumns(session, cursor, dc->uid, dc->oid)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != db_delete_from_sysdep(session, cursor, dc->uid, (int64)dc->oid, OBJ_TYPE_VIEW)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
comment_def.type = COMMENT_ON_TABLE;
comment_def.uid = dc->uid;
comment_def.id = dc->oid;
if (OG_SUCCESS != db_delete_comment(session, &comment_def)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
column.name = (char *)cm_push(session->stack, OG_NAME_BUFFER_SIZE);
for (i = 0; i < def->columns.count; i++) {
column_def = (knl_column_def_t *)cm_galist_get(&def->columns, i);
db_convert_column_def(&column, dc->uid, dc->oid, column_def, NULL, i);
if (db_write_sysview_column(session, cursor, &column) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
depender.uid = view.uid;
depender.oid = view.id;
depender.tid = OBJ_TYPE_VIEW;
depender.scn = view.chg_scn;
errno_t err = strcpy_sp(depender.name, OG_NAME_BUFFER_SIZE, view.name);
knl_securec_check(err);
if (db_write_sysdep_list(session, &depender, def->ref_objects) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
redo.op_type = RD_ALTER_TABLE;
redo.uid = view.uid;
redo.oid = view.id;
log_put(session, RD_LOGIC_OPERATION, &redo, sizeof(rd_table_t), LOG_ENTRY_FLAG_NONE);
log_add_lrep_ddl_info(session, stmt, LOGIC_OP_VIEW, RD_ALTER_TABLE, NULL);
return OG_SUCCESS;
}
status_t db_create_view(knl_session_t *session, knl_handle_t stmt, knl_view_def_t *def)
{
knl_column_t column;
knl_column_def_t *column_def = NULL;
knl_cursor_t *cursor = NULL;
knl_view_t view;
dc_user_t *user = NULL;
dc_entry_t *entry = NULL;
rd_create_view_t redo;
object_address_t depender;
if (DB_NOT_READY(session)) {
OG_THROW_ERROR(ERR_NO_DB_ACTIVE);
return OG_ERROR;
}
if (db_init_view_desc(session, &view, def) != OG_SUCCESS) {
return OG_ERROR;
}
if (dc_open_user_by_id(session, view.uid, &user) != OG_SUCCESS) {
return OG_ERROR;
}
if (dc_create_view_entry(session, user, &view) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->row = (row_head_t *)cursor->buf;
if (db_write_sysview(session, cursor, &view, def) != OG_SUCCESS) {
dc_free_broken_entry(session, view.uid, view.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
column.name = (char *)cm_push(session->stack, OG_NAME_BUFFER_SIZE);
for (uint32 i = 0; i < def->columns.count; i++) {
column_def = (knl_column_def_t *)cm_galist_get(&def->columns, i);
db_convert_column_def(&column, view.uid, view.id, column_def, NULL, i);
if (db_write_sysview_column(session, cursor, &column) != OG_SUCCESS) {
dc_free_broken_entry(session, view.uid, view.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
depender.uid = view.uid;
depender.oid = view.id;
depender.tid = OBJ_TYPE_VIEW;
depender.scn = view.chg_scn;
errno_t err = strcpy_sp(depender.name, OG_NAME_BUFFER_SIZE, view.name);
knl_securec_check(err);
if (db_write_sysdep_list(session, &depender, def->ref_objects) != OG_SUCCESS) {
dc_free_broken_entry(session, view.uid, view.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
entry = DC_GET_ENTRY(user, view.id);
cm_spin_lock(&entry->lock, &session->stat->spin_stat.stat_dc_entry);
entry->ready = OG_TRUE;
cm_spin_unlock(&entry->lock);
redo.op_type = RD_CREATE_VIEW;
redo.uid = view.uid;
redo.oid = view.id;
err = strcpy_sp(redo.obj_name, OG_NAME_BUFFER_SIZE, view.name);
knl_securec_check(err);
log_put(session, RD_LOGIC_OPERATION, &redo, sizeof(rd_create_view_t), LOG_ENTRY_FLAG_NONE);
log_add_lrep_ddl_info(session, stmt, LOGIC_OP_VIEW, RD_CREATE_VIEW, NULL);
return OG_SUCCESS;
}
status_t db_create_or_replace_view(knl_session_t *session, knl_handle_t stmt, knl_view_def_t *def)
{
knl_dictionary_t dc;
bool32 is_found = OG_FALSE;
if (knl_open_dc_if_exists(session, &def->user, &def->name, &dc, &is_found) != OG_SUCCESS) {
return OG_ERROR;
}
if (!is_found) {
return db_create_view(session, stmt, def);
}
if (SYNONYM_EXIST(&dc) || dc.type != DICT_TYPE_VIEW) {
dc_close(&dc);
OG_THROW_ERROR(ERR_DUPLICATE_TABLE, T2S(&def->user), T2S_EX(&def->name));
return OG_ERROR;
}
if (db_replace_view(session, stmt, def, &dc) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
knl_commit(session);
dc_invalidate(session, (dc_entity_t *)dc.handle);
dc_close(&dc);
return OG_SUCCESS;
}
status_t db_check_policies_before_delete(knl_session_t *session, const char *table_name, uint32 uid)
{
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_POLICY_ID, IX_SYS_POLICY_001_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 *)&uid, sizeof(uint32), IX_COL_SYS_POLICY_001_OBJ_SCHEMA_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER,
(void *)&uid, sizeof(uint32), IX_COL_SYS_POLICY_001_OBJ_SCHEMA_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)table_name, (uint16)strlen(table_name), IX_COL_SYS_POLICY_001_OBJ_NAME);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_STRING,
(void *)table_name, (uint16)strlen(table_name), IX_COL_SYS_POLICY_001_OBJ_NAME);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_POLICY_001_PNAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_POLICY_001_PNAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof == OG_FALSE) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", the table has policy, please drop policy firstly.");
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
* Description : fetch row of column according to user name and column name
* Input : cursor : cursor->action should set by caller, either delete or select
* Input : user : user name of table owner
* Input : index_name : name of index
* Input : dc : dictionary of table
* Output : NA
* Return Value : status_t
* History : 1. 2017/4/26, add description
*/
static status_t db_fetch_syscolumn_row(knl_session_t *session, knl_cursor_t *cursor, uint16 col_id,
uint32 uid, uint32 oid, knl_cursor_action_t action)
{
knl_scan_key_t *key = NULL;
uint32 id;
knl_open_sys_cursor(session, cursor, action, SYS_COLUMN_ID, IX_SYS_COLUMN_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
key = &cursor->scan_range.l_key;
id = (uint32)col_id;
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_COLUMN_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &oid, sizeof(uint32),
IX_COL_SYS_COLUMN_001_TABLE_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &id, sizeof(uint32), IX_COL_SYS_COLUMN_001_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
return OG_SUCCESS;
}
static status_t db_update_icol_from_syscolumn(knl_session_t *session, knl_cursor_t *cursor, dc_entity_t *entity,
knl_index_desc_t *idesc)
{
uint32 i;
uint32 col_id;
for (i = 0; i < idesc->column_count; i++) {
col_id = idesc->columns[i];
if (col_id < DC_VIRTUAL_COL_START) {
continue;
}
if (db_fetch_syscolumn_row(session, cursor, col_id,
idesc->uid, idesc->table_id, CURSOR_ACTION_UPDATE) != OG_SUCCESS) {
return OG_ERROR;
}
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_drop_external_table(knl_session_t *session, knl_cursor_t *cursor, table_t *table)
{
knl_table_desc_t *desc = &table->desc;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_EXTERNAL_ID, IX_EXTERNALTABS_001_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(uint32), IX_COL_EXTERNALTABS_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&desc->id,
sizeof(uint32), IX_COL_EXTERNALTABS_001_TABLE_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, desc->name,
((index_t *)cursor->index)->desc.name);
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_drop_view(knl_session_t *session, knl_handle_t stmt, knl_dictionary_t *dc)
{
knl_cursor_t *cursor = NULL;
knl_view_t *view;
dc_entity_t *entity;
knl_comment_def_t comment_def;
rd_view_t redo;
errno_t err;
obj_info_t obj_addr;
entity = DC_ENTITY(dc);
view = &entity->view;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->row = (row_head_t *)cursor->buf;
if (OG_SUCCESS != db_delete_from_sysview(session, cursor, view->uid, view->name)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != db_delete_viewcolumns(session, cursor, view->uid, view->id)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != db_delete_from_sysdep(session, cursor, view->uid, view->id, OBJ_TYPE_VIEW)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
comment_def.type = COMMENT_ON_TABLE;
comment_def.uid = view->uid;
comment_def.id = view->id;
if (OG_SUCCESS != db_delete_comment(session, &comment_def)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
obj_addr.oid = dc->oid;
obj_addr.uid = dc->uid;
obj_addr.tid = OBJ_TYPE_VIEW;
if (g_knl_callback.update_depender(session, &obj_addr) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (g_knl_callback.pl_db_drop_triggers(session, (void *)dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_drop_object_privs(session, view->uid, view->name, OBJ_TYPE_VIEW)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
redo.op_type = RD_DROP_VIEW;
redo.uid = view->uid;
redo.oid = view->id;
err = strcpy_sp(redo.obj_name, OG_NAME_BUFFER_SIZE, view->name);
knl_securec_check(err);
log_put(session, RD_LOGIC_OPERATION, &redo, sizeof(rd_view_t), LOG_ENTRY_FLAG_NONE);
log_add_lrep_ddl_info(session, stmt, LOGIC_OP_VIEW, RD_DROP_VIEW, NULL);
knl_commit(session);
g_knl_callback.pl_drop_triggers_entry(session, dc);
dc_drop_object_privs(&session->kernel->dc_ctx, view->uid, view->name, OBJ_TYPE_VIEW);
dc_drop(session, DC_ENTITY(dc));
dc_free_entry(session, DC_ENTRY(dc));
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
void print_drop_view(log_entry_t *log)
{
rd_view_t *rd = (rd_view_t *)log->data;
printf("drop view uid:%u,obj:%s\n", rd->uid, rd->obj_name);
}
static void db_fetch_view_by_uid(knl_session_t *session, uint32 uid, char *buf, uint32 size, bool32 *found)
{
knl_cursor_t *cursor = NULL;
char *viewname = NULL;
uint32 len;
errno_t err;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_VIEW_ID, IX_SYS_VIEW001_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 *)&uid,
sizeof(uint32), IX_COL_SYS_VIEW001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, (void *)&uid,
sizeof(uint32), IX_COL_SYS_VIEW001_USER);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_VIEW001_NAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_VIEW001_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
*found = OG_FALSE;
return;
}
if (!cursor->eof) {
viewname = CURSOR_COLUMN_DATA(cursor, SYS_VIEW_NAME);
len = CURSOR_COLUMN_SIZE(cursor, SYS_VIEW_NAME);
err = memcpy_sp(buf, size - 1, viewname, len);
knl_securec_check(err);
buf[len] = '\0';
*found = OG_TRUE;
} else {
*found = OG_FALSE;
}
CM_RESTORE_STACK(session->stack);
return;
}
status_t db_drop_view_by_user(knl_session_t *session, text_t *username, uint32 uid)
{
bool32 found = OG_FALSE;
char viewname[OG_NAME_BUFFER_SIZE];
knl_drop_def_t def;
db_fetch_view_by_uid(session, uid, viewname, OG_NAME_BUFFER_SIZE, &found);
while (found) {
cm_str2text_safe(viewname, (uint32)strlen(viewname), &def.name);
def.owner.str = username->str;
def.owner.len = username->len;
def.purge = 0;
def.options = 0;
(void)knl_drop_view(session, NULL, &def);
knl_set_session_scn(session, OG_INVALID_ID64);
db_fetch_view_by_uid(session, uid, viewname, OG_NAME_BUFFER_SIZE, &found);
}
return OG_SUCCESS;
}
static status_t part_truncate_lob_prepare(knl_session_t *session, lob_t *lob, lob_part_t *lob_part, bool32 reuse)
{
if (!IS_PARENT_LOBPART(&lob_part->desc)) {
if (lob_part_segment_prepare(session, lob_part, reuse, LOB_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
lob_part_t *lob_subpart = NULL;
for (uint32 i = 0; i < lob_part->desc.subpart_cnt; i++) {
for (uint32 j = 0; j < lob_part->desc.subpart_cnt; j++) {
lob_subpart = PART_GET_SUBENTITY(lob->part_lob, lob_part->subparts[j]);
if (lob_subpart == NULL) {
continue;
}
if (lob_part_segment_prepare(session, (lob_part_t *)lob_subpart, reuse,
LOB_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_truncate_lobs_prepare(knl_session_t *session, knl_dictionary_t *dc, bool32 reuse)
{
knl_column_t *column = NULL;
lob_t *lob = NULL;
lob_part_t *lob_part = NULL;
table_part_t *table_part = NULL;
dc_entity_t *entity = DC_ENTITY(dc);
table_t *table = DC_TABLE(dc);
for (uint32 i = 0; i < entity->column_count; i++) {
column = dc_get_column(entity, i);
if (!COLUMN_IS_LOB(column)) {
continue;
}
lob = (lob_t *)column->lob;
if (table->desc.parted) {
for (uint32 id = 0; id < table->part_table->desc.partcnt; id++) {
table_part = TABLE_GET_PART(table, id);
lob_part = LOB_GET_PART(lob, id);
if (!IS_READY_PART(table_part) || lob_part == NULL) {
continue;
}
if (part_truncate_lob_prepare(session, lob, lob_part, reuse) != OG_SUCCESS) {
return OG_ERROR;
}
}
} else {
if (lob_segment_prepare(session, lob, reuse, LOB_TRUNCATE_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_truncate_index_prepare(knl_session_t *session, table_t *table, index_t *index,
bool32 reuse_storage, bool32 *is_changed)
{
if (IS_PART_INDEX(index)) {
index_part_t *index_part = NULL;
table_part_t *table_part = NULL;
for (uint32 id = 0; id < index->part_index->desc.partcnt; id++) {
index_part = INDEX_GET_PART(index, id);
table_part = TABLE_GET_PART(table, id);
if (!IS_READY_PART(table_part) || index_part == NULL) {
continue;
}
if (!IS_PARENT_IDXPART(&index_part->desc)) {
if (db_update_idxpart_status(session, index_part, OG_FALSE, is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
if (btree_part_segment_prepare(session, index_part, reuse_storage,
BTREE_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
continue;
}
index_part_t *index_subpart = NULL;
for (uint32 i = 0; i < index_part->desc.subpart_cnt; i++) {
index_subpart = PART_GET_SUBENTITY(index->part_index, index_part->subparts[i]);
if (index_subpart == NULL) {
continue;
}
if (db_update_sub_idxpart_status(session, index_subpart, OG_FALSE, is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
if (btree_part_segment_prepare(session, (index_part_t *)index_subpart, reuse_storage,
BTREE_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
} else {
if (db_update_index_status(session, index, OG_FALSE, is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (btree_segment_prepare(session, index, reuse_storage, BTREE_TRUNCATE_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_truncate_part_table_prepare(knl_session_t *session, table_t *table, bool32 reuse)
{
table_part_t *table_part = NULL;
table_part_t *table_subpart = NULL;
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
if (heap_part_segment_prepare(session, table_part, reuse, HEAP_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
continue;
}
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
table_subpart = PART_GET_SUBENTITY(table->part_table, table_part->subparts[j]);
if (table_subpart == NULL) {
continue;
}
if (heap_part_segment_prepare(session, table_subpart, reuse, HEAP_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static void db_truncate_lobs(knl_session_t *session, knl_dictionary_t *dc, bool32 reuse)
{
knl_column_t *column = NULL;
lob_t *lob = NULL;
lob_part_t *lob_part = NULL;
table_part_t *table_part = NULL;
dc_entity_t *entity = DC_ENTITY(dc);
table_t *table = DC_TABLE(dc);
for (uint32 i = 0; i < entity->column_count; i++) {
column = dc_get_column(entity, i);
if (!COLUMN_IS_LOB(column)) {
continue;
}
lob = (lob_t *)column->lob;
if (table->desc.parted) {
for (uint32 id = 0; id < table->part_table->desc.partcnt; id++) {
table_part = TABLE_GET_PART(table, id);
lob_part = LOB_GET_PART(lob, id);
if (!IS_READY_PART(table_part) || lob_part == NULL) {
continue;
}
lob_truncate_part_segment(session, &lob_part->desc, reuse);
}
} else {
lob_truncate_segment(session, &lob->desc, reuse);
}
}
}
static void db_truncate_part_table(knl_session_t *session, table_t *table, bool32 reuse)
{
table_part_t *table_part = NULL;
table_part_t *table_subpart = NULL;
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
heap_truncate_part_segment(session, &table_part->desc, reuse);
continue;
}
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
table_subpart = PART_GET_SUBENTITY(table->part_table, table_part->subparts[j]);
if (table_subpart == NULL) {
continue;
}
heap_truncate_part_segment(session, &table_subpart->desc, reuse);
}
}
}
static void db_truncate_index(knl_session_t *session, table_t *table, index_t *index, bool32 reuse_storage)
{
if (IS_PART_INDEX(index)) {
index_part_t *index_part = NULL;
table_part_t *table_part = NULL;
for (uint32 id = 0; id < index->part_index->desc.partcnt; id++) {
index_part = INDEX_GET_PART(index, id);
table_part = TABLE_GET_PART(table, id);
if (!IS_READY_PART(table_part) || index_part == NULL) {
continue;
}
if (!IS_PARENT_IDXPART(&index_part->desc)) {
btree_truncate_part_segment(session, &index_part->desc, reuse_storage);
continue;
}
index_part_t *index_subpart = NULL;
for (uint32 i = 0; i < index_part->desc.subpart_cnt; i++) {
index_subpart = PART_GET_SUBENTITY(index->part_index, index_part->subparts[i]);
if (index_subpart == NULL) {
continue;
}
btree_truncate_part_segment(session, &index_subpart->desc, reuse_storage);
}
}
}
btree_truncate_segment(session, &index->desc, reuse_storage);
}
* force truncate table when garbage segment handle failed.
* If db has been killed, the records are still stored in garbage segment,
* reopen db the rest segments can be truncated.
*/
void db_force_truncate_table(knl_session_t *session, knl_dictionary_t *dc,
bool32 reuse_storage, bool32 is_not_recyclebin)
{
if (!is_not_recyclebin) {
return;
}
index_t *index = NULL;
table_t *table = DC_TABLE(dc);
dc_entity_t *entity = DC_ENTITY(dc);
if (entity->contain_lob) {
db_truncate_lobs(session, dc, reuse_storage);
}
for (uint32 i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
db_truncate_index(session, table, index, reuse_storage);
}
if (IS_PART_TABLE(table)) {
db_truncate_part_table(session, table, reuse_storage);
}
heap_truncate_segment(session, &table->desc, reuse_storage);
}
status_t db_truncate_table_prepare(knl_session_t *session, knl_dictionary_t *dc, bool32 reuse_storage,
bool32 *is_changed)
{
index_t *index = NULL;
knl_temp_cache_t *temp_table = NULL;
table_t *table = DC_TABLE(dc);
dc_entity_t *entity = DC_ENTITY(dc);
if (entity->contain_lob) {
if (db_truncate_lobs_prepare(session, dc, reuse_storage) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (table->desc.type == TABLE_TYPE_TRANS_TEMP || table->desc.type == TABLE_TYPE_SESSION_TEMP) {
cm_spin_lock(&session->temp_cache_lock, NULL);
temp_table = knl_get_temp_cache(session, dc->uid, dc->oid);
if (temp_table != NULL) {
knl_panic_log(temp_table->org_scn == table->desc.org_scn, "the temp_table's org_scn is not equal to "
"table's org_scn, panic info: table: %s temp_table org_scn %llu table org_scn %llu",
table->desc.name, temp_table->org_scn, table->desc.org_scn);
knl_free_temp_vm(session, temp_table);
}
cm_spin_unlock(&session->temp_cache_lock);
} else {
for (uint32 i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (db_truncate_index_prepare(session, table, index, reuse_storage, is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (IS_PART_TABLE(table)) {
if (db_truncate_part_table_prepare(session, table, reuse_storage) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (heap_segment_prepare(session, table, reuse_storage, HEAP_TRUNCATE_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_update_index_count(knl_session_t *session, knl_cursor_t *cursor, knl_table_desc_t *desc, bool32 is_add)
{
knl_table_desc_t desc_convert;
knl_scan_key_t *l_key = NULL;
uint32 index_count;
uint16 size;
row_assist_t ra;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_001_ID);
l_key = &cursor->scan_range.l_key;
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &desc->uid, sizeof(uint32),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_STRING, &desc->name, (uint16)strlen(desc->name),
IX_COL_SYS_TABLE_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, desc->name,
((index_t *)cursor->index)->desc.name);
dc_convert_table_desc(cursor, &desc_convert);
knl_panic_log(cm_str_equal_ins(desc->name, desc_convert.name), "the name record on desc and desc_convert are not "
"same, panic info: page %u-%u type %u table %s index %s desc name %s desc_convert name %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, desc->name,
((index_t *)cursor->index)->desc.name, desc->name, desc_convert.name);
index_count = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_TABLE_COL_INDEXES) + (is_add ? 1 : (-1));
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 2);
cursor->update_info.count = 2;
cursor->update_info.columns[0] = SYS_TABLE_COL_CHG_SCN;
cursor->update_info.columns[1] = SYS_TABLE_COL_INDEXES;
(void)row_put_int64(&ra, db_inc_scn(session));
(void)row_put_int32(&ra, index_count);
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_update(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_update_table_trig_flag(knl_session_t *session, knl_table_desc_t *desc, bool32 has_trig)
{
knl_table_desc_t desc_convert;
knl_scan_key_t *l_key = NULL;
uint32 column_size;
uint16 size;
row_assist_t ra;
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_001_ID);
l_key = &cursor->scan_range.l_key;
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_INTEGER, &desc->uid, sizeof(uint32),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), l_key, OG_TYPE_STRING, &desc->name, (uint16)strlen(desc->name),
IX_COL_SYS_TABLE_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "table", desc->name);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
column_size = CURSOR_COLUMN_SIZE(cursor, SYS_TABLE_COL_FLAG);
if (column_size == OG_NULL_VALUE_LEN) {
desc_convert.flags = 0;
} else {
desc_convert.flags = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_TABLE_COL_FLAG);
}
desc_convert.has_trig = has_trig;
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 2);
cursor->update_info.count = 2;
cursor->update_info.columns[0] = SYS_TABLE_COL_CHG_SCN;
cursor->update_info.columns[1] = SYS_TABLE_COL_FLAG;
(void)row_put_int64(&ra, db_inc_scn(session));
(void)row_put_int32(&ra, desc_convert.flags);
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
* Description : fetch row of index$ according to user name and index_name
* Input : cursor : cursor->action should set by caller, either delete or select
* Input : user : user name of table owner
* Input : index_name : name of index
* Input : dc : dictionary of table
* Output : NA
* Return Value : status_t
* History : 1. 2017/4/26, add description
*/
status_t db_fetch_sysindex_row(knl_session_t *session, knl_cursor_t *cursor, uint32 uid,
text_t *index_name, knl_cursor_action_t action, bool32 *is_found)
{
knl_scan_key_t *lkey = &cursor->scan_range.l_key;
*is_found = OG_TRUE;
knl_open_sys_cursor(session, cursor, action, SYS_INDEX_ID, IX_SYS_INDEX_002_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), lkey, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_INDEX_002_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), lkey, OG_TYPE_STRING, index_name->str, index_name->len,
IX_COL_SYS_INDEX_002_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
if (cursor->eof) {
*is_found = OG_FALSE;
}
return OG_SUCCESS;
}
status_t db_fetch_shadow_index_row(knl_session_t *session, knl_handle_t dc_entity, knl_cursor_t *cursor)
{
dc_entity_t *entity = (dc_entity_t *)dc_entity;
knl_table_desc_t *desc = &entity->table.desc;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_SHADOW_INDEX_ID, IX_SYS_SHADOW_INDEX_001_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(uint32), IX_COL_SYS_SHADOW_INDEX_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &desc->id, sizeof(uint32),
IX_COL_SYS_SHADOW_INDEX_001_TABLE_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_fetch_shadow_indexpart_row(knl_session_t *session, knl_handle_t dc_entity, knl_cursor_t *cursor)
{
dc_entity_t *entity = (dc_entity_t *)dc_entity;
knl_table_desc_t *desc = &entity->table.desc;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_SHADOW_INDEXPART_ID, IX_SYS_SHW_INDEXPART001_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &desc->uid,
sizeof(uint32), IX_COL_SYS_SHW_INDEXPART001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &desc->id,
sizeof(uint32), IX_COL_SYS_SHW_INDEXPART001_TABLE_ID);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_SHW_INDEXPART001_INDEX_ID);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_SHW_INDEXPART001_PART_ID);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_SHW_INDEXPART001_PARENTPART_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &desc->uid,
sizeof(uint32), IX_COL_SYS_SHW_INDEXPART001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &desc->id,
sizeof(uint32), IX_COL_SYS_SHW_INDEXPART001_TABLE_ID);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_SHW_INDEXPART001_INDEX_ID);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_SHW_INDEXPART001_PART_ID);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_SHW_INDEXPART001_PARENTPART_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_create_btree_segment(knl_session_t *session, index_t *index, index_part_t *index_part,
btree_t *btree, bool32 need_redo)
{
if (IS_PART_INDEX(index)) {
if (btree_create_part_segment(session, index_part) != OG_SUCCESS) {
return OG_ERROR;
}
if (IS_SUB_IDXPART(&index_part->desc)) {
if (db_upd_sub_idx_part_entry(session, &index_part->desc, index_part->desc.entry) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (db_upd_idx_part_entry(session, &index_part->desc, index_part->desc.entry) != OG_SUCCESS) {
return OG_ERROR;
}
}
buf_enter_page(session, index_part->desc.entry, LATCH_MODE_S, ENTER_PAGE_RESIDENT);
btree->segment = BTREE_GET_SEGMENT(session);
btree->buf_ctrl = session->curr_page_ctrl;
bt_put_change_stats(btree);
buf_leave_page(session, OG_FALSE);
if (btree_generate_create_undo(session, index_part->desc.entry, index_part->desc.space_id,
need_redo) != OG_SUCCESS) {
btree_drop_part_segment(session, index_part);
return OG_ERROR;
}
} else {
if (btree_create_segment(session, index) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_index_entry(session, &index->desc, index->desc.entry) != OG_SUCCESS) {
return OG_ERROR;
}
buf_enter_page(session, index->desc.entry, LATCH_MODE_S, ENTER_PAGE_RESIDENT);
btree->segment = BTREE_GET_SEGMENT(session);
btree->buf_ctrl = session->curr_page_ctrl;
bt_put_change_stats(btree);
buf_leave_page(session, OG_FALSE);
if (btree_generate_create_undo(session, index->desc.entry, index->desc.space_id,
need_redo) != OG_SUCCESS) {
btree_drop_segment(session, index);
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_prepare_fill_index(knl_session_t *session, knl_cursor_t *cursor, index_t *index,
btree_mt_context_t *ogx, mtrl_sort_ctrl_t *sort_ctrl)
{
btree_t *btree = NULL;
index_part_t *index_part = NULL;
if (IS_PART_INDEX(index)) {
index_part = INDEX_GET_PART(index, cursor->part_loc.part_no);
if (IS_PARENT_IDXPART(&index_part->desc)) {
index_part = PART_GET_SUBENTITY(index->part_index, index_part->subparts[cursor->part_loc.subpart_no]);
}
btree = &index_part->btree;
} else {
btree = &index->btree;
}
if (btree->segment == NULL) {
if (db_create_btree_segment(session, index, index_part,
btree, IS_LOGGING_TABLE_BY_TYPE(cursor->dc_type)) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (!ogx->initialized) {
if (btree_constructor_init(session, ogx, btree) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (!sort_ctrl->initialized) {
if (mtrl_sort_init(session, index, cursor->part_loc, sort_ctrl) != OG_SUCCESS) {
return OG_ERROR;
}
if (sort_ctrl->use_parallel) {
mtrl_set_sort_type(ogx->mtrl_ctx.segments[ogx->seg_id], MTRL_SORT_TYPE_QSORT);
}
}
return OG_SUCCESS;
}
static status_t db_construct_index(btree_mt_context_t *ogx, mtrl_sort_ctrl_t *sort_ctrl)
{
if (mtrl_sort_clean(sort_ctrl) != OG_SUCCESS) {
return OG_ERROR;
}
mtrl_close_segment(&ogx->mtrl_ctx, ogx->seg_id);
if (ogx->mtrl_ctx.segments[ogx->seg_id]->vm_list.count < MIN_MTRL_SORT_EXTENTS) {
sort_ctrl->use_parallel = OG_FALSE;
}
if (sort_ctrl->use_parallel) {
if (mtrl_sort_segment_parallel(sort_ctrl, &ogx->mtrl_ctx, ogx->seg_id) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (mtrl_sort_segment(&ogx->mtrl_ctx, ogx->seg_id) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (idx_construct(ogx) != OG_SUCCESS) {
return OG_ERROR;
}
ogx->initialized = OG_FALSE;
return OG_SUCCESS;
}
status_t db_fill_index_entity(knl_session_t *session, knl_cursor_t *cursor, index_t *index,
btree_mt_context_t *ogx, mtrl_sort_ctrl_t *sort_ctrl)
{
mtrl_rowid_t rid;
char *key = NULL;
* set cursor isolation level to current committed, so even if txn of delay
* committed row in heap page is overwritten, there will no "snapshot too old" error.
*/
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
if (knl_fetch(session, cursor) != OG_SUCCESS) {
(void)mtrl_sort_clean(sort_ctrl);
mtrl_release_context(&ogx->mtrl_ctx);
return OG_ERROR;
}
if (cursor->eof) {
return OG_SUCCESS;
}
if (db_prepare_fill_index(session, cursor, index, ogx, sort_ctrl) != OG_SUCCESS) {
(void)mtrl_sort_clean(sort_ctrl);
mtrl_release_context(&ogx->mtrl_ctx);
return OG_ERROR;
}
key = (char *)cm_push(session->stack, OG_KEY_BUF_SIZE);
do {
if (session->canceled) {
(void)mtrl_sort_clean(sort_ctrl);
mtrl_release_context(&ogx->mtrl_ctx);
cm_pop(session->stack);
OG_THROW_ERROR(ERR_OPERATION_CANCELED);
return OG_ERROR;
}
if (session->killed) {
(void)mtrl_sort_clean(sort_ctrl);
mtrl_release_context(&ogx->mtrl_ctx);
cm_pop(session->stack);
OG_THROW_ERROR(ERR_OPERATION_KILLED);
return OG_ERROR;
}
if (knl_make_key(session, cursor, index, key) != OG_SUCCESS) {
(void)mtrl_sort_clean(sort_ctrl);
mtrl_release_context(&ogx->mtrl_ctx);
cm_pop(session->stack);
return OG_ERROR;
}
if (index->desc.cr_mode == CR_ROW) {
((btree_key_t *)key)->scn = cursor->scn;
} else {
((pcrb_key_t *)key)->itl_id = OG_INVALID_ID8;
}
if (sort_ctrl->use_parallel) {
if (OG_SUCCESS != mtrl_insert_row_parallel(&ogx->mtrl_ctx, 0, key, sort_ctrl, &rid)) {
(void)mtrl_sort_clean(sort_ctrl);
mtrl_release_context(&ogx->mtrl_ctx);
cm_pop(session->stack);
return OG_ERROR;
}
} else {
if (OG_SUCCESS != mtrl_insert_row(&ogx->mtrl_ctx, 0, key, &rid)) {
mtrl_release_context(&ogx->mtrl_ctx);
cm_pop(session->stack);
return OG_ERROR;
}
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
(void)mtrl_sort_clean(sort_ctrl);
mtrl_release_context(&ogx->mtrl_ctx);
cm_pop(session->stack);
return OG_ERROR;
}
} while (!cursor->eof);
cm_pop(session->stack);
if (IS_PART_INDEX(index)) {
if (db_construct_index(ogx, sort_ctrl) != OG_SUCCESS) {
mtrl_release_context(&ogx->mtrl_ctx);
return OG_ERROR;
}
mtrl_release_context(&ogx->mtrl_ctx);
}
return OG_SUCCESS;
}
static status_t db_fill_part_index(knl_session_t *session, knl_cursor_t *cursor, knl_dictionary_t *dc, index_t *index,
btree_mt_context_t *ogx, mtrl_sort_ctrl_t *sort_ctrl)
{
part_table_t *part_table = ((table_t *)cursor->table)->part_table;
table_part_t *compart = NULL;
table_part_t *subpart = NULL;
for (uint32 i = 0; i < part_table->desc.partcnt; i++) {
compart = TABLE_GET_PART(cursor->table, i);
if (!IS_READY_PART(compart)) {
continue;
}
cursor->part_loc.part_no = i;
if (IS_PARENT_TABPART(&compart->desc)) {
for (uint32 j = 0; j < compart->desc.subpart_cnt; j++) {
subpart = PART_GET_SUBENTITY(part_table, compart->subparts[j]);
if (subpart == NULL) {
continue;
}
cursor->part_loc.subpart_no = j;
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
mtrl_release_context(&ogx->mtrl_ctx);
return OG_ERROR;
}
if (db_fill_index_entity(session, cursor, index, ogx, sort_ctrl) != OG_SUCCESS) {
return OG_ERROR;
}
}
} else {
cursor->part_loc.subpart_no = OG_INVALID_ID32;
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
mtrl_release_context(&ogx->mtrl_ctx);
return OG_ERROR;
}
if (db_fill_index_entity(session, cursor, index, ogx, sort_ctrl) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static inline void db_reset_mtr_ctx(mtrl_context_t *ogx)
{
if (ogx->session != NULL) {
knl_session_t *ogx_se = (knl_session_t *)ogx->session;
ogx_se->thread_shared = OG_FALSE;
}
}
static status_t db_create_all_btree_segments(knl_session_t *session, table_t *table, index_t *index, uint32 *seg_cnt)
{
bool32 need_redo = !IS_NOLOGGING_BY_TABLE_TYPE(table->desc.type);
index_part_t *index_part = NULL;
table_part_t *table_part = NULL;
index_part_t *index_sub_part = NULL;
table_part_t *table_sub_part = NULL;
uint32 seg_count = 0;
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(table, i);
index_part = INDEX_GET_PART(index, i);
if (!IS_READY_PART(table_part) || index_part == NULL) {
continue;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
if (table_part->heap.segment == NULL) {
continue;
}
if (db_create_btree_segment(session, index, index_part, &index_part->btree, need_redo) != OG_SUCCESS) {
return OG_ERROR;
}
seg_count++;
}
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
table_sub_part = PART_GET_SUBENTITY(table->part_table, table_part->subparts[j]);
index_sub_part = PART_GET_SUBENTITY(index->part_index, index_part->subparts[j]);
if (table_sub_part == NULL || index_sub_part == NULL || table_sub_part->heap.segment == NULL) {
continue;
}
if (db_create_btree_segment(session, index, index_sub_part,
&index_sub_part->btree, need_redo) != OG_SUCCESS) {
return OG_ERROR;
}
seg_count++;
}
}
*seg_cnt = seg_count;
return OG_SUCCESS;
}
#define OPTIMAL_PARAL_FETCH_COUNT 4
#define MIN_PARAL_FETCH_COUNT 2
#define OPTIMAL_PARAL_PART_COUNT 10
#define OPTIMAL_CPU_COUNT 64
#define OPTIMAL_PART_COUNT 64
static void db_prepare_part_ctx(knl_session_t *session, uint32 *paral_no, idxpart_paral_ctx_t *paral_ctx)
{
uint32 cpu_count = session->kernel->attr.cpu_count;
uint32 seg_count = paral_ctx->part_info.seg_count;
uint32 temp_paral_no = *paral_no;
temp_paral_no = seg_count < temp_paral_no ? seg_count : temp_paral_no;
if (cpu_count <= OPTIMAL_CPU_COUNT) {
paral_ctx->paral_count = seg_count < *paral_no ? OPTIMAL_PARAL_FETCH_COUNT : MIN_PARAL_FETCH_COUNT;
*paral_no = temp_paral_no;
return;
}
* if cpu count is enough, part count is huge, the parallelism give priority to part_parallel;
* if there is few part count with large paral_no,
* we suppose each partition is huge and give priority to fetch_parallel;
*/
if (seg_count > OPTIMAL_PART_COUNT) {
if (*paral_no < OPTIMAL_PARAL_PART_COUNT) {
paral_ctx->paral_count = MIN_PARAL_FETCH_COUNT;
} else {
paral_ctx->paral_count = MAX((cpu_count - temp_paral_no) / temp_paral_no, OPTIMAL_PARAL_FETCH_COUNT);
}
} else {
if (*paral_no < OPTIMAL_PARAL_PART_COUNT) {
paral_ctx->paral_count = MIN((cpu_count - temp_paral_no) / temp_paral_no, OPTIMAL_PARAL_FETCH_COUNT);
} else {
paral_ctx->paral_count = MIN((cpu_count - temp_paral_no) / temp_paral_no, *paral_no);
}
}
temp_paral_no = MIN(MAX_IDX_PARAL_THREADS, temp_paral_no);
paral_ctx->paral_count = paral_ctx->paral_count < MIN_PARAL_FETCH_COUNT ? MIN_PARAL_FETCH_COUNT :
MIN(MAX_IDX_PARAL_THREADS, paral_ctx->paral_count);
*paral_no = temp_paral_no;
}
status_t db_fill_part_index_paral(knl_session_t *session, knl_dictionary_t *dc, index_t *index, knl_index_def_t *def)
{
uint32 segment_cnt = 0;
table_t *table = DC_TABLE(dc);
idxpart_paral_ctx_t paral_ctx;
errno_t err = memset_sp(¶l_ctx, sizeof(idxpart_paral_ctx_t), 0, sizeof(idxpart_paral_ctx_t));
knl_securec_check(err);
if (db_create_all_btree_segments(session, table, index, &segment_cnt) != OG_SUCCESS) {
return OG_ERROR;
}
if (segment_cnt == 0) {
return OG_SUCCESS;
}
paral_ctx.private_dc = dc;
paral_ctx.indexes = &index;
paral_ctx.index_cnt = 1;
paral_ctx.nologging = def->nologging;
paral_ctx.part_info.seg_count = segment_cnt;
uint32 paral_no = def->parallelism;
db_prepare_part_ctx(session, ¶l_no, ¶l_ctx);
if (idxpart_alloc_resource(session, paral_no, ¶l_ctx) != OG_SUCCESS) {
idxpart_release_resource(paral_no, ¶l_ctx);
return OG_ERROR;
}
uint32 i;
uint32 count;
for (;;) {
count = paral_no;
for (i = 0; i < paral_no; i++) {
if (!paral_ctx.workers[i].is_working) {
count--;
}
if (paral_ctx.workers[i].thread.result != OG_SUCCESS) {
OG_THROW_ERROR(ERR_BUILD_INDEX_PARALLEL, paral_ctx.err_msg);
idxpart_release_resource(paral_no, ¶l_ctx);
return OG_ERROR;
}
}
if (count == 0) {
break;
}
if (knl_check_session_status(session) != OG_SUCCESS) {
idxpart_release_resource(paral_no, ¶l_ctx);
return OG_ERROR;
}
cm_sleep(100);
}
idxpart_release_resource(paral_no, ¶l_ctx);
return OG_SUCCESS;
}
static void db_init_paral_ctx(idx_paral_sort_ctx_t *paral_ctx, knl_dictionary_t *dc, index_t *index,
knl_part_locate_t part_loc)
{
table_t *table = DC_TABLE(dc);
paral_ctx->private_dc = dc;
paral_ctx->part_info.curr_part = part_loc;
paral_ctx->btree[0] = &index->btree;
paral_ctx->index_count = 1;
if (IS_PART_INDEX(index)) {
index_part_t *index_part = INDEX_GET_PART(index, part_loc.part_no);
if (IS_PARENT_IDXPART(&index_part->desc)) {
index_part = PART_GET_SUBENTITY(index->part_index, index_part->subparts[part_loc.subpart_no]);
}
paral_ctx->btree[0] = &index_part->btree;
} else if (IS_PART_TABLE(table)) {
paral_ctx->is_global = OG_TRUE;
}
}
static status_t db_prepare_paral_ctx(knl_session_t *session, knl_dictionary_t *dc,
index_t *index, knl_part_locate_t part_loc, idx_paral_sort_ctx_t *paral_ctx)
{
knl_paral_range_t paral_range;
idx_sort_worker_t *worker = NULL;
db_init_paral_ctx(paral_ctx, dc, index, part_loc);
errno_t err = memset_sp(¶l_range, sizeof(knl_paral_range_t), 0, sizeof(knl_paral_range_t));
knl_securec_check(err);
if (!paral_ctx->is_global) {
paral_range.workers = paral_ctx->paral_count;
if (knl_get_paral_schedule(session, dc, paral_ctx->part_info.curr_part,
paral_ctx->paral_count, ¶l_range) != OG_SUCCESS) {
return OG_ERROR;
}
if (paral_range.workers < paral_ctx->paral_count) {
paral_ctx->paral_count = paral_range.workers;
}
if (paral_range.workers == 0) {
return OG_SUCCESS;
}
}
uint32 mem_size = sizeof(idx_sort_worker_t) * paral_ctx->paral_count;
paral_ctx->workers = (idx_sort_worker_t*)cm_push(session->stack, mem_size);
err = memset_sp(paral_ctx->workers, mem_size, 0, mem_size);
knl_securec_check(err);
uint32 main_pool_id = session->id % session->kernel->temp_ctx_count;
for (uint32 i = 0; i < paral_ctx->paral_count; i++) {
worker = ¶l_ctx->workers[i];
worker->id = i;
worker->pool_id = (main_pool_id + i) % session->kernel->temp_ctx_count;
if (!paral_ctx->is_global) {
worker->scan_range.l_page = paral_range.l_page[i];
worker->scan_range.r_page = paral_range.r_page[i];
}
if (paral_ctx->sort_info.count == 0) {
paral_ctx->sort_info.first = i;
paral_ctx->sort_info.last = i;
paral_ctx->sort_info.count++;
} else {
paral_ctx->sort_info.last = i;
paral_ctx->sort_info.count++;
paral_ctx->workers[i - 1].next_id = i;
}
}
paral_ctx->workers[paral_ctx->paral_count - 1].next_id = OG_INVALID_ID8;
return OG_SUCCESS;
}
status_t db_manage_sub_workers(knl_session_t *session, idx_paral_sort_ctx_t *paral_ctx)
{
idx_start_all_workers(paral_ctx, BUILD_SEGMENT_PHASE);
if (idx_wait_all_workers(session, paral_ctx) != OG_SUCCESS) {
return OG_ERROR;
}
idx_start_all_workers(paral_ctx, MERGE_SEGMENT_PHASE);
if (idx_wait_all_workers(session, paral_ctx) != OG_SUCCESS) {
return OG_ERROR;
}
paral_ctx->phase = COMPLETE_PHASE;
return OG_SUCCESS;
}
status_t db_fill_index_entity_paral(knl_session_t *session, knl_dictionary_t *dc, index_t *index,
knl_part_locate_t part_loc, uint32 paral_no, bool32 nologging)
{
CM_SAVE_STACK(session->stack);
idx_paral_sort_ctx_t *paral_ctx = (idx_paral_sort_ctx_t*)cm_push(session->stack, sizeof(idx_paral_sort_ctx_t));
errno_t err = memset_sp(paral_ctx, sizeof(idx_paral_sort_ctx_t), 0, sizeof(idx_paral_sort_ctx_t));
knl_securec_check(err);
paral_ctx->paral_count = paral_no;
paral_ctx->nologging = nologging;
if (db_prepare_paral_ctx(session, dc, index, part_loc, paral_ctx) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (paral_ctx->paral_count == 0) {
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
OG_LOG_RUN_INF("[INDEX] session %d begin to fill index, paral_count %d", session->id, paral_ctx->paral_count);
if (idx_fetch_alloc_resource(session, paral_ctx)) {
idx_fetch_release_resource(paral_ctx);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_manage_sub_workers(session, paral_ctx) != OG_SUCCESS) {
idx_fetch_release_resource(paral_ctx);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
cm_spin_lock(¶l_ctx->parl_lock, NULL);
if (paral_ctx->sort_info.count == 0) {
cm_spin_unlock(¶l_ctx->parl_lock);
idx_fetch_release_resource(paral_ctx);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
uint32 id = paral_ctx->sort_info.first;
uint32 id2 = paral_ctx->workers[id].next_id;
cm_spin_unlock(¶l_ctx->parl_lock);
OG_LOG_RUN_INF("[INDEX] session %d begin to construct index", session->id);
btree_mt_context_t ogx;
idx_init_construct_ctx(paral_ctx, id, id2, &ogx);
if (idx_construct(&ogx) != OG_SUCCESS) {
idx_fetch_release_resource(paral_ctx);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
idx_fetch_release_resource(paral_ctx);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static void db_init_multi_paral_ctx(idx_paral_sort_ctx_t *paral_ctx, knl_dictionary_t *dc, index_t **index,
uint8 index_count, knl_part_locate_t part_loc)
{
paral_ctx->private_dc = dc;
paral_ctx->part_info.curr_part = part_loc;
paral_ctx->index_count = index_count;
if (!IS_PART_INDEX(index[0])) {
paral_ctx->is_global = OG_TRUE;
}
for (uint8 i = 0; i < index_count; i++) {
paral_ctx->btree[i] = &index[i]->btree;
if (IS_PART_INDEX(index[i])) {
index_part_t *index_part = INDEX_GET_PART(index[i], part_loc.part_no);
if (IS_PARENT_IDXPART(&index_part->desc)) {
index_part = PART_GET_SUBENTITY(index[i]->part_index, index_part->subparts[part_loc.subpart_no]);
}
paral_ctx->btree[i] = &index_part->btree;
}
}
}
static status_t db_prepare_multi_paral_ctx(knl_session_t *session, knl_dictionary_t *dc,
index_t **index, uint8 index_count, knl_part_locate_t part_loc, idx_paral_sort_ctx_t *paral_ctx)
{
knl_paral_range_t paral_range;
idx_build_worker_t *build_worker = NULL;
db_init_multi_paral_ctx(paral_ctx, dc, index, index_count, part_loc);
errno_t err = memset_sp(¶l_range, sizeof(knl_paral_range_t), 0, sizeof(knl_paral_range_t));
knl_securec_check(err);
paral_range.workers = paral_ctx->build_count;
if (!paral_ctx->is_global) {
if (knl_get_paral_schedule(session, dc, paral_ctx->part_info.curr_part,
paral_ctx->build_count, ¶l_range) != OG_SUCCESS) {
return OG_ERROR;
}
if (paral_range.workers < paral_ctx->build_count) {
paral_ctx->build_count = paral_range.workers;
}
if (paral_range.workers == 0) {
return OG_SUCCESS;
}
}
paral_ctx->build_workers = (idx_build_worker_t*)cm_push(session->stack,
sizeof(idx_build_worker_t) * paral_ctx->build_count);
err = memset_sp(paral_ctx->build_workers, sizeof(idx_build_worker_t) * paral_ctx->build_count,
0, sizeof(idx_build_worker_t) * paral_ctx->build_count);
knl_securec_check(err);
uint32 main_pool_id = session->id % session->kernel->temp_ctx_count;
for (uint32 i = 0; i < paral_ctx->build_count; i++) {
build_worker = ¶l_ctx->build_workers[i];
build_worker->pool_id = (main_pool_id + i) % session->kernel->temp_ctx_count;
build_worker->index_count = paral_ctx->index_count;
if (!paral_ctx->is_global) {
build_worker->scan_range.l_page = paral_range.l_page[i];
build_worker->scan_range.r_page = paral_range.r_page[i];
}
}
return OG_SUCCESS;
}
status_t db_manage_multi_sub_workers(knl_session_t *session, idx_paral_sort_ctx_t *paral_ctx)
{
idx_start_all_workers(paral_ctx, SORT_SEGMENT_PHASE);
if (idx_switch_create_phase(session, paral_ctx, SORT_SEGMENT_PHASE, MERGE_SEGMENT_PHASE) != OG_SUCCESS) {
return OG_ERROR;
}
if (idx_switch_create_phase(session, paral_ctx, MERGE_SEGMENT_PHASE, CONSTRUCT_INDEX_PHASE) != OG_SUCCESS) {
return OG_ERROR;
}
if (idx_wait_all_workers(session, paral_ctx) != OG_SUCCESS) {
return OG_ERROR;
}
paral_ctx->phase = COMPLETE_PHASE;
return OG_SUCCESS;
}
status_t db_fill_multi_indexes_paral(knl_session_t *session, knl_dictionary_t *dc, index_t **indexes,
uint32 index_cnt, uint32 paral_cnt, knl_part_locate_t part_loc, bool32 nologging)
{
CM_SAVE_STACK(session->stack);
idx_paral_sort_ctx_t *paral_ctx = (idx_paral_sort_ctx_t*)cm_push(session->stack, sizeof(idx_paral_sort_ctx_t));
errno_t err = memset_sp(paral_ctx, sizeof(idx_paral_sort_ctx_t), 0, sizeof(idx_paral_sort_ctx_t));
knl_securec_check(err);
if (index_cnt > 0 && index_cnt * paral_cnt >= OG_MAX_INDEX_PARALLELISM) {
paral_ctx->build_count = OG_MAX_INDEX_PARALLELISM / index_cnt;
} else {
paral_ctx->build_count = paral_cnt;
}
paral_ctx->nologging = nologging;
if (db_prepare_multi_paral_ctx(session, dc, indexes, index_cnt, part_loc, paral_ctx) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (paral_ctx->build_count == 0) {
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
if (idx_build_alloc_resource(session, paral_ctx)) {
idx_build_release_resource(paral_ctx, OG_TRUE);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
idx_start_build_workers(paral_ctx, BUILD_SEGMENT_PHASE);
if (idx_wait_build_workers(session, paral_ctx) != OG_SUCCESS) {
idx_build_release_resource(paral_ctx, OG_TRUE);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
idx_close_build_thread(paral_ctx);
if (idx_construct_alloc_resource(session, paral_ctx)) {
idx_construct_release_resource(paral_ctx);
idx_build_release_resource(paral_ctx, OG_FALSE);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_manage_multi_sub_workers(session, paral_ctx) != OG_SUCCESS) {
idx_construct_release_resource(paral_ctx);
idx_build_release_resource(paral_ctx, OG_FALSE);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
idx_construct_release_resource(paral_ctx);
idx_build_release_resource(paral_ctx, OG_FALSE);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_fill_index_paral(knl_session_t *session, knl_dictionary_t *dc, index_t *index, knl_index_def_t *def)
{
if (index->desc.is_func) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create index parallel", "functional index");
return OG_ERROR;
}
dc_load_all_part_segments(session, dc->handle);
if (IS_PART_INDEX(index)) {
return db_fill_part_index_paral(session, dc, index, def);
}
btree_t *btree = &index->btree;
bool32 need_redo = IS_LOGGING_TABLE_BY_TYPE(dc->type);
knl_part_locate_t part_loc = { 0, 0 };
if (db_create_btree_segment(session, index, NULL, btree, need_redo) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_fill_index_entity_paral(session, dc, index, part_loc, def->parallelism, def->nologging) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
* Description : generate index keys for index when creating index
* Input : dc : dictionary of table
* Input : index : the new created index
* Output : NA
* Return Value : status_t
* History : 1. 2017/4/26, add description
*/
static status_t db_fill_index(knl_session_t *session, knl_cursor_t *cursor, knl_table_desc_t desc, uint32 iid,
knl_index_def_t *def)
{
btree_mt_context_t ogx;
mtrl_sort_ctrl_t sort_ctrl;
knl_dictionary_t dc;
if (dc_open_table_private(session, desc.uid, desc.id, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
index_t *index = dc_find_index_by_id((dc_entity_t *)dc.handle, iid);
if (index == NULL) {
dc_close_table_private(&dc);
OG_THROW_ERROR(ERR_OBJECT_ID_NOT_EXIST, "index", iid);
return OG_ERROR;
}
if (def->parallelism != 0) {
status_t status = db_fill_index_paral(session, &dc, index, def);
dc_close_table_private(&dc);
return status;
}
uint32 size_context = sizeof(btree_mt_context_t);
uint32 size_ctrl = sizeof(mtrl_sort_ctrl_t);
errno_t err = memset_sp(&ogx, size_context, 0, size_context);
knl_securec_check(err);
err = memset_sp(&sort_ctrl, size_ctrl, 0, size_ctrl);
knl_securec_check(err);
ogx.nologging = def->nologging;
cursor->action = CURSOR_ACTION_SELECT;
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
if (knl_open_cursor(session, cursor, &dc) != OG_SUCCESS) {
dc_close_table_private(&dc);
return OG_ERROR;
}
if (IS_PART_TABLE(cursor->table)) {
if (db_fill_part_index(session, cursor, &dc, index, &ogx, &sort_ctrl) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
dc_close_table_private(&dc);
db_reset_mtr_ctx(&ogx.mtrl_ctx);
return OG_ERROR;
}
} else {
if (db_fill_index_entity(session, cursor, index, &ogx, &sort_ctrl) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
dc_close_table_private(&dc);
db_reset_mtr_ctx(&ogx.mtrl_ctx);
return OG_ERROR;
}
}
knl_close_cursor(session, cursor);
if (ogx.initialized) {
if (db_construct_index(&ogx, &sort_ctrl) != OG_SUCCESS) {
mtrl_release_context(&ogx.mtrl_ctx);
dc_close_table_private(&dc);
db_reset_mtr_ctx(&ogx.mtrl_ctx);
return OG_ERROR;
}
mtrl_release_context(&ogx.mtrl_ctx);
}
dc_close_table_private(&dc);
db_reset_mtr_ctx(&ogx.mtrl_ctx);
return OG_SUCCESS;
}
static status_t db_write_shadow_sysindex(knl_session_t *session, knl_index_desc_t *desc)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
text_t column_list;
char buf[COLUMN_LIST_BUF_LEN];
space_t *space;
status_t status;
space = SPACE_GET(session, desc->space_id);
if (!SPACE_IS_ONLINE(space)) {
OG_THROW_ERROR(ERR_SPACE_OFFLINE, space->ctrl->name, "write to shadow_index$ failed");
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_SHADOW_INDEX_ID, OG_INVALID_ID32);
column_list.len = 0;
column_list.str = buf;
if (db_encode_index_column_list(&column_list, COLUMN_LIST_BUF_LEN, desc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
row_init(&ra, cursor->buf, KNL_MAX_ROW_SIZE(session), 17);
(void)row_put_int32(&ra, desc->uid);
(void)row_put_int32(&ra, desc->table_id);
(void)row_put_int32(&ra, desc->id);
(void)row_put_str(&ra, desc->name);
(void)row_put_int32(&ra, desc->space_id);
(void)row_put_int64(&ra, desc->org_scn);
(void)row_put_int64(&ra, *(int64 *)&desc->entry);
(void)row_put_int32(&ra, desc->primary);
(void)row_put_int32(&ra, desc->unique);
(void)row_put_int32(&ra, desc->type);
(void)row_put_int32(&ra, desc->column_count);
(void)row_put_text(&ra, &column_list);
(void)row_put_int32(&ra, desc->initrans);
(void)row_put_int32(&ra, desc->cr_mode);
(void)row_put_int32(&ra, desc->flags);
(void)row_put_int32(&ra, desc->parted);
(void)row_put_int32(&ra, desc->pctfree);
status = knl_internal_insert(session, cursor);
CM_RESTORE_STACK(session->stack);
return status;
}
static status_t db_drop_shadow_index(knl_session_t *session, uint32 user_id, uint32 table_id, bool32 clean_segment)
{
knl_cursor_t *cursor = NULL;
index_t index;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_SHADOW_INDEX_ID, IX_SYS_SHADOW_INDEX_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &user_id, sizeof(uint32),
IX_COL_SYS_SHADOW_INDEX_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &table_id,
sizeof(uint32), IX_COL_SYS_SHADOW_INDEX_001_TABLE_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!cursor->eof) {
cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, NULL);
dc_convert_index(session, cursor, &index.desc);
if (!clean_segment) {
index.desc.entry = INVALID_PAGID;
OG_LOG_RUN_WAR("db drop shadow indexes found nologging table ID(%u)", table_id);
}
btree_drop_segment(session, &index);
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (index.desc.parted) {
if (db_drop_shadow_indexpart(session, user_id, table_id, clean_segment) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_clean_shadow_index(knl_session_t *session, uint32 user_id, uint32 table_id, bool32 clean_segment)
{
if (db_drop_shadow_index(session, user_id, table_id, clean_segment) != OG_SUCCESS) {
return OG_ERROR;
}
return db_drop_shadow_indexpart(session, user_id, table_id, clean_segment);
}
static status_t db_create_shadow_index(knl_session_t *session, knl_dictionary_t *dc, index_t *index,
knl_index_def_t *def, rebuild_info_t rebuild_info)
{
knl_part_obj_def_t *part_def = NULL;
space_t *space = NULL;
if (def == NULL) {
part_def = NULL;
} else {
part_def = def->part_def;
}
space = SPACE_GET(session, index->desc.space_id);
if (knl_begin_auton_rm(session) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_clean_shadow_index(session, dc->uid, dc->oid, !SPACE_IS_NOLOGGING(space)) != OG_SUCCESS) {
knl_end_auton_rm(session, OG_ERROR);
return OG_ERROR;
}
knl_end_auton_rm(session, OG_SUCCESS);
if ((def && def->space.len != 0) || (rebuild_info.spc_id != OG_INVALID_ID32)) {
index->desc.is_stored = OG_TRUE;
}
if (IS_PART_INDEX(index)) {
if (db_create_part_shadow_index(session, dc, index, part_def, rebuild_info) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_write_shadow_sysindex(session, &index->desc) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (btree_create_segment(session, index) != OG_SUCCESS) {
return OG_ERROR;
}
if (btree_generate_create_undo(session, index->desc.entry, index->desc.space_id,
IS_LOGGING_TABLE_BY_TYPE(dc->type)) != OG_SUCCESS) {
btree_drop_segment(session, index);
return OG_ERROR;
}
if (db_write_shadow_sysindex(session, &index->desc) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_delete_shadow_sysindex(knl_session_t *session, knl_cursor_t *cursor, index_t *index)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_SHADOW_INDEX_ID, IX_SYS_SHADOW_INDEX_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &index->desc.uid,
sizeof(uint32), IX_COL_SYS_SHADOW_INDEX_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &index->desc.table_id,
sizeof(uint32), IX_COL_SYS_SHADOW_INDEX_001_TABLE_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_pre_create_idx(knl_session_t *session, knl_index_def_t *idx_def, knl_dictionary_t *dc, index_t *idx)
{
dc_entity_t *entity = DC_ENTITY(dc);
table_t *table = &entity->table;
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
if (dc->type == DICT_TYPE_TABLE) {
if (IS_SYS_TABLE(table)) {
if (OG_SUCCESS != btree_create_segment(session, idx)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
}
if (OG_SUCCESS != db_write_sysindex(session, cursor, &idx->desc)) {
int32 err_code = cm_get_error_code();
if (err_code == ERR_DUPLICATE_KEY) {
cm_reset_error();
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "index", idx->desc.name);
}
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != db_update_index_count(session, cursor, &table->desc, OG_TRUE)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (IS_PART_INDEX(idx)) {
if (!IS_COMPART_TABLE(table->part_table) && idx_def->part_def != NULL && idx_def->part_def->is_composite) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create composite partition index",
"non composite partition table");
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_create_part_index(session, cursor, idx, idx_def->part_def) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
* Description : Implementation of create index
* Input : def : definition of index
* Output : NA
* Return Value : status_t
* History : 1. 2017/4/26, add description
*/
status_t db_create_index(knl_session_t *session, knl_index_def_t *def, knl_dictionary_t *dc, bool32 is_cons,
uint32 *index_id)
{
index_t index;
if (dc->type == DICT_TYPE_TABLE_EXTERNAL) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create index or cons", "external organized table");
return OG_ERROR;
}
uint32 size_index = sizeof(index_t);
dc_entity_t *entity = DC_ENTITY(dc);
table_t *table = &entity->table;
errno_t err = memset_sp((void *)&index, size_index, 0, size_index);
knl_securec_check(err);
index.entity = entity;
knl_index_desc_t *desc = &index.desc;
index.desc.is_enforced = is_cons;
index.desc.is_cons = is_cons;
index.desc.is_nologging = def->nologging;
if (db_alloc_index_id(entity, def, &index.desc.id) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_verify_index_def(session, dc, def, desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_pre_create_idx(session, def, dc, &index) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
def->parallelism = def->parallelism == -1 ? g_instance->kernel.attr.create_index_parallelism : def->parallelism;
if (dc->type == DICT_TYPE_TEMP_TABLE_SESSION || dc->type == DICT_TYPE_TEMP_TABLE_TRANS) {
if (OG_SUCCESS != temp_db_fill_index(session, cursor, &index, def->parallelism)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
} else {
if (OG_SUCCESS != db_fill_index(session, cursor, table->desc, index.desc.id, def)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
if (index_id != NULL) {
*index_id = index.desc.id;
}
return OG_SUCCESS;
}
#define SHADOW_INDEX_FILL_BATCH 100
static void db_fill_shwidx_get_part(index_t *index, shadow_index_t *shadow_index, knl_cursor_t *build_cursor,
knl_cursor_t *scan_cursor, knl_part_locate_t part_loc)
{
if (IS_PART_INDEX(index)) {
build_cursor->index_part = INDEX_GET_PART(build_cursor->index, scan_cursor->part_loc.part_no);
if (scan_cursor->part_loc.subpart_no != OG_INVALID_ID32) {
knl_panic_log(IS_PARENT_IDXPART(&((index_part_t *)build_cursor->index_part)->desc),
"the index_part is not parent_idxpart, panic info: page %u-%u type %u table %s index %s index_part %s",
build_cursor->rowid.file, build_cursor->rowid.page, ((page_head_t *)build_cursor->page_buf)->type,
((table_t *)build_cursor->table)->desc.name, ((index_t *)build_cursor->index)->desc.name,
((index_part_t *)build_cursor->index_part)->desc.name);
uint32 subpart_no = scan_cursor->part_loc.subpart_no;
index_part_t *index_part = (index_part_t *)build_cursor->index_part;
build_cursor->index_part = PART_GET_SUBENTITY(index->part_index, index_part->subparts[subpart_no]);
}
}
if (IS_PART_INDEX(index) && part_loc.part_no != OG_INVALID_ID32) {
if (SHADOW_INDEX_IS_PART(shadow_index)) {
build_cursor->index_part = &shadow_index->index_part;
} else {
build_cursor->index_part = INDEX_GET_PART(build_cursor->index, part_loc.part_no);
if (part_loc.subpart_no != OG_INVALID_ID32) {
uint32 subpart_no = part_loc.subpart_no;
index_part_t *index_part = (index_part_t *)build_cursor->index_part;
build_cursor->index_part = PART_GET_SUBENTITY(index->part_index, index_part->subparts[subpart_no]);
}
}
}
}
static status_t db_shadow_index_make_key(knl_session_t *session, knl_cursor_t *scan_cursor, index_t *index, char *key)
{
errno_t ret;
if (IS_INDEX_ONLY_SCAN(scan_cursor)) {
idx_decode_row(session, scan_cursor, scan_cursor->offsets, scan_cursor->lens, NULL);
if (scan_cursor->index_dsc) {
ret = memcpy_sp(key, OG_KEY_BUF_SIZE, scan_cursor->scan_range.r_buf, OG_KEY_BUF_SIZE);
} else {
ret = memcpy_sp(key, OG_KEY_BUF_SIZE, scan_cursor->scan_range.l_buf, OG_KEY_BUF_SIZE);
}
knl_securec_check(ret);
return OG_SUCCESS;
}
cm_decode_row((char *)scan_cursor->row, scan_cursor->offsets, scan_cursor->lens, NULL);
return knl_make_key(session, scan_cursor, index, key);
}
static status_t db_fill_shadow_index_entity(knl_session_t *session, knl_dictionary_t *dc, knl_cursor_t *scan_cursor,
knl_cursor_t *build_cursor, knl_part_locate_t part_loc, index_build_mode_t build_mode)
{
dc_entity_t *entity = DC_ENTITY(dc);
shadow_index_t *shadow_index = entity->table.shadow_index;
index_t *index = SHADOW_INDEX_ENTITY(shadow_index);
status_t status;
uint16 count = 0;
build_cursor->skip_lock = (bool8)(REBUILD_INDEX_PARALLEL == build_mode);
build_cursor->action = CURSOR_ACTION_INSERT;
if (knl_open_cursor(session, build_cursor, dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (IS_PART_TABLE(scan_cursor->table)) {
scan_cursor->part_loc = part_loc;
if (build_mode != REBUILD_INDEX_PARALLEL &&
knl_reopen_cursor(session, scan_cursor, dc) != OG_SUCCESS) {
knl_close_cursor(session, build_cursor);
return OG_ERROR;
}
}
build_cursor->index = index;
db_fill_shwidx_get_part(index, shadow_index, build_cursor, scan_cursor, part_loc);
build_cursor->part_loc = part_loc;
for (;;) {
if (knl_fetch(session, scan_cursor) != OG_SUCCESS) {
knl_close_cursor(session, build_cursor);
return OG_ERROR;
}
if (scan_cursor->eof) {
knl_close_cursor(session, build_cursor);
if (build_mode == CREATE_INDEX_ONLINE && IS_UNIQUE_PRIMARY_INDEX(index)) {
knl_commit(session);
}
return OG_SUCCESS;
}
if (session->canceled) {
knl_close_cursor(session, build_cursor);
OG_THROW_ERROR(ERR_OPERATION_CANCELED);
return OG_ERROR;
}
if (session->killed) {
knl_close_cursor(session, build_cursor);
OG_THROW_ERROR(ERR_OPERATION_KILLED);
return OG_ERROR;
}
if (db_shadow_index_make_key(session, scan_cursor, index, build_cursor->key) != OG_SUCCESS) {
knl_close_cursor(session, build_cursor);
return OG_ERROR;
}
if (index->desc.cr_mode == CR_PAGE) {
status = pcrb_insert_into_shadow(session, build_cursor);
} else {
status = btree_insert_into_shadow(session, build_cursor);
}
if (status != OG_SUCCESS) {
int32 err_code;
const char *err_msg = NULL;
cm_get_error(&err_code, &err_msg, NULL);
if (err_code != ERR_DUPLICATE_KEY) {
knl_close_cursor(session, build_cursor);
return OG_ERROR;
}
* conflict_rid instead
*/
if (build_mode == REBUILD_INDEX_ONLINE || IS_SAME_ROWID(scan_cursor->rowid, build_cursor->conflict_rid)) {
cm_reset_error();
} else {
knl_close_cursor(session, build_cursor);
return OG_ERROR;
}
}
if (build_mode == CREATE_INDEX_ONLINE && IS_UNIQUE_PRIMARY_INDEX(index)) {
count++;
if (count == SHADOW_INDEX_FILL_BATCH) {
knl_commit(session);
count = 0;
}
}
}
}
static status_t db_fill_shwidx_all_parts(knl_session_t *session, knl_cursor_t *cursor, knl_dictionary_t *dc,
knl_part_locate_t part_loc, index_build_mode_t build_mode)
{
table_t *table = DC_TABLE(dc);
table_part_t *table_compart = NULL;
part_table_t *part_table = table->part_table;
CM_SAVE_STACK(session->stack);
knl_cursor_t *build_cursor = knl_push_cursor(session);
for (uint32 i = 0; i < part_table->desc.partcnt; i++) {
table_compart = TABLE_GET_PART(table, i);
if (!IS_READY_PART(table_compart)) {
continue;
}
part_loc.part_no = i;
if (!IS_PARENT_TABPART(&table_compart->desc)) {
part_loc.subpart_no = OG_INVALID_ID32;
if (db_fill_shadow_index_entity(session, dc, cursor, build_cursor, part_loc,
build_mode) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
continue;
}
for (uint32 j = 0; j < table_compart->desc.subpart_cnt; j++) {
part_loc.subpart_no = j;
if (db_fill_shadow_index_entity(session, dc, cursor, build_cursor, part_loc,
build_mode) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_fill_shadow_part_index(knl_session_t *session, knl_cursor_t *cursor, knl_dictionary_t *dc,
knl_part_locate_t part_loc, index_build_mode_t build_mode)
{
table_t *table = DC_TABLE(dc);
table_part_t *table_compart = NULL;
CM_SAVE_STACK(session->stack);
knl_cursor_t *build_cursor = knl_push_cursor(session);
if (part_loc.part_no == OG_INVALID_ID32) {
if (db_fill_shwidx_all_parts(session, cursor, dc, part_loc, build_mode) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
} else if (part_loc.subpart_no == OG_INVALID_ID32) {
table_compart = TABLE_GET_PART(table, part_loc.part_no);
if (!IS_PARENT_TABPART(&table_compart->desc)) {
if (db_fill_shadow_index_entity(session, dc, cursor, build_cursor, part_loc, build_mode) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
for (uint32 i = 0; i < table_compart->desc.subpart_cnt; i++) {
part_loc.subpart_no = i;
if (db_fill_shadow_index_entity(session, dc, cursor, build_cursor, part_loc, build_mode) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
} else {
if (db_fill_shadow_index_entity(session, dc, cursor, build_cursor, part_loc,
build_mode) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_fill_shadow_index(knl_session_t *session, knl_cursor_t *cursor, knl_dictionary_t *dc,
knl_part_locate_t part_loc, index_build_mode_t build_mode)
{
if (IS_PART_TABLE(cursor->table)) {
if (db_fill_shadow_part_index(session, cursor, dc, part_loc, build_mode) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
CM_SAVE_STACK(session->stack);
knl_cursor_t *build_cursor = knl_push_cursor(session);
part_loc.part_no = OG_INVALID_ID32;
part_loc.subpart_no = OG_INVALID_ID32;
if (db_fill_shadow_index_entity(session, dc, cursor, build_cursor, part_loc, build_mode) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
}
return OG_SUCCESS;
}
static status_t db_create_index_directly(knl_session_t *session, knl_index_def_t *def, index_t *index)
{
table_t *table = &index->entity->table;
knl_cursor_t *scan_cursor = NULL;
CM_SAVE_STACK(session->stack);
scan_cursor = knl_push_cursor(session);
if (db_write_sysindex(session, scan_cursor, &index->desc) != OG_SUCCESS) {
int32 err_code = cm_get_error_code();
if (err_code == ERR_DUPLICATE_KEY) {
cm_reset_error();
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "index", index->desc.name);
}
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_update_index_count(session, scan_cursor, &table->desc, OG_TRUE) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (IS_PART_INDEX(index)) {
if (db_create_part_index(session, scan_cursor, index, def->part_def) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static bool32 db_judge_heap_segment_null(table_t *table)
{
part_table_t *part_table = NULL;
table_part_t *table_part = NULL;
if (IS_PART_TABLE(table)) {
part_table = table->part_table;
for (uint32 i = 0; i < part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
if (table_part->heap.segment != NULL) {
return OG_FALSE;
}
continue;
}
table_part_t *table_subpart = NULL;
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
table_subpart = PART_GET_SUBENTITY(part_table, table_part->subparts[j]);
if (table_subpart == NULL) {
continue;
}
if (table_subpart->heap.segment != NULL) {
return OG_FALSE;
}
}
}
} else {
if (table->heap.segment != NULL) {
return OG_FALSE;
}
}
return OG_TRUE;
}
static bool32 db_part_table_has_segment(knl_session_t *session, knl_dictionary_t *new_dc)
{
table_t *table = DC_TABLE(new_dc);
table_part_t *table_part = NULL;
bool32 is_null = OG_TRUE;
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
if (db_tabpart_has_segment(table->part_table, table_part)) {
is_null = OG_FALSE;
break;
}
}
return is_null;
}
static status_t db_drop_empty_idxpart_segment(knl_session_t *session, knl_dictionary_t *new_dc, index_t *new_index)
{
table_t *table = DC_TABLE(new_dc);
table_part_t *table_part = NULL;
table_part_t *table_sub_part = NULL;
index_part_t *index_part = NULL;
index_part_t *index_sub_part = NULL;
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(table, i);
index_part = INDEX_GET_PART(new_index, i);
if (!IS_READY_PART(table_part) || index_part == NULL) {
continue;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
if (table_part->heap.segment != NULL || index_part == NULL) {
continue;
}
if (db_upd_idx_part_entry(session, &index_part->desc, INVALID_PAGID) != OG_SUCCESS) {
return OG_ERROR;
}
if (btree_part_segment_prepare(session, index_part, OG_FALSE, BTREE_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
continue;
}
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
table_sub_part = PART_GET_SUBENTITY(table->part_table, table_part->subparts[j]);
if (table_sub_part == NULL || table_sub_part->heap.segment != NULL) {
continue;
}
index_sub_part = PART_GET_SUBENTITY(new_index->part_index, index_part->subparts[j]);
if (db_upd_sub_idx_part_entry(session, &index_sub_part->desc, INVALID_PAGID) != OG_SUCCESS) {
return OG_ERROR;
}
if (btree_part_segment_prepare(session, index_sub_part, OG_FALSE, BTREE_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_drop_empty_index_segment(knl_session_t *session, knl_table_desc_t desc, uint32 idx_slot)
{
knl_dictionary_t new_dc;
bool32 is_null = OG_TRUE;
status_t status = OG_SUCCESS;
if (dc_open_table_private(session, desc.uid, desc.id, &new_dc) != OG_SUCCESS) {
return OG_ERROR;
}
table_t *table = DC_TABLE(&new_dc);
index_t *index = table->index_set.items[idx_slot];
if (IS_PART_TABLE(table)) {
dc_load_all_part_segments(session, new_dc.handle);
if (IS_PART_INDEX(index)) {
status = db_drop_empty_idxpart_segment(session, &new_dc, index);
dc_close_table_private(&new_dc);
return status;
} else {
is_null = db_part_table_has_segment(session, &new_dc);
}
}
is_null = IS_PART_TABLE(table) ? is_null : (table->heap.segment == NULL);
if (is_null) {
if (db_update_index_entry(session, &index->desc, INVALID_PAGID) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
return OG_ERROR;
}
if (btree_segment_prepare(session, index, OG_FALSE, BTREE_DROP_SEGMENT) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
return OG_ERROR;
}
}
dc_close_table_private(&new_dc);
return OG_SUCCESS;
}
static status_t db_switch_shadow_index(knl_session_t *session, knl_cursor_t *cursor, table_t *table,
index_t *new_index, knl_parts_locate_t parts_loc)
{
index_t *old_index = table->index_set.items[new_index->desc.slot];
index_t *sys_index = NULL;
knl_scan_key_t *scan_key = NULL;
knl_update_info_t *update_info = NULL;
row_assist_t ra;
rd_update_core_index_t redo_index_info;
CM_SAVE_STACK(session->stack);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_INDEX_ID, IX_SYS_INDEX_001_ID);
sys_index = (index_t *)cursor->index;
scan_key = &cursor->scan_range.l_key;
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(&sys_index->desc, scan_key, OG_TYPE_INTEGER, &old_index->desc.uid, sizeof(uint32),
IX_COL_SYS_INDEX_001_USER);
knl_set_scan_key(&sys_index->desc, scan_key, OG_TYPE_INTEGER, &old_index->desc.table_id, sizeof(uint32),
IX_COL_SYS_INDEX_001_TABLE);
knl_set_scan_key(&sys_index->desc, scan_key, OG_TYPE_INTEGER, &old_index->desc.id, sizeof(uint32),
IX_COL_SYS_INDEX_001_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, table->desc.name,
sys_index->desc.name);
update_info = &cursor->update_info;
update_info->count = 8;
update_info->columns[0] = SYS_INDEX_COLUMN_ID_SPACE;
update_info->columns[1] = SYS_INDEX_COLUMN_ID_SEQUENCE;
update_info->columns[2] = SYS_INDEX_COLUMN_ID_ENTRY;
update_info->columns[3] = SYS_INDEX_COLUMN_ID_INITRANS;
update_info->columns[4] = SYS_INDEX_COLUMN_ID_CR_MODE;
update_info->columns[5] = SYS_INDEX_COLUMN_ID_FLAGS;
update_info->columns[6] = SYS_INDEX_COLUMN_ID_PARTITIONED;
update_info->columns[7] = SYS_INDEX_COLUMN_ID_PCTFREE;
update_info->data = (char *)cm_push(session->stack, OG_MAX_ROW_SIZE);
row_init(&ra, update_info->data, OG_MAX_ROW_SIZE, update_info->count);
(void)row_put_int32(&ra, new_index->desc.space_id);
(void)row_put_int64(&ra, new_index->desc.org_scn);
(void)row_put_int64(&ra, *(int64 *)&new_index->desc.entry);
(void)row_put_int32(&ra, new_index->desc.initrans);
(void)row_put_int32(&ra, new_index->desc.cr_mode);
(void)row_put_int32(&ra, new_index->desc.flags);
(void)row_put_int32(&ra, new_index->desc.parted);
(void)row_put_int32(&ra, new_index->desc.pctfree);
cm_decode_row(update_info->data, update_info->offsets, update_info->lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_delete_shadow_sysindex(session, cursor, new_index) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (IS_PART_INDEX(new_index)) {
if (db_switch_shadow_idx_partitions(session, cursor, new_index) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_drop_part_btree_segments(session, old_index, parts_loc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (btree_segment_prepare(session, old_index, OG_FALSE, BTREE_DROP_SEGMENT) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!IS_SYS_TABLE(table)) {
if (db_drop_empty_index_segment(session, table->desc, new_index->desc.slot) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (IS_CORE_SYS_TABLE(new_index->desc.uid, new_index->desc.table_id)) {
redo_index_info.op_type = RD_UPDATE_CORE_INDEX;
redo_index_info.table_id = new_index->desc.table_id;
redo_index_info.index_id = new_index->desc.id;
redo_index_info.entry = new_index->desc.entry;
db_update_core_index(session, &redo_index_info);
log_put(session, RD_LOGIC_OPERATION, &redo_index_info, sizeof(rd_update_core_index_t), LOG_ENTRY_FLAG_NONE);
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_create_index_online(knl_session_t *session, knl_index_def_t *def, knl_dictionary_t *dc)
{
index_t index;
dc_entity_t *entity;
knl_cursor_t *scan_cursor = NULL;
knl_dictionary_t new_dc;
table_t *table;
uint32 size_index;
status_t status = OG_SUCCESS;
errno_t err;
rebuild_info_t rebuild_info;
if (DB_IS_CLUSTER(session)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create index online", " cluster database");
return OG_ERROR;
}
table = DC_TABLE(dc);
entity = DC_ENTITY(dc);
if (entity->table.desc.type == TABLE_TYPE_EXTERNAL) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create index", "external organized table");
return OG_ERROR;
}
if (entity->table.desc.type == TABLE_TYPE_TRANS_TEMP || entity->table.desc.type == TABLE_TYPE_SESSION_TEMP) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create index online", "temporary table");
return OG_ERROR;
}
size_index = sizeof(index_t);
err = memset_sp((void *)&index, size_index, 0, size_index);
knl_securec_check(err);
index.entity = entity;
if (db_alloc_index_id(entity, def, &index.desc.id) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_verify_index_def(session, dc, def, &index.desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_judge_heap_segment_null(table)) {
status = db_create_index_directly(session, def, &index);
return status;
}
err = memset_sp(&rebuild_info, sizeof(rebuild_info_t), 0, sizeof(rebuild_info_t));
knl_securec_check(err);
rebuild_info.spc_id = OG_INVALID_ID32;
if (db_create_shadow_index(session, dc, &index, def, rebuild_info) != OG_SUCCESS) {
return OG_ERROR;
}
knl_commit(session);
dc_invalidate(session, entity);
CM_SAVE_STACK(session->stack);
scan_cursor = knl_push_cursor(session);
for (;;) {
if (knl_open_dc_by_id(session, index.desc.uid, index.desc.table_id, &new_dc, OG_TRUE) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
dc_close(dc);
err = memcpy_sp(dc, sizeof(knl_dictionary_t), &new_dc, sizeof(knl_dictionary_t));
knl_securec_check(err);
if (dc_load_shadow_index(session, dc) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
entity = DC_ENTITY(dc);
table = DC_TABLE(dc);
scan_cursor->action = def->unique || def->primary ? CURSOR_ACTION_UPDATE : CURSOR_ACTION_SELECT;
scan_cursor->scan_mode = SCAN_MODE_TABLE_FULL;
if (knl_open_cursor(session, scan_cursor, dc) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
scan_cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
lock_degrade_table_lock(session, entity);
err = memcpy_sp(&index, sizeof(index_t), &table->shadow_index->index, sizeof(index_t));
knl_securec_check(err);
knl_part_locate_t part_loc = { .part_no = OG_INVALID_ID32,
.subpart_no = OG_INVALID_ID32 };
if (db_fill_shadow_index(session, scan_cursor, dc, part_loc, CREATE_INDEX_ONLINE) != OG_SUCCESS) {
knl_close_cursor(session, scan_cursor);
status = OG_ERROR;
break;
}
knl_close_cursor(session, scan_cursor);
if (lock_upgrade_table_lock(session, entity, LOCK_INF_WAIT) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
if (db_write_sysindex(session, scan_cursor, &index.desc) != OG_SUCCESS) {
int32 err_code = cm_get_error_code();
if (err_code == ERR_DUPLICATE_KEY) {
cm_reset_error();
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "index", index.desc.name);
}
status = OG_ERROR;
break;
}
if (db_update_index_count(session, scan_cursor, &entity->table.desc, OG_TRUE) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
if (IS_PART_INDEX(&index)) {
if (db_write_partindex(session, scan_cursor, &index) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
}
if (db_delete_shadow_sysindex(session, scan_cursor, &index) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
if (IS_PART_INDEX(&index)) {
if (db_delete_from_shadow_sysindexpart(session, scan_cursor, index.desc.uid, index.desc.table_id,
index.desc.id) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
}
break;
}
CM_RESTORE_STACK(session->stack);
if (status != OG_SUCCESS) {
knl_rollback(session, NULL);
dc_invalidate_shadow_index(dc->handle);
if (((dc_entity_t *)dc->handle)->valid) {
if (lock_upgrade_table_lock(session, dc->handle, LOCK_INF_WAIT) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (knl_begin_auton_rm(session) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_drop_shadow_index(session, dc->uid, dc->oid, OG_TRUE) != OG_SUCCESS) {
knl_end_auton_rm(session, OG_ERROR);
return OG_ERROR;
}
knl_end_auton_rm(session, OG_SUCCESS);
dc_invalidate(session, (dc_entity_t *)dc->handle);
}
return status;
}
status_t db_fetch_index_desc(knl_session_t *session, uint32 uid, text_t *name,
knl_index_desc_t *desc)
{
bool32 is_found;
knl_dictionary_t dc;
knl_cursor_t *cursor = NULL;
dc_user_t *user = NULL;
db_get_sys_dc(session, SYS_INDEX_ID, &dc);
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (OG_SUCCESS != db_fetch_sysindex_row(session, cursor, uid, name, CURSOR_ACTION_SELECT, &is_found)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!is_found) {
if (dc_open_user_by_id(session, uid, &user) == OG_SUCCESS) {
OG_THROW_ERROR(ERR_INDEX_NOT_EXIST, user->desc.name, T2S_EX(name));
}
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
dc_convert_index(session, cursor, desc);
return OG_SUCCESS;
}
static status_t db_drop_index_update_catalog(knl_session_t *session, index_t *index, dc_entity_t *entity)
{
knl_cursor_t *cursor = knl_push_cursor(session);
knl_index_desc_t *idesc = &index->desc;
if (db_update_index_count(session, cursor, &entity->table.desc, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_delete_from_sysindex(session, cursor, idesc->uid, idesc->table_id, idesc->id) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_icol_from_syscolumn(session, cursor, entity, idesc) != OG_SUCCESS) {
return OG_ERROR;
}
if (index->desc.parted) {
if (db_delete_from_syspartobject(session, cursor, idesc->uid, idesc->table_id, idesc->id) != OG_SUCCESS) {
return OG_ERROR;
}
if (IS_COMPART_INDEX(&index->part_index->desc)) {
if (db_delete_subidxparts_with_index(session, cursor, idesc->uid, idesc->table_id,
idesc->id) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (db_delete_from_sysindexpart(session, cursor, idesc->uid, idesc->table_id, idesc->id,
OG_INVALID_ID32) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_verify_index_logical_info(index_t *index)
{
dc_entity_t *entity = index->entity;
if ((entity->lrep_info.status == LOGICREP_STATUS_ON) && (entity->lrep_info.index_id == index->desc.id)) {
return OG_ERROR;
}
if (!IS_PART_TABLE(&entity->table)) {
return OG_SUCCESS;
}
table_part_t *table_part = NULL;
table_part_t *subpart = NULL;
for (uint32 i = 0; i < entity->table.part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(&entity->table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
if ((table_part->desc.lrep_status == PART_LOGICREP_STATUS_ON) &&
(entity->lrep_info.index_id == index->desc.id)) {
return OG_ERROR;
}
continue;
}
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
subpart = PART_GET_SUBENTITY(entity->table.part_table, table_part->subparts[j]);
if (subpart == NULL) {
continue;
}
if ((subpart->desc.lrep_status == PART_LOGICREP_STATUS_ON) &&
(entity->lrep_info.index_id == index->desc.id)) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
* Description : Implementation of drop index
* Input : uid : user id of index owner
* Input : index_name : name of index
* Output : NA
* Return Value : status_t
* History : 1. 2017/4/26, add description
*/
status_t db_drop_index(knl_session_t *session, index_t *index, knl_dictionary_t *dc)
{
dc_entity_t *entity = DC_ENTITY(dc);
knl_index_desc_t *idesc = &index->desc;
if (index->dep_set.count > 0) {
OG_THROW_ERROR(ERR_TABLE_IS_REFERENCED);
return OG_ERROR;
}
if (db_verify_index_logical_info(index) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_REFERENCED_BY_LOGICAL_LOG);
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
if (db_drop_index_update_catalog(session, index, entity) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
if (dc->type == DICT_TYPE_TEMP_TABLE_SESSION || dc->type == DICT_TYPE_TEMP_TABLE_TRANS) {
knl_temp_cache_t *temp_table = knl_get_temp_cache(session, idesc->uid, idesc->table_id);
if (temp_table != NULL) {
if (temp_table->index_segid != OG_INVALID_ID32) {
temp_table->index_root[idesc->id].root_vmid = OG_INVALID_ID32;
}
temp_table->index_root[idesc->id].org_scn = OG_INVALID_ID64;
}
} else {
if (btree_segment_prepare(session, index, OG_INVALID_ID32, BTREE_DROP_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
if (index->desc.parted) {
if (db_drop_index_part_segments(session, index) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
status_t db_update_index_status(knl_session_t *session, index_t *index, bool32 is_invalid, bool32 *is_changed)
{
row_assist_t ra;
knl_index_desc_t desc;
if (is_invalid && db_verify_index_logical_info(index) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_REFERENCED_BY_LOGICAL_LOG);
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_INDEX_ID, IX_SYS_INDEX_001_ID);
knl_scan_key_t *scan_key = &cursor->scan_range.l_key;
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), scan_key, OG_TYPE_INTEGER, &index->desc.uid, sizeof(uint32),
IX_COL_SYS_INDEX_001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), scan_key, OG_TYPE_INTEGER, &index->desc.table_id, sizeof(uint32),
IX_COL_SYS_INDEX_001_TABLE);
knl_set_scan_key(INDEX_DESC(cursor->index), scan_key, OG_TYPE_INTEGER, &index->desc.id, sizeof(uint32),
IX_COL_SYS_INDEX_001_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u", cursor->rowid.file, cursor->rowid.page);
dc_convert_index(session, cursor, &desc);
if (!(*is_changed)) {
*is_changed = desc.is_invalid != is_invalid;
}
desc.is_invalid = is_invalid;
if (is_invalid) {
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 2);
cursor->update_info.count = 2;
cursor->update_info.columns[0] = SYS_INDEX_COLUMN_ID_ENTRY;
cursor->update_info.columns[1] = SYS_INDEX_COLUMN_ID_FLAGS;
(void)row_put_int64(&ra, *(int64 *)&INVALID_PAGID);
(void)row_put_int32(&ra, desc.flags);
} else {
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_INDEX_COLUMN_ID_FLAGS;
(void)row_put_int32(&ra, desc.flags);
}
cm_decode_row(ra.buf, cursor->update_info.offsets, cursor->update_info.lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_altable_drop_cons(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
knl_cursor_t *cursor = NULL;
index_t *index = NULL;
table_t *table = NULL;
uint32 i;
uint32 j;
bool32 is_found = OG_FALSE;
uint32 cons_type;
uint32 col_count;
text_t def_cols;
uint16 *idx_cols = NULL;
uint16 *cons_cols = NULL;
table = DC_TABLE(dc);
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (db_drop_cons(session, cursor, table->desc.uid, table->desc.id, dc, def, &is_found) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!is_found) {
if (def->options & DROP_IF_EXISTS) {
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
} else {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_CONS_NOT_EXIST, T2S(&def->cons_def.name));
return OG_ERROR;
}
}
cons_type = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_TYPE);
if (cons_type != CONS_TYPE_PRIMARY && cons_type != CONS_TYPE_UNIQUE) {
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
def_cols.str = CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_COLUMN_LIST);
def_cols.len = CURSOR_COLUMN_SIZE(cursor, CONSDEF_COL_COLUMN_LIST);
col_count = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_COLUMN_COUNT);
cons_cols = cm_push(session->stack, OG_MAX_INDEX_COLUMNS);
dc_convert_column_list(col_count, &def_cols, cons_cols);
for (i = 0; i < table->index_set.total_count; i++) {
idx_cols = table->index_set.items[i]->desc.columns;
if (table->index_set.items[i]->desc.column_count != col_count) {
continue;
}
for (j = 0; j < col_count; j++) {
uint16 col_id = idx_cols[j];
if (col_id >= DC_VIRTUAL_COL_START) {
col_id = table->index_set.items[i]->desc.columns_info[j].arg_cols[0];
}
if (col_id != cons_cols[j]) {
break;
}
}
if (j == col_count) {
index = table->index_set.items[i];
break;
}
}
cm_pop(session->stack);
if (index != NULL && index->desc.is_cons) {
if (db_drop_index(session, index, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_set_serial_value(knl_session_t *session, void *stmt, row_assist_t *ra, dc_entity_t *entity,
knl_cursor_t *cursor, knl_column_t *column)
{
uint64 value;
if (knl_get_serial_value(session, entity, &value, KNL_SERIAL_INC_STEP, KNL_SERIAL_INC_OFFSET) != OG_SUCCESS) {
return OG_ERROR;
}
int64 v_i64;
switch (column->datatype) {
case OG_TYPE_UINT32:
TO_UINT32_OVERFLOW_CHECK(value, int64);
uint32 ui32 = (uint32)value;
return row_put_uint32(ra, ui32);
case OG_TYPE_INTEGER:
v_i64 = (int64)value;
INT32_OVERFLOW_CHECK(v_i64);
int32 i32 = (int32)v_i64;
return row_put_int32(ra, i32);
case OG_TYPE_UINT64:
return row_put_uint64(ra, value);
case OG_TYPE_BIGINT:
v_i64 = (int64)value;
return row_put_int64(ra, v_i64);
default:
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "auto_increment column needs to be int or bigint");
return OG_ERROR;
}
}
static status_t db_set_default_value(knl_session_t *session, void *stmt, row_assist_t *ra, void *expr,
knl_cursor_t *cursor, knl_column_t *column)
{
variant_t value;
lob_locator_t *locator = NULL;
status_t status;
uint32 size_locator;
binary_t lob;
errno_t err;
if (g_knl_callback.exec_default(stmt, expr, &value) != OG_SUCCESS) {
return OG_ERROR;
}
if (value.is_null) {
if (!column->nullable) {
OG_THROW_ERROR(ERR_COLUMN_NOT_NULL, column->name);
return OG_ERROR;
}
row_put_null(ra);
return OG_SUCCESS;
}
switch (column->datatype) {
case OG_TYPE_BOOLEAN:
return row_put_bool(ra, VALUE(bool32, &value));
case OG_TYPE_UINT32:
return row_put_uint32(ra, VALUE(uint32, &value));
case OG_TYPE_INTEGER:
return row_put_int32(ra, VALUE(int32, &value));
case OG_TYPE_UINT64:
return row_put_uint64(ra, VALUE(uint64, &value));
case OG_TYPE_BIGINT:
return row_put_int64(ra, VALUE(int64, &value));
case OG_TYPE_REAL:
return row_put_real(ra, VALUE(double, &value));
case OG_TYPE_INTERVAL_DS:
return row_put_dsinterval(ra, value.v_itvl_ds);
case OG_TYPE_INTERVAL_YM:
return row_put_yminterval(ra, value.v_itvl_ym);
case OG_TYPE_TIMESTAMP:
case OG_TYPE_TIMESTAMP_TZ_FAKE:
case OG_TYPE_TIMESTAMP_LTZ:
return row_put_date(ra, VALUE(date_t, &value));
case OG_TYPE_TIMESTAMP_TZ:
return row_put_timestamp_tz(ra, VALUE_PTR(timestamp_tz_t, &value));
case OG_TYPE_CHAR:
case OG_TYPE_VARCHAR:
case OG_TYPE_STRING: {
CM_SAVE_STACK(session->stack);
g_knl_callback.keep_stack_variant(stmt, &value);
status = row_put_text(ra, VALUE_PTR(text_t, &value));
CM_RESTORE_STACK(session->stack);
return status;
}
case OG_TYPE_BLOB:
case OG_TYPE_CLOB:
case OG_TYPE_IMAGE: {
CM_SAVE_STACK(session->stack);
g_knl_callback.keep_stack_variant(stmt, &value);
size_locator = sizeof(lob_locator_t);
locator = (lob_locator_t *)cm_push(session->stack, OG_LOB_LOCATOR_BUF_SIZE);
err = memset_sp(locator, size_locator, 0xFF, size_locator);
knl_securec_check(err);
if (lob_set_column_default(session, cursor, locator, &value, column, stmt) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
cursor->set_default = OG_TRUE;
lob.size = knl_lob_locator_size(locator);
lob.bytes = (uint8 *)locator;
status = row_put_bin(ra, &lob);
CM_RESTORE_STACK(session->stack);
return status;
}
case OG_TYPE_NUMBER:
case OG_TYPE_NUMBER3:
case OG_TYPE_DECIMAL:
return row_put_dec4(ra, VALUE_PTR(dec8_t, &value));
case OG_TYPE_NUMBER2:
return row_put_dec2(ra, VALUE_PTR(dec8_t, &value));
case OG_TYPE_BINARY:
case OG_TYPE_RAW:
default: {
CM_SAVE_STACK(session->stack);
g_knl_callback.keep_stack_variant(stmt, &value);
status = row_put_bin(ra, VALUE_PTR(binary_t, &value));
CM_RESTORE_STACK(session->stack);
return status;
}
}
}
static status_t db_set_column_update_info(knl_session_t *session, void *stmt, uint32 old_col_count,
uint32 deleted_cols, knl_cursor_t *cursor)
{
uint32 new_col_count = knl_get_column_count(cursor->dc_entity);
dc_entity_t *entity = (dc_entity_t *)cursor->dc_entity;
knl_column_t *column = NULL;
row_assist_t ra;
uint32 i;
bool32 is_csf = knl_is_table_csf(entity, cursor->part_loc);
cursor->update_info.count = new_col_count + deleted_cols - old_col_count;
cm_row_init(&ra, cursor->update_info.data, OG_MAX_ROW_SIZE, new_col_count + deleted_cols - old_col_count, is_csf);
for (i = 0; i < deleted_cols; i++) {
row_put_null(&ra);
}
for (i = old_col_count; i < new_col_count; i++) {
column = knl_get_column(cursor->dc_entity, i);
cursor->update_info.columns[i + deleted_cols - old_col_count] = (uint16)i;
if (KNL_COLUMN_IS_SERIAL(column)) {
if (db_set_serial_value(session, stmt, &ra, entity, cursor, column) != OG_SUCCESS) {
return OG_ERROR;
}
} else if (column->default_text.len > 0) {
void *expr = column->default_expr;
int temp_timezone_offset = ((sql_stmt_t *)stmt)->session->nls_params.client_timezone;
errno_t ret = db_set_default_value(session, stmt, &ra, expr, cursor, column);
((sql_stmt_t *)stmt)->session->nls_params.client_timezone = temp_timezone_offset;
if (ret != OG_SUCCESS) {
return OG_ERROR;
}
} else {
row_put_null(&ra);
}
}
row_end(&ra);
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, NULL);
return OG_SUCCESS;
}
static status_t db_set_column_default_entity(knl_session_t *session, void *stmt, uint32 old_col_count,
uint32 deleted_cols, knl_cursor_t *cursor)
{
for (;;) {
if (knl_fetch(session, cursor) != OG_SUCCESS) {
lob_clean_all_default_segments(session, cursor->dc_entity, old_col_count);
return OG_ERROR;
}
if (cursor->eof) {
break;
}
if (db_set_column_update_info(session, stmt, old_col_count, deleted_cols, cursor) != OG_SUCCESS) {
lob_clean_all_default_segments(session, cursor->dc_entity, old_col_count);
return OG_ERROR;
}
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
lob_clean_all_default_segments(session, cursor->dc_entity, old_col_count);
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_try_set_column_default(knl_session_t *session, knl_dictionary_t *dc, void *stmt,
uint32 old_col_count, uint32 deleted_cols, knl_cursor_t *cursor)
{
table_part_t *table_part = NULL;
table_t *table = (table_t *)cursor->table;
if (!IS_PART_TABLE(table)) {
if (db_set_column_default_entity(session, stmt, old_col_count, deleted_cols, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
cursor->part_loc.part_no = i;
table_part = TABLE_GET_PART(table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
cursor->part_loc.subpart_no = OG_INVALID_ID32;
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_set_column_default_entity(session, stmt, old_col_count, deleted_cols, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
continue;
}
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
cursor->part_loc.subpart_no = j;
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_set_column_default_entity(session, stmt, old_col_count, deleted_cols,
cursor) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
}
return OG_SUCCESS;
}
static status_t db_set_column_default(knl_session_t *session, void *stmt, knl_dictionary_t *dc)
{
knl_cursor_t *cursor = NULL;
knl_dictionary_t new_dc;
knl_column_t *column = NULL;
uint32 deleted_cols = 0;
uint32 old_col_count = knl_get_column_count(dc->handle);
if (dc_open_table_private(session, dc->uid, dc->oid, &new_dc) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
cursor->action = CURSOR_ACTION_UPDATE;
if (knl_open_cursor(session, cursor, &new_dc) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
cursor->update_info.data = (char *)cm_push(session->stack, OG_MAX_ROW_SIZE);
dc_entity_t *entity = DC_ENTITY(&new_dc);
for (uint32 i = 0; i < old_col_count; i++) {
column = dc_get_column(entity, i);
if (KNL_COLUMN_IS_DELETED(column)) {
cursor->update_info.columns[deleted_cols++] = (uint16)i;
}
}
if (db_try_set_column_default(session, &new_dc, stmt, old_col_count, deleted_cols, cursor) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
dc_close_table_private(&new_dc);
return OG_ERROR;
}
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
dc_close_table_private(&new_dc);
return OG_SUCCESS;
}
static status_t db_update_table_desc(knl_session_t *session, knl_table_desc_t *desc, bool32 change_column_count,
bool32 is_add)
{
knl_scan_key_t *key = NULL;
uint32 column_count;
uint16 size;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_001_ID);
key = &cursor->scan_range.l_key;
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &desc->uid, sizeof(uint32),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_STRING, desc->name, (uint16)strlen(desc->name),
IX_COL_SYS_TABLE_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
column_count = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_TABLE_COL_COLS) +
(change_column_count ? (is_add ? 1 : (-1)) : 0);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 2);
(void)row_put_int64(&ra, db_inc_scn(session));
(void)row_put_int32(&ra, column_count);
cursor->update_info.count = 2;
cursor->update_info.columns[0] = SYS_TABLE_COL_CHG_SCN;
cursor->update_info.columns[1] = SYS_TABLE_COL_COLS;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_table_chgscn(knl_session_t *session, knl_table_desc_t *desc)
{
knl_cursor_t *cursor = NULL;
knl_scan_key_t *key = NULL;
uint16 size;
row_assist_t ra;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_001_ID);
key = &cursor->scan_range.l_key;
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &desc->uid, sizeof(uint32),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_STRING, desc->name, (uint16)strlen(desc->name),
IX_COL_SYS_TABLE_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_int64(&ra, db_inc_scn(session));
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_TABLE_COL_CHG_SCN;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_table_entry(knl_session_t *session, knl_table_desc_t *desc, page_id_t entry)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
uint16 size;
knl_scan_key_t *key = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, (void *)&desc->uid, sizeof(uint32),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_STRING, (void *)desc->name, (uint16)strlen(desc->name),
IX_COL_SYS_TABLE_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_int64(&ra, *(int64 *)&entry);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_TABLE_COL_ENTRY;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_update_table_pctfree(knl_session_t *session, knl_table_desc_t *desc, uint32 pctfree)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
uint16 size;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_001_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(uint32),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, desc->name,
(uint16)strlen(desc->name), IX_COL_SYS_TABLE_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_int32(&ra, pctfree);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_TABLE_COL_PCTFREE;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_update_table_initrans(knl_session_t *session, knl_table_desc_t *desc, uint32 initrans)
{
row_assist_t ra;
uint16 size;
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_001_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(uint32),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, desc->name,
(uint16)strlen(desc->name), IX_COL_SYS_TABLE_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_int32(&ra, initrans);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_TABLE_COL_INITRANS;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_table_flag(knl_session_t *session, uint32 user_id, uint32 table_id, table_flag_type_e flag_type)
{
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_002_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &user_id, sizeof(uint32),
IX_COL_SYS_TABLE_002_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &table_id, sizeof(uint32),
IX_COL_SYS_TABLE_002_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
row_assist_t ra;
knl_table_desc_t desc;
dc_convert_table_desc(cursor, &desc);
switch (flag_type) {
case TABLE_FLAG_TYPE_STORAGED:
desc.storaged = OG_TRUE;
break;
case TABLE_FLAG_TYPE_ENABLE_NOLOGGING:
desc.is_nologging = OG_TRUE;
break;
case TABLE_FLAG_TYPE_DISABLE_NOLOGGING:
desc.is_nologging = OG_FALSE;
break;
default:
knl_panic_log(0, "update table's flag to unsupport flag type");
}
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), UPDATE_COLUMN_COUNT_ONE);
(void)row_put_int32(&ra, (int32)desc.flags);
cursor->update_info.count = UPDATE_COLUMN_COUNT_ONE;
cursor->update_info.columns[0] = SYS_TABLE_COL_FLAG;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_update_storage_maxsize(knl_session_t *session, knl_cursor_t *cursor, uint64 orgscn,
uint32 max_pages)
{
row_assist_t ra;
uint16 size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_STORAGE_ID, IX_STORAGE_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 *)&orgscn,
sizeof(uint64), IX_COL_SYS_STORAGE_ORGSCN);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_int32(&ra, max_pages);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_STORAGE_COL_MAX_PAGES;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_update_table_appendonly(knl_session_t *session, knl_table_desc_t *desc, uint32 appendonly)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
uint16 size;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_001_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(uint32),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, desc->name,
(uint16)strlen(desc->name), IX_COL_SYS_TABLE_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, desc->name,
((index_t *)cursor->index)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_int32(&ra, appendonly);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_TABLE_COL_APPENDONLY;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_index_part_space(knl_session_t *session, knl_index_part_desc_t *desc, uint32 spc_id)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
uint16 size;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_INDEXPART_ID, IX_SYS_INDEXPART001_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(uint32), IX_COL_SYS_INDEXPART001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&desc->table_id,
sizeof(uint32), IX_COL_SYS_INDEXPART001_TABLE_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&desc->index_id,
sizeof(uint32), IX_COL_SYS_INDEXPART001_INDEX_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&desc->part_id,
sizeof(uint32), IX_COL_SYS_INDEXPART001_PART_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s", cursor->rowid.file,
cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, ((table_t *)cursor->table)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), UPDATE_COLUMN_COUNT_TWO);
(void)row_put_int32(&ra, spc_id);
(void)row_put_int32(&ra, desc->flags);
cursor->update_info.count = UPDATE_COLUMN_COUNT_TWO;
cursor->update_info.columns[0] = SYS_INDEXPART_COL_SPACE_ID;
cursor->update_info.columns[1] = SYS_INDEXPART_COL_FLAGS;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_index_entry(knl_session_t *session, knl_index_desc_t *desc, page_id_t entry)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
uint16 size;
knl_scan_key_t *key = NULL;
char idx_name[OG_NAME_BUFFER_SIZE];
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_INDEX_ID, IX_SYS_INDEX_002_ID);
knl_init_index_scan(cursor, OG_TRUE);
key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &desc->uid, sizeof(uint32),
IX_COL_SYS_INDEX_002_USER);
knl_get_index_name(desc, idx_name, OG_NAME_BUFFER_SIZE);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_STRING, idx_name, (uint16)strlen(idx_name),
IX_COL_SYS_INDEX_002_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
cursor->update_info.count = UPDATE_COLUMN_COUNT_TWO;
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), UPDATE_COLUMN_COUNT_TWO);
cursor->update_info.columns[0] = SYS_INDEX_COLUMN_ID_ENTRY;
cursor->update_info.columns[1] = SYS_INDEX_COLUMN_ID_SPACE;
(void)row_put_int64(&ra, *(int64 *)&entry);
(void)row_put_uint32(&ra, desc->space_id);
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_lob_entry(knl_session_t *session, knl_lob_desc_t *desc, page_id_t entry)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
uint16 size;
knl_scan_key_t *key = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_LOB_ID, IX_SYS_LOB001_ID);
knl_init_index_scan(cursor, OG_TRUE);
key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &desc->uid, sizeof(uint32),
IX_COL_SYS_LOB001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &desc->table_id, sizeof(uint32),
IX_COL_SYS_LOB001_TABLE_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &desc->column_id, sizeof(uint32),
IX_COL_SYS_LOB001_COLUMN_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 2);
(void)row_put_int64(&ra, *(int64 *)&entry);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_LOB_COL_ENTRY;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_table_policy(knl_session_t *session, uint32 uid, const char *name, text_t *new_name)
{
row_assist_t row;
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_POLICY_ID, IX_SYS_POLICY_001_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 *)&uid, sizeof(uint32), IX_COL_SYS_POLICY_001_OBJ_SCHEMA_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER,
(void *)&uid, sizeof(uint32), IX_COL_SYS_POLICY_001_OBJ_SCHEMA_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)name, (uint16)strlen(name), IX_COL_SYS_POLICY_001_OBJ_NAME);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_STRING,
(void *)name, (uint16)strlen(name), IX_COL_SYS_POLICY_001_OBJ_NAME);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_POLICY_001_PNAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_POLICY_001_PNAME);
for (;;) {
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
break;
}
row_init(&row, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), UPDATE_COLUMN_COUNT_ONE);
if (row_put_text(&row, new_name) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
cursor->update_info.count = UPDATE_COLUMN_COUNT_ONE;
cursor->update_info.columns[0] = SYS_POLICIES_COL_OBJ_NAME;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_shadow_index_entry(knl_session_t *session, knl_index_desc_t *desc, page_id_t entry)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
uint16 size;
knl_scan_key_t *key = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_SHADOW_INDEX_ID, IX_SYS_SHADOW_INDEX_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &desc->uid, sizeof(uint32),
IX_COL_SYS_SHADOW_INDEX_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &desc->table_id, sizeof(uint32),
IX_COL_SYS_SHADOW_INDEX_001_TABLE_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!cursor->eof) {
cursor->update_info.count = UPDATE_COLUMN_COUNT_ONE;
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), UPDATE_COLUMN_COUNT_ONE);
cursor->update_info.columns[0] = SYS_SHADOW_INDEX_COL_ENTRY;
(void)row_put_int64(&ra, *(int64 *)&entry);
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_table_name(knl_session_t *session, uint32 uid, const char *name, text_t *new_name,
bool32 recycled)
{
knl_cursor_t *cursor = NULL;
uint16 size;
row_assist_t ra;
knl_scan_key_t *key = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_STRING, name, (uint16)strlen(name),
IX_COL_SYS_TABLE_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s", cursor->rowid.file,
cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, ((table_t *)cursor->table)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 2);
(void)row_put_text(&ra, new_name);
(void)row_put_int32(&ra, recycled);
cursor->update_info.count = 2;
cursor->update_info.columns[0] = SYS_TABLE_COL_NAME;
cursor->update_info.columns[1] = SYS_TABLE_COL_RECYCLED;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_index_name(knl_session_t *session, uint32 uid, uint32 table_id, const char *name, text_t *new_name)
{
knl_cursor_t *cursor = NULL;
uint16 size;
row_assist_t ra;
knl_scan_key_t *key = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_INDEX_ID, IX_SYS_INDEX_002_ID);
knl_init_index_scan(cursor, OG_TRUE);
key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_INDEX_002_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_STRING, name, (uint16)strlen(name),
IX_COL_SYS_INDEX_002_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, ((index_t *)cursor->index)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_text(&ra, new_name);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_INDEX_COLUMN_ID_NAME;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_index_initrans(knl_session_t *session, knl_index_desc_t *desc, uint32 initrans)
{
uint16 size;
row_assist_t ra;
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_INDEX_ID, IX_SYS_INDEX_002_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_scan_key_t *key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, &desc->uid, sizeof(uint32),
IX_COL_SYS_INDEX_002_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_STRING, desc->name, (uint16)strlen(desc->name),
IX_COL_SYS_INDEX_002_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s index %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name, desc->name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_int32(&ra, initrans);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_INDEX_COLUMN_ID_INITRANS;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_subpart_judge_null(knl_session_t *session, knl_dictionary_t *dc, knl_part_locate_t part_loc,
bool32 *is_null)
{
knl_panic(part_loc.part_no != OG_INVALID_ID32);
knl_panic(part_loc.subpart_no != OG_INVALID_ID32);
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
cursor->action = CURSOR_ACTION_SELECT;
cursor->part_loc = part_loc;
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
*is_null = cursor->eof;
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_part_judge_null(knl_session_t *session, knl_dictionary_t *dc, knl_part_locate_t part_loc,
bool32 *is_null)
{
table_t *table = DC_TABLE(dc);
table_part_t *compart = TABLE_GET_PART(table, part_loc.part_no);
*is_null = OG_TRUE;
if (!IS_PARENT_TABPART(&compart->desc)) {
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
cursor->action = CURSOR_ACTION_SELECT;
cursor->part_loc = part_loc;
knl_panic(part_loc.subpart_no == OG_INVALID_ID32);
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
*is_null = cursor->eof;
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
bool32 subpart_is_null = OG_FALSE;
for (uint32 i = 0; i < compart->desc.subpart_cnt; i++) {
part_loc.subpart_no = i;
if (db_subpart_judge_null(session, dc, part_loc, &subpart_is_null) != OG_SUCCESS) {
return OG_ERROR;
}
if (!subpart_is_null) {
*is_null = OG_FALSE;
break;
}
}
return OG_SUCCESS;
}
static status_t db_part_table_judge_null(knl_session_t *session, knl_dictionary_t *dc, bool32 *all_null)
{
knl_part_locate_t part_loc;
bool32 is_null = OG_FALSE;
table_t *table = DC_TABLE(dc);
table_part_t *table_part = NULL;
*all_null = OG_TRUE;
part_loc.subpart_no = OG_INVALID_ID32;
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
part_loc.part_no = i;
if (db_part_judge_null(session, dc, part_loc, &is_null) != OG_SUCCESS) {
return OG_ERROR;
}
if (!is_null) {
*all_null = OG_FALSE;
break;
}
}
return OG_SUCCESS;
}
static status_t db_table_judge_null(knl_session_t *session, knl_dictionary_t *dc, bool32 *all_null)
{
table_t *table = DC_TABLE(dc);
if (IS_PART_TABLE(table)) {
return db_part_table_judge_null(session, dc, all_null);
}
*all_null = OG_TRUE;
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
cursor->action = CURSOR_ACTION_SELECT;
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
*all_null = cursor->eof;
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_part_is_empty(knl_session_t *session, knl_dictionary_t *dc, table_t *table, table_part_t *table_part,
bool32 *is_empty)
{
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
cursor->action = CURSOR_ACTION_SELECT;
cursor->is_found = OG_FALSE;
if (IS_PARENT_TABPART(&table_part->desc)) {
*is_empty = OG_TRUE;
cursor->part_loc.part_no = table_part->part_no;
for (uint32 i = 0; i < table_part->desc.subpart_cnt; i++) {
cursor->part_loc.subpart_no = i;
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->is_found) {
*is_empty = OG_FALSE;
break;
}
}
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
if (IS_SUB_TABPART(&table_part->desc)) {
table_part_t *compart = PART_GET_ENTITY(table->part_table, table_part->parent_partno);
knl_panic_log(compart != NULL,
"current compart is NULL, panic info: page %u-%u type %u table %s table_part %s", cursor->rowid.file,
cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, table->desc.name, table_part->desc.name);
cursor->part_loc.part_no = compart->part_no;
cursor->part_loc.subpart_no = table_part->part_no;
} else {
cursor->part_loc.part_no = table_part->part_no;
cursor->part_loc.subpart_no = OG_INVALID_ID32;
}
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
*is_empty = cursor->eof;
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_need_invalidate_index(knl_session_t *session, knl_dictionary_t *dc, table_t *table,
table_part_t *table_part, bool32 *is_need)
{
index_t *index = NULL;
uint32 i;
for (i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (!index->desc.parted && !index->desc.is_invalid) {
break;
}
}
if (i == table->index_set.total_count) {
*is_need = OG_FALSE;
return OG_SUCCESS;
}
bool32 is_empty = OG_TRUE;
if (db_part_is_empty(session, dc, table, table_part, &is_empty) != OG_SUCCESS) {
return OG_ERROR;
}
*is_need = !is_empty;
return OG_SUCCESS;
}
static status_t db_prepare_add_column(knl_session_t *session, knl_dictionary_t *dc, knl_column_def_t *def)
{
dc_entity_t *entity = DC_ENTITY(dc);
bool32 is_table_null = OG_FALSE;
char col_name[OG_NAME_BUFFER_SIZE];
if (entity->column_count >= session->kernel->attr.max_column_count - 1) {
OG_THROW_ERROR(ERR_MAX_COLUMN_SIZE, session->kernel->attr.max_column_count - 1);
return OG_ERROR;
}
if (db_table_judge_null(session, dc, &is_table_null) != OG_SUCCESS) {
return OG_ERROR;
}
if (!def->is_serial && !def->nullable && !is_table_null && CM_IS_EMPTY(&def->default_text)) {
(void)cm_text2str(&def->name, col_name, OG_NAME_BUFFER_SIZE);
OG_THROW_ERROR(ERR_COLUMN_NOT_NULL, col_name);
return OG_ERROR;
}
if (entity->has_serial_col && def->is_serial) {
OG_THROW_ERROR(ERR_DUPLICATE_AUTO_COLUMN);
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_table_data_judge_empty(knl_session_t *session, knl_dictionary_t *dc, bool32 *is_empty)
{
knl_cursor_t *cursor = NULL;
table_t *table = NULL;
*is_empty = OG_TRUE;
status_t status = OG_SUCCESS;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
cursor->action = CURSOR_ACTION_SELECT;
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
do {
if (knl_fetch(session, cursor) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
if (!cursor->eof) {
*is_empty = OG_FALSE;
break;
}
table = (table_t *)(cursor->table);
if (IS_PART_TABLE(table)) {
for (uint32 i = 1; i < table->part_table->desc.partcnt; i++) {
cursor->part_loc.part_no = i;
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
if (knl_fetch(session, cursor) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
if (!cursor->eof) {
*is_empty = OG_FALSE;
break;
}
}
}
} while (0);
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return status;
}
static status_t db_altable_create_inline_constraints(knl_session_t *session, knl_dictionary_t *dc,
galist_t *column_list, bool32 is_modify)
{
knl_alt_column_prop_t *col_prop = NULL;
knl_dictionary_t new_dc;
uint32 i;
uint32 j;
bool32 is_empty = OG_FALSE;
knl_constraint_def_t *cons = NULL;
for (i = 0; i < column_list->count; i++) {
col_prop = (knl_alt_column_prop_t *)cm_galist_get(column_list, i);
if (!col_prop->new_column.is_check && !col_prop->new_column.unique && !col_prop->new_column.primary) {
continue;
}
if (dc_open_table_private(session, dc->uid, dc->oid, &new_dc) != OG_SUCCESS) {
return OG_ERROR;
}
for (j = 0; j < col_prop->constraints.count; j++) {
cons = (knl_constraint_def_t *)cm_galist_get(&col_prop->constraints, j);
if (is_modify && col_prop->new_column.is_check && cons->cons_state.is_validate) {
if (db_table_data_judge_empty(session, dc, &is_empty) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
return OG_ERROR;
}
if (!is_empty && db_verify_check_data(session, &new_dc, &cons->check.text) !=
OG_SUCCESS) {
dc_close_table_private(&new_dc);
return OG_ERROR;
}
}
if (db_create_cons(session, &new_dc, cons) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
return OG_ERROR;
}
}
dc_close_table_private(&new_dc);
}
return OG_SUCCESS;
}
static status_t db_altable_add_column_check_systable(knl_session_t *session, knl_dictionary_t *dc,
knl_column_def_t *new_column)
{
if (!DB_IS_MAINTENANCE(session) && IS_SYS_DC(dc)) {
if (!new_column->nullable) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_altable_add_column(knl_session_t *session, knl_dictionary_t *dc, void *stmt, knl_altable_def_t *def)
{
knl_cursor_t *cursor = NULL;
table_t *table = NULL;
dc_entity_t *entity = NULL;
knl_column_t column = {0};
knl_column_def_t *new_column = NULL;
knl_alt_column_prop_t *column_def = NULL;
uint32 i;
knl_dictionary_t new_dc;
bool32 update_default = OG_FALSE;
space_t *space = NULL;
for (i = 0; i < def->column_defs.count; i++) {
column_def = (knl_alt_column_prop_t *)cm_galist_get(&def->column_defs, i);
new_column = &column_def->new_column;
if (db_altable_add_column_check_systable(session, dc, new_column) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "alter table add not nullable column", "system table");
return OG_ERROR;
}
if (dc_open_table_private(session, dc->uid, dc->oid, &new_dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (knl_find_column(&new_column->name, &new_dc) != NULL) {
dc_close_table_private(&new_dc);
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "column", T2S(&new_column->name));
return OG_ERROR;
}
if (db_prepare_add_column(session, &new_dc, new_column) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
table = DC_TABLE(&new_dc);
entity = DC_ENTITY(&new_dc);
cursor = knl_push_cursor(session);
column.name = (char *)cm_push(session->stack, OG_NAME_BUFFER_SIZE);
db_convert_column_def(&column, table->desc.uid, table->desc.id, new_column, NULL, entity->column_count);
if (db_write_syscolumn(session, cursor, &column) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
dc_close_table_private(&new_dc);
return OG_ERROR;
}
if (COLUMN_IS_LOB(&column) || KNL_COLUMN_IS_ARRAY(&column)) {
if (db_create_lob(session, table, &column, NULL) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (db_update_table_desc(session, &table->desc, OG_TRUE, OG_TRUE) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
space = SPACE_GET(session, table->desc.space_id);
if (SPACE_IS_ENCRYPT(space) && (!COLUMN_IS_LOB(&column))) {
if (new_column->typmod.size > OG_MAX_COLUMN_SIZE - OG_KMC_MAX_CIPHER_SIZE) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_ENCRYPTION_NOT_SUPPORT_DDL, "column size should less than",
OG_MAX_COLUMN_SIZE - OG_KMC_MAX_CIPHER_SIZE);
return OG_ERROR;
}
}
if (new_column->is_default || new_column->is_serial) {
update_default = OG_TRUE;
}
if (new_column->is_comment) {
knl_comment_def_t comment_def;
comment_def.uid = column.uid;
comment_def.id = column.table_id;
comment_def.column_id = column.id;
comment_def.comment = new_column->comment;
comment_def.type = COMMENT_ON_COLUMN;
if (OG_SUCCESS != db_comment_on(session, &comment_def)) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
}
if (update_default) {
if (db_set_column_default(session, stmt, dc) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (db_altable_create_inline_constraints(session, dc, &def->column_defs, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_column_entity_judge_null(knl_session_t *session, knl_cursor_t *cursor, uint32 column_id,
bool32 *all_null, bool32 *include_null)
{
*include_null = OG_FALSE;
*all_null = OG_TRUE;
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
while (!cursor->eof) {
if (ROW_COLUMN_COUNT(cursor->row) > column_id) {
cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, NULL);
if (CURSOR_COLUMN_SIZE(cursor, column_id) != OG_NULL_VALUE_LEN) {
*all_null = OG_FALSE;
} else {
*include_null = OG_TRUE;
if (*all_null == OG_FALSE) {
return OG_SUCCESS;
}
}
} else {
*include_null = OG_TRUE;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_column_part_judge_null(knl_session_t *session, knl_dictionary_t *dc, knl_cursor_t *cursor,
uint32 column_id, bool32 *all_null, bool32 *include_null)
{
table_t *table = (table_t *)cursor->table;
table_part_t *compart = TABLE_GET_PART(table, cursor->part_loc.part_no);
if (!IS_READY_PART(compart)) {
return OG_SUCCESS;
}
if (!IS_PARENT_TABPART(&compart->desc)) {
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
return OG_ERROR;
}
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
if (db_column_entity_judge_null(session, cursor, column_id, all_null, include_null) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
for (uint32 i = 0; i < compart->desc.subpart_cnt; i++) {
cursor->part_loc.subpart_no = i;
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
return OG_ERROR;
}
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
if (db_column_entity_judge_null(session, cursor, column_id, all_null, include_null) != OG_SUCCESS) {
return OG_ERROR;
}
if (!(*all_null)) {
return OG_SUCCESS;
}
}
return OG_SUCCESS;
}
static status_t db_column_judge_null(knl_session_t *session, uint32 column_id, knl_dictionary_t *dc,
bool32 *all_null, bool32 *include_null)
{
knl_cursor_t *cursor = NULL;
table_t *table = NULL;
*all_null = OG_TRUE;
*include_null = OG_FALSE;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
cursor->action = CURSOR_ACTION_SELECT;
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
table = (table_t *)(cursor->table);
if (!IS_PART_TABLE(table)) {
if (db_column_entity_judge_null(session, cursor, column_id, all_null, include_null)) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
cursor->part_loc.part_no = i;
if (db_column_part_judge_null(session, dc, cursor, column_id, all_null, include_null) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!(*all_null)) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
}
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_modify_column_in_syscolumn(knl_session_t *session, knl_column_t *column, knl_table_desc_t *desc)
{
uint16 size;
row_assist_t ra;
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_COLUMN_ID, IX_SYS_COLUMN_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_scan_key_t *key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, (void *)&desc->uid, sizeof(uint32),
IX_COL_SYS_COLUMN_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, (void *)&desc->id, sizeof(uint32),
IX_COL_SYS_COLUMN_001_TABLE_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, (void *)&column->id, sizeof(uint32),
IX_COL_SYS_COLUMN_001_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s", cursor->rowid.file,
cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, desc->name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 9);
(void)row_put_int32(&ra, column->datatype);
(void)row_put_int32(&ra, column->size);
row_put_prec_and_scale(&ra, column->datatype, column->precision, column->scale);
(void)row_put_int32(&ra, column->nullable);
(void)row_put_int32(&ra, column->flags);
if (KNL_COLUMN_IS_DEFAULT_NULL(column)) {
(void)row_put_null(&ra);
} else {
(void)row_put_text(&ra, &column->default_text);
}
row_put_null(&ra);
cursor->update_info.count = 8;
cursor->update_info.columns[0] = SYS_COLUMN_COL_DATATYPE;
cursor->update_info.columns[1] = SYS_COLUMN_COL_BYTES;
cursor->update_info.columns[2] = SYS_COLUMN_COL_PRECISION;
cursor->update_info.columns[3] = SYS_COLUMN_COL_SCALE;
cursor->update_info.columns[4] = SYS_COLUMN_COL_NULLABLE;
cursor->update_info.columns[5] = SYS_COLUMN_COL_FLAGS;
cursor->update_info.columns[6] = SYS_COLUMN_COL_DEFAULT_TEXT;
cursor->update_info.columns[7] = SYS_COLUMN_COL_OPTIONS;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (OG_SUCCESS != knl_internal_update(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_modify_vcolumn_in_syscolumn(knl_session_t *session, knl_dictionary_t *dc, index_t *index,
knl_column_t *new_column)
{
uint32 col_id;
typmode_t typmode;
knl_icol_info_t *icol = NULL;
knl_column_t *vcolumn = NULL;
table_t *table = DC_TABLE(dc);
dc_entity_t *entity = index->entity;
for (uint32 i = 0; i < index->desc.column_count; i++) {
col_id = index->desc.columns[i];
icol = &index->desc.columns_info[i];
if (col_id < DC_VIRTUAL_COL_START || icol->arg_cols[0] != new_column->id) {
continue;
}
vcolumn = dc_get_column(entity, col_id);
typmode.datatype = new_column->datatype;
typmode.size = new_column->size;
if (g_knl_callback.get_func_index_size(session, &vcolumn->default_text, &typmode) != OG_SUCCESS) {
return OG_ERROR;
}
if (typmode.size != vcolumn->size) {
vcolumn->size = typmode.size;
if (db_modify_column_in_syscolumn(session, vcolumn, &table->desc) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_judge_modify_part_column(table_t *table, knl_column_t *old_column, knl_column_t *new_column)
{
part_table_t *part_table = table->part_table;
for (uint32 i = 0; i < part_table->desc.partkeys; i++) {
if (part_table->keycols[i].column_id == old_column->id) {
if (old_column->datatype != new_column->datatype || old_column->size != new_column->size) {
OG_THROW_ERROR(ERR_MODIFY_PART_COLUMN);
return OG_ERROR;
}
return OG_SUCCESS;
}
}
for (uint32 i = 0; i < part_table->desc.subpartkeys; i++) {
if (part_table->sub_keycols[i].column_id == old_column->id) {
if (old_column->datatype != new_column->datatype || old_column->size != new_column->size) {
OG_THROW_ERROR(ERR_MODIFY_PART_COLUMN);
return OG_ERROR;
}
return OG_SUCCESS;
}
}
return OG_SUCCESS;
}
static bool32 db_column_in_list(uint16 *col_list, uint32 col_count, knl_column_t *column)
{
uint32 i;
for (i = 0; i < col_count; i++) {
if (column->id == col_list[i]) {
return OG_TRUE;
}
}
return OG_FALSE;
}
static status_t db_drop_old_part_lob(knl_session_t *session, knl_cursor_t *cursor, table_t *table, knl_column_t *column)
{
lob_part_t *lob_part = NULL;
lob_part_t *lob_subpart = NULL;
table_part_t *table_part = NULL;
lob_t *lob = (lob_t *)column->lob;
part_table_t *part_table = table->part_table;
uint32 total_partcnt = part_table->desc.partcnt + part_table->desc.not_ready_partcnt;
for (uint32 i = 0; i < total_partcnt; ++i) {
table_part = TABLE_GET_PART(table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
lob_part = LOB_GET_PART(lob, i);
OG_LOG_DEBUG_INF("modify lob column: delete lob part, uid: %d, tid: %d, column id: %d, part_id: %d",
lob_part->desc.uid, lob_part->desc.table_id, lob_part->desc.column_id, lob_part->desc.part_id);
if (db_delete_from_syslobpart(session, cursor, lob_part->desc.uid, lob_part->desc.table_id,
lob_part->desc.column_id, lob_part->desc.part_id) != OG_SUCCESS) {
return OG_ERROR;
}
if (!IS_PARENT_LOBPART(&lob_part->desc)) {
if (lob_part_segment_prepare(session, lob_part, OG_FALSE, LOB_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
continue;
}
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
lob_subpart = PART_GET_SUBENTITY(lob->part_lob, lob_part->subparts[j]);
if (lob_subpart == NULL) {
continue;
}
OG_LOG_DEBUG_INF("modify lob column: delete lob subpart, parent_partid %d, part_id: %d",
lob_part->desc.part_id, lob_subpart->desc.part_id);
if (db_delete_sublobparts_with_compart(session, cursor, lob_subpart->desc.uid,
lob_subpart->desc.table_id, lob_subpart->desc.column_id, lob_part->desc.part_id) != OG_SUCCESS) {
return OG_ERROR;
}
if (lob_part_segment_prepare(session, lob_subpart, OG_FALSE, LOB_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_altable_modify_lob_column(knl_session_t *session, table_t *table, knl_column_t *old_column,
knl_column_t *new_column)
{
if (COLUMN_IS_LOB(old_column) && COLUMN_IS_LOB(new_column)) {
if (old_column->nullable != new_column->nullable || !CM_IS_EMPTY(&new_column->default_text)) {
return OG_SUCCESS;
}
OG_THROW_ERROR(ERR_INVALID_OPERATION, ",invalid modification of columns");
return OG_ERROR;
}
if (COLUMN_IS_LOB(old_column)) {
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
lob_t *lob = (lob_t *)old_column->lob;
if (db_delete_from_syslob(session, cursor, table->desc.uid, table->desc.id, old_column->id) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (lob_segment_prepare(session, lob, OG_FALSE, LOB_DROP_SEGMENT) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (table->desc.parted) {
if (db_drop_old_part_lob(session, cursor, table, old_column) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
}
if (COLUMN_IS_LOB(new_column)) {
if (db_create_lob(session, table, new_column, NULL) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static bool32 db_column_in_icol_list(index_t *index, knl_column_t *old_col)
{
uint32 i;
knl_icol_info_t *icol = NULL;
if (!index->desc.is_func) {
return OG_FALSE;
}
for (i = 0; i < index->desc.column_count; i++) {
icol = &index->desc.columns_info[i];
if (!icol->is_func) {
continue;
}
if (old_col->id == icol->arg_cols[0]) {
return OG_TRUE;
}
}
return OG_FALSE;
}
static uint32 db_get_func_index_keysize(knl_session_t *session, index_t *index, knl_column_t *new_column,
bool32 is_pcr, uint32 *key_size)
{
uint32 id;
typmode_t typmode;
text_t *func_text = NULL;
knl_column_t *column = NULL;
dc_entity_t *entity = index->entity;
knl_icol_info_t *columns_info = NULL;
*key_size = is_pcr ? sizeof(pcrb_key_t) + sizeof(pcrb_dir_t) : sizeof(btree_key_t) + sizeof(btree_dir_t);
for (id = 0; id < index->desc.column_count; id++) {
column = dc_get_column(entity, index->desc.columns[id]);
columns_info = &index->desc.columns_info[id];
if (columns_info->is_func) {
func_text = &column->default_text;
if (new_column->id == columns_info->arg_cols[0]) {
virtual column size should be recalculated */
typmode.datatype = new_column->datatype;
typmode.size = new_column->size;
if (g_knl_callback.get_func_index_size(session, func_text, &typmode) != OG_SUCCESS) {
return OG_ERROR;
}
(*key_size) += btree_max_column_size(typmode.datatype, typmode.size, is_pcr);
} else {
(*key_size) += btree_max_column_size(column->datatype, column->size, is_pcr);
}
} else {
if (new_column->id == column->id) {
(*key_size) += btree_max_column_size(new_column->datatype, new_column->size, is_pcr);
} else {
(*key_size) += btree_max_column_size(column->datatype, column->size, is_pcr);
}
}
}
return OG_SUCCESS;
}
static status_t db_verify_index_key_size(knl_session_t *session, index_t *index, knl_column_t *old_column,
knl_column_t *new_column)
{
uint32 key_size;
uint32 max_key_size;
uint16 old_col_size;
uint16 new_col_size;
bool32 is_pcr = (index->desc.cr_mode == CR_PAGE);
if (index->desc.is_func) {
if (db_get_func_index_keysize(session, index, new_column, is_pcr, &key_size) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
old_col_size = btree_max_column_size(old_column->datatype, old_column->size, is_pcr);
new_col_size = btree_max_column_size(new_column->datatype, new_column->size, is_pcr);
key_size = btree_max_key_size(index) + new_col_size - old_col_size;
}
max_key_size = btree_max_allowed_size(session, &index->desc);
if (key_size > max_key_size) {
OG_THROW_ERROR(ERR_MAX_KEYLEN_EXCEEDED, max_key_size);
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_verify_index_column(knl_session_t *session, knl_dictionary_t *dc, knl_column_t *new_column,
bool32 compatible, bool32 *need_rebuild, uint32 index_count)
{
uint32 i;
index_t *index = NULL;
table_t *table = DC_TABLE(dc);
knl_column_t *old_column = knl_get_column(dc->handle, new_column->id);
bool32 type_changed = (old_column->datatype != new_column->datatype);
bool32 need_rebuild_force = (new_column->datatype == OG_TYPE_BIGINT && old_column->datatype == OG_TYPE_INTEGER);
for (i = 0; i < index_count; i++) {
index = table->index_set.items[i];
if (!db_column_in_list(index->desc.columns, index->desc.column_count, old_column)) {
if (!db_column_in_icol_list(index, old_column)) {
continue;
}
}
if (index->desc.primary && new_column->nullable) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, " primary key cannot be modified to null");
return OG_ERROR;
}
if (!index->desc.is_func && COLUMN_IS_LOB(new_column)) {
OG_THROW_ERROR(ERR_CREATE_INDEX_ON_TYPE, IS_REVERSE_INDEX(&index->desc) ? "reverse" : "normal",
get_datatype_name_str(new_column->datatype));
return OG_ERROR;
}
if ((COLUMN_IS_REAL(new_column) && IS_REVERSE_INDEX(&index->desc))) {
OG_THROW_ERROR(ERR_CREATE_INDEX_ON_TYPE, "reverse", get_datatype_name_str(new_column->datatype));
return OG_ERROR;
}
if (index->desc.is_func) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify column", "functional index");
return OG_ERROR;
}
if (session->kernel->attr.enable_idx_key_len_check &&
db_verify_index_key_size(session, index, old_column, new_column) != OG_SUCCESS) {
return OG_ERROR;
}
if (type_changed) {
if (index->dep_set.count > 0) {
OG_THROW_ERROR(ERR_COL_TYPE_MISMATCH);
return OG_ERROR;
}
if (!compatible || need_rebuild_force) {
need_rebuild[i] = OG_TRUE;
}
}
}
return OG_SUCCESS;
}
static status_t db_modify_column_index(knl_session_t *session, knl_dictionary_t *dc, bool32 *rebuild_indexes,
knl_column_t *new_column, uint32 index_count)
{
table_t *table = DC_TABLE(dc);
index_t *index = NULL;
knl_alindex_def_t rebuild_def;
for (uint32 i = 0; i < index_count; i++) {
index = table->index_set.items[i];
if (index->desc.is_func) {
if (db_modify_vcolumn_in_syscolumn(session, dc, index, new_column) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (!rebuild_indexes[i]) {
continue;
}
if (table->desc.type == TABLE_TYPE_TRANS_TEMP || table->desc.type == TABLE_TYPE_SESSION_TEMP) {
if (index->desc.is_func) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW,
"functional join index is defined on the column in global temporary table to be modified");
return OG_ERROR;
}
if (!knl_is_temp_table_empty(session, table->desc.uid, table->desc.id)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT,
"would cause rebuiding index, which", "non-empty temporary table");
return OG_ERROR;
}
}
rebuild_def.type = ALINDEX_TYPE_REBUILD;
cm_str2text(index->desc.name, &rebuild_def.name);
rebuild_def.rebuild.is_online = OG_FALSE;
rebuild_def.rebuild.parallelism = 0;
rebuild_def.rebuild.specified_parts = 0;
rebuild_def.rebuild.space.len = 0;
rebuild_def.rebuild.space.str = NULL;
rebuild_def.rebuild.pctfree = index->desc.pctfree;
rebuild_def.rebuild.cr_mode = index->desc.cr_mode;
rebuild_def.rebuild.lock_timeout = LOCK_INF_WAIT;
if (db_alter_index_rebuild(session, &rebuild_def, dc, index) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static bool32 db_modify_column_null_only(knl_column_t *old_column, knl_column_t *new_column)
{
if (old_column->id == new_column->id &&
cm_str_equal_ins(old_column->name, new_column->name) &&
old_column->uid == new_column->uid &&
old_column->table_id == new_column->table_id &&
old_column->datatype == new_column->datatype &&
old_column->size == new_column->size &&
(old_column->precision == new_column->precision) &&
old_column->scale == new_column->scale) {
return OG_TRUE;
}
return OG_FALSE;
}
static inline bool32 db_is_number_compatible(knl_column_t *old_column, knl_column_t *new_column)
{
int32 old_int_scale;
int32 new_int_scale;
if (OG_IS_NUMBER2_TYPE(old_column->datatype) && !OG_IS_NUMBER2_TYPE(new_column->datatype)) {
return OG_FALSE;
}
if (!OG_IS_NUMBER2_TYPE(old_column->datatype) && OG_IS_NUMBER2_TYPE(new_column->datatype)) {
return OG_FALSE;
}
if (old_column->precision == OG_UNSPECIFIED_NUM_PREC) {
return (new_column->precision == OG_UNSPECIFIED_NUM_PREC);
}
if (new_column->precision == OG_UNSPECIFIED_NUM_PREC) {
return OG_TRUE;
}
if (old_column->scale > new_column->scale) {
return OG_FALSE;
}
old_int_scale = old_column->precision - old_column->scale;
new_int_scale = new_column->precision - new_column->scale;
return (old_int_scale <= new_int_scale);
}
static bool32 db_is_column_compatible(knl_column_t *old_column, knl_column_t *new_column, bool32 *type_changed)
{
*type_changed = (old_column->datatype != new_column->datatype);
if (*type_changed) {
if (OG_IS_STRING_TYPE2(old_column->datatype, new_column->datatype)) {
return (old_column->size <= new_column->size);
} else if (OG_IS_NUMBER_TYPE(old_column->datatype) && OG_IS_NUMBER_TYPE(new_column->datatype)) {
return db_is_number_compatible(old_column, new_column);
} else {
return (new_column->datatype == OG_TYPE_BIGINT && old_column->datatype == OG_TYPE_INTEGER);
}
}
if (old_column->datatype == OG_TYPE_BINARY || OG_IS_STRING_TYPE(old_column->datatype)) {
return (old_column->size <= new_column->size);
} else if (OG_IS_NUMBER_TYPE(old_column->datatype) && OG_IS_NUMBER_TYPE(new_column->datatype)) {
return db_is_number_compatible(old_column, new_column);
} else {
return OG_FALSE;
}
}
static status_t db_is_modify_array_column(knl_column_t *old_column, knl_column_t *new_column)
{
if (KNL_COLUMN_IS_ARRAY(old_column) != KNL_COLUMN_IS_ARRAY(new_column)) {
OG_THROW_ERROR(ERR_MODIFY_ARRAY_COLUMN, old_column->name, KNL_COLUMN_IS_ARRAY(old_column) ? "non-" : "");
return OG_ERROR;
}
if (KNL_COLUMN_IS_ARRAY(old_column) && old_column->datatype != new_column->datatype) {
OG_THROW_ERROR(ERR_MODIFY_ARRAY_DATATYPE, old_column->name);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_check_rule_exists_by_name(knl_session_t *session, knl_ddm_def_t *def)
{
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_DDM_ID, IX_SYS_DDM_002_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 *)&def->uid,
sizeof(uint32), IX_COL_SYS_DDM_002_UID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&def->oid,
sizeof(uint32), IX_COL_SYS_DDM_002_OID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, def->rulename,
(uint16)strlen(def->rulename), IX_COL_SYS_DDM_002_RULENAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof == OG_FALSE) {
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR_EX(ERR_INVALID_OPERATION, ",this object does not have this ddm rule.");
return OG_ERROR;
}
status_t db_drop_ddm_rule_by_name(knl_session_t *session, knl_ddm_def_t *def)
{
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_DDM_ID, IX_SYS_DDM_002_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 *)&def->uid,
sizeof(uint32), IX_COL_SYS_DDM_002_UID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&def->oid,
sizeof(uint32), IX_COL_SYS_DDM_002_OID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, def->rulename,
(uint16)strlen(def->rulename), IX_COL_SYS_DDM_002_RULENAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_check_ddm_rule_by_col(knl_session_t *session, uint32 uid, uint32 oid, uint32 colid)
{
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_DDM_ID, IX_SYS_DDM_001_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 *)&uid,
sizeof(uint32), IX_COL_SYS_DDM_001_UID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&oid,
sizeof(uint32), IX_COL_SYS_DDM_001_OID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&colid,
sizeof(uint32), IX_COL_SYS_DDM_001_COLID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!cursor->eof) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR_EX(ERR_INVALID_OPERATION, ", this col has rule , please drop rule firstly.");
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_check_col_ddm_rule(knl_session_t *session, knl_dictionary_t *dc, knl_column_t *new_column)
{
dc_entity_t *entity = DC_ENTITY(dc);
knl_column_t *old_column = dc_get_column(entity, new_column->id);
bool32 type_changed = OG_FALSE;
if (db_is_column_compatible(old_column, new_column, &type_changed) == OG_FALSE) {
if (old_column->ddm_expr != NULL) {
OG_THROW_ERROR(ERR_CANNOT_MODIFY_COLUMN);
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_prepare_modify_column(knl_session_t *session, knl_dictionary_t *dc, knl_column_t *new_column,
bool32 *rebuild_indexes, uint32 index_count)
{
dc_entity_t *entity = DC_ENTITY(dc);
table_t *table = DC_TABLE(dc);
bool32 compatible = OG_FALSE;
knl_column_t *old_column = dc_get_column(entity, new_column->id);
bool32 col_null = OG_FALSE;
bool32 include_null = OG_FALSE;
uint32 i;
bool32 type_changed = OG_FALSE;
ref_cons_t *ref = NULL;
check_cons_t *check = NULL;
if (db_is_modify_array_column(old_column, new_column) != OG_SUCCESS) {
return OG_ERROR;
}
compatible = db_is_column_compatible(old_column, new_column, &type_changed);
if (db_modify_column_null_only(old_column, new_column) || compatible) {
if (old_column->nullable && !new_column->nullable) {
if (db_column_judge_null(session, old_column->id, dc, &col_null, &include_null) != OG_SUCCESS) {
return OG_ERROR;
}
if (include_null) {
OG_THROW_ERROR(ERR_COLUMN_HAS_NULL);
return OG_ERROR;
}
}
} else {
if (db_column_judge_null(session, old_column->id, dc, &col_null, &include_null) != OG_SUCCESS) {
return OG_ERROR;
}
if (!col_null) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EMPTY, new_column->name, table->desc.name);
return OG_ERROR;
}
}
if (db_verify_index_column(session, dc, new_column, compatible, rebuild_indexes,
index_count) != OG_SUCCESS) {
return OG_ERROR;
}
if (IS_PART_TABLE(table)) {
if (db_judge_modify_part_column(table, old_column, new_column) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (entity->has_serial_col) {
if (KNL_COLUMN_IS_SERIAL(old_column)) {
if ((new_column->datatype != OG_TYPE_BIGINT) &&
(new_column->datatype != OG_TYPE_INTEGER)) {
OG_THROW_ERROR(ERR_INVALID_DATA_TYPE, "column");
return OG_ERROR;
}
} else {
if (KNL_COLUMN_IS_SERIAL(new_column)) {
OG_THROW_ERROR(ERR_DUPLICATE_AUTO_COLUMN);
return OG_ERROR;
}
}
}
if (!type_changed) {
return OG_SUCCESS;
}
for (i = 0; i < table->cons_set.check_count; i++) {
check = table->cons_set.check_cons[i];
if (db_column_in_list(check->cols, check->col_count, new_column)) {
OG_THROW_ERROR(ERR_CANNOT_MODIFY_COLUMN);
return OG_ERROR;
}
}
for (i = 0; i < table->cons_set.ref_count; i++) {
ref = table->cons_set.ref_cons[i];
if (db_column_in_list(ref->cols, ref->col_count, old_column)) {
OG_THROW_ERROR(ERR_COL_TYPE_MISMATCH);
return OG_ERROR;
}
}
return OG_SUCCESS;
}
knl_column_def_t *db_altable_find_column_def(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def,
uint16 col_id)
{
uint32 i;
knl_column_t *column = NULL;
knl_alt_column_prop_t *col_def = NULL;
knl_column_def_t *def_column = NULL;
for (i = 0; i < def->column_defs.count; i++) {
col_def = (knl_alt_column_prop_t *)cm_galist_get(&def->column_defs, i);
def_column = &col_def->new_column;
column = knl_find_column(&def_column->name, dc);
if (column == NULL) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, T2S(&def->name), T2S_EX(&def_column->name));
return NULL;
}
if (column->id == col_id) {
break;
}
}
return def_column;
}
status_t db_altable_sort_column_def(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def,
uint16 *sort_col)
{
uint16 temp_col;
uint32 i;
int32 j;
knl_column_t *old_column = NULL;
knl_alt_column_prop_t *col_def = NULL;
knl_column_def_t *def_column = NULL;
for (i = 0; i < def->column_defs.count; i++) {
col_def = (knl_alt_column_prop_t *)cm_galist_get(&def->column_defs, i);
def_column = &col_def->new_column;
old_column = knl_find_column(&def_column->name, dc);
if (old_column == NULL) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, T2S(&def->name), T2S_EX(&def_column->name));
return OG_ERROR;
}
sort_col[i] = old_column->id;
}
* analyze table will update all columns order by columns id asc, we must ensure
* update columns order bu column id asc when modify many columns for preventing deadlock
* eg:analyze update column 1 and column 2,modify update column 2 and column 1
*/
for (i = 1; i < def->column_defs.count; i++) {
temp_col = sort_col[i];
for (j = i - 1; (j >= 0) && (sort_col[j] > temp_col); j--) {
sort_col[j + 1] = sort_col[j];
}
sort_col[j + 1] = temp_col;
}
return OG_SUCCESS;
}
status_t db_altable_modify_column(knl_session_t *session, knl_dictionary_t *dc, void *stmt, knl_altable_def_t *def)
{
table_t *table = NULL;
knl_column_t *old_column = NULL;
knl_column_t column;
knl_column_def_t *def_column = NULL;
knl_dictionary_t new_dc;
uint32 i;
uint16 *sort_col = NULL;
bool32 *rebuild_indexes = NULL;
uint32 index_count;
CM_SAVE_STACK(session->stack);
table = DC_TABLE(dc);
space_t *space = SPACE_GET(session, table->desc.space_id);
bool32 is_encrypt = SPACE_IS_ENCRYPT(space);
index_count = table->index_set.total_count;
if (index_count > 0) {
rebuild_indexes = (bool32 *)cm_push(session->stack, index_count * sizeof(bool32));
for (i = 0; i < index_count; i++) {
rebuild_indexes[i] = OG_FALSE;
}
}
sort_col = (uint16 *)cm_push(session->stack, OG_MAX_COLUMNS * sizeof(uint16));
if (db_altable_sort_column_def(session, dc, def, sort_col) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
for (i = 0; i < def->column_defs.count; i++) {
if (dc_open_table_private(session, dc->uid, dc->oid, &new_dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
def_column = db_altable_find_column_def(session, dc, def, sort_col[i]);
old_column = knl_find_column(&def_column->name, dc);
if (old_column == NULL) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, T2S(&def->name), T2S_EX(&def_column->name));
return OG_ERROR;
}
if (!def_column->is_option_set) {
dc_close_table_private(&new_dc);
continue;
}
if (is_encrypt && (!OG_IS_LOB_TYPE(def_column->typmod.datatype) && !def_column->typmod.is_array)) {
if (def_column->typmod.size > OG_MAX_COLUMN_SIZE - OG_KMC_MAX_CIPHER_SIZE) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_ENCRYPTION_NOT_SUPPORT_DDL, "column size should less than",
OG_MAX_COLUMN_SIZE - OG_KMC_MAX_CIPHER_SIZE);
return OG_ERROR;
}
}
table = DC_TABLE(&new_dc);
column.name = (char *)cm_push(session->stack, OG_NAME_BUFFER_SIZE);
db_convert_column_def(&column, table->desc.uid, table->desc.id, def_column,
old_column, table->desc.column_count);
column.id = old_column->id;
if (db_prepare_modify_column(session, &new_dc, &column, rebuild_indexes, index_count) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_altable_modify_lob_column(session, table,
old_column, &column) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_modify_column_in_syscolumn(session, &column, &table->desc) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_check_col_ddm_rule(session, &new_dc, &column) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_update_table_desc(session, &table->desc, OG_FALSE, OG_FALSE) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (def_column->is_comment) {
knl_comment_def_t comment_def;
comment_def.uid = column.uid;
comment_def.id = column.table_id;
comment_def.column_id = column.id;
comment_def.comment = def_column->comment;
comment_def.type = COMMENT_ON_COLUMN;
if (OG_SUCCESS != db_comment_on(session, &comment_def)) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
cm_pop(session->stack);
dc_close_table_private(&new_dc);
}
if (index_count > 0) {
if (dc_open_table_private(session, dc->uid, dc->oid, &new_dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_modify_column_index(session, &new_dc, rebuild_indexes, &column, index_count) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
dc_close_table_private(&new_dc);
}
CM_RESTORE_STACK(session->stack);
return db_altable_create_inline_constraints(session, dc, &def->column_defs, OG_TRUE);
}
static status_t knl_judge_visual_column_number(knl_dictionary_t *dc)
{
uint32 i;
uint32 column_count;
uint32 visual_count;
knl_column_t *column = NULL;
visual_count = 0;
column_count = knl_get_column_count(dc->handle);
for (i = 0; i < column_count; i++) {
column = knl_get_column(dc->handle, i);
if (!KNL_COLUMN_IS_DELETED(column)) {
visual_count += 1;
}
}
return visual_count;
}
static status_t db_judge_drop_part_column(table_t *table, uint32 column_id)
{
part_table_t *part_table = table->part_table;
for (uint32 i = 0; i < part_table->desc.partkeys; i++) {
if (part_table->keycols[i].column_id == column_id) {
OG_THROW_ERROR(ERR_DROP_PART_COLUMN);
return OG_ERROR;
}
}
for (uint32 i = 0; i < part_table->desc.subpartkeys; i++) {
if (part_table->sub_keycols[i].column_id == column_id) {
OG_THROW_ERROR(ERR_DROP_PART_COLUMN);
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_prepare_drop_column(knl_session_t *session, knl_column_t *column, knl_dictionary_t *dc)
{
uint32 i;
table_t *table = NULL;
knl_cursor_t *cursor = NULL;
text_t col_list;
uint32 cols;
bool32 used = OG_FALSE;
uint16 *col_id = NULL;
CM_SAVE_STACK(session->stack);
table = DC_TABLE(dc);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_CONSDEF_ID, IX_SYS_CONSDEF001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &table->desc.uid,
sizeof(uint32), IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &table->desc.id,
sizeof(uint32), IX_COL_SYS_CONSDEF001_TABLE_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
while (!cursor->eof) {
used = OG_FALSE;
cols = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_COLUMN_COUNT);
col_list.len = CURSOR_COLUMN_SIZE(cursor, CONSDEF_COL_COLUMN_LIST);
col_list.str = CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_COLUMN_LIST);
col_id = (uint16 *)cm_push(session->stack, OG_MAX_INDEX_COLUMNS * sizeof(uint16));
dc_convert_column_list(cols, &col_list, col_id);
for (i = 0; i < cols; i++) {
if (column->id == (uint32)col_id[i]) {
used = OG_TRUE;
break;
}
}
cm_pop(session->stack);
if (used) {
if (cols > 1) {
OG_THROW_ERROR(ERR_COLUMN_IN_CONSTRAINT);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_drop_related_index(knl_session_t *session, knl_dictionary_t *dc, knl_column_t *column)
{
table_t *table = NULL;
index_t *index = NULL;
uint32 i;
uint32 j;
bool32 drop_index = OG_FALSE;
knl_icol_info_t *icol = NULL;
table = DC_TABLE(dc);
for (i = 0; i < table->index_set.total_count; i++) {
drop_index = OG_FALSE;
index = table->index_set.items[i];
for (j = 0; j < index->desc.column_count; j++) {
if (index->desc.columns[j] < DC_VIRTUAL_COL_START) {
if (column->id == (uint32)index->desc.columns[j]) {
drop_index = OG_TRUE;
}
} else {
icol = &index->desc.columns_info[j];
if (column->id == icol->arg_cols[0]) {
drop_index = OG_TRUE;
}
}
}
if (!drop_index) {
continue;
}
knl_set_session_scn(session, OG_INVALID_ID64);
if (db_drop_index(session, index, dc) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_altable_drop_column(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
knl_update_info_t *ua = NULL;
knl_column_t *column = NULL;
table_t *table = NULL;
uint32 visual_column_count;
knl_comment_def_t comment_def;
knl_alt_column_prop_t *col_def = NULL;
uint32 col_flags;
table = DC_TABLE(dc);
knl_panic_log(def->column_defs.count == 1, "column count is abnormal, panic info: table %s column_defs's count %u",
table->desc.name, def->column_defs.count);
col_def = (knl_alt_column_prop_t *)cm_galist_get(&def->column_defs, 0);
column = knl_find_column(&col_def->name, dc);
if (column == NULL) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, T2S(&def->name), T2S_EX(&col_def->name));
return OG_ERROR;
}
if (IS_PART_TABLE(table)) {
if (db_judge_drop_part_column(table, column->id) != OG_SUCCESS) {
return OG_ERROR;
}
}
visual_column_count = knl_judge_visual_column_number(dc);
if (visual_column_count == 1) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ",cannot drop all columns in a table");
return OG_ERROR;
}
if (db_prepare_drop_column(session, column, dc) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (db_fetch_syscolumn_row(session, cursor, column->id, table->desc.uid, table->desc.id,
CURSOR_ACTION_UPDATE) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
col_flags = (column->flags | KNL_COLUMN_FLAG_DELETED);
ua = &cursor->update_info;
ua->count = 1;
ua->columns[0] = SYS_COLUMN_COL_FLAGS;
ua->lens[0] = sizeof(uint32);
row_init(&ra, ua->data, OG_MAX_ROW_SIZE, 1);
(void)row_put_int32(&ra, col_flags);
cm_decode_row(ua->data, ua->offsets, ua->lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
if (db_check_ddm_rule_by_col(session, table->desc.uid, table->desc.id, column->id) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_table_desc(session, &table->desc, OG_FALSE, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_drop_related_index(session, dc, column) != OG_SUCCESS) {
return OG_ERROR;
}
comment_def.type = COMMENT_ON_COLUMN;
comment_def.uid = column->uid;
comment_def.id = column->table_id;
comment_def.column_id = column->id;
return db_delete_comment(session, &comment_def);
}
static status_t db_rename_column_in_syscolumn(knl_session_t *session, uint16 col_id, text_t *new_name,
knl_table_desc_t *desc)
{
uint16 size;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (db_fetch_syscolumn_row(session, cursor, col_id, desc->uid, desc->id, CURSOR_ACTION_UPDATE) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s", cursor->rowid.file,
cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, desc->name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_text(&ra, new_name);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_COLUMN_COL_NAME;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (OG_SUCCESS != knl_internal_update(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t knl_find_column_in_consdef(table_t *table, knl_column_t *column)
{
uint32 i;
check_cons_t *check = NULL;
for (i = 0; i < table->cons_set.check_count; i++) {
check = table->cons_set.check_cons[i];
if (db_column_in_list(check->cols, check->col_count, column)) {
OG_THROW_ERROR(ERR_COLUMN_IN_CONSTRAINT);
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_altable_rename_column(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
table_t *table = NULL;
knl_column_t *column = NULL;
text_t *old_name = NULL;
text_t *new_name = NULL;
knl_alt_column_prop_t *col_def = NULL;
uint32 i;
index_t *index = NULL;
knl_panic(def->column_defs.count == 1);
col_def = (knl_alt_column_prop_t *)cm_galist_get(&def->column_defs, 0);
old_name = &col_def->name;
new_name = &col_def->new_name;
table = DC_TABLE(dc);
column = knl_find_column(&col_def->name, dc);
if (column == NULL) {
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, T2S(&def->user), T2S_EX(old_name));
return OG_ERROR;
}
for (i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (db_column_in_icol_list(index, column)) {
OG_THROW_ERROR(ERR_RENAME_FUNC_INDEX, T2S(old_name));
return OG_ERROR;
}
}
if (knl_find_column_in_consdef(table, column) != OG_SUCCESS) {
return OG_ERROR;
}
if (knl_find_column(&col_def->new_name, dc) != NULL) {
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "column", T2S(new_name));
return OG_ERROR;
}
if (db_rename_column_in_syscolumn(session, column->id, new_name, &table->desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_table_desc(session, &table->desc, OG_FALSE, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_altable_rename_table(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def,
void *trig_list)
{
knl_dictionary_t new_dc;
dc_user_t *user = NULL;
dc_entry_t *entry = NULL;
bool32 is_exist = OG_FALSE;
if (dc_is_reserved_entry(dc->uid, dc->oid) && !DB_IS_MAINTENANCE(session)) {
OG_THROW_ERROR(ERR_INVALID_OPERATION,
",can not rename system table %s.%s", T2S(&def->user), T2S_EX(&def->name));
return OG_ERROR;
}
if (knl_open_dc_if_exists(session, &def->user, &def->table_def.new_name, &new_dc, &is_exist) != OG_SUCCESS) {
return OG_ERROR;
}
if (is_exist || SYNONYM_EXIST(&new_dc)) {
dc_close(&new_dc);
OG_THROW_ERROR(ERR_DUPLICATE_TABLE, T2S(&def->user), T2S_EX(&def->table_def.new_name));
return OG_ERROR;
}
if (dc_open_user_by_id(session, dc->uid, &user) != OG_SUCCESS) {
return OG_ERROR;
}
entry = DC_GET_ENTRY(user, dc->oid);
if (db_update_table_name(session, dc->uid, entry->name, &def->table_def.new_name, OG_FALSE) != OG_SUCCESS) {
int32 err_code = cm_get_error_code();
if (err_code == ERR_DUPLICATE_KEY) {
cm_reset_error();
OG_THROW_ERROR(ERR_DUPLICATE_TABLE, T2S(&def->user), T2S_EX(&def->table_def.new_name));
}
return OG_ERROR;
}
if (db_update_table_policy(session, dc->uid, entry->name, &def->table_def.new_name) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_objname_for_priv(session, dc->uid, entry->name, &def->table_def.new_name,
OBJ_TYPE_TABLE) != OG_SUCCESS) {
return OG_ERROR;
}
if (g_knl_callback.pl_update_tab_from_sysproc(session, dc, &def->name,
&def->table_def.new_name) != OG_SUCCESS) {
return OG_ERROR;
}
return dc_rename_table(session, &def->table_def.new_name, dc);
}
status_t db_altable_add_cons(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
status_t status;
table_t *table = NULL;
char cons_name[OG_NAME_BUFFER_SIZE];
knl_cursor_t *cursor = NULL;
bool32 find_flag = OG_FALSE;
bool32 is_empty = OG_FALSE;
CM_SAVE_STACK(session->stack);
table = DC_TABLE(dc);
cursor = knl_push_cursor(session);
if (db_fetch_sysconsdef_by_table(session, cursor, CURSOR_ACTION_SELECT, table->desc.uid, table->desc.id,
&(def->cons_def.new_cons.name), &find_flag) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
if (find_flag) {
if (def->options & CREATE_IF_NOT_EXISTS) {
return OG_SUCCESS;
} else {
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "constraint", T2S(&def->cons_def.new_cons.name));
return OG_ERROR;
}
}
if (def->cons_def.new_cons.name.len == 0) {
knl_get_system_name(session, def->cons_def.new_cons.type, cons_name, OG_NAME_BUFFER_SIZE);
def->cons_def.new_cons.name.len = (uint32)strlen(cons_name);
def->cons_def.new_cons.name.str = cons_name;
def->cons_def.new_cons.cons_state.is_anonymous = OG_TRUE;
}
def->cons_def.new_cons.cons_state.is_contains_vircol = def->contains_vircol;
switch (def->cons_def.new_cons.type) {
case CONS_TYPE_PRIMARY:
case CONS_TYPE_UNIQUE:
case CONS_TYPE_REFERENCE:
status = db_create_cons(session, dc, &def->cons_def.new_cons);
break;
case CONS_TYPE_CHECK:
if (def->cons_def.new_cons.cons_state.is_validate) {
if (db_table_data_judge_empty(session, dc, &is_empty) != OG_SUCCESS) {
return OG_ERROR;
}
if (!is_empty && db_verify_check_data(session, dc, &def->cons_def.new_cons.check.text) != OG_SUCCESS) {
return OG_ERROR;
}
}
status = db_create_cons(session, dc, &def->cons_def.new_cons);
break;
default:
status = OG_ERROR;
break;
}
if (status != OG_ERROR) {
if (IS_CONS_STATE_FLAG_SPECIFIED(&def->cons_def.new_cons)
&& (!(IS_USEINDEX_FLAG_SPECIFIED(&def->cons_def.new_cons)))) {
OG_LOG_RUN_WAR("constraint_state clause specified but did not take effect.");
}
}
return status;
}
* alter table pctfree
* update table description, update segment list range if necessary.
* @param kernel session, alter table definition
*/
status_t db_altable_pctfree(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
table_t *table = NULL;
heap_segment_t *segment = NULL;
table = DC_TABLE(dc);
if (db_update_table_pctfree(session, &table->desc, def->table_def.pctfree) != OG_SUCCESS) {
return OG_ERROR;
}
if (table->heap.segment != NULL) {
log_atomic_op_begin(session);
buf_enter_page(session, table->heap.entry, LATCH_MODE_X, ENTER_PAGE_RESIDENT);
segment = HEAP_SEG_HEAD(session);
heap_set_pctfree(session, segment, def->table_def.pctfree);
if (SPC_IS_LOGGING_BY_PAGEID(session, table->heap.entry)) {
log_put(session, RD_HEAP_CHANGE_SEG, segment, HEAP_SEG_SIZE, LOG_ENTRY_FLAG_NONE);
}
buf_leave_page(session, OG_TRUE);
log_atomic_op_end(session);
}
return OG_SUCCESS;
}
static status_t db_alter_table_subpart_initrans(knl_session_t *session, table_t *table,
table_part_t* table_part, uint32 initrans)
{
table_part_t *table_subpart = NULL;
if (!IS_PARENT_TABPART(&table_part->desc)) {
return OG_SUCCESS;
}
for (uint32 i = 0; i < table_part->desc.subpart_cnt; i++) {
table_subpart = PART_GET_SUBENTITY(table->part_table, table_part->subparts[i]);
if (table_subpart == NULL) {
continue;
}
if (db_update_table_subpart_initrans(session, &table_subpart->desc, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
heap_set_initrans(session, &table_subpart->heap, initrans);
}
return OG_SUCCESS;
}
status_t db_altable_initrans(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
table_t *table = DC_TABLE(dc);
table_part_t *table_part = NULL;
uint32 initrans = def->table_def.initrans;
if (db_update_table_initrans(session, &table->desc, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
heap_set_initrans(session, &table->heap, initrans);
if (!IS_PART_TABLE(table)) {
return OG_SUCCESS;
}
for (uint32 id = 0; id < table->part_table->desc.partcnt; id++) {
table_part = TABLE_GET_PART(table, id);
if (!IS_READY_PART(table_part)) {
continue;
}
if (db_update_table_part_initrans(session, &table_part->desc, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
heap_set_initrans(session, &table_part->heap, initrans);
if (db_alter_table_subpart_initrans(session, table, table_part, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_altable_part_initrans(knl_session_t *session, knl_dictionary_t *dc, knl_alt_part_t *def)
{
table_t *table = DC_TABLE(dc);
table_part_t *table_part = NULL;
uint32 initrans = def->part_prop.initrans;
if (!IS_PART_TABLE(table)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify part initrans", "non-partitioned table");
return OG_ERROR;
}
if (!part_table_find_by_name(table->part_table, &def->name, &table_part)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "table", T2S(&def->name));
return OG_ERROR;
}
if (table_part->desc.not_ready) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "modify the initrans parameter of a not ready partition");
return OG_ERROR;
}
if (db_update_table_part_initrans(session, &table_part->desc, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
heap_set_initrans(session, &table_part->heap, initrans);
if (db_alter_table_subpart_initrans(session, table, table_part, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_altable_storage(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
table_t *table = DC_TABLE(dc);
space_t *space = SPACE_GET(session, table->desc.space_id);
knl_storage_desc_t storage_desc;
uint32 max_pages = CM_CALC_ALIGN((uint64)def->table_def.storage_def.maxsize, space->ctrl->block_size) /
space->ctrl->block_size;
if (table->desc.storaged && max_pages > 0 && table->desc.storage_desc.initial > 0 &&
(table->desc.storage_desc.initial > max_pages)) {
OG_THROW_ERROR(ERR_CAPABILITY_NOT_SUPPORT, "initial large than maxsize");
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
errno_t err = memset_sp(&storage_desc, sizeof(knl_storage_desc_t), 0, sizeof(knl_storage_desc_t));
knl_securec_check(err);
storage_desc.max_pages = max_pages;
if (!table->desc.storaged) {
if (db_update_table_flag(session, table->desc.uid, table->desc.id, TABLE_FLAG_TYPE_STORAGED) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_write_sysstorage(session, cursor, table->desc.org_scn, &storage_desc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
} else {
if (db_update_storage_maxsize(session, cursor, table->desc.org_scn, max_pages) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_altable_part_storage(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
dc_entity_t *entity = DC_ENTITY(dc);
table_t *table = &entity->table;
uint32 part_no;
knl_storage_desc_t storage_desc;
if (!IS_PART_TABLE(table)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify part storage", "non-partitioned table");
return OG_ERROR;
}
if (knl_find_table_part_by_name(entity, &def->part_def.name, &part_no) != OG_SUCCESS) {
return OG_ERROR;
}
table_part_t *table_part = TABLE_GET_PART(&entity->table, part_no);
if (table_part->desc.not_ready) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "modify the storage parameters of a not ready partition");
return OG_ERROR;
}
part_table_t *part_table = table->part_table;
space_t *space = SPACE_GET(session, table_part->desc.space_id);
uint32 max_pages = CM_CALC_ALIGN((uint64)def->part_def.storage_def.maxsize, space->ctrl->block_size) /
space->ctrl->block_size;
if (table_part->desc.storage_desc.initial > 0 && max_pages > 0 &&
(table_part->desc.storage_desc.initial > max_pages)) {
OG_THROW_ERROR(ERR_EXCEED_SEGMENT_MAXSIZE);
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
errno_t err = memset_sp(&storage_desc, sizeof(knl_storage_desc_t), 0, sizeof(knl_storage_desc_t));
knl_securec_check(err);
storage_desc.max_pages = max_pages;
if (!table_part->desc.storaged) {
if (db_update_part_flag(session, dc, part_table, table_part->desc.part_id, PART_FLAG_TYPE_STORAGED) !=
OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_write_sysstorage(session, cursor, table_part->desc.org_scn, &storage_desc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
} else {
if (db_update_storage_maxsize(session, cursor, table_part->desc.org_scn, max_pages) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
* alter table appendonly
* update table description.
* @param kernel session, alter table definition
*/
status_t db_altable_appendonly(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
table_t *table = NULL;
table = DC_TABLE(dc);
if (db_update_table_appendonly(session, &table->desc, def->table_def.appendonly) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_altable_drop_logical_log_inner(knl_session_t *session, knl_cursor_t *cursor,
const uint32 uid, const uint32 tableid)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_LOGIC_REP_ID, IX_SYS_LOGICREP_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_LOGICREP_001_USERID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &tableid, sizeof(uint32),
IX_COL_SYS_LOGICREP_001_TABLEID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (!cursor->eof) {
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_altable_update_logical_log(knl_session_t *session, knl_cursor_t *cursor,
const uint32 uid, const uint32 tableid, text_t *text)
{
row_assist_t ra;
uint16 size;
knl_column_t *lob_column = NULL;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_LOGIC_REP_ID,
IX_SYS_LOGICREP_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
&uid, sizeof(uint32), IX_COL_SYS_LOGICREP_001_USERID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
&tableid, sizeof(uint32), IX_COL_SYS_LOGICREP_001_TABLEID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (cursor->eof) {
return OG_ERROR;
}
lob_column = knl_get_column(cursor->dc_entity, SYS_LOGIC_REP_COLUMN_ID_PARTITIONIDS);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
if (knl_row_put_lob(session, cursor, lob_column, text, &ra) != OG_SUCCESS) {
return OG_ERROR;
}
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_LOGIC_REP_COLUMN_ID_PARTITIONIDS;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets,
cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
void db_drop_part_compare_logical(knl_session_t *session, dc_entity_t *entity,
table_part_t *table_part, text_t *text)
{
errno_t err;
table_part_t *table_parts = NULL;
text->len = 0;
for (uint32 i = 0; i < entity->table.part_table->desc.partcnt; i++) {
table_parts = TABLE_GET_PART(&entity->table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
if (table_parts->desc.lrep_status == PART_LOGICREP_STATUS_ON && table_part->part_no != i) {
if (text->len > 0) {
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, ",");
knl_securec_check_ss(err);
text->len += err;
}
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, "%s", table_parts->desc.name);
knl_securec_check_ss(err);
text->len += err;
}
continue;
}
table_part_t *subpart = NULL;
for (uint32 j = 0; i < table_parts->desc.subpart_cnt; j++) {
subpart = PART_GET_SUBENTITY(entity->table.part_table, table_parts->subparts[j]);
if (subpart == NULL) {
continue;
}
if (subpart->desc.lrep_status == PART_LOGICREP_STATUS_ON && table_part->part_no != i) {
if (text->len > 0) {
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, ",");
knl_securec_check_ss(err);
text->len += err;
}
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, "%s",
table_parts->desc.name);
knl_securec_check_ss(err);
text->len += err;
}
}
}
}
status_t db_drop_part_logical(knl_session_t *session, knl_cursor_t *cursor, dc_entity_t *entity,
table_part_t *table_part)
{
text_t text;
table_t *table = &entity->table;
uint32 uid = table->desc.uid;
uint32 tableid = table->desc.id;
status_t status = OG_SUCCESS;
if (entity->lrep_info.status == LOGICREP_STATUS_ON || entity->lrep_info.parts_count == 0 ||
table_part->desc.lrep_status != PART_LOGICREP_STATUS_ON) {
return OG_SUCCESS;
}
if (entity->lrep_info.parts_count == 1) {
status = db_altable_drop_logical_log_inner(session, cursor, uid, tableid);
if (status == OG_SUCCESS) {
table_part->desc.lrep_status = PART_LOGICREP_STATUS_OFF;
entity->lrep_info.parts_count = 0;
}
return status;
}
text.str = (char *)cm_push(session->stack, entity->lrep_info.parts_count * (OG_NAME_BUFFER_SIZE + 1));
if (text.str == NULL) {
OG_THROW_ERROR(ERR_STACK_OVERFLOW);
return OG_ERROR;
}
db_drop_part_compare_logical(session, entity, table_part, &text);
status = db_altable_update_logical_log(session, cursor, uid, tableid, &text);
if (status == OG_SUCCESS) {
table_part->desc.lrep_status = PART_LOGICREP_STATUS_OFF;
entity->lrep_info.parts_count--;
}
cm_pop(session->stack);
return status;
}
status_t db_drop_part_prepare(knl_session_t *session, table_t *table, knl_altable_def_t *def,
table_part_t **table_part, bool32 *part_not_exists)
{
if (!table->desc.parted) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "drop partition", table->desc.name);
return OG_ERROR;
}
if (!part_table_find_by_name(table->part_table, &def->part_def.name, table_part)) {
*part_not_exists = OG_TRUE;
if (!(def->options & DROP_IF_EXISTS)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "table", T2S(&def->part_def.name));
}
return OG_ERROR;
}
if (!((*table_part)->desc.flags & PARTITON_NOT_READY)) {
if (table->part_table->desc.partcnt < 2 && def->action != ALTABLE_SPLIT_PARTITION) {
OG_THROW_ERROR(ERR_DROP_ONLY_PART);
return OG_ERROR;
}
}
if (PART_CONTAIN_INTERVAL(table->part_table) && (*table_part)->part_no == table->part_table->desc.transition_no) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "drop transition partition", "interval partitioned table");
return OG_ERROR;
}
if (db_table_is_referenced(session, table, OG_TRUE)) {
OG_THROW_ERROR(ERR_TABLE_IS_REFERENCED);
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_drop_part_handle_index(knl_session_t *session, knl_cursor_t *cursor, knl_dictionary_t *dc,
table_part_t *table_part, bool32 is_part_add_or_coalesce)
{
table_t *table = DC_TABLE(dc);
bool32 is_changed = OG_FALSE;
bool32 need_invalidate_index = OG_FALSE;
knl_part_desc_t *desc = &table->part_table->desc;
if (db_need_invalidate_index(session, dc, table, table_part, &need_invalidate_index) != OG_SUCCESS) {
return OG_ERROR;
}
for (uint32 i = 0; i < table->index_set.total_count; i++) {
index_t *index = table->index_set.items[i];
if (index->desc.parted) {
index_part_t *index_part = INDEX_GET_PART(index, table_part->part_no);
if (index_part == NULL) {
continue;
}
if (db_delete_from_sysindexpart(session, cursor, desc->uid, desc->table_id, index->desc.id,
table_part->desc.part_id) != OG_SUCCESS) {
return OG_ERROR;
}
if (PART_CONTAIN_INTERVAL(table->part_table)) {
if (part_update_interval_part_count(session, table, table_part->part_no,
index->desc.id, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (db_update_part_count(session, desc->uid, desc->table_id, index->desc.id, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
continue;
}
if (db_delete_subidxparts_with_compart(session, cursor, desc->uid, desc->table_id, index->desc.id,
table_part->desc.part_id) != OG_SUCCESS) {
return OG_ERROR;
}
} else if (!is_part_add_or_coalesce) {
if (need_invalidate_index) {
if (db_update_index_status(session, index, OG_TRUE, &is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
if (btree_segment_prepare(session, index, OG_INVALID_ID32, BTREE_DROP_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
} else {
}
}
return OG_SUCCESS;
}
static status_t db_delete_part_stats(knl_session_t *session, knl_dictionary_t *dc, table_part_t *table_part)
{
dc_entity_t *entity = DC_ENTITY(dc);
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
if (stats_delete_histgram_by_part(session, cursor, dc, table_part->desc.part_id) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
if (stats_delete_histhead_by_part(session, dc, table_part->desc.part_id) != OG_SUCCESS) {
return OG_ERROR;
}
if (DB_IS_STATS_ENABLED(((knl_session_t *)session)->kernel)) {
stats_table_mon_t *table_stats = &entity->entry->appendix->table_smon;
table_stats->is_change = OG_TRUE;
table_stats->drop_segments++;
table_stats->timestamp = cm_now();
}
return OG_SUCCESS;
}
static status_t db_drop_part_handle_lob(knl_session_t *session, knl_cursor_t *cursor, knl_dictionary_t *dc,
table_part_t *table_part)
{
knl_column_t *column = NULL;
dc_entity_t *entity = DC_ENTITY(dc);
table_t *table = DC_TABLE(dc);
lob_part_t *lob_part = NULL;
knl_part_desc_t *desc = &table->part_table->desc;
for (uint32 i = 0; i < entity->column_count; i++) {
column = dc_get_column(entity, i);
if (!COLUMN_IS_LOB(column)) {
continue;
}
OG_LOG_DEBUG_INF("drop part: begin to delete from lob part$, uid: %d, tid: %d, column id: %d, part_id: %d",
desc->uid, desc->table_id, column->id, table_part->desc.part_id);
lob_part = LOB_GET_PART((lob_t *)column->lob, table_part->part_no);
if (lob_part == NULL) {
continue;
}
if (IS_PARENT_TABPART(&table_part->desc)) {
if (db_delete_sublobparts_with_compart(session, cursor, desc->uid, desc->table_id, column->id,
table_part->desc.part_id) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (db_delete_from_syslobpart(session, cursor, desc->uid, desc->table_id, column->id,
table_part->desc.part_id) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static inline status_t db_drop_part_precheck(table_t *table, knl_altable_def_t *def, bool32 is_part_add_or_coalesce)
{
if (!is_part_add_or_coalesce && !def->part_def.is_garbage_clean) {
if (table->part_table == NULL) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "table", T2S(&def->part_def.name));
return OG_ERROR;
}
if (table->part_table->desc.parttype == PART_TYPE_HASH) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "alter table drop partition", "hash partition");
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_drop_part_handle_interval(knl_session_t *session, table_t *table, table_part_t *table_part,
knl_part_desc_t *desc)
{
if (PART_CONTAIN_INTERVAL(table->part_table)) {
if (part_update_interval_part_count(session, table, table_part->part_no, OG_INVALID_ID32,
OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (db_update_part_count(session, desc->uid, desc->table_id, desc->index_id, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_drop_part_handle_objects(knl_session_t *session, knl_dictionary_t *dc, knl_cursor_t *cursor,
table_part_t *table_part, bool32 is_part_add_or_coalesce)
{
table_t *table = DC_TABLE(dc);
knl_part_desc_t *desc = &table->part_table->desc;
if (db_drop_part_handle_interval(session, table, table_part, desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (DC_ENTITY(dc)->contain_lob) {
if (db_drop_part_handle_lob(session, cursor, dc, table_part) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (db_drop_part_handle_index(session, cursor, dc, table_part, is_part_add_or_coalesce) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_drop_part(knl_session_t *session, knl_dictionary_t *dc, table_part_t *table_part,
bool32 add_or_coalesce)
{
table_t *table = DC_TABLE(dc);
if (db_delete_part_stats(session, dc, table_part) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_part_desc_t *desc = &table->part_table->desc;
if (IS_PARENT_TABPART(&table_part->desc)) {
if (db_delete_subtabparts_of_compart(session, cursor, desc->uid, desc->table_id,
table_part->desc.part_id) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (db_delete_from_systablepart(session, cursor, desc->uid, desc->table_id,
table_part->desc.part_id) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (table_part->desc.storaged && db_delete_from_sysstorage(session, cursor,
table_part->desc.org_scn) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_drop_part_handle_objects(session, dc, cursor, table_part, add_or_coalesce) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_update_table_chgscn(session, &table->desc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_drop_part_segments(session, dc, table_part->part_no) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_drop_part_logical(session, cursor, DC_ENTITY(dc), table_part) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (table_part->desc.compress) {
if (db_delete_from_syscompress(session, cursor, table_part->desc.org_scn) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
if (stats_update_global_tablestats(session, dc, table_part->part_no) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_delete_mon_sysmods(session, dc->uid, dc->oid, table_part->desc.part_id, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
session->stat->table_part_drops++;
return OG_SUCCESS;
}
* is_force=true means do not check whether it is hash/xx partition
*/
status_t db_altable_drop_part(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def,
bool32 is_part_add_or_coalesce)
{
table_t *table = DC_TABLE(dc);
table_part_t *table_part = NULL;
if (db_drop_part_precheck(table, def, is_part_add_or_coalesce) != OG_SUCCESS) {
return OG_ERROR;
}
bool32 part_not_exists = OG_FALSE;
if (db_drop_part_prepare(session, table, def, &table_part, &part_not_exists) != OG_SUCCESS) {
if (part_not_exists && (def->options & DROP_IF_EXISTS)) {
return OG_SUCCESS;
}
return OG_ERROR;
}
if (db_drop_part(session, dc, table_part, is_part_add_or_coalesce) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t part_truncate_table_compart(knl_session_t *session, table_t *table, table_part_t *table_part,
bool32 reuse)
{
table_part_t *part = NULL;
table_part_t *subpart = NULL;
for (uint32 i = 0; i < table_part->desc.subpart_cnt; i++) {
subpart = PART_GET_SUBENTITY(table->part_table, table_part->subparts[i]);
if (subpart == NULL || subpart->heap.segment == NULL) {
continue;
}
part = (table_part_t *)subpart;
if (heap_part_segment_prepare(session, part, reuse, HEAP_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t part_truncate_index_compart(knl_session_t *session, table_t *table, table_part_t *table_part,
bool32 reuse, bool32 invalidate_index)
{
index_t *index = NULL;
bool32 is_changed = OG_FALSE;
for (uint32 i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (!index->desc.parted) {
if (invalidate_index) {
if (db_update_index_status(session, index, OG_TRUE, &is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
if (btree_segment_prepare(session, index, OG_FALSE, BTREE_DROP_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
continue;
}
index_part_t *index_part = NULL;
index_part_t *index_subpart = NULL;
index_part = INDEX_GET_PART(index, table_part->part_no);
knl_panic_log(IS_PARENT_IDXPART(&index_part->desc),
"current index_part is not parent_idxpart, panic info: table %s table_part %s index %s index_part %s",
table->desc.name, table_part->desc.name, index->desc.name, index_part->desc.name);
for (uint32 j = 0; j < index_part->desc.subpart_cnt; j++) {
index_subpart = PART_GET_SUBENTITY(index->part_index, index_part->subparts[j]);
if (index_subpart == NULL || index_subpart->btree.segment == NULL) {
continue;
}
if (db_update_sub_idxpart_status(session, index_subpart, OG_FALSE, &is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
if (btree_part_segment_prepare(session, index_subpart, reuse, BTREE_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t part_truncate_lob_compart(knl_session_t *session, dc_entity_t *entity, table_part_t *table_part,
bool32 reuse)
{
if (!entity->contain_lob) {
return OG_SUCCESS;
}
knl_column_t *column = NULL;
lob_t *lob = NULL;
lob_part_t *lob_part = NULL;
lob_part_t *lob_subpart = NULL;
for (uint32 i = 0; i < entity->column_count; i++) {
column = dc_get_column(entity, i);
if (!COLUMN_IS_LOB(column)) {
continue;
}
lob = column->lob;
lob_part = LOB_GET_PART(lob, table_part->part_no);
knl_panic_log(IS_PARENT_LOBPART(&lob_part->desc),
"current lob_part is not parent_lobpart, panic info: table %s table_part %s",
entity->table.desc.name, table_part->desc.name);
for (uint32 j = 0; j < lob_part->desc.subpart_cnt; j++) {
lob_subpart = PART_GET_SUBENTITY(lob->part_lob, lob_part->subparts[j]);
if (lob_subpart == NULL || lob_subpart->lob_entity.segment == NULL) {
continue;
}
if (lob_part_segment_prepare(session, (lob_part_t *)lob_subpart, reuse,
LOB_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_truncate_table_compart(knl_session_t *session, knl_dictionary_t *dc, table_part_t *table_part,
bool32 reuse_storage, bool32 need_invalidate_index)
{
table_t *table = DC_TABLE(dc);
dc_entity_t *entity = DC_ENTITY(dc);
knl_panic_log(IS_PARENT_TABPART(&table_part->desc), "current part is not parent_tabpart, panic info: table %s",
table->desc.name);
if (part_truncate_table_compart(session, table, table_part, reuse_storage) != OG_SUCCESS) {
return OG_ERROR;
}
if (part_truncate_index_compart(session, table, table_part, reuse_storage, need_invalidate_index) != OG_SUCCESS) {
return OG_ERROR;
}
if (part_truncate_lob_compart(session, entity, table_part, reuse_storage) != OG_SUCCESS) {
return OG_ERROR;
}
stats_table_mon_t *table_stats = &entity->entry->appendix->table_smon;
table_stats->is_change = OG_TRUE;
table_stats->drop_segments++;
table_stats->timestamp = cm_now();
return OG_SUCCESS;
}
static status_t db_truncate_table_part(knl_session_t *session, knl_dictionary_t *dc, table_part_t *table_part,
bool32 reuse_storage)
{
index_t *index = NULL;
index_part_t *index_part = NULL;
lob_part_t *lob_part = NULL;
lob_t *lob = NULL;
knl_column_t *column = NULL;
stats_table_mon_t *table_stats = NULL;
bool32 is_changed = OG_FALSE;
bool32 need_invalidate_index = OG_FALSE;
dc_entity_t *entity = DC_ENTITY(dc);
table_t *table = &entity->table;
if (db_need_invalidate_index(session, dc, table, table_part, &need_invalidate_index) != OG_SUCCESS) {
return OG_ERROR;
}
if (IS_PARENT_TABPART(&table_part->desc)) {
return db_truncate_table_compart(session, dc, table_part, reuse_storage, need_invalidate_index);
}
if (heap_part_segment_prepare(session, table_part, reuse_storage, HEAP_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
if (entity->contain_lob) {
for (uint32 i = 0; i < entity->column_count; i++) {
column = dc_get_column(entity, i);
if (!COLUMN_IS_LOB(column)) {
continue;
}
lob = (lob_t *)column->lob;
lob_part = LOB_GET_PART(lob, table_part->part_no);
if (lob_part_segment_prepare(session, lob_part, reuse_storage, LOB_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
for (uint32 i = 0; i < table->index_set.total_count; i++) {
index = table->index_set.items[i];
if (index->desc.parted) {
index_part = INDEX_GET_PART(index, table_part->part_no);
if (btree_part_segment_prepare(session, index_part, reuse_storage,
BTREE_TRUNCATE_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (need_invalidate_index) {
if (db_update_index_status(session, index, OG_TRUE, &is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
if (btree_segment_prepare(session, index, OG_INVALID_ID32, BTREE_DROP_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
}
table_stats = &entity->entry->appendix->table_smon;
table_stats->is_change = OG_TRUE;
table_stats->drop_segments++;
table_stats->timestamp = cm_now();
return OG_SUCCESS;
}
status_t db_altable_truncate_part(knl_session_t *session, knl_dictionary_t *dc, knl_alt_part_t *def)
{
table_t *table;
table_part_t *table_part = NULL;
knl_session_t *se = (knl_session_t *)session;
table = DC_TABLE(dc);
if (!table->desc.parted) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "alter table truncate partition", table->desc.name);
return OG_ERROR;
}
if (!part_table_find_by_name(table->part_table, &def->name, &table_part)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "table", T2S(&def->name));
return OG_ERROR;
}
if (table_part->desc.not_ready) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "truncate a not ready partition");
return OG_ERROR;
}
if (db_table_is_referenced(session, table, OG_TRUE)) {
OG_THROW_ERROR(ERR_TABLE_IS_REFERENCED);
return OG_ERROR;
}
if (!db_tabpart_has_segment(table->part_table, table_part)) {
return OG_SUCCESS;
}
if (dc->type != DICT_TYPE_TABLE || table_part->desc.space_id == SYS_SPACE_ID ||
def->option != TRUNC_RECYCLE_STORAGE || !se->kernel->attr.recyclebin) {
return db_truncate_table_part(session, dc, table_part, def->option & TRUNC_REUSE_STORAGE);
} else {
return rb_truncate_table_part(session, dc, table_part);
}
}
bool32 db_fetch_systable_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_TABLE_ID, IX_SYS_TABLE_001_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uid),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &uid, sizeof(uid),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_TABLE_001_NAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_TABLE_001_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_FALSE;
}
return (bool32)(!cursor->eof);
}
bool32 db_fetch_sysindex_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_INDEX_ID, IX_SYS_INDEX_001_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 *)&uid,
sizeof(uint32), IX_COL_SYS_INDEX_001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, (void *)&uid,
sizeof(uint32), IX_COL_SYS_INDEX_001_USER);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_INDEX_001_TABLE);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_INDEX_001_TABLE);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_INDEX_001_ID);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_INDEX_001_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_FALSE;
}
return (bool32)(!cursor->eof);
}
bool32 db_fetch_sysconsdef_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_CONSDEF_ID, IX_SYS_CONSDEF001_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 *)&uid,
sizeof(uint32), IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, (void *)&uid,
sizeof(uint32), IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_CONSDEF001_TABLE_ID);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_CONSDEF001_TABLE_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_FALSE;
}
return (bool32)(!cursor->eof);
}
bool32 db_fetch_syssequence_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_SEQ_ID, SYS_SEQ001_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_SEQ001_UID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_SEQ001_UID);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_SEQ001_NAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_SEQ001_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_FALSE;
}
return (bool32)(!cursor->eof);
}
bool32 db_fetch_sysview_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_VIEW_ID, IX_SYS_VIEW001_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 *)&uid,
sizeof(uint32), IX_COL_SYS_VIEW001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, (void *)&uid,
sizeof(uint32), IX_COL_SYS_VIEW001_USER);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_VIEW001_NAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_VIEW001_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_FALSE;
}
return (bool32)(!cursor->eof);
}
bool32 db_fetch_sysrecyclebin_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_RB_ID, IX_SYS_RB004_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 *)&uid,
sizeof(uint32), IX_COL_SYS_RB004_USER_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_FALSE;
}
return (bool32)(!cursor->eof);
}
bool32 db_fetch_sysproc_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_PROC_ID, IX_PROC_003_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uid),
IX_COL_PROC_003_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &uid, sizeof(uid),
IX_COL_PROC_003_USER_ID);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_PROC_003_OBJ_ID);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_PROC_003_OBJ_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_FALSE;
}
return (bool32)(!cursor->eof);
}
bool32 db_fetch_sysjob_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor, text_t *user_name)
{
text_t job_user;
dc_user_t *sys_user = NULL;
if (!(dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) == OG_SUCCESS &&
DC_GET_ENTRY(sys_user, SYS_JOB_ID) != NULL)) {
cm_reset_error();
return OG_FALSE;
}
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_JOB_ID, OG_INVALID_ID32);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_FALSE;
}
while (!cursor->eof) {
job_user.str = CURSOR_COLUMN_DATA(cursor, SYS_JOB_LOWNER);
job_user.len = CURSOR_COLUMN_SIZE(cursor, SYS_JOB_LOWNER);
if (cm_compare_text_ins(user_name, &job_user) == 0) {
return OG_TRUE;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_FALSE;
}
}
return OG_FALSE;
}
bool32 db_fetch_syslibrary_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_LIBRARY_ID, IDX_LIBRARY_001_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uid),
IX_COL_SYS_LIBRARY001_OWNER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &uid, sizeof(uid),
IX_COL_SYS_LIBRARY001_OWNER);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_LIBRARY001_NAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_LIBRARY001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_FALSE;
}
if (!cursor->eof) {
return OG_TRUE;
}
return OG_FALSE;
}
bool32 db_fetch_sql_map_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_SQL_MAP_ID, IDX_SQL_MAP_002_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 *)&uid,
sizeof(uint32), IX_COL_SQL_MAP_002_SRC_USER_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_FALSE;
}
return (bool32)(!cursor->eof);
}
bool32 db_fetch_dist_rules_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_DISTRIBUTE_RULE_ID, IX_SYS_DISTRIBUTE_RULE003_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 *)&uid,
sizeof(uint32), IX_COL_SYS_DISTRIBUTE_RULE003_UID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_FALSE;
}
return (bool32)(!cursor->eof);
}
* scan if the user need dropped has any objects not deleted yet.
* @param
* - session: kernel session
* - uid : user id
* - hasObj : scan result
* @return
* - OG_SUCCESS
* - OG_ERROR
* @note null
* @see null
*/
bool32 db_user_has_objects(knl_session_t *session, uint32 uid, text_t *uname)
{
bool32 hasObj = OG_FALSE;
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->row = (row_head_t *)cursor->buf;
do {
if (db_fetch_systable_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_sysindex_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_sysconsdef_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_sysview_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_sysproc_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_syssequence_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_syssynonym_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_sysrecyclebin_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_sysjob_by_user(session, uid, cursor, uname)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_syslibrary_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_sql_map_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
if (db_fetch_dist_rules_by_user(session, uid, cursor)) {
hasObj = OG_TRUE;
break;
}
} while (0);
CM_RESTORE_STACK(session->stack);
return hasObj;
}
* drop tables owned by the user, include:
* - TABLE$ tuples
* - COLUMN$ tuples
* - constraints
* - indexes
* - childrens' refrences constraints and indexes.
* - syslob if exists.
* @param
* - session: kernel session
* - dc : dictionary cache of the table need dropped.
* @return
* - OG_SUCCESS
* - OG_ERROR
* @note null
* @see null
*/
status_t db_drop_table_cascade(knl_session_t *session, text_t *user, knl_table_desc_t *desc)
{
knl_dictionary_t dc;
table_t *table = NULL;
text_t table_name;
bool32 is_found = OG_FALSE;
dc_entry_t *entry = NULL;
errno_t ret;
cm_str2text(desc->name, &table_name);
when drop the tmp database or user would not choose the incorrect dc */
if (desc->id < OG_LTT_ID_OFFSET) {
OG_RETURN_IFERR(knl_open_dc_not_ltt(session, user, &table_name, &dc, &is_found));
} else {
OG_RETURN_IFERR(knl_open_dc_if_exists(session, user, &table_name, &dc, &is_found));
}
if (!is_found || SYNONYM_EXIST(&dc)) {
if (is_found) {
dc_close(&dc);
}
return OG_SUCCESS;
}
table = DC_TABLE(&dc);
if (db_drop_ref_constraints(session, table->desc.uid, table->desc.id) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
if (db_drop_table(session, NULL, &dc, OG_TRUE) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
if (db_altable_drop_logical_log(session, &dc, NULL) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
if (db_delete_mon_sysmods(session, table->desc.uid, table->desc.id, OG_INVALID_ID32, OG_FALSE) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
entry = DC_ENTRY(&dc);
ret = memset_sp(&entry->appendix->table_smon, sizeof(stats_table_mon_t), 0, sizeof(stats_table_mon_t));
knl_securec_check(ret);
dc_close(&dc);
return OG_SUCCESS;
}
status_t db_fetch_table_by_uid(knl_session_t *session, uint32 uid, knl_table_desc_t *desc, bool32 *found)
{
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->row = (row_head_t *)cursor->buf;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_TABLE_ID, IX_SYS_TABLE_001_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uid),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &uid, sizeof(uid),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_TABLE_001_NAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_TABLE_001_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
*found = OG_FALSE;
return OG_ERROR;
}
while (!cursor->eof) {
dc_convert_table_desc(cursor, desc);
if (desc->recycled == 0) {
*found = OG_TRUE;
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
} else {
OG_BREAK_IF_ERROR(knl_fetch(session, cursor));
}
}
CM_RESTORE_STACK(session->stack);
*found = OG_FALSE;
return OG_SUCCESS;
}
* drop tables owned by the user, include:
* - TABLE$ tuples
* - COLUMN$ tuples
* - constraints
* - indexes
* - childrens' refrences constraints and indexes.
* - syslob if exists.
* @param
* - session: kernel session
* - uid : user id
* @return
* - OG_SUCCESS
* - OG_ERROR
* @note null
* @see null
*/
status_t db_drop_table_by_user(knl_session_t *session, text_t *user)
{
uint32 uid;
bool32 found = OG_FALSE;
knl_table_desc_t desc;
if (!dc_get_user_id(session, user, &uid)) {
OG_THROW_ERROR(ERR_USER_NOT_EXIST, T2S(user));
return OG_ERROR;
}
knl_set_session_scn(session, OG_INVALID_ID64);
if (db_fetch_table_by_uid(session, uid, &desc, &found) != OG_SUCCESS) {
return OG_ERROR;
}
while (found) {
if (db_drop_table_cascade(session, user, &desc) != OG_SUCCESS) {
return OG_ERROR;
}
knl_set_session_scn(session, OG_INVALID_ID64);
if (db_fetch_table_by_uid(session, uid, &desc, &found) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_delete_job_by_user(knl_session_t *session, text_t *user)
{
knl_cursor_t *cursor = NULL;
knl_session_t *knl_session = (knl_session_t *)session;
dc_user_t *sys_user = NULL;
text_t powner;
if (!(dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) == OG_SUCCESS &&
DC_GET_ENTRY(sys_user, SYS_JOB_ID) != NULL)) {
cm_reset_error();
return OG_SUCCESS;
}
CM_SAVE_STACK(session->stack);
knl_set_session_scn(session, OG_INVALID_ID64);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(knl_session, cursor, CURSOR_ACTION_DELETE, SYS_JOB_ID, OG_INVALID_ID32);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
while (!cursor->eof) {
powner.str = CURSOR_COLUMN_DATA(cursor, SYS_JOB_POWNER);
powner.len = CURSOR_COLUMN_SIZE(cursor, SYS_JOB_POWNER);
if (cm_text_equal_ins(&powner, user) && knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_insert_ptrans(knl_session_t *session, knl_xa_xid_t *xa_xid, uint64 ltid, binary_t *tlocklob, rowid_t *rowid)
{
knl_cursor_t *cursor = NULL;
knl_column_t *lob_column = NULL;
row_assist_t ra;
text_t global_id;
text_t branch_id;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_PENDING_TRANS_ID, OG_INVALID_ID32);
row_init(&ra, cursor->buf, OG_MAX_ROW_SIZE, SYS_PENDING_TRANS_COLUMN_COUNT);
cm_str2text_safe(xa_xid->gtrid, xa_xid->gtrid_len, &global_id);
(void)row_put_text(&ra, &global_id);
(void)row_put_int64(&ra, (int64)ltid);
if (tlocklob->size < OG_TLOCKLOB_BUFFER_SIZE) {
(void)row_put_bin(&ra, tlocklob);
row_put_null(&ra);
} else {
row_put_null(&ra);
lob_column = knl_get_column(cursor->dc_entity, SYS_PENDING_TRANS_COL_TLOCK_LOBS_EXT);
if (knl_row_put_lob(session, cursor, lob_column, tlocklob, &ra) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
(void)row_put_int64(&ra, (int64)xa_xid->fmt_id);
if (xa_xid->bqual_len == 0) {
row_put_null(&ra);
} else {
cm_str2text_safe(xa_xid->bqual, xa_xid->bqual_len, &branch_id);
(void)row_put_text(&ra, &branch_id);
}
(void)row_put_int32(&ra, (int32)session->uid);
(void)row_put_int64(&ra, session->xa_scn);
(void)row_put_int64(&ra, OG_INVALID_ID64);
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
ROWID_COPY((*rowid), cursor->rowid);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_decode_ptrans_result(knl_session_t *session, knl_cursor_t *cursor, knl_xa_xid_t *xa_xid,
uint64 *ltid, binary_t *tlocklob, uint32 *uid)
{
lob_locator_t *lob_locator = NULL;
text_t rel_varchar;
binary_t rel_tlocklob;
errno_t ret;
if (xa_xid != NULL) {
rel_varchar.str = CURSOR_COLUMN_DATA(cursor, SYS_PENDING_TRANS_COL_GLOBAL_TRAN_ID);
rel_varchar.len = CURSOR_COLUMN_SIZE(cursor, SYS_PENDING_TRANS_COL_GLOBAL_TRAN_ID);
xa_xid->gtrid_len = rel_varchar.len;
ret = memcpy_sp(xa_xid->gtrid, OG_MAX_XA_BASE16_GTRID_LEN, rel_varchar.str, rel_varchar.len);
knl_securec_check(ret);
xa_xid->fmt_id = *(uint64 *)(CURSOR_COLUMN_DATA(cursor, SYS_PENDING_TRANS_COL_FORMAT_ID));
rel_varchar.str = CURSOR_COLUMN_DATA(cursor, SYS_PENDING_TRANS_COL_BRANCH_ID);
rel_varchar.len = CURSOR_COLUMN_SIZE(cursor, SYS_PENDING_TRANS_COL_BRANCH_ID);
if (rel_varchar.len == (uint32)OG_NULL_VALUE_LEN) {
xa_xid->bqual_len = 0;
} else {
xa_xid->bqual_len = rel_varchar.len;
ret = memcpy_sp(xa_xid->bqual, OG_MAX_XA_BASE16_BQUAL_LEN, rel_varchar.str, rel_varchar.len);
knl_securec_check(ret);
}
}
if (ltid != NULL) {
*ltid = *(uint64 *)(CURSOR_COLUMN_DATA(cursor, SYS_PENDING_TRANS_COL_LOCAL_TRAN_ID));
}
if (uid != NULL) {
*uid = *(uint32 *)(CURSOR_COLUMN_DATA(cursor, SYS_PENDING_TRANS_COL_OWNER));
}
if (tlocklob == NULL) {
return OG_SUCCESS;
}
if (CURSOR_COLUMN_SIZE(cursor, SYS_PENDING_TRANS_COL_TLOCK_LOBS_EXT) != OG_NULL_VALUE_LEN) {
lob_locator = (lob_locator_t *)CURSOR_COLUMN_DATA(cursor, SYS_PENDING_TRANS_COL_TLOCK_LOBS_EXT);
if (lob_locator->head.size > 0) {
tlocklob->size = knl_lob_size(lob_locator);
if (knl_read_lob(session, lob_locator, 0, tlocklob->bytes,
OG_XA_EXTEND_BUFFER_SIZE, NULL, NULL) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
}
rel_tlocklob.bytes = (uint8 *)CURSOR_COLUMN_DATA(cursor, SYS_PENDING_TRANS_COL_TLOCK_LOBS);
rel_tlocklob.size = CURSOR_COLUMN_SIZE(cursor, SYS_PENDING_TRANS_COL_TLOCK_LOBS);
tlocklob->size = 0;
if (rel_tlocklob.size == (uint32)OG_NULL_VALUE_LEN) {
return OG_SUCCESS;
}
if (cm_concat_bin(tlocklob, OG_XA_EXTEND_BUFFER_SIZE, &rel_tlocklob) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_match_ptrans(void *handle, bool32 *match)
{
ptrans_match_cond_t *cond = (ptrans_match_cond_t *)handle;
knl_session_t *session = cond->session;
knl_cursor_t *cursor = cond->cursor;
knl_xa_xid_t ret_xa_xid;
xid_t ret_ltid;
txn_snapshot_t snapshot;
*match = OG_FALSE;
if (db_decode_ptrans_result(session, cursor, &ret_xa_xid, &ret_ltid.value, NULL, NULL) != OG_SUCCESS) {
return OG_ERROR;
}
if (cond->xa_xid != NULL) {
if (!knl_xa_xid_equal(cond->xa_xid, &ret_xa_xid)) {
return OG_SUCCESS;
}
}
if (cond->only_remained) {
if (g_knl_callback.get_xa_xid(&ret_xa_xid) != OG_INVALID_ID16) {
return OG_SUCCESS;
}
tx_get_snapshot(session, ret_ltid.xmap, &snapshot);
if (snapshot.xnum == ret_ltid.xnum && snapshot.status != (uint8)XACT_END) {
return OG_SUCCESS;
}
}
if (cond->ltid != NULL) {
*match = (bool32)((*cond->ltid) == ret_ltid.value);
return OG_SUCCESS;
}
*match = OG_TRUE;
return OG_SUCCESS;
}
status_t db_fetch_ptrans_by_gtid(knl_session_t *session, knl_xa_xid_t *xa_xid, uint64 *ltid,
bool32 *is_found, rowid_t *rowid)
{
knl_match_cond_t org_match_cond = session->match_cond;
knl_cursor_t *cursor = NULL;
ptrans_match_cond_t cond;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_PENDING_TRANS_ID, OG_INVALID_ID32);
cursor->stmt = (void *)&cond;
session->match_cond = db_match_ptrans;
cond.session = session;
cond.cursor = cursor;
cond.xa_xid = xa_xid;
cond.ltid = NULL;
cond.only_remained = OG_FALSE;
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
session->match_cond = org_match_cond;
return OG_ERROR;
}
session->match_cond = org_match_cond;
if (cursor->eof) {
*is_found = OG_FALSE;
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
if (db_decode_ptrans_result(session, cursor, NULL, ltid, NULL, NULL) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
ROWID_COPY((*rowid), cursor->rowid);
CM_RESTORE_STACK(session->stack);
*is_found = OG_TRUE;
return OG_SUCCESS;
}
status_t db_fetch_ptrans_by_ltid(knl_session_t *session, uint64 ltid, knl_xa_xid_t *xa_xid,
binary_t *tlocklob, bool32 *is_found, knl_rm_t *rm)
{
knl_match_cond_t org_match_cond = session->match_cond;
knl_cursor_t *cursor = NULL;
ptrans_match_cond_t cond;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_PENDING_TRANS_ID, OG_INVALID_ID32);
cursor->stmt = (void *)&cond;
session->match_cond = db_match_ptrans;
cond.session = session;
cond.cursor = cursor;
cond.xa_xid = NULL;
cond.ltid = <id;
cond.only_remained = OG_FALSE;
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
session->match_cond = org_match_cond;
return OG_ERROR;
}
session->match_cond = org_match_cond;
if (cursor->eof) {
*is_found = OG_FALSE;
OG_LOG_DEBUG_WAR("fetch from pending_trans$ by ltid[%llu] failed.", ltid);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
if (db_decode_ptrans_result(session, cursor, xa_xid, NULL, tlocklob, &rm->uid) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
ROWID_COPY(rm->xa_rowid, cursor->rowid);
CM_RESTORE_STACK(session->stack);
*is_found = OG_TRUE;
return OG_SUCCESS;
}
status_t db_delete_ptrans_by_rowid(knl_session_t *session, knl_xa_xid_t *xa_xid, uint64 ltid, rowid_t rowid)
{
knl_match_cond_t org_match_cond = session->match_cond;
knl_cursor_t *cursor = NULL;
ptrans_match_cond_t cond;
bool32 is_found = OG_FALSE;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_PENDING_TRANS_ID, OG_INVALID_ID32);
cursor->stmt = (void *)&cond;
knl_panic_log(!IS_INVALID_ROWID(rowid), "the rowid is invalid, panic info: page %u-%u type %u table %s",
cursor->rowid.file, cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type,
((table_t *)cursor->table)->desc.name);
ROWID_COPY(cursor->rowid, rowid);
session->match_cond = db_match_ptrans;
cond.session = session;
cond.cursor = cursor;
cond.xa_xid = xa_xid;
cond.ltid = <id;
cond.only_remained = OG_FALSE;
if (knl_fetch_by_rowid(session, cursor, &is_found) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
session->match_cond = org_match_cond;
return OG_ERROR;
}
session->match_cond = org_match_cond;
if (!is_found) {
OG_LOG_DEBUG_INF("not found xa_xid[%llu] in pending_trans$.", xa_xid->fmt_id);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_delete_ptrans_remained(knl_session_t *session, knl_xa_xid_t *xa_xid, uint64 *ltid, bool32 *is_found)
{
knl_match_cond_t org_match_cond = session->match_cond;
knl_cursor_t *cursor = NULL;
ptrans_match_cond_t cond;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_PENDING_TRANS_ID, OG_INVALID_ID32);
cursor->stmt = (void *)&cond;
session->match_cond = db_match_ptrans;
cond.session = session;
cond.cursor = cursor;
cond.xa_xid = xa_xid;
cond.ltid = ltid;
cond.only_remained = OG_TRUE;
*is_found = OG_FALSE;
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
session->match_cond = org_match_cond;
knl_rollback(session, NULL);
return OG_ERROR;
}
while (!cursor->eof) {
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
session->match_cond = org_match_cond;
knl_rollback(session, NULL);
return OG_ERROR;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
session->match_cond = org_match_cond;
knl_rollback(session, NULL);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
session->match_cond = org_match_cond;
knl_commit(session);
return OG_SUCCESS;
}
status_t db_write_syssyn(knl_session_t *session, knl_cursor_t *cursor, knl_synonym_t *synonym)
{
uint32 max_size;
row_assist_t ra;
table_t *table = NULL;
max_size = session->kernel->attr.max_row_size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_SYN_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, max_size, table->desc.column_count);
if (row_put_int32(&ra, synonym->uid) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int32(&ra, synonym->id) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int64(&ra, synonym->org_scn) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int64(&ra, synonym->chg_scn) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_str(&ra, synonym->name) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_str(&ra, synonym->table_owner) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_str(&ra, synonym->table_name) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int32(&ra, synonym->flags) != OG_SUCCESS) {
return OG_ERROR;
}
if (row_put_int32(&ra, synonym->type) != OG_SUCCESS) {
return OG_ERROR;
}
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_init_synonmy_desc(knl_session_t *session, knl_synonym_t *synonym, knl_synonym_def_t *def)
{
if (!dc_get_user_id(session, &def->owner, &synonym->uid)) {
OG_THROW_ERROR(ERR_USER_NOT_EXIST, T2S(&def->owner));
return OG_ERROR;
}
synonym->id = OG_INVALID_ID32;
synonym->org_scn = db_inc_scn(session);
synonym->chg_scn = synonym->org_scn;
(void)cm_text2str(&def->name, synonym->name, OG_NAME_BUFFER_SIZE);
(void)cm_text2str(&def->table_owner, synonym->table_owner, OG_NAME_BUFFER_SIZE);
(void)cm_text2str(&def->table_name, synonym->table_name, OG_NAME_BUFFER_SIZE);
synonym->flags = OBJ_STATUS_VALID;
synonym->type = knl_get_object_type(def->ref_dc_type);
return OG_SUCCESS;
}
status_t db_create_synonym(knl_session_t *session, knl_handle_t stmt, knl_synonym_def_t *def)
{
knl_synonym_t synonym;
knl_cursor_t *cursor = NULL;
rd_synonym_t redo;
object_address_t depender;
object_address_t referer;
dc_user_t *user = NULL;
if (DB_NOT_READY(session)) {
OG_THROW_ERROR(ERR_NO_DB_ACTIVE);
return OG_ERROR;
}
if (db_init_synonmy_desc(session, &synonym, def) != OG_SUCCESS) {
return OG_ERROR;
}
if (dc_open_user_by_id(session, synonym.uid, &user) != OG_SUCCESS) {
return OG_ERROR;
}
if (dc_create_synonym_entry(session, user, &synonym) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->row = (row_head_t *)cursor->buf;
if (db_write_syssyn(session, cursor, &synonym) != OG_SUCCESS) {
dc_free_broken_entry(session, synonym.uid, synonym.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
depender.uid = synonym.uid;
depender.oid = synonym.id;
depender.tid = OBJ_TYPE_SYNONYM;
depender.scn = synonym.chg_scn;
errno_t err = strncpy_s(depender.name, OG_NAME_BUFFER_SIZE, def->name.str, def->name.len);
knl_securec_check(err);
referer.uid = def->ref_uid;
referer.oid = def->ref_oid;
referer.tid = knl_get_object_type(def->ref_dc_type);
referer.scn = def->ref_chg_scn;
err = strncpy_s(referer.name, OG_NAME_BUFFER_SIZE, def->table_name.str, def->table_name.len);
knl_securec_check(err);
if (db_write_sysdep(session, cursor, &depender, &referer, 0) != OG_SUCCESS) {
dc_free_broken_entry(session, synonym.uid, synonym.id);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
dc_ready(session, synonym.uid, synonym.id);
redo.op_type = RD_CREATE_SYNONYM;
redo.uid = synonym.uid;
redo.id = synonym.id;
log_put(session, RD_LOGIC_OPERATION, &redo, sizeof(rd_synonym_t), LOG_ENTRY_FLAG_NONE);
log_add_lrep_ddl_info(session, stmt, LOGIC_OP_SYNONYM, RD_CREATE_SYNONYM, NULL);
knl_commit(session);
return OG_SUCCESS;
}
static status_t db_delete_from_syssyn(knl_session_t *session, knl_cursor_t *cursor, dc_entry_t *syn_entry)
{
uint32 uid = (uint32)syn_entry->uid;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_SYN_ID, IX_SYS_SYNONYM001_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 *)&uid,
sizeof(uint32), IX_COL_SYS_SYNONYM001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, (void *)syn_entry->name,
(uint16)strlen(syn_entry->name), IX_COL_SYS_SYNONYM001_SYNONYM_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
if (cursor->eof) {
OG_THROW_ERROR(ERR_SYNONYM_NOT_EXIST, syn_entry->user->desc.name, syn_entry->name);
return OG_ERROR;
}
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_delete_from_sysdep(knl_session_t *session, knl_cursor_t *cursor, uint32 uid, int64 oid, uint32 tid)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_DEPENDENCY_ID, IX_DEPENDENCY1_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_DEPENDENCY1_D_OWNER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_BIGINT, &oid, sizeof(int64),
IX_COL_DEPENDENCY1_D_OBJ_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &tid, sizeof(uint32),
IX_COL_DEPENDENCY1_D_TYPE_ID);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_DEPENDENCY1_ORDER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_DEPENDENCY1_D_OWNER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_BIGINT, &oid, sizeof(int64),
IX_COL_DEPENDENCY1_D_OBJ_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &tid, sizeof(uint32),
IX_COL_DEPENDENCY1_D_TYPE_ID);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_DEPENDENCY1_ORDER_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
while (!cursor->eof) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
return OG_ERROR;
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
* db_delete_dependency
*
* This function is used to delete the referenced object info of the input object.
*/
status_t db_delete_dependency(knl_session_t *session, uint32 uid, int64 oid, uint32 tid)
{
knl_cursor_t *cursor = NULL;
status_t status;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
status = db_delete_from_sysdep(session, cursor, uid, oid, tid);
CM_RESTORE_STACK(session->stack);
return status;
}
status_t db_drop_synonym(knl_session_t *session, knl_handle_t stmt, knl_dictionary_t *dc)
{
rd_synonym_t redo;
knl_cursor_t *cursor = NULL;
dc_entry_t *syn_entry = (dc_entry_t *)dc->syn_handle;
obj_info_t obj_addr;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->row = (row_head_t *)cursor->buf;
if (OG_SUCCESS != db_delete_from_syssyn(session, cursor, syn_entry)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != db_delete_from_sysdep(session, cursor, syn_entry->uid, syn_entry->id, OBJ_TYPE_SYNONYM)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
redo.op_type = RD_DROP_SYNONYM;
redo.uid = syn_entry->uid;
redo.id = syn_entry->id;
log_put(session, RD_LOGIC_OPERATION, &redo, sizeof(rd_synonym_t), LOG_ENTRY_FLAG_NONE);
obj_addr.oid = syn_entry->id;
obj_addr.uid = syn_entry->uid;
obj_addr.tid = OBJ_TYPE_SYNONYM;
if (g_knl_callback.update_depender(session, &obj_addr) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
log_add_lrep_ddl_info(session, stmt, LOGIC_OP_SYNONYM, RD_DROP_SYNONYM, NULL);
knl_commit(session);
dc_free_broken_entry(session, syn_entry->uid, syn_entry->id);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_fetch_syssynonym_by_user(knl_session_t *session, uint32 uid, knl_cursor_t *cursor)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_SYN_ID, IX_SYS_SYNONYM001_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_SYNONYM001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_SYNONYM001_USER);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_SYNONYM001_SYNONYM_NAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_SYNONYM001_SYNONYM_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
return OG_ERROR;
}
return (bool32)(!cursor->eof);
}
status_t db_drop_synonym_by_user(knl_session_t *session, uint32 uid)
{
knl_cursor_t *cursor = NULL;
uint32 syn_id;
object_type_t syn_type;
object_type_t depend_type;
text_t syn_name;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_SYN_ID, IX_SYS_SYNONYM001_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_SYNONYM001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &uid, sizeof(uint32),
IX_COL_SYS_SYNONYM001_USER);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_SYNONYM001_SYNONYM_NAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_SYNONYM001_SYNONYM_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
while (!cursor->eof) {
syn_id = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_SYN_OBJID);
syn_type = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_SYN_TYPE);
if (IS_PL_SYN(syn_type)) {
syn_name.len = (uint32)CURSOR_COLUMN_SIZE(cursor, SYS_SYN_SYNONYM_NAME);
syn_name.str = (char*)CURSOR_COLUMN_DATA(cursor, SYS_SYN_SYNONYM_NAME);
if (g_knl_callback.pl_drop_synonym_by_user(session, uid, &syn_name) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
} else {
depend_type = OBJ_TYPE_SYNONYM;
if (OG_SUCCESS != db_delete_dependency(session, uid, syn_id, depend_type)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
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 db_delete_from_sys_roles(knl_session_t *session, uint32 rid)
{
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cursor->row = (row_head_t *)cursor->buf;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_ROLES_ID, IX_SYS_ROLES_001_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 *)&rid, sizeof(rid),
IX_COL_SYS_ROLES_001_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, (void *)&rid, sizeof(rid),
IX_COL_SYS_ROLES_001_ID);
knl_set_key_flag(&cursor->scan_range.l_key, SCAN_KEY_LEFT_INFINITE, IX_COL_SYS_ROLES_001_NAME);
knl_set_key_flag(&cursor->scan_range.r_key, SCAN_KEY_RIGHT_INFINITE, IX_COL_SYS_ROLES_001_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!cursor->eof) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_analyze_check_sample(double sample_ratio, stats_sample_level_t sample_level)
{
if (sample_ratio < 0 || sample_ratio > 1) {
OG_THROW_ERROR(ERR_INVALID_PARAMETER, "sample_ratio");
return OG_ERROR;
}
if (sample_level != BLOCK_SAMPLE && sample_level != ROW_SAMPLE) {
OG_THROW_ERROR(ERR_INVALID_PARAMETER_ENUM, "sample level", sample_level);
return OG_ERROR;
}
return OG_SUCCESS;
}
bool32 db_check_analyze_wsr_table(text_t *name)
{
char *str = "WSR";
text_t wsr_name;
text_t split_name;
wsr_name.len = (uint32)strlen(str);
wsr_name.str = str;
if (name->len <= wsr_name.len) {
return OG_FALSE;
}
split_name.len = (uint32)strlen(str);
split_name.str = name->str;
if (cm_text_equal_ins(&wsr_name, &split_name)) {
return OG_TRUE;
}
return OG_FALSE;
}
static status_t db_analyze_check_dc(knl_dictionary_t *dc, text_t *user, text_t *name, bool32 *unsupport_type)
{
dc_entity_t *entity = DC_ENTITY(dc);
if (STATS_INVALID_TABLE(entity->type)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "analyze table", dc_type2name(entity->type));
return OG_ERROR;
}
if (SYNONYM_EXIST(dc)) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, T2S(user), T2S_EX(name));
return OG_ERROR;
}
if (IS_SYS_DC(dc)) {
*unsupport_type = OG_TRUE;
return OG_SUCCESS;
}
if (dc->uid == DB_SYS_USER_ID) {
if (db_check_analyze_wsr_table(name)) {
*unsupport_type = OG_TRUE;
return OG_SUCCESS;
}
}
if (entity->stats_locked) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "analyze table", "statistics locked table");
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_analyze_table_part(knl_session_t *session, knl_analyze_tab_def_t *def, bool32 is_dynamic)
{
text_t user = def->owner;
text_t name = def->name;
stats_option_t stats_option;
knl_dictionary_t dc;
bool32 sys_table = OG_FALSE;
stats_load_info_t load_info;
status_t result = OG_SUCCESS;
SYNC_POINT_GLOBAL_START(COLLECT_STATISTICS_ANALYZED_DATA_FAIL, &result, OG_ERROR);
stats_init_stats_option(&stats_option, def);
if (db_analyze_check_sample(stats_option.sample_ratio, stats_option.sample_level) != OG_SUCCESS) {
return OG_ERROR;
}
if (dc_open(session, &user, &name, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_analyze_check_dc(&dc, &user, &name, &sys_table) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
if (sys_table) {
dc_close(&dc);
return OG_SUCCESS;
}
table_t *table = DC_TABLE(&dc);
if (!IS_PART_TABLE(table)) {
dc_close(&dc);
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "analyze partition", table->desc.name);
return OG_ERROR;
}
if (stats_analyze_single_table_part(session, &dc, def, stats_option, is_dynamic) != OG_SUCCESS) {
stats_rollback(session, is_dynamic);
stats_set_analyzed(session, &dc, def->need_analyzed);
dc_close(&dc);
return OG_ERROR;
}
stats_commit(session, is_dynamic);
stats_set_analyzed(session, &dc, def->need_analyzed);
table_part_t *table_part = (table_part_t*)def->table_part;
stats_disable_table_part_mon(&dc, table_part, def->need_analyzed);
stats_set_load_info(&load_info, DC_ENTITY(&dc), OG_TRUE, table_part->desc.part_id);
if (lock_table_shared_directly(session, &dc) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
stats_flush_logic_log(session, &dc, &load_info);
if (stats_refresh_dc(session, &dc, load_info) != OG_SUCCESS) {
unlock_tables_directly(session);
stats_dc_invalidate(session, &dc);
dc_close(&dc);
return OG_ERROR;
}
unlock_tables_directly(session);
dc_close(&dc);
SYNC_POINT_GLOBAL_END;
return result;
}
static void stat_put_version(bool32 *stat_exists, uint32 *stats_version)
{
if (*stat_exists) {
(*stats_version)++;
} else {
(*stat_exists) = OG_TRUE;
(*stats_version) = 0;
}
}
status_t db_analyze_temp_table(knl_session_t *session, knl_dictionary_t *dc, stats_option_t stats_option,
bool32 is_dynamic, bool32 *need_invalidate)
{
bool32 need_lock = !IS_LTT_BY_ID(dc->oid);
if (need_lock) {
if (lock_table_shared_directly(session, dc) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (STATS_MANUAL_SESSION_GTT(dc->type, dc->oid, is_dynamic)) {
if (knl_begin_auton_rm(session) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (stats_gather_temp_table(session, dc, stats_option, is_dynamic) != OG_SUCCESS) {
if (STATS_MANUAL_SESSION_GTT(dc->type, dc->oid, is_dynamic)) {
knl_end_auton_rm(session, OG_ERROR);
}
return OG_ERROR;
}
stats_disable_table_mon(session, dc, OG_TRUE);
* only manual collection stats for session gtt will be saved in system table.
* And if manual collection stats exists, CBO will only use it for gtt.
*/
dc_entity_t *entity = DC_ENTITY(dc);
stats_load_info_t load_info;
stats_set_load_info(&load_info, entity, OG_TRUE, OG_INVALID_ID32);
if (STATS_MANUAL_SESSION_GTT(dc->type, dc->oid, is_dynamic)) {
if (stats_refresh_dc(session, dc, load_info) != OG_SUCCESS) {
if (need_lock) {
unlock_tables_directly(session);
}
*need_invalidate = OG_TRUE;
knl_end_auton_rm(session, OG_ERROR);
return OG_ERROR;
}
knl_end_auton_rm(session, OG_SUCCESS);
}
knl_temp_cache_t *temp_cache = NULL;
if (IS_TEMP_TABLE_BY_DC(dc)) {
temp_cache = knl_get_temp_cache((knl_handle_t)session, entity->table.desc.uid, entity->table.desc.id);
if (temp_cache == NULL) {
return OG_ERROR;
}
stat_put_version(&temp_cache->stat_exists, &temp_cache->stats_version);
} else {
stat_put_version(&entity->stat_exists, &entity->stats_version);
}
if (need_lock) {
unlock_tables_directly(session);
}
return OG_SUCCESS;
}
* For gathering all table parts statistics, we don't need to lock table during gather stats and lock it
* when refresh dc.
*/
status_t db_analyze_all_table_partitions(knl_session_t *session, knl_dictionary_t *dc, stats_option_t stats_option,
bool32 is_dynamic, bool32 *is_invalidate)
{
bool32 analyzed = OG_FALSE;
stats_load_info_t load_info;
if (stats_analyze_normal_table(session, dc, stats_option, is_dynamic, &analyzed) != OG_SUCCESS) {
stats_rollback(session, is_dynamic);
stats_set_analyzed(session, dc, analyzed);
return OG_ERROR;
}
stats_commit(session, is_dynamic);
stats_set_analyzed(session, dc, analyzed);
stats_disable_table_mon(session, dc, analyzed);
if (!analyzed) {
return OG_SUCCESS;
}
if (lock_table_shared_directly(session, dc) != OG_SUCCESS) {
return OG_ERROR;
}
stats_set_load_info(&load_info, DC_ENTITY(dc), OG_TRUE, OG_INVALID_ID32);
stats_flush_logic_log(session, dc, &load_info);
if (stats_refresh_dc(session, dc, load_info) != OG_SUCCESS) {
stats_rollback(session, is_dynamic);
unlock_tables_directly(session);
*is_invalidate = OG_TRUE;
return OG_ERROR;
}
stats_commit(session, is_dynamic);
unlock_tables_directly(session);
return OG_SUCCESS;
}
status_t db_analyze_normal_table(knl_session_t *session, knl_dictionary_t *dc, stats_option_t stats_option,
bool32 is_dynamic, bool32 *need_invalidate)
{
bool32 analyzed = OG_FALSE;
stats_load_info_t load_info;
table_t *table = DC_TABLE(dc);
if (IS_PART_TABLE(table)) {
return db_analyze_all_table_partitions(session, dc, stats_option, is_dynamic, &analyzed);
}
if (lock_table_shared_directly(session, dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (stats_analyze_normal_table(session, dc, stats_option, is_dynamic, &analyzed) != OG_SUCCESS) {
stats_rollback(session, is_dynamic);
stats_set_analyzed(session, dc, analyzed);
unlock_tables_directly(session);
return OG_ERROR;
}
stats_commit(session, is_dynamic);
stats_set_analyzed(session, dc, analyzed);
stats_disable_table_mon(session, dc, analyzed);
if (analyzed) {
stats_set_load_info(&load_info, DC_ENTITY(dc), OG_TRUE, OG_INVALID_ID32);
stats_flush_logic_log(session, dc, &load_info);
if (stats_refresh_dc(session, dc, load_info) != OG_SUCCESS) {
unlock_tables_directly(session);
*need_invalidate = OG_TRUE;
return OG_ERROR;
}
}
unlock_tables_directly(session);
return OG_SUCCESS;
}
status_t db_analyze_table(knl_session_t *session, knl_analyze_tab_def_t *def, bool32 is_dynamic)
{
text_t user = def->owner;
text_t name = def->name;
stats_option_t stats_option;
knl_dictionary_t dc;
bool32 unsupport_type = OG_FALSE;
bool32 need_invalidate = OG_FALSE;
status_t status = OG_SUCCESS;
SYNC_POINT_GLOBAL_START(COLLECT_STATISTICS_ANALYZED_DATA_FAIL, &status, OG_ERROR);
stats_init_stats_option(&stats_option, def);
if (db_analyze_check_sample(stats_option.sample_ratio, stats_option.sample_level) != OG_SUCCESS) {
return OG_ERROR;
}
if (dc_open(session, &user, &name, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_analyze_check_dc(&dc, &user, &name, &unsupport_type) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
if (unsupport_type) {
dc_close(&dc);
return OG_SUCCESS;
}
if (IS_TEMP_TABLE_BY_DC((&dc))) {
status = db_analyze_temp_table(session, &dc, stats_option, is_dynamic, &need_invalidate);
} else {
status = db_analyze_normal_table(session, &dc, stats_option, is_dynamic, &need_invalidate);
}
dc_close(&dc);
if (need_invalidate) {
stats_dc_invalidate(session, &dc);
}
SYNC_POINT_GLOBAL_END;
return status;
}
status_t db_analyze_index(knl_session_t *session, knl_analyze_index_def_t *def, bool32 is_dynamic)
{
text_t user = def->owner;
text_t idx_name = def->name;
knl_dictionary_t dc;
bool32 unsupport_type = OG_FALSE;
stats_load_info_t load_info;
if (db_analyze_check_sample(def->sample_ratio, def->sample_level) != OG_SUCCESS) {
return OG_ERROR;
}
if (knl_find_dc_by_tmpidx(session, &user, &idx_name)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "analyze index", "temp table's index");
return OG_ERROR;
}
if (knl_open_dc_by_index(session, &user, NULL, &idx_name, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_analyze_check_dc(&dc, &user, &idx_name, &unsupport_type) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
if (unsupport_type) {
dc_close(&dc);
return OG_SUCCESS;
}
if (IS_TEMP_TABLE_BY_DC(&dc)) {
dc_close(&dc);
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "analyze index", "temp table's index");
return OG_ERROR;
}
if (lock_table_shared_directly(session, &dc) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
if (stats_analyze_index(session, &dc, def, is_dynamic) != OG_SUCCESS) {
stats_rollback(session, is_dynamic);
stats_set_analyzed(session, &dc, def->need_analyzed);
unlock_tables_directly(session);
dc_close(&dc);
return OG_ERROR;
}
stats_commit(session, is_dynamic);
stats_set_analyzed(session, &dc, def->need_analyzed);
stats_disable_table_mon(session, &dc, def->need_analyzed);
stats_set_load_info(&load_info, DC_ENTITY(&dc), OG_TRUE, OG_INVALID_ID32);
stats_flush_logic_log(session, &dc, &load_info);
if (stats_refresh_dc(session, &dc, load_info) != OG_SUCCESS) {
unlock_tables_directly(session);
stats_dc_invalidate(session, &dc);
dc_close(&dc);
return OG_ERROR;
}
unlock_tables_directly(session);
dc_close(&dc);
return OG_SUCCESS;
}
* db_delete_table_stats
*
* This function is used to delete table-related statistics.
*
*/
status_t db_delete_table_stats(knl_session_t *session, text_t *ownname, text_t *tabname, text_t *partname)
{
knl_dictionary_t dc;
uint32 part_no;
status_t status;
if (dc_open(session, ownname, tabname, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (SYNONYM_EXIST(&dc)) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, T2S(ownname), T2S_EX(tabname));
dc_close(&dc);
return OG_ERROR;
}
dc_entity_t *entity = DC_ENTITY(&dc);
if (STATS_INVALID_TABLE(entity->type)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "delete statistics of ", dc_type2name(entity->type));
dc_close(&dc);
return OG_ERROR;
}
if (IS_LTT_BY_ID(dc.oid)) {
dc_close(&dc);
return OG_SUCCESS;
}
if (lock_table_shared_directly(session, &dc) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
if (partname != NULL) {
if (!IS_PART_TABLE(&entity->table)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "delete partition statistics ", entity->table.desc.name);
unlock_tables_directly(session);
dc_close(&dc);
return OG_ERROR;
}
status = knl_find_table_part_by_name(entity, partname, &part_no);
if (status == OG_SUCCESS) {
table_part_t *table_part = TABLE_GET_PART(&entity->table, part_no);
status = stats_delete_part_stats(session, dc.uid, dc.oid, table_part->desc.part_id);
}
} else {
status = stats_delete_table_stats(session, dc.uid, dc.oid, OG_FALSE);
}
if (status == OG_SUCCESS) {
knl_commit(session);
} else {
knl_rollback(session, NULL);
}
unlock_tables_directly(session);
dc_close(&dc);
return status;
}
* Determine if current part exists in parts_loc
*/
bool32 is_idx_part_existed(knl_part_locate_t *current_part_loc, knl_parts_locate_t parts_loc, bool32 is_sub)
{
if (parts_loc.specified_parts == 0) {
return OG_TRUE;
}
if (parts_loc.specified_parts == 1 && parts_loc.part[0].subpart_no == OG_INVALID_ID32) {
return current_part_loc->part_no == parts_loc.part[0].part_no;
}
for (uint32 i = 0; i < parts_loc.specified_parts; i++) {
if (!is_sub && parts_loc.part[i].part_no != OG_INVALID_ID32 &&
current_part_loc->part_no == parts_loc.part[i].part_no) {
return OG_TRUE;
}
if (is_sub && parts_loc.part[i].subpart_no != OG_INVALID_ID32 &&
current_part_loc->part_no == parts_loc.part[i].part_no &&
current_part_loc->subpart_no == parts_loc.part[i].subpart_no) {
return OG_TRUE;
}
}
return OG_FALSE;
}
status_t db_fill_shadow_index_parallel(knl_session_t *session, knl_cursor_t *cursor, knl_dictionary_t *dc,
knl_part_locate_t part_loc, index_build_mode_t build_mode)
{
return db_fill_shadow_index(session, cursor, dc, part_loc, build_mode);
}
* parallel rebuild index from heap or btree, The priorities are as follows
* 1.active worker for all segments
* 2.active worker for balance worker load
*/
static status_t db_parallel_rebuild_index(knl_session_t *session, knl_dictionary_t *dc,
knl_parts_locate_t parts_loc, knl_alindex_def_t *def)
{
knl_dictionary_t new_dc;
status_t status;
index_t *old_index = NULL;
idx_paral_rebuild_ctx_t *ogx = NULL;
rebuild_index_def_t *rebuild_def = &def->rebuild;
uint32 paral_count = rebuild_def->parallelism;
uint32 split_cnt = (parts_loc.specified_parts == 0) ? MAX_SPLIT_RANGE_CNT : 1;
if (IS_SYS_DC(dc)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "rebuild index parallel", "system table");
return OG_ERROR;
}
if (dc_open_table_private(session, dc->uid, dc->oid, &new_dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (dc_load_shadow_index(session, &new_dc) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
return OG_ERROR;
}
old_index = idx_get_index_by_shadow(&new_dc);
if (old_index->desc.is_func) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "rebuild index parallel", "functional index");
dc_close_table_private(&new_dc);
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
do {
paral_count = MIN(paral_count, session->kernel->attr.cpu_count);
paral_count = MIN(paral_count, OG_MAX_REBUILD_INDEX_PARALLELISM);
status = idx_alloc_parallel_rebuild_rsc(session, &new_dc, paral_count, &ogx);
if (status == OG_ERROR) {
break;
}
ogx->current_part = parts_loc.part[0];
if (idx_is_multi_segments(ogx, parts_loc, rebuild_def)) {
status = idx_start_rebuild_workers(session, ogx, parts_loc);
} else {
status = idx_start_rebuild_worker(session, ogx, split_cnt) ? OG_SUCCESS : OG_ERROR;
}
if (status == OG_SUCCESS) {
status = idx_wait_rebuild_workers(session, ogx);
}
}while (0);
idx_release_parallel_rebuild_rsc(session, ogx, paral_count);
dc_close_table_private(&new_dc);
CM_RESTORE_STACK(session->stack);
OG_LOG_DEBUG_INF("db_rebuild_index_parallel finished, paral_count:%d,cpu_count:%d", paral_count,
session->kernel->attr.cpu_count);
return status;
}
static status_t db_rebuild_index(knl_session_t *session, knl_cursor_t *cursor, knl_dictionary_t *dc,
knl_part_locate_t part_loc)
{
knl_dictionary_t new_dc;
status_t status = OG_SUCCESS;
errno_t ret;
if (!IS_SYS_DC(dc)) {
if (dc_open_table_private(session, dc->uid, dc->oid, &new_dc) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
ret = memcpy_sp(&new_dc, sizeof(knl_dictionary_t), dc, sizeof(knl_dictionary_t));
knl_securec_check(ret);
}
do {
if (dc_load_shadow_index(session, &new_dc) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
cursor->action = CURSOR_ACTION_SELECT;
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
if (part_loc.part_no == OG_INVALID_ID32) {
cursor->part_loc.part_no = 0;
cursor->part_loc.subpart_no = 0;
} else {
cursor->part_loc = part_loc;
}
if (knl_open_cursor(session, cursor, &new_dc) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
if (db_fill_shadow_index(session, cursor, &new_dc, part_loc, REBUILD_INDEX) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
status = OG_ERROR;
break;
}
knl_close_cursor(session, cursor);
} while (0);
if (!IS_SYS_DC(dc)) {
dc_close_table_private(&new_dc);
}
return status;
}
static status_t db_rebuild_index_online(knl_session_t *session, knl_cursor_t *cursor,
knl_dictionary_t *dc, knl_part_locate_t part_loc, uint32 timeout_s)
{
dc_entity_t *entity = NULL;
knl_dictionary_t new_dc;
errno_t err;
knl_commit(session);
dc_invalidate(session, (dc_entity_t *)dc->handle);
if (DB_IS_CLUSTER(session)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "rebuild index online", " cluster database");
return OG_ERROR;
}
if (knl_open_dc_by_id(session, dc->uid, dc->oid, &new_dc, OG_TRUE) != OG_SUCCESS) {
return OG_ERROR;
}
dc_close(dc);
err = memcpy_sp(dc, sizeof(knl_dictionary_t), &new_dc, sizeof(knl_dictionary_t));
knl_securec_check(err);
if (dc_load_shadow_index(session, dc) != OG_SUCCESS) {
return OG_ERROR;
}
entity = DC_ENTITY(dc);
cursor->action = CURSOR_ACTION_SELECT;
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
cursor->part_loc.part_no = (part_loc.part_no == OG_INVALID_ID32 ? 0 : part_loc.part_no);
cursor->part_loc.subpart_no = (part_loc.subpart_no == OG_INVALID_ID32 ? 0 : part_loc.subpart_no);
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
return OG_ERROR;
}
cursor->isolevel = (uint8)ISOLATION_CURR_COMMITTED;
if (tx_begin(session) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
return OG_ERROR;
}
lock_degrade_table_lock(session, entity);
if (db_fill_shadow_index(session, cursor, dc, part_loc, REBUILD_INDEX_ONLINE) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
return OG_ERROR;
}
if (lock_upgrade_table_lock(session, entity, timeout_s) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
return OG_ERROR;
}
knl_close_cursor(session, cursor);
return OG_SUCCESS;
}
static status_t db_init_shadow_index(knl_session_t *session, rebuild_index_def_t *def, knl_dictionary_t *dc,
index_t *old_index, index_t *shadow_index)
{
knl_index_desc_t desc;
uint32 spc_id;
text_t idx_name;
space_t *space = NULL;
errno_t err;
if (CM_IS_EMPTY(&def->space) || def->specified_parts > 0) {
spc_id = old_index->desc.space_id;
} else {
if (spc_get_space_id(session, &def->space, def->is_for_create_db, &spc_id) != OG_SUCCESS) {
return OG_ERROR;
}
if (spc_check_by_uid(session, &def->space, spc_id, old_index->desc.uid) != OG_SUCCESS) {
return OG_ERROR;
}
space = SPACE_GET(session, spc_id);
if (!spc_valid_space_object(session, space->ctrl->id)) {
OG_THROW_ERROR(ERR_SPACE_HAS_REPLACED, space->ctrl->name, space->ctrl->name);
return OG_ERROR;
}
}
cm_str2text(old_index->desc.name, &idx_name);
if (db_fetch_index_desc(session, old_index->desc.uid, &idx_name, &desc) != OG_SUCCESS) {
return OG_ERROR;
}
err = memset_sp(shadow_index, sizeof(index_t), 0, sizeof(index_t));
knl_securec_check(err);
desc.slot = old_index->desc.slot;
desc.space_id = spc_id;
desc.is_invalid = OG_FALSE;
desc.entry = INVALID_PAGID;
desc.cr_mode = (def->cr_mode == OG_INVALID_ID8) ? old_index->desc.cr_mode : def->cr_mode;
desc.pctfree = (def->pctfree == OG_INVALID_ID32) ? old_index->desc.pctfree : def->pctfree;
desc.columns_info = old_index->desc.columns_info;
shadow_index->btree.is_shadow = OG_TRUE;
shadow_index->btree.index = shadow_index;
shadow_index->entity = DC_ENTITY(dc);
shadow_index->part_index = old_index->part_index;
err = memcpy_sp(&shadow_index->desc, sizeof(knl_index_desc_t), &desc, sizeof(knl_index_desc_t));
knl_securec_check(err);
return OG_SUCCESS;
}
status_t db_alter_temp_table_index(knl_session_t *session, table_t *table, index_t *old_index, index_t *index)
{
knl_cursor_t *cursor = NULL;
if (!knl_is_temp_table_empty(session, table->desc.uid, table->desc.id)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "rebuild index", "non-empty temporary table");
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (db_delete_from_sysindex(session, cursor, old_index->desc.uid, old_index->desc.table_id,
old_index->desc.id) != OG_SUCCESS) {
session->rm->is_ddl_op = OG_FALSE;
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_write_sysindex(session, cursor, &index->desc) != OG_SUCCESS) {
session->rm->is_ddl_op = OG_FALSE;
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
session->rm->is_ddl_op = OG_FALSE;
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static bool32 db_allow_index_rebuild(knl_session_t *session, knl_dictionary_t *dc, index_t *old_index,
index_t *index, bool32 is_online)
{
if (IS_SYS_DC(dc)) {
if (is_online) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "rebuild index online", "system table");
return OG_FALSE;
}
if (index->desc.space_id != old_index->desc.space_id || index->desc.cr_mode != old_index->desc.cr_mode) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify index properties", "system index");
return OG_FALSE;
}
}
space_t *dest_space = SPACE_GET(session, index->desc.space_id);
space_t *old_space = SPACE_GET(session, old_index->desc.space_id);
if (SPACE_IS_LOGGING(dest_space) != SPACE_IS_LOGGING(old_space) ||
SPACE_IS_NOLOGGING(dest_space) != SPACE_IS_NOLOGGING(old_space)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify index properties",
"index rebuild in different type space");
return OG_FALSE;
}
if ((IS_SWAP_SPACE(old_space) && !IS_SWAP_SPACE(dest_space)) ||
(!IS_SWAP_SPACE(old_space) && IS_SWAP_SPACE(dest_space))) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify index properties",
"index rebuild in different type space");
return OG_FALSE;
}
if (IS_UNDO_SPACE(dest_space)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify index properties",
"index rebuild in undo space");
return OG_FALSE;
}
return OG_TRUE;
}
static status_t db_delete_remain_shadow_index(knl_session_t *session, knl_dictionary_t *dc)
{
if (((dc_entity_t *)dc->handle)->valid) {
if (lock_upgrade_table_lock(session, dc->handle, LOCK_INF_WAIT) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (knl_begin_auton_rm(session) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_drop_shadow_index(session, dc->uid, dc->oid, OG_TRUE) != OG_SUCCESS) {
knl_end_auton_rm(session, OG_ERROR);
return OG_ERROR;
}
knl_end_auton_rm(session, OG_SUCCESS);
return OG_SUCCESS;
}
static bool32 db_get_index_part(knl_alindex_def_t *def, index_t *index, index_part_t **old_part, uint32 part_index)
{
index_part_t *index_subpart = NULL;
if (!IS_PART_INDEX(index)) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ": index is not part index");
return OG_FALSE;
}
if (!part_idx_find_by_name(index->part_index, &def->rebuild.part_name[part_index], old_part)) {
if (!subpart_idx_find_by_name(index->part_index, &def->rebuild.part_name[part_index], &index_subpart)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S(&def->rebuild.part_name[part_index]));
return OG_FALSE;
}
*old_part = index_subpart;
}
if (def->type == ALINDEX_TYPE_REBUILD_PART && IS_SUB_IDXPART(&(*old_part)->desc)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S(&def->rebuild.part_name[part_index]));
return OG_FALSE;
}
if (def->type == ALINDEX_TYPE_REBUILD_SUBPART && !IS_SUB_IDXPART(&(*old_part)->desc)) {
if (!IS_COMPART_INDEX(index->part_index)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "rebuild one sub index partition on one non-subpartitioned index");
return OG_FALSE;
}
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S(&def->rebuild.part_name[part_index]));
return OG_FALSE;
}
return OG_TRUE;
}
static void db_rebuild_init_parts_loc(knl_parts_locate_t *parts_loc, knl_alindex_def_t *def)
{
rebuild_index_def_t *rebuild_def = &def->rebuild;
for (uint32 i = 0; i < MAX_REBUILD_PARTS; i++) {
parts_loc->part[i].part_no = OG_INVALID_ID32;
parts_loc->part[i].subpart_no = OG_INVALID_ID32;
}
parts_loc->specified_parts = rebuild_def->specified_parts;
}
static void db_parts_loc_asc_sort(knl_alindex_def_t *def, knl_parts_locate_t *parts_loc)
{
knl_part_locate_t temp_part_loc;
for (uint32 i = 0; i < def->rebuild.specified_parts; i++) {
for (uint32 j = i + 1; j < def->rebuild.specified_parts; j++) {
if (parts_loc->part[i].part_no > parts_loc->part[j].part_no ||
(parts_loc->part[i].part_no == parts_loc->part[j].part_no &&
parts_loc->part[i].subpart_no > parts_loc->part[j].subpart_no)) {
temp_part_loc = parts_loc->part[i];
parts_loc->part[i] = parts_loc->part[j];
parts_loc->part[j] = temp_part_loc;
}
}
}
}
static status_t db_get_index_parts_loc(knl_session_t *session, knl_alindex_def_t *def, knl_dictionary_t *dc,
index_t *index, rebuild_info_t* rebuild_info)
{
index_part_t *old_part = NULL;
index_part_t *compart = NULL;
rebuild_index_def_t *rebuild_def = &def->rebuild;
db_rebuild_init_parts_loc(&rebuild_info->parts_loc, def);
if (!rebuild_def->specified_parts) {
return OG_SUCCESS;
}
if (db_alter_indexpart_rebuild_verify(session, def, &rebuild_info->spc_id, index, 0) != OG_SUCCESS) {
return OG_ERROR;
}
for (uint32 i = 0; i < def->rebuild.specified_parts; i++) {
if (!db_get_index_part(def, index, &old_part, i)) {
return OG_ERROR;
}
if (!IS_PARENT_IDXPART(&old_part->desc)) {
if (IS_SUB_IDXPART(&old_part->desc)) {
compart = subpart_get_parent_idx_part(index, old_part->desc.parent_partid);
knl_panic_log(compart != NULL, "the index_compart is NULL, panic info: index name %s parent part name %s",
index->desc.name, old_part->desc.name);
rebuild_info->parts_loc.part[i].part_no = compart->part_no;
rebuild_info->parts_loc.part[i].subpart_no = old_part->part_no;
} else {
rebuild_info->parts_loc.part[i].part_no = old_part->part_no;
rebuild_info->parts_loc.part[i].subpart_no = OG_INVALID_ID32;
}
} else {
rebuild_info->parts_loc.part[i].part_no = old_part->part_no;
rebuild_info->parts_loc.part[i].subpart_no = OG_INVALID_ID32;
if (rebuild_def->specified_parts > 1) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "rebuild multiple parent partition indexes");
return OG_ERROR;
}
}
}
db_parts_loc_asc_sort(def, &rebuild_info->parts_loc);
return OG_SUCCESS;
}
static status_t db_alter_index_rebuild_verify(knl_session_t *session, knl_alindex_def_t *def, knl_dictionary_t *dc,
index_t *old_index, index_t *index)
{
rebuild_index_def_t *rebuild_def = &def->rebuild;
table_t *table = DC_TABLE(dc);
knl_panic_log(old_index != NULL, "invalid index:%s of table:%s", T2S_EX(&def->name), table->desc.name);
if (IS_AUTO_REBUILD(def->rebuild.lock_timeout) && (old_index->desc.org_scn != def->rebuild.org_scn)) {
OG_THROW_ERROR(ERR_INDEX_NOT_EXIST, T2S(&def->user), T2S_EX(&def->name));
OG_LOG_RUN_INF("index_name %s, org_scn %llu does not exist", index->desc.name, def->rebuild.org_scn);
return OG_ERROR;
}
if (db_init_shadow_index(session, rebuild_def, dc, old_index, index) != OG_SUCCESS) {
return OG_ERROR;
}
if (!db_allow_index_rebuild(session, dc, old_index, index, rebuild_def->is_online)) {
return OG_ERROR;
}
if (table->desc.type == TABLE_TYPE_TRANS_TEMP || table->desc.type == TABLE_TYPE_SESSION_TEMP) {
if (rebuild_def->is_online) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "rebuild index online", "temporary table");
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_alter_index_rebuild(knl_session_t *session, knl_alindex_def_t *def, knl_dictionary_t *dc,
index_t *old_index)
{
index_t index;
status_t status;
rebuild_info_t rebuild_info;
table_t *table = DC_TABLE(dc);
if (db_alter_index_rebuild_verify(session, def, dc, old_index, &index) != OG_SUCCESS) {
return OG_ERROR;
}
if (table->desc.type == TABLE_TYPE_TRANS_TEMP || table->desc.type == TABLE_TYPE_SESSION_TEMP) {
return db_alter_temp_table_index(session, table, old_index, &index);
}
rebuild_info.is_alter = OG_TRUE;
rebuild_info.spc_id = index.desc.space_id;
rebuild_info.alter_index_type = def->type;
if (db_get_index_parts_loc(session, def, dc, old_index, &rebuild_info) != OG_SUCCESS) {
return OG_ERROR;
}
if (CM_IS_EMPTY(&def->rebuild.space)) {
rebuild_info.spc_id = OG_INVALID_ID32;
}
if (db_create_shadow_index(session, dc, &index, NULL, rebuild_info) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
uint32 part_index = 0;
do {
if (def->rebuild.is_online) {
status = db_rebuild_index_online(session, cursor, dc, rebuild_info.parts_loc.part[part_index],
def->rebuild.lock_timeout);
} else if (def->rebuild.parallelism == 0) {
status = db_rebuild_index(session, cursor, dc, rebuild_info.parts_loc.part[part_index]);
} else {
status = db_parallel_rebuild_index(session, dc, rebuild_info.parts_loc, def);
break;
}
part_index++;
} while (status == OG_SUCCESS && part_index < def->rebuild.specified_parts);
table = DC_TABLE(dc);
if (status == OG_SUCCESS) {
status = db_switch_shadow_index(session, cursor, table, &index, rebuild_info.parts_loc);
}
CM_RESTORE_STACK(session->stack);
if (status != OG_SUCCESS) {
if (def->rebuild.is_online) {
knl_rollback(session, NULL);
* in case session is killed, maybe there is no chance to clean shadow index,
* we mark it as invalid, as a result, concurrency DML need not to mantain shadow index any more.
*/
dc_invalidate_shadow_index(dc->handle);
if (db_delete_remain_shadow_index(session, dc) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return status;
}
static status_t db_clean_shwidx_subpart(knl_session_t *session, index_part_t *subpart, bool32 clean_segment)
{
index_part_t part;
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_SHADOW_INDEXPART_ID, IX_SYS_SHW_INDEXPART001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
&subpart->desc.uid, sizeof(uint32), IX_COL_SYS_SHW_INDEXPART001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
&subpart->desc.table_id, sizeof(uint32), IX_COL_SYS_SHW_INDEXPART001_TABLE_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
&subpart->desc.index_id, sizeof(uint32), IX_COL_SYS_SHW_INDEXPART001_INDEX_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
&subpart->desc.part_id, sizeof(uint32), IX_COL_SYS_SHW_INDEXPART001_PART_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER,
&subpart->desc.parent_partid, sizeof(uint32), IX_COL_SYS_SHW_INDEXPART001_PARENTPART_ID);
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_SUCCESS;
}
errno_t ret = memset_sp(&part, sizeof(index_part_t), 0, sizeof(index_part_t));
knl_securec_check(ret);
dc_convert_index_part_desc(cursor, &part.desc);
part.desc.subpart_cnt = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_SHADOW_INDEXPART_COL_SUBPART_CNT);
if (clean_segment && spc_valid_space_object(session, part.desc.space_id) && !IS_INVALID_PAGID(part.desc.entry)) {
btree_drop_part_segment(session, &part);
}
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_create_shadow_indexpart(knl_session_t *session, knl_cursor_t *cursor, index_part_t *shadow_part)
{
row_assist_t ra;
knl_index_part_desc_t *desc = &shadow_part->desc;
space_t *space = SPACE_GET(session, desc->space_id);
if (!SPACE_IS_ONLINE(space)) {
OG_THROW_ERROR(ERR_SPACE_OFFLINE, space->ctrl->name, "write to shadow_indexpart$ failed");
return OG_ERROR;
}
if (knl_begin_auton_rm(session) != OG_SUCCESS) {
return OG_ERROR;
}
if (IS_SUB_IDXPART(&shadow_part->desc)) {
if (db_clean_shwidx_subpart(session, shadow_part, !SPACE_IS_NOLOGGING(space)) != OG_SUCCESS) {
knl_end_auton_rm(session, OG_ERROR);
return OG_ERROR;
}
if (db_drop_shadow_index(session, desc->uid, desc->table_id, !SPACE_IS_NOLOGGING(space)) != OG_SUCCESS) {
knl_end_auton_rm(session, OG_ERROR);
return OG_ERROR;
}
} else {
if (db_clean_shadow_index(session, desc->uid, desc->table_id, !SPACE_IS_NOLOGGING(space)) != OG_SUCCESS) {
knl_end_auton_rm(session, OG_ERROR);
return OG_ERROR;
}
}
knl_end_auton_rm(session, OG_SUCCESS);
if (btree_create_part_segment(session, shadow_part) != OG_SUCCESS) {
return OG_ERROR;
}
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_SHADOW_INDEXPART_ID, OG_INVALID_ID32);
table_t *table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, HEAP_MAX_ROW_SIZE(session), table->desc.column_count);
(void)row_put_int32(&ra, desc->uid);
(void)row_put_int32(&ra, desc->table_id);
(void)row_put_int32(&ra, desc->index_id);
(void)row_put_int32(&ra, desc->part_id);
(void)row_put_str(&ra, desc->name);
(void)row_put_int32(&ra, desc->hiboundval.len);
(void)row_put_text(&ra, &desc->hiboundval);
(void)row_put_int32(&ra, desc->space_id);
(void)row_put_int64(&ra, desc->org_scn);
(void)row_put_int64(&ra, *(int64 *)&desc->entry);
(void)row_put_int32(&ra, desc->initrans);
(void)row_put_int32(&ra, desc->pctfree);
(void)row_put_int32(&ra, desc->flags);
(void)row_put_bin(&ra, &desc->bhiboundval);
(void)row_put_int32(&ra, desc->subpart_cnt);
return knl_internal_insert(session, cursor);
}
bool32 db_rebuild_get_part(knl_alindex_def_t *def, index_t *index, index_part_t **old_part, int part_i)
{
index_part_t *index_subpart = NULL;
if (!IS_PART_INDEX(index)) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ": index is not part index");
return OG_FALSE;
}
if (!part_idx_find_by_name(index->part_index, &def->rebuild.part_name[part_i], old_part)) {
if (!subpart_idx_find_by_name(index->part_index, &def->rebuild.part_name[part_i], &index_subpart)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S(&def->rebuild.part_name[part_i]));
return OG_FALSE;
}
*old_part = index_subpart;
}
if (def->type == ALINDEX_TYPE_REBUILD_PART && IS_SUB_IDXPART(&(*old_part)->desc)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S(&def->rebuild.part_name[part_i]));
return OG_FALSE;
}
if (def->type == ALINDEX_TYPE_REBUILD_SUBPART && !IS_SUB_IDXPART(&(*old_part)->desc)) {
if (!IS_COMPART_INDEX(index->part_index)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "rebuild one sub index partition on one non-subpartitioned index");
return OG_FALSE;
}
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S(&def->rebuild.part_name[part_i]));
return OG_FALSE;
}
return OG_TRUE;
}
static status_t db_delete_remain_shadow_indexpart(knl_session_t *session, knl_cursor_t *cursor,
knl_dictionary_t *dc, index_t *index, index_part_t *new_part)
{
if (((dc_entity_t *)dc->handle)->valid) {
if (lock_upgrade_table_lock(session, dc->handle, LOCK_INF_WAIT) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (knl_begin_auton_rm(session) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_delete_from_shadow_sysindexpart(session, cursor, index->desc.uid, index->desc.table_id,
index->desc.id) != OG_SUCCESS) {
knl_end_auton_rm(session, OG_ERROR);
return OG_ERROR;
}
btree_drop_part_segment(session, new_part);
knl_end_auton_rm(session, OG_SUCCESS);
return OG_SUCCESS;
}
static status_t db_rebuild_index_part_entity(knl_session_t *session, knl_dictionary_t *dc, index_t *index,
index_part_t *shadow_part, knl_part_locate_t part_loc, knl_alindex_def_t *def)
{
status_t status;
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_parts_locate_t parts_loc;
if (db_create_shadow_indexpart(session, cursor, shadow_part) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
index_part_t *old_compart = INDEX_GET_PART(index, part_loc.part_no);
index_part_t *old_part = (part_loc.subpart_no != OG_INVALID_ID32) ?
PART_GET_SUBENTITY(index->part_index, old_compart->subparts[part_loc.subpart_no]) : old_compart;
db_rebuild_init_parts_loc(&parts_loc, def);
parts_loc.part[0] = part_loc;
uint32 index_id = index->desc.id;
for (;;) {
if (def->rebuild.is_online) {
status = db_rebuild_index_online(session, cursor, dc, part_loc, def->rebuild.lock_timeout);
} else {
status = db_rebuild_index(session, cursor, dc, part_loc);
}
index = dc_find_index_by_id((dc_entity_t *)dc->handle, index_id);
if (index == NULL) {
OG_THROW_ERROR(ERR_OBJECT_ID_NOT_EXIST, "index", index_id);
status = OG_ERROR;
break;
}
old_compart = INDEX_GET_PART(index, part_loc.part_no);
old_part = (part_loc.subpart_no != OG_INVALID_ID32) ?
PART_GET_SUBENTITY(index->part_index, old_compart->subparts[part_loc.subpart_no]) : old_compart;
if (status != OG_SUCCESS) {
break;
}
if (db_switch_shadow_idx_partitions(session, cursor, index) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
status = btree_part_segment_prepare(session, old_part, OG_FALSE, BTREE_DROP_PART_SEGMENT);
break;
}
if (status != OG_SUCCESS) {
if (def->rebuild.is_online) {
knl_rollback(session, NULL);
dc_invalidate_shadow_index(dc->handle);
(void)db_delete_remain_shadow_indexpart(session, cursor, dc, index, shadow_part);
}
}
CM_RESTORE_STACK(session->stack);
return status;
}
static void db_init_new_part_desc(index_part_t *new_part, index_part_t *old_part, uint32 spc_id)
{
errno_t err = memset_sp(new_part, sizeof(index_part_t), 0, sizeof(index_part_t));
knl_securec_check(err);
err = memcpy_sp(&new_part->desc, sizeof(knl_index_part_desc_t), &old_part->desc, sizeof(knl_index_part_desc_t));
knl_securec_check(err);
if (spc_id != OG_INVALID_ID32) {
new_part->desc.space_id = spc_id;
new_part->desc.is_stored = OG_TRUE;
}
new_part->desc.is_invalid = OG_FALSE;
}
status_t db_allow_indexpart_rebuild(knl_session_t *session, uint32 spc_id,
index_part_t *old_part)
{
space_t *space = SPACE_GET(session, spc_id);
space_t *old_space = SPACE_GET(session, old_part->desc.space_id);
if (!part_check_index_encrypt_allowed(session, old_part->desc.space_id, space)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "rebuild part index", "cases: rebuild encrypt part index on \
non-encrypt part table or rebuild non-encrypt part index on encrypt part table.");
return OG_ERROR;
}
if (SPACE_IS_LOGGING(space) != SPACE_IS_LOGGING(old_space) ||
SPACE_IS_NOLOGGING(space) != SPACE_IS_NOLOGGING(old_space)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify part index properties",
"part index rebuild in different type space");
return OG_ERROR;
}
if ((IS_SWAP_SPACE(space) && !IS_SWAP_SPACE(old_space)) ||
(!IS_SWAP_SPACE(space) && IS_SWAP_SPACE(old_space))) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify part index properties",
"part index rebuild in different type space");
return OG_ERROR;
}
if (IS_UNDO_SPACE(space)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify part index properties", "part index rebuild in undo space");
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_alter_indexpart_rebuild_verify(knl_session_t *session, knl_alindex_def_t *def, uint32 *spc_id,
index_t *index, int32 index_i)
{
index_part_t *old_part = NULL;
rebuild_index_def_t *rebuild = &def->rebuild;
if (!db_get_index_part(def, index, &old_part, index_i)) {
return OG_ERROR;
}
if (IS_AUTO_REBUILD(def->rebuild.lock_timeout) && (old_part->desc.org_scn != def->rebuild.org_scn)) {
OG_THROW_ERROR(ERR_INDEX_NOT_EXIST, T2S(&def->user), T2S_EX(&def->name));
OG_LOG_RUN_INF("index_name %s, org_scn %llu does not exist", old_part->desc.name, def->rebuild.org_scn);
return OG_ERROR;
}
if (CM_IS_EMPTY(&rebuild->space)) {
*spc_id = old_part->desc.space_id;
} else {
if (spc_get_space_id(session, &rebuild->space, def->is_for_create_db, spc_id) != OG_SUCCESS) {
return OG_ERROR;
}
if (spc_check_by_uid(session, &rebuild->space, *spc_id, old_part->desc.uid) != OG_SUCCESS) {
return OG_ERROR;
}
}
return db_allow_indexpart_rebuild(session, *spc_id, old_part);
}
status_t db_alter_index_rebuild_part(knl_session_t *session, knl_alindex_def_t *def, knl_dictionary_t *dc,
index_t *index)
{
uint32 spc_id;
index_part_t new_part;
knl_part_locate_t part_loc;
index_part_t *old_part = NULL;
if (db_alter_indexpart_rebuild_verify(session, def, &spc_id, index, 0) != OG_SUCCESS) {
return OG_ERROR;
}
if (!db_rebuild_get_part(def, index, &old_part, 0)) {
return OG_ERROR;
}
if (CM_IS_EMPTY(&def->rebuild.space)) {
spc_id = OG_INVALID_ID32;
}
if (!IS_PARENT_IDXPART(&old_part->desc)) {
if (IS_SUB_IDXPART(&old_part->desc)) {
index_part_t *compart = subpart_get_parent_idx_part(index, old_part->desc.parent_partid);
knl_panic_log(compart != NULL, "the index_compart is NULL, panic info: index name %s parent part name %s",
index->desc.name, old_part->desc.name);
part_loc.part_no = compart->part_no;
part_loc.subpart_no = old_part->part_no;
} else {
part_loc.part_no = old_part->part_no;
part_loc.subpart_no = OG_INVALID_ID32;
}
db_init_new_part_desc(&new_part, old_part, spc_id);
return db_rebuild_index_part_entity(session, dc, index, &new_part, part_loc, def);
} else {
part_loc.part_no = old_part->part_no;
index_part_t *subpart = NULL;
for (uint32 i = 0; i < old_part->desc.subpart_cnt; i++) {
part_loc.subpart_no = i;
subpart = PART_GET_SUBENTITY(index->part_index, old_part->subparts[i]);
if (subpart == NULL) {
continue;
}
db_init_new_part_desc(&new_part, subpart, spc_id);
if (db_rebuild_index_part_entity(session, dc, index, &new_part, part_loc,
def) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (spc_id != OG_INVALID_ID32) {
old_part->desc.is_stored = OG_TRUE;
return db_update_index_part_space(session, &old_part->desc, spc_id);
}
}
return OG_SUCCESS;
}
static status_t db_alter_compart_index_coalesce(knl_session_t *session, knl_handle_t entity, index_t *index,
index_part_t *compart, knl_part_locate_t *part_loc)
{
idx_recycle_stats_t stats;
index_part_t *subpart = NULL;
for (uint32 i = 0; i < compart->desc.subpart_cnt; i++) {
part_loc->subpart_no = i;
subpart = PART_GET_SUBENTITY(index->part_index, compart->subparts[i]);
if (subpart == NULL) {
continue;
}
if (subpart->btree.segment == NULL && !IS_INVALID_PAGID(subpart->btree.entry)) {
if (dc_load_index_part_segment(session, entity, (index_part_t *)subpart) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (subpart->btree.segment == NULL) {
return OG_SUCCESS;
}
if (btree_coalesce(session, &subpart->btree, &stats, *part_loc, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_alter_part_index_coalesce(knl_session_t *session, knl_dictionary_t *dc, knl_alindex_def_t *def,
index_t *index)
{
index_part_t *index_part = NULL;
index_part_t *index_subpart = NULL;
idx_recycle_stats_t stats;
table_t *table = DC_TABLE(dc);
if (!IS_PART_TABLE(table) || !IS_PART_INDEX(index)) {
OG_THROW_ERROR(ERR_MODIFY_PART_INDEX);
return OG_ERROR;
}
if (!part_idx_find_by_name(index->part_index, &def->mod_idxpart.part_name, &index_part)) {
if (!subpart_idx_find_by_name(index->part_index, &def->mod_idxpart.part_name, &index_subpart)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S(&def->mod_idxpart.part_name));
return OG_ERROR;
}
index_part = index_subpart;
}
if (IS_SUB_IDXPART(&index_part->desc)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S_EX(&def->mod_idxpart.part_name));
return OG_ERROR;
}
knl_part_locate_t part_loc;
part_loc.part_no = index_part->part_no;
if (!IS_PARENT_IDXPART(&index_part->desc)) {
knl_panic_log(!IS_PARENT_IDXPART(&index_part->desc),
"the index_part is parent_idxpart, panic info: table %s index %s", table->desc.name, index->desc.name);
part_loc.subpart_no = OG_INVALID_ID32;
if (index_part->btree.segment == NULL && !IS_INVALID_PAGID(index_part->btree.entry)) {
if (dc_load_index_part_segment(session, dc->handle, index_part) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (index_part->btree.segment == NULL) {
return OG_SUCCESS;
}
return btree_coalesce(session, &index_part->btree, &stats, part_loc, OG_FALSE);
}
return db_alter_compart_index_coalesce(session, dc->handle, index, index_part, &part_loc);
}
status_t db_alter_subpart_index_coalesce(knl_session_t *session, knl_dictionary_t *dc, knl_alindex_def_t *def,
index_t *index)
{
index_part_t *index_part = NULL;
index_part_t *index_subpart = NULL;
idx_recycle_stats_t stats;
table_t *table = DC_TABLE(dc);
if (!IS_PART_TABLE(table) || !IS_COMPART_TABLE(table->part_table) || !IS_PART_INDEX(index)) {
OG_THROW_ERROR(ERR_MODIFY_PART_INDEX);
return OG_ERROR;
}
if (!part_idx_find_by_name(index->part_index, &def->mod_idxpart.part_name, &index_part)) {
if (!subpart_idx_find_by_name(index->part_index, &def->mod_idxpart.part_name, &index_subpart)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S(&def->mod_idxpart.part_name));
return OG_ERROR;
}
index_part = index_subpart;
}
if (!IS_SUB_IDXPART(&index_part->desc)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S_EX(&def->mod_idxpart.part_name));
return OG_ERROR;
}
knl_part_locate_t part_loc;
index_part_t *index_compart = subpart_get_parent_idx_part(index, index_part->desc.parent_partid);
knl_panic_log(index_compart != NULL, "index_compart is NULL, panic info: table %s index %s", table->desc.name,
index->desc.name);
part_loc.part_no = index_compart->part_no;
part_loc.subpart_no = index_part->part_no;
if (index_part->btree.segment == NULL && !IS_INVALID_PAGID(index_part->btree.entry)) {
if (dc_load_index_part_segment(session, dc->handle, index_part) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (index_part->btree.segment == NULL) {
return OG_SUCCESS;
}
return btree_coalesce(session, &index_part->btree, &stats, part_loc, OG_FALSE);
}
status_t db_alter_index_coalesce(knl_session_t *session, knl_dictionary_t *dc, index_t *index)
{
idx_recycle_stats_t stats;
if (IS_PART_INDEX(index)) {
OG_THROW_ERROR(ERR_PART_INDEX_COALESCE);
return OG_ERROR;
}
if (index->btree.segment == NULL) {
return OG_SUCCESS;
}
knl_part_locate_t part_loc;
part_loc.part_no = OG_INVALID_ID32;
part_loc.subpart_no = OG_INVALID_ID32;
return btree_coalesce(session, &index->btree, &stats, part_loc, OG_FALSE);
}
status_t heap_segment_prepare(knl_session_t *session, table_t *table, bool32 reuse, seg_op_t op_type)
{
knl_seg_desc_t seg;
space_t *space = SPACE_GET(session, table->desc.space_id);
if (!SPACE_IS_ONLINE(space) || !space->ctrl->used) {
return OG_SUCCESS;
}
if (IS_INVALID_PAGID(table->heap.entry)) {
return OG_SUCCESS;
}
seg.uid = table->desc.uid;
seg.oid = table->desc.id;
seg.index_id = OG_INVALID_ID32;
seg.column_id = OG_INVALID_ID32;
seg.space_id = table->desc.space_id;
seg.entry = table->heap.entry;
seg.org_scn = table->desc.org_scn;
seg.seg_scn = table->desc.seg_scn;
seg.initrans = table->desc.initrans;
seg.pctfree = table->desc.pctfree;
seg.op_type = op_type;
seg.reuse = reuse;
seg.serial = table->desc.serial_start;
if (db_write_garbage_segment(session, &seg) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t heap_part_segment_prepare(knl_session_t *session, table_part_t *table_part, bool32 reuse,
seg_op_t op_type)
{
knl_seg_desc_t seg;
space_t *space = SPACE_GET(session, table_part->desc.space_id);
if (!SPACE_IS_ONLINE(space) || !space->ctrl->used) {
return OG_SUCCESS;
}
if (IS_INVALID_PAGID(table_part->heap.entry)) {
return OG_SUCCESS;
}
seg.uid = table_part->desc.uid;
seg.oid = table_part->desc.table_id;
seg.index_id = OG_INVALID_ID32;
seg.column_id = OG_INVALID_ID32;
seg.space_id = table_part->desc.space_id;
seg.entry = table_part->heap.entry;
seg.org_scn = table_part->desc.org_scn;
seg.seg_scn = table_part->desc.seg_scn;
seg.initrans = table_part->desc.initrans;
seg.pctfree = table_part->desc.pctfree;
seg.op_type = op_type;
seg.reuse = reuse;
seg.serial = OG_INVALID_ID64;
if (db_write_garbage_segment(session, &seg) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t btree_segment_prepare(knl_session_t *session, index_t *index, bool32 reuse, seg_op_t op_type)
{
knl_seg_desc_t seg;
space_t *space = SPACE_GET(session, index->desc.space_id);
if (!SPACE_IS_ONLINE(space) || !space->ctrl->used) {
return OG_SUCCESS;
}
if (IS_INVALID_PAGID(index->btree.entry)) {
return OG_SUCCESS;
}
seg.uid = index->desc.uid;
seg.oid = index->desc.table_id;
seg.index_id = index->desc.id;
seg.column_id = OG_INVALID_ID32;
seg.space_id = index->desc.space_id;
seg.entry = index->btree.entry;
seg.org_scn = index->desc.org_scn;
seg.seg_scn = index->desc.seg_scn;
seg.initrans = index->desc.initrans;
seg.pctfree = OG_INVALID_ID32;
seg.op_type = op_type;
seg.reuse = reuse;
seg.serial = OG_INVALID_ID64;
if (db_write_garbage_segment(session, &seg) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t btree_part_segment_prepare(knl_session_t *session, index_part_t *index_part, bool32 reuse,
seg_op_t op_type)
{
knl_seg_desc_t seg;
space_t *space = SPACE_GET(session, index_part->desc.space_id);
if (!SPACE_IS_ONLINE(space) || !space->ctrl->used) {
return OG_SUCCESS;
}
if (IS_INVALID_PAGID(index_part->btree.entry)) {
return OG_SUCCESS;
}
seg.uid = index_part->desc.uid;
seg.oid = index_part->desc.table_id;
seg.index_id = index_part->desc.index_id;
seg.column_id = OG_INVALID_ID32;
seg.space_id = index_part->desc.space_id;
seg.entry = index_part->btree.entry;
seg.org_scn = index_part->desc.org_scn;
seg.seg_scn = index_part->desc.seg_scn;
seg.initrans = index_part->desc.initrans;
seg.pctfree = OG_INVALID_ID32;
seg.op_type = op_type;
seg.reuse = reuse;
seg.serial = OG_INVALID_ID64;
if (db_write_garbage_segment(session, &seg) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t lob_segment_prepare(knl_session_t *session, lob_t *lob, bool32 reuse, seg_op_t op_type)
{
knl_seg_desc_t seg;
space_t *space = SPACE_GET(session, lob->desc.space_id);
if (!SPACE_IS_ONLINE(space) || !space->ctrl->used) {
return OG_SUCCESS;
}
if (IS_INVALID_PAGID(lob->lob_entity.entry)) {
return OG_SUCCESS;
}
seg.uid = lob->desc.uid;
seg.oid = lob->desc.table_id;
seg.index_id = OG_INVALID_ID32;
seg.column_id = lob->desc.column_id;
seg.space_id = lob->desc.space_id;
seg.entry = lob->lob_entity.entry;
seg.org_scn = lob->desc.org_scn;
seg.seg_scn = lob->desc.seg_scn;
seg.initrans = OG_INVALID_ID32;
seg.pctfree = OG_INVALID_ID32;
seg.op_type = op_type;
seg.reuse = reuse;
seg.serial = OG_INVALID_ID64;
if (db_write_garbage_segment(session, &seg) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t lob_part_segment_prepare(knl_session_t *session, lob_part_t *lob_part, bool32 reuse, seg_op_t op_type)
{
knl_seg_desc_t seg;
space_t *space = SPACE_GET(session, lob_part->desc.space_id);
if (!SPACE_IS_ONLINE(space) || !space->ctrl->used) {
return OG_SUCCESS;
}
if (IS_INVALID_PAGID(lob_part->lob_entity.entry)) {
return OG_SUCCESS;
}
seg.uid = lob_part->desc.uid;
seg.oid = lob_part->desc.table_id;
seg.index_id = OG_INVALID_ID32;
seg.column_id = lob_part->desc.column_id;
seg.space_id = lob_part->desc.space_id;
seg.entry = lob_part->lob_entity.entry;
seg.org_scn = lob_part->desc.org_scn;
seg.seg_scn = lob_part->desc.seg_scn;
seg.initrans = OG_INVALID_ID32;
seg.pctfree = OG_INVALID_ID32;
seg.op_type = op_type;
seg.reuse = reuse;
seg.serial = OG_INVALID_ID64;
if (db_write_garbage_segment(session, &seg) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_update_table_increment_start(knl_session_t *session, knl_table_desc_t *desc, uint64 serial_start)
{
knl_cursor_t *cursor = NULL;
row_assist_t ra;
knl_scan_key_t *key = NULL;
uint16 size;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_TABLE_ID, IX_SYS_TABLE_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
key = &cursor->scan_range.l_key;
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_INTEGER, (void *)&desc->uid, sizeof(uint32),
IX_COL_SYS_TABLE_001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), key, OG_TYPE_STRING, (void *)desc->name, (uint16)strlen(desc->name),
IX_COL_SYS_TABLE_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
knl_panic_log(!cursor->eof, "data is not found, panic info: page %u-%u type %u table %s", cursor->rowid.file,
cursor->rowid.page, ((page_head_t *)cursor->page_buf)->type, ((table_t *)cursor->table)->desc.name);
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 2);
(void)row_put_int64(&ra, db_inc_scn(session));
(void)row_put_uint64(&ra, serial_start);
cursor->update_info.count = 2;
cursor->update_info.columns[0] = SYS_TABLE_COL_CHG_SCN;
cursor->update_info.columns[1] = SYS_TABLE_SERIAL_START;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_update_systrig_set_status(knl_session_t *session, knl_dictionary_t *dc, bool32 enable)
{
dc_entity_t *entity = (dc_entity_t *)dc->handle;
row_assist_t ra;
knl_update_info_t *ui = NULL;
knl_cursor_t *cursor = NULL;
status_t status = OG_ERROR;
uint32 table_uid = entity->table.desc.uid;
uint64 table_oid = entity->table.desc.id;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, 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, &table_uid,
(uint16)sizeof(table_uid), IX_SYS_TRIGGERS_002_ID_OBJUID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &table_uid,
(uint16)sizeof(table_uid), IX_SYS_TRIGGERS_002_ID_OBJUID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_BIGINT, &table_oid,
(uint16)sizeof(table_oid), IX_SYS_TRIGGERS_002_ID_BASEOBJ);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_BIGINT, &table_oid,
(uint16)sizeof(table_oid), 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);
for (;;) {
OG_BREAK_IF_ERROR(knl_fetch(session, cursor));
if (cursor->eof) {
status = OG_SUCCESS;
break;
}
ui = &cursor->update_info;
row_init(&ra, ui->data, OG_MAX_ROW_SIZE, 1);
(void)row_put_int32(&ra, enable);
ui->count = 1;
ui->columns[0] = SYS_TRIGGER_COL_ENABLE;
cm_decode_row(ui->data, ui->offsets, ui->lens, NULL);
OG_BREAK_IF_ERROR(knl_internal_update(session, cursor));
status = OG_SUCCESS;
}
CM_RESTORE_STACK(session->stack);
return status;
}
static status_t db_update_sysproc_set_trig(knl_session_t *session, knl_dictionary_t *dc, bool32 enable)
{
dc_entity_t *entity = (dc_entity_t *)dc->handle;
row_assist_t ra;
knl_update_info_t *ui = NULL;
knl_cursor_t *cursor = NULL;
status_t status = OG_ERROR;
text_t user;
if (knl_get_user_name(session, entity->table.desc.uid, &user) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_PROC_ID, IX_PROC_002_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, entity->table.desc.name,
(uint16)strlen(entity->table.desc.name), IX_COL_PROC_002_TRIG_TABLE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, user.str, (uint16)user.len,
IX_COL_PROC_002_TRIG_TABLE_USER);
for (;;) {
OG_BREAK_IF_ERROR(knl_fetch(session, cursor));
if (cursor->eof) {
status = OG_SUCCESS;
break;
}
ui = &cursor->update_info;
row_init(&ra, ui->data, OG_MAX_ROW_SIZE, 1);
if (enable) {
(void)row_put_str(&ra, "ENABLED");
} else {
(void)row_put_str(&ra, "DISABLED");
}
ui->count = 1;
ui->columns[0] = SYS_PROC_TRIG_STATUS_COL;
cm_decode_row(ui->data, ui->offsets, ui->lens, NULL);
OG_BREAK_IF_ERROR(knl_internal_update(session, cursor));
}
CM_RESTORE_STACK(session->stack);
return status;
}
status_t db_altable_set_all_trig_status(knl_session_t *session, knl_dictionary_t *dc, bool32 enable)
{
if (db_update_systrig_set_status(session, dc, enable) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_sysproc_set_trig(session, dc, enable) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_write_instance_info(knl_session_t *session, knl_cursor_t *cursor)
{
table_t *table = NULL;
row_assist_t ra;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_INSTANCE_INFO_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
char name[] = "NOLOGOBJECT_CNT";
row_init(&ra, (char *)cursor->row, HEAP_MAX_ROW_SIZE(session), table->desc.column_count);
(void)row_put_str(&ra, name);
(void)row_put_int64(&ra, 1);
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_update_nologobj_cnt(knl_session_t *session, bool32 is_add)
{
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_INSTANCE_INFO_ID, IX_SYS_INSTANCE_INFO_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
char name[] = "NOLOGOBJECT_CNT";
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, name, (uint16)strlen(name),
IX_COL_SYS_INSTANCE_INFO_001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
if (db_write_instance_info(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
row_assist_t ra;
uint64 nolog_cnt = *(uint64 *)CURSOR_COLUMN_DATA(cursor, SYS_INSTANCE_INFO_COL_VALUE);
if (is_add) {
nolog_cnt++;
} else {
nolog_cnt--;
}
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), UPDATE_COLUMN_COUNT_ONE);
(void)row_put_int64(&ra, (int64)nolog_cnt);
cursor->update_info.count = UPDATE_COLUMN_COUNT_ONE;
cursor->update_info.columns[0] = SYS_INSTANCE_INFO_COL_VALUE;
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_enable_nologging_precheck(knl_session_t *session, knl_dictionary_t *dc)
{
if (!DB_IS_SINGLE(session)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "set nologging attribute when database in HA mode");
return OG_ERROR;
}
if (dc->type == DICT_TYPE_TEMP_TABLE_TRANS || dc->type == DICT_TYPE_TEMP_TABLE_SESSION) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "set nologging attribute to temporaty table");
return OG_ERROR;
}
if (dc->type == DICT_TYPE_TABLE_NOLOGGING) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", nologging table already has the nologging attribute");
return OG_ERROR;
}
if (LOGIC_REP_DB_ENABLED(session)) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "set nologging attribute when logic replay is enabled");
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_altable_enable_nologging(knl_session_t *session, knl_dictionary_t *dc)
{
if (db_enable_nologging_precheck(session, dc) != OG_SUCCESS) {
return OG_ERROR;
}
table_t *table = DC_TABLE(dc);
bool32 is_null = OG_FALSE;
if (db_table_judge_null(session, dc, &is_null) != OG_SUCCESS) {
return OG_ERROR;
}
if (!is_null) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "set nologging attribute when the table is not empty");
return OG_ERROR;
}
knl_table_desc_t *desc = &table->desc;
if (table->desc.is_nologging) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", the table already has the nologging attribute");
return OG_ERROR;
}
if (db_update_table_flag(session, desc->uid, desc->id, TABLE_FLAG_TYPE_ENABLE_NOLOGGING) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_nologobj_cnt(session, OG_TRUE) != OG_SUCCESS) {
return OG_ERROR;
}
dc_user_t *user = session->kernel->dc_ctx.users[table->desc.uid];
OG_LOG_RUN_INF("[NOLOGGING INSERT] table %s.%s is set nologging", user->desc.name, table->desc.name);
return OG_SUCCESS;
}
status_t db_altable_disable_nologging(knl_session_t *session, knl_dictionary_t *dc)
{
if (dc->type == DICT_TYPE_TEMP_TABLE_TRANS || dc->type == DICT_TYPE_TEMP_TABLE_SESSION) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "unset nologging attribute to temporaty table");
return OG_ERROR;
}
if (dc->type == DICT_TYPE_TABLE_NOLOGGING) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", cannot change the nologging attribute of nologging table");
return OG_ERROR;
}
table_t *table = DC_TABLE(dc);
knl_table_desc_t *desc = &table->desc;
if (!desc->is_nologging) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", the table does not have the nologging attribute");
return OG_ERROR;
}
if (db_update_table_flag(session, desc->uid, desc->id, TABLE_FLAG_TYPE_DISABLE_NOLOGGING) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_nologobj_cnt(session, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
dc_user_t *user = session->kernel->dc_ctx.users[table->desc.uid];
OG_LOG_RUN_INF("[NOLOGGING INSERT] table %s.%s disable nologging", user->desc.name, table->desc.name);
return OG_SUCCESS;
}
static status_t db_enable_part_nologging_precheck(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def,
table_part_t **table_part)
{
if (db_enable_nologging_precheck(session, dc) != OG_SUCCESS) {
return OG_ERROR;
}
table_t *table = DC_TABLE(dc);
if (!IS_PART_TABLE(table)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, " %s not partition table", T2S(&def->name));
return OG_ERROR;
}
table_part_t *part = NULL;
if (!part_table_find_by_name(table->part_table, &def->part_def.name, &part)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "table", T2S(&def->part_def.name));
return OG_ERROR;
}
bool32 is_null = OG_FALSE;
knl_part_locate_t part_loc;
part_loc.part_no = part->part_no;
part_loc.subpart_no = OG_INVALID_ID32;
if (db_part_judge_null(session, dc, part_loc, &is_null) != OG_SUCCESS) {
return OG_ERROR;
}
if (!is_null) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "set nologging attribute when the table part is not empty");
return OG_ERROR;
}
if (part->desc.is_nologging) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", the table partition already has the nologging attribute");
return OG_ERROR;
}
*table_part = part;
return OG_SUCCESS;
}
status_t db_altable_enable_part_nologging(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
table_t *table = DC_TABLE(dc);
table_part_t *table_part = NULL;
if (db_enable_part_nologging_precheck(session, dc, def, &table_part) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_part_flag(session, dc, table->part_table, table_part->desc.part_id,
PART_FLAG_TYPE_ENABLE_NOLOGGING) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_nologobj_cnt(session, OG_TRUE) != OG_SUCCESS) {
return OG_ERROR;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
return OG_SUCCESS;
}
table_part_t *subpart = NULL;
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
subpart = PART_GET_SUBENTITY(table->part_table, table_part->subparts[j]);
if (subpart == NULL || subpart->desc.is_nologging) {
continue;
}
if (db_update_subpart_flag(session, dc, table_part, subpart->desc.part_id,
PART_FLAG_TYPE_ENABLE_NOLOGGING) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_nologobj_cnt(session, OG_TRUE) != OG_SUCCESS) {
return OG_ERROR;
}
}
dc_user_t *user = session->kernel->dc_ctx.users[table->desc.uid];
OG_LOG_RUN_INF("[NOLOGGING INSERT] table part %s.%s.%s enable nologging", user->desc.name, table->desc.name,
table_part->desc.name);
return OG_SUCCESS;
}
status_t db_altable_disable_part_nologging(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
if (dc->type == DICT_TYPE_TABLE_NOLOGGING) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", cannot change the nologging attribute of nologging table");
return OG_ERROR;
}
table_t *table = DC_TABLE(dc);
if (!IS_PART_TABLE(table)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, " %s not partition table", T2S(&def->name));
return OG_ERROR;
}
table_part_t *table_part = NULL;
if (!part_table_find_by_name(table->part_table, &def->part_def.name, &table_part)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "table", T2S(&def->part_def.name));
return OG_ERROR;
}
if (!table_part->desc.is_nologging) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", the table part does not have the nologging attribute");
return OG_ERROR;
}
if (db_update_part_flag(session, dc, table->part_table, table_part->desc.part_id,
PART_FLAG_TYPE_DISABLE_NOLOGGING) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_nologobj_cnt(session, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
return OG_SUCCESS;
}
table_part_t *subpart = NULL;
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
subpart = PART_GET_SUBENTITY(table->part_table, table_part->subparts[j]);
if (subpart == NULL || !subpart->desc.is_nologging) {
continue;
}
if (db_update_subpart_flag(session, dc, table_part, subpart->desc.part_id,
PART_FLAG_TYPE_DISABLE_NOLOGGING) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_nologobj_cnt(session, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
}
dc_user_t *user = session->kernel->dc_ctx.users[table->desc.uid];
OG_LOG_RUN_INF("[NOLOGGING INSERT] table part %s.%s.%s disable nologging", user->desc.name, table->desc.name,
table_part->desc.name);
return OG_SUCCESS;
}
status_t db_altable_enable_subpart_nologging(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
if (db_enable_nologging_precheck(session, dc) != OG_SUCCESS) {
return OG_ERROR;
}
table_t *table = DC_TABLE(dc);
if (!IS_PART_TABLE(table)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, " %s not partition table", T2S(&def->name));
return OG_ERROR;
}
if (!IS_COMPART_TABLE(table->part_table)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, " %s not composite partition table", T2S(&def->name));
return OG_ERROR;
}
table_part_t *compart = NULL;
table_part_t *subpart = NULL;
if (!subpart_table_find_by_name(table->part_table, &def->part_def.name, &compart, &subpart)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "table", T2S(&def->part_def.name));
return OG_ERROR;
}
bool32 is_null = OG_FALSE;
knl_part_locate_t part_loc;
part_loc.part_no = compart->part_no;
part_loc.subpart_no = subpart->part_no;
if (db_subpart_judge_null(session, dc, part_loc, &is_null) != OG_SUCCESS) {
return OG_ERROR;
}
if (!is_null) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_ALLOW, "set nologging attribute when the table part is not empty");
return OG_ERROR;
}
if (subpart->desc.is_nologging) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", the table subpartition already has the nologging attribute");
return OG_ERROR;
}
if (db_update_subpart_flag(session, dc, compart, subpart->desc.part_id,
PART_FLAG_TYPE_ENABLE_NOLOGGING) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_nologobj_cnt(session, OG_TRUE) != OG_SUCCESS) {
return OG_ERROR;
}
dc_user_t *user = session->kernel->dc_ctx.users[table->desc.uid];
OG_LOG_RUN_INF("[NOLOGGING INSERT] table part %s.%s.%s enable nologging", user->desc.name, table->desc.name,
subpart->desc.name);
return OG_SUCCESS;
}
status_t db_altable_disable_subpart_nologging(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
if (dc->type == DICT_TYPE_TABLE_NOLOGGING) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", cannot change the nologging attribute of nologging table");
return OG_ERROR;
}
table_t *table = DC_TABLE(dc);
part_table_t *part_table = table->part_table;
if (!IS_PART_TABLE(table)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, " %s not partition table", T2S(&def->name));
return OG_ERROR;
}
if (!IS_COMPART_TABLE(part_table)) {
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, " %s not composite partition table", T2S(&def->name));
return OG_ERROR;
}
table_part_t *compart = NULL;
table_part_t *subpart = NULL;
if (!subpart_table_find_by_name(part_table, &def->part_def.name, &compart, &subpart)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "table", T2S(&def->part_def.name));
return OG_ERROR;
}
if (!subpart->desc.is_nologging) {
OG_THROW_ERROR(ERR_INVALID_OPERATION, ", the table part does not have the nologging attribute");
return OG_ERROR;
}
if (db_update_subpart_flag(session, dc, compart, subpart->desc.part_id,
PART_FLAG_TYPE_DISABLE_NOLOGGING) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_nologobj_cnt(session, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
dc_user_t *user = session->kernel->dc_ctx.users[table->desc.uid];
OG_LOG_RUN_INF("[NOLOGGING INSERT] table part %s.%s.%s disable nologging", user->desc.name, table->desc.name,
subpart->desc.name);
return OG_SUCCESS;
}
static status_t db_alter_tmptable_auto_increment(knl_session_t *session, knl_dictionary_t *dc, uint64 serial_start)
{
dc_entity_t *entity = DC_ENTITY(dc);
dc_entry_t *entry = entity->entry;
knl_temp_cache_t *temp_table = NULL;
if (knl_ensure_temp_cache(session, entity, &temp_table) != OG_SUCCESS) {
return OG_ERROR;
}
if (serial_start <= temp_table->serial) {
return OG_SUCCESS;
}
if (temp_table->serial == 0) {
temp_table->serial++;
}
dls_spin_lock(session, &entry->serial_lock, NULL);
if (db_update_table_increment_start(session, &entity->table.desc, serial_start) != OG_SUCCESS) {
dls_spin_unlock(session, &entry->serial_lock);
return OG_ERROR;
}
entity->table.desc.serial_start = serial_start;
temp_table->serial = serial_start;
dls_spin_unlock(session, &entry->serial_lock);
return OG_SUCCESS;
}
status_t db_altable_auto_increment(knl_session_t *session, knl_dictionary_t *dc, uint64 serial_start)
{
dc_entity_t *entity = DC_ENTITY(dc);
dc_entry_t *entry = entity->entry;
if (entity->type == DICT_TYPE_TEMP_TABLE_SESSION || entity->type == DICT_TYPE_TEMP_TABLE_TRANS) {
return db_alter_tmptable_auto_increment(session, dc, serial_start);
}
dls_spin_lock(session, &entry->serial_lock, NULL);
if (serial_start <= entry->serial_value) {
dls_spin_unlock(session, &entry->serial_lock);
return OG_SUCCESS;
}
if (db_update_table_increment_start(session, &entity->table.desc, serial_start) != OG_SUCCESS) {
dls_spin_unlock(session, &entry->serial_lock);
return OG_ERROR;
}
if (!IS_INVALID_PAGID(entity->table.heap.entry) && serial_start > entity->table.heap.segment->serial) {
heap_update_serial(session, &entity->table.heap, serial_start);
}
entity->table.desc.serial_start = serial_start;
dls_spin_unlock(session, &entry->serial_lock);
return OG_SUCCESS;
}
static status_t db_validate_old_data(knl_session_t *session, knl_dictionary_t *dc, knl_dictionary_t *ref_dc,
knl_cursor_t *cursor, uint32 type)
{
text_t cond;
uint32 i;
dc_entity_t *entity = DC_ENTITY(dc);
ref_cons_t *ref_cons = NULL;
if (type == CONS_TYPE_CHECK) {
cond.len = CURSOR_COLUMN_SIZE(cursor, CONSDEF_COL_COND_TEXT);
cond.str = CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_COND_TEXT);
if (db_verify_check_data(session, dc, &cond) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
for (i = 0; i < entity->table.cons_set.ref_count; i++) {
ref_cons = entity->table.cons_set.ref_cons[i];
if (ref_cons->ref_uid == ref_dc->uid && ref_cons->ref_oid == ref_dc->oid) {
break;
}
}
if (i == entity->table.cons_set.ref_count) {
OG_LOG_RUN_ERR("[TABLE] failed to validate old cons");
return OG_ERROR;
}
if (OG_SUCCESS != db_verify_reference_data(session, dc, ref_dc, ref_cons)) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_altable_apply_constraint(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
bool32 exist = OG_TRUE;
knl_dictionary_t ref_dc;
uint32 type;
uint32 ref_uid;
uint32 ref_tid;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
knl_update_info_t *ua = NULL;
knl_constraint_def_t *cons = &def->cons_def.new_cons;
knl_constraint_state_t cons_state;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
if (db_fetch_sysconsdef_by_table(session, cursor, CURSOR_ACTION_UPDATE, dc->uid, dc->oid,
&cons->name, &exist) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!exist) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_CONS_NOT_EXIST, T2S(&cons->name));
return OG_ERROR;
}
type = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_TYPE);
if (type == CONS_TYPE_PRIMARY || type == CONS_TYPE_UNIQUE) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR_EX(ERR_SQL_SYNTAX_ERROR, "Cannot apply constaint state to primary/uniuqe constraint now.");
return OG_ERROR;
}
ref_dc.handle = NULL;
if (type == CONS_TYPE_REFERENCE) {
ref_uid = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_REF_USER);
ref_tid = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_REF_TABLE);
if (knl_open_dc_by_id(session, ref_uid, ref_tid, &ref_dc, OG_TRUE) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
uint32 timeout = session->kernel->attr.ddl_lock_timeout;
if (lock_table_directly(session, &ref_dc, timeout) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
dc_close(&ref_dc);
return OG_ERROR;
}
}
if (cons->cons_state.is_validate) {
if (OG_SUCCESS != db_validate_old_data(session, dc, &ref_dc, cursor, type)) {
if (ref_dc.handle != NULL) {
dc_close(&ref_dc);
}
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (ref_dc.handle != NULL) {
dc_close(&ref_dc);
}
cons_state.option = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_FLAGS);
cons_state.is_enable = cons->cons_state.is_enable;
cons_state.is_validate = cons->cons_state.is_validate;
cons_state.is_cascade = cons->cons_state.is_cascade;
ua = &cursor->update_info;
row_init(&ra, ua->data, HEAP_MAX_ROW_SIZE(session), 1);
if (OG_SUCCESS != row_put_int32(&ra, cons_state.option)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
ua->count = 1;
ua->columns[0] = CONSDEF_COL_FLAGS;
cm_decode_row(ua->data, ua->offsets, ua->lens, NULL);
if (OG_SUCCESS != knl_internal_update(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_altable_rename_constraint(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
knl_constraint_def_t *new_cons = &def->cons_def.new_cons;
knl_alt_cstr_prop_t *old_cons_def = &def->cons_def;
knl_constraint_state_t cons_state;
row_assist_t ra;
bool32 exist = OG_TRUE;
char new_name[OG_NAME_BUFFER_SIZE];
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
if (db_fetch_sysconsdef_by_name(session, cursor, CURSOR_ACTION_SELECT, dc->uid, dc->oid,
&new_cons->name, &exist) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (exist) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "constraint", T2S(&new_cons->name));
return OG_ERROR;
}
if (db_fetch_sysconsdef_by_table(session, cursor, CURSOR_ACTION_UPDATE, dc->uid, dc->oid,
&old_cons_def->name, &exist) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!exist) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_CONS_NOT_EXIST, T2S(&old_cons_def->name));
return OG_ERROR;
}
(void)cm_text2str(&(new_cons->name), new_name, new_cons->name.len + 1);
new_name[new_cons->name.len] = '\0';
cons_state.option = *(uint32 *)CURSOR_COLUMN_DATA(cursor, CONSDEF_COL_FLAGS);
cons_state.is_anonymous = OG_FALSE;
knl_update_info_t *ua = &cursor->update_info;
row_init(&ra, ua->data, HEAP_MAX_ROW_SIZE(session), 2);
(void)row_put_str(&ra, new_name);
(void)row_put_uint32(&ra, cons_state.option);
ua->count = 2;
ua->columns[0] = CONSDEF_COL_NAME;
ua->columns[1] = CONSDEF_COL_FLAGS;
cm_decode_row(ua->data, ua->offsets, ua->lens, NULL);
if (OG_SUCCESS != knl_internal_update(session, cursor)) {
int32 err_code = cm_get_error_code();
if (err_code == ERR_DUPLICATE_KEY) {
cm_reset_error();
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "constraint", T2S(&new_cons->name));
}
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_get_pk_idx_id(knl_session_t *session, table_t *table,
knl_altable_def_t *def, uint32 *index_id)
{
knl_cursor_t *cursor = NULL;
status_t ret;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_CONSDEF_ID, IX_SYS_CONSDEF001_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &table->desc.uid,
sizeof(uint32), IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &table->desc.id,
sizeof(uint32), IX_COL_SYS_CONSDEF001_TABLE_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &table->desc.uid,
sizeof(uint32), IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &table->desc.id,
sizeof(uint32), IX_COL_SYS_CONSDEF001_TABLE_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
ret = OG_ERROR;
while (!cursor->eof) {
if (*(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_CONSDEF_COL_CONS_TYPE) == CONS_TYPE_PRIMARY) {
*index_id = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_CONSDEF_COL_IND_ID);
ret = OG_SUCCESS;
break;
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
break;
}
}
CM_RESTORE_STACK(session->stack);
return ret;
}
static status_t db_used_by_uni_cons(knl_session_t *session, uint32 uid, uint32 tid, uint32 idx_id, bool32 *used)
{
knl_cursor_t *cursor = NULL;
status_t ret;
*used = OG_FALSE;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_CONSDEF_ID, IX_SYS_CONSDEF001_ID);
knl_init_index_scan(cursor, OG_FALSE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &uid,
sizeof(uint32), IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &tid,
sizeof(uint32), IX_COL_SYS_CONSDEF001_TABLE_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &uid,
sizeof(uint32), IX_COL_SYS_CONSDEF001_USER_ID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_STRING, &tid,
sizeof(uint32), IX_COL_SYS_CONSDEF001_TABLE_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
ret = OG_ERROR;
while (!cursor->eof) {
if ((*(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_CONSDEF_COL_CONS_TYPE) == CONS_TYPE_UNIQUE) &&
(*(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_CONSDEF_COL_IND_ID) == idx_id)) {
*used = OG_TRUE;
ret = OG_SUCCESS;
break;
}
if (OG_SUCCESS != knl_fetch(session, cursor)) {
break;
}
}
CM_RESTORE_STACK(session->stack);
return ret;
}
static status_t db_get_unique_idx_id(knl_session_t *session, table_t *table,
knl_altable_def_t *def, uint32 *index_id)
{
knl_cursor_t *cursor = NULL;
uint32 idx_id;
bool32 used = OG_FALSE;
status_t ret;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_INDEX_ID, IX_SYS_INDEX_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, &table->desc.uid,
sizeof(uint32), IX_COL_SYS_INDEX_002_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, (void
*)def->logical_log_def.idx_name.str,
def->logical_log_def.idx_name.len, IX_COL_SYS_INDEX_002_NAME);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_INTEGER, &table->desc.uid,
sizeof(uint32), IX_COL_SYS_INDEX_002_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.r_key, OG_TYPE_STRING, (void
*)def->logical_log_def.idx_name.str,
def->logical_log_def.idx_name.len, IX_COL_SYS_INDEX_002_NAME);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
ret = OG_ERROR;
if (!cursor->eof) {
idx_id = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_INDEX_COLUMN_ID_ID);
if (*(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_INDEX_COLUMN_ID_IS_UNIQUE) != 0) {
*index_id = idx_id;
ret = OG_SUCCESS;
} else {
ret = db_used_by_uni_cons(session, table->desc.uid, table->desc.id, idx_id, &used);
if ((ret == OG_SUCCESS) && (used)) {
*index_id = idx_id;
} else if (!used) {
ret = OG_ERROR;
}
}
}
CM_RESTORE_STACK(session->stack);
return ret;
}
static status_t db_check_index_is_valid(knl_session_t *session, table_t *table,
knl_altable_def_t *def, uint32 *index_id)
{
knl_cursor_t *cursor = NULL;
uint32 flags;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_INDEX_ID, IX_SYS_INDEX_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &table->desc.uid,
sizeof(uint32), IX_COL_SYS_INDEX_001_USER);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, &table->desc.id,
sizeof(uint32), IX_COL_SYS_INDEX_001_TABLE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, index_id,
sizeof(uint32), IX_COL_SYS_INDEX_001_ID);
if (OG_SUCCESS != knl_fetch(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!cursor->eof) {
flags = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_INDEX_COLUMN_ID_FLAGS);
if (!KNL_INDEX_FLAG_IS_INVALID(flags)) {
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
}
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_INVALID_LOGICAL_INDEX);
return OG_ERROR;
}
static status_t db_get_table_index_id(knl_session_t *session, table_t *table,
knl_altable_def_t *def, uint32 *index_id)
{
status_t status;
if (def->logical_log_def.key_type == LOGICREP_KEY_TYPE_PRIMARY_KEY) {
status = db_get_pk_idx_id(session, table, def, index_id);
} else if (def->logical_log_def.key_type == LOGICREP_KEY_TYPE_UNIQUE) {
status = db_get_unique_idx_id(session, table, def, index_id);
} else {
OG_LOG_RUN_ERR("unsupported logical log type(%u)", def->logical_log_def.key_type);
return OG_ERROR;
}
if (status != OG_SUCCESS) {
return status;
}
return db_check_index_is_valid(session, table, def, index_id);
}
status_t db_logical_log_get_parts(knl_session_t *session, knl_altable_def_t *def, text_t *text)
{
uint32 i;
uint32 max_size;
errno_t err;
knl_part_def_t *part_def = NULL;
max_size = def->logical_log_def.parts.count * (OG_NAME_BUFFER_SIZE + 1);
text->str = (char *)cm_push(session->stack, max_size);
text->len = 0;
for (i = 0; i < def->logical_log_def.parts.count; i++) {
part_def = (knl_part_def_t *)cm_galist_get(&def->logical_log_def.parts, i);
if (i > 0) {
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, ",");
knl_securec_check_ss(err);
text->len += err;
}
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, "%s", T2S(&part_def->name));
knl_securec_check_ss(err);
text->len += err;
}
return OG_SUCCESS;
}
void db_logical_log_get_oldparts(dc_entity_t *entity, text_t *text)
{
table_part_t *table_part = NULL;
errno_t err;
for (uint32 i = 0; i < entity->table.part_table->desc.partcnt; i++) {
table_part = TABLE_GET_PART(&entity->table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
if (IS_PARENT_TABPART(&table_part->desc)) {
table_part_t *subpart = NULL;
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
subpart = PART_GET_SUBENTITY(entity->table.part_table, table_part->subparts[j]);
if (subpart == NULL) {
continue;
}
if (subpart->desc.lrep_status == PART_LOGICREP_STATUS_ON) {
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, ",");
knl_securec_check_ss(err);
text->len += err;
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, "%s",
subpart->desc.name);
knl_securec_check_ss(err);
text->len += err;
}
}
} else {
if (table_part->desc.lrep_status == PART_LOGICREP_STATUS_ON) {
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, ",");
knl_securec_check_ss(err);
text->len += err;
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, "%s", table_part->desc.name);
knl_securec_check_ss(err);
text->len += err;
}
}
}
}
status_t db_logical_log_compare_parts(knl_session_t *session, dc_entity_t *entity, knl_altable_def_t *def, text_t *text)
{
uint32 i;
errno_t err;
knl_part_def_t *part_def = NULL;
table_part_t *table_part = NULL;
uint32 part_no = OG_INVALID_ID32;
uint32 subpart_no = OG_INVALID_ID32;
text->len = 0;
for (i = 0; i < def->logical_log_def.parts.count; i++) {
part_def = (knl_part_def_t *)cm_galist_get(&def->logical_log_def.parts, i);
if (knl_find_table_part_by_name(entity, &part_def->name, &part_no) != OG_SUCCESS) {
cm_reset_error();
if (knl_find_subpart_by_name(entity, &part_def->name, &part_no, &subpart_no) != OG_SUCCESS) {
return OG_ERROR;
}
}
table_part = TABLE_GET_PART(&entity->table, part_no);
if (subpart_no != OG_INVALID_ID32) {
table_part = PART_GET_SUBENTITY(entity->table.part_table, table_part->subparts[subpart_no]);
}
if (table_part->desc.lrep_status == PART_LOGICREP_STATUS_ON) {
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "partition logical log", T2S(&part_def->name));
return OG_ERROR;
}
if (text->len > 0) {
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, ",");
knl_securec_check_ss(err);
text->len += err;
}
err = snprintf_s(text->str + text->len, OG_NAME_BUFFER_SIZE + 1, OG_NAME_BUFFER_SIZE, "%s", T2S(&part_def->name));
knl_securec_check_ss(err);
text->len += err;
}
db_logical_log_get_oldparts(entity, text);
return OG_SUCCESS;
}
status_t db_altable_add_logical_log_inner(knl_session_t *session, knl_cursor_t *cursor,
knl_dictionary_t *dc, knl_altable_def_t *def,
const uint32 index_id)
{
row_assist_t ra;
table_t *table = NULL;
uint32 uid;
uint32 tableid;
text_t text;
knl_column_t *lob_column = NULL;
table = DC_TABLE(dc);
uid = table->desc.uid;
tableid = table->desc.id;
if (def->logical_log_def.is_parts_logical == OG_TRUE) {
if (db_logical_log_get_parts(session, def, &text) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
text.len = 0;
}
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_LOGIC_REP_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, OG_MAX_ROW_SIZE, table->desc.column_count);
(void)row_put_int32(&ra, uid);
(void)row_put_int32(&ra, tableid);
if (text.len > 0) {
(void)row_put_int32(&ra, LOGICREP_STATUS_OFF);
} else {
(void)row_put_int32(&ra, LOGICREP_STATUS_ON);
}
(void)row_put_int32(&ra, index_id);
lob_column = knl_get_column(cursor->dc_entity, SYS_LOGIC_REP_COLUMN_ID_PARTITIONIDS);
if (knl_row_put_lob(session, cursor, lob_column, &text, &ra) != OG_SUCCESS) {
return OG_ERROR;
}
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
int32 code = cm_get_error_code();
if (code == ERR_DUPLICATE_KEY) {
table = DC_TABLE(dc);
cm_reset_error();
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "logical log", table->desc.name);
}
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_altable_add_logical_log(knl_session_t *session, knl_dictionary_t *dc,
knl_altable_def_t *def)
{
uint32 uid;
uint32 tableid;
uint32 index_id;
uint32 maxsize;
uint32 src_maxsize;
text_t text;
status_t status;
table_t *table = NULL;
knl_cursor_t *cursor = NULL;
dc_entity_t *entity = NULL;
table = DC_TABLE(dc);
uid = table->desc.uid;
tableid = table->desc.id;
entity = DC_ENTITY(dc);
if (table->desc.type != TABLE_TYPE_HEAP) {
OG_THROW_ERROR(ERR_TABLE_NOT_HEAP, table->desc.name);
return OG_ERROR;
}
if (db_get_table_index_id(session, table, def, &index_id) != OG_SUCCESS) {
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "primary key or unique index on table",
table->desc.name);
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
do {
if (entity->lrep_info.status == LOGICREP_STATUS_OFF && entity->lrep_info.parts_count == 0) {
status = db_altable_add_logical_log_inner(session, cursor, dc, def, index_id);
break;
}
if (entity->lrep_info.parts_count > 0 && def->logical_log_def.is_parts_logical == OG_TRUE) {
maxsize = def->logical_log_def.parts.count * (OG_NAME_BUFFER_SIZE + 1);
src_maxsize = entity->lrep_info.parts_count * (OG_NAME_BUFFER_SIZE + 1);
text.str = (char *)cm_push(session->stack, (src_maxsize + maxsize));
if (text.str == NULL) {
OG_THROW_ERROR(ERR_STACK_OVERFLOW);
status = OG_ERROR;
break;
}
status = db_logical_log_compare_parts(session, entity, def, &text);
OG_BREAK_IF_ERROR(status);
} else {
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "logical log", table->desc.name);
status = OG_ERROR;
break;
}
status = db_altable_update_logical_log(session, cursor, uid, tableid, &text);
} while (0);
CM_RESTORE_STACK(session->stack);
return status;
}
status_t db_altable_drop_logical_log(knl_session_t *session, knl_dictionary_t *dc, knl_altable_def_t *def)
{
table_t *table;
uint32 uid;
uint32 tableid;
status_t status;
knl_cursor_t *cursor = NULL;
table = DC_TABLE(dc);
tableid = table->desc.id;
uid = table->desc.uid;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
status = db_altable_drop_logical_log_inner(session, cursor, uid, tableid);
CM_RESTORE_STACK(session->stack);
return status;
}
static status_t db_shrink_lob_parts(knl_session_t *session, knl_dictionary_t *dc, knl_cursor_t *cursor,
knl_column_t *column)
{
table_part_t *table_part = NULL;
table_t *table = DC_TABLE(dc);
dc_entity_t *entity = DC_ENTITY(dc);
for (uint32 i = 0; i < table->part_table->desc.partcnt; i++) {
cursor->part_loc.part_no = i;
table_part = PART_GET_ENTITY(table->part_table, i);
if (!IS_READY_PART(table_part)) {
continue;
}
if (!IS_PARENT_TABPART(&table_part->desc)) {
cursor->part_loc.subpart_no = OG_INVALID_ID32;
if (!SCH_LOCKED_EXCLUSIVE(entity)) {
if (lock_upgrade_table_lock(session, entity, LOCK_INF_WAIT) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (lob_shrink_space(session, cursor, column) != OG_SUCCESS) {
return OG_ERROR;
}
continue;
}
for (uint32 j = 0; j < table_part->desc.subpart_cnt; j++) {
cursor->part_loc.subpart_no = j;
if (!SCH_LOCKED_EXCLUSIVE(entity)) {
if (lock_upgrade_table_lock(session, entity, LOCK_INF_WAIT) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (knl_reopen_cursor(session, cursor, dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (lob_shrink_space(session, cursor, column) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_shrink_lob(knl_session_t *session, knl_dictionary_t *dc, knl_column_t *column)
{
table_t *table = DC_TABLE(dc);
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
cursor->part_loc.part_no = 0;
cursor->part_loc.subpart_no = 0;
cursor->scan_mode = SCAN_MODE_TABLE_FULL;
cursor->action = CURSOR_ACTION_UPDATE;
if (knl_open_cursor(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
cursor->isolevel = ISOLATION_CURR_COMMITTED;
cursor->update_info.data = (char *)cm_push(session->stack, DEFAULT_PAGE_SIZE(session));
cursor->update_info.columns[0] = column->id;
cursor->update_info.count = 1;
if (IS_PART_TABLE(table)) {
if (db_shrink_lob_parts(session, dc, cursor, column) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
} else {
if (lob_shrink_space(session, cursor, column) != OG_SUCCESS) {
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
knl_close_cursor(session, cursor);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_altable_modify_lob(knl_session_t *session, knl_altable_def_t *def)
{
knl_dictionary_t dc;
knl_modify_lob_def_t *lob_def = &def->modify_lob_def;
knl_column_t *column = NULL;
if (dc_open(session, &def->user, &def->name, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
if (dc.type < DICT_TYPE_TABLE || dc.type > DICT_TYPE_TABLE_NOLOGGING) {
dc_close(&dc);
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "alter table", "view, external organized table or system table");
return OG_ERROR;
}
if (SYNONYM_EXIST(&dc)) {
dc_close(&dc);
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, T2S(&def->user), T2S_EX(&def->name));
return OG_ERROR;
}
if (lock_table_directly(session, &dc, LOCK_INF_WAIT) != OG_SUCCESS) {
dc_close(&dc);
return OG_ERROR;
}
column = knl_find_column(&lob_def->name, &dc);
if (column == NULL) {
unlock_tables_directly(session);
dc_close(&dc);
OG_THROW_ERROR(ERR_COLUMN_NOT_EXIST, T2S(&def->user), T2S_EX(&lob_def->name));
return OG_ERROR;
}
if (!COLUMN_IS_LOB(column)) {
unlock_tables_directly(session);
dc_close(&dc);
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "modify lob", "nonlob column");
return OG_ERROR;
}
dc_entity_t *entity = DC_ENTITY(&dc);
if (db_shrink_lob(session, &dc, column) != OG_SUCCESS) {
if (SCH_LOCKED_EXCLUSIVE(dc.handle)) {
dc_invalidate(session, entity);
}
unlock_tables_directly(session);
dc_close(&dc);
return OG_ERROR;
}
dc_invalidate(session, entity);
unlock_tables_directly(session);
dc_close(&dc);
session->stat->table_alters++;
return OG_SUCCESS;
}
status_t db_ddm_check_double_rule(knl_session_t *session, knl_ddm_def_t *def)
{
knl_cursor_t *cursor = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_DDM_ID, IX_SYS_DDM_001_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 *)&def->uid,
sizeof(uint32), IX_COL_SYS_DDM_001_UID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&def->oid,
sizeof(uint32), IX_COL_SYS_DDM_001_OID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&def->column_id,
sizeof(uint32), IX_COL_SYS_DDM_001_COLID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof == OG_FALSE) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR_EX(ERR_INVALID_OPERATION, ", col has rule already.");
return OG_ERROR;
}
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_DDM_ID, IX_SYS_DDM_002_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 *)&def->uid,
sizeof(uint32), IX_COL_SYS_DDM_002_UID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_INTEGER, (void *)&def->oid,
sizeof(uint32), IX_COL_SYS_DDM_002_OID);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING, def->rulename,
(uint16)strlen(def->rulename), IX_COL_SYS_DDM_002_RULENAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof == OG_FALSE) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR_EX(ERR_INVALID_OPERATION, ", rule name already exists.");
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_write_ddm_core(knl_session_t *session, knl_ddm_def_t *def)
{
uint32 max_size;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
table_t *table = NULL;
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
max_size = session->kernel->attr.max_row_size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_DDM_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, max_size, table->desc.column_count);
(void)row_put_int32(&ra, def->uid);
(void)row_put_int32(&ra, def->oid);
(void)row_put_int32(&ra, def->column_id);
(void)row_put_str(&ra, def->rulename);
(void)row_put_str(&ra, def->ddmtype);
(void)row_put_str(&ra, def->param);
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 db_ddm_invalid_dc(knl_session_t *session, knl_ddm_def_t *def)
{
knl_dictionary_t dc;
if (knl_open_dc_by_id(session, def->uid, def->oid, &dc, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
dc_invalidate(session, (dc_entity_t *)dc.handle);
dc_close(&dc);
return OG_SUCCESS;
}
status_t db_write_sysddm(knl_session_t *session, knl_ddm_def_t *def)
{
if (db_ddm_check_double_rule(session, def) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_write_ddm_core(session, def) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_write_sysjob(knl_session_t *session, knl_job_def_t *def)
{
uint32 max_size;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
table_t *table = NULL;
dc_user_t *sys_user = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_JOB_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "JOB$");
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
max_size = session->kernel->attr.max_row_size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_JOB_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, max_size, table->desc.column_count);
(void)row_put_int64(&ra, def->job_id);
(void)row_put_str(&ra, T2S(&def->lowner));
(void)row_put_str(&ra, T2S(&def->lowner));
(void)row_put_str(&ra, T2S(&def->lowner));
row_put_null(&ra);
row_put_null(&ra);
(void)row_put_int64(&ra, def->next_date);
(void)row_put_int32(&ra, 0);
(void)row_put_str(&ra, T2S(&def->interval));
(void)row_put_int32(&ra, 0);
(void)row_put_int32(&ra, 0);
(void)row_put_str(&ra, T2S(&def->what));
(void)row_put_int64(&ra, cm_now());
(void)row_put_int32(&ra, def->instance);
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
bool32 db_check_job_priv(knl_session_t *session, text_t *user, text_t *powner)
{
if (user->len == SYS_USER_NAME_LEN && cm_strcmpni(user->str, SYS_USER_NAME, user->len) == 0) {
return OG_TRUE;
} else {
if (user->len == powner->len && cm_strcmpni(user->str, powner->str, user->len) == 0) {
return OG_TRUE;
} else {
return OG_FALSE;
}
}
}
static status_t db_set_job_update_info(knl_session_t *session, knl_cursor_t *cursor, knl_job_node_t *job)
{
row_assist_t ra;
switch (job->node_type) {
case JOB_TYPE_BROKEN:
if (job->is_broken == OG_TRUE) {
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_int32(&ra, OG_TRUE);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_JOB_FLAG;
} else {
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 2);
(void)row_put_int64(&ra, job->next_date);
(void)row_put_int32(&ra, OG_FALSE);
cursor->update_info.count = 2;
cursor->update_info.columns[0] = SYS_JOB_NEXT_DATE;
cursor->update_info.columns[1] = SYS_JOB_FLAG;
}
return OG_SUCCESS;
case JOB_TYPE_RUN:
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 2);
(void)row_put_int64(&ra, job->next_date);
(void)row_put_int32(&ra, OG_FALSE);
cursor->update_info.count = 2;
cursor->update_info.columns[0] = SYS_JOB_NEXT_DATE;
cursor->update_info.columns[1] = SYS_JOB_FLAG;
return OG_SUCCESS;
case JOB_TYPE_START:
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_int64(&ra, job->this_date);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_JOB_THIS_DATE;
return OG_SUCCESS;
case JOB_TYPE_FINISH:
if (job->is_success) {
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 4);
(void)row_put_int64(&ra, job->this_date);
row_put_null(&ra);
(void)row_put_int64(&ra, job->next_date);
(void)row_put_int32(&ra, job->failures);
cursor->update_info.count = 4;
cursor->update_info.columns[0] = SYS_JOB_LAST_DATE;
cursor->update_info.columns[1] = SYS_JOB_THIS_DATE;
cursor->update_info.columns[2] = SYS_JOB_NEXT_DATE;
cursor->update_info.columns[3] = SYS_JOB_FAILURES;
} else {
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
(void)row_put_int32(&ra, job->failures);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_JOB_FAILURES;
}
return OG_SUCCESS;
default:
OG_THROW_ERROR(ERR_UNSUPPORT_OPER_TYPE, "job operate", job->node_type);
return OG_ERROR;
}
return OG_SUCCESS;
}
* db_update_job$
*/
status_t db_update_sysjob(knl_session_t *session, text_t *user, knl_job_node_t *job, bool32 should_exist)
{
uint16 size;
text_t powner;
dc_user_t *sys_user = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_JOB_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "JOB$");
return OG_ERROR;
}
knl_set_session_scn(session, OG_INVALID_ID64);
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_JOB_ID, I_JOB_1_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_BIGINT, &job->job_id, sizeof(int64),
IX_COL_JOB_1_JOB);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
text_t job_txt;
char num_txt[OG_MAX_NUMBER_LEN];
job_txt.str = num_txt;
job_txt.len = 0;
if (cursor->eof) {
if (should_exist == OG_TRUE) {
cm_bigint2text(job->job_id, &job_txt);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "job", T2S(&job_txt));
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
powner.str = (char *)CURSOR_COLUMN_DATA(cursor, SYS_JOB_POWNER);
powner.len = CURSOR_COLUMN_SIZE(cursor, SYS_JOB_POWNER);
if (!db_check_job_priv(session, user, &powner)) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_INSUFFICIENT_PRIV);
return OG_ERROR;
}
if (db_set_job_update_info(session, cursor, job) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
knl_rollback(session, NULL);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
* db_delete_job$
*
* This function is used to delete a job record from job$.
*/
status_t db_delete_sysjob(knl_session_t *session, text_t *user, int64 jobno, bool32 should_exist)
{
knl_cursor_t *cursor = NULL;
text_t text;
text_t powner;
char num_txt[OG_MAX_NUMBER_LEN];
dc_user_t *sys_user = NULL;
text.str = num_txt;
text.len = 0;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_JOB_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "JOB$");
return OG_ERROR;
}
knl_set_session_scn(session, OG_INVALID_ID64);
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_JOB_ID, I_JOB_1_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_BIGINT, &jobno, sizeof(int64),
IX_COL_JOB_1_JOB);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!cursor->eof) {
powner.str = (char *)CURSOR_COLUMN_DATA(cursor, SYS_JOB_POWNER);
powner.len = CURSOR_COLUMN_SIZE(cursor, SYS_JOB_POWNER);
if (!db_check_job_priv(session, user, &powner)) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_INSUFFICIENT_PRIV);
return OG_ERROR;
}
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
knl_rollback(session, NULL);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
} else {
if (should_exist == OG_TRUE) {
cm_bigint2text(jobno, &text);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "job", T2S(&text));
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_sql_map_hash(knl_session_t *session, knl_cursor_t *cursor, uint32 hash_value)
{
row_assist_t ra;
knl_update_info_t *update_info = &cursor->update_info;
row_init(&ra, update_info->data, OG_MAX_ROW_SIZE, 1);
update_info->count = 1;
update_info->columns[0] = 0;
(void)row_put_int32(&ra, hash_value);
cm_decode_row(update_info->data, update_info->offsets, update_info->lens, NULL);
return knl_internal_update(session, cursor);
}
static status_t db_update_sql_map(knl_session_t *session, knl_cursor_t *cursor, knl_sql_map_t *sql_map)
{
row_assist_t ra;
knl_update_info_t *update_info = &cursor->update_info;
knl_column_t *dst_lob_column = NULL;
row_init(&ra, update_info->data, OG_MAX_ROW_SIZE, 1);
update_info->count = 1;
update_info->columns[0] = SYS_SQL_MAP_COL_DST_TEXT;
dst_lob_column = knl_get_column(cursor->dc_entity, SYS_SQL_MAP_COL_DST_TEXT);
if (knl_row_put_lob(session, cursor, dst_lob_column, &sql_map->dst_text.text, &ra) != OG_SUCCESS) {
return OG_ERROR;
}
cm_decode_row(update_info->data, update_info->offsets, update_info->lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_insert_sql_map(knl_session_t *session, knl_cursor_t *cursor, knl_sql_map_t *sql_map)
{
row_assist_t ra;
knl_column_t *src_lob_column = NULL;
knl_column_t *dst_lob_column = NULL;
cursor->action = CURSOR_ACTION_INSERT;
row_init(&ra, cursor->buf, OG_MAX_ROW_SIZE, 4);
(void)row_put_int32(&ra, sql_map->src_hash_code);
src_lob_column = knl_get_column(cursor->dc_entity, 1);
if (knl_row_put_lob(session, cursor, src_lob_column, &sql_map->src_text.text, &ra) != OG_SUCCESS) {
return OG_ERROR;
}
dst_lob_column = knl_get_column(cursor->dc_entity, SYS_SQL_MAP_COL_DST_TEXT);
if (knl_row_put_lob(session, cursor, dst_lob_column, &sql_map->dst_text.text, &ra) != OG_SUCCESS) {
return OG_ERROR;
}
(void)(row_put_int32(&ra, sql_map->user_id));
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_alter_sql_sysmap(knl_session_t *session, knl_sql_map_t *sql_map)
{
knl_cursor_t *cursor = NULL;
lob_locator_t *src_lob = NULL;
text_t src_sql;
bool8 found = OG_FALSE;
knl_set_session_scn(session, OG_INVALID_ID64);
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_SQL_MAP_ID, IDX_SQL_MAP_001_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 *)&sql_map->src_hash_code, sizeof(uint32), IX_COL_SQL_MAP_001_SRC_HASHCODE);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
while (!cursor->eof) {
if (sql_map->user_id != *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_SQL_MAP_COL_USER_ID)) {
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
continue;
}
src_lob = (lob_locator_t *)CURSOR_COLUMN_DATA(cursor, SYS_SQL_MAP_COL_SRC_TEXT);
src_sql.len = knl_lob_size(src_lob);
src_sql.str = (char *)cm_push(session->stack, src_sql.len);
if (src_sql.str == NULL) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_read_lob(session, src_lob, 0, src_sql.str, src_sql.len + 1, NULL, NULL) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cm_text_equal(&src_sql, &sql_map->src_text.text)) {
if (db_update_sql_map(session, cursor, sql_map) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
found = OG_TRUE;
break;
}
cm_pop(session->stack);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (!found) {
if (db_insert_sql_map(session, cursor, sql_map) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_delete_sql_sysmap(knl_session_t *session, knl_sql_map_t *sql_map, bool8 *is_exist)
{
knl_cursor_t *cursor = NULL;
lob_locator_t *src_lob = NULL;
text_t src_sql;
knl_set_session_scn(session, OG_INVALID_ID64);
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_SQL_MAP_ID, IDX_SQL_MAP_001_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 *)&sql_map->src_hash_code, sizeof(uint32), IX_COL_SQL_MAP_001_SRC_HASHCODE);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
while (!cursor->eof) {
if (sql_map->user_id != *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_SQL_MAP_COL_USER_ID)) {
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
continue;
}
src_lob = (lob_locator_t *)CURSOR_COLUMN_DATA(cursor, SYS_SQL_MAP_COL_SRC_TEXT);
src_sql.len = knl_lob_size(src_lob);
src_sql.str = (char *)cm_push(session->stack, src_sql.len);
if (src_sql.str == NULL) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_read_lob(session, src_lob, 0, src_sql.str, src_sql.len + 1, NULL, NULL) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cm_text_equal(&src_sql, &sql_map->src_text.text)) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
*is_exist = OG_TRUE;
}
cm_pop(session->stack);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_delete_sql_map_by_user(knl_session_t *session, uint32 uid)
{
knl_set_session_scn((knl_handle_t)session, OG_INVALID_ID64);
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_SQL_MAP_ID, IDX_SQL_MAP_002_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 *)&uid,
sizeof(uint32), IX_COL_SQL_MAP_002_SRC_USER_ID);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
while (!cursor->eof) {
if (OG_SUCCESS != knl_internal_delete(session, cursor)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_create_control_group(knl_session_t *session, knl_rsrc_group_t *group)
{
uint32 max_size;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
dc_user_t *sys_user = NULL;
table_t *table = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_RSRC_GROUP_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "SYS_RSRC_CONTROL_GROUPS");
return OG_ERROR;
}
if (db_generate_object_id(session, &group->oid) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
max_size = session->kernel->attr.max_row_size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_RSRC_GROUP_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, max_size, table->desc.column_count);
(void)row_put_int32(&ra, (int32)group->oid);
(void)row_put_str(&ra, group->name);
(void)row_put_str(&ra, group->description);
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
if (OG_ERRNO == ERR_DUPLICATE_KEY) {
cm_reset_error();
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "control group", group->name);
}
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_delete_rules_by_col(knl_session_t *session, knl_cursor_t *cursor, text_t *name, uint32 col_id)
{
text_t text;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_RSRC_PLAN_RULE_ID, OG_INVALID_ID32);
do {
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (cursor->eof) {
break;
}
text.str = CURSOR_COLUMN_DATA(cursor, col_id);
text.len = CURSOR_COLUMN_SIZE(cursor, col_id);
if (text.str != NULL && text.len != OG_NULL_VALUE_LEN && cm_text_equal(&text, name)) {
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
}
} while (OG_TRUE);
return OG_SUCCESS;
}
status_t db_update_rsrc_plan_num_rules_by_plan_name(knl_session_t *session, knl_cursor_t *cursor, text_t *plan_name,
bool8 inc_flag)
{
uint32 num_rules;
row_assist_t ra;
uint16 size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_RSRC_PLAN_ID, IX_RSRC_PLAN_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)plan_name->str, (uint16)plan_name->len, IX_COL_SYS_RSRC_PLAN001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (cursor->eof) {
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "resource plan", T2S(plan_name));
return OG_ERROR;
}
num_rules = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_COL_RULES);
if (inc_flag) {
num_rules++;
} else {
num_rules--;
}
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_RSRC_PLAN_COL_RULES;
row_put_int32(&ra, num_rules);
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_dec_rsrc_plan_num_rules_by_group_name(knl_session_t *session, knl_cursor_t *cursor, text_t *group_name)
{
text_t text;
text_t plan_name;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_RSRC_PLAN_RULE_ID, OG_INVALID_ID32);
do {
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (cursor->eof) {
break;
}
text.str = CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_GROUP);
text.len = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_GROUP);
if (text.str != NULL && text.len != OG_NULL_VALUE_LEN && cm_text_equal(&text, group_name)) {
plan_name.str = CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_PLAN);
plan_name.len = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_PLAN);
return db_update_rsrc_plan_num_rules_by_plan_name(session, cursor, &plan_name, OG_FALSE);
}
} while (OG_TRUE);
return OG_SUCCESS;
}
static status_t db_delete_group_mapping(knl_session_t *session, knl_cursor_t *cursor, text_t *group_name)
{
text_t text;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_RSRC_GROUP_MAPPING_ID, OG_INVALID_ID32);
do {
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (cursor->eof) {
break;
}
text.str = CURSOR_COLUMN_DATA(cursor, SYS_RSRC_GROUP_MAPPING_COL_GROUP);
text.len = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_GROUP_MAPPING_COL_GROUP);
if (text.len != OG_NULL_VALUE_LEN && text.str != NULL && cm_text_equal(&text, group_name)) {
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
}
} while (OG_TRUE);
return OG_SUCCESS;
}
status_t db_delete_control_group(knl_session_t *session, text_t *group_name)
{
knl_cursor_t *cursor = NULL;
dc_user_t *sys_user = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_RSRC_GROUP_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "SYS_RSRC_CONTROL_GROUPS");
return OG_ERROR;
}
if (cm_text_str_equal(group_name, OG_DEFAULT_GROUP_NAME)) {
OG_THROW_ERROR(ERR_CANNOT_MODIFY_CGROUP);
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_RSRC_GROUP_ID, IX_RSRC_GROUP_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)group_name->str, (uint16)group_name->len, IX_COL_SYS_RSRC_GROUP001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "control group", T2S(group_name));
return OG_ERROR;
}
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_dec_rsrc_plan_num_rules_by_group_name(session, cursor, group_name) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_delete_rules_by_col(session, cursor, group_name, SYS_RSRC_PLAN_RULE_COL_GROUP) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_delete_group_mapping(session, cursor, group_name) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_control_group(knl_session_t *session, knl_rsrc_group_t *group)
{
text_t text;
uint16 size;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
dc_user_t *sys_user = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_RSRC_GROUP_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "SYS_RSRC_CONTROL_GROUPS");
return OG_ERROR;
}
if (cm_str_equal(group->name, OG_DEFAULT_GROUP_NAME)) {
OG_THROW_ERROR(ERR_CANNOT_MODIFY_CGROUP);
return OG_ERROR;
}
cm_str2text(group->name, &text);
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_RSRC_GROUP_ID, IX_RSRC_GROUP_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)text.str, (uint16)text.len, IX_COL_SYS_RSRC_GROUP001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "control group", group->name);
return OG_ERROR;
}
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_RSRC_GROUP_COL_COMMENT;
if (group->description[0] != '\0') {
(void)row_put_str(&ra, group->description);
} else {
(void)row_put_null(&ra);
}
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_insert_default_plan_rule(knl_session_t *session, const char *plan_name)
{
errno_t errcode;
knl_rsrc_plan_rule_def_t def = { 0 };
const char *default_rule_comment = "Plan rule for all other operations";
errcode = strcpy_s(def.rule.plan_name, OG_NAME_BUFFER_SIZE, plan_name);
knl_securec_check(errcode);
errcode = strcpy_s(def.rule.group_name, OG_NAME_BUFFER_SIZE, OG_DEFAULT_GROUP_NAME);
knl_securec_check(errcode);
errcode = strcpy_s(def.rule.description, OG_COMMENT_BUFFER_SIZE, default_rule_comment);
knl_securec_check(errcode);
def.is_comment_set = OG_TRUE;
return db_create_rsrc_plan_rule(session, &def);
}
status_t db_create_rsrc_plan(knl_session_t *session, knl_rsrc_plan_t *plan)
{
uint32 max_size;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
dc_user_t *sys_user = NULL;
table_t *table = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_RSRC_PLAN_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "SYS_RSRC_PLANS");
return OG_ERROR;
}
if (db_generate_object_id(session, &plan->oid) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
max_size = session->kernel->attr.max_row_size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_RSRC_PLAN_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, max_size, table->desc.column_count);
(void)row_put_int32(&ra, (int32)plan->oid);
(void)row_put_str(&ra, plan->name);
(void)row_put_int32(&ra, 0);
(void)row_put_str(&ra, plan->description);
(void)row_put_int32(&ra, plan->type);
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
if (OG_ERRNO == ERR_DUPLICATE_KEY) {
cm_reset_error();
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "resource plan", plan->name);
}
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
if (db_insert_default_plan_rule(session, plan->name) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_delete_rsrc_plan(knl_session_t *session, text_t *plan_name)
{
knl_cursor_t *cursor = NULL;
dc_user_t *sys_user = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_RSRC_PLAN_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "SYS_RSRC_PLANS");
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_RSRC_PLAN_ID, IX_RSRC_PLAN_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)plan_name->str, (uint16)plan_name->len, IX_COL_SYS_RSRC_PLAN001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "resource plan", T2S(plan_name));
return OG_ERROR;
}
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_delete_rules_by_col(session, cursor, plan_name, SYS_RSRC_PLAN_RULE_COL_PLAN) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_rsrc_plan(knl_session_t *session, knl_rsrc_plan_t *plan)
{
text_t text;
uint16 size;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
dc_user_t *sys_user = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_RSRC_PLAN_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "SYS_RSRC_PLANS");
return OG_ERROR;
}
cm_str2text(plan->name, &text);
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_RSRC_PLAN_ID, IX_RSRC_PLAN_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)text.str, (uint16)text.len, IX_COL_SYS_RSRC_PLAN001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "resource plan", plan->name);
return OG_ERROR;
}
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_RSRC_PLAN_COL_COMMENT;
if (plan->description[0] != '\0') {
(void)row_put_str(&ra, plan->description);
} else {
(void)row_put_null(&ra);
}
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, &size);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static void db_fill_rsrc_plan_rule_row(row_assist_t *ra, knl_rsrc_plan_rule_def_t *def)
{
if (def->is_cpu_set) {
(void)row_put_int32(ra, def->rule.max_cpu_limit);
} else {
(void)row_put_int32(ra, 0);
}
if (def->is_sessions_set) {
(void)row_put_int32(ra, def->rule.max_sessions);
} else {
row_put_null(ra);
}
if (def->is_active_sess_set) {
(void)row_put_int32(ra, def->rule.max_active_sess);
} else {
row_put_null(ra);
}
if (def->is_queue_time_set) {
(void)row_put_int32(ra, def->rule.max_queue_time);
} else {
row_put_null(ra);
}
if (def->is_exec_time_set) {
(void)row_put_int32(ra, def->rule.max_exec_time);
} else {
row_put_null(ra);
}
if (def->is_temp_pool_set) {
(void)row_put_int32(ra, def->rule.max_temp_pool);
} else {
row_put_null(ra);
}
if (def->is_iops_set) {
(void)row_put_int32(ra, def->rule.max_iops);
} else {
row_put_null(ra);
}
if (def->is_commits_set) {
(void)row_put_int32(ra, def->rule.max_commits);
} else {
row_put_null(ra);
}
if (def->is_comment_set) {
(void)row_put_str(ra, def->rule.description);
} else {
row_put_null(ra);
}
}
static status_t db_query_rsrc_plan_by_name(knl_session_t *session, knl_cursor_t *cursor, text_t *name,
bool32 *is_exist)
{
knl_set_session_scn(session, OG_INVALID_ID64);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_RSRC_PLAN_ID, IX_RSRC_PLAN_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)name->str, (uint16)name->len, IX_COL_SYS_RSRC_PLAN001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
*is_exist = !cursor->eof;
return OG_SUCCESS;
}
static status_t db_query_control_group_by_name(knl_session_t *session, knl_cursor_t *cursor, text_t *name,
bool32 *is_exist)
{
knl_set_session_scn(session, OG_INVALID_ID64);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_RSRC_GROUP_ID, IX_RSRC_GROUP_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)name->str, (uint16)name->len, IX_COL_SYS_RSRC_GROUP001_NAME);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
*is_exist = !cursor->eof;
return OG_SUCCESS;
}
static knl_rsrc_group_t g_default_group = {
.oid = 0,
.name = OG_DEFAULT_GROUP_NAME,
.description = "Control group for users or tenants not assigned to any control group",
};
status_t db_create_rsrc_plan_rule(knl_session_t *session, knl_rsrc_plan_rule_def_t *def)
{
uint32 max_size;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
dc_user_t *sys_user = NULL;
table_t *table = NULL;
text_t name;
bool32 is_exist = OG_FALSE;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_RSRC_PLAN_RULE_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "SYS_RSRC_PLAN_RULES");
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
cm_str2text(def->rule.plan_name, &name);
if (db_query_rsrc_plan_by_name(session, cursor, &name, &is_exist) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!is_exist) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "resource plan", def->rule.plan_name);
return OG_ERROR;
}
cm_str2text(def->rule.group_name, &name);
if (db_query_control_group_by_name(session, cursor, &name, &is_exist) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!is_exist) {
if (!cm_str_equal(def->rule.group_name, OG_DEFAULT_GROUP_NAME)) {
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "control group", def->rule.group_name);
return OG_ERROR;
}
if (db_create_control_group(session, &g_default_group) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
max_size = session->kernel->attr.max_row_size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_RSRC_PLAN_RULE_ID, OG_INVALID_ID32);
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, max_size, table->desc.column_count);
(void)row_put_str(&ra, def->rule.plan_name);
(void)row_put_str(&ra, def->rule.group_name);
db_fill_rsrc_plan_rule_row(&ra, def);
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
if (OG_ERRNO == ERR_DUPLICATE_KEY) {
cm_reset_error();
char buf[OG_T2S_BUFFER_SIZE];
errno_t errcode = snprintf_s(buf, OG_T2S_BUFFER_SIZE, OG_T2S_BUFFER_SIZE - 1, "%s, %s",
def->rule.plan_name, def->rule.group_name);
knl_securec_check_ss(errcode);
OG_THROW_ERROR(ERR_OBJECT_EXISTS, "plan rule", buf);
}
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
cm_str2text(def->rule.plan_name, &name);
if (db_update_rsrc_plan_num_rules_by_plan_name(session, cursor, &name, OG_TRUE) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_delete_rsrc_plan_rule(knl_session_t *session, text_t *plan_name, text_t *group_name)
{
knl_cursor_t *cursor = NULL;
dc_user_t *sys_user = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_RSRC_PLAN_RULE_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "SYS_RSRC_PLAN_RULES");
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_RSRC_PLAN_RULE_ID, IX_RSRC_PLAN_RULE_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)plan_name->str, (uint16)plan_name->len, IX_COL_SYS_RSRC_RULE001_PLAN);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)group_name->str, (uint16)group_name->len, IX_COL_SYS_RSRC_RULE001_GROUP);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
char buf[OG_T2S_BUFFER_SIZE];
errno_t errcode = snprintf_s(buf, OG_T2S_BUFFER_SIZE, OG_T2S_BUFFER_SIZE - 1, "%s, %s",
T2S(plan_name), T2S_EX(group_name));
knl_securec_check_ss(errcode);
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "plan rule", buf);
return OG_ERROR;
}
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_delete_rules_by_col(session, cursor, group_name, SYS_RSRC_PLAN_RULE_COL_GROUP) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_update_rsrc_plan_num_rules_by_plan_name(session, cursor, plan_name, OG_FALSE) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_prepare_update_rsrc_plan_rule(knl_cursor_t *cursor, knl_rsrc_plan_rule_def_t *def)
{
uint32 size;
text_t text;
if (!def->is_cpu_set) {
size = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_CPU);
if (size != OG_NULL_VALUE_LEN) {
def->rule.max_cpu_limit = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_CPU);
def->is_cpu_set = OG_TRUE;
} else {
def->rule.max_cpu_limit = OG_DEFAULT_NULL_VALUE;
}
}
if (def->rule.max_cpu_limit == OG_DEFAULT_NULL_VALUE) {
def->is_cpu_set = OG_FALSE;
}
if (!def->is_sessions_set) {
size = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_SESSIONS);
if (size != OG_NULL_VALUE_LEN) {
def->rule.max_sessions = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_SESSIONS);
def->is_sessions_set = OG_TRUE;
} else {
def->rule.max_sessions = OG_DEFAULT_NULL_VALUE;
}
}
if (def->rule.max_sessions == OG_DEFAULT_NULL_VALUE) {
def->is_sessions_set = OG_FALSE;
}
if (!def->is_active_sess_set) {
size = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_ACTIVE_SESS);
if (size != OG_NULL_VALUE_LEN) {
def->rule.max_active_sess = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_ACTIVE_SESS);
def->is_active_sess_set = OG_TRUE;
} else {
def->rule.max_active_sess = OG_DEFAULT_NULL_VALUE;
}
}
if (def->rule.max_active_sess == OG_DEFAULT_NULL_VALUE) {
def->is_active_sess_set = OG_FALSE;
}
if (!def->is_queue_time_set) {
size = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_QUEUE_TIME);
if (size != OG_NULL_VALUE_LEN) {
def->rule.max_queue_time = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_QUEUE_TIME);
def->is_queue_time_set = OG_TRUE;
} else {
def->rule.max_queue_time = OG_DEFAULT_NULL_VALUE;
}
}
if (def->rule.max_queue_time == OG_DEFAULT_NULL_VALUE) {
def->is_queue_time_set = OG_FALSE;
}
if (!def->is_exec_time_set) {
size = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_MAX_EXEC_TIME);
if (size != OG_NULL_VALUE_LEN) {
def->rule.max_exec_time = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_MAX_EXEC_TIME);
def->is_exec_time_set = OG_TRUE;
} else {
def->rule.max_exec_time = OG_DEFAULT_NULL_VALUE;
}
}
if (def->rule.max_exec_time == OG_DEFAULT_NULL_VALUE) {
def->is_exec_time_set = OG_FALSE;
}
if (!def->is_temp_pool_set) {
size = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_TEMP_POOL);
if (size != OG_NULL_VALUE_LEN) {
def->rule.max_temp_pool = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_TEMP_POOL);
def->is_temp_pool_set = OG_TRUE;
} else {
def->rule.max_temp_pool = OG_DEFAULT_NULL_VALUE;
}
}
if (def->rule.max_temp_pool == OG_DEFAULT_NULL_VALUE) {
def->is_temp_pool_set = OG_FALSE;
}
if (!def->is_iops_set) {
size = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_MAX_IOPS);
if (size != OG_NULL_VALUE_LEN) {
def->rule.max_iops = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_MAX_IOPS);
def->is_iops_set = OG_TRUE;
} else {
def->rule.max_iops = OG_DEFAULT_NULL_VALUE;
}
}
if (def->rule.max_iops == OG_DEFAULT_NULL_VALUE) {
def->is_iops_set = OG_FALSE;
}
if (!def->is_commits_set) {
size = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_MAX_COMMITS);
if (size != OG_NULL_VALUE_LEN) {
def->rule.max_commits = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_MAX_COMMITS);
def->is_commits_set = OG_TRUE;
} else {
def->rule.max_commits = OG_DEFAULT_NULL_VALUE;
}
}
if (def->rule.max_commits == OG_DEFAULT_NULL_VALUE) {
def->is_commits_set = OG_FALSE;
}
if (!def->is_comment_set) {
text.len = CURSOR_COLUMN_SIZE(cursor, SYS_RSRC_PLAN_RULE_COL_COMMENT);
text.str = CURSOR_COLUMN_DATA(cursor, SYS_RSRC_PLAN_RULE_COL_COMMENT);
if (text.len != OG_NULL_VALUE_LEN && text.str != NULL) {
if (cm_text2str(&text, def->rule.description, OG_COMMENT_SIZE + 1) != OG_SUCCESS) {
return OG_ERROR;
}
def->is_comment_set = OG_TRUE;
} else {
def->rule.description[0] = '\0';
}
}
return OG_SUCCESS;
}
status_t db_update_rsrc_plan_rule(knl_session_t *session, knl_rsrc_plan_rule_def_t *def)
{
text_t plan_name;
text_t group_name;
uint32 col_count;
row_assist_t ra;
knl_cursor_t *cursor = NULL;
dc_user_t *sys_user = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_RSRC_PLAN_RULE_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "SYS_RSRC_PLAN_RULES");
return OG_ERROR;
}
cm_str2text(def->rule.plan_name, &plan_name);
cm_str2text(def->rule.group_name, &group_name);
CM_SAVE_STACK(session->stack);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_RSRC_PLAN_RULE_ID, IX_RSRC_PLAN_RULE_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)plan_name.str, (uint16)plan_name.len, IX_COL_SYS_RSRC_RULE001_PLAN);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)group_name.str, (uint16)group_name.len, IX_COL_SYS_RSRC_RULE001_GROUP);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (cursor->eof) {
cm_reset_error();
char buf[OG_T2S_BUFFER_SIZE];
errno_t errcode = snprintf_s(buf, OG_T2S_BUFFER_SIZE, OG_T2S_BUFFER_SIZE - 1, "%s, %s",
def->rule.plan_name, def->rule.group_name);
knl_securec_check_ss(errcode);
CM_RESTORE_STACK(session->stack);
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "plan rule", buf);
return OG_ERROR;
}
if (db_prepare_update_rsrc_plan_rule(cursor, def) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
col_count = SYS_RSRC_PLAN_RULE_COL_COUNT - 2;
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), col_count);
cursor->update_info.count = col_count;
for (uint32 i = 0; i < col_count; i++) {
cursor->update_info.columns[i] = (uint16)(i + 2);
}
db_fill_rsrc_plan_rule_row(&ra, def);
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static status_t db_insert_cgroup_mapping(knl_session_t *session, knl_cursor_t *cursor,
knl_rsrc_group_mapping_t *mapping)
{
row_assist_t ra;
table_t *table = NULL;
uint32 max_size;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_RSRC_GROUP_MAPPING_ID, OG_INVALID_ID32);
max_size = session->kernel->attr.max_row_size;
table = (table_t *)cursor->table;
row_init(&ra, cursor->buf, max_size, table->desc.column_count);
(void)row_put_str(&ra, mapping->attribute);
(void)row_put_str(&ra, mapping->value);
(void)row_put_str(&ra, mapping->group_name);
if (knl_internal_insert(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_delete_cgroup_mapping(knl_session_t *session, knl_cursor_t *cursor,
knl_rsrc_group_mapping_t *mapping)
{
text_t key;
text_t value;
cm_str2text(mapping->attribute, &key);
cm_str2text(mapping->value, &value);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_RSRC_GROUP_MAPPING_ID, IX_RSRC_GROUP_MAPPING_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)key.str, (uint16)key.len, IX_COL_SYS_RSRC_MAPPING001_ATTRIBUTE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)value.str, (uint16)value.len, IX_COL_SYS_RSRC_MAPPING001_VALUE);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (cursor->eof) {
return OG_SUCCESS;
}
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_update_cgroup_mapping(knl_session_t *session, knl_cursor_t *cursor, const char *value)
{
row_assist_t ra;
row_init(&ra, cursor->update_info.data, HEAP_MAX_ROW_SIZE(session), 1);
cursor->update_info.count = 1;
cursor->update_info.columns[0] = SYS_RSRC_GROUP_MAPPING_COL_GROUP;
(void)row_put_str(&ra, value);
cm_decode_row(cursor->update_info.data, cursor->update_info.offsets, cursor->update_info.lens, NULL);
if (knl_internal_update(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_set_cgroup_mapping_core(knl_session_t *session, knl_rsrc_group_mapping_t *mapping)
{
text_t key;
text_t value;
text_t group_name;
knl_cursor_t *cursor = NULL;
bool32 is_exist;
cm_str2text(mapping->attribute, &key);
cm_str2text(mapping->value, &value);
if (mapping->group_name[0] != '\0') {
cm_str2text(mapping->group_name, &group_name);
cursor = knl_push_cursor(session);
if (db_query_control_group_by_name(session, cursor, &group_name, &is_exist) != OG_SUCCESS) {
return OG_ERROR;
}
if (!is_exist) {
if (!cm_str_equal(mapping->group_name, OG_DEFAULT_GROUP_NAME)) {
OG_THROW_ERROR(ERR_OBJECT_NOT_EXISTS, "control group", mapping->group_name);
return OG_ERROR;
}
}
}
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_UPDATE, SYS_RSRC_GROUP_MAPPING_ID, IX_RSRC_GROUP_MAPPING_001_ID);
knl_init_index_scan(cursor, OG_TRUE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)key.str, (uint16)key.len, IX_COL_SYS_RSRC_MAPPING001_ATTRIBUTE);
knl_set_scan_key(INDEX_DESC(cursor->index), &cursor->scan_range.l_key, OG_TYPE_STRING,
(void *)value.str, (uint16)value.len, IX_COL_SYS_RSRC_MAPPING001_VALUE);
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (cursor->eof) {
if (mapping->group_name[0] != '\0') {
return db_insert_cgroup_mapping(session, cursor, mapping);
}
} else {
if (mapping->group_name[0] != '\0') {
return db_update_cgroup_mapping(session, cursor, mapping->group_name);
} else {
return db_delete_cgroup_mapping(session, cursor, mapping);
}
}
return OG_SUCCESS;
}
status_t db_set_cgroup_mapping(knl_session_t *session, knl_rsrc_group_mapping_t *mapping)
{
dc_user_t *sys_user = NULL;
if (dc_open_user_by_id(session, DB_SYS_USER_ID, &sys_user) != OG_SUCCESS ||
DC_GET_ENTRY(sys_user, SYS_RSRC_GROUP_MAPPING_ID) == NULL) {
OG_THROW_ERROR(ERR_TABLE_OR_VIEW_NOT_EXIST, "SYS", "SYS_RSRC_GROUP_MAPPINGS");
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
status_t status = db_set_cgroup_mapping_core(session, mapping);
CM_RESTORE_STACK(session->stack);
return status;
}
status_t db_clean_all_shadow_indexes(knl_session_t *session)
{
core_ctrl_t *core = &session->kernel->db.ctrl.core;
knl_cursor_t *cursor = NULL;
index_t index;
status_t status;
dc_entry_t *entry = NULL;
dc_user_t *user = NULL;
space_t *space = NULL;
bool32 is_nologging_table = OG_FALSE;
errno_t err;
if (DB_IS_READONLY(session) || !core->build_completed) {
return OG_SUCCESS;
}
CM_SAVE_STACK(session->stack);
knl_set_session_scn(session, OG_INVALID_ID64);
cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_SHADOW_INDEX_ID, OG_INVALID_ID32);
for (;;) {
if (knl_fetch(session, cursor) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
if (cursor->eof) {
status = OG_SUCCESS;
break;
}
err = memset_sp(&index, sizeof(index_t), 0, sizeof(index_t));
knl_securec_check(err);
cm_decode_row((char *)cursor->row, cursor->offsets, cursor->lens, NULL);
dc_convert_index(session, cursor, &index.desc);
dc_set_index_accessor((table_t *)cursor->table, &index);
if (dc_open_user_by_id(session, index.desc.uid, &user) != OG_SUCCESS) {
status = OG_ERROR;
break;
}
entry = DC_GET_ENTRY(user, index.desc.table_id);
if (dc_locked_by_xa(session, entry)) {
OG_LOG_RUN_WAR("skip dc clean shadow indexes for table ID(%u)", index.desc.table_id);
continue;
}
space = SPACE_GET(session, index.desc.space_id);
is_nologging_table = SPACE_IS_NOLOGGING(space) ? OG_TRUE : OG_FALSE;
if (is_nologging_table) {
index.desc.entry = INVALID_PAGID;
OG_LOG_RUN_WAR("dc clean shadow indexes found nologging table ID(%u)", index.desc.table_id);
}
btree_drop_segment(session, &index);
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
status = OG_SUCCESS;
break;
}
if (index.desc.parted) {
if (db_drop_shadow_indexpart(session, index.desc.uid, index.desc.table_id,
!is_nologging_table) != OG_SUCCESS) {
status = OG_SUCCESS;
break;
}
}
}
knl_commit(session);
if (db_clean_all_shadow_indexparts(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return status;
}
static status_t db_delete_table_segments(knl_session_t *session, knl_cursor_t *cursor, knl_dictionary_t *dc)
{
table_t *table = DC_TABLE(dc);
if (dc->type == DICT_TYPE_TEMP_TABLE_SESSION || dc->type == DICT_TYPE_TEMP_TABLE_TRANS) {
cm_spin_lock(&session->temp_cache_lock, NULL);
knl_temp_cache_t *temp_table = knl_get_temp_cache(session, dc->uid, dc->oid);
if (temp_table != NULL) {
knl_free_temp_vm(session, temp_table);
}
cm_spin_unlock(&session->temp_cache_lock);
} else if (dc->type == DICT_TYPE_TABLE_EXTERNAL) {
if (db_drop_external_table(session, cursor, table) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (db_drop_table_segments(session, dc) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
void db_drop_table_drop_dc(knl_session_t *session, knl_dictionary_t *dc, table_t *table)
{
if (db_garbage_segment_handle(session, dc->uid, dc->oid, OG_FALSE) != OG_SUCCESS) {
cm_spin_lock(&session->kernel->rmon_ctx.mark_mutex, NULL);
session->kernel->rmon_ctx.delay_clean_segments = OG_TRUE;
cm_spin_unlock(&session->kernel->rmon_ctx.mark_mutex);
OG_LOG_RUN_ERR("failed to handle garbage segment");
}
g_knl_callback.pl_drop_triggers_entry(session, dc);
dc_drop_object_privs(&session->kernel->dc_ctx, table->desc.uid, table->desc.name, OBJ_TYPE_TABLE);
dc_drop(session, DC_ENTITY(dc));
session->stat->table_drops++;
}
status_t db_drop_table(knl_session_t *session, knl_handle_t stmt, knl_dictionary_t *dc, bool32 commit)
{
knl_comment_def_t comment_def;
rd_drop_table_t redo;
obj_info_t obj_addr;
if (rb_purge_drop_related(session, dc->uid, dc->oid) != OG_SUCCESS) {
return OG_ERROR;
}
table_t *table = DC_TABLE(dc);
dc_entity_t *entity = DC_ENTITY(dc);
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
cursor->row = (row_head_t *)cursor->buf;
if (OG_SUCCESS != db_delete_from_systable(session, cursor, table->desc.uid, table->desc.name)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (table->desc.is_nologging) {
if (db_update_nologobj_cnt(session, OG_FALSE) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (table->desc.storaged && db_delete_from_sysstorage(session, cursor, table->desc.org_scn) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != db_delete_columns(session, cursor, table->desc.uid, table->desc.id)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (table->desc.parted) {
if (OG_SUCCESS != db_drop_part_table(session, cursor, table->part_table)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (table->desc.compress) {
if (db_delete_from_syscompress(session, cursor, table->desc.org_scn) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (entity->contain_lob) {
if (OG_SUCCESS != db_delete_from_syslob(session, cursor, entity->table.desc.uid,
entity->table.desc.id, OG_INVALID_INT32)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (OG_SUCCESS != db_delete_from_sysindex(session, cursor, table->desc.uid, table->desc.id, OG_INVALID_ID32)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != db_drop_all_cons(session, table->desc.uid, table->desc.id, OG_FALSE)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
#ifdef OG_RAC_ING
(void)db_delete_distribute_strategy(session, table);
#endif
comment_def.type = COMMENT_ON_TABLE;
comment_def.uid = table->desc.uid;
comment_def.id = table->desc.id;
if (OG_SUCCESS != db_delete_comment(session, &comment_def)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != stats_drop_hists(session, table->desc.uid, table->desc.id,
IS_NOLOGGING_BY_TABLE_TYPE(table->desc.type))) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (OG_SUCCESS != db_delete_mon_sysmods(session, table->desc.uid, table->desc.id, OG_INVALID_ID32, OG_FALSE)) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_delete_table_segments(session, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_check_policies_before_delete(session, table->desc.name, table->desc.uid) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_drop_object_privs(session, table->desc.uid, table->desc.name, OBJ_TYPE_TABLE) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (db_clean_shadow_index(session, dc->uid, dc->oid, OG_TRUE) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
obj_addr.oid = dc->oid;
obj_addr.uid = dc->uid;
obj_addr.tid = OBJ_TYPE_TABLE;
if (g_knl_callback.update_depender(session, &obj_addr) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (g_knl_callback.pl_db_drop_triggers(session, (void *)dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (!commit) {
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
redo.op_type = RD_DROP_TABLE;
redo.purge = OG_TRUE;
redo.uid = table->desc.uid;
redo.oid = table->desc.id;
redo.org_scn = table->desc.org_scn;
errno_t err = strcpy_sp(redo.name, OG_NAME_BUFFER_SIZE, table->desc.name);
knl_securec_check(err);
log_put(session, RD_LOGIC_OPERATION, &redo, sizeof(rd_drop_table_t), LOG_ENTRY_FLAG_NONE);
SYNC_POINT(session, "SP_B1_DROP_TABLE");
SYNC_POINT_GLOBAL_START(OGRAC_DDL_DROP_TABLE_AFTER_LOG_PUT, NULL, 0);
SYNC_POINT_GLOBAL_END;
log_add_lrep_ddl_info(session, stmt, LOGIC_OP_TABLE, RD_DROP_TABLE, table);
SYNC_POINT_GLOBAL_START(OGRAC_DDL_DROP_TABLE_BEFORE_SYNC_ABORT, NULL, 0);
SYNC_POINT_GLOBAL_END;
knl_commit(session);
SYNC_POINT_GLOBAL_START(OGRAC_DDL_DROP_TABLE_AFTER_SYNC_ABORT, NULL, 0);
SYNC_POINT_GLOBAL_END;
db_drop_table_drop_dc(session, dc, table);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_delete_dist_rules_by_user(knl_session_t *session, uint32 uid)
{
uint32 oid;
knl_set_session_scn((knl_handle_t)session, OG_INVALID_ID64);
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_cursor_t *sub_cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_DISTRIBUTE_RULE_ID, IX_SYS_DISTRIBUTE_RULE003_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 *)&uid,
sizeof(uint32), IX_COL_SYS_DISTRIBUTE_RULE003_UID);
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;
}
oid = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_DISTRIBUTE_RULE_COL_ID);
if (db_delete_columns((knl_session_t *)session, sub_cursor, uid, oid) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
if (knl_fetch(session, cursor) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_get_storage_desc(knl_session_t *session, knl_storage_desc_t *storage_desc, knl_scn_t org_scn)
{
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_STORAGE_ID, IX_STORAGE_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 *)&org_scn,
sizeof(uint64), IX_COL_SYS_STORAGE_ORGSCN);
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_SUCCESS;
}
storage_desc->initial = (CURSOR_COLUMN_SIZE(cursor, SYS_STORAGE_COL_INITIAL_PAGES) != OG_NULL_VALUE_LEN) ?
(*(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_STORAGE_COL_INITIAL_PAGES)) : 0;
storage_desc->max_pages = (CURSOR_COLUMN_SIZE(cursor, SYS_STORAGE_COL_MAX_PAGES) != OG_NULL_VALUE_LEN) ?
(*(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_STORAGE_COL_MAX_PAGES)) : 0;
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_update_part_index_status(knl_session_t *session, index_t *index, bool32 is_invalid, bool32 *is_changed)
{
if (!IS_PART_INDEX(index)) {
return OG_SUCCESS;
}
index_part_t *index_part = NULL;
index_part_t *index_subpart = NULL;
table_part_t *table_part = NULL;
table_t *table = &index->entity->table;
for (uint32 id = 0; id < index->part_index->desc.partcnt; id++) {
index_part = INDEX_GET_PART(index, id);
table_part = TABLE_GET_PART(table, id);
if (!IS_READY_PART(table_part) || index_part == NULL) {
continue;
}
if (!IS_PARENT_IDXPART(&index_part->desc)) {
if (is_invalid) {
if (btree_part_segment_prepare(session, index_part, OG_FALSE, BTREE_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (db_update_idxpart_status(session, index_part, is_invalid, is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
continue;
}
for (uint32 j = 0; j < index_part->desc.subpart_cnt; j++) {
index_subpart = PART_GET_SUBENTITY(index->part_index, index_part->subparts[j]);
if (index_subpart == NULL) {
continue;
}
if (is_invalid) {
if (btree_part_segment_prepare(session, index_subpart,
OG_FALSE, BTREE_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (db_update_sub_idxpart_status(session, index_subpart, is_invalid, is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
}
}
return OG_SUCCESS;
}
static status_t db_do_index_subpart_unusable(knl_session_t *session, index_part_t *index_subpart)
{
bool32 is_changed = OG_FALSE;
if (btree_part_segment_prepare(session, index_subpart, OG_FALSE, BTREE_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_sub_idxpart_status(session, index_subpart, OG_TRUE, &is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_do_index_part_unusable(knl_session_t *session, index_t *index, index_part_t *index_part)
{
index_part_t *index_subpart = NULL;
bool32 is_changed = OG_FALSE;
if (IS_PARENT_IDXPART(&index_part->desc)) {
for (uint32 j = 0; j < index_part->desc.subpart_cnt; j++) {
index_subpart = PART_GET_SUBENTITY(index->part_index, index_part->subparts[j]);
if (index_subpart == NULL) {
continue;
}
if (db_do_index_subpart_unusable(session, index_subpart) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
if (btree_part_segment_prepare(session, index_part, OG_FALSE, BTREE_DROP_PART_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_idxpart_status(session, index_part, OG_TRUE, &is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_alter_index_unusable(knl_session_t *session, index_t *index)
{
bool32 is_changed = OG_FALSE;
if (IS_PART_INDEX(index)) {
if (db_update_part_index_status(session, index, OG_TRUE, &is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
} else {
if (btree_segment_prepare(session, index, OG_FALSE, BTREE_DROP_SEGMENT) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_index_status(session, index, OG_TRUE, &is_changed) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_alter_index_part_unusable(knl_session_t *session, knl_alindex_def_t *def, knl_dictionary_t *dc,
index_t *index, bool32 is_subpart)
{
if (!IS_PART_INDEX(index)) {
OG_THROW_ERROR(ERR_MODIFY_PART_INDEX);
return OG_ERROR;
}
index_part_t *index_part = NULL;
if (is_subpart) {
if (subpart_idx_find_by_name(index->part_index, &def->mod_idxpart.part_name, &index_part)) {
return db_do_index_subpart_unusable(session, index_part);
}
} else {
if (part_idx_find_by_name(index->part_index, &def->mod_idxpart.part_name, &index_part)) {
return db_do_index_part_unusable(session, index, index_part);
}
}
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "table", T2S(&def->mod_idxpart.part_name));
return OG_ERROR;
}
static status_t db_alter_index_subpart_initrans(knl_session_t *session, index_t *index,
index_part_t *index_part, uint32 initrans)
{
index_part_t *index_subpart = NULL;
if (!IS_PARENT_IDXPART(&index_part->desc)) {
return OG_SUCCESS;
}
for (uint32 i = 0; i < index_part->desc.subpart_cnt; i++) {
index_subpart = PART_GET_SUBENTITY(index->part_index, index_part->subparts[i]);
if (index_subpart == NULL) {
continue;
}
if (db_upd_idx_subpart_initrans(session, &index_subpart->desc, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
btree_set_initrans(session, &index_subpart->btree, initrans);
}
return OG_SUCCESS;
}
status_t db_alter_index_initrans(knl_session_t *session, knl_alindex_def_t *def, index_t *index)
{
uint32 initrans = def->idx_def.initrans;
table_part_t *table_part = NULL;
index_part_t *index_part = NULL;
if (db_update_index_initrans(session, &index->desc, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
btree_set_initrans(session, &index->btree, initrans);
if (!IS_PART_INDEX(index)) {
return OG_SUCCESS;
}
for (uint32 id = 0; id < index->part_index->desc.partcnt; ++id) {
table_part = TABLE_GET_PART(&index->entity->table, id);
if (!IS_READY_PART(table_part)) {
continue;
}
index_part = INDEX_GET_PART(index, id);
if (db_upd_idx_part_initrans(session, &index_part->desc, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
btree_set_initrans(session, &index_part->btree, initrans);
if (db_alter_index_subpart_initrans(session, index, index_part, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_alter_index_part_initrans(knl_session_t *session, knl_alindex_def_t *def, knl_dictionary_t *dc,
index_t *index)
{
table_t *table = DC_TABLE(dc);
index_part_t *index_part = NULL;
uint32 initrans = def->mod_idxpart.initrans;
if (!IS_PART_TABLE(table) || !IS_PART_INDEX(index)) {
OG_THROW_ERROR(ERR_MODIFY_PART_INDEX);
return OG_ERROR;
}
if (!part_idx_find_by_name(index->part_index, &def->mod_idxpart.part_name, &index_part)) {
OG_THROW_ERROR(ERR_PARTITION_NOT_EXIST, "index", T2S(&def->mod_idxpart.part_name));
return OG_ERROR;
}
if (db_upd_idx_part_initrans(session, &index_part->desc, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
btree_set_initrans(session, &index_part->btree, initrans);
if (db_alter_index_subpart_initrans(session, index, index_part, initrans) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t db_alter_index_partition(knl_session_t *session, knl_alindex_def_t *def, knl_dictionary_t *dc,
index_t *index)
{
status_t status;
switch (def->mod_idxpart.type) {
case MODIFY_IDXPART_INITRANS:
status = db_alter_index_part_initrans(session, def, dc, index);
break;
case MODIFY_IDXPART_UNUSABLE:
status = db_alter_index_part_unusable(session, def, dc, index, OG_FALSE);
break;
default:
OG_THROW_ERROR(ERR_INVALID_OPERATION, ",unsupported alter index operation");
status = OG_ERROR;
}
return status;
}
status_t db_alter_index_subpartition(knl_session_t *session, knl_alindex_def_t *def, knl_dictionary_t *dc,
index_t *index)
{
status_t status;
switch (def->mod_idxpart.type) {
case MODIFY_IDXSUBPART_UNUSABLE:
status = db_alter_index_part_unusable(session, def, dc, index, OG_TRUE);
break;
default:
OG_THROW_ERROR(ERR_INVALID_OPERATION, ",unsupported alter index operation");
status = OG_ERROR;
}
return status;
}
status_t db_write_syscompress(knl_session_t *session, knl_cursor_t *cursor, uint32 space_id, uint64 org_scn,
uint32 compress_mode, compress_object_type_t obj_type)
{
row_assist_t ra;
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_INSERT, SYS_COMPRESS_ID, OG_INVALID_ID32);
row_init(&ra, (char *)cursor->row, session->kernel->attr.max_row_size, SYS_COMPRESS_COLUMN_COUNT);
(void)row_put_int64(&ra, org_scn);
(void)row_put_int32(&ra, (int32)compress_mode);
(void)row_put_int32(&ra, (int32)obj_type);
return knl_internal_insert(session, cursor);
}
status_t db_delete_from_syscompress(knl_session_t *session, knl_cursor_t *cursor, uint64 org_scn)
{
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_DELETE, SYS_COMPRESS_ID, IX_SYSCOMPRESS001_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 *)&org_scn,
sizeof(uint64), IX_COL_SYSCOMPRESS001_ORGSCN);
for (;;) {
if (knl_fetch(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
if (cursor->eof) {
break;
}
if (knl_internal_delete(session, cursor) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
status_t db_get_compress_algo(knl_session_t *session, uint8 *compress_mode, uint64 org_scn)
{
if (!DB_IS_OPEN(session)) {
return OG_SUCCESS;
}
CM_SAVE_STACK(session->stack);
knl_cursor_t *cursor = knl_push_cursor(session);
knl_open_sys_cursor(session, cursor, CURSOR_ACTION_SELECT, SYS_COMPRESS_ID, IX_SYSCOMPRESS001_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 *)&org_scn,
sizeof(uint64), IX_COL_SYSCOMPRESS001_ORGSCN);
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_SUCCESS;
}
*compress_mode = *(uint32 *)CURSOR_COLUMN_DATA(cursor, SYS_COMPRESS_COL_ALGO);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_truncate_sys_table(knl_session_t *session, uint32 table_id)
{
knl_dictionary_t dc;
table_t *table = NULL;
status_t status;
rd_table_t redo;
bool32 is_changed = OG_FALSE;
db_get_sys_dc(session, table_id, &dc);
if (OG_SUCCESS != lock_table_directly(session, &dc, session->kernel->attr.ddl_lock_timeout)) {
return OG_ERROR;
}
table = DC_TABLE(&dc);
if (db_table_is_referenced(session, table, OG_TRUE)) {
unlock_tables_directly(session);
OG_THROW_ERROR(ERR_TABLE_IS_REFERENCED);
return OG_ERROR;
}
if (knl_reset_serial_value(session, dc.handle) != OG_SUCCESS) {
unlock_tables_directly(session);
return OG_ERROR;
}
if (dc.type == DICT_TYPE_TABLE || dc.type == DICT_TYPE_TABLE_NOLOGGING) {
if (!db_table_has_segment(session, &dc)) {
unlock_tables_directly(session);
return OG_SUCCESS;
}
}
status = db_truncate_table_prepare(session, &dc, OG_FALSE, &is_changed);
if (status == OG_SUCCESS) {
SYNC_POINT(session, "SP_B1_TRUNCATE_TABLE");
knl_commit(session);
if (db_garbage_segment_handle(session, dc.uid, dc.oid, OG_FALSE) != OG_SUCCESS) {
OG_LOG_DEBUG_ERR("failed to handle garbage segment");
}
SYNC_POINT(session, "SP_B2_TRUNCATE_TABLE");
log_atomic_op_begin(session);
redo.op_type = RD_ALTER_TABLE;
redo.uid = dc.uid;
redo.oid = dc.oid;
if (IS_LOGGING_TABLE_BY_TYPE(dc.type)) {
log_put(session, RD_LOGIC_OPERATION, &redo, sizeof(rd_table_t), LOG_ENTRY_FLAG_NONE);
}
log_atomic_op_end(session);
knl_commit(session);
} else {
knl_rollback(session, NULL);
}
db_update_seg_scn(session, &dc);
unlock_tables_directly(session);
return status;
}
static status_t db_write_index_sysinfo(knl_session_t *session, knl_index_def_t *def, index_t *index,
knl_cursor_t *cursor, knl_dictionary_t *dc)
{
table_t *table = DC_TABLE(dc);
knl_index_desc_t *desc = &index->desc;
desc->is_cons = OG_FALSE;
desc->is_enforced = OG_FALSE;
desc->is_func = OG_FALSE;
if (db_verify_index_def(session, dc, def, desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_write_sysindex(session, cursor, desc) != OG_SUCCESS) {
return OG_ERROR;
}
if (db_update_index_count(session, cursor, &table->desc, OG_TRUE) != OG_SUCCESS) {
return OG_ERROR;
}
if (IS_PART_INDEX(index)) {
if (!IS_COMPART_TABLE(table->part_table) && def->part_def != NULL && def->part_def->is_composite) {
OG_THROW_ERROR(ERR_OPERATIONS_NOT_SUPPORT, "create composite partition index",
"non composite partition table");
return OG_ERROR;
}
if (db_create_part_index(session, cursor, index, def->part_def) != OG_SUCCESS) {
return OG_ERROR;
}
}
return OG_SUCCESS;
}
static status_t db_fill_indexes_paral(knl_session_t *session, knl_dictionary_t *dc, idxpart_paral_ctx_t *paral_ctx,
uint32 paral_num)
{
db_prepare_part_ctx(session, ¶l_num, paral_ctx);
if (paral_ctx->paral_count * paral_ctx->index_cnt > MAX_IDX_PARAL_THREADS) {
paral_ctx->paral_count = MAX_IDX_PARAL_THREADS / paral_ctx->index_cnt;
}
if (idxpart_alloc_resource(session, paral_num, paral_ctx) != OG_SUCCESS) {
idxpart_release_resource(paral_num, paral_ctx);
return OG_ERROR;
}
uint32 working_cnt;
for (;;) {
working_cnt = paral_num;
for (uint32 i = 0; i < paral_num; i++) {
if (!paral_ctx->workers[i].is_working) {
working_cnt--;
}
if (paral_ctx->workers[i].thread.result != OG_SUCCESS) {
OG_THROW_ERROR(ERR_BUILD_INDEX_PARALLEL, paral_ctx->err_msg);
idxpart_release_resource(paral_num, paral_ctx);
return OG_ERROR;
}
}
if (working_cnt == 0) {
break;
}
if (knl_check_session_status(session) != OG_SUCCESS) {
idxpart_release_resource(paral_num, paral_ctx);
return OG_ERROR;
}
cm_sleep(100);
}
idxpart_release_resource(paral_num, paral_ctx);
return OG_SUCCESS;
}
static status_t db_fill_part_indexes(knl_session_t *session, knl_dictionary_t *dc, knl_indexes_def_t *def,
index_t **indexes, uint32 index_cnt)
{
table_t *table = DC_TABLE(dc);
uint32 segment_cnt = 0;
for (uint32 i = 0; i < index_cnt; i++) {
segment_cnt = 0;
if (db_create_all_btree_segments(session, table, indexes[i], &segment_cnt) != OG_SUCCESS) {
return OG_ERROR;
}
}
if (segment_cnt == 0) {
return OG_SUCCESS;
}
idxpart_paral_ctx_t paral_ctx;
errno_t err = memset_sp(¶l_ctx, sizeof(idxpart_paral_ctx_t), 0, sizeof(idxpart_paral_ctx_t));
knl_securec_check(err);
paral_ctx.private_dc = dc;
paral_ctx.indexes = indexes;
paral_ctx.index_cnt = index_cnt;
paral_ctx.part_info.seg_count = segment_cnt;
uint32 paral_num = def->indexes_def[0].parallelism;
if (db_fill_indexes_paral(session, dc, ¶l_ctx, paral_num) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
static status_t db_fill_indexes(knl_session_t *session, knl_table_desc_t *desc, uint32 *index_ids, uint32 index_cnt,
knl_indexes_def_t *def)
{
knl_dictionary_t dc;
if (dc_open_table_private(session, desc->uid, desc->id, &dc) != OG_SUCCESS) {
return OG_ERROR;
}
CM_SAVE_STACK(session->stack);
index_t **indexes = (index_t **)cm_push(session->stack, sizeof(index_t *) * index_cnt);
for (uint32 i = 0; i < index_cnt; i++) {
indexes[i] = dc_find_index_by_id((dc_entity_t *)dc.handle, index_ids[i]);
if (indexes[i] == NULL) {
dc_close_table_private(&dc);
OG_THROW_ERROR(ERR_OBJECT_ID_NOT_EXIST, "index", index_ids[i]);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
dc_load_all_part_segments(session, dc.handle);
if (IS_PART_INDEX(indexes[0])) {
if (db_fill_part_indexes(session, &dc, def, indexes, index_cnt) != OG_SUCCESS) {
dc_close_table_private(&dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
} else {
bool32 need_redo = IS_LOGGING_TABLE_BY_TYPE(dc.type);
knl_part_locate_t part_loc = { 0, 0 };
for (uint32 i = 0; i < index_cnt; i++) {
if (db_create_btree_segment(session, indexes[i], NULL, &indexes[i]->btree, need_redo) != OG_SUCCESS) {
dc_close_table_private(&dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (db_fill_multi_indexes_paral(session, &dc, indexes, index_cnt, def->indexes_def[0].parallelism,
part_loc, def->indexes_def[0].nologging) != OG_SUCCESS) {
dc_close_table_private(&dc);
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
dc_close_table_private(&dc);
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
static void db_alloc_index_ids(dc_entity_t *entity, uint32 *ids, uint32 index_cnt)
{
index_t *index = NULL;
uint8 map[OG_MAX_TABLE_INDEXES];
errno_t err = memset_sp(map, OG_MAX_TABLE_INDEXES, 0, OG_MAX_TABLE_INDEXES);
knl_securec_check(err);
for (uint32 i = 0; i < entity->table.index_set.total_count; i++) {
index = entity->table.index_set.items[i];
map[index->desc.id] = 1;
}
uint32 redy_cnt = 0;
for (uint32 i = 0; i < OG_MAX_TABLE_INDEXES; i++) {
if (map[i] == 0) {
ids[redy_cnt++] = i;
}
if (redy_cnt >= index_cnt) {
break;
}
}
}
status_t db_create_indexes(knl_session_t *session, knl_indexes_def_t *def, knl_dictionary_t *dc)
{
index_t index;
table_t *table = DC_TABLE(dc);
dc_entity_t *entity = DC_ENTITY(dc);
CM_SAVE_STACK(session->stack);
uint32 *index_ids = cm_push(session->stack, sizeof(uint32) * def->index_count);
knl_cursor_t *cursor = knl_push_cursor(session);
db_alloc_index_ids(entity, index_ids, def->index_count);
for (uint32 i = 0; i < def->index_count; i++) {
errno_t ret = memset_sp(&index, sizeof(index_t), 0, sizeof(index_t));
knl_securec_check(ret);
index.entity = entity;
index.desc.id = index_ids[i];
index.desc.is_nologging = def->indexes_def[i].nologging;
if (db_write_index_sysinfo(session, &def->indexes_def[i], &index, cursor, dc) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
}
if (db_fill_indexes(session, &table->desc, index_ids, def->index_count, def) != OG_SUCCESS) {
CM_RESTORE_STACK(session->stack);
return OG_ERROR;
}
CM_RESTORE_STACK(session->stack);
return OG_SUCCESS;
}
status_t db_create_hash_part_index_segment(knl_session_t *session, knl_dictionary_t *dc, uint32 index_id)
{
knl_dictionary_t new_dc;
btree_t *btree = NULL;
index_part_t *index_part = NULL;
if (dc_open_table_private(session, dc->uid, dc->oid, &new_dc) != OG_SUCCESS) {
return OG_ERROR;
}
table_t *table = DC_TABLE(&new_dc);
uint32 partcnt = table->part_table->desc.partcnt;
knl_part_locate_t part_loc = { 0 };
part_loc.part_no = partcnt - 1;
index_t *index = dc_find_index_by_id((dc_entity_t *)new_dc.handle, index_id);
if (index == NULL) {
dc_close_table_private(&new_dc);
OG_THROW_ERROR(ERR_OBJECT_ID_NOT_EXIST, "index", index_id);
return OG_ERROR;
}
index_part = INDEX_GET_PART(index, part_loc.part_no);
if (IS_PARENT_IDXPART(&index_part->desc)) {
index_part = PART_GET_SUBENTITY(index->part_index, index_part->subparts[part_loc.subpart_no]);
}
btree = &index_part->btree;
if (btree_create_part_segment(session, index_part) != OG_SUCCESS) {
dc_close_table_private(&new_dc);
return OG_ERROR;
}
if (IS_SUB_IDXPART(&index_part->desc)) {
if (db_upd_sub_idx_part_entry(session, &index_part->desc, index_part->desc.entry) != OG_SUCCESS) {
btree_drop_part_segment(session, index_part);
dc_close_table_private(&new_dc);
return OG_ERROR;
}
} else {
if (db_upd_idx_part_entry(session, &index_part->desc, index_part->desc.entry) != OG_SUCCESS) {
btree_drop_part_segment(session, index_part);
dc_close_table_private(&new_dc);
return OG_ERROR;
}
}
buf_enter_page(session, index_part->desc.entry, LATCH_MODE_S, ENTER_PAGE_RESIDENT);
btree->segment = BTREE_GET_SEGMENT(session);
btree->buf_ctrl = session->curr_page_ctrl;
bt_put_change_stats(btree);
buf_leave_page(session, OG_FALSE);
SYNC_POINT_GLOBAL_START(OGRAC_DDL_CREATE_HASH_PART_INDEX_BEFORE_WRITE_UNDO_ABORT, NULL, 0);
SYNC_POINT_GLOBAL_END;
if (btree_generate_create_undo(session, index_part->desc.entry, index_part->desc.space_id,
IS_LOGGING_TABLE_BY_TYPE(new_dc.type)) != OG_SUCCESS) {
btree_drop_part_segment(session, index_part);
dc_close_table_private(&new_dc);
return OG_ERROR;
}
SYNC_POINT_GLOBAL_START(OGRAC_DDL_CREATE_HASH_PART_INDEX_AFTER_WRITE_UNDO_ABORT, NULL, 0);
SYNC_POINT_GLOBAL_END;
dc_close_table_private(&new_dc);
return OG_SUCCESS;
}
status_t db_create_index_segment_of_hash_parts(knl_session_t *session,
knl_dictionary_t *dc,
table_t *table)
{
return OG_SUCCESS;
for (uint32 i = 0; i < table->index_set.total_count; i++) {
index_t *index = table->index_set.items[i];
if (!IS_PART_INDEX(index)) {
continue;
}
if (db_create_hash_part_index_segment(session, dc, index->desc.id) != OG_SUCCESS) {
OG_LOG_RUN_ERR("db create hash part index sg fail, i %u, index id %u", i, index->desc.id);
return OG_ERROR;
}
}
return OG_SUCCESS;
}