github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/petri/acyclic/bindinfo/bind_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 bindinfo_test 15 16 import ( 17 "context" 18 "flag" 19 "fmt" 20 "os" 21 "testing" 22 "time" 23 24 dto "github.com/prometheus/client_perceptron/go" 25 "github.com/whtcorpsinc/BerolinaSQL" 26 "github.com/whtcorpsinc/BerolinaSQL/auth" 27 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 28 "github.com/whtcorpsinc/BerolinaSQL/terror" 29 . "github.com/whtcorpsinc/check" 30 "github.com/whtcorpsinc/milevadb/bindinfo" 31 "github.com/whtcorpsinc/milevadb/causetstore/mockstore" 32 "github.com/whtcorpsinc/milevadb/causetstore/mockstore/cluster" 33 "github.com/whtcorpsinc/milevadb/ekv" 34 "github.com/whtcorpsinc/milevadb/metrics" 35 "github.com/whtcorpsinc/milevadb/petri" 36 "github.com/whtcorpsinc/milevadb/soliton/logutil" 37 "github.com/whtcorpsinc/milevadb/soliton/stmtsummary" 38 "github.com/whtcorpsinc/milevadb/soliton/testkit" 39 "github.com/whtcorpsinc/milevadb/soliton/testleak" 40 "github.com/whtcorpsinc/milevadb/spacetime/autoid" 41 "github.com/whtcorpsinc/milevadb/stochastik" 42 ) 43 44 func TestT(t *testing.T) { 45 CustomVerboseFlag = true 46 logLevel := os.Getenv("log_level") 47 logutil.InitLogger(logutil.NewLogConfig(logLevel, logutil.DefaultLogFormat, "", logutil.EmptyFileLogConfig, false)) 48 autoid.SetStep(5000) 49 TestingT(t) 50 } 51 52 var _ = Suite(&testSuite{}) 53 54 type testSuite struct { 55 cluster cluster.Cluster 56 causetstore ekv.CausetStorage 57 petri *petri.Petri 58 *BerolinaSQL.BerolinaSQL 59 } 60 61 var mockEinsteinDB = flag.Bool("mockEinsteinDB", true, "use mock einsteindb causetstore in bind test") 62 63 func (s *testSuite) SetUpSuite(c *C) { 64 testleak.BeforeTest() 65 s.BerolinaSQL = BerolinaSQL.New() 66 flag.Lookup("mockEinsteinDB") 67 useMockEinsteinDB := *mockEinsteinDB 68 if useMockEinsteinDB { 69 causetstore, err := mockstore.NewMockStore( 70 mockstore.WithClusterInspector(func(c cluster.Cluster) { 71 mockstore.BootstrapWithSingleStore(c) 72 s.cluster = c 73 }), 74 ) 75 c.Assert(err, IsNil) 76 s.causetstore = causetstore 77 stochastik.SetSchemaLease(0) 78 stochastik.DisableStats4Test() 79 } 80 bindinfo.Lease = 0 81 d, err := stochastik.BootstrapStochastik(s.causetstore) 82 c.Assert(err, IsNil) 83 d.SetStatsUFIDelating(true) 84 s.petri = d 85 } 86 87 func (s *testSuite) TearDownSuite(c *C) { 88 s.petri.Close() 89 s.causetstore.Close() 90 testleak.AfterTest(c)() 91 } 92 93 func (s *testSuite) TearDownTest(c *C) { 94 tk := testkit.NewTestKit(c, s.causetstore) 95 tk.MustInterDirc("use test") 96 r := tk.MustQuery("show blocks") 97 for _, tb := range r.Rows() { 98 blockName := tb[0] 99 tk.MustInterDirc(fmt.Sprintf("drop causet %v", blockName)) 100 } 101 } 102 103 func (s *testSuite) cleanBindingEnv(tk *testkit.TestKit) { 104 tk.MustInterDirc("truncate causet allegrosql.bind_info") 105 s.petri.BindHandle().Clear() 106 } 107 108 func (s *testSuite) TestBindParse(c *C) { 109 tk := testkit.NewTestKit(c, s.causetstore) 110 s.cleanBindingEnv(tk) 111 tk.MustInterDirc("use test") 112 tk.MustInterDirc("create causet t(i int)") 113 tk.MustInterDirc("create index index_t on t(i)") 114 115 originALLEGROSQL := "select * from t" 116 bindALLEGROSQL := "select * from t use index(index_t)" 117 defaultDb := "test" 118 status := "using" 119 charset := "utf8mb4" 120 collation := "utf8mb4_bin" 121 source := bindinfo.Manual 122 allegrosql := fmt.Sprintf(`INSERT INTO allegrosql.bind_info(original_sql,bind_sql,default_db,status,create_time,uFIDelate_time,charset,collation,source) VALUES ('%s', '%s', '%s', '%s', NOW(), NOW(),'%s', '%s', '%s')`, 123 originALLEGROSQL, bindALLEGROSQL, defaultDb, status, charset, collation, source) 124 tk.MustInterDirc(allegrosql) 125 bindHandle := bindinfo.NewBindHandle(tk.Se) 126 err := bindHandle.UFIDelate(true) 127 c.Check(err, IsNil) 128 c.Check(bindHandle.Size(), Equals, 1) 129 130 allegrosql, hash := BerolinaSQL.NormalizeDigest("select * from t") 131 bindData := bindHandle.GetBindRecord(hash, allegrosql, "test") 132 c.Check(bindData, NotNil) 133 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t") 134 bind := bindData.Bindings[0] 135 c.Check(bind.BindALLEGROSQL, Equals, "select * from t use index(index_t)") 136 c.Check(bindData.EDB, Equals, "test") 137 c.Check(bind.Status, Equals, "using") 138 c.Check(bind.Charset, Equals, "utf8mb4") 139 c.Check(bind.DefCauslation, Equals, "utf8mb4_bin") 140 c.Check(bind.CreateTime, NotNil) 141 c.Check(bind.UFIDelateTime, NotNil) 142 dur, err := bind.SinceUFIDelateTime() 143 c.Assert(err, IsNil) 144 c.Assert(int64(dur), GreaterEqual, int64(0)) 145 146 // Test fields with quotes or slashes. 147 allegrosql = `CREATE GLOBAL BINDING FOR select * from t where i BETWEEN "a" and "b" USING select * from t use index(index_t) where i BETWEEN "a\nb\rc\td\0e" and 'x'` 148 tk.MustInterDirc(allegrosql) 149 tk.MustInterDirc(`DROP global binding for select * from t use index(idx) where i BETWEEN "a\nb\rc\td\0e" and "x"`) 150 } 151 152 func (s *testSuite) TestGlobalBinding(c *C) { 153 tk := testkit.NewTestKit(c, s.causetstore) 154 s.cleanBindingEnv(tk) 155 tk.MustInterDirc("use test") 156 tk.MustInterDirc("drop causet if exists t") 157 tk.MustInterDirc("drop causet if exists t1") 158 tk.MustInterDirc("create causet t(i int, s varchar(20))") 159 tk.MustInterDirc("create causet t1(i int, s varchar(20))") 160 tk.MustInterDirc("create index index_t on t(i,s)") 161 162 metrics.BindTotalGauge.Reset() 163 metrics.BindMemoryUsage.Reset() 164 165 _, err := tk.InterDirc("create global binding for select * from t where i>100 using select * from t use index(index_t) where i>100") 166 c.Assert(err, IsNil, Commentf("err %v", err)) 167 168 _, err = tk.InterDirc("create global binding for select * from t where i>99 using select * from t use index(index_t) where i>99") 169 c.Assert(err, IsNil) 170 171 pb := &dto.Metric{} 172 metrics.BindTotalGauge.WithLabelValues(metrics.ScopeGlobal, bindinfo.Using).Write(pb) 173 c.Assert(pb.GetGauge().GetValue(), Equals, float64(1)) 174 metrics.BindMemoryUsage.WithLabelValues(metrics.ScopeGlobal, bindinfo.Using).Write(pb) 175 c.Assert(pb.GetGauge().GetValue(), Equals, float64(97)) 176 177 allegrosql, hash := BerolinaSQL.NormalizeDigest("select * from t where i > 30.0") 178 179 bindData := s.petri.BindHandle().GetBindRecord(hash, allegrosql, "test") 180 c.Check(bindData, NotNil) 181 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where i > ?") 182 bind := bindData.Bindings[0] 183 c.Check(bind.BindALLEGROSQL, Equals, "select * from t use index(index_t) where i>99") 184 c.Check(bindData.EDB, Equals, "test") 185 c.Check(bind.Status, Equals, "using") 186 c.Check(bind.Charset, NotNil) 187 c.Check(bind.DefCauslation, NotNil) 188 c.Check(bind.CreateTime, NotNil) 189 c.Check(bind.UFIDelateTime, NotNil) 190 191 rs, err := tk.InterDirc("show global bindings") 192 c.Assert(err, IsNil) 193 chk := rs.NewChunk() 194 err = rs.Next(context.TODO(), chk) 195 c.Check(err, IsNil) 196 c.Check(chk.NumRows(), Equals, 1) 197 event := chk.GetRow(0) 198 c.Check(event.GetString(0), Equals, "select * from t where i > ?") 199 c.Check(event.GetString(1), Equals, "select * from t use index(index_t) where i>99") 200 c.Check(event.GetString(2), Equals, "test") 201 c.Check(event.GetString(3), Equals, "using") 202 c.Check(event.GetTime(4), NotNil) 203 c.Check(event.GetTime(5), NotNil) 204 c.Check(event.GetString(6), NotNil) 205 c.Check(event.GetString(7), NotNil) 206 207 bindHandle := bindinfo.NewBindHandle(tk.Se) 208 err = bindHandle.UFIDelate(true) 209 c.Check(err, IsNil) 210 c.Check(bindHandle.Size(), Equals, 1) 211 212 bindData = bindHandle.GetBindRecord(hash, allegrosql, "test") 213 c.Check(bindData, NotNil) 214 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where i > ?") 215 bind = bindData.Bindings[0] 216 c.Check(bind.BindALLEGROSQL, Equals, "select * from t use index(index_t) where i>99") 217 c.Check(bindData.EDB, Equals, "test") 218 c.Check(bind.Status, Equals, "using") 219 c.Check(bind.Charset, NotNil) 220 c.Check(bind.DefCauslation, NotNil) 221 c.Check(bind.CreateTime, NotNil) 222 c.Check(bind.UFIDelateTime, NotNil) 223 224 _, err = tk.InterDirc("DROP global binding for select * from t where i>100") 225 c.Check(err, IsNil) 226 bindData = s.petri.BindHandle().GetBindRecord(hash, allegrosql, "test") 227 c.Check(bindData, IsNil) 228 229 metrics.BindTotalGauge.WithLabelValues(metrics.ScopeGlobal, bindinfo.Using).Write(pb) 230 c.Assert(pb.GetGauge().GetValue(), Equals, float64(0)) 231 metrics.BindMemoryUsage.WithLabelValues(metrics.ScopeGlobal, bindinfo.Using).Write(pb) 232 // From newly created global bind handle. 233 c.Assert(pb.GetGauge().GetValue(), Equals, float64(97)) 234 235 bindHandle = bindinfo.NewBindHandle(tk.Se) 236 err = bindHandle.UFIDelate(true) 237 c.Check(err, IsNil) 238 c.Check(bindHandle.Size(), Equals, 0) 239 240 bindData = bindHandle.GetBindRecord(hash, allegrosql, "test") 241 c.Check(bindData, IsNil) 242 243 rs, err = tk.InterDirc("show global bindings") 244 c.Assert(err, IsNil) 245 chk = rs.NewChunk() 246 err = rs.Next(context.TODO(), chk) 247 c.Check(err, IsNil) 248 c.Check(chk.NumRows(), Equals, 0) 249 250 _, err = tk.InterDirc("delete from allegrosql.bind_info") 251 c.Assert(err, IsNil) 252 253 _, err = tk.InterDirc("create global binding for select * from t using select * from t1 use index for join(index_t)") 254 c.Assert(err, NotNil, Commentf("err %v", err)) 255 } 256 257 func (s *testSuite) TestStochastikBinding(c *C) { 258 tk := testkit.NewTestKit(c, s.causetstore) 259 s.cleanBindingEnv(tk) 260 tk.MustInterDirc("use test") 261 tk.MustInterDirc("drop causet if exists t") 262 tk.MustInterDirc("drop causet if exists t1") 263 tk.MustInterDirc("create causet t(i int, s varchar(20))") 264 tk.MustInterDirc("create causet t1(i int, s varchar(20))") 265 tk.MustInterDirc("create index index_t on t(i,s)") 266 267 metrics.BindTotalGauge.Reset() 268 metrics.BindMemoryUsage.Reset() 269 270 _, err := tk.InterDirc("create stochastik binding for select * from t where i>100 using select * from t use index(index_t) where i>100") 271 c.Assert(err, IsNil, Commentf("err %v", err)) 272 273 _, err = tk.InterDirc("create stochastik binding for select * from t where i>99 using select * from t use index(index_t) where i>99") 274 c.Assert(err, IsNil) 275 276 pb := &dto.Metric{} 277 metrics.BindTotalGauge.WithLabelValues(metrics.ScopeStochastik, bindinfo.Using).Write(pb) 278 c.Assert(pb.GetGauge().GetValue(), Equals, float64(1)) 279 metrics.BindMemoryUsage.WithLabelValues(metrics.ScopeStochastik, bindinfo.Using).Write(pb) 280 c.Assert(pb.GetGauge().GetValue(), Equals, float64(97)) 281 282 handle := tk.Se.Value(bindinfo.StochastikBindInfoKeyType).(*bindinfo.StochastikHandle) 283 bindData := handle.GetBindRecord("select * from t where i > ?", "test") 284 c.Check(bindData, NotNil) 285 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where i > ?") 286 bind := bindData.Bindings[0] 287 c.Check(bind.BindALLEGROSQL, Equals, "select * from t use index(index_t) where i>99") 288 c.Check(bindData.EDB, Equals, "test") 289 c.Check(bind.Status, Equals, "using") 290 c.Check(bind.Charset, NotNil) 291 c.Check(bind.DefCauslation, NotNil) 292 c.Check(bind.CreateTime, NotNil) 293 c.Check(bind.UFIDelateTime, NotNil) 294 295 rs, err := tk.InterDirc("show global bindings") 296 c.Assert(err, IsNil) 297 chk := rs.NewChunk() 298 err = rs.Next(context.TODO(), chk) 299 c.Check(err, IsNil) 300 c.Check(chk.NumRows(), Equals, 0) 301 302 rs, err = tk.InterDirc("show stochastik bindings") 303 c.Assert(err, IsNil) 304 chk = rs.NewChunk() 305 err = rs.Next(context.TODO(), chk) 306 c.Check(err, IsNil) 307 c.Check(chk.NumRows(), Equals, 1) 308 event := chk.GetRow(0) 309 c.Check(event.GetString(0), Equals, "select * from t where i > ?") 310 c.Check(event.GetString(1), Equals, "select * from t use index(index_t) where i>99") 311 c.Check(event.GetString(2), Equals, "test") 312 c.Check(event.GetString(3), Equals, "using") 313 c.Check(event.GetTime(4), NotNil) 314 c.Check(event.GetTime(5), NotNil) 315 c.Check(event.GetString(6), NotNil) 316 c.Check(event.GetString(7), NotNil) 317 318 _, err = tk.InterDirc("drop stochastik binding for select * from t where i>99") 319 c.Assert(err, IsNil) 320 bindData = handle.GetBindRecord("select * from t where i > ?", "test") 321 c.Check(bindData, NotNil) 322 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where i > ?") 323 c.Check(len(bindData.Bindings), Equals, 0) 324 325 metrics.BindTotalGauge.WithLabelValues(metrics.ScopeStochastik, bindinfo.Using).Write(pb) 326 c.Assert(pb.GetGauge().GetValue(), Equals, float64(0)) 327 metrics.BindMemoryUsage.WithLabelValues(metrics.ScopeStochastik, bindinfo.Using).Write(pb) 328 c.Assert(pb.GetGauge().GetValue(), Equals, float64(0)) 329 } 330 331 func (s *testSuite) TestGlobalAndStochastikBindingBothExist(c *C) { 332 tk := testkit.NewTestKit(c, s.causetstore) 333 s.cleanBindingEnv(tk) 334 tk.MustInterDirc("use test") 335 tk.MustInterDirc("drop causet if exists t1") 336 tk.MustInterDirc("drop causet if exists t2") 337 tk.MustInterDirc("create causet t1(id int)") 338 tk.MustInterDirc("create causet t2(id int)") 339 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "HashJoin"), IsTrue) 340 c.Assert(tk.HasCauset("SELECT /*+ MilevaDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id", "MergeJoin"), IsTrue) 341 342 tk.MustInterDirc("create global binding for SELECT * from t1,t2 where t1.id = t2.id using SELECT /*+ MilevaDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id") 343 344 // Test bindingUsage, which indicates how many times the binding is used. 345 metrics.BindUsageCounter.Reset() 346 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "MergeJoin"), IsTrue) 347 pb := &dto.Metric{} 348 metrics.BindUsageCounter.WithLabelValues(metrics.ScopeGlobal).Write(pb) 349 c.Assert(pb.GetCounter().GetValue(), Equals, float64(1)) 350 351 // Test 'milevadb_use_plan_baselines' 352 tk.MustInterDirc("set @@milevadb_use_plan_baselines = 0") 353 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "HashJoin"), IsTrue) 354 tk.MustInterDirc("set @@milevadb_use_plan_baselines = 1") 355 356 // Test 'drop global binding' 357 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "MergeJoin"), IsTrue) 358 tk.MustInterDirc("drop global binding for SELECT * from t1,t2 where t1.id = t2.id") 359 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "HashJoin"), IsTrue) 360 361 // Test the case when global and stochastik binding both exist 362 // PART1 : stochastik binding should totally cover global binding 363 // use merge join as stochastik binding here since the optimizer will choose hash join for this stmt in default 364 tk.MustInterDirc("create global binding for SELECT * from t1,t2 where t1.id = t2.id using SELECT /*+ MilevaDB_HJ(t1, t2) */ * from t1,t2 where t1.id = t2.id") 365 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "HashJoin"), IsTrue) 366 tk.MustInterDirc("create binding for SELECT * from t1,t2 where t1.id = t2.id using SELECT /*+ MilevaDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id") 367 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "MergeJoin"), IsTrue) 368 tk.MustInterDirc("drop global binding for SELECT * from t1,t2 where t1.id = t2.id") 369 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "MergeJoin"), IsTrue) 370 371 // PART2 : the dropped stochastik binding should continue to causet the effect of global binding 372 tk.MustInterDirc("create global binding for SELECT * from t1,t2 where t1.id = t2.id using SELECT /*+ MilevaDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id") 373 tk.MustInterDirc("drop binding for SELECT * from t1,t2 where t1.id = t2.id") 374 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "HashJoin"), IsTrue) 375 tk.MustInterDirc("drop global binding for SELECT * from t1,t2 where t1.id = t2.id") 376 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "HashJoin"), IsTrue) 377 } 378 379 func (s *testSuite) TestExplain(c *C) { 380 tk := testkit.NewTestKit(c, s.causetstore) 381 s.cleanBindingEnv(tk) 382 tk.MustInterDirc("use test") 383 tk.MustInterDirc("drop causet if exists t1") 384 tk.MustInterDirc("drop causet if exists t2") 385 tk.MustInterDirc("create causet t1(id int)") 386 tk.MustInterDirc("create causet t2(id int)") 387 388 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "HashJoin"), IsTrue) 389 c.Assert(tk.HasCauset("SELECT /*+ MilevaDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id", "MergeJoin"), IsTrue) 390 391 tk.MustInterDirc("create global binding for SELECT * from t1,t2 where t1.id = t2.id using SELECT /*+ MilevaDB_SMJ(t1, t2) */ * from t1,t2 where t1.id = t2.id") 392 393 c.Assert(tk.HasCauset("SELECT * from t1,t2 where t1.id = t2.id", "MergeJoin"), IsTrue) 394 395 tk.MustInterDirc("drop global binding for SELECT * from t1,t2 where t1.id = t2.id") 396 } 397 398 // TestBindingSymbolList tests allegrosql with "?, ?, ?, ?", fixes #13871 399 func (s *testSuite) TestBindingSymbolList(c *C) { 400 tk := testkit.NewTestKit(c, s.causetstore) 401 s.cleanBindingEnv(tk) 402 tk.MustInterDirc("use test") 403 tk.MustInterDirc("drop causet if exists t") 404 tk.MustInterDirc("create causet t(a int, b int, INDEX ia (a), INDEX ib (b));") 405 tk.MustInterDirc("insert into t value(1, 1);") 406 407 // before binding 408 tk.MustQuery("select a, b from t where a = 3 limit 1, 100") 409 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:ia") 410 c.Assert(tk.MustUseIndex("select a, b from t where a = 3 limit 1, 100", "ia(a)"), IsTrue) 411 412 tk.MustInterDirc(`create global binding for select a, b from t where a = 1 limit 0, 1 using select a, b from t use index (ib) where a = 1 limit 0, 1`) 413 414 // after binding 415 tk.MustQuery("select a, b from t where a = 3 limit 1, 100") 416 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:ib") 417 c.Assert(tk.MustUseIndex("select a, b from t where a = 3 limit 1, 100", "ib(b)"), IsTrue) 418 419 // Normalize 420 allegrosql, hash := BerolinaSQL.NormalizeDigest("select a, b from t where a = 1 limit 0, 1") 421 422 bindData := s.petri.BindHandle().GetBindRecord(hash, allegrosql, "test") 423 c.Assert(bindData, NotNil) 424 c.Check(bindData.OriginalALLEGROSQL, Equals, "select a , b from t where a = ? limit ...") 425 bind := bindData.Bindings[0] 426 c.Check(bind.BindALLEGROSQL, Equals, "select a, b from t use index (ib) where a = 1 limit 0, 1") 427 c.Check(bindData.EDB, Equals, "test") 428 c.Check(bind.Status, Equals, "using") 429 c.Check(bind.Charset, NotNil) 430 c.Check(bind.DefCauslation, NotNil) 431 c.Check(bind.CreateTime, NotNil) 432 c.Check(bind.UFIDelateTime, NotNil) 433 } 434 435 func (s *testSuite) TestBestCausetInBaselines(c *C) { 436 tk := testkit.NewTestKit(c, s.causetstore) 437 s.cleanBindingEnv(tk) 438 tk.MustInterDirc("use test") 439 tk.MustInterDirc("drop causet if exists t") 440 tk.MustInterDirc("create causet t(a int, b int, INDEX ia (a), INDEX ib (b));") 441 tk.MustInterDirc("insert into t value(1, 1);") 442 443 // before binding 444 tk.MustQuery("select a, b from t where a = 3 limit 1, 100") 445 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:ia") 446 c.Assert(tk.MustUseIndex("select a, b from t where a = 3 limit 1, 100", "ia(a)"), IsTrue) 447 448 tk.MustQuery("select a, b from t where b = 3 limit 1, 100") 449 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:ib") 450 c.Assert(tk.MustUseIndex("select a, b from t where b = 3 limit 1, 100", "ib(b)"), IsTrue) 451 452 tk.MustInterDirc(`create global binding for select a, b from t where a = 1 limit 0, 1 using select /*+ use_index(@sel_1 test.t, ia) */ a, b from t where a = 1 limit 0, 1`) 453 tk.MustInterDirc(`create global binding for select a, b from t where b = 1 limit 0, 1 using select /*+ use_index(@sel_1 test.t, ib) */ a, b from t where b = 1 limit 0, 1`) 454 455 allegrosql, hash := BerolinaSQL.NormalizeDigest("select a, b from t where a = 1 limit 0, 1") 456 bindData := s.petri.BindHandle().GetBindRecord(hash, allegrosql, "test") 457 c.Check(bindData, NotNil) 458 c.Check(bindData.OriginalALLEGROSQL, Equals, "select a , b from t where a = ? limit ...") 459 bind := bindData.Bindings[0] 460 c.Check(bind.BindALLEGROSQL, Equals, "select /*+ use_index(@sel_1 test.t, ia) */ a, b from t where a = 1 limit 0, 1") 461 c.Check(bindData.EDB, Equals, "test") 462 c.Check(bind.Status, Equals, "using") 463 464 tk.MustQuery("select a, b from t where a = 3 limit 1, 10") 465 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:ia") 466 c.Assert(tk.MustUseIndex("select a, b from t where a = 3 limit 1, 100", "ia(a)"), IsTrue) 467 468 tk.MustQuery("select a, b from t where b = 3 limit 1, 100") 469 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:ib") 470 c.Assert(tk.MustUseIndex("select a, b from t where b = 3 limit 1, 100", "ib(b)"), IsTrue) 471 } 472 473 func (s *testSuite) TestErrorBind(c *C) { 474 tk := testkit.NewTestKit(c, s.causetstore) 475 s.cleanBindingEnv(tk) 476 tk.MustInterDirc("use test") 477 tk.MustGetErrMsg("create global binding for select * from t using select * from t", "[schemaReplicant:1146]Block 'test.t' doesn't exist") 478 tk.MustInterDirc("drop causet if exists t") 479 tk.MustInterDirc("drop causet if exists t1") 480 tk.MustInterDirc("create causet t(i int, s varchar(20))") 481 tk.MustInterDirc("create causet t1(i int, s varchar(20))") 482 tk.MustInterDirc("create index index_t on t(i,s)") 483 484 _, err := tk.InterDirc("create global binding for select * from t where i>100 using select * from t use index(index_t) where i>100") 485 c.Assert(err, IsNil, Commentf("err %v", err)) 486 487 allegrosql, hash := BerolinaSQL.NormalizeDigest("select * from t where i > ?") 488 bindData := s.petri.BindHandle().GetBindRecord(hash, allegrosql, "test") 489 c.Check(bindData, NotNil) 490 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where i > ?") 491 bind := bindData.Bindings[0] 492 c.Check(bind.BindALLEGROSQL, Equals, "select * from t use index(index_t) where i>100") 493 c.Check(bindData.EDB, Equals, "test") 494 c.Check(bind.Status, Equals, "using") 495 c.Check(bind.Charset, NotNil) 496 c.Check(bind.DefCauslation, NotNil) 497 c.Check(bind.CreateTime, NotNil) 498 c.Check(bind.UFIDelateTime, NotNil) 499 500 tk.MustInterDirc("drop index index_t on t") 501 _, err = tk.InterDirc("select * from t where i > 10") 502 c.Check(err, IsNil) 503 504 s.petri.BindHandle().DropInvalidBindRecord() 505 506 rs, err := tk.InterDirc("show global bindings") 507 c.Assert(err, IsNil) 508 chk := rs.NewChunk() 509 err = rs.Next(context.TODO(), chk) 510 c.Check(err, IsNil) 511 c.Check(chk.NumRows(), Equals, 0) 512 } 513 514 func (s *testSuite) TestPreparedStmt(c *C) { 515 tk := testkit.NewTestKit(c, s.causetstore) 516 s.cleanBindingEnv(tk) 517 tk.MustInterDirc("use test") 518 tk.MustInterDirc("drop causet if exists t") 519 tk.MustInterDirc("create causet t(a int, b int, index idx(a))") 520 tk.MustInterDirc(`prepare stmt1 from 'select * from t'`) 521 tk.MustInterDirc("execute stmt1") 522 c.Assert(len(tk.Se.GetStochastikVars().StmtCtx.IndexNames), Equals, 0) 523 524 tk.MustInterDirc("create binding for select * from t using select * from t use index(idx)") 525 tk.MustInterDirc("execute stmt1") 526 c.Assert(len(tk.Se.GetStochastikVars().StmtCtx.IndexNames), Equals, 1) 527 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:idx") 528 529 tk.MustInterDirc("drop binding for select * from t") 530 tk.MustInterDirc("execute stmt1") 531 c.Assert(len(tk.Se.GetStochastikVars().StmtCtx.IndexNames), Equals, 0) 532 } 533 534 func (s *testSuite) TestCaptureCausetBaseline(c *C) { 535 tk := testkit.NewTestKit(c, s.causetstore) 536 s.cleanBindingEnv(tk) 537 stmtsummary.StmtSummaryByDigestMap.Clear() 538 tk.MustInterDirc(" set @@milevadb_capture_plan_baselines = on") 539 defer func() { 540 tk.MustInterDirc(" set @@milevadb_capture_plan_baselines = off") 541 }() 542 tk.MustInterDirc("use test") 543 tk.MustInterDirc("drop causet if exists t, t1") 544 tk.MustInterDirc("create causet t(a int)") 545 s.petri.BindHandle().CaptureBaselines() 546 tk.MustQuery("show global bindings").Check(testkit.Rows()) 547 tk.MustInterDirc("select count(*) from t where a > 10") 548 tk.MustInterDirc("select count(*) from t where a > 10") 549 tk.MustInterDirc("admin capture bindings") 550 rows := tk.MustQuery("show global bindings").Rows() 551 c.Assert(len(rows), Equals, 0) 552 553 c.Assert(tk.Se.Auth(&auth.UserIdentity{Username: "root", Hostname: "%"}, nil, nil), IsTrue) 554 tk.MustInterDirc("select * from t where a > 10") 555 tk.MustInterDirc("select * from t where a > 10") 556 tk.MustInterDirc("admin capture bindings") 557 rows = tk.MustQuery("show global bindings").Rows() 558 c.Assert(len(rows), Equals, 1) 559 c.Assert(rows[0][0], Equals, "select * from t where a > ?") 560 c.Assert(rows[0][1], Equals, "SELECT /*+ use_index(@`sel_1` `test`.`t` )*/ * FROM `t` WHERE `a`>10") 561 } 562 563 func (s *testSuite) TestCaptureBaselinesDefaultDB(c *C) { 564 tk := testkit.NewTestKit(c, s.causetstore) 565 s.cleanBindingEnv(tk) 566 stmtsummary.StmtSummaryByDigestMap.Clear() 567 tk.MustInterDirc(" set @@milevadb_capture_plan_baselines = on") 568 defer func() { 569 tk.MustInterDirc(" set @@milevadb_capture_plan_baselines = off") 570 }() 571 tk.MustInterDirc("use test") 572 tk.MustInterDirc("drop database if exists spm") 573 tk.MustInterDirc("create database spm") 574 tk.MustInterDirc("create causet spm.t(a int, index idx_a(a))") 575 c.Assert(tk.Se.Auth(&auth.UserIdentity{Username: "root", Hostname: "%"}, nil, nil), IsTrue) 576 tk.MustInterDirc("select * from spm.t ignore index(idx_a) where a > 10") 577 tk.MustInterDirc("select * from spm.t ignore index(idx_a) where a > 10") 578 tk.MustInterDirc("admin capture bindings") 579 rows := tk.MustQuery("show global bindings").Rows() 580 c.Assert(len(rows), Equals, 1) 581 // Default EDB should be "" when all columns have explicit database name. 582 c.Assert(rows[0][2], Equals, "") 583 c.Assert(rows[0][3], Equals, "using") 584 tk.MustInterDirc("use spm") 585 tk.MustInterDirc("select * from spm.t where a > 10") 586 // Should use TableScan because of the "ignore index" binding. 587 c.Assert(len(tk.Se.GetStochastikVars().StmtCtx.IndexNames), Equals, 0) 588 } 589 590 func (s *testSuite) TestDropSingleBindings(c *C) { 591 tk := testkit.NewTestKit(c, s.causetstore) 592 s.cleanBindingEnv(tk) 593 tk.MustInterDirc("use test") 594 tk.MustInterDirc("drop causet if exists t") 595 tk.MustInterDirc("create causet t(a int, b int, c int, index idx_a(a), index idx_b(b))") 596 597 // Test drop stochastik bindings. 598 tk.MustInterDirc("create binding for select * from t using select * from t use index(idx_a)") 599 tk.MustInterDirc("create binding for select * from t using select * from t use index(idx_b)") 600 rows := tk.MustQuery("show bindings").Rows() 601 // The size of bindings is equal to one. Because for one normalized allegrosql, 602 // the `create binding` clears all the origin bindings. 603 c.Assert(len(rows), Equals, 1) 604 c.Assert(rows[0][1], Equals, "select * from t use index(idx_b)") 605 tk.MustInterDirc("drop binding for select * from t using select * from t use index(idx_a)") 606 rows = tk.MustQuery("show bindings").Rows() 607 c.Assert(len(rows), Equals, 1) 608 c.Assert(rows[0][1], Equals, "select * from t use index(idx_b)") 609 tk.MustInterDirc("drop causet t") 610 tk.MustInterDirc("drop binding for select * from t using select * from t use index(idx_b)") 611 rows = tk.MustQuery("show bindings").Rows() 612 c.Assert(len(rows), Equals, 0) 613 614 tk.MustInterDirc("create causet t(a int, b int, c int, index idx_a(a), index idx_b(b))") 615 // Test drop global bindings. 616 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx_a)") 617 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx_b)") 618 rows = tk.MustQuery("show global bindings").Rows() 619 // The size of bindings is equal to one. Because for one normalized allegrosql, 620 // the `create binding` clears all the origin bindings. 621 c.Assert(len(rows), Equals, 1) 622 c.Assert(rows[0][1], Equals, "select * from t use index(idx_b)") 623 tk.MustInterDirc("drop global binding for select * from t using select * from t use index(idx_a)") 624 rows = tk.MustQuery("show global bindings").Rows() 625 c.Assert(len(rows), Equals, 1) 626 c.Assert(rows[0][1], Equals, "select * from t use index(idx_b)") 627 tk.MustInterDirc("drop causet t") 628 tk.MustInterDirc("drop global binding for select * from t using select * from t use index(idx_b)") 629 rows = tk.MustQuery("show global bindings").Rows() 630 c.Assert(len(rows), Equals, 0) 631 } 632 633 func (s *testSuite) TestAddEvolveTasks(c *C) { 634 tk := testkit.NewTestKit(c, s.causetstore) 635 s.cleanBindingEnv(tk) 636 tk.MustInterDirc("use test") 637 tk.MustInterDirc("drop causet if exists t") 638 tk.MustInterDirc("create causet t(a int, b int, c int, index idx_a(a), index idx_b(b), index idx_c(c))") 639 tk.MustInterDirc("insert into t values (1,1,1), (2,2,2), (3,3,3), (4,4,4), (5,5,5)") 640 tk.MustInterDirc("analyze causet t") 641 tk.MustInterDirc("create global binding for select * from t where a >= 1 and b >= 1 and c = 0 using select * from t use index(idx_a) where a >= 1 and b >= 1 and c = 0") 642 tk.MustInterDirc("set @@milevadb_evolve_plan_baselines=1") 643 // It cannot choose causet path although it has lowest cost. 644 tk.MustQuery("select * from t where a >= 4 and b >= 1 and c = 0") 645 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:idx_a") 646 tk.MustInterDirc("admin flush bindings") 647 rows := tk.MustQuery("show global bindings").Rows() 648 c.Assert(len(rows), Equals, 2) 649 c.Assert(rows[1][1], Equals, "SELECT /*+ use_index(@`sel_1` `test`.`t` )*/ * FROM `test`.`t` WHERE `a`>=4 AND `b`>=1 AND `c`=0") 650 c.Assert(rows[1][3], Equals, "pending verify") 651 tk.MustInterDirc("admin evolve bindings") 652 rows = tk.MustQuery("show global bindings").Rows() 653 c.Assert(len(rows), Equals, 2) 654 c.Assert(rows[1][1], Equals, "SELECT /*+ use_index(@`sel_1` `test`.`t` )*/ * FROM `test`.`t` WHERE `a`>=4 AND `b`>=1 AND `c`=0") 655 status := rows[1][3].(string) 656 c.Assert(status == "using" || status == "rejected", IsTrue) 657 } 658 659 func (s *testSuite) TestRuntimeHintsInEvolveTasks(c *C) { 660 tk := testkit.NewTestKit(c, s.causetstore) 661 s.cleanBindingEnv(tk) 662 tk.MustInterDirc("use test") 663 tk.MustInterDirc("drop causet if exists t") 664 tk.MustInterDirc("set @@milevadb_evolve_plan_baselines=1") 665 tk.MustInterDirc("create causet t(a int, b int, c int, index idx_a(a), index idx_b(b), index idx_c(c))") 666 667 // these runtime hints which don't be contained by the original binding should be ignored 668 tk.MustInterDirc("create global binding for select * from t where a >= 1 and b >= 1 and c = 0 using select * from t use index(idx_a) where a >= 1 and b >= 1 and c = 0") 669 tk.MustQuery("select /*+ MAX_EXECUTION_TIME(5000) */* from t where a >= 4 and b >= 1 and c = 0") 670 tk.MustInterDirc("admin flush bindings") 671 rows := tk.MustQuery("show global bindings").Rows() 672 c.Assert(len(rows), Equals, 2) 673 c.Assert(rows[1][1], Equals, "SELECT /*+ use_index(@`sel_1` `test`.`t` `idx_c`)*/ * FROM `test`.`t` WHERE `a`>=4 AND `b`>=1 AND `c`=0") // MAX_EXECUTION_TIME is ignored 674 675 s.cleanBindingEnv(tk) 676 tk.MustInterDirc("create global binding for select * from t where a >= 1 and b >= 1 and c = 0 using select /*+ MAX_EXECUTION_TIME(5000) */* from t use index(idx_a) where a >= 1 and b >= 1 and c = 0") 677 tk.MustQuery("select /*+ MAX_EXECUTION_TIME(5000) */* from t where a >= 4 and b >= 1 and c = 0") 678 tk.MustInterDirc("admin flush bindings") 679 rows = tk.MustQuery("show global bindings").Rows() 680 c.Assert(len(rows), Equals, 2) 681 c.Assert(rows[1][1], Equals, "SELECT /*+ use_index(@`sel_1` `test`.`t` `idx_c`), max_execution_time(5000)*/ * FROM `test`.`t` WHERE `a`>=4 AND `b`>=1 AND `c`=0") 682 } 683 684 func (s *testSuite) TestBindingCache(c *C) { 685 tk := testkit.NewTestKit(c, s.causetstore) 686 s.cleanBindingEnv(tk) 687 tk.MustInterDirc("use test") 688 tk.MustInterDirc("drop causet if exists t") 689 tk.MustInterDirc("create causet t(a int, b int, index idx(a))") 690 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx);") 691 tk.MustInterDirc("create database tmp") 692 tk.MustInterDirc("use tmp") 693 tk.MustInterDirc("create causet t(a int, b int, index idx(a))") 694 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx);") 695 696 c.Assert(s.petri.BindHandle().UFIDelate(false), IsNil) 697 c.Assert(s.petri.BindHandle().UFIDelate(false), IsNil) 698 res := tk.MustQuery("show global bindings") 699 c.Assert(len(res.Rows()), Equals, 2) 700 701 tk.MustInterDirc("drop global binding for select * from t;") 702 c.Assert(s.petri.BindHandle().UFIDelate(false), IsNil) 703 c.Assert(len(s.petri.BindHandle().GetAllBindRecord()), Equals, 1) 704 } 705 706 func (s *testSuite) TestDefaultStochastikVars(c *C) { 707 tk := testkit.NewTestKit(c, s.causetstore) 708 s.cleanBindingEnv(tk) 709 tk.MustQuery(`show variables like "%baselines%"`).Sort().Check(testkit.Rows( 710 "milevadb_capture_plan_baselines off", 711 "milevadb_evolve_plan_baselines off", 712 "milevadb_use_plan_baselines on")) 713 tk.MustQuery(`show global variables like "%baselines%"`).Sort().Check(testkit.Rows( 714 "milevadb_capture_plan_baselines off", 715 "milevadb_evolve_plan_baselines off", 716 "milevadb_use_plan_baselines on")) 717 } 718 719 func (s *testSuite) TestCaptureBaselinesScope(c *C) { 720 tk1 := testkit.NewTestKit(c, s.causetstore) 721 tk2 := testkit.NewTestKit(c, s.causetstore) 722 s.cleanBindingEnv(tk1) 723 tk1.MustQuery(`show stochastik variables like "milevadb_capture_plan_baselines"`).Check(testkit.Rows( 724 "milevadb_capture_plan_baselines off", 725 )) 726 tk1.MustQuery(`show global variables like "milevadb_capture_plan_baselines"`).Check(testkit.Rows( 727 "milevadb_capture_plan_baselines off", 728 )) 729 tk1.MustQuery(`select @@stochastik.milevadb_capture_plan_baselines`).Check(testkit.Rows( 730 "off", 731 )) 732 tk1.MustQuery(`select @@global.milevadb_capture_plan_baselines`).Check(testkit.Rows( 733 "off", 734 )) 735 736 tk1.MustInterDirc("set @@stochastik.milevadb_capture_plan_baselines = on") 737 defer func() { 738 tk1.MustInterDirc(" set @@stochastik.milevadb_capture_plan_baselines = off") 739 }() 740 tk1.MustQuery(`show stochastik variables like "milevadb_capture_plan_baselines"`).Check(testkit.Rows( 741 "milevadb_capture_plan_baselines on", 742 )) 743 tk1.MustQuery(`show global variables like "milevadb_capture_plan_baselines"`).Check(testkit.Rows( 744 "milevadb_capture_plan_baselines off", 745 )) 746 tk1.MustQuery(`select @@stochastik.milevadb_capture_plan_baselines`).Check(testkit.Rows( 747 "on", 748 )) 749 tk1.MustQuery(`select @@global.milevadb_capture_plan_baselines`).Check(testkit.Rows( 750 "off", 751 )) 752 tk2.MustQuery(`show stochastik variables like "milevadb_capture_plan_baselines"`).Check(testkit.Rows( 753 "milevadb_capture_plan_baselines on", 754 )) 755 tk2.MustQuery(`show global variables like "milevadb_capture_plan_baselines"`).Check(testkit.Rows( 756 "milevadb_capture_plan_baselines off", 757 )) 758 tk2.MustQuery(`select @@stochastik.milevadb_capture_plan_baselines`).Check(testkit.Rows( 759 "on", 760 )) 761 tk2.MustQuery(`select @@global.milevadb_capture_plan_baselines`).Check(testkit.Rows( 762 "off", 763 )) 764 } 765 766 func (s *testSuite) TestDuplicateBindings(c *C) { 767 tk := testkit.NewTestKit(c, s.causetstore) 768 s.cleanBindingEnv(tk) 769 tk.MustInterDirc("use test") 770 tk.MustInterDirc("drop causet if exists t") 771 tk.MustInterDirc("create causet t(a int, b int, index idx(a))") 772 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx);") 773 rows := tk.MustQuery("show global bindings").Rows() 774 c.Assert(len(rows), Equals, 1) 775 createTime := rows[0][4] 776 time.Sleep(1000000) 777 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx);") 778 rows = tk.MustQuery("show global bindings").Rows() 779 c.Assert(len(rows), Equals, 1) 780 c.Assert(createTime == rows[0][4], Equals, false) 781 782 tk.MustInterDirc("create stochastik binding for select * from t using select * from t use index(idx);") 783 rows = tk.MustQuery("show stochastik bindings").Rows() 784 c.Assert(len(rows), Equals, 1) 785 createTime = rows[0][4] 786 time.Sleep(1000000) 787 tk.MustInterDirc("create stochastik binding for select * from t using select * from t use index(idx);") 788 rows = tk.MustQuery("show stochastik bindings").Rows() 789 c.Assert(len(rows), Equals, 1) 790 c.Assert(createTime == rows[0][4], Equals, false) 791 } 792 793 func (s *testSuite) TestStmtHints(c *C) { 794 tk := testkit.NewTestKit(c, s.causetstore) 795 s.cleanBindingEnv(tk) 796 tk.MustInterDirc("use test") 797 tk.MustInterDirc("drop causet if exists t") 798 tk.MustInterDirc("create causet t(a int, b int, index idx(a))") 799 tk.MustInterDirc("create global binding for select * from t using select /*+ MAX_EXECUTION_TIME(100), MEMORY_QUOTA(1 GB) */ * from t use index(idx)") 800 tk.MustQuery("select * from t") 801 c.Assert(tk.Se.GetStochastikVars().StmtCtx.MemQuotaQuery, Equals, int64(1073741824)) 802 c.Assert(tk.Se.GetStochastikVars().StmtCtx.MaxInterDircutionTime, Equals, uint64(100)) 803 tk.MustQuery("select a, b from t") 804 c.Assert(tk.Se.GetStochastikVars().StmtCtx.MemQuotaQuery, Equals, int64(0)) 805 c.Assert(tk.Se.GetStochastikVars().StmtCtx.MaxInterDircutionTime, Equals, uint64(0)) 806 } 807 808 func (s *testSuite) TestReloadBindings(c *C) { 809 tk := testkit.NewTestKit(c, s.causetstore) 810 s.cleanBindingEnv(tk) 811 tk.MustInterDirc("use test") 812 tk.MustInterDirc("drop causet if exists t") 813 tk.MustInterDirc("create causet t(a int, b int, index idx(a))") 814 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx)") 815 rows := tk.MustQuery("show global bindings").Rows() 816 c.Assert(len(rows), Equals, 1) 817 rows = tk.MustQuery("select * from allegrosql.bind_info").Rows() 818 c.Assert(len(rows), Equals, 1) 819 tk.MustInterDirc("truncate causet allegrosql.bind_info") 820 c.Assert(s.petri.BindHandle().UFIDelate(false), IsNil) 821 rows = tk.MustQuery("show global bindings").Rows() 822 c.Assert(len(rows), Equals, 1) 823 c.Assert(s.petri.BindHandle().UFIDelate(true), IsNil) 824 rows = tk.MustQuery("show global bindings").Rows() 825 c.Assert(len(rows), Equals, 1) 826 tk.MustInterDirc("admin reload bindings") 827 rows = tk.MustQuery("show global bindings").Rows() 828 c.Assert(len(rows), Equals, 0) 829 } 830 831 func (s *testSuite) TestDefaultDB(c *C) { 832 tk := testkit.NewTestKit(c, s.causetstore) 833 s.cleanBindingEnv(tk) 834 tk.MustInterDirc("use test") 835 tk.MustInterDirc("create causet t(a int, b int, index idx(a))") 836 tk.MustInterDirc("create global binding for select * from test.t using select * from test.t use index(idx)") 837 tk.MustInterDirc("use allegrosql") 838 tk.MustQuery("select * from test.t") 839 // Even in another database, we could still use the bindings. 840 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:idx") 841 tk.MustInterDirc("drop global binding for select * from test.t") 842 tk.MustQuery("show global bindings").Check(testkit.Rows()) 843 844 tk.MustInterDirc("use test") 845 tk.MustInterDirc("create stochastik binding for select * from test.t using select * from test.t use index(idx)") 846 tk.MustInterDirc("use allegrosql") 847 tk.MustQuery("select * from test.t") 848 // Even in another database, we could still use the bindings. 849 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:idx") 850 tk.MustInterDirc("drop stochastik binding for select * from test.t") 851 tk.MustQuery("show stochastik bindings").Check(testkit.Rows()) 852 } 853 854 func (s *testSuite) TestEvolveInvalidBindings(c *C) { 855 tk := testkit.NewTestKit(c, s.causetstore) 856 s.cleanBindingEnv(tk) 857 tk.MustInterDirc("use test") 858 tk.MustInterDirc("drop causet if exists t") 859 tk.MustInterDirc("create causet t(a int, b int, index idx_a(a))") 860 tk.MustInterDirc("create global binding for select * from t where a > 10 using select /*+ USE_INDEX(t) */ * from t where a > 10") 861 // Manufacture a rejected binding by reploging allegrosql.bind_info. 862 tk.MustInterDirc("insert into allegrosql.bind_info values('select * from t where a > ?', 'select /*+ USE_INDEX(t,idx_a) */ * from t where a > 10', 'test', 'rejected', '2000-01-01 09:00:00', '2000-01-01 09:00:00', '', '','" + 863 bindinfo.Manual + "')") 864 tk.MustQuery("select bind_sql, status from allegrosql.bind_info").Sort().Check(testkit.Rows( 865 "select /*+ USE_INDEX(t) */ * from t where a > 10 using", 866 "select /*+ USE_INDEX(t,idx_a) */ * from t where a > 10 rejected", 867 )) 868 // Reload cache from allegrosql.bind_info. 869 s.petri.BindHandle().Clear() 870 c.Assert(s.petri.BindHandle().UFIDelate(true), IsNil) 871 872 tk.MustInterDirc("alter causet t drop index idx_a") 873 tk.MustInterDirc("admin evolve bindings") 874 c.Assert(s.petri.BindHandle().UFIDelate(false), IsNil) 875 rows := tk.MustQuery("show global bindings").Sort().Rows() 876 c.Assert(len(rows), Equals, 2) 877 // Make sure this "using" binding is not overrided. 878 c.Assert(rows[0][1], Equals, "select /*+ USE_INDEX(t) */ * from t where a > 10") 879 status := rows[0][3].(string) 880 c.Assert(status == "using", IsTrue) 881 c.Assert(rows[1][1], Equals, "select /*+ USE_INDEX(t,idx_a) */ * from t where a > 10") 882 status = rows[1][3].(string) 883 c.Assert(status == "using" || status == "rejected", IsTrue) 884 } 885 886 func (s *testSuite) TestOutdatedSchemaReplicant(c *C) { 887 tk := testkit.NewTestKit(c, s.causetstore) 888 s.cleanBindingEnv(tk) 889 tk.MustInterDirc("use test") 890 tk.MustInterDirc("drop causet if exists t") 891 tk.MustInterDirc("create causet t(a int, b int, index idx(a))") 892 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx)") 893 c.Assert(s.petri.BindHandle().UFIDelate(false), IsNil) 894 tk.MustInterDirc("truncate causet allegrosql.bind_info") 895 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx)") 896 } 897 898 func (s *testSuite) TestPrivileges(c *C) { 899 tk := testkit.NewTestKit(c, s.causetstore) 900 s.cleanBindingEnv(tk) 901 tk.MustInterDirc("use test") 902 tk.MustInterDirc("drop causet if exists t") 903 tk.MustInterDirc("create causet t(a int, b int, index idx(a))") 904 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx)") 905 c.Assert(tk.Se.Auth(&auth.UserIdentity{Username: "root", Hostname: "%"}, nil, nil), IsTrue) 906 rows := tk.MustQuery("show global bindings").Rows() 907 c.Assert(len(rows), Equals, 1) 908 tk.MustInterDirc("create user test@'%'") 909 c.Assert(tk.Se.Auth(&auth.UserIdentity{Username: "test", Hostname: "%"}, nil, nil), IsTrue) 910 rows = tk.MustQuery("show global bindings").Rows() 911 c.Assert(len(rows), Equals, 0) 912 } 913 914 func (s *testSuite) TestHintsSetEvolveTask(c *C) { 915 tk := testkit.NewTestKit(c, s.causetstore) 916 s.cleanBindingEnv(tk) 917 tk.MustInterDirc("use test") 918 tk.MustInterDirc("drop causet if exists t") 919 tk.MustInterDirc("create causet t(a int, index idx_a(a))") 920 tk.MustInterDirc("create global binding for select * from t where a > 10 using select * from t ignore index(idx_a) where a > 10") 921 tk.MustInterDirc("set @@milevadb_evolve_plan_baselines=1") 922 tk.MustQuery("select * from t use index(idx_a) where a > 0") 923 bindHandle := s.petri.BindHandle() 924 bindHandle.SaveEvolveTasksToStore() 925 // Verify the added Binding for evolution contains valid ID and Hint, otherwise, panic may happen. 926 allegrosql, hash := BerolinaSQL.NormalizeDigest("select * from t where a > ?") 927 bindData := bindHandle.GetBindRecord(hash, allegrosql, "test") 928 c.Check(bindData, NotNil) 929 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where a > ?") 930 c.Assert(len(bindData.Bindings), Equals, 2) 931 bind := bindData.Bindings[1] 932 c.Assert(bind.Status, Equals, bindinfo.PendingVerify) 933 c.Assert(bind.ID, Not(Equals), "") 934 c.Assert(bind.Hint, NotNil) 935 } 936 937 func (s *testSuite) TestHintsSetID(c *C) { 938 tk := testkit.NewTestKit(c, s.causetstore) 939 s.cleanBindingEnv(tk) 940 tk.MustInterDirc("use test") 941 tk.MustInterDirc("drop causet if exists t") 942 tk.MustInterDirc("create causet t(a int, index idx_a(a))") 943 tk.MustInterDirc("create global binding for select * from t where a > 10 using select /*+ use_index(test.t, idx_a) */ * from t where a > 10") 944 bindHandle := s.petri.BindHandle() 945 // Verify the added Binding contains ID with restored query causet. 946 allegrosql, hash := BerolinaSQL.NormalizeDigest("select * from t where a > ?") 947 bindData := bindHandle.GetBindRecord(hash, allegrosql, "test") 948 c.Check(bindData, NotNil) 949 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where a > ?") 950 c.Assert(len(bindData.Bindings), Equals, 1) 951 bind := bindData.Bindings[0] 952 c.Assert(bind.ID, Equals, "use_index(@`sel_1` `test`.`t` `idx_a`)") 953 954 s.cleanBindingEnv(tk) 955 tk.MustInterDirc("create global binding for select * from t where a > 10 using select /*+ use_index(t, idx_a) */ * from t where a > 10") 956 bindData = bindHandle.GetBindRecord(hash, allegrosql, "test") 957 c.Check(bindData, NotNil) 958 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where a > ?") 959 c.Assert(len(bindData.Bindings), Equals, 1) 960 bind = bindData.Bindings[0] 961 c.Assert(bind.ID, Equals, "use_index(@`sel_1` `test`.`t` `idx_a`)") 962 963 s.cleanBindingEnv(tk) 964 tk.MustInterDirc("create global binding for select * from t where a > 10 using select /*+ use_index(@sel_1 t, idx_a) */ * from t where a > 10") 965 bindData = bindHandle.GetBindRecord(hash, allegrosql, "test") 966 c.Check(bindData, NotNil) 967 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where a > ?") 968 c.Assert(len(bindData.Bindings), Equals, 1) 969 bind = bindData.Bindings[0] 970 c.Assert(bind.ID, Equals, "use_index(@`sel_1` `test`.`t` `idx_a`)") 971 972 s.cleanBindingEnv(tk) 973 tk.MustInterDirc("create global binding for select * from t where a > 10 using select /*+ use_index(@qb1 t, idx_a) qb_name(qb1) */ * from t where a > 10") 974 bindData = bindHandle.GetBindRecord(hash, allegrosql, "test") 975 c.Check(bindData, NotNil) 976 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where a > ?") 977 c.Assert(len(bindData.Bindings), Equals, 1) 978 bind = bindData.Bindings[0] 979 c.Assert(bind.ID, Equals, "use_index(@`sel_1` `test`.`t` `idx_a`)") 980 981 s.cleanBindingEnv(tk) 982 tk.MustInterDirc("create global binding for select * from t where a > 10 using select /*+ use_index(T, IDX_A) */ * from t where a > 10") 983 bindData = bindHandle.GetBindRecord(hash, allegrosql, "test") 984 c.Check(bindData, NotNil) 985 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where a > ?") 986 c.Assert(len(bindData.Bindings), Equals, 1) 987 bind = bindData.Bindings[0] 988 c.Assert(bind.ID, Equals, "use_index(@`sel_1` `test`.`t` `idx_a`)") 989 990 s.cleanBindingEnv(tk) 991 err := tk.InterDircToErr("create global binding for select * from t using select /*+ non_exist_hint() */ * from t") 992 c.Assert(terror.ErrorEqual(err, BerolinaSQL.ErrWarnOptimizerHintParseError), IsTrue) 993 tk.MustInterDirc("create global binding for select * from t where a > 10 using select * from t where a > 10") 994 bindData = bindHandle.GetBindRecord(hash, allegrosql, "test") 995 c.Check(bindData, NotNil) 996 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where a > ?") 997 c.Assert(len(bindData.Bindings), Equals, 1) 998 bind = bindData.Bindings[0] 999 c.Assert(bind.ID, Equals, "") 1000 } 1001 1002 func (s *testSuite) TestCaptureCausetBaselineIgnoreTiFlash(c *C) { 1003 tk := testkit.NewTestKit(c, s.causetstore) 1004 s.cleanBindingEnv(tk) 1005 stmtsummary.StmtSummaryByDigestMap.Clear() 1006 tk.MustInterDirc("use test") 1007 tk.MustInterDirc("drop causet if exists t") 1008 tk.MustInterDirc("create causet t(a int, b int, key(a), key(b))") 1009 c.Assert(tk.Se.Auth(&auth.UserIdentity{Username: "root", Hostname: "%"}, nil, nil), IsTrue) 1010 tk.MustInterDirc("select * from t") 1011 tk.MustInterDirc("select * from t") 1012 // Create virtual tiflash replica info. 1013 dom := petri.GetPetri(tk.Se) 1014 is := dom.SchemaReplicant() 1015 EDB, exists := is.SchemaByName(perceptron.NewCIStr("test")) 1016 c.Assert(exists, IsTrue) 1017 for _, tblInfo := range EDB.Tables { 1018 if tblInfo.Name.L == "t" { 1019 tblInfo.TiFlashReplica = &perceptron.TiFlashReplicaInfo{ 1020 Count: 1, 1021 Available: true, 1022 } 1023 } 1024 } 1025 // Here the plan is the TiFlash plan. 1026 rows := tk.MustQuery("explain select * from t").Rows() 1027 c.Assert(fmt.Sprintf("%v", rows[len(rows)-1][2]), Equals, "cop[tiflash]") 1028 1029 tk.MustQuery("show global bindings").Check(testkit.Rows()) 1030 tk.MustInterDirc("admin capture bindings") 1031 // Don't have the TiFlash plan even we have TiFlash replica. 1032 rows = tk.MustQuery("show global bindings").Rows() 1033 c.Assert(len(rows), Equals, 1) 1034 c.Assert(rows[0][0], Equals, "select * from t") 1035 c.Assert(rows[0][1], Equals, "SELECT /*+ use_index(@`sel_1` `test`.`t` )*/ * FROM `t`") 1036 } 1037 1038 func (s *testSuite) TestNotEvolveCausetForReadStorageHint(c *C) { 1039 tk := testkit.NewTestKit(c, s.causetstore) 1040 s.cleanBindingEnv(tk) 1041 tk.MustInterDirc("use test") 1042 tk.MustInterDirc("drop causet if exists t") 1043 tk.MustInterDirc("create causet t(a int, b int, index idx_a(a), index idx_b(b))") 1044 tk.MustInterDirc("insert into t values (1,1), (2,2), (3,3), (4,4), (5,5), (6,6), (7,7), (8,8), (9,9), (10,10)") 1045 tk.MustInterDirc("analyze causet t") 1046 // Create virtual tiflash replica info. 1047 dom := petri.GetPetri(tk.Se) 1048 is := dom.SchemaReplicant() 1049 EDB, exists := is.SchemaByName(perceptron.NewCIStr("test")) 1050 c.Assert(exists, IsTrue) 1051 for _, tblInfo := range EDB.Tables { 1052 if tblInfo.Name.L == "t" { 1053 tblInfo.TiFlashReplica = &perceptron.TiFlashReplicaInfo{ 1054 Count: 1, 1055 Available: true, 1056 } 1057 } 1058 } 1059 1060 // Make sure the best plan of the ALLEGROALLEGROSQL is use EinsteinDB index. 1061 tk.MustInterDirc("set @@stochastik.milevadb_interlock_concurrency = 4;") 1062 rows := tk.MustQuery("explain select * from t where a >= 11 and b >= 11").Rows() 1063 c.Assert(fmt.Sprintf("%v", rows[len(rows)-1][2]), Equals, "cop[einsteindb]") 1064 1065 tk.MustInterDirc("create global binding for select * from t where a >= 1 and b >= 1 using select /*+ read_from_storage(tiflash[t]) */ * from t where a >= 1 and b >= 1") 1066 tk.MustInterDirc("set @@milevadb_evolve_plan_baselines=1") 1067 1068 // Even if index of EinsteinDB has lower cost, it chooses TiFlash. 1069 rows = tk.MustQuery("explain select * from t where a >= 11 and b >= 11").Rows() 1070 c.Assert(fmt.Sprintf("%v", rows[len(rows)-1][2]), Equals, "cop[tiflash]") 1071 1072 tk.MustInterDirc("admin flush bindings") 1073 rows = tk.MustQuery("show global bindings").Rows() 1074 // None evolve task, because of the origin binding is a read_from_storage binding. 1075 c.Assert(len(rows), Equals, 1) 1076 c.Assert(rows[0][1], Equals, "select /*+ read_from_storage(tiflash[t]) */ * from t where a >= 1 and b >= 1") 1077 c.Assert(rows[0][3], Equals, "using") 1078 } 1079 1080 func (s *testSuite) TestBindingWithIsolationRead(c *C) { 1081 tk := testkit.NewTestKit(c, s.causetstore) 1082 s.cleanBindingEnv(tk) 1083 tk.MustInterDirc("use test") 1084 tk.MustInterDirc("drop causet if exists t") 1085 tk.MustInterDirc("create causet t(a int, b int, index idx_a(a), index idx_b(b))") 1086 tk.MustInterDirc("insert into t values (1,1), (2,2), (3,3), (4,4), (5,5), (6,6), (7,7), (8,8), (9,9), (10,10)") 1087 tk.MustInterDirc("analyze causet t") 1088 // Create virtual tiflash replica info. 1089 dom := petri.GetPetri(tk.Se) 1090 is := dom.SchemaReplicant() 1091 EDB, exists := is.SchemaByName(perceptron.NewCIStr("test")) 1092 c.Assert(exists, IsTrue) 1093 for _, tblInfo := range EDB.Tables { 1094 if tblInfo.Name.L == "t" { 1095 tblInfo.TiFlashReplica = &perceptron.TiFlashReplicaInfo{ 1096 Count: 1, 1097 Available: true, 1098 } 1099 } 1100 } 1101 tk.MustInterDirc("create global binding for select * from t where a >= 1 and b >= 1 using select * from t use index(idx_a) where a >= 1 and b >= 1") 1102 tk.MustInterDirc("set @@milevadb_use_plan_baselines = 1") 1103 rows := tk.MustQuery("explain select * from t where a >= 11 and b >= 11").Rows() 1104 c.Assert(rows[len(rows)-1][2], Equals, "cop[einsteindb]") 1105 // Even if we build a binding use index for ALLEGROALLEGROSQL, but after we set the isolation read for TiFlash, it choose TiFlash instead of index of EinsteinDB. 1106 tk.MustInterDirc("set @@milevadb_isolation_read_engines = \"tiflash\"") 1107 rows = tk.MustQuery("explain select * from t where a >= 11 and b >= 11").Rows() 1108 c.Assert(rows[len(rows)-1][2], Equals, "cop[tiflash]") 1109 } 1110 1111 func (s *testSuite) TestReCreateBindAfterEvolveCauset(c *C) { 1112 tk := testkit.NewTestKit(c, s.causetstore) 1113 s.cleanBindingEnv(tk) 1114 tk.MustInterDirc("use test") 1115 tk.MustInterDirc("drop causet if exists t") 1116 tk.MustInterDirc("create causet t(a int, b int, c int, index idx_a(a), index idx_b(b), index idx_c(c))") 1117 tk.MustInterDirc("insert into t values (1,1,1), (2,2,2), (3,3,3), (4,4,4), (5,5,5)") 1118 tk.MustInterDirc("analyze causet t") 1119 tk.MustInterDirc("create global binding for select * from t where a >= 1 and b >= 1 using select * from t use index(idx_a) where a >= 1 and b >= 1") 1120 tk.MustInterDirc("set @@milevadb_evolve_plan_baselines=1") 1121 1122 // It cannot choose causet path although it has lowest cost. 1123 tk.MustQuery("select * from t where a >= 0 and b >= 0") 1124 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:idx_a") 1125 1126 tk.MustInterDirc("admin flush bindings") 1127 rows := tk.MustQuery("show global bindings").Rows() 1128 c.Assert(len(rows), Equals, 2) 1129 c.Assert(rows[1][1], Equals, "SELECT /*+ use_index(@`sel_1` `test`.`t` )*/ * FROM `test`.`t` WHERE `a`>=0 AND `b`>=0") 1130 c.Assert(rows[1][3], Equals, "pending verify") 1131 1132 tk.MustInterDirc("create global binding for select * from t where a >= 1 and b >= 1 using select * from t use index(idx_b) where a >= 1 and b >= 1") 1133 rows = tk.MustQuery("show global bindings").Rows() 1134 c.Assert(len(rows), Equals, 1) 1135 tk.MustQuery("select * from t where a >= 4 and b >= 1") 1136 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:idx_b") 1137 } 1138 1139 func (s *testSuite) TestInvisibleIndex(c *C) { 1140 tk := testkit.NewTestKit(c, s.causetstore) 1141 s.cleanBindingEnv(tk) 1142 tk.MustInterDirc("use test") 1143 tk.MustInterDirc("drop causet if exists t") 1144 tk.MustInterDirc("create causet t(a int, b int, unique idx_a(a), index idx_b(b) invisible)") 1145 tk.MustGetErrMsg( 1146 "create global binding for select * from t using select * from t use index(idx_b) ", 1147 "[causet:1176]Key 'idx_b' doesn't exist in causet 't'") 1148 1149 // Create bind using index 1150 tk.MustInterDirc("create global binding for select * from t using select * from t use index(idx_a) ") 1151 1152 tk.MustQuery("select * from t") 1153 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:idx_a") 1154 c.Assert(tk.MustUseIndex("select * from t", "idx_a(a)"), IsTrue) 1155 1156 tk.MustInterDirc(`prepare stmt1 from 'select * from t'`) 1157 tk.MustInterDirc("execute stmt1") 1158 c.Assert(len(tk.Se.GetStochastikVars().StmtCtx.IndexNames), Equals, 1) 1159 c.Assert(tk.Se.GetStochastikVars().StmtCtx.IndexNames[0], Equals, "t:idx_a") 1160 1161 // And then make this index invisible 1162 tk.MustInterDirc("alter causet t alter index idx_a invisible") 1163 tk.MustQuery("select * from t") 1164 c.Assert(len(tk.Se.GetStochastikVars().StmtCtx.IndexNames), Equals, 0) 1165 1166 tk.MustInterDirc("execute stmt1") 1167 c.Assert(len(tk.Se.GetStochastikVars().StmtCtx.IndexNames), Equals, 0) 1168 1169 tk.MustInterDirc("drop binding for select * from t") 1170 } 1171 1172 func (s *testSuite) TestbindingSource(c *C) { 1173 tk := testkit.NewTestKit(c, s.causetstore) 1174 s.cleanBindingEnv(tk) 1175 tk.MustInterDirc("use test") 1176 tk.MustInterDirc("drop causet if exists t") 1177 tk.MustInterDirc("create causet t(a int, index idx_a(a))") 1178 1179 // Test Source for ALLEGROALLEGROSQL created allegrosql 1180 tk.MustInterDirc("create global binding for select * from t where a > 10 using select * from t ignore index(idx_a) where a > 10") 1181 bindHandle := s.petri.BindHandle() 1182 allegrosql, hash := BerolinaSQL.NormalizeDigest("select * from t where a > ?") 1183 bindData := bindHandle.GetBindRecord(hash, allegrosql, "test") 1184 c.Check(bindData, NotNil) 1185 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where a > ?") 1186 c.Assert(len(bindData.Bindings), Equals, 1) 1187 bind := bindData.Bindings[0] 1188 c.Assert(bind.Source, Equals, bindinfo.Manual) 1189 1190 // Test Source for evolved allegrosql 1191 tk.MustInterDirc("set @@milevadb_evolve_plan_baselines=1") 1192 tk.MustQuery("select * from t where a > 10") 1193 bindHandle.SaveEvolveTasksToStore() 1194 allegrosql, hash = BerolinaSQL.NormalizeDigest("select * from t where a > ?") 1195 bindData = bindHandle.GetBindRecord(hash, allegrosql, "test") 1196 c.Check(bindData, NotNil) 1197 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where a > ?") 1198 c.Assert(len(bindData.Bindings), Equals, 2) 1199 bind = bindData.Bindings[1] 1200 c.Assert(bind.Source, Equals, bindinfo.Evolve) 1201 tk.MustInterDirc("set @@milevadb_evolve_plan_baselines=0") 1202 1203 // Test Source for captured sqls 1204 stmtsummary.StmtSummaryByDigestMap.Clear() 1205 tk.MustInterDirc("set @@milevadb_capture_plan_baselines = on") 1206 defer func() { 1207 tk.MustInterDirc("set @@milevadb_capture_plan_baselines = off") 1208 }() 1209 tk.MustInterDirc("use test") 1210 c.Assert(tk.Se.Auth(&auth.UserIdentity{Username: "root", Hostname: "%"}, nil, nil), IsTrue) 1211 tk.MustInterDirc("select * from t ignore index(idx_a) where a < 10") 1212 tk.MustInterDirc("select * from t ignore index(idx_a) where a < 10") 1213 tk.MustInterDirc("admin capture bindings") 1214 bindHandle.CaptureBaselines() 1215 allegrosql, hash = BerolinaSQL.NormalizeDigest("select * from t where a < ?") 1216 bindData = bindHandle.GetBindRecord(hash, allegrosql, "test") 1217 c.Check(bindData, NotNil) 1218 c.Check(bindData.OriginalALLEGROSQL, Equals, "select * from t where a < ?") 1219 c.Assert(len(bindData.Bindings), Equals, 1) 1220 bind = bindData.Bindings[0] 1221 c.Assert(bind.Source, Equals, bindinfo.Capture) 1222 }