You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
233 lines
6.2 KiB
233 lines
6.2 KiB
// Copyright 2017 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package json
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"unicode/utf8"
|
|
|
|
mysql "github.com/pingcap/tidb/errno"
|
|
"github.com/pingcap/tidb/util/dbterror"
|
|
)
|
|
|
|
// TypeCode indicates JSON type.
|
|
type TypeCode = byte
|
|
|
|
const (
|
|
// TypeCodeObject indicates the JSON is an object.
|
|
TypeCodeObject TypeCode = 0x01
|
|
// TypeCodeArray indicates the JSON is an array.
|
|
TypeCodeArray TypeCode = 0x03
|
|
// TypeCodeLiteral indicates the JSON is a literal.
|
|
TypeCodeLiteral TypeCode = 0x04
|
|
// TypeCodeInt64 indicates the JSON is a signed integer.
|
|
TypeCodeInt64 TypeCode = 0x09
|
|
// TypeCodeUint64 indicates the JSON is a unsigned integer.
|
|
TypeCodeUint64 TypeCode = 0x0a
|
|
// TypeCodeFloat64 indicates the JSON is a double float number.
|
|
TypeCodeFloat64 TypeCode = 0x0b
|
|
// TypeCodeString indicates the JSON is a string.
|
|
TypeCodeString TypeCode = 0x0c
|
|
)
|
|
|
|
const (
|
|
// LiteralNil represents JSON null.
|
|
LiteralNil byte = 0x00
|
|
// LiteralTrue represents JSON true.
|
|
LiteralTrue byte = 0x01
|
|
// LiteralFalse represents JSON false.
|
|
LiteralFalse byte = 0x02
|
|
)
|
|
|
|
const unknownTypeCodeErrorMsg = "unknown type code: %d"
|
|
const unknownTypeErrorMsg = "unknown type: %s"
|
|
|
|
// safeSet holds the value true if the ASCII character with the given array
|
|
// position can be represented inside a JSON string without any further
|
|
// escaping.
|
|
//
|
|
// All values are true except for the ASCII control characters (0-31), the
|
|
// double quote ("), and the backslash character ("\").
|
|
var safeSet = [utf8.RuneSelf]bool{
|
|
' ': true,
|
|
'!': true,
|
|
'"': false,
|
|
'#': true,
|
|
'$': true,
|
|
'%': true,
|
|
'&': true,
|
|
'\'': true,
|
|
'(': true,
|
|
')': true,
|
|
'*': true,
|
|
'+': true,
|
|
',': true,
|
|
'-': true,
|
|
'.': true,
|
|
'/': true,
|
|
'0': true,
|
|
'1': true,
|
|
'2': true,
|
|
'3': true,
|
|
'4': true,
|
|
'5': true,
|
|
'6': true,
|
|
'7': true,
|
|
'8': true,
|
|
'9': true,
|
|
':': true,
|
|
';': true,
|
|
'<': true,
|
|
'=': true,
|
|
'>': true,
|
|
'?': true,
|
|
'@': true,
|
|
'A': true,
|
|
'B': true,
|
|
'C': true,
|
|
'D': true,
|
|
'E': true,
|
|
'F': true,
|
|
'G': true,
|
|
'H': true,
|
|
'I': true,
|
|
'J': true,
|
|
'K': true,
|
|
'L': true,
|
|
'M': true,
|
|
'N': true,
|
|
'O': true,
|
|
'P': true,
|
|
'Q': true,
|
|
'R': true,
|
|
'S': true,
|
|
'T': true,
|
|
'U': true,
|
|
'V': true,
|
|
'W': true,
|
|
'X': true,
|
|
'Y': true,
|
|
'Z': true,
|
|
'[': true,
|
|
'\\': false,
|
|
']': true,
|
|
'^': true,
|
|
'_': true,
|
|
'`': true,
|
|
'a': true,
|
|
'b': true,
|
|
'c': true,
|
|
'd': true,
|
|
'e': true,
|
|
'f': true,
|
|
'g': true,
|
|
'h': true,
|
|
'i': true,
|
|
'j': true,
|
|
'k': true,
|
|
'l': true,
|
|
'm': true,
|
|
'n': true,
|
|
'o': true,
|
|
'p': true,
|
|
'q': true,
|
|
'r': true,
|
|
's': true,
|
|
't': true,
|
|
'u': true,
|
|
'v': true,
|
|
'w': true,
|
|
'x': true,
|
|
'y': true,
|
|
'z': true,
|
|
'{': true,
|
|
'|': true,
|
|
'}': true,
|
|
'~': true,
|
|
'\u007f': true,
|
|
}
|
|
|
|
var (
|
|
hexChars = "0123456789abcdef"
|
|
endian = binary.LittleEndian
|
|
)
|
|
|
|
const (
|
|
headerSize = 8 // element size + data size.
|
|
dataSizeOff = 4
|
|
keyEntrySize = 6 // keyOff + keyLen
|
|
keyLenOff = 4
|
|
valTypeSize = 1
|
|
valEntrySize = 5
|
|
)
|
|
|
|
// jsonTypePrecedences is for comparing two json.
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/json.html#json-comparison
|
|
var jsonTypePrecedences = map[string]int{
|
|
"BLOB": -1,
|
|
"BIT": -2,
|
|
"OPAQUE": -3,
|
|
"DATETIME": -4,
|
|
"TIME": -5,
|
|
"DATE": -6,
|
|
"BOOLEAN": -7,
|
|
"ARRAY": -8,
|
|
"OBJECT": -9,
|
|
"STRING": -10,
|
|
"INTEGER": -11,
|
|
"UNSIGNED INTEGER": -11,
|
|
"DOUBLE": -11,
|
|
"NULL": -12,
|
|
}
|
|
|
|
// ModifyType is for modify a JSON. There are three valid values:
|
|
// ModifyInsert, ModifyReplace and ModifySet.
|
|
type ModifyType byte
|
|
|
|
const (
|
|
// ModifyInsert is for insert a new element into a JSON.
|
|
ModifyInsert ModifyType = 0x01
|
|
// ModifyReplace is for replace an old elemList from a JSON.
|
|
ModifyReplace ModifyType = 0x02
|
|
// ModifySet = ModifyInsert | ModifyReplace
|
|
ModifySet ModifyType = 0x03
|
|
)
|
|
|
|
var (
|
|
// ErrInvalidJSONText means invalid JSON text.
|
|
ErrInvalidJSONText = dbterror.ClassJSON.NewStd(mysql.ErrInvalidJSONText)
|
|
// ErrInvalidJSONPath means invalid JSON path.
|
|
ErrInvalidJSONPath = dbterror.ClassJSON.NewStd(mysql.ErrInvalidJSONPath)
|
|
// ErrInvalidJSONData means invalid JSON data.
|
|
ErrInvalidJSONData = dbterror.ClassJSON.NewStd(mysql.ErrInvalidJSONData)
|
|
// ErrInvalidJSONPathWildcard means invalid JSON path that contain wildcard characters.
|
|
ErrInvalidJSONPathWildcard = dbterror.ClassJSON.NewStd(mysql.ErrInvalidJSONPathWildcard)
|
|
// ErrInvalidJSONContainsPathType means invalid JSON contains path type.
|
|
ErrInvalidJSONContainsPathType = dbterror.ClassJSON.NewStd(mysql.ErrInvalidJSONContainsPathType)
|
|
// ErrJSONDocumentNULLKey means that json's key is null
|
|
ErrJSONDocumentNULLKey = dbterror.ClassJSON.NewStd(mysql.ErrJSONDocumentNULLKey)
|
|
// ErrInvalidJSONPathArrayCell means invalid JSON path for an array cell.
|
|
ErrInvalidJSONPathArrayCell = dbterror.ClassJSON.NewStd(mysql.ErrInvalidJSONPathArrayCell)
|
|
// ErrUnsupportedSecondArgumentType means unsupported second argument type in json_objectagg
|
|
ErrUnsupportedSecondArgumentType = dbterror.ClassJSON.NewStd(mysql.ErrUnsupportedSecondArgumentType)
|
|
)
|
|
|
|
// json_contains_path function type choices
|
|
// See: https://dev.mysql.com/doc/refman/5.7/en/json-search-functions.html#function_json-contains-path
|
|
const (
|
|
// 'all': 1 if all paths exist within the document, 0 otherwise.
|
|
ContainsPathAll = "all"
|
|
// 'one': 1 if at least one path exists within the document, 0 otherwise.
|
|
ContainsPathOne = "one"
|
|
)
|
|
|