Commit c39a7446 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-13864 (final) Change Item_func_case to store the predicant in args[0]

parent e12390a3
......@@ -447,3 +447,51 @@ EXECUTE stmt;
good was_bad_now_good
one one
DEALLOCATE PREPARE stmt;
#
# MDEV-13864 Change Item_func_case to store the predicant in args[0]
#
SET NAMES latin1;
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1);
INSERT INTO t1 VALUES ('a'),('b'),('c');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE a WHEN 'a' THEN 'a' ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN a THEN 'a' ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN a ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a' and (case 'a' when 'a' then `test`.`t1`.`a` else 'a' end) = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN 'a' ELSE a END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a' and (case 'a' when 'a' then 'a' else `test`.`t1`.`a` end) = 'a'
ALTER TABLE t1 MODIFY a VARBINARY(10);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE a WHEN 'a' THEN 'a' ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN a THEN 'a' ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN a ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN 'a' ELSE a END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
DROP TABLE t1;
......@@ -1629,8 +1629,8 @@ WHEN -9223372036854775808 THEN 'one'
c
NULL
Warnings:
Note 1105 DBUG: [0] arg=0 handler=0 (bigint)
Note 1105 DBUG: [1] arg=2 handler=1 (decimal)
Note 1105 DBUG: [0] arg=1 handler=0 (bigint)
Note 1105 DBUG: [1] arg=3 handler=1 (decimal)
DROP TABLE t1;
#
# MDEV-11555 CASE with a mixture of TIME and DATETIME returns a wrong result
......@@ -1648,10 +1648,10 @@ CASE TIME'10:20:30'
good was_bad_now_good
one one
Warnings:
Note 1105 DBUG: [0] arg=0 handler=0 (time)
Note 1105 DBUG: [1] arg=2 handler=0 (time)
Note 1105 DBUG: [0] arg=0 handler=0 (time)
Note 1105 DBUG: [1] arg=2 handler=0 (time)
Note 1105 DBUG: [2] arg=4 handler=2 (datetime)
Note 1105 DBUG: [0] arg=1 handler=0 (time)
Note 1105 DBUG: [1] arg=3 handler=0 (time)
Note 1105 DBUG: [0] arg=1 handler=0 (time)
Note 1105 DBUG: [1] arg=3 handler=0 (time)
Note 1105 DBUG: [2] arg=5 handler=2 (datetime)
SET SESSION debug_dbug="-d,Predicant_to_list_comparator";
SET SESSION debug_dbug="-d,Item_func_in";
......@@ -330,3 +330,31 @@ PREPARE stmt FROM "SELECT
EXECUTE stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
--echo #
--echo # MDEV-13864 Change Item_func_case to store the predicant in args[0]
--echo #
SET NAMES latin1;
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1);
INSERT INTO t1 VALUES ('a'),('b'),('c');
# should propagate the predicant and the WHEN arguments (they are in comparison and use ANY_SUBST)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE a WHEN 'a' THEN 'a' ELSE 'a' END='a';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN a THEN 'a' ELSE 'a' END='a';
# should not propagate the THEN and the ELSE arguments (they are not in comparison and use IDENTITY_SUBST)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN a ELSE 'a' END='a';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN 'a' ELSE a END='a';
ALTER TABLE t1 MODIFY a VARBINARY(10);
# with VARBINARY it should propagate all arguments
# as IDENTITY_SUBST for VARBINARY allows substitution
# of even those arguments that are not in comparison
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE a WHEN 'a' THEN 'a' ELSE 'a' END='a';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN a THEN 'a' ELSE 'a' END='a';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN a ELSE 'a' END='a';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN 'a' ELSE a END='a';
DROP TABLE t1;
......@@ -2814,27 +2814,6 @@ Item_func_nullif::is_null()
}
Item_func_case::Item_func_case(THD *thd, List<Item> &list,
Item *first_expr_arg, Item *else_expr_arg):
Item_func_case_expression(thd),
Predicant_to_list_comparator(thd, list.elements/*QQ*/),
first_expr_num(-1), else_expr_num(-1),
m_found_types(0)
{
ncases= list.elements;
if (first_expr_arg)
{
first_expr_num= list.elements;
list.push_back(first_expr_arg, thd->mem_root);
}
if (else_expr_arg)
{
else_expr_num= list.elements;
list.push_back(else_expr_arg, thd->mem_root);
}
set_arguments(thd, list);
}
/**
Find and return matching items for CASE or ELSE item if all compares
are failed or NULL if ELSE item isn't defined.
......@@ -2856,26 +2835,27 @@ Item_func_case::Item_func_case(THD *thd, List<Item> &list,
failed
*/
Item *Item_func_case::find_item_searched()
Item *Item_func_case_searched::find_item()
{
uint count= arg_count / 2;
uint count= when_count();
for (uint i= 0 ; i < count ; i++)
{
if (args[2 * i]->val_bool())
return args[2 * i + 1];
}
return else_expr_num != -1 ? args[else_expr_num] : 0;
Item **pos= Item_func_case_searched::else_expr_addr();
return pos ? pos[0] : 0;
}
Item *Item_func_case::find_item_simple()
Item *Item_func_case_simple::find_item()
{
/* Compare every WHEN argument with it and return the first match */
uint idx;
if (!Predicant_to_list_comparator::cmp(this, &idx, NULL))
return args[idx + 1];
return else_expr_num != -1 ? args[else_expr_num] : 0;
Item **pos= Item_func_case_simple::else_expr_addr();
return pos ? pos[0] : 0;
}
......@@ -2966,12 +2946,13 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref)
*/
uchar buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2];
if (!(arg_buffer= (Item**) thd->alloc(sizeof(Item*)*(ncases+1))))
if (!(arg_buffer= (Item**) thd->alloc(sizeof(Item*)*(arg_count))))
return TRUE;
bool res= Item_func::fix_fields(thd, ref);
if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
Item **pos= else_expr_addr();
if (!pos || pos[0]->maybe_null)
maybe_null= 1;
/*
......@@ -3006,15 +2987,17 @@ static void change_item_tree_if_needed(THD *thd,
}
bool Item_func_case::prepare_predicant_and_values(THD *thd, uint *found_types)
bool Item_func_case_simple::prepare_predicant_and_values(THD *thd,
uint *found_types)
{
bool have_null= false;
uint type_cnt;
Type_handler_hybrid_field_type tmp;
add_predicant(this, (uint) first_expr_num);
for (uint i= 0 ; i < ncases / 2; i++)
uint ncases= when_count();
add_predicant(this, 0);
for (uint i= 0 ; i < ncases; i++)
{
if (add_value_skip_null("case..when", this, i * 2, &have_null))
if (add_value_skip_null("case..when", this, i * 2 + 1, &have_null))
return true;
}
all_values_added(&tmp, &type_cnt, &m_found_types);
......@@ -3025,12 +3008,19 @@ bool Item_func_case::prepare_predicant_and_values(THD *thd, uint *found_types)
}
void Item_func_case::fix_length_and_dec()
void Item_func_case_searched::fix_length_and_dec()
{
THD *thd= current_thd;
m_found_types= 0;
if (!aggregate_then_and_else_arguments(thd) &&
first_expr_num != -1)
Item **else_ptr= Item_func_case_searched::else_expr_addr();
aggregate_then_and_else_arguments(thd, &args[1], when_count(), else_ptr);
}
void Item_func_case_simple::fix_length_and_dec()
{
THD *thd= current_thd;
Item **else_ptr= Item_func_case_simple::else_expr_addr();
if (!aggregate_then_and_else_arguments(thd, &args[2], when_count(), else_ptr))
aggregate_switch_and_when_arguments(thd);
}
......@@ -3039,20 +3029,25 @@ void Item_func_case::fix_length_and_dec()
Aggregate all THEN and ELSE expression types
and collations when string result
@param THD - current thd
@param offs - the offset of the leftmost THEN argument
@paran count - the number or THEN..ELSE pairs
@param THD - current thd
@param them_expr - the pointer to the leftmost THEN argument in args[]
@param count - the number or THEN..ELSE pairs
@param else_epxr - the pointer to the ELSE arguments in args[]
(or NULL is there is not ELSE)
*/
bool Item_func_case::aggregate_then_and_else_arguments(THD *thd)
bool Item_func_case::aggregate_then_and_else_arguments(THD *thd,
Item **then_expr,
uint count,
Item **else_expr)
{
Item **agg= arg_buffer;
uint nagg;
for (nagg= 0 ; nagg < ncases/2 ; nagg++)
agg[nagg]= args[nagg*2+1];
for (nagg= 0 ; nagg < count ; nagg++)
agg[nagg]= then_expr[nagg * 2];
if (else_expr_num != -1)
agg[nagg++]= args[else_expr_num];
if (else_expr)
agg[nagg++]= *else_expr;
if (aggregate_for_result(func_name(), agg, nagg, true))
return true;
......@@ -3061,14 +3056,14 @@ bool Item_func_case::aggregate_then_and_else_arguments(THD *thd)
return true;
/*
Copy all modified THEN and ELSE items back to args[] array.
Copy all modified THEN and ELSE items back to then_expr[] array.
Some of the items might have been changed to Item_func_conv_charset.
*/
for (nagg= 0 ; nagg < ncases / 2 ; nagg++)
change_item_tree_if_needed(thd, &args[nagg * 2 + 1], agg[nagg]);
for (nagg= 0 ; nagg < count ; nagg++)
change_item_tree_if_needed(thd, &then_expr[nagg * 2], agg[nagg]);
if (else_expr_num != -1)
change_item_tree_if_needed(thd, &args[else_expr_num], agg[nagg++]);
if (else_expr)
change_item_tree_if_needed(thd, else_expr, agg[nagg++]);
return false;
}
......@@ -3077,10 +3072,12 @@ bool Item_func_case::aggregate_then_and_else_arguments(THD *thd)
Aggregate the predicant expression and all WHEN expression types
and collations when string comparison
*/
bool Item_func_case::aggregate_switch_and_when_arguments(THD *thd)
bool Item_func_case_simple::aggregate_switch_and_when_arguments(THD *thd)
{
Item **agg= arg_buffer;
uint nagg;
uint ncases= when_count();
m_found_types= 0;
if (prepare_predicant_and_values(thd, &m_found_types))
{
/*
......@@ -3098,9 +3095,9 @@ bool Item_func_case::aggregate_switch_and_when_arguments(THD *thd)
extract the first expression and all WHEN expressions into
a temporary array, to process them easier.
*/
agg[0]= args[first_expr_num]; // The predicant
for (nagg= 0; nagg < ncases/2 ; nagg++)
agg[nagg+1]= args[nagg*2];
agg[0]= args[0]; // The predicant
for (nagg= 0; nagg < ncases ; nagg++)
agg[nagg+1]= args[nagg * 2 + 1];
nagg++;
if (!(m_found_types= collect_cmp_types(agg, nagg)))
return true;
......@@ -3138,10 +3135,10 @@ bool Item_func_case::aggregate_switch_and_when_arguments(THD *thd)
arrray, because some of the items might have been changed to converters
(e.g. Item_func_conv_charset, or Item_string for constants).
*/
change_item_tree_if_needed(thd, &args[first_expr_num], agg[0]);
change_item_tree_if_needed(thd, &args[0], agg[0]);
for (nagg= 0; nagg < ncases / 2; nagg++)
change_item_tree_if_needed(thd, &args[nagg * 2], agg[nagg + 1]);
for (nagg= 0; nagg < ncases; nagg++)
change_item_tree_if_needed(thd, &args[nagg * 2 + 1], agg[nagg + 1]);
}
if (make_unique_cmp_items(thd, cmp_collation.collation))
......@@ -3151,17 +3148,13 @@ bool Item_func_case::aggregate_switch_and_when_arguments(THD *thd)
}
Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
Item* Item_func_case_simple::propagate_equal_fields(THD *thd,
const Context &ctx,
COND_EQUAL *cond)
{
const Type_handler *first_expr_cmp_handler;
if (first_expr_num == -1)
{
// None of the arguments are in a comparison context
Item_args::propagate_equal_fields(thd, Context_identity(), cond);
return this;
}
first_expr_cmp_handler= args[first_expr_num]->type_handler_for_comparison();
first_expr_cmp_handler= args[0]->type_handler_for_comparison();
for (uint i= 0; i < arg_count; i++)
{
/*
......@@ -3171,7 +3164,7 @@ Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_
CASE ... THEN y1 ... THEN y2 ... THEN y3 ... ELSE y4 END
*/
Item *new_item= 0;
if ((int) i == first_expr_num) // Then CASE (the switch) argument
if (i == 0) // Then CASE (the switch) argument
{
/*
Cannot replace the CASE (the switch) argument if
......@@ -3208,7 +3201,7 @@ Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_
cmp_collation.collation),
cond);
}
else if ((i % 2) == 0) // WHEN arguments
else if ((i % 2) == 1 && i != arg_count - 1) // WHEN arguments
{
/*
These arguments are in comparison.
......@@ -3262,17 +3255,26 @@ void Item_func_case::print_else_argument(String *str,
}
void Item_func_case::print(String *str, enum_query_type query_type)
void Item_func_case_searched::print(String *str, enum_query_type query_type)
{
Item **pos;
str->append(STRING_WITH_LEN("case "));
if (first_expr_num != -1)
{
args[first_expr_num]->print_parenthesised(str, query_type, precedence());
str->append(' ');
}
print_when_then_arguments(str, query_type, &args[0], ncases / 2);
if (else_expr_num != -1)
print_else_argument(str, query_type, args[else_expr_num]);
print_when_then_arguments(str, query_type, &args[0], when_count());
if ((pos= Item_func_case_searched::else_expr_addr()))
print_else_argument(str, query_type, pos[0]);
str->append(STRING_WITH_LEN("end"));
}
void Item_func_case_simple::print(String *str, enum_query_type query_type)
{
Item **pos;
str->append(STRING_WITH_LEN("case "));
args[0]->print_parenthesised(str, query_type, precedence());
str->append(' ');
print_when_then_arguments(str, query_type, &args[1], when_count());
if ((pos= Item_func_case_simple::else_expr_addr()))
print_else_argument(str, query_type, pos[0]);
str->append(STRING_WITH_LEN("end"));
}
......
......@@ -2016,79 +2016,129 @@ class Predicant_to_list_comparator
/*
The class Item_func_case is the CASE ... WHEN ... THEN ... END function
implementation.
When there is no expression between CASE and the first WHEN
(the CASE expression) then this function simple checks all WHEN expressions
one after another. When some WHEN expression evaluated to TRUE then the
value of the corresponding THEN expression is returned.
When the CASE expression is specified then it is compared to each WHEN
expression individually. When an equal WHEN expression is found
corresponding THEN expression is returned.
In order to do correct comparisons several comparators are used. One for
each result type. Different result types that are used in particular
CASE ... END expression are collected in the fix_length_and_dec() member
function and only comparators for there result types are used.
*/
class Item_func_case :public Item_func_case_expression,
public Predicant_to_list_comparator
class Item_func_case :public Item_func_case_expression
{
int first_expr_num, else_expr_num;
protected:
String tmp_value;
uint ncases;
DTCollation cmp_collation;
Item **arg_buffer;
uint m_found_types;
bool prepare_predicant_and_values(THD *thd, uint *found_types);
bool aggregate_then_and_else_arguments(THD *thd);
bool aggregate_switch_and_when_arguments(THD *thd);
Item *find_item_searched();
Item *find_item_simple();
Item *find_item()
{
return first_expr_num == -1 ? find_item_searched() : find_item_simple();
}
bool aggregate_then_and_else_arguments(THD *thd,
Item **items, uint count,
Item **else_expr);
virtual Item **else_expr_addr() const= 0;
virtual Item *find_item()= 0;
void print_when_then_arguments(String *str, enum_query_type query_type,
Item **items, uint count);
void print_else_argument(String *str, enum_query_type query_type, Item *item);
public:
Item_func_case(THD *thd, List<Item> &list, Item *first_expr_arg,
Item *else_expr_arg);
Item_func_case(THD *thd, List<Item> &list)
:Item_func_case_expression(thd, list)
{ }
double real_op();
longlong int_op();
String *str_op(String *);
my_decimal *decimal_op(my_decimal *);
bool date_op(MYSQL_TIME *ltime, uint fuzzydate);
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
table_map not_null_tables() const { return 0; }
const char *func_name() const { return "case"; }
enum precedence precedence() const { return BETWEEN_PRECEDENCE; }
virtual void print(String *str, enum_query_type query_type);
CHARSET_INFO *compare_collation() const { return cmp_collation.collation; }
bool need_parentheses_in_default() { return true; }
Item *build_clone(THD *thd, MEM_ROOT *mem_root)
{
Item_func_case *clone= (Item_func_case *) Item_func::build_clone(thd, mem_root);
if (clone)
clone->arg_buffer= 0;
return clone;
}
};
/*
CASE WHEN cond THEN res [WHEN cond THEN res...] [ELSE res] END
Searched CASE checks all WHEN expressions one after another.
When some WHEN expression evaluated to TRUE then the
value of the corresponding THEN expression is returned.
*/
class Item_func_case_searched: public Item_func_case
{
uint when_count() const { return arg_count / 2; }
bool with_else() const { return arg_count % 2; }
Item **else_expr_addr() const { return with_else() ? &args[arg_count - 1] : 0; }
public:
Item_func_case_searched(THD *thd, List<Item> &list)
:Item_func_case(thd, list)
{
DBUG_ASSERT(arg_count >= 2);
}
void print(String *str, enum_query_type query_type);
void fix_length_and_dec();
Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{
// None of the arguments are in a comparison context
Item_args::propagate_equal_fields(thd, Context_identity(), cond);
return this;
}
Item *find_item();
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_case_searched>(thd, mem_root, this); }
};
/*
CASE pred WHEN value THEN res [WHEN value THEN res...] [ELSE res] END
When the predicant expression is specified then it is compared to each WHEN
expression individually. When an equal WHEN expression is found
the corresponding THEN expression is returned.
In order to do correct comparisons several comparators are used. One for
each result type. Different result types that are used in particular
CASE ... END expression are collected in the fix_length_and_dec() member
function and only comparators for there result types are used.
*/
class Item_func_case_simple: public Item_func_case,
public Predicant_to_list_comparator
{
uint m_found_types;
uint when_count() const { return (arg_count - 1) / 2; }
bool with_else() const { return arg_count % 2 == 0; }
Item **else_expr_addr() const { return with_else() ? &args[arg_count - 1] : 0; }
bool aggregate_switch_and_when_arguments(THD *thd);
bool prepare_predicant_and_values(THD *thd, uint *found_types);
public:
Item_func_case_simple(THD *thd, List<Item> &list)
:Item_func_case(thd, list),
Predicant_to_list_comparator(thd, arg_count),
m_found_types(0)
{
DBUG_ASSERT(arg_count >= 3);
}
void cleanup()
{
DBUG_ENTER("Item_func_case::cleanup");
DBUG_ENTER("Item_func_case_simple::cleanup");
Item_func::cleanup();
Predicant_to_list_comparator::cleanup();
DBUG_VOID_RETURN;
}
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond);
bool need_parentheses_in_default() { return true; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_case>(thd, mem_root, this); }
void print(String *str, enum_query_type query_type);
void fix_length_and_dec();
Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond);
Item *find_item();
Item *build_clone(THD *thd, MEM_ROOT *mem_root)
{
Item_func_case *clone= (Item_func_case *) Item_func::build_clone(thd, mem_root);
if (clone)
{
clone->arg_buffer= 0;
if (clone->Predicant_to_list_comparator::init_clone(thd, ncases))
return NULL;
}
Item_func_case_simple *clone= (Item_func_case_simple *)
Item_func_case::build_clone(thd, mem_root);
uint ncases= when_count();
if (clone && clone->Predicant_to_list_comparator::init_clone(thd, ncases))
return NULL;
return clone;
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_case_simple>(thd, mem_root, this); }
};
......
......@@ -1716,7 +1716,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <item>
literal text_literal insert_ident order_ident temporal_literal
simple_ident expr opt_expr opt_else sum_expr in_sum_expr
simple_ident expr sum_expr in_sum_expr
variable variable_aux bool_pri
predicate bit_expr parenthesized_expr
table_wild simple_expr column_default_non_parenthesized_expr udf_expr
......@@ -1744,7 +1744,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
NUM_literal
%type <item_list>
expr_list opt_udf_expr_list udf_expr_list when_list
expr_list opt_udf_expr_list udf_expr_list when_list when_list_opt_else
ident_list ident_list_arg opt_expr_list
%type <sp_cursor_stmt>
......@@ -9419,10 +9419,15 @@ column_default_non_parenthesized_expr:
if (!($$= $5.create_typecast_item(thd, $3, Lex->charset)))
MYSQL_YYABORT;
}
| CASE_SYM opt_expr when_list opt_else END
| CASE_SYM when_list_opt_else END
{
$$= new (thd->mem_root) Item_func_case(thd, *$3, $2, $4);
if ($$ == NULL)
if (!($$= new(thd->mem_root) Item_func_case_searched(thd, *$2)))
MYSQL_YYABORT;
}
| CASE_SYM expr when_list_opt_else END
{
$3->push_front($2, thd->mem_root);
if (!($$= new (thd->mem_root) Item_func_case_simple(thd, *$3)))
MYSQL_YYABORT;
}
| CONVERT_SYM '(' expr ',' cast_type ')'
......@@ -10844,16 +10849,6 @@ ident_list:
}
;
opt_expr:
/* empty */ { $$= NULL; }
| expr { $$= $1; }
;
opt_else:
/* empty */ { $$= NULL; }
| ELSE expr { $$= $2; }
;
when_list:
WHEN_SYM expr THEN_SYM expr
{
......@@ -10871,6 +10866,15 @@ when_list:
}
;
when_list_opt_else:
when_list
| when_list ELSE expr
{
$1->push_back($3, thd->mem_root);
$$= $1;
}
;
/* Equivalent to <table reference> in the SQL:2003 standard. */
/* Warning - may return NULL in case of incomplete SELECT */
table_ref:
......
......@@ -1133,7 +1133,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <item>
literal text_literal insert_ident order_ident temporal_literal
simple_ident expr opt_expr opt_else sum_expr in_sum_expr
simple_ident expr sum_expr in_sum_expr
variable variable_aux bool_pri
predicate bit_expr parenthesized_expr
table_wild simple_expr column_default_non_parenthesized_expr udf_expr
......@@ -1163,7 +1163,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
NUM_literal
%type <item_list>
expr_list opt_udf_expr_list udf_expr_list when_list
expr_list opt_udf_expr_list udf_expr_list when_list when_list_opt_else
ident_list ident_list_arg opt_expr_list
decode_when_list
......@@ -9440,10 +9440,15 @@ column_default_non_parenthesized_expr:
if (!($$= $5.create_typecast_item(thd, $3, Lex->charset)))
MYSQL_YYABORT;
}
| CASE_SYM opt_expr when_list opt_else END
| CASE_SYM when_list_opt_else END
{
$$= new (thd->mem_root) Item_func_case(thd, *$3, $2, $4);
if ($$ == NULL)
if (!($$= new(thd->mem_root) Item_func_case_searched(thd, *$2)))
MYSQL_YYABORT;
}
| CASE_SYM expr when_list_opt_else END
{
$3->push_front($2, thd->mem_root);
if (!($$= new (thd->mem_root) Item_func_case_simple(thd, *$3)))
MYSQL_YYABORT;
}
| CONVERT_SYM '(' expr ',' cast_type ')'
......@@ -9459,32 +9464,8 @@ column_default_non_parenthesized_expr:
}
| DECODE_SYM '(' expr ',' decode_when_list ')'
{
if (($5->elements % 2) == 0)
{
// No default expression
$$= new (thd->mem_root) Item_func_case(thd, *$5, $3, NULL);
}
else
{
/*
There is a default expression at the end of the list $5.
Create a new list without the default expression.
*/
List<Item> tmp;
List_iterator_fast<Item> it(*$5);
for (uint i= 0; i < $5->elements - 1; i++) // copy all but last
{
Item *item= it++;
tmp.push_back(item);
}
/*
Now the new list "tmp" contains only WHEN-THEN pairs,
The default expression is pointed by the iterator "it"
and will be returned by the next call for it++ below.
*/
$$= new (thd->mem_root) Item_func_case(thd, tmp, $3, it++);
}
if ($$ == NULL)
$5->push_front($3, thd->mem_root);
if (!($$= new (thd->mem_root) Item_func_case_simple(thd, *$5)))
MYSQL_YYABORT;
}
| DEFAULT '(' simple_ident ')'
......@@ -10907,16 +10888,6 @@ ident_list:
}
;
opt_expr:
/* empty */ { $$= NULL; }
| expr { $$= $1; }
;
opt_else:
/* empty */ { $$= NULL; }
| ELSE expr { $$= $2; }
;
when_list:
WHEN_SYM expr THEN_SYM expr
{
......@@ -10935,6 +10906,15 @@ when_list:
;
when_list_opt_else:
when_list
| when_list ELSE expr
{
$1->push_back($3, thd->mem_root);
$$= $1;
}
;
decode_when_list:
expr ',' expr
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment