diff --git a/deps/oblib/src/lib/ob_name_def.h b/deps/oblib/src/lib/ob_name_def.h index f0ad312de3..e9e9eb2689 100644 --- a/deps/oblib/src/lib/ob_name_def.h +++ b/deps/oblib/src/lib/ob_name_def.h @@ -1003,6 +1003,7 @@ #define N_JSON_EQUAL "json_equal" #define N_JSON_QUERY "json_query" #define N_JSON_EXISTS "json_exists" +#define N_JSON_OBJECT_STAR "json_object_star" #define N_POINT "point" #define N_LINESTRING "linestring" diff --git a/src/sql/engine/basic/ob_json_table_op.cpp b/src/sql/engine/basic/ob_json_table_op.cpp index b06a46b70a..22fd0f09c9 100644 --- a/src/sql/engine/basic/ob_json_table_op.cpp +++ b/src/sql/engine/basic/ob_json_table_op.cpp @@ -850,8 +850,7 @@ int JtFuncHelpler::cast_json_to_res(JtScanCtx* ctx, ObIJsonBase* js_val, JtColNo : ctx->spec_ptr_->value_expr_->datum_meta_.cs_type_; ObCollationLevel dst_coll_level = col_info.data_type_.get_collation_level(); - if (OB_ISNULL(js_val) - || (lib::is_mysql_mode() && js_val->json_type() == common::ObJsonNodeType::J_NULL)) { + if (OB_ISNULL(js_val)) { res.set_null(); } else { switch (dst_type) { @@ -2338,7 +2337,7 @@ int JtColNode::get_next_row(ObIJsonBase* in, JtScanCtx* ctx, bool& is_null_value } } else if (col_type == COL_TYPE_EXISTS || col_type == COL_TYPE_QUERY || col_type == COL_TYPE_VALUE) { if (!need_cast_res) { - } else if (is_null_result_ || (curr_ && curr_->json_type() == ObJsonNodeType::J_NULL && !curr_->is_real_json_null(curr_))) { + } else if (is_null_result_ || (curr_ && curr_->json_type() == ObJsonNodeType::J_NULL && (!curr_->is_real_json_null(curr_) || lib::is_mysql_mode()))) { if (!need_pro_emtpy) { col_expr->locate_datum_for_write(*ctx->eval_ctx_).set_null(); } else if (OB_FAIL(set_val_on_empty(ctx, need_cast_res))) { diff --git a/src/sql/engine/expr/ob_expr_eval_functions.cpp b/src/sql/engine/expr/ob_expr_eval_functions.cpp index c6fdd10432..3307741410 100644 --- a/src/sql/engine/expr/ob_expr_eval_functions.cpp +++ b/src/sql/engine/expr/ob_expr_eval_functions.cpp @@ -1064,7 +1064,7 @@ static ObExpr::EvalFunc g_expr_eval_functions[] = { NULL, //ObExprUpdateXml::eval_mysql_update_xml /* 629 */ NULL, //ObExprXmlSequence::eval_xml_sequence /* 630 */ NULL, //ObExprJsonAppend::eval_json_array_append /* 631 */ - NULL, //ObExprJsonObjectStar::eval_ora_json_object_star /* 632 */ + ObExprJsonObjectStar::eval_ora_json_object_star /* 632 */ }; static ObExpr::EvalBatchFunc g_expr_eval_batch_functions[] = { diff --git a/src/sql/engine/expr/ob_expr_json_object.cpp b/src/sql/engine/expr/ob_expr_json_object.cpp index 83df15f357..69ad1c5439 100644 --- a/src/sql/engine/expr/ob_expr_json_object.cpp +++ b/src/sql/engine/expr/ob_expr_json_object.cpp @@ -481,5 +481,56 @@ int ObExprJsonObject::eval_option_clause_value(ObExpr *expr, return ret; } +ObExprJsonObjectStar::ObExprJsonObjectStar(ObIAllocator &alloc) + : ObFuncExprOperator(alloc, T_FUN_SYS_JSON_OBJECT_WILD_STAR, N_JSON_OBJECT_STAR, OCCUR_AS_PAIR, VALID_FOR_GENERATED_COL, NOT_ROW_DIMENSION) +{ +} + +ObExprJsonObjectStar::~ObExprJsonObjectStar() +{ +} + +int ObExprJsonObjectStar::calc_result_typeN(ObExprResType& type, + ObExprResType* types_stack, + int64_t param_num, + ObExprTypeCtx& type_ctx) const +{ + INIT_SUCC(ret); + if (param_num != 1) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("incorrect num of param", K(ret)); + } else { + types_stack[0].set_calc_type(types_stack[0].get_type()); + types_stack[0].set_calc_collation_type(types_stack[0].get_collation_type()); + ObExprResType dst_type; + dst_type.set_type(ObObjType::ObVarcharType); + dst_type.set_collation_type(CS_TYPE_INVALID); + dst_type.set_full_length(4000, 1); + if (OB_FAIL(ObJsonExprHelper::set_dest_type(types_stack[0], type, dst_type, type_ctx))) { + LOG_WARN("set dest type failed", K(ret)); + } else { + type.set_calc_collation_type(type.get_collation_type()); + } + } + return ret; +} + +int ObExprJsonObjectStar::eval_ora_json_object_star(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res) +{ + INIT_SUCC(ret); + ret = OB_ERR_UNEXPECTED; + LOG_WARN("can not be use this expr, should transform to real column", K(ret)); + return ret; +} + +int ObExprJsonObjectStar::cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, + ObExpr &rt_expr) const +{ + UNUSED(expr_cg_ctx); + UNUSED(raw_expr); + rt_expr.eval_func_ = eval_ora_json_object_star; + return OB_SUCCESS; +} + } // sql } // oceanbase \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_json_object.h b/src/sql/engine/expr/ob_expr_json_object.h index da17ad13ed..fae3c16195 100644 --- a/src/sql/engine/expr/ob_expr_json_object.h +++ b/src/sql/engine/expr/ob_expr_json_object.h @@ -68,6 +68,21 @@ private: DISALLOW_COPY_AND_ASSIGN(ObExprJsonObject); }; +// mock inner expr as json object with star node +class ObExprJsonObjectStar : public ObFuncExprOperator +{ +public: + explicit ObExprJsonObjectStar(common::ObIAllocator &alloc); + virtual ~ObExprJsonObjectStar(); + virtual int calc_result_typeN(ObExprResType& type, ObExprResType* types, int64_t param_num, + common::ObExprTypeCtx& type_ctx) const override; + static int eval_ora_json_object_star(const ObExpr &expr, ObEvalCtx &ctx, ObDatum &res); + virtual int cg_expr(ObExprCGCtx &expr_cg_ctx, const ObRawExpr &raw_expr, ObExpr &rt_expr) const override; + +private: + DISALLOW_COPY_AND_ASSIGN(ObExprJsonObjectStar); +}; + } //sql } //oceanbase #endif //OCEANBASE_SQL_OB_EXPR_JSON_OBJECT_H_ \ No newline at end of file diff --git a/src/sql/engine/expr/ob_expr_json_value.cpp b/src/sql/engine/expr/ob_expr_json_value.cpp index 9856bc98ba..8600d03cd5 100644 --- a/src/sql/engine/expr/ob_expr_json_value.cpp +++ b/src/sql/engine/expr/ob_expr_json_value.cpp @@ -1842,7 +1842,7 @@ int ObExprJsonValue::get_on_mismatch(const ObExpr &expr, LOG_WARN("mismatch option add fail", K(ret)); } } else if (option_type >= OB_JSON_TYPE_MISSING_DATA && - option_type <= OB_JSON_TYPE_IMPLICIT) { + option_type <= OB_JSON_TYPE_DOT) { uint8_t old_value = 0; switch(option_type) { case OB_JSON_TYPE_MISSING_DATA :{ diff --git a/src/sql/engine/expr/ob_expr_json_value.h b/src/sql/engine/expr/ob_expr_json_value.h index c519a6bfee..3e98904aae 100644 --- a/src/sql/engine/expr/ob_expr_json_value.h +++ b/src/sql/engine/expr/ob_expr_json_value.h @@ -175,6 +175,7 @@ private: const static uint8_t OB_JSON_TYPE_EXTRA_DATA = 5; const static uint8_t OB_JSON_TYPE_TYPE_ERROR = 6; const static uint8_t OB_JSON_TYPE_IMPLICIT = 7; + const static uint8_t OB_JSON_TYPE_DOT = 8; const static uint8_t json_doc_id = 0; const static uint8_t json_path_id = 1; diff --git a/src/sql/engine/expr/ob_expr_operator_factory.cpp b/src/sql/engine/expr/ob_expr_operator_factory.cpp index 376ac93968..c52e9f1a55 100644 --- a/src/sql/engine/expr/ob_expr_operator_factory.cpp +++ b/src/sql/engine/expr/ob_expr_operator_factory.cpp @@ -1309,6 +1309,7 @@ void ObExprOperatorFactory::register_expr_operators() REG_OP_ORCL(ObExprXmlcast); REG_OP_ORCL(ObExprUpdateXml); REG_OP_ORCL(ObExprTempTableSSID); + REG_OP_ORCL(ObExprJsonObjectStar); } bool ObExprOperatorFactory::is_expr_op_type_valid(ObExprOperatorType type) diff --git a/src/sql/ob_sql_utils.cpp b/src/sql/ob_sql_utils.cpp index cec96cd61b..445e89f191 100644 --- a/src/sql/ob_sql_utils.cpp +++ b/src/sql/ob_sql_utils.cpp @@ -2467,6 +2467,21 @@ int FastUdtExprChecker::add_expr(ObRawExpr *&expr) return ret; } +JsonObjectStarChecker::JsonObjectStarChecker(common::ObIArray &rel_array) + : RelExprCheckerBase(), rel_array_(rel_array), init_size_(rel_array.count()) +{ + +} + +int JsonObjectStarChecker::add_expr(ObRawExpr *&expr) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(ObTransformUtils::extract_json_object_exprs(expr, rel_array_))) { + LOG_WARN("failed to push back expr", K(ret)); + } + return ret; +} + //used for C module bool check_stack_overflow_c() { diff --git a/src/sql/ob_sql_utils.h b/src/sql/ob_sql_utils.h index afc2610f83..4da17cd8a5 100644 --- a/src/sql/ob_sql_utils.h +++ b/src/sql/ob_sql_utils.h @@ -771,6 +771,17 @@ private: int64_t init_size_; }; +class JsonObjectStarChecker : public RelExprCheckerBase +{ +public: + JsonObjectStarChecker(common::ObIArray &rel_array); + virtual ~JsonObjectStarChecker() {} + int add_expr(ObRawExpr *&expr); +private: + common::ObIArray &rel_array_; + int64_t init_size_; +}; + struct ObSqlTraits { char sql_id_[common::OB_MAX_SQL_ID_LENGTH + 1];// sql id //最后一个字节存放'\0' diff --git a/src/sql/resolver/dml/ob_dml_resolver.cpp b/src/sql/resolver/dml/ob_dml_resolver.cpp index 895f1bd234..1b772dcba6 100755 --- a/src/sql/resolver/dml/ob_dml_resolver.cpp +++ b/src/sql/resolver/dml/ob_dml_resolver.cpp @@ -207,148 +207,12 @@ int ObDMLResolver::create_joined_table_item( return ret; } -int ObDMLResolver::expand_star_in_json_object(ParseNode *node, common::ObIAllocator &allocator, int64_t pos, int64_t& col_num) -{ - INIT_SUCC(ret); - ObSEArray columns_list; - ObVector t_vec; - TableItem *table_item = NULL; - ParseNode **child_vec = NULL; - bool tab_has_alias = false; - ObString tab_name; - int64_t num_child = 0; - bool all_tab = true; - col_num = 0; - - if (OB_ISNULL(node)) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("node should not be null", K(ret)); - } else { - num_child = node->num_child_; - } - - if (OB_SUCC(ret) && OB_NOT_NULL(node->children_[pos]) && OB_NOT_NULL(node->children_[pos]->children_[1])) { - tab_name.assign_ptr(node->children_[pos]->children_[1]->str_value_, node->children_[pos]->children_[1]->str_len_); - all_tab = false; - } - - if (OB_SUCC(ret)) { - if (OB_FAIL(get_target_column_list(columns_list, tab_name, all_tab, tab_has_alias, table_item))) { - LOG_WARN("parse column fail"); - } else { - int64_t num = columns_list.count(); - if (OB_ISNULL(table_item)) { - ret = OB_ERR_KEY_COLUMN_DOES_NOT_EXITS; - LOG_USER_ERROR(OB_ERR_KEY_COLUMN_DOES_NOT_EXITS, tab_name.length(), tab_name.ptr()); - } else if (num == 0 || (3 * num + num_child - 1) <= 0) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("column_list size is invalid", K(ret)); - } else { - col_num = num; - int64_t alloc_size = sizeof(ParseNode *) * (3 * num + num_child - 1); - if (OB_ISNULL(child_vec = static_cast(allocator.alloc(alloc_size)))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); - } - - for (int j = 0; OB_SUCC(ret) && j < num_child; j += 3) { - if (j == pos) { - for (int i = 0; OB_SUCC(ret) && i < num; i ++) { - ObString col_name(columns_list.at(i).column_name_.length(), columns_list.at(i).column_name_.ptr()); - if (OB_FAIL(add_column_expr_for_json_object_node(node, allocator, t_vec, col_name, tab_name))) { - LOG_WARN("json object star node parse fail", K(ret)); - } - } - } else { - if (OB_FAIL(t_vec.push_back(node->children_[j]))) { - LOG_WARN("vector push back failed", K(ret)); - } else if ((j + 1) < num_child && OB_FAIL(t_vec.push_back(node->children_[j + 1]))) { - LOG_WARN("vector push back failed", K(ret)); - } else if ((j + 2) < num_child && OB_FAIL(t_vec.push_back(node->children_[j + 2]))) { - LOG_WARN("vector push back failed", K(ret)); - } - } - } - if (OB_SUCC(ret)) { - node->num_child_ = 3 * num + num_child - 3; - for (int64_t i = 0; i < node->num_child_; i++) { - child_vec[i] = t_vec.at(i); - } - node->children_ = child_vec; - } - } - } - } - return ret; -} - -int ObDMLResolver::add_column_expr_for_json_object_node(ParseNode *node, - common::ObIAllocator &allocator, - ObVector &t_vec, - ObString col_name, - ObString tab_name) -{ - INIT_SUCC(ret); - ParseNode *key_node = NULL; // key node - ParseNode *val_node = NULL; // value node - ParseNode *tab_node = NULL; // tab node if exist - ParseNode *format_node = NULL; // format json node - - if (OB_ISNULL(key_node = static_cast(allocator.alloc(sizeof(ParseNode))))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); - } else { - key_node = new(key_node) ParseNode; - if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(allocator, col_name, key_node, T_CHAR))) { - LOG_WARN("key node create fail", K(ret)); - } else if (OB_FAIL(t_vec.push_back(key_node))) { - LOG_WARN("vector push back failed", K(ret)); - } - } - if (OB_FAIL(ret)) { - } else if (OB_ISNULL(val_node = static_cast(allocator.alloc(sizeof(ParseNode))))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); - } else { - val_node = new(val_node) ParseNode; - if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(allocator, col_name, val_node, T_COLUMN_REF))) { - LOG_WARN("value node create fail", K(ret)); - } else { - if (OB_NOT_NULL(tab_name.ptr())) { - if (OB_ISNULL(tab_node = static_cast(allocator.alloc(sizeof(ParseNode))))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); - } else { - // table_node - tab_node = new(tab_node) ParseNode; - if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(allocator, tab_name, tab_node, T_CHAR))) { - LOG_WARN("key node create fail", K(ret)); - } else { - val_node->children_[1] = tab_node; - } - } - } - if (OB_SUCC(ret) && OB_FAIL(t_vec.push_back(val_node))) { - LOG_WARN("vector push back failed", K(ret)); - } - } - } - if (OB_FAIL(ret)) { - } else if (OB_ISNULL(format_node = static_cast(allocator.alloc(sizeof(ParseNode))))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); - } else { - format_node = new(format_node) ParseNode; - if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(allocator, "", format_node, T_INT))) { - LOG_WARN("format value node create fail", K(ret)); - } else if (OB_FAIL(t_vec.push_back(format_node))) { - LOG_WARN("vector push back failed", K(ret)); - } - } - return ret; -} //only_is_json: 1 is json & json type ; 0 is json; 2 json type -int ObDMLResolver::check_is_json_constraint(common::ObIAllocator &allocator, ParseNode *col_node, bool& format_json, int8_t only_is_json) +int ObDMLResolver::check_is_json_constraint(common::ObIAllocator &allocator, + ParseNode *col_node, + bool& is_json_cst, + bool& is_json_type, + int8_t only_is_json) { INIT_SUCC(ret); ParseNode *tmp_node = NULL; @@ -413,7 +277,7 @@ int ObDMLResolver::check_is_json_constraint(common::ObIAllocator &allocator, Par } } - if (OB_SUCC(ret) && check_valid && OB_FAIL(ObDMLResolver::check_column_json_type(tmp_node, format_json, only_is_json))) { + if (OB_SUCC(ret) && check_valid && OB_FAIL(ObDMLResolver::check_column_json_type(tmp_node, is_json_cst, is_json_type, only_is_json))) { LOG_WARN("fail to check is_json", K(ret)); } return ret; @@ -421,162 +285,148 @@ int ObDMLResolver::check_is_json_constraint(common::ObIAllocator &allocator, Par //const_cast(&node) // process is json constraint for: json_array, json_object, json_arraragg, json_objectagg -int ObDMLResolver::pre_process_json_object_contain_star(ParseNode *node, common::ObIAllocator &allocator) +int ObDMLResolver::pre_process_json_expr_constraint(ParseNode *node, common::ObIAllocator &allocator) +{ + INIT_SUCC(ret); + if ((node->type_ == T_FUN_SYS_JSON_OBJECT || node->type_ == T_FUN_SYS_JSON_ARRAY) + && OB_FAIL(process_json_object_array_node(node, allocator))) { + LOG_WARN("fail to process json object & array with json constraint", K(ret)); + } else if ((node->type_ == T_FUN_ORA_JSON_ARRAYAGG || node->type_ == T_FUN_ORA_JSON_OBJECTAGG) + && OB_FAIL(process_json_agg_node(node, allocator))) { + LOG_WARN("fail to process json object & array agg", K(ret)); + } + return ret; +} + +int ObDMLResolver::process_json_object_array_node(ParseNode *node, common::ObIAllocator &allocator) +{ + INIT_SUCC(ret); + ParseNode *cur_node = NULL; // current node in iter + ParseNode *param_node = NULL; // first param node + ParseNode* format_node = NULL; + ParseNode* value_node = NULL; + ObJsonBuffer sql_str(&allocator); + + param_node = node->children_[0]; + bool is_object = node->type_ == T_FUN_SYS_JSON_OBJECT; + CK (OB_NOT_NULL(param_node)); + // json_array child:[i]->json_data, [i+1]->format_json + // json_object child: [i]->json_key, [i+1]->json_data, [i+2]->format_json + int8_t step = is_object ? 3 : 2; + for (int i = 0; OB_SUCC(ret) && i + (step - 1) < param_node->num_child_; i += step) { + // Singular: parse format json parameter + // first judge format json is or not true, true then pass + // false then check whether has is json constraint in this col , or set format json is true + format_node = param_node->children_[i + step - 1]; + value_node = param_node->children_[i + step - 2]; + cur_node = param_node->children_[i]; + if (is_object && OB_NOT_NULL(value_node) + && value_node->type_ == T_NULL && value_node->value_ == 2) { + value_node = cur_node; + } + if (OB_NOT_NULL(cur_node) && cur_node->type_ == T_COLUMN_REF + && OB_NOT_NULL(cur_node->children_[2]) + && cur_node->children_[2]->type_ == T_STAR) { // ignore wild card node + } else { + if (OB_NOT_NULL(value_node) && OB_NOT_NULL(format_node)) { + bool format_json = format_node->value_; + bool is_json_type = false; + if (!format_json && (value_node->type_ == T_OBJ_ACCESS_REF)) { + if (OB_FAIL(check_is_json_constraint(*allocator_, value_node, format_json, is_json_type))) { + LOG_WARN("fail to check is_json constraint of col", K(ret), K(i)); + } else if (format_json) { + format_node->value_ = 1; + } + } + } // check json_expr is json constraint + if (OB_SUCC(ret) && OB_NOT_NULL(cur_node) && is_object + && cur_node->type_ == T_OBJ_ACCESS_REF + && OB_FAIL(process_dot_notation_in_json_object(param_node, cur_node, allocator, i))) { + LOG_WARN("fail to process dot notation node in json object", K(ret)); + } + } + } + + return ret; +} + +int ObDMLResolver::process_dot_notation_in_json_object(ParseNode*& expr_node, + ParseNode* cur_node, + common::ObIAllocator &allocator, + int& pos) { INIT_SUCC(ret); - ParseNode *cur_node = NULL; // current node - ParseNode *expr_node = NULL; // first param node - ParseNode *col_node = NULL; // - ParseNode *key_node = NULL; - bool check_res = true; int8_t depth = 0; bool exist_fun = false; + ObJsonBuffer sql_str(&allocator); bool is_dot_notation = false; - ObJsonBuffer sql_str(allocator_); - int64_t num_c = 0; - int64_t col_num = 0; + ParseNode* key_node = NULL; - if (OB_ISNULL(node)) { - } else { - if (node->type_ == T_FUN_SYS_JSON_OBJECT) { - if (OB_ISNULL(node->children_[0])) { + if (OB_ISNULL(cur_node) + || cur_node->type_ != T_OBJ_ACCESS_REF + || OB_ISNULL(cur_node->children_[0]) + || OB_ISNULL(cur_node->children_[0]->str_value_)) { // do not check + } else if (OB_FAIL(pre_check_dot_notation(*cur_node, depth, exist_fun, sql_str))) { + LOG_WARN("get depth of obj access ref failed"); + } else if (!exist_fun && depth >= 3) { + is_dot_notation = true; + } + // case : json_object(t1.c1.key1) -> json_object(key1 : t1.c1.key1); + // type == T_NULL : input value only. + // value_ = 2 : distinct true NULL value + if (OB_SUCC(ret) && is_dot_notation && OB_NOT_NULL(expr_node->children_[pos + 1]) + && expr_node->children_[pos + 1]->type_ == T_NULL && expr_node->children_[pos + 1]->value_ == 2) { // case only has dot notation + if (OB_ISNULL(key_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + memset(key_node, 0, sizeof(ParseNode)); + while (OB_NOT_NULL(cur_node->children_[1]) && cur_node->children_[1]->type_ == T_OBJ_ACCESS_REF) { + cur_node = cur_node->children_[1]; + } + if (OB_ISNULL(cur_node->children_[0])) { ret = OB_ERR_UNEXPECTED; LOG_WARN("json object first node should not be null", K(ret)); } else { - num_c = node->children_[0]->num_child_; - expr_node = node->children_[0]; - } - int64_t col_num = 0; - // json object expr has many node and nodes in groups of three : key 、 value 、 format json. so i+=3 is iterator in group ,same below - for (int64_t i = 0; OB_SUCC(ret) && i + 2 < num_c; i += 3) { - cur_node = node->children_[0]->children_[i]; - if (OB_NOT_NULL(cur_node) && cur_node->type_ == T_COLUMN_REF && OB_NOT_NULL(cur_node->children_[2]) && cur_node->children_[2]->type_ == T_STAR) { - if (OB_FAIL(expand_star_in_json_object(node->children_[0], allocator, i, col_num))) { - LOG_WARN("deal expr json object fail", K(ret)); - } else if (col_num >= 0) { - num_c += (3 * (col_num -1)); - i += (3 * (col_num -1)); - } - } - - if (OB_SUCC(ret) && OB_NOT_NULL(expr_node->children_[i]) && OB_NOT_NULL(expr_node->children_[i + 1]) && OB_NOT_NULL(expr_node->children_[i + 2])) { - bool format_json = expr_node->children_[i + 2]->value_; - if (!format_json && (expr_node->children_[i + 1]->type_ == T_OBJ_ACCESS_REF - || (expr_node->children_[i]->type_ == T_OBJ_ACCESS_REF - && expr_node->children_[i + 1]->type_ == T_NULL && expr_node->children_[i + 1]->value_ == 2))) { - if (expr_node->children_[i + 1]->type_ == T_OBJ_ACCESS_REF) { - col_node = expr_node->children_[i + 1]; - } else { - col_node = expr_node->children_[i]; - } - if (OB_ISNULL(col_node)) { // do nothing - } else if (OB_FAIL(check_is_json_constraint(*allocator_, col_node, format_json))) { - LOG_WARN("fail to check is_json constraint of col", K(ret), K(i)); - } else if (format_json) { - expr_node->children_[i + 2]->value_ = 1; - } - } - } // check not null - - if (OB_SUCC(ret) && OB_NOT_NULL(cur_node) && cur_node->type_ == T_OBJ_ACCESS_REF) { - if (OB_ISNULL(cur_node) || OB_ISNULL(cur_node->children_[0]) - || OB_ISNULL(cur_node->children_[0]->str_value_)) { // do not check - } else if (OB_FAIL(check_first_node_name(cur_node->children_[0]->str_value_, check_res))) { - LOG_WARN("fail to check first node", K(ret), K(cur_node->children_[0]->str_value_)); - } else if (check_res) { - // normal query do nothing - } else if (OB_FAIL(check_depth_obj_access_ref(cur_node, depth, exist_fun, sql_str, false))) { - LOG_WARN("get depth of obj access ref failed"); - } else if (!exist_fun) { - if (depth < 3) { - // do nothing - } else { - is_dot_notation = true; - } - } - if (OB_SUCC(ret) && is_dot_notation && OB_NOT_NULL(expr_node->children_[i + 1]) - && expr_node->children_[i + 1]->type_ == T_NULL && expr_node->children_[i + 1]->value_ == 2) { // case only has dot notation - if (OB_ISNULL(key_node = static_cast(allocator_->alloc(sizeof(ParseNode))))) { - ret = OB_ALLOCATE_MEMORY_FAILED; - LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); - } else { - key_node = new(key_node) ParseNode; - memset(key_node, 0, sizeof(ParseNode)); - while (OB_NOT_NULL(cur_node->children_[1]) && cur_node->children_[1]->type_ == T_OBJ_ACCESS_REF) { - cur_node = cur_node->children_[1]; - } - if (OB_ISNULL(cur_node->children_[0])) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("json object first node should not be null", K(ret)); - } else { - key_node->type_ = T_VARCHAR; - key_node->str_value_ = cur_node->children_[0]->raw_text_; - key_node->raw_text_ = cur_node->children_[0]->raw_text_; - key_node->str_len_ = cur_node->children_[0]->text_len_; - key_node->text_len_ = cur_node->children_[0]->text_len_; - expr_node->children_[i + 1] = expr_node->children_[i]; - expr_node->children_[i] = key_node; - } - } - } - } // deal dot notation in json object - } // end for - } else if (node->type_ == T_FUN_SYS_JSON_ARRAY) { - const ParseNode *expr_node = node->children_[0]; - CK (OB_NOT_NULL(expr_node)); - for (int i = 0; OB_SUCC(ret) && i + 1 < expr_node->num_child_; i += 2) { - // Singular: parse format json parameter - // first judge format json is or not true, true then pass - // false then check whether has is json constraint in this col , or set format json is true - if (OB_NOT_NULL(expr_node->children_[i]) && OB_NOT_NULL(expr_node->children_[i + 1])) { - bool format_json = expr_node->children_[i + 1]->value_; - if (!format_json && (expr_node->children_[i]->type_ == T_OBJ_ACCESS_REF)) { - if (OB_FAIL(check_is_json_constraint(*allocator_, expr_node->children_[i], format_json))) { - LOG_WARN("fail to check is_json constraint of col", K(ret), K(i)); - } else if (format_json) { - expr_node->children_[i + 1]->value_ = 1; - } - } - } - } // check each json_array child:[i]->json_data, [i+1]->format_json - // check json_array is json constraint - } else if ((node->type_ == T_FUN_ORA_JSON_ARRAYAGG || node->type_ == T_FUN_ORA_JSON_OBJECTAGG) - && (OB_NOT_NULL(node->children_[1]) && OB_NOT_NULL(node->children_[2]))) { - ParseNode *value_node = node->children_[1]; - ParseNode *format_node = node->children_[2]; - - bool format_json = format_node->value_; - if (!format_json && (value_node->type_ == T_OBJ_ACCESS_REF)) { - if (OB_FAIL(check_is_json_constraint(*allocator_, value_node, format_json))) { - LOG_WARN("fail to check is_json constraint of col", K(ret)); - } else if (format_json) { - format_node->value_ = 1; - } + key_node->type_ = T_VARCHAR; + key_node->str_value_ = cur_node->children_[0]->raw_text_; + key_node->raw_text_ = cur_node->children_[0]->raw_text_; + key_node->str_len_ = cur_node->children_[0]->text_len_; + key_node->text_len_ = cur_node->children_[0]->text_len_; + expr_node->children_[pos + 1] = expr_node->children_[pos]; + expr_node->children_[pos] = key_node; } } - if (OB_SUCC(ret) && (node->type_ == T_FUN_ORA_JSON_ARRAYAGG || node->type_ == T_FUN_ORA_JSON_OBJECTAGG) - && OB_NOT_NULL(node->children_[1]) && OB_NOT_NULL(node->children_[4])) { - ParseNode *value_node = node->children_[1]; - ParseNode *returning_node = node->children_[4]; - bool format_json = false; - ObString def_val(7, "default"); - if (OB_FAIL(ret)) { - } else if (value_node->type_ == T_OBJ_ACCESS_REF && OB_NOT_NULL(returning_node->raw_text_)) { - if (OB_FAIL(check_is_json_constraint(*allocator_, value_node, format_json, 2))) { - LOG_WARN("fail to check json constraint of col", K(ret)); - } else if (returning_node->value_ == 0 && def_val.case_compare(returning_node->raw_text_) == 0 && format_json) { + } + return ret; +} // deal dot notation in json object + +int ObDMLResolver::process_json_agg_node(ParseNode*& node, common::ObIAllocator &allocator) +{ + INIT_SUCC(ret); + ObString def_val(7, "default"); + if ((OB_NOT_NULL(node->children_[1]) && OB_NOT_NULL(node->children_[2]) && OB_NOT_NULL(node->children_[4]))) { + ParseNode *value_node = node->children_[1]; + ParseNode *format_node = node->children_[2]; + ParseNode *returning_node = node->children_[4]; + bool is_default_ret = returning_node->value_ == 0 && def_val.case_compare(returning_node->raw_text_) == 0; + bool is_json_cst = format_node->value_; + bool is_json_type = false; + + if ((!is_json_cst || is_default_ret) && (value_node->type_ == T_OBJ_ACCESS_REF)) { + if (OB_FAIL(check_is_json_constraint(allocator, value_node, is_json_cst, is_json_type, 1))) { + LOG_WARN("fail to check is_json constraint of col", K(ret)); + } else { + if (is_json_cst) { // set format json + format_node->value_ = 1; + } + if (is_default_ret && is_json_type) { // set default returning returning_node->int16_values_[OB_NODE_CAST_TYPE_IDX] = T_JSON; /* data type */ returning_node->int16_values_[OB_NODE_CAST_COLL_IDX] = INVALID_COLLATION; returning_node->int32_values_[OB_NODE_CAST_C_LEN_IDX] = 0; /* length */ returning_node->param_num_ = 0; } } - } // check json_arrayagg and objectagg json type affect default returning - - for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) { - if (OB_FAIL(SMART_CALL(pre_process_json_object_contain_star(node->children_[i], allocator)))) { - LOG_WARN("pre process json object contain star failed", K(ret), K(i)); - } } } return ret; @@ -662,7 +512,8 @@ int ObDMLResolver::transform_dot_notation2_json_value(ParseNode &node, const ObS ParseNode *match_node = NULL; // mismatch node ParseNode *match_node_l = NULL; ParseNode *match_node_r = NULL; - bool is_json_col = false; + bool is_json_cst = false; + bool is_json_type = false; if (OB_ISNULL(param_vec = static_cast(allocator_->alloc(alloc_size)))) { ret = OB_ALLOCATE_MEMORY_FAILED; @@ -697,9 +548,9 @@ int ObDMLResolver::transform_dot_notation2_json_value(ParseNode &node, const ObS param_vec[0] = tmp_node; } if (OB_FAIL(ret)) { - } else if (OB_FAIL(check_column_json_type(tmp_node, is_json_col))) { + } else if (OB_FAIL(check_column_json_type(tmp_node, is_json_cst, is_json_type))) { LOG_WARN("check column type failed", K(ret)); - } else if ((!is_json_col)) { + } else if (!(is_json_cst || is_json_type)) { ret = OB_WRONG_COLUMN_NAME; LOG_USER_ERROR(OB_WRONG_COLUMN_NAME, static_cast(sql_str.length() - 1), sql_str.ptr()); LOG_WARN("column type not json", K(ret)); @@ -836,9 +687,9 @@ int ObDMLResolver::transform_dot_notation2_json_value(ParseNode &node, const ObS if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(*allocator_, "", match_node_r, T_INT))) { LOG_WARN("create mismatch left node failed", K(ret)); } else { - match_node_r->value_ = 3; - match_node_r->int32_values_[0] = 3; - match_node_r->int16_values_[0] = 3; + match_node_r->value_ = 8; + match_node_r->int32_values_[0] = 8; + match_node_r->int16_values_[0] = 8; param_mismatch[1] = match_node_r; } } @@ -873,7 +724,8 @@ int ObDMLResolver::transform_dot_notation2_json_query(ParseNode &node, const ObS ParseNode *path_node = NULL; // path node ParseNode *table_node = NULL; // table node ParseNode *tmp_node = NULL; // json doc node - bool is_json_col = false; + bool is_json_cst = false; + bool is_json_type = false; if (OB_ISNULL(param_vec = static_cast(allocator_->alloc(alloc_vec_size)))) { ret = OB_ALLOCATE_MEMORY_FAILED; @@ -911,9 +763,9 @@ int ObDMLResolver::transform_dot_notation2_json_query(ParseNode &node, const ObS param_vec[0] = tmp_node; } if (OB_FAIL(ret)) { - } else if (OB_FAIL(check_column_json_type(tmp_node, is_json_col))) { + } else if (OB_FAIL(check_column_json_type(tmp_node, is_json_cst, is_json_type))) { LOG_WARN("check column type failed", K(ret)); - } else if ((!is_json_col)) { + } else if (!(is_json_cst || is_json_type)) { ret = OB_WRONG_COLUMN_NAME; LOG_USER_ERROR(OB_WRONG_COLUMN_NAME, static_cast(sql_str.length() - 1), sql_str.ptr()); LOG_WARN("column type not json", K(ret)); @@ -1063,9 +915,6 @@ int ObDMLResolver::check_depth_obj_access_ref(ParseNode *node, int8_t &depth, bo if (obj_check && ((depth == 3 && is_exist_array == true) || depth < 2)) { ret = OB_ERR_NOT_OBJ_REF; LOG_WARN("not an object or REF", K(ret)); - } else if (depth == 2 && OB_FAIL(check_column_udt_type(node))) { - // cases like: a.b.fun(), a must be table alias, b must be col name, and b must be udt type - LOG_WARN("not an object or REF", K(ret)); } else { exist_fun = true; is_fun_sys = true; @@ -1149,7 +998,7 @@ int ObDMLResolver::check_size_obj_access_ref(ParseNode *node) // only_is_json == 1: when has is json constraint or json type, return true; // only_is_json == 0: when has is json constraint, return true // only_is_json == 2: when is json type, return true -int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_col, int8_t only_is_json) +int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_cst, bool &is_json_type, int8_t only_is_json) { INIT_SUCC(ret); ObSEArray columns_list; @@ -1178,7 +1027,7 @@ int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_col, } else { ColumnItem the_col_item; ObString col_name(tab_col->children_[2]->str_len_, tab_col->children_[2]->str_value_); - for (int64_t i = 0; i < columns_list.count(); i++) { + for (int64_t i = 0; pos_col == -1 && i < columns_list.count(); i++) { if (0 == col_name.case_compare(columns_list.at(i).column_name_)) { pos_col = columns_list.at(i).column_id_; the_col_item = columns_list.at(i); @@ -1193,20 +1042,20 @@ int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_col, if (only_is_json > 0) { ObColumnRefRawExpr* col_expr = the_col_item.get_expr(); if (OB_NOT_NULL(col_expr)) { - is_json_col = (col_expr->get_result_type().get_calc_type() == ObJsonType + is_json_type = (col_expr->get_result_type().get_calc_type() == ObJsonType || col_expr->get_result_type().get_type() == ObJsonType || col_expr->is_strict_json_column()); } else { - is_json_col = false; + is_json_type = false; } - if (!is_json_col) { + if (!is_json_type) { if (table_item->is_json_table()) { for (size_t i = 0; i < table_item->json_table_def_->all_cols_.count(); ++i) { const ObJtColBaseInfo& info = *table_item->json_table_def_->all_cols_.at(i); const ObString& cur_column_name = info.col_name_; if (info.col_type_ == static_cast(COL_TYPE_QUERY)) { if (ObCharset::case_compat_mode_equal(cur_column_name, col_name)) { - is_json_col = true; + is_json_type = true; break; } } @@ -1214,7 +1063,7 @@ int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_col, } } } else { - is_json_col = false; + is_json_type = false; } } else if (OB_FAIL(schema_checker_->get_table_schema(session_info_->get_effective_tenant_id(), table_item->ref_id_, table_schema))) { ret = OB_TABLE_NOT_EXIST; @@ -1224,7 +1073,7 @@ int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_col, LOG_WARN("get table schema failed", K_(table_item->table_name), K(table_item->ref_id_), K(ret)); } else { for (ObTableSchema::const_constraint_iterator iter = table_schema->constraint_begin(); - OB_SUCC(ret) && iter != table_schema->constraint_end() && !is_json_col && only_is_json <= 1; iter ++) { + OB_SUCC(ret) && iter != table_schema->constraint_end() && !is_json_cst && only_is_json <= 1; iter ++) { const ObConstraint* ptr_constrain = *iter; if (OB_ISNULL(ptr_constrain)) { ret = OB_ERR_UNEXPECTED; @@ -1239,18 +1088,19 @@ int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_col, } else if (node->type_ == T_FUN_SYS_IS_JSON && ptr_constrain->get_column_cnt() > 0 && pos_col == *(ptr_constrain->cst_col_begin())) { - is_json_col = true; + is_json_cst = true; } } - if (OB_SUCC(ret) && ((only_is_json >= 1 && !is_json_col ) || (only_is_json == 0 && is_json_col))) { + if (OB_SUCC(ret) && ((only_is_json >= 1 && !is_json_cst ) || (only_is_json == 0 && is_json_cst))) { if (OB_NOT_NULL(tab_col->children_[2]) && OB_NOT_NULL(table_schema->get_column_schema(tab_col->children_[2]->str_value_)) && table_schema->get_column_schema(tab_col->children_[2]->str_value_)->is_json()) { - if (only_is_json == 0 && is_json_col) { - is_json_col = false; + if (only_is_json == 0 && is_json_cst) { + is_json_type = false; + is_json_cst = false; } else { - is_json_col = true; + is_json_type = true; } } } @@ -1262,21 +1112,34 @@ int ObDMLResolver::check_column_json_type(ParseNode *tab_col, bool &is_json_col, } // pre check whether dot notation -int ObDMLResolver::pre_process_dot_notation(ParseNode &node) +int ObDMLResolver::pre_check_dot_notation(ParseNode &node, int8_t& depth, bool& exist_fun, ObJsonBuffer& sql_str) +{ + INIT_SUCC(ret); + bool check_res = true; + if (OB_ISNULL(node.children_[0])) { // check not return error + } else if (OB_FAIL(check_first_node_name(node.children_[0]->str_value_, check_res))) { + LOG_WARN("fail to check first node", K(ret), K(node.children_[0]->str_value_)); + } else if (check_res) { + // normal query do nothing + } else if (OB_FAIL(check_depth_obj_access_ref(&node, depth, exist_fun, sql_str))) { + LOG_WARN("get depth of obj access ref failed"); + } else if (depth == 3 && exist_fun && OB_FAIL(check_column_udt_type(&node))) { + // cases like: a.b.fun(), a must be table alias, b must be col name, and b must be udt type + LOG_WARN("not an object or REF", K(ret)); + } + return ret; +} + +// process json_expr in query sql +int ObDMLResolver::pre_process_json_expr(ParseNode &node) { INIT_SUCC(ret); int8_t depth = 0; bool exist_fun = false; ObJsonBuffer sql_str(allocator_); - bool check_res = true; - if (node.type_ == T_OBJ_ACCESS_REF) { - if (OB_ISNULL(node.children_[0])) { // check not return error - } else if (OB_FAIL(check_first_node_name(node.children_[0]->str_value_, check_res))) { - LOG_WARN("fail to check first node", K(ret), K(node.children_[0]->str_value_)); - } else if (check_res) { - // normal query do nothing - } else if (OB_FAIL(check_depth_obj_access_ref(&node, depth, exist_fun, sql_str))) { - LOG_WARN("get depth of obj access ref failed"); + if (node.type_ == T_OBJ_ACCESS_REF) { // check dot notation node + if (OB_FAIL(pre_check_dot_notation(node, depth, exist_fun, sql_str))) { + LOG_WARN("get fail to check dot notation node", K(ret)); } else if (!exist_fun) { if (depth < 3) { // do nothing @@ -1290,10 +1153,12 @@ int ObDMLResolver::pre_process_dot_notation(ParseNode &node) LOG_WARN("transform to json value failed", K(depth), K(sql_str.string())); } } + } else if (OB_FAIL(pre_process_json_expr_constraint(&node, *allocator_))) { // check json expr with is json constraint + LOG_WARN("fail to process json exor with json constraint", K(ret)); } for (int64_t i = 0; OB_SUCC(ret) && i < node.num_child_; i++) { if (OB_ISNULL(node.children_[i])) { - } else if (OB_FAIL(SMART_CALL(pre_process_dot_notation(*node.children_[i])))) { + } else if (OB_FAIL(SMART_CALL(pre_process_json_expr(*node.children_[i])))) { LOG_WARN("pre process dot notation failed", K(ret), K(i)); } } @@ -1540,10 +1405,7 @@ int ObDMLResolver::resolve_sql_expr(const ParseNode &node, ObRawExpr *&expr, static_cast(stmt_)->is_hierarchical_query(); OC( (session_info_->get_name_case_mode)(ctx.case_mode_)); - if (OB_SUCC(ret) && lib::is_oracle_mode() && OB_FAIL(pre_process_json_object_contain_star(const_cast(&node), *allocator_))) { - LOG_WARN("check node with json object fail", K(ret)); - } - if (OB_SUCC(ret) && lib::is_oracle_mode() && OB_FAIL(pre_process_dot_notation(const_cast(node)))) { + if (OB_SUCC(ret) && lib::is_oracle_mode() && OB_FAIL(pre_process_json_expr(const_cast(node)))) { LOG_WARN("deal dot notation fail", K(ret)); } if (OB_SUCC(ret)) { diff --git a/src/sql/resolver/dml/ob_dml_resolver.h b/src/sql/resolver/dml/ob_dml_resolver.h index 7e57a9b2b5..153dacce4d 100644 --- a/src/sql/resolver/dml/ob_dml_resolver.h +++ b/src/sql/resolver/dml/ob_dml_resolver.h @@ -219,28 +219,33 @@ public: bool include_hidden, ColumnItem *&col_item); // dot notation - int pre_process_dot_notation(ParseNode &node); + int pre_process_json_expr(ParseNode &node); int print_json_path(ParseNode *&tmp_path, ObJsonBuffer &res_str); int check_depth_obj_access_ref(ParseNode *node, int8_t &depth, bool &exist_fun, ObJsonBuffer &sql_str, bool obj_check = true); // obj_check : whether need check dot notaion int check_first_node_name(const ObString &node_name, bool &check_res); int transform_dot_notation2_json_query(ParseNode &node, const ObString &sql_str); int transform_dot_notation2_json_value(ParseNode &node, const ObString &sql_str); - int check_column_json_type(ParseNode *tab_col, bool &is_json_col, int8_t only_is_json = 1); + int check_column_json_type(ParseNode *tab_col, bool &is_json_col, bool &is_json_type, int8_t only_is_json = 1); int check_size_obj_access_ref(ParseNode *node); /* json object resolve star */ int get_target_column_list(ObSEArray &target_list, ObString &tab_name, bool all_tab, bool &tab_has_alias, TableItem *&tab_item, bool is_col = false); - int add_column_expr_for_json_object_node(ParseNode *node, - common::ObIAllocator &allocator, - ObVector &t_vec, - ObString col_name, - ObString table_name); - int expand_star_in_json_object(ParseNode *node, common::ObIAllocator &allocator, int64_t pos, int64_t& col_num); - int check_is_json_constraint(common::ObIAllocator &allocator, ParseNode *col_node, bool& format_json, int8_t only_is_json = 0); // 1 is json & json type ; 0 is json; 2 json type + int pre_process_json_expr_constraint(ParseNode *node, common::ObIAllocator &allocator); + int process_json_object_array_node(ParseNode *node, common::ObIAllocator &allocator); + int process_dot_notation_in_json_object(ParseNode*& expr_node, + ParseNode* cur_node, + common::ObIAllocator &allocator, + int& pos); + int process_json_agg_node(ParseNode*& node, common::ObIAllocator &allocator); + int pre_check_dot_notation(ParseNode &node, int8_t& depth, bool& exist_fun, ObJsonBuffer& sql_str); + int check_is_json_constraint(common::ObIAllocator &allocator, + ParseNode *col_node, + bool& is_json_cst, + bool& is_json_type, + int8_t only_is_json = 0); // 1 is json & json type ; 0 is json; 2 json type bool is_array_json_expr(ParseNode *node); bool is_object_json_expr(ParseNode *node); int set_format_json_output(ParseNode *node); - int pre_process_json_object_contain_star(ParseNode *node, common::ObIAllocator &allocator); int transfer_to_inner_joined(const ParseNode &parse_node, JoinedTable *&joined_table); virtual int check_special_join_table(const TableItem &join_table, bool is_left_child, ObItemType join_type); /** diff --git a/src/sql/resolver/expr/ob_raw_expr_printer.cpp b/src/sql/resolver/expr/ob_raw_expr_printer.cpp index 36174ddd33..6fdd728bc3 100644 --- a/src/sql/resolver/expr/ob_raw_expr_printer.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_printer.cpp @@ -1443,23 +1443,26 @@ int ObRawExprPrinter::print_json_object(ObSysFunRawExpr *expr) if (OB_SUCC(ret)) { for (int i = 0; i < num_para - 4; i += 3) { PRINT_EXPR(expr->get_param_expr(i)); - DATA_PRINTF(" VALUE "); - PRINT_EXPR(expr->get_param_expr(i + 1)); - if (!static_cast(expr->get_param_expr(i + 2))->get_value().is_int()) { - ret = OB_ERR_UNEXPECTED; - LOG_WARN("type value isn't int value"); + if (T_FUN_SYS_JSON_OBJECT_WILD_STAR == expr->get_param_expr(i)->get_expr_type()) { // do nothing } else { - int64_t type = static_cast(expr->get_param_expr(i + 2))->get_value().get_int(); - switch (type) { - case 0: - break; - case 1: - DATA_PRINTF(" format json"); - break; - default: - ret = OB_ERR_UNEXPECTED; - LOG_WARN("invalid type value.", K(type)); - break; + DATA_PRINTF(" VALUE "); + PRINT_EXPR(expr->get_param_expr(i + 1)); + if (!static_cast(expr->get_param_expr(i + 2))->get_value().is_int()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("type value isn't int value"); + } else { + int64_t type = static_cast(expr->get_param_expr(i + 2))->get_value().get_int(); + switch (type) { + case 0: + break; + case 1: + DATA_PRINTF(" format json"); + break; + default: + ret = OB_ERR_UNEXPECTED; + LOG_WARN("invalid type value.", K(type)); + break; + } } } if (i != num_para - 7 && OB_SUCC(ret)) { @@ -1968,6 +1971,23 @@ int ObRawExprPrinter::print_json_value(ObSysFunRawExpr *expr) return ret; } +int ObRawExprPrinter::print_dot_notation(ObSysFunRawExpr *expr) +{ + INIT_SUCC(ret); + PRINT_EXPR(expr->get_param_expr(0)); + // DATA_PRINTF("."); + // PRINT_EXPR(expr->get_param_expr(1)); + ObObj path_obj = static_cast(expr->get_param_expr(1))->get_value(); + ObItemType expr_type = expr->get_param_expr(1)->get_expr_type(); + if (T_VARCHAR != expr_type && T_CHAR != expr_type) { + } else if (!path_obj.get_string().empty()) { + // we should print string without quote + DATA_PRINTF("%.*s", (path_obj.get_string().length() - 1), (path_obj.get_string().ptr() + 1)); + } + + return ret; +} + int ObRawExprPrinter::print_json_query(ObSysFunRawExpr *expr) { INIT_SUCC(ret); @@ -2362,6 +2382,23 @@ int ObRawExprPrinter::print_is_json(ObSysFunRawExpr *expr) return ret; } +int ObRawExprPrinter::print_json_object_star(ObSysFunRawExpr *expr) +{ + INIT_SUCC(ret); + ObObj tab_obj = static_cast(expr->get_param_expr(0))->get_value(); + ObItemType expr_type = expr->get_param_expr(0)->get_expr_type(); + if (T_VARCHAR != expr_type && T_CHAR != expr_type) { + } else if (!tab_obj.get_string().empty()) { + // we should print string without qoute + DATA_PRINTF("%.*s", (tab_obj.get_string().length()), (tab_obj.get_string().ptr())); + DATA_PRINTF("."); + } + if (OB_SUCC(ret)) { + DATA_PRINTF("*"); + } + return ret; +} + int ObRawExprPrinter::print_json_expr(ObSysFunRawExpr *expr) { int ret = OB_SUCCESS; @@ -2372,11 +2409,20 @@ int ObRawExprPrinter::print_json_expr(ObSysFunRawExpr *expr) ObString func_name = expr->get_func_name(); switch (expr->get_expr_type()) { case T_FUN_SYS_JSON_VALUE: { + // if json value only have one mismatch clause, the size of parameter is 12 + const int8_t JSN_VAL_WITH_ONE_MISMATCH = 12; // json value parameter count more than 12, because mismatch is multi-val and default value. // json_value(expr(0), expr(1) returning cast_type ascii xxx on empty(default value) xxx on error(default value) xxx on mismatch (xxx)) - if (OB_UNLIKELY(expr->get_param_count() < 12)) { + if (OB_UNLIKELY(expr->get_param_count() < JSN_VAL_WITH_ONE_MISMATCH)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected param count of expr to type", K(ret), KPC(expr)); + } else if (!static_cast(expr->get_param_expr(JSN_VAL_WITH_ONE_MISMATCH - 1))->get_value().is_int()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("type value isn't int value"); + } else if (static_cast(expr->get_param_expr(JSN_VAL_WITH_ONE_MISMATCH - 1))->get_value().get_int() == 8) { + if (OB_FAIL(print_dot_notation(expr))) { + LOG_WARN("fail to print dot notation", K(ret)); + } } else { DATA_PRINTF("json_value("); PRINT_EXPR(expr->get_param_expr(0)); @@ -2390,9 +2436,17 @@ int ObRawExprPrinter::print_json_expr(ObSysFunRawExpr *expr) } case T_FUN_SYS_JSON_QUERY: { // json query (json doc, json path, (returning cast_type) opt_scalars opt_pretty opt_ascii opt_wrapper on_error on_empty on_mismatch). + int64_t type = 0; if (OB_UNLIKELY(expr->get_param_count() != 11)) { ret = OB_ERR_UNEXPECTED; LOG_WARN("unexpected param count of expr to type", K(ret), KPC(expr), K(expr->get_param_count())); + } else if (!static_cast(expr->get_param_expr(10))->get_value().is_int()) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("type value isn't int value"); + } else if (static_cast(expr->get_param_expr(10))->get_value().get_int() == 3) { + if (OB_FAIL(print_dot_notation(expr))) { + LOG_WARN("fail to print dot notation", K(ret)); + } } else { DATA_PRINTF("json_query("); PRINT_EXPR(expr->get_param_expr(0)); @@ -3077,6 +3131,12 @@ int ObRawExprPrinter::print(ObSysFunRawExpr *expr) } break; } + case T_FUN_SYS_JSON_OBJECT_WILD_STAR: { + if (OB_FAIL(print_json_object_star(expr))) { + LOG_WARN("fail to print star in json object", K(ret)); + } + break; + } case T_FUN_PAD: { if (print_params_.for_dblink_) { // Oracle do not have function pad, diff --git a/src/sql/resolver/expr/ob_raw_expr_printer.h b/src/sql/resolver/expr/ob_raw_expr_printer.h index 0be5fb2594..57121e9ebd 100644 --- a/src/sql/resolver/expr/ob_raw_expr_printer.h +++ b/src/sql/resolver/expr/ob_raw_expr_printer.h @@ -138,6 +138,8 @@ private: int print_json_expr(ObSysFunRawExpr *expr); int print_json_value(ObSysFunRawExpr *expr); int print_json_query(ObSysFunRawExpr *expr); + int print_dot_notation(ObSysFunRawExpr *expr); + int print_json_object_star(ObSysFunRawExpr *expr); int print_json_exists(ObSysFunRawExpr *expr); int print_json_equal(ObSysFunRawExpr *expr); int print_json_array(ObSysFunRawExpr *expr); diff --git a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp index e29a164e8f..b78f02605d 100644 --- a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp +++ b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.cpp @@ -955,7 +955,7 @@ int ObRawExprResolverImpl::do_recursive_resolve(const ParseNode *node, ObRawExpr } case T_FUN_SYS_JSON_QUERY: { if (OB_FAIL(process_json_query_node(node, expr))) { - LOG_WARN("fail to process lnnvl node", K(ret), K(node)); + LOG_WARN("fail to process json query node", K(ret), K(node)); } break; } @@ -967,7 +967,13 @@ int ObRawExprResolverImpl::do_recursive_resolve(const ParseNode *node, ObRawExpr } case T_FUN_SYS_JSON_OBJECT: { if (OB_FAIL(process_ora_json_object_node(node, expr))) { - LOG_WARN("fail to process lnnvl node", K(ret), K(node)); + LOG_WARN("fail to process json object node", K(ret), K(node)); + } + break; + } + case T_FUN_SYS_JSON_OBJECT_WILD_STAR: { + if (OB_FAIL(process_ora_json_object_star_node(node, expr))) { + LOG_WARN("fail to process json object star node", K(ret), K(node)); } break; } @@ -5253,6 +5259,26 @@ int ObRawExprResolverImpl::malloc_new_specified_type_node(common::ObIAllocator & t_vec[1] = NULL; col_node->children_ = t_vec; } + } else if (type == T_FUN_SYS_JSON_OBJECT_WILD_STAR) { + col_node->type_ = T_FUN_SYS_JSON_OBJECT_WILD_STAR; + col_node->num_child_ = 1; + col_node->is_hidden_const_ = 1; + int64_t alloc_access_size = sizeof(ParseNode *) * 1; + ParseNode **t_vec = NULL; + if (OB_ISNULL(t_vec = static_cast(allocator.alloc(alloc_access_size)))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + t_vec[0] = NULL; + col_node->children_ = t_vec; + } + } else if (type == T_VARCHAR) { + col_node->type_ = T_VARCHAR; + col_node->str_value_ = col_name.ptr(); + col_node->raw_text_ = col_name.ptr(); + col_node->str_len_ = col_name.length(); + col_node->text_len_ = col_name.length(); + col_node->num_child_ = 0; } else { ret = OB_ERR_UNEXPECTED; LOG_WARN("node type not exits"); @@ -5354,6 +5380,83 @@ int ObRawExprResolverImpl::get_column_raw_text_from_node(const ParseNode *node, return ret; } +int ObRawExprResolverImpl::create_json_object_star_node(ParseNode *&node, common::ObIAllocator &allocator, int64_t &pos) +{ + INIT_SUCC(ret); + bool all_tab = true; + ObSEArray columns_list; + ParseNode* json_object_star = NULL; + ParseNode* table_node = NULL; + ParseNode* value_node = NULL; + ObString tab_name; + if (OB_ISNULL(node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node should not be null", K(ret)); + } else if (OB_NOT_NULL(node->children_[pos]) && OB_NOT_NULL(node->children_[pos]->children_[1])) { + tab_name.assign_ptr(node->children_[pos]->children_[1]->str_value_, node->children_[pos]->children_[1]->str_len_); + all_tab = false; + } + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(json_object_star = static_cast(allocator.alloc(sizeof(ParseNode))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + json_object_star = new(json_object_star) ParseNode; + if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(allocator, "", json_object_star, T_FUN_SYS_JSON_OBJECT_WILD_STAR))) { + LOG_WARN("create json doc node fail", K(ret)); + } else if (OB_ISNULL(table_node = static_cast(allocator.alloc(sizeof(ParseNode))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + table_node = new(table_node) ParseNode; + } + } + if (OB_FAIL(ret)) { + } else if (all_tab && OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(allocator, "", table_node, T_INT))) { + LOG_WARN("fail to create int node", K(ret)); + } else if (!all_tab && OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(allocator, tab_name, table_node, T_VARCHAR))) { + LOG_WARN("fail to create table name node", K(ret)); + } else { + json_object_star->children_[0] = table_node; + node->children_[pos] = json_object_star; + } + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(value_node = static_cast(allocator.alloc(sizeof(ParseNode))))) { + ret = OB_ALLOCATE_MEMORY_FAILED; + LOG_WARN("fail to allocate memory", K(ret), K(sizeof(ParseNode))); + } else { + value_node = new(value_node) ParseNode; + if (OB_FAIL(ObRawExprResolverImpl::malloc_new_specified_type_node(allocator, "", value_node, T_INT))) { + LOG_WARN("create json doc node fail", K(ret)); + } else { + node->children_[pos + 1] = value_node; + } + } + return ret; +} + +int ObRawExprResolverImpl::process_ora_json_object_star_node(const ParseNode *node, ObRawExpr *&expr) +{ + INIT_SUCC(ret); + ObSysFunRawExpr *func_expr = NULL; + if (OB_FAIL(ctx_.expr_factory_.create_raw_expr(T_FUN_SYS, func_expr))) { + LOG_WARN("fail to create func_expr"); + } else { + CK(OB_NOT_NULL(func_expr)); + OX(func_expr->set_func_name(ObString::make_string("json_object_star"))); + // child 0 is table name + for (int64_t i = 0; OB_SUCC(ret) && i < node->num_child_; i++) { + ObRawExpr *param_expr = NULL; + CK(OB_NOT_NULL(node->children_[i])); + OZ(SMART_CALL(recursive_resolve(node->children_[i], param_expr))); + CK(OB_NOT_NULL(param_expr)); + OZ(func_expr->add_param_expr(param_expr)); + } + OX(expr = func_expr); + } + return ret; +} + int ObRawExprResolverImpl::process_ora_json_object_node(const ParseNode *node, ObRawExpr *&expr) { INIT_SUCC(ret); @@ -5429,9 +5532,14 @@ int ObRawExprResolverImpl::process_ora_json_object_node(const ParseNode *node, O data_node = node->children_[0]; for (int64_t i = 0; OB_SUCC(ret) && i < data_node->num_child_; i++) { // 3 node in group ObRawExpr *para_expr = NULL; - cur_node_kv = NULL; + cur_node_kv = data_node->children_[i]; int val_pos = i + 1; // key is i where i % 3 == 0 , value is i + 1, format json is i + 2 - if (OB_ISNULL(data_node->children_[i])) { + if (OB_ISNULL(cur_node_kv)) { + } else if (cur_node_kv->type_ == T_COLUMN_REF // process star node + && OB_NOT_NULL(cur_node_kv->children_[2]) + && cur_node_kv->children_[2]->type_ == T_STAR + && OB_FAIL(ObRawExprResolverImpl::create_json_object_star_node(data_node, ctx_.local_allocator_, i))) { + LOG_WARN("fail to create json object star node", K(ret)); } else if ((i % 3 == 1) && data_node->children_[i]->type_ == T_NULL && data_node->children_[i]->value_ == 2) { // 2 is flag of empty value cur_node_kv = data_node->children_[i - 1]; } else { diff --git a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h index 807ea89a3a..73b35a07e2 100644 --- a/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h +++ b/src/sql/resolver/expr/ob_raw_expr_resolver_impl.h @@ -119,6 +119,8 @@ private: int pre_check_json_path_valid(const ParseNode *node); int get_column_raw_text_from_node(const ParseNode *node, ObString &col_name); int process_ora_json_object_node(const ParseNode *node, ObRawExpr *&expr); + int create_json_object_star_node(ParseNode *&node, common::ObIAllocator &allocator, int64_t &pos); + int process_ora_json_object_star_node(const ParseNode *node, ObRawExpr *&expr); int process_is_json_node(const ParseNode *node, ObRawExpr *&expr); int process_json_equal_node(const ParseNode *node, ObRawExpr *&expr); int process_json_query_node(const ParseNode *node, ObRawExpr *&expr); diff --git a/src/sql/rewrite/ob_transform_pre_process.cpp b/src/sql/rewrite/ob_transform_pre_process.cpp index 8be290351d..4d44215164 100644 --- a/src/sql/rewrite/ob_transform_pre_process.cpp +++ b/src/sql/rewrite/ob_transform_pre_process.cpp @@ -78,6 +78,15 @@ int ObTransformPreProcess::transform_one_stmt(common::ObIArray LOG_TRACE("succeed to expand correlated cte", K(is_happened), K(ret)); } } + if (OB_SUCC(ret)) { + if (OB_FAIL(transform_json_object_expr_with_star(parent_stmts, stmt, is_happened))) { + LOG_WARN("failed to transform for json object star", K(ret)); + } else { + trans_happened |= is_happened; + OPT_TRACE("transform for udt columns", is_happened); + LOG_TRACE("succeed to transform for udt columns", K(is_happened), K(ret)); + } + } if (OB_SUCC(ret)) { if (OB_FAIL(transform_udt_columns(parent_stmts, stmt, is_happened))) { LOG_WARN("failed to transform for transform for cast multiset", K(ret)); @@ -7147,6 +7156,37 @@ int ObTransformPreProcess::check_skip_child_select_view(const ObIArray &parent_stmts, + ObDMLStmt *stmt, bool &trans_happened) +{ + INIT_SUCC(ret); + ObSEArray replace_exprs; + + JsonObjectStarChecker expr_checker(replace_exprs); + ObStmtExprGetter visitor; + visitor.checker_ = &expr_checker; + if (OB_SUCC(ret) && OB_FAIL(stmt->iterate_stmt_expr(visitor))) { + LOG_WARN("get relation exprs failed", K(ret)); + } + + //collect query udt exprs which need to be replaced + for (int64_t i = 0; OB_SUCC(ret) && i < replace_exprs.count(); i++) { + if (OB_ISNULL(replace_exprs.at(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("replace expr is null", K(ret)); + } else { + ObSysFunRawExpr *func_expr = static_cast(replace_exprs.at(i)); + if (OB_FAIL(ObTransformUtils::expand_wild_star_to_columns(ctx_, stmt, func_expr))) { + LOG_WARN("fail to transform star to column node", K(ret)); + } else { + trans_happened = true; + } + } + } + + return ret; +} + int ObTransformPreProcess::transform_query_udt_columns_exprs(const ObIArray &parent_stmts, ObDMLStmt *stmt, bool &trans_happened) { diff --git a/src/sql/rewrite/ob_transform_pre_process.h b/src/sql/rewrite/ob_transform_pre_process.h index fdd222e29f..b23e2fc13e 100644 --- a/src/sql/rewrite/ob_transform_pre_process.h +++ b/src/sql/rewrite/ob_transform_pre_process.h @@ -458,6 +458,9 @@ struct DistinctObjMeta int replace_group_id_in_stmt(ObSelectStmt *stmt); int replace_group_id_in_expr_recursive(ObRawExpr *&expr); + // transform json object with star + int transform_json_object_expr_with_star(const ObIArray &parent_stmts, + ObDMLStmt *stmt, bool &trans_happened); int transform_udt_columns(const common::ObIArray &parent_stmts, ObDMLStmt *stmt, bool &trans_happened); int transform_udt_column_conv_function(ObDmlTableInfo &table_info, ObIArray &column_conv_exprs, diff --git a/src/sql/rewrite/ob_transform_utils.cpp b/src/sql/rewrite/ob_transform_utils.cpp index 204572ae45..ccabc96a39 100644 --- a/src/sql/rewrite/ob_transform_utils.cpp +++ b/src/sql/rewrite/ob_transform_utils.cpp @@ -11869,6 +11869,33 @@ int ObTransformUtils::extract_udt_exprs(ObRawExpr *expr, ObIArray & return ret; } +int ObTransformUtils::extract_json_object_exprs(ObRawExpr *expr, ObIArray &json_exprs) +{ + int ret = OB_SUCCESS; + ObString json_object_str(11, "json_object"); + bool is_find = false; + if (OB_ISNULL(expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(expr)); + } else if (expr->get_expr_type() == T_FUN_SYS_JSON_OBJECT + && (0 == json_object_str.compare(static_cast(expr)->get_func_name()))) { + for (int32 i = 0; OB_SUCC(ret) && !is_find && i < expr->get_param_count() - 4; i += 3) { + if (expr->get_param_expr(i)->get_expr_type() != T_FUN_SYS_JSON_OBJECT_WILD_STAR) { + } else if (OB_FAIL(add_var_to_array_no_dup(json_exprs, expr))) { + LOG_WARN("failed to add var to array no dup", K(ret)); + } else { + is_find = true; + } + } + } + for (int64_t i = 0; OB_SUCC(ret) && i < expr->get_param_count(); ++i) { + if (OB_FAIL(SMART_CALL(extract_json_object_exprs(expr->get_param_expr(i), json_exprs)))) { + LOG_WARN("Failed to extract rowid exprs", K(ret)); + } + } + return ret; +} + int ObTransformUtils::is_batch_stmt_write_table(uint64_t table_id, const ObDMLStmt &stmt, bool &is_target_table) @@ -13249,6 +13276,329 @@ int ObTransformUtils::wrap_case_when_for_count(ObTransformerCtx *ctx, return ret; } +int ObTransformUtils::check_is_json_constraint(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ColumnItem& col_item, + bool &is_json) +{ + INIT_SUCC(ret); + TableItem *table = NULL; + const ParseNode *node = NULL; + const share::schema::ObTableSchema *table_schema = NULL; + is_json = false; + + if (OB_ISNULL(stmt) + || OB_ISNULL(ctx) + || OB_ISNULL(ctx->session_info_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("null unexpected", K(ctx), K(stmt), K(ret)); + } else if (OB_ISNULL(table = stmt->get_table_item_by_id(col_item.table_id_))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("failed to get table item", K(col_item.table_id_), K(ret)); + } else if (table->is_json_table() || table->is_temp_table() + || table->is_generated_table() || table->is_function_table()) { + ObColumnRefRawExpr* col_expr = col_item.get_expr(); + if (OB_NOT_NULL(col_expr)) { + is_json = (col_expr->get_result_type().get_calc_type() == ObJsonType + || col_expr->get_result_type().get_type() == ObJsonType + || col_expr->is_strict_json_column()); + } else { + is_json = false; + } + if (!is_json) { + if (table->is_json_table()) { + for (size_t i = 0; i < table->json_table_def_->all_cols_.count(); ++i) { + const ObJtColBaseInfo& info = *table->json_table_def_->all_cols_.at(i); + const ObString& cur_column_name = info.col_name_; + if (info.col_type_ == static_cast(COL_TYPE_QUERY)) { + if (ObCharset::case_compat_mode_equal(cur_column_name, col_item.column_name_)) { + is_json = true; + break; + } + } + } + } + } + } else if (OB_FAIL(ctx->schema_checker_->get_table_schema(ctx->session_info_->get_effective_tenant_id(), + table->ref_id_, table_schema))) { + ret = OB_TABLE_NOT_EXIST; + LOG_WARN("get table schema failed", K_(table->table_name), K(table->ref_id_), K(ret)); + } else if (OB_ISNULL(table_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table should not be null", K(table->ref_id_)); + } else { + for (ObTableSchema::const_constraint_iterator iter = table_schema->constraint_begin(); + OB_SUCC(ret) && iter != table_schema->constraint_end() && !is_json; iter ++) { + const ObConstraint* ptr_constrain = *iter; + if (OB_ISNULL(ptr_constrain)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table schema constrain is null", K(ret)); + } else if (OB_ISNULL(ptr_constrain->get_check_expr_str().ptr())) { + } else if (OB_FAIL(ObRawExprUtils::parse_bool_expr_node_from_str( + ptr_constrain->get_check_expr_str(), *(ctx->allocator_), node))) { + LOG_WARN("parse expr node from string failed", K(ret)); + } else if (OB_ISNULL(node)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("parse expr get node failed", K(ret)); + } else if (node->type_ == T_FUN_SYS_IS_JSON + && ptr_constrain->get_column_cnt() > 0 + && col_item.column_id_ == *(ptr_constrain->cst_col_begin())) { + is_json = true; + } + } + } + + return ret; +} + +int ObTransformUtils::add_column_expr_for_json_object_node(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ColumnItem& col_item, + ObSEArray& param_array) +{ + INIT_SUCC(ret); + ObConstRawExpr* key_expr = NULL; + ObColumnRefRawExpr* value_expr = NULL; + ObConstRawExpr* format_expr = NULL; + bool is_json = false; + + if (OB_ISNULL(ctx) || OB_ISNULL(stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("input can not be null", K(ret)); + } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_VARCHAR, key_expr))) { + LOG_WARN("create const expr failed", K(ret)); + } else if (OB_ISNULL(key_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("true expr is NULL", K(ret)); + } else { + ObObj key_obj; + key_obj.set_varchar(col_item.column_name_); + key_obj.set_collation_type(ObCharset::get_default_collation(ObCharset::get_default_charset())); + key_obj.set_collation_level(CS_LEVEL_IMPLICIT); + key_expr->set_value(key_obj); + } + if (OB_FAIL(ret)) { + } else if (OB_ISNULL(value_expr = col_item.expr_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("can not get column raw expr", K(ret)); + } else if (OB_FAIL(ctx->expr_factory_->create_raw_expr(T_INT, format_expr))) { + LOG_WARN("create const expr failed", K(ret)); + } else if (OB_ISNULL(format_expr)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("true expr is NULL", K(ret)); + } else if (check_is_json_constraint(ctx, stmt, col_item, is_json)) { + LOG_WARN("fail to check is json constraint", K(ret)); + } else { + ObObj format_obj; + format_obj.set_int(is_json); + format_expr->set_data_type(ObIntType); + format_expr->set_value(format_obj); + format_expr->set_param(format_obj); + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(param_array.push_back(key_expr))) { + LOG_WARN("can not push key expr to array", K(ret)); + } else if (OB_FAIL(param_array.push_back(value_expr))) { + LOG_WARN("can not push key expr to array", K(ret)); + } else if (OB_FAIL(param_array.push_back(format_expr))) { + LOG_WARN("can not push key expr to array", K(ret)); + } + + return ret; +} + +int ObTransformUtils::get_expand_node_from_star(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ObRawExpr *param_expr, + ObSEArray& param_array) +{ + INIT_SUCC(ret); + TableItem *table = NULL; + ObRawExpr* node_expr = NULL; + int64_t num_child = 0; + bool all_tab = true; + const int8_t TABLE_NAME_POS = 0; + ObString tab_name; + bool tab_has_alias = false; + ObSEArray columns_list; + + if (OB_ISNULL(param_expr) || param_expr->get_param_count() != 1 + || OB_ISNULL(param_expr->get_param_expr(TABLE_NAME_POS))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("node should not be null", K(ret)); + } else if (param_expr->get_param_expr(TABLE_NAME_POS)->get_expr_type() == T_VARCHAR) { + ObConstRawExpr* name_expr = static_cast(param_expr->get_param_expr(TABLE_NAME_POS)); + tab_name = name_expr->get_value().get_string(); + all_tab = false; + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(get_column_node_from_table(ctx, stmt, tab_name, columns_list, all_tab, tab_has_alias, table))) { + LOG_WARN("fail to get coulmn node from table", K(ret)); + } else if (OB_ISNULL(table)) { + ret = OB_ERR_KEY_COLUMN_DOES_NOT_EXITS; + LOG_USER_ERROR(OB_ERR_KEY_COLUMN_DOES_NOT_EXITS, tab_name.length(), tab_name.ptr()); + } else { + int64_t num = columns_list.count(); + for (int64_t i = 0; OB_SUCC(ret) && i < num; i++) { + if (columns_list.at(i).column_id_ < OB_APP_MIN_COLUMN_ID) { + } else if (OB_FAIL(add_column_expr_for_json_object_node(ctx, stmt, columns_list.at(i), param_array))) { + LOG_WARN("json object star node parse fail", K(ret)); + } + } + } + + return ret; +} + +int ObTransformUtils::get_column_node_from_table(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ObString& tab_name, + ObSEArray& column_list, + bool all_tab, + bool &tab_has_alias, + TableItem *&tab_item) +{ + INIT_SUCC(ret); + int64_t num = 0; + ObColumnRefRawExpr *col_expr = NULL; + const ObTableSchema *table_schema = NULL; + const ObColumnSchemaV2 *col_schema = NULL; + + if (OB_ISNULL(stmt)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("select stmt is null"); + } else { + num = stmt->get_table_size(); + } + for (int64_t i = 0; OB_SUCC(ret) && i < num; i++) { + const TableItem *tmp_table_item = stmt->get_table_item(i); + if (OB_ISNULL(tmp_table_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table item is null"); + } else if (OB_NOT_NULL(tab_name.ptr()) && !all_tab && tmp_table_item->table_name_ != tab_name && tmp_table_item->alias_name_ != tab_name) { + // other table should chose + } else { + if (tmp_table_item->alias_name_ == tab_name || + (num > 1 && tmp_table_item->table_name_ == tab_name && stmt->get_stmt_type() == stmt::T_SELECT)) { + tab_has_alias = true; + } + tab_item = const_cast(tmp_table_item); + + if (OB_FAIL(ctx->schema_checker_->get_table_schema(ctx->session_info_->get_effective_tenant_id(), + tmp_table_item->ref_id_, table_schema))) { // get table schema + if ((tmp_table_item->is_generated_table() + || tmp_table_item->is_temp_table()) + && OB_NOT_NULL(tmp_table_item->ref_query_)) { + ret = OB_INVALID_ARGUMENT; // not adaptive generate table + LOG_WARN("invalid argument", K(ret)); + } else if (tmp_table_item->is_json_table()) { + ret = OB_SUCCESS; + if (OB_FAIL(ObTransformUtils::get_columnitem_from_json_table(stmt, tmp_table_item, column_list))) { + LOG_WARN("fail to get column item from json table", K(ret)); + } + } else { + LOG_WARN("failed to get table schema", K(ret)); + } + } else { + ObTableSchema::const_column_iterator iter = table_schema->column_begin(); + ObTableSchema::const_column_iterator end = table_schema->column_end(); + for (int64_t i = 0; OB_SUCC(ret) && iter != end; ++iter, i++) { + col_schema = *iter; + col_expr = NULL; + ColumnItem column_item; + ColumnItem* col_item = stmt->get_column_item_by_id(tmp_table_item->table_id_, col_schema->get_column_id()); + if (OB_NOT_NULL(col_item)) { + } else if (OB_ISNULL(col_schema)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("column schema is NULL", K(ret)); + } else if (ObRawExprUtils::build_column_expr(*ctx->expr_factory_, *col_schema, col_expr)) { + LOG_WARN("fail to create col expr by column schema", K(ret)); + } else { + col_expr->set_table_name(tmp_table_item->table_name_); + col_expr->set_table_id(tmp_table_item->table_id_); + column_item.expr_ = col_expr; + column_item.table_id_ = col_expr->get_table_id(); + column_item.column_id_ = col_expr->get_column_id(); + column_item.column_name_ = col_expr->get_column_name(); + col_item = &column_item; + } + if (OB_FAIL(ret)) { + } else if (OB_FAIL(stmt->add_column_item(*col_item))) { + LOG_WARN("add column item to stmt failed", K(ret), K(col_item)); + } else if (OB_FAIL(column_list.push_back(*col_item))) { + LOG_WARN("fail to push column expr in array", K(ret)); + } + } + } + } + } + return ret; +} + +int ObTransformUtils::get_columnitem_from_json_table(ObDMLStmt *stmt, + const TableItem *tmp_table_item, + ObSEArray& column_list) +{ + INIT_SUCC(ret); + ObJsonTableDef* jt_def = NULL; + if (OB_ISNULL(jt_def = tmp_table_item->json_table_def_)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("table_item json_table_def_ is null", K(tmp_table_item->json_table_def_)); + } else { + for (size_t i = 0; OB_SUCC(ret) && i < jt_def->all_cols_.count(); ++i) { + ObJtColBaseInfo* col_info = jt_def->all_cols_.at(i); + if (OB_ISNULL(col_info)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("col info is null", K(ret), K(i)); + } else if (col_info->col_type_ != NESTED_COL_TYPE) { + ColumnItem* col_item = stmt->get_column_item_by_id(tmp_table_item->table_id_, col_info->output_column_idx_); + if (OB_ISNULL(col_item)) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("col item is null", K(ret), K(i)); + } else if (OB_FAIL(stmt->add_column_item(*col_item))) { + LOG_WARN("add column item to stmt failed", K(ret), K(col_item)); + } else if (OB_FAIL(column_list.push_back(*col_item))) { + LOG_WARN("fail to store col result", K(ret)); + } + } + } + } + return ret; +} + +int ObTransformUtils::expand_wild_star_to_columns(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ObSysFunRawExpr *json_object_expr) +{ + INIT_SUCC(ret); + ObSEArray new_col_arr; + + for (int32_t i = 0; OB_SUCC(ret) && i < json_object_expr->get_param_count(); i++) { + if (OB_ISNULL(json_object_expr->get_param_expr(i))) { + ret = OB_ERR_UNEXPECTED; + LOG_WARN("get unexpected null", K(ret), K(json_object_expr)); + } else if (json_object_expr->get_param_expr(i)->get_expr_type() == T_FUN_SYS_JSON_OBJECT_WILD_STAR) { + if (OB_FAIL(get_expand_node_from_star(ctx, stmt, json_object_expr->get_param_expr(i), new_col_arr))) { + LOG_WARN("fail to expand star node", K(ret)); + } else { + i += 2; + } + } else if (OB_FAIL(new_col_arr.push_back(json_object_expr->get_param_expr(i)))) { + LOG_WARN("fail to push back expr to array", K(ret)); + } + } + if (OB_SUCC(ret)) { + // clear child then append, raw expr not support insert + json_object_expr->clear_child(); + for (int32_t i = 0; OB_SUCC(ret) && i < new_col_arr.count(); i++) { + if (OB_FAIL(json_object_expr->add_param_expr(new_col_arr.at(i)))) { + LOG_WARN("can not push expr into json object expr", K(ret)); + } + } + } + return ret; +} + int ObTransformUtils::create_udt_hidden_columns(ObTransformerCtx *ctx, ObDMLStmt *stmt, const ObColumnRefRawExpr &udt_expr, diff --git a/src/sql/rewrite/ob_transform_utils.h b/src/sql/rewrite/ob_transform_utils.h index 9ad418136c..ab1dcdb4d2 100644 --- a/src/sql/rewrite/ob_transform_utils.h +++ b/src/sql/rewrite/ob_transform_utils.h @@ -898,6 +898,34 @@ public: ObIArray &equal_conds); static int extract_udt_exprs(ObRawExpr *expr, ObIArray &udt_exprs); + // json object with star : json_object(*) + static int check_is_json_constraint(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ColumnItem& col_item, + bool &is_json); + static int extract_json_object_exprs(ObRawExpr *expr, ObIArray &json_exprs); + static int expand_wild_star_to_columns(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ObSysFunRawExpr *json_object_expr); + static int get_columnitem_from_json_table(ObDMLStmt *stmt, + const TableItem *tmp_table_item, + ObSEArray& column_list); + static int get_column_node_from_table(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ObString& tab_name, + ObSEArray& column_list, + bool all_tab, + bool &tab_has_alias, + TableItem *&tab_item); + static int add_column_expr_for_json_object_node(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ColumnItem& col_item, + ObSEArray& param_array); + static int get_expand_node_from_star(ObTransformerCtx *ctx, + ObDMLStmt *stmt, + ObRawExpr *param_expr, + ObSEArray& param_array); + // end json object with star static int add_cast_for_replace(ObRawExprFactory &expr_factory, const ObRawExpr *from_expr, ObRawExpr *&to_expr,