diff --git a/expression/integration_test.go b/expression/integration_test.go index 238e038dcaeaa..88fef13eb6904 100755 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -6558,6 +6558,14 @@ func (s *testIntegrationSuite) TestIssue17727(c *C) { tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1")) } +func (s *testIntegrationSuite) TestIssue18515(c *C) { + tk := testkit.NewTestKit(c, s.store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t") + tk.MustExec("create table t(a int, b json, c int AS (JSON_EXTRACT(b, '$.population')), key(c));") + tk.MustExec("select /*+ TIDB_INLJ(t2) */ t1.a, t1.c, t2.a from t t1, t t2 where t1.c=t2.c;") +} + func (s *testIntegrationSerialSuite) TestIssue17989(c *C) { tk := testkit.NewTestKit(c, s.store) tk.MustExec("use test") diff --git a/planner/core/find_best_task.go b/planner/core/find_best_task.go index b578e92d3a70f..59a0bff0e93b0 100644 --- a/planner/core/find_best_task.go +++ b/planner/core/find_best_task.go @@ -708,7 +708,6 @@ func (ds *DataSource) buildIndexMergeTableScan(prop *property.PhysicalProperty, physicalTableID: ds.physicalTableID, }.Init(ds.ctx, ds.blockOffset) ts.SetSchema(ds.schema.Clone()) - ts.Columns = ExpandVirtualColumn(ts.Columns, ts.schema, ts.Table.Columns) if ts.Table.PKIsHandle { if pkColInfo := ts.Table.GetPkColInfo(); pkColInfo != nil { if ds.statisticTable.Columns[pkColInfo.ID] != nil { @@ -804,7 +803,6 @@ func (ds *DataSource) convertToIndexScan(prop *property.PhysicalProperty, candid physicalTableID: ds.physicalTableID, }.Init(ds.ctx, is.blockOffset) ts.SetSchema(ds.schema.Clone()) - ts.Columns = ExpandVirtualColumn(ts.Columns, ts.schema, ts.Table.Columns) cop.tablePlan = ts } cop.cst = cost diff --git a/planner/core/initialize.go b/planner/core/initialize.go index b7e488a4510a7..116478eb446f9 100644 --- a/planner/core/initialize.go +++ b/planner/core/initialize.go @@ -459,6 +459,14 @@ func (p BatchPointGetPlan) Init(ctx sessionctx.Context, stats *property.StatsInf return &p } +// Init initializes PointGetPlan. +func (p PointGetPlan) Init(ctx sessionctx.Context, stats *property.StatsInfo, offset int, props ...*property.PhysicalProperty) *PointGetPlan { + p.basePlan = newBasePlan(ctx, plancodec.TypePointGet, offset) + p.stats = stats + p.Columns = ExpandVirtualColumn(p.Columns, p.schema, p.TblInfo.Columns) + return &p +} + // flattenPushDownPlan converts a plan tree to a list, whose head is the leaf node like table scan. func flattenPushDownPlan(p PhysicalPlan) []PhysicalPlan { plans := make([]PhysicalPlan, 0, 5) diff --git a/planner/core/physical_plans.go b/planner/core/physical_plans.go index 00697ddd628e7..3b4c7e9d99cd3 100644 --- a/planner/core/physical_plans.go +++ b/planner/core/physical_plans.go @@ -263,6 +263,16 @@ func (ts *PhysicalTableScan) IsPartition() (bool, int64) { // ExpandVirtualColumn expands the virtual column's dependent columns to ts's schema and column. func ExpandVirtualColumn(columns []*model.ColumnInfo, schema *expression.Schema, colsInfo []*model.ColumnInfo) []*model.ColumnInfo { + copyColumn := make([]*model.ColumnInfo, len(columns)) + copy(copyColumn, columns) + var extraColumn *expression.Column + var extraColumnModel *model.ColumnInfo + if schema.Columns[len(schema.Columns)-1].ID == model.ExtraHandleID { + extraColumn = schema.Columns[len(schema.Columns)-1] + extraColumnModel = copyColumn[len(copyColumn)-1] + schema.Columns = schema.Columns[:len(schema.Columns)-1] + copyColumn = copyColumn[:len(copyColumn)-1] + } schemaColumns := schema.Columns for _, col := range schemaColumns { if col.VirtualExpr == nil { @@ -273,11 +283,15 @@ func ExpandVirtualColumn(columns []*model.ColumnInfo, schema *expression.Schema, for _, baseCol := range baseCols { if !schema.Contains(baseCol) { schema.Columns = append(schema.Columns, baseCol) - columns = append(columns, FindColumnInfoByID(colsInfo, baseCol.ID)) + copyColumn = append(copyColumn, FindColumnInfoByID(colsInfo, baseCol.ID)) } } } - return columns + if extraColumn != nil { + schema.Columns = append(schema.Columns, extraColumn) + copyColumn = append(copyColumn, extraColumnModel) + } + return copyColumn } //SetIsChildOfIndexLookUp is to set the bool if is a child of IndexLookUpReader diff --git a/planner/core/point_get_plan.go b/planner/core/point_get_plan.go index a537f46eb342b..a65c8f14f6fad 100644 --- a/planner/core/point_get_plan.go +++ b/planner/core/point_get_plan.go @@ -73,14 +73,6 @@ type nameValuePair struct { param *driver.ParamMarkerExpr } -// Init initializes PointGetPlan. -func (p PointGetPlan) Init(ctx sessionctx.Context, stats *property.StatsInfo, offset int, props ...*property.PhysicalProperty) *PointGetPlan { - p.basePlan = newBasePlan(ctx, plancodec.TypePointGet, offset) - p.stats = stats - p.Columns = ExpandVirtualColumn(p.Columns, p.schema, p.TblInfo.Columns) - return &p -} - // Schema implements the Plan interface. func (p *PointGetPlan) Schema() *expression.Schema { return p.schema diff --git a/planner/core/task.go b/planner/core/task.go index b38bc98de3d78..975314d905e0e 100644 --- a/planner/core/task.go +++ b/planner/core/task.go @@ -648,6 +648,13 @@ func finishCopTask(ctx sessionctx.Context, task task) task { // Network cost of transferring rows of table scan to TiDB. if t.tablePlan != nil { t.cst += t.count() * sessVars.NetworkFactor * t.tblColHists.GetAvgRowSize(ctx, t.tablePlan.Schema().Columns, false, false) + + tp := t.tablePlan + for len(tp.Children()) > 0 { + tp = tp.Children()[0] + } + ts := tp.(*PhysicalTableScan) + ts.Columns = ExpandVirtualColumn(ts.Columns, ts.schema, ts.Table.Columns) } t.cst /= copIterWorkers newTask := &rootTask{ @@ -676,7 +683,6 @@ func finishCopTask(ctx sessionctx.Context, task task) task { StoreType: ts.StoreType, }.Init(ctx, t.tablePlan.SelectBlockOffset()) p.stats = t.tablePlan.statsInfo() - ts.Columns = ExpandVirtualColumn(ts.Columns, ts.schema, ts.Table.Columns) newTask.p = p }