← Back to team overview

maria-developers team mailing list archive

Review for: MDEV-17399 Add support for JSON_TABLE, part #6

 

Hi Alexey,

> revision-id: 0d342ab173cdbf5d35c5f2833c66b6004b9e908e (mariadb-10.5.2-330-g0d342ab173c)
> parent(s): b1ab211dee599eabd9a5b886fafa3adea29ae041
> author: Alexey Botchkov
> committer: Alexey Botchkov
> timestamp: 2020-06-08 14:51:04 +0400
> message:
> 
> MDEV-17399 Add support for JSON_TABLE.
> 
> ha_json_table handler implemented.
> JSON_TABLE() added to SQL syntax.
> 

First, some general input: 

== Assertion with Prepared Statements ==
prepare s from 
'select * from
  json_table(?,
             \'$[*]\' columns( color varchar(100) path \'$.color\',
                          price text path \'$.price\',
                          seq for ordinality
                        )
             ) as T
order by color desc;
'
  mysqld: /home/psergey/dev-git2/10.5-hf-review/sql/item.h:1002: virtual bool Item::fix_fields(THD*, Item**): Assertion `basic_const_item()' failed.

== Default value for TEXT ==

Default value for VARCHAR(100) is SQL NULL, while for TEXT it is empty string.
Is this intentional? If yes, I would like to see the spec of the logic behind
this.

select *
from
  json_table('[{"color": "blue", "price": 50}, {"color": "red", "price": 100}]',
             '$[*]' columns(color varchar(100) path '$.nonexistent',
                            seq for ordinality
                        )
             ) as T;
+-------+------+
| color | seq  |
+-------+------+
| NULL  |    1 |
| NULL  |    2 |
+-------+------+

select *
from
  json_table('[{"color": "blue", "price": 50}, {"color": "red", "price": 100}]',
             '$[*]' columns(color text path '$.nonexistent',
                            seq for ordinality
                        )
             ) as T;
+-------+------+
| color | seq  |
+-------+------+
|       |    1 |
|       |    2 |
+-------+------+

== JSON_TABLE can have a non-unique alias? ==

create table t20(a varchar(100));
insert into t20 values ();

create table t21(a varchar(100));
insert into t21 values ();

select * from t20 as T, t21 as T;
ERROR 1066 (42000): Not unique table/alias: 'T'

Good. This is the expected behaviour.

select *
from
  t20 as T , json_table(T.a,
             '$[*]' columns(color varchar(100) path '$.nonexistent',
                            seq for ordinality
                        )
             ) as T;
Empty set (0.000 sec)

No error. I think this is wrong. Why would JSON_TABLE be allowed to use an
alias that conflicts with another table?

== EXPLAIN doesn't show table function == 

I had requested this in previous review(s): Table function use should be shown
in EXPLAIN [FORMAT=JSON].

Here's how MySQL does it:
https://gist.github.com/spetrunia/257c929b0c04a866faf6428e733999ad

Note that this can be extended to handle other table functions.

if there are no other ideas, let's use the same syntax.

== Comments ==

I still think the patch doesn't have good comments. Let me get back to you on
this.

> diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
> index 49cabec9916..3db438ee470 100644
> --- a/sql/share/errmsg-utf8.txt
> +++ b/sql/share/errmsg-utf8.txt
> @@ -7965,3 +7965,7 @@ ER_NOT_ALLOWED_IN_THIS_CONTEXT
>          eng "'%-.128s' is not allowed in this context"
>  ER_DATA_WAS_COMMITED_UNDER_ROLLBACK
>          eng "Engine %s does not support rollback. Changes where commited during rollback call"
> +ER_JSON_TABLE_ERROR_ON_FIELD
> +        eng "Field '%s' can't be set for JSON_TABLE '%s'."

> +ER_JSON_TABLE_DOUBLE_ON_RESPONSE
> +        eng "ON %s response specified more than once in JSON_TABLE definition."

I agree that using this error solves the issue I've complained about, but this
doesn't look like the right way to do it:

* Why not just emit a parser error with YYERROR in this case?
* Better: why not just remove the recursive definition from the grammar?

...
> diff --git a/sql/table_function.cc b/sql/table_function.cc
...
> +
> +/*
> +  handler::print_error has a case statement for error numbers.
> +  This value is (10000) is far out of range and will envoke the
> +  default: case.(Current error range is 120-159 from include/my_base.h)
> + */
> +#define  HA_ERR_INVALID_JSON 10000

So, is this needed anymore?  

On the other hand, the new solution with returning HA_ERR_TABLE_IN_FK_CHECK
doesn't look very good either. 
A plugin could register its own error codes, but this engine is not a plugin.
Let's discuss with Serg and get back to this.

> +static int print_path(String *str, const json_path_t *p)
> +{
> +  return str->append('\"') ||
> +         str->append((const char *) p->s.c_str, p->s.str_end - p->s.c_str) ||
> +         str->append('\"');
> +}
The above doesn't do proper quoting, which is wrong. Testcase:

select *
from
  json_table('[{"co\\\\lor": "blue", "price": 50}]',
             '$[*]' columns( color varchar(100) path '$.co\\\\lor')
             ) as T;
+-------+
| color |
+-------+
| blue  |
+-------+

create view v2 as
select *
from
  json_table('[{"co\\\\lor": "blue", "price": 50}]',
             '$[*]' columns( color varchar(100) path '$.co\\\\lor')
             ) as T;
select * from v2;
+-------+
| color |
+-------+
| NULL  |
+-------+



BR
 Sergei
-- 
Sergei Petrunia, Software Developer
MariaDB Corporation | Skype: sergefp | Blog: http://s.petrunia.net/blog