[MDEV-26299] Some views force server (and mysqldump) to generate invalid SQL for their definitions Created: 2021-08-03  Updated: 2021-11-23  Resolved: 2021-10-18

Status: Closed
Project: MariaDB Server
Component/s: Information Schema, Scripts & Clients, Views
Affects Version/s: 10.5.10, 10.5.12, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7
Fix Version/s: 10.2.41, 10.3.32, 10.4.22, 10.5.13, 10.6.5, 10.7.1

Type: Bug Priority: Critical
Reporter: Valerii Kravchuk Assignee: Oleksandr Byelkin
Resolution: Fixed Votes: 0
Labels: mysqldump


 Description   

mysqldump used to have problems generating SQL for views (see MDEV-8028). Looks like they remain for complex views involving CTE and CASE expression deeply nested in the view definition. Consider the following, purely artifical test case based on a structure of a really useful view from one of the customers:

openxs@fc33 maria10.5]$ bin/mysql --socket=/tmp/mariadb.sock 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 10.5.12-MariaDB MariaDB Server
 
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
 
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
 
MariaDB [(none)]> create database db;
Query OK, 1 row affected (0.001 sec)
 
MariaDB [(none)]> use db;
Database changed
MariaDB [db]> create or replace view dhv as 
    -> (select * from (
    ->   with recursive h(user, hosts) as 
    ->     (select user, 
    ->              cast('' as char(500)) from
    ->        ( select user, host from mysql.user 
    ->        ) as firstgen where user = ''
    ->       union all 
    ->       select nextgen.user, 
    ->              cast(case when parent.hosts = '' 
    ->                   then (concat ('.', cast(nextgen.host as char))) 
    ->                   else (concat(parent.hosts, '.', cast(nextgen.host as char))) 
    ->                   end as char) 
    ->         from 
    ->           ( select user, host from mysql.user where user != ''
    ->           )  as nextgen 
    ->        inner join h as parent 
    ->          on nextgen.user = parent.user
    ->     ) 
    ->     select * from h
    ->  ) as dt);  
Query OK, 0 rows affected (0.037 sec)

Do not mind the completely stupid view definition - it's used in purpose to simplify and obfuscate the real one, so it's easy to reproduce the problem.

So, we have this stupid view with proper column names:

MariaDB [db]> select * from dhv;
+------+-------+
| user | hosts |
+------+-------+
|      |       |
|      |       |
+------+-------+
2 rows in set (0.043 sec)
 
MariaDB [db]> desc dhv;
+-------+--------------+------+-----+---------+-------+
| Field | Type         | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+-------+
| user  | char(80)     | YES  |     | NULL    |       |
| hosts | varchar(500) | YES  |     | NULL    |       |
+-------+--------------+------+-----+---------+-------+
2 rows in set (0.002 sec)
 
MariaDB [db]> show create view dhv\G
*************************** 1. row ***************************
                View: dhv
         Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`openxs`@`localhost` SQL SECURITY DEFINER VIEW `dhv` AS (select `dt`.`user` AS `user`,`dt`.`hosts` AS `hosts` from (with recursive h(`user`,`hosts`) as (select `firstgen`.`user` AS `user`,cast('' as char(500) charset utf8) AS `hosts` from (select `user`.`User` AS `user`,`user`.`Host` AS `host` from `mysql`.`user`) `firstgen` where `firstgen`.`user` = '' union all select `nextgen`.`user` AS `user`,cast(case when `parent`.`hosts` = '' then concat('.',cast(`nextgen`.`host` as char charset utf8)) else concat(`parent`.`hosts`,'.',cast(`nextgen`.`host` as char charset utf8)) end as char charset utf8) AS `cast(case when parent.hosts = '' 
                  then (concat ('.', cast(nextgen.host as char))) 
                  else (concat(parent.hosts, '.', cast(nextgen.host as char))) 
                  end as char)` from ((select `user`.`User` AS `user`,`user`.`Host` AS `host` from `mysql`.`user` where `user`.`User` <> '') `nextgen` join `h` `parent` on(`nextgen`.`user` = `parent`.`user`)))select `h`.`user` AS `user`,`h`.`hosts` AS `hosts` from `h`) `dt`)
character_set_client: utf8
collation_connection: utf8_general_ci
1 row in set (0.002 sec)

But you can already spot the problem above, see this column alias generated for some reason:

AS `cast(case when parent.hosts = '' 
                  then (concat ('.', cast(nextgen.host as char))) 
                  else (concat(parent.hosts, '.', cast(nextgen.host as char))) 
                  end as char)`

Surely if we dump and try to reload, it fails:

[openxs@fc33 maria10.5]$ bin/mysqldump --socket=/tmp/mariadb.sock db > /tmp/db.sql 
[openxs@fc33 maria10.5]$ vi /tmp/db.sql 
[openxs@fc33 maria10.5]$ bin/mysql --socket=/tmp/mariadb.sock db < /tmp/db.sql
ERROR 1166 (42000) at line 44: Incorrect column name 'cast(case when parent.hosts = '' 
                  then (concat ('.', cast(nextgen.host as char))) '
[openxs@fc33 maria10.5]$ 

It seems to be more a server problem, as we can see from SHOW CREATE VIEW. Simpler cases seems to be covered by the fix to MySQL bug #65388 we merged, but not this complex one.



 Comments   
Comment by Oleksandr Byelkin [ 2021-09-15 ]

