mirror of
https://github.com/MariaDB/server.git
synced 2025-07-26 07:02:12 +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 commit is contained in:
@ -3003,11 +3003,12 @@ Item_func_case::Item_func_case(THD *thd, List<Item> &list,
|
|||||||
Item_func_hybrid_field_type(thd), first_expr_num(-1), else_expr_num(-1),
|
Item_func_hybrid_field_type(thd), first_expr_num(-1), else_expr_num(-1),
|
||||||
left_cmp_type(INT_RESULT), case_item(0), m_found_types(0)
|
left_cmp_type(INT_RESULT), case_item(0), m_found_types(0)
|
||||||
{
|
{
|
||||||
ncases= list.elements;
|
DBUG_ASSERT(list.elements % 2 == 0);
|
||||||
|
nwhens= list.elements / 2;
|
||||||
if (first_expr_arg)
|
if (first_expr_arg)
|
||||||
{
|
{
|
||||||
first_expr_num= list.elements;
|
first_expr_num= 0;
|
||||||
list.push_back(first_expr_arg, thd->mem_root);
|
list.push_front(first_expr_arg, thd->mem_root);
|
||||||
}
|
}
|
||||||
if (else_expr_arg)
|
if (else_expr_arg)
|
||||||
{
|
{
|
||||||
@ -3015,6 +3016,22 @@ Item_func_case::Item_func_case(THD *thd, List<Item> &list,
|
|||||||
list.push_back(else_expr_arg, thd->mem_root);
|
list.push_back(else_expr_arg, thd->mem_root);
|
||||||
}
|
}
|
||||||
set_arguments(thd, list);
|
set_arguments(thd, list);
|
||||||
|
|
||||||
|
/*
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
const size_t size= sizeof(Item*)*nwhens*2;
|
||||||
|
Item **arg_buffer= (Item **)my_safe_alloca(size);
|
||||||
|
memcpy(arg_buffer, args + first_expr_num + 1, size);
|
||||||
|
for (uint i= 0; i < nwhens ; i++)
|
||||||
|
{
|
||||||
|
args[first_expr_num + 1 + i]= arg_buffer[i*2];
|
||||||
|
args[first_expr_num + 1 + i + nwhens] = arg_buffer[i*2 + 1];
|
||||||
|
}
|
||||||
|
my_safe_afree(arg_buffer, size);
|
||||||
|
|
||||||
bzero(&cmp_items, sizeof(cmp_items));
|
bzero(&cmp_items, sizeof(cmp_items));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3045,18 +3062,17 @@ Item *Item_func_case::find_item(String *str)
|
|||||||
|
|
||||||
if (first_expr_num == -1)
|
if (first_expr_num == -1)
|
||||||
{
|
{
|
||||||
for (uint i=0 ; i < ncases ; i+=2)
|
for (uint i=0 ; i < nwhens ; i++)
|
||||||
{
|
{
|
||||||
// No expression between CASE and the first WHEN
|
// No expression between CASE and the first WHEN
|
||||||
if (args[i]->val_bool())
|
if (args[i]->val_bool())
|
||||||
return args[i+1];
|
return args[i+nwhens];
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Compare every WHEN argument with it and return the first match */
|
/* Compare every WHEN argument with it and return the first match */
|
||||||
for (uint i=0 ; i < ncases ; i+=2)
|
for (uint i=1 ; i <= nwhens; i++)
|
||||||
{
|
{
|
||||||
if (args[i]->real_item()->type() == NULL_ITEM)
|
if (args[i]->real_item()->type() == NULL_ITEM)
|
||||||
continue;
|
continue;
|
||||||
@ -3065,13 +3081,13 @@ Item *Item_func_case::find_item(String *str)
|
|||||||
DBUG_ASSERT(cmp_items[(uint)cmp_type]);
|
DBUG_ASSERT(cmp_items[(uint)cmp_type]);
|
||||||
if (!(value_added_map & (1U << (uint)cmp_type)))
|
if (!(value_added_map & (1U << (uint)cmp_type)))
|
||||||
{
|
{
|
||||||
cmp_items[(uint)cmp_type]->store_value(args[first_expr_num]);
|
cmp_items[(uint)cmp_type]->store_value(args[0]);
|
||||||
if ((null_value=args[first_expr_num]->null_value))
|
if ((null_value= args[0]->null_value))
|
||||||
return else_expr_num != -1 ? args[else_expr_num] : 0;
|
return else_expr_num != -1 ? args[else_expr_num] : 0;
|
||||||
value_added_map|= 1U << (uint)cmp_type;
|
value_added_map|= 1U << (uint)cmp_type;
|
||||||
}
|
}
|
||||||
if (cmp_items[(uint)cmp_type]->cmp(args[i]) == FALSE)
|
if (cmp_items[(uint)cmp_type]->cmp(args[i]) == FALSE)
|
||||||
return args[i + 1];
|
return args[i + nwhens];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No, WHEN clauses all missed, return ELSE expression
|
// No, WHEN clauses all missed, return ELSE expression
|
||||||
@ -3174,9 +3190,6 @@ 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))))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
bool res= Item_func::fix_fields(thd, ref);
|
bool res= Item_func::fix_fields(thd, ref);
|
||||||
/*
|
/*
|
||||||
Call check_stack_overrun after fix_fields to be sure that stack variable
|
Call check_stack_overrun after fix_fields to be sure that stack variable
|
||||||
@ -3191,31 +3204,17 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref)
|
|||||||
/**
|
/**
|
||||||
Check if (*place) and new_value points to different Items and call
|
Check if (*place) and new_value points to different Items and call
|
||||||
THD::change_item_tree() if needed.
|
THD::change_item_tree() if needed.
|
||||||
|
|
||||||
This function is a workaround for implementation deficiency in
|
|
||||||
Item_func_case. The problem there is that the 'args' attribute contains
|
|
||||||
Items from different expressions.
|
|
||||||
|
|
||||||
The function must not be used elsewhere and will be remove eventually.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void change_item_tree_if_needed(THD *thd,
|
static void change_item_tree_if_needed(THD *thd, Item **place, Item *new_value)
|
||||||
Item **place,
|
|
||||||
Item *new_value)
|
|
||||||
{
|
{
|
||||||
if (*place == new_value)
|
if (new_value && *place != new_value)
|
||||||
return;
|
thd->change_item_tree(place, new_value);
|
||||||
|
|
||||||
thd->change_item_tree(place, new_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Item_func_case::fix_length_and_dec()
|
void Item_func_case::fix_length_and_dec()
|
||||||
{
|
{
|
||||||
Item **agg= arg_buffer;
|
|
||||||
uint nagg;
|
|
||||||
THD *thd= current_thd;
|
|
||||||
|
|
||||||
m_found_types= 0;
|
m_found_types= 0;
|
||||||
if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
|
if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
|
||||||
maybe_null= 1;
|
maybe_null= 1;
|
||||||
@ -3224,33 +3223,17 @@ 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
|
||||||
*/
|
*/
|
||||||
|
Item **rets= args + first_expr_num + 1 + nwhens;
|
||||||
for (nagg= 0 ; nagg < ncases/2 ; nagg++)
|
uint nrets= nwhens + (else_expr_num != -1);
|
||||||
agg[nagg]= args[nagg*2+1];
|
set_handler_by_field_type(agg_field_type(rets, nrets, true));
|
||||||
|
|
||||||
if (else_expr_num != -1)
|
|
||||||
agg[nagg++]= args[else_expr_num];
|
|
||||||
|
|
||||||
set_handler_by_field_type(agg_field_type(agg, nagg, true));
|
|
||||||
|
|
||||||
if (Item_func_case::result_type() == STRING_RESULT)
|
if (Item_func_case::result_type() == STRING_RESULT)
|
||||||
{
|
{
|
||||||
if (count_string_result_length(Item_func_case::field_type(), agg, nagg))
|
if (count_string_result_length(Item_func_case::field_type(), rets, nrets))
|
||||||
return;
|
return;
|
||||||
/*
|
|
||||||
Copy all THEN and ELSE items back to args[] 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]);
|
|
||||||
|
|
||||||
if (else_expr_num != -1)
|
|
||||||
change_item_tree_if_needed(thd, &args[else_expr_num], agg[nagg++]);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
fix_attributes(rets, nrets);
|
||||||
fix_attributes(agg, nagg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Aggregate first expression and all WHEN expression types
|
Aggregate first expression and all WHEN expression types
|
||||||
@ -3258,25 +3241,14 @@ void Item_func_case::fix_length_and_dec()
|
|||||||
*/
|
*/
|
||||||
if (first_expr_num != -1)
|
if (first_expr_num != -1)
|
||||||
{
|
{
|
||||||
uint i;
|
left_cmp_type= args[0]->cmp_type();
|
||||||
agg[0]= args[first_expr_num];
|
|
||||||
left_cmp_type= agg[0]->cmp_type();
|
|
||||||
|
|
||||||
/*
|
if (!(m_found_types= collect_cmp_types(args, nwhens + 1)))
|
||||||
As the first 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.
|
|
||||||
*/
|
|
||||||
for (nagg= 0; nagg < ncases/2 ; nagg++)
|
|
||||||
agg[nagg+1]= args[nagg*2];
|
|
||||||
nagg++;
|
|
||||||
if (!(m_found_types= collect_cmp_types(agg, nagg)))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Item *date_arg= 0;
|
Item *date_arg= 0;
|
||||||
if (m_found_types & (1U << TIME_RESULT))
|
if (m_found_types & (1U << TIME_RESULT))
|
||||||
date_arg= find_date_time_item(args, arg_count, 0);
|
date_arg= find_date_time_item(args, nwhens + 1, 0);
|
||||||
|
|
||||||
if (m_found_types & (1U << STRING_RESULT))
|
if (m_found_types & (1U << STRING_RESULT))
|
||||||
{
|
{
|
||||||
@ -3304,25 +3276,15 @@ void Item_func_case::fix_length_and_dec()
|
|||||||
|
|
||||||
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, nwhens + 1))
|
||||||
return;
|
return;
|
||||||
/*
|
|
||||||
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[first_expr_num], agg[0]);
|
|
||||||
|
|
||||||
for (nagg= 0; nagg < ncases / 2; nagg++)
|
|
||||||
change_item_tree_if_needed(thd, &args[nagg * 2], agg[nagg + 1]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i= 0; i <= (uint)TIME_RESULT; i++)
|
for (uint i= 0; i <= (uint)TIME_RESULT; i++)
|
||||||
{
|
{
|
||||||
if (m_found_types & (1U << i) && !cmp_items[i])
|
if (m_found_types & (1U << i) && !cmp_items[i])
|
||||||
{
|
{
|
||||||
DBUG_ASSERT((Item_result)i != ROW_RESULT);
|
DBUG_ASSERT((Item_result)i != ROW_RESULT);
|
||||||
|
|
||||||
if (!(cmp_items[i]=
|
if (!(cmp_items[i]=
|
||||||
cmp_item::get_comparator((Item_result)i, date_arg,
|
cmp_item::get_comparator((Item_result)i, date_arg,
|
||||||
cmp_collation.collation)))
|
cmp_collation.collation)))
|
||||||
@ -3342,75 +3304,59 @@ Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint i= 0; i < arg_count; i++)
|
/*
|
||||||
|
First, replace CASE expression.
|
||||||
|
We 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 << left_cmp_type))
|
||||||
|
change_item_tree_if_needed(thd, args,
|
||||||
|
args[0]->propagate_equal_fields(thd, Context(ANY_SUBST, left_cmp_type,
|
||||||
|
cmp_collation.collation),
|
||||||
|
cond));
|
||||||
|
uint i= 1;
|
||||||
|
for (; i <= nwhens ; i++) // WHEN expressions
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Even "i" values cover items that are in a comparison context:
|
These arguments are in comparison.
|
||||||
CASE x0 WHEN x1 .. WHEN x2 .. WHEN x3 ..
|
Allow invariants of the same value during propagation.
|
||||||
Odd "i" values cover items that are not in comparison:
|
Note, as we pass ANY_SUBST, none of the WHEN arguments will be
|
||||||
CASE ... THEN y1 ... THEN y2 ... THEN y3 ... ELSE y4 END
|
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;
|
Item_result tmp_cmp_type= item_cmp_type(args[first_expr_num], args[i]);
|
||||||
if ((int) i == first_expr_num) // Then CASE (the switch) argument
|
change_item_tree_if_needed(thd, args + i,
|
||||||
{
|
args[i]->propagate_equal_fields(thd, Context(ANY_SUBST, tmp_cmp_type,
|
||||||
/*
|
cmp_collation.collation),
|
||||||
Cannot replace the CASE (the switch) argument if
|
cond));
|
||||||
there are multiple comparison types were found, or found a single
|
}
|
||||||
comparison type that is not equal to args[0]->cmp_type().
|
for (; i < arg_count ; i++) // THEN expressions and optional ELSE expression
|
||||||
|
{
|
||||||
- Example: multiple comparison types, can't propagate:
|
change_item_tree_if_needed(thd, args + i,
|
||||||
WHERE CASE str_column
|
args[i]->propagate_equal_fields(thd, Context_identity(), cond));
|
||||||
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 << left_cmp_type))
|
|
||||||
new_item= args[i]->propagate_equal_fields(thd,
|
|
||||||
Context(
|
|
||||||
ANY_SUBST,
|
|
||||||
left_cmp_type,
|
|
||||||
cmp_collation.collation),
|
|
||||||
cond);
|
|
||||||
}
|
|
||||||
else if ((i % 2) == 0) // 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.
|
|
||||||
*/
|
|
||||||
Item_result tmp_cmp_type= item_cmp_type(args[first_expr_num], args[i]);
|
|
||||||
new_item= args[i]->propagate_equal_fields(thd,
|
|
||||||
Context(
|
|
||||||
ANY_SUBST,
|
|
||||||
tmp_cmp_type,
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -3419,11 +3365,8 @@ Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_
|
|||||||
uint Item_func_case::decimal_precision() const
|
uint Item_func_case::decimal_precision() const
|
||||||
{
|
{
|
||||||
int max_int_part=0;
|
int max_int_part=0;
|
||||||
for (uint i=0 ; i < ncases ; i+=2)
|
for (uint i=first_expr_num + 1 + nwhens ; i < arg_count; i++)
|
||||||
set_if_bigger(max_int_part, args[i+1]->decimal_int_part());
|
set_if_bigger(max_int_part, args[i]->decimal_int_part());
|
||||||
|
|
||||||
if (else_expr_num != -1)
|
|
||||||
set_if_bigger(max_int_part, args[else_expr_num]->decimal_int_part());
|
|
||||||
return MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION);
|
return MY_MIN(max_int_part + decimals, DECIMAL_MAX_PRECISION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3438,15 +3381,15 @@ void Item_func_case::print(String *str, enum_query_type query_type)
|
|||||||
str->append(STRING_WITH_LEN("case "));
|
str->append(STRING_WITH_LEN("case "));
|
||||||
if (first_expr_num != -1)
|
if (first_expr_num != -1)
|
||||||
{
|
{
|
||||||
args[first_expr_num]->print_parenthesised(str, query_type, precedence());
|
args[0]->print_parenthesised(str, query_type, precedence());
|
||||||
str->append(' ');
|
str->append(' ');
|
||||||
}
|
}
|
||||||
for (uint i=0 ; i < ncases ; i+=2)
|
for (uint i= first_expr_num + 1 ; i < nwhens + first_expr_num + 1; i++)
|
||||||
{
|
{
|
||||||
str->append(STRING_WITH_LEN("when "));
|
str->append(STRING_WITH_LEN("when "));
|
||||||
args[i]->print_parenthesised(str, query_type, precedence());
|
args[i]->print_parenthesised(str, query_type, precedence());
|
||||||
str->append(STRING_WITH_LEN(" then "));
|
str->append(STRING_WITH_LEN(" then "));
|
||||||
args[i+1]->print_parenthesised(str, query_type, precedence());
|
args[i+nwhens]->print_parenthesised(str, query_type, precedence());
|
||||||
str->append(' ');
|
str->append(' ');
|
||||||
}
|
}
|
||||||
if (else_expr_num != -1)
|
if (else_expr_num != -1)
|
||||||
|
@ -1558,12 +1558,11 @@ class Item_func_case :public Item_func_hybrid_field_type
|
|||||||
int first_expr_num, else_expr_num;
|
int first_expr_num, else_expr_num;
|
||||||
enum Item_result left_cmp_type;
|
enum Item_result left_cmp_type;
|
||||||
String tmp_value;
|
String tmp_value;
|
||||||
uint ncases;
|
uint nwhens;
|
||||||
Item_result cmp_type;
|
Item_result cmp_type;
|
||||||
DTCollation cmp_collation;
|
DTCollation cmp_collation;
|
||||||
cmp_item *cmp_items[6]; /* For all result types */
|
cmp_item *cmp_items[6]; /* For all result types */
|
||||||
cmp_item *case_item;
|
cmp_item *case_item;
|
||||||
Item **arg_buffer;
|
|
||||||
uint m_found_types;
|
uint m_found_types;
|
||||||
public:
|
public:
|
||||||
Item_func_case(THD *thd, List<Item> &list, Item *first_expr_arg,
|
Item_func_case(THD *thd, List<Item> &list, Item *first_expr_arg,
|
||||||
@ -1593,7 +1592,6 @@ public:
|
|||||||
if (clone)
|
if (clone)
|
||||||
{
|
{
|
||||||
clone->case_item= 0;
|
clone->case_item= 0;
|
||||||
clone->arg_buffer= 0;
|
|
||||||
bzero(&clone->cmp_items, sizeof(cmp_items));
|
bzero(&clone->cmp_items, sizeof(cmp_items));
|
||||||
}
|
}
|
||||||
return clone;
|
return clone;
|
||||||
|
Reference in New Issue
Block a user