diff options
Diffstat (limited to 'sql/item.h')
-rw-r--r-- | sql/item.h | 673 |
1 files changed, 549 insertions, 124 deletions
diff --git a/sql/item.h b/sql/item.h index dacac2d725e..5bcdc45ce23 100644 --- a/sql/item.h +++ b/sql/item.h @@ -25,7 +25,6 @@ #include "sql_priv.h" /* STRING_BUFFER_USUAL_SIZE */ #include "unireg.h" #include "sql_const.h" /* RAND_TABLE_BIT, MAX_FIELD_NAME */ -#include "unireg.h" // REQUIRED: for other includes #include "thr_malloc.h" /* sql_calloc */ #include "field.h" /* Derivation */ @@ -170,6 +169,12 @@ public: default: return "UNKNOWN"; } } + int sortcmp(const String *s, const String *t) const + { + return collation->coll->strnncollsp(collation, + (uchar *) s->ptr(), s->length(), + (uchar *) t->ptr(), t->length(), 0); + } }; /*************************************************************************/ @@ -524,7 +529,7 @@ public: RETURN FALSE if parameter value has been set, - TRUE if error has occured. + TRUE if error has occurred. */ virtual bool set_value(THD *thd, sp_rcontext *ctx, Item **it)= 0; @@ -537,7 +542,7 @@ public: struct st_dyncall_create_def { - Item *num, *value; + Item *key, *value; CHARSET_INFO *cs; uint len, frac; DYNAMIC_COLUMN_TYPE type; @@ -562,11 +567,21 @@ typedef bool (Item::*Item_analyzer) (uchar **argp); typedef Item* (Item::*Item_transformer) (uchar *arg); typedef void (*Cond_traverser) (const Item *item, void *arg); +struct st_cond_statistic; + +struct find_selective_predicates_list_processor_data +{ + TABLE *table; + List<st_cond_statistic> list; +}; + class Item_equal; class COND_EQUAL; class st_select_lex_unit; +class Item_func_not; + class Item { Item(const Item &); /* Prevent use of these */ void operator=(Item &); @@ -597,7 +612,8 @@ public: SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM, XPATH_NODESET, XPATH_NODESET_CMP, - VIEW_FIXER_ITEM, EXPR_CACHE_ITEM}; + VIEW_FIXER_ITEM, EXPR_CACHE_ITEM, + DATE_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -609,11 +625,20 @@ public: /* Reuse size, only used by SP local variable assignment, otherwize 0 */ uint rsize; +protected: /* str_values's main purpose is to be used to cache the value in save_in_field */ String str_value; + +public: + /* + Cache val_str() into the own buffer, e.g. to evaluate constant + expressions with subqueries in the ORDER/GROUP clauses. + */ + String *val_str() { return val_str(&str_value); } + char * name; /* Name from select */ /* Original item name (if it was renamed)*/ char * orig_name; @@ -688,7 +713,9 @@ public: Fix after some tables has been pulled out. Basically re-calculate all attributes that are dependent on the tables. */ - virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref) {}; + virtual void fix_after_pullout(st_select_lex *new_parent, Item **ref, + bool merge) + {}; /* This method should be used in case where we are sure that we do not need @@ -705,8 +732,12 @@ public: /* 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) + virtual void save_org_in_field(Field *field, + fast_field_copier data + __attribute__ ((__unused__))) { (void) save_in_field(field, 1); } + virtual fast_field_copier setup_fast_field_copier(Field *field) + { return NULL; } virtual int save_safe_in_field(Field *field) { return save_in_field(field, 1); } virtual bool send(Protocol *protocol, String *str); @@ -808,25 +839,20 @@ public: 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. + The caller can modify the returned String, if it's not marked + "const" (with the String::mark_as_const() method). That means that + if the item returns its own internal buffer (e.g. tmp_value), it + *must* be marked "const" [1]. So normally it's preferrable to + return the result value in the String, that was passed as an + argument. But, for example, SUBSTR() returns a String that simply + points into the buffer of SUBSTR()'s args[0]->val_str(). Such a + String is always "const", so it's ok to use tmp_value for that and + avoid reallocating/copying of the argument String. + + [1] consider SELECT CONCAT(f, ":", f) FROM (SELECT func() AS f); + here the return value of f() is used twice in the top-level + select, and if they share the same tmp_value buffer, modifying the + first one will implicitly modify the second too. RETURN In case of NULL value return 0 (NULL pointer) and set null_value flag @@ -942,7 +968,7 @@ public: save_val() is method of val_* family which stores value in the given field. */ - virtual void save_val(Field *to) { save_org_in_field(to); } + virtual void save_val(Field *to) { save_org_in_field(to, NULL); } /* save_result() is method of val*result() family which stores value in the given field. @@ -963,6 +989,11 @@ public: double val_real_from_decimal(); double val_real_from_date(); + // Get TIME, DATE or DATETIME using proper sql_mode flags for the field type + bool get_temporal_with_sql_mode(MYSQL_TIME *ltime); + // Check NULL value for a TIME, DATE or DATETIME expression + bool is_null_from_temporal(); + int save_time_in_field(Field *field); int save_date_in_field(Field *field); int save_str_value_in_field(Field *field, String *result); @@ -1036,7 +1067,7 @@ public: return decimals < NOT_FIXED_DEC ? decimals : is_temporal_type_with_time(field_type()) ? TIME_SECOND_PART_DIGITS : - min(max_length, DECIMAL_MAX_SCALE); + MY_MIN(max_length, DECIMAL_MAX_SCALE); } /* Returns how many digits a divisor adds into a division result. @@ -1104,7 +1135,9 @@ public: Item **ref, bool skip_registered); virtual bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_time(MYSQL_TIME *ltime) - { return get_date(ltime, TIME_TIME_ONLY); } + { return get_date(ltime, TIME_TIME_ONLY | TIME_INVALID_DATES); } + // Get date with automatic TIME->DATETIME conversion + bool get_date_with_conversion(MYSQL_TIME *ltime, ulonglong fuzzydate); bool get_seconds(ulonglong *sec, ulong *sec_part); virtual bool get_date_result(MYSQL_TIME *ltime, ulonglong fuzzydate) { return get_date(ltime,fuzzydate); } @@ -1160,8 +1193,8 @@ public: */ virtual CHARSET_INFO *charset_for_protocol(void) const { - return result_type() == STRING_RESULT ? collation.collation : - &my_charset_bin; + return cmp_type() == STRING_RESULT ? collation.collation : + &my_charset_bin; }; virtual bool walk(Item_processor processor, bool walk_subquery, uchar *arg) @@ -1169,6 +1202,11 @@ public: return (this->*processor)(arg); } + virtual bool walk_top_and(Item_processor processor, uchar *arg) + { + return (this->*processor)(arg); + } + virtual Item* transform(Item_transformer transformer, uchar *arg); /* @@ -1211,11 +1249,11 @@ public: virtual bool intro_version(uchar *int_arg) { return 0; } virtual bool remove_dependence_processor(uchar * arg) { return 0; } - virtual bool remove_fixed(uchar * arg) { fixed= 0; 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; } @@ -1231,9 +1269,12 @@ public: 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; } bool cleanup_is_expensive_cache_processor(uchar *arg) { is_expensive_cache= (int8)(-1); @@ -1255,6 +1296,7 @@ public: return FALSE; } + /* The next function differs from the previous one that a bitmap to be updated is passed as uchar *arg. @@ -1384,7 +1426,9 @@ public: List<Item> *parameters; /* unit from which we count nest_level */ st_select_lex_unit *nest_level_base; + uint count; int nest_level; + bool collect; }; /** Collect outer references @@ -1434,13 +1478,55 @@ public: virtual void bring_value() {} Field *tmp_table_field_from_field_type(TABLE *table, bool fixed_length); - virtual Item_field *filed_for_view_update() { return 0; } + virtual Item_field *field_for_view_update() { return 0; } virtual Item *neg_transformer(THD *thd) { return NULL; } virtual Item *update_value_transformer(uchar *select_arg) { return this; } virtual Item *expr_cache_insert_transformer(uchar *thd_arg) { return this; } virtual bool expr_cache_is_needed(THD *) { return FALSE; } virtual Item *safe_charset_converter(CHARSET_INFO *tocs); + bool needs_charset_converter(uint32 length, CHARSET_INFO *tocs) const + { + /* + This will return "true" if conversion happens: + - between two non-binary different character sets + - from "binary" to "unsafe" character set + (those that can have non-well-formed string) + - from "binary" to UCS2-alike character set with mbminlen>1, + when prefix left-padding is needed for an incomplete character: + binary 0xFF -> ucs2 0x00FF) + */ + if (!String::needs_conversion_on_storage(length, + collation.collation, tocs)) + return false; + /* + No needs to add converter if an "arg" is NUMERIC or DATETIME + value (which is pure ASCII) and at the same time target DTCollation + is ASCII-compatible. For example, no needs to rewrite: + SELECT * FROM t1 WHERE datetime_field = '2010-01-01'; + to + SELECT * FROM t1 WHERE CONVERT(datetime_field USING cs) = '2010-01-01'; + + TODO: avoid conversion of any values with + repertoire ASCII and 7bit-ASCII-compatible, + not only numeric/datetime origin. + */ + if (collation.derivation == DERIVATION_NUMERIC && + collation.repertoire == MY_REPERTOIRE_ASCII && + !(collation.collation->state & MY_CS_NONASCII) && + !(tocs->state & MY_CS_NONASCII)) + return false; + return true; + } + bool needs_charset_converter(CHARSET_INFO *tocs) + { + // Pass 1 as length to force conversion if tocs->mbminlen>1. + return needs_charset_converter(1, tocs); + } + Item *const_charset_converter(CHARSET_INFO *tocs, bool lossless, + const char *func_name); + Item *const_charset_converter(CHARSET_INFO *tocs, bool lossless) + { return const_charset_converter(tocs, lossless, NULL); } void delete_self() { cleanup(); @@ -1489,7 +1575,7 @@ public: { if (is_expensive_cache < 0) is_expensive_cache= walk(&Item::is_expensive_processor, 0, (uchar*)0); - return test(is_expensive_cache); + return MY_TEST(is_expensive_cache); } virtual Field::geometry_type get_geometry_type() const { return Field::GEOM_GEOMETRY; }; @@ -1553,6 +1639,15 @@ public: virtual void get_cache_parameters(List<Item> ¶meters) { }; virtual void mark_as_condition_AND_part(TABLE_LIST *embedding) {}; + + /* how much position should be reserved for Exists2In transformation */ + virtual uint exists2in_reserved_items() { return 0; }; + + /** + 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))) {}; }; @@ -1589,12 +1684,102 @@ public: }; class sp_head; +class Item_string; + -class Item_basic_constant :public Item +/** + A common class for Item_basic_constant and Item_param +*/ +class Item_basic_value :public Item +{ + bool is_basic_value(const Item *item, Type type_arg) const + { + return item->basic_const_item() && item->type() == type_arg; + } + bool is_basic_value(Type type_arg) const + { + return basic_const_item() && type() == type_arg; + } + bool str_eq(const String *value, + const String *other, CHARSET_INFO *cs, bool binary_cmp) const + { + return binary_cmp ? + value->bin_eq(other) : + collation.collation == cs && value->eq(other, collation.collation); + } + +protected: + // Value metadata, e.g. to make string processing easier + class Metadata: private MY_STRING_METADATA + { + public: + Metadata(const String *str) + { + my_string_metadata_get(this, str->charset(), str->ptr(), str->length()); + } + Metadata(const String *str, uint repertoire) + { + MY_STRING_METADATA::repertoire= repertoire; + MY_STRING_METADATA::char_length= str->numchars(); + } + uint repertoire() const { return MY_STRING_METADATA::repertoire; } + size_t char_length() const { return MY_STRING_METADATA::char_length; } + }; + void fix_charset_and_length_from_str_value(Derivation dv, Metadata metadata) + { + /* + We have to have a different max_length than 'length' here to + ensure that we get the right length if we do use the item + to create a new table. In this case max_length must be the maximum + number of chars for a string of this type because we in Create_field:: + divide the max_length with mbmaxlen). + */ + collation.set(str_value.charset(), dv, metadata.repertoire()); + fix_char_length(metadata.char_length()); + decimals= NOT_FIXED_DEC; + } + void fix_charset_and_length_from_str_value(Derivation dv) + { + fix_charset_and_length_from_str_value(dv, Metadata(&str_value)); + } + Item_basic_value(): Item() {} + /* + In the xxx_eq() methods below we need to cast off "const" to + call val_xxx(). This is OK for Item_basic_constant and Item_param. + */ + bool null_eq(const Item *item) const + { + DBUG_ASSERT(is_basic_value(NULL_ITEM)); + return item->type() == NULL_ITEM; + } + bool str_eq(const String *value, const Item *item, bool binary_cmp) const + { + DBUG_ASSERT(is_basic_value(STRING_ITEM)); + return is_basic_value(item, STRING_ITEM) && + str_eq(value, ((Item_basic_value*)item)->val_str(NULL), + item->collation.collation, binary_cmp); + } + bool real_eq(double value, const Item *item) const + { + DBUG_ASSERT(is_basic_value(REAL_ITEM)); + return is_basic_value(item, REAL_ITEM) && + value == ((Item_basic_value*)item)->val_real(); + } + bool int_eq(longlong value, const Item *item) const + { + DBUG_ASSERT(is_basic_value(INT_ITEM)); + return is_basic_value(item, INT_ITEM) && + value == ((Item_basic_value*)item)->val_int() && + (value >= 0 || item->unsigned_flag == unsigned_flag); + } +}; + + +class Item_basic_constant :public Item_basic_value { table_map used_table_map; public: - Item_basic_constant(): Item(), used_table_map(0) {}; + Item_basic_constant(): Item_basic_value(), used_table_map(0) {}; void set_used_tables(table_map map) { used_table_map= map; } table_map used_tables() const { return used_table_map; } /* to prevent drop fixed flag (no need parent cleanup call) */ @@ -2085,10 +2270,11 @@ public: bool send(Protocol *protocol, String *str_arg); void reset_field(Field *f); bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); void make_field(Send_field *tmp_field); int save_in_field(Field *field,bool no_conversions); - void save_org_in_field(Field *field); + void save_org_in_field(Field *field, fast_field_copier optimizer_data); + fast_field_copier setup_fast_field_copier(Field *field); table_map used_tables() const; table_map all_used_tables() const; enum Item_result result_type () const @@ -2156,8 +2342,7 @@ public: bool set_no_const_sub(uchar *arg); Item *replace_equal_field(uchar *arg); inline uint32 max_disp_length() { return field->max_display_length(); } - Item_field *filed_for_view_update() { return this; } - Item *safe_charset_converter(CHARSET_INFO *tocs); + Item_field *field_for_view_update() { return this; } int fix_outer_field(THD *thd, Field **field, Item **reference); virtual Item *update_value_transformer(uchar *select_arg); virtual void print(String *str, enum_query_type query_type); @@ -2181,16 +2366,16 @@ public: class Item_null :public Item_basic_constant { public: - Item_null(char *name_par=0) + Item_null(char *name_par=0, CHARSET_INFO *cs= &my_charset_bin) { maybe_null= null_value= TRUE; max_length= 0; name= name_par ? name_par : (char*) "NULL"; fixed= 1; - collation.set(&my_charset_bin, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII); + collation.set(cs, DERIVATION_IGNORABLE, MY_REPERTOIRE_ASCII); } enum Type type() const { return NULL_ITEM; } - bool eq(const Item *item, bool binary_cmp) const; + bool eq(const Item *item, bool binary_cmp) const { return null_eq(item); } double val_real(); longlong val_int(); String *val_str(String *str); @@ -2233,13 +2418,9 @@ public: /* Item represents one placeholder ('?') of prepared statement */ -class Item_param :public Item, +class Item_param :public Item_basic_value, private Settable_routine_parameter { - char cnvbuf[MAX_FIELD_WIDTH]; - String cnvstr; - Item *cnvitem; - public: enum enum_item_param_state { @@ -2307,7 +2488,6 @@ public: Item_param(uint pos_in_query_arg); enum Item_result result_type () const { return item_result_type; } - enum Item_result cast_to_int_type() const { return item_result_type; } enum Type type() const { return item_type; } enum_field_types field_type() const { return param_type; } @@ -2342,7 +2522,7 @@ public: /* If value for parameter was not set we treat it as non-const - so noone will use parameters value in fix_fields still + so no one will use parameters value in fix_fields still parameter is constant during execution. */ virtual table_map used_tables() const @@ -2423,8 +2603,9 @@ public: virtual void print(String *str, enum_query_type query_type); 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; + { 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;} }; @@ -2545,7 +2726,8 @@ public: { return new Item_float(name, value, decimals, max_length); } Item_num *neg() { value= -value; return this; } virtual void print(String *str, enum_query_type query_type); - bool eq(const Item *, bool binary_cmp) const; + bool eq(const Item *item, bool binary_cmp) const + { return real_eq(value, item); } }; @@ -2563,70 +2745,98 @@ public: str->append(func_name); } - Item *safe_charset_converter(CHARSET_INFO *tocs); + Item *safe_charset_converter(CHARSET_INFO *tocs) + { + return const_charset_converter(tocs, true, func_name); + } }; class Item_string :public Item_basic_constant { -public: - Item_string(const char *str,uint length, - CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE, - uint repertoire= MY_REPERTOIRE_UNICODE30) - : m_cs_specified(FALSE) + bool m_cs_specified; +protected: + /** + Set the value of m_cs_specified attribute. + + m_cs_specified attribute shows whether character-set-introducer was + explicitly specified in the original query for this text literal or + not. The attribute makes sense (is used) only for views. + + This operation is to be called from the parser during parsing an input + query. + */ + inline void set_cs_specified(bool cs_specified) { - str_value.set_or_copy_aligned(str, length, cs); - collation.set(cs, dv, repertoire); - /* - We have to have a different max_length than 'length' here to - ensure that we get the right length if we do use the item - to create a new table. In this case max_length must be the maximum - number of chars for a string of this type because we in Create_field:: - divide the max_length with mbmaxlen). - */ - max_length= str_value.numchars()*cs->mbmaxlen; - set_name(str, length, cs); - decimals=NOT_FIXED_DEC; + m_cs_specified= cs_specified; + } + void fix_from_value(Derivation dv, const Metadata metadata) + { + fix_charset_and_length_from_str_value(dv, metadata); // 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) + { + fix_from_value(dv, metadata); + set_name(str_value.ptr(), str_value.length(), str_value.charset()); + } +protected: /* Just create an item and do not fill string representation */ Item_string(CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) : m_cs_specified(FALSE) { collation.set(cs, dv); max_length= 0; - set_name(NULL, 0, cs); + set_name(NULL, 0, system_charset_info); decimals= NOT_FIXED_DEC; fixed= 1; } - Item_string(const char *name_par, const char *str, uint length, - CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE, - uint repertoire= MY_REPERTOIRE_UNICODE30) +public: + // Constructors with the item name set from its value + Item_string(const char *str, uint length, CHARSET_INFO *cs, + Derivation dv, uint repertoire) : m_cs_specified(FALSE) { str_value.set_or_copy_aligned(str, length, cs); - collation.set(cs, dv, repertoire); - max_length= str_value.numchars()*cs->mbmaxlen; - set_name(name_par, 0, cs); - decimals=NOT_FIXED_DEC; - // it is constant => can be used without fix_fields (and frequently used) - fixed= 1; + fix_and_set_name_from_value(dv, Metadata(&str_value, repertoire)); } - /* - 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) + Item_string(const char *str, uint length, + CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) + : m_cs_specified(FALSE) { - str_value.copy(str_arg, length_arg, collation.collation); - max_length= str_value.numchars() * collation.collation->mbmaxlen; + str_value.set_or_copy_aligned(str, length, cs); + fix_and_set_name_from_value(dv, Metadata(&str_value)); } - void set_repertoire_from_value() + Item_string(const String *str, CHARSET_INFO *tocs, uint *conv_errors, + Derivation dv, uint repertoire) + :m_cs_specified(false) { - collation.repertoire= my_string_repertoire(str_value.charset(), - str_value.ptr(), - str_value.length()); + 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)); + } + // Constructors with an externally provided item name + Item_string(const char *name_par, const char *str, uint length, + CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE) + :m_cs_specified(false) + { + str_value.set_or_copy_aligned(str, length, cs); + fix_from_value(dv, Metadata(&str_value)); + set_name(name_par, 0, system_charset_info); + } + Item_string(const char *name_par, const char *str, uint length, + CHARSET_INFO *cs, Derivation dv, uint repertoire) + :m_cs_specified(false) + { + 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); + } + void print_value(String *to) const + { + str_value.print(to); } enum Type type() const { return STRING_ITEM; } double val_real(); @@ -2641,13 +2851,19 @@ public: enum Item_result result_type () const { return STRING_RESULT; } 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; + bool eq(const Item *item, bool binary_cmp) const + { + return str_eq(&str_value, item, binary_cmp); + } Item *clone_item() { return new Item_string(name, str_value.ptr(), - str_value.length(), collation.collation); + str_value.length(), collation.collation); + } + Item *safe_charset_converter(CHARSET_INFO *tocs) + { + return const_charset_converter(tocs, true); } - Item *safe_charset_converter(CHARSET_INFO *tocs); inline void append(char *str, uint length) { str_value.append(str, length); @@ -2681,23 +2897,80 @@ public: return m_cs_specified; } - /** - Set the value of m_cs_specified attribute. + String *check_well_formed_result(bool send_error) + { return Item::check_well_formed_result(&str_value, send_error); } - m_cs_specified attribute shows whether character-set-introducer was - explicitly specified in the original query for this text literal or - not. The attribute makes sense (is used) only for views. + enum_field_types odbc_temporal_literal_type(const LEX_STRING *type_str) const + { + /* + If string is a reasonably short pure ASCII string literal, + try to parse known ODBC style date, time or timestamp literals, + e.g: + SELECT {d'2001-01-01'}; + SELECT {t'10:20:30'}; + SELECT {ts'2001-01-01 10:20:30'}; + */ + if (collation.repertoire == MY_REPERTOIRE_ASCII && + str_value.length() < MAX_DATE_STRING_REP_LENGTH * 4) + { + if (type_str->length == 1) + { + if (type_str->str[0] == 'd') /* {d'2001-01-01'} */ + return MYSQL_TYPE_DATE; + else if (type_str->str[0] == 't') /* {t'10:20:30'} */ + return MYSQL_TYPE_TIME; + } + else if (type_str->length == 2) /* {ts'2001-01-01 10:20:30'} */ + { + if (type_str->str[0] == 't' && type_str->str[1] == 's') + return MYSQL_TYPE_DATETIME; + } + } + return MYSQL_TYPE_STRING; // Not a temporal literal + } +}; - This operation is to be called from the parser during parsing an input - query. - */ - inline void set_cs_specified(bool cs_specified) + +class Item_string_with_introducer :public Item_string +{ +public: + Item_string_with_introducer(const char *str, uint length, CHARSET_INFO *cs) + :Item_string(str, length, cs) { - m_cs_specified= cs_specified; + set_cs_specified(true); + } + Item_string_with_introducer(const char *name, + const char *str, uint length, CHARSET_INFO *tocs) + :Item_string(name, str, length, tocs) + { + set_cs_specified(true); } +}; -private: - bool m_cs_specified; + +class Item_string_sys :public Item_string +{ +public: + Item_string_sys(const char *str, uint length) + :Item_string(str, length, system_charset_info) + { } + Item_string_sys(const char *str) + :Item_string(str, strlen(str), system_charset_info) + { } +}; + + +class Item_string_ascii :public Item_string +{ +public: + Item_string_ascii(const char *str, uint length) + :Item_string(str, length, &my_charset_latin1, + DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII) + { } + Item_string_ascii(const char *str) + :Item_string(str, strlen(str), &my_charset_latin1, + DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII) + { } }; @@ -2717,7 +2990,17 @@ public: Derivation dv= DERIVATION_COERCIBLE) :Item_string(NullS, str, length, cs, dv), func_name(name_par) {} - Item *safe_charset_converter(CHARSET_INFO *tocs); + Item_static_string_func(const char *name_par, + const String *str, + CHARSET_INFO *tocs, uint *conv_errors, + Derivation dv, uint repertoire) + :Item_string(str, tocs, conv_errors, dv, repertoire), + func_name(name_par) + {} + Item *safe_charset_converter(CHARSET_INFO *tocs) + { + return const_charset_converter(tocs, true, func_name); + } virtual inline void print(String *str, enum_query_type query_type) { @@ -2820,11 +3103,19 @@ public: enum Type type() const { return VARBIN_ITEM; } enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; } - virtual Item *safe_charset_converter(CHARSET_INFO *tocs); + virtual Item *safe_charset_converter(CHARSET_INFO *tocs) + { + return const_charset_converter(tocs, true); + } bool check_partition_func_processor(uchar *int_arg) {return FALSE;} bool check_vcol_func_processor(uchar *arg) { return FALSE;} bool basic_const_item() const { return 1; } - bool eq(const Item *item, bool binary_cmp) const; + bool eq(const Item *item, bool binary_cmp) const + { + return item->basic_const_item() && item->type() == type() && + item->cast_to_int_type() == cast_to_int_type() && + str_value.bin_eq(&((Item_hex_constant*)item)->str_value); + } String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; } }; @@ -2912,6 +3203,121 @@ public: Item_bin_string(const char *str,uint str_length); }; + +class Item_temporal_literal :public Item_basic_constant +{ +protected: + MYSQL_TIME cached_time; +public: + /** + Constructor for Item_date_literal. + @param ltime DATE value. + */ + Item_temporal_literal(MYSQL_TIME *ltime) :Item_basic_constant() + { + collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); + decimals= 0; + cached_time= *ltime; + } + Item_temporal_literal(MYSQL_TIME *ltime, uint dec_arg) :Item_basic_constant() + { + collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); + decimals= dec_arg; + cached_time= *ltime; + } + bool basic_const_item() const { return true; } + bool const_item() const { return true; } + enum Type type() const { return DATE_ITEM; } + bool eq(const Item *item, bool binary_cmp) const; + 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 is_null() + { return is_null_from_temporal(); } + bool get_date_with_sql_mode(MYSQL_TIME *to); + String *val_str(String *str) + { return val_string_from_date(str); } + longlong val_int() + { return val_int_from_date(); } + double val_real() + { return val_real_from_date(); } + my_decimal *val_decimal(my_decimal *decimal_value) + { return val_decimal_from_date(decimal_value); } + Field *tmp_table_field(TABLE *table) + { return tmp_table_field_from_field_type(table, 0); } + int save_in_field(Field *field, bool no_conversions) + { return save_date_in_field(field); } +}; + + +/** + DATE'2010-01-01' +*/ +class Item_date_literal: public Item_temporal_literal +{ +public: + Item_date_literal(MYSQL_TIME *ltime) + :Item_temporal_literal(ltime) + { + max_length= MAX_DATE_WIDTH; + fixed= 1; + /* + If date has zero month or day, it can return NULL in case of + NO_ZERO_DATE or NO_ZERO_IN_DATE. + We can't just check the current sql_mode here in constructor, + because sql_mode can change in case of prepared statements + between PREPARE and EXECUTE. + */ + maybe_null= !ltime->month || !ltime->day; + } + enum_field_types field_type() const { return MYSQL_TYPE_DATE; } + void print(String *str, enum_query_type query_type); + bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); +}; + + +/** + TIME'10:10:10' +*/ +class Item_time_literal: public Item_temporal_literal +{ +public: + Item_time_literal(MYSQL_TIME *ltime, uint dec_arg) + :Item_temporal_literal(ltime, dec_arg) + { + max_length= MIN_TIME_WIDTH + (decimals ? decimals + 1 : 0); + fixed= 1; + } + enum_field_types field_type() const { return MYSQL_TYPE_TIME; } + void print(String *str, enum_query_type query_type); + bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); +}; + + +/** + TIMESTAMP'2001-01-01 10:20:30' +*/ +class Item_datetime_literal: public Item_temporal_literal +{ +public: + Item_datetime_literal(MYSQL_TIME *ltime, uint dec_arg) + :Item_temporal_literal(ltime, dec_arg) + { + max_length= MAX_DATETIME_WIDTH + (decimals ? decimals + 1 : 0); + fixed= 1; + // See the comment on maybe_null in Item_date_literal + maybe_null= !ltime->month || !ltime->day; + } + enum_field_types field_type() const { return MYSQL_TYPE_DATETIME; } + void print(String *str, enum_query_type query_type); + bool get_date(MYSQL_TIME *res, ulonglong fuzzy_date); +}; + + + class Item_result_field :public Item /* Item with result field */ { public: @@ -3018,9 +3424,11 @@ public: bool send(Protocol *prot, String *tmp); void make_field(Send_field *field); bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); int save_in_field(Field *field, bool no_conversions); - void save_org_in_field(Field *field); + void save_org_in_field(Field *field, fast_field_copier optimizer_data); + fast_field_copier setup_fast_field_copier(Field *field) + { return (*ref)->setup_fast_field_copier(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() @@ -3069,8 +3477,8 @@ public: } virtual void print(String *str, enum_query_type query_type); void cleanup(); - Item_field *filed_for_view_update() - { return (*ref)->filed_for_view_update(); } + Item_field *field_for_view_update() + { return (*ref)->field_for_view_update(); } virtual Ref_Type ref_type() { return REF; } // Row emulation: forwarding of ROW-related calls to ref @@ -3145,6 +3553,13 @@ public: alias_name_used_arg) {} + bool fix_fields(THD *thd, Item **it) + { + if ((!(*ref)->fixed && (*ref)->fix_fields(thd, ref)) || + (*ref)->check_cols(1)) + return TRUE; + return Item_ref::fix_fields(thd, it); + } void save_val(Field *to); double val_real(); longlong val_int(); @@ -3242,7 +3657,8 @@ public: bool is_null(); bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate); bool send(Protocol *protocol, String *buffer); - void save_org_in_field(Field *field) + void save_org_in_field(Field *field, + fast_field_copier data __attribute__ ((__unused__))) { save_val(field); } @@ -3262,9 +3678,9 @@ public: Item *it= ((Item *) item)->real_item(); return orig_item->eq(it, binary_cmp); } - void fix_after_pullout(st_select_lex *new_parent, Item **refptr) + void fix_after_pullout(st_select_lex *new_parent, Item **refptr, bool merge) { - orig_item->fix_after_pullout(new_parent, &orig_item); + orig_item->fix_after_pullout(new_parent, &orig_item, merge); } int save_in_field(Field *to, bool no_conversions); enum Item_result result_type () const { return orig_item->result_type(); } @@ -3283,8 +3699,8 @@ public: } bool enumerate_field_refs_processor(uchar *arg) { return orig_item->enumerate_field_refs_processor(arg); } - Item_field *filed_for_view_update() - { return orig_item->filed_for_view_update(); } + Item_field *field_for_view_update() + { return orig_item->field_for_view_update(); } /* Row emulation: forwarding of ROW-related calls to orig_item */ uint cols() @@ -3363,6 +3779,8 @@ public: bool eq(const Item *item, bool binary_cmp) const; Item *get_tmp_table_item(THD *thd) { + if (const_item()) + return copy_or_same(thd); Item *item= Item_ref::get_tmp_table_item(thd); item->name= name; return item; @@ -3449,7 +3867,8 @@ public: return Item_direct_ref::get_date(ltime, fuzzydate); } bool send(Protocol *protocol, String *buffer); - void save_org_in_field(Field *field) + void save_org_in_field(Field *field, + fast_field_copier data __attribute__ ((__unused__))) { if (check_null_ref()) field->set_null(); @@ -3505,7 +3924,7 @@ public: { ref= &outer_ref; set_properties(); - fixed= 0; + fixed= 0; /* reset flag set in set_properties() */ } Item_outer_ref(Name_resolution_context *context_arg, Item **item, const char *table_name_arg, const char *field_name_arg, @@ -3516,10 +3935,10 @@ public: {} void save_in_result_field(bool no_conversions) { - outer_ref->save_org_in_field(result_field); + outer_ref->save_org_in_field(result_field, NULL); } bool fix_fields(THD *, Item **); - void fix_after_pullout(st_select_lex *new_parent, Item **ref); + void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); table_map used_tables() const { return (*ref)->const_item() ? 0 : OUTER_REF_TABLE_BIT; @@ -3831,6 +4250,10 @@ public: int save_in_field(Field *field_arg, bool no_conversions); table_map used_tables() const { return (table_map)0L; } + 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 walk(Item_processor processor, bool walk_subquery, uchar *args) { return (arg && arg->walk(processor, walk_subquery, args)) || @@ -3872,6 +4295,8 @@ public: */ table_map used_tables() const { return RAND_TABLE_BIT; } + Item_field *field_for_view_update() { return 0; } + bool walk(Item_processor processor, bool walk_subquery, uchar *args) { return arg->walk(processor, walk_subquery, args) || @@ -4062,7 +4487,7 @@ public: virtual void store(Item *item); virtual bool cache_value()= 0; bool basic_const_item() const - { return test(example && example->basic_const_item());} + { return MY_TEST(example && example->basic_const_item()); } virtual void clear() { null_value= TRUE; value_cached= FALSE; } bool is_null() { return null_value; } virtual bool is_expensive() |