github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/allegrosql/physical_plan_test.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package embedded_test
    15  
    16  import (
    17  	"context"
    18  	"fmt"
    19  
    20  	"github.com/whtcorpsinc/BerolinaSQL"
    21  	"github.com/whtcorpsinc/BerolinaSQL/perceptron"
    22  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    23  	. "github.com/whtcorpsinc/check"
    24  	"github.com/whtcorpsinc/milevadb/causet"
    25  	"github.com/whtcorpsinc/milevadb/causet/embedded"
    26  	"github.com/whtcorpsinc/milevadb/ekv"
    27  	"github.com/whtcorpsinc/milevadb/interlock"
    28  	"github.com/whtcorpsinc/milevadb/petri"
    29  	"github.com/whtcorpsinc/milevadb/schemareplicant"
    30  	"github.com/whtcorpsinc/milevadb/soliton/hint"
    31  	"github.com/whtcorpsinc/milevadb/soliton/solitonutil"
    32  	"github.com/whtcorpsinc/milevadb/soliton/testkit"
    33  	"github.com/whtcorpsinc/milevadb/soliton/testleak"
    34  	"github.com/whtcorpsinc/milevadb/stochastik"
    35  	"github.com/whtcorpsinc/milevadb/stochastikctx"
    36  	"github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx"
    37  	"github.com/whtcorpsinc/milevadb/stochastikctx/variable"
    38  )
    39  
    40  var _ = Suite(&testCausetSuite{})
    41  var _ = SerialSuites(&testCausetSerialSuite{})
    42  
    43  type testCausetSuiteBase struct {
    44  	*BerolinaSQL.BerolinaSQL
    45  	is schemareplicant.SchemaReplicant
    46  }
    47  
    48  func (s *testCausetSuiteBase) SetUpSuite(c *C) {
    49  	s.is = schemareplicant.MockSchemaReplicant([]*perceptron.BlockInfo{embedded.MockSignedBlock(), embedded.MockUnsignedBlock()})
    50  	s.BerolinaSQL = BerolinaSQL.New()
    51  	s.BerolinaSQL.EnableWindowFunc(true)
    52  }
    53  
    54  type testCausetSerialSuite struct {
    55  	testCausetSuiteBase
    56  }
    57  
    58  type testCausetSuite struct {
    59  	testCausetSuiteBase
    60  
    61  	testData solitonutil.TestData
    62  }
    63  
    64  func (s *testCausetSuite) SetUpSuite(c *C) {
    65  	s.testCausetSuiteBase.SetUpSuite(c)
    66  
    67  	var err error
    68  	s.testData, err = solitonutil.LoadTestSuiteData("testdata", "plan_suite")
    69  	c.Assert(err, IsNil)
    70  }
    71  
    72  func (s *testCausetSuite) TearDownSuite(c *C) {
    73  	c.Assert(s.testData.GenerateOutputIfNeeded(), IsNil)
    74  }
    75  
    76  func (s *testCausetSuite) TestPosetDagCausetBuilderSimpleCase(c *C) {
    77  	defer testleak.AfterTest(c)()
    78  	causetstore, dom, err := newStoreWithBootstrap()
    79  	c.Assert(err, IsNil)
    80  	defer func() {
    81  		dom.Close()
    82  		causetstore.Close()
    83  	}()
    84  	se, err := stochastik.CreateStochastik4Test(causetstore)
    85  	c.Assert(err, IsNil)
    86  	_, err = se.InterDircute(context.Background(), "use test")
    87  	c.Assert(err, IsNil)
    88  	var input []string
    89  	var output []struct {
    90  		ALLEGROALLEGROSQL string
    91  		Best              string
    92  	}
    93  	s.testData.GetTestCases(c, &input, &output)
    94  	for i, tt := range input {
    95  		comment := Commentf("case:%v allegrosql:%s", i, tt)
    96  		stmt, err := s.ParseOneStmt(tt, "", "")
    97  		c.Assert(err, IsNil, comment)
    98  
    99  		err = se.NewTxn(context.Background())
   100  		c.Assert(err, IsNil)
   101  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   102  		c.Assert(err, IsNil)
   103  		s.testData.OnRecord(func() {
   104  			output[i].ALLEGROALLEGROSQL = tt
   105  			output[i].Best = embedded.ToString(p)
   106  		})
   107  		c.Assert(embedded.ToString(p), Equals, output[i].Best, comment)
   108  	}
   109  }
   110  
   111  func (s *testCausetSuite) TestPosetDagCausetBuilderJoin(c *C) {
   112  	defer testleak.AfterTest(c)()
   113  	causetstore, dom, err := newStoreWithBootstrap()
   114  	c.Assert(err, IsNil)
   115  	defer func() {
   116  		dom.Close()
   117  		causetstore.Close()
   118  	}()
   119  	se, err := stochastik.CreateStochastik4Test(causetstore)
   120  	c.Assert(err, IsNil)
   121  	_, err = se.InterDircute(context.Background(), "use test")
   122  	c.Assert(err, IsNil)
   123  	ctx := se.(stochastikctx.Context)
   124  	stochastikVars := ctx.GetStochastikVars()
   125  	stochastikVars.InterlockingDirectorateConcurrency = 4
   126  	stochastikVars.SetDistALLEGROSQLScanConcurrency(15)
   127  	stochastikVars.SetHashJoinConcurrency(5)
   128  
   129  	var input []string
   130  	var output []struct {
   131  		ALLEGROALLEGROSQL string
   132  		Best              string
   133  	}
   134  	s.testData.GetTestCases(c, &input, &output)
   135  	for i, tt := range input {
   136  		comment := Commentf("case:%v allegrosql:%s", i, tt)
   137  		stmt, err := s.ParseOneStmt(tt, "", "")
   138  		c.Assert(err, IsNil, comment)
   139  
   140  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   141  		c.Assert(err, IsNil)
   142  		s.testData.OnRecord(func() {
   143  			output[i].ALLEGROALLEGROSQL = tt
   144  			output[i].Best = embedded.ToString(p)
   145  		})
   146  		c.Assert(embedded.ToString(p), Equals, output[i].Best, comment)
   147  	}
   148  }
   149  
   150  func (s *testCausetSuite) TestPosetDagCausetBuilderSubquery(c *C) {
   151  	defer testleak.AfterTest(c)()
   152  	causetstore, dom, err := newStoreWithBootstrap()
   153  	c.Assert(err, IsNil)
   154  	defer func() {
   155  		dom.Close()
   156  		causetstore.Close()
   157  	}()
   158  	se, err := stochastik.CreateStochastik4Test(causetstore)
   159  	c.Assert(err, IsNil)
   160  	_, err = se.InterDircute(context.Background(), "use test")
   161  	c.Assert(err, IsNil)
   162  	se.InterDircute(context.Background(), "set sql_mode='STRICT_TRANS_TABLES'") // disable only full group by
   163  	ctx := se.(stochastikctx.Context)
   164  	stochastikVars := ctx.GetStochastikVars()
   165  	stochastikVars.SetHashAggFinalConcurrency(1)
   166  	stochastikVars.SetHashAggPartialConcurrency(1)
   167  	stochastikVars.SetHashJoinConcurrency(5)
   168  	stochastikVars.SetDistALLEGROSQLScanConcurrency(15)
   169  	stochastikVars.InterlockingDirectorateConcurrency = 4
   170  	var input []string
   171  	var output []struct {
   172  		ALLEGROALLEGROSQL string
   173  		Best              string
   174  	}
   175  	s.testData.GetTestCases(c, &input, &output)
   176  	for i, tt := range input {
   177  		comment := Commentf("for %s", tt)
   178  		stmt, err := s.ParseOneStmt(tt, "", "")
   179  		c.Assert(err, IsNil, comment)
   180  
   181  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   182  		c.Assert(err, IsNil)
   183  		s.testData.OnRecord(func() {
   184  			output[i].ALLEGROALLEGROSQL = tt
   185  			output[i].Best = embedded.ToString(p)
   186  		})
   187  		c.Assert(embedded.ToString(p), Equals, output[i].Best, Commentf("for %s", tt))
   188  	}
   189  }
   190  
   191  func (s *testCausetSuite) TestPosetDagCausetTopN(c *C) {
   192  	defer testleak.AfterTest(c)()
   193  	causetstore, dom, err := newStoreWithBootstrap()
   194  	c.Assert(err, IsNil)
   195  	defer func() {
   196  		dom.Close()
   197  		causetstore.Close()
   198  	}()
   199  	se, err := stochastik.CreateStochastik4Test(causetstore)
   200  	c.Assert(err, IsNil)
   201  	_, err = se.InterDircute(context.Background(), "use test")
   202  	c.Assert(err, IsNil)
   203  
   204  	var input []string
   205  	var output []struct {
   206  		ALLEGROALLEGROSQL string
   207  		Best              string
   208  	}
   209  	s.testData.GetTestCases(c, &input, &output)
   210  	for i, tt := range input {
   211  		comment := Commentf("case:%v allegrosql:%s", i, tt)
   212  		stmt, err := s.ParseOneStmt(tt, "", "")
   213  		c.Assert(err, IsNil, comment)
   214  
   215  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   216  		c.Assert(err, IsNil)
   217  		s.testData.OnRecord(func() {
   218  			output[i].ALLEGROALLEGROSQL = tt
   219  			output[i].Best = embedded.ToString(p)
   220  		})
   221  		c.Assert(embedded.ToString(p), Equals, output[i].Best, comment)
   222  	}
   223  }
   224  
   225  func (s *testCausetSuite) TestPosetDagCausetBuilderBasePhysicalCauset(c *C) {
   226  	defer testleak.AfterTest(c)()
   227  	causetstore, dom, err := newStoreWithBootstrap()
   228  	c.Assert(err, IsNil)
   229  	defer func() {
   230  		dom.Close()
   231  		causetstore.Close()
   232  	}()
   233  	se, err := stochastik.CreateStochastik4Test(causetstore)
   234  	c.Assert(err, IsNil)
   235  
   236  	_, err = se.InterDircute(context.Background(), "use test")
   237  	c.Assert(err, IsNil)
   238  
   239  	var input []string
   240  	var output []struct {
   241  		ALLEGROALLEGROSQL string
   242  		Best              string
   243  		Hints             string
   244  	}
   245  	s.testData.GetTestCases(c, &input, &output)
   246  	for i, tt := range input {
   247  		comment := Commentf("for %s", tt)
   248  		stmt, err := s.ParseOneStmt(tt, "", "")
   249  		c.Assert(err, IsNil, comment)
   250  
   251  		embedded.Preprocess(se, stmt, s.is)
   252  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   253  		c.Assert(err, IsNil)
   254  		s.testData.OnRecord(func() {
   255  			output[i].ALLEGROALLEGROSQL = tt
   256  			output[i].Best = embedded.ToString(p)
   257  			output[i].Hints = hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p))
   258  		})
   259  		c.Assert(embedded.ToString(p), Equals, output[i].Best, Commentf("for %s", tt))
   260  		c.Assert(hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p)), Equals, output[i].Hints, Commentf("for %s", tt))
   261  	}
   262  }
   263  
   264  func (s *testCausetSuite) TestPosetDagCausetBuilderUnion(c *C) {
   265  	defer testleak.AfterTest(c)()
   266  	causetstore, dom, err := newStoreWithBootstrap()
   267  	c.Assert(err, IsNil)
   268  	defer func() {
   269  		dom.Close()
   270  		causetstore.Close()
   271  	}()
   272  	se, err := stochastik.CreateStochastik4Test(causetstore)
   273  	c.Assert(err, IsNil)
   274  	_, err = se.InterDircute(context.Background(), "use test")
   275  	c.Assert(err, IsNil)
   276  
   277  	var input []string
   278  	var output []struct {
   279  		ALLEGROALLEGROSQL string
   280  		Best              string
   281  	}
   282  	s.testData.GetTestCases(c, &input, &output)
   283  	for i, tt := range input {
   284  		comment := Commentf("case:%v allegrosql:%s", i, tt)
   285  		stmt, err := s.ParseOneStmt(tt, "", "")
   286  		c.Assert(err, IsNil, comment)
   287  
   288  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   289  		c.Assert(err, IsNil)
   290  		s.testData.OnRecord(func() {
   291  			output[i].ALLEGROALLEGROSQL = tt
   292  			output[i].Best = embedded.ToString(p)
   293  		})
   294  		c.Assert(embedded.ToString(p), Equals, output[i].Best, comment)
   295  	}
   296  }
   297  
   298  func (s *testCausetSuite) TestPosetDagCausetBuilderUnionScan(c *C) {
   299  	defer testleak.AfterTest(c)()
   300  	causetstore, dom, err := newStoreWithBootstrap()
   301  	c.Assert(err, IsNil)
   302  	defer func() {
   303  		dom.Close()
   304  		causetstore.Close()
   305  	}()
   306  	se, err := stochastik.CreateStochastik4Test(causetstore)
   307  	c.Assert(err, IsNil)
   308  	_, err = se.InterDircute(context.Background(), "use test")
   309  	c.Assert(err, IsNil)
   310  
   311  	var input []string
   312  	var output []struct {
   313  		ALLEGROALLEGROSQL string
   314  		Best              string
   315  	}
   316  	for i, tt := range input {
   317  		comment := Commentf("for %s", tt)
   318  		stmt, err := s.ParseOneStmt(tt, "", "")
   319  		c.Assert(err, IsNil, comment)
   320  
   321  		err = se.NewTxn(context.Background())
   322  		c.Assert(err, IsNil)
   323  		// Make txn not read only.
   324  		txn, err := se.Txn(true)
   325  		c.Assert(err, IsNil)
   326  		txn.Set(ekv.Key("AAA"), []byte("BBB"))
   327  		se.StmtCommit()
   328  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   329  		c.Assert(err, IsNil)
   330  		s.testData.OnRecord(func() {
   331  			output[i].ALLEGROALLEGROSQL = tt
   332  			output[i].Best = embedded.ToString(p)
   333  		})
   334  		c.Assert(embedded.ToString(p), Equals, output[i].Best, Commentf("for %s", tt))
   335  	}
   336  }
   337  
   338  func (s *testCausetSuite) TestPosetDagCausetBuilderAgg(c *C) {
   339  	defer testleak.AfterTest(c)()
   340  	causetstore, dom, err := newStoreWithBootstrap()
   341  	c.Assert(err, IsNil)
   342  	defer func() {
   343  		dom.Close()
   344  		causetstore.Close()
   345  	}()
   346  	se, err := stochastik.CreateStochastik4Test(causetstore)
   347  	c.Assert(err, IsNil)
   348  	se.InterDircute(context.Background(), "use test")
   349  	se.InterDircute(context.Background(), "set sql_mode='STRICT_TRANS_TABLES'") // disable only full group by
   350  	ctx := se.(stochastikctx.Context)
   351  	stochastikVars := ctx.GetStochastikVars()
   352  	stochastikVars.SetHashAggFinalConcurrency(1)
   353  	stochastikVars.SetHashAggPartialConcurrency(1)
   354  	stochastikVars.SetDistALLEGROSQLScanConcurrency(15)
   355  	stochastikVars.InterlockingDirectorateConcurrency = 4
   356  
   357  	var input []string
   358  	var output []struct {
   359  		ALLEGROALLEGROSQL string
   360  		Best              string
   361  	}
   362  	s.testData.GetTestCases(c, &input, &output)
   363  	for i, tt := range input {
   364  		comment := Commentf("for %s", tt)
   365  		stmt, err := s.ParseOneStmt(tt, "", "")
   366  		c.Assert(err, IsNil, comment)
   367  
   368  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   369  		c.Assert(err, IsNil)
   370  		s.testData.OnRecord(func() {
   371  			output[i].ALLEGROALLEGROSQL = tt
   372  			output[i].Best = embedded.ToString(p)
   373  		})
   374  		c.Assert(embedded.ToString(p), Equals, output[i].Best, Commentf("for %s", tt))
   375  	}
   376  }
   377  
   378  func (s *testCausetSuite) TestRefine(c *C) {
   379  	defer testleak.AfterTest(c)()
   380  	causetstore, dom, err := newStoreWithBootstrap()
   381  	c.Assert(err, IsNil)
   382  	defer func() {
   383  		dom.Close()
   384  		causetstore.Close()
   385  	}()
   386  	se, err := stochastik.CreateStochastik4Test(causetstore)
   387  	c.Assert(err, IsNil)
   388  	_, err = se.InterDircute(context.Background(), "use test")
   389  	c.Assert(err, IsNil)
   390  
   391  	var input []string
   392  	var output []struct {
   393  		ALLEGROALLEGROSQL string
   394  		Best              string
   395  	}
   396  	s.testData.GetTestCases(c, &input, &output)
   397  	for i, tt := range input {
   398  		comment := Commentf("for %s", tt)
   399  		stmt, err := s.ParseOneStmt(tt, "", "")
   400  		c.Assert(err, IsNil, comment)
   401  		sc := se.(stochastikctx.Context).GetStochastikVars().StmtCtx
   402  		sc.IgnoreTruncate = false
   403  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   404  		c.Assert(err, IsNil, comment)
   405  		s.testData.OnRecord(func() {
   406  			output[i].ALLEGROALLEGROSQL = tt
   407  			output[i].Best = embedded.ToString(p)
   408  		})
   409  		c.Assert(embedded.ToString(p), Equals, output[i].Best, comment)
   410  	}
   411  }
   412  
   413  func (s *testCausetSuite) TestAggEliminator(c *C) {
   414  	defer testleak.AfterTest(c)()
   415  	causetstore, dom, err := newStoreWithBootstrap()
   416  	c.Assert(err, IsNil)
   417  	defer func() {
   418  		dom.Close()
   419  		causetstore.Close()
   420  	}()
   421  	se, err := stochastik.CreateStochastik4Test(causetstore)
   422  	c.Assert(err, IsNil)
   423  	_, err = se.InterDircute(context.Background(), "use test")
   424  	c.Assert(err, IsNil)
   425  	se.InterDircute(context.Background(), "set sql_mode='STRICT_TRANS_TABLES'") // disable only full group by
   426  	var input []string
   427  	var output []struct {
   428  		ALLEGROALLEGROSQL string
   429  		Best              string
   430  	}
   431  	s.testData.GetTestCases(c, &input, &output)
   432  	for i, tt := range input {
   433  		comment := Commentf("for %s", tt)
   434  		stmt, err := s.ParseOneStmt(tt, "", "")
   435  		c.Assert(err, IsNil, comment)
   436  		sc := se.(stochastikctx.Context).GetStochastikVars().StmtCtx
   437  		sc.IgnoreTruncate = false
   438  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   439  		c.Assert(err, IsNil)
   440  		s.testData.OnRecord(func() {
   441  			output[i].ALLEGROALLEGROSQL = tt
   442  			output[i].Best = embedded.ToString(p)
   443  		})
   444  		c.Assert(embedded.ToString(p), Equals, output[i].Best, Commentf("for %s", tt))
   445  	}
   446  }
   447  
   448  type overrideStore struct{ ekv.CausetStorage }
   449  
   450  func (causetstore overrideStore) GetClient() ekv.Client {
   451  	cli := causetstore.CausetStorage.GetClient()
   452  	return overrideClient{cli}
   453  }
   454  
   455  type overrideClient struct{ ekv.Client }
   456  
   457  func (cli overrideClient) IsRequestTypeSupported(reqType, subType int64) bool {
   458  	return false
   459  }
   460  
   461  func (s *testCausetSuite) TestRequestTypeSupportedOff(c *C) {
   462  	defer testleak.AfterTest(c)()
   463  	causetstore, dom, err := newStoreWithBootstrap()
   464  	c.Assert(err, IsNil)
   465  	defer func() {
   466  		dom.Close()
   467  		causetstore.Close()
   468  	}()
   469  	se, err := stochastik.CreateStochastik4Test(overrideStore{causetstore})
   470  	c.Assert(err, IsNil)
   471  	_, err = se.InterDircute(context.Background(), "use test")
   472  	c.Assert(err, IsNil)
   473  
   474  	allegrosql := "select * from t where a in (1, 10, 20)"
   475  	expect := "BlockReader(Block(t))->Sel([in(test.t.a, 1, 10, 20)])"
   476  
   477  	stmt, err := s.ParseOneStmt(allegrosql, "", "")
   478  	c.Assert(err, IsNil)
   479  	p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   480  	c.Assert(err, IsNil)
   481  	c.Assert(embedded.ToString(p), Equals, expect, Commentf("for %s", allegrosql))
   482  }
   483  
   484  func (s *testCausetSuite) TestIndexJoinUnionScan(c *C) {
   485  	defer testleak.AfterTest(c)()
   486  	causetstore, dom, err := newStoreWithBootstrap()
   487  	c.Assert(err, IsNil)
   488  	tk := testkit.NewTestKit(c, causetstore)
   489  	defer func() {
   490  		dom.Close()
   491  		causetstore.Close()
   492  	}()
   493  
   494  	tk.MustInterDirc("use test")
   495  	var input [][]string
   496  	var output []struct {
   497  		ALLEGROALLEGROSQL []string
   498  		Causet            []string
   499  	}
   500  	tk.MustInterDirc("create causet t (a int primary key, b int, index idx(a))")
   501  	tk.MustInterDirc("create causet tt (a int primary key) partition by range (a) (partition p0 values less than (100), partition p1 values less than (200))")
   502  
   503  	tk.MustInterDirc(`set @@milevadb_partition_prune_mode='` + string(variable.StaticOnly) + `'`)
   504  
   505  	s.testData.GetTestCases(c, &input, &output)
   506  	for i, ts := range input {
   507  		tk.MustInterDirc("begin")
   508  		for j, tt := range ts {
   509  			if j != len(ts)-1 {
   510  				tk.MustInterDirc(tt)
   511  			}
   512  			s.testData.OnRecord(func() {
   513  				output[i].ALLEGROALLEGROSQL = ts
   514  				if j == len(ts)-1 {
   515  					output[i].Causet = s.testData.ConvertRowsToStrings(tk.MustQuery(tt).Rows())
   516  				}
   517  			})
   518  			if j == len(ts)-1 {
   519  				tk.MustQuery(tt).Check(testkit.Rows(output[i].Causet...))
   520  			}
   521  		}
   522  		tk.MustInterDirc("rollback")
   523  	}
   524  }
   525  
   526  func (s *testCausetSuite) TestDoSubquery(c *C) {
   527  	defer testleak.AfterTest(c)()
   528  	causetstore, dom, err := newStoreWithBootstrap()
   529  	c.Assert(err, IsNil)
   530  	defer func() {
   531  		dom.Close()
   532  		causetstore.Close()
   533  	}()
   534  	se, err := stochastik.CreateStochastik4Test(causetstore)
   535  	c.Assert(err, IsNil)
   536  	_, err = se.InterDircute(context.Background(), "use test")
   537  	c.Assert(err, IsNil)
   538  	tests := []struct {
   539  		allegrosql string
   540  		best       string
   541  	}{
   542  		{
   543  			allegrosql: "do 1 in (select a from t)",
   544  			best:       "LeftHashJoin{Dual->PointGet(Handle(t.a)1)}->Projection",
   545  		},
   546  	}
   547  	for _, tt := range tests {
   548  		comment := Commentf("for %s", tt.allegrosql)
   549  		stmt, err := s.ParseOneStmt(tt.allegrosql, "", "")
   550  		c.Assert(err, IsNil, comment)
   551  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   552  		c.Assert(err, IsNil)
   553  		c.Assert(embedded.ToString(p), Equals, tt.best, comment)
   554  	}
   555  }
   556  
   557  func (s *testCausetSuite) TestIndexLookupCartesianJoin(c *C) {
   558  	defer testleak.AfterTest(c)()
   559  	causetstore, dom, err := newStoreWithBootstrap()
   560  	c.Assert(err, IsNil)
   561  	defer func() {
   562  		dom.Close()
   563  		causetstore.Close()
   564  	}()
   565  	se, err := stochastik.CreateStochastik4Test(causetstore)
   566  	c.Assert(err, IsNil)
   567  	_, err = se.InterDircute(context.Background(), "use test")
   568  	c.Assert(err, IsNil)
   569  	allegrosql := "select /*+ MilevaDB_INLJ(t1, t2) */ * from t t1 join t t2"
   570  	stmt, err := s.ParseOneStmt(allegrosql, "", "")
   571  	c.Assert(err, IsNil)
   572  	p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   573  	c.Assert(err, IsNil)
   574  	c.Assert(embedded.ToString(p), Equals, "LeftHashJoin{BlockReader(Block(t))->BlockReader(Block(t))}")
   575  	warnings := se.GetStochastikVars().StmtCtx.GetWarnings()
   576  	lastWarn := warnings[len(warnings)-1]
   577  	err = embedded.ErrInternal.GenWithStack("MilevaDB_INLJ hint is inapplicable without column equal ON condition")
   578  	c.Assert(terror.ErrorEqual(err, lastWarn.Err), IsTrue)
   579  }
   580  
   581  func (s *testCausetSuite) TestSemiJoinToInner(c *C) {
   582  	defer testleak.AfterTest(c)()
   583  	causetstore, dom, err := newStoreWithBootstrap()
   584  	c.Assert(err, IsNil)
   585  	defer func() {
   586  		dom.Close()
   587  		causetstore.Close()
   588  	}()
   589  	se, err := stochastik.CreateStochastik4Test(causetstore)
   590  	c.Assert(err, IsNil)
   591  	_, err = se.InterDircute(context.Background(), "use test")
   592  	c.Assert(err, IsNil)
   593  	var input []string
   594  	var output []struct {
   595  		ALLEGROALLEGROSQL string
   596  		Best              string
   597  	}
   598  	s.testData.GetTestCases(c, &input, &output)
   599  	for i, tt := range input {
   600  		stmt, err := s.ParseOneStmt(tt, "", "")
   601  		c.Assert(err, IsNil)
   602  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
   603  		c.Assert(err, IsNil)
   604  		s.testData.OnRecord(func() {
   605  			output[i].ALLEGROALLEGROSQL = tt
   606  			output[i].Best = embedded.ToString(p)
   607  		})
   608  		c.Assert(embedded.ToString(p), Equals, output[i].Best)
   609  	}
   610  }
   611  
   612  func (s *testCausetSuite) TestUnmatchedBlockInHint(c *C) {
   613  	defer testleak.AfterTest(c)()
   614  	causetstore, dom, err := newStoreWithBootstrap()
   615  	c.Assert(err, IsNil)
   616  	defer func() {
   617  		dom.Close()
   618  		causetstore.Close()
   619  	}()
   620  	se, err := stochastik.CreateStochastik4Test(causetstore)
   621  	c.Assert(err, IsNil)
   622  	_, err = se.InterDircute(context.Background(), "use test")
   623  	c.Assert(err, IsNil)
   624  	var input []string
   625  	var output []struct {
   626  		ALLEGROALLEGROSQL string
   627  		Warning           string
   628  	}
   629  	s.testData.GetTestCases(c, &input, &output)
   630  	for i, test := range input {
   631  		se.GetStochastikVars().StmtCtx.SetWarnings(nil)
   632  		stmt, err := s.ParseOneStmt(test, "", "")
   633  		c.Assert(err, IsNil)
   634  		_, _, err = causet.Optimize(context.TODO(), se, stmt, s.is)
   635  		c.Assert(err, IsNil)
   636  		warnings := se.GetStochastikVars().StmtCtx.GetWarnings()
   637  		s.testData.OnRecord(func() {
   638  			output[i].ALLEGROALLEGROSQL = test
   639  			if len(warnings) > 0 {
   640  				output[i].Warning = warnings[0].Err.Error()
   641  			}
   642  		})
   643  		if output[i].Warning == "" {
   644  			c.Assert(len(warnings), Equals, 0)
   645  		} else {
   646  			c.Assert(len(warnings), Equals, 1)
   647  			c.Assert(warnings[0].Level, Equals, stmtctx.WarnLevelWarning)
   648  			c.Assert(warnings[0].Err.Error(), Equals, output[i].Warning)
   649  		}
   650  	}
   651  }
   652  
   653  func (s *testCausetSuite) TestHintScope(c *C) {
   654  	defer testleak.AfterTest(c)()
   655  	causetstore, dom, err := newStoreWithBootstrap()
   656  	c.Assert(err, IsNil)
   657  	defer func() {
   658  		dom.Close()
   659  		causetstore.Close()
   660  	}()
   661  	se, err := stochastik.CreateStochastik4Test(causetstore)
   662  	c.Assert(err, IsNil)
   663  	_, err = se.InterDircute(context.Background(), "use test")
   664  	c.Assert(err, IsNil)
   665  
   666  	var input []string
   667  	var output []struct {
   668  		ALLEGROALLEGROSQL string
   669  		Best              string
   670  	}
   671  	s.testData.GetTestCases(c, &input, &output)
   672  	for i, test := range input {
   673  		comment := Commentf("case:%v allegrosql:%s", i, test)
   674  		stmt, err := s.ParseOneStmt(test, "", "")
   675  		c.Assert(err, IsNil, comment)
   676  
   677  		p, _, err := causet.Optimize(context.Background(), se, stmt, s.is)
   678  		c.Assert(err, IsNil)
   679  		s.testData.OnRecord(func() {
   680  			output[i].ALLEGROALLEGROSQL = test
   681  			output[i].Best = embedded.ToString(p)
   682  		})
   683  		c.Assert(embedded.ToString(p), Equals, output[i].Best)
   684  
   685  		warnings := se.GetStochastikVars().StmtCtx.GetWarnings()
   686  		c.Assert(warnings, HasLen, 0, comment)
   687  	}
   688  }
   689  
   690  func (s *testCausetSuite) TestJoinHints(c *C) {
   691  	defer testleak.AfterTest(c)()
   692  	causetstore, dom, err := newStoreWithBootstrap()
   693  	c.Assert(err, IsNil)
   694  	defer func() {
   695  		dom.Close()
   696  		causetstore.Close()
   697  	}()
   698  	se, err := stochastik.CreateStochastik4Test(causetstore)
   699  	c.Assert(err, IsNil)
   700  	_, err = se.InterDircute(context.Background(), "use test")
   701  	c.Assert(err, IsNil)
   702  
   703  	var input []string
   704  	var output []struct {
   705  		ALLEGROALLEGROSQL string
   706  		Best              string
   707  		Warning           string
   708  		Hints             string
   709  	}
   710  	s.testData.GetTestCases(c, &input, &output)
   711  	ctx := context.Background()
   712  	for i, test := range input {
   713  		comment := Commentf("case:%v allegrosql:%s", i, test)
   714  		stmt, err := s.ParseOneStmt(test, "", "")
   715  		c.Assert(err, IsNil, comment)
   716  
   717  		se.GetStochastikVars().StmtCtx.SetWarnings(nil)
   718  		p, _, err := causet.Optimize(ctx, se, stmt, s.is)
   719  		c.Assert(err, IsNil)
   720  		warnings := se.GetStochastikVars().StmtCtx.GetWarnings()
   721  
   722  		s.testData.OnRecord(func() {
   723  			output[i].ALLEGROALLEGROSQL = test
   724  			output[i].Best = embedded.ToString(p)
   725  			if len(warnings) > 0 {
   726  				output[i].Warning = warnings[0].Err.Error()
   727  			}
   728  			output[i].Hints = hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p))
   729  		})
   730  		c.Assert(embedded.ToString(p), Equals, output[i].Best)
   731  		if output[i].Warning == "" {
   732  			c.Assert(len(warnings), Equals, 0)
   733  		} else {
   734  			c.Assert(len(warnings), Equals, 1, Commentf("%v", warnings))
   735  			c.Assert(warnings[0].Level, Equals, stmtctx.WarnLevelWarning)
   736  			c.Assert(warnings[0].Err.Error(), Equals, output[i].Warning)
   737  		}
   738  		c.Assert(hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p)), Equals, output[i].Hints, comment)
   739  	}
   740  }
   741  
   742  func (s *testCausetSuite) TestAggregationHints(c *C) {
   743  	defer testleak.AfterTest(c)()
   744  	causetstore, dom, err := newStoreWithBootstrap()
   745  	c.Assert(err, IsNil)
   746  	defer func() {
   747  		dom.Close()
   748  		causetstore.Close()
   749  	}()
   750  	se, err := stochastik.CreateStochastik4Test(causetstore)
   751  	c.Assert(err, IsNil)
   752  	_, err = se.InterDircute(context.Background(), "use test")
   753  	c.Assert(err, IsNil)
   754  
   755  	stochastikVars := se.(stochastikctx.Context).GetStochastikVars()
   756  	stochastikVars.SetHashAggFinalConcurrency(1)
   757  	stochastikVars.SetHashAggPartialConcurrency(1)
   758  
   759  	var input []struct {
   760  		ALLEGROALLEGROSQL string
   761  		AggPushDown       bool
   762  	}
   763  	var output []struct {
   764  		ALLEGROALLEGROSQL string
   765  		Best              string
   766  		Warning           string
   767  	}
   768  	s.testData.GetTestCases(c, &input, &output)
   769  	ctx := context.Background()
   770  	for i, test := range input {
   771  		comment := Commentf("case:%v allegrosql:%s", i, test)
   772  		se.GetStochastikVars().StmtCtx.SetWarnings(nil)
   773  		se.GetStochastikVars().AllowAggPushDown = test.AggPushDown
   774  
   775  		stmt, err := s.ParseOneStmt(test.ALLEGROALLEGROSQL, "", "")
   776  		c.Assert(err, IsNil, comment)
   777  
   778  		p, _, err := causet.Optimize(ctx, se, stmt, s.is)
   779  		c.Assert(err, IsNil)
   780  		warnings := se.GetStochastikVars().StmtCtx.GetWarnings()
   781  
   782  		s.testData.OnRecord(func() {
   783  			output[i].ALLEGROALLEGROSQL = test.ALLEGROALLEGROSQL
   784  			output[i].Best = embedded.ToString(p)
   785  			if len(warnings) > 0 {
   786  				output[i].Warning = warnings[0].Err.Error()
   787  			}
   788  		})
   789  		c.Assert(embedded.ToString(p), Equals, output[i].Best, comment)
   790  		if output[i].Warning == "" {
   791  			c.Assert(len(warnings), Equals, 0, comment)
   792  		} else {
   793  			c.Assert(len(warnings), Equals, 1, comment)
   794  			c.Assert(warnings[0].Level, Equals, stmtctx.WarnLevelWarning, comment)
   795  			c.Assert(warnings[0].Err.Error(), Equals, output[i].Warning, comment)
   796  		}
   797  	}
   798  }
   799  
   800  func (s *testCausetSuite) TestAggToCopHint(c *C) {
   801  	defer testleak.AfterTest(c)()
   802  	causetstore, dom, err := newStoreWithBootstrap()
   803  	c.Assert(err, IsNil)
   804  	defer func() {
   805  		dom.Close()
   806  		causetstore.Close()
   807  	}()
   808  	tk := testkit.NewTestKit(c, causetstore)
   809  	tk.MustInterDirc("use test")
   810  	tk.MustInterDirc("drop causet if exists ta")
   811  	tk.MustInterDirc("create causet ta(a int, b int, index(a))")
   812  
   813  	var (
   814  		input  []string
   815  		output []struct {
   816  			ALLEGROALLEGROSQL string
   817  			Best              string
   818  			Warning           string
   819  		}
   820  	)
   821  	s.testData.GetTestCases(c, &input, &output)
   822  
   823  	ctx := context.Background()
   824  	is := petri.GetPetri(tk.Se).SchemaReplicant()
   825  	for i, test := range input {
   826  		comment := Commentf("case:%v allegrosql:%s", i, test)
   827  		s.testData.OnRecord(func() {
   828  			output[i].ALLEGROALLEGROSQL = test
   829  		})
   830  		c.Assert(test, Equals, output[i].ALLEGROALLEGROSQL, comment)
   831  
   832  		tk.Se.GetStochastikVars().StmtCtx.SetWarnings(nil)
   833  
   834  		stmt, err := s.ParseOneStmt(test, "", "")
   835  		c.Assert(err, IsNil, comment)
   836  
   837  		p, _, err := causet.Optimize(ctx, tk.Se, stmt, is)
   838  		c.Assert(err, IsNil)
   839  		planString := embedded.ToString(p)
   840  		s.testData.OnRecord(func() {
   841  			output[i].Best = planString
   842  		})
   843  		c.Assert(planString, Equals, output[i].Best, comment)
   844  
   845  		warnings := tk.Se.GetStochastikVars().StmtCtx.GetWarnings()
   846  		s.testData.OnRecord(func() {
   847  			if len(warnings) > 0 {
   848  				output[i].Warning = warnings[0].Err.Error()
   849  			}
   850  		})
   851  		if output[i].Warning == "" {
   852  			c.Assert(len(warnings), Equals, 0, comment)
   853  		} else {
   854  			c.Assert(len(warnings), Equals, 1, comment)
   855  			c.Assert(warnings[0].Level, Equals, stmtctx.WarnLevelWarning, comment)
   856  			c.Assert(warnings[0].Err.Error(), Equals, output[i].Warning, comment)
   857  		}
   858  	}
   859  }
   860  
   861  func (s *testCausetSuite) TestLimitToCopHint(c *C) {
   862  	defer testleak.AfterTest(c)()
   863  	causetstore, dom, err := newStoreWithBootstrap()
   864  	c.Assert(err, IsNil)
   865  	defer func() {
   866  		dom.Close()
   867  		causetstore.Close()
   868  	}()
   869  	tk := testkit.NewTestKit(c, causetstore)
   870  	tk.MustInterDirc("use test")
   871  	tk.MustInterDirc("drop causet if exists tn")
   872  	tk.MustInterDirc("create causet tn(a int, b int, c int, d int, key (a, b, c, d))")
   873  
   874  	var (
   875  		input  []string
   876  		output []struct {
   877  			ALLEGROALLEGROSQL string
   878  			Causet            []string
   879  			Warning           string
   880  		}
   881  	)
   882  
   883  	s.testData.GetTestCases(c, &input, &output)
   884  
   885  	for i, ts := range input {
   886  		s.testData.OnRecord(func() {
   887  			output[i].ALLEGROALLEGROSQL = ts
   888  			output[i].Causet = s.testData.ConvertRowsToStrings(tk.MustQuery("explain " + ts).Rows())
   889  		})
   890  		tk.MustQuery("explain " + ts).Check(testkit.Rows(output[i].Causet...))
   891  
   892  		comment := Commentf("case:%v allegrosql:%s", i, ts)
   893  		warnings := tk.Se.GetStochastikVars().StmtCtx.GetWarnings()
   894  		s.testData.OnRecord(func() {
   895  			if len(warnings) > 0 {
   896  				output[i].Warning = warnings[0].Err.Error()
   897  			}
   898  		})
   899  		if output[i].Warning == "" {
   900  			c.Assert(len(warnings), Equals, 0, comment)
   901  		} else {
   902  			c.Assert(len(warnings), Equals, 1, comment)
   903  			c.Assert(warnings[0].Level, Equals, stmtctx.WarnLevelWarning, comment)
   904  			c.Assert(warnings[0].Err.Error(), Equals, output[i].Warning, comment)
   905  		}
   906  	}
   907  }
   908  
   909  func (s *testCausetSuite) TestPushdownDistinctEnable(c *C) {
   910  	defer testleak.AfterTest(c)()
   911  	var (
   912  		input  []string
   913  		output []struct {
   914  			ALLEGROALLEGROSQL string
   915  			Causet            []string
   916  			Result            []string
   917  		}
   918  	)
   919  	s.testData.GetTestCases(c, &input, &output)
   920  	vars := []string{
   921  		fmt.Sprintf("set @@stochastik.%s = 1", variable.MilevaDBOptDistinctAggPushDown),
   922  		"set stochastik milevadb_opt_agg_push_down = 1",
   923  	}
   924  	s.doTestPushdownDistinct(c, vars, input, output)
   925  }
   926  
   927  func (s *testCausetSuite) TestPushdownDistinctDisable(c *C) {
   928  	defer testleak.AfterTest(c)()
   929  	var (
   930  		input  []string
   931  		output []struct {
   932  			ALLEGROALLEGROSQL string
   933  			Causet            []string
   934  			Result            []string
   935  		}
   936  	)
   937  
   938  	s.testData.GetTestCases(c, &input, &output)
   939  	vars := []string{
   940  		fmt.Sprintf("set @@stochastik.%s = 0", variable.MilevaDBOptDistinctAggPushDown),
   941  		"set stochastik milevadb_opt_agg_push_down = 1",
   942  	}
   943  	s.doTestPushdownDistinct(c, vars, input, output)
   944  }
   945  
   946  func (s *testCausetSuite) TestPushdownDistinctEnableAggPushDownDisable(c *C) {
   947  	var (
   948  		input  []string
   949  		output []struct {
   950  			ALLEGROALLEGROSQL string
   951  			Causet            []string
   952  			Result            []string
   953  		}
   954  	)
   955  	s.testData.GetTestCases(c, &input, &output)
   956  	vars := []string{
   957  		fmt.Sprintf("set @@stochastik.%s = 1", variable.MilevaDBOptDistinctAggPushDown),
   958  		"set stochastik milevadb_opt_agg_push_down = 0",
   959  	}
   960  	s.doTestPushdownDistinct(c, vars, input, output)
   961  }
   962  
   963  func (s *testCausetSuite) doTestPushdownDistinct(c *C, vars, input []string, output []struct {
   964  	ALLEGROALLEGROSQL string
   965  	Causet            []string
   966  	Result            []string
   967  }) {
   968  	causetstore, dom, err := newStoreWithBootstrap()
   969  	c.Assert(err, IsNil)
   970  	defer func() {
   971  		dom.Close()
   972  		causetstore.Close()
   973  	}()
   974  	tk := testkit.NewTestKit(c, causetstore)
   975  	tk.MustInterDirc("use test")
   976  
   977  	tk.MustInterDirc("drop causet if exists t")
   978  	tk.MustInterDirc("create causet t(a int, b int, c int, index(c))")
   979  	tk.MustInterDirc("insert into t values (1, 1, 1), (1, 1, 3), (1, 2, 3), (2, 1, 3), (1, 2, NULL);")
   980  
   981  	tk.MustInterDirc("drop causet if exists pt")
   982  	tk.MustInterDirc(`CREATE TABLE pt (a int, b int) PARTITION BY RANGE (a) (
   983  		PARTITION p0 VALUES LESS THAN (2),
   984  		PARTITION p1 VALUES LESS THAN (100)
   985  	);`)
   986  
   987  	tk.MustInterDirc("drop causet if exists ta")
   988  	tk.MustInterDirc("create causet ta(a int);")
   989  	tk.MustInterDirc("insert into ta values(1), (1);")
   990  	tk.MustInterDirc("drop causet if exists tb")
   991  	tk.MustInterDirc("create causet tb(a int);")
   992  	tk.MustInterDirc("insert into tb values(1), (1);")
   993  
   994  	tk.MustInterDirc("set stochastik sql_mode=''")
   995  	tk.MustInterDirc(fmt.Sprintf("set stochastik %s=1", variable.MilevaDBHashAggPartialConcurrency))
   996  	tk.MustInterDirc(fmt.Sprintf("set stochastik %s=1", variable.MilevaDBHashAggFinalConcurrency))
   997  
   998  	tk.MustInterDirc(`set @@milevadb_partition_prune_mode='` + string(variable.StaticOnly) + `'`)
   999  
  1000  	for _, v := range vars {
  1001  		tk.MustInterDirc(v)
  1002  	}
  1003  
  1004  	for i, ts := range input {
  1005  		s.testData.OnRecord(func() {
  1006  			output[i].ALLEGROALLEGROSQL = ts
  1007  			output[i].Causet = s.testData.ConvertRowsToStrings(tk.MustQuery("explain " + ts).Rows())
  1008  			output[i].Result = s.testData.ConvertRowsToStrings(tk.MustQuery(ts).Sort().Rows())
  1009  		})
  1010  		tk.MustQuery("explain " + ts).Check(testkit.Rows(output[i].Causet...))
  1011  		tk.MustQuery(ts).Sort().Check(testkit.Rows(output[i].Result...))
  1012  	}
  1013  }
  1014  
  1015  func (s *testCausetSuite) TestGroupConcatOrderby(c *C) {
  1016  	var (
  1017  		input  []string
  1018  		output []struct {
  1019  			ALLEGROALLEGROSQL string
  1020  			Causet            []string
  1021  			Result            []string
  1022  		}
  1023  	)
  1024  	s.testData.GetTestCases(c, &input, &output)
  1025  	causetstore, dom, err := newStoreWithBootstrap()
  1026  	c.Assert(err, IsNil)
  1027  	defer func() {
  1028  		dom.Close()
  1029  		causetstore.Close()
  1030  	}()
  1031  	tk := testkit.NewTestKit(c, causetstore)
  1032  	tk.MustInterDirc("use test")
  1033  	tk.MustInterDirc("drop causet if exists test;")
  1034  	tk.MustInterDirc("create causet test(id int, name int)")
  1035  	tk.MustInterDirc("insert into test values(1, 10);")
  1036  	tk.MustInterDirc("insert into test values(1, 20);")
  1037  	tk.MustInterDirc("insert into test values(1, 30);")
  1038  	tk.MustInterDirc("insert into test values(2, 20);")
  1039  	tk.MustInterDirc("insert into test values(3, 200);")
  1040  	tk.MustInterDirc("insert into test values(3, 500);")
  1041  
  1042  	tk.MustInterDirc("drop causet if exists ptest;")
  1043  	tk.MustInterDirc("CREATE TABLE ptest (id int,name int) PARTITION BY RANGE ( id ) " +
  1044  		"(PARTITION `p0` VALUES LESS THAN (2), PARTITION `p1` VALUES LESS THAN (11))")
  1045  	tk.MustInterDirc("insert into ptest select * from test;")
  1046  	tk.MustInterDirc(fmt.Sprintf("set stochastik milevadb_opt_distinct_agg_push_down = %v", 1))
  1047  	tk.MustInterDirc(fmt.Sprintf("set stochastik milevadb_opt_agg_push_down = %v", 1))
  1048  
  1049  	for i, ts := range input {
  1050  		s.testData.OnRecord(func() {
  1051  			output[i].ALLEGROALLEGROSQL = ts
  1052  			output[i].Causet = s.testData.ConvertRowsToStrings(tk.MustQuery("explain " + ts).Rows())
  1053  			output[i].Result = s.testData.ConvertRowsToStrings(tk.MustQuery(ts).Sort().Rows())
  1054  		})
  1055  		tk.MustQuery("explain " + ts).Check(testkit.Rows(output[i].Causet...))
  1056  		tk.MustQuery(ts).Check(testkit.Rows(output[i].Result...))
  1057  	}
  1058  }
  1059  
  1060  func (s *testCausetSuite) TestHintAlias(c *C) {
  1061  	defer testleak.AfterTest(c)()
  1062  	causetstore, dom, err := newStoreWithBootstrap()
  1063  	c.Assert(err, IsNil)
  1064  	defer func() {
  1065  		dom.Close()
  1066  		causetstore.Close()
  1067  	}()
  1068  	se, err := stochastik.CreateStochastik4Test(causetstore)
  1069  	c.Assert(err, IsNil)
  1070  	_, err = se.InterDircute(context.Background(), "use test")
  1071  	c.Assert(err, IsNil)
  1072  
  1073  	tests := []struct {
  1074  		sql1 string
  1075  		sql2 string
  1076  	}{
  1077  		{
  1078  			sql1: "select /*+ MilevaDB_SMJ(t1) */ t1.a, t1.b from t t1, (select /*+ MilevaDB_INLJ(t3) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a",
  1079  			sql2: "select /*+ MERGE_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ INL_JOIN(t3) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a",
  1080  		},
  1081  		{
  1082  			sql1: "select /*+ MilevaDB_HJ(t1) */ t1.a, t1.b from t t1, (select /*+ MilevaDB_SMJ(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a",
  1083  			sql2: "select /*+ HASH_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ MERGE_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a",
  1084  		},
  1085  		{
  1086  			sql1: "select /*+ MilevaDB_INLJ(t1) */ t1.a, t1.b from t t1, (select /*+ MilevaDB_HJ(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a",
  1087  			sql2: "select /*+ INL_JOIN(t1) */ t1.a, t1.b from t t1, (select /*+ HASH_JOIN(t2) */ t2.a from t t2, t t3 where t2.a = t3.c) s where t1.a=s.a",
  1088  		},
  1089  	}
  1090  	ctx := context.TODO()
  1091  	for i, tt := range tests {
  1092  		comment := Commentf("case:%v sql1:%s sql2:%s", i, tt.sql1, tt.sql2)
  1093  		stmt1, err := s.ParseOneStmt(tt.sql1, "", "")
  1094  		c.Assert(err, IsNil, comment)
  1095  		stmt2, err := s.ParseOneStmt(tt.sql2, "", "")
  1096  		c.Assert(err, IsNil, comment)
  1097  
  1098  		p1, _, err := causet.Optimize(ctx, se, stmt1, s.is)
  1099  		c.Assert(err, IsNil)
  1100  		p2, _, err := causet.Optimize(ctx, se, stmt2, s.is)
  1101  		c.Assert(err, IsNil)
  1102  
  1103  		c.Assert(embedded.ToString(p1), Equals, embedded.ToString(p2))
  1104  	}
  1105  }
  1106  
  1107  func (s *testCausetSuite) TestIndexHint(c *C) {
  1108  	defer testleak.AfterTest(c)()
  1109  	causetstore, dom, err := newStoreWithBootstrap()
  1110  	c.Assert(err, IsNil)
  1111  	defer func() {
  1112  		dom.Close()
  1113  		causetstore.Close()
  1114  	}()
  1115  	se, err := stochastik.CreateStochastik4Test(causetstore)
  1116  	c.Assert(err, IsNil)
  1117  	_, err = se.InterDircute(context.Background(), "use test")
  1118  	c.Assert(err, IsNil)
  1119  
  1120  	var input []string
  1121  	var output []struct {
  1122  		ALLEGROALLEGROSQL string
  1123  		Best              string
  1124  		HasWarn           bool
  1125  		Hints             string
  1126  	}
  1127  	s.testData.GetTestCases(c, &input, &output)
  1128  	ctx := context.Background()
  1129  	for i, test := range input {
  1130  		comment := Commentf("case:%v allegrosql:%s", i, test)
  1131  		se.GetStochastikVars().StmtCtx.SetWarnings(nil)
  1132  
  1133  		stmt, err := s.ParseOneStmt(test, "", "")
  1134  		c.Assert(err, IsNil, comment)
  1135  
  1136  		p, _, err := causet.Optimize(ctx, se, stmt, s.is)
  1137  		c.Assert(err, IsNil)
  1138  		s.testData.OnRecord(func() {
  1139  			output[i].ALLEGROALLEGROSQL = test
  1140  			output[i].Best = embedded.ToString(p)
  1141  			output[i].HasWarn = len(se.GetStochastikVars().StmtCtx.GetWarnings()) > 0
  1142  			output[i].Hints = hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p))
  1143  		})
  1144  		c.Assert(embedded.ToString(p), Equals, output[i].Best, comment)
  1145  		warnings := se.GetStochastikVars().StmtCtx.GetWarnings()
  1146  		if output[i].HasWarn {
  1147  			c.Assert(warnings, HasLen, 1, comment)
  1148  		} else {
  1149  			c.Assert(warnings, HasLen, 0, comment)
  1150  		}
  1151  		c.Assert(hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p)), Equals, output[i].Hints, comment)
  1152  	}
  1153  }
  1154  
  1155  func (s *testCausetSuite) TestIndexMergeHint(c *C) {
  1156  	defer testleak.AfterTest(c)()
  1157  	causetstore, dom, err := newStoreWithBootstrap()
  1158  	c.Assert(err, IsNil)
  1159  	defer func() {
  1160  		dom.Close()
  1161  		causetstore.Close()
  1162  	}()
  1163  	se, err := stochastik.CreateStochastik4Test(causetstore)
  1164  	c.Assert(err, IsNil)
  1165  	_, err = se.InterDircute(context.Background(), "use test")
  1166  	c.Assert(err, IsNil)
  1167  
  1168  	var input []string
  1169  	var output []struct {
  1170  		ALLEGROALLEGROSQL string
  1171  		Best              string
  1172  		HasWarn           bool
  1173  		Hints             string
  1174  	}
  1175  	s.testData.GetTestCases(c, &input, &output)
  1176  	ctx := context.Background()
  1177  	for i, test := range input {
  1178  		comment := Commentf("case:%v allegrosql:%s", i, test)
  1179  		se.GetStochastikVars().StmtCtx.SetWarnings(nil)
  1180  		stmt, err := s.ParseOneStmt(test, "", "")
  1181  		c.Assert(err, IsNil, comment)
  1182  		sctx := se.(stochastikctx.Context)
  1183  		err = interlock.ResetContextOfStmt(sctx, stmt)
  1184  		c.Assert(err, IsNil)
  1185  		p, _, err := causet.Optimize(ctx, se, stmt, s.is)
  1186  		c.Assert(err, IsNil)
  1187  		s.testData.OnRecord(func() {
  1188  			output[i].ALLEGROALLEGROSQL = test
  1189  			output[i].Best = embedded.ToString(p)
  1190  			output[i].HasWarn = len(se.GetStochastikVars().StmtCtx.GetWarnings()) > 0
  1191  			output[i].Hints = hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p))
  1192  		})
  1193  		c.Assert(embedded.ToString(p), Equals, output[i].Best, comment)
  1194  		warnings := se.GetStochastikVars().StmtCtx.GetWarnings()
  1195  		if output[i].HasWarn {
  1196  			c.Assert(warnings, HasLen, 1, comment)
  1197  		} else {
  1198  			c.Assert(warnings, HasLen, 0, comment)
  1199  		}
  1200  		c.Assert(hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p)), Equals, output[i].Hints, comment)
  1201  	}
  1202  }
  1203  
  1204  func (s *testCausetSuite) TestQueryBlockHint(c *C) {
  1205  	defer testleak.AfterTest(c)()
  1206  	causetstore, dom, err := newStoreWithBootstrap()
  1207  	c.Assert(err, IsNil)
  1208  	defer func() {
  1209  		dom.Close()
  1210  		causetstore.Close()
  1211  	}()
  1212  	se, err := stochastik.CreateStochastik4Test(causetstore)
  1213  	c.Assert(err, IsNil)
  1214  	_, err = se.InterDircute(context.Background(), "use test")
  1215  	c.Assert(err, IsNil)
  1216  
  1217  	var input []string
  1218  	var output []struct {
  1219  		ALLEGROALLEGROSQL string
  1220  		Causet            string
  1221  		Hints             string
  1222  	}
  1223  	s.testData.GetTestCases(c, &input, &output)
  1224  	ctx := context.TODO()
  1225  	for i, tt := range input {
  1226  		comment := Commentf("case:%v allegrosql: %s", i, tt)
  1227  		stmt, err := s.ParseOneStmt(tt, "", "")
  1228  		c.Assert(err, IsNil, comment)
  1229  
  1230  		p, _, err := causet.Optimize(ctx, se, stmt, s.is)
  1231  		c.Assert(err, IsNil, comment)
  1232  		s.testData.OnRecord(func() {
  1233  			output[i].ALLEGROALLEGROSQL = tt
  1234  			output[i].Causet = embedded.ToString(p)
  1235  			output[i].Hints = hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p))
  1236  		})
  1237  		c.Assert(embedded.ToString(p), Equals, output[i].Causet, comment)
  1238  		c.Assert(hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p)), Equals, output[i].Hints, comment)
  1239  	}
  1240  }
  1241  
  1242  func (s *testCausetSuite) TestInlineProjection(c *C) {
  1243  	defer testleak.AfterTest(c)()
  1244  	causetstore, dom, err := newStoreWithBootstrap()
  1245  	c.Assert(err, IsNil)
  1246  	defer func() {
  1247  		dom.Close()
  1248  		causetstore.Close()
  1249  	}()
  1250  	se, err := stochastik.CreateStochastik4Test(causetstore)
  1251  	c.Assert(err, IsNil)
  1252  	ctx := context.Background()
  1253  	_, err = se.InterDircute(ctx, "use test")
  1254  	c.Assert(err, IsNil)
  1255  	_, err = se.InterDircute(ctx, `drop causet if exists test.t1, test.t2;`)
  1256  	c.Assert(err, IsNil)
  1257  	_, err = se.InterDircute(ctx, `create causet test.t1(a bigint, b bigint, index idx_a(a), index idx_b(b));`)
  1258  	c.Assert(err, IsNil)
  1259  	_, err = se.InterDircute(ctx, `create causet test.t2(a bigint, b bigint, index idx_a(a), index idx_b(b));`)
  1260  	c.Assert(err, IsNil)
  1261  
  1262  	var input []string
  1263  	var output []struct {
  1264  		ALLEGROALLEGROSQL string
  1265  		Causet            string
  1266  		Hints             string
  1267  	}
  1268  	is := petri.GetPetri(se).SchemaReplicant()
  1269  	s.testData.GetTestCases(c, &input, &output)
  1270  	for i, tt := range input {
  1271  		comment := Commentf("case:%v allegrosql: %s", i, tt)
  1272  		stmt, err := s.ParseOneStmt(tt, "", "")
  1273  		c.Assert(err, IsNil, comment)
  1274  
  1275  		p, _, err := causet.Optimize(ctx, se, stmt, is)
  1276  		c.Assert(err, IsNil, comment)
  1277  		s.testData.OnRecord(func() {
  1278  			output[i].ALLEGROALLEGROSQL = tt
  1279  			output[i].Causet = embedded.ToString(p)
  1280  			output[i].Hints = hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p))
  1281  		})
  1282  		c.Assert(embedded.ToString(p), Equals, output[i].Causet, comment)
  1283  		c.Assert(hint.RestoreOptimizerHints(embedded.GenHintsFromPhysicalCauset(p)), Equals, output[i].Hints, comment)
  1284  	}
  1285  }
  1286  
  1287  func (s *testCausetSuite) TestPosetDagCausetBuilderSplitAvg(c *C) {
  1288  	defer testleak.AfterTest(c)()
  1289  	causetstore, dom, err := newStoreWithBootstrap()
  1290  	c.Assert(err, IsNil)
  1291  	defer func() {
  1292  		dom.Close()
  1293  		causetstore.Close()
  1294  	}()
  1295  	se, err := stochastik.CreateStochastik4Test(causetstore)
  1296  	c.Assert(err, IsNil)
  1297  	_, err = se.InterDircute(context.Background(), "use test")
  1298  	c.Assert(err, IsNil)
  1299  	tests := []struct {
  1300  		allegrosql string
  1301  		plan       string
  1302  	}{
  1303  		{
  1304  			allegrosql: "select avg(a),avg(b),avg(c) from t",
  1305  			plan:       "BlockReader(Block(t)->StreamAgg)->StreamAgg",
  1306  		},
  1307  		{
  1308  			allegrosql: "select /*+ HASH_AGG() */ avg(a),avg(b),avg(c) from t",
  1309  			plan:       "BlockReader(Block(t)->HashAgg)->HashAgg",
  1310  		},
  1311  	}
  1312  
  1313  	for _, tt := range tests {
  1314  		comment := Commentf("for %s", tt.allegrosql)
  1315  		stmt, err := s.ParseOneStmt(tt.allegrosql, "", "")
  1316  		c.Assert(err, IsNil, comment)
  1317  
  1318  		embedded.Preprocess(se, stmt, s.is)
  1319  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
  1320  		c.Assert(err, IsNil, comment)
  1321  
  1322  		c.Assert(embedded.ToString(p), Equals, tt.plan, comment)
  1323  		root, ok := p.(embedded.PhysicalCauset)
  1324  		if !ok {
  1325  			continue
  1326  		}
  1327  		testPosetDagCausetBuilderSplitAvg(c, root)
  1328  	}
  1329  }
  1330  
  1331  func testPosetDagCausetBuilderSplitAvg(c *C, root embedded.PhysicalCauset) {
  1332  	if p, ok := root.(*embedded.PhysicalBlockReader); ok {
  1333  		if p.BlockCausets != nil {
  1334  			baseAgg := p.BlockCausets[len(p.BlockCausets)-1]
  1335  			if agg, ok := baseAgg.(*embedded.PhysicalHashAgg); ok {
  1336  				for i, aggfunc := range agg.AggFuncs {
  1337  					c.Assert(agg.Schema().DeferredCausets[i].RetType, Equals, aggfunc.RetTp)
  1338  				}
  1339  			}
  1340  			if agg, ok := baseAgg.(*embedded.PhysicalStreamAgg); ok {
  1341  				for i, aggfunc := range agg.AggFuncs {
  1342  					c.Assert(agg.Schema().DeferredCausets[i].RetType, Equals, aggfunc.RetTp)
  1343  				}
  1344  			}
  1345  		}
  1346  	}
  1347  
  1348  	childs := root.Children()
  1349  	if childs == nil {
  1350  		return
  1351  	}
  1352  	for _, son := range childs {
  1353  		testPosetDagCausetBuilderSplitAvg(c, son)
  1354  	}
  1355  }
  1356  
  1357  func (s *testCausetSuite) TestIndexJoinHint(c *C) {
  1358  	defer testleak.AfterTest(c)()
  1359  	causetstore, dom, err := newStoreWithBootstrap()
  1360  	c.Assert(err, IsNil)
  1361  	defer func() {
  1362  		dom.Close()
  1363  		causetstore.Close()
  1364  	}()
  1365  	se, err := stochastik.CreateStochastik4Test(causetstore)
  1366  	c.Assert(err, IsNil)
  1367  	ctx := context.Background()
  1368  	_, err = se.InterDircute(ctx, "use test")
  1369  	c.Assert(err, IsNil)
  1370  	_, err = se.InterDircute(ctx, `drop causet if exists test.t1, test.t2, test.t;`)
  1371  	c.Assert(err, IsNil)
  1372  	_, err = se.InterDircute(ctx, `create causet test.t1(a bigint, b bigint, index idx_a(a), index idx_b(b));`)
  1373  	c.Assert(err, IsNil)
  1374  	_, err = se.InterDircute(ctx, `create causet test.t2(a bigint, b bigint, index idx_a(a), index idx_b(b));`)
  1375  	c.Assert(err, IsNil)
  1376  	_, err = se.InterDircute(ctx, "CREATE TABLE `t` ( `a` bigint(20) NOT NULL, `b` tinyint(1) DEFAULT NULL, `c` datetime DEFAULT NULL, `d` int(10) unsigned DEFAULT NULL, `e` varchar(20) DEFAULT NULL, `f` double DEFAULT NULL, `g` decimal(30,5) DEFAULT NULL, `h` float DEFAULT NULL, `i` date DEFAULT NULL, `j` timestamp NULL DEFAULT NULL, PRIMARY KEY (`a`), UNIQUE KEY `b` (`b`), KEY `c` (`c`,`d`,`e`), KEY `f` (`f`), KEY `g` (`g`,`h`), KEY `g_2` (`g`), UNIQUE KEY `g_3` (`g`), KEY `i` (`i`) );")
  1377  	c.Assert(err, IsNil)
  1378  	var input []string
  1379  	var output []struct {
  1380  		ALLEGROALLEGROSQL string
  1381  		Causet            string
  1382  	}
  1383  	is := petri.GetPetri(se).SchemaReplicant()
  1384  	s.testData.GetTestCases(c, &input, &output)
  1385  	for i, tt := range input {
  1386  		comment := Commentf("case:%v allegrosql: %s", i, tt)
  1387  		stmt, err := s.ParseOneStmt(tt, "", "")
  1388  		c.Assert(err, IsNil, comment)
  1389  		p, _, err := causet.Optimize(ctx, se, stmt, is)
  1390  		c.Assert(err, IsNil, comment)
  1391  		s.testData.OnRecord(func() {
  1392  			output[i].ALLEGROALLEGROSQL = tt
  1393  			output[i].Causet = embedded.ToString(p)
  1394  		})
  1395  		c.Assert(embedded.ToString(p), Equals, output[i].Causet, comment)
  1396  	}
  1397  }
  1398  
  1399  func (s *testCausetSuite) TestPosetDagCausetBuilderWindow(c *C) {
  1400  	defer testleak.AfterTest(c)()
  1401  	var input []string
  1402  	var output []struct {
  1403  		ALLEGROALLEGROSQL string
  1404  		Best              string
  1405  	}
  1406  	s.testData.GetTestCases(c, &input, &output)
  1407  	vars := []string{
  1408  		"set @@stochastik.milevadb_window_concurrency = 1",
  1409  	}
  1410  	s.doTestPosetDagCausetBuilderWindow(c, vars, input, output)
  1411  }
  1412  
  1413  func (s *testCausetSuite) TestPosetDagCausetBuilderWindowParallel(c *C) {
  1414  	defer testleak.AfterTest(c)()
  1415  	var input []string
  1416  	var output []struct {
  1417  		ALLEGROALLEGROSQL string
  1418  		Best              string
  1419  	}
  1420  	s.testData.GetTestCases(c, &input, &output)
  1421  	vars := []string{
  1422  		"set @@stochastik.milevadb_window_concurrency = 4",
  1423  	}
  1424  	s.doTestPosetDagCausetBuilderWindow(c, vars, input, output)
  1425  }
  1426  
  1427  func (s *testCausetSuite) doTestPosetDagCausetBuilderWindow(c *C, vars, input []string, output []struct {
  1428  	ALLEGROALLEGROSQL string
  1429  	Best              string
  1430  }) {
  1431  	causetstore, dom, err := newStoreWithBootstrap()
  1432  	c.Assert(err, IsNil)
  1433  	defer func() {
  1434  		dom.Close()
  1435  		causetstore.Close()
  1436  	}()
  1437  	se, err := stochastik.CreateStochastik4Test(causetstore)
  1438  	c.Assert(err, IsNil)
  1439  	ctx := context.Background()
  1440  	_, err = se.InterDircute(ctx, "use test")
  1441  	c.Assert(err, IsNil)
  1442  
  1443  	for _, v := range vars {
  1444  		_, err = se.InterDircute(ctx, v)
  1445  		c.Assert(err, IsNil)
  1446  	}
  1447  
  1448  	for i, tt := range input {
  1449  		comment := Commentf("case:%v allegrosql:%s", i, tt)
  1450  		stmt, err := s.ParseOneStmt(tt, "", "")
  1451  		c.Assert(err, IsNil, comment)
  1452  
  1453  		err = se.NewTxn(context.Background())
  1454  		c.Assert(err, IsNil)
  1455  		p, _, err := causet.Optimize(context.TODO(), se, stmt, s.is)
  1456  		c.Assert(err, IsNil)
  1457  		s.testData.OnRecord(func() {
  1458  			output[i].ALLEGROALLEGROSQL = tt
  1459  			output[i].Best = embedded.ToString(p)
  1460  		})
  1461  		c.Assert(embedded.ToString(p), Equals, output[i].Best, comment)
  1462  	}
  1463  }
  1464  
  1465  func (s *testCausetSuite) TestNominalSort(c *C) {
  1466  	defer testleak.AfterTest(c)()
  1467  	causetstore, dom, err := newStoreWithBootstrap()
  1468  	c.Assert(err, IsNil)
  1469  	tk := testkit.NewTestKit(c, causetstore)
  1470  	defer func() {
  1471  		dom.Close()
  1472  		causetstore.Close()
  1473  	}()
  1474  	tk.MustInterDirc("use test")
  1475  	var input []string
  1476  	var output []struct {
  1477  		ALLEGROALLEGROSQL string
  1478  		Causet            []string
  1479  		Result            []string
  1480  	}
  1481  	tk.MustInterDirc("create causet t (a int, b int, index idx_a(a), index idx_b(b))")
  1482  	tk.MustInterDirc("insert into t values(1, 1)")
  1483  	tk.MustInterDirc("insert into t values(1, 2)")
  1484  	tk.MustInterDirc("insert into t values(2, 4)")
  1485  	tk.MustInterDirc("insert into t values(3, 5)")
  1486  	s.testData.GetTestCases(c, &input, &output)
  1487  	for i, ts := range input {
  1488  		s.testData.OnRecord(func() {
  1489  			output[i].ALLEGROALLEGROSQL = ts
  1490  			output[i].Causet = s.testData.ConvertRowsToStrings(tk.MustQuery("explain " + ts).Rows())
  1491  			output[i].Result = s.testData.ConvertRowsToStrings(tk.MustQuery(ts).Rows())
  1492  		})
  1493  		tk.MustQuery("explain " + ts).Check(testkit.Rows(output[i].Causet...))
  1494  		tk.MustQuery(ts).Check(testkit.Rows(output[i].Result...))
  1495  	}
  1496  }
  1497  
  1498  func (s *testCausetSuite) TestHintFromDiffDatabase(c *C) {
  1499  	defer testleak.AfterTest(c)()
  1500  	causetstore, dom, err := newStoreWithBootstrap()
  1501  	c.Assert(err, IsNil)
  1502  	defer func() {
  1503  		dom.Close()
  1504  		causetstore.Close()
  1505  	}()
  1506  	se, err := stochastik.CreateStochastik4Test(causetstore)
  1507  	c.Assert(err, IsNil)
  1508  	ctx := context.Background()
  1509  	_, err = se.InterDircute(ctx, "use test")
  1510  	c.Assert(err, IsNil)
  1511  	_, err = se.InterDircute(ctx, `drop causet if exists test.t1`)
  1512  	c.Assert(err, IsNil)
  1513  	_, err = se.InterDircute(ctx, `create causet test.t1(a bigint, index idx_a(a));`)
  1514  	c.Assert(err, IsNil)
  1515  	_, err = se.InterDircute(ctx, `create causet test.t2(a bigint, index idx_a(a));`)
  1516  	c.Assert(err, IsNil)
  1517  
  1518  	_, err = se.InterDircute(ctx, "drop database if exists test2")
  1519  	c.Assert(err, IsNil)
  1520  	_, err = se.InterDircute(ctx, "create database test2")
  1521  	c.Assert(err, IsNil)
  1522  	_, err = se.InterDircute(ctx, "use test2")
  1523  	c.Assert(err, IsNil)
  1524  
  1525  	var input []string
  1526  	var output []struct {
  1527  		ALLEGROALLEGROSQL string
  1528  		Causet            string
  1529  	}
  1530  	is := petri.GetPetri(se).SchemaReplicant()
  1531  	s.testData.GetTestCases(c, &input, &output)
  1532  	for i, tt := range input {
  1533  		comment := Commentf("case:%v allegrosql: %s", i, tt)
  1534  		stmt, err := s.ParseOneStmt(tt, "", "")
  1535  		c.Assert(err, IsNil, comment)
  1536  		p, _, err := causet.Optimize(ctx, se, stmt, is)
  1537  		c.Assert(err, IsNil, comment)
  1538  		s.testData.OnRecord(func() {
  1539  			output[i].ALLEGROALLEGROSQL = tt
  1540  			output[i].Causet = embedded.ToString(p)
  1541  		})
  1542  		c.Assert(embedded.ToString(p), Equals, output[i].Causet, comment)
  1543  	}
  1544  }
  1545  
  1546  func (s *testCausetSuite) TestNthCausetHintWithExplain(c *C) {
  1547  	defer testleak.AfterTest(c)()
  1548  	causetstore, dom, err := newStoreWithBootstrap()
  1549  	c.Assert(err, IsNil)
  1550  	tk := testkit.NewTestKit(c, causetstore)
  1551  	defer func() {
  1552  		dom.Close()
  1553  		causetstore.Close()
  1554  	}()
  1555  	se, err := stochastik.CreateStochastik4Test(causetstore)
  1556  	c.Assert(err, IsNil)
  1557  	ctx := context.Background()
  1558  	_, err = se.InterDircute(ctx, "use test")
  1559  	c.Assert(err, IsNil)
  1560  	_, err = se.InterDircute(ctx, `drop causet if exists test.tt`)
  1561  	c.Assert(err, IsNil)
  1562  	_, err = se.InterDircute(ctx, `create causet test.tt (a int,b int, index(a), index(b));`)
  1563  	c.Assert(err, IsNil)
  1564  
  1565  	_, err = se.InterDircute(ctx, "insert into tt values (1, 1), (2, 2), (3, 4)")
  1566  	c.Assert(err, IsNil)
  1567  
  1568  	tk.MustInterDirc(`set @@milevadb_partition_prune_mode='` + string(variable.StaticOnly) + `'`)
  1569  
  1570  	var input []string
  1571  	var output []struct {
  1572  		ALLEGROALLEGROSQL string
  1573  		Causet            []string
  1574  	}
  1575  	s.testData.GetTestCases(c, &input, &output)
  1576  	for i, ts := range input {
  1577  		s.testData.OnRecord(func() {
  1578  			output[i].ALLEGROALLEGROSQL = ts
  1579  			output[i].Causet = s.testData.ConvertRowsToStrings(tk.MustQuery("explain " + ts).Rows())
  1580  		})
  1581  		tk.MustQuery("explain " + ts).Check(testkit.Rows(output[i].Causet...))
  1582  	}
  1583  
  1584  	// This assert makes sure a query with or without nth_plan() hint output exactly the same plan(including plan ID).
  1585  	// The query below is the same as queries in the testdata except for nth_plan() hint.
  1586  	// Currently its output is the same as the second test case in the testdata, which is `output[1]`. If this doesn't
  1587  	// hold in the future, you may need to modify this.
  1588  	tk.MustQuery("explain select * from test.tt where a=1 and b=1").Check(testkit.Rows(output[1].Causet...))
  1589  }