1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

MDEV-16094 Crash when using AS OF with a stored function

MDEV-16100 FOR SYSTEM_TIME erroneously resolves string user variables as transaction IDs

Problem:

Vers_history_point::resolve_unit() tested item->result_type() before
item->fix_fields() was called.

- Item_func_get_user_var::result_type() returned REAL_RESULT by default.
  This caused MDEV-16100.
- Item_func_sp::result_type() crashed on assert.
  This caused MDEV-16094

Changes:
1. Adding item->fix_fields() into Vers_history_point::resolve_unit()
   before using data type specific properties of the history point
   expression.

2. Adding a new virtual method Type_handler::Vers_history_point_resolve_unit()

3. Implementing type-specific
   Type_handler_xxx::Type_handler::Vers_history_point_resolve_unit()
    in the way to:
    a. resolve temporal and general purpose string types to TIMESTAMP
    b. resolve BIT and general purpose INT types to TRANSACTION
    c. disallow use of non-relevant data type expressions in FOR SYSTEM_TIME

    Note, DOUBLE and DECIMAL data types are disallowed intentionally.
    - DOUBLE does not have enough precision to hold huge BIGINT UNSIGNED values
    - DECIMAL rounds on conversion to INT
    Both lack of precision and rounding might potentionally lead to
    very unpredictable results when a wrong transaction ID would be chosen.
    If one really wants dangerous use of DOUBLE and DECIMAL, explicit CAST
    can be used:

      FOR SYSTEM_TIME AS OF CAST(double_or_decimal AS UNSIGNED)

    QQ: perhaps DECIMAL(N,0) could still be allowed.

4. Adding a new virtual method Item::type_handler_for_system_time(),
   to make HEX hybrids and bit literals work as TRANSACTION rather
   than TIMESTAMP.

5. sql_yacc.yy: replacing the rule temporal_literal to "TIMESTAMP TEXT_STRING".
   Other temporal literals now resolve to TIMESTAMP through the new
   Type_handler methods. No special grammar needed. This removed
   a few shift/resolve conflicts.
   (TIMESTAMP related conflicts in "history_point:" will be removed separately)

6. Removing the "timestamp_only" parameter from
   vers_select_conds_t::resolve_units() and Vers_history_point::resolve_unit().
   It was a hint telling that a table did not have any TRANSACTION-aware
   system time columns, so it's OK to resolve to TIMESTAMP in case of uncertainty.
   In the new reduction it works as follows:
   - the decision between TIMESTAMP and TRANSACTION is first made
     based only on the expression data type only
   - then, in case if the expression resolved to TRANSACTION, the table
     is checked if TRANSACTION-aware columns really exist.
   This way is safer against possible ALTER TABLE statements changing
   ROW START and ROW END columns from "BIGINT UNSIGNED" to "TIMESTAMP(x)"
   or the other way around.
This commit is contained in:
Alexander Barkov
2018-05-15 09:33:29 +04:00
parent 1b45ede6ab
commit 46be31982a
11 changed files with 562 additions and 22 deletions

View File

@ -72,6 +72,7 @@ class handler;
struct Schema_specification_st;
struct TABLE;
struct SORT_FIELD_ATTR;
class Vers_history_point;
/**
@ -1409,6 +1410,9 @@ public:
Item_func_div_fix_length_and_dec(Item_func_div *func) const= 0;
virtual bool
Item_func_mod_fix_length_and_dec(Item_func_mod *func) const= 0;
virtual bool
Vers_history_point_resolve_unit(THD *thd, Vers_history_point *point) const;
};
@ -2105,6 +2109,7 @@ public:
virtual const Type_limits_int *
type_limits_int_by_unsigned_flag(bool unsigned_flag) const= 0;
uint32 max_display_length(const Item *item) const;
bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
};
@ -2174,6 +2179,7 @@ public:
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const;
bool Item_func_div_fix_length_and_dec(Item_func_div *) const;
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const;
bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
};
@ -2298,6 +2304,7 @@ class Type_handler_general_purpose_string: public Type_handler_string_result
{
public:
bool is_general_purpose_string_type() const { return true; }
bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
};
@ -2570,6 +2577,7 @@ public:
const Record_addr &addr,
const Type_all_attributes &attr,
TABLE *table) const;
bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
};
@ -3384,6 +3392,7 @@ public:
const;
void Item_param_set_param_func(Item_param *param,
uchar **pos, ulong len) const;
bool Vers_history_point_resolve_unit(THD *thd, Vers_history_point *p) const;
};