github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/memex/builtin_json_test.go (about) 1 // Copyright 2020 WHTCORPS INC, 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 memex 15 16 import ( 17 . "github.com/whtcorpsinc/check" 18 "github.com/whtcorpsinc/BerolinaSQL/ast" 19 "github.com/whtcorpsinc/BerolinaSQL/terror" 20 "github.com/whtcorpsinc/milevadb/types" 21 "github.com/whtcorpsinc/milevadb/types/json" 22 "github.com/whtcorpsinc/milevadb/soliton/chunk" 23 "github.com/whtcorpsinc/milevadb/soliton/solitonutil" 24 ) 25 26 func (s *testEvaluatorSuite) TestJSONType(c *C) { 27 fc := funcs[ast.JSONType] 28 tbl := []struct { 29 Input interface{} 30 Expected interface{} 31 }{ 32 {nil, nil}, 33 {`3`, `INTEGER`}, 34 {`3.0`, `DOUBLE`}, 35 {`null`, `NULL`}, 36 {`true`, `BOOLEAN`}, 37 {`[]`, `ARRAY`}, 38 {`{}`, `OBJECT`}, 39 } 40 dtbl := tblToDtbl(tbl) 41 for _, t := range dtbl { 42 f, err := fc.getFunction(s.ctx, s.datumsToConstants(t["Input"])) 43 c.Assert(err, IsNil) 44 d, err := evalBuiltinFunc(f, chunk.Event{}) 45 c.Assert(err, IsNil) 46 c.Assert(d, solitonutil.CausetEquals, t["Expected"][0]) 47 } 48 } 49 50 func (s *testEvaluatorSuite) TestJSONQuote(c *C) { 51 fc := funcs[ast.JSONQuote] 52 tbl := []struct { 53 Input interface{} 54 Expected interface{} 55 }{ 56 {nil, nil}, 57 {``, `""`}, 58 {`""`, `"\"\""`}, 59 {`a`, `"a"`}, 60 {`3`, `"3"`}, 61 {`{"a": "b"}`, `"{\"a\": \"b\"}"`}, 62 {`{"a": "b"}`, `"{\"a\": \"b\"}"`}, 63 {`hello,"quoted string",world`, `"hello,\"quoted string\",world"`}, 64 {`hello,"宽字符",world`, `"hello,\"宽字符\",world"`}, 65 {`Invalid Json string is OK`, `"Invalid Json string\tis OK"`}, 66 {`1\u2232\u22322`, `"1\\u2232\\u22322"`}, 67 } 68 dtbl := tblToDtbl(tbl) 69 for _, t := range dtbl { 70 f, err := fc.getFunction(s.ctx, s.datumsToConstants(t["Input"])) 71 c.Assert(err, IsNil) 72 d, err := evalBuiltinFunc(f, chunk.Event{}) 73 c.Assert(err, IsNil) 74 c.Assert(d, solitonutil.CausetEquals, t["Expected"][0]) 75 } 76 } 77 78 func (s *testEvaluatorSuite) TestJSONUnquote(c *C) { 79 fc := funcs[ast.JSONUnquote] 80 tbl := []struct { 81 Input interface{} 82 Expected interface{} 83 }{ 84 {nil, nil}, 85 {``, ``}, 86 {`""`, ``}, 87 {`''`, `''`}, 88 {`"a"`, `a`}, 89 {`3`, `3`}, 90 {`{"a": "b"}`, `{"a": "b"}`}, 91 {`{"a": "b"}`, `{"a": "b"}`}, 92 {`"hello,\"quoted string\",world"`, `hello,"quoted string",world`}, 93 {`"hello,\"宽字符\",world"`, `hello,"宽字符",world`}, 94 {`Invalid Json string\tis OK`, `Invalid Json string\tis OK`}, 95 {`"1\\u2232\\u22322"`, `1\u2232\u22322`}, 96 {`"[{\"x\":\"{\\\"y\\\":12}\"}]"`, `[{"x":"{\"y\":12}"}]`}, 97 {`[{\"x\":\"{\\\"y\\\":12}\"}]`, `[{\"x\":\"{\\\"y\\\":12}\"}]`}, 98 } 99 dtbl := tblToDtbl(tbl) 100 for _, t := range dtbl { 101 f, err := fc.getFunction(s.ctx, s.datumsToConstants(t["Input"])) 102 c.Assert(err, IsNil) 103 d, err := evalBuiltinFunc(f, chunk.Event{}) 104 c.Assert(err, IsNil) 105 c.Assert(d, solitonutil.CausetEquals, t["Expected"][0]) 106 } 107 } 108 109 func (s *testEvaluatorSuite) TestJSONExtract(c *C) { 110 fc := funcs[ast.JSONExtract] 111 jstr := `{"a": [{"aa": [{"aaa": 1}]}], "aaa": 2}` 112 tbl := []struct { 113 Input []interface{} 114 Expected interface{} 115 Success bool 116 }{ 117 {[]interface{}{nil, nil}, nil, true}, 118 {[]interface{}{jstr, `$.a[0].aa[0].aaa`, `$.aaa`}, `[1, 2]`, true}, 119 {[]interface{}{jstr, `$.a[0].aa[0].aaa`, `$InvalidPath`}, nil, false}, 120 } 121 for _, t := range tbl { 122 args := types.MakeCausets(t.Input...) 123 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 124 c.Assert(err, IsNil) 125 d, err := evalBuiltinFunc(f, chunk.Event{}) 126 if t.Success { 127 c.Assert(err, IsNil) 128 switch x := t.Expected.(type) { 129 case string: 130 var j1 json.BinaryJSON 131 j1, err = json.ParseBinaryFromString(x) 132 c.Assert(err, IsNil) 133 j2 := d.GetMysqlJSON() 134 var cmp int 135 cmp = json.CompareBinary(j1, j2) 136 c.Assert(err, IsNil) 137 c.Assert(cmp, Equals, 0) 138 } 139 } else { 140 c.Assert(err, NotNil) 141 } 142 } 143 } 144 145 // TestJSONSetInsertReplace tests grammar of json_{set,insert,replace}. 146 func (s *testEvaluatorSuite) TestJSONSetInsertReplace(c *C) { 147 tbl := []struct { 148 fc functionClass 149 Input []interface{} 150 Expected interface{} 151 BuildSuccess bool 152 Success bool 153 }{ 154 {funcs[ast.JSONSet], []interface{}{nil, nil, nil}, nil, true, true}, 155 {funcs[ast.JSONSet], []interface{}{`{}`, `$.a`, 3}, `{"a": 3}`, true, true}, 156 {funcs[ast.JSONInsert], []interface{}{`{}`, `$.a`, 3}, `{"a": 3}`, true, true}, 157 {funcs[ast.JSONReplace], []interface{}{`{}`, `$.a`, 3}, `{}`, true, true}, 158 {funcs[ast.JSONSet], []interface{}{`{}`, `$.a`, 3, `$.b`, "3"}, `{"a": 3, "b": "3"}`, true, true}, 159 {funcs[ast.JSONSet], []interface{}{`{}`, `$.a`, nil, `$.b`, "nil"}, `{"a": null, "b": "nil"}`, true, true}, 160 {funcs[ast.JSONSet], []interface{}{`{}`, `$.a`, 3, `$.b`}, nil, false, false}, 161 {funcs[ast.JSONSet], []interface{}{`{}`, `$InvalidPath`, 3}, nil, true, false}, 162 } 163 var err error 164 var f builtinFunc 165 var d types.Causet 166 for _, t := range tbl { 167 args := types.MakeCausets(t.Input...) 168 f, err = t.fc.getFunction(s.ctx, s.datumsToConstants(args)) 169 if t.BuildSuccess { 170 c.Assert(err, IsNil) 171 d, err = evalBuiltinFunc(f, chunk.Event{}) 172 if t.Success { 173 c.Assert(err, IsNil) 174 switch x := t.Expected.(type) { 175 case string: 176 var j1 json.BinaryJSON 177 j1, err = json.ParseBinaryFromString(x) 178 c.Assert(err, IsNil) 179 j2 := d.GetMysqlJSON() 180 var cmp int 181 cmp = json.CompareBinary(j1, j2) 182 c.Assert(cmp, Equals, 0) 183 } 184 continue 185 } 186 } 187 c.Assert(err, NotNil) 188 } 189 } 190 191 func (s *testEvaluatorSuite) TestJSONMerge(c *C) { 192 fc := funcs[ast.JSONMerge] 193 tbl := []struct { 194 Input []interface{} 195 Expected interface{} 196 }{ 197 {[]interface{}{nil, nil}, nil}, 198 {[]interface{}{`{}`, `[]`}, `[{}]`}, 199 {[]interface{}{`{}`, `[]`, `3`, `"4"`}, `[{}, 3, "4"]`}, 200 } 201 for _, t := range tbl { 202 args := types.MakeCausets(t.Input...) 203 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 204 c.Assert(err, IsNil) 205 d, err := evalBuiltinFunc(f, chunk.Event{}) 206 c.Assert(err, IsNil) 207 208 switch x := t.Expected.(type) { 209 case string: 210 j1, err := json.ParseBinaryFromString(x) 211 c.Assert(err, IsNil) 212 j2 := d.GetMysqlJSON() 213 cmp := json.CompareBinary(j1, j2) 214 c.Assert(cmp, Equals, 0, Commentf("got %v expect %v", j1.String(), j2.String())) 215 case nil: 216 c.Assert(d.IsNull(), IsTrue) 217 } 218 } 219 } 220 221 func (s *testEvaluatorSuite) TestJSONMergePreserve(c *C) { 222 fc := funcs[ast.JSONMergePreserve] 223 tbl := []struct { 224 Input []interface{} 225 Expected interface{} 226 }{ 227 {[]interface{}{nil, nil}, nil}, 228 {[]interface{}{`{}`, `[]`}, `[{}]`}, 229 {[]interface{}{`{}`, `[]`, `3`, `"4"`}, `[{}, 3, "4"]`}, 230 } 231 for _, t := range tbl { 232 args := types.MakeCausets(t.Input...) 233 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 234 c.Assert(err, IsNil) 235 d, err := evalBuiltinFunc(f, chunk.Event{}) 236 c.Assert(err, IsNil) 237 238 switch x := t.Expected.(type) { 239 case string: 240 j1, err := json.ParseBinaryFromString(x) 241 c.Assert(err, IsNil) 242 j2 := d.GetMysqlJSON() 243 cmp := json.CompareBinary(j1, j2) 244 c.Assert(cmp, Equals, 0, Commentf("got %v expect %v", j1.String(), j2.String())) 245 case nil: 246 c.Assert(d.IsNull(), IsTrue) 247 } 248 } 249 } 250 251 func (s *testEvaluatorSuite) TestJSONArray(c *C) { 252 fc := funcs[ast.JSONArray] 253 tbl := []struct { 254 Input []interface{} 255 Expected string 256 }{ 257 {[]interface{}{1}, `[1]`}, 258 {[]interface{}{nil, "a", 3, `{"a": "b"}`}, `[null, "a", 3, "{\"a\": \"b\"}"]`}, 259 } 260 for _, t := range tbl { 261 args := types.MakeCausets(t.Input...) 262 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 263 c.Assert(err, IsNil) 264 d, err := evalBuiltinFunc(f, chunk.Event{}) 265 c.Assert(err, IsNil) 266 267 j1, err := json.ParseBinaryFromString(t.Expected) 268 c.Assert(err, IsNil) 269 j2 := d.GetMysqlJSON() 270 cmp := json.CompareBinary(j1, j2) 271 c.Assert(cmp, Equals, 0) 272 } 273 } 274 275 func (s *testEvaluatorSuite) TestJSONObject(c *C) { 276 fc := funcs[ast.JSONObject] 277 tbl := []struct { 278 Input []interface{} 279 Expected interface{} 280 BuildSuccess bool 281 Success bool 282 }{ 283 {[]interface{}{1, 2, 3}, nil, false, false}, 284 {[]interface{}{1, 2, "hello", nil}, `{"1": 2, "hello": null}`, true, true}, 285 {[]interface{}{nil, 2}, nil, true, false}, 286 287 // MilevaDB can only tell booleans from BerolinaSQL. 288 {[]interface{}{1, true}, `{"1": 1}`, true, true}, 289 } 290 var err error 291 var f builtinFunc 292 var d types.Causet 293 for _, t := range tbl { 294 args := types.MakeCausets(t.Input...) 295 f, err = fc.getFunction(s.ctx, s.datumsToConstants(args)) 296 if t.BuildSuccess { 297 c.Assert(err, IsNil) 298 d, err = evalBuiltinFunc(f, chunk.Event{}) 299 if t.Success { 300 c.Assert(err, IsNil) 301 switch x := t.Expected.(type) { 302 case string: 303 var j1 json.BinaryJSON 304 j1, err = json.ParseBinaryFromString(x) 305 c.Assert(err, IsNil) 306 j2 := d.GetMysqlJSON() 307 var cmp int 308 cmp = json.CompareBinary(j1, j2) 309 c.Assert(cmp, Equals, 0) 310 } 311 continue 312 } 313 } 314 c.Assert(err, NotNil) 315 } 316 } 317 318 func (s *testEvaluatorSuite) TestJSONRemove(c *C) { 319 fc := funcs[ast.JSONRemove] 320 tbl := []struct { 321 Input []interface{} 322 Expected interface{} 323 Success bool 324 }{ 325 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$"}, nil, false}, 326 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.*"}, nil, false}, 327 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$[*]"}, nil, false}, 328 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$**.a"}, nil, false}, 329 330 {[]interface{}{nil, "$.a"}, nil, true}, 331 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.a[2].aa"}, `{"a": [1, 2, {}]}`, true}, 332 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.a[1]"}, `{"a": [1, {"aa": "xx"}]}`, true}, 333 334 // Tests multi path memexs. 335 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.a[2].aa", "$.a[1]"}, `{"a": [1, {}]}`, true}, 336 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.a[1]", "$.a[1].aa"}, `{"a": [1, {}]}`, true}, 337 338 // Tests path memexs not exists. 339 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.a[3]"}, `{"a": [1, 2, {"aa": "xx"}]}`, true}, 340 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.b"}, `{"a": [1, 2, {"aa": "xx"}]}`, true}, 341 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.a[3]", "$.b"}, `{"a": [1, 2, {"aa": "xx"}]}`, true}, 342 } 343 for _, t := range tbl { 344 args := types.MakeCausets(t.Input...) 345 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 346 c.Assert(err, IsNil) 347 d, err := evalBuiltinFunc(f, chunk.Event{}) 348 349 if t.Success { 350 c.Assert(err, IsNil) 351 switch x := t.Expected.(type) { 352 case string: 353 var j1 json.BinaryJSON 354 j1, err = json.ParseBinaryFromString(x) 355 c.Assert(err, IsNil) 356 j2 := d.GetMysqlJSON() 357 var cmp int 358 cmp = json.CompareBinary(j1, j2) 359 c.Assert(cmp, Equals, 0, Commentf("got %v expect %v", j2.Value, j1.Value)) 360 } 361 } else { 362 c.Assert(err, NotNil) 363 } 364 } 365 } 366 367 func (s *testEvaluatorSuite) TestJSONContains(c *C) { 368 fc := funcs[ast.JSONContains] 369 tbl := []struct { 370 input []interface{} 371 expected interface{} 372 err error 373 }{ 374 // Tests nil arguments 375 {[]interface{}{nil, `1`, "$.c"}, nil, nil}, 376 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, nil, "$.a[3]"}, nil, nil}, 377 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, `1`, nil}, nil, nil}, 378 // Tests with path memex 379 {[]interface{}{`[1,2,[1,[5,[3]]]]`, `[1,3]`, "$[2]"}, 1, nil}, 380 {[]interface{}{`[1,2,[1,[5,{"a":[2,3]}]]]`, `[1,{"a":[3]}]`, "$[2]"}, 1, nil}, 381 {[]interface{}{`[{"a":1}]`, `{"a":1}`, "$"}, 1, nil}, 382 {[]interface{}{`[{"a":1,"b":2}]`, `{"a":1,"b":2}`, "$"}, 1, nil}, 383 {[]interface{}{`[{"a":{"a":1},"b":2}]`, `{"a":1}`, "$.a"}, 0, nil}, 384 // Tests without path memex 385 {[]interface{}{`{}`, `{}`}, 1, nil}, 386 {[]interface{}{`{"a":1}`, `{}`}, 1, nil}, 387 {[]interface{}{`{"a":1}`, `1`}, 0, nil}, 388 {[]interface{}{`{"a":[1]}`, `[1]`}, 0, nil}, 389 {[]interface{}{`{"b":2, "c":3}`, `{"c":3}`}, 1, nil}, 390 {[]interface{}{`1`, `1`}, 1, nil}, 391 {[]interface{}{`[1]`, `1`}, 1, nil}, 392 {[]interface{}{`[1,2]`, `[1]`}, 1, nil}, 393 {[]interface{}{`[1,2]`, `[1,3]`}, 0, nil}, 394 {[]interface{}{`[1,2]`, `["1"]`}, 0, nil}, 395 {[]interface{}{`[1,2,[1,3]]`, `[1,3]`}, 1, nil}, 396 {[]interface{}{`[1,2,[1,3]]`, `[1, 3]`}, 1, nil}, 397 {[]interface{}{`[1,2,[1,[5,[3]]]]`, `[1,3]`}, 1, nil}, 398 {[]interface{}{`[1,2,[1,[5,{"a":[2,3]}]]]`, `[1,{"a":[3]}]`}, 1, nil}, 399 {[]interface{}{`[{"a":1}]`, `{"a":1}`}, 1, nil}, 400 {[]interface{}{`[{"a":1,"b":2}]`, `{"a":1}`}, 1, nil}, 401 {[]interface{}{`[{"a":{"a":1},"b":2}]`, `{"a":1}`}, 0, nil}, 402 // Tests path memex contains any asterisk 403 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, `1`, "$.*"}, nil, json.ErrInvalidJSONPathWildcard}, 404 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, `1`, "$[*]"}, nil, json.ErrInvalidJSONPathWildcard}, 405 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, `1`, "$**.a"}, nil, json.ErrInvalidJSONPathWildcard}, 406 // Tests path memex does not identify a section of the target document 407 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, `1`, "$.c"}, nil, nil}, 408 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, `1`, "$.a[3]"}, nil, nil}, 409 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, `1`, "$.a[2].b"}, nil, nil}, 410 // For issue 9957: test 'argument 1 and 2 as valid json object' 411 {[]interface{}{`[1,2,[1,3]]`, `a:1`}, 1, json.ErrInvalidJSONText}, 412 {[]interface{}{`a:1`, `1`}, 1, json.ErrInvalidJSONText}, 413 } 414 for _, t := range tbl { 415 args := types.MakeCausets(t.input...) 416 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 417 c.Assert(err, IsNil) 418 d, err := evalBuiltinFunc(f, chunk.Event{}) 419 if t.err == nil { 420 c.Assert(err, IsNil) 421 if t.expected == nil { 422 c.Assert(d.IsNull(), IsTrue) 423 } else { 424 c.Assert(d.GetInt64(), Equals, int64(t.expected.(int))) 425 } 426 } else { 427 c.Assert(t.err.(*terror.Error).Equal(err), IsTrue) 428 } 429 } 430 // For issue 9957: test 'argument 1 and 2 as valid json object' 431 cases := []struct { 432 arg1 interface{} 433 arg2 interface{} 434 }{ 435 {1, ""}, 436 {0.05, ""}, 437 {"", 1}, 438 {"", 0.05}, 439 } 440 for _, cs := range cases { 441 _, err := fc.getFunction(s.ctx, s.datumsToConstants(types.MakeCausets(cs.arg1, cs.arg2))) 442 c.Assert(json.ErrInvalidJSONData.Equal(err), IsTrue) 443 } 444 } 445 446 func (s *testEvaluatorSuite) TestJSONContainsPath(c *C) { 447 fc := funcs[ast.JSONContainsPath] 448 jsonString := `{"a": 1, "b": 2, "c": {"d": 4}}` 449 invalidJSON := `{"a": 1` 450 tbl := []struct { 451 input []interface{} 452 expected interface{} 453 success bool 454 }{ 455 // Tests nil arguments 456 {[]interface{}{nil, json.ContainsPathOne, "$.c"}, nil, true}, 457 {[]interface{}{nil, json.ContainsPathAll, "$.c"}, nil, true}, 458 {[]interface{}{jsonString, nil, "$.a[3]"}, nil, true}, 459 {[]interface{}{jsonString, json.ContainsPathOne, nil}, nil, true}, 460 {[]interface{}{jsonString, json.ContainsPathAll, nil}, nil, true}, 461 // Tests with one path memex 462 {[]interface{}{jsonString, json.ContainsPathOne, "$.c.d"}, 1, true}, 463 {[]interface{}{jsonString, json.ContainsPathOne, "$.a.d"}, 0, true}, 464 {[]interface{}{jsonString, json.ContainsPathAll, "$.c.d"}, 1, true}, 465 {[]interface{}{jsonString, json.ContainsPathAll, "$.a.d"}, 0, true}, 466 // Tests with multiple path memex 467 {[]interface{}{jsonString, json.ContainsPathOne, "$.a", "$.e"}, 1, true}, 468 {[]interface{}{jsonString, json.ContainsPathOne, "$.a", "$.c"}, 1, true}, 469 {[]interface{}{jsonString, json.ContainsPathAll, "$.a", "$.e"}, 0, true}, 470 {[]interface{}{jsonString, json.ContainsPathAll, "$.a", "$.c"}, 1, true}, 471 // Tests path memex contains any asterisk 472 {[]interface{}{jsonString, json.ContainsPathOne, "$.*"}, 1, true}, 473 {[]interface{}{jsonString, json.ContainsPathOne, "$[*]"}, 0, true}, 474 {[]interface{}{jsonString, json.ContainsPathAll, "$.*"}, 1, true}, 475 {[]interface{}{jsonString, json.ContainsPathAll, "$[*]"}, 0, true}, 476 // Tests invalid json document 477 {[]interface{}{invalidJSON, json.ContainsPathOne, "$.a"}, nil, false}, 478 {[]interface{}{invalidJSON, json.ContainsPathAll, "$.a"}, nil, false}, 479 // Tests compatible contains path 480 {[]interface{}{jsonString, "ONE", "$.c.d"}, 1, true}, 481 {[]interface{}{jsonString, "ALL", "$.c.d"}, 1, true}, 482 {[]interface{}{jsonString, "One", "$.a", "$.e"}, 1, true}, 483 {[]interface{}{jsonString, "aLl", "$.a", "$.e"}, 0, true}, 484 {[]interface{}{jsonString, "test", "$.a"}, nil, false}, 485 } 486 for _, t := range tbl { 487 args := types.MakeCausets(t.input...) 488 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 489 c.Assert(err, IsNil) 490 d, err := evalBuiltinFunc(f, chunk.Event{}) 491 if t.success { 492 c.Assert(err, IsNil) 493 if t.expected == nil { 494 c.Assert(d.IsNull(), IsTrue) 495 } else { 496 c.Assert(d.GetInt64(), Equals, int64(t.expected.(int))) 497 } 498 } else { 499 c.Assert(err, NotNil) 500 } 501 } 502 } 503 504 func (s *testEvaluatorSuite) TestJSONLength(c *C) { 505 fc := funcs[ast.JSONLength] 506 tbl := []struct { 507 input []interface{} 508 expected interface{} 509 success bool 510 }{ 511 // Tests scalar arguments 512 {[]interface{}{`null`}, 1, true}, 513 {[]interface{}{`true`}, 1, true}, 514 {[]interface{}{`false`}, 1, true}, 515 {[]interface{}{`1`}, 1, true}, 516 {[]interface{}{`-1`}, 1, true}, 517 {[]interface{}{`1.1`}, 1, true}, 518 {[]interface{}{`"1"`}, 1, true}, 519 {[]interface{}{`"1"`, "$.a"}, 1, true}, 520 {[]interface{}{`null`, "$.a"}, 1, true}, 521 // Tests nil arguments 522 {[]interface{}{nil}, nil, true}, 523 {[]interface{}{nil, "a"}, nil, true}, 524 {[]interface{}{`{"a": 1}`, nil}, nil, true}, 525 {[]interface{}{nil, nil}, nil, true}, 526 // Tests with path memex 527 {[]interface{}{`[1,2,[1,[5,[3]]]]`, "$[2]"}, 2, true}, 528 {[]interface{}{`[{"a":1}]`, "$"}, 1, true}, 529 {[]interface{}{`[{"a":1,"b":2}]`, "$[0].a"}, 1, true}, 530 {[]interface{}{`{"a":{"a":1},"b":2}`, "$"}, 2, true}, 531 {[]interface{}{`{"a":{"a":1},"b":2}`, "$.a"}, 1, true}, 532 {[]interface{}{`{"a":{"a":1},"b":2}`, "$.a.a"}, 1, true}, 533 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.a[2].aa"}, 1, true}, 534 // Tests without path memex 535 {[]interface{}{`{}`}, 0, true}, 536 {[]interface{}{`{"a":1}`}, 1, true}, 537 {[]interface{}{`{"a":[1]}`}, 1, true}, 538 {[]interface{}{`{"b":2, "c":3}`}, 2, true}, 539 {[]interface{}{`[1]`}, 1, true}, 540 {[]interface{}{`[1,2]`}, 2, true}, 541 {[]interface{}{`[1,2,[1,3]]`}, 3, true}, 542 {[]interface{}{`[1,2,[1,[5,[3]]]]`}, 3, true}, 543 {[]interface{}{`[1,2,[1,[5,{"a":[2,3]}]]]`}, 3, true}, 544 {[]interface{}{`[{"a":1}]`}, 1, true}, 545 {[]interface{}{`[{"a":1,"b":2}]`}, 1, true}, 546 {[]interface{}{`[{"a":{"a":1},"b":2}]`}, 1, true}, 547 // Tests path memex contains any asterisk 548 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.*"}, nil, false}, 549 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$[*]"}, nil, false}, 550 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$**.a"}, nil, false}, 551 // Tests path memex does not identify a section of the target document 552 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.c"}, nil, true}, 553 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.a[3]"}, nil, true}, 554 {[]interface{}{`{"a": [1, 2, {"aa": "xx"}]}`, "$.a[2].b"}, nil, true}, 555 } 556 for _, t := range tbl { 557 args := types.MakeCausets(t.input...) 558 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 559 c.Assert(err, IsNil) 560 d, err := evalBuiltinFunc(f, chunk.Event{}) 561 if t.success { 562 c.Assert(err, IsNil) 563 564 if t.expected == nil { 565 c.Assert(d.IsNull(), IsTrue) 566 } else { 567 c.Assert(d.GetInt64(), Equals, int64(t.expected.(int))) 568 } 569 } else { 570 c.Assert(err, NotNil) 571 } 572 } 573 } 574 575 func (s *testEvaluatorSuite) TestJSONKeys(c *C) { 576 fc := funcs[ast.JSONKeys] 577 tbl := []struct { 578 input []interface{} 579 expected interface{} 580 success bool 581 }{ 582 583 // Tests nil arguments 584 {[]interface{}{nil}, nil, true}, 585 {[]interface{}{nil, "$.c"}, nil, true}, 586 {[]interface{}{`{"a": 1}`, nil}, nil, true}, 587 {[]interface{}{nil, nil}, nil, true}, 588 589 // Tests with other type 590 {[]interface{}{`1`}, nil, true}, 591 {[]interface{}{`"str"`}, nil, true}, 592 {[]interface{}{`true`}, nil, true}, 593 {[]interface{}{`null`}, nil, true}, 594 {[]interface{}{`[1, 2]`}, nil, true}, 595 {[]interface{}{`["1", "2"]`}, nil, true}, 596 597 // Tests without path memex 598 {[]interface{}{`{}`}, `[]`, true}, 599 {[]interface{}{`{"a": 1}`}, `["a"]`, true}, 600 {[]interface{}{`{"a": 1, "b": 2}`}, `["a", "b"]`, true}, 601 {[]interface{}{`{"a": {"c": 3}, "b": 2}`}, `["a", "b"]`, true}, 602 603 // Tests with path memex 604 {[]interface{}{`{"a": 1}`, "$.a"}, nil, true}, 605 {[]interface{}{`{"a": {"c": 3}, "b": 2}`, "$.a"}, `["c"]`, true}, 606 {[]interface{}{`{"a": {"c": 3}, "b": 2}`, "$.a.c"}, nil, true}, 607 {[]interface{}{`{"a": {"c": 3}, "b": 2}`, nil}, nil, true}, 608 609 // Tests path memex contains any asterisk 610 {[]interface{}{`{}`, "$.*"}, nil, false}, 611 {[]interface{}{`{"a": 1}`, "$.*"}, nil, false}, 612 {[]interface{}{`{"a": {"c": 3}, "b": 2}`, "$.*"}, nil, false}, 613 {[]interface{}{`{"a": {"c": 3}, "b": 2}`, "$.a.*"}, nil, false}, 614 615 // Tests path memex does not identify a section of the target document 616 {[]interface{}{`{"a": 1}`, "$.b"}, nil, true}, 617 {[]interface{}{`{"a": {"c": 3}, "b": 2}`, "$.c"}, nil, true}, 618 {[]interface{}{`{"a": {"c": 3}, "b": 2}`, "$.a.d"}, nil, true}, 619 } 620 for _, t := range tbl { 621 args := types.MakeCausets(t.input...) 622 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 623 c.Assert(err, IsNil) 624 d, err := evalBuiltinFunc(f, chunk.Event{}) 625 if t.success { 626 c.Assert(err, IsNil) 627 switch x := t.expected.(type) { 628 case string: 629 var j1 json.BinaryJSON 630 j1, err = json.ParseBinaryFromString(x) 631 c.Assert(err, IsNil) 632 j2 := d.GetMysqlJSON() 633 var cmp int 634 cmp = json.CompareBinary(j1, j2) 635 c.Assert(cmp, Equals, 0) 636 case nil: 637 c.Assert(d.IsNull(), IsTrue) 638 } 639 } else { 640 c.Assert(err, NotNil) 641 } 642 } 643 } 644 645 func (s *testEvaluatorSuite) TestJSONDepth(c *C) { 646 fc := funcs[ast.JSONDepth] 647 tbl := []struct { 648 input []interface{} 649 expected interface{} 650 success bool 651 }{ 652 // Tests scalar arguments 653 {[]interface{}{`null`}, 1, true}, 654 {[]interface{}{`true`}, 1, true}, 655 {[]interface{}{`false`}, 1, true}, 656 {[]interface{}{`1`}, 1, true}, 657 {[]interface{}{`-1`}, 1, true}, 658 {[]interface{}{`1.1`}, 1, true}, 659 {[]interface{}{`"1"`}, 1, true}, 660 // Tests nil arguments 661 {[]interface{}{nil}, nil, true}, 662 // Tests depth 663 {[]interface{}{`{}`}, 1, true}, 664 {[]interface{}{`[]`}, 1, true}, 665 {[]interface{}{`[10, 20]`}, 2, true}, 666 {[]interface{}{`[[], {}]`}, 2, true}, 667 {[]interface{}{`{"Name": "Homer"}`}, 2, true}, 668 {[]interface{}{`[10, {"a": 20}]`}, 3, true}, 669 {[]interface{}{`{"Person": {"Name": "Homer", "Age": 39, "Hobbies": ["Eating", "Sleeping"]} }`}, 4, true}, 670 {[]interface{}{`{"a":1}`}, 2, true}, 671 {[]interface{}{`{"a":[1]}`}, 3, true}, 672 {[]interface{}{`{"b":2, "c":3}`}, 2, true}, 673 {[]interface{}{`[1]`}, 2, true}, 674 {[]interface{}{`[1,2]`}, 2, true}, 675 {[]interface{}{`[1,2,[1,3]]`}, 3, true}, 676 {[]interface{}{`[1,2,[1,[5,[3]]]]`}, 5, true}, 677 {[]interface{}{`[1,2,[1,[5,{"a":[2,3]}]]]`}, 6, true}, 678 {[]interface{}{`[{"a":1}]`}, 3, true}, 679 {[]interface{}{`[{"a":1,"b":2}]`}, 3, true}, 680 {[]interface{}{`[{"a":{"a":1},"b":2}]`}, 4, true}, 681 // Tests non-json 682 {[]interface{}{`a`}, nil, false}, 683 } 684 for _, t := range tbl { 685 args := types.MakeCausets(t.input...) 686 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 687 c.Assert(err, IsNil) 688 d, err := evalBuiltinFunc(f, chunk.Event{}) 689 if t.success { 690 c.Assert(err, IsNil) 691 692 if t.expected == nil { 693 c.Assert(d.IsNull(), IsTrue) 694 } else { 695 c.Assert(d.GetInt64(), Equals, int64(t.expected.(int))) 696 } 697 } else { 698 c.Assert(err, NotNil) 699 } 700 } 701 } 702 703 func (s *testEvaluatorSuite) TestJSONArrayAppend(c *C) { 704 sampleJSON, err := json.ParseBinaryFromString(`{"b": 2}`) 705 c.Assert(err, IsNil) 706 fc := funcs[ast.JSONArrayAppend] 707 tbl := []struct { 708 input []interface{} 709 expected interface{} 710 err *terror.Error 711 }{ 712 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.d`, `z`}, `{"a": 1, "b": [2, 3], "c": 4}`, nil}, 713 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$`, `w`}, `[{"a": 1, "b": [2, 3], "c": 4}, "w"]`, nil}, 714 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$`, nil}, `[{"a": 1, "b": [2, 3], "c": 4}, null]`, nil}, 715 {[]interface{}{`{"a": 1}`, `$`, `{"b": 2}`}, `[{"a": 1}, "{\"b\": 2}"]`, nil}, 716 {[]interface{}{`{"a": 1}`, `$`, sampleJSON}, `[{"a": 1}, {"b": 2}]`, nil}, 717 {[]interface{}{`{"a": 1}`, `$.a`, sampleJSON}, `{"a": [1, {"b": 2}]}`, nil}, 718 719 {[]interface{}{`{"a": 1}`, `$.a`, sampleJSON, `$.a[1]`, sampleJSON}, `{"a": [1, [{"b": 2}, {"b": 2}]]}`, nil}, 720 {[]interface{}{nil, `$`, nil}, nil, nil}, 721 {[]interface{}{nil, `$`, `a`}, nil, nil}, 722 {[]interface{}{`null`, `$`, nil}, `[null, null]`, nil}, 723 {[]interface{}{`[]`, `$`, nil}, `[null]`, nil}, 724 {[]interface{}{`{}`, `$`, nil}, `[{}, null]`, nil}, 725 // Bad arguments. 726 {[]interface{}{`asdf`, `$`, nil}, nil, json.ErrInvalidJSONText}, 727 {[]interface{}{``, `$`, nil}, nil, json.ErrInvalidJSONText}, 728 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.d`}, nil, ErrIncorrectParameterCount}, 729 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.c`, `y`, `$.b`}, nil, ErrIncorrectParameterCount}, 730 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, nil, nil}, nil, nil}, 731 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `asdf`, nil}, nil, json.ErrInvalidJSONPath}, 732 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, 42, nil}, nil, json.ErrInvalidJSONPath}, 733 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.*`, nil}, nil, json.ErrInvalidJSONPathWildcard}, 734 // Following tests come from MyALLEGROSQL doc. 735 {[]interface{}{`["a", ["b", "c"], "d"]`, `$[1]`, 1}, `["a", ["b", "c", 1], "d"]`, nil}, 736 {[]interface{}{`["a", ["b", "c"], "d"]`, `$[0]`, 2}, `[["a", 2], ["b", "c"], "d"]`, nil}, 737 {[]interface{}{`["a", ["b", "c"], "d"]`, `$[1][0]`, 3}, `["a", [["b", 3], "c"], "d"]`, nil}, 738 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.b`, `x`}, `{"a": 1, "b": [2, 3, "x"], "c": 4}`, nil}, 739 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.c`, `y`}, `{"a": 1, "b": [2, 3], "c": [4, "y"]}`, nil}, 740 // Following tests come from MyALLEGROSQL test. 741 {[]interface{}{`[1,2,3, {"a":[4,5,6]}]`, `$`, 7}, `[1, 2, 3, {"a": [4, 5, 6]}, 7]`, nil}, 742 {[]interface{}{`[1,2,3, {"a":[4,5,6]}]`, `$`, 7, `$[3].a`, 3.14}, `[1, 2, 3, {"a": [4, 5, 6, 3.14]}, 7]`, nil}, 743 {[]interface{}{`[1,2,3, {"a":[4,5,6]}]`, `$`, 7, `$[3].b`, 8}, `[1, 2, 3, {"a": [4, 5, 6]}, 7]`, nil}, 744 } 745 746 for i, t := range tbl { 747 args := types.MakeCausets(t.input...) 748 s.ctx.GetStochastikVars().StmtCtx.SetWarnings(nil) 749 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 750 // No error should return in getFunction if t.err is nil. 751 if err != nil { 752 c.Assert(t.err, NotNil) 753 c.Assert(t.err.Equal(err), Equals, true) 754 continue 755 } 756 757 c.Assert(f, NotNil) 758 d, err := evalBuiltinFunc(f, chunk.Event{}) 759 comment := Commentf("case:%v \n input:%v \n output: %s \n expected: %v \n warnings: %v \n expected error %v", i, t.input, d.GetMysqlJSON(), t.expected, s.ctx.GetStochastikVars().StmtCtx.GetWarnings(), t.err) 760 761 if t.err != nil { 762 c.Assert(t.err.Equal(err), Equals, true, comment) 763 continue 764 } 765 766 c.Assert(err, IsNil, comment) 767 c.Assert(int(s.ctx.GetStochastikVars().StmtCtx.WarningCount()), Equals, 0, comment) 768 769 if t.expected == nil { 770 c.Assert(d.IsNull(), IsTrue, comment) 771 continue 772 } 773 774 j1, err := json.ParseBinaryFromString(t.expected.(string)) 775 776 c.Assert(err, IsNil, comment) 777 c.Assert(json.CompareBinary(j1, d.GetMysqlJSON()), Equals, 0, comment) 778 } 779 } 780 781 func (s *testEvaluatorSuite) TestJSONSearch(c *C) { 782 fc := funcs[ast.JSONSearch] 783 jsonString := `["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]` 784 jsonString2 := `["abc", [{"k": "10"}, "def"], {"x":"ab%d"}, {"y":"abcd"}]` 785 tbl := []struct { 786 input []interface{} 787 expected interface{} 788 success bool 789 }{ 790 // simple case 791 {[]interface{}{jsonString, `one`, `abc`}, `"$[0]"`, true}, 792 {[]interface{}{jsonString, `all`, `abc`}, `["$[0]", "$[2].x"]`, true}, 793 {[]interface{}{jsonString, `all`, `ghi`}, nil, true}, 794 {[]interface{}{jsonString, `ALL`, `ghi`}, nil, true}, 795 {[]interface{}{jsonString, `all`, `10`}, `"$[1][0].k"`, true}, 796 {[]interface{}{jsonString, `all`, `10`, nil, `$`}, `"$[1][0].k"`, true}, 797 {[]interface{}{jsonString, `all`, `10`, nil, `$[*]`}, `"$[1][0].k"`, true}, 798 {[]interface{}{jsonString, `all`, `10`, nil, `$**.k`}, `"$[1][0].k"`, true}, 799 {[]interface{}{jsonString, `all`, `10`, nil, `$[*][0].k`}, `"$[1][0].k"`, true}, 800 {[]interface{}{jsonString, `all`, `10`, nil, `$[1]`}, `"$[1][0].k"`, true}, 801 {[]interface{}{jsonString, `all`, `10`, nil, `$[1][0]`}, `"$[1][0].k"`, true}, 802 {[]interface{}{jsonString, `all`, `abc`, nil, `$[2]`}, `"$[2].x"`, true}, 803 {[]interface{}{jsonString, `all`, `abc`, nil, `$[2]`, `$[0]`}, `["$[2].x", "$[0]"]`, true}, 804 {[]interface{}{jsonString, `all`, `abc`, nil, `$[2]`, `$[2]`}, `"$[2].x"`, true}, 805 806 // search pattern 807 {[]interface{}{jsonString, `all`, `%a%`}, `["$[0]", "$[2].x"]`, true}, 808 {[]interface{}{jsonString, `all`, `%b%`}, `["$[0]", "$[2].x", "$[3].y"]`, true}, 809 {[]interface{}{jsonString, `all`, `%b%`, nil, `$[0]`}, `"$[0]"`, true}, 810 {[]interface{}{jsonString, `all`, `%b%`, nil, `$[2]`}, `"$[2].x"`, true}, 811 {[]interface{}{jsonString, `all`, `%b%`, nil, `$[1]`}, nil, true}, 812 {[]interface{}{jsonString, `all`, `%b%`, ``, `$[1]`}, nil, true}, 813 {[]interface{}{jsonString, `all`, `%b%`, nil, `$[3]`}, `"$[3].y"`, true}, 814 {[]interface{}{jsonString2, `all`, `ab_d`}, `["$[2].x", "$[3].y"]`, true}, 815 816 // escape char 817 {[]interface{}{jsonString2, `all`, `ab%d`}, `["$[2].x", "$[3].y"]`, true}, 818 {[]interface{}{jsonString2, `all`, `ab\%d`}, `"$[2].x"`, true}, 819 {[]interface{}{jsonString2, `all`, `ab|%d`, `|`}, `"$[2].x"`, true}, 820 821 // error handle 822 {[]interface{}{nil, `all`, `abc`}, nil, true}, // NULL json 823 {[]interface{}{`a`, `all`, `abc`}, nil, false}, // non json 824 {[]interface{}{jsonString, `wrong`, `abc`}, nil, false}, // wrong one_or_all 825 {[]interface{}{jsonString, `all`, nil}, nil, true}, // NULL search_str 826 {[]interface{}{jsonString, `all`, `abc`, `??`}, nil, false}, // wrong escape_char 827 {[]interface{}{jsonString, `all`, `abc`, nil, nil}, nil, true}, // NULL path 828 {[]interface{}{jsonString, `all`, `abc`, nil, `$xx`}, nil, false}, // wrong path 829 {[]interface{}{jsonString, nil, `abc`}, nil, true}, 830 } 831 for _, t := range tbl { 832 args := types.MakeCausets(t.input...) 833 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 834 c.Assert(err, IsNil) 835 d, err := evalBuiltinFunc(f, chunk.Event{}) 836 if t.success { 837 c.Assert(err, IsNil) 838 switch x := t.expected.(type) { 839 case string: 840 var j1, j2 json.BinaryJSON 841 j1, err = json.ParseBinaryFromString(x) 842 c.Assert(err, IsNil) 843 j2 = d.GetMysqlJSON() 844 cmp := json.CompareBinary(j1, j2) 845 c.Assert(cmp, Equals, 0) 846 case nil: 847 c.Assert(d.IsNull(), IsTrue) 848 } 849 } else { 850 c.Assert(err, NotNil) 851 } 852 } 853 } 854 855 func (s *testEvaluatorSuite) TestJSONArrayInsert(c *C) { 856 fc := funcs[ast.JSONArrayInsert] 857 tbl := []struct { 858 input []interface{} 859 expected interface{} 860 success bool 861 err *terror.Error 862 }{ 863 // Success 864 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.b[1]`, `z`}, `{"a": 1, "b": [2, "z", 3], "c": 4}`, true, nil}, 865 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.a[1]`, `z`}, `{"a": 1, "b": [2, 3], "c": 4}`, true, nil}, 866 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.d[1]`, `z`}, `{"a": 1, "b": [2, 3], "c": 4}`, true, nil}, 867 {[]interface{}{`[{"a": 1, "b": [2, 3], "c": 4}]`, `$[1]`, `w`}, `[{"a": 1, "b": [2, 3], "c": 4}, "w"]`, true, nil}, 868 {[]interface{}{`[{"a": 1, "b": [2, 3], "c": 4}]`, `$[0]`, nil}, `[null, {"a": 1, "b": [2, 3], "c": 4}]`, true, nil}, 869 {[]interface{}{`[1, 2, 3]`, `$[100]`, `{"b": 2}`}, `[1, 2, 3, "{\"b\": 2}"]`, true, nil}, 870 // About null 871 {[]interface{}{nil, `$`, nil}, nil, true, nil}, 872 {[]interface{}{nil, `$`, `a`}, nil, true, nil}, 873 {[]interface{}{`[]`, `$[0]`, nil}, `[null]`, true, nil}, 874 {[]interface{}{`{}`, `$[0]`, nil}, `{}`, true, nil}, 875 // Bad arguments 876 {[]interface{}{`asdf`, `$`, nil}, nil, false, json.ErrInvalidJSONText}, 877 {[]interface{}{``, `$`, nil}, nil, false, json.ErrInvalidJSONText}, 878 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.d`}, nil, false, ErrIncorrectParameterCount}, 879 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.c`, `y`, `$.b`}, nil, false, ErrIncorrectParameterCount}, 880 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, nil, nil}, nil, true, nil}, 881 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `asdf`, nil}, nil, false, json.ErrInvalidJSONPath}, 882 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, 42, nil}, nil, false, json.ErrInvalidJSONPath}, 883 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.*`, nil}, nil, false, json.ErrInvalidJSONPathWildcard}, 884 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.b[0]`, nil, `$.a`, nil}, nil, false, json.ErrInvalidJSONPathArrayCell}, 885 {[]interface{}{`{"a": 1, "b": [2, 3], "c": 4}`, `$.a`, nil}, nil, false, json.ErrInvalidJSONPathArrayCell}, 886 // Following tests come from MyALLEGROSQL doc. 887 {[]interface{}{`["a", {"b": [1, 2]}, [3, 4]]`, `$[1]`, `x`}, `["a", "x", {"b": [1, 2]}, [3, 4]]`, true, nil}, 888 {[]interface{}{`["a", {"b": [1, 2]}, [3, 4]]`, `$[100]`, `x`}, `["a", {"b": [1, 2]}, [3, 4], "x"]`, true, nil}, 889 {[]interface{}{`["a", {"b": [1, 2]}, [3, 4]]`, `$[1].b[0]`, `x`}, `["a", {"b": ["x", 1, 2]}, [3, 4]]`, true, nil}, 890 {[]interface{}{`["a", {"b": [1, 2]}, [3, 4]]`, `$[2][1]`, `y`}, `["a", {"b": [1, 2]}, [3, "y", 4]]`, true, nil}, 891 {[]interface{}{`["a", {"b": [1, 2]}, [3, 4]]`, `$[0]`, `x`, `$[2][1]`, `y`}, `["x", "a", {"b": [1, 2]}, [3, 4]]`, true, nil}, 892 // More test cases 893 {[]interface{}{`["a", {"b": [1, 2]}, [3, 4]]`, `$[0]`, `x`, `$[0]`, `y`}, `["y", "x", "a", {"b": [1, 2]}, [3, 4]]`, true, nil}, 894 } 895 for _, t := range tbl { 896 args := types.MakeCausets(t.input...) 897 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 898 // Parameter count error 899 if err != nil { 900 c.Assert(t.err, NotNil) 901 c.Assert(t.err.Equal(err), Equals, true) 902 continue 903 } 904 905 d, err := evalBuiltinFunc(f, chunk.Event{}) 906 907 if t.success { 908 c.Assert(err, IsNil) 909 switch x := t.expected.(type) { 910 case string: 911 var j1, j2 json.BinaryJSON 912 j1, err = json.ParseBinaryFromString(x) 913 c.Assert(err, IsNil) 914 j2 = d.GetMysqlJSON() 915 var cmp int 916 cmp = json.CompareBinary(j1, j2) 917 c.Assert(cmp, Equals, 0) 918 case nil: 919 c.Assert(d.IsNull(), IsTrue) 920 } 921 } else { 922 c.Assert(t.err.Equal(err), Equals, true) 923 } 924 } 925 } 926 927 func (s *testEvaluatorSuite) TestJSONValid(c *C) { 928 fc := funcs[ast.JSONValid] 929 tbl := []struct { 930 Input interface{} 931 Expected interface{} 932 }{ 933 {`{"a":1}`, 1}, 934 {`hello`, 0}, 935 {`"hello"`, 1}, 936 {`null`, 1}, 937 {`{}`, 1}, 938 {`[]`, 1}, 939 {`2`, 1}, 940 {`2.5`, 1}, 941 {`2020-8-19`, 0}, 942 {`"2020-8-19"`, 1}, 943 {2, 0}, 944 {2.5, 0}, 945 {nil, nil}, 946 } 947 dtbl := tblToDtbl(tbl) 948 for _, t := range dtbl { 949 f, err := fc.getFunction(s.ctx, s.datumsToConstants(t["Input"])) 950 c.Assert(err, IsNil) 951 d, err := evalBuiltinFunc(f, chunk.Event{}) 952 c.Assert(err, IsNil) 953 c.Assert(d, solitonutil.CausetEquals, t["Expected"][0]) 954 } 955 } 956 957 func (s *testEvaluatorSuite) TestJSONStorageSize(c *C) { 958 fc := funcs[ast.JSONStorageSize] 959 tbl := []struct { 960 input []interface{} 961 expected interface{} 962 success bool 963 }{ 964 // Tests scalar arguments 965 {[]interface{}{`null`}, 4, true}, 966 {[]interface{}{`true`}, 4, true}, 967 {[]interface{}{`1`}, 1, true}, 968 {[]interface{}{`"1"`}, 3, true}, 969 // Tests nil arguments 970 {[]interface{}{nil}, nil, true}, 971 // Tests valid json documents 972 {[]interface{}{`{}`}, 2, true}, 973 {[]interface{}{`{"a":1}`}, 8, true}, 974 {[]interface{}{`[{"a":{"a":1},"b":2}]`}, 25, true}, 975 {[]interface{}{`{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}`}, 45, true}, 976 // Tests invalid json documents 977 {[]interface{}{`[{"a":1]`}, 0, false}, 978 {[]interface{}{`[{a":1]`}, 0, false}, 979 } 980 for _, t := range tbl { 981 args := types.MakeCausets(t.input...) 982 f, err := fc.getFunction(s.ctx, s.datumsToConstants(args)) 983 c.Assert(err, IsNil) 984 d, err := evalBuiltinFunc(f, chunk.Event{}) 985 if t.success { 986 c.Assert(err, IsNil) 987 988 if t.expected == nil { 989 c.Assert(d.IsNull(), IsTrue) 990 } else { 991 c.Assert(d.GetInt64(), Equals, int64(t.expected.(int))) 992 } 993 } else { 994 c.Assert(err, NotNil) 995 } 996 } 997 }