summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2018-11-14 13:55:05 +0400
committerAlexander Barkov <bar@mariadb.com>2018-11-14 13:56:18 +0400
commit45769429d9a3bfa37ead21aa0d36214f980a00d7 (patch)
tree4d5f351088880b443b11f13f81209fc433c1784c /sql
parentf718477714aedd9fd598990169db6f512c9cae64 (diff)
downloadmariadb-git-45769429d9a3bfa37ead21aa0d36214f980a00d7.tar.gz
MDEV-17698 MEMORY engine performance regression
Diffstat (limited to 'sql')
-rw-r--r--sql/item.h4
-rw-r--r--sql/item_cmpfunc.cc18
-rw-r--r--sql/sql_type_int.h28
3 files changed, 39 insertions, 11 deletions
diff --git a/sql/item.h b/sql/item.h
index d743cf6c19c..6bb97d3c3a3 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1028,6 +1028,10 @@ public:
If value is not null null_value flag will be reset to FALSE.
*/
virtual longlong val_int()=0;
+ Longlong_hybrid to_longlong_hybrid()
+ {
+ return Longlong_hybrid(val_int(), unsigned_flag);
+ }
/**
Get a value for CAST(x AS SIGNED).
Too large positive unsigned integer values are converted
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index ccbae1bad34..b1f7e54546a 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2067,7 +2067,7 @@ bool Item_func_between::fix_length_and_dec()
if (!args[0] || !args[1] || !args[2])
return TRUE;
if (m_comparator.aggregate_for_comparison(Item_func_between::func_name(),
- args, 3, true))
+ args, 3, false))
{
DBUG_ASSERT(current_thd->is_error());
return TRUE;
@@ -2171,23 +2171,19 @@ longlong Item_func_between::val_int_cmp_string()
longlong Item_func_between::val_int_cmp_int()
{
- longlong value= args[0]->val_int(), a, b;
+ Longlong_hybrid value= args[0]->to_longlong_hybrid();
if ((null_value= args[0]->null_value))
return 0; /* purecov: inspected */
- a= args[1]->val_int();
- b= args[2]->val_int();
+ Longlong_hybrid a= args[1]->to_longlong_hybrid();
+ Longlong_hybrid b= args[2]->to_longlong_hybrid();
if (!args[1]->null_value && !args[2]->null_value)
- return (longlong) ((value >= a && value <= b) != negated);
+ return (longlong) ((value.cmp(a) >= 0 && value.cmp(b) <= 0) != negated);
if (args[1]->null_value && args[2]->null_value)
null_value= true;
else if (args[1]->null_value)
- {
- null_value= value <= b; // not null if false range.
- }
+ null_value= value.cmp(b) <= 0; // not null if false range.
else
- {
- null_value= value >= a;
- }
+ null_value= value.cmp(a) >= 0;
return (longlong) (!null_value && negated);
}
diff --git a/sql/sql_type_int.h b/sql/sql_type_int.h
index 1eda5651df5..7433bd5249f 100644
--- a/sql/sql_type_int.h
+++ b/sql/sql_type_int.h
@@ -24,12 +24,25 @@ class Longlong_hybrid
protected:
longlong m_value;
bool m_unsigned;
+ int cmp_signed(const Longlong_hybrid& other) const
+ {
+ return m_value < other.m_value ? -1 : m_value == other.m_value ? 0 : 1;
+ }
+ int cmp_unsigned(const Longlong_hybrid& other) const
+ {
+ return (ulonglong) m_value < (ulonglong) other.m_value ? -1 :
+ m_value == other.m_value ? 0 : 1;
+ }
public:
Longlong_hybrid(longlong nr, bool unsigned_flag)
:m_value(nr), m_unsigned(unsigned_flag)
{ }
longlong value() const { return m_value; }
bool is_unsigned() const { return m_unsigned; }
+ bool is_unsigned_outside_of_signed_range() const
+ {
+ return m_unsigned && ((ulonglong) m_value) > (ulonglong) LONGLONG_MAX;
+ }
bool neg() const { return m_value < 0 && !m_unsigned; }
ulonglong abs() const
{
@@ -39,6 +52,21 @@ public:
return ((ulonglong) LONGLONG_MAX) + 1;
return m_value < 0 ? -m_value : m_value;
}
+ int cmp(const Longlong_hybrid& other) const
+ {
+ if (m_unsigned == other.m_unsigned)
+ return m_unsigned ? cmp_unsigned(other) : cmp_signed(other);
+ if (is_unsigned_outside_of_signed_range())
+ return 1;
+ if (other.is_unsigned_outside_of_signed_range())
+ return -1;
+ /*
+ The unsigned argument is in the range 0..LONGLONG_MAX.
+ The signed argument is in the range LONGLONG_MIN..LONGLONG_MAX.
+ Safe to compare as signed.
+ */
+ return cmp_signed(other);
+ }
};
#endif // SQL_TYPE_INT_INCLUDED