github.com/dolthub/go-mysql-server@v0.18.0/enginetest/queries/json_scripts.go (about) 1 // Copyright 2021 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 queries 16 17 import ( 18 querypb "github.com/dolthub/vitess/go/vt/proto/query" 19 20 "github.com/dolthub/go-mysql-server/sql" 21 "github.com/dolthub/go-mysql-server/sql/types" 22 ) 23 24 var JsonScripts = []ScriptTest{ 25 { 26 Name: "json_value", 27 SetUpScript: []string{ 28 "CREATE TABLE xy (x bigint primary key, y JSON)", 29 `INSERT INTO xy VALUES (0, CAST('["a", "b"]' AS JSON)), (1, CAST('["a", "b", "c", "d"]' AS JSON));`, 30 `INSERT INTO xy VALUES (2, CAST('{"a": [{"b": 1}, {"c": 2}]}' AS JSON)), (3, CAST('{"a": {"b": ["c","d"]}}' AS JSON)), (4,NULL);`, 31 }, 32 Assertions: []ScriptTestAssertion{ 33 { 34 Query: `select json_value(y, '$.a', 'json') from xy`, 35 Expected: []sql.Row{ 36 {nil}, 37 {nil}, 38 {types.MustJSON("[{\"b\": 1}, {\"c\": 2}]")}, 39 {types.MustJSON("{\"b\": [\"c\",\"d\"]}")}, 40 {nil}, 41 }, 42 }, 43 { 44 Query: `select json_value(y, '$.a[0].b', 'signed') from xy where x = 2`, 45 Expected: []sql.Row{ 46 {int64(1)}, 47 }, 48 }, 49 { 50 Query: `select json_value(y, '$.a[0].b') from xy where x = 2`, 51 Expected: []sql.Row{ 52 {"1"}, 53 }, 54 }, 55 //{ 56 // Query: `select json_value(y, '$.a.b', 'signed') from xy where x = 2`, 57 // Expected: []sql.Row{ 58 // {nil}, 59 // }, 60 //}, 61 }, 62 }, 63 { 64 Name: "json_length", 65 SetUpScript: []string{ 66 "CREATE TABLE xy (x bigint primary key, y JSON)", 67 `INSERT INTO xy VALUES (0, CAST('["a", "b"]' AS JSON)), (1, CAST('["a", "b", "c", "d"]' AS JSON));`, 68 `INSERT INTO xy VALUES (2, CAST('{"a": [{"b": 1}, {"c": 2}]}' AS JSON)), (3, CAST('{"a": {"b": ["c","d"]}}' AS JSON)), (4,NULL);`, 69 }, 70 Assertions: []ScriptTestAssertion{ 71 { 72 Query: `select json_length(y) from xy`, 73 Expected: []sql.Row{ 74 {2}, 75 {4}, 76 {1}, 77 {1}, 78 {nil}, 79 }, 80 }, 81 { 82 Query: `select json_length(json_extract(x, "$.a")) from xy`, 83 ExpectedErrStr: "failed to extract from expression 'xy.x'; object is not map", 84 }, 85 { 86 Query: `select json_length(json_extract(y, "$.a")) from xy`, 87 Expected: []sql.Row{ 88 {nil}, 89 {nil}, 90 {2}, 91 {1}, 92 {nil}, 93 }, 94 }, 95 { 96 Query: `select json_length(json_extract(y, "$.a.b")) from xy where x = 3`, 97 Expected: []sql.Row{ 98 {2}, 99 }, 100 }, 101 { 102 Query: `select json_length(y, "$.a.b") from xy where x = 3`, 103 Expected: []sql.Row{ 104 {2}, 105 }, 106 }, 107 { 108 Query: `select json_length(y, "$.a[0].b") from xy where x = 2`, 109 Expected: []sql.Row{ 110 {1}, 111 }, 112 }, 113 }, 114 }, 115 { 116 // https://github.com/dolthub/go-mysql-server/issues/1855", 117 Name: "JSON_ARRAY properly handles CHAR bind vars", 118 SetUpScript: []string{ 119 "CREATE TABLE `users` (`id` bigint unsigned AUTO_INCREMENT,`name` longtext,`languages` JSON, PRIMARY KEY (`id`))", 120 `INSERT INTO users (name, languages) VALUES ('Tom', CAST('["ZH", "EN"]' AS JSON));`, 121 }, 122 Assertions: []ScriptTestAssertion{ 123 { 124 Query: `SELECT * FROM users WHERE JSON_CONTAINS (languages, JSON_ARRAY(?)) ORDER BY users.id LIMIT 1`, 125 // CHAR bind vars are converted to VAR_BINARY on the wire path 126 Bindings: map[string]*querypb.BindVariable{ 127 "v1": {Type: querypb.Type_VARBINARY, Value: []byte("ZH")}, 128 }, 129 Expected: []sql.Row{{uint64(1), "Tom", types.JSONDocument{Val: []interface{}{"ZH", "EN"}}}}, 130 }, 131 }, 132 }, 133 { 134 Name: "JSON_ARRAYAGG on one column", 135 SetUpScript: []string{ 136 "create table t (o_id int primary key)", 137 "INSERT INTO t VALUES (1),(2)", 138 }, 139 Assertions: []ScriptTestAssertion{ 140 { 141 Query: "SELECT JSON_ARRAYAGG(o_id) FROM (SELECT * FROM t ORDER BY o_id) as sub", 142 Expected: []sql.Row{ 143 { 144 types.MustJSON(`[1,2]`), 145 }, 146 }, 147 }, 148 }, 149 }, 150 { 151 Name: "Simple JSON_ARRAYAGG on two columns", 152 SetUpScript: []string{ 153 "create table t (o_id int primary key, attribute longtext)", 154 "INSERT INTO t VALUES (1, 'color'), (2, 'fabric')", 155 }, 156 Assertions: []ScriptTestAssertion{ 157 { 158 Query: "SELECT JSON_ARRAYAGG(o_id), JSON_ARRAYAGG(`attribute`) FROM (SELECT * FROM t ORDER BY o_id) as sub;", 159 Expected: []sql.Row{ 160 { 161 types.MustJSON(`[1,2]`), 162 types.MustJSON(`["color","fabric"]`), 163 }, 164 }, 165 }, 166 }, 167 }, 168 { 169 Name: "JSON_ARRAYAGG on column with string values w/ groupby", 170 SetUpScript: []string{ 171 "create table t (o_id int primary key, c0 int, attribute longtext, value longtext)", 172 "INSERT INTO t VALUES (1, 2, 'color', 'red'), (2, 2, 'fabric', 'silk')", 173 }, 174 Assertions: []ScriptTestAssertion{ 175 { 176 Query: "SELECT c0, JSON_ARRAYAGG(`attribute`) FROM (SELECT * FROM t ORDER BY o_id) as sub GROUP BY c0", 177 Expected: []sql.Row{ 178 { 179 2, 180 types.MustJSON(`["color","fabric"]`), 181 }, 182 }, 183 }, 184 { 185 Query: "SELECT c0, JSON_ARRAYAGG(value) FROM (SELECT * FROM t ORDER BY o_id) as sub GROUP BY c0", 186 Expected: []sql.Row{ 187 { 188 2, 189 types.MustJSON(`["red","silk"]`), 190 }, 191 }, 192 }, 193 }, 194 }, 195 { 196 Name: "JSON_ARRAYAGG on column with int values w/ groupby", 197 SetUpScript: []string{ 198 "create table t2 (o_id int primary key, val int)", 199 "INSERT INTO t2 VALUES (1,1), (2,1), (3,1)", 200 }, 201 Assertions: []ScriptTestAssertion{ 202 { 203 Query: "SELECT val, JSON_ARRAYAGG(o_id) FROM (SELECT * FROM t2 ORDER BY o_id) AS sub GROUP BY val", 204 Expected: []sql.Row{ 205 { 206 1, 207 types.MustJSON(`[1,2,3]`), 208 }, 209 }, 210 }, 211 }, 212 }, 213 { 214 Name: "JSON_ARRAYAGG on unknown column throws error", 215 SetUpScript: []string{ 216 "create table t2 (o_id int primary key, val int)", 217 "INSERT INTO t2 VALUES (1,1), (2,2), (3,3)", 218 }, 219 Assertions: []ScriptTestAssertion{ 220 { 221 Query: "SELECT o_id, JSON_ARRAYAGG(val2) FROM t2 GROUP BY o_id", 222 ExpectedErr: sql.ErrColumnNotFound, 223 }, 224 }, 225 }, 226 { 227 Name: "JSON_ARRAYAGG on column with no rows returns NULL", 228 SetUpScript: []string{ 229 "create table t2 (o_id int primary key)", 230 }, 231 Assertions: []ScriptTestAssertion{ 232 { 233 Query: "SELECT JSON_ARRAYAGG(o_id) FROM t2", 234 Expected: []sql.Row{ 235 { 236 types.MustJSON(`[]`), 237 }, 238 }, 239 }, 240 }, 241 }, 242 { 243 Name: "JSON_ARRAYAGG on row with 1 value, 1 null is fine", 244 SetUpScript: []string{ 245 "create table x(pk int primary key, c1 int)", 246 "INSERT INTO x VALUES (1,NULL)", 247 }, 248 Assertions: []ScriptTestAssertion{ 249 { 250 Query: "SELECT pk, JSON_ARRAYAGG(c1) FROM x GROUP BY pk", 251 Expected: []sql.Row{ 252 {1, types.MustJSON(`[null]`)}, 253 }, 254 }, 255 { 256 Query: "SELECT JSON_ARRAYAGG(c1) FROM x", 257 Expected: []sql.Row{ 258 {types.MustJSON(`[null]`)}, 259 }, 260 }, 261 }, 262 }, 263 { 264 Name: "JSON_ARRAYAGG and group by use the same field.", 265 SetUpScript: []string{ 266 "create table x(pk int primary key, c1 int)", 267 "INSERT INTO x VALUES (1, 1)", 268 "INSERT INTO x VALUES (2, 1)", 269 "INSERT INTO x VALUES (3, 3)", 270 "INSERT INTO x VALUES (4, 3)", 271 "INSERT INTO x VALUES (5, 5)", 272 }, 273 Assertions: []ScriptTestAssertion{ 274 { 275 Query: "SELECT JSON_ARRAYAGG(pk) FROM (SELECT * FROM x ORDER BY pk) as sub GROUP BY c1", 276 Expected: []sql.Row{ 277 {types.MustJSON(`[1,2]`)}, 278 {types.MustJSON(`[3,4]`)}, 279 {types.MustJSON(`[5]`)}, 280 }, 281 }, 282 }, 283 }, 284 { 285 Name: "JSON_ARRAGG with simple and nested json objects.", 286 SetUpScript: []string{ 287 "create table j(pk int primary key, field JSON)", 288 `INSERT INTO j VALUES(1, '{"key1": {"key": "value"}}')`, 289 `INSERT INTO j VALUES(2, '{"key1": "value1", "key2": "value2"}')`, 290 `INSERT INTO j VALUES(3, '{"key1": {"key": [2,3]}}')`, 291 `INSERT INTO j VALUES(4, '["a", 1]')`, 292 }, 293 Assertions: []ScriptTestAssertion{ 294 { 295 Query: "SELECT pk, JSON_ARRAYAGG(field) FROM (SELECT * FROM j ORDER BY pk) as sub GROUP BY field ORDER BY pk", 296 Expected: []sql.Row{ 297 {1, types.MustJSON(`[{"key1": {"key": "value"}}]`)}, 298 {2, types.MustJSON(`[{"key1": "value1", "key2": "value2"}]`)}, 299 {3, types.MustJSON(`[{"key1":{"key":[2,3]}}]`)}, 300 {4, types.MustJSON(`[["a",1]]`)}, 301 }, 302 }, 303 }, 304 }, 305 { 306 Name: "Simple JSON_OBJECTAGG with GROUP BY", 307 SetUpScript: []string{ 308 "create table t2 (o_id int primary key, val int)", 309 "INSERT INTO t2 VALUES (1,1), (2,1), (3,1)", 310 }, 311 Assertions: []ScriptTestAssertion{ 312 { 313 Query: "SELECT JSON_OBJECTAGG(val, o_id) FROM (SELECT * FROM t2 ORDER BY o_id) as sub GROUP BY val", 314 Expected: []sql.Row{ 315 {types.MustJSON(`{"1": 3}`)}, 316 }, 317 }, 318 }, 319 }, 320 { 321 Name: "More complex JSON_OBJECTAGG WITH GROUP BY", 322 SetUpScript: []string{ 323 "create table t (o_id int primary key, c0 int, attribute longtext, value longtext)", 324 "INSERT INTO t VALUES (1, 2, 'color', 'red'), (2, 2, 'fabric', 'silk')", 325 "INSERT INTO t VALUES (3, 3, 'color', 'green'), (4, 3, 'shape', 'square')", 326 }, 327 Assertions: []ScriptTestAssertion{ 328 { 329 Query: "SELECT c0, JSON_OBJECTAGG(`attribute`, value) FROM (SELECT * FROM t ORDER BY o_id) as sub GROUP BY c0", 330 Expected: []sql.Row{ 331 {2, types.MustJSON(`{"color": "red", "fabric": "silk"}`)}, 332 {3, types.MustJSON(`{"color": "green", "shape": "square"}`)}, 333 }, 334 }, 335 { 336 Query: `SELECT c0, JSON_OBJECTAGG(c0, value) FROM (SELECT * FROM t ORDER BY o_id) as sub GROUP BY c0`, 337 Expected: []sql.Row{ 338 {2, types.MustJSON(`{"2": "silk"}`)}, 339 {3, types.MustJSON(`{"3": "square"}`)}, 340 }, 341 }, 342 }, 343 }, 344 { 345 Name: "3 column table that uses JSON_OBJECTAGG without groupby", 346 SetUpScript: []string{ 347 "create table t (o_id int primary key, c0 int, attribute longtext, value longtext)", 348 "INSERT INTO t VALUES (1, 2, 'color', 'red'), (2, 2, 'fabric', 'silk')", 349 "INSERT INTO t VALUES (3, 3, 'color', 'green'), (4, 3, 'shape', 'square')", 350 }, 351 Assertions: []ScriptTestAssertion{ 352 { 353 Query: `select JSON_OBJECTAGG(c0, value) from (SELECT * FROM t ORDER BY o_id) as sub`, 354 Expected: []sql.Row{ 355 {types.MustJSON(`{"2": "silk", "3": "square"}`)}, 356 }, 357 }, 358 { 359 Query: "select JSON_OBJECTAGG(`attribute`, value) from (SELECT * FROM t ORDER BY o_id) as sub", 360 Expected: []sql.Row{ 361 {types.MustJSON(`{"color": "green", "fabric": "silk", "shape": "square"}`)}, 362 }, 363 }, 364 }, 365 }, 366 { 367 Name: "JSON_OBJECTAGG and null values", 368 SetUpScript: []string{ 369 `create table test (pk int primary key, val longtext)`, 370 `insert into test values (1, NULL)`, 371 }, 372 Assertions: []ScriptTestAssertion{ 373 { 374 Query: `SELECT JSON_OBJECTAGG(pk, val) from test`, 375 Expected: []sql.Row{ 376 {types.MustJSON(`{"1": null}`)}, 377 }, 378 }, 379 }, 380 }, 381 { 382 Name: "JSON_OBJECTAGG and nested json values", 383 SetUpScript: []string{ 384 "create table j(pk int primary key, c0 int, val JSON)", 385 `INSERT INTO j VALUES(1, 1, '{"key1": "value1", "key2": "value2"}')`, 386 `INSERT INTO j VALUES(2, 1, '{"key1": {"key": [2,3]}}')`, 387 `INSERT INTO j VALUES(3, 2, '["a", 1]')`, 388 }, 389 Assertions: []ScriptTestAssertion{ 390 { 391 Query: `SELECT JSON_OBJECTAGG(c0, val) from (SELECT * FROM j ORDER BY pk) as sub`, 392 Expected: []sql.Row{ 393 {types.MustJSON(`{"1": {"key1": {"key": [2, 3]}}, "2": ["a", 1]}`)}, 394 }, 395 }, 396 }, 397 }, 398 { 399 Name: "JSON_OBJECTAGG correctly returns null when no rows are present", 400 SetUpScript: []string{ 401 `create table test (pk int primary key, val longtext)`, 402 }, 403 Assertions: []ScriptTestAssertion{ 404 { 405 Query: `SELECT JSON_OBJECTAGG(pk, val) from test`, 406 Expected: []sql.Row{ 407 {nil}, 408 }, 409 }, 410 }, 411 }, 412 { 413 Name: "JSON_OBJECTAGG handles errors appropriately", 414 SetUpScript: []string{ 415 `create table test (pk int primary key, c0 int, val longtext)`, 416 `insert into test values (1, 1, NULL)`, 417 `insert into test values (2, NULL, 1)`, // NULL keys are not allowed in JSON_OBJECTAGG 418 }, 419 Assertions: []ScriptTestAssertion{ 420 { 421 Query: `SELECT JSON_OBJECTAGG(c0, notval) from test`, 422 ExpectedErr: sql.ErrColumnNotFound, 423 }, 424 { 425 Query: `SELECT JSON_OBJECTAGG(notpk, val) from test`, 426 ExpectedErr: sql.ErrColumnNotFound, 427 }, 428 { 429 Query: `SELECT JSON_OBJECTAGG(c0, val) from nottest`, 430 ExpectedErr: sql.ErrTableNotFound, 431 }, 432 { 433 Query: `SELECT JSON_OBJECTAGG(c0, val, 'badarg') from test`, 434 ExpectedErr: sql.ErrInvalidArgumentNumber, 435 }, 436 { 437 Query: `SELECT JSON_OBJECTAGG(c0, val, badarg) from test`, 438 ExpectedErr: sql.ErrColumnNotFound, 439 }, 440 { 441 Query: `SELECT JSON_OBJECTAGG(c0) from test`, 442 ExpectedErr: sql.ErrInvalidArgumentNumber, 443 }, 444 { 445 Query: `SELECT JSON_OBJECTAGG(c0, val) from test`, 446 ExpectedErr: sql.ErrJSONObjectAggNullKey, 447 }, 448 }, 449 }, 450 { 451 Name: "JSON -> and ->> operator support", 452 SetUpScript: []string{ 453 "create table t (pk int primary key, col1 JSON, col2 JSON);", 454 `insert into t values (1, JSON_OBJECT('key1', 1, 'key2', '"abc"'), JSON_ARRAY(3,10,5,17,"z"));`, 455 `insert into t values (2, JSON_OBJECT('key1', 100, 'key2', '"ghi"'), JSON_ARRAY(3,10,5,17,JSON_ARRAY(22,"y",66)));`, 456 `CREATE TABLE t2 (i INT PRIMARY KEY, j JSON);`, 457 `INSERT INTO t2 VALUES (0, '{"a": "123", "outer": {"inner": 456}}');`, 458 }, 459 Assertions: []ScriptTestAssertion{ 460 { 461 Query: `select col1->'$.key1' from t;`, 462 Expected: []sql.Row{{types.MustJSON("1")}, {types.MustJSON("100")}}, 463 }, 464 { 465 Query: `select col1->>'$.key2' from t;`, 466 Expected: []sql.Row{{"abc"}, {"ghi"}}, 467 }, 468 { 469 Query: `select pk, col1 from t where col1->'$.key1' = 1;`, 470 Expected: []sql.Row{{1, types.MustJSON(`{"key1":1, "key2":"\"abc\""}`)}}, 471 }, 472 { 473 Query: `select pk, col1 from t where col1->>'$.key2' = 'abc';`, 474 Expected: []sql.Row{{1, types.MustJSON(`{"key1":1, "key2":"\"abc\""}`)}}, 475 }, 476 { 477 Query: `select * from t where col1->>'$.key2' = 'def';`, 478 Expected: []sql.Row{}, 479 }, 480 { 481 Query: `SELECT col2->"$[3]", col2->>"$[3]" FROM t;`, 482 Expected: []sql.Row{{types.MustJSON("17"), "17"}, {types.MustJSON("17"), "17"}}, 483 }, 484 { 485 Query: `SELECT col2->"$[4]", col2->>"$[4]" FROM t where pk=1;`, 486 Expected: []sql.Row{{types.MustJSON("\"z\""), "z"}}, 487 }, 488 { 489 // TODO: JSON_Extract doesn't seem able to handle a JSON path expression that references a nested array 490 // This errors with "object is not Slice" 491 Skip: true, 492 Query: `SELECT col2->>"$[3]", col2->>"$[4][0]" FROM t;`, 493 Expected: []sql.Row{{17, 44}, {17, "y"}}, 494 }, 495 { 496 Query: `SELECT k->"$.inner" from (SELECT j->"$.outer" AS k FROM t2) sq;`, 497 Expected: []sql.Row{{types.MustJSON("456")}}, 498 }, 499 }, 500 }, 501 // from https://dev.mysql.com/doc/refman/8.0/en/json.html#json-converting-between-types:~:text=information%20and%20examples.-,Comparison%20and%20Ordering%20of%20JSON%20Values,-JSON%20values%20can 502 { 503 Name: "json is ordered correctly", 504 SetUpScript: []string{ 505 "create table t (pk int primary key, col1 json);", 506 "insert into t values (1, null);", 507 "insert into t values (2, '{}');", 508 "insert into t values (3, (select json_extract('{\"a\": null}', '$.a')));", 509 "insert into t values (4, 0);", 510 }, 511 Assertions: []ScriptTestAssertion{ 512 { 513 Query: "select * from t order by col1 asc;", 514 Expected: []sql.Row{ 515 {1, nil}, 516 {3, types.MustJSON("null")}, 517 {4, types.MustJSON("0")}, 518 {2, types.MustJSON("{}")}, 519 }, 520 }, 521 { 522 Query: "select * from t order by col1 desc;", 523 Expected: []sql.Row{ 524 {2, types.MustJSON("{}")}, 525 {4, types.MustJSON("0")}, 526 {3, types.MustJSON("null")}, 527 {1, nil}, 528 }, 529 }, 530 }, 531 }, 532 { 533 // https://github.com/dolthub/dolt/issues/4499 534 Name: "json is formatted correctly", 535 SetUpScript: []string{ 536 "create table t (pk int primary key, col1 json);", 537 538 // formatted json 539 `insert into t values (1, '{"a": 1, "b": 2}');`, 540 // unordered keys with correct spacing 541 `insert into t values (2, '{"b": 2, "a": 1}');`, 542 // ordered keys with no spacing 543 `insert into t values (3, '{"a":1,"b":2}');`, 544 // unordered keys with no spacing 545 `insert into t values (4, '{"b":2,"a":1}');`, 546 // unordered keys with extra spacing 547 `insert into t values (5, '{ "b": 2 , "a" : 1 }');`, 548 549 // ordered keys with arrays of primitives without spaces 550 `insert into t values (6, '{"a":[1,2,3],"b":[4,5,6]}');`, 551 // unordered keys with arrays of primitives without spaces 552 `insert into t values (7, '{"b":[4,5,6],"a":[1,2,3]}');`, 553 // ordered keys with arrays of primitives with extra spaces 554 `insert into t values (8, '{ "a" : [ 1 , 2 , 3 ] , "b" : [ 4 , 5 , 6 ] }');`, 555 // unordered keys with arrays of primitives with extra spaces 556 `insert into t values (9, '{ "b" : [ 4 , 5 , 6 ] , "a" : [ 1 , 2 , 3 ] }');`, 557 558 // ordered keys with arrays of objects without spaces 559 `insert into t values (10, '{"a":[{"a":1},{"b":2}],"b":[{"c":3},{"d":4}]}');`, 560 // ordered keys with arrays of objects with extra spaces 561 `insert into t values (11, '{ "a" : [ { "a" : 1 } , { "b" : 2 } ] , "b" : [ { "c" : 3 } , { "d" : 4 } ] }');`, 562 // unordered keys with arrays of objects without spaces 563 `insert into t values (12, '{"b":[{"c":3},{"d":4}],"a":[{"a":1},{"b":2}]}');`, 564 // unordered keys with arrays of objects with extra spaces 565 `insert into t values (13, '{ "b" : [ { "c" : 3 } , { "d" : 4 } ] , "a" : [ { "a" : 1 } , { "b" : 2 } ] }');`, 566 567 // formatted json with special characters 568 `insert into t values (14, '[{"a":"<>&"}]');`, 569 }, 570 Assertions: []ScriptTestAssertion{ 571 { 572 Query: "select pk, cast(col1 as char) from t order by pk asc;", 573 Expected: []sql.Row{ 574 {1, `{"a": 1, "b": 2}`}, 575 {2, `{"a": 1, "b": 2}`}, 576 {3, `{"a": 1, "b": 2}`}, 577 {4, `{"a": 1, "b": 2}`}, 578 {5, `{"a": 1, "b": 2}`}, 579 {6, `{"a": [1, 2, 3], "b": [4, 5, 6]}`}, 580 {7, `{"a": [1, 2, 3], "b": [4, 5, 6]}`}, 581 {8, `{"a": [1, 2, 3], "b": [4, 5, 6]}`}, 582 {9, `{"a": [1, 2, 3], "b": [4, 5, 6]}`}, 583 {10, `{"a": [{"a": 1}, {"b": 2}], "b": [{"c": 3}, {"d": 4}]}`}, 584 {11, `{"a": [{"a": 1}, {"b": 2}], "b": [{"c": 3}, {"d": 4}]}`}, 585 {12, `{"a": [{"a": 1}, {"b": 2}], "b": [{"c": 3}, {"d": 4}]}`}, 586 {13, `{"a": [{"a": 1}, {"b": 2}], "b": [{"c": 3}, {"d": 4}]}`}, 587 {14, `[{"a": "<>&"}]`}, 588 }, 589 }, 590 }, 591 }, 592 { 593 Name: "json_extract returns missing keys as sql null and handles json null literals correctly", 594 SetUpScript: []string{ 595 "create table t (pk int primary key, col1 json);", 596 "insert into t values (1, '{\"items\": {\"1\": 1, \"2\": 2}}');", 597 "insert into t values (2, null);", 598 "insert into t values (3, '{}');", 599 "insert into t values (4, '{\"items\": null}');", 600 "insert into t values (5, (select json_extract('{\"a\": null}', '$.a')));", 601 }, 602 Assertions: []ScriptTestAssertion{ 603 { 604 Query: "select pk, json_extract(col1, '$.items') from t order by pk;", 605 Expected: []sql.Row{ 606 {1, types.MustJSON("{\"1\":1,\"2\":2}")}, 607 {2, nil}, 608 {3, nil}, 609 {4, types.MustJSON("null")}, 610 {5, nil}, 611 }, 612 }, 613 { 614 Query: "select pk, json_extract(col1, '$') from t order by pk;", 615 Expected: []sql.Row{ 616 {1, types.MustJSON("{\"items\": {\"1\": 1, \"2\": 2}}")}, 617 {2, nil}, 618 {3, types.MustJSON("{}")}, 619 {4, types.MustJSON("{\"items\": null}")}, 620 {5, types.MustJSON("null")}, 621 }, 622 }, 623 { 624 Query: "select pk, json_extract(col1, '$.items') is null from t order by pk;", 625 Expected: []sql.Row{ 626 {1, false}, 627 {2, true}, 628 {3, true}, 629 {4, false}, 630 {5, true}, 631 }, 632 }, 633 { 634 Query: "select pk, json_extract(col1, '$.items') <> null from t order by pk;", 635 Expected: []sql.Row{ 636 {1, nil}, 637 {2, nil}, 638 {3, nil}, 639 {4, nil}, 640 {5, nil}, 641 }, 642 }, 643 { 644 Query: "select pk, json_extract(col1, '$.items.*') from t order by pk;", 645 Expected: []sql.Row{ 646 {1, types.MustJSON("[1, 2]")}, 647 {2, nil}, 648 {3, nil}, 649 {4, types.MustJSON("null")}, 650 {5, nil}, 651 }, 652 }, 653 { 654 Query: "select pk from t where json_extract(col1, '$.items') is null;", 655 Expected: []sql.Row{{2}, {3}, {5}}, 656 }, 657 { 658 Query: "select pk from t where json_extract(col1, '$.items') <> null;", 659 Expected: []sql.Row{}, 660 }, 661 }, 662 }, 663 { 664 Name: "json_contains_path returns true if the path exists", 665 SetUpScript: []string{ 666 `create table t (pk int primary key, col1 json);`, 667 `insert into t values (1, '{"a": 1}');`, 668 `insert into t values (2, '{"a": 1, "b": 2, "c": {"d": 4}}');`, 669 `insert into t values (3, '{"w": 1, "x": 2, "c": {"d": 4}}');`, 670 `insert into t values (4, '{}');`, 671 `insert into t values (5, null);`, 672 }, 673 674 Assertions: []ScriptTestAssertion{ 675 { 676 Query: "select pk, json_contains_path(col1, 'one', '$.a') from t order by pk;", 677 Expected: []sql.Row{ 678 {1, true}, 679 {2, true}, 680 {3, false}, 681 {4, false}, 682 {5, nil}, 683 }, 684 }, 685 { 686 Query: "select pk, json_contains_path(col1, 'one', '$.a', '$.x', '$.c.d') from t order by pk;", 687 Expected: []sql.Row{ 688 {1, true}, 689 {2, true}, 690 {3, true}, 691 {4, false}, 692 {5, nil}, 693 }, 694 }, 695 { 696 Query: "select pk, json_contains_path(col1, 'all', '$.a', '$.x') from t order by pk;", 697 Expected: []sql.Row{ 698 {1, false}, 699 {2, false}, 700 {3, false}, 701 {4, false}, 702 {5, nil}, 703 }, 704 }, 705 { 706 Query: "select pk, json_contains_path(col1, 'all', '$.c.d', '$.x') from t order by pk;", 707 Expected: []sql.Row{ 708 {1, false}, 709 {2, false}, 710 {3, true}, 711 {4, false}, 712 {5, nil}, 713 }, 714 }, 715 { 716 Query: "select pk, json_contains_path(col1, 'other', '$.c.d', '$.x') from t order by pk;", 717 ExpectedErrStr: "The oneOrAll argument to json_contains_path may take these values: 'one' or 'all'", 718 }, 719 }, 720 }, 721 { 722 Name: "json type value compared with number type value", 723 Assertions: []ScriptTestAssertion{ 724 { 725 Query: "SELECT JSON_EXTRACT('0.4', '$')", 726 Expected: []sql.Row{{types.MustJSON(`0.4`)}}, 727 }, 728 { 729 Query: "SELECT JSON_EXTRACT('0.4', '$') > 0;", 730 Expected: []sql.Row{{true}}, 731 }, 732 { 733 Query: "SELECT JSON_EXTRACT('0.4', '$') <= 0;", 734 Expected: []sql.Row{{false}}, 735 }, { 736 Query: "SELECT JSON_EXTRACT('0.4', '$') = 0;", 737 Expected: []sql.Row{{false}}, 738 }, 739 { 740 Query: "SELECT JSON_EXTRACT('0.4', '$') = 0.4;", 741 Expected: []sql.Row{{true}}, 742 }, 743 }, 744 }, 745 { 746 Name: "json bools", 747 SetUpScript: []string{ 748 "create table t (j json);", 749 "insert into t values ('{\"x\": true}'), ('{\"x\": false}');", 750 }, 751 Assertions: []ScriptTestAssertion{ 752 { 753 Query: "select j->'$.x' = true from t;", 754 Expected: []sql.Row{ 755 {true}, 756 {false}, 757 }, 758 }, 759 }, 760 }, 761 }