Repository: pingcap/tidb (Go)

Issue:
Unexpected result when limit used in CTE
## Bug Report

Please answer these questions before submitting your issue. Thanks!

### 1. Minimal reproduce step (Required)

    drop table if exists t;
    create table t(a int, b int);
    insert into t values (1, 1),(2, 2),(3, 3),(1, 1),(2, 2),(3, 3);
    with recursive cte(a) as (select a from t union all select a + 1 from cte limit 10) select * from cte;
<!-- a step by step guide for reproducing the bug. -->

### 2. What did you expect to see? (Required)

    mysql>     with recursive cte(a) as (select a from t union all select a + 1 from cte limit 10) select * from cte;
    +------+
    | a    |
    +------+
    |    1 |
    |    2 |
    |    3 |
    |    1 |
    |    2 |
    |    3 |
    |    2 |
    |    3 |
    |    4 |
    |    2 |
    +------+
    10 rows in set (0.00 sec)
### 3. What did you see instead (Required)

    mysql>     with recursive cte(a) as (select a from t union all select a + 1 from cte limit 10) select * from cte;
    +------+
    | a    |
    +------+
    |    1 |
    |    2 |
    |    3 |
    |    1 |
    |    2 |
    |    3 |
    |    2 |
    |    3 |
    |    4 |
    |    2 |
    |    3 |
    +------+
    11 rows in set (0.01 sec)

### 4. What is your TiDB version? (Required)

master
<!-- Paste the output of SELECT tidb_version() -->




Discussion:
## 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/executor/cte.go b/executor/cte.go
index fb0aaccb3d512..6ac26a50541b0 100644
--- a/executor/cte.go
+++ b/executor/cte.go
@@ -328,7 +328,7 @@ func (e *CTEExec) nextChunkLimit(req *chunk.Chunk) error {
 		numRows := uint64(res.NumRows())
 		if e.cursor+numRows > e.limitEnd {
 			numRows = e.limitEnd - e.cursor
-			req.Append(res.CopyConstructSel(), 0, int(numRows)+1)
+			req.Append(res.CopyConstructSel(), 0, int(numRows))
 		} else {
 			req.SwapColumns(res.CopyConstructSel())
 		}


Test patch:
diff --git a/executor/cte_test.go b/executor/cte_test.go
index aa7c2804425c8..4c6e1cf993975 100644
--- a/executor/cte_test.go
+++ b/executor/cte_test.go
@@ -373,4 +373,75 @@ func (test *CTETestSuite) TestCTEWithLimit(c *check.C) {
 	err = tk.QueryToErr("with recursive cte1 as (select 1/c1 c1 from t1 union select c1 + 1 c1 from cte1 where c1 < 2 limit 1) select * from cte1;")
 	c.Assert(err, check.NotNil)
 	c.Assert(err.Error(), check.Equals, "[executor:3636]Recursive query aborted after 1 iterations. Try increasing @@cte_max_recursion_depth to a larger value")
+
+	tk.MustExec("set cte_max_recursion_depth = 1000;")
+	tk.MustExec("drop table if exists t1;")
+	tk.MustExec("create table t1(c1 int);")
+	tk.MustExec("insert into t1 values(1), (2), (3);")
+
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 0 offset 2) select * from cte1;")
+	rows.Check(testkit.Rows())
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 1 offset 2) select * from cte1;")
+	rows.Check(testkit.Rows("3"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 2 offset 2) select * from cte1;")
+	rows.Check(testkit.Rows("3", "4"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 3 offset 2) select * from cte1;")
+	rows.Check(testkit.Rows("3", "4", "5"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 4 offset 2) select * from cte1;")
+	rows.Check(testkit.Rows("3", "4", "5", "6"))
+
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 0 offset 3) select * from cte1;")
+	rows.Check(testkit.Rows())
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 1 offset 3) select * from cte1;")
+	rows.Check(testkit.Rows("4"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 2 offset 3) select * from cte1;")
+	rows.Check(testkit.Rows("4", "5"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 3 offset 3) select * from cte1;")
+	rows.Check(testkit.Rows("4", "5", "6"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 4 offset 3) select * from cte1;")
+	rows.Check(testkit.Rows("4", "5", "6", "7"))
+
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 0 offset 4) select * from cte1;")
+	rows.Check(testkit.Rows())
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 1 offset 4) select * from cte1;")
+	rows.Check(testkit.Rows("5"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 2 offset 4) select * from cte1;")
+	rows.Check(testkit.Rows("5", "6"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 3 offset 4) select * from cte1;")
+	rows.Check(testkit.Rows("5", "6", "7"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union select c1 + 1 from cte1 limit 4 offset 4) select * from cte1;")
+	rows.Check(testkit.Rows("5", "6", "7", "8"))
+
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 0 offset 2) select * from cte1;")
+	rows.Check(testkit.Rows())
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 1 offset 2) select * from cte1;")
+	rows.Check(testkit.Rows("3"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 2 offset 2) select * from cte1;")
+	rows.Check(testkit.Rows("3", "2"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 3 offset 2) select * from cte1;")
+	rows.Check(testkit.Rows("3", "2", "3"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 4 offset 2) select * from cte1;")
+	rows.Check(testkit.Rows("3", "2", "3", "4"))
+
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 0 offset 3) select * from cte1;")
+	rows.Check(testkit.Rows())
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 1 offset 3) select * from cte1;")
+	rows.Check(testkit.Rows("2"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 2 offset 3) select * from cte1;")
+	rows.Check(testkit.Rows("2", "3"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 3 offset 3) select * from cte1;")
+	rows.Check(testkit.Rows("2", "3", "4"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 4 offset 3) select * from cte1;")
+	rows.Check(testkit.Rows("2", "3", "4", "3"))
+
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 0 offset 4) select * from cte1;")
+	rows.Check(testkit.Rows())
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 1 offset 4) select * from cte1;")
+	rows.Check(testkit.Rows("3"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 2 offset 4) select * from cte1;")
+	rows.Check(testkit.Rows("3", "4"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 3 offset 4) select * from cte1;")
+	rows.Check(testkit.Rows("3", "4", "3"))
+	rows = tk.MustQuery("with recursive cte1(c1) as (select c1 from t1 union all select c1 + 1 from cte1 limit 4 offset 4) select * from cte1;")
+	rows.Check(testkit.Rows("3", "4", "3", "4"))
 }