github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/stats/json.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 stats 12 13 import ( 14 fmt "fmt" 15 16 "github.com/cockroachdb/cockroach/pkg/sql/parser" 17 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 18 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 19 "github.com/cockroachdb/cockroach/pkg/sql/types" 20 "github.com/cockroachdb/cockroach/pkg/util/encoding" 21 "github.com/cockroachdb/cockroach/pkg/util/protoutil" 22 ) 23 24 // JSONStatistic is a struct used for JSON marshaling and unmarshaling statistics. 25 // 26 // See TableStatistic for a description of the fields. 27 type JSONStatistic struct { 28 Name string `json:"name,omitempty"` 29 CreatedAt string `json:"created_at"` 30 Columns []string `json:"columns"` 31 RowCount uint64 `json:"row_count"` 32 DistinctCount uint64 `json:"distinct_count"` 33 NullCount uint64 `json:"null_count"` 34 // HistogramColumnType is the string representation of the column type for the 35 // histogram (or unset if there is no histogram). Parsable with 36 // tree.ParseType. 37 HistogramColumnType string `json:"histo_col_type"` 38 HistogramBuckets []JSONHistoBucket `json:"histo_buckets,omitempty"` 39 } 40 41 // JSONHistoBucket is a struct used for JSON marshaling and unmarshaling of 42 // histogram data. 43 // 44 // See HistogramData for a description of the fields. 45 type JSONHistoBucket struct { 46 NumEq int64 `json:"num_eq"` 47 NumRange int64 `json:"num_range"` 48 DistinctRange float64 `json:"distinct_range"` 49 // UpperBound is the string representation of a datum; parsable with 50 // sqlbase.ParseDatumStringAs. 51 UpperBound string `json:"upper_bound"` 52 } 53 54 // SetHistogram fills in the HistogramColumnType and HistogramBuckets fields. 55 func (js *JSONStatistic) SetHistogram(h *HistogramData) error { 56 typ := h.ColumnType 57 js.HistogramColumnType = typ.SQLString() 58 js.HistogramBuckets = make([]JSONHistoBucket, len(h.Buckets)) 59 var a sqlbase.DatumAlloc 60 for i := range h.Buckets { 61 b := &h.Buckets[i] 62 js.HistogramBuckets[i].NumEq = b.NumEq 63 js.HistogramBuckets[i].NumRange = b.NumRange 64 js.HistogramBuckets[i].DistinctRange = b.DistinctRange 65 66 datum, _, err := sqlbase.DecodeTableKey(&a, typ, b.UpperBound, encoding.Ascending) 67 if err != nil { 68 return err 69 } 70 71 js.HistogramBuckets[i] = JSONHistoBucket{ 72 NumEq: b.NumEq, 73 NumRange: b.NumRange, 74 DistinctRange: b.DistinctRange, 75 UpperBound: tree.AsStringWithFlags(datum, tree.FmtExport), 76 } 77 } 78 return nil 79 } 80 81 // DecodeAndSetHistogram decodes a histogram marshaled as a Bytes datum and 82 // fills in the HistogramColumnType and HistogramBuckets fields. 83 func (js *JSONStatistic) DecodeAndSetHistogram(datum tree.Datum) error { 84 if datum == tree.DNull { 85 return nil 86 } 87 if datum.ResolvedType().Family() != types.BytesFamily { 88 return fmt.Errorf("histogram datum type should be Bytes") 89 } 90 h := &HistogramData{} 91 if err := protoutil.Unmarshal([]byte(*datum.(*tree.DBytes)), h); err != nil { 92 return err 93 } 94 return js.SetHistogram(h) 95 } 96 97 // GetHistogram converts the json histogram into HistogramData. 98 func (js *JSONStatistic) GetHistogram( 99 semaCtx *tree.SemaContext, evalCtx *tree.EvalContext, 100 ) (*HistogramData, error) { 101 if len(js.HistogramBuckets) == 0 { 102 return nil, nil 103 } 104 h := &HistogramData{} 105 colTypeRef, err := parser.ParseType(js.HistogramColumnType) 106 if err != nil { 107 return nil, err 108 } 109 colType, err := tree.ResolveType(evalCtx.Context, colTypeRef, semaCtx.GetTypeResolver()) 110 if err != nil { 111 return nil, err 112 } 113 h.ColumnType = colType 114 h.Buckets = make([]HistogramData_Bucket, len(js.HistogramBuckets)) 115 for i := range h.Buckets { 116 hb := &js.HistogramBuckets[i] 117 upperVal, err := sqlbase.ParseDatumStringAs(colType, hb.UpperBound, evalCtx) 118 if err != nil { 119 return nil, err 120 } 121 h.Buckets[i].NumEq = hb.NumEq 122 h.Buckets[i].NumRange = hb.NumRange 123 h.Buckets[i].DistinctRange = hb.DistinctRange 124 h.Buckets[i].UpperBound, err = sqlbase.EncodeTableKey(nil, upperVal, encoding.Ascending) 125 if err != nil { 126 return nil, err 127 } 128 } 129 return h, nil 130 }