MDEV-17607 DATE(COALESCE(year_column)) returns a wrong result
C++ does not guarantee the order of parameter evaluation. It was wrong to pass item->val_int() and item->null_value at the same time to any function or constructor. Adding a new helper class Longlong_null, and new methods Item::to_longlong_null() and Item_func_hybrid_field_type::to_longlong_null_op(), which make sure to properly call val_int()/int_op() and test null_value. Reorganizing the rest of the code accordingly.
This commit is contained in:
parent
2feac61e18
commit
563efeceec
@ -560,5 +560,14 @@ SELECT MAKEDATE(18446744073709551615, 1);
|
||||
MAKEDATE(18446744073709551615, 1)
|
||||
NULL
|
||||
#
|
||||
# MDEV-17607 DATE(COALESCE(year_column)) returns a wrong result
|
||||
#
|
||||
CREATE TABLE t1 (a YEAR);
|
||||
INSERT INTO t1 VALUES (NULL);
|
||||
SELECT COALESCE(a), DATE(COALESCE(a)) FROM t1;
|
||||
COALESCE(a) DATE(COALESCE(a))
|
||||
NULL NULL
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# End of 10.4 tests
|
||||
#
|
||||
|
@ -299,6 +299,15 @@ DROP TABLE t1;
|
||||
--echo #
|
||||
SELECT MAKEDATE(18446744073709551615, 1);
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-17607 DATE(COALESCE(year_column)) returns a wrong result
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a YEAR);
|
||||
INSERT INTO t1 VALUES (NULL);
|
||||
SELECT COALESCE(a), DATE(COALESCE(a)) FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.4 tests
|
||||
--echo #
|
||||
|
10
sql/item.h
10
sql/item.h
@ -1183,6 +1183,16 @@ public:
|
||||
If value is not null null_value flag will be reset to FALSE.
|
||||
*/
|
||||
virtual longlong val_int()=0;
|
||||
Longlong_null to_longlong_null()
|
||||
{
|
||||
longlong nr= val_int();
|
||||
/*
|
||||
C++ does not guarantee the order of parameter evaluation,
|
||||
so to make sure "null_value" is passed to the constructor
|
||||
after the val_int() call, val_int() is caled on a separate line.
|
||||
*/
|
||||
return Longlong_null(nr, null_value);
|
||||
}
|
||||
/**
|
||||
Get a value for CAST(x AS SIGNED).
|
||||
Too large positive unsigned integer values are converted
|
||||
|
@ -784,6 +784,16 @@ public:
|
||||
@return The result of the operation.
|
||||
*/
|
||||
virtual longlong int_op()= 0;
|
||||
Longlong_null to_longlong_null_op()
|
||||
{
|
||||
longlong nr= int_op();
|
||||
/*
|
||||
C++ does not guarantee the order of parameter evaluation,
|
||||
so to make sure "null_value" is passed to the constructor
|
||||
after the int_op() call, int_op() is caled on a separate line.
|
||||
*/
|
||||
return Longlong_null(nr, null_value);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Performs the operation that this functions implements when the
|
||||
|
@ -326,14 +326,13 @@ uint Year::year_precision(const Item *item) const
|
||||
|
||||
|
||||
VYear::VYear(Item *item)
|
||||
:Year_null(Year(item->val_int(), item->unsigned_flag,
|
||||
year_precision(item)), item->null_value)
|
||||
:Year_null(item->to_longlong_null(), item->unsigned_flag, year_precision(item))
|
||||
{ }
|
||||
|
||||
|
||||
VYear_op::VYear_op(Item_func_hybrid_field_type *item)
|
||||
:Year_null(Year(item->int_op(), item->unsigned_flag,
|
||||
year_precision(item)), item->null_value)
|
||||
:Year_null(item->to_longlong_null_op(), item->unsigned_flag,
|
||||
year_precision(item))
|
||||
{ }
|
||||
|
||||
|
||||
|
@ -412,16 +412,13 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class Year_null: public Year
|
||||
class Year_null: public Year, public Null_flag
|
||||
{
|
||||
protected:
|
||||
bool m_is_null;
|
||||
public:
|
||||
Year_null(const Year &other, bool is_null)
|
||||
:Year(is_null ? Year() : other),
|
||||
m_is_null(is_null)
|
||||
Year_null(const Longlong_null &nr, bool unsigned_flag, uint length)
|
||||
:Year(nr.is_null() ? 0 : nr.value(), unsigned_flag, length),
|
||||
Null_flag(nr.is_null())
|
||||
{ }
|
||||
bool is_null() const { return m_is_null; }
|
||||
bool to_mysql_time_with_warn(THD *thd, MYSQL_TIME *to, date_mode_t fuzzydate,
|
||||
const char *field_name) const
|
||||
{
|
||||
|
@ -1,5 +1,4 @@
|
||||
/* Copyright (c) 2006, 2010, Oracle and/or its affiliates.
|
||||
Copyright (c) 2011, 2016, MariaDB
|
||||
/* Copyright (c) 2018, MariaDB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -18,17 +17,44 @@
|
||||
#define SQL_TYPE_INT_INCLUDED
|
||||
|
||||
|
||||
// A longlong/ulonglong hybrid. Good to store results of val_int().
|
||||
class Longlong_hybrid
|
||||
class Null_flag
|
||||
{
|
||||
protected:
|
||||
bool m_is_null;
|
||||
public:
|
||||
bool is_null() const { return m_is_null; }
|
||||
Null_flag(bool is_null) :m_is_null(is_null) { }
|
||||
};
|
||||
|
||||
|
||||
class Longlong
|
||||
{
|
||||
protected:
|
||||
longlong m_value;
|
||||
public:
|
||||
longlong value() const { return m_value; }
|
||||
Longlong(longlong nr) :m_value(nr) { }
|
||||
};
|
||||
|
||||
|
||||
class Longlong_null: public Longlong, public Null_flag
|
||||
{
|
||||
public:
|
||||
Longlong_null(longlong nr, bool is_null)
|
||||
:Longlong(nr), Null_flag(is_null)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
// A longlong/ulonglong hybrid. Good to store results of val_int().
|
||||
class Longlong_hybrid: public Longlong
|
||||
{
|
||||
protected:
|
||||
bool m_unsigned;
|
||||
public:
|
||||
Longlong_hybrid(longlong nr, bool unsigned_flag)
|
||||
:m_value(nr), m_unsigned(unsigned_flag)
|
||||
:Longlong(nr), m_unsigned(unsigned_flag)
|
||||
{ }
|
||||
longlong value() const { return m_value; }
|
||||
bool is_unsigned() const { return m_unsigned; }
|
||||
bool neg() const { return m_value < 0 && !m_unsigned; }
|
||||
ulonglong abs() const
|
||||
|
Loading…
x
Reference in New Issue
Block a user