diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/examples/ha_archive.cc | 6 | ||||
-rw-r--r-- | sql/field.cc | 74 | ||||
-rw-r--r-- | sql/item.cc | 100 | ||||
-rw-r--r-- | sql/item.h | 14 | ||||
-rw-r--r-- | sql/item_subselect.cc | 1 | ||||
-rw-r--r-- | sql/sql_derived.cc | 3 |
6 files changed, 134 insertions, 64 deletions
diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index e71ae05734a..55b6455f7ad 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -330,7 +330,6 @@ err: */ int ha_archive::write_row(byte * buf) { - char *pos; z_off_t written; DBUG_ENTER("ha_archive::write_row"); @@ -415,6 +414,7 @@ int ha_archive::get_row(byte *buf) int read; // Bytes read, gzread() returns int char *last; size_t total_blob_length= 0; + Field_blob **field; DBUG_ENTER("ha_archive::get_row"); read= gzread(archive, buf, table->reclength); @@ -428,7 +428,7 @@ int ha_archive::get_row(byte *buf) DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); /* Calculate blob length, we use this for our buffer */ - for (Field_blob **field=table->blob_field; *field ; field++) + for (field=table->blob_field; *field ; field++) total_blob_length += (*field)->get_length(); /* Adjust our row buffer if we need be */ @@ -436,7 +436,7 @@ int ha_archive::get_row(byte *buf) last= (char *)buffer.ptr(); /* Loop through our blobs and read them */ - for (Field_blob **field=table->blob_field; *field ; field++) + for (field=table->blob_field; *field ; field++) { size_t size= (*field)->get_length(); read= gzread(archive, last, size); diff --git a/sql/field.cc b/sql/field.cc index 988dfbcb535..a3a19d93e58 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -172,42 +172,51 @@ static bool test_if_real(const char *str,int length, CHARSET_INFO *cs) FIELD_CAST_STOP */ static Field::field_cast_enum field_cast_decimal[]= -{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, +{Field::FIELD_CAST_DECIMAL, + Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_tiny[]= -{Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, +{Field::FIELD_CAST_TINY, + Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG, Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_short[]= -{Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG, +{Field::FIELD_CAST_SHORT, + Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG, Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_medium[]= -{Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG, +{Field::FIELD_CAST_MEDIUM, + Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG, Field::FIELD_CAST_DOUBLE, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_long[]= -{Field::FIELD_CAST_LONGLONG, +{Field::FIELD_CAST_LONG, + Field::FIELD_CAST_LONGLONG, Field::FIELD_CAST_DOUBLE, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_longlong[]= -{Field::FIELD_CAST_DOUBLE, +{Field::FIELD_CAST_LONGLONG, + Field::FIELD_CAST_DOUBLE, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_float[]= -{Field::FIELD_CAST_DOUBLE, +{Field::FIELD_CAST_FLOAT, + Field::FIELD_CAST_DOUBLE, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_double[]= -{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, +{Field::FIELD_CAST_DOUBLE, + Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_null[]= -{Field::FIELD_CAST_DECIMAL, Field::FIELD_CAST_TINY, Field::FIELD_CAST_SHORT, +{Field::FIELD_CAST_NULL, + Field::FIELD_CAST_DECIMAL, Field::FIELD_CAST_TINY, Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG, Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE, Field::FIELD_CAST_TIMESTAMP, Field::FIELD_CAST_YEAR, @@ -218,44 +227,54 @@ static Field::field_cast_enum field_cast_null[]= Field::FIELD_CAST_GEOM, Field::FIELD_CAST_ENUM, Field::FIELD_CAST_SET, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_timestamp[]= -{Field::FIELD_CAST_DATETIME, +{Field::FIELD_CAST_TIMESTAMP, + Field::FIELD_CAST_DATETIME, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_year[]= -{Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, +{Field::FIELD_CAST_YEAR, + Field::FIELD_CAST_SHORT, Field::FIELD_CAST_MEDIUM, Field::FIELD_CAST_LONG, Field::FIELD_CAST_LONGLONG, Field::FIELD_CAST_FLOAT, Field::FIELD_CAST_DOUBLE, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_date[]= -{Field::FIELD_CAST_DATETIME, +{Field::FIELD_CAST_DATE, + Field::FIELD_CAST_DATETIME, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_newdate[]= -{Field::FIELD_CAST_DATETIME, +{Field::FIELD_CAST_NEWDATE, + Field::FIELD_CAST_DATETIME, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_time[]= -{Field::FIELD_CAST_DATETIME, +{Field::FIELD_CAST_TIME, + Field::FIELD_CAST_DATETIME, Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_datetime[]= -{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, +{Field::FIELD_CAST_DATETIME, + Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_string[]= -{Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; +{Field::FIELD_CAST_STRING, + Field::FIELD_CAST_VARSTRING, Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_varstring[]= -{Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; +{Field::FIELD_CAST_VARSTRING, + Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_blob[]= -{Field::FIELD_CAST_STOP}; +{Field::FIELD_CAST_BLOB, + Field::FIELD_CAST_STOP}; +/* + Geometrical, enum and set fields can be casted only to expressions +*/ static Field::field_cast_enum field_cast_geom[]= {Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_enum[]= -{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, - Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; +{Field::FIELD_CAST_STOP}; static Field::field_cast_enum field_cast_set[]= -{Field::FIELD_CAST_STRING, Field::FIELD_CAST_VARSTRING, - Field::FIELD_CAST_BLOB, Field::FIELD_CAST_STOP}; +{Field::FIELD_CAST_STOP}; // Array of pointers on conversion table for all fields types casting static Field::field_cast_enum *field_cast_array[]= {0, //FIELD_CAST_STOP @@ -270,6 +289,17 @@ static Field::field_cast_enum *field_cast_array[]= }; +/* + Check if field of given type can store a value of this field. + + SYNOPSIS + type type for test + + RETURN + 1 can + 0 can not +*/ + bool Field::field_cast_compatible(Field::field_cast_enum type) { DBUG_ASSERT(type != FIELD_CAST_STOP); diff --git a/sql/item.cc b/sql/item.cc index 14136435a50..b0eb806cc7a 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2486,6 +2486,7 @@ Item_type_holder::Item_type_holder(THD *thd, Item *item) else field_example= 0; max_length= real_length(item); + maybe_null= item->maybe_null; collation.set(item->collation); } @@ -2503,59 +2504,84 @@ static Item_result type_convertor[4][4]= {STRING_RESULT, REAL_RESULT, INT_RESULT, ROW_RESULT}, {ROW_RESULT, ROW_RESULT, ROW_RESULT, ROW_RESULT}}; + +/* + Values of 'from' field can be stored in 'to' field. + + SYNOPSIS + is_attr_compatible() + from Item which values should be saved + to Item where values should be saved + + RETURN + 1 can be saved + 0 can not be saved +*/ + +inline bool is_attr_compatible(Item *from, Item *to) +{ + return ((to->max_length >= from->max_length) && + (to->maybe_null || !from->maybe_null) && + (to->result_type() != STRING_RESULT || + from->result_type() != STRING_RESULT || + my_charset_same(from->collation.collation, + to->collation.collation))); +} + + bool Item_type_holder::join_types(THD *thd, Item *item) { uint32 new_length= real_length(item); - bool change_field= 0, skip_store_field= 0; - Item_result new_type= type_convertor[item_type][item->result_type()]; + bool use_new_field= 0, use_expression_type= 0; + Item_result new_result_type= type_convertor[item_type][item->result_type()]; - // we have both fields + /* + Check if both items point to fields: in this case we + can adjust column types of result table in the union smartly. + */ if (field_example && item->type() == Item::FIELD_ITEM) { Field *field= ((Item_field *)item)->field; - if (field_example->field_cast_type() != field->field_cast_type()) + /* Can 'field_example' field store data of the column? */ + if ((use_new_field= + (!field->field_cast_compatible(field_example->field_cast_type()) || + !is_attr_compatible(item, this)))) { - if (!(change_field= - field_example->field_cast_compatible(field->field_cast_type()))) - { - /* - if old field can't store value of 'worse' new field we will make - decision about result field type based only on Item result type - */ - if (!field->field_cast_compatible(field_example->field_cast_type())) - skip_store_field= 1; - } + /* + The old field can't store value of the new field. + Check if the new field can store value of the old one. + */ + use_expression_type|= + (!field_example->field_cast_compatible(field->field_cast_type()) || + !is_attr_compatible(this, item)); } } + else if (field_example || item->type() == Item::FIELD_ITEM) + { + /* + Expression types can't be mixed with field types, we have to use + expression types. + */ + use_expression_type= 1; + } - // size/type should be changed - if (change_field || - (new_type != item_type) || - (max_length < new_length) || - ((new_type == INT_RESULT) && - (decimals < item->decimals)) || + /* Check whether size/type of the result item should be changed */ + if (use_new_field || use_expression_type || + (new_result_type != item_type) || (new_length > max_length) || (!maybe_null && item->maybe_null) || - (item_type == STRING_RESULT && new_type == STRING_RESULT && + (item_type == STRING_RESULT && !my_charset_same(collation.collation, item->collation.collation))) { - // new field has some parameters worse then current - skip_store_field|= (change_field && - (max_length > new_length) || - ((new_type == INT_RESULT) && - (decimals > item->decimals)) || - (maybe_null && !item->maybe_null) || - (item_type == STRING_RESULT && - new_type == STRING_RESULT && - !my_charset_same(collation.collation, - item->collation.collation))); - /* - It is safe assign pointer on field, because it will be used just after - all JOIN::prepare calls and before any SELECT execution - */ - if (skip_store_field || item->type() != Item::FIELD_ITEM) + if (use_expression_type || item->type() != Item::FIELD_ITEM) field_example= 0; else + { + /* + It is safe to assign a pointer to field here, because it will be used + before any table is closed. + */ field_example= ((Item_field*) item)->field; + } const char *old_cs= collation.collation->name, *old_derivation= collation.derivation_name(); @@ -2572,7 +2598,7 @@ bool Item_type_holder::join_types(THD *thd, Item *item) max_length= max(max_length, new_length); decimals= max(decimals, item->decimals); maybe_null|= item->maybe_null; - item_type= new_type; + item_type= new_result_type; } DBUG_ASSERT(item_type != ROW_RESULT); return 0; diff --git a/sql/item.h b/sql/item.h index 7a1e7c5d0d2..ce52705c341 100644 --- a/sql/item.h +++ b/sql/item.h @@ -218,7 +218,8 @@ public: a constant expression */ virtual bool basic_const_item() const { return 0; } - virtual Item *new_item() { return 0; } /* Only for const items */ + /* cloning of constant items (0 if it is not const) */ + virtual Item *new_item() { return 0; } virtual cond_result eq_cmp_result() const { return COND_OK; } inline uint float_length(uint decimals_par) const { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} @@ -242,11 +243,22 @@ public: virtual bool get_date_result(TIME *ltime,uint fuzzydate) { return get_date(ltime,fuzzydate); } virtual bool is_null() { return 0; } + /* + it is "top level" item of WHERE clause and we do not need correct NULL + handling + */ virtual void top_level_item() {} + /* + set field of temporary table for Item which can be switched on temporary + table during query processing (groupping and so on) + */ virtual void set_result_field(Field *field) {} virtual bool is_result_field() { return 0; } virtual bool is_bool_func() { return 0; } virtual void save_in_result_field(bool no_conversions) {} + /* + set value of aggegate function in case of no rows for groupping were found + */ virtual void no_rows_in_result() {} virtual Item *copy_or_same(THD *thd) { return this; } virtual Item *copy_andor_structure(THD *thd) { return this; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 3ddf9a1c6bf..3dbf4eae55b 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -401,7 +401,6 @@ void Item_singlerow_subselect::fix_length_and_dec() engine->fix_length_and_dec(row); value= *row; } - maybe_null= engine->may_be_null(); } uint Item_singlerow_subselect::cols() diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 05ad2094372..3259e0a4f22 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -224,7 +224,10 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, } } else + { free_tmp_table(thd, table); + unit->cleanup(); + } exit: delete derived_result; |