Skip to content

Commit ac9c0be

Browse files
author
Varun Deep Saini
committed
MDEV-25727 Add FORMAT JSON support to JSON_TABLE
Allow explicit FORMAT JSON columns in JSON_TABLE for supported string, blob, and JSON targets. Preserve the explicit clause in view printing and add regression coverage for formatted extraction, unsupported targets, and SHOW CREATE VIEW. Signed-off-by: Varun Deep Saini <varun.23bcs10048@ms.sst.scaler.com>
1 parent 637f8c4 commit ac9c0be

5 files changed

Lines changed: 108 additions & 6 deletions

File tree

mysql-test/suite/json/r/json_table_mysql.result

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,40 @@ id jpath json_path jexst
106106
3 NULL NULL 1
107107
select * from
108108
json_table(
109+
'[{"name":"Jeans","sizes":[32,34,36],"details":{"fit":"regular"},"flag":true,"jsnull":null},
110+
{"name":"T-Shirt","sizes":["Medium","Large"],"details":{"fit":"loose"},"flag":false,"jsnull":null},
111+
{"name":"Cellphone"}]',
112+
'$[*]' columns (name varchar(10) path '$.name',
113+
sizes varchar(100) format json path '$.sizes',
114+
details text format json path '$.details',
115+
flag varchar(10) format json path '$.flag',
116+
jsnull varchar(10) format json path '$.jsnull')
117+
) as jt;
118+
name sizes details flag jsnull
119+
Jeans [32,34,36] {"fit":"regular"} true null
120+
T-Shirt ["Medium","Large"] {"fit":"loose"} false null
121+
Cellphone NULL NULL NULL NULL
122+
select * from
123+
json_table(
124+
'[{"a":[1,2,3]}]',
125+
'$[*]' columns (a int format json path '$.a')
126+
) as jt;
127+
ERROR HY000: Incorrect usage of FORMAT JSON and non-string JSON_TABLE column
128+
create view v_fmt as
129+
select * from
130+
json_table(
131+
'[{"sizes":[1,2]}]',
132+
'$[*]' columns (sizes varchar(20) format json path '$.sizes')
133+
) as jt;
134+
select * from v_fmt;
135+
sizes
136+
[1,2]
137+
show create view v_fmt;
138+
View Create View character_set_client collation_connection
139+
v_fmt CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_fmt` AS select `jt`.`sizes` AS `sizes` from JSON_TABLE('[{"sizes":[1,2]}]', '$[*]' COLUMNS (`sizes` varchar(20) FORMAT JSON PATH '$.sizes')) `jt` latin1 latin1_swedish_ci
140+
drop view v_fmt;
141+
select * from
142+
json_table(
109143
'[{"a":"3"},{"a":2},{"b":1},{"a":0}]',
110144
'$[*]' columns (id for ordinality,
111145
jpath varchar(100) path '$.a' error on empty,

mysql-test/suite/json/t/json_table_mysql.test

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,35 @@ select * from
8484
#eval $query;
8585
#eval explain $query;
8686

87+
select * from
88+
json_table(
89+
'[{"name":"Jeans","sizes":[32,34,36],"details":{"fit":"regular"},"flag":true,"jsnull":null},
90+
{"name":"T-Shirt","sizes":["Medium","Large"],"details":{"fit":"loose"},"flag":false,"jsnull":null},
91+
{"name":"Cellphone"}]',
92+
'$[*]' columns (name varchar(10) path '$.name',
93+
sizes varchar(100) format json path '$.sizes',
94+
details text format json path '$.details',
95+
flag varchar(10) format json path '$.flag',
96+
jsnull varchar(10) format json path '$.jsnull')
97+
) as jt;
98+
99+
--error ER_WRONG_USAGE
100+
select * from
101+
json_table(
102+
'[{"a":[1,2,3]}]',
103+
'$[*]' columns (a int format json path '$.a')
104+
) as jt;
105+
106+
create view v_fmt as
107+
select * from
108+
json_table(
109+
'[{"sizes":[1,2]}]',
110+
'$[*]' columns (sizes varchar(20) format json path '$.sizes')
111+
) as jt;
112+
select * from v_fmt;
113+
show create view v_fmt;
114+
drop view v_fmt;
115+
87116
--error ER_JSON_TABLE_ERROR_ON_FIELD
88117
select * from
89118
json_table(

sql/json_table.cc

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ static void store_json_in_field(Field *f, const json_engine_t *je)
418418
}
419419

420420

421-
static int store_json_in_json(Field *f, json_engine_t *je)
421+
static int store_json_in_field_as_json(Field *f, json_engine_t *je)
422422
{
423423
const uchar *from= je->value_begin;
424424
const uchar *to;
@@ -617,7 +617,7 @@ int ha_json_table::fill_column_values(THD *thd, uchar * buf, uchar *pos)
617617
{
618618
if (jc->m_format_json)
619619
{
620-
if (!(error= store_json_in_json(*f, &je)))
620+
if (!(error= store_json_in_field_as_json(*f, &je)))
621621
error= er_handler.errors;
622622
}
623623
else if (!(error= !json_value_scalar(&je)))
@@ -931,6 +931,21 @@ TABLE *create_table_for_function(THD *thd, TABLE_LIST *sql_table)
931931
}
932932

933933

934+
bool Json_table_column::enable_format_json()
935+
{
936+
if (!m_field->type_handler()->is_general_purpose_string_type())
937+
{
938+
my_error(ER_WRONG_USAGE, MYF(0), "FORMAT JSON",
939+
"non-string JSON_TABLE column");
940+
return true;
941+
}
942+
943+
m_format_json= true;
944+
m_explicit_format_json= true;
945+
return false;
946+
}
947+
948+
934949
int Json_table_column::set(THD *thd, enum_type ctype, const LEX_CSTRING &path,
935950
CHARSET_INFO *cs)
936951
{
@@ -955,8 +970,11 @@ int Json_table_column::set(THD *thd, enum_type ctype, const LEX_CSTRING &path,
955970
*/
956971
m_path.s.c_str= (const uchar *) path.str;
957972

958-
if (ctype == PATH)
959-
m_format_json= m_field->type_handler() == &type_handler_long_blob_json;
973+
if (ctype == PATH &&
974+
Type_handler_json_common::is_json_type_handler(m_field->type_handler()))
975+
{
976+
m_format_json= true;
977+
}
960978

961979
return 0;
962980
}
@@ -1018,17 +1036,22 @@ int Json_table_column::print(THD *thd, Field **f, String *str)
10181036
{
10191037
static const LEX_CSTRING path= { STRING_WITH_LEN(" PATH ") };
10201038
static const LEX_CSTRING exists_path= { STRING_WITH_LEN(" EXISTS PATH ") };
1039+
bool is_json_type=
1040+
Type_handler_json_common::is_json_type_handler((*f)->type_handler());
10211041

10221042
(*f)->sql_type(column_type);
10231043

1024-
if ((m_format_json ? str->append(STRING_WITH_LEN(" JSON ")) : str->append(column_type)))
1044+
if (is_json_type ? str->append(STRING_WITH_LEN("JSON")) :
1045+
str->append(column_type))
10251046
return 1;
10261047
if (((*f)->has_charset() && m_explicit_cs &&
10271048
(str->append(STRING_WITH_LEN(" CHARSET ")) ||
10281049
str->append(&m_explicit_cs->cs_name) ||
10291050
(Charset(m_explicit_cs).can_have_collate_clause() &&
10301051
(str->append(STRING_WITH_LEN(" COLLATE ")) ||
10311052
str->append(&m_explicit_cs->coll_name))))) ||
1053+
(m_explicit_format_json &&
1054+
str->append(STRING_WITH_LEN(" FORMAT JSON"))) ||
10321055
str->append(m_column_type == PATH ? &path : &exists_path) ||
10331056
print_path(str, &m_path))
10341057
return 1;

sql/json_table.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ class Json_table_column : public Sql_alloc
151151

152152
enum_type m_column_type;
153153
bool m_format_json;
154+
bool m_explicit_format_json;
154155
json_path_t m_path;
155156
On_response m_on_error;
156157
On_response m_on_empty;
@@ -165,12 +166,14 @@ class Json_table_column : public Sql_alloc
165166
int set(THD *thd, enum_type ctype, const LEX_CSTRING &path, CHARSET_INFO *cs);
166167
int set(THD *thd, enum_type ctype, const LEX_CSTRING &path,
167168
const Lex_column_charset_collation_attrs_st &cl);
169+
bool enable_format_json();
168170
Json_table_column(Create_field *f, Json_table_nested_path *nest) :
169171
m_field(f), m_nest(nest), m_explicit_cs(NULL)
170172
{
171173
m_on_error.m_response= RESPONSE_NOT_SPECIFIED;
172174
m_on_empty.m_response= RESPONSE_NOT_SPECIFIED;
173175
m_format_json= false;
176+
m_explicit_format_json= false;
174177
}
175178
int print(THD *tnd, Field **f, String *str);
176179
};
@@ -291,4 +294,3 @@ table_map add_table_function_dependencies(List<TABLE_LIST> *join_list,
291294
table_map nest_tables, bool *error);
292295

293296
#endif /* JSON_TABLE_INCLUDED */
294-

sql/sql_yacc.yy

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12310,6 +12310,20 @@ json_table_column_type:
1231012310
MYSQL_YYABORT;
1231112311
}
1231212312
}
12313+
| json_table_field_type FORMAT_SYM JSON_SYM PATH_SYM json_text_literal
12314+
json_opt_on_empty_or_error
12315+
{
12316+
if (Lex->last_field->set_attributes(thd, $1,
12317+
COLUMN_DEFINITION_TABLE_FIELD))
12318+
MYSQL_YYABORT;
12319+
if (Lex->json_table->m_cur_json_table_column->enable_format_json() ||
12320+
Lex->json_table->m_cur_json_table_column->
12321+
set(thd, Json_table_column::PATH, $5,
12322+
$1.charset_collation_attrs()))
12323+
{
12324+
MYSQL_YYABORT;
12325+
}
12326+
}
1231312327
| json_table_field_type EXISTS PATH_SYM json_text_literal
1231412328
{
1231512329
if (Lex->last_field->set_attributes(thd, $1,

0 commit comments

Comments
 (0)