* This file is part of the oGRAC project.
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
*
* oGRAC is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
*
* ogsql_expr.h
*
*
* IDENTIFICATION
* src/ogsql/node/ogsql_expr.h
*
* -------------------------------------------------------------------------
*/
#ifndef __SQL_EXPR_H__
#define __SQL_EXPR_H__
#include "cm_defs.h"
#include "cm_list.h"
#include "var_inc.h"
#include "cm_lex.h"
#include "ogsql_stmt.h"
#include "ogsql_expr_def.h"
#ifdef __cplusplus
extern "C" {
#endif
static inline og_type_t sql_get_func_arg1_datatype(const expr_node_t *func_node)
{
CM_POINTER3(func_node, func_node->argument, func_node->argument->root);
return func_node->argument->root->datatype;
}
static inline og_type_t sql_get_func_arg2_datatype(const expr_node_t *func_node)
{
CM_POINTER2(func_node, func_node->argument);
CM_POINTER2(func_node->argument->root, func_node->argument->next->root);
return func_node->argument->next->root->datatype;
}
void sql_init_visit_assist(visit_assist_t *visit_ass, sql_stmt_t *stmt, sql_query_t *query);
void sql_set_vst_param(visit_assist_t *v_ast, void *p0, void *p1, void *p2);
const text_t *sql_get_nodetype_text(expr_node_type_t node_type);
typedef status_t (*visit_func_t)(visit_assist_t *va, expr_node_t **node);
status_t visit_expr_node(visit_assist_t *visit_ass, expr_node_t **node, visit_func_t visit_func);
status_t visit_expr_tree(visit_assist_t *visit_ass, expr_tree_t *tree, visit_func_t visit_func);
status_t visit_func_node(visit_assist_t *visit_ass, expr_node_t *node, visit_func_t visit_func);
status_t visit_case_node(visit_assist_t *visit_ass, expr_node_t *node, visit_func_t visit_func);
bool32 sql_expr_tree_equal(sql_stmt_t *stmt, expr_tree_t *tree1, expr_tree_t *tree2, uint32 *tab_map);
status_t sql_get_reserved_value(sql_stmt_t *stmt, expr_node_t *node, variant_t *val);
status_t sql_convert_to_scn(sql_stmt_t *stmt, void *expr, bool32 scn_type, uint64 *scn);
status_t sql_exec_expr_node(sql_stmt_t *stmt, expr_node_t *node, variant_t *result);
bool32 sql_expr_node_exist_table(expr_node_t *node, uint32 table_id);
bool32 sql_expr_node_exist_ancestor_table(expr_node_t *node, uint32 table_id, uint32 is_ancestor);
#define sql_expr_exist_table(expr, table_id) sql_expr_node_exist_table((expr)->root, table_id)
#define sql_expr_exist_ancestor_table(expr, table_id, is_ancestor) \
sql_expr_node_exist_ancestor_table((expr)->root, table_id, is_ancestor)
bool32 sql_is_const_expr_node(const expr_node_t *node);
bool32 sql_is_const_expr_tree(expr_tree_t *expr);
bool32 sql_expr_tree_in_tab_list(sql_array_t *tables, expr_tree_t *expr_tree, bool32 use_remote_id, bool32 *exist_col);
status_t sql_try_optimize_const_expr(sql_stmt_t *stmt, expr_node_t *node);
status_t sql_get_serial_value(sql_stmt_t *stmt, knl_dictionary_t *dc, variant_t *value);
status_t sql_expr_tree_walker(sql_stmt_t *stmt, expr_tree_t *expr_tree,
status_t (*fetch)(sql_stmt_t *stmt, expr_node_t *node, void *context), void *context);
status_t sql_expr_node_walker(sql_stmt_t *stmt, expr_node_t *node,
status_t (*fetch)(sql_stmt_t *stmt, expr_node_t *node, void *context), void *context);
status_t sql_exec_oper(sql_stmt_t *stmt, expr_node_t *node, variant_t *result);
void sql_copy_first_exec_var(sql_stmt_t *stmt, variant_t *src, variant_t *dst);
static status_t inline sql_exec_expr(sql_stmt_t *stmt, expr_tree_t *expr, variant_t *result)
{
return sql_exec_expr_node(stmt, expr->root, result);
}
static inline uint32 sql_expr_list_len(expr_tree_t *list)
{
uint32 len = 1;
while (list->next != NULL) {
len++;
list = list->next;
}
return len;
}
static inline expr_tree_t *sql_expr_list_last(expr_tree_t *list)
{
expr_tree_t *expr = list;
while (expr->next != NULL) {
expr = expr->next;
}
return expr;
}
static inline status_t sql_compare_expr(sql_stmt_t *stmt, expr_tree_t *expr1, expr_tree_t *expr2, int32 *result)
{
variant_t var1;
variant_t var2;
if (sql_exec_expr(stmt, expr1, &var1) != OG_SUCCESS) {
return OG_ERROR;
}
if (sql_exec_expr(stmt, expr2, &var2) != OG_SUCCESS) {
return OG_ERROR;
}
if (sql_compare_variant(stmt, &var1, &var2, result) != OG_SUCCESS) {
return OG_ERROR;
}
return OG_SUCCESS;
}
status_t sql_exec_default(void *stmt, void *default_expr, variant_t *val);
status_t sql_get_func_index_expr_size(knl_handle_t session, text_t *default_text, typmode_t *typmode);
bool32 sql_compare_index_expr(knl_handle_t session, text_t *func_text1, text_t *func_text2);
status_t sql_exec_index_col_func(knl_handle_t sess, knl_handle_t knl_cursor, og_type_t datatype, void *expr,
variant_t *result, bool32 is_new);
* static-checking */
static inline bool32 sql_is_skipped_expr(const expr_tree_t *expr)
{
if (TREE_IS_RES_NULL(expr) || TREE_IS_RES_DEFAULT(expr)) {
return OG_TRUE;
}
if (TREE_IS_BINDING_PARAM(expr)) {
return OG_TRUE;
}
if (OG_TYPE_UNKNOWN == TREE_DATATYPE(expr)) {
return OG_TRUE;
}
return OG_FALSE;
}
status_t sql_exec_concat(sql_stmt_t *stmt, variant_t *l_var, variant_t *r_var, variant_t *result);
status_t sql_exec_unary(expr_node_t *node, variant_t *var);
static inline bool32 sql_is_single_column(expr_node_t *expr_node)
{
return (expr_node->type == EXPR_NODE_COLUMN);
}
static inline bool32 sql_is_single_const_or_param(expr_node_t *expr_node)
{
return (bool32)(NODE_IS_CONST(expr_node) || NODE_IS_PARAM(expr_node) || NODE_IS_CSR_PARAM(expr_node));
}
static inline bool32 sql_is_single_const(expr_node_t *expr_node)
{
return NODE_IS_CONST(expr_node);
}
static inline bool32 sql_expr_tree_belong_tab_list(sql_array_t *tables, expr_tree_t *expr_tree, bool32 use_remote_id)
{
bool32 exist_col = OG_FALSE;
return (bool32)(sql_expr_tree_in_tab_list(tables, expr_tree, use_remote_id, &exist_col) && exist_col);
}
static inline void sql_convert_lob_type(expr_node_t *node, og_type_t datatype)
{
if (datatype == OG_TYPE_CLOB || datatype == OG_TYPE_IMAGE) {
node->typmod.datatype = OG_TYPE_STRING;
} else if (datatype == OG_TYPE_BLOB) {
node->typmod.datatype = OG_TYPE_RAW;
}
}
status_t sql_clone_expr_tree(void *ogx, expr_tree_t *src_expr_tree, expr_tree_t **dest_expr_tree,
ga_alloc_func_t alloc_mem_func);
status_t sql_clone_expr_node(void *ogx, expr_node_t *src_node, expr_node_t **dest_expr_node,
ga_alloc_func_t alloc_mem_func);
status_t sql_clone_var_column(void *ogx, var_column_t *src, var_column_t *dest_col, ga_alloc_func_t alloc_mem_func);
bool32 sql_expr_node_equal(sql_stmt_t *stmt, expr_node_t *node1, expr_node_t *node2, uint32 *table_map);
status_t sql_get_lob_value_from_knl(sql_stmt_t *stmt, variant_t *res);
status_t sql_get_lob_value_from_vm(sql_stmt_t *stmt, variant_t *result);
status_t sql_get_lob_value(sql_stmt_t *stmt, variant_t *result);
status_t sql_get_lob_value_from_normal(sql_stmt_t *stmt, variant_t *res);
status_t sql_get_expr_datatype(sql_stmt_t *stmt, expr_tree_t *expr, og_type_t *type);
status_t sql_get_param_value(sql_stmt_t *stmt, uint32 id, variant_t *result);
status_t sql_get_expr_unique_table(sql_stmt_t *stmt, expr_node_t *node, uint16 *tab, uint32 *ancestor);
status_t sql_get_subarray_to_value(array_assist_t *array_ass, vm_lob_t *src, int32 start, int32 end, og_type_t type,
variant_t *value);
status_t sql_get_element_to_value(sql_stmt_t *stmt, array_assist_t *array_ass, vm_lob_t *src, int32 start, int32 end,
og_type_t type, variant_t *value);
status_t sql_exec_array_element(sql_stmt_t *stmt, array_assist_t *aa, uint32 subscript, variant_t *element_val,
bool32 last, vm_lob_t *vlob);
expr_node_t *sql_find_column_in_func(expr_node_t *node);
extern cols_used_t g_cols_used_init;
static inline void init_cols_used(cols_used_t *cols_used)
{
uint32 loop;
*cols_used = g_cols_used_init;
cols_used->collect_sub_select = OG_TRUE;
for (loop = 0; loop < RELATION_LEVELS; ++loop) {
biqueue_init(&cols_used->cols_que[loop]);
}
}
void sql_collect_cols_in_expr_tree(expr_tree_t *tree, cols_used_t *used_cols);
void sql_collect_cols_in_expr_node(expr_node_t *node, cols_used_t *used_cols);
status_t add_node_2_parent_ref_core(sql_stmt_t *stmt, sql_query_t *query, expr_node_t *node, uint32 tab,
uint32 temp_ancestor);
void sql_collect_cols_in_cond(void *cond_node, cols_used_t *used_cols);
static inline expr_node_t *sql_any_self_col_node(cols_used_t *cols_used)
{
expr_node_t *col_node = OBJECT_OF(expr_node_t, biqueue_first(&cols_used->cols_que[SELF_IDX]));
return col_node;
}
static inline bool32 sql_is_same_tab(expr_node_t *l_col, expr_node_t *r_col, uint32 *tab1, uint32 *tab2)
{
uint32 l_tab = TAB_OF_NODE(l_col);
uint32 r_tab = TAB_OF_NODE(r_col);
if (tab1 != NULL) {
*tab1 = l_tab;
}
if (tab2 != NULL) {
*tab2 = r_tab;
}
return (l_tab == r_tab);
}
static inline bool32 sql_can_equal_used_by_hash(cols_used_t *l_cols_used, cols_used_t *r_cols_used, uint32 *tab1,
uint32 *tab2)
{
if (HAS_DYNAMIC_SUBSLCT(l_cols_used) || HAS_DYNAMIC_SUBSLCT(r_cols_used)) {
return OG_FALSE;
}
if (!HAS_ONLY_SELF_COLS(l_cols_used->flags) || !HAS_ONLY_SELF_COLS(r_cols_used->flags) ||
HAS_DIFF_TABS(l_cols_used, SELF_IDX) || HAS_DIFF_TABS(r_cols_used, SELF_IDX)) {
return OG_FALSE;
}
if (HAS_ROWNUM(l_cols_used) || HAS_PRIOR(l_cols_used) || HAS_ROWNUM(r_cols_used) || HAS_PRIOR(r_cols_used)) {
return OG_FALSE;
}
expr_node_t *l_col = sql_any_self_col_node(l_cols_used);
expr_node_t *r_col = sql_any_self_col_node(r_cols_used);
return !sql_is_same_tab(l_col, r_col, tab1, tab2);
}
static inline bool32 sql_can_equal_used_by_hash2(cols_used_t *l_cols_used, cols_used_t *r_cols_used)
{
uint32 l_idx;
uint32 r_idx;
if ((!HAS_ONLY_SELF_COLS(l_cols_used->flags) || !HAS_ONLY_PARENT_COLS(r_cols_used->flags)) &&
(!HAS_ONLY_SELF_COLS(r_cols_used->flags) || !HAS_ONLY_PARENT_COLS(l_cols_used->flags))) {
return OG_FALSE;
}
l_idx = HAS_SELF_COLS(l_cols_used->flags) ? (r_idx = PARENT_IDX, SELF_IDX) : (r_idx = SELF_IDX, PARENT_IDX);
uint8 left_ret = HAS_DIFF_TABS(l_cols_used, l_idx);
uint8 right_ret = HAS_DIFF_TABS(r_cols_used, r_idx);
return (bool32)(!left_ret && !right_ret);
}
status_t sql_check_not_support_reserved_value_shard(reserved_wid_t type);
static inline status_t sql_generate_origin_ref(sql_stmt_t *stmt, rs_column_t *rs_col, expr_node_t **origin_ref)
{
SAVE_AND_RESET_NODE_STACK(stmt);
if (rs_col->type == RS_COL_CALC) {
OG_RETURN_IFERR(sql_clone_expr_node(stmt->context, rs_col->expr->root, origin_ref, sql_alloc_mem));
} else {
OG_RETURN_IFERR(sql_alloc_mem(stmt->context, sizeof(expr_node_t), (void **)origin_ref));
(*origin_ref)->type = EXPR_NODE_COLUMN;
(*origin_ref)->typmod = rs_col->typmod;
OG_RETURN_IFERR(
sql_clone_var_column(stmt->context, &rs_col->v_col, &((*origin_ref)->value.v_col), sql_alloc_mem));
}
SQL_RESTORE_NODE_STACK(stmt);
return OG_SUCCESS;
}
static inline expr_node_t *sql_get_origin_ref(expr_node_t *expr_node)
{
if (expr_node->type != EXPR_NODE_GROUP) {
return expr_node;
}
return sql_get_origin_ref((expr_node_t *)expr_node->value.v_vm_col.origin_ref);
}
static inline void sql_set_expr_node_ancestor(expr_node_t *expr_node, uint32 ancestor)
{
if (expr_node->type == EXPR_NODE_COLUMN) {
NODE_ANCESTOR(expr_node) = ancestor;
} else if (expr_node->type == EXPR_NODE_GROUP) {
NODE_VM_ANCESTOR(expr_node) = ancestor;
} else if (expr_node->type == EXPR_NODE_RESERVED && (expr_node)->value.v_int == RES_WORD_ROWID) {
ROWID_NODE_ANCESTOR(expr_node) = ancestor;
}
}
static inline status_t sql_set_group_expr_node(sql_stmt_t *stmt, expr_node_t *node, uint32 id, uint32 group_id,
uint32 ancestor, expr_node_t *origin_ref)
{
SAVE_AND_RESET_NODE_STACK(stmt);
if (origin_ref == NULL) {
OG_RETURN_IFERR(sql_clone_expr_node(stmt->context, node, &origin_ref, sql_alloc_mem));
}
node->type = EXPR_NODE_GROUP;
node->value.type = OG_TYPE_INTEGER;
VALUE_PTR(var_vm_col_t, &node->value)->id = (uint16)id;
VALUE_PTR(var_vm_col_t, &node->value)->group_id = (uint16)group_id;
VALUE_PTR(var_vm_col_t, &node->value)->ancestor = ancestor;
VALUE_PTR(var_vm_col_t, &node->value)->is_ddm_col = OG_FALSE;
VALUE_PTR(var_vm_col_t, &node->value)->origin_ref = origin_ref;
if ((origin_ref->type == EXPR_NODE_COLUMN) && (origin_ref->value.v_col.is_ddm_col == OG_TRUE)) {
VALUE_PTR(var_vm_col_t, &node->value)->is_ddm_col = OG_TRUE;
origin_ref->value.v_col.is_ddm_col = OG_FALSE;
}
SQL_RESTORE_NODE_STACK(stmt);
return OG_SUCCESS;
}
static inline status_t sql_slct_add_ref_node(void *owner, expr_node_t *node, ga_alloc_func_t alloc_mem_func)
{
if (node->type != EXPR_NODE_SELECT) {
return OG_SUCCESS;
}
sql_select_t *slct = (sql_select_t *)node->value.v_obj.ptr;
if (slct->ref_nodes == NULL) {
OG_RETURN_IFERR(alloc_mem_func(owner, sizeof(galist_t), (void **)&slct->ref_nodes));
cm_galist_init(slct->ref_nodes, owner, alloc_mem_func);
}
return cm_galist_insert(slct->ref_nodes, node);
}
static inline void sql_slct_del_ref_node(sql_stmt_t *stmt, expr_node_t *node)
{
if (node->type != EXPR_NODE_SELECT) {
return;
}
sql_select_t *slct = (sql_select_t *)node->value.v_obj.ptr;
if (slct->ref_nodes != NULL) {
for (uint32 i = 0; i < slct->ref_nodes->count;) {
if (node == cm_galist_get(slct->ref_nodes, i)) {
cm_galist_delete(slct->ref_nodes, i);
continue;
}
i++;
}
}
return;
}
static inline status_t sql_modify_ref_nodes_subslct(sql_stmt_t *stmt, sql_select_t *old_slct, sql_select_t *new_slct)
{
if (old_slct->ref_nodes == NULL) {
return OG_SUCCESS;
}
if (new_slct->ref_nodes == NULL) {
OG_RETURN_IFERR(sql_alloc_mem(stmt->context, sizeof(galist_t), (void **)&new_slct->ref_nodes));
cm_galist_init(new_slct->ref_nodes, stmt->context, sql_alloc_mem);
}
expr_node_t *node = NULL;
for (uint32 i = 0; i < old_slct->ref_nodes->count; i++) {
node = (expr_node_t *)cm_galist_get(old_slct->ref_nodes, i);
if (node->type != EXPR_NODE_SELECT) {
continue;
}
node->value.v_obj.ptr = new_slct;
OG_RETURN_IFERR(cm_galist_insert(new_slct->ref_nodes, node));
}
return OG_SUCCESS;
}
status_t sql_exec_concat_lob_value(sql_stmt_t *stmt, const char *buf, uint32 size, vm_lob_t *vlob);
status_t sql_get_sequence_value(sql_stmt_t *stmt, var_seq_t *vseq, variant_t *val);
status_t sql_create_rowid_expr(sql_stmt_t *stmt, uint32 tab, expr_tree_t **expr);
extern node_func_tab_t *g_expr_calc_funcs[];
static inline node_func_tab_t *sql_get_node_func(sql_node_type_t type)
{
return &g_expr_calc_funcs[(type / EXPR_NODE_CONST)][(type % EXPR_NODE_CONST)];
}
static inline status_t sql_get_expr_node_value(sql_stmt_t *stmt, expr_node_t *node, variant_t *result)
{
return sql_get_node_func((sql_node_type_t)node->type)->invoke(stmt, node, result);
}
static inline var_address_pair_t *sql_get_last_addr_pair(expr_node_t *addr)
{
galist_t *pairs = addr->value.v_address.pairs;
if (pairs->count == 0) {
return NULL;
}
return (var_address_pair_t *)cm_galist_get(pairs, pairs->count - 1);
}
static inline bool32 sql_pair_type_is_plvar(expr_node_t *node)
{
CM_ASSERT(node->type == EXPR_NODE_V_ADDR);
return (node->value.v_address.pairs->count == 1);
}
bool32 chk_has_sharding_tab(sql_stmt_t *stmt);
status_t sql_clone_text(void *ogx, text_t *src, text_t *dest, ga_alloc_func_t alloc_mem_func);
status_t sql_set_pl_dc_for_user_func(void *verify_in, expr_node_t *node, pointer_t pl_dc_in);
var_udo_t *sql_node_get_obj(expr_node_t *node);
#ifdef __cplusplus
}
#endif
#endif