MDEV-16309 Split ::create_tmp_field() into virtual methods in Item

Detailed: changes:
1. Moving Field specific code into new methods on Field:
   - Field *Field::create_tmp_field(...)
   - virtual void init_for_tmp_table(...)

2. Removing virtual Item::create_tmp_field().
   Adding instead a new virtual method Item::create_tmp_field_ex().

   Note, a virtual create_tmp_field() still exists, but only for Item_sum.
   This resembles 10.0 code structure. Perhaps create_tmp_field() should
   be removed from Item_sum and Item_sum descendants should override
   create_tmp_field_ex() directly. This can be done in a separate commit.

3. Adding helper classes Tmp_field_src and Tmp_field_param,
   to make the API for Item::create_tmp_field_ex() smaller
   and easier to extend in the future.

4. Decomposing the public function create_tmp_field() into
   virtual implementations for Item and a number of its descendants:
   - Item_basic_value
   - Item_sp_variable
   - Item_name_const
   - Item_result_field
   - Item_field
   - Item_ref
   - Item_type_holder
   - Item_row
   - Item_func_sp
   - Item_func_user_var
   - Item_sum
   - Item_sum_field
   - Item_proc

5. Adding DBUG_ASSERT-only virtual implementations for
   Item types that should not appear in create_tmp_table_ex(),
   for easier debugging:
   - Item_nodeset_func
   - Item_nodeset_to_const_comparator
   - Item_null_result
   - Item_copy
   - Item_ident_for_show
   - Item_user_var_as_out_param

6. Moving public function create_tmp_field_from_field()
   as a method to Item_field.

7. Removing Item::set_result_field(). It's not needed any more.

8. Cleanup: Removing the enum value "EXPR_CACHE_ITEM",
   as it's not used for a very long time.
This commit is contained in:
Alexander Barkov 2018-05-28 16:57:59 +04:00
parent 13f7ac2269
commit 637af78383
16 changed files with 611 additions and 310 deletions

View File

@ -171,3 +171,48 @@ SELECT (SELECT 1 FROM t1 PROCEDURE ANALYSE()) FROM t2;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE()) FROM t2' at line 1
SELECT ((SELECT 1 FROM t1 PROCEDURE ANALYSE())) FROM t2;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'PROCEDURE ANALYSE())) FROM t2' at line 1
#
# Start of 10.4 tests
#
#
# MDEV-16309 Split ::create_tmp_field() into virtual methods in Item
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
BEGIN NOT ATOMIC
DECLARE rec ROW(Field_name TEXT,
Min_value TEXT,
Max_value TEXT,
Min_length TEXT,
Max_length TEXT,
Empties_or_zeros TEXT,
Nulls TEXT,
Avg_value_or_avg_length TEXT,
Std TEXT,
Optimal_fieldtype TEXT);
DECLARE c CURSOR FOR SELECT * FROM t1 PROCEDURE analyse();
OPEN c;
FETCH c INTO rec;
CLOSE c;
SELECT rec.field_name,
rec.Min_value, rec.Max_value,
rec.Min_length, rec. Max_length,
rec.Empties_or_zeros, rec.Nulls,
rec.Avg_value_or_avg_length, rec.Std,
rec.Optimal_fieldtype;
END;
$$
rec.field_name test.t1.a
rec.Min_value 1
rec.Max_value 3
rec.Min_length 1
rec. Max_length 1
rec.Empties_or_zeros 0
rec.Nulls 0
rec.Avg_value_or_avg_length 2.0000
rec.Std 0.8165
rec.Optimal_fieldtype ENUM('1','2','3') NOT NULL
DROP TABLE t1;
#
# End of 10.4 tests
#

View File

@ -181,3 +181,47 @@ SELECT * FROM t1 NATURAL JOIN (SELECT * FROM t2 PROCEDURE ANALYSE());
SELECT (SELECT 1 FROM t1 PROCEDURE ANALYSE()) FROM t2;
--error ER_PARSE_ERROR
SELECT ((SELECT 1 FROM t1 PROCEDURE ANALYSE())) FROM t2;
--echo #
--echo # Start of 10.4 tests
--echo #
--echo #
--echo # MDEV-16309 Split ::create_tmp_field() into virtual methods in Item
--echo #
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
--vertical_results
DELIMITER $$;
BEGIN NOT ATOMIC
DECLARE rec ROW(Field_name TEXT,
Min_value TEXT,
Max_value TEXT,
Min_length TEXT,
Max_length TEXT,
Empties_or_zeros TEXT,
Nulls TEXT,
Avg_value_or_avg_length TEXT,
Std TEXT,
Optimal_fieldtype TEXT);
DECLARE c CURSOR FOR SELECT * FROM t1 PROCEDURE analyse();
OPEN c;
FETCH c INTO rec;
CLOSE c;
SELECT rec.field_name,
rec.Min_value, rec.Max_value,
rec.Min_length, rec. Max_length,
rec.Empties_or_zeros, rec.Nulls,
rec.Avg_value_or_avg_length, rec.Std,
rec.Optimal_fieldtype;
END;
$$
DELIMITER ;$$
--horizontal_results
DROP TABLE t1;
--echo #
--echo # End of 10.4 tests
--echo #

