diff options
Diffstat (limited to 'sql/item.h')
-rw-r--r-- | sql/item.h | 1402 |
1 files changed, 999 insertions, 403 deletions
diff --git a/sql/item.h b/sql/item.h index 60073f054c9..423ee4cc089 100644 --- a/sql/item.h +++ b/sql/item.h @@ -25,45 +25,48 @@ #include "sql_priv.h" /* STRING_BUFFER_USUAL_SIZE */ #include "unireg.h" #include "sql_const.h" /* RAND_TABLE_BIT, MAX_FIELD_NAME */ -#include "thr_malloc.h" /* sql_calloc */ #include "field.h" /* Derivation */ #include "sql_type.h" +#include "sql_time.h" C_MODE_START #include <ma_dyncol.h> -C_MODE_END -#ifndef DBUG_OFF -static inline -bool trace_unsupported_func(const char *where, const char *processor_name) +/* + A prototype for a C-compatible structure to store a value of any data type. + Currently it has to stay in /sql, as it depends on String and my_decimal. + We'll do the following changes: + 1. add pure C "struct st_string" and "struct st_my_decimal" + 2. change type of m_string to struct st_string and move inside the union + 3. change type of m_decmal to struct st_my_decimal and move inside the union + 4. move the definition to some file in /include +*/ +struct st_value { - char buff[64]; - sprintf(buff, "%s::%s", where, processor_name); - DBUG_ENTER(buff); - sprintf(buff, "%s returns TRUE: unsupported function", processor_name); - DBUG_PRINT("info", ("%s", buff)); - DBUG_RETURN(TRUE); -} -#else -#define trace_unsupported_func(X,Y) TRUE -#endif + enum enum_dynamic_column_type m_type; + union + { + longlong m_longlong; + double m_double; + MYSQL_TIME m_time; + } value; + String m_string; + my_decimal m_decimal; +}; -static inline -bool trace_unsupported_by_check_vcol_func_processor(const char *where) -{ - return trace_unsupported_func(where, "check_vcol_func_processor"); -} +C_MODE_END #ifdef DBUG_OFF static inline const char *dbug_print_item(Item *item) { return NULL; } #else -extern const char *dbug_print_item(Item *item); +const char *dbug_print_item(Item *item); #endif class Protocol; struct TABLE_LIST; void item_init(void); /* Init item functions */ class Item_field; +class Item_param; class user_var_entry; class JOIN; struct KEY_FIELD; @@ -71,14 +74,45 @@ struct SARGABLE_PARAM; class RANGE_OPT_PARAM; class SEL_TREE; +enum precedence { + LOWEST_PRECEDENCE, + ASSIGN_PRECEDENCE, // := + OR_PRECEDENCE, // OR, || (unless PIPES_AS_CONCAT) + XOR_PRECEDENCE, // XOR + AND_PRECEDENCE, // AND, && + NOT_PRECEDENCE, // NOT (unless HIGH_NOT_PRECEDENCE) + BETWEEN_PRECEDENCE, // BETWEEN, CASE, WHEN, THEN, ELSE + CMP_PRECEDENCE, // =, <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN + BITOR_PRECEDENCE, // | + BITAND_PRECEDENCE, // & + SHIFT_PRECEDENCE, // <<, >> + ADDINTERVAL_PRECEDENCE, // first argument in +INTERVAL + ADD_PRECEDENCE, // +, - + MUL_PRECEDENCE, // *, /, DIV, %, MOD + BITXOR_PRECEDENCE, // ^ + PIPES_PRECEDENCE, // || (if PIPES_AS_CONCAT) + NEG_PRECEDENCE, // unary -, ~ + BANG_PRECEDENCE, // !, NOT (if HIGH_NOT_PRECEDENCE) + COLLATE_PRECEDENCE, // BINARY, COLLATE + INTERVAL_PRECEDENCE, // INTERVAL + DEFAULT_PRECEDENCE, + HIGHEST_PRECEDENCE +}; + +typedef Bounds_checked_array<Item*> Ref_ptr_array; static inline uint32 -char_to_byte_length_safe(uint32 char_length_arg, uint32 mbmaxlen_arg) +char_to_byte_length_safe(size_t char_length_arg, uint32 mbmaxlen_arg) { - ulonglong tmp= ((ulonglong) char_length_arg) * mbmaxlen_arg; - return (tmp > UINT_MAX32) ? (uint32) UINT_MAX32 : (uint32) tmp; + ulonglong tmp= ((ulonglong) char_length_arg) * mbmaxlen_arg; + return tmp > UINT_MAX32 ? UINT_MAX32 : static_cast<uint32>(tmp); } +bool mark_unsupported_function(const char *where, void *store, uint result); + +/* convenience helper for mark_unsupported_function() above */ +bool mark_unsupported_function(const char *w1, const char *w2, + void *store, uint result); /* Bits for the split_sum_func() function */ #define SPLIT_SUM_SKIP_REGISTERED 1 /* Skip registered funcs */ @@ -110,6 +144,10 @@ char_to_byte_length_safe(uint32 char_length_arg, uint32 mbmaxlen_arg) #define MY_COLL_ALLOW_CONV (MY_COLL_ALLOW_SUPERSET_CONV | MY_COLL_ALLOW_COERCIBLE_CONV) #define MY_COLL_CMP_CONV (MY_COLL_ALLOW_CONV | MY_COLL_DISALLOW_NONE) +#define NO_EXTRACTION_FL (1 << 6) +#define FULL_EXTRACTION_FL (1 << 7) +#define EXTRACTION_MASK (NO_EXTRACTION_FL | FULL_EXTRACTION_FL) + class DTCollation { public: CHARSET_INFO *collation; @@ -194,7 +232,7 @@ public: { return collation->coll->strnncollsp(collation, (uchar *) s->ptr(), s->length(), - (uchar *) t->ptr(), t->length(), 0); + (uchar *) t->ptr(), t->length()); } }; @@ -490,7 +528,7 @@ class Copy_query_with_rewrite bool copy_up_to(size_t bytes) { DBUG_ASSERT(bytes >= from); - return dst->append(src + from, bytes - from); + return dst->append(src + from, uint32(bytes - from)); } public: @@ -521,7 +559,7 @@ struct st_dyncall_create_def typedef struct st_dyncall_create_def DYNCALL_CREATE_DEF; -typedef bool (Item::*Item_processor) (uchar *arg); +typedef bool (Item::*Item_processor) (void *arg); /* Analyzer function SYNOPSIS @@ -611,7 +649,6 @@ class Item: public Value_source, public Type_std_attributes, public Type_handler { - Item(const Item &); /* Prevent use of these */ void operator=(Item &); /** The index in the JOIN::join_tab array of the JOIN_TAB this Item is attached @@ -632,7 +669,8 @@ public: static void operator delete(void *ptr,size_t size) { TRASH_FREE(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} - enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM, + enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_FUNC_ITEM, + WINDOW_FUNC_ITEM, STRING_ITEM, INT_ITEM, REAL_ITEM, NULL_ITEM, VARBIN_ITEM, COPY_STR_ITEM, FIELD_AVG_ITEM, DEFAULT_VALUE_ITEM, PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM, @@ -662,8 +700,14 @@ protected: SEL_TREE *get_mm_tree_for_const(RANGE_OPT_PARAM *param); + virtual Field *make_string_field(TABLE *table); + Field *tmp_table_field_from_field_type(TABLE *table, + bool fixed_length, + bool set_blob_packlength); Field *create_tmp_field(bool group, TABLE *table, uint convert_int_length); + void push_note_converted_to_negative_complement(THD *thd); + void push_note_converted_to_positive_complement(THD *thd); public: /* Cache val_str() into the own buffer, e.g. to evaluate constant @@ -695,6 +739,7 @@ public: bool null_value; /* if item is null */ bool with_sum_func; /* True if item contains a sum func */ bool with_param; /* True if contains an SP parameter */ + bool with_window_func; /* True if item contains a window func */ /** True if any item except Item_sum contains a field. Set during parsing. */ @@ -705,7 +750,7 @@ public: bool with_subselect; /* If this item is a subselect or some of its arguments is or contains a subselect */ - // alloc & destruct is done as start of select using sql_alloc + // alloc & destruct is done as start of select on THD::mem_root Item(THD *thd); /* Constructor used by Item_field, Item_ref & aggregate (sum) functions. @@ -722,15 +767,15 @@ public: name=0; #endif } /*lint -e1509 */ - void set_name(const char *str, uint length, CHARSET_INFO *cs); - void set_name_no_truncate(const char *str, uint length, CHARSET_INFO *cs); + void set_name(THD *thd, const char *str, uint length, CHARSET_INFO *cs); + void set_name_no_truncate(THD *thd, const char *str, uint length, + CHARSET_INFO *cs); void set_name_for_rollback(THD *thd, const char *str, uint length, CHARSET_INFO *cs); void rename(char *new_name); void init_make_field(Send_field *tmp_field,enum enum_field_types type); virtual void cleanup(); - virtual void make_field(Send_field *field); - virtual Field *make_string_field(TABLE *table); + virtual void make_field(THD *thd, Send_field *field); virtual bool fix_fields(THD *, Item **); /* Fix after some tables has been pulled out. Basically re-calculate all @@ -752,9 +797,61 @@ public: supposed to be applied recursively. */ virtual inline void quick_fix_field() { fixed= 1; } + + bool store(struct st_value *value, ulonglong fuzzydate) + { + switch (cmp_type()) { + case INT_RESULT: + { + value->m_type= unsigned_flag ? DYN_COL_UINT : DYN_COL_INT; + value->value.m_longlong= val_int(); + break; + } + case REAL_RESULT: + { + value->m_type= DYN_COL_DOUBLE; + value->value.m_double= val_real(); + break; + } + case DECIMAL_RESULT: + { + value->m_type= DYN_COL_DECIMAL; + my_decimal *dec= val_decimal(&value->m_decimal); + if (dec != &value->m_decimal && !null_value) + my_decimal2decimal(dec, &value->m_decimal); + break; + } + case STRING_RESULT: + { + value->m_type= DYN_COL_STRING; + String *str= val_str(&value->m_string); + if (str != &value->m_string && !null_value) + value->m_string.set(str->ptr(), str->length(), str->charset()); + break; + } + case TIME_RESULT: + { + value->m_type= DYN_COL_DATETIME; + get_date(&value->value.m_time, fuzzydate); + break; + } + case ROW_RESULT: + DBUG_ASSERT(false); + null_value= true; + break; + } + if (null_value) + { + value->m_type= DYN_COL_NULL; + return true; + } + return false; + } + /* Function returns 1 on overflow and -1 on fatal errors */ int save_in_field_no_warnings(Field *field, bool no_conversions); virtual int save_in_field(Field *field, bool no_conversions); + virtual bool save_in_param(THD *thd, Item_param *param); virtual void save_org_in_field(Field *field, fast_field_copier data __attribute__ ((__unused__))) @@ -765,16 +862,41 @@ public: { return save_in_field(field, 1); } virtual bool send(Protocol *protocol, String *str); virtual bool eq(const Item *, bool binary_cmp) const; + const Type_handler *type_handler() const + { + return get_handler_by_field_type(field_type()); + } + Field *make_num_distinct_aggregator_field(MEM_ROOT *mem_root, + const Item *item) const + { + return type_handler()->make_num_distinct_aggregator_field(mem_root, this); + } + Field *make_conversion_table_field(TABLE *table, + uint metadata, const Field *target) const + { + DBUG_ASSERT(0); // Should not be called in Item context + return NULL; + } /* result_type() of an item specifies how the value should be returned */ - Item_result result_type() const { return REAL_RESULT; } + Item_result result_type() const { return type_handler()->result_type(); } /* ... while cmp_type() specifies how it should be compared */ - Item_result cmp_type() const; + Item_result cmp_type() const { return type_handler()->cmp_type(); } + void make_sort_key(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, + Sort_param *param) const + { + type_handler()->make_sort_key(to, item, sort_field, param); + } + void sortlength(THD *thd, + const Type_std_attributes *item, + SORT_FIELD_ATTR *attr) const + { + type_handler()->sortlength(thd, item, attr); + } virtual Item_result cast_to_int_type() const { return cmp_type(); } enum_field_types string_field_type() const { return Type_handler::string_type_handler(max_length)->field_type(); } - enum_field_types field_type() const; virtual enum Type type() const =0; /* real_type() is the type of base item. This is same as type() for @@ -851,6 +973,20 @@ public: If value is not null null_value flag will be reset to FALSE. */ virtual longlong val_int()=0; + /** + Get a value for CAST(x AS SIGNED). + Too large positive unsigned integer values are converted + to negative complements. + Values of non-integer data types are adjusted to the SIGNED range. + */ + virtual longlong val_int_signed_typecast(); + /** + Get a value for CAST(x AS UNSIGNED). + Negative signed integer values are converted + to positive complements. + Values of non-integer data types are adjusted to the UNSIGNED range. + */ + virtual longlong val_int_unsigned_typecast(); /* This is just a shortcut to avoid the cast. You should still use unsigned_flag to check the sign of the item. @@ -961,6 +1097,8 @@ public: Returns the val_str() value converted to the given character set. */ String *val_str(String *str, String *converter, CHARSET_INFO *to); + + virtual String *val_json(String *str) { return val_str(str); } /* Return decimal representation of item with fixed point. @@ -1012,7 +1150,12 @@ public: my_decimal *val_decimal_from_time(my_decimal *decimal_value); longlong val_int_from_decimal(); longlong val_int_from_date(); - longlong val_int_from_real(); + longlong val_int_from_real() + { + DBUG_ASSERT(fixed == 1); + return Converter_double_to_longlong_with_warn(val_real(), false).result(); + } + longlong val_int_from_str(int *error); double val_real_from_decimal(); double val_real_from_date(); @@ -1076,9 +1219,10 @@ public: virtual bool basic_const_item() const { return 0; } /* cloning of constant items (0 if it is not const) */ virtual Item *clone_item(THD *thd) { return 0; } + virtual Item* build_clone(THD *thd, MEM_ROOT *mem_root) { return get_copy(thd, mem_root); } virtual cond_result eq_cmp_result() const { return COND_OK; } inline uint float_length(uint decimals_par) const - { return decimals != NOT_FIXED_DEC ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} + { return decimals < FLOATING_POINT_DECIMALS ? (DBL_DIG+2+decimals_par) : DBL_DIG+8;} /* Returns total number of decimal digits */ virtual uint decimal_precision() const; /* Returns the number of integer part digits only */ @@ -1147,15 +1291,33 @@ public: query and why they should be generated from the Item-tree, @see mysql_register_view(). */ - virtual inline void print(String *str, enum_query_type query_type) + virtual enum precedence precedence() const { return DEFAULT_PRECEDENCE; } + void print_parenthesised(String *str, enum_query_type query_type, + enum precedence parent_prec); + /** + This helper is used to print expressions as a part of a table definition, + in particular for + - generated columns + - check constraints + - default value expressions + - partitioning expressions + */ + void print_for_table_def(String *str) { - str->append(full_name()); + print_parenthesised(str, + (enum_query_type)(QT_ITEM_ORIGINAL_FUNC_NULLIF | + QT_ITEM_IDENT_SKIP_DB_NAMES | + QT_ITEM_IDENT_SKIP_TABLE_NAMES | + QT_NO_DATA_EXPANSION | + QT_TO_SYSTEM_CHARSET), + LOWEST_PRECEDENCE); } + virtual void print(String *str, enum_query_type query_type); + void print_item_w_name(String *str, enum_query_type query_type); + void print_value(String *str); - void print_item_w_name(String *, enum_query_type query_type); - void print_value(String *); virtual void update_used_tables() {} - virtual COND *build_equal_items(THD *thd, COND_EQUAL *inherited, + virtual COND *build_equal_items(THD *thd, COND_EQUAL *inheited, bool link_item_fields, COND_EQUAL **cond_equal_ref) { @@ -1191,20 +1353,29 @@ public: { return false; } - virtual void split_sum_func(THD *thd, Item **ref_pointer_array, + virtual void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List<Item> &fields, uint flags) {} /* Called for items that really have to be split */ - void split_sum_func2(THD *thd, Item **ref_pointer_array, List<Item> &fields, + void split_sum_func2(THD *thd, Ref_ptr_array ref_pointer_array, + List<Item> &fields, Item **ref, uint flags); virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_time(MYSQL_TIME *ltime) { return get_date(ltime, TIME_TIME_ONLY | TIME_INVALID_DATES); } // Get date with automatic TIME->DATETIME conversion + bool convert_time_to_datetime(THD *thd, MYSQL_TIME *ltime, ulonglong fuzzydate) + { + MYSQL_TIME tmp; + if (time_to_datetime_with_warn(thd, ltime, &tmp, fuzzydate)) + return null_value= true; + *ltime= tmp; + return false; + } bool get_date_with_conversion(MYSQL_TIME *ltime, ulonglong fuzzydate); /* Get time with automatic DATE/DATETIME to TIME conversion. - Performce a reserve operation to get_date_with_conversion(). + Performes a reverse operation to get_date_with_conversion(). Suppose: - we have a set of items (typically with the native MYSQL_TYPE_TIME type) whose item->get_date() return TIME1 value, and @@ -1342,6 +1513,9 @@ public: 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; } + /* This is to handle printing of default values */ + virtual bool need_parentheses_in_default() { return false; } virtual void save_in_result_field(bool no_conversions) {} /* set value of aggregate function in case of no rows for grouping were found @@ -1365,12 +1539,7 @@ public: &my_charset_bin; }; - virtual bool walk(Item_processor processor, bool walk_subquery, uchar *arg) - { - return (this->*processor)(arg); - } - - virtual bool walk_top_and(Item_processor processor, uchar *arg) + virtual bool walk(Item_processor processor, bool walk_subquery, void *arg) { return (this->*processor)(arg); } @@ -1407,68 +1576,54 @@ public: (*traverser)(this, arg); } - /* - This is used to get the most recent version of any function in - an item tree. The version is the version where a MySQL function - was introduced in. So any function which is added should use - this function and set the int_arg to maximum of the input data - and their own version info. - */ - virtual bool intro_version(uchar *int_arg) { return 0; } - - virtual bool remove_dependence_processor(uchar * arg) { return 0; } - virtual bool cleanup_processor(uchar *arg); - virtual bool collect_item_field_processor(uchar * arg) { return 0; } - virtual bool add_field_to_set_processor(uchar * arg) { return 0; } - virtual bool find_item_in_field_list_processor(uchar *arg) { return 0; } - virtual bool find_item_processor(uchar *arg); - virtual bool change_context_processor(uchar *context) { return 0; } - virtual bool reset_query_id_processor(uchar *query_id_arg) { return 0; } - virtual bool is_expensive_processor(uchar *arg) { return 0; } - virtual bool register_field_in_read_map(uchar *arg) { return 0; } - virtual bool register_field_in_write_map(uchar *arg) { return 0; } - virtual bool enumerate_field_refs_processor(uchar *arg) { return 0; } - virtual bool mark_as_eliminated_processor(uchar *arg) { return 0; } - virtual bool eliminate_subselect_processor(uchar *arg) { return 0; } - virtual bool set_fake_select_as_master_processor(uchar *arg) { return 0; } - virtual bool update_table_bitmaps_processor(uchar *arg) { return 0; } - virtual bool view_used_tables_processor(uchar *arg) { return 0; } - virtual bool eval_not_null_tables(uchar *opt_arg) { return 0; } - virtual bool is_subquery_processor (uchar *opt_arg) { return 0; } - virtual bool count_sargable_conds(uchar *arg) { return 0; } - virtual bool limit_index_condition_pushdown_processor(uchar *opt_arg) - { - return FALSE; - } - virtual bool exists2in_processor(uchar *opt_arg) { return 0; } - virtual bool find_selective_predicates_list_processor(uchar *opt_arg) - { return 0; } - - /* To call bool function for all arguments */ - struct bool_func_call_args - { - Item *original_func_item; - void (Item::*bool_function)(); - }; - bool call_bool_func_processor(uchar *org_item) - { - bool_func_call_args *info= (bool_func_call_args*) org_item; - /* Avoid recursion, as walk also calls for original item */ - if (info->original_func_item != this) - (this->*(info->bool_function))(); - return FALSE; - } + /*========= Item processors, to be used with Item::walk() ========*/ + virtual bool remove_dependence_processor(void *arg) { return 0; } + virtual bool cleanup_processor(void *arg); + virtual bool cleanup_excluding_fields_processor(void *arg) { return cleanup_processor(arg); } + virtual bool cleanup_excluding_const_fields_processor(void *arg) { return cleanup_processor(arg); } + virtual bool collect_item_field_processor(void *arg) { return 0; } + virtual bool collect_outer_ref_processor(void *arg) {return 0; } + virtual bool check_inner_refs_processor(void *arg) { return 0; } + virtual bool find_item_in_field_list_processor(void *arg) { return 0; } + virtual bool find_item_processor(void *arg); + virtual bool change_context_processor(void *arg) { return 0; } + virtual bool reset_query_id_processor(void *arg) { return 0; } + virtual bool is_expensive_processor(void *arg) { return 0; } + + // FIXME reduce the number of "add field to bitmap" processors + virtual bool add_field_to_set_processor(void *arg) { return 0; } + virtual bool register_field_in_read_map(void *arg) { return 0; } + virtual bool register_field_in_write_map(void *arg) { return 0; } + virtual bool register_field_in_bitmap(void *arg) { return 0; } + virtual bool update_table_bitmaps_processor(void *arg) { return 0; } + + virtual bool enumerate_field_refs_processor(void *arg) { return 0; } + virtual bool mark_as_eliminated_processor(void *arg) { return 0; } + virtual bool eliminate_subselect_processor(void *arg) { return 0; } + virtual bool set_fake_select_as_master_processor(void *arg) { return 0; } + virtual bool view_used_tables_processor(void *arg) { return 0; } + virtual bool eval_not_null_tables(void *arg) { return 0; } + virtual bool is_subquery_processor(void *arg) { return 0; } + virtual bool count_sargable_conds(void *arg) { return 0; } + virtual bool limit_index_condition_pushdown_processor(void *arg) { return 0; } + virtual bool exists2in_processor(void *arg) { return 0; } + virtual bool find_selective_predicates_list_processor(void *arg) { return 0; } - - /* - The next function differs from the previous one that a bitmap to be updated - is passed as uchar *arg. + /* + TRUE if the expression depends only on the table indicated by tab_map + or can be converted to such an exression using equalities. + Not to be used for AND/OR formulas. */ - virtual bool register_field_in_bitmap(uchar *arg) { return 0; } - - bool cache_const_expr_analyzer(uchar **arg); - Item* cache_const_expr_transformer(THD *thd, uchar *arg); + virtual bool excl_dep_on_table(table_map tab_map) { return false; } + /* + TRUE if the expression depends only on grouping fields of sel + or can be converted to such an exression using equalities. + Not to be used for AND/OR formulas. + */ + virtual bool excl_dep_on_grouping_fields(st_select_lex *sel) { return false; } + virtual bool switch_to_nullable_fields_processor(void *arg) { return 0; } + virtual bool find_function_processor (void *arg) { return 0; } /* Check if a partition function is allowed SYNOPSIS @@ -1520,21 +1675,47 @@ public: assumes that there are no multi-byte collations amongst the partition fields. */ - virtual bool check_partition_func_processor(uchar *bool_arg) { return TRUE;} - /* - @brief - Processor used to mark virtual columns used in partitioning expression + virtual bool check_partition_func_processor(void *arg) { return 1;} + virtual bool post_fix_fields_part_expr_processor(void *arg) { return 0; } + virtual bool rename_fields_processor(void *arg) { return 0; } + /** Processor used to check acceptability of an item in the defining + expression for a virtual column - @param - arg always ignored + @param arg always ignored - @retval - FALSE always + @retval 0 the item is accepted in the definition of a virtual column + @retval 1 otherwise */ - virtual bool vcol_in_partition_func_processor(uchar *arg) + struct vcol_func_processor_result { - return FALSE; + uint errors; /* Bits of possible errors */ + const char *name; /* Not supported function */ + }; + struct func_processor_rename + { + LEX_CSTRING db_name; + LEX_CSTRING table_name; + List<Create_field> fields; + }; + virtual bool check_vcol_func_processor(void *arg) + { + return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE); } + virtual bool check_field_expression_processor(void *arg) { return 0; } + virtual bool check_func_default_processor(void *arg) { return 0; } + /* + Check if an expression value has allowed arguments, like DATE/DATETIME + for date functions. Also used by partitioning code to reject + timezone-dependent expressions in a (sub)partitioning function. + */ + virtual bool check_valid_arguments_processor(void *arg) { return 0; } + virtual bool update_vcol_processor(void *arg) { return 0; } + /*============== End of Item processor list ======================*/ + + virtual Item *get_copy(THD *thd, MEM_ROOT *mem_root)=0; + + bool cache_const_expr_analyzer(uchar **arg); + Item* cache_const_expr_transformer(THD *thd, uchar *arg); virtual Item* propagate_equal_fields(THD*, const Context &, COND_EQUAL *) { @@ -1546,35 +1727,9 @@ public: COND_EQUAL *cond, Item **place); - /* - @brief - Processor used to check acceptability of an item in the defining - expression for a virtual column - - @param - arg always ignored - - @retval - FALSE the item is accepted in the definition of a virtual column - @retval - TRUE otherwise - */ - virtual bool check_vcol_func_processor(uchar *arg) - { - return trace_unsupported_by_check_vcol_func_processor(full_name()); - } - /* arg points to REPLACE_EQUAL_FIELD_ARG object */ virtual Item *replace_equal_field(THD *thd, uchar *arg) { return this; } - /* - Check if an expression value has allowed arguments, like DATE/DATETIME - for date functions. Also used by partitioning code to reject - timezone-dependent expressions in a (sub)partitioning function. - */ - virtual bool check_valid_arguments_processor(uchar *bool_arg) - { - return FALSE; - } + struct Collect_deps_prm { List<Item> *parameters; @@ -1584,31 +1739,6 @@ public: int nest_level; bool collect; }; - /** - Collect outer references - */ - virtual bool collect_outer_ref_processor(uchar *arg) {return FALSE; } - - /** - Find a function of a given type - - @param arg the function type to search (enum Item_func::Functype) - @return - @retval TRUE the function type we're searching for is found - @retval FALSE the function type wasn't found - - @description - This function can be used (together with Item::walk()) to find functions - in an item tree fragment. - */ - virtual bool find_function_processor (uchar *arg) - { - return FALSE; - } - - virtual bool check_inner_refs_processor(uchar *arg) { return FALSE; } - - virtual bool switch_to_nullable_fields_processor(uchar *arg) { return FALSE; } /* For SP local variable returns pointer to Item representing its @@ -1642,9 +1772,6 @@ public: return create_tmp_field(false, table, MY_INT32_NUM_DECIMAL_DIGITS - 2); } - Field *tmp_table_field_from_field_type(TABLE *table, - bool fixed_length, - bool set_blob_packlength); virtual Item_field *field_for_view_update() { return 0; } virtual Item *neg_transformer(THD *thd) { return NULL; } @@ -1652,6 +1779,13 @@ public: { return this; } virtual Item *expr_cache_insert_transformer(THD *thd, uchar *unused) { return this; } + virtual Item *derived_field_transformer_for_having(THD *thd, uchar *arg) + { return this; } + virtual Item *derived_field_transformer_for_where(THD *thd, uchar *arg) + { return this; } + virtual Item *derived_grouping_field_transformer_for_where(THD *thd, + uchar *arg) + { return this; } virtual bool expr_cache_is_needed(THD *) { return FALSE; } virtual Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs) const @@ -1733,7 +1867,7 @@ public: virtual bool is_expensive() { if (is_expensive_cache < 0) - is_expensive_cache= walk(&Item::is_expensive_processor, 0, (uchar*)0); + is_expensive_cache= walk(&Item::is_expensive_processor, 0, NULL); return MY_TEST(is_expensive_cache); } virtual Field::geometry_type get_geometry_type() const @@ -1749,7 +1883,7 @@ public: max_length= char_to_byte_length_safe(max_char_length_arg, cs->mbmaxlen); collation.collation= cs; } - void fix_char_length(uint32 max_char_length_arg) + void fix_char_length(size_t max_char_length_arg) { max_length= char_to_byte_length_safe(max_char_length_arg, collation.collation->mbmaxlen); @@ -1784,7 +1918,7 @@ public: table_map view_used_tables(TABLE_LIST *view) { view->view_used_tables= 0; - walk(&Item::view_used_tables_processor, 0, (uchar *) view); + walk(&Item::view_used_tables_processor, 0, view); return view->view_used_tables; } @@ -1802,14 +1936,42 @@ public: /* how much position should be reserved for Exists2In transformation */ virtual uint exists2in_reserved_items() { return 0; }; + virtual Item *neg(THD *thd); + /** Inform the item that it is located under a NOT, which is a top-level item. */ virtual void under_not(Item_func_not * upper __attribute__((unused))) {}; + + + void register_in(THD *thd); + + bool depends_only_on(table_map view_map) + { return marker & FULL_EXTRACTION_FL; } + int get_extraction_flag() + { return marker & EXTRACTION_MASK; } + void set_extraction_flag(int flags) + { + marker &= ~EXTRACTION_MASK; + marker|= flags; + } + void clear_extraction_flag() + { + marker &= ~EXTRACTION_MASK; + } }; +template <class T> +inline Item* get_item_copy (THD *thd, MEM_ROOT *mem_root, T* item) +{ + Item *copy= new (mem_root) T(*item); + copy->register_in(thd); + return copy; +} + + /** Compare two Items for List<Item>::add_unique() */ @@ -1829,7 +1991,7 @@ bool cmp_items(Item *a, Item *b); } My_enumerator enumerator; - item->walk(Item::enumerate_field_refs_processor, ...,(uchar*)&enumerator); + item->walk(Item::enumerate_field_refs_processor, ...,&enumerator); This is similar to Visitor pattern. */ @@ -1941,6 +2103,7 @@ public: Item_basic_constant(THD *thd): Item_basic_value(thd), used_table_map(0) {}; void set_used_tables(table_map map) { used_table_map= map; } table_map used_tables() const { return used_table_map; } + bool check_vcol_func_processor(void *arg) { return FALSE;} /* to prevent drop fixed flag (no need parent cleanup call) */ void cleanup() { @@ -1996,27 +2159,31 @@ public: bool is_null(); public: - inline void make_field(Send_field *field); + inline void make_field(THD *thd, Send_field *field); inline bool const_item() const; inline int save_in_field(Field *field, bool no_conversions); inline bool send(Protocol *protocol, String *str); + bool check_vcol_func_processor(void *arg) + { + return mark_unsupported_function(m_name.str, arg, VCOL_IMPOSSIBLE); + } }; /***************************************************************************** Item_sp_variable inline implementation. *****************************************************************************/ -inline void Item_sp_variable::make_field(Send_field *field) +inline void Item_sp_variable::make_field(THD *thd, Send_field *field) { Item *it= this_item(); if (name) - it->set_name(name, (uint) strlen(name), system_charset_info); + it->set_name(thd, name, (uint) strlen(name), system_charset_info); else - it->set_name(m_name.str, (uint) m_name.length, system_charset_info); - it->make_field(field); + it->set_name(thd, m_name.str, (uint) m_name.length, system_charset_info); + it->make_field(thd, field); } inline bool Item_sp_variable::const_item() const @@ -2042,13 +2209,12 @@ inline bool Item_sp_variable::send(Protocol *protocol, String *str) class Item_splocal :public Item_sp_variable, private Settable_routine_parameter, - public Rewritable_query_parameter + public Rewritable_query_parameter, + public Type_handler_hybrid_field_type { uint m_var_idx; Type m_type; - Item_result m_result_type; - enum_field_types m_field_type; public: Item_splocal(THD *thd, const LEX_STRING &sp_var_name, uint sp_var_idx, enum_field_types sp_var_type, @@ -2066,8 +2232,12 @@ public: inline uint get_var_idx() const; inline enum Type type() const; - inline Item_result result_type() const; - inline enum_field_types field_type() const { return m_field_type; } + enum_field_types field_type() const + { return Type_handler_hybrid_field_type::field_type(); } + enum Item_result result_type () const + { return Type_handler_hybrid_field_type::result_type(); } + enum Item_result cmp_type () const + { return Type_handler_hybrid_field_type::cmp_type(); } private: bool set_value(THD *thd, sp_rcontext *ctx, Item **it); @@ -2082,6 +2252,8 @@ public: { return this; } bool append_for_log(THD *thd, String *str); + + Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } }; /***************************************************************************** @@ -2103,12 +2275,6 @@ inline enum Item::Type Item_splocal::type() const return m_type; } -inline Item_result Item_splocal::result_type() const -{ - return m_result_type; -} - - /***************************************************************************** A reference to case expression in SP, used in runtime. *****************************************************************************/ @@ -2125,6 +2291,7 @@ public: inline enum Type type() const; inline Item_result result_type() const; + enum_field_types field_type() const { return this_item()->field_type(); } public: /* @@ -2133,6 +2300,7 @@ public: purposes. */ virtual void print(String *str, enum_query_type query_type); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } private: uint m_case_expr_id; @@ -2185,6 +2353,11 @@ public: bool is_null(); virtual void print(String *str, enum_query_type query_type); + enum_field_types field_type() const + { + return value_item->field_type(); + } + Item_result result_type() const { return value_item->result_type(); @@ -2204,20 +2377,20 @@ public: { return value_item->send(protocol, str); } - bool check_vcol_func_processor(uchar *arg) + bool check_vcol_func_processor(void *arg) { - return trace_unsupported_by_check_vcol_func_processor("name_const"); + return mark_unsupported_function("name_const()", arg, VCOL_IMPOSSIBLE); } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_name_const>(thd, mem_root, this); } }; class Item_num: public Item_basic_constant { public: Item_num(THD *thd): Item_basic_constant(thd) { collation.set_numeric(); } - virtual Item_num *neg(THD *thd)= 0; Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); - bool check_partition_func_processor(uchar *int_arg) { return FALSE;} - bool check_vcol_func_processor(uchar *arg) { return FALSE;} + bool check_partition_func_processor(void *int_arg) { return FALSE;} }; #define NO_CACHED_FIELD_INDEX ((uint)(-1)) @@ -2249,7 +2422,7 @@ public: save_in_field(result_field, no_conversions); } void cleanup(); - bool check_vcol_func_processor(uchar *arg) { return FALSE;} + bool check_vcol_func_processor(void *arg) { return FALSE;} }; @@ -2306,14 +2479,14 @@ public: const char *full_name() const; void cleanup(); st_select_lex *get_depended_from() const; - bool remove_dependence_processor(uchar * arg); + bool remove_dependence_processor(void * arg); virtual void print(String *str, enum_query_type query_type); - virtual bool change_context_processor(uchar *cntx) + virtual bool change_context_processor(void *cntx) { context= (Name_resolution_context *)cntx; return FALSE; } /** Collect outer references */ - virtual bool collect_outer_ref_processor(uchar *arg); + virtual bool collect_outer_ref_processor(void *arg); friend bool insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, const char *table_name, List_iterator<Item> *it, @@ -2338,9 +2511,12 @@ public: longlong val_int() { return field->val_int(); } String *val_str(String *str) { return field->val_str(str); } my_decimal *val_decimal(my_decimal *dec) { return field->val_decimal(dec); } - void make_field(Send_field *tmp_field); + void make_field(THD *thd, Send_field *tmp_field); CHARSET_INFO *charset_for_protocol(void) const { return field->charset_for_protocol(); } + enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } + Item* get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_ident_for_show>(thd, mem_root, this); } }; @@ -2394,7 +2570,7 @@ public: void reset_field(Field *f); bool fix_fields(THD *, Item **); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); - void make_field(Send_field *tmp_field); + void make_field(THD *thd, Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); void save_org_in_field(Field *field, fast_field_copier optimizer_data); fast_field_copier setup_fast_field_copier(Field *field); @@ -2427,7 +2603,6 @@ public: { TABLE *tab= field->table; tab->covering_keys.intersect(field->part_of_key); - tab->merge_keys.merge(field->part_of_key); if (tab->read_set) bitmap_fast_test_and_set(tab->read_set, field->field_index); /* @@ -2467,17 +2642,31 @@ public: 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(uchar * arg); - bool add_field_to_set_processor(uchar * arg); - bool find_item_in_field_list_processor(uchar *arg); - bool register_field_in_read_map(uchar *arg); - bool register_field_in_write_map(uchar *arg); - bool register_field_in_bitmap(uchar *arg); - bool check_partition_func_processor(uchar *int_arg) {return FALSE;} - bool vcol_in_partition_func_processor(uchar *bool_arg); - bool enumerate_field_refs_processor(uchar *arg); - bool update_table_bitmaps_processor(uchar *arg); - bool switch_to_nullable_fields_processor(uchar *arg); + bool collect_item_field_processor(void * arg); + bool add_field_to_set_processor(void * arg); + bool find_item_in_field_list_processor(void *arg); + bool register_field_in_read_map(void *arg); + bool register_field_in_write_map(void *arg); + bool register_field_in_bitmap(void *arg); + bool check_partition_func_processor(void *int_arg) {return FALSE;} + bool post_fix_fields_part_expr_processor(void *bool_arg); + bool check_valid_arguments_processor(void *bool_arg); + bool check_field_expression_processor(void *arg); + bool enumerate_field_refs_processor(void *arg); + bool update_table_bitmaps_processor(void *arg); + bool switch_to_nullable_fields_processor(void *arg); + bool update_vcol_processor(void *arg); + bool rename_fields_processor(void *arg); + bool check_vcol_func_processor(void *arg) + { + context= 0; + if (field && (field->unireg_check == Field::NEXT_NUMBER)) + { + // Auto increment fields are unsupported + return mark_unsupported_function(field_name, arg, VCOL_FIELD_REF | VCOL_AUTO_INC); + } + return mark_unsupported_function(field_name, arg, VCOL_FIELD_REF); + } void cleanup(); Item_equal *get_item_equal() { return item_equal; } void set_item_equal(Item_equal *item_eq) { item_equal= item_eq; } @@ -2488,7 +2677,19 @@ public: Item_field *field_for_view_update() { return this; } int fix_outer_field(THD *thd, Field **field, Item **reference); virtual Item *update_value_transformer(THD *thd, uchar *select_arg); + Item *derived_field_transformer_for_having(THD *thd, uchar *arg); + Item *derived_field_transformer_for_where(THD *thd, uchar *arg); + Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg); virtual void print(String *str, enum_query_type query_type); + bool excl_dep_on_table(table_map tab_map); + bool excl_dep_on_grouping_fields(st_select_lex *sel); + bool cleanup_excluding_fields_processor(void *arg) + { return field ? 0 : cleanup_processor(arg); } + bool cleanup_excluding_const_fields_processor(void *arg) + { return field && const_item() ? 0 : cleanup_processor(arg); } + + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_field>(thd, mem_root, this); } bool is_outer_field() const { DBUG_ASSERT(fixed); @@ -2580,8 +2781,9 @@ public: } Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); - bool check_partition_func_processor(uchar *int_arg) {return FALSE;} - bool check_vcol_func_processor(uchar *arg) { return FALSE;} + bool check_partition_func_processor(void *int_arg) {return FALSE;} + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_null>(thd, mem_root, this); } }; class Item_null_result :public Item_null @@ -2605,27 +2807,135 @@ public: { save_in_field(result_field, no_conversions); } - bool check_partition_func_processor(uchar *int_arg) {return TRUE;} - bool check_vcol_func_processor(uchar *arg) + bool check_partition_func_processor(void *int_arg) {return TRUE;} + bool check_vcol_func_processor(void *arg) { - return trace_unsupported_by_check_vcol_func_processor(full_name()); + return mark_unsupported_function(full_name(), arg, VCOL_IMPOSSIBLE); } }; -/* Item represents one placeholder ('?') of prepared statement */ +/* + Item represents one placeholder ('?') of prepared statement + + Notes: + Item_param::field_type() is used when this item is in a temporary table. + This is NOT placeholder metadata sent to client, as this value + is assigned after sending metadata (in setup_one_conversion_function). + For example in case of 'SELECT ?' you'll get MYSQL_TYPE_STRING both + in result set and placeholders metadata, no matter what type you will + supply for this placeholder in mysql_stmt_execute. +*/ class Item_param :public Item_basic_value, private Settable_routine_parameter, - public Rewritable_query_parameter + public Rewritable_query_parameter, + public Type_handler_hybrid_field_type { -public: + /* + NO_VALUE is a special value meaning that the parameter has not been + assigned yet. Item_param::state is assigned to NO_VALUE in constructor + and is used at prepare time. + + 1. At prepare time + Item_param::fix_fields() sets "fixed" to true, + but as Item_param::state is still NO_VALUE, + Item_param::basic_const_item() returns false. This prevents various + optimizations to happen at prepare time fix_fields(). + For example, in this query: + PREPARE stmt FROM 'SELECT FORMAT(10000,2,?)'; + Item_param::basic_const_item() is tested from + Item_func_format::fix_length_and_dec(). + + 2. At execute time: + When Item_param gets a value + (or a pseudo-value like DEFAULT_VALUE or IGNORE_VALUE): + - Item_param::state changes from NO_VALUE to something else + - Item_param::fixed is changed to true + All Item_param::set_xxx() make sure to do so. + In the state with an assigned value: + - Item_param::basic_const_item() returns true + - Item::type() returns NULL_ITEM, INT_ITEM, REAL_ITEM, DECIMAL_ITEM, + DATE_ITEM, STRING_ITEM, depending on the value assigned. + So in this state Item_param behaves in many cases like a literal. + + When Item_param::cleanup() is called: + - Item_param::state does not change + - Item_param::fixed changes to false + Note, this puts Item_param into an inconsistent state: + - Item_param::basic_const_item() still returns "true" + - Item_param::type() still pretends to be a basic constant Item + Both are not expected in combination with fixed==false. + However, these methods are not really called in this state, + see asserts in Item_param::basic_const_item() and Item_param::type(). + + When Item_param::reset() is called: + - Item_param::state changes to NO_VALUE + - Item_param::fixed changes to false + */ enum enum_item_param_state { NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE, STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE, - DECIMAL_VALUE + DECIMAL_VALUE, DEFAULT_VALUE, IGNORE_VALUE } state; + enum Type item_type; + + void fix_type(Type type) + { + item_type= type; + fixed= true; + } + + void fix_temporal(uint32 max_length_arg, uint decimals_arg); + +public: + struct CONVERSION_INFO + { + /* + Character sets conversion info for string values. + Character sets of client and connection defined at bind time are used + for all conversions, even if one of them is later changed (i.e. + between subsequent calls to mysql_stmt_execute). + */ + CHARSET_INFO *character_set_client; + CHARSET_INFO *character_set_of_placeholder; + /* + This points at character set of connection if conversion + to it is required (i. e. if placeholder typecode is not BLOB). + Otherwise it's equal to character_set_client (to simplify + check in convert_str_value()). + */ + CHARSET_INFO *final_character_set_of_str_value; + private: + bool needs_conversion() const + { + return final_character_set_of_str_value != + character_set_of_placeholder; + } + bool convert(THD *thd, String *str); + public: + void set(THD *thd, CHARSET_INFO *cs); + bool convert_if_needed(THD *thd, String *str) + { + /* + Check is so simple because all charsets were set up properly + in setup_one_conversion_function, where typecode of + placeholder was also taken into account: the variables are different + here only if conversion is really necessary. + */ + if (needs_conversion()) + return convert(thd, str); + str->set_charset(final_character_set_of_str_value); + return false; + } + }; + + /* + Used for bulk protocol only. + */ + enum enum_indicator_type indicator; + /* A buffer for string and long data values. Historically all allocated values returned from val_str() were treated as eligible to @@ -2642,46 +2952,24 @@ public: { longlong integer; double real; - /* - Character sets conversion info for string values. - Character sets of client and connection defined at bind time are used - for all conversions, even if one of them is later changed (i.e. - between subsequent calls to mysql_stmt_execute). - */ - struct CONVERSION_INFO - { - CHARSET_INFO *character_set_client; - CHARSET_INFO *character_set_of_placeholder; - /* - This points at character set of connection if conversion - to it is required (i. e. if placeholder typecode is not BLOB). - Otherwise it's equal to character_set_client (to simplify - check in convert_str_value()). - */ - CHARSET_INFO *final_character_set_of_str_value; - } cs_info; + CONVERSION_INFO cs_info; MYSQL_TIME time; } value; - /* Cached values for virtual methods to save us one switch. */ - enum Item_result item_result_type; - enum Type item_type; - - /* - Used when this item is used in a temporary table. - This is NOT placeholder metadata sent to client, as this value - is assigned after sending metadata (in setup_one_conversion_function). - For example in case of 'SELECT ?' you'll get MYSQL_TYPE_STRING both - in result set and placeholders metadata, no matter what type you will - supply for this placeholder in mysql_stmt_execute. - */ - enum enum_field_types param_type; + enum_field_types field_type() const + { return Type_handler_hybrid_field_type::field_type(); } + enum Item_result result_type () const + { return Type_handler_hybrid_field_type::result_type(); } + enum Item_result cmp_type () const + { return Type_handler_hybrid_field_type::cmp_type(); } Item_param(THD *thd, uint pos_in_query_arg); - enum Item_result result_type () const { return item_result_type; } - enum Type type() const { return item_type; } - enum_field_types field_type() const { return param_type; } + enum Type type() const + { + DBUG_ASSERT(fixed || state == NO_VALUE); + return item_type; + } double val_real(); longlong val_int(); @@ -2690,15 +2978,18 @@ public: bool get_date(MYSQL_TIME *tm, ulonglong fuzzydate); int save_in_field(Field *field, bool no_conversions); + void set_default(); + void set_ignore(); void set_null(); void set_int(longlong i, uint32 max_length_arg); void set_double(double i); void set_decimal(const char *str, ulong length); - void set_decimal(const my_decimal *dv); + void set_decimal(const my_decimal *dv, bool unsigned_arg); bool set_str(const char *str, ulong length); bool set_longdata(const char *str, ulong length); void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg); - bool set_from_user_var(THD *thd, const user_var_entry *entry); + void set_time(const MYSQL_TIME *tm, uint32 max_length_arg, uint decimals_arg); + bool set_from_item(THD *thd, Item *item); void reset(); /* Assign placeholder value from bind data. @@ -2723,6 +3014,18 @@ public: bool is_null() { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; } bool basic_const_item() const; + bool has_no_value() const + { + return state == NO_VALUE; + } + bool has_long_data_value() const + { + return state == LONG_DATA_VALUE; + } + bool has_int_value() const + { + return state == INT_VALUE; + } /* This method is used to make a copy of a basic constant item when propagating constants in the optimizer. The reason to create a new @@ -2746,11 +3049,15 @@ public: Rewritable_query_parameter *get_rewritable_query_parameter() { return this; } Settable_routine_parameter *get_settable_routine_parameter() - { return this; } + { return m_is_settable_routine_parameter ? this : NULL; } bool append_for_log(THD *thd, String *str); + bool check_vcol_func_processor(void *int_arg) {return FALSE;} + Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } private: + void invalid_default_param() const; + virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it); virtual void set_out_param_info(Send_field *info); @@ -2758,10 +3065,11 @@ private: public: virtual const Send_field *get_out_param_info() const; - virtual void make_field(Send_field *field); + virtual void make_field(THD *thd, Send_field *field); private: Send_field *m_out_param_info; + bool m_is_settable_routine_parameter; }; @@ -2793,13 +3101,28 @@ public: bool basic_const_item() const { return 1; } Item *clone_item(THD *thd); virtual void print(String *str, enum_query_type query_type); - Item_num *neg(THD *thd) { value= -value; return this; } + Item *neg(THD *thd); uint decimal_precision() const { return (uint) (max_length - MY_TEST(value < 0)); } bool eq(const Item *item, bool binary_cmp) const { return int_eq(value, item); } - bool check_partition_func_processor(uchar *bool_arg) { return FALSE;} - bool check_vcol_func_processor(uchar *arg) { return FALSE;} + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_int>(thd, mem_root, this); } +}; + + +/* + We sometimes need to distinguish a number from a boolean: + a[1] and a[true] are different things in XPath. + Also in JSON boolean values should be treated differently. +*/ +class Item_bool :public Item_int +{ +public: + Item_bool(THD *thd, const char *str_arg, longlong i): + Item_int(thd, str_arg, i, 1) {} + bool is_bool_type() { return true; } + Item *neg_transformer(THD *thd); }; @@ -2814,8 +3137,10 @@ public: String *val_str(String*); Item *clone_item(THD *thd); virtual void print(String *str, enum_query_type query_type); - Item_num *neg(THD *thd); + Item *neg(THD *thd); uint decimal_precision() const { return max_length; } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_uint>(thd, mem_root, this); } }; @@ -2858,17 +3183,12 @@ public: bool basic_const_item() const { return 1; } Item *clone_item(THD *thd); virtual void print(String *str, enum_query_type query_type); - Item_num *neg(THD *thd) - { - my_decimal_neg(&decimal_value); - unsigned_flag= !decimal_value.sign(); - return this; - } + Item *neg(THD *thd); uint decimal_precision() const { return decimal_value.precision(); } bool eq(const Item *, bool binary_cmp) const; void set_decimal_value(my_decimal *value_par); - bool check_partition_func_processor(uchar *bool_arg) { return FALSE;} - bool check_vcol_func_processor(uchar *arg) { return FALSE;} + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_decimal>(thd, mem_root, this); } }; @@ -2913,10 +3233,12 @@ public: my_decimal *val_decimal(my_decimal *); bool basic_const_item() const { return 1; } Item *clone_item(THD *thd); - Item_num *neg(THD *thd) { value= -value; return this; } + Item *neg(THD *thd); virtual void print(String *str, enum_query_type query_type); bool eq(const Item *item, bool binary_cmp) const { return real_eq(value, item); } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_float>(thd, mem_root, this); } }; @@ -2950,10 +3272,11 @@ protected: // it is constant => can be used without fix_fields (and frequently used) fixed= 1; } - void fix_and_set_name_from_value(Derivation dv, const Metadata metadata) + void fix_and_set_name_from_value(THD *thd, Derivation dv, + const Metadata metadata) { fix_from_value(dv, metadata); - set_name(str_value.ptr(), str_value.length(), str_value.charset()); + set_name(thd, str_value.ptr(), str_value.length(), str_value.charset()); } protected: /* Just create an item and do not fill string representation */ @@ -2962,7 +3285,7 @@ protected: { collation.set(cs, dv); max_length= 0; - set_name(NULL, 0, system_charset_info); + set_name(thd, NULL, 0, system_charset_info); decimals= NOT_FIXED_DEC; fixed= 1; } @@ -2971,7 +3294,7 @@ public: Item_basic_constant(thd) { collation.set(csi, DERIVATION_COERCIBLE); - set_name(NULL, 0, system_charset_info); + set_name(thd, NULL, 0, system_charset_info); decimals= NOT_FIXED_DEC; fixed= 1; str_value.copy(str_arg, length_arg, csi); @@ -2982,14 +3305,14 @@ public: Derivation dv, uint repertoire): Item_basic_constant(thd) { str_value.set_or_copy_aligned(str, length, cs); - fix_and_set_name_from_value(dv, Metadata(&str_value, repertoire)); + fix_and_set_name_from_value(thd, dv, Metadata(&str_value, repertoire)); } Item_string(THD *thd, const char *str, uint length, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE): Item_basic_constant(thd) { str_value.set_or_copy_aligned(str, length, cs); - fix_and_set_name_from_value(dv, Metadata(&str_value)); + fix_and_set_name_from_value(thd, dv, Metadata(&str_value)); } Item_string(THD *thd, const String *str, CHARSET_INFO *tocs, uint *conv_errors, Derivation dv, uint repertoire): Item_basic_constant(thd) @@ -2997,7 +3320,7 @@ public: if (str_value.copy(str, tocs, conv_errors)) str_value.set("", 0, tocs); // EOM ? str_value.mark_as_const(); - fix_and_set_name_from_value(dv, Metadata(&str_value, repertoire)); + fix_and_set_name_from_value(thd, dv, Metadata(&str_value, repertoire)); } // Constructors with an externally provided item name Item_string(THD *thd, const char *name_par, const char *str, uint length, @@ -3006,7 +3329,7 @@ public: { str_value.set_or_copy_aligned(str, length, cs); fix_from_value(dv, Metadata(&str_value)); - set_name(name_par, 0, system_charset_info); + set_name(thd, name_par, 0, system_charset_info); } Item_string(THD *thd, const char *name_par, const char *str, uint length, CHARSET_INFO *cs, Derivation dv, uint repertoire): @@ -3014,7 +3337,7 @@ public: { str_value.set_or_copy_aligned(str, length, cs); fix_from_value(dv, Metadata(&str_value, repertoire)); - set_name(name_par, 0, system_charset_info); + set_name(thd, name_par, 0, system_charset_info); } void print_value(String *to) const { @@ -3048,8 +3371,7 @@ public: max_length= str_value.numchars() * collation.collation->mbmaxlen; } virtual void print(String *str, enum_query_type query_type); - bool check_partition_func_processor(uchar *int_arg) {return FALSE;} - bool check_vcol_func_processor(uchar *arg) { return FALSE;} + bool check_partition_func_processor(void *int_arg) {return FALSE;} /** Return TRUE if character-set-introducer was explicitly specified in the @@ -3106,6 +3428,9 @@ public: } return MYSQL_TYPE_STRING; // Not a temporal literal } + + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_string>(thd, mem_root, this); } }; @@ -3135,7 +3460,7 @@ public: Item_string(thd, str, length, system_charset_info) { } Item_string_sys(THD *thd, const char *str): - Item_string(thd, str, strlen(str), system_charset_info) + Item_string(thd, str, (uint) strlen(str), system_charset_info) { } }; @@ -3148,7 +3473,7 @@ public: DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII) { } Item_string_ascii(THD *thd, const char *str): - Item_string(thd, str, strlen(str), &my_charset_latin1, + Item_string(thd, str, (uint)strlen(str), &my_charset_latin1, DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII) { } }; @@ -3180,10 +3505,12 @@ public: str->append(func_name); } - bool check_partition_func_processor(uchar *int_arg) {return TRUE;} - bool check_vcol_func_processor(uchar *arg) - { - return trace_unsupported_by_check_vcol_func_processor(func_name); + bool check_partition_func_processor(void *int_arg) {return TRUE;} + + bool check_vcol_func_processor(void *arg) + { // VCOL_TIME_FUNC because the value is not constant, but does not + // require fix_fields() to be re-run for every statement. + return mark_unsupported_function(func_name, arg, VCOL_TIME_FUNC); } }; @@ -3196,9 +3523,9 @@ public: CHARSET_INFO *cs= NULL): Item_string(thd, name_arg, length, cs) {} - bool check_vcol_func_processor(uchar *arg) + bool check_vcol_func_processor(void *arg) { - return trace_unsupported_by_check_vcol_func_processor("safe_string"); + return mark_unsupported_function("safe_string", arg, VCOL_IMPOSSIBLE); } }; @@ -3220,7 +3547,7 @@ class Item_blob :public Item_partition_func_safe_string { public: Item_blob(THD *thd, const char *name_arg, uint length): - Item_partition_func_safe_string(thd, name_arg, strlen(name_arg), &my_charset_bin) + Item_partition_func_safe_string(thd, name_arg, (uint) strlen(name_arg), &my_charset_bin) { max_length= length; } enum Type type() const { return TYPE_HOLDER; } enum_field_types field_type() const { return MYSQL_TYPE_BLOB; } @@ -3243,7 +3570,7 @@ public: Item_partition_func_safe_string(thd, "", 0, cs ? cs : &my_charset_utf8_general_ci) { name=(char*) header; max_length= length * collation.collation->mbmaxlen; } - void make_field(Send_field *field); + void make_field(THD *thd, Send_field *field); }; @@ -3285,8 +3612,7 @@ public: { return const_charset_converter(thd, tocs, true); } - bool check_partition_func_processor(uchar *int_arg) {return FALSE;} - bool check_vcol_func_processor(uchar *arg) { return FALSE;} + bool check_partition_func_processor(void *int_arg) {return FALSE;} bool basic_const_item() const { return 1; } bool eq(const Item *item, bool binary_cmp) const { @@ -3314,7 +3640,12 @@ public: DBUG_ASSERT(fixed == 1); return (double) (ulonglong) Item_hex_hybrid::val_int(); } - longlong val_int(); + longlong val_int() + { + // following assert is redundant, because fixed=1 assigned in constructor + DBUG_ASSERT(fixed == 1); + return longlong_from_hex_hybrid(str_value.ptr(), str_value.length()); + } my_decimal *val_decimal(my_decimal *decimal_value) { // following assert is redundant, because fixed=1 assigned in constructor @@ -3323,9 +3654,15 @@ public: int2my_decimal(E_DEC_FATAL_ERROR, value, TRUE, decimal_value); return decimal_value; } - int save_in_field(Field *field, bool no_conversions); + int save_in_field(Field *field, bool no_conversions) + { + field->set_notnull(); + return field->store_hex_hybrid(str_value.ptr(), str_value.length()); + } enum Item_result cast_to_int_type() const { return INT_RESULT; } void print(String *str, enum_query_type query_type); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_hex_hybrid>(thd, mem_root, this); } }; @@ -3366,6 +3703,8 @@ public: } enum Item_result cast_to_int_type() const { return STRING_RESULT; } void print(String *str, enum_query_type query_type); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_hex_string>(thd, mem_root, this); } }; @@ -3405,8 +3744,7 @@ public: enum Item_result result_type () const { return STRING_RESULT; } Item_result cmp_type() const { return TIME_RESULT; } - bool check_partition_func_processor(uchar *int_arg) {return FALSE;} - bool check_vcol_func_processor(uchar *arg) { return FALSE;} + bool check_partition_func_processor(void *int_arg) {return FALSE;} bool is_null() { return is_null_from_temporal(); } @@ -3448,6 +3786,8 @@ public: void print(String *str, enum_query_type query_type); Item *clone_item(THD *thd); bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_date_literal>(thd, mem_root, this); } }; @@ -3467,6 +3807,8 @@ public: void print(String *str, enum_query_type query_type); Item *clone_item(THD *thd); bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_time_literal>(thd, mem_root, this); } }; @@ -3488,6 +3830,8 @@ public: void print(String *str, enum_query_type query_type); Item *clone_item(THD *thd); bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_datetime_literal>(thd, mem_root, this); } }; @@ -3508,7 +3852,7 @@ class Item_date_literal_for_invalid_dates: public Item_date_literal Item_date_literal_for_invalid_dates::get_date() (unlike the regular Item_date_literal::get_date()) - does not check the result for NO_ZERO_IN_DATE and NO_ZER_DATE, + does not check the result for NO_ZERO_IN_DATE and NO_ZERO_DATE, always returns success (false), and does not produce error/warning messages. We need these _for_invalid_dates classes to be able to rewrite: @@ -3557,7 +3901,7 @@ protected: Item **args, *tmp_arg[2]; uint arg_count; void set_arguments(THD *thd, List<Item> &list); - bool walk_args(Item_processor processor, bool walk_subquery, uchar *arg) + bool walk_args(Item_processor processor, bool walk_subquery, void *arg) { for (uint i= 0; i < arg_count; i++) { @@ -3568,6 +3912,28 @@ protected: } bool transform_args(THD *thd, Item_transformer transformer, uchar *arg); void propagate_equal_fields(THD *, const Item::Context &, COND_EQUAL *); + bool excl_dep_on_table(table_map tab_map) + { + for (uint i= 0; i < arg_count; i++) + { + if (args[i]->const_item()) + continue; + if (!args[i]->excl_dep_on_table(tab_map)) + return false; + } + return true; + } + bool excl_dep_on_grouping_fields(st_select_lex *sel) + { + for (uint i= 0; i < arg_count; i++) + { + if (args[i]->const_item()) + continue; + if (!args[i]->excl_dep_on_grouping_fields(sel)) + return false; + } + return true; + } public: Item_args(void) :args(NULL), arg_count(0) @@ -3582,28 +3948,28 @@ public: { args[0]= a; args[1]= b; } - Item_args(Item *a, Item *b, Item *c) + Item_args(THD *thd, Item *a, Item *b, Item *c) { arg_count= 0; - if ((args= (Item**) sql_alloc(sizeof(Item*) * 3))) + if ((args= (Item**) thd_alloc(thd, sizeof(Item*) * 3))) { arg_count= 3; args[0]= a; args[1]= b; args[2]= c; } } - Item_args(Item *a, Item *b, Item *c, Item *d) + Item_args(THD *thd, Item *a, Item *b, Item *c, Item *d) { arg_count= 0; - if ((args= (Item**) sql_alloc(sizeof(Item*) * 4))) + if ((args= (Item**) thd_alloc(thd, sizeof(Item*) * 4))) { arg_count= 4; args[0]= a; args[1]= b; args[2]= c; args[3]= d; } } - Item_args(Item *a, Item *b, Item *c, Item *d, Item* e) + Item_args(THD *thd, Item *a, Item *b, Item *c, Item *d, Item* e) { arg_count= 5; - if ((args= (Item**) sql_alloc(sizeof(Item*) * 5))) + if ((args= (Item**) thd_alloc(thd, sizeof(Item*) * 5))) { arg_count= 5; args[0]= a; args[1]= b; args[2]= c; args[3]= d; args[4]= e; @@ -3812,17 +4178,17 @@ public: Item_func_or_sum(THD *thd, Item *a, Item *b): Item_result_field(thd), Item_args(a, b) { } Item_func_or_sum(THD *thd, Item *a, Item *b, Item *c): - Item_result_field(thd), Item_args(a, b, c) { } + Item_result_field(thd), Item_args(thd, a, b, c) { } Item_func_or_sum(THD *thd, Item *a, Item *b, Item *c, Item *d): - Item_result_field(thd), Item_args(a, b, c, d) { } + Item_result_field(thd), Item_args(thd, a, b, c, d) { } Item_func_or_sum(THD *thd, Item *a, Item *b, Item *c, Item *d, Item *e): - Item_result_field(thd), Item_args(a, b, c, d, e) { } + Item_result_field(thd), Item_args(thd, a, b, c, d, e) { } Item_func_or_sum(THD *thd, Item_func_or_sum *item): Item_result_field(thd, item), Item_args(thd, item), Used_tables_and_const_cache(item) { } Item_func_or_sum(THD *thd, List<Item> &list): Item_result_field(thd), Item_args(thd, list) { } - bool walk(Item_processor processor, bool walk_subquery, uchar *arg) + bool walk(Item_processor processor, bool walk_subquery, void *arg) { if (walk_args(processor, walk_subquery, arg)) return true; @@ -3848,6 +4214,7 @@ public: virtual void fix_length_and_dec()= 0; bool const_item() const { return const_item_cache; } table_map used_tables() const { return used_tables_cache; } + Item* build_clone(THD *thd, MEM_ROOT *mem_root); }; @@ -3912,7 +4279,7 @@ public: bool val_bool_result(); bool is_null_result(); bool send(Protocol *prot, String *tmp); - void make_field(Send_field *field); + void make_field(THD *thd, Send_field *field); bool fix_fields(THD *, Item **); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); int save_in_field(Field *field, bool no_conversions); @@ -3958,7 +4325,7 @@ public: { return ref ? (*ref)->real_item() : this; } - bool walk(Item_processor processor, bool walk_subquery, uchar *arg) + bool walk(Item_processor processor, bool walk_subquery, void *arg) { if (ref && *ref) return (*ref)->walk(processor, walk_subquery, arg) || @@ -3969,7 +4336,7 @@ public: Item* transform(THD *thd, Item_transformer, uchar *arg); Item* compile(THD *thd, Item_analyzer analyzer, uchar **arg_p, Item_transformer transformer, uchar *arg_t); - bool enumerate_field_refs_processor(uchar *arg) + bool enumerate_field_refs_processor(void *arg) { return (*ref)->enumerate_field_refs_processor(arg); } void no_rows_in_result() { @@ -4012,9 +4379,9 @@ public: if (ref && result_type() == ROW_RESULT) (*ref)->bring_value(); } - bool check_vcol_func_processor(uchar *arg) + bool check_vcol_func_processor(void *arg) { - return trace_unsupported_by_check_vcol_func_processor("ref"); + return mark_unsupported_function("ref", arg, VCOL_IMPOSSIBLE); } bool basic_const_item() const { return ref && (*ref)->basic_const_item(); } bool is_outer_field() const @@ -4023,6 +4390,8 @@ public: DBUG_ASSERT(ref); return (*ref)->is_outer_field(); } + + Item* build_clone(THD *thd, MEM_ROOT *mem_root); /** Checks if the item tree that ref points to contains a subquery. @@ -4031,6 +4400,33 @@ public: { return (*ref)->has_subquery(); } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_ref>(thd, mem_root, this); } + bool excl_dep_on_table(table_map tab_map) + { + table_map used= used_tables(); + if (used & OUTER_REF_TABLE_BIT) + return false; + return (used == tab_map) || (*ref)->excl_dep_on_table(tab_map); + } + bool excl_dep_on_grouping_fields(st_select_lex *sel) + { return (*ref)->excl_dep_on_grouping_fields(sel); } + bool cleanup_excluding_fields_processor(void *arg) + { + Item *item= real_item(); + if (item && item->type() == FIELD_ITEM && + ((Item_field *)item)->field) + return 0; + return cleanup_processor(arg); + } + bool cleanup_excluding_const_fields_processor(void *arg) + { + Item *item= real_item(); + if (item && item->type() == FIELD_ITEM && + ((Item_field *) item)->field && item->const_item()) + return 0; + return cleanup_processor(arg); + } }; @@ -4073,6 +4469,8 @@ public: bool is_null(); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); virtual Ref_Type ref_type() { return DIRECT_REF; } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_direct_ref>(thd, mem_root, this); } }; @@ -4178,7 +4576,8 @@ public: virtual void print(String *str, enum_query_type query_type); virtual const char *full_name() const { return orig_item->full_name(); } - virtual void make_field(Send_field *field) { orig_item->make_field(field); } + virtual void make_field(THD *thd, Send_field *field) + { orig_item->make_field(thd, field); } bool eq(const Item *item, bool binary_cmp) const { Item *it= ((Item *) item)->real_item(); @@ -4198,12 +4597,12 @@ public: } bool const_item() const { return orig_item->const_item(); } table_map not_null_tables() const { return orig_item->not_null_tables(); } - bool walk(Item_processor processor, bool walk_subquery, uchar *arg) + bool walk(Item_processor processor, bool walk_subquery, void *arg) { return orig_item->walk(processor, walk_subquery, arg) || (this->*processor)(arg); } - bool enumerate_field_refs_processor(uchar *arg) + bool enumerate_field_refs_processor(void *arg) { return orig_item->enumerate_field_refs_processor(arg); } Item_field *field_for_view_update() { return orig_item->field_for_view_update(); } @@ -4229,12 +4628,15 @@ public: orig_item->bring_value(); } bool is_expensive() { return orig_item->is_expensive(); } - bool is_expensive_processor(uchar *arg) + bool is_expensive_processor(void *arg) { return orig_item->is_expensive_processor(arg); } - bool check_vcol_func_processor(uchar *arg) + bool check_vcol_func_processor(void *arg) { - return trace_unsupported_by_check_vcol_func_processor("cache"); + return mark_unsupported_function("cache", arg, VCOL_IMPOSSIBLE); } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_cache_wrapper>(thd, mem_root, this); } + Item *build_clone(THD *thd, MEM_ROOT *mem_root) { return 0; } }; @@ -4302,18 +4704,25 @@ public: void update_used_tables(); table_map not_null_tables() const; bool const_item() const { return used_tables() == 0; } - bool walk(Item_processor processor, bool walk_subquery, uchar *arg) + bool walk(Item_processor processor, bool walk_subquery, void *arg) { return (*ref)->walk(processor, walk_subquery, arg) || (this->*processor)(arg); } - bool view_used_tables_processor(uchar *arg) + bool view_used_tables_processor(void *arg) { TABLE_LIST *view_arg= (TABLE_LIST *) arg; if (view_arg == view) view_arg->view_used_tables|= (*ref)->used_tables(); return 0; } + bool excl_dep_on_table(table_map tab_map); + bool excl_dep_on_grouping_fields(st_select_lex *sel); + Item *derived_field_transformer_for_having(THD *thd, uchar *arg); + Item *derived_field_transformer_for_where(THD *thd, uchar *arg); + Item *derived_grouping_field_transformer_for_where(THD *thd, + uchar *arg); + void save_val(Field *to) { if (check_null_ref()) @@ -4395,6 +4804,8 @@ public: item_equal= NULL; Item_direct_ref::cleanup(); } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_direct_view_ref>(thd, mem_root, this); } }; @@ -4451,7 +4862,7 @@ public: } table_map not_null_tables() const { return 0; } virtual Ref_Type ref_type() { return OUTER_REF; } - bool check_inner_refs_processor(uchar * arg); + bool check_inner_refs_processor(void * arg); }; @@ -4486,6 +4897,8 @@ public: bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); virtual void print(String *str, enum_query_type query_type); table_map used_tables() const; + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_ref_null_helper>(thd, mem_root, this); } }; /* @@ -4526,6 +4939,7 @@ public: #include "item_timefunc.h" #include "item_subselect.h" #include "item_xmlfunc.h" +#include "item_jsonfunc.h" #include "item_create.h" #endif @@ -4549,26 +4963,21 @@ public: from Item_). */ -class Item_copy :public Item +class Item_copy :public Item, + public Type_handler_hybrid_field_type { protected: /** - Stores the type of the resulting field that would be used to store the data + Type_handler_hybrid_field_type is used to + store the type of the resulting field that would be used to store the data in the cache. This is to avoid calls to the original item. */ - enum enum_field_types cached_field_type; /** The original item that is copied */ Item *item; /** - Stores the result type of the original item, so it can be returned - without calling the original item's method - */ - Item_result cached_result_type; - - /** Constructor of the Item_copy class stores metadata information about the original class as well as a @@ -4580,8 +4989,7 @@ protected: null_value=maybe_null=item->maybe_null; Type_std_attributes::set(item); name=item->name; - cached_field_type= item->field_type(); - cached_result_type= item->result_type(); + set_handler_by_field_type(item->field_type()); fixed= item->fixed; } @@ -4606,16 +5014,21 @@ public: Item *get_item() { return item; } /** All of the subclasses should have the same type tag */ enum Type type() const { return COPY_STR_ITEM; } - enum_field_types field_type() const { return cached_field_type; } - enum Item_result result_type () const { return cached_result_type; } - void make_field(Send_field *field) { item->make_field(field); } + enum_field_types field_type() const + { return Type_handler_hybrid_field_type::field_type(); } + enum Item_result result_type () const + { return Type_handler_hybrid_field_type::result_type(); } + enum Item_result cmp_type () const + { return Type_handler_hybrid_field_type::cmp_type(); } + + void make_field(THD *thd, Send_field *field) { item->make_field(thd, field); } table_map used_tables() const { return (table_map) 1L; } bool const_item() const { return 0; } bool is_null() { return null_value; } - bool check_vcol_func_processor(uchar *arg) + bool check_vcol_func_processor(void *arg) { - return trace_unsupported_by_check_vcol_func_processor("copy"); + return mark_unsupported_function("copy", arg, VCOL_IMPOSSIBLE); } /* @@ -4628,7 +5041,7 @@ public: virtual double val_real() = 0; virtual longlong val_int() = 0; virtual int save_in_field(Field *field, bool no_conversions) = 0; - bool walk(Item_processor processor, bool walk_subquery, uchar *args) + bool walk(Item_processor processor, bool walk_subquery, void *args) { return (item->walk(processor, walk_subquery, args)) || (this->*processor)(args); @@ -4651,6 +5064,8 @@ public: longlong val_int(); void copy(); int save_in_field(Field *field, bool no_conversions); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_copy_string>(thd, mem_root, this); } }; @@ -4673,6 +5088,8 @@ public: return null_value ? 0 : cached_value; } virtual void copy(); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_copy_int>(thd, mem_root, this); } }; @@ -4689,6 +5106,8 @@ public: { return null_value ? 0.0 : (double) (ulonglong) cached_value; } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_copy_uint>(thd, mem_root, this); } }; @@ -4715,6 +5134,8 @@ public: cached_value= item->val_real(); null_value= item->null_value; } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_copy_float>(thd, mem_root, this); } }; @@ -4734,6 +5155,8 @@ public: double val_real(); longlong val_int(); void copy(); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_copy_decimal>(thd, mem_root, this); } }; @@ -4746,17 +5169,10 @@ public: - cmp() method that compares the saved value with the current value of the source item, and if they were not equal saves item's value into the saved value. -*/ -/* - Cached_item_XXX objects are not exactly caches. They do the following: - - Each Cached_item_XXX object has - - its source item - - saved value of the source item - - cmp() method that compares the saved value with the current value of the - source item, and if they were not equal saves item's value into the saved - value. + TODO: add here: + - a way to save the new value w/o comparison + - a way to do less/equal/greater comparison */ class Cached_item :public Sql_alloc @@ -4764,48 +5180,75 @@ class Cached_item :public Sql_alloc public: bool null_value; Cached_item() :null_value(0) {} + /* + Compare the cached value with the source value. If not equal, copy + the source value to the cache. + @return + true - Not equal + false - Equal + */ virtual bool cmp(void)=0; + + /* Compare the cached value with the source value, without copying */ + virtual int cmp_read_only()=0; + virtual ~Cached_item(); /*line -e1509 */ }; -class Cached_item_str :public Cached_item +class Cached_item_item : public Cached_item { +protected: Item *item; + + Cached_item_item(Item *arg) : item(arg) {} +public: + void fetch_value_from(Item *new_item) + { + Item *save= item; + item= new_item; + cmp(); + item= save; + } +}; + +class Cached_item_str :public Cached_item_item +{ uint32 value_max_length; String value,tmp_value; public: Cached_item_str(THD *thd, Item *arg); bool cmp(void); + int cmp_read_only(); ~Cached_item_str(); // Deallocate String:s }; -class Cached_item_real :public Cached_item +class Cached_item_real :public Cached_item_item { - Item *item; double value; public: - Cached_item_real(Item *item_par) :item(item_par),value(0.0) {} + Cached_item_real(Item *item_par) :Cached_item_item(item_par),value(0.0) {} bool cmp(void); + int cmp_read_only(); }; -class Cached_item_int :public Cached_item +class Cached_item_int :public Cached_item_item { - Item *item; longlong value; public: - Cached_item_int(Item *item_par) :item(item_par),value(0) {} + Cached_item_int(Item *item_par) :Cached_item_item(item_par),value(0) {} bool cmp(void); + int cmp_read_only(); }; -class Cached_item_decimal :public Cached_item +class Cached_item_decimal :public Cached_item_item { - Item *item; my_decimal value; public: Cached_item_decimal(Item *item_par); bool cmp(void); + int cmp_read_only(); }; class Cached_item_field :public Cached_item @@ -4815,17 +5258,19 @@ class Cached_item_field :public Cached_item uint length; public: - Cached_item_field(Field *arg_field) : field(arg_field) + Cached_item_field(THD *thd, Field *arg_field): field(arg_field) { field= arg_field; /* TODO: take the memory allocation below out of the constructor. */ - buff= (uchar*) sql_calloc(length=field->pack_length()); + buff= (uchar*) thd_calloc(thd, length= field->pack_length()); } bool cmp(void); + int cmp_read_only(); }; class Item_default_value : public Item_field { + void calculate(); public: Item *arg; Item_default_value(THD *thd, Name_resolution_context *context_arg) @@ -4836,18 +5281,36 @@ public: :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a) + :Item_field(thd, context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(NULL) {} enum Type type() const { return DEFAULT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, Item **); - virtual void print(String *str, enum_query_type query_type); + void print(String *str, enum_query_type query_type); + String *val_str(String *str); + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *decimal_value); + bool get_date(MYSQL_TIME *ltime,ulonglong fuzzydate); + bool send(Protocol *protocol, String *buffer); int save_in_field(Field *field_arg, bool no_conversions); - table_map used_tables() const { return (table_map)0L; } - + bool save_in_param(THD *thd, Item_param *param) + { + // It should not be possible to have "EXECUTE .. USING DEFAULT(a)" + DBUG_ASSERT(arg == NULL); + param->set_default(); + return false; + } + table_map used_tables() const; Field *get_tmp_table_field() { return 0; } Item *get_tmp_table_item(THD *thd) { return this; } Item_field *field_for_view_update() { return 0; } + bool update_vcol_processor(void *arg) { return 0; } + bool check_func_default_processor(void *arg) { return true; } - bool walk(Item_processor processor, bool walk_subquery, uchar *args) + bool walk(Item_processor processor, bool walk_subquery, void *args) { return (arg && arg->walk(processor, walk_subquery, args)) || (this->*processor)(args); @@ -4856,6 +5319,37 @@ public: Item *transform(THD *thd, Item_transformer transformer, uchar *args); }; +/** + This class is used as bulk parameter INGNORE representation. + + It just do nothing when assigned to a field + +*/ + +class Item_ignore_value : public Item_default_value +{ +public: + Item_ignore_value(THD *thd, Name_resolution_context *context_arg) + :Item_default_value(thd, context_arg) + {}; + + void print(String *str, enum_query_type query_type); + int save_in_field(Field *field_arg, bool no_conversions); + bool save_in_param(THD *thd, Item_param *param) + { + param->set_ignore(); + return false; + } + + String *val_str(String *str); + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *decimal_value); + bool get_date(MYSQL_TIME *ltime,ulonglong fuzzydate); + bool send(Protocol *protocol, String *buffer); +}; + + /* Item_insert_value -- an implementation of VALUES() function. You can use the VALUES(col_name) function in the UPDATE clause @@ -4890,15 +5384,16 @@ public: Item_field *field_for_view_update() { return 0; } - bool walk(Item_processor processor, bool walk_subquery, uchar *args) + bool walk(Item_processor processor, bool walk_subquery, void *args) { return arg->walk(processor, walk_subquery, args) || (this->*processor)(args); } - bool check_partition_func_processor(uchar *int_arg) {return TRUE;} - bool check_vcol_func_processor(uchar *arg_arg) + bool check_partition_func_processor(void *int_arg) {return TRUE;} + bool update_vcol_processor(void *arg) { return 0; } + bool check_vcol_func_processor(void *arg) { - return trace_unsupported_by_check_vcol_func_processor("values"); + return mark_unsupported_function("values()", arg, VCOL_IMPOSSIBLE); } }; @@ -4985,10 +5480,7 @@ private: */ bool read_only; public: - bool check_vcol_func_processor(uchar *arg) - { - return trace_unsupported_by_check_vcol_func_processor("trigger"); - } + bool check_vcol_func_processor(void *arg); }; @@ -4999,7 +5491,8 @@ public: for any value. */ -class Item_cache: public Item_basic_constant +class Item_cache: public Item_basic_constant, + public Type_handler_hybrid_field_type { protected: Item *example; @@ -5009,7 +5502,6 @@ protected: by IN->EXISTS transformation. */ Field *cached_field; - enum enum_field_types cached_field_type; /* TRUE <=> cache holds value of the last stored item (i.e actual value). store() stores item to be cached and sets this flag to FALSE. @@ -5021,18 +5513,19 @@ protected: public: Item_cache(THD *thd): Item_basic_constant(thd), + Type_handler_hybrid_field_type(MYSQL_TYPE_STRING), example(0), cached_field(0), - cached_field_type(MYSQL_TYPE_STRING), value_cached(0) { fixed= 1; maybe_null= 1; null_value= 1; } +protected: Item_cache(THD *thd, enum_field_types field_type_arg): Item_basic_constant(thd), + Type_handler_hybrid_field_type(field_type_arg), example(0), cached_field(0), - cached_field_type(field_type_arg), value_cached(0) { fixed= 1; @@ -5040,6 +5533,7 @@ public: null_value= 1; } +public: virtual bool allocate(THD *thd, uint i) { return 0; } virtual bool setup(THD *thd, Item *item) { @@ -5050,12 +5544,28 @@ public: return 0; }; enum Type type() const { return CACHE_ITEM; } - enum_field_types field_type() const { return cached_field_type; } - static Item_cache* get_cache(THD *thd, const Item *item); - static Item_cache* get_cache(THD *thd, const Item* item, const Item_result type); + + enum_field_types field_type() const + { return Type_handler_hybrid_field_type::field_type(); } + enum Item_result result_type () const + { return Type_handler_hybrid_field_type::result_type(); } + enum Item_result cmp_type () const + { return Type_handler_hybrid_field_type::cmp_type(); } + + static Item_cache* get_cache(THD *thd, const Item* item, + const Item_result type, const enum_field_types f_type); + static Item_cache* get_cache(THD *thd, const Item* item, + const Item_result type) + { + return get_cache(thd, item, type, item->field_type()); + } + static Item_cache* get_cache(THD *thd, const Item *item) + { + return get_cache(thd, item, item->cmp_type()); + } virtual void keep_array() {} virtual void print(String *str, enum_query_type query_type); - bool eq_def(Field *field) + bool eq_def(const Field *field) { return cached_field ? cached_field->eq_def (field) : FALSE; } @@ -5063,9 +5573,26 @@ public: { return this == item; } - bool check_vcol_func_processor(uchar *arg) + bool check_vcol_func_processor(void *arg) { - return trace_unsupported_by_check_vcol_func_processor("cache"); + if (example) + { + Item::vcol_func_processor_result *res= (Item::vcol_func_processor_result*)arg; + example->check_vcol_func_processor(arg); + /* + Item_cache of a non-deterministic function requires re-fixing + even if the function itself doesn't (e.g. CURRENT_TIMESTAMP) + */ + if (res->errors & VCOL_NOT_STRICTLY_DETERMINISTIC) + res->errors|= VCOL_SESSION_FUNC; + return false; + } + return mark_unsupported_function("cache", arg, VCOL_IMPOSSIBLE); + } + void cleanup() + { + clear(); + Item_basic_constant::cleanup(); } /** Check if saved item has a non-NULL value. @@ -5080,7 +5607,7 @@ public: virtual void store(Item *item); virtual bool cache_value()= 0; bool basic_const_item() const - { return MY_TEST(example && example->basic_const_item()); } + { return example && example->basic_const_item(); } virtual void clear() { null_value= TRUE; value_cached= FALSE; } bool is_null() { return !has_value(); } virtual bool is_expensive() @@ -5089,7 +5616,7 @@ public: return false; return example->is_expensive(); } - bool is_expensive_processor(uchar *arg) + bool is_expensive_processor(void *arg) { DBUG_ASSERT(example); if (value_cached) @@ -5097,19 +5624,27 @@ public: return example->is_expensive_processor(arg); } virtual void set_null(); - bool walk(Item_processor processor, bool walk_subquery, uchar *arg) + bool walk(Item_processor processor, bool walk_subquery, void *arg) { if (example && example->walk(processor, walk_subquery, arg)) return TRUE; return (this->*processor)(arg); } virtual Item *safe_charset_converter(THD *thd, CHARSET_INFO *tocs); - void split_sum_func2_example(THD *thd, Item **ref_pointer_array, + void split_sum_func2_example(THD *thd, Ref_ptr_array ref_pointer_array, List<Item> &fields, uint flags) { example->split_sum_func2(thd, ref_pointer_array, fields, &example, flags); } Item *get_example() const { return example; } + + virtual Item *convert_to_basic_const_item(THD *thd) { return 0; }; + Item *derived_field_transformer_for_having(THD *thd, uchar *arg) + { return convert_to_basic_const_item(thd); } + Item *derived_field_transformer_for_where(THD *thd, uchar *arg) + { return convert_to_basic_const_item(thd); } + Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg) + { return convert_to_basic_const_item(thd); } }; @@ -5130,6 +5665,9 @@ public: enum Item_result result_type() const { return INT_RESULT; } bool cache_value(); int save_in_field(Field *field, bool no_conversions); + Item *convert_to_basic_const_item(THD *thd); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_cache_int>(thd, mem_root, this); } }; @@ -5154,6 +5692,9 @@ public: Important when storing packed datetime values. */ Item *clone_item(THD *thd); + Item *convert_to_basic_const_item(THD *thd); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_cache_temporal>(thd, mem_root, this); } }; @@ -5170,6 +5711,9 @@ public: my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return REAL_RESULT; } bool cache_value(); + Item *convert_to_basic_const_item(THD *thd); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_cache_real>(thd, mem_root, this); } }; @@ -5186,6 +5730,9 @@ public: my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return DECIMAL_RESULT; } bool cache_value(); + Item *convert_to_basic_const_item(THD *thd); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_cache_decimal>(thd, mem_root, this); } }; @@ -5199,7 +5746,7 @@ public: Item_cache_str(THD *thd, const Item *item): Item_cache(thd, item->field_type()), value(0), is_varbinary(item->type() == FIELD_ITEM && - cached_field_type == MYSQL_TYPE_VARCHAR && + Item_cache_str::field_type() == MYSQL_TYPE_VARCHAR && !((const Item_field *) item)->field->has_charset()) { collation.set(const_cast<DTCollation&>(item->collation)); @@ -5212,6 +5759,9 @@ public: CHARSET_INFO *charset() const { return value->charset(); }; int save_in_field(Field *field, bool no_conversions); bool cache_value(); + Item *convert_to_basic_const_item(THD *thd); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_cache_str>(thd, mem_root, this); } }; @@ -5235,6 +5785,8 @@ public: */ return Item::safe_charset_converter(thd, tocs); } + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_cache_str_for_nullif>(thd, mem_root, this); } }; @@ -5260,7 +5812,7 @@ public: bool setup(THD *thd, Item *item); void store(Item *item); void illegal_method_call(const char *); - void make_field(Send_field *) + void make_field(THD *thd, Send_field *) { illegal_method_call((const char*)"make_field"); }; @@ -5306,6 +5858,8 @@ public: } bool cache_value(); virtual void set_null(); + Item *get_copy(THD *thd, MEM_ROOT *mem_root) + { return get_item_copy<Item_cache_row>(thd, mem_root, this); } }; @@ -5316,11 +5870,11 @@ public: Item_type_holder do not need cleanup() because its time of live limited by single SP/PS execution. */ -class Item_type_holder: public Item +class Item_type_holder: public Item, + public Type_handler_hybrid_real_field_type { protected: TYPELIB *enum_set_typelib; - enum_field_types fld_type; Field::geometry_type geometry_type; void get_full_info(Item *item); @@ -5330,8 +5884,27 @@ protected: public: Item_type_holder(THD*, Item*); - Item_result result_type() const; - enum_field_types field_type() const { return fld_type; }; + enum_field_types field_type() const + { return Type_handler_hybrid_real_field_type::field_type(); } + enum_field_types real_field_type() const + { return Type_handler_hybrid_real_field_type::real_field_type(); } + enum Item_result result_type () const + { + /* + In 10.1 Item_type_holder::result_type() returned + Field::result_merge_type(field_type()), which returned STRING_RESULT + for the BIT data type. In 10.2 it returns INT_RESULT, similar + to what Field_bit::result_type() does. This should not be + important because Item_type_holder is a limited purpose Item + and its result_type() should not be called from outside of + Item_type_holder. It's called only internally from decimal_int_part() + from join_types(), to calculate "decimals" of the result data type. + As soon as we get BIT as one of the joined types, the result field + type cannot be numeric: it's either BIT, or VARBINARY. + */ + return Type_handler_hybrid_real_field_type::result_type(); + } + enum Type type() const { return TYPE_HOLDER; } double val_real(); longlong val_int(); @@ -5342,6 +5915,7 @@ public: static uint32 display_length(Item *item); static enum_field_types get_real_type(Item *); Field::geometry_type get_geometry_type() const { return geometry_type; }; + Item* get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; } }; @@ -5444,4 +6018,26 @@ public: void close() {} }; + +/* + It's used in ::fix_fields() methods of LIKE and JSON_SEARCH + functions to handle the ESCAPE parameter. + This parameter is quite non-standard so the specific function. +*/ +bool fix_escape_item(THD *thd, Item *escape_item, String *tmp_str, + bool escape_used_in_parsing, CHARSET_INFO *cmp_cs, + int *escape); + +inline bool Virtual_column_info::is_equal(const Virtual_column_info* vcol) const +{ + return field_type == vcol->get_real_type() + && stored_in_db == vcol->is_stored() + && expr->eq(vcol->expr, true); +} + +inline void Virtual_column_info::print(String* str) +{ + expr->print_for_table_def(str); +} + #endif /* SQL_ITEM_INCLUDED */ |