summaryrefslogtreecommitdiff
path: root/sql/item.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item.h')
-rw-r--r--sql/item.h673
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> &parameters) { };
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()