View File

@ -1562,3 +1562,29 @@ Catalog Database Table Table_alias Column Column_alias Type Length Max length Is
def INET_ATON("255.255.255.255.255.255.255.255") 8 21 20 Y 32928 0 63
INET_ATON("255.255.255.255.255.255.255.255")
18446744073709551615
#
# End of 10.3 tests
#
#
# Start of 10.4 tests
#
#
# MDEV-16309 Split ::create_tmp_field() into virtual methods in Item
#
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
BEGIN NOT ATOMIC
DECLARE a TEXT;
DECLARE c CURSOR FOR SELECT NAME_CONST('x','y') FROM t1;
OPEN c;
FETCH c INTO a;
CLOSE c;
SELECT a;
END;
$$
a
y
DROP TABLE t1;
#
# End of 10.4 tests
#

View File

@ -1203,3 +1203,34 @@ SELECT INET_ATON("255.255.255.255.255.255.255.255");
--enable_ps_protocol
--disable_metadata
--echo #
--echo # End of 10.3 tests
--echo #
--echo #
--echo # Start of 10.4 tests
--echo #
--echo #
--echo # MDEV-16309 Split ::create_tmp_field() into virtual methods in Item
--echo #
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
DELIMITER $$;
BEGIN NOT ATOMIC
DECLARE a TEXT;
DECLARE c CURSOR FOR SELECT NAME_CONST('x','y') FROM t1;
OPEN c;
FETCH c INTO a;
CLOSE c;
SELECT a;
END;
$$
DELIMITER ;$$
DROP TABLE t1;
--echo #
--echo # End of 10.4 tests
--echo #

View File

@ -2331,6 +2331,36 @@ Field *Field::new_key_field(MEM_ROOT *root, TABLE *new_table,
}
/**
Create field for temporary table from given field.
@param thd Thread handler
@param table Temporary table
@param maybe_null_arg If the result field should be NULL-able,
even if the original field is NOT NULL, e.g. for:
- OUTER JOIN fields
- WITH ROLLUP fields
- arguments of aggregate functions, e.g. SUM(column1)
@retval NULL, on error
@retval pointer to the new field created, on success.
*/
Field *Field::create_tmp_field(MEM_ROOT *mem_root, TABLE *new_table,
bool maybe_null_arg)
{
Field *new_field;
if ((new_field= make_new_field(mem_root, new_table, new_table == table)))
{
new_field->init_for_tmp_table(this, new_table);
new_field->flags|= flags & NO_DEFAULT_VALUE_FLAG;
if (maybe_null_arg)
new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join
}
return new_field;
}
/* This is used to generate a field in TABLE from TABLE_SHARE */
Field *Field::clone(MEM_ROOT *root, TABLE *new_table)

View File

@ -1228,6 +1228,12 @@ public:
virtual Field *new_key_field(MEM_ROOT *root, TABLE *new_table,
uchar *new_ptr, uint32 length,
uchar *new_null_ptr, uint new_null_bit);
Field *create_tmp_field(MEM_ROOT *root, TABLE *new_table,
bool maybe_null_arg);
Field *create_tmp_field(MEM_ROOT *root, TABLE *new_table)
{
return create_tmp_field(root, new_table, maybe_null());
}
Field *clone(MEM_ROOT *mem_root, TABLE *new_table);
Field *clone(MEM_ROOT *mem_root, TABLE *new_table, my_ptrdiff_t diff,
bool stat_flag= FALSE);
@ -1388,7 +1394,19 @@ public:
orig_table= table= table_arg;
set_table_name(&table_arg->alias);
}
virtual void init_for_tmp_table(Field *org_field, TABLE *new_table)
{
init(new_table);
orig_table= org_field->orig_table;
vcol_info= 0;
cond_selectivity= 1.0;
next_equal_field= NULL;
option_list= NULL;
option_struct= NULL;
if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
org_field->type() == MYSQL_TYPE_VARCHAR)
new_table->s->db_create_options|= HA_OPTION_PACK_RECORD;
}
/* maximum possible display length */
virtual uint32 max_display_length()= 0;
@ -2307,6 +2325,11 @@ public:
if (dec_arg >= FLOATING_POINT_DECIMALS)
dec_arg= NOT_FIXED_DEC;
}
void init_for_tmp_table(Field *org_field, TABLE *new_table)
{
Field::init_for_tmp_table(org_field, new_table);
not_fixed= true;
}
const Type_handler *type_handler() const { return &type_handler_double; }
enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
int store(const char *to,size_t length,CHARSET_INFO *charset);

View File

@ -99,7 +99,9 @@ class sp_head;
class Protocol;
struct TABLE_LIST;
void item_init(void); /* Init item functions */
class Item_result_field;
class Item_field;
class Item_ref;
class Item_param;
class user_var_entry;
class JOIN;
@ -603,6 +605,70 @@ public:
};
/**
A helper class describing what kind of Item created a temporary field.
- If m_field is set, then the temporary field was created from Field
(e.g. when the Item was Item_field, or Item_ref pointing to Item_field)
- If m_default_field is set, then there is a usable DEFAULT value.
(e.g. when the Item is Item_field)
- If m_item_result_field is set, then the temporary field was created
from certain sub-types of Item_result_field (e.g. Item_func)
See create_tmp_field() in sql_select.cc for details.
*/
class Tmp_field_src
{
Field *m_field;
Field *m_default_field;
Item_result_field *m_item_result_field;
public:
Tmp_field_src()
:m_field(0),
m_default_field(0),
m_item_result_field(0)
{ }
Field *field() const { return m_field; }
Field *default_field() const { return m_default_field; }
Item_result_field *item_result_field() const { return m_item_result_field; }
void set_field(Field *field) { m_field= field; }
void set_default_field(Field *field) { m_default_field= field; }
void set_item_result_field(Item_result_field *item)
{ m_item_result_field= item; }
};
/**
Parameters for create_tmp_field_ex().
See create_tmp_field() in sql_select.cc for details.
*/
class Tmp_field_param
{
bool m_group;
bool m_modify_item;
bool m_table_cant_handle_bit_fields;
bool m_make_copy_field;
public:
Tmp_field_param(bool group,
bool modify_item,
bool table_cant_handle_bit_fields,
bool make_copy_field)
:m_group(group),
m_modify_item(modify_item),
m_table_cant_handle_bit_fields(table_cant_handle_bit_fields),
m_make_copy_field(make_copy_field)
{ }
bool group() const { return m_group; }
bool modify_item() const { return m_modify_item; }
bool table_cant_handle_bit_fields() const
{ return m_table_cant_handle_bit_fields; }
bool make_copy_field() const { return m_make_copy_field; }
void set_modify_item(bool to) { m_modify_item= to; }
};
/****************************************************************************/
class Item: public Value_source,
public Type_all_attributes
{
@ -635,7 +701,7 @@ public:
SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,
PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM,
XPATH_NODESET, XPATH_NODESET_CMP,
VIEW_FIXER_ITEM, EXPR_CACHE_ITEM,
EXPR_CACHE_ITEM,
DATE_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
@ -682,6 +748,24 @@ protected:
return h->make_and_init_table_field(&name, Record_addr(maybe_null),
*this, table);
}
/**
Create a temporary field for a simple Item, which does not
need any special action after the field creation:
- is not an Item_field descendant (and not a reference to Item_field)
- is not an Item_result_field descendant
- does not need to copy any DEFAULT value to the result Field
- does not need to set Field::is_created_from_null_item for the result
See create_tmp_field_ex() for details on parameters and return values.
*/
Field *create_tmp_field_ex_simple(TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(!param->make_copy_field());
DBUG_ASSERT(!is_result_field());
DBUG_ASSERT(type() != NULL_ITEM);
return tmp_table_field_from_field_type(table);
}
Field *create_tmp_field_int(TABLE *table, uint convert_int_length);
void push_note_converted_to_negative_complement(THD *thd);
@ -1540,7 +1624,6 @@ public:
set field of temporary table for Item which can be switched on temporary
table during query processing (grouping and so on)
*/
virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; }
virtual bool is_bool_type() { return false; }
virtual bool is_json_type() { return false; }
@ -1817,11 +1900,17 @@ public:
return Type_handler::type_handler_long_or_longlong(max_char_length());
}
virtual Field *create_tmp_field(bool group, TABLE *table)
{
return tmp_table_field_from_field_type(table);
}
/**
Create field for temporary table.
@param table Temporary table
@param [OUT] src Who created the fields
@param param Create parameters
@retval NULL (on error)
@retval a pointer to a newly create Field (on success)
*/
virtual Field *create_tmp_field_ex(TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)= 0;
virtual Item_field *field_for_view_update() { return 0; }
virtual bool vers_trx_id() const
@ -2374,6 +2463,8 @@ protected:
value == ((Item_basic_value*)item)->val_int() &&
(value >= 0 || item->unsigned_flag == unsigned_flag);
}
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
};
@ -2455,6 +2546,11 @@ public:
inline bool const_item() const;
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
return create_tmp_field_ex_simple(table, src, param);
}
inline int save_in_field(Field *field, bool no_conversions);
inline bool send(Protocol *protocol, st_value *buffer);
bool check_vcol_func_processor(void *arg)
@ -2733,6 +2829,16 @@ public:
return TRUE;
}
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
/*
We can get to here when using a CURSOR for a query with NAME_CONST():
DECLARE c CURSOR FOR SELECT NAME_CONST('x','y') FROM t1;
OPEN c;
*/
return create_tmp_field_ex_simple(table, src, param);
}
int save_in_field(Field *field, bool no_conversions)
{
return value_item->save_in_field(field, no_conversions);
@ -2778,13 +2884,15 @@ public:
{}
~Item_result_field() {} /* Required with gcc 2.95 */
Field *get_tmp_table_field() { return result_field; }
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
void get_tmp_field_src(Tmp_field_src *src, const Tmp_field_param *param);
/*
This implementation of used_tables() used by Item_avg_field and
Item_variance_field which work when only temporary table left, so theu
return table map of the temporary table.
*/
table_map used_tables() const { return 1; }
void set_result_field(Field *field) { result_field= field; }
bool is_result_field() { return true; }
void save_in_result_field(bool no_conversions)
{
@ -2877,6 +2985,12 @@ public:
Type_std_attributes::set(par_field);
}
enum Type type() const { return FIELD_ITEM; }
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
return 0;
}
double val_real() { return field->val_real(); }
longlong val_int() { return field->val_int(); }
String *val_str(String *str) { return field->val_str(str); }
@ -2992,6 +3106,11 @@ public:
return &type_handler_null;
return field->type_handler();
}
Field *create_tmp_field_from_item_field(TABLE *new_table,
Item_ref *orig_item,
const Tmp_field_param *param);
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
TYPELIB *get_typelib() const { return field->get_typelib(); }
uint32 field_flags() const
{
@ -3048,7 +3167,6 @@ public:
cond_equal_ref);
}
bool is_result_field() { return false; }
void set_result_field(Field *field_arg) {}
void save_in_result_field(bool no_conversions) { }
Item *get_tmp_table_item(THD *thd);
bool collect_item_field_processor(void * arg);
@ -3257,6 +3375,12 @@ public:
return result_field->type_handler();
}
#endif
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
return NULL;
}
void save_in_result_field(bool no_conversions)
{
save_in_field(result_field, no_conversions);
@ -3675,8 +3799,6 @@ public:
enum Type type() const { return INT_ITEM; }
const Type_handler *type_handler() const
{ return type_handler_long_or_longlong(); }
Field *create_tmp_field(bool group, TABLE *table)
{ return tmp_table_field_from_field_type(table); }
Field *create_field_for_create_select(TABLE *table)
{ return tmp_table_field_from_field_type(table); }
longlong val_int() { DBUG_ASSERT(fixed == 1); return value; }
@ -4800,6 +4922,8 @@ public:
Field *get_tmp_table_field()
{ return result_field ? result_field : (*ref)->get_tmp_table_field(); }
Item *get_tmp_table_item(THD *thd);
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
table_map used_tables() const;
void update_used_tables();
COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
@ -5549,6 +5673,12 @@ public:
const Type_handler *type_handler() const
{ return Type_handler_hybrid_field_type::type_handler(); }
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
return NULL;
}
void make_send_field(THD *thd, Send_field *field)
{ item->make_send_field(thd, field); }
table_map used_tables() const { return (table_map) 1L; }
@ -6518,7 +6648,8 @@ public:
my_decimal *val_decimal(my_decimal *);
String *val_str(String*);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
Field *create_tmp_field(bool group, TABLE *table)
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
return Item_type_holder::real_type_handler()->
make_and_init_table_field(&name, Record_addr(maybe_null),

View File

@ -2358,8 +2358,8 @@ public:
Item_func_user_var(THD *thd, Item_func_user_var *item)
:Item_hybrid_func(thd, item),
m_var_entry(item->m_var_entry), name(item->name) { }
Field *create_tmp_field(bool group, TABLE *table)
{ return create_table_field_from_handler(table); }
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
Field *create_field_for_create_select(TABLE *table)
{ return create_table_field_from_handler(table); }
bool check_vcol_func_processor(void *arg);
@ -2534,6 +2534,12 @@ public:
{
return 0;
}
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
return NULL;
}
/* We should return something different from FIELD_ITEM here */
enum Type type() const { return STRING_ITEM;}
double val_real();
@ -2839,6 +2845,8 @@ public:
const Type_handler *type_handler() const;
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param);
Field *create_field_for_create_select(TABLE *table)
{
return result_type() != STRING_RESULT ?

View File

@ -56,6 +56,11 @@ public:
bool with_subquery() const { DBUG_ASSERT(fixed); return m_with_subquery; }
enum Type type() const { return ROW_ITEM; };
const Type_handler *type_handler() const { return &type_handler_row; }
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
return NULL; // Check with Vicentiu why it's called for Item_row
}
void illegal_method_call(const char *);
bool is_null() { return null_value; }
void make_send_field(THD *thd, Send_field *)

