summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.h
diff options
context:
space:
mode:
authorSergei Petrunia <psergey@askmonty.org>2016-03-28 22:18:38 +0300
committerSergei Petrunia <psergey@askmonty.org>2016-03-28 22:18:38 +0300
commit2bd4dc38e0d5eb257e2e29413dd01239ce075d42 (patch)
treedad0557b1d927d012aebd1c36c8c3e00462adcb1 /sql/item_cmpfunc.h
parent44fdb56c977259b2801c612116813beda403df78 (diff)
parent3df261dc31ab18ee1537f327b07320b0a07fb8f5 (diff)
downloadmariadb-git-2bd4dc38e0d5eb257e2e29413dd01239ce075d42.tar.gz
Merge branch '10.2' into bb-10.2-mdev9543
Diffstat (limited to 'sql/item_cmpfunc.h')
-rw-r--r--sql/item_cmpfunc.h124
1 files changed, 88 insertions, 36 deletions
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 38d07017b32..5789186dbe8 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1,7 +1,7 @@
#ifndef ITEM_CMPFUNC_INCLUDED
#define ITEM_CMPFUNC_INCLUDED
/* Copyright (c) 2000, 2015, Oracle and/or its affiliates.
- Copyright (c) 2009, 2015, MariaDB
+ Copyright (c) 2009, 2016, 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
@@ -795,6 +795,7 @@ public:
public:
inline void negate() { negated= !negated; }
inline void top_level_item() { pred_level= 1; }
+ bool is_top_level_item() const { return pred_level; }
Item *neg_transformer(THD *thd)
{
negated= !negated;
@@ -901,7 +902,11 @@ public:
String *str_op(String *);
my_decimal *decimal_op(my_decimal *);
bool date_op(MYSQL_TIME *ltime,uint fuzzydate);
- void fix_length_and_dec();
+ void fix_length_and_dec()
+ {
+ set_handler_by_field_type(agg_field_type(args, arg_count, true));
+ fix_attributes(args, arg_count);
+ }
const char *func_name() const { return "coalesce"; }
table_map not_null_tables() const { return 0; }
};
@@ -914,13 +919,18 @@ public:
*/
class Item_func_case_abbreviation2 :public Item_func_hybrid_field_type
{
+protected:
+ void fix_length_and_dec2(Item **items)
+ {
+ set_handler_by_field_type(agg_field_type(items, 2, true));
+ fix_attributes(items, 2);
+ }
+ uint decimal_precision2(Item **args) const;
public:
Item_func_case_abbreviation2(THD *thd, Item *a, Item *b):
Item_func_hybrid_field_type(thd, a, b) { }
Item_func_case_abbreviation2(THD *thd, Item *a, Item *b, Item *c):
Item_func_hybrid_field_type(thd, a, b, c) { }
- void fix_length_and_dec2(Item **args);
- uint decimal_precision2(Item **args) const;
};
@@ -996,11 +1006,21 @@ class Item_func_nullif :public Item_func_hybrid_field_type
- Item_field::propagate_equal_fields(ANY_SUBST) for the left "a"
- Item_field::propagate_equal_fields(IDENTITY_SUBST) for the right "a"
*/
+ Item_cache *m_cache;
+ int compare();
public:
- // Put "a" to args[0] for comparison and to args[2] for the returned value.
+ /*
+ Here we pass three arguments to the parent constructor, as NULLIF
+ is a three-argument function, it needs two copies of the first argument
+ (see above). But fix_fields() will be confused if we try to prepare the
+ same Item twice (if args[0]==args[2]), so we hide the third argument
+ (decrementing arg_count) and copy args[2]=args[0] again after fix_fields().
+ See also Item_func_nullif::fix_length_and_dec().
+ */
Item_func_nullif(THD *thd, Item *a, Item *b):
- Item_func_hybrid_field_type(thd, a, b, a)
- {}
+ Item_func_hybrid_field_type(thd, a, b, a),
+ m_cache(NULL)
+ { arg_count--; }
bool date_op(MYSQL_TIME *ltime, uint fuzzydate);
double real_op();
longlong int_op();
@@ -1010,6 +1030,9 @@ public:
uint decimal_precision() const { return args[2]->decimal_precision(); }
const char *func_name() const { return "nullif"; }
void print(String *str, enum_query_type query_type);
+ void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array,
+ List<Item> &fields, uint flags);
+ void update_used_tables();
table_map not_null_tables() const { return 0; }
bool is_null();
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
@@ -1054,7 +1077,7 @@ public:
{
my_qsort2(base,used_count,size,compare,(void*)collation);
}
- int find(Item *item);
+ bool find(Item *item);
/*
Create an instance of Item_{type} (e.g. Item_decimal) constant object
@@ -1222,6 +1245,10 @@ public:
cmp_item() { cmp_charset= &my_charset_bin; }
virtual ~cmp_item() {}
virtual void store_value(Item *item)= 0;
+ /**
+ @returns result (TRUE, FALSE or UNKNOWN) of
+ "stored argument's value <> item's value"
+ */
virtual int cmp(Item *item)= 0;
// for optimized IN with row
virtual int compare(cmp_item *item)= 0;
@@ -1234,7 +1261,14 @@ public:
}
};
-class cmp_item_string :public cmp_item
+/// cmp_item which stores a scalar (i.e. non-ROW).
+class cmp_item_scalar : public cmp_item
+{
+protected:
+ bool m_null_value; ///< If stored value is NULL
+};
+
+class cmp_item_string : public cmp_item_scalar
{
protected:
String *value_res;
@@ -1260,14 +1294,20 @@ public:
void store_value(Item *item)
{
value_res= item->val_str(&value);
+ m_null_value= item->null_value;
}
int cmp(Item *arg)
{
char buff[STRING_BUFFER_USUAL_SIZE];
- String tmp(buff, sizeof(buff), cmp_charset), *res;
- res= arg->val_str(&tmp);
- return (value_res ? (res ? sortcmp(value_res, res, cmp_charset) : 1) :
- (res ? -1 : 0));
+ String tmp(buff, sizeof(buff), cmp_charset), *res= arg->val_str(&tmp);
+ if (m_null_value || arg->null_value)
+ return UNKNOWN;
+ if (value_res && res)
+ return sortcmp(value_res, res, cmp_charset) != 0;
+ else if (!value_res && !res)
+ return FALSE;
+ else
+ return TRUE;
}
int compare(cmp_item *ci)
{
@@ -1282,7 +1322,7 @@ public:
}
};
-class cmp_item_int :public cmp_item
+class cmp_item_int : public cmp_item_scalar
{
longlong value;
public:
@@ -1290,10 +1330,12 @@ public:
void store_value(Item *item)
{
value= item->val_int();
+ m_null_value= item->null_value;
}
int cmp(Item *arg)
{
- return value != arg->val_int();
+ const bool rc= value != arg->val_int();
+ return (m_null_value || arg->null_value) ? UNKNOWN : rc;
}
int compare(cmp_item *ci)
{
@@ -1309,7 +1351,7 @@ public:
If the left item is a constant one then its value is cached in the
lval_cache variable.
*/
-class cmp_item_datetime :public cmp_item
+class cmp_item_datetime : public cmp_item_scalar
{
longlong value;
public:
@@ -1327,7 +1369,7 @@ public:
cmp_item *make_same();
};
-class cmp_item_real :public cmp_item
+class cmp_item_real : public cmp_item_scalar
{
double value;
public:
@@ -1335,10 +1377,12 @@ public:
void store_value(Item *item)
{
value= item->val_real();
+ m_null_value= item->null_value;
}
int cmp(Item *arg)
{
- return value != arg->val_real();
+ const bool rc= value != arg->val_real();
+ return (m_null_value || arg->null_value) ? UNKNOWN : rc;
}
int compare(cmp_item *ci)
{
@@ -1349,7 +1393,7 @@ public:
};
-class cmp_item_decimal :public cmp_item
+class cmp_item_decimal : public cmp_item_scalar
{
my_decimal value;
public:
@@ -1376,12 +1420,13 @@ public:
void store_value(Item *item)
{
value_res= item->val_str(&value);
+ m_null_value= item->null_value;
}
int cmp(Item *item)
{
// Should never be called
- DBUG_ASSERT(0);
- return 1;
+ DBUG_ASSERT(false);
+ return TRUE;
}
int compare(cmp_item *ci)
{
@@ -1442,39 +1487,47 @@ public:
Item *find_item(String *str);
CHARSET_INFO *compare_collation() const { return cmp_collation.collation; }
void cleanup();
- void agg_str_lengths(Item *arg);
- void agg_num_lengths(Item *arg);
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond);
};
/*
- The Item_func_in class implements the in_expr IN(values_list) function.
+ The Item_func_in class implements
+ in_expr IN (<in value list>)
+ and
+ in_expr NOT IN (<in value list>)
The current implementation distinguishes 2 cases:
- 1) all items in the value_list are constants and have the same
+ 1) all items in <in value list> are constants and have the same
result type. This case is handled by in_vector class.
- 2) items in the value_list have different result types or there is some
- non-constant items.
- In this case Item_func_in employs several cmp_item objects to performs
- comparisons of in_expr and an item from the values_list. One cmp_item
+ 2) otherwise Item_func_in employs several cmp_item objects to perform
+ comparisons of in_expr and an item from <in value list>. One cmp_item
object for each result type. Different result types are collected in the
fix_length_and_dec() member function by means of collect_cmp_types()
function.
*/
class Item_func_in :public Item_func_opt_neg
{
+ /**
+ Usable if <in value list> is made only of constants. Returns true if one
+ of these constants contains a NULL. Example:
+ IN ( (-5, (12,NULL)), ... ).
+ */
+ bool list_contains_null();
protected:
SEL_TREE *get_func_mm_tree(RANGE_OPT_PARAM *param,
Field *field, Item *value);
public:
- /*
- an array of values when the right hand arguments of IN
- are all SQL constant and there are no nulls
- */
+ /// An array of values, created when the bisection lookup method is used
in_vector *array;
+ /**
+ If there is some NULL among <in value list>, during a val_int() call; for
+ example
+ IN ( (1,(3,'col')), ... ), where 'col' is a column which evaluates to
+ NULL.
+ */
bool have_null;
- /*
- true when all arguments of the IN clause are of compatible types
+ /**
+ true when all arguments of the IN list are of compatible types
and can be used safely as comparisons for key conditions
*/
bool arg_types_compatible;
@@ -1528,7 +1581,6 @@ public:
virtual void print(String *str, enum_query_type query_type);
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
- bool nulls_in_row();
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);