@@ -45,29 +45,55 @@ func (t JsonType) Compare(ctx context.Context, a interface{}, b interface{}) (in
4545 return CompareJSON (ctx , a , b )
4646}
4747
48+ // convertJSONValue parses JSON-encoded data if the input is a string or []byte, returning the resulting JSONDocument. For
49+ // other types, the value is returned if it can be marshalled.
50+ func convertJSONValue (v interface {}) (interface {}, sql.ConvertInRange , error ) {
51+ var data []byte
52+ var charsetMaxLength int64 = 1
53+ switch x := v .(type ) {
54+ case []byte :
55+ data = x
56+ case string :
57+ data = []byte (x )
58+ charsetMaxLength = sql .Collation_Default .CharacterSet ().MaxLength ()
59+ default :
60+ // if |v| can be marshalled, it contains
61+ // a valid JSON document representation
62+ if b , berr := json .Marshal (v ); berr == nil {
63+ data = b
64+ } else {
65+ return nil , sql .InRange , nil
66+ }
67+ }
68+
69+ if int64 (len (data ))* charsetMaxLength > MaxJsonFieldByteLength {
70+ return nil , sql .InRange , ErrLengthTooLarge .New (len (data ), MaxJsonFieldByteLength )
71+ }
72+
73+ var val interface {}
74+ if err := json .Unmarshal (data , & val ); err != nil {
75+ return nil , sql .OutOfRange , sql .ErrInvalidJson .New (err .Error ())
76+ }
77+
78+ return JSONDocument {Val : val }, sql .InRange , nil
79+ }
80+
4881// Convert implements Type interface.
49- func (t JsonType ) Convert (c context.Context , v interface {}) (doc interface {}, inRange sql.ConvertInRange , err error ) {
82+ func (t JsonType ) Convert (c context.Context , v interface {}) (interface {}, sql.ConvertInRange , error ) {
5083 switch v := v .(type ) {
5184 case sql.JSONWrapper :
5285 return v , sql .InRange , nil
5386 case []byte :
54- if int64 (len (v )) > MaxJsonFieldByteLength {
55- return nil , sql .InRange , ErrLengthTooLarge .New (len (v ), MaxJsonFieldByteLength )
56- }
57- err = json .Unmarshal (v , & doc )
58- if err != nil {
59- return nil , sql .OutOfRange , sql .ErrInvalidJson .New (err .Error ())
60- }
87+ return convertJSONValue (v )
6188 case string :
62- charsetMaxLength := sql .Collation_Default .CharacterSet ().MaxLength ()
63- length := int64 (len (v )) * charsetMaxLength
64- if length > MaxJsonFieldByteLength {
65- return nil , sql .InRange , ErrLengthTooLarge .New (length , MaxJsonFieldByteLength )
66- }
67- err = json .Unmarshal ([]byte (v ), & doc )
89+ return convertJSONValue (v )
90+ // Text values may be stored in wrappers (e.g. Dolt's TextStorage), so unwrap to the raw string before decoding.
91+ case sql.StringWrapper :
92+ str , err := v .Unwrap (c )
6893 if err != nil {
69- return nil , sql .OutOfRange , sql . ErrInvalidJson . New ( err . Error ())
94+ return nil , sql .OutOfRange , err
7095 }
96+ return convertJSONValue (str )
7197 case int8 :
7298 return JSONDocument {Val : int64 (v )}, sql .InRange , nil
7399 case int16 :
@@ -91,22 +117,8 @@ func (t JsonType) Convert(c context.Context, v interface{}) (doc interface{}, in
91117 case decimal.Decimal :
92118 return JSONDocument {Val : v }, sql .InRange , nil
93119 default :
94- // if |v| can be marshalled, it contains
95- // a valid JSON document representation
96- if b , berr := json .Marshal (v ); berr == nil {
97- if int64 (len (b )) > MaxJsonFieldByteLength {
98- return nil , sql .InRange , ErrLengthTooLarge .New (len (b ), MaxJsonFieldByteLength )
99- }
100- err = json .Unmarshal (b , & doc )
101- if err != nil {
102- return nil , sql .OutOfRange , sql .ErrInvalidJson .New (err .Error ())
103- }
104- }
105- }
106- if err != nil {
107- return nil , sql .OutOfRange , err
120+ return convertJSONValue (v )
108121 }
109- return JSONDocument {Val : doc }, sql .InRange , nil
110122}
111123
112124// Equals implements the Type interface.
0 commit comments