View File

@ -1237,9 +1237,11 @@ Field *Item_sum_hybrid::create_tmp_field(bool group, TABLE *table)
if (args[0]->type() == Item::FIELD_ITEM)
{
Field *field= ((Item_field*) args[0])->field;
if ((field= create_tmp_field_from_field(table->in_use, field, &name,
table, NULL)))
field->flags&= ~NOT_NULL_FLAG;
if ((field= field->create_tmp_field(table->in_use->mem_root, table, true)))
{
DBUG_ASSERT((field->flags & NOT_NULL_FLAG) == 0);
field->field_name= name;
}
DBUG_RETURN(field);
}
DBUG_RETURN(tmp_table_field_from_field_type(table));

View File

@ -510,7 +510,12 @@ public:
}
virtual void make_unique() { force_copy_fields= TRUE; }
Item *get_tmp_table_item(THD *thd);
Field *create_tmp_field(bool group, TABLE *table);
virtual Field *create_tmp_field(bool group, TABLE *table);
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
return create_tmp_field(param->group(), table);
}
virtual bool collect_outer_ref_processor(void *param);
bool init_sum_func_check(THD *thd);
bool check_sum_func(THD *thd, Item **ref);
@ -1377,6 +1382,11 @@ public:
fixed= true;
}
table_map used_tables() const { return (table_map) 1L; }
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
return create_tmp_field_ex_simple(table, src, param);
}
void save_in_result_field(bool no_conversions) { DBUG_ASSERT(0); }
bool check_vcol_func_processor(void *arg)
{

View File

@ -187,6 +187,12 @@ public:
nodeset->length(0);
}
enum Type type() const { return XPATH_NODESET; }
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
return NULL;
}
String *val_str(String *str)
{
prepare_nodes();
@ -592,7 +598,12 @@ public:
{
return mark_unsupported_function(func_name(), arg, VCOL_IMPOSSIBLE);
}
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(0);
return NULL;
}
longlong val_int()
{
Item_func *comp= (Item_func*)args[1];

View File

@ -44,6 +44,16 @@ public:
this->name.length= strlen(name_par);
}
enum Type type() const { return Item::PROC_ITEM; }
Field *create_tmp_field_ex(TABLE *table, Tmp_field_src *src,
const Tmp_field_param *param)
{
/*
We can get to here when using a CURSOR for a query with PROCEDURE:
DECLARE c CURSOR FOR SELECT * FROM t1 PROCEDURE analyse();
OPEN c;
*/
return create_tmp_field_ex_simple(table, src, param);
}
virtual void set(double nr)=0;
virtual void set(const char *str,uint length,CHARSET_INFO *cs)=0;
virtual void set(longlong nr)=0;

