Skip to content
/ server Public
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions mysql-test/suite/json/r/json_table_mysql.result
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,86 @@ id jpath json_path jexst
3 NULL NULL 1
select * from
json_table(
'[{"name":"Jeans","sizes":[32,34,36],"details":{"fit":"regular"},"flag":true,"jsnull":null},
{"name":"T-Shirt","sizes":["Medium","Large"],"details":{"fit":"loose"},"flag":false,"jsnull":null},
{"name":"Cellphone"}]',
'$[*]' columns (name varchar(10) path '$.name',
sizes varchar(100) format json path '$.sizes',
details text format json path '$.details',
flag varchar(10) format json path '$.flag',
jsnull varchar(10) format json path '$.jsnull')
) as jt;
name sizes details flag jsnull
Jeans [32,34,36] {"fit":"regular"} true null
T-Shirt ["Medium","Large"] {"fit":"loose"} false null
Cellphone NULL NULL NULL NULL
select * from
json_table(
'[{"doc":[1,2]},{"doc":{"k":"v"}},{"doc":null},{}]',
'$[*]' columns (doc json format json path '$.doc' null on empty)
) as jt;
doc
[1,2]
{"k":"v"}
null
NULL
SELECT HEX(doc) FROM
json_table(
'[{"doc":[1,2]},{}]',
'$[*]' columns (doc blob format json path '$.doc' null on empty)
) as jt;
HEX(doc)
5B312C325D
NULL
select * from
json_table(
'[{"name":"Jeans","sizes":[32,34,36]},{"name":"Cellphone"}]',
'$[*]' columns (name varchar(10) path '$.name',
sizes varchar(100) format json path '$.sizes'
default '[99]' on empty)
) as jt;
name sizes
Jeans [32,34,36]
Cellphone [99]
select * from
json_table(
'[{"a":[1]},{"a":[2]}]',
'$' columns (a varchar(20) format json path '$[*].a' error on error)
) as jt;
ERROR HY000: Can't store multiple matches of the path in the column 'a' of JSON_TABLE 'jt'.
select * from
json_table(
'[{"a":[1,2,3]}]',
'$[*]' columns (a int format json path '$.a')
) as jt;
ERROR HY000: Incorrect usage of FORMAT JSON and non-string JSON_TABLE column
create view v_fmt as
select * from
json_table(
'[{"sizes":[1,2]}]',
'$[*]' columns (sizes varchar(20) format json path '$.sizes')
) as jt;
select * from v_fmt;
sizes
[1,2]
show create view v_fmt;
View Create View character_set_client collation_connection
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
drop view v_fmt;
create view v_fmt_cs as
select * from
json_table(
'[{"sizes":[1,2]}]',
'$[*]' columns (
sizes varchar(20) character set utf8mb4 collate utf8mb4_bin
format json path '$.sizes')
) as jt;
show create view v_fmt_cs;
View Create View character_set_client collation_connection
v_fmt_cs CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v_fmt_cs` AS select `jt`.`sizes` AS `sizes` from JSON_TABLE('[{"sizes":[1,2]}]', '$[*]' COLUMNS (`sizes` varchar(20) CHARSET utf8mb4 COLLATE utf8mb4_bin FORMAT JSON PATH '$.sizes')) `jt` latin1 latin1_swedish_ci
drop view v_fmt_cs;
select * from
json_table(
'[{"a":"3"},{"a":2},{"b":1},{"a":0}]',
'$[*]' columns (id for ordinality,
jpath varchar(100) path '$.a' error on empty,
Expand Down
67 changes: 67 additions & 0 deletions mysql-test/suite/json/t/json_table_mysql.test
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,73 @@ select * from
#eval $query;
#eval explain $query;

select * from
json_table(
'[{"name":"Jeans","sizes":[32,34,36],"details":{"fit":"regular"},"flag":true,"jsnull":null},
{"name":"T-Shirt","sizes":["Medium","Large"],"details":{"fit":"loose"},"flag":false,"jsnull":null},
{"name":"Cellphone"}]',
'$[*]' columns (name varchar(10) path '$.name',
sizes varchar(100) format json path '$.sizes',
details text format json path '$.details',
flag varchar(10) format json path '$.flag',
jsnull varchar(10) format json path '$.jsnull')
) as jt;

select * from
json_table(
'[{"doc":[1,2]},{"doc":{"k":"v"}},{"doc":null},{}]',
'$[*]' columns (doc json format json path '$.doc' null on empty)
) as jt;

SELECT HEX(doc) FROM
json_table(
'[{"doc":[1,2]},{}]',
'$[*]' columns (doc blob format json path '$.doc' null on empty)
) as jt;

select * from
json_table(
'[{"name":"Jeans","sizes":[32,34,36]},{"name":"Cellphone"}]',
'$[*]' columns (name varchar(10) path '$.name',
sizes varchar(100) format json path '$.sizes'
default '[99]' on empty)
) as jt;

--error ER_JSON_TABLE_MULTIPLE_MATCHES
select * from
json_table(
'[{"a":[1]},{"a":[2]}]',
'$' columns (a varchar(20) format json path '$[*].a' error on error)
) as jt;

--error ER_WRONG_USAGE
select * from
json_table(
'[{"a":[1,2,3]}]',
'$[*]' columns (a int format json path '$.a')
) as jt;

create view v_fmt as
select * from
json_table(
'[{"sizes":[1,2]}]',
'$[*]' columns (sizes varchar(20) format json path '$.sizes')
) as jt;
select * from v_fmt;
show create view v_fmt;
drop view v_fmt;

create view v_fmt_cs as
select * from
json_table(
'[{"sizes":[1,2]}]',
'$[*]' columns (
sizes varchar(20) character set utf8mb4 collate utf8mb4_bin
format json path '$.sizes')
) as jt;
show create view v_fmt_cs;
drop view v_fmt_cs;

--error ER_JSON_TABLE_ERROR_ON_FIELD
select * from
json_table(
Expand Down
33 changes: 28 additions & 5 deletions sql/json_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ static void store_json_in_field(Field *f, const json_engine_t *je)
}


static int store_json_in_json(Field *f, json_engine_t *je)
static int store_json_in_field_as_json(Field *f, json_engine_t *je)
{
const uchar *from= je->value_begin;
const uchar *to;
Expand Down Expand Up @@ -617,7 +617,7 @@ int ha_json_table::fill_column_values(THD *thd, uchar * buf, uchar *pos)
{
if (jc->m_format_json)
{
if (!(error= store_json_in_json(*f, &je)))
if (!(error= store_json_in_field_as_json(*f, &je)))
error= er_handler.errors;
}
else if (!(error= !json_value_scalar(&je)))
Expand Down Expand Up @@ -931,6 +931,21 @@ TABLE *create_table_for_function(THD *thd, TABLE_LIST *sql_table)
}


bool Json_table_column::enable_format_json()
{
if (!m_field->type_handler()->is_general_purpose_string_type())
{
my_error(ER_WRONG_USAGE, MYF(0), "FORMAT JSON",
"non-string JSON_TABLE column");
return true;
}

m_format_json= true;
m_explicit_format_json= true;
return false;
}


int Json_table_column::set(THD *thd, enum_type ctype, const LEX_CSTRING &path,
CHARSET_INFO *cs)
{
Expand All @@ -955,8 +970,11 @@ int Json_table_column::set(THD *thd, enum_type ctype, const LEX_CSTRING &path,
*/
m_path.s.c_str= (const uchar *) path.str;

if (ctype == PATH)
m_format_json= m_field->type_handler() == &type_handler_long_blob_json;
if (ctype == PATH &&
Type_handler_json_common::is_json_type_handler(m_field->type_handler()))
{
m_format_json= true;
}

return 0;
}
Expand Down Expand Up @@ -1018,17 +1036,22 @@ int Json_table_column::print(THD *thd, Field **f, String *str)
{
static const LEX_CSTRING path= { STRING_WITH_LEN(" PATH ") };
static const LEX_CSTRING exists_path= { STRING_WITH_LEN(" EXISTS PATH ") };
bool is_json_type=
Type_handler_json_common::is_json_type_handler(m_field->type_handler());

(*f)->sql_type(column_type);

if ((m_format_json ? str->append(STRING_WITH_LEN(" JSON ")) : str->append(column_type)))
if (is_json_type ? str->append(STRING_WITH_LEN("JSON")) :
str->append(column_type))
return 1;
if (((*f)->has_charset() && m_explicit_cs &&
(str->append(STRING_WITH_LEN(" CHARSET ")) ||
str->append(&m_explicit_cs->cs_name) ||
(Charset(m_explicit_cs).can_have_collate_clause() &&
(str->append(STRING_WITH_LEN(" COLLATE ")) ||
str->append(&m_explicit_cs->coll_name))))) ||
(m_explicit_format_json &&
str->append(STRING_WITH_LEN(" FORMAT JSON"))) ||
str->append(m_column_type == PATH ? &path : &exists_path) ||
print_path(str, &m_path))
return 1;
Expand Down
4 changes: 3 additions & 1 deletion sql/json_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class Json_table_column : public Sql_alloc

enum_type m_column_type;
bool m_format_json;
bool m_explicit_format_json;
json_path_t m_path;
On_response m_on_error;
On_response m_on_empty;
Expand All @@ -165,12 +166,14 @@ class Json_table_column : public Sql_alloc
int set(THD *thd, enum_type ctype, const LEX_CSTRING &path, CHARSET_INFO *cs);
int set(THD *thd, enum_type ctype, const LEX_CSTRING &path,
const Lex_column_charset_collation_attrs_st &cl);
bool enable_format_json();
Json_table_column(Create_field *f, Json_table_nested_path *nest) :
m_field(f), m_nest(nest), m_explicit_cs(NULL)
{
m_on_error.m_response= RESPONSE_NOT_SPECIFIED;
m_on_empty.m_response= RESPONSE_NOT_SPECIFIED;
m_format_json= false;
m_explicit_format_json= false;
}
int print(THD *tnd, Field **f, String *str);
};
Expand Down Expand Up @@ -291,4 +294,3 @@ table_map add_table_function_dependencies(List<TABLE_LIST> *join_list,
table_map nest_tables, bool *error);

#endif /* JSON_TABLE_INCLUDED */

14 changes: 14 additions & 0 deletions sql/sql_yacc.yy
Original file line number Diff line number Diff line change
Expand Up @@ -12310,6 +12310,20 @@ json_table_column_type:
MYSQL_YYABORT;
}
}
| json_table_field_type FORMAT_SYM JSON_SYM PATH_SYM json_text_literal
json_opt_on_empty_or_error
{
if (Lex->last_field->set_attributes(thd, $1,
COLUMN_DEFINITION_TABLE_FIELD))
MYSQL_YYABORT;
if (Lex->json_table->m_cur_json_table_column->enable_format_json() ||
Lex->json_table->m_cur_json_table_column->
set(thd, Json_table_column::PATH, $5,
$1.charset_collation_attrs()))
{
MYSQL_YYABORT;
}
}
| json_table_field_type EXISTS PATH_SYM json_text_literal
{
if (Lex->last_field->set_attributes(thd, $1,
Expand Down