mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-9407 Illegal mix of collation when using GROUP_CONCAT in a VIEW
MDEV-9408 CREATE TABLE SELECT MAX(int_column) creates different columns for table vs view There were three almost identical pieces of the code: - Field *Item_func::tmp_table_field(); - Field *Item_sum::create_tmp_field(); - Field *create_tmp_field_from_item(); with a difference in very small details (hence the bugs): Only Item_func::tmp_table_field() was correct, the other two were not. Removing the two incorrect pieces of the redundant code. Joining these three functions/methods into a single virtual method Item::create_tmp_field(). Additionally, moving Item::make_string_field() and Item::tmp_table_field_from_field_type() from the public into the protected section of the class declaration, as they are now not needed outside of Item.
This commit is contained in:
@@ -13728,3 +13728,23 @@ SET NAMES utf8;
|
|||||||
#
|
#
|
||||||
# End of MariaDB-10.1 tests
|
# End of MariaDB-10.1 tests
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# Start of MariaDB-10.2 tests
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# MDEV-9407 Illegal mix of collation when using GROUP_CONCAT in a VIEW
|
||||||
|
#
|
||||||
|
SET NAMES utf8;
|
||||||
|
CREATE TABLE t1 (col1 VARCHAR(12) CHARACTER SET utf8 COLLATE utf8_unicode_ci);
|
||||||
|
INSERT INTO t1 VALUES ('a'),('b');
|
||||||
|
CREATE VIEW v1 AS SELECT group_concat('f') AS col1;
|
||||||
|
SELECT col1 FROM v1 UNION SELECT col1 FROM t1;
|
||||||
|
col1
|
||||||
|
f
|
||||||
|
a
|
||||||
|
b
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# End of MariaDB-10.2 tests
|
||||||
|
#
|
||||||
|
@@ -5878,3 +5878,39 @@ DROP TABLE t1;
|
|||||||
#
|
#
|
||||||
# End of 10.1 tests
|
# End of 10.1 tests
|
||||||
#
|
#
|
||||||
|
#
|
||||||
|
# Start of 10.2 tests
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# MDEV-9408 CREATE TABLE SELECT MAX(int_column) creates different columns for table vs view
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
id int(11) NOT NULL PRIMARY KEY,
|
||||||
|
country varchar(32),
|
||||||
|
code int(11) default NULL
|
||||||
|
);
|
||||||
|
INSERT INTO t1 VALUES (1,'ITALY',100),(2,'ITALY',200),(3,'FRANCE',100), (4,'ITALY',100);
|
||||||
|
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||||
|
CREATE TABLE t2 AS
|
||||||
|
SELECT code, COUNT(DISTINCT country), MAX(id) FROM t1 GROUP BY code ORDER BY MAX(id);
|
||||||
|
SHOW CREATE TABLE t2;
|
||||||
|
Table Create Table
|
||||||
|
t2 CREATE TABLE `t2` (
|
||||||
|
`code` int(11) DEFAULT NULL,
|
||||||
|
`COUNT(DISTINCT country)` bigint(21) NOT NULL,
|
||||||
|
`MAX(id)` int(11)
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
CREATE TABLE t3 AS
|
||||||
|
SELECT code, COUNT(DISTINCT country), MAX(id) FROM v1 GROUP BY code ORDER BY MAX(id);
|
||||||
|
SHOW CREATE TABLE t3;
|
||||||
|
Table Create Table
|
||||||
|
t3 CREATE TABLE `t3` (
|
||||||
|
`code` int(11) DEFAULT NULL,
|
||||||
|
`COUNT(DISTINCT country)` bigint(21) NOT NULL,
|
||||||
|
`MAX(id)` int(11) DEFAULT NULL
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
#
|
||||||
|
# End of 10.2 tests
|
||||||
|
#
|
||||||
|
@@ -646,3 +646,24 @@ SET NAMES utf8;
|
|||||||
--echo #
|
--echo #
|
||||||
--echo # End of MariaDB-10.1 tests
|
--echo # End of MariaDB-10.1 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Start of MariaDB-10.2 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-9407 Illegal mix of collation when using GROUP_CONCAT in a VIEW
|
||||||
|
--echo #
|
||||||
|
SET NAMES utf8;
|
||||||
|
CREATE TABLE t1 (col1 VARCHAR(12) CHARACTER SET utf8 COLLATE utf8_unicode_ci);
|
||||||
|
INSERT INTO t1 VALUES ('a'),('b');
|
||||||
|
CREATE VIEW v1 AS SELECT group_concat('f') AS col1;
|
||||||
|
SELECT col1 FROM v1 UNION SELECT col1 FROM t1;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of MariaDB-10.2 tests
|
||||||
|
--echo #
|
||||||
|
@@ -5741,3 +5741,31 @@ DROP TABLE t1;
|
|||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.1 tests
|
--echo # End of 10.1 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Start of 10.2 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-9408 CREATE TABLE SELECT MAX(int_column) creates different columns for table vs view
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (
|
||||||
|
id int(11) NOT NULL PRIMARY KEY,
|
||||||
|
country varchar(32),
|
||||||
|
code int(11) default NULL
|
||||||
|
);
|
||||||
|
INSERT INTO t1 VALUES (1,'ITALY',100),(2,'ITALY',200),(3,'FRANCE',100), (4,'ITALY',100);
|
||||||
|
CREATE VIEW v1 AS SELECT * FROM t1;
|
||||||
|
CREATE TABLE t2 AS
|
||||||
|
SELECT code, COUNT(DISTINCT country), MAX(id) FROM t1 GROUP BY code ORDER BY MAX(id);
|
||||||
|
SHOW CREATE TABLE t2;
|
||||||
|
CREATE TABLE t3 AS
|
||||||
|
SELECT code, COUNT(DISTINCT country), MAX(id) FROM v1 GROUP BY code ORDER BY MAX(id);
|
||||||
|
SHOW CREATE TABLE t3;
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP TABLE t1,t2,t3;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.2 tests
|
||||||
|
--echo #
|
||||||
|
30
sql/item.h
30
sql/item.h
@@ -656,6 +656,14 @@ protected:
|
|||||||
|
|
||||||
SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param);
|
SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param);
|
||||||
|
|
||||||
|
virtual Field *make_string_field(TABLE *table);
|
||||||
|
Field *tmp_table_field_from_field_type(TABLE *table,
|
||||||
|
bool fixed_length,
|
||||||
|
bool set_blob_packlength);
|
||||||
|
Field *create_tmp_field(bool group, TABLE *table,
|
||||||
|
uint convert_blob_length,
|
||||||
|
uint convert_int_length);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/*
|
/*
|
||||||
Cache val_str() into the own buffer, e.g. to evaluate constant
|
Cache val_str() into the own buffer, e.g. to evaluate constant
|
||||||
@@ -722,7 +730,6 @@ public:
|
|||||||
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
|
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
|
||||||
virtual void cleanup();
|
virtual void cleanup();
|
||||||
virtual void make_field(THD *thd, Send_field *field);
|
virtual void make_field(THD *thd, Send_field *field);
|
||||||
virtual Field *make_string_field(TABLE *table);
|
|
||||||
virtual bool fix_fields(THD *, Item **);
|
virtual bool fix_fields(THD *, Item **);
|
||||||
/*
|
/*
|
||||||
Fix after some tables has been pulled out. Basically re-calculate all
|
Fix after some tables has been pulled out. Basically re-calculate all
|
||||||
@@ -1046,8 +1053,6 @@ public:
|
|||||||
int save_str_value_in_field(Field *field, String *result);
|
int save_str_value_in_field(Field *field, String *result);
|
||||||
|
|
||||||
virtual Field *get_tmp_table_field() { return 0; }
|
virtual Field *get_tmp_table_field() { return 0; }
|
||||||
/* This is also used to create fields in CREATE ... SELECT: */
|
|
||||||
virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
|
|
||||||
virtual Field *create_field_for_create_select(THD *thd, TABLE *table);
|
virtual Field *create_field_for_create_select(THD *thd, TABLE *table);
|
||||||
virtual Field *create_field_for_schema(THD *thd, TABLE *table);
|
virtual Field *create_field_for_schema(THD *thd, TABLE *table);
|
||||||
virtual const char *full_name() const { return name ? name : "???"; }
|
virtual const char *full_name() const { return name ? name : "???"; }
|
||||||
@@ -1655,9 +1660,18 @@ public:
|
|||||||
// used in row subselects to get value of elements
|
// used in row subselects to get value of elements
|
||||||
virtual void bring_value() {}
|
virtual void bring_value() {}
|
||||||
|
|
||||||
Field *tmp_table_field_from_field_type(TABLE *table,
|
virtual Field *create_tmp_field(bool group, TABLE *table,
|
||||||
bool fixed_length,
|
uint convert_blob_length)
|
||||||
bool set_blob_packlength);
|
{
|
||||||
|
/*
|
||||||
|
Values with MY_INT32_NUM_DECIMAL_DIGITS digits may or may not fit into
|
||||||
|
Field_long : make them Field_longlong.
|
||||||
|
*/
|
||||||
|
return create_tmp_field(false, table,
|
||||||
|
convert_blob_length,
|
||||||
|
MY_INT32_NUM_DECIMAL_DIGITS - 2);
|
||||||
|
}
|
||||||
|
|
||||||
virtual Item_field *field_for_view_update() { return 0; }
|
virtual Item_field *field_for_view_update() { return 0; }
|
||||||
|
|
||||||
virtual Item *neg_transformer(THD *thd) { return NULL; }
|
virtual Item *neg_transformer(THD *thd) { return NULL; }
|
||||||
@@ -2252,7 +2266,6 @@ public:
|
|||||||
{}
|
{}
|
||||||
~Item_result_field() {} /* Required with gcc 2.95 */
|
~Item_result_field() {} /* Required with gcc 2.95 */
|
||||||
Field *get_tmp_table_field() { return result_field; }
|
Field *get_tmp_table_field() { return result_field; }
|
||||||
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
|
|
||||||
/*
|
/*
|
||||||
This implementation of used_tables() used by Item_avg_field and
|
This implementation of used_tables() used by Item_avg_field and
|
||||||
Item_variance_field which work when only temporary table left, so theu
|
Item_variance_field which work when only temporary table left, so theu
|
||||||
@@ -3440,8 +3453,6 @@ public:
|
|||||||
{ return val_real_from_date(); }
|
{ return val_real_from_date(); }
|
||||||
my_decimal *val_decimal(my_decimal *decimal_value)
|
my_decimal *val_decimal(my_decimal *decimal_value)
|
||||||
{ return val_decimal_from_date(decimal_value); }
|
{ return val_decimal_from_date(decimal_value); }
|
||||||
Field *tmp_table_field(TABLE *table)
|
|
||||||
{ return tmp_table_field_from_field_type(table, false, false); }
|
|
||||||
int save_in_field(Field *field, bool no_conversions)
|
int save_in_field(Field *field, bool no_conversions)
|
||||||
{ return save_date_in_field(field); }
|
{ return save_date_in_field(field); }
|
||||||
};
|
};
|
||||||
@@ -3947,7 +3958,6 @@ public:
|
|||||||
enum_field_types field_type() const { return (*ref)->field_type(); }
|
enum_field_types field_type() const { return (*ref)->field_type(); }
|
||||||
Field *get_tmp_table_field()
|
Field *get_tmp_table_field()
|
||||||
{ return result_field ? result_field : (*ref)->get_tmp_table_field(); }
|
{ return result_field ? result_field : (*ref)->get_tmp_table_field(); }
|
||||||
Field *tmp_table_field(TABLE *t_arg) { return 0; }
|
|
||||||
Item *get_tmp_table_item(THD *thd);
|
Item *get_tmp_table_item(THD *thd);
|
||||||
table_map used_tables() const;
|
table_map used_tables() const;
|
||||||
void update_used_tables();
|
void update_used_tables();
|
||||||
|
@@ -2300,11 +2300,6 @@ uint Item_func_case_abbreviation2::decimal_precision2(Item **args) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Field *Item_func_ifnull::tmp_table_field(TABLE *table)
|
|
||||||
{
|
|
||||||
return tmp_table_field_from_field_type(table, false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
double
|
double
|
||||||
Item_func_ifnull::real_op()
|
Item_func_ifnull::real_op()
|
||||||
{
|
{
|
||||||
|
@@ -940,7 +940,9 @@ public:
|
|||||||
maybe_null= args[1]->maybe_null;
|
maybe_null= args[1]->maybe_null;
|
||||||
}
|
}
|
||||||
const char *func_name() const { return "ifnull"; }
|
const char *func_name() const { return "ifnull"; }
|
||||||
Field *tmp_table_field(TABLE *table);
|
Field *create_field_for_create_select(THD *thd, TABLE *table)
|
||||||
|
{ return tmp_table_field_from_field_type(table, false, false); }
|
||||||
|
|
||||||
table_map not_null_tables() const { return 0; }
|
table_map not_null_tables() const { return 0; }
|
||||||
uint decimal_precision() const
|
uint decimal_precision() const
|
||||||
{
|
{
|
||||||
|
@@ -509,43 +509,6 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Field *Item_func::tmp_table_field(TABLE *table)
|
|
||||||
{
|
|
||||||
Field *field= NULL;
|
|
||||||
MEM_ROOT *mem_root= table->in_use->mem_root;
|
|
||||||
|
|
||||||
switch (result_type()) {
|
|
||||||
case INT_RESULT:
|
|
||||||
if (max_char_length() > MY_INT32_NUM_DECIMAL_DIGITS)
|
|
||||||
field= new (mem_root)
|
|
||||||
Field_longlong(max_char_length(), maybe_null, name,
|
|
||||||
unsigned_flag);
|
|
||||||
else
|
|
||||||
field= new (mem_root)
|
|
||||||
Field_long(max_char_length(), maybe_null, name,
|
|
||||||
unsigned_flag);
|
|
||||||
break;
|
|
||||||
case REAL_RESULT:
|
|
||||||
field= new (mem_root)
|
|
||||||
Field_double(max_char_length(), maybe_null, name, decimals);
|
|
||||||
break;
|
|
||||||
case STRING_RESULT:
|
|
||||||
return make_string_field(table);
|
|
||||||
case DECIMAL_RESULT:
|
|
||||||
field= Field_new_decimal::create_from_item(mem_root, this);
|
|
||||||
break;
|
|
||||||
case ROW_RESULT:
|
|
||||||
case TIME_RESULT:
|
|
||||||
// This case should never be chosen
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
field= 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (field)
|
|
||||||
field->init(table);
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bool Item_func::is_expensive_processor(uchar *arg)
|
bool Item_func::is_expensive_processor(uchar *arg)
|
||||||
{
|
{
|
||||||
@@ -2908,10 +2871,10 @@ void Item_func_min_max::fix_length_and_dec()
|
|||||||
collation.set_numeric();
|
collation.set_numeric();
|
||||||
fix_char_length(float_length(decimals));
|
fix_char_length(float_length(decimals));
|
||||||
/*
|
/*
|
||||||
Set type to DOUBLE, as Item_func::tmp_table_field() does not
|
Set type to DOUBLE, as Item_func::create_tmp_field() does not
|
||||||
distinguish between DOUBLE and FLOAT and always creates Field_double.
|
distinguish between DOUBLE and FLOAT and always creates Field_double.
|
||||||
Perhaps we should eventually change this to use agg_field_type() here,
|
Perhaps we should eventually change this to use agg_field_type() here,
|
||||||
and fix Item_func::tmp_table_field() to create Field_float when possible.
|
and fix Item_func::create_tmp_field() to create Field_float when possible.
|
||||||
*/
|
*/
|
||||||
set_handler_by_field_type(MYSQL_TYPE_DOUBLE);
|
set_handler_by_field_type(MYSQL_TYPE_DOUBLE);
|
||||||
break;
|
break;
|
||||||
@@ -6801,16 +6764,6 @@ longlong Item_func_found_rows::val_int()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Field *
|
|
||||||
Item_func_sp::tmp_table_field(TABLE *t_arg)
|
|
||||||
{
|
|
||||||
DBUG_ENTER("Item_func_sp::tmp_table_field");
|
|
||||||
|
|
||||||
DBUG_ASSERT(sp_result_field);
|
|
||||||
DBUG_RETURN(sp_result_field);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Checks if requested access to function can be granted to user.
|
@brief Checks if requested access to function can be granted to user.
|
||||||
If function isn't found yet, it searches function first.
|
If function isn't found yet, it searches function first.
|
||||||
|
@@ -171,12 +171,11 @@ public:
|
|||||||
}
|
}
|
||||||
void signal_divide_by_null();
|
void signal_divide_by_null();
|
||||||
friend class udf_handler;
|
friend class udf_handler;
|
||||||
Field *tmp_table_field() { return result_field; }
|
|
||||||
Field *tmp_table_field(TABLE *t_arg);
|
|
||||||
Field *create_field_for_create_select(THD *thd, TABLE *table)
|
Field *create_field_for_create_select(THD *thd, TABLE *table)
|
||||||
{
|
{
|
||||||
|
DBUG_ASSERT(thd == table->in_use);
|
||||||
return result_type() != STRING_RESULT ?
|
return result_type() != STRING_RESULT ?
|
||||||
tmp_table_field(table) :
|
create_tmp_field(false, table, 0, MY_INT32_NUM_DECIMAL_DIGITS) :
|
||||||
tmp_table_field_from_field_type(table, false, false);
|
tmp_table_field_from_field_type(table, false, false);
|
||||||
}
|
}
|
||||||
Item *get_tmp_table_item(THD *thd);
|
Item *get_tmp_table_item(THD *thd);
|
||||||
@@ -1767,7 +1766,7 @@ public:
|
|||||||
Field *create_field_for_create_select(THD *thd, TABLE *table)
|
Field *create_field_for_create_select(THD *thd, TABLE *table)
|
||||||
{
|
{
|
||||||
return result_type() != STRING_RESULT ?
|
return result_type() != STRING_RESULT ?
|
||||||
tmp_table_field(table) :
|
create_tmp_field(false, table, 0, MY_INT32_NUM_DECIMAL_DIGITS) :
|
||||||
tmp_table_field_from_field_type(table, false, true);
|
tmp_table_field_from_field_type(table, false, true);
|
||||||
}
|
}
|
||||||
table_map used_tables() const
|
table_map used_tables() const
|
||||||
@@ -2136,8 +2135,12 @@ public:
|
|||||||
|
|
||||||
enum enum_field_types field_type() const;
|
enum enum_field_types field_type() const;
|
||||||
|
|
||||||
Field *tmp_table_field(TABLE *t_arg);
|
Field *create_field_for_create_select(THD *thd, TABLE *table)
|
||||||
|
{
|
||||||
|
return result_type() != STRING_RESULT ?
|
||||||
|
sp_result_field :
|
||||||
|
tmp_table_field_from_field_type(table, false, false);
|
||||||
|
}
|
||||||
void make_field(THD *thd, Send_field *tmp_field);
|
void make_field(THD *thd, Send_field *tmp_field);
|
||||||
|
|
||||||
Item_result result_type() const;
|
Item_result result_type() const;
|
||||||
|
@@ -41,7 +41,7 @@
|
|||||||
#include "opt_range.h"
|
#include "opt_range.h"
|
||||||
|
|
||||||
|
|
||||||
Field *Item_geometry_func::tmp_table_field(TABLE *t_arg)
|
Field *Item_geometry_func::create_field_for_create_select(THD *thd, TABLE *t_arg)
|
||||||
{
|
{
|
||||||
Field *result;
|
Field *result;
|
||||||
if ((result= new Field_geom(max_length, maybe_null, name, t_arg->s,
|
if ((result= new Field_geom(max_length, maybe_null, name, t_arg->s,
|
||||||
|
@@ -40,7 +40,7 @@ public:
|
|||||||
Item_geometry_func(THD *thd, List<Item> &list): Item_str_func(thd, list) {}
|
Item_geometry_func(THD *thd, List<Item> &list): Item_str_func(thd, list) {}
|
||||||
void fix_length_and_dec();
|
void fix_length_and_dec();
|
||||||
enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; }
|
enum_field_types field_type() const { return MYSQL_TYPE_GEOMETRY; }
|
||||||
Field *tmp_table_field(TABLE *t_arg);
|
Field *create_field_for_create_select(THD *thd, TABLE *table);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Item_func_geometry_from_text: public Item_geometry_func
|
class Item_func_geometry_from_text: public Item_geometry_func
|
||||||
|
@@ -496,44 +496,6 @@ Item *Item_sum::get_tmp_table_item(THD *thd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Field *Item_sum::create_tmp_field(bool group, TABLE *table,
|
|
||||||
uint convert_blob_length)
|
|
||||||
{
|
|
||||||
Field *UNINIT_VAR(field);
|
|
||||||
MEM_ROOT *mem_root= table->in_use->mem_root;
|
|
||||||
|
|
||||||
switch (result_type()) {
|
|
||||||
case REAL_RESULT:
|
|
||||||
field= new (mem_root)
|
|
||||||
Field_double(max_length, maybe_null, name, decimals, TRUE);
|
|
||||||
break;
|
|
||||||
case INT_RESULT:
|
|
||||||
field= new (mem_root)
|
|
||||||
Field_longlong(max_length, maybe_null, name, unsigned_flag);
|
|
||||||
break;
|
|
||||||
case STRING_RESULT:
|
|
||||||
if (max_length/collation.collation->mbmaxlen <= 255 ||
|
|
||||||
convert_blob_length > Field_varstring::MAX_SIZE ||
|
|
||||||
!convert_blob_length)
|
|
||||||
return make_string_field(table);
|
|
||||||
field= new (mem_root) Field_varstring(convert_blob_length, maybe_null,
|
|
||||||
name, table->s, collation.collation);
|
|
||||||
break;
|
|
||||||
case DECIMAL_RESULT:
|
|
||||||
field= Field_new_decimal::create_from_item(mem_root, this);
|
|
||||||
break;
|
|
||||||
case ROW_RESULT:
|
|
||||||
case TIME_RESULT:
|
|
||||||
// This case should never be choosen
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (field)
|
|
||||||
field->init(table);
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Item_sum::update_used_tables ()
|
void Item_sum::update_used_tables ()
|
||||||
{
|
{
|
||||||
if (!Item_sum::const_item())
|
if (!Item_sum::const_item())
|
||||||
|
@@ -481,8 +481,12 @@ public:
|
|||||||
}
|
}
|
||||||
virtual void make_unique() { force_copy_fields= TRUE; }
|
virtual void make_unique() { force_copy_fields= TRUE; }
|
||||||
Item *get_tmp_table_item(THD *thd);
|
Item *get_tmp_table_item(THD *thd);
|
||||||
virtual Field *create_tmp_field(bool group, TABLE *table,
|
Field *create_tmp_field(bool group, TABLE *table,
|
||||||
uint convert_blob_length);
|
uint convert_blob_length)
|
||||||
|
{
|
||||||
|
return Item::create_tmp_field(group, table, convert_blob_length,
|
||||||
|
MY_INT32_NUM_DECIMAL_DIGITS);
|
||||||
|
}
|
||||||
virtual bool collect_outer_ref_processor(uchar *param);
|
virtual bool collect_outer_ref_processor(uchar *param);
|
||||||
bool init_sum_func_check(THD *thd);
|
bool init_sum_func_check(THD *thd);
|
||||||
bool check_sum_func(THD *thd, Item **ref);
|
bool check_sum_func(THD *thd, Item **ref);
|
||||||
@@ -1093,7 +1097,6 @@ public:
|
|||||||
}
|
}
|
||||||
table_map used_tables() const { return (table_map) 1L; }
|
table_map used_tables() const { return (table_map) 1L; }
|
||||||
Field *get_tmp_table_field() { DBUG_ASSERT(0); return NULL; }
|
Field *get_tmp_table_field() { DBUG_ASSERT(0); return NULL; }
|
||||||
Field *tmp_table_field(TABLE *) { DBUG_ASSERT(0); return NULL; }
|
|
||||||
void set_result_field(Field *) { DBUG_ASSERT(0); }
|
void set_result_field(Field *) { DBUG_ASSERT(0); }
|
||||||
void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); }
|
void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); }
|
||||||
};
|
};
|
||||||
@@ -1483,6 +1486,8 @@ class Item_func_group_concat : public Item_sum
|
|||||||
friend int dump_leaf_key(void* key_arg,
|
friend int dump_leaf_key(void* key_arg,
|
||||||
element_count count __attribute__((unused)),
|
element_count count __attribute__((unused)),
|
||||||
void* item_arg);
|
void* item_arg);
|
||||||
|
protected:
|
||||||
|
virtual Field *make_string_field(TABLE *table);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Item_func_group_concat(THD *thd, Name_resolution_context *context_arg,
|
Item_func_group_concat(THD *thd, Name_resolution_context *context_arg,
|
||||||
@@ -1497,7 +1502,6 @@ public:
|
|||||||
const char *func_name() const { return "group_concat"; }
|
const char *func_name() const { return "group_concat"; }
|
||||||
virtual Item_result result_type () const { return STRING_RESULT; }
|
virtual Item_result result_type () const { return STRING_RESULT; }
|
||||||
virtual Item_result cmp_type () const { return STRING_RESULT; }
|
virtual Item_result cmp_type () const { return STRING_RESULT; }
|
||||||
virtual Field *make_string_field(TABLE *table);
|
|
||||||
enum_field_types field_type() const
|
enum_field_types field_type() const
|
||||||
{
|
{
|
||||||
if (too_big_for_varchar())
|
if (too_big_for_varchar())
|
||||||
|
@@ -502,7 +502,7 @@ public:
|
|||||||
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date) { DBUG_ASSERT(0); return 1; }
|
bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date) { DBUG_ASSERT(0); return 1; }
|
||||||
my_decimal *val_decimal(my_decimal *decimal_value)
|
my_decimal *val_decimal(my_decimal *decimal_value)
|
||||||
{ return val_decimal_from_date(decimal_value); }
|
{ return val_decimal_from_date(decimal_value); }
|
||||||
Field *tmp_table_field(TABLE *table)
|
Field *create_field_for_create_select(THD *thd, TABLE *table)
|
||||||
{ return tmp_table_field_from_field_type(table, false, false); }
|
{ return tmp_table_field_from_field_type(table, false, false); }
|
||||||
int save_in_field(Field *field, bool no_conversions)
|
int save_in_field(Field *field, bool no_conversions)
|
||||||
{ return save_date_in_field(field); }
|
{ return save_date_in_field(field); }
|
||||||
|
@@ -3892,7 +3892,7 @@ void select_insert::abort_result_set() {
|
|||||||
Field *Item::create_field_for_create_select(THD *thd, TABLE *table)
|
Field *Item::create_field_for_create_select(THD *thd, TABLE *table)
|
||||||
{
|
{
|
||||||
Field *def_field, *tmp_field;
|
Field *def_field, *tmp_field;
|
||||||
return create_tmp_field(thd, table, this, type(),
|
return ::create_tmp_field(thd, table, this, type(),
|
||||||
(Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0, 0);
|
(Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15681,6 +15681,73 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field,
|
|||||||
return new_field;
|
return new_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Field *Item::create_tmp_field(bool group, TABLE *table,
|
||||||
|
uint convert_blob_length,
|
||||||
|
uint convert_int_length)
|
||||||
|
{
|
||||||
|
Field *UNINIT_VAR(new_field);
|
||||||
|
MEM_ROOT *mem_root= table->in_use->mem_root;
|
||||||
|
|
||||||
|
switch (cmp_type()) {
|
||||||
|
case REAL_RESULT:
|
||||||
|
new_field= new (mem_root)
|
||||||
|
Field_double(max_length, maybe_null, name, decimals, TRUE);
|
||||||
|
break;
|
||||||
|
case INT_RESULT:
|
||||||
|
/*
|
||||||
|
Select an integer type with the minimal fit precision.
|
||||||
|
convert_int_length is sign inclusive, don't consider the sign.
|
||||||
|
*/
|
||||||
|
if (max_char_length() > convert_int_length)
|
||||||
|
new_field= new (mem_root)
|
||||||
|
Field_longlong(max_char_length(), maybe_null, name, unsigned_flag);
|
||||||
|
else
|
||||||
|
new_field= new (mem_root)
|
||||||
|
Field_long(max_char_length(), maybe_null, name, unsigned_flag);
|
||||||
|
break;
|
||||||
|
case TIME_RESULT:
|
||||||
|
new_field= tmp_table_field_from_field_type(table, true, false);
|
||||||
|
break;
|
||||||
|
case STRING_RESULT:
|
||||||
|
DBUG_ASSERT(collation.collation);
|
||||||
|
|
||||||
|
/*
|
||||||
|
GEOMETRY fields have STRING_RESULT result type.
|
||||||
|
To preserve type they needed to be handled separately.
|
||||||
|
*/
|
||||||
|
if (field_type() == MYSQL_TYPE_GEOMETRY)
|
||||||
|
new_field= tmp_table_field_from_field_type(table, true, false);
|
||||||
|
/*
|
||||||
|
Make sure that the blob fits into a Field_varstring which has
|
||||||
|
2-byte lenght.
|
||||||
|
*/
|
||||||
|
else if (max_length / collation.collation->mbmaxlen > 255 &&
|
||||||
|
convert_blob_length <= Field_varstring::MAX_SIZE &&
|
||||||
|
convert_blob_length)
|
||||||
|
new_field= new (mem_root)
|
||||||
|
Field_varstring(convert_blob_length, maybe_null,
|
||||||
|
name, table->s, collation.collation);
|
||||||
|
else
|
||||||
|
new_field= make_string_field(table);
|
||||||
|
new_field->set_derivation(collation.derivation);
|
||||||
|
break;
|
||||||
|
case DECIMAL_RESULT:
|
||||||
|
new_field= Field_new_decimal::create_from_item(mem_root, this);
|
||||||
|
break;
|
||||||
|
case ROW_RESULT:
|
||||||
|
// This case should never be choosen
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
new_field= 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (new_field)
|
||||||
|
new_field->init(table);
|
||||||
|
return new_field;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create field for temporary table using type of given item.
|
Create field for temporary table using type of given item.
|
||||||
|
|
||||||
@@ -15709,69 +15776,9 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
|
|||||||
Item ***copy_func, bool modify_item,
|
Item ***copy_func, bool modify_item,
|
||||||
uint convert_blob_length)
|
uint convert_blob_length)
|
||||||
{
|
{
|
||||||
bool maybe_null= item->maybe_null;
|
|
||||||
Field *UNINIT_VAR(new_field);
|
Field *UNINIT_VAR(new_field);
|
||||||
MEM_ROOT *mem_root= thd->mem_root;
|
DBUG_ASSERT(thd == table->in_use);
|
||||||
|
new_field= item->Item::create_tmp_field(false, table, convert_blob_length);
|
||||||
switch (item->result_type()) {
|
|
||||||
case REAL_RESULT:
|
|
||||||
new_field= new (mem_root)
|
|
||||||
Field_double(item->max_length, maybe_null,
|
|
||||||
item->name, item->decimals, TRUE);
|
|
||||||
break;
|
|
||||||
case INT_RESULT:
|
|
||||||
/*
|
|
||||||
Select an integer type with the minimal fit precision.
|
|
||||||
MY_INT32_NUM_DECIMAL_DIGITS is sign inclusive, don't consider the sign.
|
|
||||||
Values with MY_INT32_NUM_DECIMAL_DIGITS digits may or may not fit into
|
|
||||||
Field_long : make them Field_longlong.
|
|
||||||
*/
|
|
||||||
if (item->max_length >= (MY_INT32_NUM_DECIMAL_DIGITS - 1))
|
|
||||||
new_field=new (mem_root)
|
|
||||||
Field_longlong(item->max_length, maybe_null,
|
|
||||||
item->name, item->unsigned_flag);
|
|
||||||
else
|
|
||||||
new_field=new (mem_root)
|
|
||||||
Field_long(item->max_length, maybe_null, item->name,
|
|
||||||
item->unsigned_flag);
|
|
||||||
break;
|
|
||||||
case STRING_RESULT:
|
|
||||||
DBUG_ASSERT(item->collation.collation);
|
|
||||||
|
|
||||||
/*
|
|
||||||
DATE/TIME and GEOMETRY fields have STRING_RESULT result type.
|
|
||||||
To preserve type they needed to be handled separately.
|
|
||||||
*/
|
|
||||||
if (item->cmp_type() == TIME_RESULT ||
|
|
||||||
item->field_type() == MYSQL_TYPE_GEOMETRY)
|
|
||||||
new_field= item->tmp_table_field_from_field_type(table, true, false);
|
|
||||||
/*
|
|
||||||
Make sure that the blob fits into a Field_varstring which has
|
|
||||||
2-byte lenght.
|
|
||||||
*/
|
|
||||||
else if (item->max_length/item->collation.collation->mbmaxlen > 255 &&
|
|
||||||
convert_blob_length <= Field_varstring::MAX_SIZE &&
|
|
||||||
convert_blob_length)
|
|
||||||
new_field= new (mem_root)
|
|
||||||
Field_varstring(convert_blob_length, maybe_null,
|
|
||||||
item->name, table->s,
|
|
||||||
item->collation.collation);
|
|
||||||
else
|
|
||||||
new_field= item->make_string_field(table);
|
|
||||||
new_field->set_derivation(item->collation.derivation);
|
|
||||||
break;
|
|
||||||
case DECIMAL_RESULT:
|
|
||||||
new_field= Field_new_decimal::create_from_item(mem_root, item);
|
|
||||||
break;
|
|
||||||
case ROW_RESULT:
|
|
||||||
default:
|
|
||||||
// This case should never be choosen
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
new_field= 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (new_field)
|
|
||||||
new_field->init(table);
|
|
||||||
|
|
||||||
if (copy_func && item->real_item()->is_result_field())
|
if (copy_func && item->real_item()->is_result_field())
|
||||||
*((*copy_func)++) = item; // Save for copy_funcs
|
*((*copy_func)++) = item; // Save for copy_funcs
|
||||||
@@ -15866,8 +15873,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case Item::SUM_FUNC_ITEM:
|
case Item::SUM_FUNC_ITEM:
|
||||||
{
|
{
|
||||||
Item_sum *item_sum=(Item_sum*) item;
|
result= item->create_tmp_field(group, table, convert_blob_length);
|
||||||
result= item_sum->create_tmp_field(group, table, convert_blob_length);
|
|
||||||
if (!result)
|
if (!result)
|
||||||
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
|
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
|
||||||
return result;
|
return result;
|
||||||
|
Reference in New Issue
Block a user