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  }