-
-
Notifications
You must be signed in to change notification settings - Fork 2k
MDEV-37713/MDEV-37714 Fold boolean literals in SELECT-list #4754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| SELECT TRUE AND TRUE; | ||
| TRUE AND TRUE | ||
| 1 | ||
| SELECT TRUE AND FALSE; | ||
| TRUE AND FALSE | ||
| 0 | ||
| SELECT FALSE AND TRUE; | ||
| FALSE AND TRUE | ||
| 0 | ||
| SELECT FALSE AND FALSE; | ||
| FALSE AND FALSE | ||
| 0 | ||
| SELECT TRUE OR TRUE; | ||
| TRUE OR TRUE | ||
| 1 | ||
| SELECT TRUE OR FALSE; | ||
| TRUE OR FALSE | ||
| 1 | ||
| SELECT TRUE OR TRUE; | ||
| TRUE OR TRUE | ||
| 1 | ||
| SELECT FALSE OR FALSE; | ||
| FALSE OR FALSE | ||
| 0 | ||
| SELECT TRUE AND NULL; | ||
| TRUE AND NULL | ||
| NULL | ||
| SELECT NULL AND TRUE; | ||
| NULL AND TRUE | ||
| NULL | ||
| SELECT FALSE AND NULL; | ||
| FALSE AND NULL | ||
| 0 | ||
| SELECT NULL AND FALSE; | ||
| NULL AND FALSE | ||
| 0 | ||
| SELECT TRUE OR NULL; | ||
| TRUE OR NULL | ||
| 1 | ||
| SELECT NULL OR TRUE; | ||
| NULL OR TRUE | ||
| 1 | ||
| SELECT FALSE OR NULL; | ||
| FALSE OR NULL | ||
| NULL | ||
| SELECT NULL OR FALSE; | ||
| NULL OR FALSE | ||
| NULL | ||
| SELECT NULL AND NULL; | ||
| NULL AND NULL | ||
| NULL | ||
| SELECT NULL OR NULL; | ||
| NULL OR NULL | ||
| NULL | ||
| SELECT NOT NULL OR TRUE, NOT NULL AND FALSE; | ||
| NOT NULL OR TRUE NOT NULL AND FALSE | ||
| 1 0 | ||
| SELECT NULL AND TRUE, NULL OR FALSE; | ||
| NULL AND TRUE NULL OR FALSE | ||
| NULL NULL | ||
| PREPARE s FROM 'SELECT NOT NULL OR TRUE, NOT NULL AND FALSE'; | ||
| EXECUTE s; | ||
| NOT NULL OR TRUE NOT NULL AND FALSE | ||
| 1 0 | ||
| EXECUTE s; | ||
| NOT NULL OR TRUE NOT NULL AND FALSE | ||
| 1 0 | ||
| DEALLOCATE PREPARE s; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # | ||
| # MDEV-37713/MDEV-37714 | ||
| # Test correctness of boolean folding | ||
| # | ||
|
|
||
| SELECT TRUE AND TRUE; | ||
| SELECT TRUE AND FALSE; | ||
| SELECT FALSE AND TRUE; | ||
| SELECT FALSE AND FALSE; | ||
| SELECT TRUE OR TRUE; | ||
| SELECT TRUE OR FALSE; | ||
| SELECT TRUE OR TRUE; | ||
| SELECT FALSE OR FALSE; | ||
|
|
||
| SELECT TRUE AND NULL; | ||
| SELECT NULL AND TRUE; | ||
| SELECT FALSE AND NULL; | ||
| SELECT NULL AND FALSE; | ||
| SELECT TRUE OR NULL; | ||
| SELECT NULL OR TRUE; | ||
| SELECT FALSE OR NULL; | ||
| SELECT NULL OR FALSE; | ||
|
|
||
| SELECT NULL AND NULL; | ||
| SELECT NULL OR NULL; | ||
|
|
||
| SELECT NOT NULL OR TRUE, NOT NULL AND FALSE; | ||
| SELECT NULL AND TRUE, NULL OR FALSE; | ||
|
|
||
| PREPARE s FROM 'SELECT NOT NULL OR TRUE, NOT NULL AND FALSE'; | ||
| EXECUTE s; | ||
| EXECUTE s; | ||
| DEALLOCATE PREPARE s; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8223,6 +8223,23 @@ bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, | |
| DBUG_RETURN(TRUE); /* purecov: inspected */ | ||
| } | ||
| item= *(it.ref()); // Item might have changed in fix_fields() | ||
| /* | ||
| If item is a SELECT-list COND_ITEM, rewrite it on the first time this | ||
| query is optimized to fold boolean expressions | ||
| */ | ||
| if (thd->lex->current_select->context_analysis_place == SELECT_LIST && | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any specific reason why you're doing this only for the SELECT list expressions?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Forgot to mention one thing: When doing the optimization you are doing you need to check for NULL-ness!
should return NULL and not true.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Clauses like WHERE/HAVING/ON already implement this folding through the I guess you can say the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This works! The
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about TRUE or NULL ? This should still return NULL. And in your example above it's returning TRUE (1).
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the latest stable version of MariaDB it returns TRUE btw, for all of the test cases I wrote I tested it against a distribution version of MariaDB running in a Docker container |
||
| item->type() == Item::COND_ITEM && | ||
| thd->lex->current_select->first_cond_optimization) | ||
| { | ||
| Query_arena_stmt on_stmt_arena(thd); | ||
| Item *new_item= static_cast<Item_cond *>(item)->simplify_cond(thd); | ||
| if (new_item != item) | ||
| { | ||
| new_item->share_name_with(item); | ||
| it.replace(new_item); | ||
| item= new_item; | ||
| } | ||
| } | ||
| if (!ref.is_null()) | ||
| { | ||
| ref[0]= item; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the list ever be empty, given that you're removing one of the branches only if another branch exists?
I'd say no. And then this is dead code. And should be turned into an assert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The list can be empty. For example if we are dealing with something like
TRUE AND TRUE, bothTRUEs will be dropped during the while loop, and we will be left with an empty listThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I follow. You will only simplify a X AND|OR Y by replacing it with X or Y. This is a multiple parameter expression. You will do nothing on single parameter expressions.
Can you please demonstrate how the list becomes empty with an example SQL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In an expression or sub-expression composed of only boolean literals, the list can become empty. An example SQL expression where this happens is
SELECT TRUE AND TRUE, orSELECT FALSE OR FALSE. Since all TRUEs are dropped from AND clauses and all FALSEs are dropped from OR clauses. I tested this on my end and I can confirm that the code afterif (list.is_empty())is run in certain cases, but I'd be happy to clarify/demonstrate further.