Commit 637af783 authored by Alexander Barkov's avatar Alexander Barkov

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.
parent 13f7ac22
......@@ -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 #
......@@ -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)
......
......@@ -1228,6 +1228,12 @@ class Field: public Value_source
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 @@ class Field: public Value_source
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 @@ class Field_double :public Field_real {
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);
......
This diff is collapsed.
......@@ -2358,8 +2358,8 @@ class Item_func_user_var :public Item_hybrid_func
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 @@ class Item_user_var_as_out_param :public Item,
{
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 @@ class Item_func_sp :public Item_func,
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 @@ class Item_row: public Item,
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 @@ class Item_sum :public Item_func_or_sum
}
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 @@ class Item_sum_field :public Item
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 @@ class Item_nodeset_func :public Item_str_func
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 @@ class Item_nodeset_to_const_comparator :public Item_bool_func
{
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 @@ class Item_proc :public Item
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, &param);
}
......
This diff is collapsed.
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment