Skip to content

fix: return the constant instead of the first child when simplifying conjunctions - #650

Open
sayanx64 wants to merge 1 commit into
oceanbase:mainfrom
sayanx64:issue_637
Open

sayanx64 wants to merge 1 commit into
oceanbase:mainfrom
sayanx64:issue_637

Conversation

@sayanx64

Copy link
Copy Markdown

What problem were solved in this pull request?

Issue Number: close #637

Problem:

ConjunctionSimplificationRule folds a conjunction that contains a boolean constant: x AND false is always false and x OR true is always true. But instead of replacing the conjunction with that constant, it replaced it with the first child (child_exprs.front()), which is only correct when the constant happens to be the first child.

This is reachable from plain SQL. ComparisonSimplificationRule folds 1 = 2 into false, and because the grammar rule condition AND condition_list appends the first condition last, the constant ends up after id = 1:

create table t(id int, v int);
insert into t values(1, 10);
insert into t values(2, 20);
select * from t where 1 = 2 and id = 1;

Before (returns a row, and the scan is kept):

miniob > select * from t where 1 = 2 and id = 1;
id | v
1 | 10
miniob > explain select * from t where 1 = 2 and id = 1;
Query Plan
OPERATOR(NAME)
PROJECT
└─TABLE_SCAN(t)

After (empty, and the predicate subtree is pruned):

miniob > select * from t where 1 = 2 and id = 1;
id | v
miniob > explain select * from t where 1 = 2 and id = 1;
Query Plan
OPERATOR(NAME)
PROJECT

where id = 1 and 1 = 2 was already correct before this change, because there the constant happens to be the first child.

What is changed and how it works?

In ConjunctionSimplificationRule::rewrite:

  • x AND false / x OR true: replace the conjunction with false / true instead of its first child.
  • When every child is removed (true AND true, false OR false), replace the conjunction with true (AND) or false (OR). Before, an empty conjunction was left behind, and ConjunctionExpr::get_value returns true for an empty conjunction, so false OR false evaluated to true.
  • Set change_made whenever the expression is modified (also pointed out in the issue).
  • Continue from the iterator returned by vector::erase instead of reusing the invalidated one.

New unit test unittest/observer/conjunction_simplification_rule_test.cpp covers both short-circuit cases, the all-removed case, removing true from AND / false from OR, a single remaining child, and the no-op case. The first four tests fail on main.

Other information

…conjunctions

ConjunctionSimplificationRule replaced `expr AND false` and `expr OR true`
with the first child of the conjunction instead of the constant, so it was
only correct when the constant happened to be the first child. For example,
`select * from t where 1 = 2 and id = 1` returned the row with id = 1.

- replace the conjunction with the boolean constant it short-circuits to
- replace a conjunction whose children were all removed with `true` (AND)
  or `false` (OR); an empty conjunction always evaluated to true
- set change_made whenever the expression is modified
- continue from the iterator returned by vector::erase

Fixes oceanbase#637
@sayanx64

Copy link
Copy Markdown
Author

Hi @hnwyllmm, CI is green on this PR. Could you take a look when you have time?

While checking its first CI run, which failed in mvcc_trx_log_test (the flaky test from #442), I found the cause of that flake and opened #651 with a fix and a deterministic test.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] The conjunction simplification returns wrong answer

1 participant