github.com/XiaoMi/Gaea@v1.2.5/parser/tidb-types/json/binary_functions.go (about) 1 // Copyright 2017 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package json 15 16 import ( 17 "bytes" 18 "encoding/binary" 19 "encoding/hex" 20 "fmt" 21 "sort" 22 "strconv" 23 "unicode/utf8" 24 "unsafe" 25 26 "github.com/pingcap/errors" 27 28 "github.com/XiaoMi/Gaea/util/hack" 29 ) 30 31 // Type returns type of BinaryJSON as string. 32 func (bj BinaryJSON) Type() string { 33 switch bj.TypeCode { 34 case TypeCodeObject: 35 return "OBJECT" 36 case TypeCodeArray: 37 return "ARRAY" 38 case TypeCodeLiteral: 39 switch bj.Value[0] { 40 case LiteralNil: 41 return "NULL" 42 default: 43 return "BOOLEAN" 44 } 45 case TypeCodeInt64: 46 return "INTEGER" 47 case TypeCodeUint64: 48 return "UNSIGNED INTEGER" 49 case TypeCodeFloat64: 50 return "DOUBLE" 51 case TypeCodeString: 52 return "STRING" 53 default: 54 msg := fmt.Sprintf(unknownTypeCodeErrorMsg, bj.TypeCode) 55 panic(msg) 56 } 57 } 58 59 // Quote is for JSON_QUOTE 60 func (bj BinaryJSON) Quote() string { 61 str := hack.String(bj.GetString()) 62 return strconv.Quote(string(str)) 63 } 64 65 // Unquote is for JSON_UNQUOTE. 66 func (bj BinaryJSON) Unquote() (string, error) { 67 switch bj.TypeCode { 68 case TypeCodeString: 69 tmp := string(hack.String(bj.GetString())) 70 s, err := unquoteString(tmp) 71 if err != nil { 72 return "", errors.Trace(err) 73 } 74 // Remove prefix and suffix '"'. 75 slen := len(s) 76 if slen > 1 { 77 head, tail := s[0], s[slen-1] 78 if head == '"' && tail == '"' { 79 return s[1 : slen-1], nil 80 } 81 } 82 return s, nil 83 default: 84 return bj.String(), nil 85 } 86 } 87 88 // unquoteString recognizes the escape sequences shown in: 89 // https://dev.mysql.com/doc/refman/5.7/en/json-modification-functions.html#json-unquote-character-escape-sequences 90 func unquoteString(s string) (string, error) { 91 ret := new(bytes.Buffer) 92 for i := 0; i < len(s); i++ { 93 if s[i] == '\\' { 94 i++ 95 if i == len(s) { 96 return "", errors.New("Missing a closing quotation mark in string") 97 } 98 switch s[i] { 99 case '"': 100 ret.WriteByte('"') 101 case 'b': 102 ret.WriteByte('\b') 103 case 'f': 104 ret.WriteByte('\f') 105 case 'n': 106 ret.WriteByte('\n') 107 case 'r': 108 ret.WriteByte('\r') 109 case 't': 110 ret.WriteByte('\t') 111 case '\\': 112 ret.WriteByte('\\') 113 case 'u': 114 if i+4 > len(s) { 115 return "", errors.Errorf("Invalid unicode: %s", s[i+1:]) 116 } 117 char, size, err := decodeEscapedUnicode(hack.Slice(s[i+1 : i+5])) 118 if err != nil { 119 return "", errors.Trace(err) 120 } 121 ret.Write(char[0:size]) 122 i += 4 123 default: 124 // For all other escape sequences, backslash is ignored. 125 ret.WriteByte(s[i]) 126 } 127 } else { 128 ret.WriteByte(s[i]) 129 } 130 } 131 return ret.String(), nil 132 } 133 134 // decodeEscapedUnicode decodes unicode into utf8 bytes specified in RFC 3629. 135 // According RFC 3629, the max length of utf8 characters is 4 bytes. 136 // And MySQL use 4 bytes to represent the unicode which must be in [0, 65536). 137 func decodeEscapedUnicode(s []byte) (char [4]byte, size int, err error) { 138 size, err = hex.Decode(char[0:2], s) 139 if err != nil || size != 2 { 140 // The unicode must can be represented in 2 bytes. 141 return char, 0, errors.Trace(err) 142 } 143 var unicode uint16 144 err = binary.Read(bytes.NewReader(char[0:2]), binary.BigEndian, &unicode) 145 if err != nil { 146 return char, 0, errors.Trace(err) 147 } 148 size = utf8.RuneLen(rune(unicode)) 149 utf8.EncodeRune(char[0:size], rune(unicode)) 150 return 151 } 152 153 // Extract receives several path expressions as arguments, matches them in bj, and returns: 154 // ret: target JSON matched any path expressions. maybe autowrapped as an array. 155 // found: true if any path expressions matched. 156 func (bj BinaryJSON) Extract(pathExprList []PathExpression) (ret BinaryJSON, found bool) { 157 buf := make([]BinaryJSON, 0, 1) 158 for _, pathExpr := range pathExprList { 159 buf = bj.extractTo(buf, pathExpr) 160 } 161 if len(buf) == 0 { 162 found = false 163 } else if len(pathExprList) == 1 && len(buf) == 1 { 164 // If pathExpr contains asterisks, len(elemList) won't be 1 165 // even if len(pathExprList) equals to 1. 166 found = true 167 ret = buf[0] 168 } else { 169 found = true 170 ret = buildBinaryArray(buf) 171 } 172 return 173 } 174 175 func (bj BinaryJSON) extractTo(buf []BinaryJSON, pathExpr PathExpression) []BinaryJSON { 176 if len(pathExpr.legs) == 0 { 177 return append(buf, bj) 178 } 179 currentLeg, subPathExpr := pathExpr.popOneLeg() 180 if currentLeg.typ == pathLegIndex { 181 if bj.TypeCode != TypeCodeArray { 182 if currentLeg.arrayIndex <= 0 && currentLeg.arrayIndex != arrayIndexAsterisk { 183 buf = bj.extractTo(buf, subPathExpr) 184 } 185 return buf 186 } 187 elemCount := bj.GetElemCount() 188 if currentLeg.arrayIndex == arrayIndexAsterisk { 189 for i := 0; i < elemCount; i++ { 190 buf = bj.arrayGetElem(i).extractTo(buf, subPathExpr) 191 } 192 } else if currentLeg.arrayIndex < elemCount { 193 buf = bj.arrayGetElem(currentLeg.arrayIndex).extractTo(buf, subPathExpr) 194 } 195 } else if currentLeg.typ == pathLegKey && bj.TypeCode == TypeCodeObject { 196 elemCount := bj.GetElemCount() 197 if currentLeg.dotKey == "*" { 198 for i := 0; i < elemCount; i++ { 199 buf = bj.objectGetVal(i).extractTo(buf, subPathExpr) 200 } 201 } else { 202 child, ok := bj.objectSearchKey(hack.Slice(currentLeg.dotKey)) 203 if ok { 204 buf = child.extractTo(buf, subPathExpr) 205 } 206 } 207 } else if currentLeg.typ == pathLegDoubleAsterisk { 208 buf = bj.extractTo(buf, subPathExpr) 209 if bj.TypeCode == TypeCodeArray { 210 elemCount := bj.GetElemCount() 211 for i := 0; i < elemCount; i++ { 212 buf = bj.arrayGetElem(i).extractTo(buf, pathExpr) 213 } 214 } else if bj.TypeCode == TypeCodeObject { 215 elemCount := bj.GetElemCount() 216 for i := 0; i < elemCount; i++ { 217 buf = bj.objectGetVal(i).extractTo(buf, pathExpr) 218 } 219 } 220 } 221 return buf 222 } 223 224 func (bj BinaryJSON) objectSearchKey(key []byte) (BinaryJSON, bool) { 225 elemCount := bj.GetElemCount() 226 idx := sort.Search(elemCount, func(i int) bool { 227 return bytes.Compare(bj.objectGetKey(i), key) >= 0 228 }) 229 if idx < elemCount && bytes.Equal(bj.objectGetKey(idx), key) { 230 return bj.objectGetVal(idx), true 231 } 232 return BinaryJSON{}, false 233 } 234 235 func buildBinaryArray(elems []BinaryJSON) BinaryJSON { 236 totalSize := headerSize + len(elems)*valEntrySize 237 for _, elem := range elems { 238 if elem.TypeCode != TypeCodeLiteral { 239 totalSize += len(elem.Value) 240 } 241 } 242 buf := make([]byte, headerSize+len(elems)*valEntrySize, totalSize) 243 endian.PutUint32(buf, uint32(len(elems))) 244 endian.PutUint32(buf[dataSizeOff:], uint32(totalSize)) 245 buf = buildBinaryElements(buf, headerSize, elems) 246 return BinaryJSON{TypeCode: TypeCodeArray, Value: buf} 247 } 248 249 func buildBinaryElements(buf []byte, entryStart int, elems []BinaryJSON) []byte { 250 for i, elem := range elems { 251 buf[entryStart+i*valEntrySize] = elem.TypeCode 252 if elem.TypeCode == TypeCodeLiteral { 253 buf[entryStart+i*valEntrySize+valTypeSize] = elem.Value[0] 254 } else { 255 endian.PutUint32(buf[entryStart+i*valEntrySize+valTypeSize:], uint32(len(buf))) 256 buf = append(buf, elem.Value...) 257 } 258 } 259 return buf 260 } 261 262 func buildBinaryObject(keys [][]byte, elems []BinaryJSON) BinaryJSON { 263 totalSize := headerSize + len(elems)*(keyEntrySize+valEntrySize) 264 for i, elem := range elems { 265 if elem.TypeCode != TypeCodeLiteral { 266 totalSize += len(elem.Value) 267 } 268 totalSize += len(keys[i]) 269 } 270 buf := make([]byte, headerSize+len(elems)*(keyEntrySize+valEntrySize), totalSize) 271 endian.PutUint32(buf, uint32(len(elems))) 272 endian.PutUint32(buf[dataSizeOff:], uint32(totalSize)) 273 for i, key := range keys { 274 endian.PutUint32(buf[headerSize+i*keyEntrySize:], uint32(len(buf))) 275 endian.PutUint16(buf[headerSize+i*keyEntrySize+keyLenOff:], uint16(len(key))) 276 buf = append(buf, key...) 277 } 278 entryStart := headerSize + len(elems)*keyEntrySize 279 buf = buildBinaryElements(buf, entryStart, elems) 280 return BinaryJSON{TypeCode: TypeCodeObject, Value: buf} 281 } 282 283 // Modify modifies a JSON object by insert, replace or set. 284 // All path expressions cannot contain * or ** wildcard. 285 // If any error occurs, the input won't be changed. 286 func (bj BinaryJSON) Modify(pathExprList []PathExpression, values []BinaryJSON, mt ModifyType) (retj BinaryJSON, err error) { 287 if len(pathExprList) != len(values) { 288 // TODO: should return 1582(42000) 289 return retj, errors.New("Incorrect parameter count") 290 } 291 for _, pathExpr := range pathExprList { 292 if pathExpr.flags.containsAnyAsterisk() { 293 // TODO: should return 3149(42000) 294 return retj, errors.New("Invalid path expression") 295 } 296 } 297 for i := 0; i < len(pathExprList); i++ { 298 pathExpr, value := pathExprList[i], values[i] 299 modifier := &binaryModifier{bj: bj} 300 switch mt { 301 case ModifyInsert: 302 bj = modifier.insert(pathExpr, value) 303 case ModifyReplace: 304 bj = modifier.replace(pathExpr, value) 305 case ModifySet: 306 bj = modifier.set(pathExpr, value) 307 } 308 } 309 return bj, nil 310 } 311 312 // Remove removes the elements indicated by pathExprList from JSON. 313 func (bj BinaryJSON) Remove(pathExprList []PathExpression) (BinaryJSON, error) { 314 for _, pathExpr := range pathExprList { 315 if len(pathExpr.legs) == 0 { 316 // TODO: should return 3153(42000) 317 return bj, errors.New("Invalid path expression") 318 } 319 if pathExpr.flags.containsAnyAsterisk() { 320 // TODO: should return 3149(42000) 321 return bj, errors.New("Invalid path expression") 322 } 323 modifer := &binaryModifier{bj: bj} 324 bj = modifer.remove(pathExpr) 325 } 326 return bj, nil 327 } 328 329 type binaryModifier struct { 330 bj BinaryJSON 331 modifyPtr *byte 332 modifyValue BinaryJSON 333 } 334 335 func (bm *binaryModifier) set(path PathExpression, newBj BinaryJSON) BinaryJSON { 336 result := make([]BinaryJSON, 0, 1) 337 result = bm.bj.extractTo(result, path) 338 if len(result) > 0 { 339 bm.modifyPtr = &result[0].Value[0] 340 bm.modifyValue = newBj 341 return bm.rebuild() 342 } 343 bm.doInsert(path, newBj) 344 return bm.rebuild() 345 } 346 347 func (bm *binaryModifier) replace(path PathExpression, newBj BinaryJSON) BinaryJSON { 348 result := make([]BinaryJSON, 0, 1) 349 result = bm.bj.extractTo(result, path) 350 if len(result) == 0 { 351 return bm.bj 352 } 353 bm.modifyPtr = &result[0].Value[0] 354 bm.modifyValue = newBj 355 return bm.rebuild() 356 } 357 358 func (bm *binaryModifier) insert(path PathExpression, newBj BinaryJSON) BinaryJSON { 359 result := make([]BinaryJSON, 0, 1) 360 result = bm.bj.extractTo(result, path) 361 if len(result) > 0 { 362 return bm.bj 363 } 364 bm.doInsert(path, newBj) 365 return bm.rebuild() 366 } 367 368 // doInsert inserts the newBj to its parent, and builds the new parent. 369 func (bm *binaryModifier) doInsert(path PathExpression, newBj BinaryJSON) { 370 parentPath, lastLeg := path.popOneLastLeg() 371 result := make([]BinaryJSON, 0, 1) 372 result = bm.bj.extractTo(result, parentPath) 373 if len(result) == 0 { 374 return 375 } 376 parentBj := result[0] 377 if lastLeg.typ == pathLegIndex { 378 bm.modifyPtr = &parentBj.Value[0] 379 if parentBj.TypeCode != TypeCodeArray { 380 bm.modifyValue = buildBinaryArray([]BinaryJSON{parentBj, newBj}) 381 return 382 } 383 elemCount := parentBj.GetElemCount() 384 elems := make([]BinaryJSON, 0, elemCount+1) 385 for i := 0; i < elemCount; i++ { 386 elems = append(elems, parentBj.arrayGetElem(i)) 387 } 388 elems = append(elems, newBj) 389 bm.modifyValue = buildBinaryArray(elems) 390 return 391 } 392 if parentBj.TypeCode != TypeCodeObject { 393 return 394 } 395 bm.modifyPtr = &parentBj.Value[0] 396 elemCount := parentBj.GetElemCount() 397 insertKey := hack.Slice(lastLeg.dotKey) 398 insertIdx := sort.Search(elemCount, func(i int) bool { 399 return bytes.Compare(parentBj.objectGetKey(i), insertKey) >= 0 400 }) 401 keys := make([][]byte, 0, elemCount+1) 402 elems := make([]BinaryJSON, 0, elemCount+1) 403 for i := 0; i < elemCount; i++ { 404 if i == insertIdx { 405 keys = append(keys, insertKey) 406 elems = append(elems, newBj) 407 } 408 keys = append(keys, parentBj.objectGetKey(i)) 409 elems = append(elems, parentBj.objectGetVal(i)) 410 } 411 if insertIdx == elemCount { 412 keys = append(keys, insertKey) 413 elems = append(elems, newBj) 414 } 415 bm.modifyValue = buildBinaryObject(keys, elems) 416 } 417 418 func (bm *binaryModifier) remove(path PathExpression) BinaryJSON { 419 result := make([]BinaryJSON, 0, 1) 420 result = bm.bj.extractTo(result, path) 421 if len(result) == 0 { 422 return bm.bj 423 } 424 bm.doRemove(path) 425 return bm.rebuild() 426 } 427 428 func (bm *binaryModifier) doRemove(path PathExpression) { 429 parentPath, lastLeg := path.popOneLastLeg() 430 result := make([]BinaryJSON, 0, 1) 431 result = bm.bj.extractTo(result, parentPath) 432 if len(result) == 0 { 433 return 434 } 435 parentBj := result[0] 436 if lastLeg.typ == pathLegIndex { 437 if parentBj.TypeCode != TypeCodeArray { 438 return 439 } 440 bm.modifyPtr = &parentBj.Value[0] 441 elemCount := parentBj.GetElemCount() 442 elems := make([]BinaryJSON, 0, elemCount-1) 443 for i := 0; i < elemCount; i++ { 444 if i != lastLeg.arrayIndex { 445 elems = append(elems, parentBj.arrayGetElem(i)) 446 } 447 } 448 bm.modifyValue = buildBinaryArray(elems) 449 return 450 } 451 if parentBj.TypeCode != TypeCodeObject { 452 return 453 } 454 bm.modifyPtr = &parentBj.Value[0] 455 elemCount := parentBj.GetElemCount() 456 removeKey := hack.Slice(lastLeg.dotKey) 457 keys := make([][]byte, 0, elemCount+1) 458 elems := make([]BinaryJSON, 0, elemCount+1) 459 for i := 0; i < elemCount; i++ { 460 key := parentBj.objectGetKey(i) 461 if !bytes.Equal(key, removeKey) { 462 keys = append(keys, parentBj.objectGetKey(i)) 463 elems = append(elems, parentBj.objectGetVal(i)) 464 } 465 } 466 bm.modifyValue = buildBinaryObject(keys, elems) 467 } 468 469 // rebuild merges the old and the modified JSON into a new BinaryJSON 470 func (bm *binaryModifier) rebuild() BinaryJSON { 471 buf := make([]byte, 0, len(bm.bj.Value)+len(bm.modifyValue.Value)) 472 value, tpCode := bm.rebuildTo(buf) 473 return BinaryJSON{TypeCode: tpCode, Value: value} 474 } 475 476 func (bm *binaryModifier) rebuildTo(buf []byte) ([]byte, TypeCode) { 477 if bm.modifyPtr == &bm.bj.Value[0] { 478 bm.modifyPtr = nil 479 return append(buf, bm.modifyValue.Value...), bm.modifyValue.TypeCode 480 } else if bm.modifyPtr == nil { 481 return append(buf, bm.bj.Value...), bm.bj.TypeCode 482 } 483 bj := bm.bj 484 switch bj.TypeCode { 485 case TypeCodeLiteral, TypeCodeInt64, TypeCodeUint64, TypeCodeFloat64, TypeCodeString: 486 return append(buf, bj.Value...), bj.TypeCode 487 } 488 docOff := len(buf) 489 elemCount := bj.GetElemCount() 490 var valEntryStart int 491 if bj.TypeCode == TypeCodeArray { 492 copySize := headerSize + elemCount*valEntrySize 493 valEntryStart = headerSize 494 buf = append(buf, bj.Value[:copySize]...) 495 } else { 496 copySize := headerSize + elemCount*(keyEntrySize+valEntrySize) 497 valEntryStart = headerSize + elemCount*keyEntrySize 498 buf = append(buf, bj.Value[:copySize]...) 499 if elemCount > 0 { 500 firstKeyOff := int(endian.Uint32(bj.Value[headerSize:])) 501 lastKeyOff := int(endian.Uint32(bj.Value[headerSize+(elemCount-1)*keyEntrySize:])) 502 lastKeyLen := int(endian.Uint16(bj.Value[headerSize+(elemCount-1)*keyEntrySize+keyLenOff:])) 503 buf = append(buf, bj.Value[firstKeyOff:lastKeyOff+lastKeyLen]...) 504 } 505 } 506 for i := 0; i < elemCount; i++ { 507 valEntryOff := valEntryStart + i*valEntrySize 508 elem := bj.valEntryGet(valEntryOff) 509 bm.bj = elem 510 var tpCode TypeCode 511 valOff := len(buf) - docOff 512 buf, tpCode = bm.rebuildTo(buf) 513 buf[docOff+valEntryOff] = tpCode 514 if tpCode == TypeCodeLiteral { 515 lastIdx := len(buf) - 1 516 endian.PutUint32(buf[docOff+valEntryOff+valTypeSize:], uint32(buf[lastIdx])) 517 buf = buf[:lastIdx] 518 } else { 519 endian.PutUint32(buf[docOff+valEntryOff+valTypeSize:], uint32(valOff)) 520 } 521 } 522 endian.PutUint32(buf[docOff+dataSizeOff:], uint32(len(buf)-docOff)) 523 return buf, bj.TypeCode 524 } 525 526 // floatEpsilon is the acceptable error quantity when comparing two float numbers. 527 const floatEpsilon = 1.e-8 528 529 // compareFloat64 returns an integer comparing the float64 x to y, 530 // allowing precision loss. 531 func compareFloat64PrecisionLoss(x, y float64) int { 532 if x-y < floatEpsilon && y-x < floatEpsilon { 533 return 0 534 } else if x-y < 0 { 535 return -1 536 } 537 return 1 538 } 539 540 // CompareBinary compares two binary json objects. Returns -1 if left < right, 541 // 0 if left == right, else returns 1. 542 func CompareBinary(left, right BinaryJSON) int { 543 precedence1 := jsonTypePrecedences[left.Type()] 544 precedence2 := jsonTypePrecedences[right.Type()] 545 var cmp int 546 if precedence1 == precedence2 { 547 if precedence1 == jsonTypePrecedences["NULL"] { 548 // for JSON null. 549 cmp = 0 550 } 551 switch left.TypeCode { 552 case TypeCodeLiteral: 553 // false is less than true. 554 cmp = int(right.Value[0]) - int(left.Value[0]) 555 case TypeCodeInt64, TypeCodeUint64, TypeCodeFloat64: 556 leftFloat := i64AsFloat64(left.GetInt64(), left.TypeCode) 557 rightFloat := i64AsFloat64(right.GetInt64(), right.TypeCode) 558 cmp = compareFloat64PrecisionLoss(leftFloat, rightFloat) 559 case TypeCodeString: 560 cmp = bytes.Compare(left.GetString(), right.GetString()) 561 case TypeCodeArray: 562 leftCount := left.GetElemCount() 563 rightCount := right.GetElemCount() 564 for i := 0; i < leftCount && i < rightCount; i++ { 565 elem1 := left.arrayGetElem(i) 566 elem2 := right.arrayGetElem(i) 567 cmp = CompareBinary(elem1, elem2) 568 if cmp != 0 { 569 return cmp 570 } 571 } 572 cmp = leftCount - rightCount 573 case TypeCodeObject: 574 // only equal is defined on two json objects. 575 // larger and smaller are not defined. 576 cmp = bytes.Compare(left.Value, right.Value) 577 } 578 } else { 579 cmp = precedence1 - precedence2 580 } 581 return cmp 582 } 583 584 func i64AsFloat64(i64 int64, typeCode TypeCode) float64 { 585 switch typeCode { 586 case TypeCodeLiteral, TypeCodeInt64: 587 return float64(i64) 588 case TypeCodeUint64: 589 u64 := *(*uint64)(unsafe.Pointer(&i64)) 590 return float64(u64) 591 case TypeCodeFloat64: 592 return *(*float64)(unsafe.Pointer(&i64)) 593 default: 594 msg := fmt.Sprintf(unknownTypeCodeErrorMsg, typeCode) 595 panic(msg) 596 } 597 } 598 599 // MergeBinary merges multiple BinaryJSON into one according the following rules: 600 // 1) adjacent arrays are merged to a single array; 601 // 2) adjacent object are merged to a single object; 602 // 3) a scalar value is autowrapped as an array before merge; 603 // 4) an adjacent array and object are merged by autowrapping the object as an array. 604 func MergeBinary(bjs []BinaryJSON) BinaryJSON { 605 var remain = bjs 606 var objects []BinaryJSON 607 var results []BinaryJSON 608 for len(remain) > 0 { 609 if remain[0].TypeCode != TypeCodeObject { 610 results = append(results, remain[0]) 611 remain = remain[1:] 612 } else { 613 objects, remain = getAdjacentObjects(remain) 614 results = append(results, mergeBinaryObject(objects)) 615 } 616 } 617 if len(results) == 1 { 618 return results[0] 619 } 620 return mergeBinaryArray(results) 621 } 622 623 func getAdjacentObjects(bjs []BinaryJSON) (objects, remain []BinaryJSON) { 624 for i := 0; i < len(bjs); i++ { 625 if bjs[i].TypeCode != TypeCodeObject { 626 return bjs[:i], bjs[i:] 627 } 628 } 629 return bjs, nil 630 } 631 632 func mergeBinaryArray(elems []BinaryJSON) BinaryJSON { 633 buf := make([]BinaryJSON, 0, len(elems)) 634 for i := 0; i < len(elems); i++ { 635 elem := elems[i] 636 if elem.TypeCode != TypeCodeArray { 637 buf = append(buf, elem) 638 } else { 639 childCount := elem.GetElemCount() 640 for j := 0; j < childCount; j++ { 641 buf = append(buf, elem.arrayGetElem(j)) 642 } 643 } 644 } 645 return buildBinaryArray(buf) 646 } 647 648 func mergeBinaryObject(objects []BinaryJSON) BinaryJSON { 649 keyValMap := make(map[string]BinaryJSON) 650 keys := make([][]byte, 0, len(keyValMap)) 651 for _, obj := range objects { 652 elemCount := obj.GetElemCount() 653 for i := 0; i < elemCount; i++ { 654 key := obj.objectGetKey(i) 655 val := obj.objectGetVal(i) 656 if old, ok := keyValMap[string(key)]; ok { 657 keyValMap[string(key)] = MergeBinary([]BinaryJSON{old, val}) 658 } else { 659 keyValMap[string(key)] = val 660 keys = append(keys, key) 661 } 662 } 663 } 664 sort.Slice(keys, func(i, j int) bool { 665 return bytes.Compare(keys[i], keys[j]) < 0 666 }) 667 values := make([]BinaryJSON, len(keys)) 668 for i, key := range keys { 669 values[i] = keyValMap[string(key)] 670 } 671 return buildBinaryObject(keys, values) 672 } 673 674 // PeekBytesAsJSON trys to peek some bytes from b, until 675 // we can deserialize a JSON from those bytes. 676 func PeekBytesAsJSON(b []byte) (n int, err error) { 677 if len(b) <= 0 { 678 err = errors.New("Cant peek from empty bytes") 679 return 680 } 681 switch c := TypeCode(b[0]); c { 682 case TypeCodeObject, TypeCodeArray: 683 if len(b) >= valTypeSize+headerSize { 684 size := endian.Uint32(b[valTypeSize+dataSizeOff:]) 685 n = valTypeSize + int(size) 686 return 687 } 688 case TypeCodeString: 689 strLen, lenLen := binary.Uvarint(b[valTypeSize:]) 690 return valTypeSize + int(strLen) + lenLen, nil 691 case TypeCodeInt64, TypeCodeUint64, TypeCodeFloat64: 692 n = valTypeSize + 8 693 return 694 case TypeCodeLiteral: 695 n = valTypeSize + 1 696 return 697 } 698 err = errors.New("Invalid JSON bytes") 699 return 700 } 701 702 // ContainsBinary check whether JSON document contains specific target according the following rules: 703 // 1) object contains a target object if and only if every key is contained in source object and the value associated with the target key is contained in the value associated with the source key; 704 // 2) array contains a target nonarray if and only if the target is contained in some element of the array; 705 // 3) array contains a target array if and only if every element is contained in some element of the array; 706 // 4) scalar contains a target scalar if and only if they are comparable and are equal; 707 func ContainsBinary(obj, target BinaryJSON) bool { 708 switch obj.TypeCode { 709 case TypeCodeObject: 710 if target.TypeCode == TypeCodeObject { 711 len := target.GetElemCount() 712 for i := 0; i < len; i++ { 713 key := target.objectGetKey(i) 714 val := target.objectGetVal(i) 715 if exp, exists := obj.objectSearchKey(key); !exists || !ContainsBinary(exp, val) { 716 return false 717 } 718 } 719 return true 720 } 721 return false 722 case TypeCodeArray: 723 if target.TypeCode == TypeCodeArray { 724 len := target.GetElemCount() 725 for i := 0; i < len; i++ { 726 if !ContainsBinary(obj, target.arrayGetElem(i)) { 727 return false 728 } 729 } 730 return true 731 } 732 len := obj.GetElemCount() 733 for i := 0; i < len; i++ { 734 if ContainsBinary(obj.arrayGetElem(i), target) { 735 return true 736 } 737 } 738 return false 739 default: 740 return CompareBinary(obj, target) == 0 741 } 742 } 743 744 // GetElemDepth for JSON_DEPTH 745 // Returns the maximum depth of a JSON document 746 // rules referenced by MySQL JSON_DEPTH function 747 // [https://dev.mysql.com/doc/refman/5.7/en/json-attribute-functions.html#function_json-depth] 748 // 1) An empty array, empty object, or scalar value has depth 1. 749 // 2) A nonempty array containing only elements of depth 1 or nonempty object containing only member values of depth 1 has depth 2. 750 // 3) Otherwise, a JSON document has depth greater than 2. 751 // e.g. depth of '{}', '[]', 'true': 1 752 // e.g. depth of '[10, 20]', '[[], {}]': 2 753 // e.g. depth of '[10, {"a": 20}]': 3 754 func (bj BinaryJSON) GetElemDepth() int { 755 switch bj.TypeCode { 756 case TypeCodeObject: 757 len := bj.GetElemCount() 758 maxDepth := 0 759 for i := 0; i < len; i++ { 760 obj := bj.objectGetVal(i) 761 depth := obj.GetElemDepth() 762 if depth > maxDepth { 763 maxDepth = depth 764 } 765 } 766 return maxDepth + 1 767 case TypeCodeArray: 768 len := bj.GetElemCount() 769 maxDepth := 0 770 for i := 0; i < len; i++ { 771 obj := bj.arrayGetElem(i) 772 depth := obj.GetElemDepth() 773 if depth > maxDepth { 774 maxDepth = depth 775 } 776 } 777 return maxDepth + 1 778 default: 779 return 1 780 } 781 }