I checked, if put definition returned by SHOW CREATE VIEW back to the server and there was no an error, so no problem with SHOW CREATE VIEW. The problem made probably by mysqldump, which try "verschlimmbessern" the result of SHOW CREATE VIEW.

i.e. the problem existts and it is problem of mysqldump utility (with high probability).

Comment by Elena Stepanova [ 2021-09-15 ]

sanja,

Please check again, something was wrong with your experiment. Copy-pasting SHOW CREATE from the description does cause a syntax error.

CREATE ALGORITHM=UNDEFINED DEFINER=`openxs`@`localhost` SQL SECURITY DEFINER VIEW `dhv` AS (select `dt`.`user` AS `user`,`dt`.`hosts` AS `hosts` from (with recursive h(`user`,`hosts`) as (select `firstgen`.`user` AS `user`,cast('' as char(500) charset utf8) AS `hosts` from (select `user`.`User` AS `user`,`user`.`Host` AS `host` from `mysql`.`user`) `firstgen` where `firstgen`.`user` = '' union all select `nextgen`.`user` AS `user`,cast(case when `parent`.`hosts` = '' then concat('.',cast(`nextgen`.`host` as char charset utf8)) else concat(`parent`.`hosts`,'.',cast(`nextgen`.`host` as char charset utf8)) end as char charset utf8) AS `cast(case when parent.hosts = '' 
                  then (concat ('.', cast(nextgen.host as char))) 
                  else (concat(parent.hosts, '.', cast(nextgen.host as char))) 
                  end as char)` from ((select `user`.`User` AS `user`,`user`.`Host` AS `host` from `mysql`.`user` where `user`.`User` <> '') `nextgen` join `h` `parent` on(`nextgen`.`user` = `parent`.`user`)))select `h`.`user` AS `user`,`h`.`hosts` AS `hosts` from `h`) `dt`);

ERROR 1166 (42000): Incorrect column name 'cast(case when parent.hosts = '' 
                  then (concat ('.', cast(nextgen.host as char))) '

Comment by Oleksandr Byelkin [ 2021-09-15 ]

I used mysqltest as usual so yes, I have not noticed the error.

Comment by Oleksandr Byelkin [ 2021-10-01 ]

It looks like we need escape automatic generated names for views or just regenerate them in case of presence of symbols which should be escaped.

Comment by Oleksandr Byelkin [ 2021-10-01 ]

despite clame of valerii the bug is present beginning from 10.2 and shoud be fixed there

Comment by Oleksandr Byelkin [ 2021-10-01 ]

create view v1 as 
(select * from (
  with recursive h(user, hosts) as 
    (select user, 
             cast('' as char(500)) from
       ( select user, host from mysql.user 
       ) as firstgen where user = ''
      union all 
      select nextgen.user, 
             cast(case when parent.hosts = '' 
                  then (concat ('.', cast(nextgen.host as char))) 
                  else (concat(parent.hosts, '.', cast(nextgen.host as char))) 
                  end as char) 
        from 
          ( select user, host from mysql.user where user != ''
          )  as nextgen 
       inner join h as parent 
         on nextgen.user = parent.user
    ) 
    select * from h
 ) as dt);  
 
#show create view v1;
 
let $definition=`select VIEW_DEFINITION from information_schema.views where TABLE_NAME="v1"`;
 
drop view v1;
 
eval CREATE VIEW v1 AS $definition;
 
drop view v1;

Comment by Oleksandr Byelkin [ 2021-10-01 ]

create view v1 as 
 select * from 
  (select
  "12345678901234567890123456789012345678901234567890123456789012345") as t1;  
 
let $definition=`select VIEW_DEFINITION from information_schema.views where TABLE_NAME="v1"`;
 
drop view v1;
 
eval CREATE VIEW v1 AS $definition;
 
drop view v1;

Comment by Oleksandr Byelkin [ 2021-10-01 ]

commit fcf2c5fff14875a1b9e1ac554ada95db3223a4a9 (HEAD -> bb-10.2-MDEV-26299, origin/bb-10.2-MDEV-26299)
Author: Oleksandr Byelkin <sanja@mariadb.com>
Date:   Fri Oct 1 14:46:22 2021 +0200
 
    MDEV-26299: Some views force server (and mysqldump) to generate invalid SQL for their definitions
    
    Do not print illegal table field names for non-top-level SELECT list,
    they will not be refered in any case but create problem for parsing
    of printed result.

Comment by Oleksandr Byelkin [ 2021-10-01 ]

in the test case problem was that the name was too long, other cases also probably possible.

Comment by Oleksandr Byelkin [ 2021-10-15 ]

I checked if it is easy to fix automatic names, IMHO in 10.2 it can interfer with many other code including Item comparison

Comment by Oleksandr Byelkin [ 2021-10-18 ]

branch bb-10.2-MDEV-26299

commit bdaf94d5a21c3a974d2c7d6d586289d4375dce92 (HEAD -> bb-10.2-MDEV-26299, origin/bb-10.2-MDEV-26299)
Author: Oleksandr Byelkin <sanja@mariadb.com>
Date:   Fri Oct 1 14:46:22 2021 +0200
 
    MDEV-26299: Some views force server (and mysqldump) to generate invalid SQL for their definitions
    
    Do not print illegal table field names for non-top-level SELECT list,
    they will not be refered in any case but create problem for parsing
    of printed result.

Comment by Sergei Golubchik [ 2021-10-18 ]

ok to push

Generated at Thu Feb 08 09:44:15 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.