Repository: pingcap/tidb (Go)

Issue:
columns that match group by expr should not trigger only-full-group-by-error
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)

```sql
DROP TABLE IF EXISTS t1;
CREATE TABLE `t1` (
  `id` int(11) NOT NULL PRIMARY KEY,
  `c1` int(11) NOT NULL DEFAULT '0'
);

SELECT c1 FROM t1 GROUP BY c1 ORDER BY c1 ASC; -- legal (obviously)
SELECT ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) AS `c1` FROM `t1` GROUP BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ORDER BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ASC; -- legal
SELECT ((floor(((`c1` - 10) / 300)) * 50000) + 0.0) AS `c1` FROM `t1` GROUP BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ORDER BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ASC; -- illegal
```

### 2. What did you expect to see? (Required)

If a column in the FROM list matches the GROUP BY expression exactly, and all functions specified are deterministic, then there is no violation of only-full-group-by. Here is the result from MySQL 8.0.24:

```sql
mysql [localhost:8024] {msandbox} (test) > SELECT c1 FROM t1 GROUP BY c1 ORDER BY c1 ASC; -- legal (obviously)
Empty set (0.00 sec)

mysql [localhost:8024] {msandbox} (test) > SELECT ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) AS `c1` FROM `t1` GROUP BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ORDER BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ASC; -- legal
Empty set (0.00 sec)

mysql [localhost:8024] {msandbox} (test) > SELECT ((floor(((`c1` - 10) / 300)) * 50000) + 0.0) AS `c1` FROM `t1` GROUP BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ORDER BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ASC; -- illegal
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'test.t1.c1' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

```

### 3. What did you see instead (Required)

```sql
Empty set (0.00 sec)

mysql> SELECT ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) AS `c1` FROM `t1` GROUP BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ORDER BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ASC; -- legal
ERROR 1055 (42000): Expression #1 of ORDER BY is not in GROUP BY clause and contains nonaggregated column '' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
mysql> SELECT ((floor(((`c1` - 10) / 300)) * 50000) + 0.0) AS `c1` FROM `t1` GROUP BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ORDER BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ASC; -- illegal
ERROR 1055 (42000): Expression #1 of ORDER BY is not in GROUP BY clause and contains nonaggregated column '' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
```


### 4. What is your TiDB version? (Required)

```sql
mysql> SELECT tidb_version()\G
*************************** 1. row ***************************
tidb_version(): Release Version: v4.0.0-beta.2-2893-gb7c22aa31-dirty
Edition: Community
Git Commit Hash: b7c22aa31d062b77a96493519a6b50ca9b627971
Git Branch: show-privileges
UTC Build Time: 2021-05-13 20:47:08
GoVersion: go1.13.15
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false
1 row in set (0.00 sec)
```



Discussion:
Here is another example of the same problem, except the group by expression is two columns. Both columns appear in the SELECT list, and should be considered legal:

```sql
DROP TABLE IF EXISTS a;

CREATE TABLE a (
  `id` varchar(64) NOT NULL PRIMARY KEY,
  `s_id` bigint(20) NOT NULL DEFAULT '0',
  `s_date` datetime NOT NULL DEFAULT '1999-01-01 00:00:00',
  `d_id` bigint(20) NOT NULL DEFAULT '0',
  `d_date` datetime NOT NULL DEFAULT '1999-01-01 00:00:00',
  `o_date` datetime NOT NULL DEFAULT '1999-01-01 00:00:00'
);

SELECT case
         when a.s_id = 0 then
          a.d_id
         else
          a.s_id
       end as site_id,
       date_format((case
                     when a.d_date > '1999-01-01 00:00:00' and
                          a.s_date > '1999-01-01 00:00:00' and
                          a.d_date < a.s_date then
                      a.d_date
                     when a.d_date > '1999-01-01 00:00:00' and
                          a.s_date > '1999-01-01 00:00:00' and
                          a.d_date > a.s_date then
                      a.s_date
                     when a.d_date > '1999-01-01 00:00:00' and
                          a.s_date = '1999-01-01 00:00:00' then
                      a.d_date
                     when a.d_date = '1999-01-01 00:00:00' and
                          a.s_date > '1999-01-01 00:00:00' then
                      a.s_date
                     else
                      a.s_date
                   end),
                   '%Y-%m-%d %H') as sum_day,
       count(1) as c
  from a
 where a.o_date > '2021-05-12 00:00:00'
   and (a.s_id > 0 or a.d_id > 0)
 group by case
            when a.s_id = 0 then
             a.d_id
            else
             a.s_id
          end,
          date_format((case
                        when a.d_date > '1999-01-01 00:00:00' and
                             a.s_date > '1999-01-01 00:00:00' and
                             a.d_date < a.s_date then
                         a.d_date
                        when a.d_date > '1999-01-01 00:00:00' and
                             a.s_date > '1999-01-01 00:00:00' and
                             a.d_date > a.s_date then
                         a.s_date
                        when a.d_date > '1999-01-01 00:00:00' and
                             a.s_date = '1999-01-01 00:00:00' then
                         a.d_date
                        when a.d_date = '1999-01-01 00:00:00' and
                             a.s_date > '1999-01-01 00:00:00' then
                         a.s_date
                        else
                         a.s_date
                      end),
                      '%Y-%m-%d %H');
```

