Skip to content

Commit

Permalink
planner: fix panic during starting tidb-server if creating global bin…
Browse files Browse the repository at this point in the history
…ding for partition table (#40402) (#40406)

close #40368
  • Loading branch information
ti-chi-bot authored Jan 17, 2023
1 parent 47b5ee4 commit fa7889f
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 23 deletions.
2 changes: 1 addition & 1 deletion executor/analyzetest/analyze_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2935,7 +2935,7 @@ PARTITION BY RANGE ( a ) (
tk.MustQuery("select * from t where a > 1 and b > 1 and c > 1 and d > 1")
require.NoError(t, h.LoadNeededHistograms())
tbl := h.GetTableStats(tableInfo)
require.Equal(t, 4, len(tbl.Columns))
require.Equal(t, 0, len(tbl.Columns))

// ignore both p0's 3 buckets, persisted-partition-options' 1 bucket, just use table-level 2 buckets
tk.MustExec("analyze table t partition p0")
Expand Down
5 changes: 5 additions & 0 deletions planner/core/collect_column_stats_usage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,11 @@ func TestCollectHistNeededColumns(t *testing.T) {
if len(tt.pruneMode) > 0 {
s.ctx.GetSessionVars().PartitionPruneMode.Store(tt.pruneMode)
}
if s.ctx.GetSessionVars().IsDynamicPartitionPruneEnabled() {
s.ctx.GetSessionVars().StmtCtx.UseDynamicPruneMode = true
} else {
s.ctx.GetSessionVars().StmtCtx.UseDynamicPruneMode = false
}
stmt, err := s.p.ParseOneStmt(tt.sql, "", "")
require.NoError(t, err, comment)
err = Preprocess(context.Background(), s.ctx, stmt, WithPreprocessorReturn(&PreprocessorReturn{InfoSchema: s.is}))
Expand Down
36 changes: 36 additions & 0 deletions planner/core/integration_partition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1619,3 +1619,39 @@ func TestPartitionRangeColumnPruning(t *testing.T) {
tk.MustQuery(`select * from t1 where a = 'a' AND c = 'd'`).Check(testkit.Rows("a <nil> d"))
tk.MustExec(`drop table t1`)
}

func TestPartitionProcessorWithUninitializedTable(t *testing.T) {
store := testkit.CreateMockStore(t)
tk := testkit.NewTestKit(t, store)
tk.MustExec("use test")
tk.MustExec(" create table q1(a int, b int, key (a)) partition by range (a) (partition p0 values less than (10), partition p1 values less than (20));")
tk.MustExec(" create table q2(a int, b int, key (a)) partition by range (a) (partition p0 values less than (10), partition p1 values less than (20));")

rows := [][]interface{}{
{"HashJoin"},
{"├─PartitionUnion(Build)"},
{"│ ├─TableReader"},
{"│ │ └─TableFullScan"},
{"│ └─TableReader"},
{"│ └─TableFullScan"},
{"└─PartitionUnion(Probe)"},
{" ├─TableReader"},
{" │ └─TableFullScan"},
{" └─TableReader"},
{" └─TableFullScan"},
}
tk.MustQuery("explain format=brief select * from q1,q2").CheckAt([]int{0}, rows)

tk.MustExec("analyze table q1")
tk.MustQuery("explain format=brief select * from q1,q2").CheckAt([]int{0}, rows)

tk.MustExec("analyze table q2")
rows = [][]interface{}{
{"HashJoin"},
{"├─TableReader(Build)"},
{"│ └─TableFullScan"},
{"└─TableReader(Probe)"},
{" └─TableFullScan"},
}
tk.MustQuery("explain format=brief select * from q1,q2").CheckAt([]int{0}, rows)
}
51 changes: 30 additions & 21 deletions planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -4452,30 +4452,39 @@ func (b *PlanBuilder) buildDataSource(ctx context.Context, tn *ast.TableName, as
}

if tableInfo.GetPartitionInfo() != nil {
h := domain.GetDomain(b.ctx).StatsHandle()
tblStats := h.GetTableStats(tableInfo)
isDynamicEnabled := b.ctx.GetSessionVars().IsDynamicPartitionPruneEnabled()
globalStatsReady := tblStats.IsInitialized()
// If dynamic partition prune isn't enabled or global stats is not ready, we won't enable dynamic prune mode in query
usePartitionProcessor := !isDynamicEnabled || !globalStatsReady

failpoint.Inject("forceDynamicPrune", func(val failpoint.Value) {
if val.(bool) {
if isDynamicEnabled {
usePartitionProcessor = false
}
}
})

if usePartitionProcessor {
// If `UseDynamicPruneMode` already been false, then we don't need to check whether execute `flagPartitionProcessor`
// otherwise we need to check global stats initialized for each partition table
if !b.ctx.GetSessionVars().IsDynamicPartitionPruneEnabled() {
b.optFlag = b.optFlag | flagPartitionProcessor
b.ctx.GetSessionVars().StmtCtx.UseDynamicPruneMode = false
if isDynamicEnabled {
b.ctx.GetSessionVars().StmtCtx.AppendWarning(
fmt.Errorf("disable dynamic pruning due to %s has no global stats", tableInfo.Name.String()))
} else {
if !b.ctx.GetSessionVars().StmtCtx.UseDynamicPruneMode {
b.optFlag = b.optFlag | flagPartitionProcessor
} else {
h := domain.GetDomain(b.ctx).StatsHandle()
tblStats := h.GetTableStats(tableInfo)
isDynamicEnabled := b.ctx.GetSessionVars().IsDynamicPartitionPruneEnabled()
globalStatsReady := tblStats.IsInitialized()
// If dynamic partition prune isn't enabled or global stats is not ready, we won't enable dynamic prune mode in query
usePartitionProcessor := !isDynamicEnabled || !globalStatsReady

failpoint.Inject("forceDynamicPrune", func(val failpoint.Value) {
if val.(bool) {
if isDynamicEnabled {
usePartitionProcessor = false
}
}
})

if usePartitionProcessor {
b.optFlag = b.optFlag | flagPartitionProcessor
b.ctx.GetSessionVars().StmtCtx.UseDynamicPruneMode = false
if isDynamicEnabled {
b.ctx.GetSessionVars().StmtCtx.AppendWarning(
fmt.Errorf("disable dynamic pruning due to %s has no global stats", tableInfo.Name.String()))
}
}
}
}

pt := tbl.(table.PartitionedTable)
// check partition by name.
if len(tn.PartitionNames) > 0 {
Expand Down
7 changes: 6 additions & 1 deletion statistics/handle/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -994,8 +994,13 @@ func (h *Handle) GetTableStats(tblInfo *model.TableInfo, opts ...TableStatsOpt)

// GetPartitionStats retrieves the partition stats from cache.
func (h *Handle) GetPartitionStats(tblInfo *model.TableInfo, pid int64, opts ...TableStatsOpt) *statistics.Table {
statsCache := h.statsCache.Load().(statsCache)
var tbl *statistics.Table
if h == nil {
tbl = statistics.PseudoTable(tblInfo)
tbl.PhysicalID = pid
return tbl
}
statsCache := h.statsCache.Load().(statsCache)
var ok bool
option := &tableStatsOption{}
for _, opt := range opts {
Expand Down

0 comments on commit fa7889f

Please sign in to comment.