github.com/dolthub/go-mysql-server@v0.18.0/sql/types/json.go (about) 1 // Copyright 2022 Dolthub, 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package types 16 17 import ( 18 "bytes" 19 "encoding/json" 20 "reflect" 21 22 "github.com/dolthub/vitess/go/sqltypes" 23 "github.com/dolthub/vitess/go/vt/proto/query" 24 25 "github.com/dolthub/go-mysql-server/sql" 26 ) 27 28 var ( 29 jsonValueType = reflect.TypeOf((*sql.JSONWrapper)(nil)).Elem() 30 31 MaxJsonFieldByteLength = int64(1024) * int64(1024) * int64(1024) 32 ) 33 34 var JSON sql.Type = JsonType{} 35 var _ sql.CollationCoercible = JsonType{} 36 37 type JsonType struct{} 38 39 // Compare implements Type interface. 40 func (t JsonType) Compare(a interface{}, b interface{}) (int, error) { 41 if hasNulls, res := CompareNulls(a, b); hasNulls { 42 return res, nil 43 } 44 return CompareJSON(a, b) 45 } 46 47 // Convert implements Type interface. 48 func (t JsonType) Convert(v interface{}) (doc interface{}, inRange sql.ConvertInRange, err error) { 49 switch v := v.(type) { 50 case sql.JSONWrapper: 51 return v, sql.InRange, nil 52 case []byte: 53 if int64(len(v)) > MaxJsonFieldByteLength { 54 return nil, sql.InRange, ErrLengthTooLarge.New(len(v), MaxJsonFieldByteLength) 55 } 56 err = json.Unmarshal(v, &doc) 57 if err != nil { 58 return nil, sql.OutOfRange, sql.ErrInvalidJson.New(err.Error()) 59 } 60 case string: 61 charsetMaxLength := sql.Collation_Default.CharacterSet().MaxLength() 62 length := int64(len(v)) * charsetMaxLength 63 if length > MaxJsonFieldByteLength { 64 return nil, sql.InRange, ErrLengthTooLarge.New(length, MaxJsonFieldByteLength) 65 } 66 err = json.Unmarshal([]byte(v), &doc) 67 if err != nil { 68 return nil, sql.OutOfRange, sql.ErrInvalidJson.New(err.Error()) 69 } 70 default: 71 // if |v| can be marshalled, it contains 72 // a valid JSON document representation 73 if b, berr := json.Marshal(v); berr == nil { 74 if int64(len(b)) > MaxJsonFieldByteLength { 75 return nil, sql.InRange, ErrLengthTooLarge.New(len(b), MaxJsonFieldByteLength) 76 } 77 err = json.Unmarshal(b, &doc) 78 if err != nil { 79 return nil, sql.OutOfRange, sql.ErrInvalidJson.New(err.Error()) 80 } 81 } 82 } 83 if err != nil { 84 return nil, sql.OutOfRange, err 85 } 86 return JSONDocument{Val: doc}, sql.InRange, nil 87 } 88 89 // Equals implements the Type interface. 90 func (t JsonType) Equals(otherType sql.Type) bool { 91 _, ok := otherType.(JsonType) 92 return ok 93 } 94 95 // MaxTextResponseByteLength implements the Type interface 96 func (t JsonType) MaxTextResponseByteLength(_ *sql.Context) uint32 { 97 return uint32(MaxJsonFieldByteLength*sql.Collation_Default.CharacterSet().MaxLength()) - 1 98 } 99 100 // Promote implements the Type interface. 101 func (t JsonType) Promote() sql.Type { 102 return t 103 } 104 105 // SQL implements Type interface. 106 func (t JsonType) SQL(ctx *sql.Context, dest []byte, v interface{}) (sqltypes.Value, error) { 107 if v == nil { 108 return sqltypes.NULL, nil 109 } 110 111 // Convert to jsonType 112 jsVal, _, err := t.Convert(v) 113 if err != nil { 114 return sqltypes.NULL, err 115 } 116 js := jsVal.(sql.JSONWrapper) 117 118 var val []byte 119 switch j := js.(type) { 120 case JSONStringer: 121 str, err := j.JSONString() 122 if err != nil { 123 return sqltypes.NULL, err 124 } 125 val = AppendAndSliceString(dest, str) 126 default: 127 jsonBytes, err := json.Marshal(js.ToInterface()) 128 if err != nil { 129 return sqltypes.NULL, err 130 } 131 132 jsonBytes = bytes.ReplaceAll(jsonBytes, []byte(",\""), []byte(", \"")) 133 jsonBytes = bytes.ReplaceAll(jsonBytes, []byte("\":"), []byte("\": ")) 134 val = AppendAndSliceBytes(dest, jsonBytes) 135 } 136 137 return sqltypes.MakeTrusted(sqltypes.TypeJSON, val), nil 138 } 139 140 // String implements Type interface. 141 func (t JsonType) String() string { 142 return "json" 143 } 144 145 // Type implements Type interface. 146 func (t JsonType) Type() query.Type { 147 return sqltypes.TypeJSON 148 } 149 150 // ValueType implements Type interface. 151 func (t JsonType) ValueType() reflect.Type { 152 return jsonValueType 153 } 154 155 // Zero implements Type interface. 156 func (t JsonType) Zero() interface{} { 157 // MySQL throws an error for INSERT IGNORE, UPDATE IGNORE, etc. when bad json is encountered: 158 // ERROR 3140 (22032): Invalid JSON text: "Invalid value." at position 0 in value for column 'table.column'. 159 return nil 160 } 161 162 // CollationCoercibility implements sql.CollationCoercible interface. 163 func (JsonType) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 164 return sql.Collation_Default, 5 165 } 166 167 // DeepCopyJson implements deep copy of JSON document 168 func DeepCopyJson(v interface{}) interface{} { 169 if v == nil { 170 return nil 171 } 172 173 switch v.(type) { 174 case map[string]interface{}: 175 m := v.(map[string]interface{}) 176 newMap := make(map[string]interface{}) 177 for k, value := range m { 178 newMap[k] = DeepCopyJson(value) 179 } 180 return newMap 181 case []interface{}: 182 arr := v.([]interface{}) 183 newArray := make([]interface{}, len(arr)) 184 for i, doc := range arr { 185 newArray[i] = DeepCopyJson(doc) 186 } 187 return newArray 188 case bool, string, float64, float32, 189 int, int8, int16, int32, int64, 190 uint, uint8, uint16, uint32, uint64: 191 return v 192 default: 193 return nil 194 } 195 } 196 197 func MustJSON(s string) JSONDocument { 198 var doc interface{} 199 if err := json.Unmarshal([]byte(s), &doc); err != nil { 200 panic(err) 201 } 202 return JSONDocument{Val: doc} 203 }