1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-29 08:21:15 +03:00

MCOL-4642 NOT IN subquery containing an isnull in the OR predicate crashes server.

InSub::handleFunc() was incorrectly exiting early for an IN subquery
containing an isnull predicate in the OR operation in the WHERE clause.
This patch properly handles the OR predicate containing an isnull/isnotnull
predicate in the WHERE clause. We don't remove the isnull operand from the
filter ParseTree in 6.x as the server no longer injects the isnull predicate
in the IN subquery due to MCOL-4617, where we moved the creation and injection
of in-to-exists predicate into the engine.
This commit is contained in:
Gagan Goel
2021-06-02 06:51:05 -04:00
parent 4d835d78d3
commit 6f69194462
3 changed files with 97 additions and 27 deletions

View File

@ -266,7 +266,6 @@ void InSub::handleFunc(gp_walk_info* gwip, Item_func* func)
if (cond->argument_list()->elements == 1)
return;
// (cache=item or isnull(item)) case. remove "or isnull()"
if (cond->argument_list()->elements == 2)
{
// don't know how to deal with this. don't think it's a fatal error either.
@ -278,35 +277,22 @@ void InSub::handleFunc(gp_walk_info* gwip, Item_func* func)
if (!pt->left() || !pt->right())
return;
SimpleFilter* sf = dynamic_cast<SimpleFilter*>(pt->left()->data());
SimpleFilter* lsf = dynamic_cast<SimpleFilter*>(pt->left()->data());
SimpleFilter* rsf = dynamic_cast<SimpleFilter*>(pt->right()->data());
//assert (sf && sf->op()->op() == execplan::OP_ISNULL);
if (!sf || sf->op()->op() != execplan::OP_ISNULL)
if (!lsf || !rsf)
return;
delete sf;
sf = dynamic_cast<SimpleFilter*>(pt->right()->data());
//idbassert(sf && sf->op()->op() == execplan::OP_EQ);
if (!sf || sf->op()->op() != execplan::OP_EQ)
return;
// set NULLMATCH for both operand. It's really a setting for the join.
// should only set NULLMATCH when the subtype is NOT_IN. for some IN subquery
// with aggregation column, MySQL inefficiently convert to:
// (cache=item or item is null) and item is not null, which is equivalent to
// cache = item. Do not set NULLMATCH for this case.
// Because we don't know IN or NOTIN yet, set candidate bit and switch to NULLMATCH
// later in handleNot function.
if (sf->lhs()->joinInfo() & JOIN_CORRELATED)
sf->lhs()->joinInfo(sf->lhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE);
if (sf->rhs()->joinInfo() & JOIN_CORRELATED)
sf->rhs()->joinInfo(sf->rhs()->joinInfo() | JOIN_NULLMATCH_CANDIDATE);
pt = pt->right();
gwip->ptWorkStack.pop();
gwip->ptWorkStack.push(pt);
// (a=b or isnull(item))/(a=b or isnotnull(item)) case.
// swap the lhs and rhs operands of the OR operator.
if ((lsf->op()->op() == execplan::OP_ISNULL ||
lsf->op()->op() == execplan::OP_ISNOTNULL) &&
rsf->op()->op() == execplan::OP_EQ)
{
ParseTree* temp = pt->left();
pt->left(pt->right());
pt->right(temp);
}
}
}
else if (cond->functype() == Item_func::EQ_FUNC)