Skip to content

Commit 51054ba

Browse files
committed
MDEV-37072: Implement IS JSON predicate
Add support for the SQL standard IS JSON predicate with the syntax: expr IS [ NOT ] JSON [ { VALUE | ARRAY | OBJECT | SCALAR } ] [ { WITH | WITHOUT } UNIQUE [ KEYS ] ] The predicate allows checking if an expression is valid JSON and optionally constrains the JSON type (VALUE, ARRAY, OBJECT, SCALAR) and whether object keys are unique. The implementation includes: - Basic IS JSON validation - Support for NOT operator - Type constraints (VALUE, ARRAY, OBJECT, SCALAR) - Unique keys constraint (WITH/WITHOUT UNIQUE KEYS)
1 parent e7bb12f commit 51054ba

File tree

6 files changed

+547
-2
lines changed

6 files changed

+547
-2
lines changed

mysql-test/main/func_json.result

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5263,4 +5263,195 @@ SET @obj1='{ "a": 1,"b": 2,"c": 3}';
52635263
SELECT JSON_OBJECT_FILTER_KEYS (@obj1,@arr1);
52645264
JSON_OBJECT_FILTER_KEYS (@obj1,@arr1)
52655265
NULL
5266+
#
5267+
# MDEV-37072: Implement IS JSON predicate
5268+
#
5269+
SELECT '[1, 2]' IS JSON;
5270+
'[1, 2]' IS JSON
5271+
1
5272+
SELECT '{"key1":1, "key2":[2,3]}' IS JSON;
5273+
'{"key1":1, "key2":[2,3]}' IS JSON
5274+
1
5275+
SELECT '123' IS JSON;
5276+
'123' IS JSON
5277+
1
5278+
SELECT 'null' IS JSON;
5279+
'null' IS JSON
5280+
1
5281+
SELECT 'invalid' IS JSON;
5282+
'invalid' IS JSON
5283+
0
5284+
SELECT '{"key1":1, "key2":[2,3]' IS JSON;
5285+
'{"key1":1, "key2":[2,3]' IS JSON
5286+
0
5287+
SELECT '[1, 2' IS JSON;
5288+
'[1, 2' IS JSON
5289+
0
5290+
SELECT 'NULL' IS JSON;
5291+
'NULL' IS JSON
5292+
0
5293+
SELECT 'invalid' IS NOT JSON;
5294+
'invalid' IS NOT JSON
5295+
1
5296+
SELECT '{"key1":1, "key2":[2,3]' IS NOT JSON;
5297+
'{"key1":1, "key2":[2,3]' IS NOT JSON
5298+
1
5299+
SELECT '[1, 2]' IS NOT JSON;
5300+
'[1, 2]' IS NOT JSON
5301+
0
5302+
SELECT '{"key1":1, "key2":[2,3]}' IS NOT JSON;
5303+
'{"key1":1, "key2":[2,3]}' IS NOT JSON
5304+
0
5305+
# Type constraints
5306+
SELECT js,
5307+
js IS JSON "json?",
5308+
js IS JSON VALUE "value?",
5309+
js IS JSON SCALAR "scalar?",
5310+
js IS JSON OBJECT "object?",
5311+
js IS JSON ARRAY "array?"
5312+
FROM (VALUES
5313+
('123'), ('"string"'), ('{"key":1}'), ('[1,2,3]'), ('[]'), ('{}'),
5314+
('true'), ('false'), ('null')) foo(js);
5315+
js json? value? scalar? object? array?
5316+
123 1 1 1 0 0
5317+
"string" 1 1 1 0 0
5318+
{"key":1} 1 1 0 1 0
5319+
[1,2,3] 1 1 0 0 1
5320+
[] 1 1 0 0 1
5321+
{} 1 1 0 1 0
5322+
true 1 1 1 0 0
5323+
false 1 1 1 0 0
5324+
null 1 1 1 0 0
5325+
# UNIQUE KEYS constraint
5326+
SELECT js,
5327+
js IS JSON OBJECT WITH UNIQUE KEYS "object_with_unique",
5328+
js IS JSON OBJECT WITHOUT UNIQUE KEYS "object_without_unique",
5329+
js IS JSON ARRAY WITH UNIQUE KEYS "array_with_unique",
5330+
js IS JSON ARRAY WITHOUT UNIQUE KEYS "array_without_unique"
5331+
FROM (VALUES
5332+
('{"a":1, "b":2, "c":3}'),
5333+
('{"a":1, "a":2, "a":3}'),
5334+
('[{"a":"1"},{"c":"2","c":"3"}]'),
5335+
('[{"a":"1"},{"b":"2","c":"3"}]'),
5336+
('[1,2,3]'), ('[1,1,1]'), ('[]'), ('123'),
5337+
('"string"'), ('true'), ('null')) foo(js);
5338+
js object_with_unique object_without_unique array_with_unique array_without_unique
5339+
{"a":1, "b":2, "c":3} 1 1 0 0
5340+
{"a":1, "a":2, "a":3} 1 1 0 0
5341+
[{"a":"1"},{"c":"2","c":"3"}] 0 0 1 1
5342+
[{"a":"1"},{"b":"2","c":"3"}] 0 0 1 1
5343+
[1,2,3] 0 0 1 1
5344+
[1,1,1] 0 0 1 1
5345+
[] 0 0 1 1
5346+
123 0 0 0 0
5347+
"string" 0 0 0 0
5348+
true 0 0 0 0
5349+
null 0 0 0 0
5350+
# Test with table data
5351+
CREATE TABLE test_json (
5352+
json_col JSON,
5353+
text_col TEXT
5354+
);
5355+
INSERT INTO test_json VALUES
5356+
('{"name":"Alice", "age":25}', '{"name":"Alice", "age":25}'),
5357+
('[1,2,3]', '[1,2,3]'),
5358+
('42', '42'),
5359+
('"hello"', '"hello"'),
5360+
('true', 'true'),
5361+
('null', 'null'),
5362+
('"invalid"', 'invalid'),
5363+
('{"key1":1, "key2":2}', '{"key1":1, "key2":2}'),
5364+
('{"key1":1, "key1":2}', '{"key1":1, "key1":2}');
5365+
SELECT
5366+
json_col,
5367+
json_col IS JSON as is_json,
5368+
json_col IS JSON VALUE as is_value,
5369+
json_col IS JSON SCALAR as is_scalar,
5370+
json_col IS JSON OBJECT as is_object,
5371+
json_col IS JSON ARRAY as is_array,
5372+
json_col IS JSON OBJECT WITH UNIQUE KEYS as object_with_unique,
5373+
json_col IS JSON OBJECT WITHOUT UNIQUE KEYS as object_without_unique
5374+
FROM test_json;
5375+
json_col is_json is_value is_scalar is_object is_array object_with_unique object_without_unique
5376+
{"name":"Alice", "age":25} 1 1 0 1 0 1 1
5377+
[1,2,3] 1 1 0 0 1 0 0
5378+
42 1 1 1 0 0 0 0
5379+
"hello" 1 1 1 0 0 0 0
5380+
true 1 1 1 0 0 0 0
5381+
null 1 1 1 0 0 0 0
5382+
"invalid" 1 1 1 0 0 0 0
5383+
{"key1":1, "key2":2} 1 1 0 1 0 1 1
5384+
{"key1":1, "key1":2} 1 1 0 1 0 0 1
5385+
SELECT
5386+
text_col,
5387+
text_col IS JSON as is_json,
5388+
text_col IS JSON VALUE as is_value,
5389+
text_col IS JSON SCALAR as is_scalar,
5390+
text_col IS JSON OBJECT as is_object,
5391+
text_col IS JSON ARRAY as is_array
5392+
FROM test_json;
5393+
text_col is_json is_value is_scalar is_object is_array
5394+
{"name":"Alice", "age":25} 1 1 0 1 0
5395+
[1,2,3] 1 1 0 0 1
5396+
42 1 1 1 0 0
5397+
"hello" 1 1 1 0 0
5398+
true 1 1 1 0 0
5399+
null 1 1 1 0 0
5400+
invalid 0 0 0 0 0
5401+
{"key1":1, "key2":2} 1 1 0 1 0
5402+
{"key1":1, "key1":2} 1 1 0 1 0
5403+
SELECT
5404+
COUNT(*) as total_rows,
5405+
SUM(json_col IS JSON) as valid_json_count,
5406+
SUM(json_col IS JSON OBJECT) as object_count,
5407+
SUM(json_col IS JSON ARRAY) as array_count,
5408+
SUM(json_col IS JSON SCALAR) as scalar_count
5409+
FROM test_json;
5410+
total_rows valid_json_count object_count array_count scalar_count
5411+
9 9 3 1 5
5412+
# Edge cases
5413+
set names utf8mb4;
5414+
SELECT js,
5415+
js IS JSON "json?",
5416+
js IS JSON VALUE "value?",
5417+
js IS JSON SCALAR "scalar?",
5418+
js IS JSON OBJECT "object?",
5419+
js IS JSON ARRAY "array?"
5420+
FROM (VALUES
5421+
(NULL), (''), (' '), ('\n'), ('\t'),
5422+
('{"key":1,}'), ('{"key":1, "key2":}'), ('{key:1}'),
5423+
('{"emoji":"😊"}'), ('{"unicode":"\\u0041"}'),
5424+
(x'48656C6C6F'), ('2'), (CONCAT('{"a":', 1, '}')),
5425+
(JSON_OBJECT('a', 1, 'b', 2)), (JSON_ARRAY(1, 2, 3)), (JSON_QUOTE('hello'))) foo(js);
5426+
js json? value? scalar? object? array?
5427+
NULL NULL NULL NULL NULL NULL
5428+
0 0 0 0 0
5429+
0 0 0 0 0
5430+
5431+
0 0 0 0 0
5432+
0 0 0 0 0
5433+
{"key":1,} 0 0 0 0 0
5434+
{"key":1, "key2":} 0 0 0 0 0
5435+
{key:1} 0 0 0 0 0
5436+
{"emoji":"😊"} 1 1 0 1 0
5437+
{"unicode":"\u0041"} 1 1 0 1 0
5438+
Hello 0 0 0 0 0
5439+
2 1 1 1 0 0
5440+
{"a":1} 1 1 0 1 0
5441+
{"a": 1, "b": 2} 1 1 0 1 0
5442+
[1, 2, 3] 1 1 0 0 1
5443+
"hello" 1 1 1 0 0
5444+
# Large json object with unique keys
5445+
SET @json = '{"key1":1';
5446+
SET @i = 2;
5447+
WHILE @i <= 1000 DO
5448+
SET @json = CONCAT(@json, ',"key', @i, '":', @i);
5449+
SET @i = @i + 1;
5450+
END WHILE;
5451+
SET @json = CONCAT(@json, '}');
5452+
SELECT @json IS JSON OBJECT WITH UNIQUE KEYS AS unique_keys;
5453+
|
5454+
unique_keys
5455+
1
5456+
DROP TABLE test_json;
52665457
# End of 11.2 Test

