1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +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:
Alexander Barkov
2022-04-04 14:50:21 +04:00
parent 228b7e4db5
commit 2b6d241ee4
34 changed files with 3754 additions and 126 deletions

View File

@ -33,6 +33,12 @@ public:
return src;
}
Create_func *find_native_function_builder(THD *thd, const LEX_CSTRING &name)
const
{
return native_functions_hash_oracle.find(thd, name);
}
Item *make_item_func_replace(THD *thd,
Item *subj,
Item *find,
@ -64,6 +70,7 @@ Schema mariadb_schema(Lex_cstring(STRING_WITH_LEN("mariadb_schema")));
Schema_oracle oracle_schema(Lex_cstring(STRING_WITH_LEN("oracle_schema")));
Schema_maxdb maxdb_schema(Lex_cstring(STRING_WITH_LEN("maxdb_schema")));
const Schema &oracle_schema_ref= oracle_schema;
Schema *Schema::find_by_name(const LEX_CSTRING &name)
{
@ -88,6 +95,26 @@ Schema *Schema::find_implied(THD *thd)
}
Create_func *
Schema::find_native_function_builder(THD *thd, const LEX_CSTRING &name) const
{
return native_functions_hash.find(thd, name);
}
Item *Schema::make_item_func_call_native(THD *thd,
const Lex_ident_sys &name,
List<Item> *args) const
{
Create_func *builder= find_native_function_builder(thd, name);
if (builder)
return builder->create_func(thd, &name, args);
my_error(ER_FUNCTION_NOT_DEFINED, MYF(0), name.str);
return NULL;
}
Item *Schema::make_item_func_replace(THD *thd,
Item *subj,
Item *find,