Repository: pingcap/tidb (Go)

Issue:
inl_hash_join does not work as expected
## Bug Report

Please answer these questions before submitting your issue. Thanks!

1. What did you do?
``` go
tidb> use test

tidb> create table t1(a int, index(a));
Query OK, 0 rows affected (0.01 sec)

tidb> create table t2(a int, index(a));
Query OK, 0 rows affected (0.01 sec)

tidb> use test2

tidb> desc select /*+ inl_hash_join(test.t1) */ * from test.t1 join test.t2 on test.t1.a = test.t2.a;
+-----------------------------+----------+-----------+-----------------------------------------------------+
| id                          | estRows  | task      | operator info                                       |
+-----------------------------+----------+-----------+-----------------------------------------------------+
| MergeJoin_7                 | 12487.50 | root      | inner join, left key:test.t1.a, right key:test.t2.a |
| ├─IndexReader_35(Build)     | 9990.00  | root      | index:IndexFullScan_34                              |
| │ └─IndexFullScan_34        | 9990.00  | cop[tikv] | table:t2, index:a, keep order:true, stats:pseudo    |
| └─IndexReader_33(Probe)     | 9990.00  | root      | index:IndexFullScan_32                              |
|   └─IndexFullScan_32        | 9990.00  | cop[tikv] | table:t1, index:a, keep order:true, stats:pseudo    |
+-----------------------------+----------+-----------+-----------------------------------------------------+
5 rows in set, 1 warning (0.00 sec)

tidb> show warnings;
+---------+------+-------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                       |
+---------+------+-------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1815 | There are no matching table names for (t1) in optimizer hint /*+ INL_HASH_JOIN(t1) */. Maybe you can use the table alias name |
+---------+------+-------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
```

2. What did you expect to see?
indexHashJoin can be chosen forcibly


4. What version of TiDB are you using (`tidb-server -V` or run `select tidb_version();` on TiDB)?
``` sql
Release Version: v4.0.0-beta-345-gf51a7fc6e
Git Commit Hash: f51a7fc6e9b24fc0c0eb1ecb6da2e67ad8a34be4
Git Branch: master
UTC Build Time: 2020-03-12 06:26:29
GoVersion: go1.13
Race Enabled: false
TiKV Min Version: v3.0.0-60965b006877ca7234adaced7890d7b029ed1306
Check Table Before Drop: false
```



Discussion:

Patch:
diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go
index 0fb860f152732..79ce8f67d53f1 100644
--- a/planner/core/planbuilder.go
+++ b/planner/core/planbuilder.go
@@ -115,7 +115,7 @@ func tableNames2HintTableInfo(ctx sessionctx.Context, hintTables []ast.HintTable
 	hintTableInfos := make([]hintTableInfo, len(hintTables))
 	defaultDBName := model.NewCIStr(ctx.GetSessionVars().CurrentDB)
 	for i, hintTable := range hintTables {
-		tableInfo := hintTableInfo{tblName: hintTable.TableName, selectOffset: p.getHintOffset(hintTable.QBName, nodeType, currentOffset)}
+		tableInfo := hintTableInfo{dbName: hintTable.DBName, tblName: hintTable.TableName, selectOffset: p.getHintOffset(hintTable.QBName, nodeType, currentOffset)}
 		if tableInfo.dbName.L == "" {
 			tableInfo.dbName = defaultDBName
 		}


Test patch:
diff --git a/planner/core/physical_plan_test.go b/planner/core/physical_plan_test.go
index 9c8fc01e00ed9..3d0488c1ac8e3 100644
--- a/planner/core/physical_plan_test.go
+++ b/planner/core/physical_plan_test.go
@@ -1277,3 +1277,51 @@ func (s *testPlanSuite) TestNominalSort(c *C) {
 		tk.MustQuery(ts).Check(testkit.Rows(output[i].Result...))
 	}
 }
+
+func (s *testPlanSuite) TestHintFromDiffDatabase(c *C) {
+	defer testleak.AfterTest(c)()
+	store, dom, err := newStoreWithBootstrap()
+	c.Assert(err, IsNil)
+	defer func() {
+		dom.Close()
+		store.Close()
+	}()
+	se, err := session.CreateSession4Test(store)
+	c.Assert(err, IsNil)
+	ctx := context.Background()
+	_, err = se.Execute(ctx, "use test")
+	c.Assert(err, IsNil)
+	_, err = se.Execute(ctx, `drop table if exists test.t1`)
+	c.Assert(err, IsNil)
+	_, err = se.Execute(ctx, `create table test.t1(a bigint, index idx_a(a));`)
+	c.Assert(err, IsNil)
+	_, err = se.Execute(ctx, `create table test.t2(a bigint, index idx_a(a));`)
+	c.Assert(err, IsNil)
+
+	_, err = se.Execute(ctx, "drop database if exists test2")
+	c.Assert(err, IsNil)
+	_, err = se.Execute(ctx, "create database test2")
+	c.Assert(err, IsNil)
+	_, err = se.Execute(ctx, "use test2")
+	c.Assert(err, IsNil)
+
+	var input []string
+	var output []struct {
+		SQL  string
+		Plan string
+	}
+	is := domain.GetDomain(se).InfoSchema()
+	s.testData.GetTestCases(c, &input, &output)
+	for i, tt := range input {
+		comment := Commentf("case:%v sql: %s", i, tt)
+		stmt, err := s.ParseOneStmt(tt, "", "")
+		c.Assert(err, IsNil, comment)
+		p, _, err := planner.Optimize(ctx, se, stmt, is)
+		c.Assert(err, IsNil, comment)
+		s.testData.OnRecord(func() {
+			output[i].SQL = tt
+			output[i].Plan = core.ToString(p)
+		})
+		c.Assert(core.ToString(p), Equals, output[i].Plan, comment)
+	}
+}
diff --git a/planner/core/testdata/plan_suite_in.json b/planner/core/testdata/plan_suite_in.json
index 46b68f86f9986..c4a4acc6f37fd 100644
--- a/planner/core/testdata/plan_suite_in.json
+++ b/planner/core/testdata/plan_suite_in.json
@@ -569,5 +569,11 @@
       "select /*+ INL_HASH_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;",
       "select /*+ INL_MERGE_JOIN(t1) */ t1.b, t2.b from t1 inner join t2 on t1.a = t2.a;"
     ]
+  },
+  {
+    "name": "TestHintFromDiffDatabase",
+    "cases": [
+      "select /*+ inl_hash_join(test.t1) */ * from test.t2 join test.t1 on test.t2.a = test.t1.a"
+    ]
   }
 ]
diff --git a/planner/core/testdata/plan_suite_out.json b/planner/core/testdata/plan_suite_out.json
index 748eed8b65186..6ba675d4faf10 100644
--- a/planner/core/testdata/plan_suite_out.json
+++ b/planner/core/testdata/plan_suite_out.json
@@ -1661,5 +1661,14 @@
         "Hints": "USE_INDEX(@`sel_1` `test`.`t1` `idx_a`), USE_INDEX(@`sel_1` `test`.`t2` )"
       }
     ]
+  },
+  {
+    "Name": "TestHintFromDiffDatabase",
+    "Cases": [
+      {
+        "SQL": "select /*+ inl_hash_join(test.t1) */ * from test.t2 join test.t1 on test.t2.a = test.t1.a",
+        "Plan": "IndexHashJoin{IndexReader(Index(t2.idx_a)[[-inf,+inf]])->IndexReader(Index(t1.idx_a)[[NULL,+inf]]->Sel([not(isnull(test.t1.a))]))}(test.t2.a,test.t1.a)"
+      }
+    ]
   }
 ]