diff --git a/pkg/sql/opt/exec/execbuilder/testdata/explain_gist b/pkg/sql/opt/exec/execbuilder/testdata/explain_gist index 1b6f5422d8b8..7cf69d0e3145 100644 --- a/pkg/sql/opt/exec/execbuilder/testdata/explain_gist +++ b/pkg/sql/opt/exec/execbuilder/testdata/explain_gist @@ -62,3 +62,25 @@ query T SELECT crdb_internal.decode_plan_gist('$gist') ---- • + +# Regression test for #76800 +statement ok +CREATE TABLE t2 (a int, b int, c int, d int, e int) + +let $gist +EXPLAIN (GIST) SELECT * FROM t2 + +# To hit bug requires deleting lots of columns because of hidden columns. +statement ok +ALTER TABLE t2 DROP COLUMN b; +ALTER TABLE t2 DROP COLUMN c; +ALTER TABLE t2 DROP COLUMN a; +ALTER TABLE t2 DROP COLUMN d; +ALTER TABLE t2 DROP COLUMN e + +query T +SELECT crdb_internal.decode_plan_gist('$gist') +---- +• scan + table: t2@t2_pkey + spans: FULL SCAN diff --git a/pkg/sql/opt/exec/explain/result_columns.go b/pkg/sql/opt/exec/explain/result_columns.go index 5c2a15104d3a..8840e0e59969 100644 --- a/pkg/sql/opt/exec/explain/result_columns.go +++ b/pkg/sql/opt/exec/explain/result_columns.go @@ -201,11 +201,15 @@ func getResultColumns( func tableColumns(table cat.Table, ordinals exec.TableColumnOrdinalSet) colinfo.ResultColumns { cols := make(colinfo.ResultColumns, 0, ordinals.Len()) for i, ok := ordinals.Next(0); ok; i, ok = ordinals.Next(i + 1) { - col := table.Column(i) - cols = append(cols, colinfo.ResultColumn{ - Name: string(col.ColName()), - Typ: col.DatumType(), - }) + // Be defensive about bitset values because they may come from cached + // gists and the columns they refer to could have been removed. + if i < table.ColumnCount() { + col := table.Column(i) + cols = append(cols, colinfo.ResultColumn{ + Name: string(col.ColName()), + Typ: col.DatumType(), + }) + } } return cols } diff --git a/pkg/sql/plan_opt.go b/pkg/sql/plan_opt.go index f4f92af94671..a6afc4da3c4b 100644 --- a/pkg/sql/plan_opt.go +++ b/pkg/sql/plan_opt.go @@ -655,8 +655,7 @@ func (opc *optPlanningCtx) runExecBuilder( return nil } -// DecodeGist Avoid an import cycle by keeping the cat out of the tree, RFC: is -// there a better way? +// DecodeGist Avoid an import cycle by keeping the cat out of the tree. func (p *planner) DecodeGist(gist string) ([]string, error) { return explain.DecodePlanGistToRows(gist, &p.optPlanningCtx.catalog) }