Bug #99404 AGG alias in ORDER BY works, but not if in an expression
Submitted: 30 Apr 2020 7:11 Modified: 3 May 2020 10:19
Reporter: bai Kevin Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:8.0.17 and before OS:Linux
Assigned to: CPU Architecture:Any

[30 Apr 2020 7:11] bai Kevin
Description:
AGG alias in ORDER BY works, but not if in an expression.

For example:
SELECT c2, avg(c3) as avg FROM t1 GROUP BY c2 ORDER BY avg / 2;

The result of sorting will get the wrong result.

How to repeat:

+CREATE TABLE t1(c1 INT AUTO_INCREMENT PRIMARY KEY, c2 CHAR(20), c3 INT, c4 INT);
+INSERT INTO t1(c2, c3, c4) VALUES("abcdef", 10, 1);
+INSERT INTO t1(c2, c3, c4) VALUES("abc", 29, 1);
+INSERT INTO t1(c2, c3, c4) VALUES("abcdef", 180, 3);
+INSERT INTO t1(c2, c3, c4) VALUES("ab", 10, 2);
+INSERT INTO t1(c2, c3, c4) VALUES("abcd", 89, 1);
+INSERT INTO t1(c2, c3, c4) VALUES("ab", 50, 8);
+INSERT INTO t1(c2, c3, c4) VALUES("abc", 47, 2);
+INSERT INTO t1(c2, c3, c4) VALUES("abcdef", 103, 4);
+INSERT INTO t1(c2, c3, c4) VALUES("abc", 38, 3);
+INSERT INTO t1(c2, c3, c4) VALUES("abcdef", 73, 3);
+ALTER TABLE t1 ADD INDEX i_c2(c2);
+SELECT c2, avg(c3) as avg FROM t1 GROUP BY c2 ORDER BY avg;
+c2     avg
+ab     30.0000
+abc    38.0000
+abcd   89.0000
+abcdef 91.5000

+SELECT c2, avg(c3) as avg FROM t1 GROUP BY c2 ORDER BY avg / 2;
+c2     avg
+abcd   89.0000
+ab     30.0000
+abcdef 91.5000
+abc    38.0000

Suggested fix:
@@ -5224,7 +5224,21 @@ bool Item_field::fix_fields(THD *thd, Item **reference) {
               item tree, then we use new Item_ref as an
               intermediate value to resolve referenced item only.
               In this case the new Item_ref item is unused.
+
+              The new Item_ref should point to the Item_ref in the
+              base_ref_items but not the Item in the select list. Otherwise,
+              when the REF_SLICE_ACTIVE is switched to the other slice like
+              REF_SLICE_TMP1, the Item_ref can't be switched to the new one.
+              For example:
+              SELECT c2, avg(c3) as avg FROM t1 GROUP BY c2 ORDER BY avg/2;
+              When fixing the Item alias avg in the expr avg/2, if the new
+              Item_ref pointer to the select list, then it will still point
+              to the original Item in the select list after active slice is
+              switched to the REF_SLICE_TMP1. In reality, it should point to
+              the new field item of the temporary table. Later the sorting
+              with the wrong Item_ref will make wrong results.
             */
+            res = &thd->lex->current_select()->base_ref_items[counter];
             Item_ref *rf = new Item_ref(context, res, table_name, field_name,
                                         resolution == RESOLVED_AGAINST_ALIAS);
             if (!rf) return 1;
[30 Apr 2020 12:33] MySQL Verification Team
Hi Mr. Kevin,

Thank you for your bug report.

However, this is not a bug, since I am not able to repeat it with the current 8.0 patch-fix release, which is 8.0.20:

c2	avg
ab	30.0000
abc	38.0000
abcd	89.0000
abcdef	91.5000
c2	avg
ab	30.0000
abc	38.0000
abcd	89.0000
abcdef	91.5000

Results are exactly as they should be.

Hence, all you have to do is upgrade to the latest 8.0 release.

Not a bug.
[3 May 2020 10:19] bai Kevin
Yes. There is no this bug after 8.0.18 because of new AggregateIterator. But before 8.0.18, there is this bug in every version before.
[4 May 2020 12:19] MySQL Verification Team
Hi,

8.0.18, 8.0.17 etc, are not versions. These are patch fix releases. Version is 8.0.

Hence, we fix bugs in 8.0 in a new bug-fix release, not in the old ones.