mysql-test/main/func_json.test

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4162,4 +4162,133 @@ SET CHARACTER SET utf8;
41624162
SET @obj1='{ "a": 1,"b": 2,"c": 3}';
41634163
SELECT JSON_OBJECT_FILTER_KEYS (@obj1,@arr1);
41644164

4165+
4166+
--echo #
4167+
--echo # MDEV-37072: Implement IS JSON predicate
4168+
--echo #
4169+
4170+
SELECT '[1, 2]' IS JSON;
4171+
SELECT '{"key1":1, "key2":[2,3]}' IS JSON;
4172+
SELECT '123' IS JSON;
4173+
SELECT 'null' IS JSON;
4174+
4175+
SELECT 'invalid' IS JSON;
4176+
SELECT '{"key1":1, "key2":[2,3]' IS JSON;
4177+
SELECT '[1, 2' IS JSON;
4178+
SELECT 'NULL' IS JSON;
4179+
4180+
SELECT 'invalid' IS NOT JSON;
4181+
SELECT '{"key1":1, "key2":[2,3]' IS NOT JSON;
4182+
SELECT '[1, 2]' IS NOT JSON;
4183+
SELECT '{"key1":1, "key2":[2,3]}' IS NOT JSON;
4184+
4185+
--echo # Type constraints
4186+
4187+
SELECT js,
4188+
js IS JSON "json?",
4189+
js IS JSON VALUE "value?",
4190+
js IS JSON SCALAR "scalar?",
4191+
js IS JSON OBJECT "object?",
4192+
js IS JSON ARRAY "array?"
4193+
FROM (VALUES
4194+
('123'), ('"string"'), ('{"key":1}'), ('[1,2,3]'), ('[]'), ('{}'),
4195+
('true'), ('false'), ('null')) foo(js);
4196+
4197+
--echo # UNIQUE KEYS constraint
4198+
4199+
SELECT js,
4200+
js IS JSON OBJECT WITH UNIQUE KEYS "object_with_unique",
4201+
js IS JSON OBJECT WITHOUT UNIQUE KEYS "object_without_unique",
4202+
js IS JSON ARRAY WITH UNIQUE KEYS "array_with_unique",
4203+
js IS JSON ARRAY WITHOUT UNIQUE KEYS "array_without_unique"
4204+
FROM (VALUES
4205+
('{"a":1, "b":2, "c":3}'),
4206+
('{"a":1, "a":2, "a":3}'),
4207+
('[{"a":"1"},{"c":"2","c":"3"}]'),
4208+
('[{"a":"1"},{"b":"2","c":"3"}]'),
4209+
('[1,2,3]'), ('[1,1,1]'), ('[]'), ('123'),
4210+
('"string"'), ('true'), ('null')) foo(js);
4211+
4212+
--echo # Test with table data
4213+
4214+
CREATE TABLE test_json (
4215+
json_col JSON,
4216+
text_col TEXT
4217+
);
4218+
4219+
INSERT INTO test_json VALUES
4220+
('{"name":"Alice", "age":25}', '{"name":"Alice", "age":25}'),
4221+
('[1,2,3]', '[1,2,3]'),
4222+
('42', '42'),
4223+
('"hello"', '"hello"'),
4224+
('true', 'true'),
4225+
('null', 'null'),
4226+
('"invalid"', 'invalid'),
4227+
('{"key1":1, "key2":2}', '{"key1":1, "key2":2}'),
4228+
('{"key1":1, "key1":2}', '{"key1":1, "key1":2}');
4229+
4230+
SELECT
4231+
json_col,
4232+
json_col IS JSON as is_json,
4233+
json_col IS JSON VALUE as is_value,
4234+
json_col IS JSON SCALAR as is_scalar,
4235+
json_col IS JSON OBJECT as is_object,
4236+
json_col IS JSON ARRAY as is_array,
4237+
json_col IS JSON OBJECT WITH UNIQUE KEYS as object_with_unique,
4238+
json_col IS JSON OBJECT WITHOUT UNIQUE KEYS as object_without_unique
4239+
FROM test_json;
4240+
4241+
SELECT
4242+
text_col,
4243+
text_col IS JSON as is_json,
4244+
text_col IS JSON VALUE as is_value,
4245+
text_col IS JSON SCALAR as is_scalar,
4246+
text_col IS JSON OBJECT as is_object,
4247+
text_col IS JSON ARRAY as is_array
4248+
FROM test_json;
4249+
4250+
SELECT
4251+
COUNT(*) as total_rows,
4252+
SUM(json_col IS JSON) as valid_json_count,
4253+
SUM(json_col IS JSON OBJECT) as object_count,
4254+
SUM(json_col IS JSON ARRAY) as array_count,
4255+
SUM(json_col IS JSON SCALAR) as scalar_count
4256+
FROM test_json;
4257+
4258+
--echo # Edge cases
4259+
set names utf8mb4;
4260+
4261+
SELECT js,
4262+
js IS JSON "json?",
4263+
js IS JSON VALUE "value?",
4264+
js IS JSON SCALAR "scalar?",
4265+
js IS JSON OBJECT "object?",
4266+
js IS JSON ARRAY "array?"
4267+
FROM (VALUES
4268+
(NULL), (''), (' '), ('\n'), ('\t'),
4269+
('{"key":1,}'), ('{"key":1, "key2":}'), ('{key:1}'),
4270+
('{"emoji":"😊"}'), ('{"unicode":"\\u0041"}'),
4271+
(x'48656C6C6F'), ('2'), (CONCAT('{"a":', 1, '}')),
4272+
(JSON_OBJECT('a', 1, 'b', 2)), (JSON_ARRAY(1, 2, 3)), (JSON_QUOTE('hello'))) foo(js);
4273+
4274+
--echo # Large json object with unique keys
4275+
4276+
DELIMITER |;
4277+
SET @json = '{"key1":1';
4278+
SET @i = 2;
4279+
4280+
WHILE @i <= 1000 DO
4281+
SET @json = CONCAT(@json, ',"key', @i, '":', @i);
4282+
SET @i = @i + 1;
4283+
END WHILE;
4284+
4285+
SET @json = CONCAT(@json, '}');
4286+
4287+
SELECT @json IS JSON OBJECT WITH UNIQUE KEYS AS unique_keys;
4288+
|
4289+
DELIMITER ;|
4290+
4291+
DROP TABLE test_json;
4292+
4293+
41654294
--echo # End of 11.2 Test

0 commit comments

Comments
 (0)