summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2018-11-15 06:35:37 +0400
committerAlexander Barkov <bar@mariadb.com>2018-11-15 06:35:37 +0400
commit7f175595c83b3ef55d6aa00cc7707ec565398bf5 (patch)
treef38b02fdd380103d281fac6923371f0c47693a92
parentb68d8a05d326bed43aefa73d717c0307278ca6bb (diff)
downloadmariadb-git-7f175595c83b3ef55d6aa00cc7707ec565398bf5.tar.gz
Backport for "MDEV-17698 MEMORY engine performance regression"
Also, backporting a part of: MDEV-11485 Split Item_func_between::val_int() into virtual methods in Type_handler for easier merge to 10.3.
-rw-r--r--sql/item.h4
-rw-r--r--sql/item_cmpfunc.cc190
-rw-r--r--sql/item_cmpfunc.h5
-rw-r--r--sql/sql_type_int.h28
4 files changed, 140 insertions, 87 deletions
diff --git a/sql/item.h b/sql/item.h
index dacac2d725e..38dce1f3b97 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -794,6 +794,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);
+ }
/*
This is just a shortcut to avoid the cast. You should still use
unsigned_flag to check the sign of the item.
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index d4a2c767b15..3af79c23ee7 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -158,7 +158,10 @@ static int cmp_row_type(Item* item1, Item* item2)
0 otherwise
*/
-static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
+static int agg_cmp_type(Item_result *type,
+ Item **items,
+ uint nitems,
+ bool int_uint_as_dec)
{
uint unsigned_count= items[0]->unsigned_flag;
type[0]= items[0]->cmp_type();
@@ -180,7 +183,9 @@ static int agg_cmp_type(Item_result *type, Item **items, uint nitems)
If all arguments are of INT type but have different unsigned_flag values,
switch to DECIMAL_RESULT.
*/
- if (type[0] == INT_RESULT && unsigned_count != nitems && unsigned_count != 0)
+ if (int_uint_as_dec &&
+ type[0] == INT_RESULT &&
+ unsigned_count != nitems && unsigned_count != 0)
type[0]= DECIMAL_RESULT;
return 0;
}
@@ -2295,7 +2300,7 @@ void Item_func_between::fix_length_and_dec()
*/
if (!args[0] || !args[1] || !args[2])
return;
- if ( agg_cmp_type(&cmp_type, args, 3))
+ if (agg_cmp_type(&cmp_type, args, 3, false))
return;
if (cmp_type == STRING_RESULT &&
agg_arg_charsets_for_comparison(cmp_collation, args, 3))
@@ -2329,6 +2334,97 @@ void Item_func_between::fix_length_and_dec()
}
+longlong Item_func_between::val_int_cmp_string()
+{
+ String *value,*a,*b;
+ value=args[0]->val_str(&value0);
+ if ((null_value=args[0]->null_value))
+ return 0;
+ a= args[1]->val_str(&value1);
+ b= args[2]->val_str(&value2);
+ if (!args[1]->null_value && !args[2]->null_value)
+ return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 &&
+ sortcmp(value,b,cmp_collation.collation) <= 0) !=
+ negated);
+ if (args[1]->null_value && args[2]->null_value)
+ null_value= true;
+ else if (args[1]->null_value)
+ {
+ // Set to not null if false range.
+ null_value= sortcmp(value,b,cmp_collation.collation) <= 0;
+ }
+ else
+ {
+ // Set to not null if false range.
+ null_value= sortcmp(value,a,cmp_collation.collation) >= 0;
+ }
+ return (longlong) (!null_value && negated);
+}
+
+
+longlong Item_func_between::val_int_cmp_int()
+{
+ Longlong_hybrid value= args[0]->to_longlong_hybrid();
+ if ((null_value= args[0]->null_value))
+ return 0; /* purecov: inspected */
+ 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.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.cmp(b) <= 0; // not null if false range.
+ else
+ null_value= value.cmp(a) >= 0;
+ return (longlong) (!null_value && negated);
+}
+
+
+longlong Item_func_between::val_int_cmp_decimal()
+{
+ my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf),
+ a_buf, *a_dec, b_buf, *b_dec;
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ a_dec= args[1]->val_decimal(&a_buf);
+ b_dec= args[2]->val_decimal(&b_buf);
+ if (!args[1]->null_value && !args[2]->null_value)
+ return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 &&
+ my_decimal_cmp(dec, b_dec) <= 0) != negated);
+ if (args[1]->null_value && args[2]->null_value)
+ null_value= true;
+ else if (args[1]->null_value)
+ null_value= (my_decimal_cmp(dec, b_dec) <= 0);
+ else
+ null_value= (my_decimal_cmp(dec, a_dec) >= 0);
+ return (longlong) (!null_value && negated);
+}
+
+
+longlong Item_func_between::val_int_cmp_real()
+{
+ double value= args[0]->val_real(),a,b;
+ if ((null_value=args[0]->null_value))
+ return 0; /* purecov: inspected */
+ a= args[1]->val_real();
+ b= args[2]->val_real();
+ if (!args[1]->null_value && !args[2]->null_value)
+ return (longlong) ((value >= a && value <= b) != 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.
+ }
+ else
+ {
+ null_value= value >= a;
+ }
+ return (longlong) (!null_value && negated);
+}
+
+
longlong Item_func_between::val_int()
{
DBUG_ASSERT(fixed == 1);
@@ -2370,94 +2466,14 @@ longlong Item_func_between::val_int()
null_value= value >= a;
break;
}
-
case STRING_RESULT:
- {
- String *value,*a,*b;
- value=args[0]->val_str(&value0);
- if ((null_value=args[0]->null_value))
- return 0;
- a=args[1]->val_str(&value1);
- b=args[2]->val_str(&value2);
- if (!args[1]->null_value && !args[2]->null_value)
- return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 &&
- sortcmp(value,b,cmp_collation.collation) <= 0) !=
- negated);
- if (args[1]->null_value && args[2]->null_value)
- null_value=1;
- else if (args[1]->null_value)
- {
- // Set to not null if false range.
- null_value= sortcmp(value,b,cmp_collation.collation) <= 0;
- }
- else
- {
- // Set to not null if false range.
- null_value= sortcmp(value,a,cmp_collation.collation) >= 0;
- }
- break;
- }
+ return val_int_cmp_string();
case INT_RESULT:
- {
- longlong value=args[0]->val_int(), a, b;
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
- a=args[1]->val_int();
- b=args[2]->val_int();
- if (!args[1]->null_value && !args[2]->null_value)
- return (longlong) ((value >= a && value <= b) != negated);
- if (args[1]->null_value && args[2]->null_value)
- null_value=1;
- else if (args[1]->null_value)
- {
- null_value= value <= b; // not null if false range.
- }
- else
- {
- null_value= value >= a;
- }
- break;
- }
+ return val_int_cmp_int();
case DECIMAL_RESULT:
- {
- my_decimal dec_buf, *dec= args[0]->val_decimal(&dec_buf),
- a_buf, *a_dec, b_buf, *b_dec;
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
- a_dec= args[1]->val_decimal(&a_buf);
- b_dec= args[2]->val_decimal(&b_buf);
- if (!args[1]->null_value && !args[2]->null_value)
- return (longlong) ((my_decimal_cmp(dec, a_dec) >= 0 &&
- my_decimal_cmp(dec, b_dec) <= 0) != negated);
- if (args[1]->null_value && args[2]->null_value)
- null_value=1;
- else if (args[1]->null_value)
- null_value= (my_decimal_cmp(dec, b_dec) <= 0);
- else
- null_value= (my_decimal_cmp(dec, a_dec) >= 0);
- break;
- }
+ return val_int_cmp_decimal();
case REAL_RESULT:
- {
- double value= args[0]->val_real(),a,b;
- if ((null_value=args[0]->null_value))
- return 0; /* purecov: inspected */
- a= args[1]->val_real();
- b= args[2]->val_real();
- if (!args[1]->null_value && !args[2]->null_value)
- return (longlong) ((value >= a && value <= b) != negated);
- if (args[1]->null_value && args[2]->null_value)
- null_value=1;
- else if (args[1]->null_value)
- {
- null_value= value <= b; // not null if false range.
- }
- else
- {
- null_value= value >= a;
- }
- break;
- }
+ return val_int_cmp_real();
case ROW_RESULT:
case IMPOSSIBLE_RESULT:
DBUG_ASSERT(0);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index c4e6a53dd6b..12a12e05845 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -694,6 +694,11 @@ public:
bool eval_not_null_tables(uchar *opt_arg);
void fix_after_pullout(st_select_lex *new_parent, Item **ref);
bool count_sargable_conds(uchar *arg);
+
+ longlong val_int_cmp_string();
+ longlong val_int_cmp_int();
+ longlong val_int_cmp_real();
+ longlong val_int_cmp_decimal();
};
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