diff --git a/README.md b/README.md index f3c07bf0b1ad8..b4fcc35237280 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,6 @@ In addition, you may enjoy following: - [@PingCAP](https://twitter.com/PingCAP) on Twitter - Question tagged [#tidb on StackOverflow](https://stackoverflow.com/questions/tagged/tidb) - The PingCAP Team [English Blog](https://en.pingcap.com/blog) and [Chinese Blog](https://pingcap.com/blog-cn/) -- [TiDB Monthly](https://pingcap.com/weekly/) For support, please contact [PingCAP](http://bit.ly/contact_us_via_github). diff --git a/executor/aggregate_test.go b/executor/aggregate_test.go index 94820a028123d..85e8bcc4f236d 100644 --- a/executor/aggregate_test.go +++ b/executor/aggregate_test.go @@ -1293,12 +1293,14 @@ func (s *testSuiteAgg) TestIssue20658(c *C) { tk.MustExec("CREATE TABLE t(a bigint, b bigint);") tk.MustExec("set tidb_init_chunk_size=1;") tk.MustExec("set tidb_max_chunk_size=32;") + randSeed := time.Now().UnixNano() + r := rand.New(rand.NewSource(randSeed)) var insertSQL string for i := 0; i < 1000; i++ { if i == 0 { - insertSQL += fmt.Sprintf("(%d, %d)", rand.Intn(100), rand.Intn(100)) + insertSQL += fmt.Sprintf("(%d, %d)", r.Intn(100), r.Intn(100)) } else { - insertSQL += fmt.Sprintf(",(%d, %d)", rand.Intn(100), rand.Intn(100)) + insertSQL += fmt.Sprintf(",(%d, %d)", r.Intn(100), r.Intn(100)) } } tk.MustExec(fmt.Sprintf("insert into t values %s;", insertSQL)) @@ -1307,7 +1309,7 @@ func (s *testSuiteAgg) TestIssue20658(c *C) { for _, sql := range sqls { var expected [][]interface{} for _, con := range concurrencies { - comment := Commentf("sql: %s; concurrency: %d", sql, con) + comment := Commentf("sql: %s; concurrency: %d, seed: ", sql, con, randSeed) tk.MustExec(fmt.Sprintf("set @@tidb_streamagg_concurrency=%d;", con)) if con == 1 { expected = tk.MustQuery(sql).Sort().Rows() diff --git a/executor/builder.go b/executor/builder.go index b04dfe45f4bab..c8a128e505562 100644 --- a/executor/builder.go +++ b/executor/builder.go @@ -706,10 +706,11 @@ func (b *executorBuilder) buildSimple(v *plannercore.Simple) Executor { base := newBaseExecutor(b.ctx, v.Schema(), v.ID()) base.initCap = chunk.ZeroCapacity e := &SimpleExec{ - baseExecutor: base, - Statement: v.Statement, - IsFromRemote: v.IsFromRemote, - is: b.is, + baseExecutor: base, + Statement: v.Statement, + IsFromRemote: v.IsFromRemote, + is: b.is, + StalenessTxnOption: v.StalenessTxnOption, } return e } diff --git a/executor/executor_test.go b/executor/executor_test.go index 8836b4f59fbd3..a796a27326a70 100644 --- a/executor/executor_test.go +++ b/executor/executor_test.go @@ -3067,9 +3067,10 @@ func (s *testSerialSuite) TestTiDBLastTxnInfoCommitMode(c *C) { c.Assert(rows[0][1], Equals, "false") c.Assert(rows[0][2], Equals, "false") - config.UpdateGlobal(func(conf *config.Config) { - conf.TiKVClient.AsyncCommit.SafeWindow = 0 - }) + c.Assert(failpoint.Enable("github.com/pingcap/tidb/store/tikv/invalidMaxCommitTS", "return"), IsNil) + defer func() { + c.Assert(failpoint.Disable("github.com/pingcap/tidb/store/tikv/invalidMaxCommitTS"), IsNil) + }() tk.MustExec("set @@tidb_enable_async_commit = 1") tk.MustExec("set @@tidb_enable_1pc = 0") diff --git a/executor/memtable_reader.go b/executor/memtable_reader.go index 76ea478d91e71..f98306b5da51d 100644 --- a/executor/memtable_reader.go +++ b/executor/memtable_reader.go @@ -191,6 +191,9 @@ func fetchClusterConfig(sctx sessionctx.Context, nodeTypes, nodeAddrs set.String url = fmt.Sprintf("%s://%s%s", util.InternalHTTPSchema(), statusAddr, pdapi.Config) case "tikv", "tidb": url = fmt.Sprintf("%s://%s/config", util.InternalHTTPSchema(), statusAddr) + case "tiflash": + // TODO: support show tiflash config once tiflash supports it + return default: ch <- result{err: errors.Errorf("unknown node type: %s(%s)", typ, address)} return diff --git a/executor/memtable_reader_test.go b/executor/memtable_reader_test.go index 53607dd80ef03..5b55a9d601b03 100644 --- a/executor/memtable_reader_test.go +++ b/executor/memtable_reader_test.go @@ -170,7 +170,7 @@ func (s *testMemTableReaderSuite) TestTiDBClusterConfig(c *C) { // mock servers servers := []string{} - for _, typ := range []string{"tidb", "tikv", "pd"} { + for _, typ := range []string{"tidb", "tikv", "tiflash", "pd"} { for _, server := range testServers { servers = append(servers, strings.Join([]string{typ, server.address, server.address}, ",")) } diff --git a/executor/partition_table_test.go b/executor/partition_table_test.go index 446e689184086..7398789eadba5 100644 --- a/executor/partition_table_test.go +++ b/executor/partition_table_test.go @@ -1829,3 +1829,49 @@ PARTITION BY RANGE (a) ( s.testData.GetTestCases(c, &input, &output) s.verifyPartitionResult(tk, input, output) } + +func (s *testSuiteWithData) TestRangePartitionBoundariesLtM(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("set @@tidb_partition_prune_mode = 'dynamic'") + tk.MustExec("create database TestRangePartitionBoundariesLtM") + defer tk.MustExec("drop database TestRangePartitionBoundariesLtM") + tk.MustExec("use TestRangePartitionBoundariesLtM") + tk.MustExec("drop table if exists t") + tk.MustExec(`CREATE TABLE t +(a INT, b varchar(255)) +PARTITION BY RANGE (a) ( + PARTITION p0 VALUES LESS THAN (1000000), + PARTITION p1 VALUES LESS THAN (2000000), + PARTITION p2 VALUES LESS THAN (3000000))`) + + var input []string + var output []testOutput + s.testData.GetTestCases(c, &input, &output) + s.verifyPartitionResult(tk, input, output) +} + +func (s *testSuiteWithData) TestRangePartitionBoundariesLtS(c *C) { + tk := testkit.NewTestKit(c, s.store) + + tk.MustExec("set @@tidb_partition_prune_mode = 'dynamic'") + tk.MustExec("create database TestRangePartitionBoundariesLtS") + defer tk.MustExec("drop database TestRangePartitionBoundariesLtS") + tk.MustExec("use TestRangePartitionBoundariesLtS") + tk.MustExec("drop table if exists t") + tk.MustExec(`CREATE TABLE t +(a INT, b varchar(255)) +PARTITION BY RANGE (a) ( + PARTITION p0 VALUES LESS THAN (1), + PARTITION p1 VALUES LESS THAN (2), + PARTITION p2 VALUES LESS THAN (3), + PARTITION p3 VALUES LESS THAN (4), + PARTITION p4 VALUES LESS THAN (5), + PARTITION p5 VALUES LESS THAN (6), + PARTITION p6 VALUES LESS THAN (7))`) + + var input []string + var output []testOutput + s.testData.GetTestCases(c, &input, &output) + s.verifyPartitionResult(tk, input, output) +} diff --git a/executor/simple.go b/executor/simple.go index 3c45ee05ada4e..193949eda3fdd 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -74,6 +74,9 @@ type SimpleExec struct { IsFromRemote bool done bool is infoschema.InfoSchema + + // StalenessTxnOption is used to execute the staleness txn during a read-only begin statement. + StalenessTxnOption *sessionctx.StalenessTxnOption } func (e *baseExecutor) getSysSession() (sessionctx.Context, error) { @@ -566,13 +569,16 @@ func (e *SimpleExec) executeUse(s *ast.UseStmt) error { } func (e *SimpleExec) executeBegin(ctx context.Context, s *ast.BeginStmt) error { - // If `START TRANSACTION READ ONLY WITH TIMESTAMP BOUND` is the first statement in TxnCtx, we should + // If `START TRANSACTION READ ONLY` is the first statement in TxnCtx, we should // always create a new Txn instead of reusing it. if s.ReadOnly { enableNoopFuncs := e.ctx.GetSessionVars().EnableNoopFuncs - if !enableNoopFuncs && s.Bound == nil { + if !enableNoopFuncs && s.AsOf == nil && s.Bound == nil { return expression.ErrFunctionsNoopImpl.GenWithStackByArgs("READ ONLY") } + if s.AsOf != nil { + return e.executeStartTransactionReadOnlyWithBoundedStaleness(ctx, s) + } if s.Bound != nil { return e.executeStartTransactionReadOnlyWithTimestampBound(ctx, s) } @@ -614,6 +620,22 @@ func (e *SimpleExec) executeBegin(ctx context.Context, s *ast.BeginStmt) error { return nil } +func (e *SimpleExec) executeStartTransactionReadOnlyWithBoundedStaleness(ctx context.Context, s *ast.BeginStmt) error { + if e.StalenessTxnOption == nil { + return errors.New("Failed to get timestamp during start transaction read only as of timestamp") + } + if err := e.ctx.NewTxnWithStalenessOption(ctx, *e.StalenessTxnOption); err != nil { + return err + } + + // With START TRANSACTION, autocommit remains disabled until you end + // the transaction with COMMIT or ROLLBACK. The autocommit mode then + // reverts to its previous state. + e.ctx.GetSessionVars().SetInTxn(true) + return nil +} + +// TODO: deprecate this syntax and only keep `AS OF TIMESTAMP` statement. func (e *SimpleExec) executeStartTransactionReadOnlyWithTimestampBound(ctx context.Context, s *ast.BeginStmt) error { opt := sessionctx.StalenessTxnOption{} opt.Mode = s.Bound.Mode @@ -632,8 +654,7 @@ func (e *SimpleExec) executeStartTransactionReadOnlyWithTimestampBound(ctx conte if err != nil { return err } - startTS := oracle.GoTimeToTS(gt) - opt.StartTS = startTS + opt.StartTS = oracle.GoTimeToTS(gt) case ast.TimestampBoundExactStaleness: // TODO: support funcCallExpr in future v, ok := s.Bound.Timestamp.(*driver.ValueExpr) @@ -668,8 +689,7 @@ func (e *SimpleExec) executeStartTransactionReadOnlyWithTimestampBound(ctx conte if err != nil { return err } - startTS := oracle.GoTimeToTS(gt) - opt.StartTS = startTS + opt.StartTS = oracle.GoTimeToTS(gt) } err := e.ctx.NewTxnWithStalenessOption(ctx, opt) if err != nil { diff --git a/executor/stale_txn_test.go b/executor/stale_txn_test.go index db2b55a9a1637..dc5ddd0785208 100644 --- a/executor/stale_txn_test.go +++ b/executor/stale_txn_test.go @@ -73,13 +73,30 @@ func (s *testStaleTxnSerialSuite) TestExactStalenessTransaction(c *C) { zone: "sz", }, { - name: "begin", + name: "begin after TimestampBoundReadTimestamp", preSQL: `START TRANSACTION READ ONLY WITH TIMESTAMP BOUND READ TIMESTAMP '2020-09-06 00:00:00';`, sql: "begin", IsStaleness: false, txnScope: kv.GlobalTxnScope, zone: "", }, + { + name: "AsOfTimestamp", + preSQL: "begin", + sql: `START TRANSACTION READ ONLY AS OF TIMESTAMP '2020-09-06 00:00:00';`, + IsStaleness: true, + expectPhysicalTS: 1599321600000, + txnScope: "local", + zone: "sh", + }, + { + name: "begin after AsOfTimestamp", + preSQL: `START TRANSACTION READ ONLY AS OF TIMESTAMP '2020-09-06 00:00:00';`, + sql: "begin", + IsStaleness: false, + txnScope: oracle.GlobalTxnScope, + zone: "", + }, } tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") @@ -106,8 +123,8 @@ func (s *testStaleTxnSerialSuite) TestExactStalenessTransaction(c *C) { } c.Assert(tk.Se.GetSessionVars().TxnCtx.IsStaleness, Equals, testcase.IsStaleness) tk.MustExec("commit") - failpoint.Disable("github.com/pingcap/tidb/config/injectTxnScope") } + failpoint.Disable("github.com/pingcap/tidb/config/injectTxnScope") } func (s *testStaleTxnSerialSuite) TestStaleReadKVRequest(c *C) { @@ -147,13 +164,17 @@ func (s *testStaleTxnSerialSuite) TestStaleReadKVRequest(c *C) { failpoint.Enable("github.com/pingcap/tidb/config/injectTxnScope", fmt.Sprintf(`return("%v")`, testcase.zone)) failpoint.Enable("github.com/pingcap/tidb/store/tikv/assertStoreLabels", fmt.Sprintf(`return("%v_%v")`, placement.DCLabelKey, testcase.txnScope)) failpoint.Enable("github.com/pingcap/tidb/store/tikv/assertStaleReadFlag", `return(true)`) + // Using NOW() will cause the loss of fsp precision, so we use NOW(3) to be accurate to the millisecond. + tk.MustExec(`START TRANSACTION READ ONLY AS OF TIMESTAMP NOW(3);`) + tk.MustQuery(testcase.sql) + tk.MustExec(`commit`) tk.MustExec(`START TRANSACTION READ ONLY WITH TIMESTAMP BOUND EXACT STALENESS '00:00:00';`) tk.MustQuery(testcase.sql) tk.MustExec(`commit`) - failpoint.Disable("github.com/pingcap/tidb/config/injectTxnScope") - failpoint.Disable("github.com/pingcap/tidb/store/tikv/assertStoreLabels") - failpoint.Disable("github.com/pingcap/tidb/store/tikv/assertStaleReadFlag") } + failpoint.Disable("github.com/pingcap/tidb/config/injectTxnScope") + failpoint.Disable("github.com/pingcap/tidb/store/tikv/assertStoreLabels") + failpoint.Disable("github.com/pingcap/tidb/store/tikv/assertStaleReadFlag") } func (s *testStaleTxnSerialSuite) TestStalenessAndHistoryRead(c *C) { @@ -169,6 +190,17 @@ func (s *testStaleTxnSerialSuite) TestStalenessAndHistoryRead(c *C) { tk.MustExec(updateSafePoint) // set @@tidb_snapshot before staleness txn tk.MustExec(`set @@tidb_snapshot="2016-10-08 16:45:26";`) + tk.MustExec(`START TRANSACTION READ ONLY AS OF TIMESTAMP '2020-09-06 00:00:00';`) + // 1599321600000 == 2020-09-06 00:00:00 + c.Assert(oracle.ExtractPhysical(tk.Se.GetSessionVars().TxnCtx.StartTS), Equals, int64(1599321600000)) + tk.MustExec("commit") + // set @@tidb_snapshot during staleness txn + tk.MustExec(`START TRANSACTION READ ONLY AS OF TIMESTAMP '2020-09-06 00:00:00';`) + tk.MustExec(`set @@tidb_snapshot="2016-10-08 16:45:26";`) + c.Assert(oracle.ExtractPhysical(tk.Se.GetSessionVars().TxnCtx.StartTS), Equals, int64(1599321600000)) + tk.MustExec("commit") + // set @@tidb_snapshot before staleness txn + tk.MustExec(`set @@tidb_snapshot="2016-10-08 16:45:26";`) tk.MustExec(`START TRANSACTION READ ONLY WITH TIMESTAMP BOUND READ TIMESTAMP '2020-09-06 00:00:00';`) c.Assert(oracle.ExtractPhysical(tk.Se.GetSessionVars().TxnCtx.StartTS), Equals, int64(1599321600000)) tk.MustExec("commit") @@ -190,23 +222,20 @@ func (s *testStaleTxnSerialSuite) TestTimeBoundedStalenessTxn(c *C) { name string sql string injectSafeTS uint64 - useSafeTS bool + // compareWithSafeTS will be 0 if StartTS==SafeTS, -1 if StartTS < SafeTS, and +1 if StartTS > SafeTS. + compareWithSafeTS int }{ { - name: "max 20 seconds ago, safeTS 10 secs ago", - sql: `START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MAX STALENESS '00:00:20'`, - injectSafeTS: func() uint64 { - return oracle.GoTimeToTS(time.Now().Add(-10 * time.Second)) - }(), - useSafeTS: true, + name: "max 20 seconds ago, safeTS 10 secs ago", + sql: `START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MAX STALENESS '00:00:20'`, + injectSafeTS: oracle.GoTimeToTS(time.Now().Add(-10 * time.Second)), + compareWithSafeTS: 0, }, { - name: "max 10 seconds ago, safeTS 20 secs ago", - sql: `START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MAX STALENESS '00:00:10'`, - injectSafeTS: func() uint64 { - return oracle.GoTimeToTS(time.Now().Add(-20 * time.Second)) - }(), - useSafeTS: false, + name: "max 10 seconds ago, safeTS 20 secs ago", + sql: `START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MAX STALENESS '00:00:10'`, + injectSafeTS: oracle.GoTimeToTS(time.Now().Add(-20 * time.Second)), + compareWithSafeTS: 1, }, { name: "max 20 seconds ago, safeTS 10 secs ago", @@ -214,10 +243,8 @@ func (s *testStaleTxnSerialSuite) TestTimeBoundedStalenessTxn(c *C) { return fmt.Sprintf(`START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MIN READ TIMESTAMP '%v'`, time.Now().Add(-20*time.Second).Format("2006-01-02 15:04:05")) }(), - injectSafeTS: func() uint64 { - return oracle.GoTimeToTS(time.Now().Add(-10 * time.Second)) - }(), - useSafeTS: true, + injectSafeTS: oracle.GoTimeToTS(time.Now().Add(-10 * time.Second)), + compareWithSafeTS: 0, }, { name: "max 10 seconds ago, safeTS 20 secs ago", @@ -225,25 +252,46 @@ func (s *testStaleTxnSerialSuite) TestTimeBoundedStalenessTxn(c *C) { return fmt.Sprintf(`START TRANSACTION READ ONLY WITH TIMESTAMP BOUND MIN READ TIMESTAMP '%v'`, time.Now().Add(-10*time.Second).Format("2006-01-02 15:04:05")) }(), - injectSafeTS: func() uint64 { - return oracle.GoTimeToTS(time.Now().Add(-20 * time.Second)) - }(), - useSafeTS: false, + injectSafeTS: oracle.GoTimeToTS(time.Now().Add(-20 * time.Second)), + compareWithSafeTS: 1, + }, + { + name: "20 seconds ago to now, safeTS 10 secs ago", + sql: `START TRANSACTION READ ONLY AS OF TIMESTAMP tidb_bounded_staleness(NOW() - INTERVAL 20 SECOND, NOW())`, + injectSafeTS: oracle.GoTimeToTS(time.Now().Add(-10 * time.Second)), + compareWithSafeTS: 0, + }, + { + name: "10 seconds ago to now, safeTS 20 secs ago", + sql: `START TRANSACTION READ ONLY AS OF TIMESTAMP tidb_bounded_staleness(NOW() - INTERVAL 10 SECOND, NOW())`, + injectSafeTS: oracle.GoTimeToTS(time.Now().Add(-20 * time.Second)), + compareWithSafeTS: 1, + }, + { + name: "20 seconds ago to 10 seconds ago, safeTS 5 secs ago", + sql: `START TRANSACTION READ ONLY AS OF TIMESTAMP tidb_bounded_staleness(NOW() - INTERVAL 20 SECOND, NOW() - INTERVAL 10 SECOND)`, + injectSafeTS: oracle.GoTimeToTS(time.Now().Add(-5 * time.Second)), + compareWithSafeTS: -1, }, } for _, testcase := range testcases { c.Log(testcase.name) c.Assert(failpoint.Enable("github.com/pingcap/tidb/store/tikv/injectSafeTS", fmt.Sprintf("return(%v)", testcase.injectSafeTS)), IsNil) + c.Assert(failpoint.Enable("github.com/pingcap/tidb/expression/injectSafeTS", + fmt.Sprintf("return(%v)", testcase.injectSafeTS)), IsNil) tk.MustExec(testcase.sql) - if testcase.useSafeTS { + if testcase.compareWithSafeTS == 1 { + c.Assert(tk.Se.GetSessionVars().TxnCtx.StartTS, Greater, testcase.injectSafeTS) + } else if testcase.compareWithSafeTS == 0 { c.Assert(tk.Se.GetSessionVars().TxnCtx.StartTS, Equals, testcase.injectSafeTS) } else { - c.Assert(tk.Se.GetSessionVars().TxnCtx.StartTS, Greater, testcase.injectSafeTS) + c.Assert(tk.Se.GetSessionVars().TxnCtx.StartTS, Less, testcase.injectSafeTS) } tk.MustExec("commit") - failpoint.Disable("github.com/pingcap/tidb/store/tikv/injectSafeTS") } + failpoint.Disable("github.com/pingcap/tidb/expression/injectSafeTS") + failpoint.Disable("github.com/pingcap/tidb/store/tikv/injectSafeTS") } func (s *testStaleTxnSerialSuite) TestStalenessTransactionSchemaVer(c *C) { @@ -263,4 +311,16 @@ func (s *testStaleTxnSerialSuite) TestStalenessTransactionSchemaVer(c *C) { schemaVer3 := tk.Se.GetSessionVars().GetInfoSchema().SchemaMetaVersion() // got an old infoSchema c.Assert(schemaVer3, Equals, schemaVer1) + + schemaVer4 := tk.Se.GetSessionVars().GetInfoSchema().SchemaMetaVersion() + time.Sleep(time.Second) + tk.MustExec("create table t (id int primary key);") + schemaVer5 := tk.Se.GetSessionVars().GetInfoSchema().SchemaMetaVersion() + // confirm schema changed + c.Assert(schemaVer4, Less, schemaVer5) + + tk.MustExec(`START TRANSACTION READ ONLY AS OF TIMESTAMP NOW() - INTERVAL 1 SECOND`) + schemaVer6 := tk.Se.GetSessionVars().GetInfoSchema().SchemaMetaVersion() + // got an old infoSchema + c.Assert(schemaVer6, Equals, schemaVer4) } diff --git a/executor/testdata/executor_suite_in.json b/executor/testdata/executor_suite_in.json index a8db9425a7078..cd8fa234c0117 100644 --- a/executor/testdata/executor_suite_in.json +++ b/executor/testdata/executor_suite_in.json @@ -273,5 +273,340 @@ "SELECT * FROM t WHERE a BETWEEN 2 AND 7", "SELECT * FROM t WHERE a BETWEEN 7 AND 4" ] + }, + { + "name": "TestRangePartitionBoundariesLtM", + "cases": [ + "INSERT INTO t VALUES (999998, '999998 Filler ...'), (999999, '999999 Filler ...'), (1000000, '1000000 Filler ...'), (1000001, '1000001 Filler ...'), (1000002, '1000002 Filler ...')", + "INSERT INTO t VALUES (1999998, '1999998 Filler ...'), (1999999, '1999999 Filler ...'), (2000000, '2000000 Filler ...'), (2000001, '2000001 Filler ...'), (2000002, '2000002 Filler ...')", + "INSERT INTO t VALUES (2999998, '2999998 Filler ...'), (2999999, '2999999 Filler ...')", + "INSERT INTO t VALUES (-2147483648, 'MIN_INT filler...'), (0, '0 Filler...')", + "ANALYZE TABLE t", + "SELECT * FROM t WHERE a < -2147483648", + "SELECT * FROM t WHERE a > -2147483648", + "SELECT * FROM t WHERE a <= -2147483648", + "SELECT * FROM t WHERE a >= -2147483648", + "SELECT * FROM t WHERE a < 0", + "SELECT * FROM t WHERE a > 0", + "SELECT * FROM t WHERE a <= 0", + "SELECT * FROM t WHERE a >= 0", + "SELECT * FROM t WHERE a < 999998", + "SELECT * FROM t WHERE a > 999998", + "SELECT * FROM t WHERE a <= 999998", + "SELECT * FROM t WHERE a >= 999998", + "SELECT * FROM t WHERE a < 999999", + "SELECT * FROM t WHERE a > 999999", + "SELECT * FROM t WHERE a <= 999999", + "SELECT * FROM t WHERE a >= 999999", + "SELECT * FROM t WHERE a < 1000000", + "SELECT * FROM t WHERE a > 1000000", + "SELECT * FROM t WHERE a <= 1000000", + "SELECT * FROM t WHERE a >= 1000000", + "SELECT * FROM t WHERE a < 1000001", + "SELECT * FROM t WHERE a > 1000001", + "SELECT * FROM t WHERE a <= 1000001", + "SELECT * FROM t WHERE a >= 1000001", + "SELECT * FROM t WHERE a < 1000002", + "SELECT * FROM t WHERE a > 1000002", + "SELECT * FROM t WHERE a <= 1000002", + "SELECT * FROM t WHERE a >= 1000002", + "SELECT * FROM t WHERE a < 3000000", + "SELECT * FROM t WHERE a > 3000000", + "SELECT * FROM t WHERE a <= 3000000", + "SELECT * FROM t WHERE a >= 3000000", + "SELECT * FROM t WHERE a < 3000001", + "SELECT * FROM t WHERE a > 3000001", + "SELECT * FROM t WHERE a <= 3000001", + "SELECT * FROM t WHERE a >= 3000001", + "SELECT * FROM t WHERE a < 999997", + "SELECT * FROM t WHERE a > 999997", + "SELECT * FROM t WHERE a <= 999997", + "SELECT * FROM t WHERE a >= 999997", + "SELECT * FROM t WHERE a >= 999997 AND a <= 999999", + "SELECT * FROM t WHERE a > 999997 AND a <= 999999", + "SELECT * FROM t WHERE a > 999997 AND a < 999999", + "SELECT * FROM t WHERE a > 999997 AND a <= 999999", + "SELECT * FROM t WHERE a < 999998", + "SELECT * FROM t WHERE a > 999998", + "SELECT * FROM t WHERE a <= 999998", + "SELECT * FROM t WHERE a >= 999998", + "SELECT * FROM t WHERE a >= 999998 AND a <= 1000000", + "SELECT * FROM t WHERE a > 999998 AND a <= 1000000", + "SELECT * FROM t WHERE a > 999998 AND a < 1000000", + "SELECT * FROM t WHERE a > 999998 AND a <= 1000000", + "SELECT * FROM t WHERE a < 999999", + "SELECT * FROM t WHERE a > 999999", + "SELECT * FROM t WHERE a <= 999999", + "SELECT * FROM t WHERE a >= 999999", + "SELECT * FROM t WHERE a >= 999999 AND a <= 1000001", + "SELECT * FROM t WHERE a > 999999 AND a <= 1000001", + "SELECT * FROM t WHERE a > 999999 AND a < 1000001", + "SELECT * FROM t WHERE a > 999999 AND a <= 1000001", + "SELECT * FROM t WHERE a < 1000000", + "SELECT * FROM t WHERE a > 1000000", + "SELECT * FROM t WHERE a <= 1000000", + "SELECT * FROM t WHERE a >= 1000000", + "SELECT * FROM t WHERE a >= 1000000 AND a <= 1000002", + "SELECT * FROM t WHERE a > 1000000 AND a <= 1000002", + "SELECT * FROM t WHERE a > 1000000 AND a < 1000002", + "SELECT * FROM t WHERE a > 1000000 AND a <= 1000002", + "SELECT * FROM t WHERE a < 1999997", + "SELECT * FROM t WHERE a > 1999997", + "SELECT * FROM t WHERE a <= 1999997", + "SELECT * FROM t WHERE a >= 1999997", + "SELECT * FROM t WHERE a >= 1999997 AND a <= 1999999", + "SELECT * FROM t WHERE a > 1999997 AND a <= 1999999", + "SELECT * FROM t WHERE a > 1999997 AND a < 1999999", + "SELECT * FROM t WHERE a > 1999997 AND a <= 1999999", + "SELECT * FROM t WHERE a < 1999998", + "SELECT * FROM t WHERE a > 1999998", + "SELECT * FROM t WHERE a <= 1999998", + "SELECT * FROM t WHERE a >= 1999998", + "SELECT * FROM t WHERE a >= 1999998 AND a <= 2000000", + "SELECT * FROM t WHERE a > 1999998 AND a <= 2000000", + "SELECT * FROM t WHERE a > 1999998 AND a < 2000000", + "SELECT * FROM t WHERE a > 1999998 AND a <= 2000000", + "SELECT * FROM t WHERE a < 1999999", + "SELECT * FROM t WHERE a > 1999999", + "SELECT * FROM t WHERE a <= 1999999", + "SELECT * FROM t WHERE a >= 1999999", + "SELECT * FROM t WHERE a >= 1999999 AND a <= 2000001", + "SELECT * FROM t WHERE a > 1999999 AND a <= 2000001", + "SELECT * FROM t WHERE a > 1999999 AND a < 2000001", + "SELECT * FROM t WHERE a > 1999999 AND a <= 2000001", + "SELECT * FROM t WHERE a < 2000000", + "SELECT * FROM t WHERE a > 2000000", + "SELECT * FROM t WHERE a <= 2000000", + "SELECT * FROM t WHERE a >= 2000000", + "SELECT * FROM t WHERE a >= 2000000 AND a <= 2000002", + "SELECT * FROM t WHERE a > 2000000 AND a <= 2000002", + "SELECT * FROM t WHERE a > 2000000 AND a < 2000002", + "SELECT * FROM t WHERE a > 2000000 AND a <= 2000002", + "SELECT * FROM t WHERE a < 2999997", + "SELECT * FROM t WHERE a > 2999997", + "SELECT * FROM t WHERE a <= 2999997", + "SELECT * FROM t WHERE a >= 2999997", + "SELECT * FROM t WHERE a >= 2999997 AND a <= 2999999", + "SELECT * FROM t WHERE a > 2999997 AND a <= 2999999", + "SELECT * FROM t WHERE a > 2999997 AND a < 2999999", + "SELECT * FROM t WHERE a > 2999997 AND a <= 2999999", + "SELECT * FROM t WHERE a < 2999998", + "SELECT * FROM t WHERE a > 2999998", + "SELECT * FROM t WHERE a <= 2999998", + "SELECT * FROM t WHERE a >= 2999998", + "SELECT * FROM t WHERE a >= 2999998 AND a <= 3000000", + "SELECT * FROM t WHERE a > 2999998 AND a <= 3000000", + "SELECT * FROM t WHERE a > 2999998 AND a < 3000000", + "SELECT * FROM t WHERE a > 2999998 AND a <= 3000000", + "SELECT * FROM t WHERE a < 2999999", + "SELECT * FROM t WHERE a > 2999999", + "SELECT * FROM t WHERE a <= 2999999", + "SELECT * FROM t WHERE a >= 2999999", + "SELECT * FROM t WHERE a >= 2999999 AND a <= 3000001", + "SELECT * FROM t WHERE a > 2999999 AND a <= 3000001", + "SELECT * FROM t WHERE a > 2999999 AND a < 3000001", + "SELECT * FROM t WHERE a > 2999999 AND a <= 3000001", + "SELECT * FROM t WHERE a < 3000000", + "SELECT * FROM t WHERE a > 3000000", + "SELECT * FROM t WHERE a <= 3000000", + "SELECT * FROM t WHERE a >= 3000000", + "SELECT * FROM t WHERE a >= 3000000 AND a <= 3000002", + "SELECT * FROM t WHERE a > 3000000 AND a <= 3000002", + "SELECT * FROM t WHERE a > 3000000 AND a < 3000002", + "SELECT * FROM t WHERE a > 3000000 AND a <= 3000002" + ] + }, + { + "name": "TestRangePartitionBoundariesLtS", + "cases": [ + "INSERT INTO t VALUES (0, '0 Filler...')", + "INSERT INTO t VALUES (1, '1 Filler...')", + "INSERT INTO t VALUES (2, '2 Filler...')", + "INSERT INTO t VALUES (3, '3 Filler...')", + "INSERT INTO t VALUES (4, '4 Filler...')", + "INSERT INTO t VALUES (5, '5 Filler...')", + "INSERT INTO t VALUES (6, '6 Filler...')", + "ANALYZE TABLE t", + "SELECT * FROM t WHERE a < -1", + "SELECT * FROM t WHERE a > -1", + "SELECT * FROM t WHERE a <= -1", + "SELECT * FROM t WHERE a >= -1", + "SELECT * FROM t WHERE a < 2 OR a > -1", + "SELECT * FROM t WHERE a > 2 AND a < -1", + "SELECT * FROM t WHERE NOT (a < 2 OR a > -1)", + "SELECT * FROM t WHERE NOT (a > 2 AND a < -1)", + "SELECT * FROM t WHERE a < 2 OR a >= -1", + "SELECT * FROM t WHERE a >= 2 AND a < -1", + "SELECT * FROM t WHERE NOT (a < 2 OR a >= -1)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a < -1)", + "SELECT * FROM t WHERE a <= 2 OR a > -1", + "SELECT * FROM t WHERE a > 2 AND a <= -1", + "SELECT * FROM t WHERE NOT (a <= 2 OR a > -1)", + "SELECT * FROM t WHERE NOT (a > 2 AND a <= -1)", + "SELECT * FROM t WHERE a <= 2 OR a >= -1", + "SELECT * FROM t WHERE a >= 2 AND a <= -1", + "SELECT * FROM t WHERE NOT (a <= 2 OR a >= -1)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a <= -1)", + "SELECT * FROM t WHERE a < 0", + "SELECT * FROM t WHERE a > 0", + "SELECT * FROM t WHERE a <= 0", + "SELECT * FROM t WHERE a >= 0", + "SELECT * FROM t WHERE a < 2 OR a > 0", + "SELECT * FROM t WHERE a > 2 AND a < 0", + "SELECT * FROM t WHERE NOT (a < 2 OR a > 0)", + "SELECT * FROM t WHERE NOT (a > 2 AND a < 0)", + "SELECT * FROM t WHERE a < 2 OR a >= 0", + "SELECT * FROM t WHERE a >= 2 AND a < 0", + "SELECT * FROM t WHERE NOT (a < 2 OR a >= 0)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a < 0)", + "SELECT * FROM t WHERE a <= 2 OR a > 0", + "SELECT * FROM t WHERE a > 2 AND a <= 0", + "SELECT * FROM t WHERE NOT (a <= 2 OR a > 0)", + "SELECT * FROM t WHERE NOT (a > 2 AND a <= 0)", + "SELECT * FROM t WHERE a <= 2 OR a >= 0", + "SELECT * FROM t WHERE a >= 2 AND a <= 0", + "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 0)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 0)", + "SELECT * FROM t WHERE a < 1", + "SELECT * FROM t WHERE a > 1", + "SELECT * FROM t WHERE a <= 1", + "SELECT * FROM t WHERE a >= 1", + "SELECT * FROM t WHERE a < 2 OR a > 1", + "SELECT * FROM t WHERE a > 2 AND a < 1", + "SELECT * FROM t WHERE NOT (a < 2 OR a > 1)", + "SELECT * FROM t WHERE NOT (a > 2 AND a < 1)", + "SELECT * FROM t WHERE a < 2 OR a >= 1", + "SELECT * FROM t WHERE a >= 2 AND a < 1", + "SELECT * FROM t WHERE NOT (a < 2 OR a >= 1)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a < 1)", + "SELECT * FROM t WHERE a <= 2 OR a > 1", + "SELECT * FROM t WHERE a > 2 AND a <= 1", + "SELECT * FROM t WHERE NOT (a <= 2 OR a > 1)", + "SELECT * FROM t WHERE NOT (a > 2 AND a <= 1)", + "SELECT * FROM t WHERE a <= 2 OR a >= 1", + "SELECT * FROM t WHERE a >= 2 AND a <= 1", + "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 1)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 1)", + "SELECT * FROM t WHERE a < 2", + "SELECT * FROM t WHERE a > 2", + "SELECT * FROM t WHERE a <= 2", + "SELECT * FROM t WHERE a >= 2", + "SELECT * FROM t WHERE a < 2 OR a > 2", + "SELECT * FROM t WHERE a > 2 AND a < 2", + "SELECT * FROM t WHERE NOT (a < 2 OR a > 2)", + "SELECT * FROM t WHERE NOT (a > 2 AND a < 2)", + "SELECT * FROM t WHERE a < 2 OR a >= 2", + "SELECT * FROM t WHERE a >= 2 AND a < 2", + "SELECT * FROM t WHERE NOT (a < 2 OR a >= 2)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a < 2)", + "SELECT * FROM t WHERE a <= 2 OR a > 2", + "SELECT * FROM t WHERE a > 2 AND a <= 2", + "SELECT * FROM t WHERE NOT (a <= 2 OR a > 2)", + "SELECT * FROM t WHERE NOT (a > 2 AND a <= 2)", + "SELECT * FROM t WHERE a <= 2 OR a >= 2", + "SELECT * FROM t WHERE a >= 2 AND a <= 2", + "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 2)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 2)", + "SELECT * FROM t WHERE a < 3", + "SELECT * FROM t WHERE a > 3", + "SELECT * FROM t WHERE a <= 3", + "SELECT * FROM t WHERE a >= 3", + "SELECT * FROM t WHERE a < 2 OR a > 3", + "SELECT * FROM t WHERE a > 2 AND a < 3", + "SELECT * FROM t WHERE NOT (a < 2 OR a > 3)", + "SELECT * FROM t WHERE NOT (a > 2 AND a < 3)", + "SELECT * FROM t WHERE a < 2 OR a >= 3", + "SELECT * FROM t WHERE a >= 2 AND a < 3", + "SELECT * FROM t WHERE NOT (a < 2 OR a >= 3)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a < 3)", + "SELECT * FROM t WHERE a <= 2 OR a > 3", + "SELECT * FROM t WHERE a > 2 AND a <= 3", + "SELECT * FROM t WHERE NOT (a <= 2 OR a > 3)", + "SELECT * FROM t WHERE NOT (a > 2 AND a <= 3)", + "SELECT * FROM t WHERE a <= 2 OR a >= 3", + "SELECT * FROM t WHERE a >= 2 AND a <= 3", + "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 3)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 3)", + "SELECT * FROM t WHERE a < 4", + "SELECT * FROM t WHERE a > 4", + "SELECT * FROM t WHERE a <= 4", + "SELECT * FROM t WHERE a >= 4", + "SELECT * FROM t WHERE a < 2 OR a > 4", + "SELECT * FROM t WHERE a > 2 AND a < 4", + "SELECT * FROM t WHERE NOT (a < 2 OR a > 4)", + "SELECT * FROM t WHERE NOT (a > 2 AND a < 4)", + "SELECT * FROM t WHERE a < 2 OR a >= 4", + "SELECT * FROM t WHERE a >= 2 AND a < 4", + "SELECT * FROM t WHERE NOT (a < 2 OR a >= 4)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a < 4)", + "SELECT * FROM t WHERE a <= 2 OR a > 4", + "SELECT * FROM t WHERE a > 2 AND a <= 4", + "SELECT * FROM t WHERE NOT (a <= 2 OR a > 4)", + "SELECT * FROM t WHERE NOT (a > 2 AND a <= 4)", + "SELECT * FROM t WHERE a <= 2 OR a >= 4", + "SELECT * FROM t WHERE a >= 2 AND a <= 4", + "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 4)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 4)", + "SELECT * FROM t WHERE a < 5", + "SELECT * FROM t WHERE a > 5", + "SELECT * FROM t WHERE a <= 5", + "SELECT * FROM t WHERE a >= 5", + "SELECT * FROM t WHERE a < 2 OR a > 5", + "SELECT * FROM t WHERE a > 2 AND a < 5", + "SELECT * FROM t WHERE NOT (a < 2 OR a > 5)", + "SELECT * FROM t WHERE NOT (a > 2 AND a < 5)", + "SELECT * FROM t WHERE a < 2 OR a >= 5", + "SELECT * FROM t WHERE a >= 2 AND a < 5", + "SELECT * FROM t WHERE NOT (a < 2 OR a >= 5)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a < 5)", + "SELECT * FROM t WHERE a <= 2 OR a > 5", + "SELECT * FROM t WHERE a > 2 AND a <= 5", + "SELECT * FROM t WHERE NOT (a <= 2 OR a > 5)", + "SELECT * FROM t WHERE NOT (a > 2 AND a <= 5)", + "SELECT * FROM t WHERE a <= 2 OR a >= 5", + "SELECT * FROM t WHERE a >= 2 AND a <= 5", + "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 5)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 5)", + "SELECT * FROM t WHERE a < 6", + "SELECT * FROM t WHERE a > 6", + "SELECT * FROM t WHERE a <= 6", + "SELECT * FROM t WHERE a >= 6", + "SELECT * FROM t WHERE a < 2 OR a > 6", + "SELECT * FROM t WHERE a > 2 AND a < 6", + "SELECT * FROM t WHERE NOT (a < 2 OR a > 6)", + "SELECT * FROM t WHERE NOT (a > 2 AND a < 6)", + "SELECT * FROM t WHERE a < 2 OR a >= 6", + "SELECT * FROM t WHERE a >= 2 AND a < 6", + "SELECT * FROM t WHERE NOT (a < 2 OR a >= 6)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a < 6)", + "SELECT * FROM t WHERE a <= 2 OR a > 6", + "SELECT * FROM t WHERE a > 2 AND a <= 6", + "SELECT * FROM t WHERE NOT (a <= 2 OR a > 6)", + "SELECT * FROM t WHERE NOT (a > 2 AND a <= 6)", + "SELECT * FROM t WHERE a <= 2 OR a >= 6", + "SELECT * FROM t WHERE a >= 2 AND a <= 6", + "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 6)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 6)", + "SELECT * FROM t WHERE a < 7", + "SELECT * FROM t WHERE a > 7", + "SELECT * FROM t WHERE a <= 7", + "SELECT * FROM t WHERE a >= 7", + "SELECT * FROM t WHERE a < 2 OR a > 7", + "SELECT * FROM t WHERE a > 2 AND a < 7", + "SELECT * FROM t WHERE NOT (a < 2 OR a > 7)", + "SELECT * FROM t WHERE NOT (a > 2 AND a < 7)", + "SELECT * FROM t WHERE a < 2 OR a >= 7", + "SELECT * FROM t WHERE a >= 2 AND a < 7", + "SELECT * FROM t WHERE NOT (a < 2 OR a >= 7)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a < 7)", + "SELECT * FROM t WHERE a <= 2 OR a > 7", + "SELECT * FROM t WHERE a > 2 AND a <= 7", + "SELECT * FROM t WHERE NOT (a <= 2 OR a > 7)", + "SELECT * FROM t WHERE NOT (a > 2 AND a <= 7)", + "SELECT * FROM t WHERE a <= 2 OR a >= 7", + "SELECT * FROM t WHERE a >= 2 AND a <= 7", + "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 7)", + "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 7)" + ] } ] diff --git a/executor/testdata/executor_suite_out.json b/executor/testdata/executor_suite_out.json index bd5fbdb486ac0..fd834a5229662 100644 --- a/executor/testdata/executor_suite_out.json +++ b/executor/testdata/executor_suite_out.json @@ -2562,5 +2562,3816 @@ "Res": null } ] + }, + { + "Name": "TestRangePartitionBoundariesLtM", + "Cases": [ + { + "SQL": "INSERT INTO t VALUES (999998, '999998 Filler ...'), (999999, '999999 Filler ...'), (1000000, '1000000 Filler ...'), (1000001, '1000001 Filler ...'), (1000002, '1000002 Filler ...')", + "Plan": null, + "Res": null + }, + { + "SQL": "INSERT INTO t VALUES (1999998, '1999998 Filler ...'), (1999999, '1999999 Filler ...'), (2000000, '2000000 Filler ...'), (2000001, '2000001 Filler ...'), (2000002, '2000002 Filler ...')", + "Plan": null, + "Res": null + }, + { + "SQL": "INSERT INTO t VALUES (2999998, '2999998 Filler ...'), (2999999, '2999999 Filler ...')", + "Plan": null, + "Res": null + }, + { + "SQL": "INSERT INTO t VALUES (-2147483648, 'MIN_INT filler...'), (0, '0 Filler...')", + "Plan": null, + "Res": null + }, + { + "SQL": "ANALYZE TABLE t", + "Plan": null, + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a < -2147483648", + "Plan": [ + "p0" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a > -2147483648", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= -2147483648", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= -2147483648", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 0", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 0", + "Plan": [ + "all" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 0", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 0", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 999998", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999998", + "Plan": [ + "all" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 999998", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "999998 999998 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 999998", + "Plan": [ + "all" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 999999", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "999998 999998 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999999", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 999999", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 999999", + "Plan": [ + "all" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 1000000", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1000000", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 1000000", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1000000", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 1000001", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1000001", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 1000001", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1000001", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 1000002", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1000002", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 1000002", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1000002", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 3000000", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 3000000", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a <= 3000000", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 3000000", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a < 3000001", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 3000001", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a <= 3000001", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 3000001", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a < 999997", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999997", + "Plan": [ + "all" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 999997", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 999997", + "Plan": [ + "all" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 999997 AND a <= 999999", + "Plan": [ + "p0" + ], + "Res": [ + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999997 AND a <= 999999", + "Plan": [ + "p0" + ], + "Res": [ + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999997 AND a < 999999", + "Plan": [ + "p0" + ], + "Res": [ + "999998 999998 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999997 AND a <= 999999", + "Plan": [ + "p0" + ], + "Res": [ + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 999998", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999998", + "Plan": [ + "all" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 999998", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "999998 999998 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 999998", + "Plan": [ + "all" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 999998 AND a <= 1000000", + "Plan": [ + "p0 p1" + ], + "Res": [ + "1000000 1000000 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999998 AND a <= 1000000", + "Plan": [ + "p0 p1" + ], + "Res": [ + "1000000 1000000 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999998 AND a < 1000000", + "Plan": [ + "p0" + ], + "Res": [ + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999998 AND a <= 1000000", + "Plan": [ + "p0 p1" + ], + "Res": [ + "1000000 1000000 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 999999", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "999998 999998 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999999", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 999999", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 999999", + "Plan": [ + "all" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 999999 AND a <= 1000001", + "Plan": [ + "p0 p1" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999999 AND a <= 1000001", + "Plan": [ + "p1" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999999 AND a < 1000001", + "Plan": [ + "p1" + ], + "Res": [ + "1000000 1000000 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 999999 AND a <= 1000001", + "Plan": [ + "p1" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 1000000", + "Plan": [ + "p0" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1000000", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 1000000", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1000000", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1000000 AND a <= 1000002", + "Plan": [ + "p1" + ], + "Res": [ + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1000000 AND a <= 1000002", + "Plan": [ + "p1" + ], + "Res": [ + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1000000 AND a < 1000002", + "Plan": [ + "p1" + ], + "Res": [ + "1000001 1000001 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1000000 AND a <= 1000002", + "Plan": [ + "p1" + ], + "Res": [ + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 1999997", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999997", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 1999997", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1999997", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1999997 AND a <= 1999999", + "Plan": [ + "p1" + ], + "Res": [ + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999997 AND a <= 1999999", + "Plan": [ + "p1" + ], + "Res": [ + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999997 AND a < 1999999", + "Plan": [ + "p1" + ], + "Res": [ + "1999998 1999998 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999997 AND a <= 1999999", + "Plan": [ + "p1" + ], + "Res": [ + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 1999998", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999998", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 1999998", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1999998", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1999998 AND a <= 2000000", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999998 AND a <= 2000000", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999998 AND a < 2000000", + "Plan": [ + "p1" + ], + "Res": [ + "1999999 1999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999998 AND a <= 2000000", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 1999999", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999999", + "Plan": [ + "p2" + ], + "Res": [ + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 1999999", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1999999", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1999999 AND a <= 2000001", + "Plan": [ + "p1 p2" + ], + "Res": [ + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999999 AND a <= 2000001", + "Plan": [ + "p2" + ], + "Res": [ + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999999 AND a < 2000001", + "Plan": [ + "p2" + ], + "Res": [ + "2000000 2000000 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1999999 AND a <= 2000001", + "Plan": [ + "p2" + ], + "Res": [ + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2000000", + "Plan": [ + "p0 p1" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2000000", + "Plan": [ + "p2" + ], + "Res": [ + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2000000", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2000000", + "Plan": [ + "p2" + ], + "Res": [ + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2000000 AND a <= 2000002", + "Plan": [ + "p2" + ], + "Res": [ + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2000000 AND a <= 2000002", + "Plan": [ + "p2" + ], + "Res": [ + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2000000 AND a < 2000002", + "Plan": [ + "p2" + ], + "Res": [ + "2000001 2000001 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2000000 AND a <= 2000002", + "Plan": [ + "p2" + ], + "Res": [ + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2999997", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999997", + "Plan": [ + "p2" + ], + "Res": [ + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2999997", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2999997", + "Plan": [ + "p2" + ], + "Res": [ + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2999997 AND a <= 2999999", + "Plan": [ + "p2" + ], + "Res": [ + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999997 AND a <= 2999999", + "Plan": [ + "p2" + ], + "Res": [ + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999997 AND a < 2999999", + "Plan": [ + "p2" + ], + "Res": [ + "2999998 2999998 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999997 AND a <= 2999999", + "Plan": [ + "p2" + ], + "Res": [ + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2999998", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999998", + "Plan": [ + "p2" + ], + "Res": [ + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2999998", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2999998", + "Plan": [ + "p2" + ], + "Res": [ + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2999998 AND a <= 3000000", + "Plan": [ + "p2" + ], + "Res": [ + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999998 AND a <= 3000000", + "Plan": [ + "p2" + ], + "Res": [ + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999998 AND a < 3000000", + "Plan": [ + "p2" + ], + "Res": [ + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999998 AND a <= 3000000", + "Plan": [ + "p2" + ], + "Res": [ + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2999999", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999999", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2999999", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2999999", + "Plan": [ + "p2" + ], + "Res": [ + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2999999 AND a <= 3000001", + "Plan": [ + "p2" + ], + "Res": [ + "2999999 2999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999999 AND a <= 3000001", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999999 AND a < 3000001", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a > 2999999 AND a <= 3000001", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a < 3000000", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 3000000", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a <= 3000000", + "Plan": [ + "all" + ], + "Res": [ + "-2147483648 MIN_INT filler...", + "0 0 Filler...", + "1000000 1000000 Filler ...", + "1000001 1000001 Filler ...", + "1000002 1000002 Filler ...", + "1999998 1999998 Filler ...", + "1999999 1999999 Filler ...", + "2000000 2000000 Filler ...", + "2000001 2000001 Filler ...", + "2000002 2000002 Filler ...", + "2999998 2999998 Filler ...", + "2999999 2999999 Filler ...", + "999998 999998 Filler ...", + "999999 999999 Filler ..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 3000000", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a >= 3000000 AND a <= 3000002", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a > 3000000 AND a <= 3000002", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a > 3000000 AND a < 3000002", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a > 3000000 AND a <= 3000002", + "Plan": [ + "dual" + ], + "Res": null + } + ] + }, + { + "Name": "TestRangePartitionBoundariesLtS", + "Cases": [ + { + "SQL": "INSERT INTO t VALUES (0, '0 Filler...')", + "Plan": null, + "Res": null + }, + { + "SQL": "INSERT INTO t VALUES (1, '1 Filler...')", + "Plan": null, + "Res": null + }, + { + "SQL": "INSERT INTO t VALUES (2, '2 Filler...')", + "Plan": null, + "Res": null + }, + { + "SQL": "INSERT INTO t VALUES (3, '3 Filler...')", + "Plan": null, + "Res": null + }, + { + "SQL": "INSERT INTO t VALUES (4, '4 Filler...')", + "Plan": null, + "Res": null + }, + { + "SQL": "INSERT INTO t VALUES (5, '5 Filler...')", + "Plan": null, + "Res": null + }, + { + "SQL": "INSERT INTO t VALUES (6, '6 Filler...')", + "Plan": null, + "Res": null + }, + { + "SQL": "ANALYZE TABLE t", + "Plan": null, + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a < -1", + "Plan": [ + "p0" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a > -1", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= -1", + "Plan": [ + "p0" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a >= -1", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a > -1", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a < -1", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a > -1)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a < -1)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a >= -1", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a < -1", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a >= -1)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a < -1)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a > -1", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a <= -1", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a > -1)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a <= -1)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a >= -1", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a <= -1", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a >= -1)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a <= -1)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 0", + "Plan": [ + "p0" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a > 0", + "Plan": [ + "p1 p2 p3 p4 p5 p6" + ], + "Res": [ + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 0", + "Plan": [ + "p0" + ], + "Res": [ + "0 0 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 0", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a > 0", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a < 0", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a > 0)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a < 0)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a >= 0", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a < 0", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a >= 0)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a < 0)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a > 0", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a <= 0", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a > 0)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a <= 0)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a >= 0", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a <= 0", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 0)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 0)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 1", + "Plan": [ + "p0" + ], + "Res": [ + "0 0 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 1", + "Plan": [ + "p2 p3 p4 p5 p6" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 1", + "Plan": [ + "p0 p1" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 1", + "Plan": [ + "p1 p2 p3 p4 p5 p6" + ], + "Res": [ + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a > 1", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a < 1", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a > 1)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a < 1)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a >= 1", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a < 1", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a >= 1)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a < 1)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a > 1", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a <= 1", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a > 1)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a <= 1)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a >= 1", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a <= 1", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 1)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 1)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2", + "Plan": [ + "p0 p1" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2", + "Plan": [ + "p3 p4 p5 p6" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2", + "Plan": [ + "p0 p1 p2" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2", + "Plan": [ + "p2 p3 p4 p5 p6" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a > 2", + "Plan": [ + "p0 p1 p3 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a < 2", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a > 2)", + "Plan": [ + "p2" + ], + "Res": [ + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a < 2)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a >= 2", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a < 2", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a >= 2)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a < 2)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a > 2", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a <= 2", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a > 2)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a <= 2)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a >= 2", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a <= 2", + "Plan": [ + "p2" + ], + "Res": [ + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 2)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 2)", + "Plan": [ + "p0 p1 p3 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 3", + "Plan": [ + "p0 p1 p2" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 3", + "Plan": [ + "p4 p5 p6" + ], + "Res": [ + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 3", + "Plan": [ + "p0 p1 p2 p3" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 3", + "Plan": [ + "p3 p4 p5 p6" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a > 3", + "Plan": [ + "p0 p1 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a < 3", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a > 3)", + "Plan": [ + "p2 p3" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a < 3)", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a >= 3", + "Plan": [ + "p0 p1 p3 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a < 3", + "Plan": [ + "p2" + ], + "Res": [ + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a >= 3)", + "Plan": [ + "p2" + ], + "Res": [ + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a < 3)", + "Plan": [ + "p0 p1 p3 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a > 3", + "Plan": [ + "p0 p1 p2 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a <= 3", + "Plan": [ + "p3" + ], + "Res": [ + "3 3 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a > 3)", + "Plan": [ + "p3" + ], + "Res": [ + "3 3 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a <= 3)", + "Plan": [ + "p0 p1 p2 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a >= 3", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a <= 3", + "Plan": [ + "p2 p3" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 3)", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 3)", + "Plan": [ + "p0 p1 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 4", + "Plan": [ + "p0 p1 p2 p3" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 4", + "Plan": [ + "p5 p6" + ], + "Res": [ + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 4", + "Plan": [ + "p0 p1 p2 p3 p4" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 4", + "Plan": [ + "p4 p5 p6" + ], + "Res": [ + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a > 4", + "Plan": [ + "p0 p1 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a < 4", + "Plan": [ + "p3" + ], + "Res": [ + "3 3 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a > 4)", + "Plan": [ + "p2 p3 p4" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a < 4)", + "Plan": [ + "p0 p1 p2 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a >= 4", + "Plan": [ + "p0 p1 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a < 4", + "Plan": [ + "p2 p3" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a >= 4)", + "Plan": [ + "p2 p3" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a < 4)", + "Plan": [ + "p0 p1 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a > 4", + "Plan": [ + "p0 p1 p2 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a <= 4", + "Plan": [ + "p3 p4" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a > 4)", + "Plan": [ + "p3 p4" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a <= 4)", + "Plan": [ + "p0 p1 p2 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a >= 4", + "Plan": [ + "p0 p1 p2 p4 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a <= 4", + "Plan": [ + "p2 p3 p4" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 4)", + "Plan": [ + "p3" + ], + "Res": [ + "3 3 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 4)", + "Plan": [ + "p0 p1 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 5", + "Plan": [ + "p0 p1 p2 p3 p4" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 5", + "Plan": [ + "p6" + ], + "Res": [ + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 5", + "Plan": [ + "p0 p1 p2 p3 p4 p5" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 5", + "Plan": [ + "p5 p6" + ], + "Res": [ + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a > 5", + "Plan": [ + "p0 p1 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a < 5", + "Plan": [ + "p3 p4" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a > 5)", + "Plan": [ + "p2 p3 p4 p5" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a < 5)", + "Plan": [ + "p0 p1 p2 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a >= 5", + "Plan": [ + "p0 p1 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a < 5", + "Plan": [ + "p2 p3 p4" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a >= 5)", + "Plan": [ + "p2 p3 p4" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a < 5)", + "Plan": [ + "p0 p1 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a > 5", + "Plan": [ + "p0 p1 p2 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a <= 5", + "Plan": [ + "p3 p4 p5" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a > 5)", + "Plan": [ + "p3 p4 p5" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a <= 5)", + "Plan": [ + "p0 p1 p2 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a >= 5", + "Plan": [ + "p0 p1 p2 p5 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a <= 5", + "Plan": [ + "p2 p3 p4 p5" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 5)", + "Plan": [ + "p3 p4" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 5)", + "Plan": [ + "p0 p1 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 6", + "Plan": [ + "p0 p1 p2 p3 p4 p5" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 6", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a <= 6", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 6", + "Plan": [ + "p6" + ], + "Res": [ + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a > 6", + "Plan": [ + "p0 p1" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a < 6", + "Plan": [ + "p3 p4 p5" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a > 6)", + "Plan": [ + "p2 p3 p4 p5 p6" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a < 6)", + "Plan": [ + "p0 p1 p2 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a >= 6", + "Plan": [ + "p0 p1 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a < 6", + "Plan": [ + "p2 p3 p4 p5" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a >= 6)", + "Plan": [ + "p2 p3 p4 p5" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a < 6)", + "Plan": [ + "p0 p1 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a > 6", + "Plan": [ + "p0 p1 p2" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a <= 6", + "Plan": [ + "p3 p4 p5 p6" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a > 6)", + "Plan": [ + "p3 p4 p5 p6" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a <= 6)", + "Plan": [ + "p0 p1 p2" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a >= 6", + "Plan": [ + "p0 p1 p2 p6" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a <= 6", + "Plan": [ + "p2 p3 p4 p5 p6" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 6)", + "Plan": [ + "p3 p4 p5" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 6)", + "Plan": [ + "p0 p1" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 7", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 7", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a <= 7", + "Plan": [ + "all" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 7", + "Plan": [ + "dual" + ], + "Res": null + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a > 7", + "Plan": [ + "p0 p1" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a < 7", + "Plan": [ + "p3 p4 p5 p6" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a > 7)", + "Plan": [ + "p2 p3 p4 p5 p6" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a < 7)", + "Plan": [ + "p0 p1 p2" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a < 2 OR a >= 7", + "Plan": [ + "p0 p1" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a < 7", + "Plan": [ + "p2 p3 p4 p5 p6" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a < 2 OR a >= 7)", + "Plan": [ + "p2 p3 p4 p5 p6" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a < 7)", + "Plan": [ + "p0 p1" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a > 7", + "Plan": [ + "p0 p1 p2" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a > 2 AND a <= 7", + "Plan": [ + "p3 p4 p5 p6" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a > 7)", + "Plan": [ + "p3 p4 p5 p6" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a > 2 AND a <= 7)", + "Plan": [ + "p0 p1 p2" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a <= 2 OR a >= 7", + "Plan": [ + "p0 p1 p2" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler...", + "2 2 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE a >= 2 AND a <= 7", + "Plan": [ + "p2 p3 p4 p5 p6" + ], + "Res": [ + "2 2 Filler...", + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a <= 2 OR a >= 7)", + "Plan": [ + "p3 p4 p5 p6" + ], + "Res": [ + "3 3 Filler...", + "4 4 Filler...", + "5 5 Filler...", + "6 6 Filler..." + ] + }, + { + "SQL": "SELECT * FROM t WHERE NOT (a >= 2 AND a <= 7)", + "Plan": [ + "p0 p1" + ], + "Res": [ + "0 0 Filler...", + "1 1 Filler..." + ] + } + ] } ] diff --git a/expression/builtin_time_test.go b/expression/builtin_time_test.go index e247e8756ae9a..4015794377486 100644 --- a/expression/builtin_time_test.go +++ b/expression/builtin_time_test.go @@ -2928,7 +2928,7 @@ func (s *testEvaluatorSuite) TestTiDBBoundedStaleness(c *C) { // Test whether it's deterministic. safeTime1 := t2.Add(-1 * time.Second) - safeTS1 := oracle.ComposeTS(safeTime1.Unix()*1000, 0) + safeTS1 := oracle.GoTimeToTS(safeTime1) c.Assert(failpoint.Enable("github.com/pingcap/tidb/expression/injectSafeTS", fmt.Sprintf("return(%v)", safeTS1)), IsNil) f, err := fc.getFunction(s.ctx, s.datumsToConstants([]types.Datum{types.NewDatum(t1Str), types.NewDatum(t2Str)})) @@ -2941,7 +2941,7 @@ func (s *testEvaluatorSuite) TestTiDBBoundedStaleness(c *C) { c.Assert(resultTime, Equals, safeTime1.Format(types.TimeFormat)) // SafeTS updated. safeTime2 := t2.Add(1 * time.Second) - safeTS2 := oracle.ComposeTS(safeTime2.Unix()*1000, 0) + safeTS2 := oracle.GoTimeToTS(safeTime2) c.Assert(failpoint.Enable("github.com/pingcap/tidb/expression/injectSafeTS", fmt.Sprintf("return(%v)", safeTS2)), IsNil) f, err = fc.getFunction(s.ctx, s.datumsToConstants([]types.Datum{types.NewDatum(t1Str), types.NewDatum(t2Str)})) diff --git a/planner/core/common_plans.go b/planner/core/common_plans.go index 3818486955646..b42a84d926eeb 100644 --- a/planner/core/common_plans.go +++ b/planner/core/common_plans.go @@ -723,6 +723,9 @@ type Simple struct { // and executing in co-processor. // Used for `global kill`. See https://github.com/pingcap/tidb/blob/master/docs/design/2020-06-01-global-kill.md. IsFromRemote bool + + // StalenessTxnOption is the transaction option that will be built when planner builder calls buildSimple. + StalenessTxnOption *sessionctx.StalenessTxnOption } // PhysicalSimpleWrapper is a wrapper of `Simple` to implement physical plan interface. diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index ccab0a28cc863..2ae66a61602a5 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -43,6 +43,7 @@ import ( "github.com/pingcap/tidb/sessionctx/variable" "github.com/pingcap/tidb/statistics" "github.com/pingcap/tidb/store/tikv" + "github.com/pingcap/tidb/store/tikv/oracle" "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/types" driver "github.com/pingcap/tidb/types/parser_driver" @@ -643,7 +644,7 @@ func (b *PlanBuilder) Build(ctx context.Context, node ast.Node) (Plan, error) { *ast.GrantStmt, *ast.DropUserStmt, *ast.AlterUserStmt, *ast.RevokeStmt, *ast.KillStmt, *ast.DropStatsStmt, *ast.GrantRoleStmt, *ast.RevokeRoleStmt, *ast.SetRoleStmt, *ast.SetDefaultRoleStmt, *ast.ShutdownStmt, *ast.RenameUserStmt: - return b.buildSimple(node.(ast.StmtNode)) + return b.buildSimple(ctx, node.(ast.StmtNode)) case ast.DDLNode: return b.buildDDL(ctx, x) case *ast.CreateBindingStmt: @@ -2259,7 +2260,7 @@ func (b *PlanBuilder) buildShow(ctx context.Context, show *ast.ShowStmt) (Plan, return np, nil } -func (b *PlanBuilder) buildSimple(node ast.StmtNode) (Plan, error) { +func (b *PlanBuilder) buildSimple(ctx context.Context, node ast.StmtNode) (Plan, error) { p := &Simple{Statement: node} switch raw := node.(type) { @@ -2325,10 +2326,41 @@ func (b *PlanBuilder) buildSimple(node ast.StmtNode) (Plan, error) { } case *ast.ShutdownStmt: b.visitInfo = appendVisitInfo(b.visitInfo, mysql.ShutdownPriv, "", "", "", nil) + case *ast.BeginStmt: + if raw.AsOf != nil { + startTS, err := b.calculateTsExpr(raw.AsOf) + if err != nil { + return nil, err + } + p.StalenessTxnOption = &sessionctx.StalenessTxnOption{ + Mode: ast.TimestampBoundReadTimestamp, + StartTS: startTS, + } + } } return p, nil } +// calculateTsExpr calculates the TsExpr of AsOfClause to get a StartTS. +func (b *PlanBuilder) calculateTsExpr(asOfClause *ast.AsOfClause) (uint64, error) { + tsVal, err := evalAstExpr(b.ctx, asOfClause.TsExpr) + if err != nil { + return 0, err + } + toTypeTimestamp := types.NewFieldType(mysql.TypeTimestamp) + // We need at least the millionsecond here, so set fsp to 3. + toTypeTimestamp.Decimal = 3 + tsTimestamp, err := tsVal.ConvertTo(b.ctx.GetSessionVars().StmtCtx, toTypeTimestamp) + if err != nil { + return 0, err + } + tsTime, err := tsTimestamp.GetMysqlTime().GoTime(b.ctx.GetSessionVars().TimeZone) + if err != nil { + return 0, err + } + return oracle.GoTimeToTS(tsTime), nil +} + func collectVisitInfoFromRevokeStmt(sctx sessionctx.Context, vi []visitInfo, stmt *ast.RevokeStmt) []visitInfo { // To use REVOKE, you must have the GRANT OPTION privilege, // and you must have the privileges that you are granting. diff --git a/privilege/privileges/privileges.go b/privilege/privileges/privileges.go index 0e8d88a90c5a1..cdaca2f634263 100644 --- a/privilege/privileges/privileges.go +++ b/privilege/privileges/privileges.go @@ -531,7 +531,8 @@ func (p *UserPrivileges) GetAllRoles(user, host string) []*auth.RoleIdentity { } // IsDynamicPrivilege returns true if the DYNAMIC privilege is built-in or has been registered by a plugin -func (p *UserPrivileges) IsDynamicPrivilege(privNameInUpper string) bool { +func (p *UserPrivileges) IsDynamicPrivilege(privName string) bool { + privNameInUpper := strings.ToUpper(privName) for _, priv := range dynamicPrivs { if privNameInUpper == priv { return true @@ -541,7 +542,11 @@ func (p *UserPrivileges) IsDynamicPrivilege(privNameInUpper string) bool { } // RegisterDynamicPrivilege is used by plugins to add new privileges to TiDB -func RegisterDynamicPrivilege(privNameInUpper string) error { +func RegisterDynamicPrivilege(privName string) error { + privNameInUpper := strings.ToUpper(privName) + if len(privNameInUpper) > 32 { + return errors.New("privilege name is longer than 32 characters") + } dynamicPrivLock.Lock() defer dynamicPrivLock.Unlock() for _, priv := range dynamicPrivs { diff --git a/privilege/privileges/privileges_test.go b/privilege/privileges/privileges_test.go index 3917d822aa403..1563f8d72cf7b 100644 --- a/privilege/privileges/privileges_test.go +++ b/privilege/privileges/privileges_test.go @@ -39,6 +39,7 @@ import ( "github.com/pingcap/tidb/store/mockstore" "github.com/pingcap/tidb/util" "github.com/pingcap/tidb/util/sem" + "github.com/pingcap/tidb/util/sqlexec" "github.com/pingcap/tidb/util/testkit" "github.com/pingcap/tidb/util/testleak" "github.com/pingcap/tidb/util/testutil" @@ -1579,7 +1580,33 @@ func (s *testPrivilegeSuite) TestDynamicPrivsRegistration(c *C) { count := len(privileges.GetDynamicPrivileges()) c.Assert(pm.IsDynamicPrivilege("ACDC_ADMIN"), IsFalse) - privileges.RegisterDynamicPrivilege("ACDC_ADMIN") + c.Assert(privileges.RegisterDynamicPrivilege("ACDC_ADMIN"), IsNil) c.Assert(pm.IsDynamicPrivilege("ACDC_ADMIN"), IsTrue) c.Assert(len(privileges.GetDynamicPrivileges()), Equals, count+1) + + c.Assert(pm.IsDynamicPrivilege("iAmdynamIC"), IsFalse) + c.Assert(privileges.RegisterDynamicPrivilege("IAMdynamic"), IsNil) + c.Assert(pm.IsDynamicPrivilege("IAMdyNAMIC"), IsTrue) + c.Assert(len(privileges.GetDynamicPrivileges()), Equals, count+2) + + c.Assert(privileges.RegisterDynamicPrivilege("THIS_PRIVILEGE_NAME_IS_TOO_LONG_THE_MAX_IS_32_CHARS").Error(), Equals, "privilege name is longer than 32 characters") + c.Assert(pm.IsDynamicPrivilege("THIS_PRIVILEGE_NAME_IS_TOO_LONG_THE_MAX_IS_32_CHARS"), IsFalse) + + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("CREATE USER privassigntest") + tk.MustExec("SET tidb_enable_dynamic_privileges=1") + + // Check that all privileges registered are assignable to users, + // including the recently registered ACDC_ADMIN + for _, priv := range privileges.GetDynamicPrivileges() { + sqlGrant, err := sqlexec.EscapeSQL("GRANT %n ON *.* TO privassigntest", priv) + c.Assert(err, IsNil) + tk.MustExec(sqlGrant) + } + // Check that all privileges registered are revokable + for _, priv := range privileges.GetDynamicPrivileges() { + sqlGrant, err := sqlexec.EscapeSQL("REVOKE %n ON *.* FROM privassigntest", priv) + c.Assert(err, IsNil) + tk.MustExec(sqlGrant) + } } diff --git a/session/session.go b/session/session.go index f116daf96dd04..2874330a02fd3 100644 --- a/session/session.go +++ b/session/session.go @@ -1960,20 +1960,9 @@ func (s *session) isTxnRetryable() bool { } func (s *session) NewTxn(ctx context.Context) error { - if s.txn.Valid() { - txnStartTS := s.txn.StartTS() - txnScope := s.GetSessionVars().TxnCtx.TxnScope - err := s.CommitTxn(ctx) - if err != nil { - return err - } - vars := s.GetSessionVars() - logutil.Logger(ctx).Info("NewTxn() inside a transaction auto commit", - zap.Int64("schemaVersion", vars.GetInfoSchema().SchemaMetaVersion()), - zap.Uint64("txnStartTS", txnStartTS), - zap.String("txnScope", txnScope)) + if err := s.checkBeforeNewTxn(ctx); err != nil { + return err } - txn, err := s.store.BeginWithOption(tikv.DefaultStartTSOption().SetTxnScope(s.sessionVars.CheckAndGetTxnScope())) if err != nil { return err @@ -1995,6 +1984,23 @@ func (s *session) NewTxn(ctx context.Context) error { return nil } +func (s *session) checkBeforeNewTxn(ctx context.Context) error { + if s.txn.Valid() { + txnStartTS := s.txn.StartTS() + txnScope := s.GetSessionVars().TxnCtx.TxnScope + err := s.CommitTxn(ctx) + if err != nil { + return err + } + vars := s.GetSessionVars() + logutil.Logger(ctx).Info("Try to create a new txn inside a transaction auto commit", + zap.Int64("schemaVersion", vars.GetInfoSchema().SchemaMetaVersion()), + zap.Uint64("txnStartTS", txnStartTS), + zap.String("txnScope", txnScope)) + } + return nil +} + func (s *session) SetValue(key fmt.Stringer, value interface{}) { s.mu.Lock() s.mu.values[key] = value @@ -2782,22 +2788,14 @@ func (s *session) InitTxnWithStartTS(startTS uint64) error { // NewTxnWithStalenessOption create a transaction with Staleness option func (s *session) NewTxnWithStalenessOption(ctx context.Context, option sessionctx.StalenessTxnOption) error { - if s.txn.Valid() { - txnID := s.txn.StartTS() - txnScope := s.txn.GetOption(kv.TxnScope).(string) - err := s.CommitTxn(ctx) - if err != nil { - return err - } - vars := s.GetSessionVars() - logutil.Logger(ctx).Info("InitTxnWithExactStaleness() inside a transaction auto commit", - zap.Int64("schemaVersion", vars.GetInfoSchema().SchemaMetaVersion()), - zap.Uint64("txnStartTS", txnID), - zap.String("txnScope", txnScope)) + err := s.checkBeforeNewTxn(ctx) + if err != nil { + return err } - var txn kv.Transaction - var err error - txnScope := s.GetSessionVars().CheckAndGetTxnScope() + var ( + txn kv.Transaction + txnScope = s.GetSessionVars().CheckAndGetTxnScope() + ) switch option.Mode { case ast.TimestampBoundReadTimestamp: txn, err = s.store.BeginWithOption(tikv.DefaultStartTSOption().SetTxnScope(txnScope).SetStartTs(option.StartTS)) diff --git a/session/session_test.go b/session/session_test.go index a6c7908237bca..9d2d63cb02804 100644 --- a/session/session_test.go +++ b/session/session_test.go @@ -4109,7 +4109,7 @@ func (s *testSessionSerialSuite) TestValidateReadOnlyInStalenessTransaction(c *C tk.MustExec(`set @@tidb_enable_noop_functions=1;`) for _, testcase := range testcases { c.Log(testcase.name) - tk.MustExec(`START TRANSACTION READ ONLY WITH TIMESTAMP BOUND EXACT STALENESS '00:00:00';`) + tk.MustExec(`START TRANSACTION READ ONLY AS OF TIMESTAMP NOW(3);`) if testcase.isValidate { _, err := tk.Exec(testcase.sql) c.Assert(err, IsNil) @@ -4169,7 +4169,7 @@ func (s *testSessionSerialSuite) TestSpecialSQLInStalenessTxn(c *C) { tk.MustExec("CREATE USER 'newuser' IDENTIFIED BY 'mypassword';") for _, testcase := range testcases { comment := Commentf(testcase.name) - tk.MustExec(`START TRANSACTION READ ONLY WITH TIMESTAMP BOUND EXACT STALENESS '00:00:00';`) + tk.MustExec(`START TRANSACTION READ ONLY AS OF TIMESTAMP NOW(3);`) c.Assert(tk.Se.GetSessionVars().TxnCtx.IsStaleness, Equals, true, comment) tk.MustExec(testcase.sql) c.Assert(tk.Se.GetSessionVars().TxnCtx.IsStaleness, Equals, testcase.sameSession, comment) diff --git a/sessionctx/context.go b/sessionctx/context.go index 2aeda663a038d..59a917f86a9bc 100644 --- a/sessionctx/context.go +++ b/sessionctx/context.go @@ -73,7 +73,7 @@ type Context interface { // It should be called right before we builds an executor. InitTxnWithStartTS(startTS uint64) error - // NewTxnWithStalenessOption initializes a transaction with StalenessTxnOption + // NewTxnWithStalenessOption initializes a transaction with StalenessTxnOption. NewTxnWithStalenessOption(ctx context.Context, option StalenessTxnOption) error // GetStore returns the store of session. diff --git a/store/copr/batch_coprocessor.go b/store/copr/batch_coprocessor.go index 8c73f58fbf892..6efbf76775186 100644 --- a/store/copr/batch_coprocessor.go +++ b/store/copr/batch_coprocessor.go @@ -302,7 +302,7 @@ func buildBatchCopTasks(bo *Backoffer, cache *tikv.RegionCache, ranges *tikv.Key // As mentioned above, nil rpcCtx is always attributed to failed stores. // It's equal to long poll the store but get no response. Here we'd better use // TiFlash error to trigger the TiKV fallback mechanism. - err = bo.Backoff(tikv.BoTiFlashRPC, errors.New("Cannot find region with TiFlash peer")) + err = bo.Backoff(tikv.BoTiFlashRPC(), errors.New("Cannot find region with TiFlash peer")) if err != nil { return nil, errors.Trace(err) } @@ -548,7 +548,7 @@ func (b *batchCopIterator) handleStreamedBatchCopResponse(ctx context.Context, b return nil } - if err1 := bo.BackoffTiKVRPC(errors.Errorf("recv stream response error: %v, task store addr: %s", err, task.storeAddr)); err1 != nil { + if err1 := bo.Backoff(tikv.BoTiKVRPC(), errors.Errorf("recv stream response error: %v, task store addr: %s", err, task.storeAddr)); err1 != nil { return errors.Trace(err) } @@ -597,9 +597,8 @@ func (b *batchCopIterator) handleBatchCopResponse(bo *Backoffer, response *copro resp.detail.BackoffSleep = make(map[string]time.Duration, len(backoffTimes)) resp.detail.BackoffTimes = make(map[string]int, len(backoffTimes)) for backoff := range backoffTimes { - backoffName := backoff.String() - resp.detail.BackoffTimes[backoffName] = backoffTimes[backoff] - resp.detail.BackoffSleep[backoffName] = time.Duration(bo.GetBackoffSleepMS()[backoff]) * time.Millisecond + resp.detail.BackoffTimes[backoff] = backoffTimes[backoff] + resp.detail.BackoffSleep[backoff] = time.Duration(bo.GetBackoffSleepMS()[backoff]) * time.Millisecond } resp.detail.CalleeAddress = task.storeAddr diff --git a/store/copr/coprocessor.go b/store/copr/coprocessor.go index 989a6d835ce0f..c66c3cda9af35 100644 --- a/store/copr/coprocessor.go +++ b/store/copr/coprocessor.go @@ -833,9 +833,9 @@ func (worker *copIteratorWorker) handleCopStreamResult(bo *Backoffer, rpcCtx *ti err1 := errors.Errorf("recv stream response error: %v, task: %s", err, task) if task.storeType == kv.TiFlash { - err1 = bo.Backoff(tikv.BoTiFlashRPC, err1) + err1 = bo.Backoff(tikv.BoTiFlashRPC(), err1) } else { - err1 = bo.BackoffTiKVRPC(err1) + err1 = bo.Backoff(tikv.BoTiKVRPC(), err1) } if err1 != nil { @@ -869,7 +869,7 @@ func (worker *copIteratorWorker) handleCopResponse(bo *Backoffer, rpcCtx *tikv.R } errStr := fmt.Sprintf("region_id:%v, region_ver:%v, store_type:%s, peer_addr:%s, error:%s", task.region.GetID(), task.region.GetVer(), task.storeType.Name(), task.storeAddr, regionErr.String()) - if err := bo.Backoff(tikv.BoRegionMiss, errors.New(errStr)); err != nil { + if err := bo.Backoff(tikv.BoRegionMiss(), errors.New(errStr)); err != nil { return nil, errors.Trace(err) } // We may meet RegionError at the first packet, but not during visiting the stream. @@ -884,7 +884,7 @@ func (worker *copIteratorWorker) handleCopResponse(bo *Backoffer, rpcCtx *tikv.R return nil, errors.Trace(err1) } if msBeforeExpired > 0 { - if err := bo.BackoffWithMaxSleep(tikv.BoTxnLockFast, int(msBeforeExpired), errors.New(lockErr.String())); err != nil { + if err := bo.BackoffWithMaxSleepTxnLockFast(int(msBeforeExpired), errors.New(lockErr.String())); err != nil { return nil, errors.Trace(err) } } @@ -915,9 +915,8 @@ func (worker *copIteratorWorker) handleCopResponse(bo *Backoffer, rpcCtx *tikv.R resp.detail.BackoffSleep = make(map[string]time.Duration, len(backoffTimes)) resp.detail.BackoffTimes = make(map[string]int, len(backoffTimes)) for backoff := range backoffTimes { - backoffName := backoff.String() - resp.detail.BackoffTimes[backoffName] = backoffTimes[backoff] - resp.detail.BackoffSleep[backoffName] = time.Duration(bo.GetBackoffSleepMS()[backoff]) * time.Millisecond + resp.detail.BackoffTimes[backoff] = backoffTimes[backoff] + resp.detail.BackoffSleep[backoff] = time.Duration(bo.GetBackoffSleepMS()[backoff]) * time.Millisecond } if rpcCtx != nil { resp.detail.CalleeAddress = rpcCtx.Addr diff --git a/store/copr/mpp.go b/store/copr/mpp.go index 1941f2b3fbfa4..6d58e4ef732fe 100644 --- a/store/copr/mpp.go +++ b/store/copr/mpp.go @@ -340,7 +340,7 @@ func (m *mppIterator) establishMPPConns(bo *Backoffer, req *kv.MPPDispatchReques return } - if err1 := bo.BackoffTiKVRPC(errors.Errorf("recv stream response error: %v", err)); err1 != nil { + if err1 := bo.Backoff(tikv.BoTiKVRPC(), errors.Errorf("recv stream response error: %v", err)); err1 != nil { if errors.Cause(err) == context.Canceled { logutil.BgLogger().Info("stream recv timeout", zap.Error(err)) } else { @@ -383,9 +383,8 @@ func (m *mppIterator) handleMPPStreamResponse(bo *Backoffer, response *mpp.MPPDa resp.detail.BackoffSleep = make(map[string]time.Duration, len(backoffTimes)) resp.detail.BackoffTimes = make(map[string]int, len(backoffTimes)) for backoff := range backoffTimes { - backoffName := backoff.String() - resp.detail.BackoffTimes[backoffName] = backoffTimes[backoff] - resp.detail.BackoffSleep[backoffName] = time.Duration(bo.GetBackoffSleepMS()[backoff]) * time.Millisecond + resp.detail.BackoffTimes[backoff] = backoffTimes[backoff] + resp.detail.BackoffSleep[backoff] = time.Duration(bo.GetBackoffSleepMS()[backoff]) * time.Millisecond } resp.detail.CalleeAddress = req.Meta.GetAddress() diff --git a/store/driver/backoff/backoff.go b/store/driver/backoff/backoff.go index f634366381d06..35979edc638b4 100644 --- a/store/driver/backoff/backoff.go +++ b/store/driver/backoff/backoff.go @@ -43,29 +43,22 @@ func (b *Backoffer) TiKVBackoffer() *tikv.Backoffer { return b.b } -// Backoff sleeps a while base on the backoffType and records the error message. +// Backoff sleeps a while base on the BackoffConfig and records the error message. // It returns a retryable error if total sleep time exceeds maxSleep. -func (b *Backoffer) Backoff(typ tikv.BackoffType, err error) error { - e := b.b.Backoff(typ, err) +func (b *Backoffer) Backoff(cfg *tikv.BackoffConfig, err error) error { + e := b.b.Backoff(cfg, err) return derr.ToTiDBErr(e) } -// BackoffTiKVRPC sleeps a while base on the TiKVRPC and records the error message. -// It returns a retryable error if total sleep time exceeds maxSleep. -func (b *Backoffer) BackoffTiKVRPC(err error) error { - e := b.b.BackoffTiKVRPC(err) - return derr.ToTiDBErr(e) -} - -// BackoffWithMaxSleep sleeps a while base on the backoffType and records the error message +// BackoffWithMaxSleepTxnLockFast sleeps a while for the operation TxnLockFast and records the error message // and never sleep more than maxSleepMs for each sleep. -func (b *Backoffer) BackoffWithMaxSleep(typ tikv.BackoffType, maxSleepMs int, err error) error { - e := b.b.BackoffWithMaxSleep(typ, maxSleepMs, err) +func (b *Backoffer) BackoffWithMaxSleepTxnLockFast(maxSleepMs int, err error) error { + e := b.b.BackoffWithMaxSleepTxnLockFast(maxSleepMs, err) return derr.ToTiDBErr(e) } // GetBackoffTimes returns a map contains backoff time count by type. -func (b *Backoffer) GetBackoffTimes() map[tikv.BackoffType]int { +func (b *Backoffer) GetBackoffTimes() map[string]int { return b.b.GetBackoffTimes() } @@ -80,7 +73,7 @@ func (b *Backoffer) GetVars() *tikv.Variables { } // GetBackoffSleepMS returns a map contains backoff sleep time by type. -func (b *Backoffer) GetBackoffSleepMS() map[tikv.BackoffType]int { +func (b *Backoffer) GetBackoffSleepMS() map[string]int { return b.b.GetBackoffSleepMS() } diff --git a/store/driver/tikv_driver.go b/store/driver/tikv_driver.go index 2d93b7eda4abb..5f5471d8e7251 100644 --- a/store/driver/tikv_driver.go +++ b/store/driver/tikv_driver.go @@ -231,7 +231,7 @@ func (s *tikvStore) EtcdAddrs() ([]string, error) { for { members, err := pdClient.GetAllMembers(ctx) if err != nil { - err := bo.Backoff(tikv.BoRegionMiss, err) + err := bo.Backoff(tikv.BoRegionMiss(), err) if err != nil { return nil, err } diff --git a/store/gcworker/gc_worker.go b/store/gcworker/gc_worker.go index b5b42df1838b9..72ae8bc34f0fa 100644 --- a/store/gcworker/gc_worker.go +++ b/store/gcworker/gc_worker.go @@ -1089,7 +1089,7 @@ retryScanAndResolve: return stat, errors.Trace(err) } if regionErr != nil { - err = bo.Backoff(tikv.BoRegionMiss, errors.New(regionErr.String())) + err = bo.Backoff(tikv.BoRegionMiss(), errors.New(regionErr.String())) if err != nil { return stat, errors.Trace(err) } @@ -1125,7 +1125,7 @@ retryScanAndResolve: return stat, errors.Trace(err1) } if !ok { - err = bo.Backoff(tikv.BoTxnLock, errors.Errorf("remain locks: %d", len(locks))) + err = bo.Backoff(tikv.BoTxnLock(), errors.Errorf("remain locks: %d", len(locks))) if err != nil { return stat, errors.Trace(err) } @@ -1497,7 +1497,7 @@ func (w *GCWorker) resolveLocksAcrossRegions(ctx context.Context, locks []*tikv. return errors.Trace(err) } if !ok { - err = bo.Backoff(tikv.BoTxnLock, errors.Errorf("remain locks: %d", len(locks))) + err = bo.Backoff(tikv.BoTxnLock(), errors.Errorf("remain locks: %d", len(locks))) if err != nil { return errors.Trace(err) } @@ -1525,7 +1525,7 @@ func (w *GCWorker) uploadSafePointToPD(ctx context.Context, safePoint uint64) er if errors.Cause(err) == context.Canceled { return errors.Trace(err) } - err = bo.Backoff(tikv.BoPDRPC, errors.Errorf("failed to upload safe point to PD, err: %v", err)) + err = bo.Backoff(tikv.BoPDRPC(), errors.Errorf("failed to upload safe point to PD, err: %v", err)) if err != nil { return errors.Trace(err) } @@ -1567,7 +1567,7 @@ func (w *GCWorker) doGCForRange(ctx context.Context, startKey []byte, endKey []b // we check regionErr here first, because we know 'regionErr' and 'err' should not return together, to keep it to // make the process correct. if regionErr != nil { - err = bo.Backoff(tikv.BoRegionMiss, errors.New(regionErr.String())) + err = bo.Backoff(tikv.BoRegionMiss(), errors.New(regionErr.String())) if err == nil { continue } diff --git a/store/tikv/backoff.go b/store/tikv/backoff.go index c622e21d2ee5d..918acc9addcb8 100644 --- a/store/tikv/backoff.go +++ b/store/tikv/backoff.go @@ -23,17 +23,8 @@ import ( // Backoffer is a utility for retrying queries. type Backoffer = retry.Backoffer -// BackoffType defines the backoff type. -type BackoffType = retry.BackoffType - -// Back off types. -const ( - BoRegionMiss = retry.BoRegionMiss - BoTiFlashRPC = retry.BoTiFlashRPC - BoTxnLockFast = retry.BoTxnLockFast - BoTxnLock = retry.BoTxnLock - BoPDRPC = retry.BoPDRPC -) +// BackoffConfig defines the backoff configuration. +type BackoffConfig = retry.Config // Maximum total sleep time(in ms) for kv/cop commands. const ( @@ -62,6 +53,31 @@ func TxnStartKey() interface{} { return retry.TxnStartKey } +// BoRegionMiss returns the default backoff config for RegionMiss. +func BoRegionMiss() *BackoffConfig { + return retry.BoRegionMiss +} + +// BoTiFlashRPC returns the default backoff config for TiFlashRPC. +func BoTiFlashRPC() *BackoffConfig { + return retry.BoTiFlashRPC +} + +// BoTxnLock returns the default backoff config for TxnLock. +func BoTxnLock() *BackoffConfig { + return retry.BoTxnLock +} + +// BoPDRPC returns the default backoff config for PDRPC. +func BoPDRPC() *BackoffConfig { + return retry.BoPDRPC +} + +// BoTiKVRPC returns the default backoff config for TiKVRPC. +func BoTiKVRPC() *BackoffConfig { + return retry.BoTiKVRPC +} + // NewGcResolveLockMaxBackoffer creates a Backoffer for Gc to resolve lock. func NewGcResolveLockMaxBackoffer(ctx context.Context) *Backoffer { return retry.NewBackofferWithVars(ctx, gcResolveLockMaxBackoff, nil) diff --git a/store/tikv/batch_request_sender.go b/store/tikv/batch_request_sender.go index 9aad070b70306..74a62dcfd781c 100644 --- a/store/tikv/batch_request_sender.go +++ b/store/tikv/batch_request_sender.go @@ -21,6 +21,7 @@ import ( "github.com/pingcap/errors" "github.com/pingcap/kvproto/pkg/metapb" tikverr "github.com/pingcap/tidb/store/tikv/error" + "github.com/pingcap/tidb/store/tikv/retry" "github.com/pingcap/tidb/store/tikv/tikvrpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -93,6 +94,6 @@ func (ss *RegionBatchRequestSender) onSendFailForBatchRegions(bo *Backoffer, ctx // When a store is not available, the leader of related region should be elected quickly. // TODO: the number of retry time should be limited:since region may be unavailable // when some unrecoverable disaster happened. - err = bo.Backoff(BoTiFlashRPC, errors.Errorf("send request error: %v, ctx: %v, regionInfos: %v", err, ctx, regionInfos)) + err = bo.Backoff(retry.BoTiFlashRPC, errors.Errorf("send request error: %v, ctx: %v, regionInfos: %v", err, ctx, regionInfos)) return errors.Trace(err) } diff --git a/store/tikv/client_batch.go b/store/tikv/client_batch.go index e5ec039fc6911..70f1cf27ccacc 100644 --- a/store/tikv/client_batch.go +++ b/store/tikv/client_batch.go @@ -673,7 +673,7 @@ func (c *batchCommandsClient) recreateStreamingClient(err error, streamClient *b break } - err2 := b.BackoffTiKVRPC(err1) + err2 := b.Backoff(retry.BoTiKVRPC, err1) // As timeout is set to math.MaxUint32, err2 should always be nil. // This line is added to make the 'make errcheck' pass. terror.Log(err2) diff --git a/store/tikv/prewrite.go b/store/tikv/prewrite.go index ffb47e1fb46fa..49ddc1525b748 100644 --- a/store/tikv/prewrite.go +++ b/store/tikv/prewrite.go @@ -269,7 +269,7 @@ func (action actionPrewrite) handleSingleBatch(c *twoPhaseCommitter, bo *Backoff } atomic.AddInt64(&c.getDetail().ResolveLockTime, int64(time.Since(start))) if msBeforeExpired > 0 { - err = bo.BackoffWithMaxSleep(retry.BoTxnLock, int(msBeforeExpired), errors.Errorf("2PC prewrite lockedKeys: %d", len(locks))) + err = bo.BackoffWithCfgAndMaxSleep(retry.BoTxnLock, int(msBeforeExpired), errors.Errorf("2PC prewrite lockedKeys: %d", len(locks))) if err != nil { return errors.Trace(err) } diff --git a/store/tikv/region_request.go b/store/tikv/region_request.go index f42f7add092db..36b297c580102 100644 --- a/store/tikv/region_request.go +++ b/store/tikv/region_request.go @@ -575,7 +575,7 @@ func (s *RegionRequestSender) onSendFail(bo *Backoffer, ctx *RPCContext, err err if ctx.Store != nil && ctx.Store.storeType == tikvrpc.TiFlash { err = bo.Backoff(retry.BoTiFlashRPC, errors.Errorf("send tiflash request error: %v, ctx: %v, try next peer later", err, ctx)) } else { - err = bo.BackoffTiKVRPC(errors.Errorf("send tikv request error: %v, ctx: %v, try next peer later", err, ctx)) + err = bo.Backoff(retry.BoTiKVRPC, errors.Errorf("send tikv request error: %v, ctx: %v, try next peer later", err, ctx)) } return errors.Trace(err) } diff --git a/store/tikv/retry/backoff.go b/store/tikv/retry/backoff.go index 9e7a527c69caa..d07b9c4fdccae 100644 --- a/store/tikv/retry/backoff.go +++ b/store/tikv/retry/backoff.go @@ -17,7 +17,6 @@ import ( "context" "fmt" "math" - "math/rand" "strings" "sync/atomic" "time" @@ -30,202 +29,24 @@ import ( "github.com/pingcap/tidb/store/tikv/logutil" "github.com/pingcap/tidb/store/tikv/metrics" "github.com/pingcap/tidb/store/tikv/util" - "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) -const ( - // NoJitter makes the backoff sequence strict exponential. - NoJitter = 1 + iota - // FullJitter applies random factors to strict exponential. - FullJitter - // EqualJitter is also randomized, but prevents very short sleeps. - EqualJitter - // DecorrJitter increases the maximum jitter based on the last random value. - DecorrJitter -) - -func (t BackoffType) metric() prometheus.Observer { - switch t { - // TODO: distinguish tikv and tiflash in metrics - case boTiKVRPC, BoTiFlashRPC: - return metrics.BackoffHistogramRPC - case BoTxnLock: - return metrics.BackoffHistogramLock - case BoTxnLockFast: - return metrics.BackoffHistogramLockFast - case BoPDRPC: - return metrics.BackoffHistogramPD - case BoRegionMiss: - return metrics.BackoffHistogramRegionMiss - case BoTiKVServerBusy, BoTiFlashServerBusy: - return metrics.BackoffHistogramServerBusy - case BoStaleCmd: - return metrics.BackoffHistogramStaleCmd - } - return metrics.BackoffHistogramEmpty -} - -// NewBackoffFn creates a backoff func which implements exponential backoff with -// optional jitters. -// See http://www.awsarchitectureblog.com/2015/03/backoff.html -func NewBackoffFn(base, cap, jitter int) func(ctx context.Context, maxSleepMs int) int { - if base < 2 { - // Top prevent panic in 'rand.Intn'. - base = 2 - } - attempts := 0 - lastSleep := base - return func(ctx context.Context, maxSleepMs int) int { - var sleep int - switch jitter { - case NoJitter: - sleep = expo(base, cap, attempts) - case FullJitter: - v := expo(base, cap, attempts) - sleep = rand.Intn(v) - case EqualJitter: - v := expo(base, cap, attempts) - sleep = v/2 + rand.Intn(v/2) - case DecorrJitter: - sleep = int(math.Min(float64(cap), float64(base+rand.Intn(lastSleep*3-base)))) - } - logutil.BgLogger().Debug("backoff", - zap.Int("base", base), - zap.Int("sleep", sleep), - zap.Int("attempts", attempts)) - - realSleep := sleep - // when set maxSleepMs >= 0 in `tikv.BackoffWithMaxSleep` will force sleep maxSleepMs milliseconds. - if maxSleepMs >= 0 && realSleep > maxSleepMs { - realSleep = maxSleepMs - } - select { - case <-time.After(time.Duration(realSleep) * time.Millisecond): - attempts++ - lastSleep = sleep - return realSleep - case <-ctx.Done(): - return 0 - } - } -} - -func expo(base, cap, n int) int { - return int(math.Min(float64(cap), float64(base)*math.Pow(2.0, float64(n)))) -} - -// BackoffType defines the backoff type. -type BackoffType int - -// Back off types. -const ( - boTiKVRPC BackoffType = iota - BoTiFlashRPC - BoTxnLock - BoTxnLockFast - BoPDRPC - BoRegionMiss - BoTiKVServerBusy - BoTiFlashServerBusy - BoTxnNotFound - BoStaleCmd - BoMaxTsNotSynced -) - -func (t BackoffType) createFn(vars *kv.Variables) func(context.Context, int) int { - switch t { - case boTiKVRPC, BoTiFlashRPC: - return NewBackoffFn(100, 2000, EqualJitter) - case BoTxnLock: - return NewBackoffFn(200, 3000, EqualJitter) - case BoTxnLockFast: - return NewBackoffFn(vars.BackoffLockFast, 3000, EqualJitter) - case BoPDRPC: - return NewBackoffFn(500, 3000, EqualJitter) - case BoRegionMiss: - // change base time to 2ms, because it may recover soon. - return NewBackoffFn(2, 500, NoJitter) - case BoTxnNotFound: - return NewBackoffFn(2, 500, NoJitter) - case BoTiKVServerBusy, BoTiFlashServerBusy: - return NewBackoffFn(2000, 10000, EqualJitter) - case BoStaleCmd: - return NewBackoffFn(2, 1000, NoJitter) - case BoMaxTsNotSynced: - return NewBackoffFn(2, 500, NoJitter) - } - return nil -} - -func (t BackoffType) String() string { - switch t { - case boTiKVRPC: - return "tikvRPC" - case BoTiFlashRPC: - return "tiflashRPC" - case BoTxnLock: - return "txnLock" - case BoTxnLockFast: - return "txnLockFast" - case BoPDRPC: - return "pdRPC" - case BoRegionMiss: - return "regionMiss" - case BoTiKVServerBusy: - return "tikvServerBusy" - case BoTiFlashServerBusy: - return "tiflashServerBusy" - case BoStaleCmd: - return "staleCommand" - case BoTxnNotFound: - return "txnNotFound" - case BoMaxTsNotSynced: - return "maxTsNotSynced" - } - return "" -} - -// TError returns pingcap/error of the backoff type. -func (t BackoffType) TError() error { - switch t { - case boTiKVRPC: - return tikverr.ErrTiKVServerTimeout - case BoTiFlashRPC: - return tikverr.ErrTiFlashServerTimeout - case BoTxnLock, BoTxnLockFast, BoTxnNotFound: - return tikverr.ErrResolveLockTimeout - case BoPDRPC: - return tikverr.NewErrPDServerTimeout("") - case BoRegionMiss: - return tikverr.ErrRegionUnavailable - case BoTiKVServerBusy: - return tikverr.ErrTiKVServerBusy - case BoTiFlashServerBusy: - return tikverr.ErrTiFlashServerBusy - case BoStaleCmd: - return tikverr.ErrTiKVStaleCommand - case BoMaxTsNotSynced: - return tikverr.ErrTiKVMaxTimestampNotSynced - } - return tikverr.ErrUnknown -} - // Backoffer is a utility for retrying queries. type Backoffer struct { ctx context.Context - fn map[BackoffType]func(context.Context, int) int + fn map[string]backoffFn maxSleep int totalSleep int errors []error - types []fmt.Stringer + configs []fmt.Stringer vars *kv.Variables noop bool - backoffSleepMS map[BackoffType]int - backoffTimes map[BackoffType]int + backoffSleepMS map[string]int + backoffTimes map[string]int } type txnStartCtxKeyType struct{} @@ -265,26 +86,71 @@ func (b *Backoffer) withVars(vars *kv.Variables) *Backoffer { return b } -// Backoff sleeps a while base on the backoffType and records the error message. +// Backoff sleeps a while base on the Config and records the error message. // It returns a retryable error if total sleep time exceeds maxSleep. -func (b *Backoffer) Backoff(typ BackoffType, err error) error { +func (b *Backoffer) Backoff(cfg *Config, err error) error { if span := opentracing.SpanFromContext(b.ctx); span != nil && span.Tracer() != nil { - span1 := span.Tracer().StartSpan(fmt.Sprintf("tikv.backoff.%s", typ), opentracing.ChildOf(span.Context())) + span1 := span.Tracer().StartSpan(fmt.Sprintf("tikv.backoff.%s", cfg), opentracing.ChildOf(span.Context())) defer span1.Finish() opentracing.ContextWithSpan(b.ctx, span1) } - return b.BackoffWithMaxSleep(typ, -1, err) + return b.BackoffWithCfgAndMaxSleep(cfg, -1, err) } -// BackoffTiKVRPC sleeps a while base on the TiKVRPC and records the error message. -// It returns a retryable error if total sleep time exceeds maxSleep. -func (b *Backoffer) BackoffTiKVRPC(err error) error { - return b.Backoff(boTiKVRPC, err) +// BackoffWithMaxSleepTxnLockFast sleeps a while base on the MaxSleepTxnLock and records the error message +// and never sleep more than maxSleepMs for each sleep. +func (b *Backoffer) BackoffWithMaxSleepTxnLockFast(maxSleepMs int, err error) error { + cfg := BoTxnLockFast + return b.BackoffWithCfgAndMaxSleep(cfg, maxSleepMs, err) +} + +// BackoffWithMaxSleep is deprecated, please use BackoffWithCfgAndMaxSleep instead. TODO: remove it when br is ready. +func (b *Backoffer) BackoffWithMaxSleep(typ int, maxSleepMs int, err error) error { + // Back off types. + const ( + boTiKVRPC int = iota + boTiFlashRPC + boTxnLock + boTxnLockFast + boPDRPC + boRegionMiss + boTiKVServerBusy + boTiFlashServerBusy + boTxnNotFound + boStaleCmd + boMaxTsNotSynced + ) + switch typ { + case boTiKVRPC: + return b.BackoffWithCfgAndMaxSleep(BoTiKVRPC, maxSleepMs, err) + case boTiFlashRPC: + return b.BackoffWithCfgAndMaxSleep(BoTiFlashRPC, maxSleepMs, err) + case boTxnLock: + return b.BackoffWithCfgAndMaxSleep(BoTxnLock, maxSleepMs, err) + case boTxnLockFast: + return b.BackoffWithCfgAndMaxSleep(BoTxnLockFast, maxSleepMs, err) + case boPDRPC: + return b.BackoffWithCfgAndMaxSleep(BoPDRPC, maxSleepMs, err) + case boRegionMiss: + return b.BackoffWithCfgAndMaxSleep(BoRegionMiss, maxSleepMs, err) + case boTiKVServerBusy: + return b.BackoffWithCfgAndMaxSleep(BoTiKVServerBusy, maxSleepMs, err) + case boTiFlashServerBusy: + return b.BackoffWithCfgAndMaxSleep(BoTiFlashServerBusy, maxSleepMs, err) + case boTxnNotFound: + return b.BackoffWithCfgAndMaxSleep(BoTxnNotFound, maxSleepMs, err) + case boStaleCmd: + return b.BackoffWithCfgAndMaxSleep(BoStaleCmd, maxSleepMs, err) + case boMaxTsNotSynced: + return b.BackoffWithCfgAndMaxSleep(BoMaxTsNotSynced, maxSleepMs, err) + } + cfg := NewConfig("", metrics.BackoffHistogramEmpty, nil, tikverr.ErrUnknown) + return b.BackoffWithCfgAndMaxSleep(cfg, maxSleepMs, err) } -// BackoffWithMaxSleep sleeps a while base on the backoffType and records the error message +// BackoffWithCfgAndMaxSleep sleeps a while base on the Config and records the error message // and never sleep more than maxSleepMs for each sleep. -func (b *Backoffer) BackoffWithMaxSleep(typ BackoffType, maxSleepMs int, err error) error { +func (b *Backoffer) BackoffWithCfgAndMaxSleep(cfg *Config, maxSleepMs int, err error) error { if strings.Contains(err.Error(), tikverr.MismatchClusterID) { logutil.BgLogger().Fatal("critical error", zap.Error(err)) } @@ -295,9 +161,9 @@ func (b *Backoffer) BackoffWithMaxSleep(typ BackoffType, maxSleepMs int, err err } b.errors = append(b.errors, errors.Errorf("%s at %s", err.Error(), time.Now().Format(time.RFC3339Nano))) - b.types = append(b.types, typ) + b.configs = append(b.configs, cfg) if b.noop || (b.maxSleep > 0 && b.totalSleep >= b.maxSleep) { - errMsg := fmt.Sprintf("%s backoffer.maxSleep %dms is exceeded, errors:", typ.String(), b.maxSleep) + errMsg := fmt.Sprintf("%s backoffer.maxSleep %dms is exceeded, errors:", cfg.String(), b.maxSleep) for i, err := range b.errors { // Print only last 3 errors for non-DEBUG log levels. if log.GetLevel() == zapcore.DebugLevel || i >= len(b.errors)-3 { @@ -306,30 +172,29 @@ func (b *Backoffer) BackoffWithMaxSleep(typ BackoffType, maxSleepMs int, err err } logutil.BgLogger().Warn(errMsg) // Use the first backoff type to generate a MySQL error. - return b.types[0].(BackoffType).TError() + return b.configs[0].(*Config).err } // Lazy initialize. if b.fn == nil { - b.fn = make(map[BackoffType]func(context.Context, int) int) + b.fn = make(map[string]backoffFn) } - f, ok := b.fn[typ] + f, ok := b.fn[cfg.name] if !ok { - f = typ.createFn(b.vars) - b.fn[typ] = f + f = cfg.createBackoffFn(b.vars) + b.fn[cfg.name] = f } - realSleep := f(b.ctx, maxSleepMs) - typ.metric().Observe(float64(realSleep) / 1000) + cfg.metric.Observe(float64(realSleep) / 1000) b.totalSleep += realSleep if b.backoffSleepMS == nil { - b.backoffSleepMS = make(map[BackoffType]int) + b.backoffSleepMS = make(map[string]int) } - b.backoffSleepMS[typ] += realSleep + b.backoffSleepMS[cfg.name] += realSleep if b.backoffTimes == nil { - b.backoffTimes = make(map[BackoffType]int) + b.backoffTimes = make(map[string]int) } - b.backoffTimes[typ]++ + b.backoffTimes[cfg.name]++ stmtExec := b.ctx.Value(util.ExecDetailsKey) if stmtExec != nil { @@ -352,7 +217,7 @@ func (b *Backoffer) BackoffWithMaxSleep(typ BackoffType, maxSleepMs int, err err zap.Error(err), zap.Int("totalSleep", b.totalSleep), zap.Int("maxSleep", b.maxSleep), - zap.Stringer("type", typ), + zap.Stringer("type", cfg), zap.Reflect("txnStartTS", startTs)) return nil } @@ -361,7 +226,7 @@ func (b *Backoffer) String() string { if b.totalSleep == 0 { return "" } - return fmt.Sprintf(" backoff(%dms %v)", b.totalSleep, b.types) + return fmt.Sprintf(" backoff(%dms %v)", b.totalSleep, b.configs) } // Clone creates a new Backoffer which keeps current Backoffer's sleep time and errors, and shares @@ -401,7 +266,7 @@ func (b *Backoffer) GetTotalSleep() int { // GetTypes returns type list. func (b *Backoffer) GetTypes() []fmt.Stringer { - return b.types + return b.configs } // GetCtx returns the binded context. @@ -415,12 +280,12 @@ func (b *Backoffer) SetCtx(ctx context.Context) { } // GetBackoffTimes returns a map contains backoff time count by type. -func (b *Backoffer) GetBackoffTimes() map[BackoffType]int { +func (b *Backoffer) GetBackoffTimes() map[string]int { return b.backoffTimes } // GetBackoffSleepMS returns a map contains backoff sleep time by type. -func (b *Backoffer) GetBackoffSleepMS() map[BackoffType]int { +func (b *Backoffer) GetBackoffSleepMS() map[string]int { return b.backoffSleepMS } diff --git a/store/tikv/retry/backoff_test.go b/store/tikv/retry/backoff_test.go index f8dfb9ed120f3..a0a566499b10f 100644 --- a/store/tikv/retry/backoff_test.go +++ b/store/tikv/retry/backoff_test.go @@ -27,7 +27,7 @@ var _ = Suite(&testBackoffSuite{}) func (s *testBackoffSuite) TestBackoffWithMax(c *C) { b := NewBackofferWithVars(context.TODO(), 2000, nil) - err := b.BackoffWithMaxSleep(BoTxnLockFast, 30, errors.New("test")) + err := b.BackoffWithMaxSleepTxnLockFast(30, errors.New("test")) c.Assert(err, IsNil) c.Assert(b.totalSleep, Equals, 30) } diff --git a/store/tikv/retry/config.go b/store/tikv/retry/config.go new file mode 100644 index 0000000000000..bd118cabd8028 --- /dev/null +++ b/store/tikv/retry/config.go @@ -0,0 +1,159 @@ +// Copyright 2021 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package retry + +import ( + "context" + "math" + "math/rand" + "strings" + "time" + + tikverr "github.com/pingcap/tidb/store/tikv/error" + "github.com/pingcap/tidb/store/tikv/kv" + "github.com/pingcap/tidb/store/tikv/logutil" + "github.com/pingcap/tidb/store/tikv/metrics" + "github.com/prometheus/client_golang/prometheus" + "go.uber.org/zap" +) + +// Config is the configuration of the Backoff function. +type Config struct { + name string + metric prometheus.Observer + fnCfg *BackoffFnCfg + err error +} + +// backoffFn is the backoff function which compute the sleep time and do sleep. +type backoffFn func(ctx context.Context, maxSleepMs int) int + +func (c *Config) createBackoffFn(vars *kv.Variables) backoffFn { + if strings.EqualFold(c.name, txnLockFastName) { + return newBackoffFn(vars.BackoffLockFast, c.fnCfg.cap, c.fnCfg.jitter) + } + return newBackoffFn(c.fnCfg.base, c.fnCfg.cap, c.fnCfg.jitter) +} + +// BackoffFnCfg is the configuration for the backoff func which implements exponential backoff with +// optional jitters. +// See http://www.awsarchitectureblog.com/2015/03/backoff.html +type BackoffFnCfg struct { + base int + cap int + jitter int +} + +// NewBackoffFnCfg creates the config for BackoffFn. +func NewBackoffFnCfg(base, cap, jitter int) *BackoffFnCfg { + return &BackoffFnCfg{ + base, + cap, + jitter, + } +} + +// NewConfig creates a new Config for the Backoff operation. +func NewConfig(name string, metric prometheus.Observer, backoffFnCfg *BackoffFnCfg, err error) *Config { + return &Config{ + name: name, + metric: metric, + fnCfg: backoffFnCfg, + err: err, + } +} + +func (c *Config) String() string { + return c.name +} + +const txnLockFastName = "txnLockFast" + +// Backoff Config samples. +var ( + // TODO: distinguish tikv and tiflash in metrics + BoTiKVRPC = NewConfig("tikvRPC", metrics.BackoffHistogramRPC, NewBackoffFnCfg(100, 2000, EqualJitter), tikverr.ErrTiKVServerTimeout) + BoTiFlashRPC = NewConfig("tiflashRPC", metrics.BackoffHistogramRPC, NewBackoffFnCfg(100, 2000, EqualJitter), tikverr.ErrTiFlashServerTimeout) + BoTxnLock = NewConfig("txnLock", metrics.BackoffHistogramLock, NewBackoffFnCfg(200, 3000, EqualJitter), tikverr.ErrResolveLockTimeout) + BoPDRPC = NewConfig("pdRPC", metrics.BackoffHistogramPD, NewBackoffFnCfg(500, 3000, EqualJitter), tikverr.NewErrPDServerTimeout("")) + // change base time to 2ms, because it may recover soon. + BoRegionMiss = NewConfig("regionMiss", metrics.BackoffHistogramRegionMiss, NewBackoffFnCfg(2, 500, NoJitter), tikverr.ErrRegionUnavailable) + BoTiKVServerBusy = NewConfig("tikvServerBusy", metrics.BackoffHistogramServerBusy, NewBackoffFnCfg(2000, 10000, EqualJitter), tikverr.ErrTiKVServerBusy) + BoTiFlashServerBusy = NewConfig("tiflashServerBusy", metrics.BackoffHistogramServerBusy, NewBackoffFnCfg(2000, 10000, EqualJitter), tikverr.ErrTiFlashServerBusy) + BoTxnNotFound = NewConfig("txnNotFound", metrics.BackoffHistogramEmpty, NewBackoffFnCfg(2, 500, NoJitter), tikverr.ErrResolveLockTimeout) + BoStaleCmd = NewConfig("staleCommand", metrics.BackoffHistogramStaleCmd, NewBackoffFnCfg(2, 1000, NoJitter), tikverr.ErrTiKVStaleCommand) + BoMaxTsNotSynced = NewConfig("maxTsNotSynced", metrics.BackoffHistogramEmpty, NewBackoffFnCfg(2, 500, NoJitter), tikverr.ErrTiKVMaxTimestampNotSynced) + // TxnLockFast's `base` load from vars.BackoffLockFast when create BackoffFn. + BoTxnLockFast = NewConfig(txnLockFastName, metrics.BackoffHistogramLockFast, NewBackoffFnCfg(2, 3000, EqualJitter), tikverr.ErrResolveLockTimeout) +) + +const ( + // NoJitter makes the backoff sequence strict exponential. + NoJitter = 1 + iota + // FullJitter applies random factors to strict exponential. + FullJitter + // EqualJitter is also randomized, but prevents very short sleeps. + EqualJitter + // DecorrJitter increases the maximum jitter based on the last random value. + DecorrJitter +) + +// newBackoffFn creates a backoff func which implements exponential backoff with +// optional jitters. +// See http://www.awsarchitectureblog.com/2015/03/backoff.html +func newBackoffFn(base, cap, jitter int) backoffFn { + if base < 2 { + // Top prevent panic in 'rand.Intn'. + base = 2 + } + attempts := 0 + lastSleep := base + return func(ctx context.Context, maxSleepMs int) int { + var sleep int + switch jitter { + case NoJitter: + sleep = expo(base, cap, attempts) + case FullJitter: + v := expo(base, cap, attempts) + sleep = rand.Intn(v) + case EqualJitter: + v := expo(base, cap, attempts) + sleep = v/2 + rand.Intn(v/2) + case DecorrJitter: + sleep = int(math.Min(float64(cap), float64(base+rand.Intn(lastSleep*3-base)))) + } + logutil.BgLogger().Debug("backoff", + zap.Int("base", base), + zap.Int("sleep", sleep), + zap.Int("attempts", attempts)) + + realSleep := sleep + // when set maxSleepMs >= 0 in `tikv.BackoffWithMaxSleep` will force sleep maxSleepMs milliseconds. + if maxSleepMs >= 0 && realSleep > maxSleepMs { + realSleep = maxSleepMs + } + select { + case <-time.After(time.Duration(realSleep) * time.Millisecond): + attempts++ + lastSleep = sleep + return realSleep + case <-ctx.Done(): + return 0 + } + } +} + +func expo(base, cap, n int) int { + return int(math.Min(float64(cap), float64(base)*math.Pow(2.0, float64(n)))) +} diff --git a/store/tikv/scan.go b/store/tikv/scan.go index 035291a783aec..94ece80ff067f 100644 --- a/store/tikv/scan.go +++ b/store/tikv/scan.go @@ -254,7 +254,7 @@ func (s *Scanner) getData(bo *Backoffer) error { return errors.Trace(err) } if msBeforeExpired > 0 { - err = bo.BackoffWithMaxSleep(retry.BoTxnLockFast, int(msBeforeExpired), errors.Errorf("key is locked during scanning")) + err = bo.BackoffWithMaxSleepTxnLockFast(int(msBeforeExpired), errors.Errorf("key is locked during scanning")) if err != nil { return errors.Trace(err) } diff --git a/store/tikv/snapshot.go b/store/tikv/snapshot.go index ab3862fe4bf0b..180ac59369aca 100644 --- a/store/tikv/snapshot.go +++ b/store/tikv/snapshot.go @@ -381,7 +381,7 @@ func (s *KVSnapshot) batchGetSingleRegion(bo *Backoffer, batch batchKeys, collec return errors.Trace(err) } if msBeforeExpired > 0 { - err = bo.BackoffWithMaxSleep(retry.BoTxnLockFast, int(msBeforeExpired), errors.Errorf("batchGet lockedKeys: %d", len(lockedKeys))) + err = bo.BackoffWithMaxSleepTxnLockFast(int(msBeforeExpired), errors.Errorf("batchGet lockedKeys: %d", len(lockedKeys))) if err != nil { return errors.Trace(err) } @@ -527,7 +527,7 @@ func (s *KVSnapshot) get(ctx context.Context, bo *Backoffer, k []byte) ([]byte, return nil, errors.Trace(err) } if msBeforeExpired > 0 { - err = bo.BackoffWithMaxSleep(retry.BoTxnLockFast, int(msBeforeExpired), errors.New(keyErr.String())) + err = bo.BackoffWithMaxSleepTxnLockFast(int(msBeforeExpired), errors.New(keyErr.String())) if err != nil { return nil, errors.Trace(err) } @@ -730,8 +730,8 @@ func (s *KVSnapshot) mergeRegionRequestStats(stats map[tikvrpc.CmdType]*RPCRunti // SnapshotRuntimeStats records the runtime stats of snapshot. type SnapshotRuntimeStats struct { rpcStats RegionRequestRuntimeStats - backoffSleepMS map[retry.BackoffType]int - backoffTimes map[retry.BackoffType]int + backoffSleepMS map[string]int + backoffTimes map[string]int scanDetail *util.ScanDetail timeDetail *util.TimeDetail } @@ -745,8 +745,8 @@ func (rs *SnapshotRuntimeStats) Clone() *SnapshotRuntimeStats { } } if len(rs.backoffSleepMS) > 0 { - newRs.backoffSleepMS = make(map[retry.BackoffType]int) - newRs.backoffTimes = make(map[retry.BackoffType]int) + newRs.backoffSleepMS = make(map[string]int) + newRs.backoffTimes = make(map[string]int) for k, v := range rs.backoffSleepMS { newRs.backoffSleepMS[k] += v } @@ -767,10 +767,10 @@ func (rs *SnapshotRuntimeStats) Merge(other *SnapshotRuntimeStats) { } if len(other.backoffSleepMS) > 0 { if rs.backoffSleepMS == nil { - rs.backoffSleepMS = make(map[retry.BackoffType]int) + rs.backoffSleepMS = make(map[string]int) } if rs.backoffTimes == nil { - rs.backoffTimes = make(map[retry.BackoffType]int) + rs.backoffTimes = make(map[string]int) } for k, v := range other.backoffSleepMS { rs.backoffSleepMS[k] += v @@ -791,7 +791,7 @@ func (rs *SnapshotRuntimeStats) String() string { } ms := rs.backoffSleepMS[k] d := time.Duration(ms) * time.Millisecond - buf.WriteString(fmt.Sprintf("%s_backoff:{num:%d, total_time:%s}", k.String(), v, util.FormatDuration(d))) + buf.WriteString(fmt.Sprintf("%s_backoff:{num:%d, total_time:%s}", k, v, util.FormatDuration(d))) } timeDetail := rs.timeDetail.String() if timeDetail != "" { diff --git a/store/tikv/tests/snapshot_test.go b/store/tikv/tests/snapshot_test.go index a126decfc1c7d..ee2a71730b5bf 100644 --- a/store/tikv/tests/snapshot_test.go +++ b/store/tikv/tests/snapshot_test.go @@ -273,7 +273,7 @@ func (s *testSnapshotSuite) TestSnapshotRuntimeStats(c *C) { snapshot.MergeRegionRequestStats(reqStats.Stats) snapshot.MergeRegionRequestStats(reqStats.Stats) bo := tikv.NewBackofferWithVars(context.Background(), 2000, nil) - err := bo.BackoffWithMaxSleep(tikv.BoTxnLockFast, 30, errors.New("test")) + err := bo.BackoffWithMaxSleepTxnLockFast(30, errors.New("test")) c.Assert(err, IsNil) snapshot.RecordBackoffInfo(bo) snapshot.RecordBackoffInfo(bo)