mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
MDEV-13864 (final) Change Item_func_case to store the predicant in args[0]
This commit is contained in:
@@ -447,3 +447,51 @@ EXECUTE stmt;
|
|||||||
good was_bad_now_good
|
good was_bad_now_good
|
||||||
one one
|
one one
|
||||||
DEALLOCATE PREPARE stmt;
|
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
|
c
|
||||||
NULL
|
NULL
|
||||||
Warnings:
|
Warnings:
|
||||||
Note 1105 DBUG: [0] arg=0 handler=0 (bigint)
|
Note 1105 DBUG: [0] arg=1 handler=0 (bigint)
|
||||||
Note 1105 DBUG: [1] arg=2 handler=1 (decimal)
|
Note 1105 DBUG: [1] arg=3 handler=1 (decimal)
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
#
|
#
|
||||||
# MDEV-11555 CASE with a mixture of TIME and DATETIME returns a wrong result
|
# 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
|
good was_bad_now_good
|
||||||
one one
|
one one
|
||||||
Warnings:
|
Warnings:
|
||||||
Note 1105 DBUG: [0] arg=0 handler=0 (time)
|
Note 1105 DBUG: [0] arg=1 handler=0 (time)
|
||||||
Note 1105 DBUG: [1] arg=2 handler=0 (time)
|
Note 1105 DBUG: [1] arg=3 handler=0 (time)
|
||||||
Note 1105 DBUG: [0] arg=0 handler=0 (time)
|
Note 1105 DBUG: [0] arg=1 handler=0 (time)
|
||||||
Note 1105 DBUG: [1] arg=2 handler=0 (time)
|
Note 1105 DBUG: [1] arg=3 handler=0 (time)
|
||||||
Note 1105 DBUG: [2] arg=4 handler=2 (datetime)
|
Note 1105 DBUG: [2] arg=5 handler=2 (datetime)
|
||||||
SET SESSION debug_dbug="-d,Predicant_to_list_comparator";
|
SET SESSION debug_dbug="-d,Predicant_to_list_comparator";
|
||||||
SET SESSION debug_dbug="-d,Item_func_in";
|
SET SESSION debug_dbug="-d,Item_func_in";
|
||||||
|
@@ -330,3 +330,31 @@ PREPARE stmt FROM "SELECT
|
|||||||
EXECUTE stmt;
|
EXECUTE stmt;
|
||||||
EXECUTE stmt;
|
EXECUTE stmt;
|
||||||
DEALLOCATE PREPARE 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
|
Find and return matching items for CASE or ELSE item if all compares
|
||||||
are failed or NULL if ELSE item isn't defined.
|
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
|
failed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
Item *Item_func_case_searched::find_item()
|
||||||
Item *Item_func_case::find_item_searched()
|
|
||||||
{
|
{
|
||||||
uint count= arg_count / 2;
|
uint count= when_count();
|
||||||
for (uint i= 0 ; i < count ; i++)
|
for (uint i= 0 ; i < count ; i++)
|
||||||
{
|
{
|
||||||
if (args[2 * i]->val_bool())
|
if (args[2 * i]->val_bool())
|
||||||
return args[2 * i + 1];
|
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 */
|
/* Compare every WHEN argument with it and return the first match */
|
||||||
uint idx;
|
uint idx;
|
||||||
if (!Predicant_to_list_comparator::cmp(this, &idx, NULL))
|
if (!Predicant_to_list_comparator::cmp(this, &idx, NULL))
|
||||||
return args[idx + 1];
|
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];
|
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;
|
return TRUE;
|
||||||
|
|
||||||
bool res= Item_func::fix_fields(thd, ref);
|
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;
|
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;
|
bool have_null= false;
|
||||||
uint type_cnt;
|
uint type_cnt;
|
||||||
Type_handler_hybrid_field_type tmp;
|
Type_handler_hybrid_field_type tmp;
|
||||||
add_predicant(this, (uint) first_expr_num);
|
uint ncases= when_count();
|
||||||
for (uint i= 0 ; i < ncases / 2; i++)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
all_values_added(&tmp, &type_cnt, &m_found_types);
|
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;
|
THD *thd= current_thd;
|
||||||
m_found_types= 0;
|
Item **else_ptr= Item_func_case_searched::else_expr_addr();
|
||||||
if (!aggregate_then_and_else_arguments(thd) &&
|
aggregate_then_and_else_arguments(thd, &args[1], when_count(), else_ptr);
|
||||||
first_expr_num != -1)
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
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
|
Aggregate all THEN and ELSE expression types
|
||||||
and collations when string result
|
and collations when string result
|
||||||
|
|
||||||
@param THD - current thd
|
@param THD - current thd
|
||||||
@param offs - the offset of the leftmost THEN argument
|
@param them_expr - the pointer to the leftmost THEN argument in args[]
|
||||||
@paran count - the number or THEN..ELSE pairs
|
@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;
|
Item **agg= arg_buffer;
|
||||||
uint nagg;
|
uint nagg;
|
||||||
|
|
||||||
for (nagg= 0 ; nagg < ncases/2 ; nagg++)
|
for (nagg= 0 ; nagg < count ; nagg++)
|
||||||
agg[nagg]= args[nagg*2+1];
|
agg[nagg]= then_expr[nagg * 2];
|
||||||
|
|
||||||
if (else_expr_num != -1)
|
if (else_expr)
|
||||||
agg[nagg++]= args[else_expr_num];
|
agg[nagg++]= *else_expr;
|
||||||
|
|
||||||
if (aggregate_for_result(func_name(), agg, nagg, true))
|
if (aggregate_for_result(func_name(), agg, nagg, true))
|
||||||
return true;
|
return true;
|
||||||
@@ -3061,14 +3056,14 @@ bool Item_func_case::aggregate_then_and_else_arguments(THD *thd)
|
|||||||
return true;
|
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.
|
Some of the items might have been changed to Item_func_conv_charset.
|
||||||
*/
|
*/
|
||||||
for (nagg= 0 ; nagg < ncases / 2 ; nagg++)
|
for (nagg= 0 ; nagg < count ; nagg++)
|
||||||
change_item_tree_if_needed(thd, &args[nagg * 2 + 1], agg[nagg]);
|
change_item_tree_if_needed(thd, &then_expr[nagg * 2], agg[nagg]);
|
||||||
|
|
||||||
if (else_expr_num != -1)
|
if (else_expr)
|
||||||
change_item_tree_if_needed(thd, &args[else_expr_num], agg[nagg++]);
|
change_item_tree_if_needed(thd, else_expr, agg[nagg++]);
|
||||||
return false;
|
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
|
Aggregate the predicant expression and all WHEN expression types
|
||||||
and collations when string comparison
|
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;
|
Item **agg= arg_buffer;
|
||||||
uint nagg;
|
uint nagg;
|
||||||
|
uint ncases= when_count();
|
||||||
|
m_found_types= 0;
|
||||||
if (prepare_predicant_and_values(thd, &m_found_types))
|
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
|
extract the first expression and all WHEN expressions into
|
||||||
a temporary array, to process them easier.
|
a temporary array, to process them easier.
|
||||||
*/
|
*/
|
||||||
agg[0]= args[first_expr_num]; // The predicant
|
agg[0]= args[0]; // The predicant
|
||||||
for (nagg= 0; nagg < ncases/2 ; nagg++)
|
for (nagg= 0; nagg < ncases ; nagg++)
|
||||||
agg[nagg+1]= args[nagg*2];
|
agg[nagg+1]= args[nagg * 2 + 1];
|
||||||
nagg++;
|
nagg++;
|
||||||
if (!(m_found_types= collect_cmp_types(agg, nagg)))
|
if (!(m_found_types= collect_cmp_types(agg, nagg)))
|
||||||
return true;
|
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
|
arrray, because some of the items might have been changed to converters
|
||||||
(e.g. Item_func_conv_charset, or Item_string for constants).
|
(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++)
|
for (nagg= 0; nagg < ncases; nagg++)
|
||||||
change_item_tree_if_needed(thd, &args[nagg * 2], agg[nagg + 1]);
|
change_item_tree_if_needed(thd, &args[nagg * 2 + 1], agg[nagg + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (make_unique_cmp_items(thd, cmp_collation.collation))
|
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;
|
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++)
|
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
|
CASE ... THEN y1 ... THEN y2 ... THEN y3 ... ELSE y4 END
|
||||||
*/
|
*/
|
||||||
Item *new_item= 0;
|
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
|
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),
|
cmp_collation.collation),
|
||||||
cond);
|
cond);
|
||||||
}
|
}
|
||||||
else if ((i % 2) == 0) // WHEN arguments
|
else if ((i % 2) == 1 && i != arg_count - 1) // WHEN arguments
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
These arguments are in comparison.
|
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 "));
|
str->append(STRING_WITH_LEN("case "));
|
||||||
if (first_expr_num != -1)
|
print_when_then_arguments(str, query_type, &args[0], when_count());
|
||||||
{
|
if ((pos= Item_func_case_searched::else_expr_addr()))
|
||||||
args[first_expr_num]->print_parenthesised(str, query_type, precedence());
|
print_else_argument(str, query_type, pos[0]);
|
||||||
str->append(' ');
|
str->append(STRING_WITH_LEN("end"));
|
||||||
}
|
}
|
||||||
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]);
|
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"));
|
str->append(STRING_WITH_LEN("end"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2016,79 +2016,129 @@ public:
|
|||||||
/*
|
/*
|
||||||
The class Item_func_case is the CASE ... WHEN ... THEN ... END function
|
The class Item_func_case is the CASE ... WHEN ... THEN ... END function
|
||||||
implementation.
|
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,
|
class Item_func_case :public Item_func_case_expression
|
||||||
public Predicant_to_list_comparator
|
|
||||||
{
|
{
|
||||||
int first_expr_num, else_expr_num;
|
protected:
|
||||||
String tmp_value;
|
String tmp_value;
|
||||||
uint ncases;
|
|
||||||
DTCollation cmp_collation;
|
DTCollation cmp_collation;
|
||||||
Item **arg_buffer;
|
Item **arg_buffer;
|
||||||
uint m_found_types;
|
bool aggregate_then_and_else_arguments(THD *thd,
|
||||||
bool prepare_predicant_and_values(THD *thd, uint *found_types);
|
Item **items, uint count,
|
||||||
bool aggregate_then_and_else_arguments(THD *thd);
|
Item **else_expr);
|
||||||
bool aggregate_switch_and_when_arguments(THD *thd);
|
virtual Item **else_expr_addr() const= 0;
|
||||||
Item *find_item_searched();
|
virtual Item *find_item()= 0;
|
||||||
Item *find_item_simple();
|
|
||||||
Item *find_item()
|
|
||||||
{
|
|
||||||
return first_expr_num == -1 ? find_item_searched() : find_item_simple();
|
|
||||||
}
|
|
||||||
void print_when_then_arguments(String *str, enum_query_type query_type,
|
void print_when_then_arguments(String *str, enum_query_type query_type,
|
||||||
Item **items, uint count);
|
Item **items, uint count);
|
||||||
void print_else_argument(String *str, enum_query_type query_type, Item *item);
|
void print_else_argument(String *str, enum_query_type query_type, Item *item);
|
||||||
public:
|
public:
|
||||||
Item_func_case(THD *thd, List<Item> &list, Item *first_expr_arg,
|
Item_func_case(THD *thd, List<Item> &list)
|
||||||
Item *else_expr_arg);
|
:Item_func_case_expression(thd, list)
|
||||||
|
{ }
|
||||||
double real_op();
|
double real_op();
|
||||||
longlong int_op();
|
longlong int_op();
|
||||||
String *str_op(String *);
|
String *str_op(String *);
|
||||||
my_decimal *decimal_op(my_decimal *);
|
my_decimal *decimal_op(my_decimal *);
|
||||||
bool date_op(MYSQL_TIME *ltime, uint fuzzydate);
|
bool date_op(MYSQL_TIME *ltime, uint fuzzydate);
|
||||||
bool fix_fields(THD *thd, Item **ref);
|
bool fix_fields(THD *thd, Item **ref);
|
||||||
void fix_length_and_dec();
|
|
||||||
table_map not_null_tables() const { return 0; }
|
table_map not_null_tables() const { return 0; }
|
||||||
const char *func_name() const { return "case"; }
|
const char *func_name() const { return "case"; }
|
||||||
enum precedence precedence() const { return BETWEEN_PRECEDENCE; }
|
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; }
|
CHARSET_INFO *compare_collation() const { return cmp_collation.collation; }
|
||||||
void cleanup()
|
|
||||||
{
|
|
||||||
DBUG_ENTER("Item_func_case::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; }
|
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); }
|
|
||||||
Item *build_clone(THD *thd, MEM_ROOT *mem_root)
|
Item *build_clone(THD *thd, MEM_ROOT *mem_root)
|
||||||
{
|
{
|
||||||
Item_func_case *clone= (Item_func_case *) Item_func::build_clone(thd, mem_root);
|
Item_func_case *clone= (Item_func_case *) Item_func::build_clone(thd, mem_root);
|
||||||
if (clone)
|
if (clone)
|
||||||
{
|
|
||||||
clone->arg_buffer= 0;
|
clone->arg_buffer= 0;
|
||||||
if (clone->Predicant_to_list_comparator::init_clone(thd, ncases))
|
return clone;
|
||||||
return NULL;
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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_simple::cleanup");
|
||||||
|
Item_func::cleanup();
|
||||||
|
Predicant_to_list_comparator::cleanup();
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
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_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;
|
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>
|
%type <item>
|
||||||
literal text_literal insert_ident order_ident temporal_literal
|
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
|
variable variable_aux bool_pri
|
||||||
predicate bit_expr parenthesized_expr
|
predicate bit_expr parenthesized_expr
|
||||||
table_wild simple_expr column_default_non_parenthesized_expr udf_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
|
NUM_literal
|
||||||
|
|
||||||
%type <item_list>
|
%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
|
ident_list ident_list_arg opt_expr_list
|
||||||
|
|
||||||
%type <sp_cursor_stmt>
|
%type <sp_cursor_stmt>
|
||||||
@@ -9419,10 +9419,15 @@ column_default_non_parenthesized_expr:
|
|||||||
if (!($$= $5.create_typecast_item(thd, $3, Lex->charset)))
|
if (!($$= $5.create_typecast_item(thd, $3, Lex->charset)))
|
||||||
MYSQL_YYABORT;
|
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 (!($$= new(thd->mem_root) Item_func_case_searched(thd, *$2)))
|
||||||
if ($$ == NULL)
|
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;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
| CONVERT_SYM '(' expr ',' cast_type ')'
|
| 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_list:
|
||||||
WHEN_SYM expr THEN_SYM expr
|
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. */
|
/* Equivalent to <table reference> in the SQL:2003 standard. */
|
||||||
/* Warning - may return NULL in case of incomplete SELECT */
|
/* Warning - may return NULL in case of incomplete SELECT */
|
||||||
table_ref:
|
table_ref:
|
||||||
|
@@ -1133,7 +1133,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
|||||||
|
|
||||||
%type <item>
|
%type <item>
|
||||||
literal text_literal insert_ident order_ident temporal_literal
|
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
|
variable variable_aux bool_pri
|
||||||
predicate bit_expr parenthesized_expr
|
predicate bit_expr parenthesized_expr
|
||||||
table_wild simple_expr column_default_non_parenthesized_expr udf_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
|
NUM_literal
|
||||||
|
|
||||||
%type <item_list>
|
%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
|
ident_list ident_list_arg opt_expr_list
|
||||||
decode_when_list
|
decode_when_list
|
||||||
|
|
||||||
@@ -9440,10 +9440,15 @@ column_default_non_parenthesized_expr:
|
|||||||
if (!($$= $5.create_typecast_item(thd, $3, Lex->charset)))
|
if (!($$= $5.create_typecast_item(thd, $3, Lex->charset)))
|
||||||
MYSQL_YYABORT;
|
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 (!($$= new(thd->mem_root) Item_func_case_searched(thd, *$2)))
|
||||||
if ($$ == NULL)
|
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;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
| CONVERT_SYM '(' expr ',' cast_type ')'
|
| CONVERT_SYM '(' expr ',' cast_type ')'
|
||||||
@@ -9459,32 +9464,8 @@ column_default_non_parenthesized_expr:
|
|||||||
}
|
}
|
||||||
| DECODE_SYM '(' expr ',' decode_when_list ')'
|
| DECODE_SYM '(' expr ',' decode_when_list ')'
|
||||||
{
|
{
|
||||||
if (($5->elements % 2) == 0)
|
$5->push_front($3, thd->mem_root);
|
||||||
{
|
if (!($$= new (thd->mem_root) Item_func_case_simple(thd, *$5)))
|
||||||
// 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)
|
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
| DEFAULT '(' simple_ident ')'
|
| 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_list:
|
||||||
WHEN_SYM expr THEN_SYM expr
|
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:
|
decode_when_list:
|
||||||
expr ',' expr
|
expr ',' expr
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user