diff options
Diffstat (limited to 'sql/item.h')
-rw-r--r-- | sql/item.h | 1561 |
1 files changed, 1295 insertions, 266 deletions
diff --git a/sql/item.h b/sql/item.h index 3eab695cb5e..23849226c2f 100644 --- a/sql/item.h +++ b/sql/item.h @@ -22,11 +22,11 @@ class Protocol; struct st_table_list; void item_init(void); /* Init item functions */ - +class Item_field; /* "Declared Type Collation" - A combination of collation and its deriviation. + A combination of collation and its derivation. */ enum Derivation @@ -45,7 +45,7 @@ enum Derivation MY_COLL_ALLOW_COERCIBLE_CONV - allow conversion of a coercible value (i.e. constant). MY_COLL_ALLOW_CONV - allow any kind of conversion - (combintion of the above two) + (combination of the above two) MY_COLL_DISALLOW_NONE - don't allow return DERIVATION_NONE (e.g. when aggregating for comparison) MY_COLL_CMP_CONV - combination of MY_COLL_ALLOW_CONV @@ -105,74 +105,398 @@ public: } }; + +/*************************************************************************/ +/* + A framework to easily handle different return types for hybrid items + (hybrid item is an item whose operand can be of any type, e.g. integer, + real, decimal). +*/ + +struct Hybrid_type_traits; + +struct Hybrid_type +{ + longlong integer; + + double real; + /* + Use two decimal buffers interchangeably to speed up += operation + which has no native support in decimal library. + Hybrid_type+= arg is implemented as dec_buf[1]= dec_buf[0] + arg. + The third decimal is used as a handy temporary storage. + */ + my_decimal dec_buf[3]; + int used_dec_buf_no; + + /* + Traits moved to a separate class to + a) be able to easily change object traits in runtime + b) they work as a differentiator for the union above + */ + const Hybrid_type_traits *traits; + + Hybrid_type() {} + /* XXX: add traits->copy() when needed */ + Hybrid_type(const Hybrid_type &rhs) :traits(rhs.traits) {} +}; + + +/* Hybryd_type_traits interface + default implementation for REAL_RESULT */ + +struct Hybrid_type_traits +{ + virtual Item_result type() const { return REAL_RESULT; } + + virtual void + fix_length_and_dec(Item *item, Item *arg) const; + + /* Hybrid_type operations. */ + virtual void set_zero(Hybrid_type *val) const { val->real= 0.0; } + virtual void add(Hybrid_type *val, Field *f) const + { val->real+= f->val_real(); } + virtual void div(Hybrid_type *val, ulonglong u) const + { val->real/= ulonglong2double(u); } + + virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const + { return (longlong) rint(val->real); } + virtual double val_real(Hybrid_type *val) const { return val->real; } + virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const; + virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const; + static const Hybrid_type_traits *instance(); + Hybrid_type_traits() {} + virtual ~Hybrid_type_traits() {} +}; + + +struct Hybrid_type_traits_decimal: public Hybrid_type_traits +{ + virtual Item_result type() const { return DECIMAL_RESULT; } + + virtual void + fix_length_and_dec(Item *arg, Item *item) const; + + /* Hybrid_type operations. */ + virtual void set_zero(Hybrid_type *val) const; + virtual void add(Hybrid_type *val, Field *f) const; + virtual void div(Hybrid_type *val, ulonglong u) const; + + virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const; + virtual double val_real(Hybrid_type *val) const; + virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const + { return &val->dec_buf[val->used_dec_buf_no]; } + virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const; + static const Hybrid_type_traits_decimal *instance(); + Hybrid_type_traits_decimal() {}; +}; + + +struct Hybrid_type_traits_integer: public Hybrid_type_traits +{ + virtual Item_result type() const { return INT_RESULT; } + + virtual void + fix_length_and_dec(Item *arg, Item *item) const; + + /* Hybrid_type operations. */ + virtual void set_zero(Hybrid_type *val) const + { val->integer= 0; } + virtual void add(Hybrid_type *val, Field *f) const + { val->integer+= f->val_int(); } + virtual void div(Hybrid_type *val, ulonglong u) const + { val->integer/= (longlong) u; } + + virtual longlong val_int(Hybrid_type *val, bool unsigned_flag) const + { return val->integer; } + virtual double val_real(Hybrid_type *val) const + { return (double) val->integer; } + virtual my_decimal *val_decimal(Hybrid_type *val, my_decimal *buf) const + { + int2my_decimal(E_DEC_FATAL_ERROR, val->integer, 0, &val->dec_buf[2]); + return &val->dec_buf[2]; + } + virtual String *val_str(Hybrid_type *val, String *buf, uint8 decimals) const + { buf->set(val->integer, &my_charset_bin); return buf;} + static const Hybrid_type_traits_integer *instance(); + Hybrid_type_traits_integer() {}; +}; + + +void dummy_error_processor(THD *thd, void *data); + +void view_error_processor(THD *thd, void *data); + +/* + Instances of Name_resolution_context store the information necesary for + name resolution of Items and other context analysis of a query made in + fix_fields(). + + This structure is a part of SELECT_LEX, a pointer to this structure is + assigned when an item is created (which happens mostly during parsing + (sql_yacc.yy)), but the structure itself will be initialized after parsing + is complete + + TODO: move subquery of INSERT ... SELECT and CREATE ... SELECT to + separate SELECT_LEX which allow to remove tricks of changing this + structure before and after INSERT/CREATE and its SELECT to make correct + field name resolution. +*/ +struct Name_resolution_context: Sql_alloc +{ + /* + The name resolution context to search in when an Item cannot be + resolved in this context (the context of an outer select) + */ + Name_resolution_context *outer_context; + + /* + List of tables used to resolve the items of this context. Usually these + are tables from the FROM clause of SELECT statement. The exceptions are + INSERT ... SELECT and CREATE ... SELECT statements, where SELECT + subquery is not moved to a separate SELECT_LEX. For these types of + statements we have to change this member dynamically to ensure correct + name resolution of different parts of the statement. + */ + TABLE_LIST *table_list; + /* + In most cases the two table references below replace 'table_list' above + for the purpose of name resolution. The first and last name resolution + table references allow us to search only in a sub-tree of the nested + join tree in a FROM clause. This is needed for NATURAL JOIN, JOIN ... USING + and JOIN ... ON. + */ + TABLE_LIST *first_name_resolution_table; + /* + Last table to search in the list of leaf table references that begins + with first_name_resolution_table. + */ + TABLE_LIST *last_name_resolution_table; + + /* + SELECT_LEX item belong to, in case of merged VIEW it can differ from + SELECT_LEX where item was created, so we can't use table_list/field_list + from there + */ + st_select_lex *select_lex; + + /* + Processor of errors caused during Item name resolving, now used only to + hide underlying tables in errors about views (i.e. it substitute some + errors for views) + */ + void (*error_processor)(THD *, void *); + void *error_processor_data; + + /* + When TRUE items are resolved in this context both against the + SELECT list and this->table_list. If FALSE, items are resolved + only against this->table_list. + */ + bool resolve_in_select_list; + + /* + Security context of this name resolution context. It's used for views + and is non-zero only if the view is defined with SQL SECURITY DEFINER. + */ + Security_context *security_ctx; + + Name_resolution_context() + :outer_context(0), table_list(0), select_lex(0), + error_processor_data(0), + security_ctx(0) + {} + + void init() + { + resolve_in_select_list= FALSE; + error_processor= &dummy_error_processor; + first_name_resolution_table= NULL; + last_name_resolution_table= NULL; + } + + void resolve_in_table_list_only(TABLE_LIST *tables) + { + table_list= first_name_resolution_table= tables; + resolve_in_select_list= FALSE; + } + + void process_error(THD *thd) + { + (*error_processor)(thd, error_processor_data); + } +}; + + +/* + Store and restore the current state of a name resolution context. +*/ + +class Name_resolution_context_state +{ +private: + TABLE_LIST *save_table_list; + TABLE_LIST *save_first_name_resolution_table; + TABLE_LIST *save_next_name_resolution_table; + bool save_resolve_in_select_list; + +public: + Name_resolution_context_state() {} /* Remove gcc warning */ + TABLE_LIST *save_next_local; + +public: + /* Save the state of a name resolution context. */ + void save_state(Name_resolution_context *context, TABLE_LIST *table_list) + { + save_table_list= context->table_list; + save_first_name_resolution_table= context->first_name_resolution_table; + save_next_name_resolution_table= (context->first_name_resolution_table) ? + context->first_name_resolution_table-> + next_name_resolution_table : + NULL; + save_resolve_in_select_list= context->resolve_in_select_list; + save_next_local= table_list->next_local; + } + + /* Restore a name resolution context from saved state. */ + void restore_state(Name_resolution_context *context, TABLE_LIST *table_list) + { + table_list->next_local= save_next_local; + context->table_list= save_table_list; + context->first_name_resolution_table= save_first_name_resolution_table; + if (context->first_name_resolution_table) + context->first_name_resolution_table-> + next_name_resolution_table= save_next_name_resolution_table; + context->resolve_in_select_list= save_resolve_in_select_list; + } +}; + +/*************************************************************************/ + +class sp_rcontext; + + +class Settable_routine_parameter +{ +public: + /* + Set required privileges for accessing the parameter. + + SYNOPSIS + set_required_privilege() + rw if 'rw' is true then we are going to read and set the + parameter, so SELECT and UPDATE privileges might be + required, otherwise we only reading it and SELECT + privilege might be required. + */ + Settable_routine_parameter() {} + virtual ~Settable_routine_parameter() {} + virtual void set_required_privilege(bool rw) {}; + + /* + Set parameter value. + + SYNOPSIS + set_value() + thd thread handle + ctx context to which parameter belongs (if it is local + variable). + it item which represents new value + + RETURN + FALSE if parameter value has been set, + TRUE if error has occured. + */ + virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it)= 0; +}; + + typedef bool (Item::*Item_processor)(byte *arg); +typedef Item* (Item::*Item_transformer) (byte *arg); +typedef void (*Cond_traverser) (const Item *item, void *arg); + class Item { Item(const Item &); /* Prevent use of these */ void operator=(Item &); public: - static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } + static void *operator new(size_t size) + { return (void*) sql_alloc((uint) size); } static void *operator new(size_t size, MEM_ROOT *mem_root) { return (void*) alloc_root(mem_root, (uint) size); } - static void operator delete(void *ptr,size_t size) {} + static void operator delete(void *ptr,size_t size) { TRASH(ptr, size); } static void operator delete(void *ptr, MEM_ROOT *mem_root) {} - enum Type {FIELD_ITEM, FUNC_ITEM, SUM_FUNC_ITEM, STRING_ITEM, + enum Type {FIELD_ITEM= 0, FUNC_ITEM, SUM_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, FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM, SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, - PARAM_ITEM}; + PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM, + VIEW_FIXER_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; + + enum traverse_order { POSTFIX, PREFIX }; + /* Reuse size, only used by SP local variable assignment, otherwize 0 */ + uint rsize; + /* str_values's main purpose is to be used to cache the value in save_in_field */ String str_value; my_string name; /* Name from select */ + /* Original item name (if it was renamed)*/ + my_string orig_name; Item *next; uint32 max_length; - uint8 marker,decimals; + uint name_length; /* Length of name */ + uint8 marker, decimals; my_bool maybe_null; /* If item may be null */ my_bool null_value; /* if item is null */ my_bool unsigned_flag; my_bool with_sum_func; my_bool fixed; /* If item fixed with fix_fields */ + my_bool is_autogenerated_name; /* indicate was name of this Item + autogenerated or set by user */ DTCollation collation; + my_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 Item(); /* - Constructor used by Item_field, Item_ref & agregate (sum) functions. + Constructor used by Item_field, Item_ref & aggregate (sum) functions. Used for duplicating lists in processing queries with temporary tables Also it used for Item_cond_and/Item_cond_or for creating - top AND/OR ctructure of WHERE clause to protect it of + top AND/OR structure of WHERE clause to protect it of optimisation changes in prepared statements */ Item(THD *thd, Item *item); - virtual ~Item() { name=0; } /*lint -e1509 */ - void set_name(const char *str,uint length, CHARSET_INFO *cs); - void init_make_field(Send_field *tmp_field,enum enum_field_types type); - virtual void cleanup() + virtual ~Item() { - DBUG_ENTER("Item::cleanup"); - DBUG_PRINT("info", ("Type: %d", (int)type())); - fixed=0; - marker= 0; - DBUG_VOID_RETURN; - } +#ifdef EXTRA_DEBUG + name=0; +#endif + } /*lint -e1509 */ + void set_name(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 bool fix_fields(THD *, struct st_table_list *, Item **); + Field *make_string_field(TABLE *table); + virtual bool fix_fields(THD *, Item **); /* should be used in case where we are sure that we do not need complete fix_fields() procedure. */ inline void quick_fix_field() { fixed= 1; } /* 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 void save_org_in_field(Field *field) { (void) save_in_field(field, 1); } @@ -185,40 +509,123 @@ public: virtual enum_field_types field_type() const; virtual enum Type type() const =0; /* valXXX methods must return NULL or 0 or 0.0 if null_value is set. */ - virtual double val()=0; + /* + Return double precision floating point representation of item. + + SYNOPSIS + val_real() + + RETURN + In case of NULL value return 0.0 and set null_value flag to TRUE. + If value is not null null_value flag will be reset to FALSE. + */ + virtual double val_real()=0; + /* + Return integer representation of item. + + SYNOPSIS + val_int() + + RETURN + In case of NULL value return 0 and set null_value flag to TRUE. + If value is not null null_value flag will be reset to FALSE. + */ virtual longlong val_int()=0; /* + This is just a shortcut to avoid the cast. You should still use + unsigned_flag to check the sign of the item. + */ + inline ulonglong val_uint() { return (ulonglong) val_int(); } + /* Return string representation of this item object. - The argument to val_str() is an allocated buffer this or any - nested Item object can use to store return value of this method. - This buffer should only be used if the item itself doesn't have an - own String buffer. In case when the item maintains it's own string - buffer, it's preferrable to return it instead to minimize number of - mallocs/memcpys. - The caller of this method can modify returned string, but only in - case when it was allocated on heap, (is_alloced() is true). This - allows the caller to efficiently use a buffer allocated by a child - without having to allocate a buffer of it's own. The buffer, given - to val_str() as agrument, belongs to the caller and is later used - by the caller at it's own choosing. - A few implications from the above: - - unless you return a string object which only points to your buffer - but doesn't manages it you should be ready that it will be - modified. - - even for not allocated strings (is_alloced() == false) the caller - can change charset (see Item_func_{typecast/binary}. XXX: is this - a bug? - - still you should try to minimize data copying and return internal - object whenever possible. + SYNOPSIS + val_str() + str an allocated buffer this or any nested Item object can use to + store return value of this method. + + NOTE + Buffer passed via argument should only be used if the item itself + doesn't have an own String buffer. In case when the item maintains + it's own string buffer, it's preferable to return it instead to + minimize number of mallocs/memcpys. + The caller of this method can modify returned string, but only in case + when it was allocated on heap, (is_alloced() is true). This allows + the caller to efficiently use a buffer allocated by a child without + having to allocate a buffer of it's own. The buffer, given to + val_str() as argument, belongs to the caller and is later used by the + caller at it's own choosing. + A few implications from the above: + - unless you return a string object which only points to your buffer + but doesn't manages it you should be ready that it will be + modified. + - even for not allocated strings (is_alloced() == false) the caller + can change charset (see Item_func_{typecast/binary}. XXX: is this + a bug? + - still you should try to minimize data copying and return internal + object whenever possible. + + RETURN + In case of NULL value return 0 (NULL pointer) and set null_value flag + to TRUE. + If value is not null null_value flag will be reset to FALSE. + */ + virtual String *val_str(String *str)=0; + /* + Return decimal representation of item with fixed point. + + SYNOPSIS + val_decimal() + decimal_buffer buffer which can be used by Item for returning value + (but can be not) + + NOTE + Returned value should not be changed if it is not the same which was + passed via argument. + + RETURN + Return pointer on my_decimal (it can be other then passed via argument) + if value is not NULL (null_value flag will be reset to FALSE). + In case of NULL value it return 0 pointer and set null_value flag + to TRUE. + */ + virtual my_decimal *val_decimal(my_decimal *decimal_buffer)= 0; + /* + Return boolean value of item. + + RETURN + FALSE value is false or NULL + TRUE value is true (not equal to 0) */ - virtual String *val_str(String*)=0; + virtual bool val_bool(); + /* Helper functions, see item_sum.cc */ + String *val_string_from_real(String *str); + String *val_string_from_int(String *str); + String *val_string_from_decimal(String *str); + my_decimal *val_decimal_from_real(my_decimal *decimal_value); + my_decimal *val_decimal_from_int(my_decimal *decimal_value); + my_decimal *val_decimal_from_string(my_decimal *decimal_value); + longlong val_int_from_decimal(); + double val_real_from_decimal(); + virtual Field *get_tmp_table_field() { return 0; } + /* This is also used to create fields in CREATE ... SELECT: */ virtual Field *tmp_table_field(TABLE *t_arg) { return 0; } virtual const char *full_name() const { return name ? name : "???"; } - virtual double val_result() { return val(); } + + /* + *result* family of methods is analog of *val* family (see above) but + return value of result_field of item if it is present. If Item have not + result field, it return val(). This methods set null_value flag in same + way as *val* methods do it. + */ + virtual double val_result() { return val_real(); } virtual longlong val_int_result() { return val_int(); } virtual String *str_result(String* tmp) { return val_str(tmp); } + virtual my_decimal *val_decimal_result(my_decimal *val) + { return val_decimal(val); } + virtual bool val_bool_result() { return val_bool(); } + /* bit map of tables used by item */ virtual table_map used_tables() const { return (table_map) 0L; } /* @@ -243,6 +650,9 @@ public: 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;} + virtual uint decimal_precision() const; + inline int decimal_int_part() const + { return my_decimal_int_part(decimal_precision(), decimals); } /* Returns true if this is constant (during query execution, i.e. its value will not change until next fix_fields) and its value is known. @@ -254,6 +664,18 @@ public: */ virtual bool const_during_execution() const { return (used_tables() & ~PARAM_TABLE_BIT) == 0; } + /* + This is an essential method for correct functioning of VIEWS. + To save a view in an .frm file we need its unequivocal + definition in SQL that takes into account sql_mode and + environmental settings. Currently such definition is restored + by traversing through the parsed tree of a view and + print()'ing SQL syntax of every node to a String buffer. This + method is used to print the SQL definition of an item. The + second use of this method is for EXPLAIN EXTENDED, to print + the SQL of a query after all optimizations of the parsed tree + have been done. + */ virtual void print(String *str_arg) { str_arg->append(full_name()); } void print_item_w_name(String *); virtual void update_used_tables() {} @@ -261,7 +683,7 @@ public: List<Item> &fields) {} /* Called for items that really have to be split */ void split_sum_func2(THD *thd, Item **ref_pointer_array, List<Item> &fields, - Item **ref); + Item **ref, bool skip_registered); virtual bool get_date(TIME *ltime,uint fuzzydate); virtual bool get_time(TIME *ltime); virtual bool get_date_result(TIME *ltime,uint fuzzydate) @@ -289,14 +711,14 @@ public: virtual void top_level_item() {} /* set field of temporary table for Item which can be switched on temporary - table during query processing (groupping and so on) + table during query processing (grouping and so on) */ virtual void set_result_field(Field *field) {} virtual bool is_result_field() { return 0; } virtual bool is_bool_func() { return 0; } virtual void save_in_result_field(bool no_conversions) {} /* - set value of aggegate function in case of no rows for groupping were found + set value of aggregate function in case of no rows for grouping were found */ virtual void no_rows_in_result() {} virtual Item *copy_or_same(THD *thd) { return this; } @@ -312,9 +734,42 @@ public: return (this->*processor)(arg); } + virtual Item* transform(Item_transformer transformer, byte *arg) + { + return (this->*transformer)(arg); + } + + virtual void traverse_cond(Cond_traverser traverser, + void *arg, traverse_order order) + { + (*traverser)(this, arg); + } + virtual bool remove_dependence_processor(byte * arg) { return 0; } virtual bool remove_fixed(byte * arg) { fixed= 0; return 0; } - + virtual bool cleanup_processor(byte *arg); + virtual bool collect_item_field_processor(byte * arg) { return 0; } + virtual bool find_item_in_field_list_processor(byte *arg) { return 0; } + virtual bool change_context_processor(byte *context) { return 0; } + virtual bool reset_query_id_processor(byte *query_id) { return 0; } + + virtual Item *equal_fields_propagator(byte * arg) { return this; } + virtual Item *set_no_const_sub(byte *arg) { return this; } + virtual Item *replace_equal_field(byte * arg) { return this; } + + /* + For SP local variable returns pointer to Item representing its + current value and pointer to current Item otherwise. + */ + virtual Item *this_item() { return this; } + virtual const Item *this_item() const { return this; } + + /* + For SP local variable returns address of pointer to Item representing its + current value and pointer passed via parameter otherwise. + */ + virtual Item **this_item_addr(THD *thd, Item **addr) { return addr; } + // Row emulation virtual uint cols() { return 1; } virtual Item* el(uint i) { return this; } @@ -326,6 +781,7 @@ public: virtual void bring_value() {} Field *tmp_table_field_from_field_type(TABLE *table); + virtual Item_field *filed_for_view_update() { return 0; } virtual Item *neg_transformer(THD *thd) { return NULL; } virtual Item *safe_charset_converter(CHARSET_INFO *tocs); @@ -334,6 +790,17 @@ public: cleanup(); delete this; } + + virtual bool is_splocal() { return 0; } /* Needed for error checking */ + + /* + Return Settable_routine_parameter interface of the Item. Return 0 + if this Item is not Settable_routine_parameter. + */ + virtual Settable_routine_parameter *get_settable_routine_parameter() + { + return 0; + } /* result_as_longlong() must return TRUE for Items representing DATE/TIME functions and DATE/TIME table fields. @@ -345,6 +812,275 @@ public: }; +class sp_head; + + +/***************************************************************************** + The class is a base class for representation of stored routine variables in + the Item-hierarchy. There are the following kinds of SP-vars: + - local variables (Item_splocal); + - CASE expression (Item_case_expr); +*****************************************************************************/ + +class Item_sp_variable :public Item +{ +protected: + /* + THD, which is stored in fix_fields() and is used in this_item() to avoid + current_thd use. + */ + THD *m_thd; + +public: + LEX_STRING m_name; + + /* + Buffer, pointing to the string value of the item. We need it to + protect internal buffer from changes. See comment to analogous + member in Item_param for more details. + */ + String str_value_ptr; + +public: +#ifndef DBUG_OFF + /* + Routine to which this Item_splocal belongs. Used for checking if correct + runtime context is used for variable handling. + */ + sp_head *m_sp; +#endif + +public: + Item_sp_variable(char *sp_var_name_str, uint sp_var_name_length); + +public: + bool fix_fields(THD *thd, Item **); + + double val_real(); + longlong val_int(); + String *val_str(String *sp); + my_decimal *val_decimal(my_decimal *decimal_value); + bool is_null(); + +public: + inline void make_field(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); +}; + +/***************************************************************************** + Item_sp_variable inline implementation. +*****************************************************************************/ + +inline void Item_sp_variable::make_field(Send_field *field) +{ + Item *it= this_item(); + + if (name) + it->set_name(name, (uint) strlen(name), system_charset_info); + else + it->set_name(m_name.str, m_name.length, system_charset_info); + it->make_field(field); +} + +inline bool Item_sp_variable::const_item() const +{ + return TRUE; +} + +inline int Item_sp_variable::save_in_field(Field *field, bool no_conversions) +{ + return this_item()->save_in_field(field, no_conversions); +} + +inline bool Item_sp_variable::send(Protocol *protocol, String *str) +{ + return this_item()->send(protocol, str); +} + + +/***************************************************************************** + A reference to local SP variable (incl. reference to SP parameter), used in + runtime. +*****************************************************************************/ + +class Item_splocal :public Item_sp_variable, + private Settable_routine_parameter +{ + uint m_var_idx; + + Type m_type; + Item_result m_result_type; + +public: + /* + Position of this reference to SP variable in the statement (the + statement itself is in sp_instr_stmt::m_query). + This is valid only for references to SP variables in statements, + excluding DECLARE CURSOR statement. It is used to replace references to SP + variables with NAME_CONST calls when putting statements into the binary + log. + Value of 0 means that this object doesn't corresponding to reference to + SP variable in query text. + */ + uint pos_in_query; + + Item_splocal(const LEX_STRING &sp_var_name, uint sp_var_idx, + enum_field_types sp_var_type, uint pos_in_q= 0); + + bool is_splocal() { return 1; } /* Needed for error checking */ + + Item *this_item(); + const Item *this_item() const; + Item **this_item_addr(THD *thd, Item **); + + void print(String *str); + +public: + inline const LEX_STRING *my_name() const; + + inline uint get_var_idx() const; + + inline enum Type type() const; + inline Item_result result_type() const; + +private: + bool set_value(THD *thd, sp_rcontext *ctx, Item **it); + +public: + Settable_routine_parameter *get_settable_routine_parameter() + { + return this; + } +}; + +/***************************************************************************** + Item_splocal inline implementation. +*****************************************************************************/ + +inline const LEX_STRING *Item_splocal::my_name() const +{ + return &m_name; +} + +inline uint Item_splocal::get_var_idx() const +{ + return m_var_idx; +} + +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. +*****************************************************************************/ + +class Item_case_expr :public Item_sp_variable +{ +public: + Item_case_expr(int case_expr_id); + +public: + Item *this_item(); + const Item *this_item() const; + Item **this_item_addr(THD *thd, Item **); + + inline enum Type type() const; + inline Item_result result_type() const; + +public: + /* + NOTE: print() is intended to be used from views and for debug. + Item_case_expr can not occur in views, so here it is only for debug + purposes. + */ + void print(String *str); + +private: + int m_case_expr_id; +}; + +/***************************************************************************** + Item_case_expr inline implementation. +*****************************************************************************/ + +inline enum Item::Type Item_case_expr::type() const +{ + return this_item()->type(); +} + +inline Item_result Item_case_expr::result_type() const +{ + return this_item()->result_type(); +} + + +/* + NAME_CONST(given_name, const_value). + This 'function' has all properties of the supplied const_value (which is + assumed to be a literal constant), and the name given_name. + + This is used to replace references to SP variables when we write PROCEDURE + statements into the binary log. + + TODO + Together with Item_splocal and Item::this_item() we can actually extract + common a base of this class and Item_splocal. Maybe it is possible to + extract a common base with class Item_ref, too. +*/ + +class Item_name_const : public Item +{ + Item *value_item; + Item *name_item; +public: + Item_name_const(Item *name, Item *val): value_item(val), name_item(name) + { + Item::maybe_null= TRUE; + } + + bool fix_fields(THD *, Item **); + + enum Type type() const; + double val_real(); + longlong val_int(); + String *val_str(String *sp); + my_decimal *val_decimal(my_decimal *); + bool is_null(); + void print(String *str); + + Item_result result_type() const + { + return value_item->result_type(); + } + + bool const_item() const + { + return TRUE; + } + + int save_in_field(Field *field, bool no_conversions) + { + return value_item->save_in_field(field, no_conversions); + } + + bool send(Protocol *protocol, String *str) + { + return value_item->send(protocol, str); + } +}; + bool agg_item_collations(DTCollation &c, const char *name, Item **items, uint nitems, uint flags= 0); bool agg_item_collations_for_comparison(DTCollation &c, const char *name, @@ -357,6 +1093,7 @@ bool agg_item_charsets(DTCollation &c, const char *name, class Item_num: public Item { public: + Item_num() {} /* Remove gcc warning */ virtual Item_num *neg()= 0; Item *safe_charset_converter(CHARSET_INFO *tocs); }; @@ -376,10 +1113,13 @@ protected: const char *orig_db_name; const char *orig_table_name; const char *orig_field_name; + public: + Name_resolution_context *context; const char *db_name; const char *table_name; const char *field_name; + bool alias_name_used; /* true if item was resolved against alias */ /* Cached value of index for this field in table->field array, used by prep. stmts for speeding up their re-execution. Holds NO_CACHED_FIELD_INDEX @@ -393,26 +1133,44 @@ public: */ TABLE_LIST *cached_table; st_select_lex *depended_from; - Item_ident(const char *db_name_par,const char *table_name_par, - const char *field_name_par); + Item_ident(Name_resolution_context *context_arg, + const char *db_name_arg, const char *table_name_arg, + const char *field_name_arg); Item_ident(THD *thd, Item_ident *item); const char *full_name() const; void cleanup(); bool remove_dependence_processor(byte * arg); + void print(String *str); + virtual bool change_context_processor(byte *cntx) + { context= (Name_resolution_context *)cntx; return FALSE; } + friend bool insert_fields(THD *thd, Name_resolution_context *context, + const char *db_name, + const char *table_name, List_iterator<Item> *it, + bool any_privileges); }; +class Item_equal; +class COND_EQUAL; class Item_field :public Item_ident { +protected: void set_field(Field *field); public: Field *field,*result_field; + Item_equal *item_equal; + bool no_const_subst; + /* + if any_privileges set to TRUE then here real effective privileges will + be stored + */ + uint have_privileges; + /* field need any privileges (for VIEW creation) */ + bool any_privileges; - Item_field(const char *db_par,const char *table_name_par, - const char *field_name_par) - :Item_ident(db_par,table_name_par,field_name_par), - field(0), result_field(0) - { collation.set(DERIVATION_IMPLICIT); } + Item_field(Name_resolution_context *context_arg, + const char *db_arg,const char *table_name_arg, + const char *field_name_arg); /* Constructor needed to process subselect with temporary tables (see Item) */ @@ -422,7 +1180,7 @@ public: and database names will live as long as Item_field (this is important in prepared statements). */ - Item_field(THD *thd, Field *field); + Item_field(THD *thd, Name_resolution_context *context_arg, Field *field); /* If this constructor is used, fix_fields() won't work, because db_name, table_name and column_name are unknown. It's necessary to call @@ -431,15 +1189,18 @@ public: Item_field(Field *field); enum Type type() const { return FIELD_ITEM; } bool eq(const Item *item, bool binary_cmp) const; - double val(); + double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal *); String *val_str(String*); double val_result(); longlong val_int_result(); String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *); + bool val_bool_result(); bool send(Protocol *protocol, String *str_arg); void reset_field(Field *f); - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); void save_org_in_field(Field *field); @@ -463,12 +1224,28 @@ public: bool get_time(TIME *ltime); bool is_null() { return field->is_null(); } Item *get_tmp_table_item(THD *thd); + bool collect_item_field_processor(byte * arg); + bool find_item_in_field_list_processor(byte *arg); + bool reset_query_id_processor(byte *arg) + { + field->query_id= *((query_id_t *) arg); + if (result_field) + result_field->query_id= field->query_id; + return 0; + } void cleanup(); - inline uint32 max_disp_length() { return field->max_length(); } bool result_as_longlong() { return field->can_be_compared_as_longlong(); } + Item_equal *find_item_equal(COND_EQUAL *cond_equal); + Item *equal_fields_propagator(byte *arg); + Item *set_no_const_sub(byte *arg); + Item *replace_equal_field(byte *arg); + inline uint32 max_disp_length() { return field->max_length(); } + Item_field *filed_for_view_update() { return this; } + Item *safe_charset_converter(CHARSET_INFO *tocs); + int fix_outer_field(THD *thd, Field **field, Item **reference); friend class Item_default_value; friend class Item_insert_value; friend class st_select_lex_unit; @@ -487,20 +1264,21 @@ public: } enum Type type() const { return NULL_ITEM; } bool eq(const Item *item, bool binary_cmp) const; - double val(); + double val_real(); longlong val_int(); String *val_str(String *str); + my_decimal *val_decimal(my_decimal *); int save_in_field(Field *field, bool no_conversions); int save_safe_in_field(Field *field); bool send(Protocol *protocol, String *str); enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_NULL; } - // to prevent drop fixed flag (no need parent cleanup call) + /* to prevent drop fixed flag (no need parent cleanup call) */ void cleanup() {} bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } bool is_null() { return 1; } - void print(String *str) { str->append("NULL", 4); } + void print(String *str) { str->append(STRING_WITH_LEN("NULL")); } Item *safe_charset_converter(CHARSET_INFO *tocs); }; @@ -520,11 +1298,16 @@ public: class Item_param :public Item { + char cnvbuf[MAX_FIELD_WIDTH]; + String cnvstr; + Item *cnvitem; public: + enum enum_item_param_state { NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE, - STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE + STRING_VALUE, TIME_VALUE, LONG_DATA_VALUE, + DECIMAL_VALUE } state; /* @@ -538,6 +1321,7 @@ public: Can not be declared inside the union as it's not a POD type. */ String str_value_ptr; + my_decimal decimal_value; union { longlong integer; @@ -588,8 +1372,9 @@ public: enum Type type() const { return item_type; } enum_field_types field_type() const { return param_type; } - double val(); + double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal*); String *val_str(String*); bool get_time(TIME *tm); bool get_date(TIME *tm, uint fuzzydate); @@ -598,6 +1383,7 @@ public: 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); bool set_str(const char *str, ulong length); bool set_longdata(const char *str, ulong length); void set_time(TIME *tm, timestamp_type type, uint32 max_length_arg); @@ -622,7 +1408,7 @@ public: */ virtual table_map used_tables() const { return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; } - void print(String *str) { str->append('?'); } + void print(String *str); bool is_null() { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; } bool basic_const_item() const; @@ -636,8 +1422,8 @@ public: constant, assert otherwise. This method is called only if basic_const_item returned TRUE. */ - Item *new_item(); Item *safe_charset_converter(CHARSET_INFO *tocs); + Item *new_item(); /* Implement by-value equality evaluation if parameter value is set and is a basic constant (integer, real or string). @@ -653,10 +1439,10 @@ public: longlong value; Item_int(int32 i,uint length=11) :value((longlong) i) { max_length=length; fixed= 1; } -#ifdef HAVE_LONG_LONG Item_int(longlong i,uint length=21) :value(i) - { max_length=length; fixed= 1;} -#endif + { max_length=length; fixed= 1; } + Item_int(ulonglong i, uint length= 21) :value((longlong)i) + { max_length=length; fixed= 1; unsigned_flag= 1; } Item_int(const char *str_arg,longlong i,uint length) :value(i) { max_length=length; name=(char*) str_arg; fixed= 1; } Item_int(const char *str_arg, uint length=64); @@ -664,7 +1450,8 @@ public: enum Item_result result_type () const { return INT_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_LONGLONG; } longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } - double val() { DBUG_ASSERT(fixed == 1); return (double) value; } + double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } + my_decimal *val_decimal(my_decimal *); String *val_str(String*); int save_in_field(Field *field, bool no_conversions); bool basic_const_item() const { return 1; } @@ -673,6 +1460,8 @@ public: void cleanup() {} void print(String *str); Item_num *neg() { value= -value; return this; } + uint decimal_precision() const + { return (uint)(max_length - test(value < 0)); } bool eq(const Item *, bool binary_cmp) const; }; @@ -681,44 +1470,82 @@ class Item_uint :public Item_int { public: Item_uint(const char *str_arg, uint length); + Item_uint(ulonglong i) :Item_int((ulonglong) i, 10) {} Item_uint(const char *str_arg, longlong i, uint length); - Item_uint(uint32 i) :Item_int((longlong) i, 10) - { unsigned_flag= 1; } - double val() + double val_real() { DBUG_ASSERT(fixed == 1); return ulonglong2double((ulonglong)value); } String *val_str(String*); Item *new_item() { return new Item_uint(name,max_length); } int save_in_field(Field *field, bool no_conversions); void print(String *str); Item_num *neg (); + uint decimal_precision() const { return max_length; } }; -class Item_real :public Item_num +/* decimal (fixed point) constant */ +class Item_decimal :public Item_num { +protected: + my_decimal decimal_value; public: - double value; - // Item_real() :value(0) {} - Item_real(const char *str_arg, uint length) :value(my_atof(str_arg)) + Item_decimal(const char *str_arg, uint length, CHARSET_INFO *charset); + Item_decimal(const char *str, const my_decimal *val_arg, + uint decimal_par, uint length); + Item_decimal(my_decimal *value_par); + Item_decimal(longlong val, bool unsig); + Item_decimal(double val, int precision, int scale); + Item_decimal(const char *bin, int precision, int scale); + + enum Type type() const { return DECIMAL_ITEM; } + enum Item_result result_type () const { return DECIMAL_RESULT; } + enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; } + longlong val_int(); + double val_real(); + String *val_str(String*); + my_decimal *val_decimal(my_decimal *val) { return &decimal_value; } + int save_in_field(Field *field, bool no_conversions); + bool basic_const_item() const { return 1; } + Item *new_item() { - name=(char*) str_arg; - decimals=(uint8) nr_of_decimals(str_arg); - max_length=length; - fixed= 1; + return new Item_decimal(name, &decimal_value, decimals, max_length); + } + // to prevent drop fixed flag (no need parent cleanup call) + void cleanup() {} + void print(String *str); + Item_num *neg() + { + my_decimal_neg(&decimal_value); + unsigned_flag= !decimal_value.sign(); + return this; } - Item_real(const char *str,double val_arg,uint decimal_par,uint length) + uint decimal_precision() const { return decimal_value.precision(); } + bool eq(const Item *, bool binary_cmp) const; + void set_decimal_value(my_decimal *value_par); +}; + + +class Item_float :public Item_num +{ + char *presentation; +public: + double value; + // Item_real() :value(0) {} + Item_float(const char *str_arg, uint length); + Item_float(const char *str,double val_arg,uint decimal_par,uint length) :value(val_arg) { - name=(char*) str; + presentation= name=(char*) str; decimals=(uint8) decimal_par; max_length=length; fixed= 1; } - Item_real(double value_par) :value(value_par) { fixed= 1; } + Item_float(double value_par) :presentation(0), value(value_par) { fixed= 1; } + int save_in_field(Field *field, bool no_conversions); enum Type type() const { return REAL_ITEM; } enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } - double val() { DBUG_ASSERT(fixed == 1); return value; } + double val_real() { DBUG_ASSERT(fixed == 1); return value; } longlong val_int() { DBUG_ASSERT(fixed == 1); @@ -730,28 +1557,34 @@ public: { return LONGLONG_MAX; } - return (longlong) (value+(value > 0 ? 0.5 : -0.5)); + return (longlong) rint(value); } String *val_str(String*); + my_decimal *val_decimal(my_decimal *); bool basic_const_item() const { return 1; } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} - Item *new_item() { return new Item_real(name,value,decimals,max_length); } + Item *new_item() + { return new Item_float(name, value, decimals, max_length); } Item_num *neg() { value= -value; return this; } + void print(String *str); bool eq(const Item *, bool binary_cmp) const; }; -class Item_float :public Item_real +class Item_static_float_func :public Item_float { + const char *func_name; public: - Item_float(const char *str,uint length) :Item_real(str,length) - { - decimals=NOT_FIXED_DEC; - max_length=DBL_DIG+8; - } + Item_static_float_func(const char *str, double val_arg, uint decimal_par, + uint length) + :Item_float(NullS, val_arg, decimal_par, length), func_name(str) + {} + void print(String *str) { str->append(func_name); } + Item *safe_charset_converter(CHARSET_INFO *tocs); }; + class Item_string :public Item { public: @@ -773,41 +1606,47 @@ public: // it is constant => can be used without fix_fields (and frequently used) fixed= 1; } + /* Just create an item and do not fill string representation */ + Item_string(CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) + { + collation.set(cs, dv); + max_length= 0; + set_name(NULL, 0, cs); + decimals= NOT_FIXED_DEC; + fixed= 1; + } Item_string(const char *name_par, const char *str, uint length, CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) { collation.set(cs, dv); str_value.set_or_copy_aligned(str,length,cs); max_length= str_value.numchars()*cs->mbmaxlen; - set_name(name_par,0,cs); + set_name(name_par, 0, cs); decimals=NOT_FIXED_DEC; // it is constant => can be used without fix_fields (and frequently used) fixed= 1; } - enum Type type() const { return STRING_ITEM; } - double val() - { - DBUG_ASSERT(fixed == 1); - int err; - char *end_not_used; - return my_strntod(str_value.charset(), (char*) str_value.ptr(), - str_value.length(), &end_not_used, &err); - } - longlong val_int() + /* + This is used in stored procedures to avoid memory leaks and + does a deep copy of its argument. + */ + void set_str_with_copy(const char *str_arg, uint length_arg) { - DBUG_ASSERT(fixed == 1); - int err; - return my_strntoll(str_value.charset(), str_value.ptr(), - str_value.length(), 10, (char**) 0, &err); + str_value.copy(str_arg, length_arg, collation.collation); + max_length= str_value.numchars() * collation.collation->mbmaxlen; } + enum Type type() const { return STRING_ITEM; } + double val_real(); + longlong val_int(); String *val_str(String*) { DBUG_ASSERT(fixed == 1); return (String*) &str_value; } + my_decimal *val_decimal(my_decimal *); int save_in_field(Field *field, bool no_conversions); enum Item_result result_type () const { return STRING_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_STRING; } + enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } bool basic_const_item() const { return 1; } bool eq(const Item *item, bool binary_cmp) const; Item *new_item() @@ -816,20 +1655,34 @@ public: str_value.length(), collation.collation); } Item *safe_charset_converter(CHARSET_INFO *tocs); - String *const_string() { return &str_value; } inline void append(char *str, uint length) { str_value.append(str, length); } void print(String *str); // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} }; + +class Item_static_string_func :public Item_string +{ + const char *func_name; +public: + Item_static_string_func(const char *name_par, const char *str, uint length, + CHARSET_INFO *cs, + Derivation dv= DERIVATION_COERCIBLE) + :Item_string(NullS, str, length, cs, dv), func_name(name_par) + {} + Item *safe_charset_converter(CHARSET_INFO *tocs); + void print(String *str) { str->append(func_name); } +}; + + /* for show tables */ class Item_datetime :public Item_string { public: Item_datetime(const char *item_name): Item_string(item_name,"",0, - &my_charset_bin) + &my_charset_bin) { max_length=19;} enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } }; @@ -857,20 +1710,22 @@ public: }; -class Item_varbinary :public Item +class Item_hex_string: public Item { public: - Item_varbinary(const char *str,uint str_length); + Item_hex_string(): Item() {} + Item_hex_string(const char *str,uint str_length); enum Type type() const { return VARBIN_ITEM; } - double val() - { DBUG_ASSERT(fixed == 1); return (double) Item_varbinary::val_int(); } + double val_real() + { DBUG_ASSERT(fixed == 1); return (double) Item_hex_string::val_int(); } longlong val_int(); bool basic_const_item() const { return 1; } String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; } + my_decimal *val_decimal(my_decimal *); int save_in_field(Field *field, bool no_conversions); enum Item_result result_type () const { return STRING_RESULT; } enum Item_result cast_to_int_type() const { return INT_RESULT; } - enum_field_types field_type() const { return MYSQL_TYPE_STRING; } + enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} bool eq(const Item *item, bool binary_cmp) const; @@ -878,6 +1733,12 @@ public: }; +class Item_bin_string: public Item_hex_string +{ +public: + Item_bin_string(const char *str,uint str_length); +}; + class Item_result_field :public Item /* Item with result field */ { public: @@ -907,11 +1768,14 @@ class Item_ref :public Item_ident protected: void set_properties(); public: + enum Ref_Type { REF, DIRECT_REF, VIEW_REF }; Field *result_field; /* Save result here */ Item **ref; - Item_ref(const char *db_par, const char *table_name_par, - const char *field_name_par) - :Item_ident(db_par, table_name_par, field_name_par), ref(0) {} + Item_ref(Name_resolution_context *context_arg, + const char *db_arg, const char *table_name_arg, + const char *field_name_arg) + :Item_ident(context_arg, db_arg, table_name_arg, field_name_arg), + result_field(0), ref(0) {} /* This constructor is used in two scenarios: A) *item = NULL @@ -926,76 +1790,70 @@ public: TODO we probably fix a superset of problems like in BUG#6658. Check this with Bar, and if we have a more broader set of problems like this. */ - Item_ref(Item **item, const char *table_name_par, const char *field_name_par) - :Item_ident(NullS, table_name_par, field_name_par), ref(item) - { - DBUG_ASSERT(item); - if (*item) - set_properties(); - } + Item_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, const char *field_name_arg); /* Constructor need to process subselect with temporary tables (see Item) */ - Item_ref(THD *thd, Item_ref *item) :Item_ident(thd, item), ref(item->ref) {} + Item_ref(THD *thd, Item_ref *item) + :Item_ident(thd, item), result_field(item->result_field), ref(item->ref) {} enum Type type() const { return REF_ITEM; } bool eq(const Item *item, bool binary_cmp) const - { return ref && (*ref)->eq(item, binary_cmp); } - double val() - { - DBUG_ASSERT(fixed); - double tmp=(*ref)->val_result(); - null_value=(*ref)->null_value; - return tmp; - } - longlong val_int() - { - DBUG_ASSERT(fixed); - longlong tmp=(*ref)->val_int_result(); - null_value=(*ref)->null_value; - return tmp; - } - String *val_str(String* tmp) - { - DBUG_ASSERT(fixed); - tmp=(*ref)->str_result(tmp); - null_value=(*ref)->null_value; - return tmp; - } - bool is_null() - { - DBUG_ASSERT(fixed); - (void) (*ref)->val_int_result(); - return (*ref)->null_value; - } - bool get_date(TIME *ltime,uint fuzzydate) - { - DBUG_ASSERT(fixed); - return (null_value=(*ref)->get_date_result(ltime,fuzzydate)); + { + Item *it= ((Item *) item)->real_item(); + return ref && (*ref)->eq(it, binary_cmp); } - bool send(Protocol *prot, String *tmp){ return (*ref)->send(prot, tmp); } - void make_field(Send_field *field) { (*ref)->make_field(field); } - bool fix_fields(THD *, struct st_table_list *, Item **); - int save_in_field(Field *field, bool no_conversions) - { return (*ref)->save_in_field(field, no_conversions); } - void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } + double val_real(); + longlong val_int(); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); + String *val_str(String* tmp); + bool is_null(); + bool get_date(TIME *ltime,uint fuzzydate); + double val_result(); + longlong val_int_result(); + String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *); + bool val_bool_result(); + bool send(Protocol *prot, String *tmp); + void make_field(Send_field *field); + bool fix_fields(THD *, Item **); + int save_in_field(Field *field, bool no_conversions); + void save_org_in_field(Field *field); enum Item_result result_type () const { return (*ref)->result_type(); } enum_field_types field_type() const { return (*ref)->field_type(); } - Field *get_tmp_table_field() { return result_field; } + Field *get_tmp_table_field() + { return result_field ? result_field : (*ref)->get_tmp_table_field(); } + Item *get_tmp_table_item(THD *thd) + { + return (result_field ? new Item_field(result_field) : + (*ref)->get_tmp_table_item(thd)); + } table_map used_tables() const { return depended_from ? OUTER_REF_TABLE_BIT : (*ref)->used_tables(); } + table_map not_null_tables() const { return (*ref)->not_null_tables(); } void set_result_field(Field *field) { result_field= field; } bool is_result_field() { return 1; } void save_in_result_field(bool no_conversions) { (*ref)->save_in_field(result_field, no_conversions); } - Item *real_item() { return *ref; } + Item *real_item() + { + return ref ? (*ref)->real_item() : this; + } + bool walk(Item_processor processor, byte *arg) + { return (*ref)->walk(processor, arg); } void print(String *str); bool result_as_longlong() { return (*ref)->result_as_longlong(); } + void cleanup(); + Item_field *filed_for_view_update() + { return (*ref)->filed_for_view_update(); } + virtual Ref_Type ref_type() { return REF; } }; @@ -1006,39 +1864,41 @@ public: class Item_direct_ref :public Item_ref { public: - Item_direct_ref(Item **item, const char *table_name_par, - const char *field_name_par) - :Item_ref(item, table_name_par, field_name_par) {} + Item_direct_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, + const char *field_name_arg) + :Item_ref(context_arg, item, table_name_arg, field_name_arg) {} /* Constructor need to process subselect with temporary tables (see Item) */ Item_direct_ref(THD *thd, Item_direct_ref *item) : Item_ref(thd, item) {} - double val() - { - double tmp=(*ref)->val(); - null_value=(*ref)->null_value; - return tmp; - } - longlong val_int() - { - longlong tmp=(*ref)->val_int(); - null_value=(*ref)->null_value; - return tmp; - } - String *val_str(String* tmp) - { - tmp=(*ref)->val_str(tmp); - null_value=(*ref)->null_value; - return tmp; - } - bool is_null() - { - (void) (*ref)->val_int(); - return (*ref)->null_value; - } - bool get_date(TIME *ltime,uint fuzzydate) - { - return (null_value=(*ref)->get_date(ltime,fuzzydate)); - } + double val_real(); + longlong val_int(); + String *val_str(String* tmp); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); + bool is_null(); + bool get_date(TIME *ltime,uint fuzzydate); + virtual Ref_Type ref_type() { return DIRECT_REF; } +}; + +/* + Class for view fields, the same as Item_direct_ref, but call fix_fields + of reference if it is not called yet +*/ +class Item_direct_view_ref :public Item_direct_ref +{ +public: + Item_direct_view_ref(Name_resolution_context *context_arg, Item **item, + const char *table_name_arg, + const char *field_name_arg) + :Item_direct_ref(context_arg, item, table_name_arg, field_name_arg) {} + /* Constructor need to process subselect with temporary tables (see Item) */ + Item_direct_view_ref(THD *thd, Item_direct_ref *item) + :Item_direct_ref(thd, item) {} + + bool fix_fields(THD *, Item **); + bool eq(const Item *item, bool binary_cmp) const; + virtual Ref_Type ref_type() { return VIEW_REF; } }; @@ -1049,12 +1909,16 @@ class Item_ref_null_helper: public Item_ref protected: Item_in_subselect* owner; public: - Item_ref_null_helper(Item_in_subselect* master, Item **item, - const char *table_name_par, const char *field_name_par): - Item_ref(item, table_name_par, field_name_par), owner(master) {} - double val(); + Item_ref_null_helper(Name_resolution_context *context_arg, + Item_in_subselect* master, Item **item, + const char *table_name_arg, const char *field_name_arg) + :Item_ref(context_arg, item, table_name_arg, field_name_arg), + owner(master) {} + double val_real(); longlong val_int(); String* val_str(String* s); + my_decimal *val_decimal(my_decimal *); + bool val_bool(); bool get_date(TIME *ltime, uint fuzzydate); void print(String *str); /* @@ -1081,15 +1945,17 @@ class Item_int_with_ref :public Item_int { Item *ref; public: - Item_int_with_ref(longlong i, Item *ref_arg) :Item_int(i), ref(ref_arg) + Item_int_with_ref(longlong i, Item *ref_arg, my_bool unsigned_arg) : + Item_int(i), ref(ref_arg) { - unsigned_flag= ref_arg->unsigned_flag; + unsigned_flag= unsigned_arg; } int save_in_field(Field *field, bool no_conversions) { return ref->save_in_field(field, no_conversions); } Item *new_item(); + virtual Item *real_item() { return ref; } }; @@ -1121,20 +1987,23 @@ public: enum Type type() const { return COPY_STR_ITEM; } enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return cached_field_type; } - double val() + double val_real() { - int err; + int err_not_used; char *end_not_used; return (null_value ? 0.0 : my_strntod(str_value.charset(), (char*) str_value.ptr(), - str_value.length(), &end_not_used, &err)); + str_value.length(), &end_not_used, &err_not_used)); } longlong val_int() - { + { int err; - return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(),str_value.length(),10, (char**) 0,&err); + return null_value ? LL(0) : my_strntoll(str_value.charset(),str_value.ptr(), + str_value.length(),10, (char**) 0, + &err); } String *val_str(String*); + my_decimal *val_decimal(my_decimal *); void make_field(Send_field *field) { item->make_field(field); } void copy(); int save_in_field(Field *field, bool no_conversions); @@ -1144,55 +2013,64 @@ public: }; -class Item_buff :public Sql_alloc +class Cached_item :public Sql_alloc { public: my_bool null_value; - Item_buff() :null_value(0) {} + Cached_item() :null_value(0) {} virtual bool cmp(void)=0; - virtual ~Item_buff(); /*line -e1509 */ + virtual ~Cached_item(); /*line -e1509 */ }; -class Item_str_buff :public Item_buff +class Cached_item_str :public Cached_item { Item *item; String value,tmp_value; public: - Item_str_buff(THD *thd, Item *arg); + Cached_item_str(THD *thd, Item *arg); bool cmp(void); - ~Item_str_buff(); // Deallocate String:s + ~Cached_item_str(); // Deallocate String:s }; -class Item_real_buff :public Item_buff +class Cached_item_real :public Cached_item { Item *item; double value; public: - Item_real_buff(Item *item_par) :item(item_par),value(0.0) {} + Cached_item_real(Item *item_par) :item(item_par),value(0.0) {} bool cmp(void); }; -class Item_int_buff :public Item_buff +class Cached_item_int :public Cached_item { Item *item; longlong value; public: - Item_int_buff(Item *item_par) :item(item_par),value(0) {} + Cached_item_int(Item *item_par) :item(item_par),value(0) {} bool cmp(void); }; -class Item_field_buff :public Item_buff +class Cached_item_decimal :public Cached_item +{ + Item *item; + my_decimal value; +public: + Cached_item_decimal(Item *item_par); + bool cmp(void); +}; + +class Cached_item_field :public Cached_item { char *buff; Field *field; uint length; public: - Item_field_buff(Item_field *item) + Cached_item_field(Item_field *item) { - field=item->field; + field= item->field; buff= (char*) sql_calloc(length=field->pack_length()); } bool cmp(void); @@ -1202,40 +2080,61 @@ class Item_default_value : public Item_field { public: Item *arg; - Item_default_value() : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(NULL) {} - Item_default_value(Item *a) : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + Item_default_value(Name_resolution_context *context_arg) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(NULL) {} + Item_default_value(Name_resolution_context *context_arg, Item *a) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a) {} enum Type type() const { return DEFAULT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); - int save_in_field(Field *field_arg, bool no_conversions) - { - if (!arg) - { - field_arg->set_default(); - return 0; - } - return Item_field::save_in_field(field_arg, no_conversions); - } + int save_in_field(Field *field_arg, bool no_conversions); table_map used_tables() const { return (table_map)0L; } - + bool walk(Item_processor processor, byte *args) { return arg->walk(processor, args) || (this->*processor)(args); } + + /* + This method like the walk method traverses the item tree, but + at the same time it can replace some nodes in the tree + */ + Item *transform(Item_transformer transformer, byte *args) + { + Item *new_item= arg->transform(transformer, args); + if (!new_item) + return 0; + arg= new_item; + return (this->*transformer)(args); + } }; +/* + Item_insert_value -- an implementation of VALUES() function. + You can use the VALUES(col_name) function in the UPDATE clause + to refer to column values from the INSERT portion of the INSERT + ... UPDATE statement. In other words, VALUES(col_name) in the + UPDATE clause refers to the value of col_name that would be + inserted, had no duplicate-key conflict occurred. + In all other places this function returns NULL. +*/ + class Item_insert_value : public Item_field { public: Item *arg; - Item_insert_value(Item *a) : - Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} + Item_insert_value(Name_resolution_context *context_arg, Item *a) + :Item_field(context_arg, (const char *)NULL, (const char *)NULL, + (const char *)NULL), + arg(a) {} bool eq(const Item *item, bool binary_cmp) const; - bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_fields(THD *, Item **); void print(String *str); int save_in_field(Field *field_arg, bool no_conversions) { @@ -1250,6 +2149,108 @@ public: } }; + +/* + We need this two enums here instead of sql_lex.h because + at least one of them is used by Item_trigger_field interface. + + Time when trigger is invoked (i.e. before or after row actually + inserted/updated/deleted). +*/ +enum trg_action_time_type +{ + TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1, TRG_ACTION_MAX +}; + +/* + Event on which trigger is invoked. +*/ +enum trg_event_type +{ + TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2, TRG_EVENT_MAX +}; + +class Table_triggers_list; + +/* + Represents NEW/OLD version of field of row which is + changed/read in trigger. + + Note: For this item main part of actual binding to Field object happens + not during fix_fields() call (like for Item_field) but right after + parsing of trigger definition, when table is opened, with special + setup_field() call. On fix_fields() stage we simply choose one of + two Field instances representing either OLD or NEW version of this + field. +*/ +class Item_trigger_field : public Item_field, + private Settable_routine_parameter +{ +public: + /* Is this item represents row from NEW or OLD row ? */ + enum row_version_type {OLD_ROW, NEW_ROW}; + row_version_type row_version; + /* Next in list of all Item_trigger_field's in trigger */ + Item_trigger_field *next_trg_field; + /* Index of the field in the TABLE::field array */ + uint field_idx; + /* Pointer to Table_trigger_list object for table of this trigger */ + Table_triggers_list *triggers; + + Item_trigger_field(Name_resolution_context *context_arg, + row_version_type row_ver_arg, + const char *field_name_arg, + ulong priv, const bool ro) + :Item_field(context_arg, + (const char *)NULL, (const char *)NULL, field_name_arg), + row_version(row_ver_arg), field_idx((uint)-1), original_privilege(priv), + want_privilege(priv), table_grants(NULL), read_only (ro) + {} + void setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info); + enum Type type() const { return TRIGGER_FIELD_ITEM; } + bool eq(const Item *item, bool binary_cmp) const; + bool fix_fields(THD *, Item **); + void print(String *str); + table_map used_tables() const { return (table_map)0L; } + void cleanup(); + +private: + void set_required_privilege(bool rw); + bool set_value(THD *thd, sp_rcontext *ctx, Item **it); + +public: + Settable_routine_parameter *get_settable_routine_parameter() + { + return (read_only ? 0 : this); + } + + bool set_value(THD *thd, Item **it) + { + return set_value(thd, NULL, it); + } + +private: + /* + 'want_privilege' holds privileges required to perform operation on + this trigger field (SELECT_ACL if we are going to read it and + UPDATE_ACL if we are going to update it). It is initialized at + parse time but can be updated later if this trigger field is used + as OUT or INOUT parameter of stored routine (in this case + set_required_privilege() is called to appropriately update + want_privilege and cleanup() is responsible for restoring of + original want_privilege once parameter's value is updated). + */ + ulong original_privilege; + ulong want_privilege; + GRANT_INFO *table_grants; + /* + Trigger field is read-only unless it belongs to the NEW row in a + BEFORE INSERT of BEFORE UPDATE trigger. + */ + bool read_only; +}; + + class Item_cache: public Item { protected: @@ -1267,6 +2268,7 @@ public: max_length= item->max_length; decimals= item->decimals; collation.set(item->collation); + unsigned_flag= item->unsigned_flag; return 0; }; virtual void store(Item *)= 0; @@ -1279,24 +2281,23 @@ public: void print(String *str); }; + class Item_cache_int: public Item_cache { +protected: longlong value; public: Item_cache_int(): Item_cache(), value(0) {} - + void store(Item *item); - double val() { DBUG_ASSERT(fixed == 1); return (double) value; } + double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; } longlong val_int() { DBUG_ASSERT(fixed == 1); return value; } - String* val_str(String *str) - { - DBUG_ASSERT(fixed == 1); - str->set(value, default_charset()); - return str; - } + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return INT_RESULT; } }; + class Item_cache_real: public Item_cache { double value; @@ -1304,31 +2305,42 @@ public: Item_cache_real(): Item_cache(), value(0) {} void store(Item *item); - double val() { DBUG_ASSERT(fixed == 1); return value; } - longlong val_int() - { - DBUG_ASSERT(fixed == 1); - return (longlong) (value+(value > 0 ? 0.5 : -0.5)); - } - String* val_str(String *str) - { - str->set(value, decimals, default_charset()); - return str; - } + double val_real() { DBUG_ASSERT(fixed == 1); return value; } + longlong val_int(); + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return REAL_RESULT; } }; + +class Item_cache_decimal: public Item_cache +{ +protected: + my_decimal decimal_value; +public: + Item_cache_decimal(): Item_cache() {} + + void store(Item *item); + double val_real(); + longlong val_int(); + String* val_str(String *str); + my_decimal *val_decimal(my_decimal *); + enum Item_result result_type() const { return DECIMAL_RESULT; } +}; + + class Item_cache_str: public Item_cache { - char buffer[80]; + char buffer[STRING_BUFFER_USUAL_SIZE]; String *value, value_buff; public: Item_cache_str(): Item_cache(), value(0) { } - + void store(Item *item); - double val(); + double val_real(); longlong val_int(); String* val_str(String *) { DBUG_ASSERT(fixed == 1); return value; } + my_decimal *val_decimal(my_decimal *); enum Item_result result_type() const { return STRING_RESULT; } CHARSET_INFO *charset() const { return value->charset(); }; }; @@ -1358,7 +2370,7 @@ public: { illegal_method_call((const char*)"make_field"); }; - double val() + double val_real() { illegal_method_call((const char*)"val"); return 0; @@ -1373,6 +2385,12 @@ public: illegal_method_call((const char*)"val_str"); return 0; }; + my_decimal *val_decimal(my_decimal *val) + { + illegal_method_call((const char*)"val_decimal"); + return 0; + }; + enum Item_result result_type() const { return ROW_RESULT; } uint cols() { return item_count; } @@ -1409,14 +2427,18 @@ protected: enum_field_types fld_type; void get_full_info(Item *item); + + /* It is used to count decimal precision in join_types */ + int prev_decimal_int_part; public: Item_type_holder(THD*, Item*); Item_result result_type() const; - virtual enum_field_types field_type() const { return fld_type; }; + enum_field_types field_type() const { return fld_type; }; enum Type type() const { return TYPE_HOLDER; } - double val(); + double val_real(); longlong val_int(); + my_decimal *val_decimal(my_decimal *); String *val_str(String*); bool join_types(THD *thd, Item *); Field *make_field_by_type(TABLE *table); @@ -1425,7 +2447,14 @@ public: }; -extern Item_buff *new_Item_buff(THD *thd, Item *item); +class st_select_lex; +void mark_select_range_as_dependent(THD *thd, + st_select_lex *last_select, + st_select_lex *current_sel, + Field *found_field, Item *found_item, + Item_ident *resolved_item); + +extern Cached_item *new_Cached_item(THD *thd, Item *item); extern Item_result item_cmp_type(Item_result a,Item_result b); extern void resolve_const_item(THD *thd, Item **ref, Item *cmp_item); extern bool field_is_equal_to_item(Field *field,Item *item); |