mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
MDEV-27744 LPAD in vcol created in ORACLE mode makes table corrupted in non-ORACLE
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.
This commit is contained in:
@ -2407,6 +2407,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.
|
||||
|
||||
@ -2733,8 +2742,8 @@ 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) 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 *);
|
||||
@ -4045,8 +4054,41 @@ public:
|
||||
|
||||
Item *create_item_query_expression(THD *thd, st_select_lex_unit *unit);
|
||||
|
||||
Item *make_item_func_call_generic(THD *thd, Lex_ident_cli_st *db,
|
||||
Lex_ident_cli_st *name, List<Item> *args);
|
||||
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_replace(THD *thd,
|
||||
const Lex_ident_cli_st &schema_name,
|
||||
const Lex_ident_cli_st &func_name,
|
||||
List<Item> *args);
|
||||
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_substr(THD *thd,
|
||||
const Lex_ident_cli_st &schema_name,
|
||||
const Lex_ident_cli_st &func_name,
|
||||
List<Item> *args);
|
||||
Item *make_item_func_trim(THD *thd,
|
||||
const Lex_ident_cli_st &schema_name,
|
||||
const Lex_ident_cli_st &func_name,
|
||||
const Lex_trim_st &spec);
|
||||
Item *make_item_func_trim(THD *thd,
|
||||
const Lex_ident_cli_st &schema_name,
|
||||
const Lex_ident_cli_st &func_name,
|
||||
List<Item> *args);
|
||||
Item *make_item_func_call_generic(THD *thd,
|
||||
const Lex_ident_cli_st *db,
|
||||
const 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,
|
||||
|
Reference in New Issue
Block a user