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 }