View File

@ -4080,9 +4080,9 @@ void select_insert::abort_result_set() {
Field *Item::create_field_for_create_select(TABLE *table)
{
Field *def_field, *tmp_field;
return ::create_tmp_field(table->in_use, table, this, type(),
(Item ***) 0, &tmp_field, &def_field, 0, 0, 0, 0);
static Tmp_field_param param(false, false, false, false);
Tmp_field_src src;
return create_tmp_field_ex(table, &src, &param);
}

View File

@ -16525,60 +16525,6 @@ const_expression_in_where(COND *cond, Item *comp_item, Field *comp_field,
Create internal temporary table
****************************************************************************/
/**
Create field for temporary table from given field.
@param thd Thread handler
@param org_field field from which new field will be created
@param name New field name
@param table Temporary table
@param item !=NULL if item->result_field should point to new field.
This is relevant for how fill_record() is going to work:
If item != NULL then fill_record() will update
the record in the original table.
If item == NULL then fill_record() will update
the temporary table
@retval
NULL on error
@retval
new_created field
*/
Field *create_tmp_field_from_field(THD *thd, Field *org_field,
LEX_CSTRING *name, TABLE *table,
Item_field *item)
{
Field *new_field;
new_field= org_field->make_new_field(thd->mem_root, table,
table == org_field->table);
if (new_field)
{
new_field->init(table);
new_field->orig_table= org_field->orig_table;
if (item)
item->result_field= new_field;
else
new_field->field_name= *name;
new_field->flags|= org_field->flags & NO_DEFAULT_VALUE_FLAG;
if (org_field->maybe_null() || (item && item->maybe_null))
new_field->flags&= ~NOT_NULL_FLAG; // Because of outer join
if (org_field->type() == MYSQL_TYPE_VAR_STRING ||
org_field->type() == MYSQL_TYPE_VARCHAR)
table->s->db_create_options|= HA_OPTION_PACK_RECORD;
else if (org_field->type() == FIELD_TYPE_DOUBLE)
((Field_double *) new_field)->not_fixed= TRUE;
new_field->vcol_info= 0;
new_field->cond_selectivity= 1.0;
new_field->next_equal_field= NULL;
new_field->option_list= NULL;
new_field->option_struct= NULL;
}
return new_field;
}
Field *Item::create_tmp_field_int(TABLE *table, uint convert_int_length)
{
const Type_handler *h= &type_handler_long;
@ -16619,59 +16565,6 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table)
}
static void create_tmp_field_from_item_finalize(THD *thd,
Field *new_field,
Item *item,
Item ***copy_func,
bool modify_item)
{
if (copy_func &&
(item->is_result_field() ||
(item->real_item()->is_result_field())))
*((*copy_func)++) = item; // Save for copy_funcs
if (modify_item)
item->set_result_field(new_field);
if (item->type() == Item::NULL_ITEM)
new_field->is_created_from_null_item= TRUE;
}
/**
Create field for temporary table using type of given item.
@param thd Thread handler
@param item Item to create a field for
@param table Temporary table
@param copy_func If set and item is a function, store copy of
item in this array
@param modify_item 1 if item->result_field should point to new
item. This is relevent for how fill_record()
is going to work:
If modify_item is 1 then fill_record() will
update the record in the original table.
If modify_item is 0 then fill_record() will
update the temporary table
@param convert_blob_length If >0 create a varstring(convert_blob_length)
field instead of blob.
@retval
0 on error
@retval
new_created field
*/
static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
Item ***copy_func, bool modify_item)
{
Field *UNINIT_VAR(new_field);
DBUG_ASSERT(thd == table->in_use);
if ((new_field= item->create_tmp_field(false, table)))
create_tmp_field_from_item_finalize(thd, new_field, item,
copy_func, modify_item);
return new_field;
}
/**
Create field for information schema table.
@ -16708,20 +16601,207 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table)
}
/**
Create a temporary field for Item_field (or its descendant),
either direct or referenced by an Item_ref.
*/
Field *
Item_field::create_tmp_field_from_item_field(TABLE *new_table,
Item_ref *orig_item,
const Tmp_field_param *param)
{
DBUG_ASSERT(!is_result_field());
Field *result;
/*
If item have to be able to store NULLs but underlaid field can't do it,
create_tmp_field_from_field() can't be used for tmp field creation.
*/
if (((maybe_null && in_rollup) ||
(new_table->in_use->create_tmp_table_for_derived && /* for mat. view/dt */
orig_item && orig_item->maybe_null)) &&
!field->maybe_null())
{
/*
The item the ref points to may have maybe_null flag set while
the ref doesn't have it. This may happen for outer fields
when the outer query decided at some point after name resolution phase
that this field might be null. Take this into account here.
*/
Record_addr rec(orig_item ? orig_item->maybe_null : maybe_null);
const Type_handler *handler= type_handler()->
type_handler_for_tmp_table(this);
result= handler->make_and_init_table_field(&name, rec, *this, new_table);
}
else if (param->table_cant_handle_bit_fields() &&
field->type() == MYSQL_TYPE_BIT)
{
const Type_handler *handler= type_handler_long_or_longlong();
result= handler->make_and_init_table_field(&name,
Record_addr(maybe_null),
*this, new_table);
}
else
{
LEX_CSTRING *tmp= orig_item ? &orig_item->name : &name;
bool tmp_maybe_null= param->modify_item() ? maybe_null :
field->maybe_null();
result= field->create_tmp_field(new_table->in_use->mem_root, new_table,
tmp_maybe_null);
if (result)
result->field_name= *tmp;
}
if (result && param->modify_item())
result_field= result;
return result;
}
Field *Item_field::create_tmp_field_ex(TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(!is_result_field());
Field *result;
src->set_field(field);
if (!(result= create_tmp_field_from_item_field(table, NULL, param)))
return NULL;
/*
Fields that are used as arguments to the DEFAULT() function already have
their data pointers set to the default value during name resolution. See
Item_default_value::fix_fields.
*/
if (type() != Item::DEFAULT_VALUE_ITEM && field->eq_def(result))
src->set_default_field(field);
return result;
}
Field *Item_ref::create_tmp_field_ex(TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
Item *item= real_item();
DBUG_ASSERT(is_result_field());
if (item->type() == Item::FIELD_ITEM)
{
Field *result;
Item_field *field= (Item_field*) item;
Tmp_field_param prm2(*param);
prm2.set_modify_item(false);
src->set_field(field->field);
if (!(result= field->create_tmp_field_from_item_field(table, this, &prm2)))
return NULL;
if (param->modify_item())
result_field= result;
return result;
}
return Item_result_field::create_tmp_field_ex(table, src, param);
}
void Item_result_field::get_tmp_field_src(Tmp_field_src *src,
const Tmp_field_param *param)
{
if (param->make_copy_field())
{
DBUG_ASSERT(result_field);
src->set_field(result_field);
}
else
{
src->set_item_result_field(this); // Save for copy_funcs
}
}
Field *Item_result_field::create_tmp_field_ex(TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
/*
Possible Item types:
- Item_cache_wrapper (only for CREATE..SELECT ?)
- Item_func
- Item_subselect
*/
DBUG_ASSERT(is_result_field());
DBUG_ASSERT(type() != NULL_ITEM);
get_tmp_field_src(src, param);
Field *result;
if ((result= tmp_table_field_from_field_type(table)) && param->modify_item())
result_field= result;
return result;
}
Field *Item_func_user_var::create_tmp_field_ex(TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
DBUG_ASSERT(is_result_field());
DBUG_ASSERT(type() != NULL_ITEM);
get_tmp_field_src(src, param);
Field *result;
if ((result= create_table_field_from_handler(table)) && param->modify_item())
result_field= result;
return result;
}
Field *Item_func_sp::create_tmp_field_ex(TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
Field *result;
get_tmp_field_src(src, param);
if ((result= sp_result_field->create_tmp_field(table->in_use->mem_root,
table)))
{
result->field_name= name;
if (param->modify_item())
result_field= result;
}
return result;
}
Field *Item_basic_value::create_tmp_field_ex(TABLE *table,
Tmp_field_src *src,
const Tmp_field_param *param)
{
/*
create_tmp_field_ex() for this type of Items is called for:
- CREATE TABLE ... SELECT
- In ORDER BY: SELECT max(a) FROM t1 GROUP BY a ORDER BY 'const';
- In CURSORS:
DECLARE c CURSOR FOR SELECT 'test';
OPEN c;
*/
DBUG_ASSERT(!param->make_copy_field());
DBUG_ASSERT(!is_result_field());
Field *result;
if ((result= tmp_table_field_from_field_type(table)))
{
if (type() == Item::NULL_ITEM) // Item_null or Item_param
result->is_created_from_null_item= true;
}
return result;
}
/**
Create field for temporary table.
@param thd Thread handler
@param table Temporary table
@param item Item to create a field for
@param type Type of item (normally item->type)
@param copy_func If set and item is a function, store copy of item
@param table Temporary table
@param item Item to create a field for
@param type Type of item (normally item->type)
@param copy_func If set and item is a function, store copy of item
in this array
@param from_field if field will be created using other field as example,
pointer example field will be written here
@param default_field If field has a default value field, store it here
@param group 1 if we are going to do a relative group by on result
@param modify_item 1 if item->result_field should point to new item.
@param default_field If field has a default value field, store it here
@param group 1 if we are going to do a relative group by on result
@param modify_item 1 if item->result_field should point to new item.
This is relevent for how fill_record() is going to
work:
If modify_item is 1 then fill_record() will update
@ -16730,172 +16810,28 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table)
the temporary table
@retval
0 on error
0 on error
@retval
new_created field
Create a temporary field for Item_field (or its descendant),
either direct or referenced by an Item_ref.
*/
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Field *create_tmp_field(TABLE *table, Item *item,
Item ***copy_func, Field **from_field,
Field **default_field,
bool group, bool modify_item,
bool table_cant_handle_bit_fields,
bool make_copy_field)
{
Field *result;
Item::Type orig_type= type;
Item *orig_item= 0;
DBUG_ASSERT(thd == table->in_use);
if (type != Item::FIELD_ITEM &&
item->real_item()->type() == Item::FIELD_ITEM)
{
orig_item= item;
item= item->real_item();
type= Item::FIELD_ITEM;
}
switch (type) {
case Item::TYPE_HOLDER:
case Item::SUM_FUNC_ITEM:
{
result= item->create_tmp_field(group, table);
if (!result)
my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR));
return result;
}
case Item::FIELD_ITEM:
case Item::DEFAULT_VALUE_ITEM:
case Item::INSERT_VALUE_ITEM:
case Item::TRIGGER_FIELD_ITEM:
{
Item_field *field= (Item_field*) item;
bool orig_modify= modify_item;
if (orig_type == Item::REF_ITEM)
modify_item= 0;
/*
If item have to be able to store NULLs but underlaid field can't do it,
create_tmp_field_from_field() can't be used for tmp field creation.
*/
if (((field->maybe_null && field->in_rollup) ||
(thd->create_tmp_table_for_derived && /* for mat. view/dt */
orig_item && orig_item->maybe_null)) &&
!field->field->maybe_null())
{
bool save_maybe_null= FALSE;
/*
The item the ref points to may have maybe_null flag set while
the ref doesn't have it. This may happen for outer fields
when the outer query decided at some point after name resolution phase
that this field might be null. Take this into account here.
*/
if (orig_item)
{
save_maybe_null= item->maybe_null;
item->maybe_null= orig_item->maybe_null;
}
result= create_tmp_field_from_item(thd, item, table, NULL,
modify_item);
*from_field= field->field;
if (result && modify_item)
field->result_field= result;
if (orig_item)
item->maybe_null= save_maybe_null;
}
else if (table_cant_handle_bit_fields && field->field->type() ==
MYSQL_TYPE_BIT)
{
const Type_handler *handler= item->type_handler_long_or_longlong();
*from_field= field->field;
if ((result=
handler->make_and_init_table_field(&item->name,
Record_addr(item->maybe_null),
*item, table)))
create_tmp_field_from_item_finalize(thd, result, item,
copy_func, modify_item);
if (result && modify_item)
field->result_field= result;
}
else
{
LEX_CSTRING *tmp= orig_item ? &orig_item->name : &item->name;
result= create_tmp_field_from_field(thd, (*from_field= field->field),
tmp, table,
modify_item ? field :
NULL);
}
if (orig_type == Item::REF_ITEM && orig_modify)
((Item_ref*)orig_item)->set_result_field(result);
/*
Fields that are used as arguments to the DEFAULT() function already have
their data pointers set to the default value during name resolution. See
Item_default_value::fix_fields.
*/
if (orig_type != Item::DEFAULT_VALUE_ITEM && field->field->eq_def(result))
*default_field= field->field;
return result;
}
/* Fall through */
case Item::FUNC_ITEM:
if (((Item_func *) item)->functype() == Item_func::FUNC_SP)
{
Item_func_sp *item_func_sp= (Item_func_sp *) item;
Field *sp_result_field= item_func_sp->get_sp_result_field();
if (make_copy_field)
{
DBUG_ASSERT(item_func_sp->result_field);
*from_field= item_func_sp->result_field;
}
else
{
*((*copy_func)++)= item;
}
Field *result_field=
create_tmp_field_from_field(thd,
sp_result_field,
&item_func_sp->name,
table,
NULL);
if (modify_item)
item->set_result_field(result_field);
return result_field;
}
/* Fall through */
case Item::COND_ITEM:
case Item::FIELD_AVG_ITEM:
case Item::FIELD_STD_ITEM:
case Item::SUBSELECT_ITEM:
/* The following can only happen with 'CREATE TABLE ... SELECT' */
case Item::PROC_ITEM:
case Item::INT_ITEM:
case Item::REAL_ITEM:
case Item::DECIMAL_ITEM:
case Item::STRING_ITEM:
case Item::DATE_ITEM:
case Item::REF_ITEM:
case Item::NULL_ITEM:
case Item::VARBIN_ITEM:
case Item::CACHE_ITEM:
case Item::WINDOW_FUNC_ITEM: // psergey-winfunc:
case Item::EXPR_CACHE_ITEM:
case Item::PARAM_ITEM:
if (make_copy_field)
{
DBUG_ASSERT(((Item_result_field*)item)->result_field);
*from_field= ((Item_result_field*)item)->result_field;
}
return create_tmp_field_from_item(thd, item, table,
(make_copy_field ? 0 : copy_func),
modify_item);
default: // Dosen't have to be stored
return 0;
}
Tmp_field_src src;
Tmp_field_param prm(group, modify_item, table_cant_handle_bit_fields,
make_copy_field);
Field *result= item->create_tmp_field_ex(table, &src, &prm);
*from_field= src.field();
*default_field= src.default_field();
if (src.item_result_field())
*((*copy_func)++)= src.item_result_field();
return result;
}
/*
@ -17202,7 +17138,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
{
Item *tmp_item;
Field *new_field=
create_tmp_field(thd, table, arg, arg->type(), &copy_func,
create_tmp_field(table, arg, &copy_func,
tmp_from_field, &default_field[fieldnr],
group != 0,not_all_columns,
distinct, false);
@ -17252,7 +17188,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
else
{
/*
The last parameter to create_tmp_field() is a bit tricky:
The last parameter to create_tmp_field_ex() is a bit tricky:
We need to set it to 0 in union, to get fill_record() to modify the
temporary table.
@ -17266,7 +17202,7 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
*/
Field *new_field= (param->schema_table) ?
item->create_field_for_schema(thd, table) :
create_tmp_field(thd, table, item, type, &copy_func,
create_tmp_field(table, item, &copy_func,
tmp_from_field, &default_field[fieldnr],
group != 0,
!force_copy_fields &&
@ -17280,7 +17216,6 @@ create_tmp_table(THD *thd, TMP_TABLE_PARAM *param, List<Item> &fields,
*/
item->marker == 4 || param->bit_fields_as_long,
force_copy_fields);
if (!new_field)
{
if (thd->is_fatal_error)
@ -23466,7 +23401,7 @@ calc_group_buffer(JOIN *join,ORDER *group)
{
/*
Group strings are taken as varstrings and require an length field.
A field is not yet created by create_tmp_field()
A field is not yet created by create_tmp_field_ex()
and the sizes should match up.
*/
key_length+= group_item->max_length + HA_KEY_BLOB_LENGTH;

View File

@ -1804,10 +1804,6 @@ bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
void copy_fields(TMP_TABLE_PARAM *param);
bool copy_funcs(Item **func_ptr, const THD *thd);
uint find_shortest_key(TABLE *table, const key_map *usable_keys);
Field* create_tmp_field_from_field(THD *thd, Field* org_field,
LEX_CSTRING *name, TABLE *table,
Item_field *item);
bool is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args);
/* functions from opt_sum.cc */
@ -2059,12 +2055,6 @@ bool mysql_select(THD *thd,
void free_underlaid_joins(THD *thd, SELECT_LEX *select);
bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
select_result *result);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item ***copy_func, Field **from_field,
Field **def_field,
bool group, bool modify_item,
bool table_cant_handle_bit_fields,
bool make_copy_field);
/*
General routine to change field->ptr of a NULL-terminated array of Field