summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/examples/ha_archive.cc6
-rw-r--r--sql/field.cc74
-rw-r--r--sql/item.cc100
-rw-r--r--sql/item.h14
-rw-r--r--sql/item_subselect.cc1
-rw-r--r--sql/sql_derived.cc3
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;