1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

MDEV-17399 Add support for JSON_TABLE.

The specific table handler for the table functions was introduced,
and used to implement JSON_TABLE.
This commit is contained in:
Alexey Botchkov
2021-03-17 09:03:45 +04:00
parent a3099a3b4a
commit e9fd327ee3
40 changed files with 6001 additions and 43 deletions

View File

@@ -0,0 +1,466 @@
select * from json_table('[{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}]', '$[*]' COLUMNS( a INT PATH '$.a')) as tt;
a
1
2
select * from JSON_TABLE( '[ {"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]', '$[*]' COLUMNS( a INT PATH '$.a', NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$'))) as jt;
a b
1 11
1 111
2 22
2 222
3 NULL
SELECT * FROM JSON_TABLE( '[ {"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]', '$[*]' COLUMNS( a INT PATH '$.a', NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$'), NESTED PATH '$.b[*]' COLUMNS (c INT PATH '$') ) ) jt;
a b c
1 11 NULL
1 111 NULL
1 NULL 11
1 NULL 111
2 22 NULL
2 222 NULL
2 NULL 22
2 NULL 222
3 NULL NULL
create table t1 (id varchar(5), json varchar(1024));
insert into t1 values ('j1', '[{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}]');
insert into t1 values ('j2', '[{"a": 3, "b": [11,111]}, {"a": 4, "b": [22,222]}, {"a": 5, "b": [22,222]}]');
select id, json, a from t1, json_table(t1.json, '$[*]' COLUMNS(js_id FOR ORDINALITY, a INT PATH '$.a')) as tt;
id json a
j1 [{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}] 1
j1 [{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}] 2
j2 [{"a": 3, "b": [11,111]}, {"a": 4, "b": [22,222]}, {"a": 5, "b": [22,222]}] 3
j2 [{"a": 3, "b": [11,111]}, {"a": 4, "b": [22,222]}, {"a": 5, "b": [22,222]}] 4
j2 [{"a": 3, "b": [11,111]}, {"a": 4, "b": [22,222]}, {"a": 5, "b": [22,222]}] 5
select * from t1, JSON_TABLE(t1.json, '$[*]' COLUMNS(js_id FOR ORDINALITY, a INT PATH '$.a', NESTED PATH '$.b[*]' COLUMNS (l_js_id FOR ORDINALITY, b INT PATH '$'))) as jt;
id json js_id a l_js_id b
j1 [{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}] 1 1 1 11
j1 [{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}] 1 1 2 111
j1 [{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}] 2 2 1 22
j1 [{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}] 2 2 2 222
j2 [{"a": 3, "b": [11,111]}, {"a": 4, "b": [22,222]}, {"a": 5, "b": [22,222]}] 1 3 1 11
j2 [{"a": 3, "b": [11,111]}, {"a": 4, "b": [22,222]}, {"a": 5, "b": [22,222]}] 1 3 2 111
j2 [{"a": 3, "b": [11,111]}, {"a": 4, "b": [22,222]}, {"a": 5, "b": [22,222]}] 2 4 1 22
j2 [{"a": 3, "b": [11,111]}, {"a": 4, "b": [22,222]}, {"a": 5, "b": [22,222]}] 2 4 2 222
j2 [{"a": 3, "b": [11,111]}, {"a": 4, "b": [22,222]}, {"a": 5, "b": [22,222]}] 3 5 1 22
j2 [{"a": 3, "b": [11,111]}, {"a": 4, "b": [22,222]}, {"a": 5, "b": [22,222]}] 3 5 2 222
select * from t1, JSON_TABLE(t1.no_field, '$[*]' COLUMNS(js_id FOR ORDINALITY, a INT PATH '$.a', NESTED PATH '$.b[*]' COLUMNS (l_js_id FOR ORDINALITY, b INT PATH '$'))) as jt;
ERROR 42S22: Unknown column 't1.no_field' in 'JSON_TABLE argument'
select * from t1, JSON_TABLE(t1.no_field, '$[*]' COLUMNS(js_id FOR ORDINALITY, a INT PATH '$.a', NESTED PATH '$.b[*]' COLUMNS (l_js_id FOR ORDINALITY, a INT PATH '$'))) as jt;
ERROR 42S21: Duplicate column name 'a'
DROP TABLE t1;
create table t1 (item_name varchar(32), item_props varchar(1024));
insert into t1 values ('Laptop', '{"color": "black", "price": 1000}');
insert into t1 values ('Jeans', '{"color": "blue", "price": 50}');
select * from t1 left join json_table(t1.item_props,'$' columns( color varchar(100) path '$.color')) as T on 1;
item_name item_props color
Laptop {"color": "black", "price": 1000} black
Jeans {"color": "blue", "price": 50} blue
select * from t1 right join json_table(t1.item_props,'$' columns( color varchar(100) path '$.color')) as T on 1;
ERROR 42000: Cross dependency found in OUTER JOIN; examine your ON conditions
DROP TABLE t1;
select * from JSON_TABLE( '[ {"xa": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]', '$[*]' COLUMNS( a INT PATH '$.a' default '101' on empty, NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$'))) as jt;
a b
101 11
101 111
2 22
2 222
3 NULL
select * from JSON_TABLE( '[ {"xa": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]', '$[*]' COLUMNS( a INT PATH '$.a' default '202' on error, NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$'))) as jt;
a b
NULL 11
NULL 111
2 22
2 222
3 NULL
select * from JSON_TABLE( '[ {"a": [1, 2], "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]', '$[*]' COLUMNS( a INT PATH '$.a' default '101' on empty, NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$'))) as jt;
a b
NULL 11
NULL 111
2 22
2 222
3 NULL
select * from JSON_TABLE( '[ {"a": [1, 2], "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]', '$[*]' COLUMNS( a INT PATH '$.a' default '202' on error default '101' on empty, NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$'))) as jt;
a b
202 11
202 111
2 22
2 222
3 NULL
select * from JSON_TABLE( '[{"a": [1, 2], "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3} xx YY]', '$[*]' COLUMNS( a INT PATH '$.a' default '202' on error default '101' on empty, NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$'))) as jt;
ERROR HY000: Syntax error in JSON text in argument 1 to function 'JSON_TABLE' at position 65
select * from JSON_TABLE( '[{"a": [1, 2], "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]', '$[*]' COLUMNS( a INT PATH '$.a' error on error default '101' on empty, NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$'))) as jt;
ERROR HY000: Field 'a' can't be set for JSON_TABLE 'jt'.
select * from json_table('{"a":0}',"$" columns(a decimal(1,1) path '$.a')) foo;
a
0.0
connect con1,localhost,root,,;
select a from json_table('{"a":0}',"$" columns(a for ordinality)) foo;
a
1
connection default;
disconnect con1;
create database db;
use db;
create table t (a text);
insert into t values ('{"foo":"bar"}');
create user u@localhost;
grant select (a) on db.t to u@localhost;
connect con1,localhost,u,,db;
select a from t;
a
{"foo":"bar"}
select * from t, json_table(t.a, '$' columns(f varchar(20) path '$.foo')) as jt;
a f
{"foo":"bar"} bar
connection default;
disconnect con1;
drop user u@localhost;
drop database db;
use test;
create table t1 (
color varchar(32),
price int
);
insert into t1 values ("red", 100), ("blue", 50);
insert into t1 select * from t1;
insert into t1 select * from t1;
set @save_optimizer_switch=@@optimizer_switch;
set optimizer_switch='firstmatch=off';
select * from
json_table('[{"color": "blue", "price": 50},
{"color": "red", "price": 100}]',
'$[*]' columns( color varchar(100) path '$.color',
price text path '$.price'
)
) as T
where
T.color in (select color from t1 where t1.price=T.price);
color price
blue 50
red 100
set @@optimizer_switch=@save_optimizer_switch;
drop table t1;
select * from
json_table(' [ {"color": "blue", "sizes": [1,2,3,4], "prices" : [10,20]},
{"color": "red", "sizes": [10,11,12,13,14], "prices" : [100,200,300]} ]',
'$[*]' columns(
color varchar(4) path '$.color',
seq0 for ordinality,
nested path '$.sizes[*]'
columns (seq1 for ordinality,
size int path '$'),
nested path '$.prices[*]'
columns (seq2 for ordinality,
price int path '$')
)
) as T;
color seq0 seq1 size seq2 price
blue 1 1 1 NULL NULL
blue 1 2 2 NULL NULL
blue 1 3 3 NULL NULL
blue 1 4 4 NULL NULL
blue 1 NULL NULL 1 10
blue 1 NULL NULL 2 20
red 2 1 10 NULL NULL
red 2 2 11 NULL NULL
red 2 3 12 NULL NULL
red 2 4 13 NULL NULL
red 2 5 14 NULL NULL
red 2 NULL NULL 1 100
red 2 NULL NULL 2 200
red 2 NULL NULL 3 300
select * from json_table('[{"color": "blue", "price": 50},
{"color": "red", "price": 100},
{"color": "rojo", "price": 10.0},
{"color": "blanco", "price": 11.0}]',
'$[*]' columns( color varchar(100) path '$.color',
price text path '$.price', seq for ordinality)) as T order by color desc;
color price seq
rojo 10.0 3
red 100 2
blue 50 1
blanco 11.0 4
create view v as select * from json_table('{"as":"b", "x":123}',"$" columns(a varchar(8) path '$.a' default '-' on empty, x int path '$.x')) x;
select * from v;
a x
- 123
show create table v;
View Create View character_set_client collation_connection
v CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `x`.`a` AS `a`,`x`.`x` AS `x` from JSON_TABLE('{"as":"b", "x":123}', '$' COLUMNS (`a` varchar(8) PATH '$.a' DEFAULT '-' ON EMPTY, `x` int(11) PATH '$.x')) `x` latin1 latin1_swedish_ci
drop view v;
select * from json_table('{"as":"b", "x":123}',
"$" columns(a varchar(8) path '$.a' default '-' on empty null on error null on empty, x int path '$.x')) x;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'null on empty, x int path '$.x')) x' at line 2
select * from json_table('{"a":"foo","b":"bar"}', '$'
columns (v varchar(20) path '$.*')) as jt;
v
NULL
select * from json_table('{"a":"foo","b":"bar"}', '$'
columns (v varchar(20) path '$.*' default '-' on error)) as jt;
v
-
select * from json_table('{"b":"bar"}', '$'
columns (v varchar(20) path '$.*' default '-' on error)) as jt;
v
bar
create table t1 (a varchar(100));
insert into t1 values ('1');
select * from t1 as T, json_table(T.a, '$[*]' columns(color varchar(100) path '$.nonexistent', seq for ordinality)) as T;
ERROR 42000: Not unique table/alias: 'T'
drop table t1;
prepare s from 'select * from
json_table(?,
\'$[*]\' columns( color varchar(100) path \'$.color\',
price text path \'$.price\',
seq for ordinality)) as T
order by color desc; ';
execute s using '[{"color": "red", "price":1}, {"color":"brown", "price":2}]';
color price seq
red 1 1
brown 2 2
deallocate prepare s;
create view v2 as select * from json_table('[{"co\\\\lor": "blue", "price": 50}]', '$[*]' columns( color varchar(100) path '$.co\\\\lor') ) as T;
select * from v2;
color
blue
drop view v2;
explain format=json select * from
json_table('[{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}]', '$[*]' COLUMNS( a INT PATH '$.a')) as tt;
EXPLAIN
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "tt",
"access_type": "ALL",
"rows": 40,
"filtered": 100,
"table_function": "json_table"
}
}
}
explain select * from
json_table('[{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}]', '$[*]' COLUMNS( a INT PATH '$.a')) as tt;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE tt ALL NULL NULL NULL NULL 40 Table function: json_table
create view v1 as select * from
json_table('[{"color": "blue", "price": 50}]',
'$[*]' columns(color text path '$.nonexistent',
seq for ordinality)) as `ALIAS NOT QUOTED`;
select * from v1;
color seq
NULL 1
drop view v1;
create view v1 as select * from
json_table('[{"color": "blue", "price": 50},
{"color": "red", "price": 100}]',
'$[*]' columns(
color text path "$.QUOTES \" HERE \"",
color1 text path '$.QUOTES " HERE "',
color2 text path "$.QUOTES ' HERE '",
seq for ordinality)) as T;
select * from v1;
color color1 color2 seq
NULL NULL NULL 1
NULL NULL NULL 2
drop view v1;
CREATE TABLE t1 (x INT);
INSERT INTO t1 VALUES (1), (2), (3);
SELECT t1.x*2 m, jt.* FROM t1,
JSON_TABLE(m, '$[*]' COLUMNS (i INT PATH '$')) jt;
ERROR 42S22: Unknown column 'm' in 'JSON_TABLE argument'
DROP TABLE t1;
select * from json_table(JS3.size, '$' columns (size INT PATH '$.size')) as JS1, json_table(JS1.size, '$' columns (size INT PATH '$.size')) as JS2, json_table(JS1.size, '$' columns (size INT PATH '$.size')) as JS3 where 1;
ERROR 42S02: Unknown table 'JS3' in JSON_TABLE argument
create table t1 (json varchar(100) character set utf8);
insert into t1 values ('{"value":"АБВ"}');
create table tj1 as
select T.value
from t1, json_table(t1.json, '$' columns (value varchar(32) PATH '$.value')) T;
show create table tj1;
Table Create Table
tj1 CREATE TABLE `tj1` (
`value` varchar(32) CHARACTER SET utf8 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
drop table tj1;
CREATE TABLE t1(id INT, f1 JSON);
INSERT INTO t1 VALUES
(1, '{\"1\": 1}'),
(2, '{\"1\": 2}'),
(3, '{\"1\": 3}'),
(4, '{\"1\": 4}'),
(5, '{\"1\": 5}'),
(6, '{\"1\": 6}');
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze Warning Engine-independent statistics are not collected for column 'f1'
test.t1 analyze status OK
SELECT * FROM JSON_TABLE(tt3.f1, "$" COLUMNS (id FOR ORDINALITY)) AS tbl STRAIGHT_JOIN t1 AS tt3;
ERROR 42S02: Unknown table 'tt3' in JSON_TABLE argument
SELECT * FROM t1 as jj1,
(SELECT tt2.*
FROM
t1 as tt2,
JSON_TABLE(tt3.f1, "$" COLUMNS (id FOR ORDINALITY)) AS tbl
STRAIGHT_JOIN
t1 AS tt3
) dt
ORDER BY 1,3 LIMIT 10;
ERROR 42S22: Unknown column 'tt3.f1' in 'JSON_TABLE argument'
drop table t1;
select collation(x) from
JSON_TABLE('["abc"]', '$[*]' COLUMNS (x VARCHAR(10) CHARSET latin1 PATH '$')) tbl;
collation(x)
latin1_swedish_ci
SELECT * FROM JSON_TABLE('{"x":1, "y":2}', _utf8mb4'$' COLUMNS (NESTED PATH _utf8mb4'$.x'
COLUMNS(y INT PATH _utf8mb4'$.y' DEFAULT _utf8mb4'1' ON EMPTY DEFAULT _utf8mb4'2' ON ERROR))) jt;
y
1
select * from json_table(
'{"name":"t-shirt", "colors": ["yellow", "blue"],"sizes": ["small", "medium", "large"]}',
'$' columns(name varchar(32) path '$.name',
nested path '$.colors[*]' columns (
color varchar(32) path '$',
nested path '$.sizes[*]' columns (
size varchar(32) path '$'
)))) as t;
name color size
t-shirt yellow NULL
t-shirt blue NULL
SELECT x, length(x) FROM
JSON_TABLE('{}', '$' COLUMNS (x VARCHAR(10) PATH '$.x' DEFAULT 'abcdefg' ON EMPTY)) jt;
x length(x)
abcdefg 7
select * from
json_table('[{"a":"aa"}, {"b":null}]', '$[*]'
columns (col1 int path '$.b' default '456' on empty)) as tt;
col1
456
NULL
select * from
json_table('[{"a":"aa"}, {"b":true}]', '$[*]'
columns (col1 int path '$.b' default '456' on empty)) as tt;
col1
456
1
select * from
json_table('[{"a":"aa"}, {"b":false}]', '$[*]'
columns (col1 int path '$.b' default '456' on empty)) as tt;
col1
456
0
select * from
json_table('[{"a":"aa"}, {"b":null}]', '$[*]'
columns (col1 varchar(100) path '$.b' default '456' on empty)) as tt;
col1
456
NULL
select * from
json_table('[{"a":"aa"}, {"b":true}]', '$[*]'
columns (col1 varchar(100) path '$.b' default '456' on empty)) as tt;
col1
456
true
select * from
json_table('[{"a":"aa"}, {"b":false}]', '$[*]'
columns (col1 varchar(100) path '$.b' default '456' on empty)) as tt;
col1
456
false
select * from
json_table( '[{"a":"asd"}, {"a":123}, {"a":[]}, {"a":{}} ]', '$[*]'
columns (id for ordinality,
intcol int path '$.a' default '1234' on empty default '5678' on error)
) as tt;
id intcol
1 5678
2 123
3 5678
4 5678
SELECT COUNT(*) FROM JSON_TABLE('[1, 2]', '$[*]' COLUMNS( I INT PATH '$')) tt;
COUNT(*)
2
create table t1 (a int);
insert into t1 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t2 (js json, b int);
insert into t2 select '[1,2,3]',A.a from t1 A, t1 B;
explain select * from t1,
(select * from t2, json_table(t2.js, '$[*]' columns (o for ordinality)) as jt) as TT2
where 1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 10
1 SIMPLE t2 ALL NULL NULL NULL NULL 100 Using join buffer (flat, BNL join)
1 SIMPLE jt ALL NULL NULL NULL NULL 40 Table function: json_table
drop table t1, t2;
CREATE TABLE t1 (x INT);
INSERT INTO t1 VALUES (1);
CREATE TABLE t2 (j JSON);
INSERT INTO t2 (j) VALUES ('[1,2,3]');
SELECT * FROM t1 RIGHT JOIN
(SELECT o FROM t2, JSON_TABLE(j, '$[*]' COLUMNS (o FOR ORDINALITY)) AS jt) AS t3 ON (t3.o = t1.x);
x o
1 1
NULL 2
NULL 3
DROP TABLE t1, t2;
create table t20 (a int not null);
create table t21 (a int not null primary key, js varchar(100));
insert into t20 values (1),(2);
insert into t21 values (1, '{"a":100}');
explain select t20.a, jt1.ab
from t20 left join t21 on t20.a=t21.a
join JSON_TABLE(t21.js,'$' COLUMNS (ab INT PATH '$.a')) AS jt1;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t20 ALL NULL NULL NULL NULL 2
1 SIMPLE t21 eq_ref PRIMARY PRIMARY 4 test.t20.a 1
1 SIMPLE jt1 ALL NULL NULL NULL NULL 40 Table function: json_table
drop table t20, t21;
select * from
json_table(
'[
{"name": "X",
"colors":["blue"], "sizes": [1,2,3,4], "prices" : [10,20]},
{"name": "Y",
"colors":["red"], "sizes": [10,11], "prices" : [100,200,300]}
]',
'$[*]' columns
(
seq0 for ordinality,
name varchar(4) path '$.name',
nested path '$.colors[*]' columns (
seq1 for ordinality,
color text path '$'
),
nested path '$.sizes[*]' columns (
seq2 for ordinality,
size int path '$'
),
nested path '$.prices[*]' columns (
seq3 for ordinality,
price int path '$'
)
)
) as T order by seq0, name;
seq0 name seq1 color seq2 size seq3 price
1 X NULL NULL NULL NULL 1 10
1 X NULL NULL NULL NULL 2 20
1 X NULL NULL 1 1 NULL NULL
1 X NULL NULL 2 2 NULL NULL
1 X NULL NULL 3 3 NULL NULL
1 X NULL NULL 4 4 NULL NULL
1 X 1 blue NULL NULL NULL NULL
2 Y NULL NULL NULL NULL 1 100
2 Y NULL NULL NULL NULL 2 200
2 Y NULL NULL NULL NULL 3 300
2 Y NULL NULL 1 10 NULL NULL
2 Y NULL NULL 2 11 NULL NULL
2 Y 1 red NULL NULL NULL NULL
select * from json_table('[]', '$' COLUMNS(x FOR ORDINALITY));
ERROR HY000: Every table function must have an alias.
select min(x) from json_table('[]', '$' COLUMNS(x FOR ORDINALITY)) a;
min(x)
1
#
# End of 10.5 tests
#

File diff suppressed because it is too large Load Diff