auth: added quoting for account names on output.#1220
auth: added quoting for account names on output.#1220mjonss wants to merge 5 commits intopingcap:masterfrom
Conversation
auth/auth.go
Outdated
|
|
||
| // String converts UserIdentity to the format user@host. | ||
| func EscapeAccountName(s string) string { | ||
| return "'" + strings.ReplaceAll(s, "'", "\\'") + "'" |
There was a problem hiding this comment.
| return "'" + strings.ReplaceAll(s, "'", "\\'") + "'" | |
| return "`" + strings.ReplaceAll(s, "`", "``") + "`" |
Doubling the quotation mark is the ISO standard way of escaping. \ is prone to NO_BACKSLASH_ESCAPES.
But speaking of backslash escapes, if the user name contains a \ this ReplaceAll is also wrong when @@sql_mode has no NO_BACKSLASH_ESCAPES. So it's the safest just to use the identifier form instead of the string form.
There was a problem hiding this comment.
Thanks for pointing this out, I missed that!
What I tried to reflect was the error message from MySQL, when implementing RENAME USER:
mysql> rename user "User's"@"root's friend" to u1@localhost;
ERROR 1396 (HY000): Operation RENAME USER failed for 'User\'s'@'root\'s friend'
mysql> select @@sql_mode;
+-----------------------------------------------------------------------------------------------------------------------+
| @@sql_mode |
+-----------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+-----------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> set @@sql_mode="ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION,NO_BACKSLASH_ESCAPES"
-> ;
Query OK, 0 rows affected (0.01 sec)
mysql> select @@sql_mode;
+--------------------------------------------------------------------------------------------------------------------------------------------+
| @@sql_mode |
+--------------------------------------------------------------------------------------------------------------------------------------------+
| ONLY_FULL_GROUP_BY,NO_BACKSLASH_ESCAPES,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION |
+--------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> rename user "User's"@"root's friend" to u1@localhost;
ERROR 1396 (HY000): Operation RENAME USER failed for 'User''s'@'root''s friend'
mysql> So to be error string compatible, we should probably still use (') "single quote" character, instead of (`) "backtick" character.
I will see if I can make it adjust according to NO_BACKSLASH_ESCAPES.
Do you think we should use (`) backtick and always do double backtick instead of escaping with () backslash?
There was a problem hiding this comment.
Are there anyway to get the context/parser/lexer/sql_mode without changing the types/api for this?
Otherwise I cannot see how to adapt to the sessions sql_mode setting, which would support your suggestion to just use double quoting.
There was a problem hiding this comment.
I updated the PR to only use double quoting (replace ' with ''), i.e. still using single quote character, but not use backslash as escape character, to avoid issues with NO_BACKSLASH_ESCAPES sql_mode.
To be agnostic about NO_BACKSLASH_ESCAPES sql_mode. Currently the interface for these functions do not include sql_mode, so by not using backslash as escape character, we avoid the need to check this sql_mode.
|
I noted that create user `u'v"w\x@y``z`;
-- ...
select current_user();
+----------------+
| current_user() |
+----------------+
| u'v"w\x@y`z@% |
+----------------+
1 row in set (0.00 sec) |
| // We do not have access to the sql_mode here, | ||
| // so assume NO_BACKSLASH_ESCAPES in effect, | ||
| // since it is still correct if not set. | ||
| return "'" + strings.ReplaceAll(s, "'", "''") + "'" |
There was a problem hiding this comment.
Will strings.ReplaceAll work as expected when the string contains \'?
There was a problem hiding this comment.
Will this change work under ANSI_SQL mode https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_ansi_quotes
Good catch, I think it makes sense to be keep being compatible with MySQL here. I will try to address this as well. |
|
|
In which context do you mean? Do you refer to any test in this PR? Or is it a test that is missing? The But as noticed above too, is that the |
|
I doubt The raw name a user intend is Then it has to be written as In Go, strings.ReplaceAll() turns And this is what the user intend any more. @mjonss |
The first problem is to define the 'correct job', which is already inconsistent in MySQL and gets even more complicated with the Some examples of the inconsistencies: mysql> set sql_mode = "";
Query OK, 0 rows affected (0,00 sec)
mysql> create user "\\'"@testname; -- raw string (\')
Query OK, 0 rows affected (0,02 sec)
mysql> create user "\\'"@testname; -- raw string (\') reported with backslash escaped string in error
ERROR 1396 (HY000): Operation CREATE USER failed for '\\\''@'testname'
mysql> set sql_mode = "NO_BACKSLASH_ESCAPES";
Query OK, 0 rows affected (0,00 sec)
mysql> create user "\'"@testname; -- raw string (\') reported with duplicated single quote.
ERROR 1396 (HY000): Operation CREATE USER failed for '\'''@'testname'
mysql> create user '\'''@testname; -- raw string (\') due to NO_BACKSLASH_ESCAPE sql_mode
ERROR 1396 (HY000): Operation CREATE USER failed for '\'''@'testname'
mysql> set sql_mode = "";
Query OK, 0 rows affected (0,00 sec)
-- not possible without NO_BACKSLASH_ESCAPE
mysql> create user '\'''@testname;
'> '\c
mysql> select user,host from mysql.user where host = 'testname'; -- will return the raw string
+------+----------+
| user | host |
+------+----------+
| \' | testname |
+------+----------+
1 row in set (0,00 sec)
mysql> create table quote_test (a varchar(255) not null primary key);
Query OK, 0 rows affected (0,08 sec)
mysql> set sql_mode = "";
Query OK, 0 rows affected (0,00 sec)
-- not possible without sql_mode NO_BACKSLASH_ESCAPES
mysql> insert into quote_test values ('\''');
'> \c
'> '\c
mysql> insert into quote_test values ("\\'"); -- raw string (\')
Query OK, 1 row affected (0,04 sec)
mysql> insert into quote_test values ('\\\''); -- raw string (\') badly escaped in error message
ERROR 1062 (23000): Duplicate entry '\'' for key 'quote_test.PRIMARY'
mysql> set sql_mode = "NO_BACKSLASH_ESCAPES";
Query OK, 0 rows affected (0,00 sec)
mysql> insert into quote_test values ('\'''); -- raw string (\') badly escaped in error message
ERROR 1062 (23000): Duplicate entry '\'' for key 'quote_test.PRIMARY'
mysql> I don't think we should support the inconsistencies as MySQL above, but implement the correct and consistent behaviour. To do that we need to be aware of the sql_mode So that is why I proposed to close this PR (unless objections) and create a new issue in tidb repository with a more clear definition of what to implement, which in my view should work like MySQL when it comes to results, but be correct and consistent for warnings and errors. One way to say it is correct is that the output should also be valid input in the same context/sql_mode. |
|
There is a Line 170 in 1599cce It seems |
|
I will close this for now, and if needed we can restart the conversation and how to address this, since it depends on sql_mode |
What problem does this PR solve?
While working on RENAME USER, I noticed that the output for errors related to accounts was not the same as for MySQL, so I added the missing quoting for TiDB.
What is changed and how it works?
Only quoting the name and host for accounts so user@host becomes 'user'@'host'
Check List
Tests
Code changes
EscapeAccountName(string) stringSide effects
Related changes
N/A