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:
parent
13f7ac2269
commit
637af78383
@ -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
|
||||
#
|
||||
|
@ -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 #
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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 #
|
||||
|
30
sql/field.cc
30
sql/field.cc
@ -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)
|
||||
|
25
sql/field.h
25
sql/field.h
@ -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);
|
||||
|
155
sql/item.h
155
sql/item.h
@ -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),
|
||||
|
@ -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 ?
|
||||
|
@ -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 *)
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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, ¶m);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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(), ©_func,
|
||||
create_tmp_field(table, arg, ©_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, ©_func,
|
||||
create_tmp_field(table, item, ©_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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user