summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.cc
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2011-07-02 22:08:51 +0200
committerSergei Golubchik <sergii@pisem.net>2011-07-02 22:08:51 +0200
commit9809f05199aeb0b67991fac41bd86f38730768dc (patch)
treefa2792ff86d0da014b535d743759810612338042 /sql/item_cmpfunc.cc
parent0accbd0364e0333e0b119aa9ce93e34ded9df6cb (diff)
parent5a0e7394a5ae0c7b6a1ea35b7ea3a8985325987a (diff)
downloadmariadb-git-9809f05199aeb0b67991fac41bd86f38730768dc.tar.gz
5.5-merge
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r--sql/item_cmpfunc.cc119
1 files changed, 80 insertions, 39 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index e8cf6e97a28..b0c2dac7b74 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -403,7 +403,7 @@ static bool convert_constant_item(THD *thd, Item_field *field_item,
Field *field= field_item->field;
int result= 0;
- if (!(*item)->with_subselect && (*item)->const_item())
+ if ((*item)->const_item())
{
TABLE *table= field->table;
ulonglong orig_sql_mode= thd->variables.sql_mode;
@@ -499,7 +499,7 @@ void Item_bool_func2::fix_length_and_dec()
}
thd= current_thd;
- if (!thd->is_context_analysis_only())
+ if (!thd->lex->is_ps_or_view_context_analysis())
{
if (args[0]->real_item()->type() == FIELD_ITEM)
{
@@ -803,7 +803,7 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value)
confuse storage engines since in context analysis mode tables
aren't locked.
*/
- if (!thd->is_context_analysis_only() &&
+ if (!thd->lex->is_ps_or_view_context_analysis() &&
cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() &&
(str_arg->type() != Item::FUNC_ITEM ||
((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC))
@@ -923,7 +923,7 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
*/
Query_arena backup;
Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup);
- Item_cache_int *cache= new Item_cache_int();
+ Item_cache_int *cache= new Item_cache_int(MYSQL_TYPE_DATETIME);
if (save_arena)
thd->set_query_arena(save_arena);
@@ -1044,7 +1044,7 @@ Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value,
Item_result type)
{
/* Don't need cache if doing context analysis only. */
- if (!thd_arg->is_context_analysis_only() &&
+ if (!thd->lex->is_ps_or_view_context_analysis() &&
(*value)->const_item() && type != (*value)->result_type())
{
Item_cache *cache= Item_cache::get_cache(*value, type);
@@ -1221,9 +1221,12 @@ get_year_value(THD *thd, Item ***item_arg, Item **cache_arg,
value of 2000.
*/
Item *real_item= item->real_item();
- if (!(real_item->type() == Item::FIELD_ITEM &&
- ((Item_field *)real_item)->field->type() == MYSQL_TYPE_YEAR &&
- ((Item_field *)real_item)->field->field_length == 4))
+ Field *field= NULL;
+ if (real_item->type() == Item::FIELD_ITEM)
+ field= ((Item_field *)real_item)->field;
+ else if (real_item->type() == Item::CACHE_ITEM)
+ field= ((Item_cache *)real_item)->field();
+ if (!(field && field->type() == MYSQL_TYPE_YEAR && field->field_length == 4))
{
if (value < 70)
value+= 100;
@@ -2211,7 +2214,6 @@ void Item_func_interval::fix_length_and_dec()
if (dec != &range->dec)
{
range->dec= *dec;
- range->dec.fix_buffer_pointer();
}
}
else
@@ -2763,7 +2765,7 @@ Item_func_if::fix_length_and_dec()
if (null1)
{
cached_result_type= arg2_type;
- collation.set(args[2]->collation.collation);
+ collation.set(args[2]->collation);
cached_field_type= args[2]->field_type();
max_length= args[2]->max_length;
return;
@@ -2772,7 +2774,7 @@ Item_func_if::fix_length_and_dec()
if (null2)
{
cached_result_type= arg1_type;
- collation.set(args[1]->collation.collation);
+ collation.set(args[1]->collation);
cached_field_type= args[1]->field_type();
max_length= args[1]->max_length;
return;
@@ -3154,6 +3156,14 @@ void Item_func_case::fix_length_and_dec()
{
if (agg_arg_charsets_for_string_result(collation, agg, nagg))
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++)
+ args[nagg * 2 + 1]= agg[nagg];
+ if (else_expr_num != -1)
+ args[else_expr_num]= agg[nagg++];
}
else
collation.set_numeric();
@@ -3169,20 +3179,53 @@ void Item_func_case::fix_length_and_dec()
agg[0]= args[first_expr_num];
left_result_type= agg[0]->result_type();
+ /*
+ 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 (!(found_types= collect_cmp_types(agg, nagg)))
return;
- if (with_sum_func || current_thd->lex->current_select->group_list.elements)
+ if (found_types & (1 << STRING_RESULT))
{
/*
- See TODO commentary in the setup_copy_fields function:
- item in a group may be wrapped with an Item_copy_string item.
- That item has a STRING_RESULT result type, so we need
- to take this type into account.
+ If we'll do string comparison, we also need to aggregate
+ character set and collation for first/WHEN items and
+ install converters for some of them to cmp_collation when necessary.
+ This is done because cmp_item compatators cannot compare
+ strings in two different character sets.
+ Some examples when we install converters:
+
+ 1. Converter installed for the first expression:
+
+ CASE latin1_item WHEN utf16_item THEN ... END
+
+ is replaced to:
+
+ CASE CONVERT(latin1_item USING utf16) WHEN utf16_item THEN ... END
+
+ 2. Converter installed for the left WHEN item:
+
+ CASE utf16_item WHEN latin1_item THEN ... END
+
+ is replaced to:
+
+ CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END
*/
- found_types |= (1 << item_cmp_type(left_result_type, STRING_RESULT));
+ if (agg_arg_charsets_for_comparison(cmp_collation, agg, nagg))
+ 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).
+ */
+ args[first_expr_num]= agg[0];
+ for (nagg= 0; nagg < ncases / 2; nagg++)
+ args[nagg * 2]= agg[nagg + 1];
}
for (i= 0; i <= (uint)DECIMAL_RESULT; i++)
@@ -3190,9 +3233,6 @@ void Item_func_case::fix_length_and_dec()
if (found_types & (1 << i) && !cmp_items[i])
{
DBUG_ASSERT((Item_result)i != ROW_RESULT);
- if ((Item_result)i == STRING_RESULT &&
- agg_arg_charsets_for_comparison(cmp_collation, agg, nagg))
- return;
if (!(cmp_items[i]=
cmp_item::get_comparator((Item_result)i,
cmp_collation.collation)))
@@ -4154,13 +4194,11 @@ void Item_func_in::fix_length_and_dec()
uint j=0;
for (uint i=1 ; i < arg_count ; i++)
{
- if (!args[i]->null_value) // Skip NULL values
- {
- array->set(j,args[i]);
- j++;
- }
- else
- have_null= 1;
+ array->set(j,args[i]);
+ if (!args[i]->null_value) // Skip NULL values
+ j++;
+ else
+ have_null= 1;
}
if ((array->used_count= j))
array->sort();
@@ -4470,7 +4508,7 @@ bool Item_cond::walk(Item_processor processor, bool walk_subquery, uchar *arg)
Item *Item_cond::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
List_iterator<Item> li(list);
Item *item;
@@ -4878,12 +4916,13 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
return TRUE;
}
- if (escape_item->const_item() && !thd->lex->view_prepare_mode)
+ if (escape_item->const_item())
{
/* If we are on execution stage */
String *escape_str= escape_item->val_str(&cmp.value1);
if (escape_str)
{
+ const char *escape_str_ptr= escape_str->ptr();
if (escape_used_in_parsing && (
(((thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES) &&
escape_str->numchars() != 1) ||
@@ -4898,9 +4937,9 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
CHARSET_INFO *cs= escape_str->charset();
my_wc_t wc;
int rc= cs->cset->mb_wc(cs, &wc,
- (const uchar*) escape_str->ptr(),
- (const uchar*) escape_str->ptr() +
- escape_str->length());
+ (const uchar*) escape_str_ptr,
+ (const uchar*) escape_str_ptr +
+ escape_str->length());
escape= (int) (rc > 0 ? wc : '\\');
}
else
@@ -4917,13 +4956,13 @@ bool Item_func_like::fix_fields(THD *thd, Item **ref)
{
char ch;
uint errors;
- uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str->ptr(),
+ uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str_ptr,
escape_str->length(),
escape_str->charset(), &errors);
escape= cnvlen ? ch : '\\';
}
else
- escape= *(escape_str->ptr());
+ escape= escape_str_ptr ? *escape_str_ptr : '\\';
}
}
else
@@ -5780,21 +5819,23 @@ longlong Item_equal::val_int()
return 0;
List_iterator_fast<Item_field> it(fields);
Item *item= const_item ? const_item : it++;
- if ((null_value= item->is_null()))
- return 0;
eval_item->store_value(item);
+ if ((null_value= item->null_value))
+ return 0;
while ((item_field= it++))
{
/* Skip fields of non-const tables. They haven't been read yet */
if (item_field->field->table->const_table)
{
- if ((null_value= item_field->is_null()) || eval_item->cmp(item_field))
+ int res= eval_item->cmp(item_field);
+ if ((null_value= item_field->null_value) || res)
return 0;
}
}
return 1;
}
+
void Item_equal::fix_length_and_dec()
{
Item *item= get_first(NULL);
@@ -5816,7 +5857,7 @@ bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg)
Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
List_iterator<Item_field> it(fields);
Item *item;