Skip to content
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
35 changes: 35 additions & 0 deletions mysql-test/suite/json/r/mdev13594.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# MDEV-13594: Support for JSON operators -> and ->>
CREATE TABLE t1 (id INT, data JSON);
INSERT INTO t1 VALUES (1, '{"name":"Alice","age":30}');
INSERT INTO t1 VALUES (2, '{"name":"Bob","age":25}');
SELECT data->'$.name' FROM t1;
data->'$.name'
"Alice"
"Bob"
SELECT data->>'$.name' FROM t1;
data->>'$.name'
Alice
Bob
SELECT id FROM t1 WHERE data->>'$.name' = 'Alice';
id
1
SELECT data->'$.age' FROM t1;
data->'$.age'
30
25
SELECT id FROM t1 ORDER BY data->>'$.name';
id
1
2
SELECT '{"x":1}'->'$.x';
'{"x":1}'->'$.x'
1
SELECT
data->'$.name',
JSON_EXTRACT(data, '$.name'),
data->>'$.name',
JSON_UNQUOTE(JSON_EXTRACT(data, '$.name'))
FROM t1 LIMIT 1;
data->'$.name' JSON_EXTRACT(data, '$.name') data->>'$.name' JSON_UNQUOTE(JSON_EXTRACT(data, '$.name'))
"Alice" "Alice" Alice Alice
DROP TABLE t1;
33 changes: 33 additions & 0 deletions mysql-test/suite/json/t/mdev13594.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
--echo # MDEV-13594: Support for JSON operators -> and ->>

CREATE TABLE t1 (id INT, data JSON);
INSERT INTO t1 VALUES (1, '{"name":"Alice","age":30}');
INSERT INTO t1 VALUES (2, '{"name":"Bob","age":25}');

# Test -> operator (JSON_EXTRACT equivalent)
SELECT data->'$.name' FROM t1;

# Test ->> operator (JSON_UNQUOTE(JSON_EXTRACT) equivalent)
SELECT data->>'$.name' FROM t1;

# Test in WHERE clause
SELECT id FROM t1 WHERE data->>'$.name' = 'Alice';

# Test with numeric path
SELECT data->'$.age' FROM t1;

# Test in ORDER BY
SELECT id FROM t1 ORDER BY data->>'$.name';

# Test with literal JSON string (not just column)
SELECT '{"x":1}'->'$.x';

# Verify equivalence
SELECT
data->'$.name',
JSON_EXTRACT(data, '$.name'),
data->>'$.name',
JSON_UNQUOTE(JSON_EXTRACT(data, '$.name'))
FROM t1 LIMIT 1;

DROP TABLE t1;
10 changes: 10 additions & 0 deletions sql/sql_lex.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2091,6 +2091,16 @@ int Lex_input_stream::lex_one_token(YYSTYPE *yylval, THD *thd)
return((int) c);

case MY_LEX_MINUS_OR_COMMENT:
if (yyPeek() == '>')
{
yySkip();
if (yyPeek() == '>')
{
yySkip();
return JSON_UNQUOTED_SEPARATOR_SYM;
}
return JSON_SEPARATOR_SYM;
}
if (yyPeek() == '-' &&
(my_isspace(cs,yyPeekn(1)) ||
my_iscntrl(cs,yyPeekn(1))))
Expand Down
49 changes: 45 additions & 4 deletions sql/sql_yacc.yy
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
*/

%ifdef MARIADB
%expect 70
%expect 72
%else
%expect 71
%expect 73
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the interest of more consistent processing, can you please answer all questions from the previous pull request? E.g. I had a question on this line. And I see that it's still unaddressed.

%endif

/*
Expand Down Expand Up @@ -474,6 +474,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%token <NONE> SHIFT_LEFT /* OPERATOR */
%token <NONE> SHIFT_RIGHT /* OPERATOR */
%token <NONE> ARROW_SYM /* OPERATOR */
%token <NONE> JSON_SEPARATOR_SYM /* OPERATOR */
%token <NONE> JSON_UNQUOTED_SEPARATOR_SYM /* OPERATOR */


/*
Expand Down Expand Up @@ -1232,6 +1234,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
%left SHIFT_LEFT SHIFT_RIGHT
%left '-' '+' ORACLE_CONCAT_SYM
%left '*' '/' '%' DIV_SYM MOD_SYM
%left JSON_SEPARATOR_SYM JSON_UNQUOTED_SEPARATOR_SYM
%left '^'
%left MYSQL_CONCAT_SYM
/*
Expand Down Expand Up @@ -1592,7 +1595,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
boolean_test
predicate bit_expr parenthesized_expr
table_wild simple_expr column_default_non_parenthesized_expr udf_expr
primary_expr string_factor_expr mysql_concatenation_expr
primary_expr primary_base_expr string_factor_expr mysql_concatenation_expr
select_sublist_qualified_asterisk
expr_or_ignore expr_or_ignore_or_default
signed_literal expr_or_literal
Expand Down Expand Up @@ -10612,7 +10615,7 @@ column_default_non_parenthesized_expr:
}
;

primary_expr:
primary_base_expr:
column_default_non_parenthesized_expr
| explicit_cursor_attr
| '(' parenthesized_expr ')' { $$= $2; }
Expand All @@ -10623,6 +10626,44 @@ primary_expr:
}
;

primary_expr:
primary_base_expr
| primary_base_expr JSON_SEPARATOR_SYM TEXT_STRING
{
Item *path= new (thd->mem_root) Item_string(thd, $3.str, $3.length,
thd->variables.collation_connection);
if (unlikely(path == NULL))
MYSQL_YYABORT;
List<Item> *list= new (thd->mem_root) List<Item>;
if (unlikely(list == NULL ||
list->push_back($1, thd->mem_root) ||
list->push_back(path, thd->mem_root)))
MYSQL_YYABORT;
$$= new (thd->mem_root) Item_func_json_extract(thd, *list);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
| primary_base_expr JSON_UNQUOTED_SEPARATOR_SYM TEXT_STRING
{
Item *path= new (thd->mem_root) Item_string(thd, $3.str, $3.length,
thd->variables.collation_connection);
if (unlikely(path == NULL))
MYSQL_YYABORT;
List<Item> *list= new (thd->mem_root) List<Item>;
if (unlikely(list == NULL ||
list->push_back($1, thd->mem_root) ||
list->push_back(path, thd->mem_root)))
MYSQL_YYABORT;
Item *extract= new (thd->mem_root) Item_func_json_extract(thd, *list);
if (unlikely(extract == NULL))
MYSQL_YYABORT;
$$= new (thd->mem_root) Item_func_json_unquote(thd, extract);
if (unlikely($$ == NULL))
MYSQL_YYABORT;
}
;
;

string_factor_expr:
primary_expr
| string_factor_expr COLLATE_SYM collation_name
Expand Down
Loading