Commit d0a6a788 authored by Sergei Petrunia's avatar Sergei Petrunia

MDEV-25822 JSON_TABLE: default values should allow non-string literals

(Polished initial patch by Alexey Botchkov)
Make the code handle DEFAULT values of any datatype

- Make Json_table_column::On_response::m_default be Item*, not LEX_STRING.
- Change the parser to use string literal non-terminals for producing
  the DEFAULT value
-- Also, stop updating json_table->m_text_literal_cs for the DEFAULT
   value literals as it is not used.
parent 231900e5
...@@ -1036,5 +1036,50 @@ id select_type table type possible_keys key key_len ref rows Extra ...@@ -1036,5 +1036,50 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DEPENDENT SUBQUERY jt ALL NULL NULL NULL NULL 40 Table function: json_table 2 DEPENDENT SUBQUERY jt ALL NULL NULL NULL NULL 40 Table function: json_table
drop table t1; drop table t1;
# #
# MDEV-25822: JSON_TABLE: default values should allow non-string literals
#
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 0.5 on empty)) as T;
col1
0.5
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 5 on empty)) as T;
col1
5
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 'asdf' on empty)) as T;
col1
asdf
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default -0.5 on empty)) as T;
col1
-0.5
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 18446744073709551615 on empty)) as T;
col1
18446744073709551615
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default DATE '2021-01-01' on empty)) as T;
col1
2021-01-01
create view v as select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 5 on empty)) as T;
select * from v;
col1
5
show create view v;
View Create View character_set_client collation_connection
v CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `T`.`col1` AS `col1` from JSON_TABLE('{"a": "b"}', '$' COLUMNS (`col1` varchar(32) PATH '$.fooo' DEFAULT 5 ON EMPTY)) `T` latin1 latin1_swedish_ci
drop view v;
create view v as select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 18446744073709551615 on empty)) as T;
select * from v;
col1
18446744073709551615
show create view v;
View Create View character_set_client collation_connection
v CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `T`.`col1` AS `col1` from JSON_TABLE('{"a": "b"}', '$' COLUMNS (`col1` varchar(32) PATH '$.fooo' DEFAULT 18446744073709551615 ON EMPTY)) `T` latin1 latin1_swedish_ci
drop view v;
create view v as select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 'asdf' on empty)) as T;
select * from v;
col1
asdf
show create view v;
View Create View character_set_client collation_connection
v CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `T`.`col1` AS `col1` from JSON_TABLE('{"a": "b"}', '$' COLUMNS (`col1` varchar(32) PATH '$.fooo' DEFAULT 'asdf' ON EMPTY)) `T` latin1 latin1_swedish_ci
drop view v;
#
# End of 10.6 tests # End of 10.6 tests
# #
...@@ -545,10 +545,12 @@ Warning 1366 Incorrect double value: 'asdf' for column ``.`(temporary)`.`f` at r ...@@ -545,10 +545,12 @@ Warning 1366 Incorrect double value: 'asdf' for column ``.`(temporary)`.`f` at r
Warning 1366 Incorrect decimal value: 'asdf' for column ``.`(temporary)`.`d` at row 1 Warning 1366 Incorrect decimal value: 'asdf' for column ``.`(temporary)`.`d` at row 1
SELECT * FROM SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT NULL ON EMPTY)) jt; JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT NULL ON EMPTY)) jt;
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)) jt' at line 2 x
NULL
SELECT * FROM SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT NULL ON ERROR)) jt; JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT NULL ON ERROR)) jt;
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 ERROR)) jt' at line 2 x
NULL
SELECT * FROM SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT 0 ON EMPTY)) jt; JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT 0 ON EMPTY)) jt;
x x
...@@ -561,12 +563,14 @@ SELECT * FROM ...@@ -561,12 +563,14 @@ SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x DATE JSON_TABLE('{}', '$' COLUMNS (x DATE
PATH '$.x' PATH '$.x'
DEFAULT DATE'2020-01-01' ON EMPTY)) jt; DEFAULT DATE'2020-01-01' ON EMPTY)) jt;
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 'DATE'2020-01-01' ON EMPTY)) jt' at line 4 x
2020-01-01
SELECT * FROM SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x DATE JSON_TABLE('{}', '$' COLUMNS (x DATE
PATH '$.x' PATH '$.x'
DEFAULT DATE'2020-01-01' ON ERROR)) jt; DEFAULT DATE'2020-01-01' ON ERROR)) jt;
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 'DATE'2020-01-01' ON ERROR)) jt' at line 4 x
NULL
# #
# Bug#25413069: SIG11 IN CHECK_COLUMN_GRANT_IN_TABLE_REF # Bug#25413069: SIG11 IN CHECK_COLUMN_GRANT_IN_TABLE_REF
# #
......
...@@ -893,6 +893,30 @@ explain select c, ...@@ -893,6 +893,30 @@ explain select c,
drop table t1; drop table t1;
--echo #
--echo # MDEV-25822: JSON_TABLE: default values should allow non-string literals
--echo #
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 0.5 on empty)) as T;
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 5 on empty)) as T;
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 'asdf' on empty)) as T;
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default -0.5 on empty)) as T;
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 18446744073709551615 on empty)) as T;
select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default DATE '2021-01-01' on empty)) as T;
create view v as select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 5 on empty)) as T;
select * from v;
show create view v;
drop view v;
create view v as select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 18446744073709551615 on empty)) as T;
select * from v;
show create view v;
drop view v;
create view v as select * from json_table('{"a": "b"}', '$' columns(col1 varchar(32) path '$.fooo' default 'asdf' on empty)) as T;
select * from v;
show create view v;
drop view v;
--echo # --echo #
--echo # End of 10.6 tests --echo # End of 10.6 tests
--echo # --echo #
...@@ -445,11 +445,8 @@ SELECT * FROM JSON_TABLE('"asdf"', '$' COLUMNS( ...@@ -445,11 +445,8 @@ SELECT * FROM JSON_TABLE('"asdf"', '$' COLUMNS(
f FLOAT PATH '$', f FLOAT PATH '$',
d DECIMAL PATH '$')) AS jt; d DECIMAL PATH '$')) AS jt;
# DEFAULT NULL is not accepted syntax.
--error ER_PARSE_ERROR
SELECT * FROM SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT NULL ON EMPTY)) jt; JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT NULL ON EMPTY)) jt;
--error ER_PARSE_ERROR
SELECT * FROM SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT NULL ON ERROR)) jt; JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT NULL ON ERROR)) jt;
...@@ -457,13 +454,10 @@ SELECT * FROM ...@@ -457,13 +454,10 @@ SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT 0 ON EMPTY)) jt; JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT 0 ON EMPTY)) jt;
SELECT * FROM SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT 0 ON ERROR)) jt; JSON_TABLE('{}', '$' COLUMNS (x INT PATH '$.x' DEFAULT 0 ON ERROR)) jt;
# We don't accept dates in DEFAULT
--error 1064
SELECT * FROM SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x DATE JSON_TABLE('{}', '$' COLUMNS (x DATE
PATH '$.x' PATH '$.x'
DEFAULT DATE'2020-01-01' ON EMPTY)) jt; DEFAULT DATE'2020-01-01' ON EMPTY)) jt;
--error 1064
SELECT * FROM SELECT * FROM
JSON_TABLE('{}', '$' COLUMNS (x DATE JSON_TABLE('{}', '$' COLUMNS (x DATE
PATH '$.x' PATH '$.x'
......
...@@ -1030,8 +1030,7 @@ int Json_table_column::On_response::respond(Json_table_column *jc, Field *f, ...@@ -1030,8 +1030,7 @@ int Json_table_column::On_response::respond(Json_table_column *jc, Field *f,
return 1; return 1;
case Json_table_column::RESPONSE_DEFAULT: case Json_table_column::RESPONSE_DEFAULT:
f->set_notnull(); f->set_notnull();
f->store(m_default.str, m_default->save_in_field(f, TRUE);
m_default.length, jc->m_defaults_cs);
break; break;
} }
return 0; return 0;
...@@ -1041,7 +1040,11 @@ int Json_table_column::On_response::respond(Json_table_column *jc, Field *f, ...@@ -1041,7 +1040,11 @@ int Json_table_column::On_response::respond(Json_table_column *jc, Field *f,
int Json_table_column::On_response::print(const char *name, String *str) const int Json_table_column::On_response::print(const char *name, String *str) const
{ {
LEX_CSTRING resp; LEX_CSTRING resp;
const LEX_CSTRING *ds= NULL;
char valbuf[512];
String val(valbuf, sizeof(valbuf), str->charset());
String *ds= NULL;
if (m_response == Json_table_column::RESPONSE_NOT_SPECIFIED) if (m_response == Json_table_column::RESPONSE_NOT_SPECIFIED)
return 0; return 0;
...@@ -1056,7 +1059,7 @@ int Json_table_column::On_response::print(const char *name, String *str) const ...@@ -1056,7 +1059,7 @@ int Json_table_column::On_response::print(const char *name, String *str) const
case Json_table_column::RESPONSE_DEFAULT: case Json_table_column::RESPONSE_DEFAULT:
{ {
lex_string_set3(&resp, STRING_WITH_LEN("DEFAULT")); lex_string_set3(&resp, STRING_WITH_LEN("DEFAULT"));
ds= &m_default; ds= m_default->val_str(&val);
break; break;
} }
default: default:
...@@ -1065,9 +1068,14 @@ int Json_table_column::On_response::print(const char *name, String *str) const ...@@ -1065,9 +1068,14 @@ int Json_table_column::On_response::print(const char *name, String *str) const
} }
return (str->append(' ') || str->append(resp) || return (str->append(' ') || str->append(resp) ||
(ds && (str->append(STRING_WITH_LEN(" '")) || (ds &&
str->append_for_single_quote(ds->str, ds->length) || (str->append(' ') ||
str->append('\''))) || (m_default->result_type()==STRING_RESULT && str->append('\''))||
str->append_for_single_quote(ds) ||
(m_default->result_type()==STRING_RESULT && str->append('\''))))||
str->append(STRING_WITH_LEN(" ON ")) || str->append(STRING_WITH_LEN(" ON ")) ||
str->append(name, strlen(name))); str->append(name, strlen(name)));
} }
......
...@@ -140,7 +140,7 @@ class Json_table_column : public Sql_alloc ...@@ -140,7 +140,7 @@ class Json_table_column : public Sql_alloc
{ {
public: public:
Json_table_column::enum_on_response m_response; Json_table_column::enum_on_response m_response;
LEX_CSTRING m_default; Item *m_default;
int respond(Json_table_column *jc, Field *f, uint error_num); int respond(Json_table_column *jc, Field *f, uint error_num);
int print(const char *name, String *str) const; int print(const char *name, String *str) const;
bool specified() const { return m_response != RESPONSE_NOT_SPECIFIED; } bool specified() const { return m_response != RESPONSE_NOT_SPECIFIED; }
...@@ -154,7 +154,6 @@ class Json_table_column : public Sql_alloc ...@@ -154,7 +154,6 @@ class Json_table_column : public Sql_alloc
Create_field *m_field; Create_field *m_field;
Json_table_nested_path *m_nest; Json_table_nested_path *m_nest;
CHARSET_INFO *m_explicit_cs; CHARSET_INFO *m_explicit_cs;
CHARSET_INFO *m_defaults_cs;
void set(enum_type ctype) void set(enum_type ctype)
{ {
......
...@@ -1328,7 +1328,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); ...@@ -1328,7 +1328,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
TEXT_STRING TEXT_STRING
NCHAR_STRING NCHAR_STRING
json_text_literal json_text_literal
json_text_literal_or_num
%type <lex_str_ptr> %type <lex_str_ptr>
opt_table_alias_clause opt_table_alias_clause
...@@ -1512,6 +1511,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); ...@@ -1512,6 +1511,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
simple_target_specification simple_target_specification
condition_number condition_number
opt_versioning_interval_start opt_versioning_interval_start
json_default_literal
%type <item_param> param_marker %type <item_param> param_marker
...@@ -11595,26 +11595,6 @@ json_text_literal: ...@@ -11595,26 +11595,6 @@ json_text_literal:
} }
; ;
json_text_literal_or_num:
json_text_literal
| NUM
{
Lex->json_table->m_text_literal_cs= NULL;
}
| LONG_NUM
{
Lex->json_table->m_text_literal_cs= NULL;
}
| DECIMAL_NUM
{
Lex->json_table->m_text_literal_cs= NULL;
}
| FLOAT_NUM
{
Lex->json_table->m_text_literal_cs= NULL;
}
;
join_table_list: join_table_list:
derived_table_list { MYSQL_YYABORT_UNLESS($$=$1); } derived_table_list { MYSQL_YYABORT_UNLESS($$=$1); }
; ;
...@@ -11720,6 +11700,12 @@ json_opt_on_empty_or_error: ...@@ -11720,6 +11700,12 @@ json_opt_on_empty_or_error:
| json_on_empty_response json_on_error_response | json_on_empty_response json_on_error_response
; ;
json_default_literal:
literal
| signed_literal
;
json_on_response: json_on_response:
ERROR_SYM ERROR_SYM
{ {
...@@ -11729,12 +11715,10 @@ json_on_response: ...@@ -11729,12 +11715,10 @@ json_on_response:
{ {
$$.m_response= Json_table_column::RESPONSE_NULL; $$.m_response= Json_table_column::RESPONSE_NULL;
} }
| DEFAULT json_text_literal_or_num | DEFAULT json_default_literal
{ {
$$.m_response= Json_table_column::RESPONSE_DEFAULT; $$.m_response= Json_table_column::RESPONSE_DEFAULT;
$$.m_default= $2; $$.m_default= $2;
Lex->json_table->m_cur_json_table_column->m_defaults_cs=
thd->variables.collation_connection;
} }
; ;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment