github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/show_histogram.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package sql 12 13 import ( 14 "context" 15 "fmt" 16 17 "github.com/cockroachdb/cockroach/pkg/security" 18 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 19 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 20 "github.com/cockroachdb/cockroach/pkg/sql/stats" 21 "github.com/cockroachdb/cockroach/pkg/sql/types" 22 "github.com/cockroachdb/cockroach/pkg/util/protoutil" 23 "github.com/cockroachdb/errors" 24 ) 25 26 // Ideally, we would want upper_bound to have the type of the column the 27 // histogram is on. However, we don't want to have a SHOW statement for which 28 // the schema depends on its parameters. 29 var showHistogramColumns = sqlbase.ResultColumns{ 30 {Name: "upper_bound", Typ: types.String}, 31 {Name: "range_rows", Typ: types.Int}, 32 {Name: "distinct_range_rows", Typ: types.Float}, 33 {Name: "equal_rows", Typ: types.Int}, 34 } 35 36 // ShowHistogram returns a SHOW HISTOGRAM statement. 37 // Privileges: Any privilege on the respective table. 38 func (p *planner) ShowHistogram(ctx context.Context, n *tree.ShowHistogram) (planNode, error) { 39 return &delayedNode{ 40 name: fmt.Sprintf("SHOW HISTOGRAM %d", n.HistogramID), 41 columns: showHistogramColumns, 42 43 constructor: func(ctx context.Context, p *planner) (planNode, error) { 44 row, err := p.ExtendedEvalContext().ExecCfg.InternalExecutor.QueryRowEx( 45 ctx, 46 "read-histogram", 47 p.txn, 48 sqlbase.InternalExecutorSessionDataOverride{User: security.RootUser}, 49 `SELECT histogram 50 FROM system.table_statistics 51 WHERE "statisticID" = $1`, 52 n.HistogramID, 53 ) 54 if err != nil { 55 return nil, err 56 } 57 if row == nil { 58 return nil, fmt.Errorf("histogram %d not found", n.HistogramID) 59 } 60 if len(row) != 1 { 61 return nil, errors.AssertionFailedf("expected 1 column from internal query") 62 } 63 if row[0] == tree.DNull { 64 // We found a statistic, but it has no histogram. 65 return nil, fmt.Errorf("histogram %d not found", n.HistogramID) 66 } 67 68 histogram := &stats.HistogramData{} 69 histData := *row[0].(*tree.DBytes) 70 if err := protoutil.Unmarshal([]byte(histData), histogram); err != nil { 71 return nil, err 72 } 73 74 v := p.newContainerValuesNode(showHistogramColumns, 0) 75 for _, b := range histogram.Buckets { 76 ed, _, err := sqlbase.EncDatumFromBuffer( 77 histogram.ColumnType, sqlbase.DatumEncoding_ASCENDING_KEY, b.UpperBound, 78 ) 79 if err != nil { 80 v.Close(ctx) 81 return nil, err 82 } 83 row := tree.Datums{ 84 tree.NewDString(ed.String(histogram.ColumnType)), 85 tree.NewDInt(tree.DInt(b.NumRange)), 86 tree.NewDFloat(tree.DFloat(b.DistinctRange)), 87 tree.NewDInt(tree.DInt(b.NumEq)), 88 } 89 if _, err := v.rows.AddRow(ctx, row); err != nil { 90 v.Close(ctx) 91 return nil, err 92 } 93 } 94 return v, nil 95 }, 96 }, nil 97 }