diff options
author | unknown <evgen@moonbone.local> | 2006-06-18 14:56:35 +0400 |
---|---|---|
committer | unknown <evgen@moonbone.local> | 2006-06-18 14:56:35 +0400 |
commit | 610b1a4ebda3d2f7dec8db7a5e8226ac0f07338c (patch) | |
tree | bc8abc7cba71ffb27a7c5d27a1b756f5b4700da3 /sql/item_cmpfunc.cc | |
parent | 60a9c875e86fabbaf460d9b05fc74941c5169204 (diff) | |
parent | 9ec3f63f7eb9c4b9bcfbcddbc25937475b4edb9f (diff) | |
download | mariadb-git-610b1a4ebda3d2f7dec8db7a5e8226ac0f07338c.tar.gz |
Manually merged
configure.in:
Auto merged
client/mysqlbinlog.cc:
Auto merged
mysql-test/mysql-test-run.pl:
Auto merged
mysql-test/r/archive.result:
Auto merged
mysql-test/r/auto_increment.result:
Auto merged
mysql-test/r/cast.result:
Auto merged
mysql-test/r/ctype_utf8.result:
Auto merged
mysql-test/r/func_group.result:
Auto merged
mysql-test/r/func_str.result:
Auto merged
mysql-test/r/func_time.result:
Auto merged
mysql-test/r/multi_update.result:
Auto merged
mysql-test/r/ndb_lock.result:
Auto merged
mysql-test/r/replace.result:
Auto merged
mysql-test/r/union.result:
Auto merged
mysql-test/t/archive.test:
Auto merged
mysql-test/t/auto_increment.test:
Auto merged
mysql-test/t/delayed.test:
Auto merged
mysql-test/t/func_time.test:
Auto merged
mysql-test/t/multi_update.test:
Auto merged
mysql-test/t/ndb_lock.test:
Auto merged
mysql-test/t/select.test:
Auto merged
sql/field.cc:
Auto merged
sql/ha_ndbcluster.cc:
Auto merged
sql/item.h:
Auto merged
sql/item_cmpfunc.h:
Auto merged
sql/item_func.cc:
Auto merged
sql/item_strfunc.cc:
Auto merged
sql/item_timefunc.cc:
Auto merged
sql/opt_range.cc:
Auto merged
sql/opt_sum.cc:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_insert.cc:
Auto merged
sql/sql_lex.cc:
Auto merged
sql/sql_lex.h:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_select.cc:
Auto merged
sql/sql_select.h:
Auto merged
sql/sql_yacc.yy:
Auto merged
sql/structs.h:
Auto merged
storage/archive/ha_archive.cc:
Auto merged
tests/mysql_client_test.c:
Auto merged
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r-- | sql/item_cmpfunc.cc | 154 |
1 files changed, 132 insertions, 22 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3a1f4b50458..a3464c3bc25 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -63,25 +63,144 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) } +/* + Aggregates result types from the array of items. + + SYNOPSIS: + agg_cmp_type() + thd thread handle + type [out] the aggregated type + items array of items to aggregate the type from + nitems number of items in the array + + DESCRIPTION + This function aggregates result types from the array of items. Found type + supposed to be used later for comparison of values of these items. + Aggregation itself is performed by the item_cmp_type() function. + + NOTES + Aggregation rules: + If all items are constants the type will be aggregated from all items. + If there are some non-constant items then only types of non-constant + items will be used for aggregation. + If there are DATE/TIME fields/functions in the list and no string + fields/functions in the list then: + The INT_RESULT type will be used for aggregation instead of original + result type of any DATE/TIME field/function in the list + All constant items in the list will be converted to a DATE/TIME using + found field or result field of found function. + + Implementation notes: + The code is equivalent to: + 1. Check the list for presence of a STRING field/function. + Collect the is_const flag. + 2. Get a Field* object to use for type coercion + 3. Perform type conversion. + 1 and 2 are implemented in 2 loops. The first searches for a DATE/TIME + field/function and checks presence of a STRING field/function. + The second loop works only if a DATE/TIME field/function is found. + It checks presence of a STRING field/function in the rest of the list. + + TODO + 1) The current implementation can produce false comparison results for + expressions like: + date_time_field BETWEEN string_field_with_dates AND string_constant + if the string_constant will omit some of leading zeroes. + In order to fully implement correct comparison of DATE/TIME the new + DATETIME_RESULT result type should be introduced and agg_cmp_type() + should return the DATE/TIME field used for the conversion. Later + this field can be used by comparison functions like Item_func_between to + convert string values to ints on the fly and thus return correct results. + This modification will affect functions BETWEEN, IN and CASE. + + 2) If in the list a DATE field/function and a DATETIME field/function + are present in the list then the first found field/function will be + used for conversion. This may lead to wrong results and probably should + be fixed. +*/ + static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems) { uint i; + Item::Type res= (Item::Type)0; + /* Used only for date/time fields, max_length = 19 */ + char buff[20]; + uchar null_byte; Field *field= NULL; - /* If the first argument is a FIELD_ITEM, pull out the field. */ - if (items[0]->real_item()->type() == Item::FIELD_ITEM) - field=((Item_field *)(items[0]->real_item()))->field; - /* But if it can't be compared as a longlong, we don't really care. */ - if (field && !field->can_be_compared_as_longlong()) - field= NULL; + /* Search for date/time fields/functions */ + for (i= 0; i < nitems; i++) + { + if (!items[i]->result_as_longlong()) + { + /* Do not convert anything if a string field/function is present */ + if (!items[i]->const_item() && items[i]->result_type() == STRING_RESULT) + { + i= nitems; + break; + } + continue; + } + if ((res= items[i]->real_item()->type()) == Item::FIELD_ITEM) + { + field= ((Item_field *)items[i]->real_item())->field; + break; + } + else if (res == Item::FUNC_ITEM) + { + field= items[i]->tmp_table_field_from_field_type(0); + if (field) + field->move_field(buff, &null_byte, 0); + break; + } + } + if (field) + { + /* Check the rest of the list for presence of a string field/function. */ + for (i++ ; i < nitems; i++) + { + if (!items[i]->const_item() && items[i]->result_type() == STRING_RESULT && + !items[i]->result_as_longlong()) + { + if (res == Item::FUNC_ITEM) + delete field; + field= 0; + break; + } + } + } + /* Reset to 0 on first occurence of non-const item. 1 otherwise */ + bool is_const= items[0]->const_item(); + /* + If the first item is a date/time function then its result should be + compared as int + */ + if (field) + { + /* Suppose we are comparing dates and some non-constant items are present. */ + type[0]= INT_RESULT; + is_const= 0; + } + else + type[0]= items[0]->result_type(); - type[0]= items[0]->result_type(); - for (i= 1; i < nitems; i++) + for (i= 0; i < nitems ; i++) { - type[0]= item_cmp_type(type[0], items[i]->result_type()); - if (field && convert_constant_item(thd, field, &items[i])) - type[0]= INT_RESULT; + if (!items[i]->const_item()) + { + Item_result result= field && items[i]->result_as_longlong() ? + INT_RESULT : items[i]->result_type(); + type[0]= is_const ? result : item_cmp_type(type[0], result); + is_const= 0; + } + else if (is_const) + type[0]= item_cmp_type(type[0], items[i]->result_type()); + else if (field) + convert_constant_item(thd, field, &items[i]); } + + if (res == Item::FUNC_ITEM && field) + delete field; } @@ -238,14 +357,6 @@ static bool convert_constant_item(THD *thd, Field *field, Item **item) if (!(*item)->with_subselect && (*item)->const_item()) { /* For comparison purposes allow invalid dates like 2000-01-32 */ - TABLE *table= field->table; - ulong orig_sql_mode= table->in_use->variables.sql_mode; - my_bitmap_map *old_write_map= - dbug_tmp_use_all_columns(table, table->write_set); - my_bitmap_map *old_read_map= - dbug_tmp_use_all_columns(table, table->read_set); - - table->in_use->variables.sql_mode|= MODE_INVALID_DATES; if (!(*item)->save_in_field(field, 1) && !((*item)->null_value)) { Item *tmp= new Item_int_with_ref(field->val_int(), *item, @@ -1106,9 +1217,8 @@ void Item_func_between::fix_length_and_dec() return; agg_cmp_type(thd, &cmp_type, args, 3); - if (cmp_type == STRING_RESULT && - agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV)) - return; + if (cmp_type == STRING_RESULT) + agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV); } |