This statement produces an error in TiDB, but is valid in MySQL.
## Please edit this comment or add a new comment to complete the following information

### Not a bug

1. Remove the 'type/bug' label
2. Add notes to indicate why it is not a bug

### Duplicate bug

1. Add the 'type/duplicate' label
2. Add the link to the original bug

### Bug

Note: Make Sure that 'component', and 'severity' labels are added
Example for how to fill out the template: https://github.com/pingcap/tidb/issues/20100

#### 1. Root Cause Analysis (RCA) (optional) 
<!-- Write down the reason why this bug occurs -->

#### 2. Symptom (optional)

<!-- What will the user see when this bug occurs. The error message may be in the terminal, log or monitoring -->

#### 3. All Trigger Conditions (optional)

<!-- All the user scenarios that may trigger this bug -->

#### 4. Workaround (optional)

#### 5. Affected versions

<!--
In the format of [start_version:end_version], multiple version ranges are
accepted. If the bug only affects the unreleased version, please input:
"unreleased". For example:

Notes:
  1. Do not use any white spaces in '[]'.
  2. The range in '[]' is a closed interval
  3. The version format is `v$Major.$Minor.$Patch`, the $Majoy and $Minor
     number in a version range should be the same. [v3.0.1:v3.1.2] is
     invalid because the $Minor number of the version range is different.

Example 1: [v3.0.1:v3.0.5], [v4.0.1:v4.0.5]
Example 2: unreleased
-->

#### 6. Fixed versions

<!--
The first released version that contains this fix in each minor version. If the bug's affected version has been released, the fixed version should be a detailed version number; If the bug doesn't affect any released version, the fixed version can be "master";  

Example 1: v3.0.13, v4.0.5
Example 2: master
-->



Patch:
diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go
index fc6fb53dcff44..10f7ee31323f1 100644
--- a/planner/core/logical_plan_builder.go
+++ b/planner/core/logical_plan_builder.go
@@ -2825,7 +2825,7 @@ func (b *PlanBuilder) checkOnlyFullGroupByWithGroupClause(p LogicalPlan, sel *as
 					continue
 				}
 			}
-			checkExprInGroupByOrIsSingleValue(p, item.Expr, offset, ErrExprInOrderBy, gbyOrSingleValueColNames, gbyExprs, notInGbyOrSingleValueColNames)
+			checkExprInGroupByOrIsSingleValue(p, getInnerFromParenthesesAndUnaryPlus(item.Expr), offset, ErrExprInOrderBy, gbyOrSingleValueColNames, gbyExprs, notInGbyOrSingleValueColNames)
 		}
 	}
 	if len(notInGbyOrSingleValueColNames) == 0 {


Test patch:
diff --git a/executor/aggregate_test.go b/executor/aggregate_test.go
index 85e8bcc4f236d..b93d8dd619d88 100644
--- a/executor/aggregate_test.go
+++ b/executor/aggregate_test.go
@@ -824,6 +824,21 @@ func (s *testSuiteAgg) TestIssue16279(c *C) {
 	tk.MustQuery("select count(a) , date_format(a, '%Y-%m-%d') as xx from s group by xx")
 }
 
+func (s *testSuiteAgg) TestIssue24676(c *C) {
+	tk := testkit.NewTestKit(c, s.store)
+	tk.MustExec("use test")
+	tk.MustExec("set sql_mode = 'ONLY_FULL_GROUP_BY'")
+	tk.MustExec("drop table if exists t1")
+	tk.MustExec(`create table t1(
+		id int(11) NOT NULL PRIMARY KEY,
+		c1 int(11) NOT NULL DEFAULT '0'
+		)`)
+	tk.MustQuery("SELECT c1 FROM t1 GROUP BY c1 ORDER BY c1 ASC;")
+	tk.MustQuery("SELECT ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) AS `c1` FROM `t1` GROUP BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ORDER BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ASC;")
+	err := tk.ExecToErr("SELECT ((floor(((`c1` - 10) / 300)) * 50000) + 0.0) AS `c1` FROM `t1` GROUP BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ORDER BY ((floor(((`c1` - 0.0) / 50000)) * 50000) + 0.0) ASC;")
+	c.Assert(terror.ErrorEqual(err, plannercore.ErrFieldNotInGroupBy), IsTrue, Commentf("err %v", err))
+}
+
 func (s *testSuiteAgg) TestAggPushDownPartitionTable(c *C) {
 	tk := testkit.NewTestKit(c, s.store)
 	tk.MustExec("use test")