fix move query ref expr across stmts bug
This commit is contained in:
parent
a9c2876a24
commit
38085f4781
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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))) {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user