HashValue converts certain JSON values for aggregate comparisons. For example int64(3) == float64(3.0) Other than the numeric condition, this function has to construct a bidirectional map between hash value and the original representation
(buf []byte)
| 565 | // Other than the numeric condition, this function has to construct a bidirectional map between hash value |
| 566 | // and the original representation |
| 567 | func (bj BinaryJSON) HashValue(buf []byte) []byte { |
| 568 | switch bj.TypeCode { |
| 569 | case JSONTypeCodeInt64: |
| 570 | // Convert to a FLOAT if no precision is lost. |
| 571 | // In the future, it will be better to convert to a DECIMAL value instead |
| 572 | // See: https://github.com/pingcap/tidb/issues/9988 |
| 573 | |
| 574 | // A double precision float can have 52-bit in fraction part. |
| 575 | if getInt64FractionLength(bj.GetInt64()) <= 52 { |
| 576 | buf = append(buf, JSONTypeCodeFloat64) |
| 577 | buf = appendBinaryFloat64(buf, float64(bj.GetInt64())) |
| 578 | } else { |
| 579 | buf = append(buf, bj.TypeCode) |
| 580 | buf = append(buf, bj.Value...) |
| 581 | } |
| 582 | case JSONTypeCodeUint64: |
| 583 | // A double precision float can have 52-bit in fraction part. |
| 584 | if getUint64FractionLength(bj.GetUint64()) <= 52 { |
| 585 | buf = append(buf, JSONTypeCodeFloat64) |
| 586 | buf = appendBinaryFloat64(buf, float64(bj.GetUint64())) |
| 587 | } else { |
| 588 | buf = append(buf, bj.TypeCode) |
| 589 | buf = append(buf, bj.Value...) |
| 590 | } |
| 591 | case JSONTypeCodeArray: |
| 592 | // this hash value is bidirectional, because you can get the element one-by-one |
| 593 | // and you know the end of it, as the elemCount is also appended here |
| 594 | buf = append(buf, bj.TypeCode) |
| 595 | elemCount := int(jsonEndian.Uint32(bj.Value)) |
| 596 | buf = append(buf, bj.Value[0:dataSizeOff]...) |
| 597 | for i := 0; i < elemCount; i++ { |
| 598 | buf = bj.ArrayGetElem(i).HashValue(buf) |
| 599 | } |
| 600 | case JSONTypeCodeObject: |
| 601 | // this hash value is bidirectional, because you can get the key using the json |
| 602 | // string format, and get the value accordingly. |
| 603 | buf = append(buf, bj.TypeCode) |
| 604 | elemCount := int(jsonEndian.Uint32(bj.Value)) |
| 605 | buf = append(buf, bj.Value[0:dataSizeOff]...) |
| 606 | for i := 0; i < elemCount; i++ { |
| 607 | keyJSON := CreateBinaryJSON(string(bj.objectGetKey(i))) |
| 608 | buf = append(buf, keyJSON.Value...) |
| 609 | buf = bj.objectGetVal(i).HashValue(buf) |
| 610 | } |
| 611 | default: |
| 612 | buf = append(buf, bj.TypeCode) |
| 613 | buf = append(buf, bj.Value...) |
| 614 | } |
| 615 | return buf |
| 616 | } |
| 617 | |
| 618 | // GetValue return the primitive value of the JSON. |
| 619 | func (bj BinaryJSON) GetValue() any { |