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  }