diff options
author | Alexander Barkov <bar@mariadb.com> | 2022-04-04 14:50:21 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2023-04-25 13:54:27 +0400 |
commit | c610c25e591e609a3456c993da8c002d1c45dd6e (patch) | |
tree | f67ce72e50ff17e63eccbcd54484dd49e84946eb /sql/sql_lex.h | |
parent | 29fb041007285c34d9c22dbc6359a2e9b9ea32f3 (diff) | |
download | mariadb-git-bb-10.4-bar-MDEV-27744.tar.gz |
MDEV-27744 InnoDB: Failing assertion: !cursor->index->is_committed() in row0ins.cc (from row_ins_sec_index_entry_by_modify) | Assertion `0' failed in row_upd_sec_index_entry (debug) | Corruptionbb-10.4-bar-MDEV-27744
The crash happened with an indexed virtual column whose
value is evaluated using a function that has a different meaning
in sql_mode='' vs sql_mode=ORACLE:
- DECODE()
- LTRIM()
- RTRIM()
- LPAD()
- RPAD()
- REPLACE()
- SUBSTR()
For example:
CREATE TABLE t1 (
b VARCHAR(1),
g CHAR(1) GENERATED ALWAYS AS (SUBSTR(b,0,0)) VIRTUAL,
KEY g(g)
);
So far we had replacement XXX_ORACLE() functions for all mentioned function,
e.g. SUBSTR_ORACLE() for SUBSTR(). So it was possible to correctly re-parse
SUBSTR_ORACLE() even in sql_mode=''.
But it was not possible to re-parse the MariaDB version of SUBSTR()
after switching to sql_mode=ORACLE. It was erroneously mis-interpreted
as SUBSTR_ORACLE().
As a result, this combination worked fine:
SET sql_mode=ORACLE;
CREATE TABLE t1 ... g CHAR(1) GENERATED ALWAYS AS (SUBSTR(b,0,0)) VIRTUAL, ...;
INSERT ...
FLUSH TABLES;
SET sql_mode='';
INSERT ...
But the other way around it crashed:
SET sql_mode='';
CREATE TABLE t1 ... g CHAR(1) GENERATED ALWAYS AS (SUBSTR(b,0,0)) VIRTUAL, ...;
INSERT ...
FLUSH TABLES;
SET sql_mode=ORACLE;
INSERT ...
At CREATE time, SUBSTR was instantiated as Item_func_substr and printed
in the FRM file as substr(). At re-open time with sql_mode=ORACLE, "substr()"
was erroneously instantiated as Item_func_substr_oracle.
Fix:
The fix proposes a symmetric solution. It provides a way to re-parse reliably
all sql_mode dependent functions to their original CREATE TABLE time meaning,
no matter what the open-time sql_mode is.
We take advantage of the same idea we previously used to resolve sql_mode
dependent data types.
Now all sql_mode dependent functions are printed by SHOW using a schema
qualifier when the current sql_mode differs from the function sql_mode:
SET sql_mode='';
CREATE TABLE t1 ... SUBSTR(a,b,c) ..;
SET sql_mode=ORACLE;
SHOW CREATE TABLE t1; -> mariadb_schema.substr(a,b,c)
SET sql_mode=ORACLE;
CREATE TABLE t2 ... SUBSTR(a,b,c) ..;
SET sql_mode='';
SHOW CREATE TABLE t1; -> oracle_schema.substr(a,b,c)
Old replacement names like substr_oracle() are still understood for
backward compatibility and used in FRM files (for downgrade compatibility),
but they are not printed by SHOW any more.
Diffstat (limited to 'sql/sql_lex.h')
-rw-r--r-- | sql/sql_lex.h | 37 |
1 files changed, 29 insertions, 8 deletions
diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6170637ad77..bee7fd67060 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -2395,6 +2395,15 @@ public: void reduce_digest_token(uint token_left, uint token_right); private: + + enum Ident_mode + { + GENERAL_KEYWORD_OR_FUNC_LPAREN, + QUALIFIED_SPECIAL_FUNC_LPAREN + }; + + int scan_ident_common(THD *thd, Lex_ident_cli_st *str, Ident_mode mode); + /** Set the echo mode. @@ -2592,7 +2601,7 @@ public: } /** Get the raw query buffer. */ - const char *get_buf() + const char *get_buf() const { return m_buf; } @@ -2604,7 +2613,7 @@ public: } /** Get the end of the raw query buffer. */ - const char *get_end_of_query() + const char *get_end_of_query() const { return m_end_of_query; } @@ -2648,7 +2657,7 @@ public: Get the token end position in the pre-processed buffer, with trailing spaces removed. */ - const char *get_cpp_tok_end_rtrim() + const char *get_cpp_tok_end_rtrim() const { const char *p; for (p= m_cpp_tok_end; @@ -2720,9 +2729,9 @@ private: bool consume_comment(int remaining_recursions_permitted); int lex_one_token(union YYSTYPE *yylval, THD *thd); - int find_keyword(Lex_ident_cli_st *str, uint len, bool function); + int find_keyword(Lex_ident_cli_st *str, uint len, bool function) const; + int find_keyword_qualified_special_func(Lex_ident_cli_st *str, uint len) const; LEX_CSTRING get_token(uint skip, uint length); - int scan_ident_sysvar(THD *thd, Lex_ident_cli_st *str); int scan_ident_start(THD *thd, Lex_ident_cli_st *str); int scan_ident_middle(THD *thd, Lex_ident_cli_st *str, CHARSET_INFO **cs, my_lex_states *); @@ -4033,12 +4042,24 @@ public: Item *create_item_query_expression(THD *thd, st_select_lex_unit *unit); - Item *make_item_func_replace(THD *thd, Item *org, Item *find, Item *replace); - Item *make_item_func_substr(THD *thd, Item *a, Item *b, Item *c); - Item *make_item_func_substr(THD *thd, Item *a, Item *b); + static const Schema * + find_func_schema_by_name_or_error(const Lex_ident_sys &schema_name, + const Lex_ident_sys &func_name); + Item *make_item_func_replace(THD *thd, + const Lex_ident_cli_st &schema_name, + const Lex_ident_cli_st &func_name, + Item *org, Item *find, Item *replace); + Item *make_item_func_substr(THD *thd, + const Lex_ident_cli_st &schema_name, + const Lex_ident_cli_st &func_name, + const Lex_substring_spec_st &spec); Item *make_item_func_call_generic(THD *thd, Lex_ident_cli_st *db, Lex_ident_cli_st *name, List<Item> *args); Item *make_item_func_call_generic(THD *thd, + const Lex_ident_sys &db, + const Lex_ident_sys &name, + List<Item> *args); + Item *make_item_func_call_generic(THD *thd, Lex_ident_cli_st *db, Lex_ident_cli_st *pkg, Lex_ident_cli_st *name, |