fix move query ref expr across stmts bug

This commit is contained in:
jinmaoli 2023-11-08 06:43:02 +00:00 committed by ob-robot
parent a9c2876a24
commit 38085f4781
6 changed files with 92 additions and 11 deletions

View File

@ -6802,7 +6802,8 @@ int ObOptimizerUtil::check_pushdown_filter_for_set(const ObSelectStmt &parent_st
LOG_WARN("predicate is null", K(ret));
} else if (OB_FAIL(ObRawExprUtils::extract_set_op_exprs(pred, set_op_exprs))) {
LOG_WARN("failed to extract set op exprs", K(ret));
} else if (OB_FAIL(ObTransformUtils::check_pushdown_into_set_valid(pred,
} else if (OB_FAIL(ObTransformUtils::check_pushdown_into_set_valid(&subquery,
pred,
set_op_exprs,
is_simple_expr))) {
LOG_WARN("failed to check pushdown into set", K(ret));

View File

@ -1670,8 +1670,8 @@ int ObTransformPredicateMoveAround::pushdown_into_set_stmt(ObSelectStmt *stmt,
ObSEArray<ObRawExpr*, 16> invalid_pushdown_preds;
ObSEArray<ObRawExpr*, 16> invalid_pullup_preds;
const int64_t pushdown_preds_cnt = pushdown_preds.count();
if (OB_FAIL(extract_valid_preds(parent_stmt, pushdown_preds, valid_preds, invalid_pushdown_preds))
|| OB_FAIL(extract_valid_preds(parent_stmt, pullup_preds, valid_preds, invalid_pullup_preds))) {
if (OB_FAIL(extract_valid_preds(parent_stmt, stmt, pushdown_preds, valid_preds, invalid_pushdown_preds))
|| OB_FAIL(extract_valid_preds(parent_stmt, stmt, pullup_preds, valid_preds, invalid_pullup_preds))) {
LOG_WARN("failed to check push down", K(ret));
} else if (OB_FAIL(rename_preds.assign(valid_preds))) {
LOG_WARN("failed to assign rename preds", K(ret));
@ -1722,6 +1722,7 @@ int ObTransformPredicateMoveAround::pushdown_into_set_stmt(ObSelectStmt *stmt,
* @return int
*/
int ObTransformPredicateMoveAround::extract_valid_preds(ObSelectStmt *stmt,
ObSelectStmt *child_stmt,
ObIArray<ObRawExpr *> &all_preds,
ObIArray<ObRawExpr *> &valid_preds,
ObIArray<ObRawExpr *> &invalid_preds)
@ -1745,7 +1746,8 @@ int ObTransformPredicateMoveAround::extract_valid_preds(ObSelectStmt *stmt,
is_valid = false;
}
if (OB_SUCC(ret) && is_valid) {
if (OB_FAIL(ObTransformUtils::check_pushdown_into_set_valid(expr,
if (OB_FAIL(ObTransformUtils::check_pushdown_into_set_valid(child_stmt,
expr,
parent_set_exprs,
is_valid))) {
LOG_WARN("failed to check expr pushdown validity", K(ret));

View File

@ -179,6 +179,7 @@ private:
ObIArray<ObRawExpr *> &output_pushdown_preds);
int extract_valid_preds(ObSelectStmt *stmt,
ObSelectStmt *child_stmt,
ObIArray<ObRawExpr *> &all_preds,
ObIArray<ObRawExpr *> &valid_exprs,
ObIArray<ObRawExpr *> &invalid_exprs);

View File

@ -620,6 +620,7 @@ int ObTransformQueryPushDown::check_select_item_subquery(ObSelectStmt &select_st
int ret = OB_SUCCESS;
can_be = true;
ObSEArray<ObRawExpr*, 4> column_exprs_from_subquery;
ObSEArray<ObQueryRefRawExpr*, 4> query_ref_exprs;
ObRawExpr *expr = NULL;
TableItem *table = NULL;
ObSqlBitSet<> table_set;
@ -628,12 +629,25 @@ int ObTransformQueryPushDown::check_select_item_subquery(ObSelectStmt &select_st
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect select stmt", K(ret), K(select_stmt.get_from_item_size()), K(table));
}
for (int64_t i = 0; OB_SUCC(ret) && i < view.get_select_item_size(); ++i) {
for (int64_t i = 0; OB_SUCC(ret) && can_be && i < view.get_select_item_size(); ++i) {
if (OB_ISNULL(expr = view.get_select_item(i).expr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpect null expr", K(ret));
} else if (!expr->has_flag(CNT_SUB_QUERY)) {
/* do nothing */
} else if (expr->has_flag(IS_WITH_ANY) || expr->has_flag(IS_WITH_ALL) ||
expr->get_expr_type() == T_OP_EXISTS || expr->get_expr_type() == T_OP_NOT_EXISTS) {
/*
* Disable query pushdown when a select item of view is `any/all/exists subquery` form.
* As for the query below, after pushing down, v.c2 will be used for both projection and filtering,
* which may result in an incorrect stmt status in the subsequent rewrite loop.
* e.g. select * from
* (select t1.c1, (exists(select 1 from t2 where (t1.c1 = t2.c1))) as c2 from t1) v
* where v.c2 is true;
*/
can_be = false;
} else if (OB_FAIL(ObTransformUtils::extract_query_ref_expr(expr, query_ref_exprs, true))) {
LOG_WARN("failed to extract query ref exprs", K(ret));
} else if (OB_ISNULL(expr = select_stmt.get_column_expr_by_id(table->table_id_,
i + OB_APP_MIN_COLUMN_ID))) {
/* do nothing */
@ -641,7 +655,24 @@ int ObTransformQueryPushDown::check_select_item_subquery(ObSelectStmt &select_st
LOG_WARN("failed to push back column expr", K(ret));
}
}
if (OB_FAIL(ret)) {
// check query ref exprs of view's select items
if (OB_FAIL(ret) || !can_be) {
/* do nothing */
} else if (query_ref_exprs.count() > 0) {
for (int64_t i = 0; OB_SUCC(ret) && can_be && i < query_ref_exprs.count(); i++) {
ObQueryRefRawExpr* query_ref = NULL;
if (OB_ISNULL(query_ref = query_ref_exprs.at(i))) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null pointer", K(ret));
} else if (query_ref->is_set() || query_ref->get_output_column() != 1) {
can_be = false;
}
}
}
// check query ref exprs of upper select stmt
if (OB_FAIL(ret) || !can_be) {
} else if (column_exprs_from_subquery.empty()) {
/* do nothing */
} else if (OB_FAIL(select_stmt.get_table_rel_ids(*table, table_set))) {

View File

@ -13838,13 +13838,15 @@ int ObTransformUtils::check_convert_string_safely(const ObRawExpr *expr,
// Q2: select * from (select * from t1 intersect select * from t2) v where concat(c1,'a') = 'aa';
// only predicate in Q1 can be pushdown into set stmt
// TODO: sean.yyj, concat(c1,'a') = 'aa' can be pushdown into UNION after solved collation level bug
int ObTransformUtils::check_pushdown_into_set_valid(ObRawExpr *expr,
int ObTransformUtils::check_pushdown_into_set_valid(const ObSelectStmt* child_stmt,
ObRawExpr *expr,
const ObIArray<ObRawExpr *> &set_op_exprs,
bool &is_valid)
{
int ret = OB_SUCCESS;
ObSEArray<ObRawExpr *, 4> parent_exprs;
if (OB_FAIL(recursive_check_pushdown_into_set_valid(expr,
if (OB_FAIL(recursive_check_pushdown_into_set_valid(child_stmt,
expr,
set_op_exprs,
parent_exprs,
is_valid))) {
@ -13854,6 +13856,7 @@ int ObTransformUtils::check_pushdown_into_set_valid(ObRawExpr *expr,
}
int ObTransformUtils::recursive_check_pushdown_into_set_valid(
const ObSelectStmt* child_stmt,
ObRawExpr *expr,
const ObIArray<ObRawExpr *> &set_op_exprs,
ObIArray<ObRawExpr *> &parent_exprs,
@ -13869,6 +13872,8 @@ int ObTransformUtils::recursive_check_pushdown_into_set_valid(
} else if (ObOptimizerUtil::find_item(set_op_exprs, expr)) {
if (OB_FAIL(ObTransformUtils::check_can_replace(expr, parent_exprs, false, is_valid))) {
LOG_WARN("failed to check can replace expr", K(ret));
} else if (is_valid && check_child_projection_validity(child_stmt, expr, is_valid)) {
LOG_WARN("failed to check push to set child validity", K(ret));
}
} else if (OB_UNLIKELY(expr->is_set_op_expr())) {
ret = OB_ERR_UNEXPECTED;
@ -13878,7 +13883,8 @@ int ObTransformUtils::recursive_check_pushdown_into_set_valid(
if (OB_FAIL(parent_exprs.push_back(expr))) {
LOG_WARN("failed to push back", K(ret));
}
if (OB_FAIL(SMART_CALL(recursive_check_pushdown_into_set_valid(expr->get_param_expr(i),
if (OB_FAIL(SMART_CALL(recursive_check_pushdown_into_set_valid(child_stmt,
expr->get_param_expr(i),
set_op_exprs,
parent_exprs,
is_valid)))) {
@ -13892,5 +13898,40 @@ int ObTransformUtils::recursive_check_pushdown_into_set_valid(
return ret;
}
int ObTransformUtils::check_child_projection_validity(const ObSelectStmt *child_stmt,
ObRawExpr *expr,
bool &is_valid)
{
int ret = OB_SUCCESS;
is_valid = true;
ObSetOpRawExpr* set_op_expr = NULL;
if (OB_ISNULL(child_stmt) || OB_ISNULL(expr)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null pointer", K(ret), K(child_stmt), K(expr));
} else if (OB_UNLIKELY(!expr->is_set_op_expr())) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected expr type", K(ret), K(expr->get_expr_type()));
} else if (OB_FALSE_IT(set_op_expr = static_cast<ObSetOpRawExpr*>(expr))) {
} else {
int64_t proj_idx = set_op_expr->get_idx();
ObRawExpr *proj_expr = NULL;
if (proj_idx < 0 || proj_idx >= child_stmt->get_select_item_size()) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected index of select items", K(ret), K(proj_idx), K(child_stmt->get_select_item_size()));
} else if (OB_ISNULL(proj_expr = child_stmt->get_select_item(proj_idx).expr_)) {
ret = OB_ERR_UNEXPECTED;
LOG_WARN("unexpected null pointer", K(ret));
} else if (proj_expr->has_flag(CNT_SUB_QUERY)) {
/*
* disable pushdown predicates that reference a select item containing subquery in set query.
* e.g. select * from (select 1 a, exists(select 1 from t2 where t1.c1=t2.c1) b from t1
* union all select c1,c2 from t1) v where b is true;
*/
is_valid = false;
}
}
return ret;
}
} // namespace sql
} // namespace oceanbase

View File

@ -1824,17 +1824,22 @@ public:
bool used_in_compare,
bool &can_replace);
static int check_pushdown_into_set_valid(ObRawExpr *expr,
static int check_pushdown_into_set_valid(const ObSelectStmt* child_stmt,
ObRawExpr *expr,
const ObIArray<ObRawExpr *> &set_op_exprs,
bool &is_valid);
static int recursive_check_pushdown_into_set_valid(ObRawExpr *expr,
static int recursive_check_pushdown_into_set_valid(const ObSelectStmt* child_stmt,
ObRawExpr *expr,
const ObIArray<ObRawExpr *> &set_op_exprs,
ObIArray<ObRawExpr *> &parent_exprs,
bool &is_valid);
static int get_explicated_ref_columns(const uint64_t table_id,
ObDMLStmt *stmt,
ObIArray<ObRawExpr*> &table_cols);
static int check_child_projection_validity(const ObSelectStmt *child_stmt,
ObRawExpr *expr,
bool &is_valid);
private:
static int inner_get_lazy_left_join(ObDMLStmt *stmt,
TableItem *table,