mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
cleanup: Item_func_case
reorder items in args[] array. Instead of
when1,then1,when2,then2,...[,case][,else]
sort them as
[case,]when1,when2,...,then1,then2,...[,else]
in this case all items used for comparison take a continuous part
of the array and can be aggregated directly. and all items that
can be returned take a continuous part of the array and can be
aggregated directly. Old code had to copy them to a temporary
array before aggreation, and then copy back (thd->change_item_tree)
everything that was changed.
this is a 10.3 version of bf1ca14ff3
This commit is contained in:
@ -1630,7 +1630,7 @@ c
|
|||||||
NULL
|
NULL
|
||||||
Warnings:
|
Warnings:
|
||||||
Note 1105 DBUG: [0] arg=1 handler=0 (bigint)
|
Note 1105 DBUG: [0] arg=1 handler=0 (bigint)
|
||||||
Note 1105 DBUG: [1] arg=3 handler=1 (decimal)
|
Note 1105 DBUG: [1] arg=2 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
|
||||||
@ -1649,9 +1649,9 @@ good was_bad_now_good
|
|||||||
one one
|
one one
|
||||||
Warnings:
|
Warnings:
|
||||||
Note 1105 DBUG: [0] arg=1 handler=0 (time)
|
Note 1105 DBUG: [0] arg=1 handler=0 (time)
|
||||||
Note 1105 DBUG: [1] arg=3 handler=0 (time)
|
Note 1105 DBUG: [1] arg=2 handler=0 (time)
|
||||||
Note 1105 DBUG: [0] arg=1 handler=0 (time)
|
Note 1105 DBUG: [0] arg=1 handler=0 (time)
|
||||||
Note 1105 DBUG: [1] arg=3 handler=0 (time)
|
Note 1105 DBUG: [1] arg=2 handler=0 (time)
|
||||||
Note 1105 DBUG: [2] arg=5 handler=2 (datetime)
|
Note 1105 DBUG: [2] arg=3 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";
|
||||||
|
@ -2890,6 +2890,28 @@ Item_func_nullif::is_null()
|
|||||||
return (null_value= (!compare() ? 1 : args[2]->null_value));
|
return (null_value= (!compare() ? 1 : args[2]->null_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Item_func_case::reorder_args(uint start)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Reorder args, to have at first the optional CASE expression, then all WHEN
|
||||||
|
expressions, then all THEN expressions. And the optional ELSE expression
|
||||||
|
at the end.
|
||||||
|
|
||||||
|
We reorder an even number of arguments, starting from start.
|
||||||
|
*/
|
||||||
|
uint count = (arg_count - start) / 2;
|
||||||
|
const size_t size= sizeof(Item*) * count * 2;
|
||||||
|
Item **arg_buffer= (Item **)my_safe_alloca(size);
|
||||||
|
memcpy(arg_buffer, &args[start], size);
|
||||||
|
for (uint i= 0; i < count; i++)
|
||||||
|
{
|
||||||
|
args[start + i]= arg_buffer[i*2];
|
||||||
|
args[start + i + count]= arg_buffer[i*2 + 1];
|
||||||
|
}
|
||||||
|
my_safe_afree(arg_buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
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
|
||||||
@ -2917,8 +2939,8 @@ Item *Item_func_case_searched::find_item()
|
|||||||
uint count= when_count();
|
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[i]->val_bool())
|
||||||
return args[2 * i + 1];
|
return args[i + count];
|
||||||
}
|
}
|
||||||
Item **pos= Item_func_case_searched::else_expr_addr();
|
Item **pos= Item_func_case_searched::else_expr_addr();
|
||||||
return pos ? pos[0] : 0;
|
return pos ? pos[0] : 0;
|
||||||
@ -2930,7 +2952,7 @@ 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 + when_count()];
|
||||||
Item **pos= Item_func_case_simple::else_expr_addr();
|
Item **pos= Item_func_case_simple::else_expr_addr();
|
||||||
return pos ? pos[0] : 0;
|
return pos ? pos[0] : 0;
|
||||||
}
|
}
|
||||||
@ -2940,7 +2962,7 @@ Item *Item_func_decode_oracle::find_item()
|
|||||||
{
|
{
|
||||||
uint idx;
|
uint idx;
|
||||||
if (!Predicant_to_list_comparator::cmp_nulls_equal(this, &idx))
|
if (!Predicant_to_list_comparator::cmp_nulls_equal(this, &idx))
|
||||||
return args[idx + 1];
|
return args[idx + when_count()];
|
||||||
Item **pos= Item_func_decode_oracle::else_expr_addr();
|
Item **pos= Item_func_decode_oracle::else_expr_addr();
|
||||||
return pos ? pos[0] : 0;
|
return pos ? pos[0] : 0;
|
||||||
}
|
}
|
||||||
@ -3038,27 +3060,11 @@ bool Item_func_case::time_op(MYSQL_TIME *ltime)
|
|||||||
|
|
||||||
bool Item_func_case::fix_fields(THD *thd, Item **ref)
|
bool Item_func_case::fix_fields(THD *thd, Item **ref)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
buff should match stack usage from
|
|
||||||
Item_func_case::val_int() -> Item_func_case::find_item()
|
|
||||||
*/
|
|
||||||
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*)*(arg_count))))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
bool res= Item_func::fix_fields(thd, ref);
|
bool res= Item_func::fix_fields(thd, ref);
|
||||||
|
|
||||||
Item **pos= else_expr_addr();
|
Item **pos= else_expr_addr();
|
||||||
if (!pos || pos[0]->maybe_null)
|
if (!pos || pos[0]->maybe_null)
|
||||||
maybe_null= 1;
|
maybe_null= 1;
|
||||||
|
|
||||||
/*
|
|
||||||
Call check_stack_overrun after fix_fields to be sure that stack variable
|
|
||||||
is not optimized away
|
|
||||||
*/
|
|
||||||
if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
|
|
||||||
return TRUE; // Fatal error flag is set!
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3068,8 +3074,11 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref)
|
|||||||
THD::change_item_tree() if needed.
|
THD::change_item_tree() if needed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void change_item_tree_if_needed(THD *thd, Item **place, Item *new_value)
|
static void propagate_and_change_item_tree(THD *thd, Item **place,
|
||||||
|
COND_EQUAL *cond,
|
||||||
|
const Item::Context &ctx)
|
||||||
{
|
{
|
||||||
|
Item *new_value= (*place)->propagate_equal_fields(thd, ctx, cond);
|
||||||
if (new_value && *place != new_value)
|
if (new_value && *place != new_value)
|
||||||
thd->change_item_tree(place, new_value);
|
thd->change_item_tree(place, new_value);
|
||||||
}
|
}
|
||||||
@ -3087,8 +3096,8 @@ bool Item_func_case_simple::prepare_predicant_and_values(THD *thd,
|
|||||||
for (uint i= 0 ; i < ncases; i++)
|
for (uint i= 0 ; i < ncases; i++)
|
||||||
{
|
{
|
||||||
if (nulls_equal ?
|
if (nulls_equal ?
|
||||||
add_value("case..when", this, i * 2 + 1) :
|
add_value("case..when", this, i + 1) :
|
||||||
add_value_skip_null("case..when", this, i * 2 + 1, &have_null))
|
add_value_skip_null("case..when", this, i + 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);
|
||||||
@ -3102,16 +3111,14 @@ bool Item_func_case_simple::prepare_predicant_and_values(THD *thd,
|
|||||||
void Item_func_case_searched::fix_length_and_dec()
|
void Item_func_case_searched::fix_length_and_dec()
|
||||||
{
|
{
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
Item **else_ptr= Item_func_case_searched::else_expr_addr();
|
aggregate_then_and_else_arguments(thd, when_count());
|
||||||
aggregate_then_and_else_arguments(thd, &args[1], when_count(), else_ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_func_case_simple::fix_length_and_dec()
|
void Item_func_case_simple::fix_length_and_dec()
|
||||||
{
|
{
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
Item **else_ptr= Item_func_case_simple::else_expr_addr();
|
if (!aggregate_then_and_else_arguments(thd, when_count() + 1))
|
||||||
if (!aggregate_then_and_else_arguments(thd, &args[2], when_count(), else_ptr))
|
|
||||||
aggregate_switch_and_when_arguments(thd, false);
|
aggregate_switch_and_when_arguments(thd, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3119,8 +3126,7 @@ void Item_func_case_simple::fix_length_and_dec()
|
|||||||
void Item_func_decode_oracle::fix_length_and_dec()
|
void Item_func_decode_oracle::fix_length_and_dec()
|
||||||
{
|
{
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
Item **else_ptr= Item_func_decode_oracle::else_expr_addr();
|
if (!aggregate_then_and_else_arguments(thd, when_count() + 1))
|
||||||
if (!aggregate_then_and_else_arguments(thd, &args[2], when_count(), else_ptr))
|
|
||||||
aggregate_switch_and_when_arguments(thd, true);
|
aggregate_switch_and_when_arguments(thd, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3130,40 +3136,16 @@ void Item_func_decode_oracle::fix_length_and_dec()
|
|||||||
and collations when string result
|
and collations when string result
|
||||||
|
|
||||||
@param THD - current thd
|
@param THD - current thd
|
||||||
@param them_expr - the pointer to the leftmost THEN argument in args[]
|
@param start - an element in args to start aggregating from
|
||||||
@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, uint start)
|
||||||
Item **then_expr,
|
|
||||||
uint count,
|
|
||||||
Item **else_expr)
|
|
||||||
{
|
{
|
||||||
Item **agg= arg_buffer;
|
if (aggregate_for_result(func_name(), args + start, arg_count - start, true))
|
||||||
uint nagg;
|
|
||||||
|
|
||||||
for (nagg= 0 ; nagg < count ; nagg++)
|
|
||||||
agg[nagg]= then_expr[nagg * 2];
|
|
||||||
|
|
||||||
if (else_expr)
|
|
||||||
agg[nagg++]= *else_expr;
|
|
||||||
|
|
||||||
if (aggregate_for_result(func_name(), agg, nagg, true))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (fix_attributes(agg, nagg))
|
if (fix_attributes(args + start, arg_count - start))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*
|
|
||||||
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 < count ; nagg++)
|
|
||||||
change_item_tree_if_needed(thd, &then_expr[nagg * 2], agg[nagg]);
|
|
||||||
|
|
||||||
if (else_expr)
|
|
||||||
change_item_tree_if_needed(thd, else_expr, agg[nagg++]);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3175,8 +3157,6 @@ bool Item_func_case::aggregate_then_and_else_arguments(THD *thd,
|
|||||||
bool Item_func_case_simple::aggregate_switch_and_when_arguments(THD *thd,
|
bool Item_func_case_simple::aggregate_switch_and_when_arguments(THD *thd,
|
||||||
bool nulls_eq)
|
bool nulls_eq)
|
||||||
{
|
{
|
||||||
Item **agg= arg_buffer;
|
|
||||||
uint nagg;
|
|
||||||
uint ncases= when_count();
|
uint ncases= when_count();
|
||||||
m_found_types= 0;
|
m_found_types= 0;
|
||||||
if (prepare_predicant_and_values(thd, &m_found_types, nulls_eq))
|
if (prepare_predicant_and_values(thd, &m_found_types, nulls_eq))
|
||||||
@ -3190,17 +3170,7 @@ bool Item_func_case_simple::aggregate_switch_and_when_arguments(THD *thd,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
if (!(m_found_types= collect_cmp_types(args, ncases + 1)))
|
||||||
As the predicant expression and WHEN expressions
|
|
||||||
are intermixed in args[] array THEN and ELSE items,
|
|
||||||
extract the first expression and all WHEN expressions into
|
|
||||||
a temporary array, to process them easier.
|
|
||||||
*/
|
|
||||||
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;
|
return true;
|
||||||
|
|
||||||
if (m_found_types & (1U << STRING_RESULT))
|
if (m_found_types & (1U << STRING_RESULT))
|
||||||
@ -3229,17 +3199,8 @@ bool Item_func_case_simple::aggregate_switch_and_when_arguments(THD *thd,
|
|||||||
|
|
||||||
CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END
|
CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END
|
||||||
*/
|
*/
|
||||||
if (agg_arg_charsets_for_comparison(cmp_collation, agg, nagg))
|
if (agg_arg_charsets_for_comparison(cmp_collation, args, ncases + 1))
|
||||||
return true;
|
return true;
|
||||||
/*
|
|
||||||
Now copy first expression and all WHEN expressions back to args[]
|
|
||||||
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[0], agg[0]);
|
|
||||||
|
|
||||||
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))
|
if (make_unique_cmp_items(thd, cmp_collation.collation))
|
||||||
@ -3256,78 +3217,57 @@ Item* Item_func_case_simple::propagate_equal_fields(THD *thd,
|
|||||||
const Type_handler *first_expr_cmp_handler;
|
const Type_handler *first_expr_cmp_handler;
|
||||||
|
|
||||||
first_expr_cmp_handler= args[0]->type_handler_for_comparison();
|
first_expr_cmp_handler= args[0]->type_handler_for_comparison();
|
||||||
for (uint i= 0; i < arg_count; i++)
|
/*
|
||||||
|
Cannot replace the CASE (the switch) argument if
|
||||||
|
there are multiple comparison types were found, or found a single
|
||||||
|
comparison type that is not equal to args[0]->cmp_type().
|
||||||
|
|
||||||
|
- Example: multiple comparison types, can't propagate:
|
||||||
|
WHERE CASE str_column
|
||||||
|
WHEN 'string' THEN TRUE
|
||||||
|
WHEN 1 THEN TRUE
|
||||||
|
ELSE FALSE END;
|
||||||
|
|
||||||
|
- Example: a single incompatible comparison type, can't propagate:
|
||||||
|
WHERE CASE str_column
|
||||||
|
WHEN DATE'2001-01-01' THEN TRUE
|
||||||
|
ELSE FALSE END;
|
||||||
|
|
||||||
|
- Example: a single incompatible comparison type, can't propagate:
|
||||||
|
WHERE CASE str_column
|
||||||
|
WHEN 1 THEN TRUE
|
||||||
|
ELSE FALSE END;
|
||||||
|
|
||||||
|
- Example: a single compatible comparison type, ok to propagate:
|
||||||
|
WHERE CASE str_column
|
||||||
|
WHEN 'str1' THEN TRUE
|
||||||
|
WHEN 'str2' THEN TRUE
|
||||||
|
ELSE FALSE END;
|
||||||
|
*/
|
||||||
|
if (m_found_types == (1UL << first_expr_cmp_handler->cmp_type()))
|
||||||
|
propagate_and_change_item_tree(thd, &args[0], cond,
|
||||||
|
Context(ANY_SUBST, first_expr_cmp_handler, cmp_collation.collation));
|
||||||
|
|
||||||
|
/*
|
||||||
|
These arguments are in comparison.
|
||||||
|
Allow invariants of the same value during propagation.
|
||||||
|
Note, as we pass ANY_SUBST, none of the WHEN arguments will be
|
||||||
|
replaced to zero-filled constants (only IDENTITY_SUBST allows this).
|
||||||
|
Such a change for WHEN arguments would require rebuilding cmp_items.
|
||||||
|
*/
|
||||||
|
uint i, count= when_count();
|
||||||
|
for (i= 1; i <= count; i++)
|
||||||
{
|
{
|
||||||
/*
|
Type_handler_hybrid_field_type tmp(first_expr_cmp_handler);
|
||||||
These arguments are in comparison.
|
if (!tmp.aggregate_for_comparison(args[i]->type_handler_for_comparison()))
|
||||||
Allow invariants of the same value during propagation.
|
propagate_and_change_item_tree(thd, &args[i], cond,
|
||||||
Note, as we pass ANY_SUBST, none of the WHEN arguments will be
|
Context(ANY_SUBST, tmp.type_handler(), cmp_collation.collation));
|
||||||
replaced to zero-filled constants (only IDENTITY_SUBST allows this).
|
|
||||||
Such a change for WHEN arguments would require rebuilding cmp_items.
|
|
||||||
*/
|
|
||||||
Item *new_item= 0;
|
|
||||||
if (i == 0) // Then CASE (the switch) argument
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Cannot replace the CASE (the switch) argument if
|
|
||||||
there are multiple comparison types were found, or found a single
|
|
||||||
comparison type that is not equal to args[0]->cmp_type().
|
|
||||||
|
|
||||||
- Example: multiple comparison types, can't propagate:
|
|
||||||
WHERE CASE str_column
|
|
||||||
WHEN 'string' THEN TRUE
|
|
||||||
WHEN 1 THEN TRUE
|
|
||||||
ELSE FALSE END;
|
|
||||||
|
|
||||||
- Example: a single incompatible comparison type, can't propagate:
|
|
||||||
WHERE CASE str_column
|
|
||||||
WHEN DATE'2001-01-01' THEN TRUE
|
|
||||||
ELSE FALSE END;
|
|
||||||
|
|
||||||
- Example: a single incompatible comparison type, can't propagate:
|
|
||||||
WHERE CASE str_column
|
|
||||||
WHEN 1 THEN TRUE
|
|
||||||
ELSE FALSE END;
|
|
||||||
|
|
||||||
- Example: a single compatible comparison type, ok to propagate:
|
|
||||||
WHERE CASE str_column
|
|
||||||
WHEN 'str1' THEN TRUE
|
|
||||||
WHEN 'str2' THEN TRUE
|
|
||||||
ELSE FALSE END;
|
|
||||||
*/
|
|
||||||
if (m_found_types == (1UL << first_expr_cmp_handler->cmp_type()))
|
|
||||||
new_item= args[i]->propagate_equal_fields(thd,
|
|
||||||
Context(
|
|
||||||
ANY_SUBST,
|
|
||||||
first_expr_cmp_handler,
|
|
||||||
cmp_collation.collation),
|
|
||||||
cond);
|
|
||||||
}
|
|
||||||
else if ((i % 2) == 1 && i != arg_count - 1) // WHEN arguments
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
These arguments are in comparison.
|
|
||||||
Allow invariants of the same value during propagation.
|
|
||||||
Note, as we pass ANY_SUBST, none of the WHEN arguments will be
|
|
||||||
replaced to zero-filled constants (only IDENTITY_SUBST allows this).
|
|
||||||
Such a change for WHEN arguments would require rebuilding cmp_items.
|
|
||||||
*/
|
|
||||||
Type_handler_hybrid_field_type tmp(first_expr_cmp_handler);
|
|
||||||
if (!tmp.aggregate_for_comparison(args[i]->type_handler_for_comparison()))
|
|
||||||
new_item= args[i]->propagate_equal_fields(thd,
|
|
||||||
Context(
|
|
||||||
ANY_SUBST,
|
|
||||||
tmp.type_handler(),
|
|
||||||
cmp_collation.collation),
|
|
||||||
cond);
|
|
||||||
}
|
|
||||||
else // THEN and ELSE arguments (they are not in comparison)
|
|
||||||
{
|
|
||||||
new_item= args[i]->propagate_equal_fields(thd, Context_identity(), cond);
|
|
||||||
}
|
|
||||||
if (new_item && new_item != args[i])
|
|
||||||
thd->change_item_tree(&args[i], new_item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// THEN and ELSE arguments (they are not in comparison)
|
||||||
|
for (; i < arg_count; i++)
|
||||||
|
propagate_and_change_item_tree(thd, &args[i], cond, Context_identity());
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3339,9 +3279,9 @@ void Item_func_case::print_when_then_arguments(String *str,
|
|||||||
for (uint i=0 ; i < count ; i++)
|
for (uint i=0 ; i < count ; i++)
|
||||||
{
|
{
|
||||||
str->append(STRING_WITH_LEN("when "));
|
str->append(STRING_WITH_LEN("when "));
|
||||||
items[i * 2]->print_parenthesised(str, query_type, precedence());
|
items[i]->print_parenthesised(str, query_type, precedence());
|
||||||
str->append(STRING_WITH_LEN(" then "));
|
str->append(STRING_WITH_LEN(" then "));
|
||||||
items[i * 2 + 1]->print_parenthesised(str, query_type, precedence());
|
items[i + count]->print_parenthesised(str, query_type, precedence());
|
||||||
str->append(' ');
|
str->append(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3381,6 +3321,28 @@ void Item_func_case_simple::print(String *str, enum_query_type query_type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Item_func_decode_oracle::print(String *str, enum_query_type query_type)
|
||||||
|
{
|
||||||
|
str->append(func_name());
|
||||||
|
str->append('(');
|
||||||
|
args[0]->print(str, query_type);
|
||||||
|
for (uint i= 1, count= when_count() ; i <= count; i++)
|
||||||
|
{
|
||||||
|
str->append(',');
|
||||||
|
args[i]->print(str, query_type);
|
||||||
|
str->append(',');
|
||||||
|
args[i+count]->print(str, query_type);
|
||||||
|
}
|
||||||
|
Item **else_expr= Item_func_case_simple::else_expr_addr();
|
||||||
|
if (else_expr)
|
||||||
|
{
|
||||||
|
str->append(',');
|
||||||
|
(*else_expr)->print(str, query_type);
|
||||||
|
}
|
||||||
|
str->append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Coalesce - return first not NULL argument.
|
Coalesce - return first not NULL argument.
|
||||||
*/
|
*/
|
||||||
@ -4910,17 +4872,14 @@ Item *Item_cond::propagate_equal_fields(THD *thd,
|
|||||||
DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
|
DBUG_ASSERT(!thd->stmt_arena->is_stmt_prepare());
|
||||||
DBUG_ASSERT(arg_count == 0);
|
DBUG_ASSERT(arg_count == 0);
|
||||||
List_iterator<Item> li(list);
|
List_iterator<Item> li(list);
|
||||||
Item *item;
|
while (li++)
|
||||||
while ((item= li++))
|
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
The exact value of the second parameter to propagate_equal_fields()
|
The exact value of the last parameter to propagate_and_change_item_tree()
|
||||||
is not important at this point. Item_func derivants will create and
|
is not important at this point. Item_func derivants will create and
|
||||||
pass their own context to the arguments.
|
pass their own context to the arguments.
|
||||||
*/
|
*/
|
||||||
Item *new_item= item->propagate_equal_fields(thd, Context_boolean(), cond);
|
propagate_and_change_item_tree(thd, li.ref(), cond, Context_boolean());
|
||||||
if (new_item && new_item != item)
|
|
||||||
thd->change_item_tree(li.ref(), new_item);
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -2104,15 +2104,13 @@ class Item_func_case :public Item_func_case_expression
|
|||||||
protected:
|
protected:
|
||||||
String tmp_value;
|
String tmp_value;
|
||||||
DTCollation cmp_collation;
|
DTCollation cmp_collation;
|
||||||
Item **arg_buffer;
|
bool aggregate_then_and_else_arguments(THD *thd, uint count);
|
||||||
bool aggregate_then_and_else_arguments(THD *thd,
|
|
||||||
Item **items, uint count,
|
|
||||||
Item **else_expr);
|
|
||||||
virtual Item **else_expr_addr() const= 0;
|
virtual Item **else_expr_addr() const= 0;
|
||||||
virtual Item *find_item()= 0;
|
virtual Item *find_item()= 0;
|
||||||
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);
|
||||||
|
void reorder_args(uint start);
|
||||||
public:
|
public:
|
||||||
Item_func_case(THD *thd, List<Item> &list)
|
Item_func_case(THD *thd, List<Item> &list)
|
||||||
:Item_func_case_expression(thd, list)
|
:Item_func_case_expression(thd, list)
|
||||||
@ -2129,13 +2127,6 @@ public:
|
|||||||
enum precedence precedence() const { return BETWEEN_PRECEDENCE; }
|
enum precedence precedence() const { return BETWEEN_PRECEDENCE; }
|
||||||
CHARSET_INFO *compare_collation() const { return cmp_collation.collation; }
|
CHARSET_INFO *compare_collation() const { return cmp_collation.collation; }
|
||||||
bool need_parentheses_in_default() { return true; }
|
bool need_parentheses_in_default() { return true; }
|
||||||
Item *build_clone(THD *thd)
|
|
||||||
{
|
|
||||||
Item_func_case *clone= (Item_func_case *) Item_func::build_clone(thd);
|
|
||||||
if (clone)
|
|
||||||
clone->arg_buffer= 0;
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -2156,6 +2147,7 @@ public:
|
|||||||
:Item_func_case(thd, list)
|
:Item_func_case(thd, list)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(arg_count >= 2);
|
DBUG_ASSERT(arg_count >= 2);
|
||||||
|
reorder_args(0);
|
||||||
}
|
}
|
||||||
void print(String *str, enum_query_type query_type);
|
void print(String *str, enum_query_type query_type);
|
||||||
void fix_length_and_dec();
|
void fix_length_and_dec();
|
||||||
@ -2200,6 +2192,7 @@ public:
|
|||||||
m_found_types(0)
|
m_found_types(0)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(arg_count >= 3);
|
DBUG_ASSERT(arg_count >= 3);
|
||||||
|
reorder_args(1);
|
||||||
}
|
}
|
||||||
void cleanup()
|
void cleanup()
|
||||||
{
|
{
|
||||||
@ -2233,8 +2226,7 @@ public:
|
|||||||
:Item_func_case_simple(thd, list)
|
:Item_func_case_simple(thd, list)
|
||||||
{ }
|
{ }
|
||||||
const char *func_name() const { return "decode_oracle"; }
|
const char *func_name() const { return "decode_oracle"; }
|
||||||
void print(String *str, enum_query_type query_type)
|
void print(String *str, enum_query_type query_type);
|
||||||
{ Item_func::print(str, query_type); }
|
|
||||||
void fix_length_and_dec();
|
void fix_length_and_dec();
|
||||||
Item *find_item();
|
Item *find_item();
|
||||||
Item *get_copy(THD *thd)
|
Item *get_copy(THD *thd)
|
||||||
|
Reference in New Issue
Block a user