github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/util/json/encode.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 json
    12  
    13  import (
    14  	"github.com/cockroachdb/apd/v3"
    15  	"github.com/cockroachdb/cockroachdb-parser/pkg/util/encoding"
    16  	"github.com/cockroachdb/errors"
    17  )
    18  
    19  // This file implements the format described in the JSONB encoding RFC.
    20  
    21  const offlenStride = 32
    22  
    23  const arrayContainerTag = 0x80000000
    24  const objectContainerTag = 0x40000000
    25  const scalarContainerTag = 0x20000000
    26  
    27  const containerHeaderTypeMask = 0xE0000000
    28  const containerHeaderLenMask = 0x1FFFFFFF
    29  
    30  const maxByteLength = int(jEntryOffLenMask)
    31  
    32  const containerHeaderLen = 4
    33  const jEntryLen = 4
    34  
    35  // checkLength ensures that an encoded value is not too long to fit into the
    36  // JEntry header. This should never come up, since it would require a ~250MB
    37  // JSON value, but check it just to be safe.
    38  func checkLength(length int) error {
    39  	if length > maxByteLength {
    40  		return errors.Newf("JSON value too large: %d bytes", errors.Safe(length))
    41  	}
    42  	return nil
    43  }
    44  
    45  // Note: the encoding of each of null, true, and false are the encoding of length 0.
    46  // Their values are purely dictated by their type.
    47  func (jsonNull) encode(appendTo []byte) (e jEntry, b []byte, err error) {
    48  	return nullJEntry, appendTo, nil
    49  }
    50  
    51  func (jsonTrue) encode(appendTo []byte) (e jEntry, b []byte, err error) {
    52  	return trueJEntry, appendTo, nil
    53  }
    54  
    55  func (jsonFalse) encode(appendTo []byte) (e jEntry, b []byte, err error) {
    56  	return falseJEntry, appendTo, nil
    57  }
    58  
    59  func (j jsonString) encode(appendTo []byte) (e jEntry, b []byte, err error) {
    60  	if err := checkLength(len(j)); err != nil {
    61  		return jEntry{}, b, err
    62  	}
    63  	return makeStringJEntry(len(j)), append(appendTo, []byte(j)...), nil
    64  }
    65  
    66  func (j jsonNumber) encode(appendTo []byte) (e jEntry, b []byte, err error) {
    67  	decOffset := len(appendTo)
    68  	dec := apd.Decimal(j)
    69  	appendTo = encoding.EncodeUntaggedDecimalValue(appendTo, &dec)
    70  	lengthInBytes := len(appendTo) - decOffset
    71  	if err := checkLength(lengthInBytes); err != nil {
    72  		return jEntry{}, b, err
    73  	}
    74  	return makeNumberJEntry(lengthInBytes), appendTo, nil
    75  }
    76  
    77  // encodingModeForIdx determines which encoding mode we choose to use for a
    78  // given i-th entry in an array or object.
    79  func encodingModeForIdx(i int, offset uint32) encodingMode {
    80  	if i%offlenStride == 0 {
    81  		return offsetEncode(offset)
    82  	}
    83  	return lengthMode
    84  }
    85  
    86  func (j jsonArray) encode(appendTo []byte) (e jEntry, b []byte, err error) {
    87  	encodingStartPosition := len(appendTo)
    88  	// Array container header.
    89  	appendTo = encoding.EncodeUint32Ascending(appendTo, arrayContainerTag|uint32(len(j)))
    90  	// Reserve space for the JEntries and store where they start so we can fill them in later.
    91  	jEntryIdx := len(appendTo)
    92  	for i := 0; i < len(j); i++ {
    93  		appendTo = append(appendTo, 0, 0, 0, 0)
    94  	}
    95  	offset := uint32(0)
    96  	for i := 0; i < len(j); i++ {
    97  		var nextJEntry jEntry
    98  		nextJEntry, appendTo, err = j[i].encode(appendTo)
    99  		if err != nil {
   100  			return jEntry{}, appendTo, err
   101  		}
   102  
   103  		length := nextJEntry.length
   104  		offset += length
   105  
   106  		appendTo = encoding.PutUint32Ascending(appendTo, nextJEntry.encoded(encodingModeForIdx(i, offset)), jEntryIdx+i*4)
   107  	}
   108  	lengthInBytes := len(appendTo) - encodingStartPosition
   109  	if err := checkLength(lengthInBytes); err != nil {
   110  		return jEntry{}, b, err
   111  	}
   112  	return makeContainerJEntry(lengthInBytes), appendTo, nil
   113  }
   114  
   115  func (j jsonObject) encode(appendTo []byte) (e jEntry, b []byte, err error) {
   116  	encodingStartPosition := len(appendTo)
   117  	// Object container header.
   118  	appendTo = encoding.EncodeUint32Ascending(appendTo, objectContainerTag|uint32(len(j)))
   119  	// Reserve space for the key and value JEntries and store where they start so
   120  	// we can fill them in later.
   121  	jEntryIdx := len(appendTo)
   122  	for i := 0; i < len(j)*2; i++ {
   123  		appendTo = append(appendTo, 0, 0, 0, 0)
   124  	}
   125  	offset := uint32(0)
   126  	// Encode all keys.
   127  	for i := 0; i < len(j); i++ {
   128  		var nextJEntry jEntry
   129  		nextJEntry, appendTo, err = j[i].k.encode(appendTo)
   130  		if err != nil {
   131  			return jEntry{}, appendTo, err
   132  		}
   133  
   134  		length := nextJEntry.length
   135  		offset += length
   136  
   137  		appendTo = encoding.PutUint32Ascending(appendTo, nextJEntry.encoded(encodingModeForIdx(i, offset)), jEntryIdx+i*4)
   138  	}
   139  	// Encode all values.
   140  	for i := 0; i < len(j); i++ {
   141  		var nextJEntry jEntry
   142  		nextJEntry, appendTo, err = j[i].v.encode(appendTo)
   143  		if err != nil {
   144  			return jEntry{}, appendTo, err
   145  		}
   146  
   147  		length := nextJEntry.length
   148  		offset += length
   149  
   150  		appendTo = encoding.PutUint32Ascending(appendTo, nextJEntry.encoded(encodingModeForIdx(i, offset)), jEntryIdx+(len(j)+i)*4)
   151  	}
   152  	lengthInBytes := len(appendTo) - encodingStartPosition
   153  	if err := checkLength(lengthInBytes); err != nil {
   154  		return jEntry{}, b, err
   155  	}
   156  	return makeContainerJEntry(lengthInBytes), appendTo, nil
   157  }
   158  
   159  // EncodeJSON encodes a JSON value as a sequence of bytes.
   160  func EncodeJSON(appendTo []byte, j JSON) ([]byte, error) {
   161  	switch j.Type() {
   162  	case ArrayJSONType, ObjectJSONType:
   163  		// We just discard the JEntry in these cases.
   164  		var err error
   165  		_, appendTo, err = j.encode(appendTo)
   166  		if err != nil {
   167  			return appendTo, err
   168  		}
   169  		return appendTo, nil
   170  	default: // j is a scalar, so we must construct a scalar container for it at the top level.
   171  		// Scalar container header.
   172  		appendTo = encoding.EncodeUint32Ascending(appendTo, scalarContainerTag)
   173  		// Reserve space for scalar jEntry.
   174  		jEntryIdx := len(appendTo)
   175  		appendTo = encoding.EncodeUint32Ascending(appendTo, 0)
   176  		var entry jEntry
   177  		var err error
   178  		entry, appendTo, err = j.encode(appendTo)
   179  		if err != nil {
   180  			return appendTo, err
   181  		}
   182  		appendTo = encoding.PutUint32Ascending(appendTo, entry.encoded(lengthMode), jEntryIdx)
   183  		return appendTo, nil
   184  	}
   185  }
   186  
   187  // DecodeJSON decodes a value encoded with EncodeJSON.
   188  func DecodeJSON(b []byte) ([]byte, JSON, error) {
   189  	b, containerHeader, err := encoding.DecodeUint32Ascending(b)
   190  	if err != nil {
   191  		return b, nil, err
   192  	}
   193  	switch containerHeader & containerHeaderTypeMask {
   194  	case scalarContainerTag:
   195  		var entry jEntry
   196  		var err error
   197  		b, entry, err = decodeJEntry(b, 0)
   198  		if err != nil {
   199  			return b, nil, err
   200  		}
   201  		return decodeJSONValue(entry, b)
   202  	case arrayContainerTag:
   203  		return decodeJSONArray(containerHeader, b)
   204  	case objectContainerTag:
   205  		return decodeJSONObject(containerHeader, b)
   206  	}
   207  	return b, nil, errors.AssertionFailedf(
   208  		"error decoding JSON value, header: %x", errors.Safe(containerHeader))
   209  }
   210  
   211  // FromEncoding returns a JSON value which is lazily decoded.
   212  func FromEncoding(b []byte) (JSON, error) {
   213  	return newEncodedFromRoot(b)
   214  }
   215  
   216  func decodeJSONArray(containerHeader uint32, b []byte) ([]byte, JSON, error) {
   217  	length := containerHeader & containerHeaderLenMask
   218  	b, jEntries, err := decodeJEntries(int(length), b)
   219  	if err != nil {
   220  		return b, nil, err
   221  	}
   222  	result := make(jsonArray, length)
   223  	for i := uint32(0); i < length; i++ {
   224  		var nextJSON JSON
   225  		b, nextJSON, err = decodeJSONValue(jEntries[i], b)
   226  		if err != nil {
   227  			return b, nil, err
   228  		}
   229  		result[i] = nextJSON
   230  	}
   231  	return b, result, nil
   232  }
   233  
   234  func decodeJEntries(n int, b []byte) ([]byte, []jEntry, error) {
   235  	var err error
   236  	jEntries := make([]jEntry, n)
   237  	off := uint32(0)
   238  	for i := 0; i < n; i++ {
   239  		var nextJEntry jEntry
   240  		b, nextJEntry, err = decodeJEntry(b, off)
   241  		if err != nil {
   242  			return b, nil, err
   243  		}
   244  		off += nextJEntry.length
   245  		jEntries[i] = nextJEntry
   246  	}
   247  	return b, jEntries, nil
   248  }
   249  
   250  func decodeJSONObject(containerHeader uint32, b []byte) ([]byte, JSON, error) {
   251  	length := int(containerHeader & containerHeaderLenMask)
   252  
   253  	b, jEntries, err := decodeJEntries(length*2, b)
   254  	if err != nil {
   255  		return b, nil, err
   256  	}
   257  
   258  	// There are `length` key entries at the start and `length` value entries at the back.
   259  	keyJEntries := jEntries[:length]
   260  	valueJEntries := jEntries[length:]
   261  
   262  	result := make(jsonObject, length)
   263  	// Decode the keys.
   264  	for i := 0; i < length; i++ {
   265  		var nextJSON JSON
   266  		b, nextJSON, err = decodeJSONValue(keyJEntries[i], b)
   267  		if err != nil {
   268  			return b, nil, err
   269  		}
   270  		if key, ok := nextJSON.(jsonString); ok {
   271  			result[i].k = key
   272  		} else {
   273  			return b, nil, errors.AssertionFailedf(
   274  				"key encoded as non-string: %T", nextJSON)
   275  		}
   276  	}
   277  
   278  	// Decode the values.
   279  	for i := 0; i < length; i++ {
   280  		var nextJSON JSON
   281  		b, nextJSON, err = decodeJSONValue(valueJEntries[i], b)
   282  		if err != nil {
   283  			return b, nil, err
   284  		}
   285  		result[i].v = nextJSON
   286  	}
   287  	return b, result, nil
   288  }
   289  
   290  func decodeJSONNumber(b []byte) ([]byte, JSON, error) {
   291  	b, d, err := encoding.DecodeUntaggedDecimalValue(b)
   292  	if err != nil {
   293  		return b, nil, err
   294  	}
   295  	return b, jsonNumber(d), nil
   296  }
   297  
   298  func decodeJSONValue(e jEntry, b []byte) ([]byte, JSON, error) {
   299  	switch e.typCode {
   300  	case trueTag:
   301  		return b, TrueJSONValue, nil
   302  	case falseTag:
   303  		return b, FalseJSONValue, nil
   304  	case nullTag:
   305  		return b, NullJSONValue, nil
   306  	case stringTag:
   307  		return b[e.length:], jsonString(b[:e.length]), nil
   308  	case numberTag:
   309  		return decodeJSONNumber(b)
   310  	case containerTag:
   311  		return DecodeJSON(b)
   312  	}
   313  	return b, nil, errors.AssertionFailedf(
   314  		"error decoding JSON value, unexpected type code: %d", errors.Safe(e.typCode))
   315  }