mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-33496 Out of range error in AVG(YEAR(datetime)) due to a wrong data type
Functions extracting non-negative datetime components: - YEAR(dt), EXTRACT(YEAR FROM dt) - QUARTER(td), EXTRACT(QUARTER FROM dt) - MONTH(dt), EXTRACT(MONTH FROM dt) - WEEK(dt), EXTRACT(WEEK FROM dt) - HOUR(dt), - MINUTE(dt), - SECOND(dt), - MICROSECOND(dt), - DAYOFYEAR(dt) - EXTRACT(YEAR_MONTH FROM dt) did not set their max_length properly, so in the DECIMAL context they created a too small DECIMAL column, which led to the 'Out of range value' error. The problem is that most of these functions historically returned the signed INT data type. There were two simple ways to fix these functions: 1. Add +1 to max_length. But this would also change their size in the string context and create too long VARCHAR columns, with +1 excessive size. 2. Preserve max_length, but change the data type from INT to INT UNSIGNED. But this would break backward compatibility. Also, using UNSIGNED is generally not desirable, it's better to stay with signed when possible. This fix implements another solution, which it makes all these functions work well in all contexts: int, decimal, string. Fix details: - Adding a new special class Type_handler_long_ge0 - the data type handler for expressions which: * should look like normal signed INT * but which known not to return negative values Expressions handled by Type_handler_long_ge0 store in Item::max_length only the number of digits, without adding +1 for the sign. - Fixing Item_extract to use Type_handler_long_ge0 for non-negative datetime components: YEAR, YEAR_MONTH, QUARTER, MONTH, WEEK - Adding a new abstract class Item_long_ge0_func, for functions returning non-negative datetime components. Item_long_ge0_func uses Type_handler_long_ge0 as the type handler. The class hierarchy now looks as follows: Item_long_ge0_func Item_long_func_date_field Item_func_to_days Item_func_dayofmonth Item_func_dayofyear Item_func_quarter Item_func_year Item_long_func_time_field Item_func_hour Item_func_minute Item_func_second Item_func_microsecond - Cleanup: EXTRACT(QUARTER FROM dt) created an excessive VARCHAR column in string context. Changing its length from 2 to 1.
This commit is contained in:
@ -5758,6 +5758,38 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
The expression of this type reports itself as signed,
|
||||
however it's known not to return negative values.
|
||||
Items of this data type count only digits in Item::max_length,
|
||||
without adding +1 for the sign. This allows expressions
|
||||
of this type convert nicely to VARCHAR and DECIMAL.
|
||||
For example, YEAR(now()) is:
|
||||
- VARCHAR(4) in a string context
|
||||
- DECIMAL(4,0) in a decimal context
|
||||
- but INT(5) in an integer context
|
||||
*/
|
||||
class Type_handler_long_ge0: public Type_handler_long
|
||||
{
|
||||
public:
|
||||
uint Item_decimal_precision(const Item *item) const override;
|
||||
bool Item_func_signed_fix_length_and_dec(Item_func_signed *item)
|
||||
const override;
|
||||
bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item)
|
||||
const override;
|
||||
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
|
||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
|
||||
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override;
|
||||
Field *make_table_field_from_def(TABLE_SHARE *share,
|
||||
MEM_ROOT *mem_root,
|
||||
const LEX_CSTRING *name,
|
||||
const Record_addr &addr,
|
||||
const Bit_addr &bit,
|
||||
const Column_definition_attributes *attr,
|
||||
uint32 flags) const override;
|
||||
};
|
||||
|
||||
|
||||
class Type_handler_ulong: public Type_handler_long
|
||||
{
|
||||
public:
|
||||
@ -7598,6 +7630,7 @@ extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_tiny> type_han
|
||||
extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_short> type_handler_sshort;
|
||||
extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_int24> type_handler_sint24;
|
||||
extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_long> type_handler_slong;
|
||||
extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_long_ge0> type_handler_slong_ge0;
|
||||
extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_longlong> type_handler_slonglong;
|
||||
|
||||
extern Named_type_handler<Type_handler_utiny> type_handler_utiny;
|
||||
|
Reference in New Issue
Block a user